Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (c) 2018 Crane Merchandising Systems. All rights reserved.
0003 // Copyright (C) 2018 Oleh Kravchenko <oleg@kaa.org.ua>
0004 
0005 #include <linux/delay.h>
0006 #include <linux/leds.h>
0007 #include <linux/module.h>
0008 #include <linux/of_device.h>
0009 #include <linux/spi/spi.h>
0010 #include <linux/workqueue.h>
0011 
0012 /*
0013  *  CR0014114 SPI protocol descrtiption:
0014  *  +----+-----------------------------------+----+
0015  *  | CMD|             BRIGHTNESS            |CRC |
0016  *  +----+-----------------------------------+----+
0017  *  |    | LED0| LED1| LED2| LED3| LED4| LED5|    |
0018  *  |    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |
0019  *  |    |R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|R|G|B|    |
0020  *  | 1  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1  |
0021  *  |    |1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|    |
0022  *  |    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+    |
0023  *  |    |               18                  |    |
0024  *  +----+-----------------------------------+----+
0025  *  |                    20                       |
0026  *  +---------------------------------------------+
0027  *
0028  *  PS: Boards can be connected to the chain:
0029  *      SPI -> board0 -> board1 -> board2 ..
0030  */
0031 
0032 /* CR0014114 SPI commands */
0033 #define CR_SET_BRIGHTNESS   0x80
0034 #define CR_INIT_REENUMERATE 0x81
0035 #define CR_NEXT_REENUMERATE 0x82
0036 
0037 /* CR0014114 default settings */
0038 #define CR_MAX_BRIGHTNESS   GENMASK(6, 0)
0039 #define CR_FW_DELAY_MSEC    10
0040 #define CR_RECOUNT_DELAY    (HZ * 3600)
0041 
0042 #define CR_DEV_NAME     "cr0014114"
0043 
0044 struct cr0014114_led {
0045     struct cr0014114    *priv;
0046     struct led_classdev ldev;
0047     u8          brightness;
0048 };
0049 
0050 struct cr0014114 {
0051     bool            do_recount;
0052     size_t          count;
0053     struct delayed_work work;
0054     struct device       *dev;
0055     struct mutex        lock;
0056     struct spi_device   *spi;
0057     u8          *buf;
0058     unsigned long       delay;
0059     struct cr0014114_led    leds[];
0060 };
0061 
0062 static void cr0014114_calc_crc(u8 *buf, const size_t len)
0063 {
0064     size_t  i;
0065     u8  crc;
0066 
0067     for (i = 1, crc = 1; i < len - 1; i++)
0068         crc += buf[i];
0069     crc |= BIT(7);
0070 
0071     /* special case when CRC matches the SPI commands */
0072     if (crc == CR_SET_BRIGHTNESS ||
0073         crc == CR_INIT_REENUMERATE ||
0074         crc == CR_NEXT_REENUMERATE)
0075         crc = 0xfe;
0076 
0077     buf[len - 1] = crc;
0078 }
0079 
0080 static int cr0014114_recount(struct cr0014114 *priv)
0081 {
0082     int ret;
0083     size_t  i;
0084     u8  cmd;
0085 
0086     dev_dbg(priv->dev, "LEDs recount is started\n");
0087 
0088     cmd = CR_INIT_REENUMERATE;
0089     ret = spi_write(priv->spi, &cmd, sizeof(cmd));
0090     if (ret)
0091         goto err;
0092 
0093     cmd = CR_NEXT_REENUMERATE;
0094     for (i = 0; i < priv->count; i++) {
0095         msleep(CR_FW_DELAY_MSEC);
0096 
0097         ret = spi_write(priv->spi, &cmd, sizeof(cmd));
0098         if (ret)
0099             goto err;
0100     }
0101 
0102 err:
0103     dev_dbg(priv->dev, "LEDs recount is finished\n");
0104 
0105     if (ret)
0106         dev_err(priv->dev, "with error %d", ret);
0107 
0108     return ret;
0109 }
0110 
0111 static int cr0014114_sync(struct cr0014114 *priv)
0112 {
0113     int     ret;
0114     size_t      i;
0115     unsigned long   udelay, now = jiffies;
0116 
0117     /* to avoid SPI mistiming with firmware we should wait some time */
0118     if (time_after(priv->delay, now)) {
0119         udelay = jiffies_to_usecs(priv->delay - now);
0120         usleep_range(udelay, udelay + 1);
0121     }
0122 
0123     if (unlikely(priv->do_recount)) {
0124         ret = cr0014114_recount(priv);
0125         if (ret)
0126             goto err;
0127 
0128         priv->do_recount = false;
0129         msleep(CR_FW_DELAY_MSEC);
0130     }
0131 
0132     priv->buf[0] = CR_SET_BRIGHTNESS;
0133     for (i = 0; i < priv->count; i++)
0134         priv->buf[i + 1] = priv->leds[i].brightness;
0135     cr0014114_calc_crc(priv->buf, priv->count + 2);
0136     ret = spi_write(priv->spi, priv->buf, priv->count + 2);
0137 
0138 err:
0139     priv->delay = jiffies + msecs_to_jiffies(CR_FW_DELAY_MSEC);
0140 
0141     return ret;
0142 }
0143 
0144 static void cr0014114_recount_work(struct work_struct *work)
0145 {
0146     int         ret;
0147     struct cr0014114    *priv = container_of(work,
0148                              struct cr0014114,
0149                              work.work);
0150 
0151     mutex_lock(&priv->lock);
0152     priv->do_recount = true;
0153     ret = cr0014114_sync(priv);
0154     mutex_unlock(&priv->lock);
0155 
0156     if (ret)
0157         dev_warn(priv->dev, "sync of LEDs failed %d\n", ret);
0158 
0159     schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY);
0160 }
0161 
0162 static int cr0014114_set_sync(struct led_classdev *ldev,
0163                   enum led_brightness brightness)
0164 {
0165     int         ret;
0166     struct cr0014114_led    *led = container_of(ldev,
0167                             struct cr0014114_led,
0168                             ldev);
0169 
0170     dev_dbg(led->priv->dev, "Set brightness to %d\n", brightness);
0171 
0172     mutex_lock(&led->priv->lock);
0173     led->brightness = (u8)brightness;
0174     ret = cr0014114_sync(led->priv);
0175     mutex_unlock(&led->priv->lock);
0176 
0177     return ret;
0178 }
0179 
0180 static int cr0014114_probe_dt(struct cr0014114 *priv)
0181 {
0182     size_t          i = 0;
0183     struct cr0014114_led    *led;
0184     struct fwnode_handle    *child;
0185     struct led_init_data    init_data = {};
0186     int         ret;
0187 
0188     device_for_each_child_node(priv->dev, child) {
0189         led = &priv->leds[i];
0190 
0191         led->priv             = priv;
0192         led->ldev.max_brightness      = CR_MAX_BRIGHTNESS;
0193         led->ldev.brightness_set_blocking = cr0014114_set_sync;
0194 
0195         init_data.fwnode = child;
0196         init_data.devicename = CR_DEV_NAME;
0197         init_data.default_label = ":";
0198 
0199         ret = devm_led_classdev_register_ext(priv->dev, &led->ldev,
0200                              &init_data);
0201         if (ret) {
0202             dev_err(priv->dev,
0203                 "failed to register LED device, err %d", ret);
0204             fwnode_handle_put(child);
0205             return ret;
0206         }
0207 
0208         i++;
0209     }
0210 
0211     return 0;
0212 }
0213 
0214 static int cr0014114_probe(struct spi_device *spi)
0215 {
0216     struct cr0014114    *priv;
0217     size_t          count;
0218     int         ret;
0219 
0220     count = device_get_child_node_count(&spi->dev);
0221     if (!count) {
0222         dev_err(&spi->dev, "LEDs are not defined in device tree!");
0223         return -ENODEV;
0224     }
0225 
0226     priv = devm_kzalloc(&spi->dev, struct_size(priv, leds, count),
0227                 GFP_KERNEL);
0228     if (!priv)
0229         return -ENOMEM;
0230 
0231     priv->buf = devm_kzalloc(&spi->dev, count + 2, GFP_KERNEL);
0232     if (!priv->buf)
0233         return -ENOMEM;
0234 
0235     mutex_init(&priv->lock);
0236     INIT_DELAYED_WORK(&priv->work, cr0014114_recount_work);
0237     priv->count = count;
0238     priv->dev   = &spi->dev;
0239     priv->spi   = spi;
0240     priv->delay = jiffies -
0241               msecs_to_jiffies(CR_FW_DELAY_MSEC);
0242 
0243     priv->do_recount = true;
0244     ret = cr0014114_sync(priv);
0245     if (ret) {
0246         dev_err(priv->dev, "first recount failed %d\n", ret);
0247         return ret;
0248     }
0249 
0250     priv->do_recount = true;
0251     ret = cr0014114_sync(priv);
0252     if (ret) {
0253         dev_err(priv->dev, "second recount failed %d\n", ret);
0254         return ret;
0255     }
0256 
0257     ret = cr0014114_probe_dt(priv);
0258     if (ret)
0259         return ret;
0260 
0261     /* setup recount work to workaround buggy firmware */
0262     schedule_delayed_work(&priv->work, CR_RECOUNT_DELAY);
0263 
0264     spi_set_drvdata(spi, priv);
0265 
0266     return 0;
0267 }
0268 
0269 static void cr0014114_remove(struct spi_device *spi)
0270 {
0271     struct cr0014114 *priv = spi_get_drvdata(spi);
0272 
0273     cancel_delayed_work_sync(&priv->work);
0274     mutex_destroy(&priv->lock);
0275 }
0276 
0277 static const struct of_device_id cr0014114_dt_ids[] = {
0278     { .compatible = "crane,cr0014114", },
0279     {},
0280 };
0281 
0282 MODULE_DEVICE_TABLE(of, cr0014114_dt_ids);
0283 
0284 static struct spi_driver cr0014114_driver = {
0285     .probe      = cr0014114_probe,
0286     .remove     = cr0014114_remove,
0287     .driver = {
0288         .name       = KBUILD_MODNAME,
0289         .of_match_table = cr0014114_dt_ids,
0290     },
0291 };
0292 
0293 module_spi_driver(cr0014114_driver);
0294 
0295 MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
0296 MODULE_DESCRIPTION("cr0014114 LED driver");
0297 MODULE_LICENSE("GPL v2");
0298 MODULE_ALIAS("spi:cr0014114");