]>
Commit | Line | Data |
---|---|---|
8a4e6154 MF |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* | |
3 | * TI TPS380x Supply Voltage Supervisor and Reset Controller Driver | |
4 | * | |
5 | * Copyright (C) 2022 Pengutronix, Marco Felsch <[email protected]> | |
6 | * | |
7 | * Based on Simple Reset Controller Driver | |
8 | * | |
9 | * Copyright (C) 2017 Pengutronix, Philipp Zabel <[email protected]> | |
10 | */ | |
11 | ||
12 | #include <linux/delay.h> | |
13 | #include <linux/gpio/consumer.h> | |
14 | #include <linux/module.h> | |
15 | #include <linux/of.h> | |
16 | #include <linux/platform_device.h> | |
17 | #include <linux/property.h> | |
18 | #include <linux/reset-controller.h> | |
19 | ||
20 | struct tps380x_reset { | |
21 | struct reset_controller_dev rcdev; | |
22 | struct gpio_desc *reset_gpio; | |
23 | unsigned int reset_ms; | |
24 | }; | |
25 | ||
26 | struct tps380x_reset_devdata { | |
27 | unsigned int min_reset_ms; | |
28 | unsigned int typ_reset_ms; | |
29 | unsigned int max_reset_ms; | |
30 | }; | |
31 | ||
32 | static inline | |
33 | struct tps380x_reset *to_tps380x_reset(struct reset_controller_dev *rcdev) | |
34 | { | |
35 | return container_of(rcdev, struct tps380x_reset, rcdev); | |
36 | } | |
37 | ||
38 | static int | |
39 | tps380x_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) | |
40 | { | |
41 | struct tps380x_reset *tps380x = to_tps380x_reset(rcdev); | |
42 | ||
43 | gpiod_set_value_cansleep(tps380x->reset_gpio, 1); | |
44 | ||
45 | return 0; | |
46 | } | |
47 | ||
48 | static int | |
49 | tps380x_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) | |
50 | { | |
51 | struct tps380x_reset *tps380x = to_tps380x_reset(rcdev); | |
52 | ||
53 | gpiod_set_value_cansleep(tps380x->reset_gpio, 0); | |
54 | msleep(tps380x->reset_ms); | |
55 | ||
56 | return 0; | |
57 | } | |
58 | ||
59 | static const struct reset_control_ops reset_tps380x_ops = { | |
60 | .assert = tps380x_reset_assert, | |
61 | .deassert = tps380x_reset_deassert, | |
62 | }; | |
63 | ||
64 | static int tps380x_reset_of_xlate(struct reset_controller_dev *rcdev, | |
65 | const struct of_phandle_args *reset_spec) | |
66 | { | |
67 | /* No special handling needed, we have only one reset line per device */ | |
68 | return 0; | |
69 | } | |
70 | ||
71 | static int tps380x_reset_probe(struct platform_device *pdev) | |
72 | { | |
73 | struct device *dev = &pdev->dev; | |
74 | const struct tps380x_reset_devdata *devdata; | |
75 | struct tps380x_reset *tps380x; | |
76 | ||
77 | devdata = device_get_match_data(dev); | |
78 | if (!devdata) | |
79 | return -EINVAL; | |
80 | ||
81 | tps380x = devm_kzalloc(dev, sizeof(*tps380x), GFP_KERNEL); | |
82 | if (!tps380x) | |
83 | return -ENOMEM; | |
84 | ||
85 | tps380x->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); | |
86 | if (IS_ERR(tps380x->reset_gpio)) | |
87 | return dev_err_probe(dev, PTR_ERR(tps380x->reset_gpio), | |
88 | "Failed to get GPIO\n"); | |
89 | ||
90 | tps380x->reset_ms = devdata->max_reset_ms; | |
91 | ||
92 | tps380x->rcdev.ops = &reset_tps380x_ops; | |
93 | tps380x->rcdev.owner = THIS_MODULE; | |
94 | tps380x->rcdev.dev = dev; | |
95 | tps380x->rcdev.of_node = dev->of_node; | |
96 | tps380x->rcdev.of_reset_n_cells = 0; | |
97 | tps380x->rcdev.of_xlate = tps380x_reset_of_xlate; | |
98 | tps380x->rcdev.nr_resets = 1; | |
99 | ||
100 | return devm_reset_controller_register(dev, &tps380x->rcdev); | |
101 | } | |
102 | ||
103 | static const struct tps380x_reset_devdata tps3801_reset_data = { | |
104 | .min_reset_ms = 120, | |
105 | .typ_reset_ms = 200, | |
106 | .max_reset_ms = 280, | |
107 | }; | |
108 | ||
109 | static const struct of_device_id tps380x_reset_dt_ids[] = { | |
110 | { .compatible = "ti,tps3801", .data = &tps3801_reset_data }, | |
111 | { /* sentinel */ }, | |
112 | }; | |
113 | MODULE_DEVICE_TABLE(of, tps380x_reset_dt_ids); | |
114 | ||
115 | static struct platform_driver tps380x_reset_driver = { | |
116 | .probe = tps380x_reset_probe, | |
117 | .driver = { | |
118 | .name = "tps380x-reset", | |
119 | .of_match_table = tps380x_reset_dt_ids, | |
120 | }, | |
121 | }; | |
122 | module_platform_driver(tps380x_reset_driver); | |
123 | ||
124 | MODULE_AUTHOR("Marco Felsch <[email protected]>"); | |
d985db83 | 125 | MODULE_DESCRIPTION("TI TPS380x Supply Voltage Supervisor and Reset Driver"); |
8a4e6154 | 126 | MODULE_LICENSE("GPL v2"); |