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