Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright 2014 Belkin Inc.
  4 * Copyright 2015 Andrew Lunn <andrew@lunn.ch>
 
 
 
 
  5 */
  6
  7#include <linux/i2c.h>
  8#include <linux/leds.h>
  9#include <linux/module.h>
 10#include <linux/of.h>
 
 11#include <linux/regmap.h>
 12#include <linux/slab.h>
 13
 14#define TLC591XX_MAX_LEDS	16
 15#define TLC591XX_MAX_BRIGHTNESS	256
 16
 17#define TLC591XX_REG_MODE1	0x00
 18#define MODE1_RESPON_ADDR_MASK	0xF0
 19#define MODE1_NORMAL_MODE	(0 << 4)
 20#define MODE1_SPEED_MODE	(1 << 4)
 21
 22#define TLC591XX_REG_MODE2	0x01
 23#define MODE2_DIM		(0 << 5)
 24#define MODE2_BLINK		(1 << 5)
 25#define MODE2_OCH_STOP		(0 << 3)
 26#define MODE2_OCH_ACK		(1 << 3)
 27
 28#define TLC591XX_REG_PWM(x)	(0x02 + (x))
 29
 30#define TLC591XX_REG_GRPPWM	0x12
 31#define TLC591XX_REG_GRPFREQ	0x13
 32
 33/* LED Driver Output State, determine the source that drives LED outputs */
 34#define LEDOUT_OFF		0x0	/* Output LOW */
 35#define LEDOUT_ON		0x1	/* Output HI-Z */
 36#define LEDOUT_DIM		0x2	/* Dimming */
 37#define LEDOUT_BLINK		0x3	/* Blinking */
 38#define LEDOUT_MASK		0x3
 39
 40#define ldev_to_led(c)		container_of(c, struct tlc591xx_led, ldev)
 41
 42struct tlc591xx_led {
 43	bool active;
 44	unsigned int led_no;
 45	struct led_classdev ldev;
 46	struct tlc591xx_priv *priv;
 47};
 48
 49struct tlc591xx_priv {
 50	struct tlc591xx_led leds[TLC591XX_MAX_LEDS];
 51	struct regmap *regmap;
 52	unsigned int reg_ledout_offset;
 53};
 54
 55struct tlc591xx {
 56	unsigned int max_leds;
 57	unsigned int reg_ledout_offset;
 58};
 59
 60static const struct tlc591xx tlc59116 = {
 61	.max_leds = 16,
 62	.reg_ledout_offset = 0x14,
 63};
 64
 65static const struct tlc591xx tlc59108 = {
 66	.max_leds = 8,
 67	.reg_ledout_offset = 0x0c,
 68};
 69
 70static int
 71tlc591xx_set_mode(struct regmap *regmap, u8 mode)
 72{
 73	int err;
 74	u8 val;
 75
 76	err = regmap_write(regmap, TLC591XX_REG_MODE1, MODE1_NORMAL_MODE);
 77	if (err)
 78		return err;
 79
 80	val = MODE2_OCH_STOP | mode;
 81
 82	return regmap_write(regmap, TLC591XX_REG_MODE2, val);
 83}
 84
 85static int
 86tlc591xx_set_ledout(struct tlc591xx_priv *priv, struct tlc591xx_led *led,
 87		    u8 val)
 88{
 89	unsigned int i = (led->led_no % 4) * 2;
 90	unsigned int mask = LEDOUT_MASK << i;
 91	unsigned int addr = priv->reg_ledout_offset + (led->led_no >> 2);
 92
 93	val = val << i;
 94
 95	return regmap_update_bits(priv->regmap, addr, mask, val);
 96}
 97
 98static int
 99tlc591xx_set_pwm(struct tlc591xx_priv *priv, struct tlc591xx_led *led,
100		 u8 brightness)
101{
102	u8 pwm = TLC591XX_REG_PWM(led->led_no);
103
104	return regmap_write(priv->regmap, pwm, brightness);
105}
106
107static int
108tlc591xx_brightness_set(struct led_classdev *led_cdev,
109			enum led_brightness brightness)
110{
111	struct tlc591xx_led *led = ldev_to_led(led_cdev);
112	struct tlc591xx_priv *priv = led->priv;
113	int err;
114
115	switch ((int)brightness) {
116	case 0:
117		err = tlc591xx_set_ledout(priv, led, LEDOUT_OFF);
118		break;
119	case TLC591XX_MAX_BRIGHTNESS:
120		err = tlc591xx_set_ledout(priv, led, LEDOUT_ON);
121		break;
122	default:
123		err = tlc591xx_set_ledout(priv, led, LEDOUT_DIM);
124		if (!err)
125			err = tlc591xx_set_pwm(priv, led, brightness);
126	}
127
128	return err;
129}
130
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131static const struct regmap_config tlc591xx_regmap = {
132	.reg_bits = 8,
133	.val_bits = 8,
134	.max_register = 0x1e,
135};
136
137static const struct of_device_id of_tlc591xx_leds_match[] __maybe_unused = {
138	{ .compatible = "ti,tlc59116",
139	  .data = &tlc59116 },
140	{ .compatible = "ti,tlc59108",
141	  .data = &tlc59108 },
142	{},
143};
144MODULE_DEVICE_TABLE(of, of_tlc591xx_leds_match);
145
146static int
147tlc591xx_probe(struct i2c_client *client)
 
