xref: /openbmc/linux/drivers/mfd/da9150-core.c (revision 9816d859)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2b8fce55cSAdam Thomson /*
3b8fce55cSAdam Thomson  * DA9150 Core MFD Driver
4b8fce55cSAdam Thomson  *
5b8fce55cSAdam Thomson  * Copyright (c) 2014 Dialog Semiconductor
6b8fce55cSAdam Thomson  *
7b8fce55cSAdam Thomson  * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
8b8fce55cSAdam Thomson  */
9b8fce55cSAdam Thomson 
10b8fce55cSAdam Thomson #include <linux/kernel.h>
11b8fce55cSAdam Thomson #include <linux/module.h>
12b8fce55cSAdam Thomson #include <linux/platform_device.h>
13b8fce55cSAdam Thomson #include <linux/i2c.h>
14b8fce55cSAdam Thomson #include <linux/regmap.h>
15b8fce55cSAdam Thomson #include <linux/slab.h>
16b8fce55cSAdam Thomson #include <linux/irq.h>
17b8fce55cSAdam Thomson #include <linux/interrupt.h>
18b8fce55cSAdam Thomson #include <linux/mfd/core.h>
19b8fce55cSAdam Thomson #include <linux/mfd/da9150/core.h>
20b8fce55cSAdam Thomson #include <linux/mfd/da9150/registers.h>
21b8fce55cSAdam Thomson 
221ac710e0SAdam Thomson /* Raw device access, used for QIF */
da9150_i2c_read_device(struct i2c_client * client,u8 addr,int count,u8 * buf)231ac710e0SAdam Thomson static int da9150_i2c_read_device(struct i2c_client *client, u8 addr, int count,
241ac710e0SAdam Thomson 				  u8 *buf)
251ac710e0SAdam Thomson {
261ac710e0SAdam Thomson 	struct i2c_msg xfer;
271ac710e0SAdam Thomson 	int ret;
281ac710e0SAdam Thomson 
291ac710e0SAdam Thomson 	/*
301ac710e0SAdam Thomson 	 * Read is split into two transfers as device expects STOP/START rather
311ac710e0SAdam Thomson 	 * than repeated start to carry out this kind of access.
321ac710e0SAdam Thomson 	 */
331ac710e0SAdam Thomson 
341ac710e0SAdam Thomson 	/* Write address */
351ac710e0SAdam Thomson 	xfer.addr = client->addr;
361ac710e0SAdam Thomson 	xfer.flags = 0;
371ac710e0SAdam Thomson 	xfer.len = 1;
381ac710e0SAdam Thomson 	xfer.buf = &addr;
391ac710e0SAdam Thomson 
401ac710e0SAdam Thomson 	ret = i2c_transfer(client->adapter, &xfer, 1);
411ac710e0SAdam Thomson 	if (ret != 1) {
421ac710e0SAdam Thomson 		if (ret < 0)
431ac710e0SAdam Thomson 			return ret;
441ac710e0SAdam Thomson 		else
451ac710e0SAdam Thomson 			return -EIO;
461ac710e0SAdam Thomson 	}
471ac710e0SAdam Thomson 
481ac710e0SAdam Thomson 	/* Read data */
491ac710e0SAdam Thomson 	xfer.addr = client->addr;
501ac710e0SAdam Thomson 	xfer.flags = I2C_M_RD;
511ac710e0SAdam Thomson 	xfer.len = count;
521ac710e0SAdam Thomson 	xfer.buf = buf;
531ac710e0SAdam Thomson 
541ac710e0SAdam Thomson 	ret = i2c_transfer(client->adapter, &xfer, 1);
551ac710e0SAdam Thomson 	if (ret == 1)
561ac710e0SAdam Thomson 		return 0;
571ac710e0SAdam Thomson 	else if (ret < 0)
581ac710e0SAdam Thomson 		return ret;
591ac710e0SAdam Thomson 	else
601ac710e0SAdam Thomson 		return -EIO;
611ac710e0SAdam Thomson }
621ac710e0SAdam Thomson 
da9150_i2c_write_device(struct i2c_client * client,u8 addr,int count,const u8 * buf)631ac710e0SAdam Thomson static int da9150_i2c_write_device(struct i2c_client *client, u8 addr,
641ac710e0SAdam Thomson 				   int count, const u8 *buf)
651ac710e0SAdam Thomson {
661ac710e0SAdam Thomson 	struct i2c_msg xfer;
671ac710e0SAdam Thomson 	u8 *reg_data;
681ac710e0SAdam Thomson 	int ret;
691ac710e0SAdam Thomson 
701ac710e0SAdam Thomson 	reg_data = kzalloc(1 + count, GFP_KERNEL);
711ac710e0SAdam Thomson 	if (!reg_data)
721ac710e0SAdam Thomson 		return -ENOMEM;
731ac710e0SAdam Thomson 
741ac710e0SAdam Thomson 	reg_data[0] = addr;
751ac710e0SAdam Thomson 	memcpy(&reg_data[1], buf, count);
761ac710e0SAdam Thomson 
771ac710e0SAdam Thomson 	/* Write address & data */
781ac710e0SAdam Thomson 	xfer.addr = client->addr;
791ac710e0SAdam Thomson 	xfer.flags = 0;
801ac710e0SAdam Thomson 	xfer.len = 1 + count;
811ac710e0SAdam Thomson 	xfer.buf = reg_data;
821ac710e0SAdam Thomson 
831ac710e0SAdam Thomson 	ret = i2c_transfer(client->adapter, &xfer, 1);
841ac710e0SAdam Thomson 	kfree(reg_data);
851ac710e0SAdam Thomson 	if (ret == 1)
861ac710e0SAdam Thomson 		return 0;
871ac710e0SAdam Thomson 	else if (ret < 0)
881ac710e0SAdam Thomson 		return ret;
891ac710e0SAdam Thomson 	else
901ac710e0SAdam Thomson 		return -EIO;
911ac710e0SAdam Thomson }
921ac710e0SAdam Thomson 
da9150_volatile_reg(struct device * dev,unsigned int reg)93b8fce55cSAdam Thomson static bool da9150_volatile_reg(struct device *dev, unsigned int reg)
94b8fce55cSAdam Thomson {
95b8fce55cSAdam Thomson 	switch (reg) {
96b8fce55cSAdam Thomson 	case DA9150_PAGE_CON:
97b8fce55cSAdam Thomson 	case DA9150_STATUS_A:
98b8fce55cSAdam Thomson 	case DA9150_STATUS_B:
99b8fce55cSAdam Thomson 	case DA9150_STATUS_C:
100b8fce55cSAdam Thomson 	case DA9150_STATUS_D:
101b8fce55cSAdam Thomson 	case DA9150_STATUS_E:
102b8fce55cSAdam Thomson 	case DA9150_STATUS_F:
103b8fce55cSAdam Thomson 	case DA9150_STATUS_G:
104b8fce55cSAdam Thomson 	case DA9150_STATUS_H:
105b8fce55cSAdam Thomson 	case DA9150_STATUS_I:
106b8fce55cSAdam Thomson 	case DA9150_STATUS_J:
107b8fce55cSAdam Thomson 	case DA9150_STATUS_K:
108b8fce55cSAdam Thomson 	case DA9150_STATUS_L:
109b8fce55cSAdam Thomson 	case DA9150_STATUS_N:
110b8fce55cSAdam Thomson 	case DA9150_FAULT_LOG_A:
111b8fce55cSAdam Thomson 	case DA9150_FAULT_LOG_B:
112b8fce55cSAdam Thomson 	case DA9150_EVENT_E:
113b8fce55cSAdam Thomson 	case DA9150_EVENT_F:
114b8fce55cSAdam Thomson 	case DA9150_EVENT_G:
115b8fce55cSAdam Thomson 	case DA9150_EVENT_H:
116b8fce55cSAdam Thomson 	case DA9150_CONTROL_B:
117b8fce55cSAdam Thomson 	case DA9150_CONTROL_C:
118b8fce55cSAdam Thomson 	case DA9150_GPADC_MAN:
119b8fce55cSAdam Thomson 	case DA9150_GPADC_RES_A:
120b8fce55cSAdam Thomson 	case DA9150_GPADC_RES_B:
121b8fce55cSAdam Thomson 	case DA9150_ADETVB_CFG_C:
122b8fce55cSAdam Thomson 	case DA9150_ADETD_STAT:
123b8fce55cSAdam Thomson 	case DA9150_ADET_CMPSTAT:
124b8fce55cSAdam Thomson 	case DA9150_ADET_CTRL_A:
125b8fce55cSAdam Thomson 	case DA9150_PPR_TCTR_B:
126b8fce55cSAdam Thomson 	case DA9150_COREBTLD_STAT_A:
127b8fce55cSAdam Thomson 	case DA9150_CORE_DATA_A:
128b8fce55cSAdam Thomson 	case DA9150_CORE_DATA_B:
129b8fce55cSAdam Thomson 	case DA9150_CORE_DATA_C:
130b8fce55cSAdam Thomson 	case DA9150_CORE_DATA_D:
131b8fce55cSAdam Thomson 	case DA9150_CORE2WIRE_STAT_A:
132b8fce55cSAdam Thomson 	case DA9150_FW_CTRL_C:
133b8fce55cSAdam Thomson 	case DA9150_FG_CTRL_B:
134b8fce55cSAdam Thomson 	case DA9150_FW_CTRL_B:
135b8fce55cSAdam Thomson 	case DA9150_GPADC_CMAN:
136b8fce55cSAdam Thomson 	case DA9150_GPADC_CRES_A:
137b8fce55cSAdam Thomson 	case DA9150_GPADC_CRES_B:
138b8fce55cSAdam Thomson 	case DA9150_CC_ICHG_RES_A:
139b8fce55cSAdam Thomson 	case DA9150_CC_ICHG_RES_B:
140b8fce55cSAdam Thomson 	case DA9150_CC_IAVG_RES_A:
141b8fce55cSAdam Thomson 	case DA9150_CC_IAVG_RES_B:
142b8fce55cSAdam Thomson 	case DA9150_TAUX_CTRL_A:
143b8fce55cSAdam Thomson 	case DA9150_TAUX_VALUE_H:
144b8fce55cSAdam Thomson 	case DA9150_TAUX_VALUE_L:
145b8fce55cSAdam Thomson 	case DA9150_TBAT_RES_A:
146b8fce55cSAdam Thomson 	case DA9150_TBAT_RES_B:
147b8fce55cSAdam Thomson 		return true;
148b8fce55cSAdam Thomson 	default:
149b8fce55cSAdam Thomson 		return false;
150b8fce55cSAdam Thomson 	}
151b8fce55cSAdam Thomson }
152b8fce55cSAdam Thomson 
153b8fce55cSAdam Thomson static const struct regmap_range_cfg da9150_range_cfg[] = {
154b8fce55cSAdam Thomson 	{
155b8fce55cSAdam Thomson 		.range_min = DA9150_PAGE_CON,
156b8fce55cSAdam Thomson 		.range_max = DA9150_TBAT_RES_B,
157b8fce55cSAdam Thomson 		.selector_reg = DA9150_PAGE_CON,
158b8fce55cSAdam Thomson 		.selector_mask = DA9150_I2C_PAGE_MASK,
159b8fce55cSAdam Thomson 		.selector_shift = DA9150_I2C_PAGE_SHIFT,
160b8fce55cSAdam Thomson 		.window_start = 0,
161b8fce55cSAdam Thomson 		.window_len = 256,
162b8fce55cSAdam Thomson 	},
163b8fce55cSAdam Thomson };
164b8fce55cSAdam Thomson 
165fbf2c4a7SKrzysztof Kozlowski static const struct regmap_config da9150_regmap_config = {
166b8fce55cSAdam Thomson 	.reg_bits = 8,
167b8fce55cSAdam Thomson 	.val_bits = 8,
168b8fce55cSAdam Thomson 	.ranges = da9150_range_cfg,
169b8fce55cSAdam Thomson 	.num_ranges = ARRAY_SIZE(da9150_range_cfg),
170b8fce55cSAdam Thomson 	.max_register = DA9150_TBAT_RES_B,
171b8fce55cSAdam Thomson 
172b8fce55cSAdam Thomson 	.cache_type = REGCACHE_RBTREE,
173b8fce55cSAdam Thomson 
174b8fce55cSAdam Thomson 	.volatile_reg = da9150_volatile_reg,
175b8fce55cSAdam Thomson };
176b8fce55cSAdam Thomson 
da9150_read_qif(struct da9150 * da9150,u8 addr,int count,u8 * buf)1771ac710e0SAdam Thomson void da9150_read_qif(struct da9150 *da9150, u8 addr, int count, u8 *buf)
1781ac710e0SAdam Thomson {
1791ac710e0SAdam Thomson 	int ret;
1801ac710e0SAdam Thomson 
1811ac710e0SAdam Thomson 	ret = da9150_i2c_read_device(da9150->core_qif, addr, count, buf);
1821ac710e0SAdam Thomson 	if (ret < 0)
1831ac710e0SAdam Thomson 		dev_err(da9150->dev, "Failed to read from QIF 0x%x: %d\n",
1841ac710e0SAdam Thomson 			addr, ret);
1851ac710e0SAdam Thomson }
1861ac710e0SAdam Thomson EXPORT_SYMBOL_GPL(da9150_read_qif);
1871ac710e0SAdam Thomson 
da9150_write_qif(struct da9150 * da9150,u8 addr,int count,const u8 * buf)1881ac710e0SAdam Thomson void da9150_write_qif(struct da9150 *da9150, u8 addr, int count, const u8 *buf)
1891ac710e0SAdam Thomson {
1901ac710e0SAdam Thomson 	int ret;
1911ac710e0SAdam Thomson 
1921ac710e0SAdam Thomson 	ret = da9150_i2c_write_device(da9150->core_qif, addr, count, buf);
1931ac710e0SAdam Thomson 	if (ret < 0)
1941ac710e0SAdam Thomson 		dev_err(da9150->dev, "Failed to write to QIF 0x%x: %d\n",
1951ac710e0SAdam Thomson 			addr, ret);
1961ac710e0SAdam Thomson }
1971ac710e0SAdam Thomson EXPORT_SYMBOL_GPL(da9150_write_qif);
1981ac710e0SAdam Thomson 
da9150_reg_read(struct da9150 * da9150,u16 reg)199b8fce55cSAdam Thomson u8 da9150_reg_read(struct da9150 *da9150, u16 reg)
200b8fce55cSAdam Thomson {
201b8fce55cSAdam Thomson 	int val, ret;
202b8fce55cSAdam Thomson 
203b8fce55cSAdam Thomson 	ret = regmap_read(da9150->regmap, reg, &val);
204b8fce55cSAdam Thomson 	if (ret)
205b8fce55cSAdam Thomson 		dev_err(da9150->dev, "Failed to read from reg 0x%x: %d\n",
206b8fce55cSAdam Thomson 			reg, ret);
207b8fce55cSAdam Thomson 
208b8fce55cSAdam Thomson 	return (u8) val;
209b8fce55cSAdam Thomson }
210b8fce55cSAdam Thomson EXPORT_SYMBOL_GPL(da9150_reg_read);
211b8fce55cSAdam Thomson 
da9150_reg_write(struct da9150 * da9150,u16 reg,u8 val)212b8fce55cSAdam Thomson void da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val)
213b8fce55cSAdam Thomson {
214b8fce55cSAdam Thomson 	int ret;
215b8fce55cSAdam Thomson 
216b8fce55cSAdam Thomson 	ret = regmap_write(da9150->regmap, reg, val);
217b8fce55cSAdam Thomson 	if (ret)
218b8fce55cSAdam Thomson 		dev_err(da9150->dev, "Failed to write to reg 0x%x: %d\n",
219b8fce55cSAdam Thomson 			reg, ret);
220b8fce55cSAdam Thomson }
221b8fce55cSAdam Thomson EXPORT_SYMBOL_GPL(da9150_reg_write);
222b8fce55cSAdam Thomson 
da9150_set_bits(struct da9150 * da9150,u16 reg,u8 mask,u8 val)223b8fce55cSAdam Thomson void da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val)
224b8fce55cSAdam Thomson {
225b8fce55cSAdam Thomson 	int ret;
226b8fce55cSAdam Thomson 
227b8fce55cSAdam Thomson 	ret = regmap_update_bits(da9150->regmap, reg, mask, val);
228b8fce55cSAdam Thomson 	if (ret)
229b8fce55cSAdam Thomson 		dev_err(da9150->dev, "Failed to set bits in reg 0x%x: %d\n",
230b8fce55cSAdam Thomson 			reg, ret);
231b8fce55cSAdam Thomson }
232b8fce55cSAdam Thomson EXPORT_SYMBOL_GPL(da9150_set_bits);
233b8fce55cSAdam Thomson 
da9150_bulk_read(struct da9150 * da9150,u16 reg,int count,u8 * buf)234b8fce55cSAdam Thomson void da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf)
235b8fce55cSAdam Thomson {
236b8fce55cSAdam Thomson 	int ret;
237b8fce55cSAdam Thomson 
238b8fce55cSAdam Thomson 	ret = regmap_bulk_read(da9150->regmap, reg, buf, count);
239b8fce55cSAdam Thomson 	if (ret)
240b8fce55cSAdam Thomson 		dev_err(da9150->dev, "Failed to bulk read from reg 0x%x: %d\n",
241b8fce55cSAdam Thomson 			reg, ret);
242b8fce55cSAdam Thomson }
243b8fce55cSAdam Thomson EXPORT_SYMBOL_GPL(da9150_bulk_read);
244b8fce55cSAdam Thomson 
da9150_bulk_write(struct da9150 * da9150,u16 reg,int count,const u8 * buf)245b8fce55cSAdam Thomson void da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf)
246b8fce55cSAdam Thomson {
247b8fce55cSAdam Thomson 	int ret;
248b8fce55cSAdam Thomson 
249b8fce55cSAdam Thomson 	ret = regmap_raw_write(da9150->regmap, reg, buf, count);
250b8fce55cSAdam Thomson 	if (ret)
251b8fce55cSAdam Thomson 		dev_err(da9150->dev, "Failed to bulk write to reg 0x%x %d\n",
252b8fce55cSAdam Thomson 			reg, ret);
253b8fce55cSAdam Thomson }
254b8fce55cSAdam Thomson EXPORT_SYMBOL_GPL(da9150_bulk_write);
255b8fce55cSAdam Thomson 
2567ce7b26fSKrzysztof Kozlowski static const struct regmap_irq da9150_irqs[] = {
257b8fce55cSAdam Thomson 	[DA9150_IRQ_VBUS] = {
258b8fce55cSAdam Thomson 		.reg_offset = 0,
259b8fce55cSAdam Thomson 		.mask = DA9150_E_VBUS_MASK,
260b8fce55cSAdam Thomson 	},
261b8fce55cSAdam Thomson 	[DA9150_IRQ_CHG] = {
262b8fce55cSAdam Thomson 		.reg_offset = 0,
263b8fce55cSAdam Thomson 		.mask = DA9150_E_CHG_MASK,
264b8fce55cSAdam Thomson 	},
265b8fce55cSAdam Thomson 	[DA9150_IRQ_TCLASS] = {
266b8fce55cSAdam Thomson 		.reg_offset = 0,
267b8fce55cSAdam Thomson 		.mask = DA9150_E_TCLASS_MASK,
268b8fce55cSAdam Thomson 	},
269b8fce55cSAdam Thomson 	[DA9150_IRQ_TJUNC] = {
270b8fce55cSAdam Thomson 		.reg_offset = 0,
271b8fce55cSAdam Thomson 		.mask = DA9150_E_TJUNC_MASK,
272b8fce55cSAdam Thomson 	},
273b8fce55cSAdam Thomson 	[DA9150_IRQ_VFAULT] = {
274b8fce55cSAdam Thomson 		.reg_offset = 0,
275b8fce55cSAdam Thomson 		.mask = DA9150_E_VFAULT_MASK,
276b8fce55cSAdam Thomson 	},
277b8fce55cSAdam Thomson 	[DA9150_IRQ_CONF] = {
278b8fce55cSAdam Thomson 		.reg_offset = 1,
279b8fce55cSAdam Thomson 		.mask = DA9150_E_CONF_MASK,
280b8fce55cSAdam Thomson 	},
281b8fce55cSAdam Thomson 	[DA9150_IRQ_DAT] = {
282b8fce55cSAdam Thomson 		.reg_offset = 1,
283b8fce55cSAdam Thomson 		.mask = DA9150_E_DAT_MASK,
284b8fce55cSAdam Thomson 	},
285b8fce55cSAdam Thomson 	[DA9150_IRQ_DTYPE] = {
286b8fce55cSAdam Thomson 		.reg_offset = 1,
287b8fce55cSAdam Thomson 		.mask = DA9150_E_DTYPE_MASK,
288b8fce55cSAdam Thomson 	},
289b8fce55cSAdam Thomson 	[DA9150_IRQ_ID] = {
290b8fce55cSAdam Thomson 		.reg_offset = 1,
291b8fce55cSAdam Thomson 		.mask = DA9150_E_ID_MASK,
292b8fce55cSAdam Thomson 	},
293b8fce55cSAdam Thomson 	[DA9150_IRQ_ADP] = {
294b8fce55cSAdam Thomson 		.reg_offset = 1,
295b8fce55cSAdam Thomson 		.mask = DA9150_E_ADP_MASK,
296b8fce55cSAdam Thomson 	},
297b8fce55cSAdam Thomson 	[DA9150_IRQ_SESS_END] = {
298b8fce55cSAdam Thomson 		.reg_offset = 1,
299b8fce55cSAdam Thomson 		.mask = DA9150_E_SESS_END_MASK,
300b8fce55cSAdam Thomson 	},
301b8fce55cSAdam Thomson 	[DA9150_IRQ_SESS_VLD] = {
302b8fce55cSAdam Thomson 		.reg_offset = 1,
303b8fce55cSAdam Thomson 		.mask = DA9150_E_SESS_VLD_MASK,
304b8fce55cSAdam Thomson 	},
305b8fce55cSAdam Thomson 	[DA9150_IRQ_FG] = {
306b8fce55cSAdam Thomson 		.reg_offset = 2,
307b8fce55cSAdam Thomson 		.mask = DA9150_E_FG_MASK,
308b8fce55cSAdam Thomson 	},
309b8fce55cSAdam Thomson 	[DA9150_IRQ_GP] = {
310b8fce55cSAdam Thomson 		.reg_offset = 2,
311b8fce55cSAdam Thomson 		.mask = DA9150_E_GP_MASK,
312b8fce55cSAdam Thomson 	},
313b8fce55cSAdam Thomson 	[DA9150_IRQ_TBAT] = {
314b8fce55cSAdam Thomson 		.reg_offset = 2,
315b8fce55cSAdam Thomson 		.mask = DA9150_E_TBAT_MASK,
316b8fce55cSAdam Thomson 	},
317b8fce55cSAdam Thomson 	[DA9150_IRQ_GPIOA] = {
318b8fce55cSAdam Thomson 		.reg_offset = 2,
319b8fce55cSAdam Thomson 		.mask = DA9150_E_GPIOA_MASK,
320b8fce55cSAdam Thomson 	},
321b8fce55cSAdam Thomson 	[DA9150_IRQ_GPIOB] = {
322b8fce55cSAdam Thomson 		.reg_offset = 2,
323b8fce55cSAdam Thomson 		.mask = DA9150_E_GPIOB_MASK,
324b8fce55cSAdam Thomson 	},
325b8fce55cSAdam Thomson 	[DA9150_IRQ_GPIOC] = {
326b8fce55cSAdam Thomson 		.reg_offset = 2,
327b8fce55cSAdam Thomson 		.mask = DA9150_E_GPIOC_MASK,
328b8fce55cSAdam Thomson 	},
329b8fce55cSAdam Thomson 	[DA9150_IRQ_GPIOD] = {
330b8fce55cSAdam Thomson 		.reg_offset = 2,
331b8fce55cSAdam Thomson 		.mask = DA9150_E_GPIOD_MASK,
332b8fce55cSAdam Thomson 	},
333b8fce55cSAdam Thomson 	[DA9150_IRQ_GPADC] = {
334b8fce55cSAdam Thomson 		.reg_offset = 2,
335b8fce55cSAdam Thomson 		.mask = DA9150_E_GPADC_MASK,
336b8fce55cSAdam Thomson 	},
337b8fce55cSAdam Thomson 	[DA9150_IRQ_WKUP] = {
338b8fce55cSAdam Thomson 		.reg_offset = 3,
339b8fce55cSAdam Thomson 		.mask = DA9150_E_WKUP_MASK,
340b8fce55cSAdam Thomson 	},
341b8fce55cSAdam Thomson };
342b8fce55cSAdam Thomson 
3437ce7b26fSKrzysztof Kozlowski static const struct regmap_irq_chip da9150_regmap_irq_chip = {
344b8fce55cSAdam Thomson 	.name = "da9150_irq",
345b8fce55cSAdam Thomson 	.status_base = DA9150_EVENT_E,
346b8fce55cSAdam Thomson 	.mask_base = DA9150_IRQ_MASK_E,
347b8fce55cSAdam Thomson 	.ack_base = DA9150_EVENT_E,
348b8fce55cSAdam Thomson 	.num_regs = DA9150_NUM_IRQ_REGS,
349b8fce55cSAdam Thomson 	.irqs = da9150_irqs,
350b8fce55cSAdam Thomson 	.num_irqs = ARRAY_SIZE(da9150_irqs),
351b8fce55cSAdam Thomson };
352b8fce55cSAdam Thomson 
353a0fa0abeSRikard Falkeborn static const struct resource da9150_gpadc_resources[] = {
3541d7f833fSAdam Thomson 	DEFINE_RES_IRQ_NAMED(DA9150_IRQ_GPADC, "GPADC"),
355b8fce55cSAdam Thomson };
356b8fce55cSAdam Thomson 
357a0fa0abeSRikard Falkeborn static const struct resource da9150_charger_resources[] = {
3581d7f833fSAdam Thomson 	DEFINE_RES_IRQ_NAMED(DA9150_IRQ_CHG, "CHG_STATUS"),
3591d7f833fSAdam Thomson 	DEFINE_RES_IRQ_NAMED(DA9150_IRQ_TJUNC, "CHG_TJUNC"),
3601d7f833fSAdam Thomson 	DEFINE_RES_IRQ_NAMED(DA9150_IRQ_VFAULT, "CHG_VFAULT"),
3611d7f833fSAdam Thomson 	DEFINE_RES_IRQ_NAMED(DA9150_IRQ_VBUS, "CHG_VBUS"),
362b8fce55cSAdam Thomson };
363b8fce55cSAdam Thomson 
364a0fa0abeSRikard Falkeborn static const struct resource da9150_fg_resources[] = {
3651ac710e0SAdam Thomson 	DEFINE_RES_IRQ_NAMED(DA9150_IRQ_FG, "FG"),
3661ac710e0SAdam Thomson };
3671ac710e0SAdam Thomson 
3681ac710e0SAdam Thomson enum da9150_dev_idx {
3691ac710e0SAdam Thomson 	DA9150_GPADC_IDX = 0,
3701ac710e0SAdam Thomson 	DA9150_CHARGER_IDX,
3711ac710e0SAdam Thomson 	DA9150_FG_IDX,
3721ac710e0SAdam Thomson };
3731ac710e0SAdam Thomson 
374b8fce55cSAdam Thomson static struct mfd_cell da9150_devs[] = {
3751ac710e0SAdam Thomson 	[DA9150_GPADC_IDX] = {
376b8fce55cSAdam Thomson 		.name = "da9150-gpadc",
377b8fce55cSAdam Thomson 		.of_compatible = "dlg,da9150-gpadc",
378b8fce55cSAdam Thomson 		.resources = da9150_gpadc_resources,
379b8fce55cSAdam Thomson 		.num_resources = ARRAY_SIZE(da9150_gpadc_resources),
380b8fce55cSAdam Thomson 	},
3811ac710e0SAdam Thomson 	[DA9150_CHARGER_IDX] = {
382b8fce55cSAdam Thomson 		.name = "da9150-charger",
383b8fce55cSAdam Thomson 		.of_compatible = "dlg,da9150-charger",
384b8fce55cSAdam Thomson 		.resources = da9150_charger_resources,
385b8fce55cSAdam Thomson 		.num_resources = ARRAY_SIZE(da9150_charger_resources),
386b8fce55cSAdam Thomson 	},
3871ac710e0SAdam Thomson 	[DA9150_FG_IDX] = {
3881ac710e0SAdam Thomson 		.name = "da9150-fuel-gauge",
3891ac710e0SAdam Thomson 		.of_compatible = "dlg,da9150-fuel-gauge",
3901ac710e0SAdam Thomson 		.resources = da9150_fg_resources,
3911ac710e0SAdam Thomson 		.num_resources = ARRAY_SIZE(da9150_fg_resources),
3921ac710e0SAdam Thomson 	},
393b8fce55cSAdam Thomson };
394b8fce55cSAdam Thomson 
da9150_probe(struct i2c_client * client)3953dc6eb9fSUwe Kleine-König static int da9150_probe(struct i2c_client *client)
396b8fce55cSAdam Thomson {
397b8fce55cSAdam Thomson 	struct da9150 *da9150;
398b8fce55cSAdam Thomson 	struct da9150_pdata *pdata = dev_get_platdata(&client->dev);
3991ac710e0SAdam Thomson 	int qif_addr;
400b8fce55cSAdam Thomson 	int ret;
401b8fce55cSAdam Thomson 
402b8fce55cSAdam Thomson 	da9150 = devm_kzalloc(&client->dev, sizeof(*da9150), GFP_KERNEL);
403b8fce55cSAdam Thomson 	if (!da9150)
404b8fce55cSAdam Thomson 		return -ENOMEM;
405b8fce55cSAdam Thomson 
406b8fce55cSAdam Thomson 	da9150->dev = &client->dev;
407b8fce55cSAdam Thomson 	da9150->irq = client->irq;
408b8fce55cSAdam Thomson 	i2c_set_clientdata(client, da9150);
409b8fce55cSAdam Thomson 
410b8fce55cSAdam Thomson 	da9150->regmap = devm_regmap_init_i2c(client, &da9150_regmap_config);
411b8fce55cSAdam Thomson 	if (IS_ERR(da9150->regmap)) {
412b8fce55cSAdam Thomson 		ret = PTR_ERR(da9150->regmap);
413b8fce55cSAdam Thomson 		dev_err(da9150->dev, "Failed to allocate register map: %d\n",
414b8fce55cSAdam Thomson 			ret);
415b8fce55cSAdam Thomson 		return ret;
416b8fce55cSAdam Thomson 	}
417b8fce55cSAdam Thomson 
4181ac710e0SAdam Thomson 	/* Setup secondary I2C interface for QIF access */
4191ac710e0SAdam Thomson 	qif_addr = da9150_reg_read(da9150, DA9150_CORE2WIRE_CTRL_A);
4201ac710e0SAdam Thomson 	qif_addr = (qif_addr & DA9150_CORE_BASE_ADDR_MASK) >> 1;
4211ac710e0SAdam Thomson 	qif_addr |= DA9150_QIF_I2C_ADDR_LSB;
422e310ee86SWolfram Sang 	da9150->core_qif = i2c_new_dummy_device(client->adapter, qif_addr);
423e310ee86SWolfram Sang 	if (IS_ERR(da9150->core_qif)) {
4241ac710e0SAdam Thomson 		dev_err(da9150->dev, "Failed to attach QIF client\n");
425e310ee86SWolfram Sang 		return PTR_ERR(da9150->core_qif);
4261ac710e0SAdam Thomson 	}
4271ac710e0SAdam Thomson 
4281ac710e0SAdam Thomson 	i2c_set_clientdata(da9150->core_qif, da9150);
4291ac710e0SAdam Thomson 
4301ac710e0SAdam Thomson 	if (pdata) {
4311ac710e0SAdam Thomson 		da9150->irq_base = pdata->irq_base;
4321ac710e0SAdam Thomson 
4331ac710e0SAdam Thomson 		da9150_devs[DA9150_FG_IDX].platform_data = pdata->fg_pdata;
4341ac710e0SAdam Thomson 		da9150_devs[DA9150_FG_IDX].pdata_size =
4351ac710e0SAdam Thomson 			sizeof(struct da9150_fg_pdata);
4361ac710e0SAdam Thomson 	} else {
4371ac710e0SAdam Thomson 		da9150->irq_base = -1;
4381ac710e0SAdam Thomson 	}
439b8fce55cSAdam Thomson 
440b8fce55cSAdam Thomson 	ret = regmap_add_irq_chip(da9150->regmap, da9150->irq,
441b8fce55cSAdam Thomson 				  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
442b8fce55cSAdam Thomson 				  da9150->irq_base, &da9150_regmap_irq_chip,
443b8fce55cSAdam Thomson 				  &da9150->regmap_irq_data);
4441ac710e0SAdam Thomson 	if (ret) {
4451ac710e0SAdam Thomson 		dev_err(da9150->dev, "Failed to add regmap irq chip: %d\n",
4461ac710e0SAdam Thomson 			ret);
4471ac710e0SAdam Thomson 		goto regmap_irq_fail;
4481ac710e0SAdam Thomson 	}
4491ac710e0SAdam Thomson 
450b8fce55cSAdam Thomson 
451b8fce55cSAdam Thomson 	da9150->irq_base = regmap_irq_chip_get_base(da9150->regmap_irq_data);
4521ac710e0SAdam Thomson 
453b8fce55cSAdam Thomson 	enable_irq_wake(da9150->irq);
454b8fce55cSAdam Thomson 
455b8fce55cSAdam Thomson 	ret = mfd_add_devices(da9150->dev, -1, da9150_devs,
456b8fce55cSAdam Thomson 			      ARRAY_SIZE(da9150_devs), NULL,
457b8fce55cSAdam Thomson 			      da9150->irq_base, NULL);
458b8fce55cSAdam Thomson 	if (ret) {
459b8fce55cSAdam Thomson 		dev_err(da9150->dev, "Failed to add child devices: %d\n", ret);
4601ac710e0SAdam Thomson 		goto mfd_fail;
461b8fce55cSAdam Thomson 	}
462b8fce55cSAdam Thomson 
463b8fce55cSAdam Thomson 	return 0;
4641ac710e0SAdam Thomson 
4651ac710e0SAdam Thomson mfd_fail:
4661ac710e0SAdam Thomson 	regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
4671ac710e0SAdam Thomson regmap_irq_fail:
4681ac710e0SAdam Thomson 	i2c_unregister_device(da9150->core_qif);
4691ac710e0SAdam Thomson 
4701ac710e0SAdam Thomson 	return ret;
471b8fce55cSAdam Thomson }
472b8fce55cSAdam Thomson 
da9150_remove(struct i2c_client * client)473ed5c2f5fSUwe Kleine-König static void da9150_remove(struct i2c_client *client)
474b8fce55cSAdam Thomson {
475b8fce55cSAdam Thomson 	struct da9150 *da9150 = i2c_get_clientdata(client);
476b8fce55cSAdam Thomson 
477b8fce55cSAdam Thomson 	regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
478b8fce55cSAdam Thomson 	mfd_remove_devices(da9150->dev);
4791ac710e0SAdam Thomson 	i2c_unregister_device(da9150->core_qif);
480b8fce55cSAdam Thomson }
481b8fce55cSAdam Thomson 
da9150_shutdown(struct i2c_client * client)482b8fce55cSAdam Thomson static void da9150_shutdown(struct i2c_client *client)
483b8fce55cSAdam Thomson {
484b8fce55cSAdam Thomson 	struct da9150 *da9150 = i2c_get_clientdata(client);
485b8fce55cSAdam Thomson 
486b8fce55cSAdam Thomson 	/* Make sure we have a wakup source for the device */
487b8fce55cSAdam Thomson 	da9150_set_bits(da9150, DA9150_CONFIG_D,
488b8fce55cSAdam Thomson 			DA9150_WKUP_PM_EN_MASK,
489b8fce55cSAdam Thomson 			DA9150_WKUP_PM_EN_MASK);
490b8fce55cSAdam Thomson 
491b8fce55cSAdam Thomson 	/* Set device to DISABLED mode */
492b8fce55cSAdam Thomson 	da9150_set_bits(da9150, DA9150_CONTROL_C,
493b8fce55cSAdam Thomson 			DA9150_DISABLE_MASK, DA9150_DISABLE_MASK);
494b8fce55cSAdam Thomson }
495b8fce55cSAdam Thomson 
496b8fce55cSAdam Thomson static const struct i2c_device_id da9150_i2c_id[] = {
497b8fce55cSAdam Thomson 	{ "da9150", },
498b8fce55cSAdam Thomson 	{ }
499b8fce55cSAdam Thomson };
500b8fce55cSAdam Thomson MODULE_DEVICE_TABLE(i2c, da9150_i2c_id);
501b8fce55cSAdam Thomson 
502b8fce55cSAdam Thomson static const struct of_device_id da9150_of_match[] = {
503b8fce55cSAdam Thomson 	{ .compatible = "dlg,da9150", },
504b8fce55cSAdam Thomson 	{ }
505b8fce55cSAdam Thomson };
506b8fce55cSAdam Thomson MODULE_DEVICE_TABLE(of, da9150_of_match);
507b8fce55cSAdam Thomson 
508b8fce55cSAdam Thomson static struct i2c_driver da9150_driver = {
509b8fce55cSAdam Thomson 	.driver	= {
510b8fce55cSAdam Thomson 		.name	= "da9150",
51198a6521cSKrzysztof Kozlowski 		.of_match_table = da9150_of_match,
512b8fce55cSAdam Thomson 	},
513*9816d859SUwe Kleine-König 	.probe		= da9150_probe,
514b8fce55cSAdam Thomson 	.remove		= da9150_remove,
515b8fce55cSAdam Thomson 	.shutdown	= da9150_shutdown,
516b8fce55cSAdam Thomson 	.id_table	= da9150_i2c_id,
517b8fce55cSAdam Thomson };
518b8fce55cSAdam Thomson 
519b8fce55cSAdam Thomson module_i2c_driver(da9150_driver);
520b8fce55cSAdam Thomson 
521b8fce55cSAdam Thomson MODULE_DESCRIPTION("MFD Core Driver for DA9150");
522b8fce55cSAdam Thomson MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
523b8fce55cSAdam Thomson MODULE_LICENSE("GPL");
524