Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (c) 2019 Crane Merchandising Systems. All rights reserved.
0003 // Copyright (C) 2019 Oleh Kravchenko <oleg@kaa.org.ua>
0004 
0005 #include <linux/delay.h>
0006 #include <linux/leds.h>
0007 #include <linux/mod_devicetable.h>
0008 #include <linux/module.h>
0009 #include <linux/property.h>
0010 #include <linux/spi/spi.h>
0011 
0012 /*
0013  * EL15203000 SPI protocol description:
0014  * +-----+---------+
0015  * | LED | COMMAND |
0016  * +-----+---------+
0017  * |  1  |    1    |
0018  * +-----+---------+
0019  * (*) LEDs MCU board expects 20 msec delay per byte.
0020  *
0021  * LEDs:
0022  * +----------+--------------+-------------------------------------------+
0023  * |    ID    |     NAME     |         DESCRIPTION                       |
0024  * +----------+--------------+-------------------------------------------+
0025  * | 'P' 0x50 |     Pipe     | Consists from 5 LEDs, controlled by board |
0026  * +----------+--------------+-------------------------------------------+
0027  * | 'S' 0x53 | Screen frame | Light tube around the screen              |
0028  * +----------+--------------+-------------------------------------------+
0029  * | 'V' 0x56 | Vending area | Highlights a cup of coffee                |
0030  * +----------+--------------+-------------------------------------------+
0031  *
0032  * COMMAND:
0033  * +----------+-----------------+--------------+--------------+
0034  * |  VALUES  |       PIPE      | SCREEN FRAME | VENDING AREA |
0035  * +----------+-----------------+--------------+--------------+
0036  * | '0' 0x30 |                      Off                      |
0037  * +----------+-----------------------------------------------+
0038  * | '1' 0x31 |                      On                       |
0039  * +----------+-----------------+--------------+--------------+
0040  * | '2' 0x32 |     Cascade     |   Breathing  |
0041  * +----------+-----------------+--------------+
0042  * | '3' 0x33 | Inverse cascade |
0043  * +----------+-----------------+
0044  * | '4' 0x34 |     Bounce      |
0045  * +----------+-----------------+
0046  * | '5' 0x35 | Inverse bounce  |
0047  * +----------+-----------------+
0048  */
0049 
0050 /* EL15203000 default settings */
0051 #define EL_FW_DELAY_USEC    20000ul
0052 #define EL_PATTERN_DELAY_MSEC   800u
0053 #define EL_PATTERN_LEN      10u
0054 #define EL_PATTERN_HALF_LEN (EL_PATTERN_LEN / 2)
0055 
0056 enum el15203000_command {
0057     /* for all LEDs */
0058     EL_OFF          = '0',
0059     EL_ON           = '1',
0060 
0061     /* for Screen LED */
0062     EL_SCREEN_BREATHING = '2',
0063 
0064     /* for Pipe LED */
0065     EL_PIPE_CASCADE     = '2',
0066     EL_PIPE_INV_CASCADE = '3',
0067     EL_PIPE_BOUNCE      = '4',
0068     EL_PIPE_INV_BOUNCE  = '5',
0069 };
0070 
0071 struct el15203000_led {
0072     struct led_classdev ldev;
0073     struct el15203000   *priv;
0074     u32         reg;
0075 };
0076 
0077 struct el15203000 {
0078     struct device       *dev;
0079     struct mutex        lock;
0080     struct spi_device   *spi;
0081     unsigned long       delay;
0082     size_t          count;
0083     struct el15203000_led   leds[];
0084 };
0085 
0086 #define to_el15203000_led(d)    container_of(d, struct el15203000_led, ldev)
0087 
0088 static int el15203000_cmd(struct el15203000_led *led, u8 brightness)
0089 {
0090     int     ret;
0091     u8      cmd[2];
0092     size_t      i;
0093 
0094     mutex_lock(&led->priv->lock);
0095 
0096     dev_dbg(led->priv->dev, "Set brightness of 0x%02x(%c) to 0x%02x(%c)",
0097         led->reg, led->reg, brightness, brightness);
0098 
0099     /* to avoid SPI mistiming with firmware we should wait some time */
0100     if (time_after(led->priv->delay, jiffies)) {
0101         dev_dbg(led->priv->dev, "Wait %luus to sync",
0102             EL_FW_DELAY_USEC);
0103 
0104         usleep_range(EL_FW_DELAY_USEC,
0105                  EL_FW_DELAY_USEC + 1);
0106     }
0107 
0108     cmd[0] = led->reg;
0109     cmd[1] = brightness;
0110 
0111     for (i = 0; i < ARRAY_SIZE(cmd); i++) {
0112         if (i)
0113             usleep_range(EL_FW_DELAY_USEC,
0114                      EL_FW_DELAY_USEC + 1);
0115 
0116         ret = spi_write(led->priv->spi, &cmd[i], sizeof(cmd[i]));
0117         if (ret) {
0118             dev_err(led->priv->dev,
0119                 "spi_write() error %d", ret);
0120             break;
0121         }
0122     }
0123 
0124     led->priv->delay = jiffies + usecs_to_jiffies(EL_FW_DELAY_USEC);
0125 
0126     mutex_unlock(&led->priv->lock);
0127 
0128     return ret;
0129 }
0130 
0131 static int el15203000_set_blocking(struct led_classdev *ldev,
0132                    enum led_brightness brightness)
0133 {
0134     struct el15203000_led *led = to_el15203000_led(ldev);
0135 
0136     return el15203000_cmd(led, brightness == LED_OFF ? EL_OFF : EL_ON);
0137 }
0138 
0139 static int el15203000_pattern_set_S(struct led_classdev *ldev,
0140                     struct led_pattern *pattern,
0141                     u32 len, int repeat)
0142 {
0143     struct el15203000_led *led = to_el15203000_led(ldev);
0144 
0145     if (repeat > 0 || len != 2 ||
0146         pattern[0].delta_t != 4000 || pattern[0].brightness != 0 ||
0147         pattern[1].delta_t != 4000 || pattern[1].brightness != 1)
0148         return -EINVAL;
0149 
0150     dev_dbg(led->priv->dev, "Breathing mode for 0x%02x(%c)",
0151         led->reg, led->reg);
0152 
0153     return el15203000_cmd(led, EL_SCREEN_BREATHING);
0154 }
0155 
0156 static bool is_cascade(const struct led_pattern *pattern, u32 len,
0157                bool inv, bool right)
0158 {
0159     int val, t;
0160     u32 i;
0161 
0162     if (len != EL_PATTERN_HALF_LEN)
0163         return false;
0164 
0165     val = right ? BIT(4) : BIT(0);
0166 
0167     for (i = 0; i < len; i++) {
0168         t = inv ? ~val & GENMASK(4, 0) : val;
0169 
0170         if (pattern[i].delta_t != EL_PATTERN_DELAY_MSEC ||
0171             pattern[i].brightness != t)
0172             return false;
0173 
0174         val = right ? val >> 1 : val << 1;
0175     }
0176 
0177     return true;
0178 }
0179 
0180 static bool is_bounce(const struct led_pattern *pattern, u32 len, bool inv)
0181 {
0182     if (len != EL_PATTERN_LEN)
0183         return false;
0184 
0185     return is_cascade(pattern, EL_PATTERN_HALF_LEN, inv, false) &&
0186            is_cascade(pattern + EL_PATTERN_HALF_LEN,
0187               EL_PATTERN_HALF_LEN, inv, true);
0188 }
0189 
0190 static int el15203000_pattern_set_P(struct led_classdev *ldev,
0191                     struct led_pattern *pattern,
0192                     u32 len, int repeat)
0193 {
0194     struct el15203000_led   *led = to_el15203000_led(ldev);
0195     u8          cmd;
0196 
0197     if (repeat > 0)
0198         return -EINVAL;
0199 
0200     if (is_cascade(pattern, len, false, false)) {
0201         dev_dbg(led->priv->dev, "Cascade mode for 0x%02x(%c)",
0202             led->reg, led->reg);
0203 
0204         cmd = EL_PIPE_CASCADE;
0205     } else if (is_cascade(pattern, len, true, false)) {
0206         dev_dbg(led->priv->dev, "Inverse cascade mode for 0x%02x(%c)",
0207             led->reg, led->reg);
0208 
0209         cmd = EL_PIPE_INV_CASCADE;
0210     } else if (is_bounce(pattern, len, false)) {
0211         dev_dbg(led->priv->dev, "Bounce mode for 0x%02x(%c)",
0212             led->reg, led->reg);
0213 
0214         cmd = EL_PIPE_BOUNCE;
0215     } else if (is_bounce(pattern, len, true)) {
0216         dev_dbg(led->priv->dev, "Inverse bounce mode for 0x%02x(%c)",
0217             led->reg, led->reg);
0218 
0219         cmd = EL_PIPE_INV_BOUNCE;
0220     } else {
0221         dev_err(led->priv->dev, "Invalid hw_pattern for 0x%02x(%c)!",
0222             led->reg, led->reg);
0223 
0224         return -EINVAL;
0225     }
0226 
0227     return el15203000_cmd(led, cmd);
0228 }
0229 
0230 static int el15203000_pattern_clear(struct led_classdev *ldev)
0231 {
0232     struct el15203000_led *led = to_el15203000_led(ldev);
0233 
0234     return el15203000_cmd(led, EL_OFF);
0235 }
0236 
0237 static int el15203000_probe_dt(struct el15203000 *priv)
0238 {
0239     struct el15203000_led   *led = priv->leds;
0240     struct fwnode_handle    *child;
0241     int         ret;
0242 
0243     device_for_each_child_node(priv->dev, child) {
0244         struct led_init_data init_data = {};
0245 
0246         ret = fwnode_property_read_u32(child, "reg", &led->reg);
0247         if (ret) {
0248             dev_err(priv->dev, "LED without ID number");
0249             goto err_child_out;
0250         }
0251 
0252         if (led->reg > U8_MAX) {
0253             dev_err(priv->dev, "LED value %d is invalid", led->reg);
0254             ret = -EINVAL;
0255             goto err_child_out;
0256         }
0257 
0258         led->priv             = priv;
0259         led->ldev.max_brightness      = LED_ON;
0260         led->ldev.brightness_set_blocking = el15203000_set_blocking;
0261 
0262         if (led->reg == 'S') {
0263             led->ldev.pattern_set   = el15203000_pattern_set_S;
0264             led->ldev.pattern_clear = el15203000_pattern_clear;
0265         } else if (led->reg == 'P') {
0266             led->ldev.pattern_set   = el15203000_pattern_set_P;
0267             led->ldev.pattern_clear = el15203000_pattern_clear;
0268         }
0269 
0270         init_data.fwnode = child;
0271         ret = devm_led_classdev_register_ext(priv->dev, &led->ldev,
0272                              &init_data);
0273         if (ret) {
0274             dev_err(priv->dev,
0275                 "failed to register LED device %s, err %d",
0276                 led->ldev.name, ret);
0277             goto err_child_out;
0278         }
0279 
0280         led++;
0281     }
0282 
0283     return 0;
0284 
0285 err_child_out:
0286     fwnode_handle_put(child);
0287     return ret;
0288 }
0289 
0290 static int el15203000_probe(struct spi_device *spi)
0291 {
0292     struct el15203000   *priv;
0293     size_t          count;
0294 
0295     count = device_get_child_node_count(&spi->dev);
0296     if (!count) {
0297         dev_err(&spi->dev, "LEDs are not defined in device tree!");
0298         return -ENODEV;
0299     }
0300 
0301     priv = devm_kzalloc(&spi->dev, struct_size(priv, leds, count),
0302                 GFP_KERNEL);
0303     if (!priv)
0304         return -ENOMEM;
0305 
0306     mutex_init(&priv->lock);
0307     priv->count = count;
0308     priv->dev   = &spi->dev;
0309     priv->spi   = spi;
0310     priv->delay = jiffies -
0311               usecs_to_jiffies(EL_FW_DELAY_USEC);
0312 
0313     spi_set_drvdata(spi, priv);
0314 
0315     return el15203000_probe_dt(priv);
0316 }
0317 
0318 static void el15203000_remove(struct spi_device *spi)
0319 {
0320     struct el15203000 *priv = spi_get_drvdata(spi);
0321 
0322     mutex_destroy(&priv->lock);
0323 }
0324 
0325 static const struct of_device_id el15203000_dt_ids[] = {
0326     { .compatible = "crane,el15203000", },
0327     {},
0328 };
0329 
0330 MODULE_DEVICE_TABLE(of, el15203000_dt_ids);
0331 
0332 static struct spi_driver el15203000_driver = {
0333     .probe      = el15203000_probe,
0334     .remove     = el15203000_remove,
0335     .driver = {
0336         .name       = KBUILD_MODNAME,
0337         .of_match_table = el15203000_dt_ids,
0338     },
0339 };
0340 
0341 module_spi_driver(el15203000_driver);
0342 
0343 MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
0344 MODULE_DESCRIPTION("el15203000 LED driver");
0345 MODULE_LICENSE("GPL v2");
0346 MODULE_ALIAS("spi:el15203000");