1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * linux/arch/arm/common/locomo.c |
4 | * |
5 | * Sharp LoCoMo support |
6 | * |
7 | * This file contains all generic LoCoMo support. |
8 | * |
9 | * All initialization functions provided here are intended to be called |
10 | * from machine specific code with proper arguments when required. |
11 | * |
12 | * Based on sa1111.c |
13 | */ |
14 | |
15 | #include <linux/module.h> |
16 | #include <linux/init.h> |
17 | #include <linux/kernel.h> |
18 | #include <linux/delay.h> |
19 | #include <linux/errno.h> |
20 | #include <linux/ioport.h> |
21 | #include <linux/platform_device.h> |
22 | #include <linux/slab.h> |
23 | #include <linux/spinlock.h> |
24 | #include <linux/io.h> |
25 | |
26 | #include <asm/irq.h> |
27 | #include <asm/mach/irq.h> |
28 | |
29 | #include <asm/hardware/locomo.h> |
30 | |
31 | /* LoCoMo Interrupts */ |
32 | #define IRQ_LOCOMO_KEY (0) |
33 | #define IRQ_LOCOMO_GPIO (1) |
34 | #define IRQ_LOCOMO_LT (2) |
35 | #define IRQ_LOCOMO_SPI (3) |
36 | |
37 | /* M62332 output channel selection */ |
38 | #define M62332_EVR_CH 1 /* M62332 volume channel number */ |
39 | /* 0 : CH.1 , 1 : CH. 2 */ |
40 | /* DAC send data */ |
41 | #define M62332_SLAVE_ADDR 0x4e /* Slave address */ |
42 | #define M62332_W_BIT 0x00 /* W bit (0 only) */ |
43 | #define M62332_SUB_ADDR 0x00 /* Sub address */ |
44 | #define M62332_A_BIT 0x00 /* A bit (0 only) */ |
45 | |
46 | /* DAC setup and hold times (expressed in us) */ |
47 | #define DAC_BUS_FREE_TIME 5 /* 4.7 us */ |
48 | #define DAC_START_SETUP_TIME 5 /* 4.7 us */ |
49 | #define DAC_STOP_SETUP_TIME 4 /* 4.0 us */ |
50 | #define DAC_START_HOLD_TIME 5 /* 4.7 us */ |
51 | #define DAC_SCL_LOW_HOLD_TIME 5 /* 4.7 us */ |
52 | #define DAC_SCL_HIGH_HOLD_TIME 4 /* 4.0 us */ |
53 | #define DAC_DATA_SETUP_TIME 1 /* 250 ns */ |
54 | #define DAC_DATA_HOLD_TIME 1 /* 300 ns */ |
55 | #define DAC_LOW_SETUP_TIME 1 /* 300 ns */ |
56 | #define DAC_HIGH_SETUP_TIME 1 /* 1000 ns */ |
57 | |
58 | /* the following is the overall data for the locomo chip */ |
59 | struct locomo { |
60 | struct device *dev; |
61 | unsigned long phys; |
62 | unsigned int irq; |
63 | int irq_base; |
64 | spinlock_t lock; |
65 | void __iomem *base; |
66 | #ifdef CONFIG_PM |
67 | void *saved_state; |
68 | #endif |
69 | }; |
70 | |
71 | struct locomo_dev_info { |
72 | unsigned long offset; |
73 | unsigned long length; |
74 | unsigned int devid; |
75 | unsigned int irq[1]; |
76 | const char * name; |
77 | }; |
78 | |
79 | /* All the locomo devices. If offset is non-zero, the mapbase for the |
80 | * locomo_dev will be set to the chip base plus offset. If offset is |
81 | * zero, then the mapbase for the locomo_dev will be set to zero. An |
82 | * offset of zero means the device only uses GPIOs or other helper |
83 | * functions inside this file */ |
84 | static struct locomo_dev_info locomo_devices[] = { |
85 | { |
86 | .devid = LOCOMO_DEVID_KEYBOARD, |
87 | .irq = { IRQ_LOCOMO_KEY }, |
88 | .name = "locomo-keyboard" , |
89 | .offset = LOCOMO_KEYBOARD, |
90 | .length = 16, |
91 | }, |
92 | { |
93 | .devid = LOCOMO_DEVID_FRONTLIGHT, |
94 | .irq = {}, |
95 | .name = "locomo-frontlight" , |
96 | .offset = LOCOMO_FRONTLIGHT, |
97 | .length = 8, |
98 | |
99 | }, |
100 | { |
101 | .devid = LOCOMO_DEVID_BACKLIGHT, |
102 | .irq = {}, |
103 | .name = "locomo-backlight" , |
104 | .offset = LOCOMO_BACKLIGHT, |
105 | .length = 8, |
106 | }, |
107 | { |
108 | .devid = LOCOMO_DEVID_AUDIO, |
109 | .irq = {}, |
110 | .name = "locomo-audio" , |
111 | .offset = LOCOMO_AUDIO, |
112 | .length = 4, |
113 | }, |
114 | { |
115 | .devid = LOCOMO_DEVID_LED, |
116 | .irq = {}, |
117 | .name = "locomo-led" , |
118 | .offset = LOCOMO_LED, |
119 | .length = 8, |
120 | }, |
121 | { |
122 | .devid = LOCOMO_DEVID_UART, |
123 | .irq = {}, |
124 | .name = "locomo-uart" , |
125 | .offset = 0, |
126 | .length = 0, |
127 | }, |
128 | { |
129 | .devid = LOCOMO_DEVID_SPI, |
130 | .irq = {}, |
131 | .name = "locomo-spi" , |
132 | .offset = LOCOMO_SPI, |
133 | .length = 0x30, |
134 | }, |
135 | }; |
136 | |
137 | static void locomo_handler(struct irq_desc *desc) |
138 | { |
139 | struct locomo *lchip = irq_desc_get_handler_data(desc); |
140 | int req, i; |
141 | |
142 | /* Acknowledge the parent IRQ */ |
143 | desc->irq_data.chip->irq_ack(&desc->irq_data); |
144 | |
145 | /* check why this interrupt was generated */ |
146 | req = locomo_readl(lchip->base + LOCOMO_ICR) & 0x0f00; |
147 | |
148 | if (req) { |
149 | unsigned int irq; |
150 | |
151 | /* generate the next interrupt(s) */ |
152 | irq = lchip->irq_base; |
153 | for (i = 0; i <= 3; i++, irq++) { |
154 | if (req & (0x0100 << i)) { |
155 | generic_handle_irq(irq); |
156 | } |
157 | |
158 | } |
159 | } |
160 | } |
161 | |
162 | static void locomo_ack_irq(struct irq_data *d) |
163 | { |
164 | } |
165 | |
166 | static void locomo_mask_irq(struct irq_data *d) |
167 | { |
168 | struct locomo *lchip = irq_data_get_irq_chip_data(d); |
169 | unsigned int r; |
170 | r = locomo_readl(lchip->base + LOCOMO_ICR); |
171 | r &= ~(0x0010 << (d->irq - lchip->irq_base)); |
172 | locomo_writel(r, lchip->base + LOCOMO_ICR); |
173 | } |
174 | |
175 | static void locomo_unmask_irq(struct irq_data *d) |
176 | { |
177 | struct locomo *lchip = irq_data_get_irq_chip_data(d); |
178 | unsigned int r; |
179 | r = locomo_readl(lchip->base + LOCOMO_ICR); |
180 | r |= (0x0010 << (d->irq - lchip->irq_base)); |
181 | locomo_writel(r, lchip->base + LOCOMO_ICR); |
182 | } |
183 | |
184 | static struct irq_chip locomo_chip = { |
185 | .name = "LOCOMO" , |
186 | .irq_ack = locomo_ack_irq, |
187 | .irq_mask = locomo_mask_irq, |
188 | .irq_unmask = locomo_unmask_irq, |
189 | }; |
190 | |
191 | static void locomo_setup_irq(struct locomo *lchip) |
192 | { |
193 | int irq = lchip->irq_base; |
194 | |
195 | /* |
196 | * Install handler for IRQ_LOCOMO_HW. |
197 | */ |
198 | irq_set_irq_type(lchip->irq, IRQ_TYPE_EDGE_FALLING); |
199 | irq_set_chained_handler_and_data(lchip->irq, locomo_handler, lchip); |
200 | |
201 | /* Install handlers for IRQ_LOCOMO_* */ |
202 | for ( ; irq <= lchip->irq_base + 3; irq++) { |
203 | irq_set_chip_and_handler(irq, &locomo_chip, handle_level_irq); |
204 | irq_set_chip_data(irq, lchip); |
205 | irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); |
206 | } |
207 | } |
208 | |
209 | |
210 | static void locomo_dev_release(struct device *_dev) |
211 | { |
212 | struct locomo_dev *dev = LOCOMO_DEV(_dev); |
213 | |
214 | kfree(objp: dev); |
215 | } |
216 | |
217 | static int |
218 | locomo_init_one_child(struct locomo *lchip, struct locomo_dev_info *info) |
219 | { |
220 | struct locomo_dev *dev; |
221 | int ret; |
222 | |
223 | dev = kzalloc(sizeof(struct locomo_dev), GFP_KERNEL); |
224 | if (!dev) { |
225 | ret = -ENOMEM; |
226 | goto out; |
227 | } |
228 | |
229 | /* |
230 | * If the parent device has a DMA mask associated with it, |
231 | * propagate it down to the children. |
232 | */ |
233 | if (lchip->dev->dma_mask) { |
234 | dev->dma_mask = *lchip->dev->dma_mask; |
235 | dev->dev.dma_mask = &dev->dma_mask; |
236 | } |
237 | |
238 | dev_set_name(dev: &dev->dev, name: "%s" , info->name); |
239 | dev->devid = info->devid; |
240 | dev->dev.parent = lchip->dev; |
241 | dev->dev.bus = &locomo_bus_type; |
242 | dev->dev.release = locomo_dev_release; |
243 | dev->dev.coherent_dma_mask = lchip->dev->coherent_dma_mask; |
244 | |
245 | if (info->offset) |
246 | dev->mapbase = lchip->base + info->offset; |
247 | else |
248 | dev->mapbase = 0; |
249 | dev->length = info->length; |
250 | |
251 | dev->irq[0] = (lchip->irq_base == NO_IRQ) ? |
252 | NO_IRQ : lchip->irq_base + info->irq[0]; |
253 | |
254 | ret = device_register(dev: &dev->dev); |
255 | if (ret) { |
256 | out: |
257 | kfree(objp: dev); |
258 | } |
259 | return ret; |
260 | } |
261 | |
262 | #ifdef CONFIG_PM |
263 | |
264 | struct locomo_save_data { |
265 | u16 LCM_GPO; |
266 | u16 LCM_SPICT; |
267 | u16 LCM_GPE; |
268 | u16 LCM_ASD; |
269 | u16 LCM_SPIMD; |
270 | }; |
271 | |
272 | static int locomo_suspend(struct platform_device *dev, pm_message_t state) |
273 | { |
274 | struct locomo *lchip = platform_get_drvdata(pdev: dev); |
275 | struct locomo_save_data *save; |
276 | unsigned long flags; |
277 | |
278 | save = kmalloc(size: sizeof(struct locomo_save_data), GFP_KERNEL); |
279 | if (!save) |
280 | return -ENOMEM; |
281 | |
282 | lchip->saved_state = save; |
283 | |
284 | spin_lock_irqsave(&lchip->lock, flags); |
285 | |
286 | save->LCM_GPO = locomo_readl(lchip->base + LOCOMO_GPO); /* GPIO */ |
287 | locomo_writel(0x00, lchip->base + LOCOMO_GPO); |
288 | save->LCM_SPICT = locomo_readl(lchip->base + LOCOMO_SPI + LOCOMO_SPICT); /* SPI */ |
289 | locomo_writel(0x40, lchip->base + LOCOMO_SPI + LOCOMO_SPICT); |
290 | save->LCM_GPE = locomo_readl(lchip->base + LOCOMO_GPE); /* GPIO */ |
291 | locomo_writel(0x00, lchip->base + LOCOMO_GPE); |
292 | save->LCM_ASD = locomo_readl(lchip->base + LOCOMO_ASD); /* ADSTART */ |
293 | locomo_writel(0x00, lchip->base + LOCOMO_ASD); |
294 | save->LCM_SPIMD = locomo_readl(lchip->base + LOCOMO_SPI + LOCOMO_SPIMD); /* SPI */ |
295 | locomo_writel(0x3C14, lchip->base + LOCOMO_SPI + LOCOMO_SPIMD); |
296 | |
297 | locomo_writel(0x00, lchip->base + LOCOMO_PAIF); |
298 | locomo_writel(0x00, lchip->base + LOCOMO_DAC); |
299 | locomo_writel(0x00, lchip->base + LOCOMO_BACKLIGHT + LOCOMO_TC); |
300 | |
301 | if ((locomo_readl(lchip->base + LOCOMO_LED + LOCOMO_LPT0) & 0x88) && (locomo_readl(lchip->base + LOCOMO_LED + LOCOMO_LPT1) & 0x88)) |
302 | locomo_writel(0x00, lchip->base + LOCOMO_C32K); /* CLK32 off */ |
303 | else |
304 | /* 18MHz already enabled, so no wait */ |
305 | locomo_writel(0xc1, lchip->base + LOCOMO_C32K); /* CLK32 on */ |
306 | |
307 | locomo_writel(0x00, lchip->base + LOCOMO_TADC); /* 18MHz clock off*/ |
308 | locomo_writel(0x00, lchip->base + LOCOMO_AUDIO + LOCOMO_ACC); /* 22MHz/24MHz clock off */ |
309 | locomo_writel(0x00, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS); /* FL */ |
310 | |
311 | spin_unlock_irqrestore(lock: &lchip->lock, flags); |
312 | |
313 | return 0; |
314 | } |
315 | |
316 | static int locomo_resume(struct platform_device *dev) |
317 | { |
318 | struct locomo *lchip = platform_get_drvdata(pdev: dev); |
319 | struct locomo_save_data *save; |
320 | unsigned long r; |
321 | unsigned long flags; |
322 | |
323 | save = lchip->saved_state; |
324 | if (!save) |
325 | return 0; |
326 | |
327 | spin_lock_irqsave(&lchip->lock, flags); |
328 | |
329 | locomo_writel(save->LCM_GPO, lchip->base + LOCOMO_GPO); |
330 | locomo_writel(save->LCM_SPICT, lchip->base + LOCOMO_SPI + LOCOMO_SPICT); |
331 | locomo_writel(save->LCM_GPE, lchip->base + LOCOMO_GPE); |
332 | locomo_writel(save->LCM_ASD, lchip->base + LOCOMO_ASD); |
333 | locomo_writel(save->LCM_SPIMD, lchip->base + LOCOMO_SPI + LOCOMO_SPIMD); |
334 | |
335 | locomo_writel(0x00, lchip->base + LOCOMO_C32K); |
336 | locomo_writel(0x90, lchip->base + LOCOMO_TADC); |
337 | |
338 | locomo_writel(0, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KSC); |
339 | r = locomo_readl(lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC); |
340 | r &= 0xFEFF; |
341 | locomo_writel(r, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC); |
342 | locomo_writel(0x1, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KCMD); |
343 | |
344 | spin_unlock_irqrestore(lock: &lchip->lock, flags); |
345 | |
346 | lchip->saved_state = NULL; |
347 | kfree(objp: save); |
348 | |
349 | return 0; |
350 | } |
351 | #endif |
352 | |
353 | static int |
354 | __locomo_probe(struct device *me, struct resource *mem, int irq) |
355 | { |
356 | struct locomo_platform_data *pdata = me->platform_data; |
357 | struct locomo *lchip; |
358 | unsigned long r; |
359 | int i, ret = -ENODEV; |
360 | |
361 | lchip = kzalloc(size: sizeof(struct locomo), GFP_KERNEL); |
362 | if (!lchip) |
363 | return -ENOMEM; |
364 | |
365 | spin_lock_init(&lchip->lock); |
366 | |
367 | lchip->dev = me; |
368 | dev_set_drvdata(dev: lchip->dev, data: lchip); |
369 | |
370 | lchip->phys = mem->start; |
371 | lchip->irq = irq; |
372 | lchip->irq_base = (pdata) ? pdata->irq_base : NO_IRQ; |
373 | |
374 | /* |
375 | * Map the whole region. This also maps the |
376 | * registers for our children. |
377 | */ |
378 | lchip->base = ioremap(offset: mem->start, PAGE_SIZE); |
379 | if (!lchip->base) { |
380 | ret = -ENOMEM; |
381 | goto out; |
382 | } |
383 | |
384 | /* locomo initialize */ |
385 | locomo_writel(0, lchip->base + LOCOMO_ICR); |
386 | /* KEYBOARD */ |
387 | locomo_writel(0, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC); |
388 | |
389 | /* GPIO */ |
390 | locomo_writel(0, lchip->base + LOCOMO_GPO); |
391 | locomo_writel((LOCOMO_GPIO(1) | LOCOMO_GPIO(2) | LOCOMO_GPIO(13) | LOCOMO_GPIO(14)) |
392 | , lchip->base + LOCOMO_GPE); |
393 | locomo_writel((LOCOMO_GPIO(1) | LOCOMO_GPIO(2) | LOCOMO_GPIO(13) | LOCOMO_GPIO(14)) |
394 | , lchip->base + LOCOMO_GPD); |
395 | locomo_writel(0, lchip->base + LOCOMO_GIE); |
396 | |
397 | /* Frontlight */ |
398 | locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS); |
399 | locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALD); |
400 | |
401 | /* Longtime timer */ |
402 | locomo_writel(0, lchip->base + LOCOMO_LTINT); |
403 | /* SPI */ |
404 | locomo_writel(0, lchip->base + LOCOMO_SPI + LOCOMO_SPIIE); |
405 | |
406 | locomo_writel(6 + 8 + 320 + 30 - 10, lchip->base + LOCOMO_ASD); |
407 | r = locomo_readl(lchip->base + LOCOMO_ASD); |
408 | r |= 0x8000; |
409 | locomo_writel(r, lchip->base + LOCOMO_ASD); |
410 | |
411 | locomo_writel(6 + 8 + 320 + 30 - 10 - 128 + 4, lchip->base + LOCOMO_HSD); |
412 | r = locomo_readl(lchip->base + LOCOMO_HSD); |
413 | r |= 0x8000; |
414 | locomo_writel(r, lchip->base + LOCOMO_HSD); |
415 | |
416 | locomo_writel(128 / 8, lchip->base + LOCOMO_HSC); |
417 | |
418 | /* XON */ |
419 | locomo_writel(0x80, lchip->base + LOCOMO_TADC); |
420 | udelay(1000); |
421 | /* CLK9MEN */ |
422 | r = locomo_readl(lchip->base + LOCOMO_TADC); |
423 | r |= 0x10; |
424 | locomo_writel(r, lchip->base + LOCOMO_TADC); |
425 | udelay(100); |
426 | |
427 | /* init DAC */ |
428 | r = locomo_readl(lchip->base + LOCOMO_DAC); |
429 | r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB; |
430 | locomo_writel(r, lchip->base + LOCOMO_DAC); |
431 | |
432 | r = locomo_readl(lchip->base + LOCOMO_VER); |
433 | printk(KERN_INFO "LoCoMo Chip: %lu%lu\n" , (r >> 8), (r & 0xff)); |
434 | |
435 | /* |
436 | * The interrupt controller must be initialised before any |
437 | * other device to ensure that the interrupts are available. |
438 | */ |
439 | if (lchip->irq != NO_IRQ && lchip->irq_base != NO_IRQ) |
440 | locomo_setup_irq(lchip); |
441 | |
442 | for (i = 0; i < ARRAY_SIZE(locomo_devices); i++) |
443 | locomo_init_one_child(lchip, &locomo_devices[i]); |
444 | return 0; |
445 | |
446 | out: |
447 | kfree(objp: lchip); |
448 | return ret; |
449 | } |
450 | |
451 | static int locomo_remove_child(struct device *dev, void *data) |
452 | { |
453 | device_unregister(dev); |
454 | return 0; |
455 | } |
456 | |
457 | static void __locomo_remove(struct locomo *lchip) |
458 | { |
459 | device_for_each_child(dev: lchip->dev, NULL, fn: locomo_remove_child); |
460 | |
461 | if (lchip->irq != NO_IRQ) { |
462 | irq_set_chained_handler_and_data(lchip->irq, NULL, NULL); |
463 | } |
464 | |
465 | iounmap(addr: lchip->base); |
466 | kfree(objp: lchip); |
467 | } |
468 | |
469 | /** |
470 | * locomo_probe - probe for a single LoCoMo chip. |
471 | * @dev: platform device |
472 | * |
473 | * Probe for a LoCoMo chip. This must be called |
474 | * before any other locomo-specific code. |
475 | * |
476 | * Returns: |
477 | * * %-EINVAL - device's IORESOURCE_MEM not found |
478 | * * %-ENXIO - could not allocate an IRQ for the device |
479 | * * %-ENODEV - device not found. |
480 | * * %-EBUSY - physical address already marked in-use. |
481 | * * %-ENOMEM - could not allocate or iomap memory. |
482 | * * %0 - successful. |
483 | */ |
484 | static int locomo_probe(struct platform_device *dev) |
485 | { |
486 | struct resource *mem; |
487 | int irq; |
488 | |
489 | mem = platform_get_resource(dev, IORESOURCE_MEM, 0); |
490 | if (!mem) |
491 | return -EINVAL; |
492 | irq = platform_get_irq(dev, 0); |
493 | if (irq < 0) |
494 | return -ENXIO; |
495 | |
496 | return __locomo_probe(me: &dev->dev, mem, irq); |
497 | } |
498 | |
499 | static void locomo_remove(struct platform_device *dev) |
500 | { |
501 | struct locomo *lchip = platform_get_drvdata(pdev: dev); |
502 | |
503 | if (lchip) { |
504 | __locomo_remove(lchip); |
505 | platform_set_drvdata(pdev: dev, NULL); |
506 | } |
507 | } |
508 | |
509 | /* |
510 | * Not sure if this should be on the system bus or not yet. |
511 | * We really want some way to register a system device at |
512 | * the per-machine level, and then have this driver pick |
513 | * up the registered devices. |
514 | */ |
515 | static struct platform_driver locomo_device_driver = { |
516 | .probe = locomo_probe, |
517 | .remove_new = locomo_remove, |
518 | #ifdef CONFIG_PM |
519 | .suspend = locomo_suspend, |
520 | .resume = locomo_resume, |
521 | #endif |
522 | .driver = { |
523 | .name = "locomo" , |
524 | }, |
525 | }; |
526 | |
527 | /* |
528 | * Get the parent device driver (us) structure |
529 | * from a child function device |
530 | */ |
531 | static inline struct locomo *locomo_chip_driver(struct locomo_dev *ldev) |
532 | { |
533 | return (struct locomo *)dev_get_drvdata(dev: ldev->dev.parent); |
534 | } |
535 | |
536 | void locomo_gpio_set_dir(struct device *dev, unsigned int bits, unsigned int dir) |
537 | { |
538 | struct locomo *lchip = dev_get_drvdata(dev); |
539 | unsigned long flags; |
540 | unsigned int r; |
541 | |
542 | if (!lchip) |
543 | return; |
544 | |
545 | spin_lock_irqsave(&lchip->lock, flags); |
546 | |
547 | r = locomo_readl(lchip->base + LOCOMO_GPD); |
548 | if (dir) |
549 | r |= bits; |
550 | else |
551 | r &= ~bits; |
552 | locomo_writel(r, lchip->base + LOCOMO_GPD); |
553 | |
554 | r = locomo_readl(lchip->base + LOCOMO_GPE); |
555 | if (dir) |
556 | r |= bits; |
557 | else |
558 | r &= ~bits; |
559 | locomo_writel(r, lchip->base + LOCOMO_GPE); |
560 | |
561 | spin_unlock_irqrestore(lock: &lchip->lock, flags); |
562 | } |
563 | EXPORT_SYMBOL(locomo_gpio_set_dir); |
564 | |
565 | int locomo_gpio_read_level(struct device *dev, unsigned int bits) |
566 | { |
567 | struct locomo *lchip = dev_get_drvdata(dev); |
568 | unsigned long flags; |
569 | unsigned int ret; |
570 | |
571 | if (!lchip) |
572 | return -ENODEV; |
573 | |
574 | spin_lock_irqsave(&lchip->lock, flags); |
575 | ret = locomo_readl(lchip->base + LOCOMO_GPL); |
576 | spin_unlock_irqrestore(lock: &lchip->lock, flags); |
577 | |
578 | ret &= bits; |
579 | return ret; |
580 | } |
581 | EXPORT_SYMBOL(locomo_gpio_read_level); |
582 | |
583 | int locomo_gpio_read_output(struct device *dev, unsigned int bits) |
584 | { |
585 | struct locomo *lchip = dev_get_drvdata(dev); |
586 | unsigned long flags; |
587 | unsigned int ret; |
588 | |
589 | if (!lchip) |
590 | return -ENODEV; |
591 | |
592 | spin_lock_irqsave(&lchip->lock, flags); |
593 | ret = locomo_readl(lchip->base + LOCOMO_GPO); |
594 | spin_unlock_irqrestore(lock: &lchip->lock, flags); |
595 | |
596 | ret &= bits; |
597 | return ret; |
598 | } |
599 | EXPORT_SYMBOL(locomo_gpio_read_output); |
600 | |
601 | void locomo_gpio_write(struct device *dev, unsigned int bits, unsigned int set) |
602 | { |
603 | struct locomo *lchip = dev_get_drvdata(dev); |
604 | unsigned long flags; |
605 | unsigned int r; |
606 | |
607 | if (!lchip) |
608 | return; |
609 | |
610 | spin_lock_irqsave(&lchip->lock, flags); |
611 | |
612 | r = locomo_readl(lchip->base + LOCOMO_GPO); |
613 | if (set) |
614 | r |= bits; |
615 | else |
616 | r &= ~bits; |
617 | locomo_writel(r, lchip->base + LOCOMO_GPO); |
618 | |
619 | spin_unlock_irqrestore(lock: &lchip->lock, flags); |
620 | } |
621 | EXPORT_SYMBOL(locomo_gpio_write); |
622 | |
623 | static void locomo_m62332_sendbit(void *mapbase, int bit) |
624 | { |
625 | unsigned int r; |
626 | |
627 | r = locomo_readl(mapbase + LOCOMO_DAC); |
628 | r &= ~(LOCOMO_DAC_SCLOEB); |
629 | locomo_writel(r, mapbase + LOCOMO_DAC); |
630 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
631 | udelay(DAC_DATA_HOLD_TIME); /* 300 nsec */ |
632 | r = locomo_readl(mapbase + LOCOMO_DAC); |
633 | r &= ~(LOCOMO_DAC_SCLOEB); |
634 | locomo_writel(r, mapbase + LOCOMO_DAC); |
635 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
636 | udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ |
637 | |
638 | if (bit & 1) { |
639 | r = locomo_readl(mapbase + LOCOMO_DAC); |
640 | r |= LOCOMO_DAC_SDAOEB; |
641 | locomo_writel(r, mapbase + LOCOMO_DAC); |
642 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ |
643 | } else { |
644 | r = locomo_readl(mapbase + LOCOMO_DAC); |
645 | r &= ~(LOCOMO_DAC_SDAOEB); |
646 | locomo_writel(r, mapbase + LOCOMO_DAC); |
647 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
648 | } |
649 | |
650 | udelay(DAC_DATA_SETUP_TIME); /* 250 nsec */ |
651 | r = locomo_readl(mapbase + LOCOMO_DAC); |
652 | r |= LOCOMO_DAC_SCLOEB; |
653 | locomo_writel(r, mapbase + LOCOMO_DAC); |
654 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ |
655 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.0 usec */ |
656 | } |
657 | |
658 | void locomo_m62332_senddata(struct locomo_dev *ldev, unsigned int dac_data, int channel) |
659 | { |
660 | struct locomo *lchip = locomo_chip_driver(ldev); |
661 | int i; |
662 | unsigned char data; |
663 | unsigned int r; |
664 | void *mapbase = lchip->base; |
665 | unsigned long flags; |
666 | |
667 | spin_lock_irqsave(&lchip->lock, flags); |
668 | |
669 | /* Start */ |
670 | udelay(DAC_BUS_FREE_TIME); /* 5.0 usec */ |
671 | r = locomo_readl(mapbase + LOCOMO_DAC); |
672 | r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB; |
673 | locomo_writel(r, mapbase + LOCOMO_DAC); |
674 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ |
675 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.0 usec */ |
676 | r = locomo_readl(mapbase + LOCOMO_DAC); |
677 | r &= ~(LOCOMO_DAC_SDAOEB); |
678 | locomo_writel(r, mapbase + LOCOMO_DAC); |
679 | udelay(DAC_START_HOLD_TIME); /* 5.0 usec */ |
680 | udelay(DAC_DATA_HOLD_TIME); /* 300 nsec */ |
681 | |
682 | /* Send slave address and W bit (LSB is W bit) */ |
683 | data = (M62332_SLAVE_ADDR << 1) | M62332_W_BIT; |
684 | for (i = 1; i <= 8; i++) { |
685 | locomo_m62332_sendbit(mapbase, bit: data >> (8 - i)); |
686 | } |
687 | |
688 | /* Check A bit */ |
689 | r = locomo_readl(mapbase + LOCOMO_DAC); |
690 | r &= ~(LOCOMO_DAC_SCLOEB); |
691 | locomo_writel(r, mapbase + LOCOMO_DAC); |
692 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
693 | udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ |
694 | r = locomo_readl(mapbase + LOCOMO_DAC); |
695 | r &= ~(LOCOMO_DAC_SDAOEB); |
696 | locomo_writel(r, mapbase + LOCOMO_DAC); |
697 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
698 | r = locomo_readl(mapbase + LOCOMO_DAC); |
699 | r |= LOCOMO_DAC_SCLOEB; |
700 | locomo_writel(r, mapbase + LOCOMO_DAC); |
701 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ |
702 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ |
703 | if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */ |
704 | printk(KERN_WARNING "locomo: m62332_senddata Error 1\n" ); |
705 | goto out; |
706 | } |
707 | |
708 | /* Send Sub address (LSB is channel select) */ |
709 | /* channel = 0 : ch1 select */ |
710 | /* = 1 : ch2 select */ |
711 | data = M62332_SUB_ADDR + channel; |
712 | for (i = 1; i <= 8; i++) { |
713 | locomo_m62332_sendbit(mapbase, bit: data >> (8 - i)); |
714 | } |
715 | |
716 | /* Check A bit */ |
717 | r = locomo_readl(mapbase + LOCOMO_DAC); |
718 | r &= ~(LOCOMO_DAC_SCLOEB); |
719 | locomo_writel(r, mapbase + LOCOMO_DAC); |
720 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
721 | udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ |
722 | r = locomo_readl(mapbase + LOCOMO_DAC); |
723 | r &= ~(LOCOMO_DAC_SDAOEB); |
724 | locomo_writel(r, mapbase + LOCOMO_DAC); |
725 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
726 | r = locomo_readl(mapbase + LOCOMO_DAC); |
727 | r |= LOCOMO_DAC_SCLOEB; |
728 | locomo_writel(r, mapbase + LOCOMO_DAC); |
729 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ |
730 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ |
731 | if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */ |
732 | printk(KERN_WARNING "locomo: m62332_senddata Error 2\n" ); |
733 | goto out; |
734 | } |
735 | |
736 | /* Send DAC data */ |
737 | for (i = 1; i <= 8; i++) { |
738 | locomo_m62332_sendbit(mapbase, bit: dac_data >> (8 - i)); |
739 | } |
740 | |
741 | /* Check A bit */ |
742 | r = locomo_readl(mapbase + LOCOMO_DAC); |
743 | r &= ~(LOCOMO_DAC_SCLOEB); |
744 | locomo_writel(r, mapbase + LOCOMO_DAC); |
745 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
746 | udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ |
747 | r = locomo_readl(mapbase + LOCOMO_DAC); |
748 | r &= ~(LOCOMO_DAC_SDAOEB); |
749 | locomo_writel(r, mapbase + LOCOMO_DAC); |
750 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
751 | r = locomo_readl(mapbase + LOCOMO_DAC); |
752 | r |= LOCOMO_DAC_SCLOEB; |
753 | locomo_writel(r, mapbase + LOCOMO_DAC); |
754 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ |
755 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ |
756 | if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */ |
757 | printk(KERN_WARNING "locomo: m62332_senddata Error 3\n" ); |
758 | } |
759 | |
760 | out: |
761 | /* stop */ |
762 | r = locomo_readl(mapbase + LOCOMO_DAC); |
763 | r &= ~(LOCOMO_DAC_SCLOEB); |
764 | locomo_writel(r, mapbase + LOCOMO_DAC); |
765 | udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ |
766 | udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ |
767 | r = locomo_readl(mapbase + LOCOMO_DAC); |
768 | r |= LOCOMO_DAC_SCLOEB; |
769 | locomo_writel(r, mapbase + LOCOMO_DAC); |
770 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ |
771 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4 usec */ |
772 | r = locomo_readl(mapbase + LOCOMO_DAC); |
773 | r |= LOCOMO_DAC_SDAOEB; |
774 | locomo_writel(r, mapbase + LOCOMO_DAC); |
775 | udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ |
776 | udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4 usec */ |
777 | |
778 | r = locomo_readl(mapbase + LOCOMO_DAC); |
779 | r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB; |
780 | locomo_writel(r, mapbase + LOCOMO_DAC); |
781 | udelay(DAC_LOW_SETUP_TIME); /* 1000 nsec */ |
782 | udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ |
783 | |
784 | spin_unlock_irqrestore(lock: &lchip->lock, flags); |
785 | } |
786 | EXPORT_SYMBOL(locomo_m62332_senddata); |
787 | |
788 | /* |
789 | * Frontlight control |
790 | */ |
791 | |
792 | void locomo_frontlight_set(struct locomo_dev *dev, int duty, int vr, int bpwf) |
793 | { |
794 | unsigned long flags; |
795 | struct locomo *lchip = locomo_chip_driver(ldev: dev); |
796 | |
797 | if (vr) |
798 | locomo_gpio_write(dev->dev.parent, LOCOMO_GPIO_FL_VR, 1); |
799 | else |
800 | locomo_gpio_write(dev->dev.parent, LOCOMO_GPIO_FL_VR, 0); |
801 | |
802 | spin_lock_irqsave(&lchip->lock, flags); |
803 | locomo_writel(bpwf, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS); |
804 | udelay(100); |
805 | locomo_writel(duty, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALD); |
806 | locomo_writel(bpwf | LOCOMO_ALC_EN, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS); |
807 | spin_unlock_irqrestore(lock: &lchip->lock, flags); |
808 | } |
809 | EXPORT_SYMBOL(locomo_frontlight_set); |
810 | |
811 | /* |
812 | * LoCoMo "Register Access Bus." |
813 | * |
814 | * We model this as a regular bus type, and hang devices directly |
815 | * off this. |
816 | */ |
817 | static int locomo_match(struct device *_dev, struct device_driver *_drv) |
818 | { |
819 | struct locomo_dev *dev = LOCOMO_DEV(_dev); |
820 | struct locomo_driver *drv = LOCOMO_DRV(_drv); |
821 | |
822 | return dev->devid == drv->devid; |
823 | } |
824 | |
825 | static int locomo_bus_probe(struct device *dev) |
826 | { |
827 | struct locomo_dev *ldev = LOCOMO_DEV(dev); |
828 | struct locomo_driver *drv = LOCOMO_DRV(dev->driver); |
829 | int ret = -ENODEV; |
830 | |
831 | if (drv->probe) |
832 | ret = drv->probe(ldev); |
833 | return ret; |
834 | } |
835 | |
836 | static void locomo_bus_remove(struct device *dev) |
837 | { |
838 | struct locomo_dev *ldev = LOCOMO_DEV(dev); |
839 | struct locomo_driver *drv = LOCOMO_DRV(dev->driver); |
840 | |
841 | if (drv->remove) |
842 | drv->remove(ldev); |
843 | } |
844 | |
845 | struct bus_type locomo_bus_type = { |
846 | .name = "locomo-bus" , |
847 | .match = locomo_match, |
848 | .probe = locomo_bus_probe, |
849 | .remove = locomo_bus_remove, |
850 | }; |
851 | |
852 | int locomo_driver_register(struct locomo_driver *driver) |
853 | { |
854 | driver->drv.bus = &locomo_bus_type; |
855 | return driver_register(drv: &driver->drv); |
856 | } |
857 | EXPORT_SYMBOL(locomo_driver_register); |
858 | |
859 | void locomo_driver_unregister(struct locomo_driver *driver) |
860 | { |
861 | driver_unregister(drv: &driver->drv); |
862 | } |
863 | EXPORT_SYMBOL(locomo_driver_unregister); |
864 | |
865 | static int __init locomo_init(void) |
866 | { |
867 | int ret = bus_register(bus: &locomo_bus_type); |
868 | if (ret == 0) |
869 | platform_driver_register(&locomo_device_driver); |
870 | return ret; |
871 | } |
872 | |
873 | static void __exit locomo_exit(void) |
874 | { |
875 | platform_driver_unregister(&locomo_device_driver); |
876 | bus_unregister(bus: &locomo_bus_type); |
877 | } |
878 | |
879 | module_init(locomo_init); |
880 | module_exit(locomo_exit); |
881 | |
882 | MODULE_DESCRIPTION("Sharp LoCoMo core driver" ); |
883 | MODULE_LICENSE("GPL" ); |
884 | MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>" ); |
885 | |