148{
149	struct device_node *np;
150	struct device *dev = &client->dev;
 
151	const struct tlc591xx *tlc591xx;
152	struct tlc591xx_priv *priv;
153	int err, count, reg;
154
155	np = dev_of_node(dev);
156	if (!np)
157		return -ENODEV;
158
159	tlc591xx = device_get_match_data(dev);
160	if (!tlc591xx)
161		return -ENODEV;
162
163	count = of_get_available_child_count(np);
164	if (!count || count > tlc591xx->max_leds)
165		return -EINVAL;
166
167	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
168	if (!priv)
169		return -ENOMEM;
170
171	priv->regmap = devm_regmap_init_i2c(client, &tlc591xx_regmap);
172	if (IS_ERR(priv->regmap)) {
173		err = PTR_ERR(priv->regmap);
174		dev_err(dev, "Failed to allocate register map: %d\n", err);
175		return err;
176	}
177	priv->reg_ledout_offset = tlc591xx->reg_ledout_offset;
178
179	i2c_set_clientdata(client, priv);
180
181	err = tlc591xx_set_mode(priv->regmap, MODE2_DIM);
182	if (err < 0)
183		return err;
184
185	for_each_available_child_of_node_scoped(np, child) {
186		struct tlc591xx_led *led;
187		struct led_init_data init_data = {};
188
189		init_data.fwnode = of_fwnode_handle(child);
190
191		err = of_property_read_u32(child, "reg", &reg);
192		if (err)
193			return err;
194
195		if (reg < 0 || reg >= tlc591xx->max_leds ||
196		    priv->leds[reg].active)
197			return -EINVAL;
 
 
 
 
 
 
 
 
 
 
 
 
 
198
199		led = &priv->leds[reg];
200
201		led->active = true;
202		led->priv = priv;
203		led->led_no = reg;
204		led->ldev.brightness_set_blocking = tlc591xx_brightness_set;
205		led->ldev.max_brightness = TLC591XX_MAX_BRIGHTNESS;
206		err = devm_led_classdev_register_ext(dev, &led->ldev,
207						     &init_data);
208		if (err < 0)
209			return dev_err_probe(dev, err,
210					     "couldn't register LED %s\n",
211					     led->ldev.name);
212	}
213	return 0;
214}
215
216static const struct i2c_device_id tlc591xx_id[] = {
217	{ "tlc59116" },
218	{ "tlc59108" },
219	{},
220};
221MODULE_DEVICE_TABLE(i2c, tlc591xx_id);
222
223static struct i2c_driver tlc591xx_driver = {
224	.driver = {
225		.name = "tlc591xx",
226		.of_match_table = of_match_ptr(of_tlc591xx_leds_match),
227	},
228	.probe = tlc591xx_probe,
 
229	.id_table = tlc591xx_id,
230};
231
232module_i2c_driver(tlc591xx_driver);
233
234MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
235MODULE_LICENSE("GPL");
236MODULE_DESCRIPTION("TLC591XX LED driver");
v4.10.11
 
  1/*
  2 * Copyright 2014 Belkin Inc.
  3 * Copyright 2015 Andrew Lunn <andrew@lunn.ch>
  4 *
  5 * This program is free software; you can redistribute it and/or modify
  6 * it under the terms of the GNU General Public License as published by
  7 * the Free Software Foundation; version 2 of the License.
  8 */
  9
 10#include <linux/i2c.h>
 11#include <linux/leds.h>
 12#include <linux/module.h>
 13#include <linux/of.h>
 14#include <linux/of_device.h>
 15#include <linux/regmap.h>
 16#include <linux/slab.h>
 17
 18#define TLC591XX_MAX_LEDS	16
 
 19
 20#define TLC591XX_REG_MODE1	0x00
 21#define MODE1_RESPON_ADDR_MASK	0xF0
 22#define MODE1_NORMAL_MODE	(0 << 4)
 23#define MODE1_SPEED_MODE	(1 << 4)
 24
 25#define TLC591XX_REG_MODE2	0x01
 26#define MODE2_DIM		(0 << 5)
 27#define MODE2_BLINK		(1 << 5)
 28#define MODE2_OCH_STOP		(0 << 3)
 29#define MODE2_OCH_ACK		(1 << 3)
 30
 31#define TLC591XX_REG_PWM(x)	(0x02 + (x))
 32
 33#define TLC591XX_REG_GRPPWM	0x12
 34#define TLC591XX_REG_GRPFREQ	0x13
 35
 36/* LED Driver Output State, determine the source that drives LED outputs */
 37#define LEDOUT_OFF		0x0	/* Output LOW */
 38#define LEDOUT_ON		0x1	/* Output HI-Z */
 39#define LEDOUT_DIM		0x2	/* Dimming */
 40#define LEDOUT_BLINK		0x3	/* Blinking */
 41#define LEDOUT_MASK		0x3
 42
 43#define ldev_to_led(c)		container_of(c, struct tlc591xx_led, ldev)
 44
 45struct tlc591xx_led {
 46	bool active;
 47	unsigned int led_no;
 48	struct led_classdev ldev;
 49	struct tlc591xx_priv *priv;
 50};
 51
 52struct tlc591xx_priv {
 53	struct tlc591xx_led leds[TLC591XX_MAX_LEDS];
 54	struct regmap *regmap;
 55	unsigned int reg_ledout_offset;
 56};
 57
 58struct tlc591xx {
 59	unsigned int max_leds;
 60	unsigned int reg_ledout_offset;
 61};
 62
 63static const struct tlc591xx tlc59116 = {
 64	.max_leds = 16,
 65	.reg_ledout_offset = 0x14,
 66};
 67
 68static const struct tlc591xx tlc59108 = {
 69	.max_leds = 8,
 70	.reg_ledout_offset = 0x0c,
 71};
 72
 73static int
 74tlc591xx_set_mode(struct regmap *regmap, u8 mode)
 75{
 76	int err;
 77	u8 val;
 78
 79	err = regmap_write(regmap, TLC591XX_REG_MODE1, MODE1_NORMAL_MODE);
 80	if (err)
 81		return err;
 82
 83	val = MODE2_OCH_STOP | mode;
 84
 85	return regmap_write(regmap, TLC591XX_REG_MODE2, val);
 86}
 87
 88static int
 89tlc591xx_set_ledout(struct tlc591xx_priv *priv, struct tlc591xx_led *led,
 90		    u8 val)
 91{
 92	unsigned int i = (led->led_no % 4) * 2;
 93	unsigned int mask = LEDOUT_MASK << i;
 94	unsigned int addr = priv->reg_ledout_offset + (led->led_no >> 2);
 95
 96	val = val << i;
 97
 98	return regmap_update_bits(priv->regmap, addr, mask, val);
 99}
