xref: /linux/drivers/misc/tps6594-pfsm.c (revision bf977a9ad33d204c8ca646cef83184eb364820ff)
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