1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * PFSM (Pre-configurable Finite State Machine) driver for the following
4 * PMICs:
5 * - LP8764
6 * - TPS65224
7 * - TPS652G1
8 * - TPS6594
9 * - TPS6593
10 *
11 * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/
12 */
13
14 #include <linux/errno.h>
15 #include <linux/fs.h>
16 #include <linux/interrupt.h>
17 #include <linux/ioctl.h>
18 #include <linux/miscdevice.h>
19 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 #include <linux/regmap.h>
22
23 #include <linux/mfd/tps6594.h>
24
25 #include <linux/tps6594_pfsm.h>
26
27 #define TPS6594_STARTUP_DEST_MCU_ONLY_VAL 2
28 #define TPS6594_STARTUP_DEST_ACTIVE_VAL 3
29 #define TPS6594_STARTUP_DEST_SHIFT 5
30 #define TPS6594_STARTUP_DEST_MCU_ONLY (TPS6594_STARTUP_DEST_MCU_ONLY_VAL \
31 << TPS6594_STARTUP_DEST_SHIFT)
32 #define TPS6594_STARTUP_DEST_ACTIVE (TPS6594_STARTUP_DEST_ACTIVE_VAL \
33 << TPS6594_STARTUP_DEST_SHIFT)
34
35 /*
36 * To update the PMIC firmware, the user must be able to access
37 * page 0 (user registers) and page 1 (NVM control and configuration).
38 */
39 #define TPS6594_PMIC_MAX_POS 0x200
40
41 #define TPS6594_FILE_TO_PFSM(f) container_of((f)->private_data, struct tps6594_pfsm, miscdev)
42
43 /**
44 * struct tps6594_pfsm - device private data structure
45 *
46 * @miscdev: misc device infos
47 * @regmap: regmap for accessing the device registers
48 * @chip_id: chip identifier of the device
49 */
50 struct tps6594_pfsm {
51 struct miscdevice miscdev;
52 struct regmap *regmap;
53 unsigned long chip_id;
54 };
55
tps6594_pfsm_read(struct file * f,char __user * buf,size_t count,loff_t * ppos)56 static ssize_t tps6594_pfsm_read(struct file *f, char __user *buf,
57 size_t count, loff_t *ppos)
58 {
59 struct tps6594_pfsm *pfsm = TPS6594_FILE_TO_PFSM(f);
60 loff_t pos = *ppos;
61 unsigned int val;
62 int ret;
63 int i;
64
65 if (pos < 0)
66 return -EINVAL;
67 if (pos >= TPS6594_PMIC_MAX_POS)
68 return 0;
69 if (count > TPS6594_PMIC_MAX_POS - pos)
70 count = TPS6594_PMIC_MAX_POS - pos;
71
72 for (i = 0 ; i < count ; i++) {
73 ret = regmap_read(pfsm->regmap, pos + i, &val);
74 if (ret)
75 return ret;
76
77 if (put_user(val, buf + i))
78 return -EFAULT;
79 }
80
81 *ppos = pos + count;
82
83 return count;
84 }
85
tps6594_pfsm_write(struct file * f,const char __user * buf,size_t count,loff_t * ppos)86 static ssize_t tps6594_pfsm_write(struct file *f, const char __user *buf,
87 size_t count, loff_t *ppos)
88 {
89 struct tps6594_pfsm *pfsm = TPS6594_FILE_TO_PFSM(f);
90 loff_t pos = *ppos;
91 char val;
92 int ret;
93 int i;
94
95 if (pos < 0)
96 return -EINVAL;
97 if (pos >= TPS6594_PMIC_MAX_POS || !count)
98 return 0;
99 if (count > TPS6594_PMIC_MAX_POS - pos)
100 count = TPS6594_PMIC_MAX_POS - pos;
101
102 for (i = 0 ; i < count ; i++) {
103 if (get_user(val, buf + i))
104 return -EFAULT;
105
106 ret = regmap_write(pfsm->regmap, pos + i, val);
107 if (ret)
108 return ret;
109 }
110
111 *ppos = pos + count;
112
113 return count;
114 }
115
tps6594_pfsm_configure_ret_trig(struct regmap * regmap,u8 gpio_ret,u8 ddr_ret)116 static int tps6594_pfsm_configure_ret_trig(struct regmap *regmap, u8 gpio_ret, u8 ddr_ret)
117 {
118 int ret;
119
120 if (gpio_ret)
121 ret = regmap_set_bits(regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
122 TPS6594_BIT_TRIGGER_I2C(5) | TPS6594_BIT_TRIGGER_I2C(6));
123 else
124 ret = regmap_clear_bits(regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
125 TPS6594_BIT_TRIGGER_I2C(5) | TPS6594_BIT_TRIGGER_I2C(6));
126 if (ret)
127 return ret;
128
129 if (ddr_ret)
130 ret = regmap_set_bits(regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
131 TPS6594_BIT_TRIGGER_I2C(7));
132 else
133 ret = regmap_clear_bits(regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
134 TPS6594_BIT_TRIGGER_I2C(7));
135
136 return ret;
137 }
138
tps6594_pfsm_ioctl(struct file * f,unsigned int cmd,unsigned long arg)139 static long tps6594_pfsm_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
140 {
141 struct tps6594_pfsm *pfsm = TPS6594_FILE_TO_PFSM(f);
142 struct pmic_state_opt state_opt;
143 void __user *argp = (void __user *)arg;
144 unsigned int regmap_reg, mask;
145 int ret = -ENOIOCTLCMD;
146
147 switch (cmd) {
148 case PMIC_GOTO_STANDBY:
149 /* Disable LP mode on TPS6594 Family PMIC */
150 if (pfsm->chip_id != TPS65224 && pfsm->chip_id != TPS652G1) {
151 ret = regmap_clear_bits(pfsm->regmap, TPS6594_REG_RTC_CTRL_2,
152 TPS6594_BIT_LP_STANDBY_SEL);
153
154 if (ret)
155 return ret;
156 }
157
158 /* Force trigger */
159 ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
160 TPS6594_BIT_TRIGGER_I2C(0), TPS6594_BIT_TRIGGER_I2C(0));
161 break;
162 case PMIC_GOTO_LP_STANDBY:
163 /* TPS65224/TPS652G1 does not support LP STANDBY */
164 if (pfsm->chip_id == TPS65224 || pfsm->chip_id == TPS652G1)
165 return ret;
166
167 /* Enable LP mode */
168 ret = regmap_set_bits(pfsm->regmap, TPS6594_REG_RTC_CTRL_2,
169 TPS6594_BIT_LP_STANDBY_SEL);
170 if (ret)
171 return ret;
172
173 /* Force trigger */
174 ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
175 TPS6594_BIT_TRIGGER_I2C(0), TPS6594_BIT_TRIGGER_I2C(0));
176 break;
177 case PMIC_UPDATE_PGM:
178 /* Force trigger */
179 ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
180 TPS6594_BIT_TRIGGER_I2C(3), TPS6594_BIT_TRIGGER_I2C(3));
181 break;
182 case PMIC_SET_ACTIVE_STATE:
183 /* Modify NSLEEP1-2 bits */
184 ret = regmap_set_bits(pfsm->regmap, TPS6594_REG_FSM_NSLEEP_TRIGGERS,
185 TPS6594_BIT_NSLEEP1B | TPS6594_BIT_NSLEEP2B);
186 break;
187 case PMIC_SET_MCU_ONLY_STATE:
188 /* TPS65224/TPS652G1 does not support MCU_ONLY_STATE */
189 if (pfsm->chip_id == TPS65224 || pfsm->chip_id == TPS652G1)
190 return ret;
191
192 if (copy_from_user(&state_opt, argp, sizeof(state_opt)))
193 return -EFAULT;
194
195 /* Configure retention triggers */
196 ret = tps6594_pfsm_configure_ret_trig(pfsm->regmap, state_opt.gpio_retention,
197 state_opt.ddr_retention);
198 if (ret)
199 return ret;
200
201 /* Modify NSLEEP1-2 bits */
202 ret = regmap_clear_bits(pfsm->regmap, TPS6594_REG_FSM_NSLEEP_TRIGGERS,
203 TPS6594_BIT_NSLEEP1B);
204 if (ret)
205 return ret;
206
207 ret = regmap_set_bits(pfsm->regmap, TPS6594_REG_FSM_NSLEEP_TRIGGERS,
208 TPS6594_BIT_NSLEEP2B);
209 break;
210 case PMIC_SET_RETENTION_STATE:
211 if (copy_from_user(&state_opt, argp, sizeof(state_opt)))
212 return -EFAULT;
213
214 /* Configure wake-up destination */
215 if (pfsm->chip_id == TPS65224 || pfsm->chip_id == TPS652G1) {
216 regmap_reg = TPS65224_REG_STARTUP_CTRL;
217 mask = TPS65224_MASK_STARTUP_DEST;
218 } else {
219 regmap_reg = TPS6594_REG_RTC_CTRL_2;
220 mask = TPS6594_MASK_STARTUP_DEST;
221 }
222
223 if (state_opt.mcu_only_startup_dest)
224 ret = regmap_write_bits(pfsm->regmap, regmap_reg,
225 mask, TPS6594_STARTUP_DEST_MCU_ONLY);
226 else
227 ret = regmap_write_bits(pfsm->regmap, regmap_reg,
228 mask, TPS6594_STARTUP_DEST_ACTIVE);
229 if (ret)
230 return ret;
231
232 /* Configure retention triggers */
233 ret = tps6594_pfsm_configure_ret_trig(pfsm->regmap, state_opt.gpio_retention,
234 state_opt.ddr_retention);
235 if (ret)
236 return ret;
237
238 /* Modify NSLEEP1-2 bits */
239 if (pfsm->chip_id == TPS65224 || pfsm->chip_id == TPS652G1)
240 ret = regmap_clear_bits(pfsm->regmap,
241 TPS6594_REG_FSM_NSLEEP_TRIGGERS,
242 TPS6594_BIT_NSLEEP1B);
243 else
244 ret = regmap_clear_bits(pfsm->regmap,
245 TPS6594_REG_FSM_NSLEEP_TRIGGERS,
246 TPS6594_BIT_NSLEEP2B);
247 break;
248 }
249
250 return ret;
251 }
252
253 static const struct file_operations tps6594_pfsm_fops = {
254 .owner = THIS_MODULE,
255 .llseek = generic_file_llseek,
256 .read = tps6594_pfsm_read,
257 .write = tps6594_pfsm_write,
258 .unlocked_ioctl = tps6594_pfsm_ioctl,
259 .compat_ioctl = compat_ptr_ioctl,
260 };
261
tps6594_pfsm_isr(int irq,void * dev_id)262 static irqreturn_t tps6594_pfsm_isr(int irq, void *dev_id)
263 {
264 struct platform_device *pdev = dev_id;
265 int i;
266
267 for (i = 0 ; i < pdev->num_resources ; i++) {
268 if (irq == platform_get_irq_byname(pdev, pdev->resource[i].name)) {
269 dev_err(pdev->dev.parent, "%s event detected\n", pdev->resource[i].name);
270 return IRQ_HANDLED;
271 }
272 }
273
274 return IRQ_NONE;
275 }
276
tps6594_pfsm_probe(struct platform_device * pdev)277 static int tps6594_pfsm_probe(struct platform_device *pdev)
278 {
279 struct tps6594_pfsm *pfsm;
280 struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent);
281 struct device *dev = &pdev->dev;
282 int irq;
283 int ret;
284 int i;
285
286 pfsm = devm_kzalloc(dev, sizeof(struct tps6594_pfsm), GFP_KERNEL);
287 if (!pfsm)
288 return -ENOMEM;
289
290 pfsm->regmap = tps->regmap;
291
292 pfsm->miscdev.minor = MISC_DYNAMIC_MINOR;
293 pfsm->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "pfsm-%ld-0x%02x",
294 tps->chip_id, tps->reg);
295 if (!pfsm->miscdev.name)
296 return -ENOMEM;
297
298 pfsm->miscdev.fops = &tps6594_pfsm_fops;
299 pfsm->miscdev.parent = dev->parent;
300 pfsm->chip_id = tps->chip_id;
301
302 for (i = 0 ; i < pdev->num_resources ; i++) {
303 irq = platform_get_irq_byname(pdev, pdev->resource[i].name);
304 if (irq < 0)
305 return irq;
306
307 ret = devm_request_threaded_irq(dev, irq, NULL,
308 tps6594_pfsm_isr, IRQF_ONESHOT,
309 pdev->resource[i].name, pdev);
310 if (ret)
311 return dev_err_probe(dev, ret, "Failed to request irq\n");
312 }
313
314 platform_set_drvdata(pdev, pfsm);
315
316 return misc_register(&pfsm->miscdev);
317 }
318
tps6594_pfsm_remove(struct platform_device * pdev)319 static void tps6594_pfsm_remove(struct platform_device *pdev)
320 {
321 struct tps6594_pfsm *pfsm = platform_get_drvdata(pdev);
322
323 misc_deregister(&pfsm->miscdev);
324 }
325
326 static struct platform_driver tps6594_pfsm_driver = {
327 .driver = {
328 .name = "tps6594-pfsm",
329 },
330 .probe = tps6594_pfsm_probe,
331 .remove = tps6594_pfsm_remove,
332 };
333
334 module_platform_driver(tps6594_pfsm_driver);
335
336 MODULE_ALIAS("platform:tps6594-pfsm");
337 MODULE_AUTHOR("Julien Panis <jpanis@baylibre.com>");
338 MODULE_DESCRIPTION("TPS6594 Pre-configurable Finite State Machine Driver");
339 MODULE_LICENSE("GPL");
340