kernel: bump 4.14 to 4.14.41
[openwrt/openwrt.git] / target / linux / ath79 / patches-4.14 / 0003-leds-add-reset-controller-based-driver.patch
1 From ecbd9c87f073f097d9fe56390353e64e963e866a Mon Sep 17 00:00:00 2001
2 From: John Crispin <john@phrozen.org>
3 Date: Tue, 6 Mar 2018 10:03:03 +0100
4 Subject: [PATCH 03/27] leds: add reset-controller based driver
5
6 Signed-off-by: John Crispin <john@phrozen.org>
7 ---
8 drivers/leds/Kconfig | 11 ++++
9 drivers/leds/Makefile | 1 +
10 drivers/leds/leds-reset.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++
11 3 files changed, 149 insertions(+)
12 create mode 100644 drivers/leds/leds-reset.c
13
14 --- a/drivers/leds/Kconfig
15 +++ b/drivers/leds/Kconfig
16 @@ -696,6 +696,17 @@ config LEDS_NIC78BX
17 To compile this driver as a module, choose M here: the module
18 will be called leds-nic78bx.
19
20 +config LEDS_RESET
21 + tristate "LED support for reset-controller API"
22 + depends on LEDS_CLASS
23 + depends on RESET_CONTROLLER
24 + help
25 + This option enables support for LEDs connected to pins driven by reset
26 + controllers. Yes, DNI actual built HW like that.
27 +
28 + To compile this driver as a module, choose M here: the module
29 + will be called leds-reset.
30 +
31 comment "LED Triggers"
32 source "drivers/leds/trigger/Kconfig"
33
34 --- /dev/null
35 +++ b/drivers/leds/leds-reset.c
36 @@ -0,0 +1,137 @@
37 +/*
38 + * Copyright (C) 2018 John Crispin <john@phrozen.org>
39 + *
40 + * This program is free software; you can redistribute it and/or modify
41 + * it under the terms of the GNU General Public License version 2 as
42 + * published by the Free Software Foundation.
43 + *
44 + */
45 +#include <linux/err.h>
46 +#include <linux/reset.h>
47 +#include <linux/kernel.h>
48 +#include <linux/leds.h>
49 +#include <linux/module.h>
50 +#include <linux/of.h>
51 +#include <linux/platform_device.h>
52 +#include <linux/reset.h>
53 +
54 +struct reset_led_data {
55 + struct led_classdev cdev;
56 + struct reset_control *rst;
57 +};
58 +
59 +static inline struct reset_led_data *
60 + cdev_to_reset_led_data(struct led_classdev *led_cdev)
61 +{
62 + return container_of(led_cdev, struct reset_led_data, cdev);
63 +}
64 +
65 +static void reset_led_set(struct led_classdev *led_cdev,
66 + enum led_brightness value)
67 +{
68 + struct reset_led_data *led_dat = cdev_to_reset_led_data(led_cdev);
69 +
70 + if (value == LED_OFF)
71 + reset_control_assert(led_dat->rst);
72 + else
73 + reset_control_deassert(led_dat->rst);
74 +}
75 +
76 +struct reset_leds_priv {
77 + int num_leds;
78 + struct reset_led_data leds[];
79 +};
80 +
81 +static inline int sizeof_reset_leds_priv(int num_leds)
82 +{
83 + return sizeof(struct reset_leds_priv) +
84 + (sizeof(struct reset_led_data) * num_leds);
85 +}
86 +
87 +static struct reset_leds_priv *reset_leds_create(struct platform_device *pdev)
88 +{
89 + struct device *dev = &pdev->dev;
90 + struct fwnode_handle *child;
91 + struct reset_leds_priv *priv;
92 + int count, ret;
93 +
94 + count = device_get_child_node_count(dev);
95 + if (!count)
96 + return ERR_PTR(-ENODEV);
97 +
98 + priv = devm_kzalloc(dev, sizeof_reset_leds_priv(count), GFP_KERNEL);
99 + if (!priv)
100 + return ERR_PTR(-ENOMEM);
101 +
102 + device_for_each_child_node(dev, child) {
103 + struct reset_led_data *led = &priv->leds[priv->num_leds];
104 + struct device_node *np = to_of_node(child);
105 +
106 + ret = fwnode_property_read_string(child, "label", &led->cdev.name);
107 + if (!led->cdev.name) {
108 + fwnode_handle_put(child);
109 + return ERR_PTR(-EINVAL);
110 + }
111 + led->rst = __of_reset_control_get(np, NULL, 0, 0, 0);
112 + if (IS_ERR(led->rst))
113 + return ERR_PTR(-EINVAL);
114 +
115 + led->cdev.brightness_set = reset_led_set;
116 + ret = devm_of_led_classdev_register(&pdev->dev, np, &led->cdev);
117 + if (ret < 0)
118 + return ERR_PTR(ret);
119 + led->cdev.dev->of_node = np;
120 + priv->num_leds++;
121 + }
122 +
123 + return priv;
124 +}
125 +
126 +static const struct of_device_id of_reset_leds_match[] = {
127 + { .compatible = "reset-leds", },
128 + {},
129 +};
130 +
131 +MODULE_DEVICE_TABLE(of, of_reset_leds_match);
132 +
133 +static int reset_led_probe(struct platform_device *pdev)
134 +{
135 + struct reset_leds_priv *priv;
136 +
137 + priv = reset_leds_create(pdev);
138 + if (IS_ERR(priv))
139 + return PTR_ERR(priv);
140 +
141 + platform_set_drvdata(pdev, priv);
142 +
143 + return 0;
144 +}
145 +
146 +static void reset_led_shutdown(struct platform_device *pdev)
147 +{
148 + struct reset_leds_priv *priv = platform_get_drvdata(pdev);
149 + int i;
150 +
151 + for (i = 0; i < priv->num_leds; i++) {
152 + struct reset_led_data *led = &priv->leds[i];
153 +
154 + if (!(led->cdev.flags & LED_RETAIN_AT_SHUTDOWN))
155 + reset_led_set(&led->cdev, LED_OFF);
156 + }
157 +}
158 +
159 +static struct platform_driver reset_led_driver = {
160 + .probe = reset_led_probe,
161 + .shutdown = reset_led_shutdown,
162 + .driver = {
163 + .name = "leds-reset",
164 + .of_match_table = of_reset_leds_match,
165 + },
166 +};
167 +
168 +module_platform_driver(reset_led_driver);
169 +
170 +MODULE_AUTHOR("John Crispin <john@phrozen.org>");
171 +MODULE_DESCRIPTION("reset controller LED driver");
172 +MODULE_LICENSE("GPL");
173 +MODULE_ALIAS("platform:leds-reset");
174 --- a/drivers/leds/Makefile
175 +++ b/drivers/leds/Makefile
176 @@ -73,6 +73,7 @@ obj-$(CONFIG_LEDS_PM8058) += leds-pm805
177 obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o
178 obj-$(CONFIG_LEDS_NIC78BX) += leds-nic78bx.o
179 obj-$(CONFIG_LEDS_MT6323) += leds-mt6323.o
180 +obj-$(CONFIG_LEDS_RESET) += leds-reset.o
181
182 # LED SPI Drivers
183 obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o