xref: /openbmc/linux/drivers/mfd/palmas.c (revision 4124e6e2)
12945fbc2SGraeme Gregory /*
22945fbc2SGraeme Gregory  * TI Palmas MFD Driver
32945fbc2SGraeme Gregory  *
42945fbc2SGraeme Gregory  * Copyright 2011-2012 Texas Instruments Inc.
52945fbc2SGraeme Gregory  *
62945fbc2SGraeme Gregory  * Author: Graeme Gregory <gg@slimlogic.co.uk>
72945fbc2SGraeme Gregory  *
82945fbc2SGraeme Gregory  *  This program is free software; you can redistribute it and/or modify it
92945fbc2SGraeme Gregory  *  under  the terms of the GNU General  Public License as published by the
102945fbc2SGraeme Gregory  *  Free Software Foundation;  either version 2 of the License, or (at your
112945fbc2SGraeme Gregory  *  option) any later version.
122945fbc2SGraeme Gregory  *
132945fbc2SGraeme Gregory  */
142945fbc2SGraeme Gregory 
152945fbc2SGraeme Gregory #include <linux/module.h>
162945fbc2SGraeme Gregory #include <linux/moduleparam.h>
172945fbc2SGraeme Gregory #include <linux/init.h>
182945fbc2SGraeme Gregory #include <linux/slab.h>
192945fbc2SGraeme Gregory #include <linux/i2c.h>
202945fbc2SGraeme Gregory #include <linux/interrupt.h>
212945fbc2SGraeme Gregory #include <linux/irq.h>
222945fbc2SGraeme Gregory #include <linux/regmap.h>
232945fbc2SGraeme Gregory #include <linux/err.h>
242945fbc2SGraeme Gregory #include <linux/mfd/core.h>
252945fbc2SGraeme Gregory #include <linux/mfd/palmas.h>
261ffb0be3SJ Keerthy #include <linux/of_device.h>
272945fbc2SGraeme Gregory 
282945fbc2SGraeme Gregory static const struct regmap_config palmas_regmap_config[PALMAS_NUM_CLIENTS] = {
292945fbc2SGraeme Gregory 	{
302945fbc2SGraeme Gregory 		.reg_bits = 8,
312945fbc2SGraeme Gregory 		.val_bits = 8,
322945fbc2SGraeme Gregory 		.max_register = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
332945fbc2SGraeme Gregory 					PALMAS_PRIMARY_SECONDARY_PAD3),
342945fbc2SGraeme Gregory 	},
352945fbc2SGraeme Gregory 	{
362945fbc2SGraeme Gregory 		.reg_bits = 8,
372945fbc2SGraeme Gregory 		.val_bits = 8,
382945fbc2SGraeme Gregory 		.max_register = PALMAS_BASE_TO_REG(PALMAS_GPADC_BASE,
392945fbc2SGraeme Gregory 					PALMAS_GPADC_SMPS_VSEL_MONITORING),
402945fbc2SGraeme Gregory 	},
412945fbc2SGraeme Gregory 	{
422945fbc2SGraeme Gregory 		.reg_bits = 8,
432945fbc2SGraeme Gregory 		.val_bits = 8,
442945fbc2SGraeme Gregory 		.max_register = PALMAS_BASE_TO_REG(PALMAS_TRIM_GPADC_BASE,
452945fbc2SGraeme Gregory 					PALMAS_GPADC_TRIM16),
462945fbc2SGraeme Gregory 	},
472945fbc2SGraeme Gregory };
482945fbc2SGraeme Gregory 
492945fbc2SGraeme Gregory static const struct regmap_irq palmas_irqs[] = {
502945fbc2SGraeme Gregory 	/* INT1 IRQs */
512945fbc2SGraeme Gregory 	[PALMAS_CHARG_DET_N_VBUS_OVV_IRQ] = {
522945fbc2SGraeme Gregory 		.mask = PALMAS_INT1_STATUS_CHARG_DET_N_VBUS_OVV,
532945fbc2SGraeme Gregory 	},
542945fbc2SGraeme Gregory 	[PALMAS_PWRON_IRQ] = {
552945fbc2SGraeme Gregory 		.mask = PALMAS_INT1_STATUS_PWRON,
562945fbc2SGraeme Gregory 	},
572945fbc2SGraeme Gregory 	[PALMAS_LONG_PRESS_KEY_IRQ] = {
582945fbc2SGraeme Gregory 		.mask = PALMAS_INT1_STATUS_LONG_PRESS_KEY,
592945fbc2SGraeme Gregory 	},
602945fbc2SGraeme Gregory 	[PALMAS_RPWRON_IRQ] = {
612945fbc2SGraeme Gregory 		.mask = PALMAS_INT1_STATUS_RPWRON,
622945fbc2SGraeme Gregory 	},
632945fbc2SGraeme Gregory 	[PALMAS_PWRDOWN_IRQ] = {
642945fbc2SGraeme Gregory 		.mask = PALMAS_INT1_STATUS_PWRDOWN,
652945fbc2SGraeme Gregory 	},
662945fbc2SGraeme Gregory 	[PALMAS_HOTDIE_IRQ] = {
672945fbc2SGraeme Gregory 		.mask = PALMAS_INT1_STATUS_HOTDIE,
682945fbc2SGraeme Gregory 	},
692945fbc2SGraeme Gregory 	[PALMAS_VSYS_MON_IRQ] = {
702945fbc2SGraeme Gregory 		.mask = PALMAS_INT1_STATUS_VSYS_MON,
712945fbc2SGraeme Gregory 	},
722945fbc2SGraeme Gregory 	[PALMAS_VBAT_MON_IRQ] = {
732945fbc2SGraeme Gregory 		.mask = PALMAS_INT1_STATUS_VBAT_MON,
742945fbc2SGraeme Gregory 	},
752945fbc2SGraeme Gregory 	/* INT2 IRQs*/
762945fbc2SGraeme Gregory 	[PALMAS_RTC_ALARM_IRQ] = {
772945fbc2SGraeme Gregory 		.mask = PALMAS_INT2_STATUS_RTC_ALARM,
782945fbc2SGraeme Gregory 		.reg_offset = 1,
792945fbc2SGraeme Gregory 	},
802945fbc2SGraeme Gregory 	[PALMAS_RTC_TIMER_IRQ] = {
812945fbc2SGraeme Gregory 		.mask = PALMAS_INT2_STATUS_RTC_TIMER,
822945fbc2SGraeme Gregory 		.reg_offset = 1,
832945fbc2SGraeme Gregory 	},
842945fbc2SGraeme Gregory 	[PALMAS_WDT_IRQ] = {
852945fbc2SGraeme Gregory 		.mask = PALMAS_INT2_STATUS_WDT,
862945fbc2SGraeme Gregory 		.reg_offset = 1,
872945fbc2SGraeme Gregory 	},
882945fbc2SGraeme Gregory 	[PALMAS_BATREMOVAL_IRQ] = {
892945fbc2SGraeme Gregory 		.mask = PALMAS_INT2_STATUS_BATREMOVAL,
902945fbc2SGraeme Gregory 		.reg_offset = 1,
912945fbc2SGraeme Gregory 	},
922945fbc2SGraeme Gregory 	[PALMAS_RESET_IN_IRQ] = {
932945fbc2SGraeme Gregory 		.mask = PALMAS_INT2_STATUS_RESET_IN,
942945fbc2SGraeme Gregory 		.reg_offset = 1,
952945fbc2SGraeme Gregory 	},
962945fbc2SGraeme Gregory 	[PALMAS_FBI_BB_IRQ] = {
972945fbc2SGraeme Gregory 		.mask = PALMAS_INT2_STATUS_FBI_BB,
982945fbc2SGraeme Gregory 		.reg_offset = 1,
992945fbc2SGraeme Gregory 	},
1002945fbc2SGraeme Gregory 	[PALMAS_SHORT_IRQ] = {
1012945fbc2SGraeme Gregory 		.mask = PALMAS_INT2_STATUS_SHORT,
1022945fbc2SGraeme Gregory 		.reg_offset = 1,
1032945fbc2SGraeme Gregory 	},
1042945fbc2SGraeme Gregory 	[PALMAS_VAC_ACOK_IRQ] = {
1052945fbc2SGraeme Gregory 		.mask = PALMAS_INT2_STATUS_VAC_ACOK,
1062945fbc2SGraeme Gregory 		.reg_offset = 1,
1072945fbc2SGraeme Gregory 	},
1082945fbc2SGraeme Gregory 	/* INT3 IRQs */
1092945fbc2SGraeme Gregory 	[PALMAS_GPADC_AUTO_0_IRQ] = {
1102945fbc2SGraeme Gregory 		.mask = PALMAS_INT3_STATUS_GPADC_AUTO_0,
1112945fbc2SGraeme Gregory 		.reg_offset = 2,
1122945fbc2SGraeme Gregory 	},
1132945fbc2SGraeme Gregory 	[PALMAS_GPADC_AUTO_1_IRQ] = {
1142945fbc2SGraeme Gregory 		.mask = PALMAS_INT3_STATUS_GPADC_AUTO_1,
1152945fbc2SGraeme Gregory 		.reg_offset = 2,
1162945fbc2SGraeme Gregory 	},
1172945fbc2SGraeme Gregory 	[PALMAS_GPADC_EOC_SW_IRQ] = {
1182945fbc2SGraeme Gregory 		.mask = PALMAS_INT3_STATUS_GPADC_EOC_SW,
1192945fbc2SGraeme Gregory 		.reg_offset = 2,
1202945fbc2SGraeme Gregory 	},
1212945fbc2SGraeme Gregory 	[PALMAS_GPADC_EOC_RT_IRQ] = {
1222945fbc2SGraeme Gregory 		.mask = PALMAS_INT3_STATUS_GPADC_EOC_RT,
1232945fbc2SGraeme Gregory 		.reg_offset = 2,
1242945fbc2SGraeme Gregory 	},
1252945fbc2SGraeme Gregory 	[PALMAS_ID_OTG_IRQ] = {
1262945fbc2SGraeme Gregory 		.mask = PALMAS_INT3_STATUS_ID_OTG,
1272945fbc2SGraeme Gregory 		.reg_offset = 2,
1282945fbc2SGraeme Gregory 	},
1292945fbc2SGraeme Gregory 	[PALMAS_ID_IRQ] = {
1302945fbc2SGraeme Gregory 		.mask = PALMAS_INT3_STATUS_ID,
1312945fbc2SGraeme Gregory 		.reg_offset = 2,
1322945fbc2SGraeme Gregory 	},
1332945fbc2SGraeme Gregory 	[PALMAS_VBUS_OTG_IRQ] = {
1342945fbc2SGraeme Gregory 		.mask = PALMAS_INT3_STATUS_VBUS_OTG,
1352945fbc2SGraeme Gregory 		.reg_offset = 2,
1362945fbc2SGraeme Gregory 	},
1372945fbc2SGraeme Gregory 	[PALMAS_VBUS_IRQ] = {
1382945fbc2SGraeme Gregory 		.mask = PALMAS_INT3_STATUS_VBUS,
1392945fbc2SGraeme Gregory 		.reg_offset = 2,
1402945fbc2SGraeme Gregory 	},
1412945fbc2SGraeme Gregory 	/* INT4 IRQs */
1422945fbc2SGraeme Gregory 	[PALMAS_GPIO_0_IRQ] = {
1432945fbc2SGraeme Gregory 		.mask = PALMAS_INT4_STATUS_GPIO_0,
1442945fbc2SGraeme Gregory 		.reg_offset = 3,
1452945fbc2SGraeme Gregory 	},
1462945fbc2SGraeme Gregory 	[PALMAS_GPIO_1_IRQ] = {
1472945fbc2SGraeme Gregory 		.mask = PALMAS_INT4_STATUS_GPIO_1,
1482945fbc2SGraeme Gregory 		.reg_offset = 3,
1492945fbc2SGraeme Gregory 	},
1502945fbc2SGraeme Gregory 	[PALMAS_GPIO_2_IRQ] = {
1512945fbc2SGraeme Gregory 		.mask = PALMAS_INT4_STATUS_GPIO_2,
1522945fbc2SGraeme Gregory 		.reg_offset = 3,
1532945fbc2SGraeme Gregory 	},
1542945fbc2SGraeme Gregory 	[PALMAS_GPIO_3_IRQ] = {
1552945fbc2SGraeme Gregory 		.mask = PALMAS_INT4_STATUS_GPIO_3,
1562945fbc2SGraeme Gregory 		.reg_offset = 3,
1572945fbc2SGraeme Gregory 	},
1582945fbc2SGraeme Gregory 	[PALMAS_GPIO_4_IRQ] = {
1592945fbc2SGraeme Gregory 		.mask = PALMAS_INT4_STATUS_GPIO_4,
1602945fbc2SGraeme Gregory 		.reg_offset = 3,
1612945fbc2SGraeme Gregory 	},
1622945fbc2SGraeme Gregory 	[PALMAS_GPIO_5_IRQ] = {
1632945fbc2SGraeme Gregory 		.mask = PALMAS_INT4_STATUS_GPIO_5,
1642945fbc2SGraeme Gregory 		.reg_offset = 3,
1652945fbc2SGraeme Gregory 	},
1662945fbc2SGraeme Gregory 	[PALMAS_GPIO_6_IRQ] = {
1672945fbc2SGraeme Gregory 		.mask = PALMAS_INT4_STATUS_GPIO_6,
1682945fbc2SGraeme Gregory 		.reg_offset = 3,
1692945fbc2SGraeme Gregory 	},
1702945fbc2SGraeme Gregory 	[PALMAS_GPIO_7_IRQ] = {
1712945fbc2SGraeme Gregory 		.mask = PALMAS_INT4_STATUS_GPIO_7,
1722945fbc2SGraeme Gregory 		.reg_offset = 3,
1732945fbc2SGraeme Gregory 	},
1742945fbc2SGraeme Gregory };
1752945fbc2SGraeme Gregory 
1762945fbc2SGraeme Gregory static struct regmap_irq_chip palmas_irq_chip = {
1772945fbc2SGraeme Gregory 	.name = "palmas",
1782945fbc2SGraeme Gregory 	.irqs = palmas_irqs,
1792945fbc2SGraeme Gregory 	.num_irqs = ARRAY_SIZE(palmas_irqs),
1802945fbc2SGraeme Gregory 
1812945fbc2SGraeme Gregory 	.num_regs = 4,
1822945fbc2SGraeme Gregory 	.irq_reg_stride = 5,
1832945fbc2SGraeme Gregory 	.status_base = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE,
1842945fbc2SGraeme Gregory 			PALMAS_INT1_STATUS),
1852945fbc2SGraeme Gregory 	.mask_base = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE,
1862945fbc2SGraeme Gregory 			PALMAS_INT1_MASK),
1872945fbc2SGraeme Gregory };
1882945fbc2SGraeme Gregory 
189df545d1cSLaxman Dewangan static int palmas_set_pdata_irq_flag(struct i2c_client *i2c,
1909c14ac33SGraeme Gregory 		struct palmas_platform_data *pdata)
1919c14ac33SGraeme Gregory {
192df545d1cSLaxman Dewangan 	struct irq_data *irq_data = irq_get_irq_data(i2c->irq);
193df545d1cSLaxman Dewangan 	if (!irq_data) {
194df545d1cSLaxman Dewangan 		dev_err(&i2c->dev, "Invalid IRQ: %d\n", i2c->irq);
195df545d1cSLaxman Dewangan 		return -EINVAL;
196df545d1cSLaxman Dewangan 	}
197df545d1cSLaxman Dewangan 
198df545d1cSLaxman Dewangan 	pdata->irq_flags = irqd_get_trigger_type(irq_data);
199df545d1cSLaxman Dewangan 	dev_info(&i2c->dev, "Irq flag is 0x%08x\n", pdata->irq_flags);
200df545d1cSLaxman Dewangan 	return 0;
201df545d1cSLaxman Dewangan }
202df545d1cSLaxman Dewangan 
203df545d1cSLaxman Dewangan static void palmas_dt_to_pdata(struct i2c_client *i2c,
204df545d1cSLaxman Dewangan 		struct palmas_platform_data *pdata)
205df545d1cSLaxman Dewangan {
206df545d1cSLaxman Dewangan 	struct device_node *node = i2c->dev.of_node;
2079c14ac33SGraeme Gregory 	int ret;
2089c14ac33SGraeme Gregory 	u32 prop;
2099c14ac33SGraeme Gregory 
2102154a2b3SJ Keerthy 	ret = of_property_read_u32(node, "ti,mux-pad1", &prop);
2119c14ac33SGraeme Gregory 	if (!ret) {
2129c14ac33SGraeme Gregory 		pdata->mux_from_pdata = 1;
2139c14ac33SGraeme Gregory 		pdata->pad1 = prop;
2149c14ac33SGraeme Gregory 	}
2159c14ac33SGraeme Gregory 
2162154a2b3SJ Keerthy 	ret = of_property_read_u32(node, "ti,mux-pad2", &prop);
2179c14ac33SGraeme Gregory 	if (!ret) {
2189c14ac33SGraeme Gregory 		pdata->mux_from_pdata = 1;
2199c14ac33SGraeme Gregory 		pdata->pad2 = prop;
2209c14ac33SGraeme Gregory 	}
2219c14ac33SGraeme Gregory 
2229c14ac33SGraeme Gregory 	/* The default for this register is all masked */
2232154a2b3SJ Keerthy 	ret = of_property_read_u32(node, "ti,power-ctrl", &prop);
2249c14ac33SGraeme Gregory 	if (!ret)
2259c14ac33SGraeme Gregory 		pdata->power_ctrl = prop;
2269c14ac33SGraeme Gregory 	else
2279c14ac33SGraeme Gregory 		pdata->power_ctrl = PALMAS_POWER_CTRL_NSLEEP_MASK |
2289c14ac33SGraeme Gregory 					PALMAS_POWER_CTRL_ENABLE1_MASK |
2299c14ac33SGraeme Gregory 					PALMAS_POWER_CTRL_ENABLE2_MASK;
230df545d1cSLaxman Dewangan 	if (i2c->irq)
231df545d1cSLaxman Dewangan 		palmas_set_pdata_irq_flag(i2c, pdata);
2329c14ac33SGraeme Gregory }
2339c14ac33SGraeme Gregory 
2341ffb0be3SJ Keerthy static unsigned int palmas_features = PALMAS_PMIC_FEATURE_SMPS10_BOOST;
2354124e6e2SJ Keerthy static unsigned int tps659038_features;
2361ffb0be3SJ Keerthy 
2371ffb0be3SJ Keerthy static const struct of_device_id of_palmas_match_tbl[] = {
2381ffb0be3SJ Keerthy 	{
2391ffb0be3SJ Keerthy 		.compatible = "ti,palmas",
2401ffb0be3SJ Keerthy 		.data = &palmas_features,
2411ffb0be3SJ Keerthy 	},
2424124e6e2SJ Keerthy 	{
2434124e6e2SJ Keerthy 		.compatible = "ti,tps659038",
2444124e6e2SJ Keerthy 		.data = &tps659038_features,
2454124e6e2SJ Keerthy 	},
2461ffb0be3SJ Keerthy 	{ },
2471ffb0be3SJ Keerthy };
2481ffb0be3SJ Keerthy 
249f791be49SBill Pemberton static int palmas_i2c_probe(struct i2c_client *i2c,
2502945fbc2SGraeme Gregory 			    const struct i2c_device_id *id)
2512945fbc2SGraeme Gregory {
2522945fbc2SGraeme Gregory 	struct palmas *palmas;
2532945fbc2SGraeme Gregory 	struct palmas_platform_data *pdata;
2549c14ac33SGraeme Gregory 	struct device_node *node = i2c->dev.of_node;
2552945fbc2SGraeme Gregory 	int ret = 0, i;
2561ffb0be3SJ Keerthy 	unsigned int reg, addr, *features;
2572945fbc2SGraeme Gregory 	int slave;
2581ffb0be3SJ Keerthy 	const struct of_device_id *match;
2592945fbc2SGraeme Gregory 
2602945fbc2SGraeme Gregory 	pdata = dev_get_platdata(&i2c->dev);
2619c14ac33SGraeme Gregory 
2629c14ac33SGraeme Gregory 	if (node && !pdata) {
2639c14ac33SGraeme Gregory 		pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL);
2649c14ac33SGraeme Gregory 
2659c14ac33SGraeme Gregory 		if (!pdata)
2669c14ac33SGraeme Gregory 			return -ENOMEM;
2679c14ac33SGraeme Gregory 
268df545d1cSLaxman Dewangan 		palmas_dt_to_pdata(i2c, pdata);
2699c14ac33SGraeme Gregory 	}
2709c14ac33SGraeme Gregory 
2712945fbc2SGraeme Gregory 	if (!pdata)
2722945fbc2SGraeme Gregory 		return -EINVAL;
2732945fbc2SGraeme Gregory 
2742945fbc2SGraeme Gregory 	palmas = devm_kzalloc(&i2c->dev, sizeof(struct palmas), GFP_KERNEL);
2752945fbc2SGraeme Gregory 	if (palmas == NULL)
2762945fbc2SGraeme Gregory 		return -ENOMEM;
2772945fbc2SGraeme Gregory 
2782945fbc2SGraeme Gregory 	i2c_set_clientdata(i2c, palmas);
2792945fbc2SGraeme Gregory 	palmas->dev = &i2c->dev;
2802945fbc2SGraeme Gregory 	palmas->irq = i2c->irq;
2812945fbc2SGraeme Gregory 
2821ffb0be3SJ Keerthy 	match = of_match_device(of_match_ptr(of_palmas_match_tbl), &i2c->dev);
2831ffb0be3SJ Keerthy 
2841ffb0be3SJ Keerthy 	if (!match)
2851ffb0be3SJ Keerthy 		return -ENODATA;
2861ffb0be3SJ Keerthy 
2871ffb0be3SJ Keerthy 	features = (unsigned int *)match->data;
2881ffb0be3SJ Keerthy 	palmas->features = *features;
2891ffb0be3SJ Keerthy 
2902945fbc2SGraeme Gregory 	for (i = 0; i < PALMAS_NUM_CLIENTS; i++) {
2912945fbc2SGraeme Gregory 		if (i == 0)
2922945fbc2SGraeme Gregory 			palmas->i2c_clients[i] = i2c;
2932945fbc2SGraeme Gregory 		else {
2942945fbc2SGraeme Gregory 			palmas->i2c_clients[i] =
2952945fbc2SGraeme Gregory 					i2c_new_dummy(i2c->adapter,
2962945fbc2SGraeme Gregory 							i2c->addr + i);
2972945fbc2SGraeme Gregory 			if (!palmas->i2c_clients[i]) {
2982945fbc2SGraeme Gregory 				dev_err(palmas->dev,
2992945fbc2SGraeme Gregory 					"can't attach client %d\n", i);
3002945fbc2SGraeme Gregory 				ret = -ENOMEM;
3012945fbc2SGraeme Gregory 				goto err;
3022945fbc2SGraeme Gregory 			}
303c4fbec3cSLaxman Dewangan 			palmas->i2c_clients[i]->dev.of_node = of_node_get(node);
3042945fbc2SGraeme Gregory 		}
3052945fbc2SGraeme Gregory 		palmas->regmap[i] = devm_regmap_init_i2c(palmas->i2c_clients[i],
3062945fbc2SGraeme Gregory 				&palmas_regmap_config[i]);
3072945fbc2SGraeme Gregory 		if (IS_ERR(palmas->regmap[i])) {
3082945fbc2SGraeme Gregory 			ret = PTR_ERR(palmas->regmap[i]);
3092945fbc2SGraeme Gregory 			dev_err(palmas->dev,
3102945fbc2SGraeme Gregory 				"Failed to allocate regmap %d, err: %d\n",
3112945fbc2SGraeme Gregory 				i, ret);
3122945fbc2SGraeme Gregory 			goto err;
3132945fbc2SGraeme Gregory 		}
3142945fbc2SGraeme Gregory 	}
3152945fbc2SGraeme Gregory 
316ad522f4eSJ Keerthy 	if (!palmas->irq) {
317ad522f4eSJ Keerthy 		dev_warn(palmas->dev, "IRQ missing: skipping irq request\n");
318ad522f4eSJ Keerthy 		goto no_irq;
319ad522f4eSJ Keerthy 	}
320ad522f4eSJ Keerthy 
321df545d1cSLaxman Dewangan 	/* Change interrupt line output polarity */
322df545d1cSLaxman Dewangan 	if (pdata->irq_flags & IRQ_TYPE_LEVEL_HIGH)
323df545d1cSLaxman Dewangan 		reg = PALMAS_POLARITY_CTRL_INT_POLARITY;
324df545d1cSLaxman Dewangan 	else
325df545d1cSLaxman Dewangan 		reg = 0;
326df545d1cSLaxman Dewangan 	ret = palmas_update_bits(palmas, PALMAS_PU_PD_OD_BASE,
327df545d1cSLaxman Dewangan 			PALMAS_POLARITY_CTRL, PALMAS_POLARITY_CTRL_INT_POLARITY,
328df545d1cSLaxman Dewangan 			reg);
329df545d1cSLaxman Dewangan 	if (ret < 0) {
330df545d1cSLaxman Dewangan 		dev_err(palmas->dev, "POLARITY_CTRL updat failed: %d\n", ret);
331df545d1cSLaxman Dewangan 		goto err;
332df545d1cSLaxman Dewangan 	}
333df545d1cSLaxman Dewangan 
334b330f85dSGraeme Gregory 	/* Change IRQ into clear on read mode for efficiency */
335b330f85dSGraeme Gregory 	slave = PALMAS_BASE_TO_SLAVE(PALMAS_INTERRUPT_BASE);
336b330f85dSGraeme Gregory 	addr = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE, PALMAS_INT_CTRL);
337b330f85dSGraeme Gregory 	reg = PALMAS_INT_CTRL_INT_CLEAR;
338b330f85dSGraeme Gregory 
339b330f85dSGraeme Gregory 	regmap_write(palmas->regmap[slave], addr, reg);
340b330f85dSGraeme Gregory 
341b330f85dSGraeme Gregory 	ret = regmap_add_irq_chip(palmas->regmap[slave], palmas->irq,
342df545d1cSLaxman Dewangan 			IRQF_ONESHOT | pdata->irq_flags, 0, &palmas_irq_chip,
3432945fbc2SGraeme Gregory 			&palmas->irq_data);
3442945fbc2SGraeme Gregory 	if (ret < 0)
3452945fbc2SGraeme Gregory 		goto err;
3462945fbc2SGraeme Gregory 
347ad522f4eSJ Keerthy no_irq:
3482945fbc2SGraeme Gregory 	slave = PALMAS_BASE_TO_SLAVE(PALMAS_PU_PD_OD_BASE);
3492945fbc2SGraeme Gregory 	addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
3502945fbc2SGraeme Gregory 			PALMAS_PRIMARY_SECONDARY_PAD1);
3512945fbc2SGraeme Gregory 
3522945fbc2SGraeme Gregory 	if (pdata->mux_from_pdata) {
3532945fbc2SGraeme Gregory 		reg = pdata->pad1;
3542945fbc2SGraeme Gregory 		ret = regmap_write(palmas->regmap[slave], addr, reg);
3552945fbc2SGraeme Gregory 		if (ret)
3563f78deccSGraeme Gregory 			goto err_irq;
3572945fbc2SGraeme Gregory 	} else {
3582945fbc2SGraeme Gregory 		ret = regmap_read(palmas->regmap[slave], addr, &reg);
3592945fbc2SGraeme Gregory 		if (ret)
3603f78deccSGraeme Gregory 			goto err_irq;
3612945fbc2SGraeme Gregory 	}
3622945fbc2SGraeme Gregory 
3632945fbc2SGraeme Gregory 	if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0))
3642945fbc2SGraeme Gregory 		palmas->gpio_muxed |= PALMAS_GPIO_0_MUXED;
3652945fbc2SGraeme Gregory 	if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK))
3662945fbc2SGraeme Gregory 		palmas->gpio_muxed |= PALMAS_GPIO_1_MUXED;
3672945fbc2SGraeme Gregory 	else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK) ==
3682945fbc2SGraeme Gregory 			(2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT))
3692945fbc2SGraeme Gregory 		palmas->led_muxed |= PALMAS_LED1_MUXED;
3702945fbc2SGraeme Gregory 	else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK) ==
3712945fbc2SGraeme Gregory 			(3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT))
3722945fbc2SGraeme Gregory 		palmas->pwm_muxed |= PALMAS_PWM1_MUXED;
3732945fbc2SGraeme Gregory 	if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK))
3742945fbc2SGraeme Gregory 		palmas->gpio_muxed |= PALMAS_GPIO_2_MUXED;
3752945fbc2SGraeme Gregory 	else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK) ==
3762945fbc2SGraeme Gregory 			(2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT))
3772945fbc2SGraeme Gregory 		palmas->led_muxed |= PALMAS_LED2_MUXED;
3782945fbc2SGraeme Gregory 	else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK) ==
3792945fbc2SGraeme Gregory 			(3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT))
3802945fbc2SGraeme Gregory 		palmas->pwm_muxed |= PALMAS_PWM2_MUXED;
3812945fbc2SGraeme Gregory 	if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_3))
3822945fbc2SGraeme Gregory 		palmas->gpio_muxed |= PALMAS_GPIO_3_MUXED;
3832945fbc2SGraeme Gregory 
3842945fbc2SGraeme Gregory 	addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE,
3852945fbc2SGraeme Gregory 			PALMAS_PRIMARY_SECONDARY_PAD2);
3862945fbc2SGraeme Gregory 
3872945fbc2SGraeme Gregory 	if (pdata->mux_from_pdata) {
3882945fbc2SGraeme Gregory 		reg = pdata->pad2;
3892945fbc2SGraeme Gregory 		ret = regmap_write(palmas->regmap[slave], addr, reg);
3902945fbc2SGraeme Gregory 		if (ret)
3913f78deccSGraeme Gregory 			goto err_irq;
3922945fbc2SGraeme Gregory 	} else {
3932945fbc2SGraeme Gregory 		ret = regmap_read(palmas->regmap[slave], addr, &reg);
3942945fbc2SGraeme Gregory 		if (ret)
3953f78deccSGraeme Gregory 			goto err_irq;
3962945fbc2SGraeme Gregory 	}
3972945fbc2SGraeme Gregory 
3982945fbc2SGraeme Gregory 	if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4))
3992945fbc2SGraeme Gregory 		palmas->gpio_muxed |= PALMAS_GPIO_4_MUXED;
4002945fbc2SGraeme Gregory 	if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_5_MASK))
4012945fbc2SGraeme Gregory 		palmas->gpio_muxed |= PALMAS_GPIO_5_MUXED;
4022945fbc2SGraeme Gregory 	if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_6))
4032945fbc2SGraeme Gregory 		palmas->gpio_muxed |= PALMAS_GPIO_6_MUXED;
4042945fbc2SGraeme Gregory 	if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK))
4052945fbc2SGraeme Gregory 		palmas->gpio_muxed |= PALMAS_GPIO_7_MUXED;
4062945fbc2SGraeme Gregory 
4072945fbc2SGraeme Gregory 	dev_info(palmas->dev, "Muxing GPIO %x, PWM %x, LED %x\n",
4082945fbc2SGraeme Gregory 			palmas->gpio_muxed, palmas->pwm_muxed,
4092945fbc2SGraeme Gregory 			palmas->led_muxed);
4102945fbc2SGraeme Gregory 
4112945fbc2SGraeme Gregory 	reg = pdata->power_ctrl;
4122945fbc2SGraeme Gregory 
4132945fbc2SGraeme Gregory 	slave = PALMAS_BASE_TO_SLAVE(PALMAS_PMU_CONTROL_BASE);
4142945fbc2SGraeme Gregory 	addr = PALMAS_BASE_TO_REG(PALMAS_PMU_CONTROL_BASE, PALMAS_POWER_CTRL);
4152945fbc2SGraeme Gregory 
4162945fbc2SGraeme Gregory 	ret = regmap_write(palmas->regmap[slave], addr, reg);
4172945fbc2SGraeme Gregory 	if (ret)
4183f78deccSGraeme Gregory 		goto err_irq;
4192945fbc2SGraeme Gregory 
4209c14ac33SGraeme Gregory 	/*
4219c14ac33SGraeme Gregory 	 * If we are probing with DT do this the DT way and return here
4229c14ac33SGraeme Gregory 	 * otherwise continue and add devices using mfd helpers.
4239c14ac33SGraeme Gregory 	 */
4249c14ac33SGraeme Gregory 	if (node) {
4259c14ac33SGraeme Gregory 		ret = of_platform_populate(node, NULL, NULL, &i2c->dev);
4269c14ac33SGraeme Gregory 		if (ret < 0)
4279c14ac33SGraeme Gregory 			goto err_irq;
4289c14ac33SGraeme Gregory 		else
4299c14ac33SGraeme Gregory 			return ret;
4309c14ac33SGraeme Gregory 	}
4319c14ac33SGraeme Gregory 
4322945fbc2SGraeme Gregory 	return ret;
4332945fbc2SGraeme Gregory 
4343f78deccSGraeme Gregory err_irq:
4353f78deccSGraeme Gregory 	regmap_del_irq_chip(palmas->irq, palmas->irq_data);
4363f78deccSGraeme Gregory err:
4372945fbc2SGraeme Gregory 	return ret;
4382945fbc2SGraeme Gregory }
4392945fbc2SGraeme Gregory 
4402945fbc2SGraeme Gregory static int palmas_i2c_remove(struct i2c_client *i2c)
4412945fbc2SGraeme Gregory {
4422945fbc2SGraeme Gregory 	struct palmas *palmas = i2c_get_clientdata(i2c);
4432945fbc2SGraeme Gregory 
4442945fbc2SGraeme Gregory 	mfd_remove_devices(palmas->dev);
4452945fbc2SGraeme Gregory 	regmap_del_irq_chip(palmas->irq, palmas->irq_data);
4462945fbc2SGraeme Gregory 
4472945fbc2SGraeme Gregory 	return 0;
4482945fbc2SGraeme Gregory }
4492945fbc2SGraeme Gregory 
4502945fbc2SGraeme Gregory static const struct i2c_device_id palmas_i2c_id[] = {
4512945fbc2SGraeme Gregory 	{ "palmas", },
4522945fbc2SGraeme Gregory 	{ "twl6035", },
4532945fbc2SGraeme Gregory 	{ "twl6037", },
4542945fbc2SGraeme Gregory 	{ "tps65913", },
45500ba81c1SAxel Lin 	{ /* end */ }
4562945fbc2SGraeme Gregory };
4572945fbc2SGraeme Gregory MODULE_DEVICE_TABLE(i2c, palmas_i2c_id);
4582945fbc2SGraeme Gregory 
4592945fbc2SGraeme Gregory static struct i2c_driver palmas_i2c_driver = {
4602945fbc2SGraeme Gregory 	.driver = {
4612945fbc2SGraeme Gregory 		   .name = "palmas",
4622945fbc2SGraeme Gregory 		   .of_match_table = of_palmas_match_tbl,
4632945fbc2SGraeme Gregory 		   .owner = THIS_MODULE,
4642945fbc2SGraeme Gregory 	},
4652945fbc2SGraeme Gregory 	.probe = palmas_i2c_probe,
4662945fbc2SGraeme Gregory 	.remove = palmas_i2c_remove,
4672945fbc2SGraeme Gregory 	.id_table = palmas_i2c_id,
4682945fbc2SGraeme Gregory };
4692945fbc2SGraeme Gregory 
4702945fbc2SGraeme Gregory static int __init palmas_i2c_init(void)
4712945fbc2SGraeme Gregory {
4722945fbc2SGraeme Gregory 	return i2c_add_driver(&palmas_i2c_driver);
4732945fbc2SGraeme Gregory }
4742945fbc2SGraeme Gregory /* init early so consumer devices can complete system boot */
4752945fbc2SGraeme Gregory subsys_initcall(palmas_i2c_init);
4762945fbc2SGraeme Gregory 
4772945fbc2SGraeme Gregory static void __exit palmas_i2c_exit(void)
4782945fbc2SGraeme Gregory {
4792945fbc2SGraeme Gregory 	i2c_del_driver(&palmas_i2c_driver);
4802945fbc2SGraeme Gregory }
4812945fbc2SGraeme Gregory module_exit(palmas_i2c_exit);
4822945fbc2SGraeme Gregory 
4832945fbc2SGraeme Gregory MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
4842945fbc2SGraeme Gregory MODULE_DESCRIPTION("Palmas chip family multi-function driver");
4852945fbc2SGraeme Gregory MODULE_LICENSE("GPL");
486