Merge tag 'io_uring-6.6-2023-10-20' of git://git.kernel.dk/linux
[platform/kernel/linux-starfive.git] / drivers / misc / tps6594-pfsm.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * PFSM (Pre-configurable Finite State Machine) driver for TI 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  */
43 struct tps6594_pfsm {
44         struct miscdevice miscdev;
45         struct regmap *regmap;
46 };
47
48 static ssize_t tps6594_pfsm_read(struct file *f, char __user *buf,
49                                  size_t count, loff_t *ppos)
50 {
51         struct tps6594_pfsm *pfsm = TPS6594_FILE_TO_PFSM(f);
52         loff_t pos = *ppos;
53         unsigned int val;
54         int ret;
55         int i;
56
57         if (pos < 0)
58                 return -EINVAL;
59         if (pos >= TPS6594_PMIC_MAX_POS)
60                 return 0;
61         if (count > TPS6594_PMIC_MAX_POS - pos)
62                 count = TPS6594_PMIC_MAX_POS - pos;
63
64         for (i = 0 ; i < count ; i++) {
65                 ret = regmap_read(pfsm->regmap, pos + i, &val);
66                 if (ret)
67                         return ret;
68
69                 if (put_user(val, buf + i))
70                         return -EFAULT;
71         }
72
73         *ppos = pos + count;
74
75         return count;
76 }
77
78 static ssize_t tps6594_pfsm_write(struct file *f, const char __user *buf,
79                                   size_t count, loff_t *ppos)
80 {
81         struct tps6594_pfsm *pfsm = TPS6594_FILE_TO_PFSM(f);
82         loff_t pos = *ppos;
83         char val;
84         int ret;
85         int i;
86
87         if (pos < 0)
88                 return -EINVAL;
89         if (pos >= TPS6594_PMIC_MAX_POS || !count)
90                 return 0;
91         if (count > TPS6594_PMIC_MAX_POS - pos)
92                 count = TPS6594_PMIC_MAX_POS - pos;
93
94         for (i = 0 ; i < count ; i++) {
95                 if (get_user(val, buf + i))
96                         return -EFAULT;
97
98                 ret = regmap_write(pfsm->regmap, pos + i, val);
99                 if (ret)
100                         return ret;
101         }
102
103         *ppos = pos + count;
104
105         return count;
106 }
107
108 static int tps6594_pfsm_configure_ret_trig(struct regmap *regmap, u8 gpio_ret, u8 ddr_ret)
109 {
110         int ret;
111
112         if (gpio_ret)
113                 ret = regmap_set_bits(regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
114                                       TPS6594_BIT_TRIGGER_I2C(5) | TPS6594_BIT_TRIGGER_I2C(6));
115         else
116                 ret = regmap_clear_bits(regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
117                                         TPS6594_BIT_TRIGGER_I2C(5) | TPS6594_BIT_TRIGGER_I2C(6));
118         if (ret)
119                 return ret;
120
121         if (ddr_ret)
122                 ret = regmap_set_bits(regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
123                                       TPS6594_BIT_TRIGGER_I2C(7));
124         else
125                 ret = regmap_clear_bits(regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
126                                         TPS6594_BIT_TRIGGER_I2C(7));
127
128         return ret;
129 }
130
131 static long tps6594_pfsm_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
132 {
133         struct tps6594_pfsm *pfsm = TPS6594_FILE_TO_PFSM(f);
134         struct pmic_state_opt state_opt;
135         void __user *argp = (void __user *)arg;
136         int ret = -ENOIOCTLCMD;
137
138         switch (cmd) {
139         case PMIC_GOTO_STANDBY:
140                 /* Disable LP mode */
141                 ret = regmap_clear_bits(pfsm->regmap, TPS6594_REG_RTC_CTRL_2,
142                                         TPS6594_BIT_LP_STANDBY_SEL);
143                 if (ret)
144                         return ret;
145
146                 /* Force trigger */
147                 ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
148                                         TPS6594_BIT_TRIGGER_I2C(0), TPS6594_BIT_TRIGGER_I2C(0));
149                 break;
150         case PMIC_GOTO_LP_STANDBY:
151                 /* Enable LP mode */
152                 ret = regmap_set_bits(pfsm->regmap, TPS6594_REG_RTC_CTRL_2,
153                                       TPS6594_BIT_LP_STANDBY_SEL);
154                 if (ret)
155                         return ret;
156
157                 /* Force trigger */
158                 ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
159                                         TPS6594_BIT_TRIGGER_I2C(0), TPS6594_BIT_TRIGGER_I2C(0));
160                 break;
161         case PMIC_UPDATE_PGM:
162                 /* Force trigger */
163                 ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_FSM_I2C_TRIGGERS,
164                                         TPS6594_BIT_TRIGGER_I2C(3), TPS6594_BIT_TRIGGER_I2C(3));
165                 break;
166         case PMIC_SET_ACTIVE_STATE:
167                 /* Modify NSLEEP1-2 bits */
168                 ret = regmap_set_bits(pfsm->regmap, TPS6594_REG_FSM_NSLEEP_TRIGGERS,
169                                       TPS6594_BIT_NSLEEP1B | TPS6594_BIT_NSLEEP2B);
170                 break;
171         case PMIC_SET_MCU_ONLY_STATE:
172                 if (copy_from_user(&state_opt, argp, sizeof(state_opt)))
173                         return -EFAULT;
174
175                 /* Configure retention triggers */
176                 ret = tps6594_pfsm_configure_ret_trig(pfsm->regmap, state_opt.gpio_retention,
177                                                       state_opt.ddr_retention);
178                 if (ret)
179                         return ret;
180
181                 /* Modify NSLEEP1-2 bits */
182                 ret = regmap_clear_bits(pfsm->regmap, TPS6594_REG_FSM_NSLEEP_TRIGGERS,
183                                         TPS6594_BIT_NSLEEP1B);
184                 if (ret)
185                         return ret;
186
187                 ret = regmap_set_bits(pfsm->regmap, TPS6594_REG_FSM_NSLEEP_TRIGGERS,
188                                       TPS6594_BIT_NSLEEP2B);
189                 break;
190         case PMIC_SET_RETENTION_STATE:
191                 if (copy_from_user(&state_opt, argp, sizeof(state_opt)))
192                         return -EFAULT;
193
194                 /* Configure wake-up destination */
195                 if (state_opt.mcu_only_startup_dest)
196                         ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_RTC_CTRL_2,
197                                                 TPS6594_MASK_STARTUP_DEST,
198                                                 TPS6594_STARTUP_DEST_MCU_ONLY);
199                 else
200                         ret = regmap_write_bits(pfsm->regmap, TPS6594_REG_RTC_CTRL_2,
201                                                 TPS6594_MASK_STARTUP_DEST,
202                                                 TPS6594_STARTUP_DEST_ACTIVE);
203                 if (ret)
204                         return ret;
205
206                 /* Configure retention triggers */
207                 ret = tps6594_pfsm_configure_ret_trig(pfsm->regmap, state_opt.gpio_retention,
208                                                       state_opt.ddr_retention);
209                 if (ret)
210                         return ret;
211
212                 /* Modify NSLEEP1-2 bits */
213                 ret = regmap_clear_bits(pfsm->regmap, TPS6594_REG_FSM_NSLEEP_TRIGGERS,
214                                         TPS6594_BIT_NSLEEP2B);
215                 break;
216         }
217
218         return ret;
219 }
220
221 static const struct file_operations tps6594_pfsm_fops = {
222         .owner          = THIS_MODULE,
223         .llseek         = generic_file_llseek,
224         .read           = tps6594_pfsm_read,
225         .write          = tps6594_pfsm_write,
226         .unlocked_ioctl = tps6594_pfsm_ioctl,
227         .compat_ioctl   = compat_ptr_ioctl,
228 };
229
230 static irqreturn_t tps6594_pfsm_isr(int irq, void *dev_id)
231 {
232         struct platform_device *pdev = dev_id;
233         int i;
234
235         for (i = 0 ; i < pdev->num_resources ; i++) {
236                 if (irq == platform_get_irq_byname(pdev, pdev->resource[i].name)) {
237                         dev_err(pdev->dev.parent, "%s event detected\n", pdev->resource[i].name);
238                         return IRQ_HANDLED;
239                 }
240         }
241
242         return IRQ_NONE;
243 }
244
245 static int tps6594_pfsm_probe(struct platform_device *pdev)
246 {
247         struct tps6594_pfsm *pfsm;
248         struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent);
249         struct device *dev = &pdev->dev;
250         int irq;
251         int ret;
252         int i;
253
254         pfsm = devm_kzalloc(dev, sizeof(struct tps6594_pfsm), GFP_KERNEL);
255         if (!pfsm)
256                 return -ENOMEM;
257
258         pfsm->regmap = tps->regmap;
259
260         pfsm->miscdev.minor = MISC_DYNAMIC_MINOR;
261         pfsm->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "pfsm-%ld-0x%02x",
262                                             tps->chip_id, tps->reg);
263         pfsm->miscdev.fops = &tps6594_pfsm_fops;
264         pfsm->miscdev.parent = dev->parent;
265
266         for (i = 0 ; i < pdev->num_resources ; i++) {
267                 irq = platform_get_irq_byname(pdev, pdev->resource[i].name);
268                 if (irq < 0)
269                         return irq;
270
271                 ret = devm_request_threaded_irq(dev, irq, NULL,
272                                                 tps6594_pfsm_isr, IRQF_ONESHOT,
273                                                 pdev->resource[i].name, pdev);
274                 if (ret)
275                         return dev_err_probe(dev, ret, "Failed to request irq\n");
276         }
277
278         platform_set_drvdata(pdev, pfsm);
279
280         return misc_register(&pfsm->miscdev);
281 }
282
283 static void tps6594_pfsm_remove(struct platform_device *pdev)
284 {
285         struct tps6594_pfsm *pfsm = platform_get_drvdata(pdev);
286
287         misc_deregister(&pfsm->miscdev);
288 }
289
290 static struct platform_driver tps6594_pfsm_driver = {
291         .driver = {
292                 .name = "tps6594-pfsm",
293         },
294         .probe = tps6594_pfsm_probe,
295         .remove_new = tps6594_pfsm_remove,
296 };
297
298 module_platform_driver(tps6594_pfsm_driver);
299
300 MODULE_ALIAS("platform:tps6594-pfsm");
301 MODULE_AUTHOR("Julien Panis <jpanis@baylibre.com>");
302 MODULE_DESCRIPTION("TPS6594 Pre-configurable Finite State Machine Driver");
303 MODULE_LICENSE("GPL");