xref: /OK3568_Linux_fs/kernel/drivers/mfd/as3711.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * AS3711 PMIC MFC driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2012 Renesas Electronics Corporation
6*4882a593Smuzhiyun  * Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/device.h>
10*4882a593Smuzhiyun #include <linux/err.h>
11*4882a593Smuzhiyun #include <linux/i2c.h>
12*4882a593Smuzhiyun #include <linux/init.h>
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/mfd/as3711.h>
15*4882a593Smuzhiyun #include <linux/mfd/core.h>
16*4882a593Smuzhiyun #include <linux/of.h>
17*4882a593Smuzhiyun #include <linux/regmap.h>
18*4882a593Smuzhiyun #include <linux/slab.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun enum {
21*4882a593Smuzhiyun 	AS3711_REGULATOR,
22*4882a593Smuzhiyun 	AS3711_BACKLIGHT,
23*4882a593Smuzhiyun };
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /*
26*4882a593Smuzhiyun  * Ok to have it static: it is only used during probing and multiple I2C devices
27*4882a593Smuzhiyun  * cannot be probed simultaneously. Just make sure to avoid stale data.
28*4882a593Smuzhiyun  */
29*4882a593Smuzhiyun static struct mfd_cell as3711_subdevs[] = {
30*4882a593Smuzhiyun 	[AS3711_REGULATOR] = {.name = "as3711-regulator",},
31*4882a593Smuzhiyun 	[AS3711_BACKLIGHT] = {.name = "as3711-backlight",},
32*4882a593Smuzhiyun };
33*4882a593Smuzhiyun 
as3711_volatile_reg(struct device * dev,unsigned int reg)34*4882a593Smuzhiyun static bool as3711_volatile_reg(struct device *dev, unsigned int reg)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun 	switch (reg) {
37*4882a593Smuzhiyun 	case AS3711_GPIO_SIGNAL_IN:
38*4882a593Smuzhiyun 	case AS3711_INTERRUPT_STATUS_1:
39*4882a593Smuzhiyun 	case AS3711_INTERRUPT_STATUS_2:
40*4882a593Smuzhiyun 	case AS3711_INTERRUPT_STATUS_3:
41*4882a593Smuzhiyun 	case AS3711_CHARGER_STATUS_1:
42*4882a593Smuzhiyun 	case AS3711_CHARGER_STATUS_2:
43*4882a593Smuzhiyun 	case AS3711_REG_STATUS:
44*4882a593Smuzhiyun 		return true;
45*4882a593Smuzhiyun 	}
46*4882a593Smuzhiyun 	return false;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun 
as3711_precious_reg(struct device * dev,unsigned int reg)49*4882a593Smuzhiyun static bool as3711_precious_reg(struct device *dev, unsigned int reg)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun 	switch (reg) {
52*4882a593Smuzhiyun 	case AS3711_INTERRUPT_STATUS_1:
53*4882a593Smuzhiyun 	case AS3711_INTERRUPT_STATUS_2:
54*4882a593Smuzhiyun 	case AS3711_INTERRUPT_STATUS_3:
55*4882a593Smuzhiyun 		return true;
56*4882a593Smuzhiyun 	}
57*4882a593Smuzhiyun 	return false;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun 
as3711_readable_reg(struct device * dev,unsigned int reg)60*4882a593Smuzhiyun static bool as3711_readable_reg(struct device *dev, unsigned int reg)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	switch (reg) {
63*4882a593Smuzhiyun 	case AS3711_SD_1_VOLTAGE:
64*4882a593Smuzhiyun 	case AS3711_SD_2_VOLTAGE:
65*4882a593Smuzhiyun 	case AS3711_SD_3_VOLTAGE:
66*4882a593Smuzhiyun 	case AS3711_SD_4_VOLTAGE:
67*4882a593Smuzhiyun 	case AS3711_LDO_1_VOLTAGE:
68*4882a593Smuzhiyun 	case AS3711_LDO_2_VOLTAGE:
69*4882a593Smuzhiyun 	case AS3711_LDO_3_VOLTAGE:
70*4882a593Smuzhiyun 	case AS3711_LDO_4_VOLTAGE:
71*4882a593Smuzhiyun 	case AS3711_LDO_5_VOLTAGE:
72*4882a593Smuzhiyun 	case AS3711_LDO_6_VOLTAGE:
73*4882a593Smuzhiyun 	case AS3711_LDO_7_VOLTAGE:
74*4882a593Smuzhiyun 	case AS3711_LDO_8_VOLTAGE:
75*4882a593Smuzhiyun 	case AS3711_SD_CONTROL:
76*4882a593Smuzhiyun 	case AS3711_GPIO_SIGNAL_OUT:
77*4882a593Smuzhiyun 	case AS3711_GPIO_SIGNAL_IN:
78*4882a593Smuzhiyun 	case AS3711_SD_CONTROL_1:
79*4882a593Smuzhiyun 	case AS3711_SD_CONTROL_2:
80*4882a593Smuzhiyun 	case AS3711_CURR_CONTROL:
81*4882a593Smuzhiyun 	case AS3711_CURR1_VALUE:
82*4882a593Smuzhiyun 	case AS3711_CURR2_VALUE:
83*4882a593Smuzhiyun 	case AS3711_CURR3_VALUE:
84*4882a593Smuzhiyun 	case AS3711_STEPUP_CONTROL_1:
85*4882a593Smuzhiyun 	case AS3711_STEPUP_CONTROL_2:
86*4882a593Smuzhiyun 	case AS3711_STEPUP_CONTROL_4:
87*4882a593Smuzhiyun 	case AS3711_STEPUP_CONTROL_5:
88*4882a593Smuzhiyun 	case AS3711_REG_STATUS:
89*4882a593Smuzhiyun 	case AS3711_INTERRUPT_STATUS_1:
90*4882a593Smuzhiyun 	case AS3711_INTERRUPT_STATUS_2:
91*4882a593Smuzhiyun 	case AS3711_INTERRUPT_STATUS_3:
92*4882a593Smuzhiyun 	case AS3711_CHARGER_STATUS_1:
93*4882a593Smuzhiyun 	case AS3711_CHARGER_STATUS_2:
94*4882a593Smuzhiyun 	case AS3711_ASIC_ID_1:
95*4882a593Smuzhiyun 	case AS3711_ASIC_ID_2:
96*4882a593Smuzhiyun 		return true;
97*4882a593Smuzhiyun 	}
98*4882a593Smuzhiyun 	return false;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun static const struct regmap_config as3711_regmap_config = {
102*4882a593Smuzhiyun 	.reg_bits = 8,
103*4882a593Smuzhiyun 	.val_bits = 8,
104*4882a593Smuzhiyun 	.volatile_reg = as3711_volatile_reg,
105*4882a593Smuzhiyun 	.readable_reg = as3711_readable_reg,
106*4882a593Smuzhiyun 	.precious_reg = as3711_precious_reg,
107*4882a593Smuzhiyun 	.max_register = AS3711_MAX_REG,
108*4882a593Smuzhiyun 	.num_reg_defaults_raw = AS3711_NUM_REGS,
109*4882a593Smuzhiyun 	.cache_type = REGCACHE_RBTREE,
110*4882a593Smuzhiyun };
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun #ifdef CONFIG_OF
113*4882a593Smuzhiyun static const struct of_device_id as3711_of_match[] = {
114*4882a593Smuzhiyun 	{.compatible = "ams,as3711",},
115*4882a593Smuzhiyun 	{}
116*4882a593Smuzhiyun };
117*4882a593Smuzhiyun #endif
118*4882a593Smuzhiyun 
as3711_i2c_probe(struct i2c_client * client,const struct i2c_device_id * id)119*4882a593Smuzhiyun static int as3711_i2c_probe(struct i2c_client *client,
120*4882a593Smuzhiyun 			    const struct i2c_device_id *id)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun 	struct as3711 *as3711;
123*4882a593Smuzhiyun 	struct as3711_platform_data *pdata;
124*4882a593Smuzhiyun 	unsigned int id1, id2;
125*4882a593Smuzhiyun 	int ret;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	if (!client->dev.of_node) {
128*4882a593Smuzhiyun 		pdata = dev_get_platdata(&client->dev);
129*4882a593Smuzhiyun 		if (!pdata)
130*4882a593Smuzhiyun 			dev_dbg(&client->dev, "Platform data not found\n");
131*4882a593Smuzhiyun 	} else {
132*4882a593Smuzhiyun 		pdata = devm_kzalloc(&client->dev,
133*4882a593Smuzhiyun 				     sizeof(*pdata), GFP_KERNEL);
134*4882a593Smuzhiyun 		if (!pdata)
135*4882a593Smuzhiyun 			return -ENOMEM;
136*4882a593Smuzhiyun 	}
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	as3711 = devm_kzalloc(&client->dev, sizeof(struct as3711), GFP_KERNEL);
139*4882a593Smuzhiyun 	if (!as3711)
140*4882a593Smuzhiyun 		return -ENOMEM;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	as3711->dev = &client->dev;
143*4882a593Smuzhiyun 	i2c_set_clientdata(client, as3711);
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 	if (client->irq)
146*4882a593Smuzhiyun 		dev_notice(&client->dev, "IRQ not supported yet\n");
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	as3711->regmap = devm_regmap_init_i2c(client, &as3711_regmap_config);
149*4882a593Smuzhiyun 	if (IS_ERR(as3711->regmap)) {
150*4882a593Smuzhiyun 		ret = PTR_ERR(as3711->regmap);
151*4882a593Smuzhiyun 		dev_err(&client->dev,
152*4882a593Smuzhiyun 			"regmap initialization failed: %d\n", ret);
153*4882a593Smuzhiyun 		return ret;
154*4882a593Smuzhiyun 	}
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	ret = regmap_read(as3711->regmap, AS3711_ASIC_ID_1, &id1);
157*4882a593Smuzhiyun 	if (!ret)
158*4882a593Smuzhiyun 		ret = regmap_read(as3711->regmap, AS3711_ASIC_ID_2, &id2);
159*4882a593Smuzhiyun 	if (ret < 0) {
160*4882a593Smuzhiyun 		dev_err(&client->dev, "regmap_read() failed: %d\n", ret);
161*4882a593Smuzhiyun 		return ret;
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 	if (id1 != 0x8b)
164*4882a593Smuzhiyun 		return -ENODEV;
165*4882a593Smuzhiyun 	dev_info(as3711->dev, "AS3711 detected: %x:%x\n", id1, id2);
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	/*
168*4882a593Smuzhiyun 	 * We can reuse as3711_subdevs[],
169*4882a593Smuzhiyun 	 * it will be copied in mfd_add_devices()
170*4882a593Smuzhiyun 	 */
171*4882a593Smuzhiyun 	if (pdata) {
172*4882a593Smuzhiyun 		as3711_subdevs[AS3711_REGULATOR].platform_data =
173*4882a593Smuzhiyun 			&pdata->regulator;
174*4882a593Smuzhiyun 		as3711_subdevs[AS3711_REGULATOR].pdata_size =
175*4882a593Smuzhiyun 			sizeof(pdata->regulator);
176*4882a593Smuzhiyun 		as3711_subdevs[AS3711_BACKLIGHT].platform_data =
177*4882a593Smuzhiyun 			&pdata->backlight;
178*4882a593Smuzhiyun 		as3711_subdevs[AS3711_BACKLIGHT].pdata_size =
179*4882a593Smuzhiyun 			sizeof(pdata->backlight);
180*4882a593Smuzhiyun 	} else {
181*4882a593Smuzhiyun 		as3711_subdevs[AS3711_REGULATOR].platform_data = NULL;
182*4882a593Smuzhiyun 		as3711_subdevs[AS3711_REGULATOR].pdata_size = 0;
183*4882a593Smuzhiyun 		as3711_subdevs[AS3711_BACKLIGHT].platform_data = NULL;
184*4882a593Smuzhiyun 		as3711_subdevs[AS3711_BACKLIGHT].pdata_size = 0;
185*4882a593Smuzhiyun 	}
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	ret = devm_mfd_add_devices(as3711->dev, -1, as3711_subdevs,
188*4882a593Smuzhiyun 				   ARRAY_SIZE(as3711_subdevs), NULL, 0, NULL);
189*4882a593Smuzhiyun 	if (ret < 0)
190*4882a593Smuzhiyun 		dev_err(&client->dev, "add mfd devices failed: %d\n", ret);
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	return ret;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun static const struct i2c_device_id as3711_i2c_id[] = {
196*4882a593Smuzhiyun 	{.name = "as3711", .driver_data = 0},
197*4882a593Smuzhiyun 	{}
198*4882a593Smuzhiyun };
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun static struct i2c_driver as3711_i2c_driver = {
201*4882a593Smuzhiyun 	.driver = {
202*4882a593Smuzhiyun 		   .name = "as3711",
203*4882a593Smuzhiyun 		   .of_match_table = of_match_ptr(as3711_of_match),
204*4882a593Smuzhiyun 	},
205*4882a593Smuzhiyun 	.probe = as3711_i2c_probe,
206*4882a593Smuzhiyun 	.id_table = as3711_i2c_id,
207*4882a593Smuzhiyun };
208*4882a593Smuzhiyun 
as3711_i2c_init(void)209*4882a593Smuzhiyun static int __init as3711_i2c_init(void)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun 	return i2c_add_driver(&as3711_i2c_driver);
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun /* Initialise early */
214*4882a593Smuzhiyun subsys_initcall(as3711_i2c_init);
215