xref: /openbmc/linux/drivers/mfd/mc13xxx-core.c (revision e477e51a)
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