0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 #include <linux/leds.h>
0032 #include <linux/module.h>
0033 #include <linux/of_device.h>
0034 #include <linux/spi/spi.h>
0035 #include <linux/mutex.h>
0036 #include <uapi/linux/uleds.h>
0037
0038 struct spi_byte_chipdef {
0039
0040 u8 off_value;
0041
0042 u8 max_value;
0043 };
0044
0045 struct spi_byte_led {
0046 struct led_classdev ldev;
0047 struct spi_device *spi;
0048 char name[LED_MAX_NAME_SIZE];
0049 struct mutex mutex;
0050 const struct spi_byte_chipdef *cdef;
0051 };
0052
0053 static const struct spi_byte_chipdef ubnt_acb_spi_led_cdef = {
0054 .off_value = 0x0,
0055 .max_value = 0x3F,
0056 };
0057
0058 static const struct of_device_id spi_byte_dt_ids[] = {
0059 { .compatible = "ubnt,acb-spi-led", .data = &ubnt_acb_spi_led_cdef },
0060 {},
0061 };
0062
0063 MODULE_DEVICE_TABLE(of, spi_byte_dt_ids);
0064
0065 static int spi_byte_brightness_set_blocking(struct led_classdev *dev,
0066 enum led_brightness brightness)
0067 {
0068 struct spi_byte_led *led = container_of(dev, struct spi_byte_led, ldev);
0069 u8 value;
0070 int ret;
0071
0072 value = (u8) brightness + led->cdef->off_value;
0073
0074 mutex_lock(&led->mutex);
0075 ret = spi_write(led->spi, &value, sizeof(value));
0076 mutex_unlock(&led->mutex);
0077
0078 return ret;
0079 }
0080
0081 static int spi_byte_probe(struct spi_device *spi)
0082 {
0083 struct device_node *child;
0084 struct device *dev = &spi->dev;
0085 struct spi_byte_led *led;
0086 const char *name = "leds-spi-byte::";
0087 const char *state;
0088 int ret;
0089
0090 if (of_get_available_child_count(dev_of_node(dev)) != 1) {
0091 dev_err(dev, "Device must have exactly one LED sub-node.");
0092 return -EINVAL;
0093 }
0094 child = of_get_next_available_child(dev_of_node(dev), NULL);
0095
0096 led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
0097 if (!led)
0098 return -ENOMEM;
0099
0100 of_property_read_string(child, "label", &name);
0101 strlcpy(led->name, name, sizeof(led->name));
0102 led->spi = spi;
0103 mutex_init(&led->mutex);
0104 led->cdef = device_get_match_data(dev);
0105 led->ldev.name = led->name;
0106 led->ldev.brightness = LED_OFF;
0107 led->ldev.max_brightness = led->cdef->max_value - led->cdef->off_value;
0108 led->ldev.brightness_set_blocking = spi_byte_brightness_set_blocking;
0109
0110 state = of_get_property(child, "default-state", NULL);
0111 if (state) {
0112 if (!strcmp(state, "on")) {
0113 led->ldev.brightness = led->ldev.max_brightness;
0114 } else if (strcmp(state, "off")) {
0115
0116 dev_err(dev, "default-state can only be 'on' or 'off'");
0117 return -EINVAL;
0118 }
0119 }
0120 spi_byte_brightness_set_blocking(&led->ldev,
0121 led->ldev.brightness);
0122
0123 ret = devm_led_classdev_register(&spi->dev, &led->ldev);
0124 if (ret) {
0125 mutex_destroy(&led->mutex);
0126 return ret;
0127 }
0128 spi_set_drvdata(spi, led);
0129
0130 return 0;
0131 }
0132
0133 static void spi_byte_remove(struct spi_device *spi)
0134 {
0135 struct spi_byte_led *led = spi_get_drvdata(spi);
0136
0137 mutex_destroy(&led->mutex);
0138 }
0139
0140 static struct spi_driver spi_byte_driver = {
0141 .probe = spi_byte_probe,
0142 .remove = spi_byte_remove,
0143 .driver = {
0144 .name = KBUILD_MODNAME,
0145 .of_match_table = spi_byte_dt_ids,
0146 },
0147 };
0148
0149 module_spi_driver(spi_byte_driver);
0150
0151 MODULE_AUTHOR("Christian Mauderer <oss@c-mauderer.de>");
0152 MODULE_DESCRIPTION("single byte SPI LED driver");
0153 MODULE_LICENSE("GPL v2");
0154 MODULE_ALIAS("spi:leds-spi-byte");