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