common: Drop log.h from common header
[platform/kernel/u-boot.git] / drivers / led / led_bcm6328.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
4  */
5
6 #include <common.h>
7 #include <dm.h>
8 #include <errno.h>
9 #include <led.h>
10 #include <log.h>
11 #include <asm/io.h>
12 #include <dm/lists.h>
13
14 #define LEDS_MAX                        24
15
16 /* LED Init register */
17 #define LED_INIT_REG                    0x00
18 #define LED_INIT_FASTINTV_MS            20
19 #define LED_INIT_FASTINTV_SHIFT         6
20 #define LED_INIT_FASTINTV_MASK          (0x3f << LED_INIT_FASTINTV_SHIFT)
21 #define LED_INIT_SLEDEN_SHIFT           12
22 #define LED_INIT_SLEDEN_MASK            (1 << LED_INIT_SLEDEN_SHIFT)
23 #define LED_INIT_SLEDMUX_SHIFT          13
24 #define LED_INIT_SLEDMUX_MASK           (1 << LED_INIT_SLEDMUX_SHIFT)
25 #define LED_INIT_SLEDCLKNPOL_SHIFT      14
26 #define LED_INIT_SLEDCLKNPOL_MASK       (1 << LED_INIT_SLEDCLKNPOL_SHIFT)
27 #define LED_INIT_SLEDDATAPPOL_SHIFT     15
28 #define LED_INIT_SLEDDATANPOL_MASK      (1 << LED_INIT_SLEDDATAPPOL_SHIFT)
29 #define LED_INIT_SLEDSHIFTDIR_SHIFT     16
30 #define LED_INIT_SLEDSHIFTDIR_MASK      (1 << LED_INIT_SLEDSHIFTDIR_SHIFT)
31
32 /* LED Mode registers */
33 #define LED_MODE_REG_HI                 0x04
34 #define LED_MODE_REG_LO                 0x08
35 #define LED_MODE_ON                     0
36 #define LED_MODE_FAST                   1
37 #define LED_MODE_BLINK                  2
38 #define LED_MODE_OFF                    3
39 #define LED_MODE_MASK                   0x3
40
41 struct bcm6328_led_priv {
42         void __iomem *regs;
43         void __iomem *mode;
44         uint8_t shift;
45         bool active_low;
46 };
47
48 static unsigned long bcm6328_led_get_mode(struct bcm6328_led_priv *priv)
49 {
50         return ((readl_be(priv->mode) >> priv->shift) & LED_MODE_MASK);
51 }
52
53 static int bcm6328_led_set_mode(struct bcm6328_led_priv *priv, uint8_t mode)
54 {
55         clrsetbits_be32(priv->mode, (LED_MODE_MASK << priv->shift),
56                         (mode << priv->shift));
57
58         return 0;
59 }
60
61 static enum led_state_t bcm6328_led_get_state(struct udevice *dev)
62 {
63         struct bcm6328_led_priv *priv = dev_get_priv(dev);
64         enum led_state_t state = LEDST_OFF;
65
66         switch (bcm6328_led_get_mode(priv)) {
67 #ifdef CONFIG_LED_BLINK
68         case LED_MODE_BLINK:
69         case LED_MODE_FAST:
70                 state = LEDST_BLINK;
71                 break;
72 #endif
73         case LED_MODE_OFF:
74                 state = (priv->active_low ? LEDST_ON : LEDST_OFF);
75                 break;
76         case LED_MODE_ON:
77                 state = (priv->active_low ? LEDST_OFF : LEDST_ON);
78                 break;
79         }
80
81         return state;
82 }
83
84 static int bcm6328_led_set_state(struct udevice *dev, enum led_state_t state)
85 {
86         struct bcm6328_led_priv *priv = dev_get_priv(dev);
87         unsigned long mode;
88
89         switch (state) {
90 #ifdef CONFIG_LED_BLINK
91         case LEDST_BLINK:
92                 mode = LED_MODE_BLINK;
93                 break;
94 #endif
95         case LEDST_OFF:
96                 mode = (priv->active_low ? LED_MODE_ON : LED_MODE_OFF);
97                 break;
98         case LEDST_ON:
99                 mode = (priv->active_low ? LED_MODE_OFF : LED_MODE_ON);
100                 break;
101         case LEDST_TOGGLE:
102                 if (bcm6328_led_get_state(dev) == LEDST_OFF)
103                         return bcm6328_led_set_state(dev, LEDST_ON);
104                 else
105                         return bcm6328_led_set_state(dev, LEDST_OFF);
106                 break;
107         default:
108                 return -ENOSYS;
109         }
110
111         return bcm6328_led_set_mode(priv, mode);
112 }
113
114 #ifdef CONFIG_LED_BLINK
115 static unsigned long bcm6328_blink_delay(int delay)
116 {
117         unsigned long bcm6328_delay = delay;
118
119         bcm6328_delay += (LED_INIT_FASTINTV_MS / 2);
120         bcm6328_delay /= LED_INIT_FASTINTV_MS;
121         bcm6328_delay <<= LED_INIT_FASTINTV_SHIFT;
122
123         if (bcm6328_delay > LED_INIT_FASTINTV_MASK)
124                 return LED_INIT_FASTINTV_MASK;
125         else
126                 return bcm6328_delay;
127 }
128
129 static int bcm6328_led_set_period(struct udevice *dev, int period_ms)
130 {
131         struct bcm6328_led_priv *priv = dev_get_priv(dev);
132
133         clrsetbits_be32(priv->regs + LED_INIT_REG, LED_INIT_FASTINTV_MASK,
134                         bcm6328_blink_delay(period_ms));
135
136         return 0;
137 }
138 #endif
139
140 static const struct led_ops bcm6328_led_ops = {
141         .get_state = bcm6328_led_get_state,
142         .set_state = bcm6328_led_set_state,
143 #ifdef CONFIG_LED_BLINK
144         .set_period = bcm6328_led_set_period,
145 #endif
146 };
147
148 static int bcm6328_led_probe(struct udevice *dev)
149 {
150         struct led_uc_plat *uc_plat = dev_get_uclass_platdata(dev);
151
152         /* Top-level LED node */
153         if (!uc_plat->label) {
154                 void __iomem *regs;
155                 u32 set_bits = 0;
156
157                 regs = dev_remap_addr(dev);
158                 if (!regs)
159                         return -EINVAL;
160
161                 if (dev_read_bool(dev, "brcm,serial-leds"))
162                         set_bits |= LED_INIT_SLEDEN_MASK;
163                 if (dev_read_bool(dev, "brcm,serial-mux"))
164                         set_bits |= LED_INIT_SLEDMUX_MASK;
165                 if (dev_read_bool(dev, "brcm,serial-clk-low"))
166                         set_bits |= LED_INIT_SLEDCLKNPOL_MASK;
167                 if (!dev_read_bool(dev, "brcm,serial-dat-low"))
168                         set_bits |= LED_INIT_SLEDDATANPOL_MASK;
169                 if (!dev_read_bool(dev, "brcm,serial-shift-inv"))
170                         set_bits |= LED_INIT_SLEDSHIFTDIR_MASK;
171
172                 clrsetbits_be32(regs + LED_INIT_REG, ~0, set_bits);
173         } else {
174                 struct bcm6328_led_priv *priv = dev_get_priv(dev);
175                 unsigned int pin;
176
177                 priv->regs = dev_remap_addr(dev_get_parent(dev));
178                 if (!priv->regs)
179                         return -EINVAL;
180
181                 pin = dev_read_u32_default(dev, "reg", LEDS_MAX);
182                 if (pin >= LEDS_MAX)
183                         return -EINVAL;
184
185                 if (pin < 8) {
186                         /* LEDs 0-7 (bits 47:32) */
187                         priv->mode = priv->regs + LED_MODE_REG_HI;
188                         priv->shift = (pin << 1);
189                 } else {
190                         /* LEDs 8-23 (bits 31:0) */
191                         priv->mode = priv->regs + LED_MODE_REG_LO;
192                         priv->shift = ((pin - 8) << 1);
193                 }
194
195                 if (dev_read_bool(dev, "active-low"))
196                         priv->active_low = true;
197         }
198
199         return 0;
200 }
201
202 static int bcm6328_led_bind(struct udevice *parent)
203 {
204         ofnode node;
205
206         dev_for_each_subnode(node, parent) {
207                 struct led_uc_plat *uc_plat;
208                 struct udevice *dev;
209                 const char *label;
210                 int ret;
211
212                 label = ofnode_read_string(node, "label");
213                 if (!label) {
214                         debug("%s: node %s has no label\n", __func__,
215                               ofnode_get_name(node));
216                         return -EINVAL;
217                 }
218
219                 ret = device_bind_driver_to_node(parent, "bcm6328-led",
220                                                  ofnode_get_name(node),
221                                                  node, &dev);
222                 if (ret)
223                         return ret;
224
225                 uc_plat = dev_get_uclass_platdata(dev);
226                 uc_plat->label = label;
227         }
228
229         return 0;
230 }
231
232 static const struct udevice_id bcm6328_led_ids[] = {
233         { .compatible = "brcm,bcm6328-leds" },
234         { /* sentinel */ }
235 };
236
237 U_BOOT_DRIVER(bcm6328_led) = {
238         .name = "bcm6328-led",
239         .id = UCLASS_LED,
240         .of_match = bcm6328_led_ids,
241         .ops = &bcm6328_led_ops,
242         .bind = bcm6328_led_bind,
243         .probe = bcm6328_led_probe,
244         .priv_auto_alloc_size = sizeof(struct bcm6328_led_priv),
245 };