1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright 2009-2010 Pengutronix
4*4882a593Smuzhiyun * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * loosely based on an earlier driver that has
7*4882a593Smuzhiyun * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/of.h>
12*4882a593Smuzhiyun #include <linux/of_device.h>
13*4882a593Smuzhiyun #include <linux/platform_device.h>
14*4882a593Smuzhiyun #include <linux/mfd/core.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include "mc13xxx.h"
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #define MC13XXX_IRQSTAT0 0
19*4882a593Smuzhiyun #define MC13XXX_IRQMASK0 1
20*4882a593Smuzhiyun #define MC13XXX_IRQSTAT1 3
21*4882a593Smuzhiyun #define MC13XXX_IRQMASK1 4
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #define MC13XXX_REVISION 7
24*4882a593Smuzhiyun #define MC13XXX_REVISION_REVMETAL (0x07 << 0)
25*4882a593Smuzhiyun #define MC13XXX_REVISION_REVFULL (0x03 << 3)
26*4882a593Smuzhiyun #define MC13XXX_REVISION_ICID (0x07 << 6)
27*4882a593Smuzhiyun #define MC13XXX_REVISION_FIN (0x03 << 9)
28*4882a593Smuzhiyun #define MC13XXX_REVISION_FAB (0x03 << 11)
29*4882a593Smuzhiyun #define MC13XXX_REVISION_ICIDCODE (0x3f << 13)
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #define MC34708_REVISION_REVMETAL (0x07 << 0)
32*4882a593Smuzhiyun #define MC34708_REVISION_REVFULL (0x07 << 3)
33*4882a593Smuzhiyun #define MC34708_REVISION_FIN (0x07 << 6)
34*4882a593Smuzhiyun #define MC34708_REVISION_FAB (0x07 << 9)
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #define MC13XXX_PWRCTRL 15
37*4882a593Smuzhiyun #define MC13XXX_PWRCTRL_WDIRESET (1 << 12)
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #define MC13XXX_ADC1 44
40*4882a593Smuzhiyun #define MC13XXX_ADC1_ADEN (1 << 0)
41*4882a593Smuzhiyun #define MC13XXX_ADC1_RAND (1 << 1)
42*4882a593Smuzhiyun #define MC13XXX_ADC1_ADSEL (1 << 3)
43*4882a593Smuzhiyun #define MC13XXX_ADC1_ASC (1 << 20)
44*4882a593Smuzhiyun #define MC13XXX_ADC1_ADTRIGIGN (1 << 21)
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun #define MC13XXX_ADC2 45
47*4882a593Smuzhiyun
mc13xxx_lock(struct mc13xxx * mc13xxx)48*4882a593Smuzhiyun void mc13xxx_lock(struct mc13xxx *mc13xxx)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun if (!mutex_trylock(&mc13xxx->lock)) {
51*4882a593Smuzhiyun dev_dbg(mc13xxx->dev, "wait for %s from %ps\n",
52*4882a593Smuzhiyun __func__, __builtin_return_address(0));
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun mutex_lock(&mc13xxx->lock);
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun dev_dbg(mc13xxx->dev, "%s from %ps\n",
57*4882a593Smuzhiyun __func__, __builtin_return_address(0));
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun EXPORT_SYMBOL(mc13xxx_lock);
60*4882a593Smuzhiyun
mc13xxx_unlock(struct mc13xxx * mc13xxx)61*4882a593Smuzhiyun void mc13xxx_unlock(struct mc13xxx *mc13xxx)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun dev_dbg(mc13xxx->dev, "%s from %ps\n",
64*4882a593Smuzhiyun __func__, __builtin_return_address(0));
65*4882a593Smuzhiyun mutex_unlock(&mc13xxx->lock);
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun EXPORT_SYMBOL(mc13xxx_unlock);
68*4882a593Smuzhiyun
mc13xxx_reg_read(struct mc13xxx * mc13xxx,unsigned int offset,u32 * val)69*4882a593Smuzhiyun int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun int ret;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun ret = regmap_read(mc13xxx->regmap, offset, val);
74*4882a593Smuzhiyun dev_vdbg(mc13xxx->dev, "[0x%02x] -> 0x%06x\n", offset, *val);
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun return ret;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun EXPORT_SYMBOL(mc13xxx_reg_read);
79*4882a593Smuzhiyun
mc13xxx_reg_write(struct mc13xxx * mc13xxx,unsigned int offset,u32 val)80*4882a593Smuzhiyun int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun dev_vdbg(mc13xxx->dev, "[0x%02x] <- 0x%06x\n", offset, val);
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun if (val >= BIT(24))
85*4882a593Smuzhiyun return -EINVAL;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun return regmap_write(mc13xxx->regmap, offset, val);
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun EXPORT_SYMBOL(mc13xxx_reg_write);
90*4882a593Smuzhiyun
mc13xxx_reg_rmw(struct mc13xxx * mc13xxx,unsigned int offset,u32 mask,u32 val)91*4882a593Smuzhiyun int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset,
92*4882a593Smuzhiyun u32 mask, u32 val)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun BUG_ON(val & ~mask);
95*4882a593Smuzhiyun dev_vdbg(mc13xxx->dev, "[0x%02x] <- 0x%06x (mask: 0x%06x)\n",
96*4882a593Smuzhiyun offset, val, mask);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun return regmap_update_bits(mc13xxx->regmap, offset, mask, val);
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun EXPORT_SYMBOL(mc13xxx_reg_rmw);
101*4882a593Smuzhiyun
mc13xxx_irq_mask(struct mc13xxx * mc13xxx,int irq)102*4882a593Smuzhiyun int mc13xxx_irq_mask(struct mc13xxx *mc13xxx, int irq)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun int virq = regmap_irq_get_virq(mc13xxx->irq_data, irq);
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun disable_irq_nosync(virq);
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun return 0;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun EXPORT_SYMBOL(mc13xxx_irq_mask);
111*4882a593Smuzhiyun
mc13xxx_irq_unmask(struct mc13xxx * mc13xxx,int irq)112*4882a593Smuzhiyun int mc13xxx_irq_unmask(struct mc13xxx *mc13xxx, int irq)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun int virq = regmap_irq_get_virq(mc13xxx->irq_data, irq);
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun enable_irq(virq);
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun return 0;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun EXPORT_SYMBOL(mc13xxx_irq_unmask);
121*4882a593Smuzhiyun
mc13xxx_irq_status(struct mc13xxx * mc13xxx,int irq,int * enabled,int * pending)122*4882a593Smuzhiyun int mc13xxx_irq_status(struct mc13xxx *mc13xxx, int irq,
123*4882a593Smuzhiyun int *enabled, int *pending)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun int ret;
126*4882a593Smuzhiyun unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1;
127*4882a593Smuzhiyun unsigned int offstat = irq < 24 ? MC13XXX_IRQSTAT0 : MC13XXX_IRQSTAT1;
128*4882a593Smuzhiyun u32 irqbit = 1 << (irq < 24 ? irq : irq - 24);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun if (irq < 0 || irq >= ARRAY_SIZE(mc13xxx->irqs))
131*4882a593Smuzhiyun return -EINVAL;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun if (enabled) {
134*4882a593Smuzhiyun u32 mask;
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun ret = mc13xxx_reg_read(mc13xxx, offmask, &mask);
137*4882a593Smuzhiyun if (ret)
138*4882a593Smuzhiyun return ret;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun *enabled = mask & irqbit;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun if (pending) {
144*4882a593Smuzhiyun u32 stat;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun ret = mc13xxx_reg_read(mc13xxx, offstat, &stat);
147*4882a593Smuzhiyun if (ret)
148*4882a593Smuzhiyun return ret;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun *pending = stat & irqbit;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun return 0;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun EXPORT_SYMBOL(mc13xxx_irq_status);
156*4882a593Smuzhiyun
mc13xxx_irq_request(struct mc13xxx * mc13xxx,int irq,irq_handler_t handler,const char * name,void * dev)157*4882a593Smuzhiyun int mc13xxx_irq_request(struct mc13xxx *mc13xxx, int irq,
158*4882a593Smuzhiyun irq_handler_t handler, const char *name, void *dev)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun int virq = regmap_irq_get_virq(mc13xxx->irq_data, irq);
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun return devm_request_threaded_irq(mc13xxx->dev, virq, NULL, handler,
163*4882a593Smuzhiyun IRQF_ONESHOT, name, dev);
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun EXPORT_SYMBOL(mc13xxx_irq_request);
166*4882a593Smuzhiyun
mc13xxx_irq_free(struct mc13xxx * mc13xxx,int irq,void * dev)167*4882a593Smuzhiyun int mc13xxx_irq_free(struct mc13xxx *mc13xxx, int irq, void *dev)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun int virq = regmap_irq_get_virq(mc13xxx->irq_data, irq);
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun devm_free_irq(mc13xxx->dev, virq, dev);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun return 0;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun EXPORT_SYMBOL(mc13xxx_irq_free);
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun #define maskval(reg, mask) (((reg) & (mask)) >> __ffs(mask))
mc13xxx_print_revision(struct mc13xxx * mc13xxx,u32 revision)178*4882a593Smuzhiyun static void mc13xxx_print_revision(struct mc13xxx *mc13xxx, u32 revision)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun dev_info(mc13xxx->dev, "%s: rev: %d.%d, "
181*4882a593Smuzhiyun "fin: %d, fab: %d, icid: %d/%d\n",
182*4882a593Smuzhiyun mc13xxx->variant->name,
183*4882a593Smuzhiyun maskval(revision, MC13XXX_REVISION_REVFULL),
184*4882a593Smuzhiyun maskval(revision, MC13XXX_REVISION_REVMETAL),
185*4882a593Smuzhiyun maskval(revision, MC13XXX_REVISION_FIN),
186*4882a593Smuzhiyun maskval(revision, MC13XXX_REVISION_FAB),
187*4882a593Smuzhiyun maskval(revision, MC13XXX_REVISION_ICID),
188*4882a593Smuzhiyun maskval(revision, MC13XXX_REVISION_ICIDCODE));
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
mc34708_print_revision(struct mc13xxx * mc13xxx,u32 revision)191*4882a593Smuzhiyun static void mc34708_print_revision(struct mc13xxx *mc13xxx, u32 revision)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun dev_info(mc13xxx->dev, "%s: rev %d.%d, fin: %d, fab: %d\n",
194*4882a593Smuzhiyun mc13xxx->variant->name,
195*4882a593Smuzhiyun maskval(revision, MC34708_REVISION_REVFULL),
196*4882a593Smuzhiyun maskval(revision, MC34708_REVISION_REVMETAL),
197*4882a593Smuzhiyun maskval(revision, MC34708_REVISION_FIN),
198*4882a593Smuzhiyun maskval(revision, MC34708_REVISION_FAB));
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun /* These are only exported for mc13xxx-i2c and mc13xxx-spi */
202*4882a593Smuzhiyun struct mc13xxx_variant mc13xxx_variant_mc13783 = {
203*4882a593Smuzhiyun .name = "mc13783",
204*4882a593Smuzhiyun .print_revision = mc13xxx_print_revision,
205*4882a593Smuzhiyun };
206*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(mc13xxx_variant_mc13783);
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun struct mc13xxx_variant mc13xxx_variant_mc13892 = {
209*4882a593Smuzhiyun .name = "mc13892",
210*4882a593Smuzhiyun .print_revision = mc13xxx_print_revision,
211*4882a593Smuzhiyun };
212*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(mc13xxx_variant_mc13892);
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun struct mc13xxx_variant mc13xxx_variant_mc34708 = {
215*4882a593Smuzhiyun .name = "mc34708",
216*4882a593Smuzhiyun .print_revision = mc34708_print_revision,
217*4882a593Smuzhiyun };
218*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(mc13xxx_variant_mc34708);
219*4882a593Smuzhiyun
mc13xxx_get_chipname(struct mc13xxx * mc13xxx)220*4882a593Smuzhiyun static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun return mc13xxx->variant->name;
223*4882a593Smuzhiyun }
224*4882a593Smuzhiyun
mc13xxx_get_flags(struct mc13xxx * mc13xxx)225*4882a593Smuzhiyun int mc13xxx_get_flags(struct mc13xxx *mc13xxx)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun return mc13xxx->flags;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun EXPORT_SYMBOL(mc13xxx_get_flags);
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun #define MC13XXX_ADC1_CHAN0_SHIFT 5
232*4882a593Smuzhiyun #define MC13XXX_ADC1_CHAN1_SHIFT 8
233*4882a593Smuzhiyun #define MC13783_ADC1_ATO_SHIFT 11
234*4882a593Smuzhiyun #define MC13783_ADC1_ATOX (1 << 19)
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun struct mc13xxx_adcdone_data {
237*4882a593Smuzhiyun struct mc13xxx *mc13xxx;
238*4882a593Smuzhiyun struct completion done;
239*4882a593Smuzhiyun };
240*4882a593Smuzhiyun
mc13xxx_handler_adcdone(int irq,void * data)241*4882a593Smuzhiyun static irqreturn_t mc13xxx_handler_adcdone(int irq, void *data)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun struct mc13xxx_adcdone_data *adcdone_data = data;
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun complete_all(&adcdone_data->done);
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun return IRQ_HANDLED;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun #define MC13XXX_ADC_WORKING (1 << 0)
251*4882a593Smuzhiyun
mc13xxx_adc_do_conversion(struct mc13xxx * mc13xxx,unsigned int mode,unsigned int channel,u8 ato,bool atox,unsigned int * sample)252*4882a593Smuzhiyun int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
253*4882a593Smuzhiyun unsigned int channel, u8 ato, bool atox,
254*4882a593Smuzhiyun unsigned int *sample)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun u32 adc0, adc1, old_adc0;
257*4882a593Smuzhiyun int i, ret;
258*4882a593Smuzhiyun struct mc13xxx_adcdone_data adcdone_data = {
259*4882a593Smuzhiyun .mc13xxx = mc13xxx,
260*4882a593Smuzhiyun };
261*4882a593Smuzhiyun init_completion(&adcdone_data.done);
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun dev_dbg(mc13xxx->dev, "%s\n", __func__);
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun mc13xxx_lock(mc13xxx);
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun if (mc13xxx->adcflags & MC13XXX_ADC_WORKING) {
268*4882a593Smuzhiyun ret = -EBUSY;
269*4882a593Smuzhiyun goto out;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun mc13xxx->adcflags |= MC13XXX_ADC_WORKING;
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun ret = mc13xxx_reg_read(mc13xxx, MC13XXX_ADC0, &old_adc0);
275*4882a593Smuzhiyun if (ret)
276*4882a593Smuzhiyun goto out;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun adc0 = MC13XXX_ADC0_ADINC1 | MC13XXX_ADC0_ADINC2 |
279*4882a593Smuzhiyun MC13XXX_ADC0_CHRGRAWDIV;
280*4882a593Smuzhiyun adc1 = MC13XXX_ADC1_ADEN | MC13XXX_ADC1_ADTRIGIGN | MC13XXX_ADC1_ASC;
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun /*
283*4882a593Smuzhiyun * Channels mapped through ADIN7:
284*4882a593Smuzhiyun * 7 - General purpose ADIN7
285*4882a593Smuzhiyun * 16 - UID
286*4882a593Smuzhiyun * 17 - Die temperature
287*4882a593Smuzhiyun */
288*4882a593Smuzhiyun if (channel > 7 && channel < 16) {
289*4882a593Smuzhiyun adc1 |= MC13XXX_ADC1_ADSEL;
290*4882a593Smuzhiyun } else if (channel == 16) {
291*4882a593Smuzhiyun adc0 |= MC13XXX_ADC0_ADIN7SEL_UID;
292*4882a593Smuzhiyun channel = 7;
293*4882a593Smuzhiyun } else if (channel == 17) {
294*4882a593Smuzhiyun adc0 |= MC13XXX_ADC0_ADIN7SEL_DIE;
295*4882a593Smuzhiyun channel = 7;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun switch (mode) {
299*4882a593Smuzhiyun case MC13XXX_ADC_MODE_TS:
300*4882a593Smuzhiyun adc0 |= MC13XXX_ADC0_ADREFEN | MC13XXX_ADC0_TSMOD0 |
301*4882a593Smuzhiyun MC13XXX_ADC0_TSMOD1;
302*4882a593Smuzhiyun adc1 |= 4 << MC13XXX_ADC1_CHAN1_SHIFT;
303*4882a593Smuzhiyun break;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun case MC13XXX_ADC_MODE_SINGLE_CHAN:
306*4882a593Smuzhiyun adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK;
307*4882a593Smuzhiyun adc1 |= (channel & 0x7) << MC13XXX_ADC1_CHAN0_SHIFT;
308*4882a593Smuzhiyun adc1 |= MC13XXX_ADC1_RAND;
309*4882a593Smuzhiyun break;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun case MC13XXX_ADC_MODE_MULT_CHAN:
312*4882a593Smuzhiyun adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK;
313*4882a593Smuzhiyun adc1 |= 4 << MC13XXX_ADC1_CHAN1_SHIFT;
314*4882a593Smuzhiyun break;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun default:
317*4882a593Smuzhiyun mc13xxx_unlock(mc13xxx);
318*4882a593Smuzhiyun return -EINVAL;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun adc1 |= ato << MC13783_ADC1_ATO_SHIFT;
322*4882a593Smuzhiyun if (atox)
323*4882a593Smuzhiyun adc1 |= MC13783_ADC1_ATOX;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun dev_dbg(mc13xxx->dev, "%s: request irq\n", __func__);
326*4882a593Smuzhiyun ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE,
327*4882a593Smuzhiyun mc13xxx_handler_adcdone, __func__, &adcdone_data);
328*4882a593Smuzhiyun if (ret)
329*4882a593Smuzhiyun goto out;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun mc13xxx_reg_write(mc13xxx, MC13XXX_ADC0, adc0);
332*4882a593Smuzhiyun mc13xxx_reg_write(mc13xxx, MC13XXX_ADC1, adc1);
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun mc13xxx_unlock(mc13xxx);
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun ret = wait_for_completion_interruptible_timeout(&adcdone_data.done, HZ);
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun if (!ret)
339*4882a593Smuzhiyun ret = -ETIMEDOUT;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun mc13xxx_lock(mc13xxx);
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_ADCDONE, &adcdone_data);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun if (ret > 0)
346*4882a593Smuzhiyun for (i = 0; i < 4; ++i) {
347*4882a593Smuzhiyun ret = mc13xxx_reg_read(mc13xxx,
348*4882a593Smuzhiyun MC13XXX_ADC2, &sample[i]);
349*4882a593Smuzhiyun if (ret)
350*4882a593Smuzhiyun break;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun if (mode == MC13XXX_ADC_MODE_TS)
354*4882a593Smuzhiyun /* restore TSMOD */
355*4882a593Smuzhiyun mc13xxx_reg_write(mc13xxx, MC13XXX_ADC0, old_adc0);
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun mc13xxx->adcflags &= ~MC13XXX_ADC_WORKING;
358*4882a593Smuzhiyun out:
359*4882a593Smuzhiyun mc13xxx_unlock(mc13xxx);
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun return ret;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(mc13xxx_adc_do_conversion);
364*4882a593Smuzhiyun
mc13xxx_add_subdevice_pdata(struct mc13xxx * mc13xxx,const char * format,void * pdata,size_t pdata_size)365*4882a593Smuzhiyun static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
366*4882a593Smuzhiyun const char *format, void *pdata, size_t pdata_size)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun char buf[30];
369*4882a593Smuzhiyun const char *name = mc13xxx_get_chipname(mc13xxx);
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun struct mfd_cell cell = {
372*4882a593Smuzhiyun .platform_data = pdata,
373*4882a593Smuzhiyun .pdata_size = pdata_size,
374*4882a593Smuzhiyun };
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun /* there is no asnprintf in the kernel :-( */
377*4882a593Smuzhiyun if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf))
378*4882a593Smuzhiyun return -E2BIG;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun cell.name = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL);
381*4882a593Smuzhiyun if (!cell.name)
382*4882a593Smuzhiyun return -ENOMEM;
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun return mfd_add_devices(mc13xxx->dev, -1, &cell, 1, NULL, 0,
385*4882a593Smuzhiyun regmap_irq_get_domain(mc13xxx->irq_data));
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun
mc13xxx_add_subdevice(struct mc13xxx * mc13xxx,const char * format)388*4882a593Smuzhiyun static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun #ifdef CONFIG_OF
mc13xxx_probe_flags_dt(struct mc13xxx * mc13xxx)394*4882a593Smuzhiyun static int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
395*4882a593Smuzhiyun {
396*4882a593Smuzhiyun struct device_node *np = mc13xxx->dev->of_node;
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun if (!np)
399*4882a593Smuzhiyun return -ENODEV;
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun if (of_property_read_bool(np, "fsl,mc13xxx-uses-adc"))
402*4882a593Smuzhiyun mc13xxx->flags |= MC13XXX_USE_ADC;
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun if (of_property_read_bool(np, "fsl,mc13xxx-uses-codec"))
405*4882a593Smuzhiyun mc13xxx->flags |= MC13XXX_USE_CODEC;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun if (of_property_read_bool(np, "fsl,mc13xxx-uses-rtc"))
408*4882a593Smuzhiyun mc13xxx->flags |= MC13XXX_USE_RTC;
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun if (of_property_read_bool(np, "fsl,mc13xxx-uses-touch"))
411*4882a593Smuzhiyun mc13xxx->flags |= MC13XXX_USE_TOUCHSCREEN;
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun return 0;
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun #else
mc13xxx_probe_flags_dt(struct mc13xxx * mc13xxx)416*4882a593Smuzhiyun static inline int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun return -ENODEV;
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun #endif
421*4882a593Smuzhiyun
mc13xxx_common_init(struct device * dev)422*4882a593Smuzhiyun int mc13xxx_common_init(struct device *dev)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun struct mc13xxx_platform_data *pdata = dev_get_platdata(dev);
425*4882a593Smuzhiyun struct mc13xxx *mc13xxx = dev_get_drvdata(dev);
426*4882a593Smuzhiyun u32 revision;
427*4882a593Smuzhiyun int i, ret;
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun mc13xxx->dev = dev;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision);
432*4882a593Smuzhiyun if (ret)
433*4882a593Smuzhiyun return ret;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun mc13xxx->variant->print_revision(mc13xxx, revision);
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun ret = mc13xxx_reg_rmw(mc13xxx, MC13XXX_PWRCTRL,
438*4882a593Smuzhiyun MC13XXX_PWRCTRL_WDIRESET, MC13XXX_PWRCTRL_WDIRESET);
439*4882a593Smuzhiyun if (ret)
440*4882a593Smuzhiyun return ret;
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(mc13xxx->irqs); i++) {
443*4882a593Smuzhiyun mc13xxx->irqs[i].reg_offset = i / MC13XXX_IRQ_PER_REG;
444*4882a593Smuzhiyun mc13xxx->irqs[i].mask = BIT(i % MC13XXX_IRQ_PER_REG);
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun mc13xxx->irq_chip.name = dev_name(dev);
448*4882a593Smuzhiyun mc13xxx->irq_chip.status_base = MC13XXX_IRQSTAT0;
449*4882a593Smuzhiyun mc13xxx->irq_chip.mask_base = MC13XXX_IRQMASK0;
450*4882a593Smuzhiyun mc13xxx->irq_chip.ack_base = MC13XXX_IRQSTAT0;
451*4882a593Smuzhiyun mc13xxx->irq_chip.irq_reg_stride = MC13XXX_IRQSTAT1 - MC13XXX_IRQSTAT0;
452*4882a593Smuzhiyun mc13xxx->irq_chip.init_ack_masked = true;
453*4882a593Smuzhiyun mc13xxx->irq_chip.use_ack = true;
454*4882a593Smuzhiyun mc13xxx->irq_chip.num_regs = MC13XXX_IRQ_REG_CNT;
455*4882a593Smuzhiyun mc13xxx->irq_chip.irqs = mc13xxx->irqs;
456*4882a593Smuzhiyun mc13xxx->irq_chip.num_irqs = ARRAY_SIZE(mc13xxx->irqs);
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun ret = regmap_add_irq_chip(mc13xxx->regmap, mc13xxx->irq, IRQF_ONESHOT,
459*4882a593Smuzhiyun 0, &mc13xxx->irq_chip, &mc13xxx->irq_data);
460*4882a593Smuzhiyun if (ret)
461*4882a593Smuzhiyun return ret;
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun mutex_init(&mc13xxx->lock);
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun if (mc13xxx_probe_flags_dt(mc13xxx) < 0 && pdata)
466*4882a593Smuzhiyun mc13xxx->flags = pdata->flags;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun if (pdata) {
469*4882a593Smuzhiyun mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
470*4882a593Smuzhiyun &pdata->regulators, sizeof(pdata->regulators));
471*4882a593Smuzhiyun mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
472*4882a593Smuzhiyun pdata->leds, sizeof(*pdata->leds));
473*4882a593Smuzhiyun mc13xxx_add_subdevice_pdata(mc13xxx, "%s-pwrbutton",
474*4882a593Smuzhiyun pdata->buttons, sizeof(*pdata->buttons));
475*4882a593Smuzhiyun if (mc13xxx->flags & MC13XXX_USE_CODEC)
476*4882a593Smuzhiyun mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
477*4882a593Smuzhiyun pdata->codec, sizeof(*pdata->codec));
478*4882a593Smuzhiyun if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
479*4882a593Smuzhiyun mc13xxx_add_subdevice_pdata(mc13xxx, "%s-ts",
480*4882a593Smuzhiyun &pdata->touch, sizeof(pdata->touch));
481*4882a593Smuzhiyun } else {
482*4882a593Smuzhiyun mc13xxx_add_subdevice(mc13xxx, "%s-regulator");
483*4882a593Smuzhiyun mc13xxx_add_subdevice(mc13xxx, "%s-led");
484*4882a593Smuzhiyun mc13xxx_add_subdevice(mc13xxx, "%s-pwrbutton");
485*4882a593Smuzhiyun if (mc13xxx->flags & MC13XXX_USE_CODEC)
486*4882a593Smuzhiyun mc13xxx_add_subdevice(mc13xxx, "%s-codec");
487*4882a593Smuzhiyun if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
488*4882a593Smuzhiyun mc13xxx_add_subdevice(mc13xxx, "%s-ts");
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun if (mc13xxx->flags & MC13XXX_USE_ADC)
492*4882a593Smuzhiyun mc13xxx_add_subdevice(mc13xxx, "%s-adc");
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun if (mc13xxx->flags & MC13XXX_USE_RTC)
495*4882a593Smuzhiyun mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun return 0;
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(mc13xxx_common_init);
500*4882a593Smuzhiyun
mc13xxx_common_exit(struct device * dev)501*4882a593Smuzhiyun int mc13xxx_common_exit(struct device *dev)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun struct mc13xxx *mc13xxx = dev_get_drvdata(dev);
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun mfd_remove_devices(dev);
506*4882a593Smuzhiyun regmap_del_irq_chip(mc13xxx->irq, mc13xxx->irq_data);
507*4882a593Smuzhiyun mutex_destroy(&mc13xxx->lock);
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun return 0;
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(mc13xxx_common_exit);
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun MODULE_DESCRIPTION("Core driver for Freescale MC13XXX PMIC");
514*4882a593Smuzhiyun MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
515*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
516