1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
28e005935SUwe Kleine-König /*
38e005935SUwe Kleine-König * Copyright 2009-2010 Pengutronix
48e005935SUwe Kleine-König * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
58e005935SUwe Kleine-König *
68e005935SUwe Kleine-König * loosely based on an earlier driver that has
78e005935SUwe Kleine-König * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
88e005935SUwe Kleine-König */
98e005935SUwe Kleine-König
108e005935SUwe Kleine-König #include <linux/module.h>
11876989d5SShawn Guo #include <linux/of.h>
12876989d5SShawn Guo #include <linux/of_device.h>
1310f9edaeSAlexander Shiyan #include <linux/platform_device.h>
1410f9edaeSAlexander Shiyan #include <linux/mfd/core.h>
158e005935SUwe Kleine-König
16a0c7c1d4SMarc Reilly #include "mc13xxx.h"
178e005935SUwe Kleine-König
188e005935SUwe Kleine-König #define MC13XXX_IRQSTAT0 0
198e005935SUwe Kleine-König #define MC13XXX_IRQMASK0 1
208e005935SUwe Kleine-König #define MC13XXX_IRQSTAT1 3
218e005935SUwe Kleine-König #define MC13XXX_IRQMASK1 4
228e005935SUwe Kleine-König
238e005935SUwe Kleine-König #define MC13XXX_REVISION 7
248e005935SUwe Kleine-König #define MC13XXX_REVISION_REVMETAL (0x07 << 0)
258e005935SUwe Kleine-König #define MC13XXX_REVISION_REVFULL (0x03 << 3)
268e005935SUwe Kleine-König #define MC13XXX_REVISION_ICID (0x07 << 6)
278e005935SUwe Kleine-König #define MC13XXX_REVISION_FIN (0x03 << 9)
288e005935SUwe Kleine-König #define MC13XXX_REVISION_FAB (0x03 << 11)
298e005935SUwe Kleine-König #define MC13XXX_REVISION_ICIDCODE (0x3f << 13)
308e005935SUwe Kleine-König
310312e024SUwe Kleine-König #define MC34708_REVISION_REVMETAL (0x07 << 0)
320312e024SUwe Kleine-König #define MC34708_REVISION_REVFULL (0x07 << 3)
330312e024SUwe Kleine-König #define MC34708_REVISION_FIN (0x07 << 6)
340312e024SUwe Kleine-König #define MC34708_REVISION_FAB (0x07 << 9)
350312e024SUwe Kleine-König
3634a4958eSMarkus Pargmann #define MC13XXX_PWRCTRL 15
3734a4958eSMarkus Pargmann #define MC13XXX_PWRCTRL_WDIRESET (1 << 12)
3834a4958eSMarkus Pargmann
39fec316d6SUwe Kleine-König #define MC13XXX_ADC1 44
40fec316d6SUwe Kleine-König #define MC13XXX_ADC1_ADEN (1 << 0)
41fec316d6SUwe Kleine-König #define MC13XXX_ADC1_RAND (1 << 1)
42fec316d6SUwe Kleine-König #define MC13XXX_ADC1_ADSEL (1 << 3)
43fec316d6SUwe Kleine-König #define MC13XXX_ADC1_ASC (1 << 20)
44fec316d6SUwe Kleine-König #define MC13XXX_ADC1_ADTRIGIGN (1 << 21)
458e005935SUwe Kleine-König
46fec316d6SUwe Kleine-König #define MC13XXX_ADC2 45
478e005935SUwe Kleine-König
mc13xxx_lock(struct mc13xxx * mc13xxx)488e005935SUwe Kleine-König void mc13xxx_lock(struct mc13xxx *mc13xxx)
498e005935SUwe Kleine-König {
508e005935SUwe Kleine-König if (!mutex_trylock(&mc13xxx->lock)) {
515d5a7bffSScott Wood dev_dbg(mc13xxx->dev, "wait for %s from %ps\n",
528e005935SUwe Kleine-König __func__, __builtin_return_address(0));
538e005935SUwe Kleine-König
548e005935SUwe Kleine-König mutex_lock(&mc13xxx->lock);
558e005935SUwe Kleine-König }
565d5a7bffSScott Wood dev_dbg(mc13xxx->dev, "%s from %ps\n",
578e005935SUwe Kleine-König __func__, __builtin_return_address(0));
588e005935SUwe Kleine-König }
598e005935SUwe Kleine-König EXPORT_SYMBOL(mc13xxx_lock);
608e005935SUwe Kleine-König
mc13xxx_unlock(struct mc13xxx * mc13xxx)618e005935SUwe Kleine-König void mc13xxx_unlock(struct mc13xxx *mc13xxx)
628e005935SUwe Kleine-König {
635d5a7bffSScott Wood dev_dbg(mc13xxx->dev, "%s from %ps\n",
648e005935SUwe Kleine-König __func__, __builtin_return_address(0));
658e005935SUwe Kleine-König mutex_unlock(&mc13xxx->lock);
668e005935SUwe Kleine-König }
678e005935SUwe Kleine-König EXPORT_SYMBOL(mc13xxx_unlock);
688e005935SUwe Kleine-König
mc13xxx_reg_read(struct mc13xxx * mc13xxx,unsigned int offset,u32 * val)698e005935SUwe Kleine-König int mc13xxx_reg_read(struct mc13xxx *mc13xxx, unsigned int offset, u32 *val)
708e005935SUwe Kleine-König {
718e005935SUwe Kleine-König int ret;
728e005935SUwe Kleine-König
7391b5e741SMarc Reilly ret = regmap_read(mc13xxx->regmap, offset, val);
745006fe54SMarc Reilly dev_vdbg(mc13xxx->dev, "[0x%02x] -> 0x%06x\n", offset, *val);
758e005935SUwe Kleine-König
768e005935SUwe Kleine-König return ret;
778e005935SUwe Kleine-König }
788e005935SUwe Kleine-König EXPORT_SYMBOL(mc13xxx_reg_read);
798e005935SUwe Kleine-König
mc13xxx_reg_write(struct mc13xxx * mc13xxx,unsigned int offset,u32 val)808e005935SUwe Kleine-König int mc13xxx_reg_write(struct mc13xxx *mc13xxx, unsigned int offset, u32 val)
818e005935SUwe Kleine-König {
825006fe54SMarc Reilly dev_vdbg(mc13xxx->dev, "[0x%02x] <- 0x%06x\n", offset, val);
838e005935SUwe Kleine-König
84328fe79cSAlexander Shiyan if (val >= BIT(24))
858e005935SUwe Kleine-König return -EINVAL;
868e005935SUwe Kleine-König
8791b5e741SMarc Reilly return regmap_write(mc13xxx->regmap, offset, val);
888e005935SUwe Kleine-König }
898e005935SUwe Kleine-König EXPORT_SYMBOL(mc13xxx_reg_write);
908e005935SUwe Kleine-König
mc13xxx_reg_rmw(struct mc13xxx * mc13xxx,unsigned int offset,u32 mask,u32 val)918e005935SUwe Kleine-König int mc13xxx_reg_rmw(struct mc13xxx *mc13xxx, unsigned int offset,
928e005935SUwe Kleine-König u32 mask, u32 val)
938e005935SUwe Kleine-König {
948e005935SUwe Kleine-König BUG_ON(val & ~mask);
9591b5e741SMarc Reilly dev_vdbg(mc13xxx->dev, "[0x%02x] <- 0x%06x (mask: 0x%06x)\n",
9691b5e741SMarc Reilly offset, val, mask);
978e005935SUwe Kleine-König
9891b5e741SMarc Reilly return regmap_update_bits(mc13xxx->regmap, offset, mask, val);
998e005935SUwe Kleine-König }
1008e005935SUwe Kleine-König EXPORT_SYMBOL(mc13xxx_reg_rmw);
1018e005935SUwe Kleine-König
mc13xxx_irq_mask(struct mc13xxx * mc13xxx,int irq)1028e005935SUwe Kleine-König int mc13xxx_irq_mask(struct mc13xxx *mc13xxx, int irq)
1038e005935SUwe Kleine-König {
10410f9edaeSAlexander Shiyan int virq = regmap_irq_get_virq(mc13xxx->irq_data, irq);
1058e005935SUwe Kleine-König
10610f9edaeSAlexander Shiyan disable_irq_nosync(virq);
1078e005935SUwe Kleine-König
1088e005935SUwe Kleine-König return 0;
1098e005935SUwe Kleine-König }
1108e005935SUwe Kleine-König EXPORT_SYMBOL(mc13xxx_irq_mask);
1118e005935SUwe Kleine-König
mc13xxx_irq_unmask(struct mc13xxx * mc13xxx,int irq)1128e005935SUwe Kleine-König int mc13xxx_irq_unmask(struct mc13xxx *mc13xxx, int irq)
1138e005935SUwe Kleine-König {
11410f9edaeSAlexander Shiyan int virq = regmap_irq_get_virq(mc13xxx->irq_data, irq);
1158e005935SUwe Kleine-König
11610f9edaeSAlexander Shiyan enable_irq(virq);
1178e005935SUwe Kleine-König
1188e005935SUwe Kleine-König return 0;
1198e005935SUwe Kleine-König }
1208e005935SUwe Kleine-König EXPORT_SYMBOL(mc13xxx_irq_unmask);
1218e005935SUwe Kleine-König
mc13xxx_irq_status(struct mc13xxx * mc13xxx,int irq,int * enabled,int * pending)1228e005935SUwe Kleine-König int mc13xxx_irq_status(struct mc13xxx *mc13xxx, int irq,
1238e005935SUwe Kleine-König int *enabled, int *pending)
1248e005935SUwe Kleine-König {
1258e005935SUwe Kleine-König int ret;
1268e005935SUwe Kleine-König unsigned int offmask = irq < 24 ? MC13XXX_IRQMASK0 : MC13XXX_IRQMASK1;
1278e005935SUwe Kleine-König unsigned int offstat = irq < 24 ? MC13XXX_IRQSTAT0 : MC13XXX_IRQSTAT1;
1288e005935SUwe Kleine-König u32 irqbit = 1 << (irq < 24 ? irq : irq - 24);
1298e005935SUwe Kleine-König
13010f9edaeSAlexander Shiyan if (irq < 0 || irq >= ARRAY_SIZE(mc13xxx->irqs))
1318e005935SUwe Kleine-König return -EINVAL;
1328e005935SUwe Kleine-König
1338e005935SUwe Kleine-König if (enabled) {
1348e005935SUwe Kleine-König u32 mask;
1358e005935SUwe Kleine-König
1368e005935SUwe Kleine-König ret = mc13xxx_reg_read(mc13xxx, offmask, &mask);
1378e005935SUwe Kleine-König if (ret)
1388e005935SUwe Kleine-König return ret;
1398e005935SUwe Kleine-König
1408e005935SUwe Kleine-König *enabled = mask & irqbit;
1418e005935SUwe Kleine-König }
1428e005935SUwe Kleine-König
1438e005935SUwe Kleine-König if (pending) {
1448e005935SUwe Kleine-König u32 stat;
1458e005935SUwe Kleine-König
1468e005935SUwe Kleine-König ret = mc13xxx_reg_read(mc13xxx, offstat, &stat);
1478e005935SUwe Kleine-König if (ret)
1488e005935SUwe Kleine-König return ret;
1498e005935SUwe Kleine-König
1508e005935SUwe Kleine-König *pending = stat & irqbit;
1518e005935SUwe Kleine-König }
1528e005935SUwe Kleine-König
1538e005935SUwe Kleine-König return 0;
1548e005935SUwe Kleine-König }
1558e005935SUwe Kleine-König EXPORT_SYMBOL(mc13xxx_irq_status);
1568e005935SUwe Kleine-König
mc13xxx_irq_request(struct mc13xxx * mc13xxx,int irq,irq_handler_t handler,const char * name,void * dev)1578e005935SUwe Kleine-König int mc13xxx_irq_request(struct mc13xxx *mc13xxx, int irq,
1588e005935SUwe Kleine-König irq_handler_t handler, const char *name, void *dev)
1598e005935SUwe Kleine-König {
16010f9edaeSAlexander Shiyan int virq = regmap_irq_get_virq(mc13xxx->irq_data, irq);
1618e005935SUwe Kleine-König
16210f9edaeSAlexander Shiyan return devm_request_threaded_irq(mc13xxx->dev, virq, NULL, handler,
1630b182c28SFabio Estevam IRQF_ONESHOT, name, dev);
1648e005935SUwe Kleine-König }
1658e005935SUwe Kleine-König EXPORT_SYMBOL(mc13xxx_irq_request);
1668e005935SUwe Kleine-König
mc13xxx_irq_free(struct mc13xxx * mc13xxx,int irq,void * dev)1678e005935SUwe Kleine-König int mc13xxx_irq_free(struct mc13xxx *mc13xxx, int irq, void *dev)
1688e005935SUwe Kleine-König {
16910f9edaeSAlexander Shiyan int virq = regmap_irq_get_virq(mc13xxx->irq_data, irq);
1708e005935SUwe Kleine-König
17110f9edaeSAlexander Shiyan devm_free_irq(mc13xxx->dev, virq, dev);
1728e005935SUwe Kleine-König
1738e005935SUwe Kleine-König return 0;
1748e005935SUwe Kleine-König }
1758e005935SUwe Kleine-König EXPORT_SYMBOL(mc13xxx_irq_free);
1768e005935SUwe Kleine-König
1778e005935SUwe Kleine-König #define maskval(reg, mask) (((reg) & (mask)) >> __ffs(mask))
mc13xxx_print_revision(struct mc13xxx * mc13xxx,u32 revision)178cd0f34b0SUwe Kleine-König static void mc13xxx_print_revision(struct mc13xxx *mc13xxx, u32 revision)
1798e005935SUwe Kleine-König {
1805006fe54SMarc Reilly dev_info(mc13xxx->dev, "%s: rev: %d.%d, "
1818e005935SUwe Kleine-König "fin: %d, fab: %d, icid: %d/%d\n",
182cd0f34b0SUwe Kleine-König mc13xxx->variant->name,
1838e005935SUwe Kleine-König maskval(revision, MC13XXX_REVISION_REVFULL),
1848e005935SUwe Kleine-König maskval(revision, MC13XXX_REVISION_REVMETAL),
1858e005935SUwe Kleine-König maskval(revision, MC13XXX_REVISION_FIN),
1868e005935SUwe Kleine-König maskval(revision, MC13XXX_REVISION_FAB),
1878e005935SUwe Kleine-König maskval(revision, MC13XXX_REVISION_ICID),
1888e005935SUwe Kleine-König maskval(revision, MC13XXX_REVISION_ICIDCODE));
1898e005935SUwe Kleine-König }
1908e005935SUwe Kleine-König
mc34708_print_revision(struct mc13xxx * mc13xxx,u32 revision)1910312e024SUwe Kleine-König static void mc34708_print_revision(struct mc13xxx *mc13xxx, u32 revision)
1920312e024SUwe Kleine-König {
1930312e024SUwe Kleine-König dev_info(mc13xxx->dev, "%s: rev %d.%d, fin: %d, fab: %d\n",
1940312e024SUwe Kleine-König mc13xxx->variant->name,
1950312e024SUwe Kleine-König maskval(revision, MC34708_REVISION_REVFULL),
1960312e024SUwe Kleine-König maskval(revision, MC34708_REVISION_REVMETAL),
1970312e024SUwe Kleine-König maskval(revision, MC34708_REVISION_FIN),
1980312e024SUwe Kleine-König maskval(revision, MC34708_REVISION_FAB));
1990312e024SUwe Kleine-König }
2000312e024SUwe Kleine-König
201cd0f34b0SUwe Kleine-König /* These are only exported for mc13xxx-i2c and mc13xxx-spi */
202cd0f34b0SUwe Kleine-König struct mc13xxx_variant mc13xxx_variant_mc13783 = {
203cd0f34b0SUwe Kleine-König .name = "mc13783",
204cd0f34b0SUwe Kleine-König .print_revision = mc13xxx_print_revision,
205cd0f34b0SUwe Kleine-König };
206cd0f34b0SUwe Kleine-König EXPORT_SYMBOL_GPL(mc13xxx_variant_mc13783);
207cd0f34b0SUwe Kleine-König
208cd0f34b0SUwe Kleine-König struct mc13xxx_variant mc13xxx_variant_mc13892 = {
209cd0f34b0SUwe Kleine-König .name = "mc13892",
210cd0f34b0SUwe Kleine-König .print_revision = mc13xxx_print_revision,
211cd0f34b0SUwe Kleine-König };
212cd0f34b0SUwe Kleine-König EXPORT_SYMBOL_GPL(mc13xxx_variant_mc13892);
2138e005935SUwe Kleine-König
2140312e024SUwe Kleine-König struct mc13xxx_variant mc13xxx_variant_mc34708 = {
2150312e024SUwe Kleine-König .name = "mc34708",
2160312e024SUwe Kleine-König .print_revision = mc34708_print_revision,
2170312e024SUwe Kleine-König };
2180312e024SUwe Kleine-König EXPORT_SYMBOL_GPL(mc13xxx_variant_mc34708);
2190312e024SUwe Kleine-König
mc13xxx_get_chipname(struct mc13xxx * mc13xxx)2208e005935SUwe Kleine-König static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx)
2218e005935SUwe Kleine-König {
222cd0f34b0SUwe Kleine-König return mc13xxx->variant->name;
2238e005935SUwe Kleine-König }
2248e005935SUwe Kleine-König
mc13xxx_get_flags(struct mc13xxx * mc13xxx)2258e005935SUwe Kleine-König int mc13xxx_get_flags(struct mc13xxx *mc13xxx)
2268e005935SUwe Kleine-König {
227876989d5SShawn Guo return mc13xxx->flags;
2288e005935SUwe Kleine-König }
2298e005935SUwe Kleine-König EXPORT_SYMBOL(mc13xxx_get_flags);
2308e005935SUwe Kleine-König
231fec316d6SUwe Kleine-König #define MC13XXX_ADC1_CHAN0_SHIFT 5
232fec316d6SUwe Kleine-König #define MC13XXX_ADC1_CHAN1_SHIFT 8
2331039d762SMichael Thalmeier #define MC13783_ADC1_ATO_SHIFT 11
2341039d762SMichael Thalmeier #define MC13783_ADC1_ATOX (1 << 19)
2358e005935SUwe Kleine-König
2368e005935SUwe Kleine-König struct mc13xxx_adcdone_data {
2378e005935SUwe Kleine-König struct mc13xxx *mc13xxx;
2388e005935SUwe Kleine-König struct completion done;
2398e005935SUwe Kleine-König };
2408e005935SUwe Kleine-König
mc13xxx_handler_adcdone(int irq,void * data)241fec316d6SUwe Kleine-König static irqreturn_t mc13xxx_handler_adcdone(int irq, void *data)
2428e005935SUwe Kleine-König {
2438e005935SUwe Kleine-König struct mc13xxx_adcdone_data *adcdone_data = data;
2448e005935SUwe Kleine-König
2458e005935SUwe Kleine-König complete_all(&adcdone_data->done);
2468e005935SUwe Kleine-König
2478e005935SUwe Kleine-König return IRQ_HANDLED;
2488e005935SUwe Kleine-König }
2498e005935SUwe Kleine-König
250fec316d6SUwe Kleine-König #define MC13XXX_ADC_WORKING (1 << 0)
2518e005935SUwe Kleine-König
mc13xxx_adc_do_conversion(struct mc13xxx * mc13xxx,unsigned int mode,unsigned int channel,u8 ato,bool atox,unsigned int * sample)252fec316d6SUwe Kleine-König int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
2531039d762SMichael Thalmeier unsigned int channel, u8 ato, bool atox,
2541039d762SMichael Thalmeier unsigned int *sample)
2558e005935SUwe Kleine-König {
2568e005935SUwe Kleine-König u32 adc0, adc1, old_adc0;
2578e005935SUwe Kleine-König int i, ret;
2588e005935SUwe Kleine-König struct mc13xxx_adcdone_data adcdone_data = {
2598e005935SUwe Kleine-König .mc13xxx = mc13xxx,
2608e005935SUwe Kleine-König };
2618e005935SUwe Kleine-König init_completion(&adcdone_data.done);
2628e005935SUwe Kleine-König
2635006fe54SMarc Reilly dev_dbg(mc13xxx->dev, "%s\n", __func__);
2648e005935SUwe Kleine-König
2658e005935SUwe Kleine-König mc13xxx_lock(mc13xxx);
2668e005935SUwe Kleine-König
267fec316d6SUwe Kleine-König if (mc13xxx->adcflags & MC13XXX_ADC_WORKING) {
2688e005935SUwe Kleine-König ret = -EBUSY;
2698e005935SUwe Kleine-König goto out;
2708e005935SUwe Kleine-König }
2718e005935SUwe Kleine-König
272fec316d6SUwe Kleine-König mc13xxx->adcflags |= MC13XXX_ADC_WORKING;
2738e005935SUwe Kleine-König
2749e28989dSKangjie Lu ret = mc13xxx_reg_read(mc13xxx, MC13XXX_ADC0, &old_adc0);
2759e28989dSKangjie Lu if (ret)
2769e28989dSKangjie Lu goto out;
2778e005935SUwe Kleine-König
27855143439SFabio Estevam adc0 = MC13XXX_ADC0_ADINC1 | MC13XXX_ADC0_ADINC2 |
27955143439SFabio Estevam MC13XXX_ADC0_CHRGRAWDIV;
280fec316d6SUwe Kleine-König adc1 = MC13XXX_ADC1_ADEN | MC13XXX_ADC1_ADTRIGIGN | MC13XXX_ADC1_ASC;
2818e005935SUwe Kleine-König
282ed645cccSAndrey Gusakov /*
283ed645cccSAndrey Gusakov * Channels mapped through ADIN7:
284ed645cccSAndrey Gusakov * 7 - General purpose ADIN7
285ed645cccSAndrey Gusakov * 16 - UID
286ed645cccSAndrey Gusakov * 17 - Die temperature
287ed645cccSAndrey Gusakov */
288ed645cccSAndrey Gusakov if (channel > 7 && channel < 16) {
289fec316d6SUwe Kleine-König adc1 |= MC13XXX_ADC1_ADSEL;
290ed645cccSAndrey Gusakov } else if (channel == 16) {
291ed645cccSAndrey Gusakov adc0 |= MC13XXX_ADC0_ADIN7SEL_UID;
292ed645cccSAndrey Gusakov channel = 7;
293ed645cccSAndrey Gusakov } else if (channel == 17) {
294ed645cccSAndrey Gusakov adc0 |= MC13XXX_ADC0_ADIN7SEL_DIE;
295ed645cccSAndrey Gusakov channel = 7;
296ed645cccSAndrey Gusakov }
2978e005935SUwe Kleine-König
2988e005935SUwe Kleine-König switch (mode) {
299fec316d6SUwe Kleine-König case MC13XXX_ADC_MODE_TS:
300fec316d6SUwe Kleine-König adc0 |= MC13XXX_ADC0_ADREFEN | MC13XXX_ADC0_TSMOD0 |
301fec316d6SUwe Kleine-König MC13XXX_ADC0_TSMOD1;
302fec316d6SUwe Kleine-König adc1 |= 4 << MC13XXX_ADC1_CHAN1_SHIFT;
3038e005935SUwe Kleine-König break;
3048e005935SUwe Kleine-König
305fec316d6SUwe Kleine-König case MC13XXX_ADC_MODE_SINGLE_CHAN:
3062161891aSRobin van der Gracht adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK;
307fec316d6SUwe Kleine-König adc1 |= (channel & 0x7) << MC13XXX_ADC1_CHAN0_SHIFT;
308fec316d6SUwe Kleine-König adc1 |= MC13XXX_ADC1_RAND;
3098e005935SUwe Kleine-König break;
3108e005935SUwe Kleine-König
311fec316d6SUwe Kleine-König case MC13XXX_ADC_MODE_MULT_CHAN:
3122161891aSRobin van der Gracht adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK;
313fec316d6SUwe Kleine-König adc1 |= 4 << MC13XXX_ADC1_CHAN1_SHIFT;
3148e005935SUwe Kleine-König break;
3158e005935SUwe Kleine-König
3168e005935SUwe Kleine-König default:
317fec316d6SUwe Kleine-König mc13xxx_unlock(mc13xxx);
3188e005935SUwe Kleine-König return -EINVAL;
3198e005935SUwe Kleine-König }
3208e005935SUwe Kleine-König
3211039d762SMichael Thalmeier adc1 |= ato << MC13783_ADC1_ATO_SHIFT;
3221039d762SMichael Thalmeier if (atox)
3231039d762SMichael Thalmeier adc1 |= MC13783_ADC1_ATOX;
3245006fe54SMarc Reilly
3255006fe54SMarc Reilly dev_dbg(mc13xxx->dev, "%s: request irq\n", __func__);
326*e477e51aSJiasheng Jiang ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE,
327fec316d6SUwe Kleine-König mc13xxx_handler_adcdone, __func__, &adcdone_data);
328*e477e51aSJiasheng Jiang if (ret)
329*e477e51aSJiasheng Jiang goto out;
3308e005935SUwe Kleine-König
331fec316d6SUwe Kleine-König mc13xxx_reg_write(mc13xxx, MC13XXX_ADC0, adc0);
332fec316d6SUwe Kleine-König mc13xxx_reg_write(mc13xxx, MC13XXX_ADC1, adc1);
3338e005935SUwe Kleine-König
3348e005935SUwe Kleine-König mc13xxx_unlock(mc13xxx);
3358e005935SUwe Kleine-König
3368e005935SUwe Kleine-König ret = wait_for_completion_interruptible_timeout(&adcdone_data.done, HZ);
3378e005935SUwe Kleine-König
3388e005935SUwe Kleine-König if (!ret)
3398e005935SUwe Kleine-König ret = -ETIMEDOUT;
3408e005935SUwe Kleine-König
3418e005935SUwe Kleine-König mc13xxx_lock(mc13xxx);
3428e005935SUwe Kleine-König
343fec316d6SUwe Kleine-König mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_ADCDONE, &adcdone_data);
3448e005935SUwe Kleine-König
3458e005935SUwe Kleine-König if (ret > 0)
3468e005935SUwe Kleine-König for (i = 0; i < 4; ++i) {
3478e005935SUwe Kleine-König ret = mc13xxx_reg_read(mc13xxx,
348fec316d6SUwe Kleine-König MC13XXX_ADC2, &sample[i]);
3498e005935SUwe Kleine-König if (ret)
3508e005935SUwe Kleine-König break;
3518e005935SUwe Kleine-König }
3528e005935SUwe Kleine-König
353fec316d6SUwe Kleine-König if (mode == MC13XXX_ADC_MODE_TS)
3548e005935SUwe Kleine-König /* restore TSMOD */
355fec316d6SUwe Kleine-König mc13xxx_reg_write(mc13xxx, MC13XXX_ADC0, old_adc0);
3568e005935SUwe Kleine-König
357fec316d6SUwe Kleine-König mc13xxx->adcflags &= ~MC13XXX_ADC_WORKING;
3588e005935SUwe Kleine-König out:
3598e005935SUwe Kleine-König mc13xxx_unlock(mc13xxx);
3608e005935SUwe Kleine-König
3618e005935SUwe Kleine-König return ret;
3628e005935SUwe Kleine-König }
363fec316d6SUwe Kleine-König EXPORT_SYMBOL_GPL(mc13xxx_adc_do_conversion);
3648e005935SUwe Kleine-König
mc13xxx_add_subdevice_pdata(struct mc13xxx * mc13xxx,const char * format,void * pdata,size_t pdata_size)3658e005935SUwe Kleine-König static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
366c8a03c96SSamuel Ortiz const char *format, void *pdata, size_t pdata_size)
3678e005935SUwe Kleine-König {
3688e005935SUwe Kleine-König char buf[30];
3698e005935SUwe Kleine-König const char *name = mc13xxx_get_chipname(mc13xxx);
3708e005935SUwe Kleine-König
3718e005935SUwe Kleine-König struct mfd_cell cell = {
372c8a03c96SSamuel Ortiz .platform_data = pdata,
373c8a03c96SSamuel Ortiz .pdata_size = pdata_size,
3748e005935SUwe Kleine-König };
3758e005935SUwe Kleine-König
3768e005935SUwe Kleine-König /* there is no asnprintf in the kernel :-( */
3778e005935SUwe Kleine-König if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf))
3788e005935SUwe Kleine-König return -E2BIG;
3798e005935SUwe Kleine-König
3808e005935SUwe Kleine-König cell.name = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL);
3818e005935SUwe Kleine-König if (!cell.name)
3828e005935SUwe Kleine-König return -ENOMEM;
3838e005935SUwe Kleine-König
38410f9edaeSAlexander Shiyan return mfd_add_devices(mc13xxx->dev, -1, &cell, 1, NULL, 0,
38510f9edaeSAlexander Shiyan regmap_irq_get_domain(mc13xxx->irq_data));
3868e005935SUwe Kleine-König }
3878e005935SUwe Kleine-König
mc13xxx_add_subdevice(struct mc13xxx * mc13xxx,const char * format)3888e005935SUwe Kleine-König static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
3898e005935SUwe Kleine-König {
390c8a03c96SSamuel Ortiz return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
3918e005935SUwe Kleine-König }
3928e005935SUwe Kleine-König
393876989d5SShawn Guo #ifdef CONFIG_OF
mc13xxx_probe_flags_dt(struct mc13xxx * mc13xxx)394876989d5SShawn Guo static int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
395876989d5SShawn Guo {
39691b5e741SMarc Reilly struct device_node *np = mc13xxx->dev->of_node;
397876989d5SShawn Guo
398876989d5SShawn Guo if (!np)
399876989d5SShawn Guo return -ENODEV;
400876989d5SShawn Guo
401505b9e57SSaurabh Sengar if (of_property_read_bool(np, "fsl,mc13xxx-uses-adc"))
402876989d5SShawn Guo mc13xxx->flags |= MC13XXX_USE_ADC;
403876989d5SShawn Guo
404505b9e57SSaurabh Sengar if (of_property_read_bool(np, "fsl,mc13xxx-uses-codec"))
405876989d5SShawn Guo mc13xxx->flags |= MC13XXX_USE_CODEC;
406876989d5SShawn Guo
407505b9e57SSaurabh Sengar if (of_property_read_bool(np, "fsl,mc13xxx-uses-rtc"))
408876989d5SShawn Guo mc13xxx->flags |= MC13XXX_USE_RTC;
409876989d5SShawn Guo
410505b9e57SSaurabh Sengar if (of_property_read_bool(np, "fsl,mc13xxx-uses-touch"))
411876989d5SShawn Guo mc13xxx->flags |= MC13XXX_USE_TOUCHSCREEN;
412876989d5SShawn Guo
413876989d5SShawn Guo return 0;
414876989d5SShawn Guo }
415876989d5SShawn Guo #else
mc13xxx_probe_flags_dt(struct mc13xxx * mc13xxx)416876989d5SShawn Guo static inline int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
417876989d5SShawn Guo {
418876989d5SShawn Guo return -ENODEV;
419876989d5SShawn Guo }
420876989d5SShawn Guo #endif
421876989d5SShawn Guo
mc13xxx_common_init(struct device * dev)422db9ef449SAlexander Shiyan int mc13xxx_common_init(struct device *dev)
423876989d5SShawn Guo {
424db9ef449SAlexander Shiyan struct mc13xxx_platform_data *pdata = dev_get_platdata(dev);
425db9ef449SAlexander Shiyan struct mc13xxx *mc13xxx = dev_get_drvdata(dev);
426cd0f34b0SUwe Kleine-König u32 revision;
42710f9edaeSAlexander Shiyan int i, ret;
4288e005935SUwe Kleine-König
429db9ef449SAlexander Shiyan mc13xxx->dev = dev;
4308e005935SUwe Kleine-König
431cd0f34b0SUwe Kleine-König ret = mc13xxx_reg_read(mc13xxx, MC13XXX_REVISION, &revision);
4325006fe54SMarc Reilly if (ret)
433db9ef449SAlexander Shiyan return ret;
4348e005935SUwe Kleine-König
435cd0f34b0SUwe Kleine-König mc13xxx->variant->print_revision(mc13xxx, revision);
436cd0f34b0SUwe Kleine-König
43734a4958eSMarkus Pargmann ret = mc13xxx_reg_rmw(mc13xxx, MC13XXX_PWRCTRL,
43834a4958eSMarkus Pargmann MC13XXX_PWRCTRL_WDIRESET, MC13XXX_PWRCTRL_WDIRESET);
43934a4958eSMarkus Pargmann if (ret)
44034a4958eSMarkus Pargmann return ret;
44134a4958eSMarkus Pargmann
44210f9edaeSAlexander Shiyan for (i = 0; i < ARRAY_SIZE(mc13xxx->irqs); i++) {
44310f9edaeSAlexander Shiyan mc13xxx->irqs[i].reg_offset = i / MC13XXX_IRQ_PER_REG;
44410f9edaeSAlexander Shiyan mc13xxx->irqs[i].mask = BIT(i % MC13XXX_IRQ_PER_REG);
44510f9edaeSAlexander Shiyan }
4468e005935SUwe Kleine-König
44710f9edaeSAlexander Shiyan mc13xxx->irq_chip.name = dev_name(dev);
44810f9edaeSAlexander Shiyan mc13xxx->irq_chip.status_base = MC13XXX_IRQSTAT0;
44910f9edaeSAlexander Shiyan mc13xxx->irq_chip.mask_base = MC13XXX_IRQMASK0;
45010f9edaeSAlexander Shiyan mc13xxx->irq_chip.ack_base = MC13XXX_IRQSTAT0;
45110f9edaeSAlexander Shiyan mc13xxx->irq_chip.irq_reg_stride = MC13XXX_IRQSTAT1 - MC13XXX_IRQSTAT0;
45210f9edaeSAlexander Shiyan mc13xxx->irq_chip.init_ack_masked = true;
45310f9edaeSAlexander Shiyan mc13xxx->irq_chip.use_ack = true;
45410f9edaeSAlexander Shiyan mc13xxx->irq_chip.num_regs = MC13XXX_IRQ_REG_CNT;
45510f9edaeSAlexander Shiyan mc13xxx->irq_chip.irqs = mc13xxx->irqs;
45610f9edaeSAlexander Shiyan mc13xxx->irq_chip.num_irqs = ARRAY_SIZE(mc13xxx->irqs);
45710f9edaeSAlexander Shiyan
45810f9edaeSAlexander Shiyan ret = regmap_add_irq_chip(mc13xxx->regmap, mc13xxx->irq, IRQF_ONESHOT,
45910f9edaeSAlexander Shiyan 0, &mc13xxx->irq_chip, &mc13xxx->irq_data);
4608e005935SUwe Kleine-König if (ret)
4618e005935SUwe Kleine-König return ret;
4628e005935SUwe Kleine-König
46348ca9a52SFabio Estevam mutex_init(&mc13xxx->lock);
46448ca9a52SFabio Estevam
465876989d5SShawn Guo if (mc13xxx_probe_flags_dt(mc13xxx) < 0 && pdata)
466876989d5SShawn Guo mc13xxx->flags = pdata->flags;
467876989d5SShawn Guo
468876989d5SShawn Guo if (pdata) {
469876989d5SShawn Guo mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
470876989d5SShawn Guo &pdata->regulators, sizeof(pdata->regulators));
471c8a03c96SSamuel Ortiz mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
472c8a03c96SSamuel Ortiz pdata->leds, sizeof(*pdata->leds));
47330fc7ac3SPhilippe Rétornaz mc13xxx_add_subdevice_pdata(mc13xxx, "%s-pwrbutton",
47430fc7ac3SPhilippe Rétornaz pdata->buttons, sizeof(*pdata->buttons));
475a2ff8459SAlexander Shiyan if (mc13xxx->flags & MC13XXX_USE_CODEC)
476a2ff8459SAlexander Shiyan mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
477a2ff8459SAlexander Shiyan pdata->codec, sizeof(*pdata->codec));
478a2ff8459SAlexander Shiyan if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
479a2ff8459SAlexander Shiyan mc13xxx_add_subdevice_pdata(mc13xxx, "%s-ts",
480a2ff8459SAlexander Shiyan &pdata->touch, sizeof(pdata->touch));
481876989d5SShawn Guo } else {
482876989d5SShawn Guo mc13xxx_add_subdevice(mc13xxx, "%s-regulator");
483876989d5SShawn Guo mc13xxx_add_subdevice(mc13xxx, "%s-led");
484876989d5SShawn Guo mc13xxx_add_subdevice(mc13xxx, "%s-pwrbutton");
485a2ff8459SAlexander Shiyan if (mc13xxx->flags & MC13XXX_USE_CODEC)
486a2ff8459SAlexander Shiyan mc13xxx_add_subdevice(mc13xxx, "%s-codec");
487a2ff8459SAlexander Shiyan if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
488a2ff8459SAlexander Shiyan mc13xxx_add_subdevice(mc13xxx, "%s-ts");
489876989d5SShawn Guo }
49030fc7ac3SPhilippe Rétornaz
49110f9edaeSAlexander Shiyan if (mc13xxx->flags & MC13XXX_USE_ADC)
49210f9edaeSAlexander Shiyan mc13xxx_add_subdevice(mc13xxx, "%s-adc");
49310f9edaeSAlexander Shiyan
49410f9edaeSAlexander Shiyan if (mc13xxx->flags & MC13XXX_USE_RTC)
49510f9edaeSAlexander Shiyan mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
49610f9edaeSAlexander Shiyan
4978e005935SUwe Kleine-König return 0;
4988e005935SUwe Kleine-König }
499a0c7c1d4SMarc Reilly EXPORT_SYMBOL_GPL(mc13xxx_common_init);
5008e005935SUwe Kleine-König
mc13xxx_common_exit(struct device * dev)501c39cf60fSUwe Kleine-König void mc13xxx_common_exit(struct device *dev)
5028e005935SUwe Kleine-König {
503db9ef449SAlexander Shiyan struct mc13xxx *mc13xxx = dev_get_drvdata(dev);
5048e005935SUwe Kleine-König
505db9ef449SAlexander Shiyan mfd_remove_devices(dev);
50610f9edaeSAlexander Shiyan regmap_del_irq_chip(mc13xxx->irq, mc13xxx->irq_data);
507db9ef449SAlexander Shiyan mutex_destroy(&mc13xxx->lock);
5088e005935SUwe Kleine-König }
509db9ef449SAlexander Shiyan EXPORT_SYMBOL_GPL(mc13xxx_common_exit);
5108e005935SUwe Kleine-König
5118e005935SUwe Kleine-König MODULE_DESCRIPTION("Core driver for Freescale MC13XXX PMIC");
5128e005935SUwe Kleine-König MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
5138e005935SUwe Kleine-König MODULE_LICENSE("GPL v2");
514