1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2025 Pengutronix
4 *
5 * Author: Steffen Trumtrar <kernel@pengutronix.de>
6 */
7
8 #include <linux/init.h>
9 #include <linux/module.h>
10 #include <linux/mutex.h>
11 #include <linux/of.h>
12 #include <linux/platform_device.h>
13 #include <linux/regmap.h>
14 #include <linux/spi/spi.h>
15
16 #include "leds-lp5860.h"
17
18 #define LP5860_SPI_WRITE_FLAG BIT(13)
19
20 /*
21 * The lp5860 uses a rather uncommon SPI data format: The R/W flag is on BIT(5) in the two address
22 * bytes; BIT(4) to BIT(0) are don't care. Therefore it has 10 bits for the address and 6 bits for
23 * padding the address. The address bytes are sent MSB first. Matching the cores registers to regmap
24 * results in write_flag_mask being BIT(13).
25 */
26 static const struct regmap_config lp5860_regmap_config = {
27 .name = "lp5860",
28 .reg_bits = 10,
29 .pad_bits = 6,
30 .val_bits = 8,
31 .write_flag_mask = LP5860_SPI_WRITE_FLAG,
32 .reg_format_endian = REGMAP_ENDIAN_BIG,
33 .max_register = LP5860_MAX_REG,
34 };
35
lp5860_probe(struct spi_device * spi)36 static int lp5860_probe(struct spi_device *spi)
37 {
38 struct device *dev = &spi->dev;
39 struct lp5860 *lp5860;
40 unsigned int multi_leds;
41 int ret;
42
43 multi_leds = device_get_child_node_count(dev);
44 if (!multi_leds) {
45 dev_err(dev, "LEDs are not defined in Device Tree!");
46 return -ENODEV;
47 }
48
49 if (multi_leds > LP5860_MAX_LED) {
50 dev_err(dev, "Too many LEDs specified.\n");
51 return -EINVAL;
52 }
53
54 lp5860 = devm_kzalloc(dev, struct_size(lp5860, leds, multi_leds),
55 GFP_KERNEL);
56 if (!lp5860)
57 return -ENOMEM;
58
59 lp5860->regmap = devm_regmap_init_spi(spi, &lp5860_regmap_config);
60 if (IS_ERR(lp5860->regmap))
61 return dev_err_probe(&spi->dev, PTR_ERR(lp5860->regmap),
62 "Failed to initialise Regmap.\n");
63
64 lp5860->dev = dev;
65
66 ret = devm_mutex_init(dev, &lp5860->lock);
67 if (ret)
68 return ret;
69
70 spi_set_drvdata(spi, lp5860);
71
72 return lp5860_device_init(dev);
73 }
74
lp5860_remove(struct spi_device * spi)75 static void lp5860_remove(struct spi_device *spi)
76 {
77 lp5860_device_remove(&spi->dev);
78 }
79
80 static const struct of_device_id lp5860_of_match[] = {
81 { .compatible = "ti,lp5860" },
82 {}
83 };
84 MODULE_DEVICE_TABLE(of, lp5860_of_match);
85
86 static struct spi_driver lp5860_driver = {
87 .driver = {
88 .name = "lp5860-spi",
89 .of_match_table = lp5860_of_match,
90 },
91 .probe = lp5860_probe,
92 .remove = lp5860_remove,
93 };
94 module_spi_driver(lp5860_driver);
95
96 MODULE_AUTHOR("Steffen Trumtrar <kernel@pengutronix.de>");
97 MODULE_DESCRIPTION("TI LP5860 RGB LED SPI driver");
98 MODULE_LICENSE("GPL");
99