xref: /OK3568_Linux_fs/kernel/drivers/mfd/da9150-core.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * DA9150 Core MFD Driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) 2014 Dialog Semiconductor
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/platform_device.h>
13*4882a593Smuzhiyun #include <linux/i2c.h>
14*4882a593Smuzhiyun #include <linux/regmap.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun #include <linux/irq.h>
17*4882a593Smuzhiyun #include <linux/interrupt.h>
18*4882a593Smuzhiyun #include <linux/mfd/core.h>
19*4882a593Smuzhiyun #include <linux/mfd/da9150/core.h>
20*4882a593Smuzhiyun #include <linux/mfd/da9150/registers.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun /* Raw device access, used for QIF */
da9150_i2c_read_device(struct i2c_client * client,u8 addr,int count,u8 * buf)23*4882a593Smuzhiyun static int da9150_i2c_read_device(struct i2c_client *client, u8 addr, int count,
24*4882a593Smuzhiyun 				  u8 *buf)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun 	struct i2c_msg xfer;
27*4882a593Smuzhiyun 	int ret;
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun 	/*
30*4882a593Smuzhiyun 	 * Read is split into two transfers as device expects STOP/START rather
31*4882a593Smuzhiyun 	 * than repeated start to carry out this kind of access.
32*4882a593Smuzhiyun 	 */
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	/* Write address */
35*4882a593Smuzhiyun 	xfer.addr = client->addr;
36*4882a593Smuzhiyun 	xfer.flags = 0;
37*4882a593Smuzhiyun 	xfer.len = 1;
38*4882a593Smuzhiyun 	xfer.buf = &addr;
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 	ret = i2c_transfer(client->adapter, &xfer, 1);
41*4882a593Smuzhiyun 	if (ret != 1) {
42*4882a593Smuzhiyun 		if (ret < 0)
43*4882a593Smuzhiyun 			return ret;
44*4882a593Smuzhiyun 		else
45*4882a593Smuzhiyun 			return -EIO;
46*4882a593Smuzhiyun 	}
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	/* Read data */
49*4882a593Smuzhiyun 	xfer.addr = client->addr;
50*4882a593Smuzhiyun 	xfer.flags = I2C_M_RD;
51*4882a593Smuzhiyun 	xfer.len = count;
52*4882a593Smuzhiyun 	xfer.buf = buf;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	ret = i2c_transfer(client->adapter, &xfer, 1);
55*4882a593Smuzhiyun 	if (ret == 1)
56*4882a593Smuzhiyun 		return 0;
57*4882a593Smuzhiyun 	else if (ret < 0)
58*4882a593Smuzhiyun 		return ret;
59*4882a593Smuzhiyun 	else
60*4882a593Smuzhiyun 		return -EIO;
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun 
da9150_i2c_write_device(struct i2c_client * client,u8 addr,int count,const u8 * buf)63*4882a593Smuzhiyun static int da9150_i2c_write_device(struct i2c_client *client, u8 addr,
64*4882a593Smuzhiyun 				   int count, const u8 *buf)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	struct i2c_msg xfer;
67*4882a593Smuzhiyun 	u8 *reg_data;
68*4882a593Smuzhiyun 	int ret;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	reg_data = kzalloc(1 + count, GFP_KERNEL);
71*4882a593Smuzhiyun 	if (!reg_data)
72*4882a593Smuzhiyun 		return -ENOMEM;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	reg_data[0] = addr;
75*4882a593Smuzhiyun 	memcpy(&reg_data[1], buf, count);
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	/* Write address & data */
78*4882a593Smuzhiyun 	xfer.addr = client->addr;
79*4882a593Smuzhiyun 	xfer.flags = 0;
80*4882a593Smuzhiyun 	xfer.len = 1 + count;
81*4882a593Smuzhiyun 	xfer.buf = reg_data;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	ret = i2c_transfer(client->adapter, &xfer, 1);
84*4882a593Smuzhiyun 	kfree(reg_data);
85*4882a593Smuzhiyun 	if (ret == 1)
86*4882a593Smuzhiyun 		return 0;
87*4882a593Smuzhiyun 	else if (ret < 0)
88*4882a593Smuzhiyun 		return ret;
89*4882a593Smuzhiyun 	else
90*4882a593Smuzhiyun 		return -EIO;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun 
da9150_volatile_reg(struct device * dev,unsigned int reg)93*4882a593Smuzhiyun static bool da9150_volatile_reg(struct device *dev, unsigned int reg)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun 	switch (reg) {
96*4882a593Smuzhiyun 	case DA9150_PAGE_CON:
97*4882a593Smuzhiyun 	case DA9150_STATUS_A:
98*4882a593Smuzhiyun 	case DA9150_STATUS_B:
99*4882a593Smuzhiyun 	case DA9150_STATUS_C:
100*4882a593Smuzhiyun 	case DA9150_STATUS_D:
101*4882a593Smuzhiyun 	case DA9150_STATUS_E:
102*4882a593Smuzhiyun 	case DA9150_STATUS_F:
103*4882a593Smuzhiyun 	case DA9150_STATUS_G:
104*4882a593Smuzhiyun 	case DA9150_STATUS_H:
105*4882a593Smuzhiyun 	case DA9150_STATUS_I:
106*4882a593Smuzhiyun 	case DA9150_STATUS_J:
107*4882a593Smuzhiyun 	case DA9150_STATUS_K:
108*4882a593Smuzhiyun 	case DA9150_STATUS_L:
109*4882a593Smuzhiyun 	case DA9150_STATUS_N:
110*4882a593Smuzhiyun 	case DA9150_FAULT_LOG_A:
111*4882a593Smuzhiyun 	case DA9150_FAULT_LOG_B:
112*4882a593Smuzhiyun 	case DA9150_EVENT_E:
113*4882a593Smuzhiyun 	case DA9150_EVENT_F:
114*4882a593Smuzhiyun 	case DA9150_EVENT_G:
115*4882a593Smuzhiyun 	case DA9150_EVENT_H:
116*4882a593Smuzhiyun 	case DA9150_CONTROL_B:
117*4882a593Smuzhiyun 	case DA9150_CONTROL_C:
118*4882a593Smuzhiyun 	case DA9150_GPADC_MAN:
119*4882a593Smuzhiyun 	case DA9150_GPADC_RES_A:
120*4882a593Smuzhiyun 	case DA9150_GPADC_RES_B:
121*4882a593Smuzhiyun 	case DA9150_ADETVB_CFG_C:
122*4882a593Smuzhiyun 	case DA9150_ADETD_STAT:
123*4882a593Smuzhiyun 	case DA9150_ADET_CMPSTAT:
124*4882a593Smuzhiyun 	case DA9150_ADET_CTRL_A:
125*4882a593Smuzhiyun 	case DA9150_PPR_TCTR_B:
126*4882a593Smuzhiyun 	case DA9150_COREBTLD_STAT_A:
127*4882a593Smuzhiyun 	case DA9150_CORE_DATA_A:
128*4882a593Smuzhiyun 	case DA9150_CORE_DATA_B:
129*4882a593Smuzhiyun 	case DA9150_CORE_DATA_C:
130*4882a593Smuzhiyun 	case DA9150_CORE_DATA_D:
131*4882a593Smuzhiyun 	case DA9150_CORE2WIRE_STAT_A:
132*4882a593Smuzhiyun 	case DA9150_FW_CTRL_C:
133*4882a593Smuzhiyun 	case DA9150_FG_CTRL_B:
134*4882a593Smuzhiyun 	case DA9150_FW_CTRL_B:
135*4882a593Smuzhiyun 	case DA9150_GPADC_CMAN:
136*4882a593Smuzhiyun 	case DA9150_GPADC_CRES_A:
137*4882a593Smuzhiyun 	case DA9150_GPADC_CRES_B:
138*4882a593Smuzhiyun 	case DA9150_CC_ICHG_RES_A:
139*4882a593Smuzhiyun 	case DA9150_CC_ICHG_RES_B:
140*4882a593Smuzhiyun 	case DA9150_CC_IAVG_RES_A:
141*4882a593Smuzhiyun 	case DA9150_CC_IAVG_RES_B:
142*4882a593Smuzhiyun 	case DA9150_TAUX_CTRL_A:
143*4882a593Smuzhiyun 	case DA9150_TAUX_VALUE_H:
144*4882a593Smuzhiyun 	case DA9150_TAUX_VALUE_L:
145*4882a593Smuzhiyun 	case DA9150_TBAT_RES_A:
146*4882a593Smuzhiyun 	case DA9150_TBAT_RES_B:
147*4882a593Smuzhiyun 		return true;
148*4882a593Smuzhiyun 	default:
149*4882a593Smuzhiyun 		return false;
150*4882a593Smuzhiyun 	}
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun static const struct regmap_range_cfg da9150_range_cfg[] = {
154*4882a593Smuzhiyun 	{
155*4882a593Smuzhiyun 		.range_min = DA9150_PAGE_CON,
156*4882a593Smuzhiyun 		.range_max = DA9150_TBAT_RES_B,
157*4882a593Smuzhiyun 		.selector_reg = DA9150_PAGE_CON,
158*4882a593Smuzhiyun 		.selector_mask = DA9150_I2C_PAGE_MASK,
159*4882a593Smuzhiyun 		.selector_shift = DA9150_I2C_PAGE_SHIFT,
160*4882a593Smuzhiyun 		.window_start = 0,
161*4882a593Smuzhiyun 		.window_len = 256,
162*4882a593Smuzhiyun 	},
163*4882a593Smuzhiyun };
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun static const struct regmap_config da9150_regmap_config = {
166*4882a593Smuzhiyun 	.reg_bits = 8,
167*4882a593Smuzhiyun 	.val_bits = 8,
168*4882a593Smuzhiyun 	.ranges = da9150_range_cfg,
169*4882a593Smuzhiyun 	.num_ranges = ARRAY_SIZE(da9150_range_cfg),
170*4882a593Smuzhiyun 	.max_register = DA9150_TBAT_RES_B,
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	.cache_type = REGCACHE_RBTREE,
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	.volatile_reg = da9150_volatile_reg,
175*4882a593Smuzhiyun };
176*4882a593Smuzhiyun 
da9150_read_qif(struct da9150 * da9150,u8 addr,int count,u8 * buf)177*4882a593Smuzhiyun void da9150_read_qif(struct da9150 *da9150, u8 addr, int count, u8 *buf)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun 	int ret;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	ret = da9150_i2c_read_device(da9150->core_qif, addr, count, buf);
182*4882a593Smuzhiyun 	if (ret < 0)
183*4882a593Smuzhiyun 		dev_err(da9150->dev, "Failed to read from QIF 0x%x: %d\n",
184*4882a593Smuzhiyun 			addr, ret);
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(da9150_read_qif);
187*4882a593Smuzhiyun 
da9150_write_qif(struct da9150 * da9150,u8 addr,int count,const u8 * buf)188*4882a593Smuzhiyun void da9150_write_qif(struct da9150 *da9150, u8 addr, int count, const u8 *buf)
189*4882a593Smuzhiyun {
190*4882a593Smuzhiyun 	int ret;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	ret = da9150_i2c_write_device(da9150->core_qif, addr, count, buf);
193*4882a593Smuzhiyun 	if (ret < 0)
194*4882a593Smuzhiyun 		dev_err(da9150->dev, "Failed to write to QIF 0x%x: %d\n",
195*4882a593Smuzhiyun 			addr, ret);
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(da9150_write_qif);
198*4882a593Smuzhiyun 
da9150_reg_read(struct da9150 * da9150,u16 reg)199*4882a593Smuzhiyun u8 da9150_reg_read(struct da9150 *da9150, u16 reg)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun 	int val, ret;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	ret = regmap_read(da9150->regmap, reg, &val);
204*4882a593Smuzhiyun 	if (ret)
205*4882a593Smuzhiyun 		dev_err(da9150->dev, "Failed to read from reg 0x%x: %d\n",
206*4882a593Smuzhiyun 			reg, ret);
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	return (u8) val;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(da9150_reg_read);
211*4882a593Smuzhiyun 
da9150_reg_write(struct da9150 * da9150,u16 reg,u8 val)212*4882a593Smuzhiyun void da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun 	int ret;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	ret = regmap_write(da9150->regmap, reg, val);
217*4882a593Smuzhiyun 	if (ret)
218*4882a593Smuzhiyun 		dev_err(da9150->dev, "Failed to write to reg 0x%x: %d\n",
219*4882a593Smuzhiyun 			reg, ret);
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(da9150_reg_write);
222*4882a593Smuzhiyun 
da9150_set_bits(struct da9150 * da9150,u16 reg,u8 mask,u8 val)223*4882a593Smuzhiyun void da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun 	int ret;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	ret = regmap_update_bits(da9150->regmap, reg, mask, val);
228*4882a593Smuzhiyun 	if (ret)
229*4882a593Smuzhiyun 		dev_err(da9150->dev, "Failed to set bits in reg 0x%x: %d\n",
230*4882a593Smuzhiyun 			reg, ret);
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(da9150_set_bits);
233*4882a593Smuzhiyun 
da9150_bulk_read(struct da9150 * da9150,u16 reg,int count,u8 * buf)234*4882a593Smuzhiyun void da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun 	int ret;
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	ret = regmap_bulk_read(da9150->regmap, reg, buf, count);
239*4882a593Smuzhiyun 	if (ret)
240*4882a593Smuzhiyun 		dev_err(da9150->dev, "Failed to bulk read from reg 0x%x: %d\n",
241*4882a593Smuzhiyun 			reg, ret);
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(da9150_bulk_read);
244*4882a593Smuzhiyun 
da9150_bulk_write(struct da9150 * da9150,u16 reg,int count,const u8 * buf)245*4882a593Smuzhiyun void da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun 	int ret;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	ret = regmap_raw_write(da9150->regmap, reg, buf, count);
250*4882a593Smuzhiyun 	if (ret)
251*4882a593Smuzhiyun 		dev_err(da9150->dev, "Failed to bulk write to reg 0x%x %d\n",
252*4882a593Smuzhiyun 			reg, ret);
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(da9150_bulk_write);
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun static const struct regmap_irq da9150_irqs[] = {
257*4882a593Smuzhiyun 	[DA9150_IRQ_VBUS] = {
258*4882a593Smuzhiyun 		.reg_offset = 0,
259*4882a593Smuzhiyun 		.mask = DA9150_E_VBUS_MASK,
260*4882a593Smuzhiyun 	},
261*4882a593Smuzhiyun 	[DA9150_IRQ_CHG] = {
262*4882a593Smuzhiyun 		.reg_offset = 0,
263*4882a593Smuzhiyun 		.mask = DA9150_E_CHG_MASK,
264*4882a593Smuzhiyun 	},
265*4882a593Smuzhiyun 	[DA9150_IRQ_TCLASS] = {
266*4882a593Smuzhiyun 		.reg_offset = 0,
267*4882a593Smuzhiyun 		.mask = DA9150_E_TCLASS_MASK,
268*4882a593Smuzhiyun 	},
269*4882a593Smuzhiyun 	[DA9150_IRQ_TJUNC] = {
270*4882a593Smuzhiyun 		.reg_offset = 0,
271*4882a593Smuzhiyun 		.mask = DA9150_E_TJUNC_MASK,
272*4882a593Smuzhiyun 	},
273*4882a593Smuzhiyun 	[DA9150_IRQ_VFAULT] = {
274*4882a593Smuzhiyun 		.reg_offset = 0,
275*4882a593Smuzhiyun 		.mask = DA9150_E_VFAULT_MASK,
276*4882a593Smuzhiyun 	},
277*4882a593Smuzhiyun 	[DA9150_IRQ_CONF] = {
278*4882a593Smuzhiyun 		.reg_offset = 1,
279*4882a593Smuzhiyun 		.mask = DA9150_E_CONF_MASK,
280*4882a593Smuzhiyun 	},
281*4882a593Smuzhiyun 	[DA9150_IRQ_DAT] = {
282*4882a593Smuzhiyun 		.reg_offset = 1,
283*4882a593Smuzhiyun 		.mask = DA9150_E_DAT_MASK,
284*4882a593Smuzhiyun 	},
285*4882a593Smuzhiyun 	[DA9150_IRQ_DTYPE] = {
286*4882a593Smuzhiyun 		.reg_offset = 1,
287*4882a593Smuzhiyun 		.mask = DA9150_E_DTYPE_MASK,
288*4882a593Smuzhiyun 	},
289*4882a593Smuzhiyun 	[DA9150_IRQ_ID] = {
290*4882a593Smuzhiyun 		.reg_offset = 1,
291*4882a593Smuzhiyun 		.mask = DA9150_E_ID_MASK,
292*4882a593Smuzhiyun 	},
293*4882a593Smuzhiyun 	[DA9150_IRQ_ADP] = {
294*4882a593Smuzhiyun 		.reg_offset = 1,
295*4882a593Smuzhiyun 		.mask = DA9150_E_ADP_MASK,
296*4882a593Smuzhiyun 	},
297*4882a593Smuzhiyun 	[DA9150_IRQ_SESS_END] = {
298*4882a593Smuzhiyun 		.reg_offset = 1,
299*4882a593Smuzhiyun 		.mask = DA9150_E_SESS_END_MASK,
300*4882a593Smuzhiyun 	},
301*4882a593Smuzhiyun 	[DA9150_IRQ_SESS_VLD] = {
302*4882a593Smuzhiyun 		.reg_offset = 1,
303*4882a593Smuzhiyun 		.mask = DA9150_E_SESS_VLD_MASK,
304*4882a593Smuzhiyun 	},
305*4882a593Smuzhiyun 	[DA9150_IRQ_FG] = {
306*4882a593Smuzhiyun 		.reg_offset = 2,
307*4882a593Smuzhiyun 		.mask = DA9150_E_FG_MASK,
308*4882a593Smuzhiyun 	},
309*4882a593Smuzhiyun 	[DA9150_IRQ_GP] = {
310*4882a593Smuzhiyun 		.reg_offset = 2,
311*4882a593Smuzhiyun 		.mask = DA9150_E_GP_MASK,
312*4882a593Smuzhiyun 	},
313*4882a593Smuzhiyun 	[DA9150_IRQ_TBAT] = {
314*4882a593Smuzhiyun 		.reg_offset = 2,
315*4882a593Smuzhiyun 		.mask = DA9150_E_TBAT_MASK,
316*4882a593Smuzhiyun 	},
317*4882a593Smuzhiyun 	[DA9150_IRQ_GPIOA] = {
318*4882a593Smuzhiyun 		.reg_offset = 2,
319*4882a593Smuzhiyun 		.mask = DA9150_E_GPIOA_MASK,
320*4882a593Smuzhiyun 	},
321*4882a593Smuzhiyun 	[DA9150_IRQ_GPIOB] = {
322*4882a593Smuzhiyun 		.reg_offset = 2,
323*4882a593Smuzhiyun 		.mask = DA9150_E_GPIOB_MASK,
324*4882a593Smuzhiyun 	},
325*4882a593Smuzhiyun 	[DA9150_IRQ_GPIOC] = {
326*4882a593Smuzhiyun 		.reg_offset = 2,
327*4882a593Smuzhiyun 		.mask = DA9150_E_GPIOC_MASK,
328*4882a593Smuzhiyun 	},
329*4882a593Smuzhiyun 	[DA9150_IRQ_GPIOD] = {
330*4882a593Smuzhiyun 		.reg_offset = 2,
331*4882a593Smuzhiyun 		.mask = DA9150_E_GPIOD_MASK,
332*4882a593Smuzhiyun 	},
333*4882a593Smuzhiyun 	[DA9150_IRQ_GPADC] = {
334*4882a593Smuzhiyun 		.reg_offset = 2,
335*4882a593Smuzhiyun 		.mask = DA9150_E_GPADC_MASK,
336*4882a593Smuzhiyun 	},
337*4882a593Smuzhiyun 	[DA9150_IRQ_WKUP] = {
338*4882a593Smuzhiyun 		.reg_offset = 3,
339*4882a593Smuzhiyun 		.mask = DA9150_E_WKUP_MASK,
340*4882a593Smuzhiyun 	},
341*4882a593Smuzhiyun };
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun static const struct regmap_irq_chip da9150_regmap_irq_chip = {
344*4882a593Smuzhiyun 	.name = "da9150_irq",
345*4882a593Smuzhiyun 	.status_base = DA9150_EVENT_E,
346*4882a593Smuzhiyun 	.mask_base = DA9150_IRQ_MASK_E,
347*4882a593Smuzhiyun 	.ack_base = DA9150_EVENT_E,
348*4882a593Smuzhiyun 	.num_regs = DA9150_NUM_IRQ_REGS,
349*4882a593Smuzhiyun 	.irqs = da9150_irqs,
350*4882a593Smuzhiyun 	.num_irqs = ARRAY_SIZE(da9150_irqs),
351*4882a593Smuzhiyun };
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun static struct resource da9150_gpadc_resources[] = {
354*4882a593Smuzhiyun 	DEFINE_RES_IRQ_NAMED(DA9150_IRQ_GPADC, "GPADC"),
355*4882a593Smuzhiyun };
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun static struct resource da9150_charger_resources[] = {
358*4882a593Smuzhiyun 	DEFINE_RES_IRQ_NAMED(DA9150_IRQ_CHG, "CHG_STATUS"),
359*4882a593Smuzhiyun 	DEFINE_RES_IRQ_NAMED(DA9150_IRQ_TJUNC, "CHG_TJUNC"),
360*4882a593Smuzhiyun 	DEFINE_RES_IRQ_NAMED(DA9150_IRQ_VFAULT, "CHG_VFAULT"),
361*4882a593Smuzhiyun 	DEFINE_RES_IRQ_NAMED(DA9150_IRQ_VBUS, "CHG_VBUS"),
362*4882a593Smuzhiyun };
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun static struct resource da9150_fg_resources[] = {
365*4882a593Smuzhiyun 	DEFINE_RES_IRQ_NAMED(DA9150_IRQ_FG, "FG"),
366*4882a593Smuzhiyun };
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun enum da9150_dev_idx {
369*4882a593Smuzhiyun 	DA9150_GPADC_IDX = 0,
370*4882a593Smuzhiyun 	DA9150_CHARGER_IDX,
371*4882a593Smuzhiyun 	DA9150_FG_IDX,
372*4882a593Smuzhiyun };
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun static struct mfd_cell da9150_devs[] = {
375*4882a593Smuzhiyun 	[DA9150_GPADC_IDX] = {
376*4882a593Smuzhiyun 		.name = "da9150-gpadc",
377*4882a593Smuzhiyun 		.of_compatible = "dlg,da9150-gpadc",
378*4882a593Smuzhiyun 		.resources = da9150_gpadc_resources,
379*4882a593Smuzhiyun 		.num_resources = ARRAY_SIZE(da9150_gpadc_resources),
380*4882a593Smuzhiyun 	},
381*4882a593Smuzhiyun 	[DA9150_CHARGER_IDX] = {
382*4882a593Smuzhiyun 		.name = "da9150-charger",
383*4882a593Smuzhiyun 		.of_compatible = "dlg,da9150-charger",
384*4882a593Smuzhiyun 		.resources = da9150_charger_resources,
385*4882a593Smuzhiyun 		.num_resources = ARRAY_SIZE(da9150_charger_resources),
386*4882a593Smuzhiyun 	},
387*4882a593Smuzhiyun 	[DA9150_FG_IDX] = {
388*4882a593Smuzhiyun 		.name = "da9150-fuel-gauge",
389*4882a593Smuzhiyun 		.of_compatible = "dlg,da9150-fuel-gauge",
390*4882a593Smuzhiyun 		.resources = da9150_fg_resources,
391*4882a593Smuzhiyun 		.num_resources = ARRAY_SIZE(da9150_fg_resources),
392*4882a593Smuzhiyun 	},
393*4882a593Smuzhiyun };
394*4882a593Smuzhiyun 
da9150_probe(struct i2c_client * client,const struct i2c_device_id * id)395*4882a593Smuzhiyun static int da9150_probe(struct i2c_client *client,
396*4882a593Smuzhiyun 			const struct i2c_device_id *id)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun 	struct da9150 *da9150;
399*4882a593Smuzhiyun 	struct da9150_pdata *pdata = dev_get_platdata(&client->dev);
400*4882a593Smuzhiyun 	int qif_addr;
401*4882a593Smuzhiyun 	int ret;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	da9150 = devm_kzalloc(&client->dev, sizeof(*da9150), GFP_KERNEL);
404*4882a593Smuzhiyun 	if (!da9150)
405*4882a593Smuzhiyun 		return -ENOMEM;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	da9150->dev = &client->dev;
408*4882a593Smuzhiyun 	da9150->irq = client->irq;
409*4882a593Smuzhiyun 	i2c_set_clientdata(client, da9150);
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	da9150->regmap = devm_regmap_init_i2c(client, &da9150_regmap_config);
412*4882a593Smuzhiyun 	if (IS_ERR(da9150->regmap)) {
413*4882a593Smuzhiyun 		ret = PTR_ERR(da9150->regmap);
414*4882a593Smuzhiyun 		dev_err(da9150->dev, "Failed to allocate register map: %d\n",
415*4882a593Smuzhiyun 			ret);
416*4882a593Smuzhiyun 		return ret;
417*4882a593Smuzhiyun 	}
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	/* Setup secondary I2C interface for QIF access */
420*4882a593Smuzhiyun 	qif_addr = da9150_reg_read(da9150, DA9150_CORE2WIRE_CTRL_A);
421*4882a593Smuzhiyun 	qif_addr = (qif_addr & DA9150_CORE_BASE_ADDR_MASK) >> 1;
422*4882a593Smuzhiyun 	qif_addr |= DA9150_QIF_I2C_ADDR_LSB;
423*4882a593Smuzhiyun 	da9150->core_qif = i2c_new_dummy_device(client->adapter, qif_addr);
424*4882a593Smuzhiyun 	if (IS_ERR(da9150->core_qif)) {
425*4882a593Smuzhiyun 		dev_err(da9150->dev, "Failed to attach QIF client\n");
426*4882a593Smuzhiyun 		return PTR_ERR(da9150->core_qif);
427*4882a593Smuzhiyun 	}
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	i2c_set_clientdata(da9150->core_qif, da9150);
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun 	if (pdata) {
432*4882a593Smuzhiyun 		da9150->irq_base = pdata->irq_base;
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 		da9150_devs[DA9150_FG_IDX].platform_data = pdata->fg_pdata;
435*4882a593Smuzhiyun 		da9150_devs[DA9150_FG_IDX].pdata_size =
436*4882a593Smuzhiyun 			sizeof(struct da9150_fg_pdata);
437*4882a593Smuzhiyun 	} else {
438*4882a593Smuzhiyun 		da9150->irq_base = -1;
439*4882a593Smuzhiyun 	}
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	ret = regmap_add_irq_chip(da9150->regmap, da9150->irq,
442*4882a593Smuzhiyun 				  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
443*4882a593Smuzhiyun 				  da9150->irq_base, &da9150_regmap_irq_chip,
444*4882a593Smuzhiyun 				  &da9150->regmap_irq_data);
445*4882a593Smuzhiyun 	if (ret) {
446*4882a593Smuzhiyun 		dev_err(da9150->dev, "Failed to add regmap irq chip: %d\n",
447*4882a593Smuzhiyun 			ret);
448*4882a593Smuzhiyun 		goto regmap_irq_fail;
449*4882a593Smuzhiyun 	}
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 
452*4882a593Smuzhiyun 	da9150->irq_base = regmap_irq_chip_get_base(da9150->regmap_irq_data);
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	enable_irq_wake(da9150->irq);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	ret = mfd_add_devices(da9150->dev, -1, da9150_devs,
457*4882a593Smuzhiyun 			      ARRAY_SIZE(da9150_devs), NULL,
458*4882a593Smuzhiyun 			      da9150->irq_base, NULL);
459*4882a593Smuzhiyun 	if (ret) {
460*4882a593Smuzhiyun 		dev_err(da9150->dev, "Failed to add child devices: %d\n", ret);
461*4882a593Smuzhiyun 		goto mfd_fail;
462*4882a593Smuzhiyun 	}
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	return 0;
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun mfd_fail:
467*4882a593Smuzhiyun 	regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
468*4882a593Smuzhiyun regmap_irq_fail:
469*4882a593Smuzhiyun 	i2c_unregister_device(da9150->core_qif);
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	return ret;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun 
da9150_remove(struct i2c_client * client)474*4882a593Smuzhiyun static int da9150_remove(struct i2c_client *client)
475*4882a593Smuzhiyun {
476*4882a593Smuzhiyun 	struct da9150 *da9150 = i2c_get_clientdata(client);
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
479*4882a593Smuzhiyun 	mfd_remove_devices(da9150->dev);
480*4882a593Smuzhiyun 	i2c_unregister_device(da9150->core_qif);
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	return 0;
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun 
da9150_shutdown(struct i2c_client * client)485*4882a593Smuzhiyun static void da9150_shutdown(struct i2c_client *client)
486*4882a593Smuzhiyun {
487*4882a593Smuzhiyun 	struct da9150 *da9150 = i2c_get_clientdata(client);
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	/* Make sure we have a wakup source for the device */
490*4882a593Smuzhiyun 	da9150_set_bits(da9150, DA9150_CONFIG_D,
491*4882a593Smuzhiyun 			DA9150_WKUP_PM_EN_MASK,
492*4882a593Smuzhiyun 			DA9150_WKUP_PM_EN_MASK);
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	/* Set device to DISABLED mode */
495*4882a593Smuzhiyun 	da9150_set_bits(da9150, DA9150_CONTROL_C,
496*4882a593Smuzhiyun 			DA9150_DISABLE_MASK, DA9150_DISABLE_MASK);
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun static const struct i2c_device_id da9150_i2c_id[] = {
500*4882a593Smuzhiyun 	{ "da9150", },
501*4882a593Smuzhiyun 	{ }
502*4882a593Smuzhiyun };
503*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, da9150_i2c_id);
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun static const struct of_device_id da9150_of_match[] = {
506*4882a593Smuzhiyun 	{ .compatible = "dlg,da9150", },
507*4882a593Smuzhiyun 	{ }
508*4882a593Smuzhiyun };
509*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, da9150_of_match);
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun static struct i2c_driver da9150_driver = {
512*4882a593Smuzhiyun 	.driver	= {
513*4882a593Smuzhiyun 		.name	= "da9150",
514*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(da9150_of_match),
515*4882a593Smuzhiyun 	},
516*4882a593Smuzhiyun 	.probe		= da9150_probe,
517*4882a593Smuzhiyun 	.remove		= da9150_remove,
518*4882a593Smuzhiyun 	.shutdown	= da9150_shutdown,
519*4882a593Smuzhiyun 	.id_table	= da9150_i2c_id,
520*4882a593Smuzhiyun };
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun module_i2c_driver(da9150_driver);
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun MODULE_DESCRIPTION("MFD Core Driver for DA9150");
525*4882a593Smuzhiyun MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
526*4882a593Smuzhiyun MODULE_LICENSE("GPL");
527