1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * I2C access for DA9052 PMICs.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright(c) 2011 Dialog Semiconductor Ltd.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Author: David Dajun Chen <dchen@diasemi.com>
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/device.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/input.h>
13*4882a593Smuzhiyun #include <linux/mfd/core.h>
14*4882a593Smuzhiyun #include <linux/i2c.h>
15*4882a593Smuzhiyun #include <linux/err.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <linux/mfd/da9052/da9052.h>
18*4882a593Smuzhiyun #include <linux/mfd/da9052/reg.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #ifdef CONFIG_OF
21*4882a593Smuzhiyun #include <linux/of.h>
22*4882a593Smuzhiyun #include <linux/of_device.h>
23*4882a593Smuzhiyun #endif
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun /* I2C safe register check */
i2c_safe_reg(unsigned char reg)26*4882a593Smuzhiyun static inline bool i2c_safe_reg(unsigned char reg)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun switch (reg) {
29*4882a593Smuzhiyun case DA9052_STATUS_A_REG:
30*4882a593Smuzhiyun case DA9052_STATUS_B_REG:
31*4882a593Smuzhiyun case DA9052_STATUS_C_REG:
32*4882a593Smuzhiyun case DA9052_STATUS_D_REG:
33*4882a593Smuzhiyun case DA9052_ADC_RES_L_REG:
34*4882a593Smuzhiyun case DA9052_ADC_RES_H_REG:
35*4882a593Smuzhiyun case DA9052_VDD_RES_REG:
36*4882a593Smuzhiyun case DA9052_ICHG_AV_REG:
37*4882a593Smuzhiyun case DA9052_TBAT_RES_REG:
38*4882a593Smuzhiyun case DA9052_ADCIN4_RES_REG:
39*4882a593Smuzhiyun case DA9052_ADCIN5_RES_REG:
40*4882a593Smuzhiyun case DA9052_ADCIN6_RES_REG:
41*4882a593Smuzhiyun case DA9052_TJUNC_RES_REG:
42*4882a593Smuzhiyun case DA9052_TSI_X_MSB_REG:
43*4882a593Smuzhiyun case DA9052_TSI_Y_MSB_REG:
44*4882a593Smuzhiyun case DA9052_TSI_LSB_REG:
45*4882a593Smuzhiyun case DA9052_TSI_Z_MSB_REG:
46*4882a593Smuzhiyun return true;
47*4882a593Smuzhiyun default:
48*4882a593Smuzhiyun return false;
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun /*
53*4882a593Smuzhiyun * There is an issue with DA9052 and DA9053_AA/BA/BB PMIC where the PMIC
54*4882a593Smuzhiyun * gets lockup up or fails to respond following a system reset.
55*4882a593Smuzhiyun * This fix is to follow any read or write with a dummy read to a safe
56*4882a593Smuzhiyun * register.
57*4882a593Smuzhiyun */
da9052_i2c_fix(struct da9052 * da9052,unsigned char reg)58*4882a593Smuzhiyun static int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun int val;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun switch (da9052->chip_id) {
63*4882a593Smuzhiyun case DA9052:
64*4882a593Smuzhiyun case DA9053_AA:
65*4882a593Smuzhiyun case DA9053_BA:
66*4882a593Smuzhiyun case DA9053_BB:
67*4882a593Smuzhiyun /* A dummy read to a safe register address. */
68*4882a593Smuzhiyun if (!i2c_safe_reg(reg))
69*4882a593Smuzhiyun return regmap_read(da9052->regmap,
70*4882a593Smuzhiyun DA9052_PARK_REGISTER,
71*4882a593Smuzhiyun &val);
72*4882a593Smuzhiyun break;
73*4882a593Smuzhiyun case DA9053_BC:
74*4882a593Smuzhiyun default:
75*4882a593Smuzhiyun /*
76*4882a593Smuzhiyun * For other chips parking of I2C register
77*4882a593Smuzhiyun * to a safe place is not required.
78*4882a593Smuzhiyun */
79*4882a593Smuzhiyun break;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun return 0;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun /*
86*4882a593Smuzhiyun * According to errata item 24, multiwrite mode should be avoided
87*4882a593Smuzhiyun * in order to prevent register data corruption after power-down.
88*4882a593Smuzhiyun */
da9052_i2c_disable_multiwrite(struct da9052 * da9052)89*4882a593Smuzhiyun static int da9052_i2c_disable_multiwrite(struct da9052 *da9052)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun int reg_val, ret;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun ret = regmap_read(da9052->regmap, DA9052_CONTROL_B_REG, ®_val);
94*4882a593Smuzhiyun if (ret < 0)
95*4882a593Smuzhiyun return ret;
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun if (!(reg_val & DA9052_CONTROL_B_WRITEMODE)) {
98*4882a593Smuzhiyun reg_val |= DA9052_CONTROL_B_WRITEMODE;
99*4882a593Smuzhiyun ret = regmap_write(da9052->regmap, DA9052_CONTROL_B_REG,
100*4882a593Smuzhiyun reg_val);
101*4882a593Smuzhiyun if (ret < 0)
102*4882a593Smuzhiyun return ret;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun return 0;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun static const struct i2c_device_id da9052_i2c_id[] = {
109*4882a593Smuzhiyun {"da9052", DA9052},
110*4882a593Smuzhiyun {"da9053-aa", DA9053_AA},
111*4882a593Smuzhiyun {"da9053-ba", DA9053_BA},
112*4882a593Smuzhiyun {"da9053-bb", DA9053_BB},
113*4882a593Smuzhiyun {"da9053-bc", DA9053_BC},
114*4882a593Smuzhiyun {}
115*4882a593Smuzhiyun };
116*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, da9052_i2c_id);
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun #ifdef CONFIG_OF
119*4882a593Smuzhiyun static const struct of_device_id dialog_dt_ids[] = {
120*4882a593Smuzhiyun { .compatible = "dlg,da9052", .data = &da9052_i2c_id[0] },
121*4882a593Smuzhiyun { .compatible = "dlg,da9053-aa", .data = &da9052_i2c_id[1] },
122*4882a593Smuzhiyun { .compatible = "dlg,da9053-ba", .data = &da9052_i2c_id[2] },
123*4882a593Smuzhiyun { .compatible = "dlg,da9053-bb", .data = &da9052_i2c_id[3] },
124*4882a593Smuzhiyun { .compatible = "dlg,da9053-bc", .data = &da9052_i2c_id[4] },
125*4882a593Smuzhiyun { /* sentinel */ }
126*4882a593Smuzhiyun };
127*4882a593Smuzhiyun #endif
128*4882a593Smuzhiyun
da9052_i2c_probe(struct i2c_client * client,const struct i2c_device_id * id)129*4882a593Smuzhiyun static int da9052_i2c_probe(struct i2c_client *client,
130*4882a593Smuzhiyun const struct i2c_device_id *id)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun struct da9052 *da9052;
133*4882a593Smuzhiyun int ret;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun da9052 = devm_kzalloc(&client->dev, sizeof(struct da9052), GFP_KERNEL);
136*4882a593Smuzhiyun if (!da9052)
137*4882a593Smuzhiyun return -ENOMEM;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun da9052->dev = &client->dev;
140*4882a593Smuzhiyun da9052->chip_irq = client->irq;
141*4882a593Smuzhiyun da9052->fix_io = da9052_i2c_fix;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun i2c_set_clientdata(client, da9052);
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun da9052->regmap = devm_regmap_init_i2c(client, &da9052_regmap_config);
146*4882a593Smuzhiyun if (IS_ERR(da9052->regmap)) {
147*4882a593Smuzhiyun ret = PTR_ERR(da9052->regmap);
148*4882a593Smuzhiyun dev_err(&client->dev, "Failed to allocate register map: %d\n",
149*4882a593Smuzhiyun ret);
150*4882a593Smuzhiyun return ret;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun ret = da9052_i2c_disable_multiwrite(da9052);
154*4882a593Smuzhiyun if (ret < 0)
155*4882a593Smuzhiyun return ret;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun #ifdef CONFIG_OF
158*4882a593Smuzhiyun if (!id) {
159*4882a593Smuzhiyun struct device_node *np = client->dev.of_node;
160*4882a593Smuzhiyun const struct of_device_id *deviceid;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun deviceid = of_match_node(dialog_dt_ids, np);
163*4882a593Smuzhiyun id = deviceid->data;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun #endif
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun if (!id) {
168*4882a593Smuzhiyun ret = -ENODEV;
169*4882a593Smuzhiyun dev_err(&client->dev, "id is null.\n");
170*4882a593Smuzhiyun return ret;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun return da9052_device_init(da9052, id->driver_data);
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun
da9052_i2c_remove(struct i2c_client * client)176*4882a593Smuzhiyun static int da9052_i2c_remove(struct i2c_client *client)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun struct da9052 *da9052 = i2c_get_clientdata(client);
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun da9052_device_exit(da9052);
181*4882a593Smuzhiyun return 0;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun static struct i2c_driver da9052_i2c_driver = {
185*4882a593Smuzhiyun .probe = da9052_i2c_probe,
186*4882a593Smuzhiyun .remove = da9052_i2c_remove,
187*4882a593Smuzhiyun .id_table = da9052_i2c_id,
188*4882a593Smuzhiyun .driver = {
189*4882a593Smuzhiyun .name = "da9052",
190*4882a593Smuzhiyun #ifdef CONFIG_OF
191*4882a593Smuzhiyun .of_match_table = dialog_dt_ids,
192*4882a593Smuzhiyun #endif
193*4882a593Smuzhiyun },
194*4882a593Smuzhiyun };
195*4882a593Smuzhiyun
da9052_i2c_init(void)196*4882a593Smuzhiyun static int __init da9052_i2c_init(void)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun int ret;
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun ret = i2c_add_driver(&da9052_i2c_driver);
201*4882a593Smuzhiyun if (ret != 0) {
202*4882a593Smuzhiyun pr_err("DA9052 I2C registration failed %d\n", ret);
203*4882a593Smuzhiyun return ret;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun return 0;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun subsys_initcall(da9052_i2c_init);
209*4882a593Smuzhiyun
da9052_i2c_exit(void)210*4882a593Smuzhiyun static void __exit da9052_i2c_exit(void)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun i2c_del_driver(&da9052_i2c_driver);
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun module_exit(da9052_i2c_exit);
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
217*4882a593Smuzhiyun MODULE_DESCRIPTION("I2C driver for Dialog DA9052 PMIC");
218*4882a593Smuzhiyun MODULE_LICENSE("GPL");
219