leds-cr0014114.c (6867B)
1// SPDX-License-Identifier: GPL-2.0 2// Copyright (c) 2018 Crane Merchandising Systems. All rights reserved. 3// Copyright (C) 2018 Oleh Kravchenko <oleg@kaa.org.ua> 4 5#include <linux/delay.h> 6#include <linux/leds.h> 7#include <linux/module.h> 8#include <linux/of_device.h> 9#include <linux/spi/spi.h> 10#include <linux/workqueue.h> 11 12/* 13 * CR0014114 SPI protocol descrtiption: 14 * +----+-----------------------------------+----+ 15 * | CMD| BRIGHTNESS |CRC | 16 * +----+-----------------------------------+----+ 17 * | | LED0| LED1| LED2| LED3| LED4| LED5| | 18 * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 19 * | |R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|R|G|B| | 20 * | 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1 | 21 * | |1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1| | 22 * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 23 * | | 18 | | 24 * +----+-----------------------------------+----+ 25 * | 20 | 26 * +---------------------------------------------+ 27 * 28 * PS: Boards can be connected to the chain: 29 * SPI -> board0 -> board1 -> board2 .. 30 */ 31 32/* CR0014114 SPI commands */ 33#define CR_SET_BRIGHTNESS 0x80 34#define CR_INIT_REENUMERATE 0x81 35#define CR_NEXT_REENUMERATE 0x82 36 37/* CR0014114 default settings */ 38#define CR_MAX_BRIGHTNESS GENMASK(6, 0) 39#define CR_FW_DELAY_MSEC 10 40#define CR_RECOUNT_DELAY (HZ * 3600) 41 42#define CR_DEV_NAME "cr0014114" 43 44struct cr0014114_led { 45 struct cr0014114 *priv; 46 struct led_classdev ldev; 47 u8 brightness; 48}; 49 50struct cr0014114 { 51 bool do_recount; 52 size_t count; 53 struct delayed_work work; 54 struct device *dev; 55 struct mutex lock; 56 struct spi_device *spi; 57 u8 *buf; 58 unsigned long delay; 59 struct cr0014114_led leds[]; 60}; 61 62static void cr0014114_calc_crc(u8 *buf, const size_t len) 63{ 64 size_t i; 65 u8 crc; 66 67 for (i = 1, crc = 1; i < len - 1; i++) 68 crc += buf[i]; 69 crc |= BIT(7); 70 71 /* special case when CRC matches the SPI commands */ 72 if (crc == CR_SET_BRIGHTNESS || 73 crc == CR_INIT_REENUMERATE || 74 crc == CR_NEXT_REENUMERATE) 75 crc = 0xfe; 76 77 buf[len - 1] = crc; 78} 79 80static int cr0014114_recount(struct cr0014114 *priv) 81{ 82 int ret; 83 size_t i; 84 u8 cmd; 85 86 dev_dbg(priv->dev, "LEDs recount is started\n"); 87 88 cmd = CR_INIT_REENUMERATE; 89 ret = spi_write(priv->spi, &cmd, sizeof(cmd)); 90 if (ret) 91 goto err; 92 93 cmd = CR_NEXT_REENUMERATE; 94 for (i = 0; i < priv->count; i++) { 95 msleep(CR_FW_DELAY_MSEC); 96 97 ret = spi_write(priv->spi, &cmd, sizeof(cmd)); 98 if (ret) 99 goto err; 100 } 101 102err: 103 dev_dbg(priv->dev, "LEDs recount is finished\n"); 104 105 if (ret) 106 dev_err(priv->dev, "with error %d", ret); 107 108 return ret; 109} 110 111static int cr0014114_sync(struct cr0014114 *priv) 112{ 113 int ret; 114 size_t i; 115 unsigned long udelay, now = jiffies; 116 117 /* to avoid SPI mistiming with firmware we should wait some time */ 118 if (time_after(priv->delay, now)) { 119 udelay = jiffies_to_usecs(priv->delay - now); 120 usleep_range(udelay, udelay + 1); 121 } 122 123 if (unlikely(priv->do_recount)) { 124 ret = cr0014114_recount(priv); 125 if (ret) 126 goto err; 127 128 priv->do_recount = false; 129 msleep(CR_FW_DELAY_MSEC); 130 } 131 132 priv->buf[0] = CR_SET_BRIGHTNESS; 133 for (i = 0; i < priv->count; i++) 134 priv->buf[i + 1] = priv->leds[i].brightness; 135 cr0014114_calc_crc(priv->buf, priv->count + 2); 136 ret = spi_write(priv->spi, priv->buf, priv->count + 2); 137 138err: 139 priv->delay = jiffies + msecs_to_jiffies(CR_FW_DELAY_MSEC); 140 141 return ret; 142} 143 144static void cr0014114_recount_work(struct work_struct *work) 145{ 146 int ret; 147 struct cr0014114 *priv = container_of(work, 148 struct cr0014114, 149 work.work); 150 151 mutex_lock(&priv->lock); 152 priv->do_recount = true; 153 ret = cr0014114_sync(priv); 154 mutex_unlock(&priv->lock); 155 156 if (ret) 157 dev_warn(priv->dev, "sync of LEDs failed %d\n", ret); 158 159 schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY); 160} 161 162static int cr0014114_set_sync(struct led_classdev *ldev, 163 enum led_brightness brightness) 164{ 165 int ret; 166 struct cr0014114_led *led = container_of(ldev, 167 struct cr0014114_led, 168 ldev); 169 170 dev_dbg(led->priv->dev, "Set brightness to %d\n", brightness); 171 172 mutex_lock(&led->priv->lock); 173 led->brightness = (u8)brightness; 174 ret = cr0014114_sync(led->priv); 175 mutex_unlock(&led->priv->lock); 176 177 return ret; 178} 179 180static int cr0014114_probe_dt(struct cr0014114 *priv) 181{ 182 size_t i = 0; 183 struct cr0014114_led *led; 184 struct fwnode_handle *child; 185 struct led_init_data init_data = {}; 186 int ret; 187 188 device_for_each_child_node(priv->dev, child) { 189 led = &priv->leds[i]; 190 191 led->priv = priv; 192 led->ldev.max_brightness = CR_MAX_BRIGHTNESS; 193 led->ldev.brightness_set_blocking = cr0014114_set_sync; 194 195 init_data.fwnode = child; 196 init_data.devicename = CR_DEV_NAME; 197 init_data.default_label = ":"; 198 199 ret = devm_led_classdev_register_ext(priv->dev, &led->ldev, 200 &init_data); 201 if (ret) { 202 dev_err(priv->dev, 203 "failed to register LED device, err %d", ret); 204 fwnode_handle_put(child); 205 return ret; 206 } 207 208 i++; 209 } 210 211 return 0; 212} 213 214static int cr0014114_probe(struct spi_device *spi) 215{ 216 struct cr0014114 *priv; 217 size_t count; 218 int ret; 219 220 count = device_get_child_node_count(&spi->dev); 221 if (!count) { 222 dev_err(&spi->dev, "LEDs are not defined in device tree!"); 223 return -ENODEV; 224 } 225 226 priv = devm_kzalloc(&spi->dev, struct_size(priv, leds, count), 227 GFP_KERNEL); 228 if (!priv) 229 return -ENOMEM; 230 231 priv->buf = devm_kzalloc(&spi->dev, count + 2, GFP_KERNEL); 232 if (!priv->buf) 233 return -ENOMEM; 234 235 mutex_init(&priv->lock); 236 INIT_DELAYED_WORK(&priv->work, cr0014114_recount_work); 237 priv->count = count; 238 priv->dev = &spi->dev; 239 priv->spi = spi; 240 priv->delay = jiffies - 241 msecs_to_jiffies(CR_FW_DELAY_MSEC); 242 243 priv->do_recount = true; 244 ret = cr0014114_sync(priv); 245 if (ret) { 246 dev_err(priv->dev, "first recount failed %d\n", ret); 247 return ret; 248 } 249 250 priv->do_recount = true; 251 ret = cr0014114_sync(priv); 252 if (ret) { 253 dev_err(priv->dev, "second recount failed %d\n", ret); 254 return ret; 255 } 256 257 ret = cr0014114_probe_dt(priv); 258 if (ret) 259 return ret; 260 261 /* setup recount work to workaround buggy firmware */ 262 schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY); 263 264 spi_set_drvdata(spi, priv); 265 266 return 0; 267} 268 269static void cr0014114_remove(struct spi_device *spi) 270{ 271 struct cr0014114 *priv = spi_get_drvdata(spi); 272 273 cancel_delayed_work_sync(&priv->work); 274 mutex_destroy(&priv->lock); 275} 276 277static const struct of_device_id cr0014114_dt_ids[] = { 278 { .compatible = "crane,cr0014114", }, 279 {}, 280}; 281 282MODULE_DEVICE_TABLE(of, cr0014114_dt_ids); 283 284static struct spi_driver cr0014114_driver = { 285 .probe = cr0014114_probe, 286 .remove = cr0014114_remove, 287 .driver = { 288 .name = KBUILD_MODNAME, 289 .of_match_table = cr0014114_dt_ids, 290 }, 291}; 292 293module_spi_driver(cr0014114_driver); 294 295MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>"); 296MODULE_DESCRIPTION("cr0014114 LED driver"); 297MODULE_LICENSE("GPL v2"); 298MODULE_ALIAS("spi:cr0014114");