0001
0002
0003
0004
0005 #include <linux/delay.h>
0006 #include <linux/io.h>
0007 #include <linux/leds.h>
0008 #include <linux/module.h>
0009 #include <linux/of.h>
0010 #include <linux/pinctrl/consumer.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/spinlock.h>
0013
0014 #define BCM63138_MAX_LEDS 32
0015 #define BCM63138_MAX_BRIGHTNESS 9
0016
0017 #define BCM63138_LED_BITS 4
0018 #define BCM63138_LED_MASK ((1 << BCM63138_LED_BITS) - 1)
0019 #define BCM63138_LEDS_PER_REG (32 / BCM63138_LED_BITS)
0020
0021 #define BCM63138_GLB_CTRL 0x00
0022 #define BCM63138_GLB_CTRL_SERIAL_LED_DATA_PPOL 0x00000002
0023 #define BCM63138_GLB_CTRL_SERIAL_LED_EN_POL 0x00000008
0024 #define BCM63138_MASK 0x04
0025 #define BCM63138_HW_LED_EN 0x08
0026 #define BCM63138_SERIAL_LED_SHIFT_SEL 0x0c
0027 #define BCM63138_FLASH_RATE_CTRL1 0x10
0028 #define BCM63138_FLASH_RATE_CTRL2 0x14
0029 #define BCM63138_FLASH_RATE_CTRL3 0x18
0030 #define BCM63138_FLASH_RATE_CTRL4 0x1c
0031 #define BCM63138_BRIGHT_CTRL1 0x20
0032 #define BCM63138_BRIGHT_CTRL2 0x24
0033 #define BCM63138_BRIGHT_CTRL3 0x28
0034 #define BCM63138_BRIGHT_CTRL4 0x2c
0035 #define BCM63138_POWER_LED_CFG 0x30
0036 #define BCM63138_HW_POLARITY 0xb4
0037 #define BCM63138_SW_DATA 0xb8
0038 #define BCM63138_SW_POLARITY 0xbc
0039 #define BCM63138_PARALLEL_LED_POLARITY 0xc0
0040 #define BCM63138_SERIAL_LED_POLARITY 0xc4
0041 #define BCM63138_HW_LED_STATUS 0xc8
0042 #define BCM63138_FLASH_CTRL_STATUS 0xcc
0043 #define BCM63138_FLASH_BRT_CTRL 0xd0
0044 #define BCM63138_FLASH_P_LED_OUT_STATUS 0xd4
0045 #define BCM63138_FLASH_S_LED_OUT_STATUS 0xd8
0046
0047 struct bcm63138_leds {
0048 struct device *dev;
0049 void __iomem *base;
0050 spinlock_t lock;
0051 };
0052
0053 struct bcm63138_led {
0054 struct bcm63138_leds *leds;
0055 struct led_classdev cdev;
0056 u32 pin;
0057 bool active_low;
0058 };
0059
0060
0061
0062
0063
0064 static void bcm63138_leds_write(struct bcm63138_leds *leds, unsigned int reg,
0065 u32 data)
0066 {
0067 writel(data, leds->base + reg);
0068 }
0069
0070 static unsigned long bcm63138_leds_read(struct bcm63138_leds *leds,
0071 unsigned int reg)
0072 {
0073 return readl(leds->base + reg);
0074 }
0075
0076 static void bcm63138_leds_update_bits(struct bcm63138_leds *leds,
0077 unsigned int reg, u32 mask, u32 val)
0078 {
0079 WARN_ON(val & ~mask);
0080
0081 bcm63138_leds_write(leds, reg, (bcm63138_leds_read(leds, reg) & ~mask) | (val & mask));
0082 }
0083
0084
0085
0086
0087
0088 static void bcm63138_leds_set_flash_rate(struct bcm63138_leds *leds,
0089 struct bcm63138_led *led,
0090 u8 value)
0091 {
0092 int reg_offset = (led->pin >> fls((BCM63138_LEDS_PER_REG - 1))) * 4;
0093 int shift = (led->pin & (BCM63138_LEDS_PER_REG - 1)) * BCM63138_LED_BITS;
0094
0095 bcm63138_leds_update_bits(leds, BCM63138_FLASH_RATE_CTRL1 + reg_offset,
0096 BCM63138_LED_MASK << shift, value << shift);
0097 }
0098
0099 static void bcm63138_leds_set_bright(struct bcm63138_leds *leds,
0100 struct bcm63138_led *led,
0101 u8 value)
0102 {
0103 int reg_offset = (led->pin >> fls((BCM63138_LEDS_PER_REG - 1))) * 4;
0104 int shift = (led->pin & (BCM63138_LEDS_PER_REG - 1)) * BCM63138_LED_BITS;
0105
0106 bcm63138_leds_update_bits(leds, BCM63138_BRIGHT_CTRL1 + reg_offset,
0107 BCM63138_LED_MASK << shift, value << shift);
0108 }
0109
0110 static void bcm63138_leds_enable_led(struct bcm63138_leds *leds,
0111 struct bcm63138_led *led,
0112 enum led_brightness value)
0113 {
0114 u32 bit = BIT(led->pin);
0115
0116 bcm63138_leds_update_bits(leds, BCM63138_SW_DATA, bit, value ? bit : 0);
0117 }
0118
0119
0120
0121
0122
0123 static void bcm63138_leds_brightness_set(struct led_classdev *led_cdev,
0124 enum led_brightness value)
0125 {
0126 struct bcm63138_led *led = container_of(led_cdev, struct bcm63138_led, cdev);
0127 struct bcm63138_leds *leds = led->leds;
0128 unsigned long flags;
0129
0130 spin_lock_irqsave(&leds->lock, flags);
0131
0132 bcm63138_leds_enable_led(leds, led, value);
0133 if (!value)
0134 bcm63138_leds_set_flash_rate(leds, led, 0);
0135 else
0136 bcm63138_leds_set_bright(leds, led, value);
0137
0138 spin_unlock_irqrestore(&leds->lock, flags);
0139 }
0140
0141 static int bcm63138_leds_blink_set(struct led_classdev *led_cdev,
0142 unsigned long *delay_on,
0143 unsigned long *delay_off)
0144 {
0145 struct bcm63138_led *led = container_of(led_cdev, struct bcm63138_led, cdev);
0146 struct bcm63138_leds *leds = led->leds;
0147 unsigned long flags;
0148 u8 value;
0149
0150 if (!*delay_on && !*delay_off) {
0151 *delay_on = 640;
0152 *delay_off = 640;
0153 }
0154
0155 if (*delay_on != *delay_off) {
0156 dev_dbg(led_cdev->dev, "Blinking at unequal delays is not supported\n");
0157 return -EINVAL;
0158 }
0159
0160 switch (*delay_on) {
0161 case 1152 ... 1408:
0162 value = 0x7;
0163 break;
0164 case 576 ... 704:
0165 value = 0x6;
0166 break;
0167 case 288 ... 352:
0168 value = 0x5;
0169 break;
0170 case 126 ... 154:
0171 value = 0x4;
0172 break;
0173 case 59 ... 72:
0174 value = 0x3;
0175 break;
0176 default:
0177 dev_dbg(led_cdev->dev, "Blinking delay value %lu is unsupported\n",
0178 *delay_on);
0179 return -EINVAL;
0180 }
0181
0182 spin_lock_irqsave(&leds->lock, flags);
0183
0184 bcm63138_leds_enable_led(leds, led, BCM63138_MAX_BRIGHTNESS);
0185 bcm63138_leds_set_flash_rate(leds, led, value);
0186
0187 spin_unlock_irqrestore(&leds->lock, flags);
0188
0189 return 0;
0190 }
0191
0192
0193
0194
0195
0196 static void bcm63138_leds_create_led(struct bcm63138_leds *leds,
0197 struct device_node *np)
0198 {
0199 struct led_init_data init_data = {
0200 .fwnode = of_fwnode_handle(np),
0201 };
0202 struct device *dev = leds->dev;
0203 struct bcm63138_led *led;
0204 struct pinctrl *pinctrl;
0205 u32 bit;
0206 int err;
0207
0208 led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
0209 if (!led) {
0210 dev_err(dev, "Failed to alloc LED\n");
0211 return;
0212 }
0213
0214 led->leds = leds;
0215
0216 if (of_property_read_u32(np, "reg", &led->pin)) {
0217 dev_err(dev, "Missing \"reg\" property in %pOF\n", np);
0218 goto err_free;
0219 }
0220
0221 if (led->pin >= BCM63138_MAX_LEDS) {
0222 dev_err(dev, "Invalid \"reg\" value %d\n", led->pin);
0223 goto err_free;
0224 }
0225
0226 led->active_low = of_property_read_bool(np, "active-low");
0227
0228 led->cdev.max_brightness = BCM63138_MAX_BRIGHTNESS;
0229 led->cdev.brightness_set = bcm63138_leds_brightness_set;
0230 led->cdev.blink_set = bcm63138_leds_blink_set;
0231
0232 err = devm_led_classdev_register_ext(dev, &led->cdev, &init_data);
0233 if (err) {
0234 dev_err(dev, "Failed to register LED %pOF: %d\n", np, err);
0235 goto err_free;
0236 }
0237
0238 pinctrl = devm_pinctrl_get_select_default(led->cdev.dev);
0239 if (IS_ERR(pinctrl) && PTR_ERR(pinctrl) != -ENODEV) {
0240 dev_warn(led->cdev.dev, "Failed to select %pOF pinctrl: %ld\n",
0241 np, PTR_ERR(pinctrl));
0242 }
0243
0244 bit = BIT(led->pin);
0245 bcm63138_leds_update_bits(leds, BCM63138_PARALLEL_LED_POLARITY, bit,
0246 led->active_low ? 0 : bit);
0247 bcm63138_leds_update_bits(leds, BCM63138_HW_LED_EN, bit, 0);
0248 bcm63138_leds_set_flash_rate(leds, led, 0);
0249 bcm63138_leds_enable_led(leds, led, led->cdev.brightness);
0250
0251 return;
0252
0253 err_free:
0254 devm_kfree(dev, led);
0255 }
0256
0257 static int bcm63138_leds_probe(struct platform_device *pdev)
0258 {
0259 struct device_node *np = dev_of_node(&pdev->dev);
0260 struct device *dev = &pdev->dev;
0261 struct bcm63138_leds *leds;
0262 struct device_node *child;
0263
0264 leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL);
0265 if (!leds)
0266 return -ENOMEM;
0267
0268 leds->dev = dev;
0269
0270 leds->base = devm_platform_ioremap_resource(pdev, 0);
0271 if (IS_ERR(leds->base))
0272 return PTR_ERR(leds->base);
0273
0274 spin_lock_init(&leds->lock);
0275
0276 bcm63138_leds_write(leds, BCM63138_GLB_CTRL,
0277 BCM63138_GLB_CTRL_SERIAL_LED_DATA_PPOL |
0278 BCM63138_GLB_CTRL_SERIAL_LED_EN_POL);
0279 bcm63138_leds_write(leds, BCM63138_HW_LED_EN, 0);
0280 bcm63138_leds_write(leds, BCM63138_SERIAL_LED_POLARITY, 0);
0281 bcm63138_leds_write(leds, BCM63138_PARALLEL_LED_POLARITY, 0);
0282
0283 for_each_available_child_of_node(np, child) {
0284 bcm63138_leds_create_led(leds, child);
0285 }
0286
0287 return 0;
0288 }
0289
0290 static const struct of_device_id bcm63138_leds_of_match_table[] = {
0291 { .compatible = "brcm,bcm63138-leds", },
0292 { },
0293 };
0294
0295 static struct platform_driver bcm63138_leds_driver = {
0296 .probe = bcm63138_leds_probe,
0297 .driver = {
0298 .name = "leds-bcm63xxx",
0299 .of_match_table = bcm63138_leds_of_match_table,
0300 },
0301 };
0302
0303 module_platform_driver(bcm63138_leds_driver);
0304
0305 MODULE_AUTHOR("Rafał Miłecki");
0306 MODULE_LICENSE("GPL");
0307 MODULE_DEVICE_TABLE(of, bcm63138_leds_of_match_table);