100
101static int
102tlc591xx_set_pwm(struct tlc591xx_priv *priv, struct tlc591xx_led *led,
103		 u8 brightness)
104{
105	u8 pwm = TLC591XX_REG_PWM(led->led_no);
106
107	return regmap_write(priv->regmap, pwm, brightness);
108}
109
110static int
111tlc591xx_brightness_set(struct led_classdev *led_cdev,
112			enum led_brightness brightness)
113{
114	struct tlc591xx_led *led = ldev_to_led(led_cdev);
115	struct tlc591xx_priv *priv = led->priv;
116	int err;
117
118	switch (brightness) {
119	case 0:
120		err = tlc591xx_set_ledout(priv, led, LEDOUT_OFF);
121		break;
122	case LED_FULL:
123		err = tlc591xx_set_ledout(priv, led, LEDOUT_ON);
124		break;
125	default:
126		err = tlc591xx_set_ledout(priv, led, LEDOUT_DIM);
127		if (!err)
128			err = tlc591xx_set_pwm(priv, led, brightness);
129	}
130
131	return err;
132}
133
134static void
135tlc591xx_destroy_devices(struct tlc591xx_priv *priv, unsigned int j)
136{
137	int i = j;
138
139	while (--i >= 0) {
140		if (priv->leds[i].active)
141			led_classdev_unregister(&priv->leds[i].ldev);
142	}
143}
144
145static int
146tlc591xx_configure(struct device *dev,
147		   struct tlc591xx_priv *priv,
148		   const struct tlc591xx *tlc591xx)
149{
150	unsigned int i;
151	int err = 0;
152
153	tlc591xx_set_mode(priv->regmap, MODE2_DIM);
154	for (i = 0; i < TLC591XX_MAX_LEDS; i++) {
155		struct tlc591xx_led *led = &priv->leds[i];
156
157		if (!led->active)
158			continue;
159
160		led->priv = priv;
161		led->led_no = i;
162		led->ldev.brightness_set_blocking = tlc591xx_brightness_set;
163		led->ldev.max_brightness = LED_FULL;
164		err = led_classdev_register(dev, &led->ldev);
165		if (err < 0) {
166			dev_err(dev, "couldn't register LED %s\n",
167				led->ldev.name);
168			goto exit;
169		}
170	}
171
172	return 0;
173
174exit:
175	tlc591xx_destroy_devices(priv, i);
176	return err;
177}
178
179static const struct regmap_config tlc591xx_regmap = {
180	.reg_bits = 8,
181	.val_bits = 8,
182	.max_register = 0x1e,
183};
184
185static const struct of_device_id of_tlc591xx_leds_match[] = {
186	{ .compatible = "ti,tlc59116",
187	  .data = &tlc59116 },
188	{ .compatible = "ti,tlc59108",
189	  .data = &tlc59108 },
190	{},
191};
192MODULE_DEVICE_TABLE(of, of_tlc591xx_leds_match);
193
194static int
195tlc591xx_probe(struct i2c_client *client,
196	       const struct i2c_device_id *id)
197{
198	struct device_node *np = client->dev.of_node, *child;
199	struct device *dev = &client->dev;
200	const struct of_device_id *match;
201	const struct tlc591xx *tlc591xx;
202	struct tlc591xx_priv *priv;
203	int err, count, reg;
204
205	match = of_match_device(of_tlc591xx_leds_match, dev);
206	if (!match)
207		return -ENODEV;
208
209	tlc591xx = match->data;
210	if (!np)
211		return -ENODEV;
212
213	count = of_get_child_count(np);
214	if (!count || count > tlc591xx->max_leds)
215		return -EINVAL;
216
217	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
218	if (!priv)
219		return -ENOMEM;
220
221	priv->regmap = devm_regmap_init_i2c(client, &tlc591xx_regmap);
222	if (IS_ERR(priv->regmap)) {
223		err = PTR_ERR(priv->regmap);
224		dev_err(dev, "Failed to allocate register map: %d\n", err);
225		return err;
226	}
227	priv->reg_ledout_offset = tlc591xx->reg_ledout_offset;
228
229	i2c_set_clientdata(client, priv);
230
231	for_each_child_of_node(np, child) {
 
 
 
 
 
 
 
 
 
232		err = of_property_read_u32(child, "reg", &reg);
233		if (err)
234			return err;
235		if (reg < 0 || reg >= tlc591xx->max_leds)
236			return -EINVAL;
237		if (priv->leds[reg].active)
238			return -EINVAL;
239		priv->leds[reg].active = true;
240		priv->leds[reg].ldev.name =
241			of_get_property(child, "label", NULL) ? : child->name;
242		priv->leds[reg].ldev.default_trigger =
243			of_get_property(child, "linux,default-trigger", NULL);
244	}
245	return tlc591xx_configure(dev, priv, tlc591xx);
246}
247
248static int
249tlc591xx_remove(struct i2c_client *client)
250{
251	struct tlc591xx_priv *priv = i2c_get_clientdata(client);
252
253	tlc591xx_destroy_devices(priv, TLC591XX_MAX_LEDS);
254
 
 
 
 
 
 
 
 
 
 
 
 
255	return 0;
256}
257
258static const struct i2c_device_id tlc591xx_id[] = {
259	{ "tlc59116" },
260	{ "tlc59108" },
261	{},
262};
263MODULE_DEVICE_TABLE(i2c, tlc591xx_id);
264
265static struct i2c_driver tlc591xx_driver = {
266	.driver = {
267		.name = "tlc591xx",
268		.of_match_table = of_match_ptr(of_tlc591xx_leds_match),
269	},
270	.probe = tlc591xx_probe,
271	.remove = tlc591xx_remove,
272	.id_table = tlc591xx_id,
273};
274
275module_i2c_driver(tlc591xx_driver);
276
277MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
278MODULE_LICENSE("GPL");
279MODULE_DESCRIPTION("TLC591XX LED driver");