2 * Copyright (C) 2017 Álvaro Fernández Rojas <noltari@gmail.com>
4 * SPDX-License-Identifier: GPL-2.0+
17 /* LED Mode register */
18 #define LED_MODE_REG 0x0
19 #define LED_MODE_OFF 0
21 #define LED_MODE_MASK 1
23 /* LED Control register */
24 #define LED_CTRL_REG 0x4
25 #define LED_CTRL_CLK_MASK 0x3
26 #define LED_CTRL_CLK_1 0
27 #define LED_CTRL_CLK_2 1
28 #define LED_CTRL_CLK_4 2
29 #define LED_CTRL_CLK_8 3
30 #define LED_CTRL_POL_SHIFT 2
31 #define LED_CTRL_POL_MASK (1 << LED_CTRL_POL_SHIFT)
32 #define LED_CTRL_BUSY_SHIFT 3
33 #define LED_CTRL_BUSY_MASK (1 << LED_CTRL_BUSY_SHIFT)
35 DECLARE_GLOBAL_DATA_PTR
;
37 struct bcm6358_led_priv
{
43 static void bcm6358_led_busy(void __iomem
*regs
)
45 while (readl_be(regs
+ LED_CTRL_REG
) & LED_CTRL_BUSY_MASK
)
49 static unsigned long bcm6358_led_get_mode(struct bcm6358_led_priv
*priv
)
51 bcm6358_led_busy(priv
->regs
);
53 return (readl_be(priv
->regs
+ LED_MODE_REG
) >> priv
->pin
) &
57 static int bcm6358_led_set_mode(struct bcm6358_led_priv
*priv
, uint8_t mode
)
59 bcm6358_led_busy(priv
->regs
);
61 clrsetbits_be32(priv
->regs
+ LED_MODE_REG
,
62 (LED_MODE_MASK
<< priv
->pin
),
68 static enum led_state_t
bcm6358_led_get_state(struct udevice
*dev
)
70 struct bcm6358_led_priv
*priv
= dev_get_priv(dev
);
71 enum led_state_t state
= LEDST_OFF
;
73 switch (bcm6358_led_get_mode(priv
)) {
75 state
= (priv
->active_low
? LEDST_ON
: LEDST_OFF
);
78 state
= (priv
->active_low
? LEDST_OFF
: LEDST_ON
);
85 static int bcm6358_led_set_state(struct udevice
*dev
, enum led_state_t state
)
87 struct bcm6358_led_priv
*priv
= dev_get_priv(dev
);
92 mode
= (priv
->active_low
? LED_MODE_ON
: LED_MODE_OFF
);
95 mode
= (priv
->active_low
? LED_MODE_OFF
: LED_MODE_ON
);
98 if (bcm6358_led_get_state(dev
) == LEDST_OFF
)
99 return bcm6358_led_set_state(dev
, LEDST_ON
);
101 return bcm6358_led_set_state(dev
, LEDST_OFF
);
107 return bcm6358_led_set_mode(priv
, mode
);
110 static const struct led_ops bcm6358_led_ops
= {
111 .get_state
= bcm6358_led_get_state
,
112 .set_state
= bcm6358_led_set_state
,
115 static int bcm6358_led_probe(struct udevice
*dev
)
117 struct led_uc_plat
*uc_plat
= dev_get_uclass_platdata(dev
);
121 /* Top-level LED node */
122 if (!uc_plat
->label
) {
124 unsigned int clk_div
;
127 addr
= devfdt_get_addr_size_index(dev
, 0, &size
);
128 if (addr
== FDT_ADDR_T_NONE
)
131 regs
= ioremap(addr
, size
);
133 if (fdtdec_get_bool(gd
->fdt_blob
, dev_of_offset(dev
),
135 set_bits
|= LED_CTRL_POL_MASK
;
136 clk_div
= fdtdec_get_uint(gd
->fdt_blob
, dev_of_offset(dev
),
137 "brcm,clk-div", LED_CTRL_CLK_1
);
140 set_bits
|= LED_CTRL_CLK_8
;
143 set_bits
|= LED_CTRL_CLK_4
;
146 set_bits
|= LED_CTRL_CLK_2
;
149 set_bits
|= LED_CTRL_CLK_1
;
153 bcm6358_led_busy(regs
);
154 clrsetbits_be32(regs
+ LED_CTRL_REG
,
155 LED_CTRL_POL_MASK
| LED_CTRL_CLK_MASK
,
158 struct bcm6358_led_priv
*priv
= dev_get_priv(dev
);
161 addr
= devfdt_get_addr_size_index(dev_get_parent(dev
), 0,
163 if (addr
== FDT_ADDR_T_NONE
)
166 pin
= fdtdec_get_uint(gd
->fdt_blob
, dev_of_offset(dev
), "reg",
171 priv
->regs
= ioremap(addr
, size
);
174 if (fdtdec_get_bool(gd
->fdt_blob
, dev_of_offset(dev
),
176 priv
->active_low
= true;
182 static int bcm6358_led_bind(struct udevice
*parent
)
184 const void *blob
= gd
->fdt_blob
;
187 for (node
= fdt_first_subnode(blob
, dev_of_offset(parent
));
189 node
= fdt_next_subnode(blob
, node
)) {
190 struct led_uc_plat
*uc_plat
;
195 label
= fdt_getprop(blob
, node
, "label", NULL
);
197 debug("%s: node %s has no label\n", __func__
,
198 fdt_get_name(blob
, node
, NULL
));
202 ret
= device_bind_driver_to_node(parent
, "bcm6358-led",
203 fdt_get_name(blob
, node
, NULL
),
208 uc_plat
= dev_get_uclass_platdata(dev
);
209 uc_plat
->label
= label
;
215 static const struct udevice_id bcm6358_led_ids
[] = {
216 { .compatible
= "brcm,bcm6358-leds" },
220 U_BOOT_DRIVER(bcm6358_led
) = {
221 .name
= "bcm6358-led",
223 .of_match
= bcm6358_led_ids
,
224 .bind
= bcm6358_led_bind
,
225 .probe
= bcm6358_led_probe
,
226 .priv_auto_alloc_size
= sizeof(struct bcm6358_led_priv
),
227 .ops
= &bcm6358_led_ops
,