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