1// SPDX-License-Identifier: GPL-2.0
2// Copyright (c) 2019 Crane Merchandising Systems. All rights reserved.
3// Copyright (C) 2019 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
11/*
12 * EL15203000 SPI protocol description:
13 * +-----+---------+
14 * | LED | COMMAND |
15 * +-----+---------+
16 * |  1  |    1    |
17 * +-----+---------+
18 * (*) LEDs MCU board expects 20 msec delay per byte.
19 *
20 * LEDs:
21 * +----------+--------------+-------------------------------------------+
22 * |    ID    |     NAME     |         DESCRIPTION                       |
23 * +----------+--------------+-------------------------------------------+
24 * | 'P' 0x50 |     Pipe     | Consists from 5 LEDs, controlled by board |
25 * +----------+--------------+-------------------------------------------+
26 * | 'S' 0x53 | Screen frame | Light tube around the screen              |
27 * +----------+--------------+-------------------------------------------+
28 * | 'V' 0x56 | Vending area | Highlights a cup of coffee                |
29 * +----------+--------------+-------------------------------------------+
30 *
31 * COMMAND:
32 * +----------+-----------------+--------------+--------------+
33 * |  VALUES  |       PIPE      | SCREEN FRAME | VENDING AREA |
34 * +----------+-----------------+--------------+--------------+
35 * | '0' 0x30 |                      Off                      |
36 * +----------+-----------------------------------------------+
37 * | '1' 0x31 |                      On                       |
38 * +----------+-----------------+--------------+--------------+
39 * | '2' 0x32 |     Cascade     |   Breathing  |
40 * +----------+-----------------+--------------+
41 * | '3' 0x33 | Inverse cascade |
42 * +----------+-----------------+
43 * | '4' 0x34 |     Bounce      |
44 * +----------+-----------------+
45 * | '5' 0x35 | Inverse bounce  |
46 * +----------+-----------------+
47 */
48
49/* EL15203000 default settings */
50#define EL_FW_DELAY_USEC	20000ul
51#define EL_PATTERN_DELAY_MSEC	800u
52#define EL_PATTERN_LEN		10u
53#define EL_PATTERN_HALF_LEN	(EL_PATTERN_LEN / 2)
54
55enum el15203000_command {
56	/* for all LEDs */
57	EL_OFF			= '0',
58	EL_ON			= '1',
59
60	/* for Screen LED */
61	EL_SCREEN_BREATHING	= '2',
62
63	/* for Pipe LED */
64	EL_PIPE_CASCADE		= '2',
65	EL_PIPE_INV_CASCADE	= '3',
66	EL_PIPE_BOUNCE		= '4',
67	EL_PIPE_INV_BOUNCE	= '5',
68};
69
70struct el15203000_led {
71	struct el15203000	*priv;
72	struct led_classdev	ldev;
73	u32			reg;
74};
75
76struct el15203000 {
77	struct device		*dev;
78	struct mutex		lock;
79	struct spi_device	*spi;
80	unsigned long		delay;
81	size_t			count;
82	struct el15203000_led	leds[];
83};
84
85static int el15203000_cmd(struct el15203000_led *led, u8 brightness)
86{
87	int		ret;
88	u8		cmd[2];
89	size_t		i;
90
91	mutex_lock(&led->priv->lock);
92
93	dev_dbg(led->priv->dev, "Set brightness of 0x%02x(%c) to 0x%02x(%c)",
94		led->reg, led->reg, brightness, brightness);
95
96	/* to avoid SPI mistiming with firmware we should wait some time */
97	if (time_after(led->priv->delay, jiffies)) {
98		dev_dbg(led->priv->dev, "Wait %luus to sync",
99			EL_FW_DELAY_USEC);
100
101		usleep_range(EL_FW_DELAY_USEC,
102			     EL_FW_DELAY_USEC + 1);
103	}
104
105	cmd[0] = led->reg;
106	cmd[1] = brightness;
107
108	for (i = 0; i < ARRAY_SIZE(cmd); i++) {
109		if (i)
110			usleep_range(EL_FW_DELAY_USEC,
111				     EL_FW_DELAY_USEC + 1);
112
113		ret = spi_write(led->priv->spi, &cmd[i], sizeof(cmd[i]));
114		if (ret) {
115			dev_err(led->priv->dev,
116				"spi_write() error %d", ret);
117			break;
118		}
119	}
120
121	led->priv->delay = jiffies + usecs_to_jiffies(EL_FW_DELAY_USEC);
122
123	mutex_unlock(&led->priv->lock);
124
125	return ret;
126}
127
128static int el15203000_set_blocking(struct led_classdev *ldev,
129				   enum led_brightness brightness)
130{
131	struct el15203000_led *led = container_of(ldev,
132						  struct el15203000_led,
133						  ldev);
134
135	return el15203000_cmd(led, brightness == LED_OFF ? EL_OFF : EL_ON);
136}
137
138static int el15203000_pattern_set_S(struct led_classdev *ldev,
139				    struct led_pattern *pattern,
140				    u32 len, int repeat)
141{
142	struct el15203000_led *led = container_of(ldev,
143						  struct el15203000_led,
144						  ldev);
145
146	if (repeat > 0 || len != 2 ||
147	    pattern[0].delta_t != 4000 || pattern[0].brightness != 0 ||
148	    pattern[1].delta_t != 4000 || pattern[1].brightness != 1)
149		return -EINVAL;
150
151	dev_dbg(led->priv->dev, "Breathing mode for 0x%02x(%c)",
152		led->reg, led->reg);
153
154	return el15203000_cmd(led, EL_SCREEN_BREATHING);
155}
156
157static bool is_cascade(const struct led_pattern *pattern, u32 len,
158		       bool inv, bool right)
159{
160	int val, t;
161	u32 i;
162
163	if (len != EL_PATTERN_HALF_LEN)
164		return false;
165
166	val = right ? BIT(4) : BIT(0);
167
168	for (i = 0; i < len; i++) {
169		t = inv ? ~val & GENMASK(4, 0) : val;
170
171		if (pattern[i].delta_t != EL_PATTERN_DELAY_MSEC ||
172		    pattern[i].brightness != t)
173			return false;
174
175		val = right ? val >> 1 : val << 1;
176	}
177
178	return true;
179}
180
181static bool is_bounce(const struct led_pattern *pattern, u32 len, bool inv)
182{
183	if (len != EL_PATTERN_LEN)
184		return false;
185
186	return is_cascade(pattern, EL_PATTERN_HALF_LEN, inv, false) &&
187	       is_cascade(pattern + EL_PATTERN_HALF_LEN,
188			  EL_PATTERN_HALF_LEN, inv, true);
189}
190
191static int el15203000_pattern_set_P(struct led_classdev *ldev,
192				    struct led_pattern *pattern,
193				    u32 len, int repeat)
194{
195	u8			cmd;
196	struct el15203000_led	*led = container_of(ldev,
197						    struct el15203000_led,
198						    ldev);
199
200	if (repeat > 0)
201		return -EINVAL;
202
203	if (is_cascade(pattern, len, false, false)) {
204		dev_dbg(led->priv->dev, "Cascade mode for 0x%02x(%c)",
205			led->reg, led->reg);
206
207		cmd = EL_PIPE_CASCADE;
208	} else if (is_cascade(pattern, len, true, false)) {
209		dev_dbg(led->priv->dev, "Inverse cascade mode for 0x%02x(%c)",
210			led->reg, led->reg);
211
212		cmd = EL_PIPE_INV_CASCADE;
213	} else if (is_bounce(pattern, len, false)) {
214		dev_dbg(led->priv->dev, "Bounce mode for 0x%02x(%c)",
215			led->reg, led->reg);
216
217		cmd = EL_PIPE_BOUNCE;
218	} else if (is_bounce(pattern, len, true)) {
219		dev_dbg(led->priv->dev, "Inverse bounce mode for 0x%02x(%c)",
220			led->reg, led->reg);
221
222		cmd = EL_PIPE_INV_BOUNCE;
223	} else {
224		dev_err(led->priv->dev, "Invalid hw_pattern for 0x%02x(%c)!",
225			led->reg, led->reg);
226
227		return -EINVAL;
228	}
229
230	return el15203000_cmd(led, cmd);
231}
232
233static int el15203000_pattern_clear(struct led_classdev *ldev)
234{
235	struct el15203000_led	*led = container_of(ldev,
236						    struct el15203000_led,
237						    ldev);
238
239	return el15203000_cmd(led, EL_OFF);
240}
241
242static int el15203000_probe_dt(struct el15203000 *priv)
243{
244	struct el15203000_led	*led = priv->leds;
245	struct fwnode_handle	*child;
246	int			ret;
247
248	device_for_each_child_node(priv->dev, child) {
249		struct led_init_data init_data = {};
250
251		ret = fwnode_property_read_u32(child, "reg", &led->reg);
252		if (ret) {
253			dev_err(priv->dev, "LED without ID number");
254			fwnode_handle_put(child);
255
256			break;
257		}
258
259		if (led->reg > U8_MAX) {
260			dev_err(priv->dev, "LED value %d is invalid", led->reg);
261			fwnode_handle_put(child);
262
263			return -EINVAL;
264		}
265
266		led->priv			  = priv;
267		led->ldev.max_brightness	  = LED_ON;
268		led->ldev.brightness_set_blocking = el15203000_set_blocking;
269
270		if (led->reg == 'S') {
271			led->ldev.pattern_set	= el15203000_pattern_set_S;
272			led->ldev.pattern_clear	= el15203000_pattern_clear;
273		} else if (led->reg == 'P') {
274			led->ldev.pattern_set	= el15203000_pattern_set_P;
275			led->ldev.pattern_clear	= el15203000_pattern_clear;
276		}
277
278		init_data.fwnode = child;
279		ret = devm_led_classdev_register_ext(priv->dev, &led->ldev,
280						     &init_data);
281		if (ret) {
282			dev_err(priv->dev,
283				"failed to register LED device %s, err %d",
284				led->ldev.name, ret);
285			fwnode_handle_put(child);
286
287			break;
288		}
289
290		led++;
291	}
292
293	return ret;
294}
295
296static int el15203000_probe(struct spi_device *spi)
297{
298	struct el15203000	*priv;
299	size_t			count;
300
301	count = device_get_child_node_count(&spi->dev);
302	if (!count) {
303		dev_err(&spi->dev, "LEDs are not defined in device tree!");
304		return -ENODEV;
305	}
306
307	priv = devm_kzalloc(&spi->dev, struct_size(priv, leds, count),
308			    GFP_KERNEL);
309	if (!priv)
310		return -ENOMEM;
311
312	mutex_init(&priv->lock);
313	priv->count	= count;
314	priv->dev	= &spi->dev;
315	priv->spi	= spi;
316	priv->delay	= jiffies -
317			  usecs_to_jiffies(EL_FW_DELAY_USEC);
318
319	spi_set_drvdata(spi, priv);
320
321	return el15203000_probe_dt(priv);
322}
323
324static int el15203000_remove(struct spi_device *spi)
325{
326	struct el15203000 *priv = spi_get_drvdata(spi);
327
328	mutex_destroy(&priv->lock);
329
330	return 0;
331}
332
333static const struct of_device_id el15203000_dt_ids[] = {
334	{ .compatible = "crane,el15203000", },
335	{},
336};
337
338MODULE_DEVICE_TABLE(of, el15203000_dt_ids);
339
340static struct spi_driver el15203000_driver = {
341	.probe		= el15203000_probe,
342	.remove		= el15203000_remove,
343	.driver = {
344		.name		= KBUILD_MODNAME,
345		.of_match_table	= el15203000_dt_ids,
346	},
347};
348
349module_spi_driver(el15203000_driver);
350
351MODULE_AUTHOR("Oleh Kravchenko <oleg@kaa.org.ua>");
352MODULE_DESCRIPTION("el15203000 LED driver");
353MODULE_LICENSE("GPL v2");
354MODULE_ALIAS("spi:el15203000");
355