1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Driver for Sercomm MSP430G2513 LEDs.
5 * Copyright 2023 Álvaro Fernández Rojas <noltari@gmail.com>
8 #include <linux/delay.h>
9 #include <linux/leds.h>
10 #include <linux/module.h>
11 #include <linux/of_device.h>
12 #include <linux/spi/spi.h>
16 * MSP430G2513 SPI protocol description:
17 * +----+----+----+----+----+----+
18 * | b1 | b2 | b3 | b4 | b5 | b6 |
19 * +----+----+----+----+----+----+
20 * 6 bytes TX & RX per transaction.
23 * MSP430G2513 can control up to 9 LEDs.
26 * b3-b6: LED function parameters
33 * - b5: repeat (0 = infinite)
36 * - b4: blink while pulsing? (unknown)
37 * - b5: repeat (0 = infinite)
40 * - b4: blink while pulsing? (unknown)
41 * - b5: repeat (0 = infinite)
44 * - b4: blink while pulsing? (unknown)
45 * - b5: repeat (0 = infinite)
47 * - b3: brightness [0,4]
49 * MCU Commands (b1 = 0x55):
50 * [0x0a] FW upgrade data
51 * - b3: Data size (usually 0x40), which is appended to TX & RX.
52 * [0x31] Get MCU version? (unknown)
53 * [0x68] Get MCU work mode
54 * [0xa5] Start FW upgrade
55 * [0xf0] End FW upgrade
58 #define MSP430_CMD_BYTES 6
59 #define MSP430_CMD_MCU 0x55
60 #define MSP430_MCU_WM 0x68
62 #define MSP430_LED_MIN_ID 1
63 #define MSP430_LED_MAX_ID 9
65 #define MSP430_LED_OFF 0
66 #define MSP430_LED_ON 1
67 #define MSP430_LED_FLASH 2
68 #define MSP430_LED_PULSE 3
69 #define MSP430_LED_PULSE_ON 4
70 #define MSP430_LED_PULSE_OFF 5
71 #define MSP430_LED_LEVEL 6
73 #define MSP430_LED_BLINK_DEF 500
74 #define MSP430_LED_BLINK_MASK 0xff
75 #define MSP430_LED_BLINK_MS 6
76 #define MSP430_LED_BLINK_MAX (MSP430_LED_BLINK_MS * \
77 MSP430_LED_BLINK_MASK)
79 #define MSP430_LED_BRIGHTNESS_MAX 5
80 #define MSP430_LED_REPEAT_MAX 0xff
83 * struct msp430_led - state container for Sercomm MSP430 based LEDs
84 * @cdev: LED class device for this LED
89 struct led_classdev cdev
;
90 struct spi_device
*spi
;
94 static inline int msp430_cmd(struct spi_device
*spi
, u8 tx
[MSP430_CMD_BYTES
],
95 u8 rx
[MSP430_CMD_BYTES
])
97 struct device
*dev
= &spi
->dev
;
100 memset(rx
, 0, MSP430_CMD_BYTES
);
102 rc
= spi_write_then_read(spi
, tx
, MSP430_CMD_BYTES
,
103 rx
, MSP430_CMD_BYTES
);
105 dev_err(dev
, "spi error\n");
107 dev_dbg(dev
, "msp430_cmd: [%02x %02x %02x %02x %02x %02x]"
108 " -> [%02x %02x %02x %02x %02x %02x]",
109 tx
[0], tx
[1], tx
[2], tx
[3], tx
[4], tx
[5],
110 rx
[0], rx
[1], rx
[2], rx
[3], rx
[4], rx
[5]);
115 static unsigned long msp430_blink_delay(unsigned long delay
)
117 unsigned long msp430_delay
;
119 msp430_delay
= delay
+ MSP430_LED_BLINK_MS
/ 2;
120 msp430_delay
= msp430_delay
/ MSP430_LED_BLINK_MS
;
121 if (msp430_delay
== 0)
127 static int msp430_blink_set(struct led_classdev
*led_cdev
,
128 unsigned long *delay_on
,
129 unsigned long *delay_off
)
131 struct msp430_led
*led
=
132 container_of(led_cdev
, struct msp430_led
, cdev
);
133 u8 tx
[MSP430_CMD_BYTES
] = {led
->id
, MSP430_LED_FLASH
, 0, 0, 0, 0};
134 u8 rx
[MSP430_CMD_BYTES
];
138 *delay_on
= MSP430_LED_BLINK_DEF
;
140 *delay_off
= MSP430_LED_BLINK_DEF
;
142 delay
= msp430_blink_delay(*delay_on
);
143 if (delay
!= msp430_blink_delay(*delay_off
)) {
144 dev_dbg(led_cdev
->dev
,
145 "fallback to soft blinking (delay_on != delay_off)\n");
149 if (delay
> MSP430_LED_BLINK_MASK
) {
150 dev_dbg(led_cdev
->dev
,
151 "fallback to soft blinking (delay > %ums)\n",
152 MSP430_LED_BLINK_MAX
);
158 return msp430_cmd(led
->spi
, tx
, rx
);
161 static int msp430_brightness_set(struct led_classdev
*led_cdev
,
162 enum led_brightness brightness
)
164 struct msp430_led
*led
=
165 container_of(led_cdev
, struct msp430_led
, cdev
);
166 u8 tx
[MSP430_CMD_BYTES
] = {led
->id
, 0, 0, 0, 0, 0};
167 u8 rx
[MSP430_CMD_BYTES
];
168 u8 val
= (u8
) brightness
;
173 tx
[1] = MSP430_LED_OFF
;
175 case MSP430_LED_BRIGHTNESS_MAX
:
176 tx
[1] = MSP430_LED_ON
;
179 tx
[1] = MSP430_LED_LEVEL
;
184 return msp430_cmd(led
->spi
, tx
, rx
);
187 static int msp430_pattern_clear(struct led_classdev
*ldev
)
189 msp430_brightness_set(ldev
, LED_OFF
);
194 static int msp430_pattern_set(struct led_classdev
*led_cdev
,
195 struct led_pattern
*pattern
,
198 struct msp430_led
*led
=
199 container_of(led_cdev
, struct msp430_led
, cdev
);
200 u8 tx
[MSP430_CMD_BYTES
] = {led
->id
, 0, 0, 0, 0, 0};
201 u8 rx
[MSP430_CMD_BYTES
];
202 unsigned long delay0
;
203 unsigned long delay1
;
207 repeat
> MSP430_LED_REPEAT_MAX
||
208 pattern
[0].delta_t
> MSP430_LED_BLINK_MAX
||
209 pattern
[1].delta_t
> MSP430_LED_BLINK_MAX
)
212 delay0
= msp430_blink_delay(pattern
[0].delta_t
);
213 delay1
= msp430_blink_delay(pattern
[1].delta_t
);
215 /* Infinite pattern */
219 /* Pulse: <off> <delay> <max> <delay> */
220 if (delay0
== delay1
&&
221 pattern
[0].brightness
== LED_OFF
&&
222 pattern
[1].brightness
== MSP430_LED_BRIGHTNESS_MAX
)
224 tx
[1] = MSP430_LED_PULSE
;
229 /* Pulse On: <off> <delay> <max> <0ms> */
230 if (pattern
[0].delta_t
!= 0 &&
231 pattern
[1].delta_t
== 0 &&
232 pattern
[0].brightness
== LED_OFF
&&
233 pattern
[1].brightness
== MSP430_LED_BRIGHTNESS_MAX
) {
234 tx
[1] = MSP430_LED_PULSE_ON
;
239 /* Pulse Off: <max> <delay> <off> <0ms> */
240 if (pattern
[0].delta_t
!= 0 &&
241 pattern
[1].delta_t
== 0 &&
242 pattern
[0].brightness
== MSP430_LED_BRIGHTNESS_MAX
&&
243 pattern
[1].brightness
== LED_OFF
) {
244 tx
[1] = MSP430_LED_PULSE_OFF
;
252 rc
= msp430_cmd(led
->spi
, tx
, rx
);
259 static int msp430_led(struct spi_device
*spi
, struct device_node
*nc
, u8 id
)
261 struct device
*dev
= &spi
->dev
;
262 struct led_init_data init_data
= {};
263 struct msp430_led
*led
;
264 enum led_default_state state
;
267 led
= devm_kzalloc(dev
, sizeof(*led
), GFP_KERNEL
);
274 init_data
.fwnode
= of_fwnode_handle(nc
);
276 state
= led_init_default_state_get(init_data
.fwnode
);
278 case LEDS_DEFSTATE_ON
:
279 led
->cdev
.brightness
= MSP430_LED_BRIGHTNESS_MAX
;
282 led
->cdev
.brightness
= LED_OFF
;
286 msp430_brightness_set(&led
->cdev
, led
->cdev
.brightness
);
288 led
->cdev
.blink_set
= msp430_blink_set
;
289 led
->cdev
.brightness_set_blocking
= msp430_brightness_set
;
290 led
->cdev
.max_brightness
= MSP430_LED_BRIGHTNESS_MAX
;
291 led
->cdev
.pattern_clear
= msp430_pattern_clear
;
292 led
->cdev
.pattern_set
= msp430_pattern_set
;
294 rc
= devm_led_classdev_register_ext(dev
, &led
->cdev
, &init_data
);
298 dev_dbg(dev
, "registered LED %s\n", led
->cdev
.name
);
303 static inline int msp430_check_workmode(struct spi_device
*spi
)
305 struct device
*dev
= &spi
->dev
;
306 u8 tx
[MSP430_CMD_BYTES
] = {MSP430_CMD_MCU
, MSP430_MCU_WM
, 0, 0, 0, 0};
307 u8 rx
[MSP430_CMD_BYTES
];
310 rc
= msp430_cmd(spi
, tx
, rx
);
314 if ((rx
[3] == 0xA5 && rx
[4] == 'Z') ||
315 (rx
[4] == 0xA5 && rx
[5] == 'Z') ||
316 (rx
[4] == '\b' && rx
[5] == '\n')) {
317 dev_err(dev
, "invalid workmode: "
318 "[%02x %02x %02x %02x %02x %02x]\n",
319 rx
[0], rx
[1], rx
[2], rx
[3], rx
[4], rx
[5]);
326 static int msp430_leds_probe(struct spi_device
*spi
)
328 struct device
*dev
= &spi
->dev
;
329 struct device_node
*np
= dev_of_node(dev
);
330 struct device_node
*child
;
333 rc
= msp430_check_workmode(spi
);
337 for_each_available_child_of_node(np
, child
) {
340 if (of_property_read_u32(child
, "reg", ®
))
343 if (reg
< MSP430_LED_MIN_ID
|| reg
> MSP430_LED_MAX_ID
) {
344 dev_err(dev
, "invalid LED (%u) [%d, %d]\n", reg
,
345 MSP430_LED_MIN_ID
, MSP430_LED_MAX_ID
);
349 rc
= msp430_led(spi
, child
, reg
);
359 static const struct of_device_id msp430_leds_of_match
[] = {
360 { .compatible
= "sercomm,msp430-leds", },
363 MODULE_DEVICE_TABLE(of
, msp430_leds_of_match
);
365 static const struct spi_device_id msp430_leds_id_table
[] = {
366 { "msp430-leds", 0 },
369 MODULE_DEVICE_TABLE(spi
, msp430_leds_id_table
);
371 static struct spi_driver msp430_leds_driver
= {
373 .name
= KBUILD_MODNAME
,
374 .of_match_table
= msp430_leds_of_match
,
376 .id_table
= msp430_leds_id_table
,
377 .probe
= msp430_leds_probe
,
379 module_spi_driver(msp430_leds_driver
);
381 MODULE_AUTHOR("Álvaro Fernández Rojas <noltari@gmail.com>");
382 MODULE_DESCRIPTION("LED driver for Sercomm MSP430 controllers");
383 MODULE_LICENSE("GPL v2");
384 MODULE_ALIAS("platform:leds-sercomm-msp430");