Commit 8e00593557c3c5a7bc6f636412a1cadcf4624232
Committed by
Samuel Ortiz
1 parent
b4e017e332
Exists in
master
and in
7 other branches
mfd: Add mc13892 support to mc13xxx
mc13892 is the companion PMIC for Freescale's i.MX51. It's similar enough to mc13782 to support it in a single driver. This patch introduces enough compatibility cruft to keep all users of the superseded mc13783 driver unchanged. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Showing 6 changed files with 1113 additions and 882 deletions Side-by-side Diff
drivers/mfd/Kconfig
... | ... | @@ -409,11 +409,16 @@ |
409 | 409 | so that function-specific drivers can bind to them. |
410 | 410 | |
411 | 411 | config MFD_MC13783 |
412 | - tristate "Support Freescale MC13783" | |
412 | + tristate | |
413 | + | |
414 | +config MFD_MC13XXX | |
415 | + tristate "Support Freescale MC13783 and MC13892" | |
413 | 416 | depends on SPI_MASTER |
414 | 417 | select MFD_CORE |
418 | + select MFD_MC13783 | |
415 | 419 | help |
416 | - Support for the Freescale (Atlas) MC13783 PMIC and audio CODEC. | |
420 | + Support for the Freescale (Atlas) PMIC and audio CODECs | |
421 | + MC13783 and MC13892. | |
417 | 422 | This driver provides common support for accessing the device, |
418 | 423 | additional drivers must be enabled in order to use the |
419 | 424 | functionality of the device. |
drivers/mfd/Makefile
drivers/mfd/mc13783-core.c
1 | -/* | |
2 | - * Copyright 2009 Pengutronix | |
3 | - * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> | |
4 | - * | |
5 | - * loosely based on an earlier driver that has | |
6 | - * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> | |
7 | - * | |
8 | - * This program is free software; you can redistribute it and/or modify it under | |
9 | - * the terms of the GNU General Public License version 2 as published by the | |
10 | - * Free Software Foundation. | |
11 | - */ | |
12 | -#include <linux/slab.h> | |
13 | -#include <linux/module.h> | |
14 | -#include <linux/platform_device.h> | |
15 | -#include <linux/mutex.h> | |
16 | -#include <linux/interrupt.h> | |
17 | -#include <linux/spi/spi.h> | |
18 | -#include <linux/mfd/core.h> | |
19 | -#include <linux/mfd/mc13783.h> | |
20 | - | |
21 | -struct mc13783 { | |
22 | - struct spi_device *spidev; | |
23 | - struct mutex lock; | |
24 | - int irq; | |
25 | - int adcflags; | |
26 | - | |
27 | - irq_handler_t irqhandler[MC13783_NUM_IRQ]; | |
28 | - void *irqdata[MC13783_NUM_IRQ]; | |
29 | -}; | |
30 | - | |
31 | -#define MC13783_REG_REVISION 7 | |
32 | -#define MC13783_REG_ADC_0 43 | |
33 | -#define MC13783_REG_ADC_1 44 | |
34 | -#define MC13783_REG_ADC_2 45 | |
35 | - | |
36 | -#define MC13783_IRQSTAT0 0 | |
37 | -#define MC13783_IRQSTAT0_ADCDONEI (1 << 0) | |
38 | -#define MC13783_IRQSTAT0_ADCBISDONEI (1 << 1) | |
39 | -#define MC13783_IRQSTAT0_TSI (1 << 2) | |
40 | -#define MC13783_IRQSTAT0_WHIGHI (1 << 3) | |
41 | -#define MC13783_IRQSTAT0_WLOWI (1 << 4) | |
42 | -#define MC13783_IRQSTAT0_CHGDETI (1 << 6) | |
43 | -#define MC13783_IRQSTAT0_CHGOVI (1 << 7) | |
44 | -#define MC13783_IRQSTAT0_CHGREVI (1 << 8) | |
45 | -#define MC13783_IRQSTAT0_CHGSHORTI (1 << 9) | |
46 | -#define MC13783_IRQSTAT0_CCCVI (1 << 10) | |
47 | -#define MC13783_IRQSTAT0_CHGCURRI (1 << 11) | |
48 | -#define MC13783_IRQSTAT0_BPONI (1 << 12) | |
49 | -#define MC13783_IRQSTAT0_LOBATLI (1 << 13) | |
50 | -#define MC13783_IRQSTAT0_LOBATHI (1 << 14) | |
51 | -#define MC13783_IRQSTAT0_UDPI (1 << 15) | |
52 | -#define MC13783_IRQSTAT0_USBI (1 << 16) | |
53 | -#define MC13783_IRQSTAT0_IDI (1 << 19) | |
54 | -#define MC13783_IRQSTAT0_SE1I (1 << 21) | |
55 | -#define MC13783_IRQSTAT0_CKDETI (1 << 22) | |
56 | -#define MC13783_IRQSTAT0_UDMI (1 << 23) | |
57 | - | |
58 | -#define MC13783_IRQMASK0 1 | |
59 | -#define MC13783_IRQMASK0_ADCDONEM MC13783_IRQSTAT0_ADCDONEI | |
60 | -#define MC13783_IRQMASK0_ADCBISDONEM MC13783_IRQSTAT0_ADCBISDONEI | |
61 | -#define MC13783_IRQMASK0_TSM MC13783_IRQSTAT0_TSI | |
62 | -#define MC13783_IRQMASK0_WHIGHM MC13783_IRQSTAT0_WHIGHI | |
63 | -#define MC13783_IRQMASK0_WLOWM MC13783_IRQSTAT0_WLOWI | |
64 | -#define MC13783_IRQMASK0_CHGDETM MC13783_IRQSTAT0_CHGDETI | |
65 | -#define MC13783_IRQMASK0_CHGOVM MC13783_IRQSTAT0_CHGOVI | |
66 | -#define MC13783_IRQMASK0_CHGREVM MC13783_IRQSTAT0_CHGREVI | |
67 | -#define MC13783_IRQMASK0_CHGSHORTM MC13783_IRQSTAT0_CHGSHORTI | |
68 | -#define MC13783_IRQMASK0_CCCVM MC13783_IRQSTAT0_CCCVI | |
69 | -#define MC13783_IRQMASK0_CHGCURRM MC13783_IRQSTAT0_CHGCURRI | |
70 | -#define MC13783_IRQMASK0_BPONM MC13783_IRQSTAT0_BPONI | |
71 | -#define MC13783_IRQMASK0_LOBATLM MC13783_IRQSTAT0_LOBATLI | |
72 | -#define MC13783_IRQMASK0_LOBATHM MC13783_IRQSTAT0_LOBATHI | |
73 | -#define MC13783_IRQMASK0_UDPM MC13783_IRQSTAT0_UDPI | |
74 | -#define MC13783_IRQMASK0_USBM MC13783_IRQSTAT0_USBI | |
75 | -#define MC13783_IRQMASK0_IDM MC13783_IRQSTAT0_IDI | |
76 | -#define MC13783_IRQMASK0_SE1M MC13783_IRQSTAT0_SE1I | |
77 | -#define MC13783_IRQMASK0_CKDETM MC13783_IRQSTAT0_CKDETI | |
78 | -#define MC13783_IRQMASK0_UDMM MC13783_IRQSTAT0_UDMI | |
79 | - | |
80 | -#define MC13783_IRQSTAT1 3 | |
81 | -#define MC13783_IRQSTAT1_1HZI (1 << 0) | |
82 | -#define MC13783_IRQSTAT1_TODAI (1 << 1) | |
83 | -#define MC13783_IRQSTAT1_ONOFD1I (1 << 3) | |
84 | -#define MC13783_IRQSTAT1_ONOFD2I (1 << 4) | |
85 | -#define MC13783_IRQSTAT1_ONOFD3I (1 << 5) | |
86 | -#define MC13783_IRQSTAT1_SYSRSTI (1 << 6) | |
87 | -#define MC13783_IRQSTAT1_RTCRSTI (1 << 7) | |
88 | -#define MC13783_IRQSTAT1_PCI (1 << 8) | |
89 | -#define MC13783_IRQSTAT1_WARMI (1 << 9) | |
90 | -#define MC13783_IRQSTAT1_MEMHLDI (1 << 10) | |
91 | -#define MC13783_IRQSTAT1_PWRRDYI (1 << 11) | |
92 | -#define MC13783_IRQSTAT1_THWARNLI (1 << 12) | |
93 | -#define MC13783_IRQSTAT1_THWARNHI (1 << 13) | |
94 | -#define MC13783_IRQSTAT1_CLKI (1 << 14) | |
95 | -#define MC13783_IRQSTAT1_SEMAFI (1 << 15) | |
96 | -#define MC13783_IRQSTAT1_MC2BI (1 << 17) | |
97 | -#define MC13783_IRQSTAT1_HSDETI (1 << 18) | |
98 | -#define MC13783_IRQSTAT1_HSLI (1 << 19) | |
99 | -#define MC13783_IRQSTAT1_ALSPTHI (1 << 20) | |
100 | -#define MC13783_IRQSTAT1_AHSSHORTI (1 << 21) | |
101 | - | |
102 | -#define MC13783_IRQMASK1 4 | |
103 | -#define MC13783_IRQMASK1_1HZM MC13783_IRQSTAT1_1HZI | |
104 | -#define MC13783_IRQMASK1_TODAM MC13783_IRQSTAT1_TODAI | |
105 | -#define MC13783_IRQMASK1_ONOFD1M MC13783_IRQSTAT1_ONOFD1I | |
106 | -#define MC13783_IRQMASK1_ONOFD2M MC13783_IRQSTAT1_ONOFD2I | |
107 | -#define MC13783_IRQMASK1_ONOFD3M MC13783_IRQSTAT1_ONOFD3I | |
108 | -#define MC13783_IRQMASK1_SYSRSTM MC13783_IRQSTAT1_SYSRSTI | |
109 | -#define MC13783_IRQMASK1_RTCRSTM MC13783_IRQSTAT1_RTCRSTI | |
110 | -#define MC13783_IRQMASK1_PCM MC13783_IRQSTAT1_PCI | |
111 | -#define MC13783_IRQMASK1_WARMM MC13783_IRQSTAT1_WARMI | |
112 | -#define MC13783_IRQMASK1_MEMHLDM MC13783_IRQSTAT1_MEMHLDI | |
113 | -#define MC13783_IRQMASK1_PWRRDYM MC13783_IRQSTAT1_PWRRDYI | |
114 | -#define MC13783_IRQMASK1_THWARNLM MC13783_IRQSTAT1_THWARNLI | |
115 | -#define MC13783_IRQMASK1_THWARNHM MC13783_IRQSTAT1_THWARNHI | |
116 | -#define MC13783_IRQMASK1_CLKM MC13783_IRQSTAT1_CLKI | |
117 | -#define MC13783_IRQMASK1_SEMAFM MC13783_IRQSTAT1_SEMAFI | |
118 | -#define MC13783_IRQMASK1_MC2BM MC13783_IRQSTAT1_MC2BI | |
119 | -#define MC13783_IRQMASK1_HSDETM MC13783_IRQSTAT1_HSDETI | |
120 | -#define MC13783_IRQMASK1_HSLM MC13783_IRQSTAT1_HSLI | |
121 | -#define MC13783_IRQMASK1_ALSPTHM MC13783_IRQSTAT1_ALSPTHI | |
122 | -#define MC13783_IRQMASK1_AHSSHORTM MC13783_IRQSTAT1_AHSSHORTI | |
123 | - | |
124 | -#define MC13783_ADC1 44 | |
125 | -#define MC13783_ADC1_ADEN (1 << 0) | |
126 | -#define MC13783_ADC1_RAND (1 << 1) | |
127 | -#define MC13783_ADC1_ADSEL (1 << 3) | |
128 | -#define MC13783_ADC1_ASC (1 << 20) | |
129 | -#define MC13783_ADC1_ADTRIGIGN (1 << 21) | |
130 | - | |
131 | -#define MC13783_NUMREGS 0x3f | |
132 | - | |
133 | -void mc13783_lock(struct mc13783 *mc13783) | |
134 | -{ | |
135 | - if (!mutex_trylock(&mc13783->lock)) { | |
136 | - dev_dbg(&mc13783->spidev->dev, "wait for %s from %pf\n", | |
137 | - __func__, __builtin_return_address(0)); | |
138 | - | |
139 | - mutex_lock(&mc13783->lock); | |
140 | - } | |
141 | - dev_dbg(&mc13783->spidev->dev, "%s from %pf\n", | |
142 | - __func__, __builtin_return_address(0)); | |
143 | -} | |
144 | -EXPORT_SYMBOL(mc13783_lock); | |
145 | - | |
146 | -void mc13783_unlock(struct mc13783 *mc13783) | |
147 | -{ | |
148 | - dev_dbg(&mc13783->spidev->dev, "%s from %pf\n", | |
149 | - __func__, __builtin_return_address(0)); | |
150 | - mutex_unlock(&mc13783->lock); | |
151 | -} | |
152 | -EXPORT_SYMBOL(mc13783_unlock); | |
153 | - | |
154 | -#define MC13783_REGOFFSET_SHIFT 25 | |
155 | -int mc13783_reg_read(struct mc13783 *mc13783, unsigned int offset, u32 *val) | |
156 | -{ | |
157 | - struct spi_transfer t; | |
158 | - struct spi_message m; | |
159 | - int ret; | |
160 | - | |
161 | - BUG_ON(!mutex_is_locked(&mc13783->lock)); | |
162 | - | |
163 | - if (offset > MC13783_NUMREGS) | |
164 | - return -EINVAL; | |
165 | - | |
166 | - *val = offset << MC13783_REGOFFSET_SHIFT; | |
167 | - | |
168 | - memset(&t, 0, sizeof(t)); | |
169 | - | |
170 | - t.tx_buf = val; | |
171 | - t.rx_buf = val; | |
172 | - t.len = sizeof(u32); | |
173 | - | |
174 | - spi_message_init(&m); | |
175 | - spi_message_add_tail(&t, &m); | |
176 | - | |
177 | - ret = spi_sync(mc13783->spidev, &m); | |
178 | - | |
179 | - /* error in message.status implies error return from spi_sync */ | |
180 | - BUG_ON(!ret && m.status); | |
181 | - | |
182 | - if (ret) | |
183 | - return ret; | |
184 | - | |
185 | - *val &= 0xffffff; | |
186 | - | |
187 | - dev_vdbg(&mc13783->spidev->dev, "[0x%02x] -> 0x%06x\n", offset, *val); | |
188 | - | |
189 | - return 0; | |
190 | -} | |
191 | -EXPORT_SYMBOL(mc13783_reg_read); | |
192 | - | |
193 | -int mc13783_reg_write(struct mc13783 *mc13783, unsigned int offset, u32 val) | |
194 | -{ | |
195 | - u32 buf; | |
196 | - struct spi_transfer t; | |
197 | - struct spi_message m; | |
198 | - int ret; | |
199 | - | |
200 | - BUG_ON(!mutex_is_locked(&mc13783->lock)); | |
201 | - | |
202 | - dev_vdbg(&mc13783->spidev->dev, "[0x%02x] <- 0x%06x\n", offset, val); | |
203 | - | |
204 | - if (offset > MC13783_NUMREGS || val > 0xffffff) | |
205 | - return -EINVAL; | |
206 | - | |
207 | - buf = 1 << 31 | offset << MC13783_REGOFFSET_SHIFT | val; | |
208 | - | |
209 | - memset(&t, 0, sizeof(t)); | |
210 | - | |
211 | - t.tx_buf = &buf; | |
212 | - t.rx_buf = &buf; | |
213 | - t.len = sizeof(u32); | |
214 | - | |
215 | - spi_message_init(&m); | |
216 | - spi_message_add_tail(&t, &m); | |
217 | - | |
218 | - ret = spi_sync(mc13783->spidev, &m); | |
219 | - | |
220 | - BUG_ON(!ret && m.status); | |
221 | - | |
222 | - if (ret) | |
223 | - return ret; | |
224 | - | |
225 | - return 0; | |
226 | -} | |
227 | -EXPORT_SYMBOL(mc13783_reg_write); | |
228 | - | |
229 | -int mc13783_reg_rmw(struct mc13783 *mc13783, unsigned int offset, | |
230 | - u32 mask, u32 val) | |
231 | -{ | |
232 | - int ret; | |
233 | - u32 valread; | |
234 | - | |
235 | - BUG_ON(val & ~mask); | |
236 | - | |
237 | - ret = mc13783_reg_read(mc13783, offset, &valread); | |
238 | - if (ret) | |
239 | - return ret; | |
240 | - | |
241 | - valread = (valread & ~mask) | val; | |
242 | - | |
243 | - return mc13783_reg_write(mc13783, offset, valread); | |
244 | -} | |
245 | -EXPORT_SYMBOL(mc13783_reg_rmw); | |
246 | - | |
247 | -int mc13783_get_flags(struct mc13783 *mc13783) | |
248 | -{ | |
249 | - struct mc13783_platform_data *pdata = | |
250 | - dev_get_platdata(&mc13783->spidev->dev); | |
251 | - | |
252 | - return pdata->flags; | |
253 | -} | |
254 | -EXPORT_SYMBOL(mc13783_get_flags); | |
255 | - | |
256 | -int mc13783_irq_mask(struct mc13783 *mc13783, int irq) | |
257 | -{ | |
258 | - int ret; | |
259 | - unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1; | |
260 | - u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | |
261 | - u32 mask; | |
262 | - | |
263 | - if (irq < 0 || irq >= MC13783_NUM_IRQ) | |
264 | - return -EINVAL; | |
265 | - | |
266 | - ret = mc13783_reg_read(mc13783, offmask, &mask); | |
267 | - if (ret) | |
268 | - return ret; | |
269 | - | |
270 | - if (mask & irqbit) | |
271 | - /* already masked */ | |
272 | - return 0; | |
273 | - | |
274 | - return mc13783_reg_write(mc13783, offmask, mask | irqbit); | |
275 | -} | |
276 | -EXPORT_SYMBOL(mc13783_irq_mask); | |
277 | - | |
278 | -int mc13783_irq_unmask(struct mc13783 *mc13783, int irq) | |
279 | -{ | |
280 | - int ret; | |
281 | - unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1; | |
282 | - u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | |
283 | - u32 mask; | |
284 | - | |
285 | - if (irq < 0 || irq >= MC13783_NUM_IRQ) | |
286 | - return -EINVAL; | |
287 | - | |
288 | - ret = mc13783_reg_read(mc13783, offmask, &mask); | |
289 | - if (ret) | |
290 | - return ret; | |
291 | - | |
292 | - if (!(mask & irqbit)) | |
293 | - /* already unmasked */ | |
294 | - return 0; | |
295 | - | |
296 | - return mc13783_reg_write(mc13783, offmask, mask & ~irqbit); | |
297 | -} | |
298 | -EXPORT_SYMBOL(mc13783_irq_unmask); | |
299 | - | |
300 | -int mc13783_irq_status(struct mc13783 *mc13783, int irq, | |
301 | - int *enabled, int *pending) | |
302 | -{ | |
303 | - int ret; | |
304 | - unsigned int offmask = irq < 24 ? MC13783_IRQMASK0 : MC13783_IRQMASK1; | |
305 | - unsigned int offstat = irq < 24 ? MC13783_IRQSTAT0 : MC13783_IRQSTAT1; | |
306 | - u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | |
307 | - | |
308 | - if (irq < 0 || irq >= MC13783_NUM_IRQ) | |
309 | - return -EINVAL; | |
310 | - | |
311 | - if (enabled) { | |
312 | - u32 mask; | |
313 | - | |
314 | - ret = mc13783_reg_read(mc13783, offmask, &mask); | |
315 | - if (ret) | |
316 | - return ret; | |
317 | - | |
318 | - *enabled = mask & irqbit; | |
319 | - } | |
320 | - | |
321 | - if (pending) { | |
322 | - u32 stat; | |
323 | - | |
324 | - ret = mc13783_reg_read(mc13783, offstat, &stat); | |
325 | - if (ret) | |
326 | - return ret; | |
327 | - | |
328 | - *pending = stat & irqbit; | |
329 | - } | |
330 | - | |
331 | - return 0; | |
332 | -} | |
333 | -EXPORT_SYMBOL(mc13783_irq_status); | |
334 | - | |
335 | -int mc13783_irq_ack(struct mc13783 *mc13783, int irq) | |
336 | -{ | |
337 | - unsigned int offstat = irq < 24 ? MC13783_IRQSTAT0 : MC13783_IRQSTAT1; | |
338 | - unsigned int val = 1 << (irq < 24 ? irq : irq - 24); | |
339 | - | |
340 | - BUG_ON(irq < 0 || irq >= MC13783_NUM_IRQ); | |
341 | - | |
342 | - return mc13783_reg_write(mc13783, offstat, val); | |
343 | -} | |
344 | -EXPORT_SYMBOL(mc13783_irq_ack); | |
345 | - | |
346 | -int mc13783_irq_request_nounmask(struct mc13783 *mc13783, int irq, | |
347 | - irq_handler_t handler, const char *name, void *dev) | |
348 | -{ | |
349 | - BUG_ON(!mutex_is_locked(&mc13783->lock)); | |
350 | - BUG_ON(!handler); | |
351 | - | |
352 | - if (irq < 0 || irq >= MC13783_NUM_IRQ) | |
353 | - return -EINVAL; | |
354 | - | |
355 | - if (mc13783->irqhandler[irq]) | |
356 | - return -EBUSY; | |
357 | - | |
358 | - mc13783->irqhandler[irq] = handler; | |
359 | - mc13783->irqdata[irq] = dev; | |
360 | - | |
361 | - return 0; | |
362 | -} | |
363 | -EXPORT_SYMBOL(mc13783_irq_request_nounmask); | |
364 | - | |
365 | -int mc13783_irq_request(struct mc13783 *mc13783, int irq, | |
366 | - irq_handler_t handler, const char *name, void *dev) | |
367 | -{ | |
368 | - int ret; | |
369 | - | |
370 | - ret = mc13783_irq_request_nounmask(mc13783, irq, handler, name, dev); | |
371 | - if (ret) | |
372 | - return ret; | |
373 | - | |
374 | - ret = mc13783_irq_unmask(mc13783, irq); | |
375 | - if (ret) { | |
376 | - mc13783->irqhandler[irq] = NULL; | |
377 | - mc13783->irqdata[irq] = NULL; | |
378 | - return ret; | |
379 | - } | |
380 | - | |
381 | - return 0; | |
382 | -} | |
383 | -EXPORT_SYMBOL(mc13783_irq_request); | |
384 | - | |
385 | -int mc13783_irq_free(struct mc13783 *mc13783, int irq, void *dev) | |
386 | -{ | |
387 | - int ret; | |
388 | - BUG_ON(!mutex_is_locked(&mc13783->lock)); | |
389 | - | |
390 | - if (irq < 0 || irq >= MC13783_NUM_IRQ || !mc13783->irqhandler[irq] || | |
391 | - mc13783->irqdata[irq] != dev) | |
392 | - return -EINVAL; | |
393 | - | |
394 | - ret = mc13783_irq_mask(mc13783, irq); | |
395 | - if (ret) | |
396 | - return ret; | |
397 | - | |
398 | - mc13783->irqhandler[irq] = NULL; | |
399 | - mc13783->irqdata[irq] = NULL; | |
400 | - | |
401 | - return 0; | |
402 | -} | |
403 | -EXPORT_SYMBOL(mc13783_irq_free); | |
404 | - | |
405 | -static inline irqreturn_t mc13783_irqhandler(struct mc13783 *mc13783, int irq) | |
406 | -{ | |
407 | - return mc13783->irqhandler[irq](irq, mc13783->irqdata[irq]); | |
408 | -} | |
409 | - | |
410 | -/* | |
411 | - * returns: number of handled irqs or negative error | |
412 | - * locking: holds mc13783->lock | |
413 | - */ | |
414 | -static int mc13783_irq_handle(struct mc13783 *mc13783, | |
415 | - unsigned int offstat, unsigned int offmask, int baseirq) | |
416 | -{ | |
417 | - u32 stat, mask; | |
418 | - int ret = mc13783_reg_read(mc13783, offstat, &stat); | |
419 | - int num_handled = 0; | |
420 | - | |
421 | - if (ret) | |
422 | - return ret; | |
423 | - | |
424 | - ret = mc13783_reg_read(mc13783, offmask, &mask); | |
425 | - if (ret) | |
426 | - return ret; | |
427 | - | |
428 | - while (stat & ~mask) { | |
429 | - int irq = __ffs(stat & ~mask); | |
430 | - | |
431 | - stat &= ~(1 << irq); | |
432 | - | |
433 | - if (likely(mc13783->irqhandler[baseirq + irq])) { | |
434 | - irqreturn_t handled; | |
435 | - | |
436 | - handled = mc13783_irqhandler(mc13783, baseirq + irq); | |
437 | - if (handled == IRQ_HANDLED) | |
438 | - num_handled++; | |
439 | - } else { | |
440 | - dev_err(&mc13783->spidev->dev, | |
441 | - "BUG: irq %u but no handler\n", | |
442 | - baseirq + irq); | |
443 | - | |
444 | - mask |= 1 << irq; | |
445 | - | |
446 | - ret = mc13783_reg_write(mc13783, offmask, mask); | |
447 | - } | |
448 | - } | |
449 | - | |
450 | - return num_handled; | |
451 | -} | |
452 | - | |
453 | -static irqreturn_t mc13783_irq_thread(int irq, void *data) | |
454 | -{ | |
455 | - struct mc13783 *mc13783 = data; | |
456 | - irqreturn_t ret; | |
457 | - int handled = 0; | |
458 | - | |
459 | - mc13783_lock(mc13783); | |
460 | - | |
461 | - ret = mc13783_irq_handle(mc13783, MC13783_IRQSTAT0, | |
462 | - MC13783_IRQMASK0, MC13783_IRQ_ADCDONE); | |
463 | - if (ret > 0) | |
464 | - handled = 1; | |
465 | - | |
466 | - ret = mc13783_irq_handle(mc13783, MC13783_IRQSTAT1, | |
467 | - MC13783_IRQMASK1, MC13783_IRQ_1HZ); | |
468 | - if (ret > 0) | |
469 | - handled = 1; | |
470 | - | |
471 | - mc13783_unlock(mc13783); | |
472 | - | |
473 | - return IRQ_RETVAL(handled); | |
474 | -} | |
475 | - | |
476 | -#define MC13783_ADC1_CHAN0_SHIFT 5 | |
477 | -#define MC13783_ADC1_CHAN1_SHIFT 8 | |
478 | - | |
479 | -struct mc13783_adcdone_data { | |
480 | - struct mc13783 *mc13783; | |
481 | - struct completion done; | |
482 | -}; | |
483 | - | |
484 | -static irqreturn_t mc13783_handler_adcdone(int irq, void *data) | |
485 | -{ | |
486 | - struct mc13783_adcdone_data *adcdone_data = data; | |
487 | - | |
488 | - mc13783_irq_ack(adcdone_data->mc13783, irq); | |
489 | - | |
490 | - complete_all(&adcdone_data->done); | |
491 | - | |
492 | - return IRQ_HANDLED; | |
493 | -} | |
494 | - | |
495 | -#define MC13783_ADC_WORKING (1 << 0) | |
496 | - | |
497 | -int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode, | |
498 | - unsigned int channel, unsigned int *sample) | |
499 | -{ | |
500 | - u32 adc0, adc1, old_adc0; | |
501 | - int i, ret; | |
502 | - struct mc13783_adcdone_data adcdone_data = { | |
503 | - .mc13783 = mc13783, | |
504 | - }; | |
505 | - init_completion(&adcdone_data.done); | |
506 | - | |
507 | - dev_dbg(&mc13783->spidev->dev, "%s\n", __func__); | |
508 | - | |
509 | - mc13783_lock(mc13783); | |
510 | - | |
511 | - if (mc13783->adcflags & MC13783_ADC_WORKING) { | |
512 | - ret = -EBUSY; | |
513 | - goto out; | |
514 | - } | |
515 | - | |
516 | - mc13783->adcflags |= MC13783_ADC_WORKING; | |
517 | - | |
518 | - mc13783_reg_read(mc13783, MC13783_ADC0, &old_adc0); | |
519 | - | |
520 | - adc0 = MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2; | |
521 | - adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN | MC13783_ADC1_ASC; | |
522 | - | |
523 | - if (channel > 7) | |
524 | - adc1 |= MC13783_ADC1_ADSEL; | |
525 | - | |
526 | - switch (mode) { | |
527 | - case MC13783_ADC_MODE_TS: | |
528 | - adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_TSMOD0 | | |
529 | - MC13783_ADC0_TSMOD1; | |
530 | - adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; | |
531 | - break; | |
532 | - | |
533 | - case MC13783_ADC_MODE_SINGLE_CHAN: | |
534 | - adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; | |
535 | - adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT; | |
536 | - adc1 |= MC13783_ADC1_RAND; | |
537 | - break; | |
538 | - | |
539 | - case MC13783_ADC_MODE_MULT_CHAN: | |
540 | - adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; | |
541 | - adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; | |
542 | - break; | |
543 | - | |
544 | - default: | |
545 | - mc13783_unlock(mc13783); | |
546 | - return -EINVAL; | |
547 | - } | |
548 | - | |
549 | - dev_dbg(&mc13783->spidev->dev, "%s: request irq\n", __func__); | |
550 | - mc13783_irq_request(mc13783, MC13783_IRQ_ADCDONE, | |
551 | - mc13783_handler_adcdone, __func__, &adcdone_data); | |
552 | - mc13783_irq_ack(mc13783, MC13783_IRQ_ADCDONE); | |
553 | - | |
554 | - mc13783_reg_write(mc13783, MC13783_REG_ADC_0, adc0); | |
555 | - mc13783_reg_write(mc13783, MC13783_REG_ADC_1, adc1); | |
556 | - | |
557 | - mc13783_unlock(mc13783); | |
558 | - | |
559 | - ret = wait_for_completion_interruptible_timeout(&adcdone_data.done, HZ); | |
560 | - | |
561 | - if (!ret) | |
562 | - ret = -ETIMEDOUT; | |
563 | - | |
564 | - mc13783_lock(mc13783); | |
565 | - | |
566 | - mc13783_irq_free(mc13783, MC13783_IRQ_ADCDONE, &adcdone_data); | |
567 | - | |
568 | - if (ret > 0) | |
569 | - for (i = 0; i < 4; ++i) { | |
570 | - ret = mc13783_reg_read(mc13783, | |
571 | - MC13783_REG_ADC_2, &sample[i]); | |
572 | - if (ret) | |
573 | - break; | |
574 | - } | |
575 | - | |
576 | - if (mode == MC13783_ADC_MODE_TS) | |
577 | - /* restore TSMOD */ | |
578 | - mc13783_reg_write(mc13783, MC13783_REG_ADC_0, old_adc0); | |
579 | - | |
580 | - mc13783->adcflags &= ~MC13783_ADC_WORKING; | |
581 | -out: | |
582 | - mc13783_unlock(mc13783); | |
583 | - | |
584 | - return ret; | |
585 | -} | |
586 | -EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion); | |
587 | - | |
588 | -static int mc13783_add_subdevice_pdata(struct mc13783 *mc13783, | |
589 | - const char *name, void *pdata, size_t pdata_size) | |
590 | -{ | |
591 | - struct mfd_cell cell = { | |
592 | - .name = name, | |
593 | - .platform_data = pdata, | |
594 | - .data_size = pdata_size, | |
595 | - }; | |
596 | - | |
597 | - return mfd_add_devices(&mc13783->spidev->dev, -1, &cell, 1, NULL, 0); | |
598 | -} | |
599 | - | |
600 | -static int mc13783_add_subdevice(struct mc13783 *mc13783, const char *name) | |
601 | -{ | |
602 | - return mc13783_add_subdevice_pdata(mc13783, name, NULL, 0); | |
603 | -} | |
604 | - | |
605 | -static int mc13783_check_revision(struct mc13783 *mc13783) | |
606 | -{ | |
607 | - u32 rev_id, rev1, rev2, finid, icid; | |
608 | - | |
609 | - mc13783_reg_read(mc13783, MC13783_REG_REVISION, &rev_id); | |
610 | - | |
611 | - rev1 = (rev_id & 0x018) >> 3; | |
612 | - rev2 = (rev_id & 0x007); | |
613 | - icid = (rev_id & 0x01C0) >> 6; | |
614 | - finid = (rev_id & 0x01E00) >> 9; | |
615 | - | |
616 | - /* Ver 0.2 is actually 3.2a. Report as 3.2 */ | |
617 | - if ((rev1 == 0) && (rev2 == 2)) | |
618 | - rev1 = 3; | |
619 | - | |
620 | - if (rev1 == 0 || icid != 2) { | |
621 | - dev_err(&mc13783->spidev->dev, "No MC13783 detected.\n"); | |
622 | - return -ENODEV; | |
623 | - } | |
624 | - | |
625 | - dev_info(&mc13783->spidev->dev, | |
626 | - "MC13783 Rev %d.%d FinVer %x detected\n", | |
627 | - rev1, rev2, finid); | |
628 | - | |
629 | - return 0; | |
630 | -} | |
631 | - | |
632 | -static int mc13783_probe(struct spi_device *spi) | |
633 | -{ | |
634 | - struct mc13783 *mc13783; | |
635 | - struct mc13783_platform_data *pdata = dev_get_platdata(&spi->dev); | |
636 | - int ret; | |
637 | - | |
638 | - mc13783 = kzalloc(sizeof(*mc13783), GFP_KERNEL); | |
639 | - if (!mc13783) | |
640 | - return -ENOMEM; | |
641 | - | |
642 | - dev_set_drvdata(&spi->dev, mc13783); | |
643 | - spi->mode = SPI_MODE_0 | SPI_CS_HIGH; | |
644 | - spi->bits_per_word = 32; | |
645 | - spi_setup(spi); | |
646 | - | |
647 | - mc13783->spidev = spi; | |
648 | - | |
649 | - mutex_init(&mc13783->lock); | |
650 | - mc13783_lock(mc13783); | |
651 | - | |
652 | - ret = mc13783_check_revision(mc13783); | |
653 | - if (ret) | |
654 | - goto err_revision; | |
655 | - | |
656 | - /* mask all irqs */ | |
657 | - ret = mc13783_reg_write(mc13783, MC13783_IRQMASK0, 0x00ffffff); | |
658 | - if (ret) | |
659 | - goto err_mask; | |
660 | - | |
661 | - ret = mc13783_reg_write(mc13783, MC13783_IRQMASK1, 0x00ffffff); | |
662 | - if (ret) | |
663 | - goto err_mask; | |
664 | - | |
665 | - ret = request_threaded_irq(spi->irq, NULL, mc13783_irq_thread, | |
666 | - IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13783", mc13783); | |
667 | - | |
668 | - if (ret) { | |
669 | -err_mask: | |
670 | -err_revision: | |
671 | - mutex_unlock(&mc13783->lock); | |
672 | - dev_set_drvdata(&spi->dev, NULL); | |
673 | - kfree(mc13783); | |
674 | - return ret; | |
675 | - } | |
676 | - | |
677 | - mc13783_unlock(mc13783); | |
678 | - | |
679 | - if (pdata->flags & MC13783_USE_ADC) | |
680 | - mc13783_add_subdevice(mc13783, "mc13783-adc"); | |
681 | - | |
682 | - if (pdata->flags & MC13783_USE_CODEC) | |
683 | - mc13783_add_subdevice(mc13783, "mc13783-codec"); | |
684 | - | |
685 | - if (pdata->flags & MC13783_USE_REGULATOR) { | |
686 | - struct mc13783_regulator_platform_data regulator_pdata = { | |
687 | - .num_regulators = pdata->num_regulators, | |
688 | - .regulators = pdata->regulators, | |
689 | - }; | |
690 | - | |
691 | - mc13783_add_subdevice_pdata(mc13783, "mc13783-regulator", | |
692 | - ®ulator_pdata, sizeof(regulator_pdata)); | |
693 | - } | |
694 | - | |
695 | - if (pdata->flags & MC13783_USE_RTC) | |
696 | - mc13783_add_subdevice(mc13783, "mc13783-rtc"); | |
697 | - | |
698 | - if (pdata->flags & MC13783_USE_TOUCHSCREEN) | |
699 | - mc13783_add_subdevice(mc13783, "mc13783-ts"); | |
700 | - | |
701 | - if (pdata->flags & MC13783_USE_LED) | |
702 | - mc13783_add_subdevice_pdata(mc13783, "mc13783-led", | |
703 | - pdata->leds, sizeof(*pdata->leds)); | |
704 | - | |
705 | - return 0; | |
706 | -} | |
707 | - | |
708 | -static int __devexit mc13783_remove(struct spi_device *spi) | |
709 | -{ | |
710 | - struct mc13783 *mc13783 = dev_get_drvdata(&spi->dev); | |
711 | - | |
712 | - free_irq(mc13783->spidev->irq, mc13783); | |
713 | - | |
714 | - mfd_remove_devices(&spi->dev); | |
715 | - | |
716 | - return 0; | |
717 | -} | |
718 | - | |
719 | -static struct spi_driver mc13783_driver = { | |
720 | - .driver = { | |
721 | - .name = "mc13783", | |
722 | - .bus = &spi_bus_type, | |
723 | - .owner = THIS_MODULE, | |
724 | - }, | |
725 | - .probe = mc13783_probe, | |
726 | - .remove = __devexit_p(mc13783_remove), | |
727 | -}; | |
728 | - | |
729 | -static int __init mc13783_init(void) | |
730 | -{ | |
731 | - return spi_register_driver(&mc13783_driver); | |
732 | -} | |
733 | -subsys_initcall(mc13783_init); | |
734 | - | |
735 | -static void __exit mc13783_exit(void) | |
736 | -{ | |
737 | - spi_unregister_driver(&mc13783_driver); | |
738 | -} | |
739 | -module_exit(mc13783_exit); | |
740 | - | |
741 | -MODULE_DESCRIPTION("Core driver for Freescale MC13783 PMIC"); | |
742 | -MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>"); | |
743 | -MODULE_LICENSE("GPL v2"); |
drivers/mfd/mc13xxx-core.c
1 | +/* | |
2 | + * Copyright 2009-2010 Pengutronix | |
3 | + * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> | |
4 | + * | |
5 | + * loosely based on an earlier driver that has | |
6 | + * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> | |
7 | + * | |
8 | + * This program is free software; you can redistribute it and/or modify it under | |
9 | + * the terms of the GNU General Public License version 2 as published by the | |
10 | + * Free Software Foundation. | |
11 | + */ | |
12 | +#define DEBUG | |
13 | +#define VERBOSE_DEBUG | |
14 | + | |
15 | +#include <linux/slab.h> | |
16 | +#include <linux/module.h> | |
17 | +#include <linux/platform_device.h> | |
18 | +#include <linux/mutex.h> | |
19 | +#include <linux/interrupt.h> | |
20 | +#include <linux/spi/spi.h> | |
21 | +#include <linux/mfd/core.h> | |
22 | +#include <linux/mfd/mc13xxx.h> | |
23 | + | |
24 | +struct mc13xxx { | |
25 | + struct spi_device *spidev; | |
26 | + struct mutex lock; | |
27 | + int irq; | |
28 | + | |
29 | + irq_handler_t irqhandler[MC13XXX_NUM_IRQ]; | |
30 | + void *irqdata[MC13XXX_NUM_IRQ]; | |
31 | +}; | |
32 | + | |
33 | +struct mc13783 { | |
34 | + struct mc13xxx mc13xxx; | |
35 | + | |
36 | + int adcflags; | |
37 | +}; | |
38 | + | |
39 | +struct mc13xxx *mc13783_to_mc13xxx(struct mc13783 *mc13783) | |
40 | +{ | |
41 | + return &mc13783->mc13xxx; | |
42 | +} | |
43 | +EXPORT_SYMBOL(mc13783_to_mc13xxx); | |
44 | + | |
45 | +#define MC13XXX_IRQSTAT0 0 | |
46 | +#define MC13XXX_IRQSTAT0_ADCDONEI (1 << 0) | |
47 | +#define MC13XXX_IRQSTAT0_ADCBISDONEI (1 << 1) | |
48 | +#define MC13XXX_IRQSTAT0_TSI (1 << 2) | |
49 | +#define MC13783_IRQSTAT0_WHIGHI (1 << 3) | |
50 | +#define MC13783_IRQSTAT0_WLOWI (1 << 4) | |
51 | +#define MC13XXX_IRQSTAT0_CHGDETI (1 << 6) | |
52 | +#define MC13783_IRQSTAT0_CHGOVI (1 << 7) | |
53 | +#define MC13XXX_IRQSTAT0_CHGREVI (1 << 8) | |
54 | +#define MC13XXX_IRQSTAT0_CHGSHORTI (1 << 9) | |
55 | +#define MC13XXX_IRQSTAT0_CCCVI (1 << 10) | |
56 | +#define MC13XXX_IRQSTAT0_CHGCURRI (1 << 11) | |
57 | +#define MC13XXX_IRQSTAT0_BPONI (1 << 12) | |
58 | +#define MC13XXX_IRQSTAT0_LOBATLI (1 << 13) | |
59 | +#define MC13XXX_IRQSTAT0_LOBATHI (1 << 14) | |
60 | +#define MC13783_IRQSTAT0_UDPI (1 << 15) | |
61 | +#define MC13783_IRQSTAT0_USBI (1 << 16) | |
62 | +#define MC13783_IRQSTAT0_IDI (1 << 19) | |
63 | +#define MC13783_IRQSTAT0_SE1I (1 << 21) | |
64 | +#define MC13783_IRQSTAT0_CKDETI (1 << 22) | |
65 | +#define MC13783_IRQSTAT0_UDMI (1 << 23) | |
66 | + | |
67 | +#define MC13XXX_IRQMASK0 1 | |
68 | +#define MC13XXX_IRQMASK0_ADCDONEM MC13XXX_IRQSTAT0_ADCDONEI | |
69 | +#define MC13XXX_IRQMASK0_ADCBISDONEM MC13XXX_IRQSTAT0_ADCBISDONEI | |
70 | +#define MC13XXX_IRQMASK0_TSM MC13XXX_IRQSTAT0_TSI | |
71 | +#define MC13783_IRQMASK0_WHIGHM MC13783_IRQSTAT0_WHIGHI | |
72 | +#define MC13783_IRQMASK0_WLOWM MC13783_IRQSTAT0_WLOWI | |
73 | +#define MC13XXX_IRQMASK0_CHGDETM MC13XXX_IRQSTAT0_CHGDETI | |
74 | +#define MC13783_IRQMASK0_CHGOVM MC13783_IRQSTAT0_CHGOVI | |
75 | +#define MC13XXX_IRQMASK0_CHGREVM MC13XXX_IRQSTAT0_CHGREVI | |
76 | +#define MC13XXX_IRQMASK0_CHGSHORTM MC13XXX_IRQSTAT0_CHGSHORTI | |
77 | +#define MC13XXX_IRQMASK0_CCCVM MC13XXX_IRQSTAT0_CCCVI | |
78 | +#define MC13XXX_IRQMASK0_CHGCURRM MC13XXX_IRQSTAT0_CHGCURRI | |
79 | +#define MC13XXX_IRQMASK0_BPONM MC13XXX_IRQSTAT0_BPONI | |
80 | +#define MC13XXX_IRQMASK0_LOBATLM MC13XXX_IRQSTAT0_LOBATLI | |
81 | +#define MC13XXX_IRQMASK0_LOBATHM MC13XXX_IRQSTAT0_LOBATHI | |
82 | +#define MC13783_IRQMASK0_UDPM MC13783_IRQSTAT0_UDPI | |
83 | +#define MC13783_IRQMASK0_USBM MC13783_IRQSTAT0_USBI | |
84 | +#define MC13783_IRQMASK0_IDM MC13783_IRQSTAT0_IDI | |
85 | +#define MC13783_IRQMASK0_SE1M MC13783_IRQSTAT0_SE1I | |
86 | +#define MC13783_IRQMASK0_CKDETM MC13783_IRQSTAT0_CKDETI | |
87 | +#define MC13783_IRQMASK0_UDMM MC13783_IRQSTAT0_UDMI | |
88 | + | |
89 | +#define MC13XXX_IRQSTAT1 3 | |
90 | +#define MC13XXX_IRQSTAT1_1HZI (1 << 0) | |
91 | +#define MC13XXX_IRQSTAT1_TODAI (1 << 1) | |
92 | +#define MC13783_IRQSTAT1_ONOFD1I (1 << 3) | |
93 | +#define MC13783_IRQSTAT1_ONOFD2I (1 << 4) | |
94 | +#define MC13783_IRQSTAT1_ONOFD3I (1 << 5) | |
95 | +#define MC13XXX_IRQSTAT1_SYSRSTI (1 << 6) | |
96 | +#define MC13XXX_IRQSTAT1_RTCRSTI (1 << 7) | |
97 | +#define MC13XXX_IRQSTAT1_PCI (1 << 8) | |
98 | +#define MC13XXX_IRQSTAT1_WARMI (1 << 9) | |
99 | +#define MC13XXX_IRQSTAT1_MEMHLDI (1 << 10) | |
100 | +#define MC13783_IRQSTAT1_PWRRDYI (1 << 11) | |
101 | +#define MC13XXX_IRQSTAT1_THWARNLI (1 << 12) | |
102 | +#define MC13XXX_IRQSTAT1_THWARNHI (1 << 13) | |
103 | +#define MC13XXX_IRQSTAT1_CLKI (1 << 14) | |
104 | +#define MC13783_IRQSTAT1_SEMAFI (1 << 15) | |
105 | +#define MC13783_IRQSTAT1_MC2BI (1 << 17) | |
106 | +#define MC13783_IRQSTAT1_HSDETI (1 << 18) | |
107 | +#define MC13783_IRQSTAT1_HSLI (1 << 19) | |
108 | +#define MC13783_IRQSTAT1_ALSPTHI (1 << 20) | |
109 | +#define MC13783_IRQSTAT1_AHSSHORTI (1 << 21) | |
110 | + | |
111 | +#define MC13XXX_IRQMASK1 4 | |
112 | +#define MC13XXX_IRQMASK1_1HZM MC13XXX_IRQSTAT1_1HZI | |
113 | +#define MC13XXX_IRQMASK1_TODAM MC13XXX_IRQSTAT1_TODAI | |
114 | +#define MC13783_IRQMASK1_ONOFD1M MC13783_IRQSTAT1_ONOFD1I | |
115 | +#define MC13783_IRQMASK1_ONOFD2M MC13783_IRQSTAT1_ONOFD2I | |
116 | +#define MC13783_IRQMASK1_ONOFD3M MC13783_IRQSTAT1_ONOFD3I | |
117 | +#define MC13XXX_IRQMASK1_SYSRSTM MC13XXX_IRQSTAT1_SYSRSTI | |
118 | +#define MC13XXX_IRQMASK1_RTCRSTM MC13XXX_IRQSTAT1_RTCRSTI | |
119 | +#define MC13XXX_IRQMASK1_PCM MC13XXX_IRQSTAT1_PCI | |
120 | +#define MC13XXX_IRQMASK1_WARMM MC13XXX_IRQSTAT1_WARMI | |
121 | +#define MC13XXX_IRQMASK1_MEMHLDM MC13XXX_IRQSTAT1_MEMHLDI | |
122 | +#define MC13783_IRQMASK1_PWRRDYM MC13783_IRQSTAT1_PWRRDYI | |
123 | +#define MC13XXX_IRQMASK1_THWARNLM MC13XXX_IRQSTAT1_THWARNLI | |
124 | +#define MC13XXX_IRQMASK1_THWARNHM MC13XXX_IRQSTAT1_THWARNHI | |
125 | +#define MC13XXX_IRQMASK1_CLKM MC13XXX_IRQSTAT1_CLKI | |
126 | +#define MC13783_IRQMASK1_SEMAFM MC13783_IRQSTAT1_SEMAFI | |
127 | +#define MC13783_IRQMASK1_MC2BM MC13783_IRQSTAT1_MC2BI | |
128 | +#define MC13783_IRQMASK1_HSDETM MC13783_IRQSTAT1_HSDETI | |
129 | +#define MC13783_IRQMASK1_HSLM MC13783_IRQSTAT1_HSLI | |
130 | +#define MC13783_IRQMASK1_ALSPTHM MC13783_IRQSTAT1_ALSPTHI | |
131 | +#define MC13783_IRQMASK1_AHSSHORTM MC13783_IRQSTAT1_AHSSHORTI | |
132 | + | |
133 | +#define MC13XXX_REVISION 7 | |
134 | +#define MC13XXX_REVISION_REVMETAL (0x07 << 0) | |
135 | +#define MC13XXX_REVISION_REVFULL (0x03 << 3) | |
136 | +#define MC13XXX_REVISION_ICID (0x07 << 6) | |
137 | +#define MC13XXX_REVISION_FIN (0x03 << 9) | |
138 | +#define MC13XXX_REVISION_FAB (0x03 << 11) | |
139 | +#define MC13XXX_REVISION_ICIDCODE (0x3f << 13) | |
140 | + | |
141 | +#define MC13783_ADC1 44 | |
142 | +#define MC13783_ADC1_ADEN (1 << 0) | |
143 | +#define MC13783_ADC1_RAND (1 << 1) | |
144 | +#define MC13783_ADC1_ADSEL (1 << 3) | |
145 | +#define MC13783_ADC1_ASC (1 << 20) | |
146 | +#define MC13783_ADC1_ADTRIGIGN (1 << 21) | |
147 | + | |
148 | +#define MC13783_ADC2 45 | |
149 | + | |
150 | +#define MC13XXX_NUMREGS 0x3f | |
151 | + | |
152 | +void mc13xxx_lock(struct mc13xxx *mc13xxx) | |
153 | +{ | |
154 | + if (!mutex_trylock(&mc13xxx->lock)) { | |
155 | + dev_dbg(&mc13xxx->spidev->dev, "wait for %s from %pf\n", | |
156 | + __func__, __builtin_return_address(0)); | |
157 | + | |
158 | + mutex_lock(&mc13xxx->lock); | |
159 | + } | |
160 | + dev_dbg(&mc13xxx->spidev->dev, "%s from %pf\n", | |
161 | + __func__, __builtin_return_address(0)); | |
162 | +} | |
163 | +EXPORT_SYMBOL(mc13xxx_lock); | |
164 | + | |
165 | +void mc13xxx_unlock(struct mc13xxx *mc13xxx) | |
166 | +{ | |
167 | + dev_dbg(&mc13xxx->spidev->dev, "%s from %pf\n", | |
168 | + __func__, __builtin_return_address(0)); | |
169 | + mutex_unlock(&mc13xxx->lock); | |
170 | +} | |
171 | +EXPORT_SYMBOL(mc13xxx_unlock); | |
172 | + | |
173 | +#define MC13XXX_REGOFFSET_SHIFT 25 | |
174 | +int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val) | |
175 | +{ | |
176 | + struct spi_transfer t; | |
177 | + struct spi_message m; | |
178 | + int ret; | |
179 | + | |
180 | + BUG_ON(!mutex_is_locked(&mc13xxx->lock)); | |
181 | + | |
182 | + if (offset > MC13XXX_NUMREGS) | |
183 | + return -EINVAL; | |
184 | + | |
185 | + *val = offset << MC13XXX_REGOFFSET_SHIFT; | |
186 | + | |
187 | + memset(&t, 0, sizeof(t)); | |
188 | + | |
189 | + t.tx_buf = val; | |
190 | + t.rx_buf = val; | |
191 | + t.len = sizeof(u32); | |
192 | + | |
193 | + spi_message_init(&m); | |
194 | + spi_message_add_tail(&t, &m); | |
195 | + | |
196 | + ret = spi_sync(mc13xxx->spidev, &m); | |
197 | + | |
198 | + /* error in message.status implies error return from spi_sync */ | |
199 | + BUG_ON(!ret && m.status); | |
200 | + | |
201 | + if (ret) | |
202 | + return ret; | |
203 | + | |
204 | + *val &= 0xffffff; | |
205 | + | |
206 | + dev_vdbg(&mc13xxx->spidev->dev, "[0x%02x] -> 0x%06x\n", offset, *val); | |
207 | + | |
208 | + return 0; | |
209 | +} | |
210 | +EXPORT_SYMBOL(mc13xxx_reg_read); | |
211 | + | |
212 | +int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val) | |
213 | +{ | |
214 | + u32 buf; | |
215 | + struct spi_transfer t; | |
216 | + struct spi_message m; | |
217 | + int ret; | |
218 | + | |
219 | + BUG_ON(!mutex_is_locked(&mc13xxx->lock)); | |
220 | + | |
221 | + dev_vdbg(&mc13xxx->spidev->dev, "[0x%02x] <- 0x%06x\n", offset, val); | |
222 | + | |
223 | + if (offset > MC13XXX_NUMREGS || val > 0xffffff) | |
224 | + return -EINVAL; | |
225 | + | |
226 | + buf = 1 << 31 | offset << MC13XXX_REGOFFSET_SHIFT | val; | |
227 | + | |
228 | + memset(&t, 0, sizeof(t)); | |
229 | + | |
230 | + t.tx_buf = &buf; | |
231 | + t.rx_buf = &buf; | |
232 | + t.len = sizeof(u32); | |
233 | + | |
234 | + spi_message_init(&m); | |
235 | + spi_message_add_tail(&t, &m); | |
236 | + | |
237 | + ret = spi_sync(mc13xxx->spidev, &m); | |
238 | + | |
239 | + BUG_ON(!ret && m.status); | |
240 | + | |
241 | + if (ret) | |
242 | + return ret; | |
243 | + | |
244 | + return 0; | |
245 | +} | |
246 | +EXPORT_SYMBOL(mc13xxx_reg_write); | |
247 | + | |
248 | +int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset, | |
249 | + u32 mask, u32 val) | |
250 | +{ | |
251 | + int ret; | |
252 | + u32 valread; | |
253 | + | |
254 | + BUG_ON(val & ~mask); | |
255 | + | |
256 | + ret = mc13xxx_reg_read(mc13xxx, offset, &valread); | |
257 | + if (ret) | |
258 | + return ret; | |
259 | + | |
260 | + valread = (valread & ~mask) | val; | |
261 | + | |
262 | + return mc13xxx_reg_write(mc13xxx, offset, valread); | |
263 | +} | |
264 | +EXPORT_SYMBOL(mc13xxx_reg_rmw); | |
265 | + | |
266 | +int mc13xxx_irq_mask(struct mc13xxx *mc13xxx, int irq) | |
267 | +{ | |
268 | + int ret; | |
269 | + unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1; | |
270 | + u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | |
271 | + u32 mask; | |
272 | + | |
273 | + if (irq < 0 || irq >= MC13XXX_NUM_IRQ) | |
274 | + return -EINVAL; | |
275 | + | |
276 | + ret = mc13xxx_reg_read(mc13xxx, offmask, &mask); | |
277 | + if (ret) | |
278 | + return ret; | |
279 | + | |
280 | + if (mask & irqbit) | |
281 | + /* already masked */ | |
282 | + return 0; | |
283 | + | |
284 | + return mc13xxx_reg_write(mc13xxx, offmask, mask | irqbit); | |
285 | +} | |
286 | +EXPORT_SYMBOL(mc13xxx_irq_mask); | |
287 | + | |
288 | +int mc13xxx_irq_unmask(struct mc13xxx *mc13xxx, int irq) | |
289 | +{ | |
290 | + int ret; | |
291 | + unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1; | |
292 | + u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | |
293 | + u32 mask; | |
294 | + | |
295 | + if (irq < 0 || irq >= MC13XXX_NUM_IRQ) | |
296 | + return -EINVAL; | |
297 | + | |
298 | + ret = mc13xxx_reg_read(mc13xxx, offmask, &mask); | |
299 | + if (ret) | |
300 | + return ret; | |
301 | + | |
302 | + if (!(mask & irqbit)) | |
303 | + /* already unmasked */ | |
304 | + return 0; | |
305 | + | |
306 | + return mc13xxx_reg_write(mc13xxx, offmask, mask & ~irqbit); | |
307 | +} | |
308 | +EXPORT_SYMBOL(mc13xxx_irq_unmask); | |
309 | + | |
310 | +int mc13xxx_irq_status(struct mc13xxx *mc13xxx, int irq, | |
311 | + int *enabled, int *pending) | |
312 | +{ | |
313 | + int ret; | |
314 | + unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1; | |
315 | + unsigned int offstat = irq < 24 ? MC13XXX_IRQSTAT0 : MC13XXX_IRQSTAT1; | |
316 | + u32 irqbit = 1 << (irq < 24 ? irq : irq - 24); | |
317 | + | |
318 | + if (irq < 0 || irq >= MC13XXX_NUM_IRQ) | |
319 | + return -EINVAL; | |
320 | + | |
321 | + if (enabled) { | |
322 | + u32 mask; | |
323 | + | |
324 | + ret = mc13xxx_reg_read(mc13xxx, offmask, &mask); | |
325 | + if (ret) | |
326 | + return ret; | |
327 | + | |
328 | + *enabled = mask & irqbit; | |
329 | + } | |
330 | + | |
331 | + if (pending) { | |
332 | + u32 stat; | |
333 | + | |
334 | + ret = mc13xxx_reg_read(mc13xxx, offstat, &stat); | |
335 | + if (ret) | |
336 | + return ret; | |
337 | + | |
338 | + *pending = stat & irqbit; | |
339 | + } | |
340 | + | |
341 | + return 0; | |
342 | +} | |
343 | +EXPORT_SYMBOL(mc13xxx_irq_status); | |
344 | + | |
345 | +int mc13xxx_irq_ack(struct mc13xxx *mc13xxx, int irq) | |
346 | +{ | |
347 | + unsigned int offstat = irq < 24 ? MC13XXX_IRQSTAT0 : MC13XXX_IRQSTAT1; | |
348 | + unsigned int val = 1 << (irq < 24 ? irq : irq - 24); | |
349 | + | |
350 | + BUG_ON(irq < 0 || irq >= MC13XXX_NUM_IRQ); | |
351 | + | |
352 | + return mc13xxx_reg_write(mc13xxx, offstat, val); | |
353 | +} | |
354 | +EXPORT_SYMBOL(mc13xxx_irq_ack); | |
355 | + | |
356 | +int mc13xxx_irq_request_nounmask(struct mc13xxx *mc13xxx, int irq, | |
357 | + irq_handler_t handler, const char *name, void *dev) | |
358 | +{ | |
359 | + BUG_ON(!mutex_is_locked(&mc13xxx->lock)); | |
360 | + BUG_ON(!handler); | |
361 | + | |
362 | + if (irq < 0 || irq >= MC13XXX_NUM_IRQ) | |
363 | + return -EINVAL; | |
364 | + | |
365 | + if (mc13xxx->irqhandler[irq]) | |
366 | + return -EBUSY; | |
367 | + | |
368 | + mc13xxx->irqhandler[irq] = handler; | |
369 | + mc13xxx->irqdata[irq] = dev; | |
370 | + | |
371 | + return 0; | |
372 | +} | |
373 | +EXPORT_SYMBOL(mc13xxx_irq_request_nounmask); | |
374 | + | |
375 | +int mc13xxx_irq_request(struct mc13xxx *mc13xxx, int irq, | |
376 | + irq_handler_t handler, const char *name, void *dev) | |
377 | +{ | |
378 | + int ret; | |
379 | + | |
380 | + ret = mc13xxx_irq_request_nounmask(mc13xxx, irq, handler, name, dev); | |
381 | + if (ret) | |
382 | + return ret; | |
383 | + | |
384 | + ret = mc13xxx_irq_unmask(mc13xxx, irq); | |
385 | + if (ret) { | |
386 | + mc13xxx->irqhandler[irq] = NULL; | |
387 | + mc13xxx->irqdata[irq] = NULL; | |
388 | + return ret; | |
389 | + } | |
390 | + | |
391 | + return 0; | |
392 | +} | |
393 | +EXPORT_SYMBOL(mc13xxx_irq_request); | |
394 | + | |
395 | +int mc13xxx_irq_free(struct mc13xxx *mc13xxx, int irq, void *dev) | |
396 | +{ | |
397 | + int ret; | |
398 | + BUG_ON(!mutex_is_locked(&mc13xxx->lock)); | |
399 | + | |
400 | + if (irq < 0 || irq >= MC13XXX_NUM_IRQ || !mc13xxx->irqhandler[irq] || | |
401 | + mc13xxx->irqdata[irq] != dev) | |
402 | + return -EINVAL; | |
403 | + | |
404 | + ret = mc13xxx_irq_mask(mc13xxx, irq); | |
405 | + if (ret) | |
406 | + return ret; | |
407 | + | |
408 | + mc13xxx->irqhandler[irq] = NULL; | |
409 | + mc13xxx->irqdata[irq] = NULL; | |
410 | + | |
411 | + return 0; | |
412 | +} | |
413 | +EXPORT_SYMBOL(mc13xxx_irq_free); | |
414 | + | |
415 | +static inline irqreturn_t mc13xxx_irqhandler(struct mc13xxx *mc13xxx, int irq) | |
416 | +{ | |
417 | + return mc13xxx->irqhandler[irq](irq, mc13xxx->irqdata[irq]); | |
418 | +} | |
419 | + | |
420 | +/* | |
421 | + * returns: number of handled irqs or negative error | |
422 | + * locking: holds mc13xxx->lock | |
423 | + */ | |
424 | +static int mc13xxx_irq_handle(struct mc13xxx *mc13xxx, | |
425 | + unsigned int offstat, unsigned int offmask, int baseirq) | |
426 | +{ | |
427 | + u32 stat, mask; | |
428 | + int ret = mc13xxx_reg_read(mc13xxx, offstat, &stat); | |
429 | + int num_handled = 0; | |
430 | + | |
431 | + if (ret) | |
432 | + return ret; | |
433 | + | |
434 | + ret = mc13xxx_reg_read(mc13xxx, offmask, &mask); | |
435 | + if (ret) | |
436 | + return ret; | |
437 | + | |
438 | + while (stat & ~mask) { | |
439 | + int irq = __ffs(stat & ~mask); | |
440 | + | |
441 | + stat &= ~(1 << irq); | |
442 | + | |
443 | + if (likely(mc13xxx->irqhandler[baseirq + irq])) { | |
444 | + irqreturn_t handled; | |
445 | + | |
446 | + handled = mc13xxx_irqhandler(mc13xxx, baseirq + irq); | |
447 | + if (handled == IRQ_HANDLED) | |
448 | + num_handled++; | |
449 | + } else { | |
450 | + dev_err(&mc13xxx->spidev->dev, | |
451 | + "BUG: irq %u but no handler\n", | |
452 | + baseirq + irq); | |
453 | + | |
454 | + mask |= 1 << irq; | |
455 | + | |
456 | + ret = mc13xxx_reg_write(mc13xxx, offmask, mask); | |
457 | + } | |
458 | + } | |
459 | + | |
460 | + return num_handled; | |
461 | +} | |
462 | + | |
463 | +static irqreturn_t mc13xxx_irq_thread(int irq, void *data) | |
464 | +{ | |
465 | + struct mc13xxx *mc13xxx = data; | |
466 | + irqreturn_t ret; | |
467 | + int handled = 0; | |
468 | + | |
469 | + mc13xxx_lock(mc13xxx); | |
470 | + | |
471 | + ret = mc13xxx_irq_handle(mc13xxx, MC13XXX_IRQSTAT0, | |
472 | + MC13XXX_IRQMASK0, 0); | |
473 | + if (ret > 0) | |
474 | + handled = 1; | |
475 | + | |
476 | + ret = mc13xxx_irq_handle(mc13xxx, MC13XXX_IRQSTAT1, | |
477 | + MC13XXX_IRQMASK1, 24); | |
478 | + if (ret > 0) | |
479 | + handled = 1; | |
480 | + | |
481 | + mc13xxx_unlock(mc13xxx); | |
482 | + | |
483 | + return IRQ_RETVAL(handled); | |
484 | +} | |
485 | + | |
486 | +enum mc13xxx_id { | |
487 | + MC13XXX_ID_MC13783, | |
488 | + MC13XXX_ID_MC13892, | |
489 | + MC13XXX_ID_INVALID, | |
490 | +}; | |
491 | + | |
492 | +const char *mc13xxx_chipname[] = { | |
493 | + [MC13XXX_ID_MC13783] = "mc13783", | |
494 | + [MC13XXX_ID_MC13892] = "mc13892", | |
495 | +}; | |
496 | + | |
497 | +#define maskval(reg, mask) (((reg) & (mask)) >> __ffs(mask)) | |
498 | +static int mc13xxx_identify(struct mc13xxx *mc13xxx, enum mc13xxx_id *id) | |
499 | +{ | |
500 | + u32 icid; | |
501 | + u32 revision; | |
502 | + const char *name; | |
503 | + int ret; | |
504 | + | |
505 | + ret = mc13xxx_reg_read(mc13xxx, 46, &icid); | |
506 | + if (ret) | |
507 | + return ret; | |
508 | + | |
509 | + icid = (icid >> 6) & 0x7; | |
510 | + | |
511 | + switch (icid) { | |
512 | + case 2: | |
513 | + *id = MC13XXX_ID_MC13783; | |
514 | + name = "mc13783"; | |
515 | + break; | |
516 | + case 7: | |
517 | + *id = MC13XXX_ID_MC13892; | |
518 | + name = "mc13892"; | |
519 | + break; | |
520 | + default: | |
521 | + *id = MC13XXX_ID_INVALID; | |
522 | + break; | |
523 | + } | |
524 | + | |
525 | + if (*id == MC13XXX_ID_MC13783 || *id == MC13XXX_ID_MC13892) { | |
526 | + ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision); | |
527 | + if (ret) | |
528 | + return ret; | |
529 | + | |
530 | + dev_info(&mc13xxx->spidev->dev, "%s: rev: %d.%d, " | |
531 | + "fin: %d, fab: %d, icid: %d/%d\n", | |
532 | + mc13xxx_chipname[*id], | |
533 | + maskval(revision, MC13XXX_REVISION_REVFULL), | |
534 | + maskval(revision, MC13XXX_REVISION_REVMETAL), | |
535 | + maskval(revision, MC13XXX_REVISION_FIN), | |
536 | + maskval(revision, MC13XXX_REVISION_FAB), | |
537 | + maskval(revision, MC13XXX_REVISION_ICID), | |
538 | + maskval(revision, MC13XXX_REVISION_ICIDCODE)); | |
539 | + } | |
540 | + | |
541 | + if (*id != MC13XXX_ID_INVALID) { | |
542 | + const struct spi_device_id *devid = | |
543 | + spi_get_device_id(mc13xxx->spidev); | |
544 | + if (!devid || devid->driver_data != *id) | |
545 | + dev_warn(&mc13xxx->spidev->dev, "device id doesn't " | |
546 | + "match auto detection!\n"); | |
547 | + } | |
548 | + | |
549 | + return 0; | |
550 | +} | |
551 | + | |
552 | +static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx) | |
553 | +{ | |
554 | + const struct spi_device_id *devid = | |
555 | + spi_get_device_id(mc13xxx->spidev); | |
556 | + | |
557 | + if (!devid) | |
558 | + return NULL; | |
559 | + | |
560 | + return mc13xxx_chipname[devid->driver_data]; | |
561 | +} | |
562 | + | |
563 | +#include <linux/mfd/mc13783.h> | |
564 | + | |
565 | +int mc13xxx_get_flags(struct mc13xxx *mc13xxx) | |
566 | +{ | |
567 | + struct mc13xxx_platform_data *pdata = | |
568 | + dev_get_platdata(&mc13xxx->spidev->dev); | |
569 | + | |
570 | + return pdata->flags; | |
571 | +} | |
572 | +EXPORT_SYMBOL(mc13xxx_get_flags); | |
573 | + | |
574 | +#define MC13783_ADC1_CHAN0_SHIFT 5 | |
575 | +#define MC13783_ADC1_CHAN1_SHIFT 8 | |
576 | + | |
577 | +struct mc13xxx_adcdone_data { | |
578 | + struct mc13xxx *mc13xxx; | |
579 | + struct completion done; | |
580 | +}; | |
581 | + | |
582 | +static irqreturn_t mc13783_handler_adcdone(int irq, void *data) | |
583 | +{ | |
584 | + struct mc13xxx_adcdone_data *adcdone_data = data; | |
585 | + | |
586 | + mc13xxx_irq_ack(adcdone_data->mc13xxx, irq); | |
587 | + | |
588 | + complete_all(&adcdone_data->done); | |
589 | + | |
590 | + return IRQ_HANDLED; | |
591 | +} | |
592 | + | |
593 | +#define MC13783_ADC_WORKING (1 << 0) | |
594 | + | |
595 | +int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode, | |
596 | + unsigned int channel, unsigned int *sample) | |
597 | +{ | |
598 | + struct mc13xxx *mc13xxx = &mc13783->mc13xxx; | |
599 | + u32 adc0, adc1, old_adc0; | |
600 | + int i, ret; | |
601 | + struct mc13xxx_adcdone_data adcdone_data = { | |
602 | + .mc13xxx = mc13xxx, | |
603 | + }; | |
604 | + init_completion(&adcdone_data.done); | |
605 | + | |
606 | + dev_dbg(&mc13xxx->spidev->dev, "%s\n", __func__); | |
607 | + | |
608 | + mc13xxx_lock(mc13xxx); | |
609 | + | |
610 | + if (mc13783->adcflags & MC13783_ADC_WORKING) { | |
611 | + ret = -EBUSY; | |
612 | + goto out; | |
613 | + } | |
614 | + | |
615 | + mc13783->adcflags |= MC13783_ADC_WORKING; | |
616 | + | |
617 | + mc13xxx_reg_read(mc13xxx, MC13783_ADC0, &old_adc0); | |
618 | + | |
619 | + adc0 = MC13783_ADC0_ADINC1 | MC13783_ADC0_ADINC2; | |
620 | + adc1 = MC13783_ADC1_ADEN | MC13783_ADC1_ADTRIGIGN | MC13783_ADC1_ASC; | |
621 | + | |
622 | + if (channel > 7) | |
623 | + adc1 |= MC13783_ADC1_ADSEL; | |
624 | + | |
625 | + switch (mode) { | |
626 | + case MC13783_ADC_MODE_TS: | |
627 | + adc0 |= MC13783_ADC0_ADREFEN | MC13783_ADC0_TSMOD0 | | |
628 | + MC13783_ADC0_TSMOD1; | |
629 | + adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; | |
630 | + break; | |
631 | + | |
632 | + case MC13783_ADC_MODE_SINGLE_CHAN: | |
633 | + adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; | |
634 | + adc1 |= (channel & 0x7) << MC13783_ADC1_CHAN0_SHIFT; | |
635 | + adc1 |= MC13783_ADC1_RAND; | |
636 | + break; | |
637 | + | |
638 | + case MC13783_ADC_MODE_MULT_CHAN: | |
639 | + adc0 |= old_adc0 & MC13783_ADC0_TSMOD_MASK; | |
640 | + adc1 |= 4 << MC13783_ADC1_CHAN1_SHIFT; | |
641 | + break; | |
642 | + | |
643 | + default: | |
644 | + mc13783_unlock(mc13783); | |
645 | + return -EINVAL; | |
646 | + } | |
647 | + | |
648 | + dev_dbg(&mc13783->mc13xxx.spidev->dev, "%s: request irq\n", __func__); | |
649 | + mc13xxx_irq_request(mc13xxx, MC13783_IRQ_ADCDONE, | |
650 | + mc13783_handler_adcdone, __func__, &adcdone_data); | |
651 | + mc13xxx_irq_ack(mc13xxx, MC13783_IRQ_ADCDONE); | |
652 | + | |
653 | + mc13xxx_reg_write(mc13xxx, MC13783_ADC0, adc0); | |
654 | + mc13xxx_reg_write(mc13xxx, MC13783_ADC1, adc1); | |
655 | + | |
656 | + mc13xxx_unlock(mc13xxx); | |
657 | + | |
658 | + ret = wait_for_completion_interruptible_timeout(&adcdone_data.done, HZ); | |
659 | + | |
660 | + if (!ret) | |
661 | + ret = -ETIMEDOUT; | |
662 | + | |
663 | + mc13xxx_lock(mc13xxx); | |
664 | + | |
665 | + mc13xxx_irq_free(mc13xxx, MC13783_IRQ_ADCDONE, &adcdone_data); | |
666 | + | |
667 | + if (ret > 0) | |
668 | + for (i = 0; i < 4; ++i) { | |
669 | + ret = mc13xxx_reg_read(mc13xxx, | |
670 | + MC13783_ADC2, &sample[i]); | |
671 | + if (ret) | |
672 | + break; | |
673 | + } | |
674 | + | |
675 | + if (mode == MC13783_ADC_MODE_TS) | |
676 | + /* restore TSMOD */ | |
677 | + mc13xxx_reg_write(mc13xxx, MC13783_ADC0, old_adc0); | |
678 | + | |
679 | + mc13783->adcflags &= ~MC13783_ADC_WORKING; | |
680 | +out: | |
681 | + mc13xxx_unlock(mc13xxx); | |
682 | + | |
683 | + return ret; | |
684 | +} | |
685 | +EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion); | |
686 | + | |
687 | +static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, | |
688 | + const char *format, void *pdata, size_t pdata_size) | |
689 | +{ | |
690 | + char buf[30]; | |
691 | + const char *name = mc13xxx_get_chipname(mc13xxx); | |
692 | + | |
693 | + struct mfd_cell cell = { | |
694 | + .platform_data = pdata, | |
695 | + .data_size = pdata_size, | |
696 | + }; | |
697 | + | |
698 | + /* there is no asnprintf in the kernel :-( */ | |
699 | + if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf)) | |
700 | + return -E2BIG; | |
701 | + | |
702 | + cell.name = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL); | |
703 | + if (!cell.name) | |
704 | + return -ENOMEM; | |
705 | + | |
706 | + return mfd_add_devices(&mc13xxx->spidev->dev, -1, &cell, 1, NULL, 0); | |
707 | +} | |
708 | + | |
709 | +static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format) | |
710 | +{ | |
711 | + return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0); | |
712 | +} | |
713 | + | |
714 | +static int mc13xxx_probe(struct spi_device *spi) | |
715 | +{ | |
716 | + struct mc13xxx *mc13xxx; | |
717 | + struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev); | |
718 | + enum mc13xxx_id id; | |
719 | + int ret; | |
720 | + | |
721 | + mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL); | |
722 | + if (!mc13xxx) | |
723 | + return -ENOMEM; | |
724 | + | |
725 | + dev_set_drvdata(&spi->dev, mc13xxx); | |
726 | + spi->mode = SPI_MODE_0 | SPI_CS_HIGH; | |
727 | + spi->bits_per_word = 32; | |
728 | + spi_setup(spi); | |
729 | + | |
730 | + mc13xxx->spidev = spi; | |
731 | + | |
732 | + mutex_init(&mc13xxx->lock); | |
733 | + mc13xxx_lock(mc13xxx); | |
734 | + | |
735 | + ret = mc13xxx_identify(mc13xxx, &id); | |
736 | + if (ret || id == MC13XXX_ID_INVALID) | |
737 | + goto err_revision; | |
738 | + | |
739 | + /* mask all irqs */ | |
740 | + ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK0, 0x00ffffff); | |
741 | + if (ret) | |
742 | + goto err_mask; | |
743 | + | |
744 | + ret = mc13xxx_reg_write(mc13xxx, MC13XXX_IRQMASK1, 0x00ffffff); | |
745 | + if (ret) | |
746 | + goto err_mask; | |
747 | + | |
748 | + ret = request_threaded_irq(spi->irq, NULL, mc13xxx_irq_thread, | |
749 | + IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx); | |
750 | + | |
751 | + if (ret) { | |
752 | +err_mask: | |
753 | +err_revision: | |
754 | + mutex_unlock(&mc13xxx->lock); | |
755 | + dev_set_drvdata(&spi->dev, NULL); | |
756 | + kfree(mc13xxx); | |
757 | + return ret; | |
758 | + } | |
759 | + | |
760 | + mc13xxx_unlock(mc13xxx); | |
761 | + | |
762 | + if (pdata->flags & MC13XXX_USE_ADC) | |
763 | + mc13xxx_add_subdevice(mc13xxx, "%s-adc"); | |
764 | + | |
765 | + if (pdata->flags & MC13XXX_USE_CODEC) | |
766 | + mc13xxx_add_subdevice(mc13xxx, "%s-codec"); | |
767 | + | |
768 | + if (pdata->flags & MC13XXX_USE_REGULATOR) { | |
769 | + struct mc13xxx_regulator_platform_data regulator_pdata = { | |
770 | + .num_regulators = pdata->num_regulators, | |
771 | + .regulators = pdata->regulators, | |
772 | + }; | |
773 | + | |
774 | + mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", | |
775 | + ®ulator_pdata, sizeof(regulator_pdata)); | |
776 | + } | |
777 | + | |
778 | + if (pdata->flags & MC13XXX_USE_RTC) | |
779 | + mc13xxx_add_subdevice(mc13xxx, "%s-rtc"); | |
780 | + | |
781 | + if (pdata->flags & MC13XXX_USE_TOUCHSCREEN) | |
782 | + mc13xxx_add_subdevice(mc13xxx, "%s-ts"); | |
783 | + | |
784 | + if (pdata->flags & MC13XXX_USE_LED) { | |
785 | + mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", | |
786 | + pdata->leds, sizeof(*pdata->leds)); | |
787 | + } | |
788 | + | |
789 | + return 0; | |
790 | +} | |
791 | + | |
792 | +static int __devexit mc13xxx_remove(struct spi_device *spi) | |
793 | +{ | |
794 | + struct mc13xxx *mc13xxx = dev_get_drvdata(&spi->dev); | |
795 | + | |
796 | + free_irq(mc13xxx->spidev->irq, mc13xxx); | |
797 | + | |
798 | + mfd_remove_devices(&spi->dev); | |
799 | + | |
800 | + return 0; | |
801 | +} | |
802 | + | |
803 | +static const struct spi_device_id mc13xxx_device_id[] = { | |
804 | + { | |
805 | + .name = "mc13783", | |
806 | + .driver_data = MC13XXX_ID_MC13783, | |
807 | + }, { | |
808 | + .name = "mc13892", | |
809 | + .driver_data = MC13XXX_ID_MC13892, | |
810 | + }, { | |
811 | + /* sentinel */ | |
812 | + } | |
813 | +}; | |
814 | + | |
815 | +static struct spi_driver mc13xxx_driver = { | |
816 | + .id_table = mc13xxx_device_id, | |
817 | + .driver = { | |
818 | + .name = "mc13xxx", | |
819 | + .bus = &spi_bus_type, | |
820 | + .owner = THIS_MODULE, | |
821 | + }, | |
822 | + .probe = mc13xxx_probe, | |
823 | + .remove = __devexit_p(mc13xxx_remove), | |
824 | +}; | |
825 | + | |
826 | +static int __init mc13xxx_init(void) | |
827 | +{ | |
828 | + return spi_register_driver(&mc13xxx_driver); | |
829 | +} | |
830 | +subsys_initcall(mc13xxx_init); | |
831 | + | |
832 | +static void __exit mc13xxx_exit(void) | |
833 | +{ | |
834 | + spi_unregister_driver(&mc13xxx_driver); | |
835 | +} | |
836 | +module_exit(mc13xxx_exit); | |
837 | + | |
838 | +MODULE_DESCRIPTION("Core driver for Freescale MC13XXX PMIC"); | |
839 | +MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>"); | |
840 | +MODULE_LICENSE("GPL v2"); |
include/linux/mfd/mc13783.h
1 | 1 | /* |
2 | - * Copyright 2009 Pengutronix | |
2 | + * Copyright 2009-2010 Pengutronix | |
3 | 3 | * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> |
4 | 4 | * |
5 | 5 | * This program is free software; you can redistribute it and/or modify it under |
6 | 6 | |
7 | 7 | |
8 | 8 | |
9 | 9 | |
10 | 10 | |
11 | 11 | |
... | ... | @@ -9,32 +9,85 @@ |
9 | 9 | #ifndef __LINUX_MFD_MC13783_H |
10 | 10 | #define __LINUX_MFD_MC13783_H |
11 | 11 | |
12 | -#include <linux/interrupt.h> | |
12 | +#include <linux/mfd/mc13xxx.h> | |
13 | 13 | |
14 | 14 | struct mc13783; |
15 | 15 | |
16 | -void mc13783_lock(struct mc13783 *mc13783); | |
17 | -void mc13783_unlock(struct mc13783 *mc13783); | |
16 | +struct mc13xxx *mc13783_to_mc13xxx(struct mc13783 *mc13783); | |
18 | 17 | |
19 | -int mc13783_reg_read(struct mc13783 *mc13783, unsigned int offset, u32 *val); | |
20 | -int mc13783_reg_write(struct mc13783 *mc13783, unsigned int offset, u32 val); | |
21 | -int mc13783_reg_rmw(struct mc13783 *mc13783, unsigned int offset, | |
22 | - u32 mask, u32 val); | |
18 | +static inline void mc13783_lock(struct mc13783 *mc13783) | |
19 | +{ | |
20 | + mc13xxx_lock(mc13783_to_mc13xxx(mc13783)); | |
21 | +} | |
23 | 22 | |
24 | -int mc13783_get_flags(struct mc13783 *mc13783); | |
23 | +static inline void mc13783_unlock(struct mc13783 *mc13783) | |
24 | +{ | |
25 | + mc13xxx_unlock(mc13783_to_mc13xxx(mc13783)); | |
26 | +} | |
25 | 27 | |
26 | -int mc13783_irq_request(struct mc13783 *mc13783, int irq, | |
27 | - irq_handler_t handler, const char *name, void *dev); | |
28 | -int mc13783_irq_request_nounmask(struct mc13783 *mc13783, int irq, | |
29 | - irq_handler_t handler, const char *name, void *dev); | |
30 | -int mc13783_irq_free(struct mc13783 *mc13783, int irq, void *dev); | |
28 | +static inline int mc13783_reg_read(struct mc13783 *mc13783, | |
29 | + unsigned int offset, u32 *val) | |
30 | +{ | |
31 | + return mc13xxx_reg_read(mc13783_to_mc13xxx(mc13783), offset, val); | |
32 | +} | |
31 | 33 | |
32 | -int mc13783_irq_mask(struct mc13783 *mc13783, int irq); | |
33 | -int mc13783_irq_unmask(struct mc13783 *mc13783, int irq); | |
34 | -int mc13783_irq_status(struct mc13783 *mc13783, int irq, | |
35 | - int *enabled, int *pending); | |
36 | -int mc13783_irq_ack(struct mc13783 *mc13783, int irq); | |
34 | +static inline int mc13783_reg_write(struct mc13783 *mc13783, | |
35 | + unsigned int offset, u32 val) | |
36 | +{ | |
37 | + return mc13xxx_reg_write(mc13783_to_mc13xxx(mc13783), offset, val); | |
38 | +} | |
37 | 39 | |
40 | +static inline int mc13783_reg_rmw(struct mc13783 *mc13783, | |
41 | + unsigned int offset, u32 mask, u32 val) | |
42 | +{ | |
43 | + return mc13xxx_reg_rmw(mc13783_to_mc13xxx(mc13783), offset, mask, val); | |
44 | +} | |
45 | + | |
46 | +static inline int mc13783_get_flags(struct mc13783 *mc13783) | |
47 | +{ | |
48 | + return mc13xxx_get_flags(mc13783_to_mc13xxx(mc13783)); | |
49 | +} | |
50 | + | |
51 | +static inline int mc13783_irq_request(struct mc13783 *mc13783, int irq, | |
52 | + irq_handler_t handler, const char *name, void *dev) | |
53 | +{ | |
54 | + return mc13xxx_irq_request(mc13783_to_mc13xxx(mc13783), irq, | |
55 | + handler, name, dev); | |
56 | +} | |
57 | + | |
58 | +static inline int mc13783_irq_request_nounmask(struct mc13783 *mc13783, int irq, | |
59 | + irq_handler_t handler, const char *name, void *dev) | |
60 | +{ | |
61 | + return mc13xxx_irq_request_nounmask(mc13783_to_mc13xxx(mc13783), irq, | |
62 | + handler, name, dev); | |
63 | +} | |
64 | + | |
65 | +static inline int mc13783_irq_free(struct mc13783 *mc13783, int irq, void *dev) | |
66 | +{ | |
67 | + return mc13xxx_irq_free(mc13783_to_mc13xxx(mc13783), irq, dev); | |
68 | +} | |
69 | + | |
70 | +static inline int mc13783_irq_mask(struct mc13783 *mc13783, int irq) | |
71 | +{ | |
72 | + return mc13xxx_irq_mask(mc13783_to_mc13xxx(mc13783), irq); | |
73 | +} | |
74 | + | |
75 | +static inline int mc13783_irq_unmask(struct mc13783 *mc13783, int irq) | |
76 | +{ | |
77 | + return mc13xxx_irq_unmask(mc13783_to_mc13xxx(mc13783), irq); | |
78 | +} | |
79 | +static inline int mc13783_irq_status(struct mc13783 *mc13783, int irq, | |
80 | + int *enabled, int *pending) | |
81 | +{ | |
82 | + return mc13xxx_irq_status(mc13783_to_mc13xxx(mc13783), | |
83 | + irq, enabled, pending); | |
84 | +} | |
85 | + | |
86 | +static inline int mc13783_irq_ack(struct mc13783 *mc13783, int irq) | |
87 | +{ | |
88 | + return mc13xxx_irq_ack(mc13783_to_mc13xxx(mc13783), irq); | |
89 | +} | |
90 | + | |
38 | 91 | #define MC13783_ADC0 43 |
39 | 92 | #define MC13783_ADC0_ADREFEN (1 << 10) |
40 | 93 | #define MC13783_ADC0_ADREFMODE (1 << 11) |
41 | 94 | |
42 | 95 | |
... | ... | @@ -48,97 +101,19 @@ |
48 | 101 | MC13783_ADC0_TSMOD1 | \ |
49 | 102 | MC13783_ADC0_TSMOD2) |
50 | 103 | |
51 | -struct mc13783_led_platform_data { | |
52 | -#define MC13783_LED_MD 0 | |
53 | -#define MC13783_LED_AD 1 | |
54 | -#define MC13783_LED_KP 2 | |
55 | -#define MC13783_LED_R1 3 | |
56 | -#define MC13783_LED_G1 4 | |
57 | -#define MC13783_LED_B1 5 | |
58 | -#define MC13783_LED_R2 6 | |
59 | -#define MC13783_LED_G2 7 | |
60 | -#define MC13783_LED_B2 8 | |
61 | -#define MC13783_LED_R3 9 | |
62 | -#define MC13783_LED_G3 10 | |
63 | -#define MC13783_LED_B3 11 | |
64 | -#define MC13783_LED_MAX MC13783_LED_B3 | |
65 | - int id; | |
66 | - const char *name; | |
67 | - const char *default_trigger; | |
104 | +#define mc13783_regulator_init_data mc13xxx_regulator_init_data | |
105 | +#define mc13783_regulator_platform_data mc13xxx_regulator_platform_data | |
106 | +#define mc13783_led_platform_data mc13xxx_led_platform_data | |
107 | +#define mc13783_leds_platform_data mc13xxx_leds_platform_data | |
68 | 108 | |
69 | -/* Three or two bits current selection depending on the led */ | |
70 | - char max_current; | |
71 | -}; | |
109 | +#define mc13783_platform_data mc13xxx_platform_data | |
110 | +#define MC13783_USE_TOUCHSCREEN MC13XXX_USE_TOUCHSCREEN | |
111 | +#define MC13783_USE_CODEC MC13XXX_USE_CODEC | |
112 | +#define MC13783_USE_ADC MC13XXX_USE_ADC | |
113 | +#define MC13783_USE_RTC MC13XXX_USE_RTC | |
114 | +#define MC13783_USE_REGULATOR MC13XXX_USE_REGULATOR | |
115 | +#define MC13783_USE_LED MC13XXX_USE_LED | |
72 | 116 | |
73 | -struct mc13783_leds_platform_data { | |
74 | - int num_leds; | |
75 | - struct mc13783_led_platform_data *led; | |
76 | - | |
77 | -#define MC13783_LED_TRIODE_MD (1 << 0) | |
78 | -#define MC13783_LED_TRIODE_AD (1 << 1) | |
79 | -#define MC13783_LED_TRIODE_KP (1 << 2) | |
80 | -#define MC13783_LED_BOOST_EN (1 << 3) | |
81 | -#define MC13783_LED_TC1HALF (1 << 4) | |
82 | -#define MC13783_LED_SLEWLIMTC (1 << 5) | |
83 | -#define MC13783_LED_SLEWLIMBL (1 << 6) | |
84 | -#define MC13783_LED_TRIODE_TC1 (1 << 7) | |
85 | -#define MC13783_LED_TRIODE_TC2 (1 << 8) | |
86 | -#define MC13783_LED_TRIODE_TC3 (1 << 9) | |
87 | - int flags; | |
88 | - | |
89 | -#define MC13783_LED_AB_DISABLED 0 | |
90 | -#define MC13783_LED_AB_MD1 1 | |
91 | -#define MC13783_LED_AB_MD12 2 | |
92 | -#define MC13783_LED_AB_MD123 3 | |
93 | -#define MC13783_LED_AB_MD1234 4 | |
94 | -#define MC13783_LED_AB_MD1234_AD1 5 | |
95 | -#define MC13783_LED_AB_MD1234_AD12 6 | |
96 | -#define MC13783_LED_AB_MD1_AD 7 | |
97 | - char abmode; | |
98 | - | |
99 | -#define MC13783_LED_ABREF_200MV 0 | |
100 | -#define MC13783_LED_ABREF_400MV 1 | |
101 | -#define MC13783_LED_ABREF_600MV 2 | |
102 | -#define MC13783_LED_ABREF_800MV 3 | |
103 | - char abref; | |
104 | - | |
105 | -#define MC13783_LED_PERIOD_10MS 0 | |
106 | -#define MC13783_LED_PERIOD_100MS 1 | |
107 | -#define MC13783_LED_PERIOD_500MS 2 | |
108 | -#define MC13783_LED_PERIOD_2S 3 | |
109 | - char bl_period; | |
110 | - char tc1_period; | |
111 | - char tc2_period; | |
112 | - char tc3_period; | |
113 | -}; | |
114 | - | |
115 | -/* to be cleaned up */ | |
116 | -struct regulator_init_data; | |
117 | - | |
118 | -struct mc13783_regulator_init_data { | |
119 | - int id; | |
120 | - struct regulator_init_data *init_data; | |
121 | -}; | |
122 | - | |
123 | -struct mc13783_regulator_platform_data { | |
124 | - int num_regulators; | |
125 | - struct mc13783_regulator_init_data *regulators; | |
126 | -}; | |
127 | - | |
128 | -struct mc13783_platform_data { | |
129 | - int num_regulators; | |
130 | - struct mc13783_regulator_init_data *regulators; | |
131 | - struct mc13783_leds_platform_data *leds; | |
132 | - | |
133 | -#define MC13783_USE_TOUCHSCREEN (1 << 0) | |
134 | -#define MC13783_USE_CODEC (1 << 1) | |
135 | -#define MC13783_USE_ADC (1 << 2) | |
136 | -#define MC13783_USE_RTC (1 << 3) | |
137 | -#define MC13783_USE_REGULATOR (1 << 4) | |
138 | -#define MC13783_USE_LED (1 << 5) | |
139 | - unsigned int flags; | |
140 | -}; | |
141 | - | |
142 | 117 | #define MC13783_ADC_MODE_TS 1 |
143 | 118 | #define MC13783_ADC_MODE_SINGLE_CHAN 2 |
144 | 119 | #define MC13783_ADC_MODE_MULT_CHAN 3 |
145 | 120 | |
146 | 121 | |
147 | 122 | |
148 | 123 | |
149 | 124 | |
150 | 125 | |
151 | 126 | |
... | ... | @@ -181,47 +156,47 @@ |
181 | 156 | #define MC13783_REGU_PWGT1SPI 31 |
182 | 157 | #define MC13783_REGU_PWGT2SPI 32 |
183 | 158 | |
184 | -#define MC13783_IRQ_ADCDONE 0 | |
185 | -#define MC13783_IRQ_ADCBISDONE 1 | |
186 | -#define MC13783_IRQ_TS 2 | |
159 | +#define MC13783_IRQ_ADCDONE MC13XXX_IRQ_ADCDONE | |
160 | +#define MC13783_IRQ_ADCBISDONE MC13XXX_IRQ_ADCBISDONE | |
161 | +#define MC13783_IRQ_TS MC13XXX_IRQ_TS | |
187 | 162 | #define MC13783_IRQ_WHIGH 3 |
188 | 163 | #define MC13783_IRQ_WLOW 4 |
189 | -#define MC13783_IRQ_CHGDET 6 | |
164 | +#define MC13783_IRQ_CHGDET MC13XXX_IRQ_CHGDET | |
190 | 165 | #define MC13783_IRQ_CHGOV 7 |
191 | -#define MC13783_IRQ_CHGREV 8 | |
192 | -#define MC13783_IRQ_CHGSHORT 9 | |
193 | -#define MC13783_IRQ_CCCV 10 | |
194 | -#define MC13783_IRQ_CHGCURR 11 | |
195 | -#define MC13783_IRQ_BPON 12 | |
196 | -#define MC13783_IRQ_LOBATL 13 | |
197 | -#define MC13783_IRQ_LOBATH 14 | |
166 | +#define MC13783_IRQ_CHGREV MC13XXX_IRQ_CHGREV | |
167 | +#define MC13783_IRQ_CHGSHORT MC13XXX_IRQ_CHGSHORT | |
168 | +#define MC13783_IRQ_CCCV MC13XXX_IRQ_CCCV | |
169 | +#define MC13783_IRQ_CHGCURR MC13XXX_IRQ_CHGCURR | |
170 | +#define MC13783_IRQ_BPON MC13XXX_IRQ_BPON | |
171 | +#define MC13783_IRQ_LOBATL MC13XXX_IRQ_LOBATL | |
172 | +#define MC13783_IRQ_LOBATH MC13XXX_IRQ_LOBATH | |
198 | 173 | #define MC13783_IRQ_UDP 15 |
199 | 174 | #define MC13783_IRQ_USB 16 |
200 | 175 | #define MC13783_IRQ_ID 19 |
201 | 176 | #define MC13783_IRQ_SE1 21 |
202 | 177 | #define MC13783_IRQ_CKDET 22 |
203 | 178 | #define MC13783_IRQ_UDM 23 |
204 | -#define MC13783_IRQ_1HZ 24 | |
205 | -#define MC13783_IRQ_TODA 25 | |
179 | +#define MC13783_IRQ_1HZ MC13XXX_IRQ_1HZ | |
180 | +#define MC13783_IRQ_TODA MC13XXX_IRQ_TODA | |
206 | 181 | #define MC13783_IRQ_ONOFD1 27 |
207 | 182 | #define MC13783_IRQ_ONOFD2 28 |
208 | 183 | #define MC13783_IRQ_ONOFD3 29 |
209 | -#define MC13783_IRQ_SYSRST 30 | |
210 | -#define MC13783_IRQ_RTCRST 31 | |
211 | -#define MC13783_IRQ_PC 32 | |
212 | -#define MC13783_IRQ_WARM 33 | |
213 | -#define MC13783_IRQ_MEMHLD 34 | |
184 | +#define MC13783_IRQ_SYSRST MC13XXX_IRQ_SYSRST | |
185 | +#define MC13783_IRQ_RTCRST MC13XXX_IRQ_RTCRST | |
186 | +#define MC13783_IRQ_PC MC13XXX_IRQ_PC | |
187 | +#define MC13783_IRQ_WARM MC13XXX_IRQ_WARM | |
188 | +#define MC13783_IRQ_MEMHLD MC13XXX_IRQ_MEMHLD | |
214 | 189 | #define MC13783_IRQ_PWRRDY 35 |
215 | -#define MC13783_IRQ_THWARNL 36 | |
216 | -#define MC13783_IRQ_THWARNH 37 | |
217 | -#define MC13783_IRQ_CLK 38 | |
190 | +#define MC13783_IRQ_THWARNL MC13XXX_IRQ_THWARNL | |
191 | +#define MC13783_IRQ_THWARNH MC13XXX_IRQ_THWARNH | |
192 | +#define MC13783_IRQ_CLK MC13XXX_IRQ_CLK | |
218 | 193 | #define MC13783_IRQ_SEMAF 39 |
219 | 194 | #define MC13783_IRQ_MC2B 41 |
220 | 195 | #define MC13783_IRQ_HSDET 42 |
221 | 196 | #define MC13783_IRQ_HSL 43 |
222 | 197 | #define MC13783_IRQ_ALSPTH 44 |
223 | 198 | #define MC13783_IRQ_AHSSHORT 45 |
224 | -#define MC13783_NUM_IRQ 46 | |
199 | +#define MC13783_NUM_IRQ MC13XXX_NUM_IRQ | |
225 | 200 | |
226 | -#endif /* __LINUX_MFD_MC13783_H */ | |
201 | +#endif /* ifndef __LINUX_MFD_MC13783_H */ |
include/linux/mfd/mc13xxx.h
1 | +/* | |
2 | + * Copyright 2009-2010 Pengutronix | |
3 | + * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> | |
4 | + * | |
5 | + * This program is free software; you can redistribute it and/or modify it under | |
6 | + * the terms of the GNU General Public License version 2 as published by the | |
7 | + * Free Software Foundation. | |
8 | + */ | |
9 | +#ifndef __LINUX_MFD_MC13XXX_H | |
10 | +#define __LINUX_MFD_MC13XXX_H | |
11 | + | |
12 | +#include <linux/interrupt.h> | |
13 | + | |
14 | +struct mc13xxx; | |
15 | + | |
16 | +void mc13xxx_lock(struct mc13xxx *mc13xxx); | |
17 | +void mc13xxx_unlock(struct mc13xxx *mc13xxx); | |
18 | + | |
19 | +int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val); | |
20 | +int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val); | |
21 | +int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset, | |
22 | + u32 mask, u32 val); | |
23 | + | |
24 | +int mc13xxx_get_flags(struct mc13xxx *mc13xxx); | |
25 | + | |
26 | +int mc13xxx_irq_request(struct mc13xxx *mc13xxx, int irq, | |
27 | + irq_handler_t handler, const char *name, void *dev); | |
28 | +int mc13xxx_irq_request_nounmask(struct mc13xxx *mc13xxx, int irq, | |
29 | + irq_handler_t handler, const char *name, void *dev); | |
30 | +int mc13xxx_irq_free(struct mc13xxx *mc13xxx, int irq, void *dev); | |
31 | + | |
32 | +int mc13xxx_irq_mask(struct mc13xxx *mc13xxx, int irq); | |
33 | +int mc13xxx_irq_unmask(struct mc13xxx *mc13xxx, int irq); | |
34 | +int mc13xxx_irq_status(struct mc13xxx *mc13xxx, int irq, | |
35 | + int *enabled, int *pending); | |
36 | +int mc13xxx_irq_ack(struct mc13xxx *mc13xxx, int irq); | |
37 | + | |
38 | +int mc13xxx_get_flags(struct mc13xxx *mc13xxx); | |
39 | + | |
40 | +#define MC13XXX_IRQ_ADCDONE 0 | |
41 | +#define MC13XXX_IRQ_ADCBISDONE 1 | |
42 | +#define MC13XXX_IRQ_TS 2 | |
43 | +#define MC13XXX_IRQ_CHGDET 6 | |
44 | +#define MC13XXX_IRQ_CHGREV 8 | |
45 | +#define MC13XXX_IRQ_CHGSHORT 9 | |
46 | +#define MC13XXX_IRQ_CCCV 10 | |
47 | +#define MC13XXX_IRQ_CHGCURR 11 | |
48 | +#define MC13XXX_IRQ_BPON 12 | |
49 | +#define MC13XXX_IRQ_LOBATL 13 | |
50 | +#define MC13XXX_IRQ_LOBATH 14 | |
51 | +#define MC13XXX_IRQ_1HZ 24 | |
52 | +#define MC13XXX_IRQ_TODA 25 | |
53 | +#define MC13XXX_IRQ_SYSRST 30 | |
54 | +#define MC13XXX_IRQ_RTCRST 31 | |
55 | +#define MC13XXX_IRQ_PC 32 | |
56 | +#define MC13XXX_IRQ_WARM 33 | |
57 | +#define MC13XXX_IRQ_MEMHLD 34 | |
58 | +#define MC13XXX_IRQ_THWARNL 36 | |
59 | +#define MC13XXX_IRQ_THWARNH 37 | |
60 | +#define MC13XXX_IRQ_CLK 38 | |
61 | + | |
62 | +#define MC13XXX_NUM_IRQ 46 | |
63 | + | |
64 | +struct regulator_init_data; | |
65 | + | |
66 | +struct mc13xxx_regulator_init_data { | |
67 | + int id; | |
68 | + struct regulator_init_data *init_data; | |
69 | +}; | |
70 | + | |
71 | +struct mc13xxx_regulator_platform_data { | |
72 | + int num_regulators; | |
73 | + struct mc13xxx_regulator_init_data *regulators; | |
74 | +}; | |
75 | + | |
76 | +struct mc13xxx_led_platform_data { | |
77 | +#define MC13783_LED_MD 0 | |
78 | +#define MC13783_LED_AD 1 | |
79 | +#define MC13783_LED_KP 2 | |
80 | +#define MC13783_LED_R1 3 | |
81 | +#define MC13783_LED_G1 4 | |
82 | +#define MC13783_LED_B1 5 | |
83 | +#define MC13783_LED_R2 6 | |
84 | +#define MC13783_LED_G2 7 | |
85 | +#define MC13783_LED_B2 8 | |
86 | +#define MC13783_LED_R3 9 | |
87 | +#define MC13783_LED_G3 10 | |
88 | +#define MC13783_LED_B3 11 | |
89 | +#define MC13783_LED_MAX MC13783_LED_B3 | |
90 | + int id; | |
91 | + const char *name; | |
92 | + const char *default_trigger; | |
93 | + | |
94 | +/* Three or two bits current selection depending on the led */ | |
95 | + char max_current; | |
96 | +}; | |
97 | + | |
98 | +struct mc13xxx_leds_platform_data { | |
99 | + int num_leds; | |
100 | + struct mc13xxx_led_platform_data *led; | |
101 | + | |
102 | +#define MC13783_LED_TRIODE_MD (1 << 0) | |
103 | +#define MC13783_LED_TRIODE_AD (1 << 1) | |
104 | +#define MC13783_LED_TRIODE_KP (1 << 2) | |
105 | +#define MC13783_LED_BOOST_EN (1 << 3) | |
106 | +#define MC13783_LED_TC1HALF (1 << 4) | |
107 | +#define MC13783_LED_SLEWLIMTC (1 << 5) | |
108 | +#define MC13783_LED_SLEWLIMBL (1 << 6) | |
109 | +#define MC13783_LED_TRIODE_TC1 (1 << 7) | |
110 | +#define MC13783_LED_TRIODE_TC2 (1 << 8) | |
111 | +#define MC13783_LED_TRIODE_TC3 (1 << 9) | |
112 | + int flags; | |
113 | + | |
114 | +#define MC13783_LED_AB_DISABLED 0 | |
115 | +#define MC13783_LED_AB_MD1 1 | |
116 | +#define MC13783_LED_AB_MD12 2 | |
117 | +#define MC13783_LED_AB_MD123 3 | |
118 | +#define MC13783_LED_AB_MD1234 4 | |
119 | +#define MC13783_LED_AB_MD1234_AD1 5 | |
120 | +#define MC13783_LED_AB_MD1234_AD12 6 | |
121 | +#define MC13783_LED_AB_MD1_AD 7 | |
122 | + char abmode; | |
123 | + | |
124 | +#define MC13783_LED_ABREF_200MV 0 | |
125 | +#define MC13783_LED_ABREF_400MV 1 | |
126 | +#define MC13783_LED_ABREF_600MV 2 | |
127 | +#define MC13783_LED_ABREF_800MV 3 | |
128 | + char abref; | |
129 | + | |
130 | +#define MC13783_LED_PERIOD_10MS 0 | |
131 | +#define MC13783_LED_PERIOD_100MS 1 | |
132 | +#define MC13783_LED_PERIOD_500MS 2 | |
133 | +#define MC13783_LED_PERIOD_2S 3 | |
134 | + char bl_period; | |
135 | + char tc1_period; | |
136 | + char tc2_period; | |
137 | + char tc3_period; | |
138 | +}; | |
139 | + | |
140 | +struct mc13xxx_platform_data { | |
141 | +#define MC13XXX_USE_TOUCHSCREEN (1 << 0) | |
142 | +#define MC13XXX_USE_CODEC (1 << 1) | |
143 | +#define MC13XXX_USE_ADC (1 << 2) | |
144 | +#define MC13XXX_USE_RTC (1 << 3) | |
145 | +#define MC13XXX_USE_REGULATOR (1 << 4) | |
146 | +#define MC13XXX_USE_LED (1 << 5) | |
147 | + unsigned int flags; | |
148 | + | |
149 | + int num_regulators; | |
150 | + struct mc13xxx_regulator_init_data *regulators; | |
151 | + struct mc13xxx_leds_platform_data *leds; | |
152 | +}; | |
153 | + | |
154 | +#endif /* ifndef __LINUX_MFD_MC13XXX_H */ |