Commit | Line | Data |
---|---|---|
74c17a0a JN |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // | |
3 | // Driver for TPS65219 Integrated Power Management Integrated Chips (PMIC) | |
4 | // | |
5 | // Copyright (C) 2022 BayLibre Incorporated - https://www.baylibre.com/ | |
6 | ||
7 | #include <linux/i2c.h> | |
8 | #include <linux/reboot.h> | |
9 | #include <linux/regmap.h> | |
10 | ||
11 | #include <linux/mfd/core.h> | |
12 | #include <linux/mfd/tps65219.h> | |
13 | ||
14 | static int tps65219_warm_reset(struct tps65219 *tps) | |
15 | { | |
16 | return regmap_update_bits(tps->regmap, TPS65219_REG_MFP_CTRL, | |
17 | TPS65219_MFP_WARM_RESET_I2C_CTRL_MASK, | |
18 | TPS65219_MFP_WARM_RESET_I2C_CTRL_MASK); | |
19 | } | |
20 | ||
21 | static int tps65219_cold_reset(struct tps65219 *tps) | |
22 | { | |
23 | return regmap_update_bits(tps->regmap, TPS65219_REG_MFP_CTRL, | |
24 | TPS65219_MFP_COLD_RESET_I2C_CTRL_MASK, | |
25 | TPS65219_MFP_COLD_RESET_I2C_CTRL_MASK); | |
26 | } | |
27 | ||
28 | static int tps65219_restart(struct notifier_block *this, | |
29 | unsigned long reboot_mode, void *cmd) | |
30 | { | |
31 | struct tps65219 *tps; | |
32 | ||
33 | tps = container_of(this, struct tps65219, nb); | |
34 | ||
35 | if (reboot_mode == REBOOT_WARM) | |
36 | tps65219_warm_reset(tps); | |
37 | else | |
38 | tps65219_cold_reset(tps); | |
39 | ||
40 | return NOTIFY_DONE; | |
41 | } | |
42 | ||
43 | static struct notifier_block pmic_rst_restart_nb = { | |
44 | .notifier_call = tps65219_restart, | |
45 | .priority = 200, | |
46 | }; | |
47 | ||
48 | static const struct resource tps65219_pwrbutton_resources[] = { | |
49 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_PB_FALLING_EDGE_DETECT, "falling"), | |
50 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_PB_RISING_EDGE_DETECT, "rising"), | |
51 | }; | |
52 | ||
53 | static const struct resource tps65219_regulator_resources[] = { | |
54 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO3_SCG, "LDO3_SCG"), | |
55 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO3_OC, "LDO3_OC"), | |
56 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO3_UV, "LDO3_UV"), | |
57 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO4_SCG, "LDO4_SCG"), | |
58 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO4_OC, "LDO4_OC"), | |
59 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO4_UV, "LDO4_UV"), | |
60 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO1_SCG, "LDO1_SCG"), | |
61 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO1_OC, "LDO1_OC"), | |
62 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO1_UV, "LDO1_UV"), | |
63 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO2_SCG, "LDO2_SCG"), | |
64 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO2_OC, "LDO2_OC"), | |
65 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO2_UV, "LDO2_UV"), | |
66 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK3_SCG, "BUCK3_SCG"), | |
67 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK3_OC, "BUCK3_OC"), | |
68 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK3_NEG_OC, "BUCK3_NEG_OC"), | |
69 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK3_UV, "BUCK3_UV"), | |
70 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK1_SCG, "BUCK1_SCG"), | |
71 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK1_OC, "BUCK1_OC"), | |
72 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK1_NEG_OC, "BUCK1_NEG_OC"), | |
73 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK1_UV, "BUCK1_UV"), | |
74 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK2_SCG, "BUCK2_SCG"), | |
75 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK2_OC, "BUCK2_OC"), | |
76 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK2_NEG_OC, "BUCK2_NEG_OC"), | |
77 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK2_UV, "BUCK2_UV"), | |
78 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK1_RV, "BUCK1_RV"), | |
79 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK2_RV, "BUCK2_RV"), | |
80 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK3_RV, "BUCK3_RV"), | |
81 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO1_RV, "LDO1_RV"), | |
82 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO2_RV, "LDO2_RV"), | |
83 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO3_RV, "LDO3_RV"), | |
84 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO4_RV, "LDO4_RV"), | |
85 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK1_RV_SD, "BUCK1_RV_SD"), | |
86 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK2_RV_SD, "BUCK2_RV_SD"), | |
87 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK3_RV_SD, "BUCK3_RV_SD"), | |
88 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO1_RV_SD, "LDO1_RV_SD"), | |
89 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO2_RV_SD, "LDO2_RV_SD"), | |
90 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO3_RV_SD, "LDO3_RV_SD"), | |
91 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO4_RV_SD, "LDO4_RV_SD"), | |
92 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_TIMEOUT, "TIMEOUT"), | |
93 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_3_WARM, "SENSOR_3_WARM"), | |
94 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_2_WARM, "SENSOR_2_WARM"), | |
95 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_1_WARM, "SENSOR_1_WARM"), | |
96 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_0_WARM, "SENSOR_0_WARM"), | |
97 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_3_HOT, "SENSOR_3_HOT"), | |
98 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_2_HOT, "SENSOR_2_HOT"), | |
99 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_1_HOT, "SENSOR_1_HOT"), | |
100 | DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_0_HOT, "SENSOR_0_HOT"), | |
101 | }; | |
102 | ||
103 | static const struct mfd_cell tps65219_cells[] = { | |
104 | { | |
105 | .name = "tps65219-regulator", | |
106 | .resources = tps65219_regulator_resources, | |
107 | .num_resources = ARRAY_SIZE(tps65219_regulator_resources), | |
108 | }, | |
109 | { .name = "tps65219-gpios", }, | |
110 | }; | |
111 | ||
112 | static const struct mfd_cell tps65219_pwrbutton_cell = { | |
113 | .name = "tps65219-pwrbutton", | |
114 | .resources = tps65219_pwrbutton_resources, | |
115 | .num_resources = ARRAY_SIZE(tps65219_pwrbutton_resources), | |
116 | }; | |
117 | ||
118 | static const struct regmap_config tps65219_regmap_config = { | |
119 | .reg_bits = 8, | |
120 | .val_bits = 8, | |
121 | .max_register = TPS65219_REG_FACTORY_CONFIG_2, | |
122 | }; | |
123 | ||
124 | /* | |
125 | * Mapping of main IRQ register bits to sub-IRQ register offsets so that we can | |
126 | * access corect sub-IRQ registers based on bits that are set in main IRQ | |
127 | * register. | |
128 | */ | |
129 | /* Timeout Residual Voltage Shutdown */ | |
130 | static unsigned int bit0_offsets[] = { TPS65219_REG_INT_TO_RV_POS }; | |
131 | static unsigned int bit1_offsets[] = { TPS65219_REG_INT_RV_POS }; /* Residual Voltage */ | |
132 | static unsigned int bit2_offsets[] = { TPS65219_REG_INT_SYS_POS }; /* System */ | |
133 | static unsigned int bit3_offsets[] = { TPS65219_REG_INT_BUCK_1_2_POS }; /* Buck 1-2 */ | |
134 | static unsigned int bit4_offsets[] = { TPS65219_REG_INT_BUCK_3_POS }; /* Buck 3 */ | |
135 | static unsigned int bit5_offsets[] = { TPS65219_REG_INT_LDO_1_2_POS }; /* LDO 1-2 */ | |
136 | static unsigned int bit6_offsets[] = { TPS65219_REG_INT_LDO_3_4_POS }; /* LDO 3-4 */ | |
137 | static unsigned int bit7_offsets[] = { TPS65219_REG_INT_PB_POS }; /* Power Button */ | |
138 | ||
139 | static struct regmap_irq_sub_irq_map tps65219_sub_irq_offsets[] = { | |
140 | REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets), | |
141 | REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets), | |
142 | REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets), | |
143 | REGMAP_IRQ_MAIN_REG_OFFSET(bit3_offsets), | |
144 | REGMAP_IRQ_MAIN_REG_OFFSET(bit4_offsets), | |
145 | REGMAP_IRQ_MAIN_REG_OFFSET(bit5_offsets), | |
146 | REGMAP_IRQ_MAIN_REG_OFFSET(bit6_offsets), | |
147 | REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets), | |
148 | }; | |
149 | ||
150 | #define TPS65219_REGMAP_IRQ_REG(int_name, register_position) \ | |
151 | REGMAP_IRQ_REG(int_name, register_position, int_name##_MASK) | |
152 | ||
153 | static struct regmap_irq tps65219_irqs[] = { | |
154 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO3_SCG, TPS65219_REG_INT_LDO_3_4_POS), | |
155 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO3_OC, TPS65219_REG_INT_LDO_3_4_POS), | |
156 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO3_UV, TPS65219_REG_INT_LDO_3_4_POS), | |
157 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO4_SCG, TPS65219_REG_INT_LDO_3_4_POS), | |
158 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO4_OC, TPS65219_REG_INT_LDO_3_4_POS), | |
159 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO4_UV, TPS65219_REG_INT_LDO_3_4_POS), | |
160 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO1_SCG, TPS65219_REG_INT_LDO_1_2_POS), | |
161 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO1_OC, TPS65219_REG_INT_LDO_1_2_POS), | |
162 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO1_UV, TPS65219_REG_INT_LDO_1_2_POS), | |
163 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO2_SCG, TPS65219_REG_INT_LDO_1_2_POS), | |
164 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO2_OC, TPS65219_REG_INT_LDO_1_2_POS), | |
165 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO2_UV, TPS65219_REG_INT_LDO_1_2_POS), | |
166 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK3_SCG, TPS65219_REG_INT_BUCK_3_POS), | |
167 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK3_OC, TPS65219_REG_INT_BUCK_3_POS), | |
168 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK3_NEG_OC, TPS65219_REG_INT_BUCK_3_POS), | |
169 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK3_UV, TPS65219_REG_INT_BUCK_3_POS), | |
170 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK2_SCG, TPS65219_REG_INT_BUCK_1_2_POS), | |
171 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK2_OC, TPS65219_REG_INT_BUCK_1_2_POS), | |
172 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK2_NEG_OC, TPS65219_REG_INT_BUCK_1_2_POS), | |
173 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK2_UV, TPS65219_REG_INT_BUCK_1_2_POS), | |
174 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK1_SCG, TPS65219_REG_INT_BUCK_1_2_POS), | |
175 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK1_OC, TPS65219_REG_INT_BUCK_1_2_POS), | |
176 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK1_NEG_OC, TPS65219_REG_INT_BUCK_1_2_POS), | |
177 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK1_UV, TPS65219_REG_INT_BUCK_1_2_POS), | |
178 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_3_WARM, TPS65219_REG_INT_SYS_POS), | |
179 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_2_WARM, TPS65219_REG_INT_SYS_POS), | |
180 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_1_WARM, TPS65219_REG_INT_SYS_POS), | |
181 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_0_WARM, TPS65219_REG_INT_SYS_POS), | |
182 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_3_HOT, TPS65219_REG_INT_SYS_POS), | |
183 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_2_HOT, TPS65219_REG_INT_SYS_POS), | |
184 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_1_HOT, TPS65219_REG_INT_SYS_POS), | |
185 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_0_HOT, TPS65219_REG_INT_SYS_POS), | |
186 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK1_RV, TPS65219_REG_INT_RV_POS), | |
187 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK2_RV, TPS65219_REG_INT_RV_POS), | |
188 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK3_RV, TPS65219_REG_INT_RV_POS), | |
189 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO1_RV, TPS65219_REG_INT_RV_POS), | |
190 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO2_RV, TPS65219_REG_INT_RV_POS), | |
191 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO3_RV, TPS65219_REG_INT_RV_POS), | |
192 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO4_RV, TPS65219_REG_INT_RV_POS), | |
193 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK1_RV_SD, TPS65219_REG_INT_TO_RV_POS), | |
194 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK2_RV_SD, TPS65219_REG_INT_TO_RV_POS), | |
195 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK3_RV_SD, TPS65219_REG_INT_TO_RV_POS), | |
196 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO1_RV_SD, TPS65219_REG_INT_TO_RV_POS), | |
197 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO2_RV_SD, TPS65219_REG_INT_TO_RV_POS), | |
198 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO3_RV_SD, TPS65219_REG_INT_TO_RV_POS), | |
199 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO4_RV_SD, TPS65219_REG_INT_TO_RV_POS), | |
200 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_TIMEOUT, TPS65219_REG_INT_TO_RV_POS), | |
201 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_PB_FALLING_EDGE_DETECT, TPS65219_REG_INT_PB_POS), | |
202 | TPS65219_REGMAP_IRQ_REG(TPS65219_INT_PB_RISING_EDGE_DETECT, TPS65219_REG_INT_PB_POS), | |
203 | }; | |
204 | ||
205 | static struct regmap_irq_chip tps65219_irq_chip = { | |
206 | .name = "tps65219_irq", | |
207 | .main_status = TPS65219_REG_INT_SOURCE, | |
208 | .num_main_regs = 1, | |
209 | .num_main_status_bits = 8, | |
210 | .irqs = tps65219_irqs, | |
211 | .num_irqs = ARRAY_SIZE(tps65219_irqs), | |
212 | .status_base = TPS65219_REG_INT_LDO_3_4, | |
213 | .ack_base = TPS65219_REG_INT_LDO_3_4, | |
214 | .clear_ack = 1, | |
215 | .num_regs = 8, | |
216 | .sub_reg_offsets = tps65219_sub_irq_offsets, | |
217 | }; | |
218 | ||
219 | static int tps65219_probe(struct i2c_client *client) | |
220 | { | |
221 | struct tps65219 *tps; | |
222 | unsigned int chipid; | |
223 | bool pwr_button; | |
224 | int ret; | |
225 | ||
226 | tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); | |
227 | if (!tps) | |
228 | return -ENOMEM; | |
229 | ||
230 | i2c_set_clientdata(client, tps); | |
231 | ||
232 | tps->dev = &client->dev; | |
233 | ||
234 | tps->regmap = devm_regmap_init_i2c(client, &tps65219_regmap_config); | |
235 | if (IS_ERR(tps->regmap)) { | |
236 | ret = PTR_ERR(tps->regmap); | |
237 | dev_err(tps->dev, "Failed to allocate register map: %d\n", ret); | |
238 | return ret; | |
239 | } | |
240 | ||
241 | ret = devm_regmap_add_irq_chip(&client->dev, tps->regmap, client->irq, | |
242 | IRQF_ONESHOT, 0, &tps65219_irq_chip, | |
243 | &tps->irq_data); | |
244 | if (ret) | |
245 | return ret; | |
246 | ||
247 | ret = regmap_read(tps->regmap, TPS65219_REG_TI_DEV_ID, &chipid); | |
248 | if (ret) { | |
249 | dev_err(tps->dev, "Failed to read device ID: %d\n", ret); | |
250 | return ret; | |
251 | } | |
252 | ||
253 | ret = devm_mfd_add_devices(tps->dev, PLATFORM_DEVID_AUTO, | |
254 | tps65219_cells, ARRAY_SIZE(tps65219_cells), | |
255 | NULL, 0, regmap_irq_get_domain(tps->irq_data)); | |
256 | if (ret) { | |
257 | dev_err(tps->dev, "Failed to add child devices: %d\n", ret); | |
258 | return ret; | |
259 | } | |
260 | ||
261 | pwr_button = of_property_read_bool(tps->dev->of_node, "ti,power-button"); | |
262 | if (pwr_button) { | |
263 | ret = devm_mfd_add_devices(tps->dev, PLATFORM_DEVID_AUTO, | |
264 | &tps65219_pwrbutton_cell, 1, NULL, 0, | |
265 | regmap_irq_get_domain(tps->irq_data)); | |
266 | if (ret) { | |
267 | dev_err(tps->dev, "Failed to add power-button: %d\n", ret); | |
268 | return ret; | |
269 | } | |
270 | } | |
271 | ||
272 | tps->nb = pmic_rst_restart_nb; | |
273 | ret = register_restart_handler(&tps->nb); | |
274 | if (ret) { | |
275 | dev_err(tps->dev, "cannot register restart handler, %d\n", ret); | |
276 | return ret; | |
277 | } | |
278 | ||
279 | return 0; | |
280 | } | |
281 | ||
282 | static const struct of_device_id of_tps65219_match_table[] = { | |
283 | { .compatible = "ti,tps65219", }, | |
284 | {} | |
285 | }; | |
286 | MODULE_DEVICE_TABLE(of, of_tps65219_match_table); | |
287 | ||
288 | static struct i2c_driver tps65219_driver = { | |
289 | .driver = { | |
290 | .name = "tps65219", | |
291 | .of_match_table = of_tps65219_match_table, | |
292 | }, | |
293 | .probe_new = tps65219_probe, | |
294 | }; | |
295 | module_i2c_driver(tps65219_driver); | |
296 | ||
297 | MODULE_AUTHOR("Jerome Neanne <jneanne@baylibre.com>"); | |
298 | MODULE_DESCRIPTION("TPS65219 power management IC driver"); | |
299 | MODULE_LICENSE("GPL"); |