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