brintos

brintos / linux-shallow public Read only

0
0
Text · 16.2 KiB · d5c4421 Raw
638 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Kinetic KTD2026/7 RGB/White LED driver with I2C interface4 *5 * Copyright 2023 André Apitzsch <git@apitzsch.eu>6 *7 * Datasheet: https://www.kinet-ic.com/uploads/KTD2026-7-04h.pdf8 */9 10#include <linux/i2c.h>11#include <linux/led-class-multicolor.h>12#include <linux/module.h>13#include <linux/mutex.h>14#include <linux/of.h>15#include <linux/of_device.h>16#include <linux/regmap.h>17#include <linux/regulator/consumer.h>18 19#define KTD2026_NUM_LEDS 320#define KTD2027_NUM_LEDS 421#define KTD202X_MAX_LEDS 422 23/* Register bank */24#define KTD202X_REG_RESET_CONTROL	0x0025#define KTD202X_REG_FLASH_PERIOD	0x0126#define KTD202X_REG_PWM1_TIMER		0x0227#define KTD202X_REG_PWM2_TIMER		0x0328#define KTD202X_REG_CHANNEL_CTRL	0x0429#define KTD202X_REG_TRISE_FALL		0x0530#define KTD202X_REG_LED_IOUT(x)		(0x06 + (x))31 32/* Register 0 */33#define KTD202X_TIMER_SLOT_CONTROL_TSLOT1	0x0034#define KTD202X_TIMER_SLOT_CONTROL_TSLOT2	0x0135#define KTD202X_TIMER_SLOT_CONTROL_TSLOT3	0x0236#define KTD202X_TIMER_SLOT_CONTROL_TSLOT4	0x0337#define KTD202X_RSTR_RESET			0x0738 39#define KTD202X_ENABLE_CTRL_WAKE	0x00 /* SCL High & SDA High */40#define KTD202X_ENABLE_CTRL_SLEEP	0x08 /* SCL High & SDA Toggling */41 42#define KTD202X_TRISE_FALL_SCALE_NORMAL		0x0043#define KTD202X_TRISE_FALL_SCALE_SLOW_X2	0x2044#define KTD202X_TRISE_FALL_SCALE_SLOW_X4	0x4045#define KTD202X_TRISE_FALL_SCALE_FAST_X8	0x6046 47/* Register 1 */48#define KTD202X_FLASH_PERIOD_256_MS_LOG_RAMP	0x0049 50/* Register 2-3 */51#define KTD202X_FLASH_ON_TIME_0_4_PERCENT	0x0152 53/* Register 4 */54#define KTD202X_CHANNEL_CTRL_MASK(x) (BIT(2 * (x)) | BIT(2 * (x) + 1))55#define KTD202X_CHANNEL_CTRL_OFF 0x0056#define KTD202X_CHANNEL_CTRL_ON(x) BIT(2 * (x))57#define KTD202X_CHANNEL_CTRL_PWM1(x) BIT(2 * (x) + 1)58#define KTD202X_CHANNEL_CTRL_PWM2(x) (BIT(2 * (x)) | BIT(2 * (x) + 1))59 60/* Register 5 */61#define KTD202X_RAMP_TIMES_2_MS			0x0062 63/* Register 6-9 */64#define KTD202X_LED_CURRENT_10_mA		0x4f65 66#define KTD202X_FLASH_PERIOD_MIN_MS 25667#define KTD202X_FLASH_PERIOD_STEP_MS 12868#define KTD202X_FLASH_PERIOD_MAX_STEPS 12669#define KTD202X_FLASH_ON_MAX 25670 71#define KTD202X_MAX_BRIGHTNESS 19272 73static const struct reg_default ktd202x_reg_defaults[] = {74	{ KTD202X_REG_RESET_CONTROL, KTD202X_TIMER_SLOT_CONTROL_TSLOT1 |75		KTD202X_ENABLE_CTRL_WAKE | KTD202X_TRISE_FALL_SCALE_NORMAL },76	{ KTD202X_REG_FLASH_PERIOD, KTD202X_FLASH_PERIOD_256_MS_LOG_RAMP },77	{ KTD202X_REG_PWM1_TIMER, KTD202X_FLASH_ON_TIME_0_4_PERCENT },78	{ KTD202X_REG_PWM2_TIMER, KTD202X_FLASH_ON_TIME_0_4_PERCENT },79	{ KTD202X_REG_CHANNEL_CTRL, KTD202X_CHANNEL_CTRL_OFF },80	{ KTD202X_REG_TRISE_FALL, KTD202X_RAMP_TIMES_2_MS },81	{ KTD202X_REG_LED_IOUT(0), KTD202X_LED_CURRENT_10_mA },82	{ KTD202X_REG_LED_IOUT(1), KTD202X_LED_CURRENT_10_mA },83	{ KTD202X_REG_LED_IOUT(2), KTD202X_LED_CURRENT_10_mA },84	{ KTD202X_REG_LED_IOUT(3), KTD202X_LED_CURRENT_10_mA },85};86 87struct ktd202x_led {88	struct ktd202x *chip;89	union {90		struct led_classdev cdev;91		struct led_classdev_mc mcdev;92	};93	u32 index;94};95 96struct ktd202x {97	struct mutex mutex;98	struct regulator_bulk_data regulators[2];99	struct device *dev;100	struct regmap *regmap;101	bool enabled;102	unsigned long num_leds;103	struct ktd202x_led leds[] __counted_by(num_leds);104};105 106static int ktd202x_chip_disable(struct ktd202x *chip)107{108	int ret;109 110	if (!chip->enabled)111		return 0;112 113	regmap_write(chip->regmap, KTD202X_REG_RESET_CONTROL, KTD202X_ENABLE_CTRL_SLEEP);114 115	ret = regulator_bulk_disable(ARRAY_SIZE(chip->regulators), chip->regulators);116	if (ret) {117		dev_err(chip->dev, "Failed to disable regulators: %d\n", ret);118		return ret;119	}120 121	chip->enabled = false;122	return 0;123}124 125static int ktd202x_chip_enable(struct ktd202x *chip)126{127	int ret;128 129	if (chip->enabled)130		return 0;131 132	ret = regulator_bulk_enable(ARRAY_SIZE(chip->regulators), chip->regulators);133	if (ret) {134		dev_err(chip->dev, "Failed to enable regulators: %d\n", ret);135		return ret;136	}137	chip->enabled = true;138 139	ret = regmap_write(chip->regmap, KTD202X_REG_RESET_CONTROL, KTD202X_ENABLE_CTRL_WAKE);140 141	if (ret) {142		dev_err(chip->dev, "Failed to enable the chip: %d\n", ret);143		ktd202x_chip_disable(chip);144	}145 146	return ret;147}148 149static bool ktd202x_chip_in_use(struct ktd202x *chip)150{151	int i;152 153	for (i = 0; i < chip->num_leds; i++) {154		if (chip->leds[i].cdev.brightness)155			return true;156	}157 158	return false;159}160 161static int ktd202x_brightness_set(struct ktd202x_led *led,162				  struct mc_subled *subleds,163				  unsigned int num_channels)164{165	bool mode_blink = false;166	int channel;167	int state;168	int ret;169	int i;170 171	if (ktd202x_chip_in_use(led->chip)) {172		ret = ktd202x_chip_enable(led->chip);173		if (ret)174			return ret;175	}176 177	ret = regmap_read(led->chip->regmap, KTD202X_REG_CHANNEL_CTRL, &state);178	if (ret)179		return ret;180 181	/*182	 * In multicolor case, assume blink mode if PWM is set for at least one183	 * channel because another channel cannot be in state ON at the same time184	 */185	for (i = 0; i < num_channels; i++) {186		int channel_state;187 188		channel = subleds[i].channel;189		channel_state = (state >> 2 * channel) & KTD202X_CHANNEL_CTRL_MASK(0);190		if (channel_state == KTD202X_CHANNEL_CTRL_OFF)191			continue;192		mode_blink = channel_state == KTD202X_CHANNEL_CTRL_PWM1(0);193		break;194	}195 196	for (i = 0; i < num_channels; i++) {197		enum led_brightness brightness;198		int mode;199 200		brightness = subleds[i].brightness;201		channel = subleds[i].channel;202 203		if (brightness) {204			/* Register expects brightness between 0 and MAX_BRIGHTNESS - 1 */205			ret = regmap_write(led->chip->regmap, KTD202X_REG_LED_IOUT(channel),206					   brightness - 1);207			if (ret)208				return ret;209 210			if (mode_blink)211				mode = KTD202X_CHANNEL_CTRL_PWM1(channel);212			else213				mode = KTD202X_CHANNEL_CTRL_ON(channel);214		} else {215			mode = KTD202X_CHANNEL_CTRL_OFF;216		}217		ret = regmap_update_bits(led->chip->regmap, KTD202X_REG_CHANNEL_CTRL,218					 KTD202X_CHANNEL_CTRL_MASK(channel), mode);219		if (ret)220			return ret;221	}222 223	if (!ktd202x_chip_in_use(led->chip))224		return ktd202x_chip_disable(led->chip);225 226	return 0;227}228 229static int ktd202x_brightness_single_set(struct led_classdev *cdev,230					 enum led_brightness value)231{232	struct ktd202x_led *led = container_of(cdev, struct ktd202x_led, cdev);233	struct mc_subled info;234	int ret;235 236	cdev->brightness = value;237 238	mutex_lock(&led->chip->mutex);239 240	info.brightness = value;241	info.channel = led->index;242	ret = ktd202x_brightness_set(led, &info, 1);243 244	mutex_unlock(&led->chip->mutex);245 246	return ret;247}248 249static int ktd202x_brightness_mc_set(struct led_classdev *cdev,250				     enum led_brightness value)251{252	struct led_classdev_mc *mc = lcdev_to_mccdev(cdev);253	struct ktd202x_led *led = container_of(mc, struct ktd202x_led, mcdev);254	int ret;255 256	cdev->brightness = value;257 258	mutex_lock(&led->chip->mutex);259 260	led_mc_calc_color_components(mc, value);261	ret = ktd202x_brightness_set(led, mc->subled_info, mc->num_colors);262 263	mutex_unlock(&led->chip->mutex);264 265	return ret;266}267 268static int ktd202x_blink_set(struct ktd202x_led *led, unsigned long *delay_on,269			     unsigned long *delay_off, struct mc_subled *subleds,270			     unsigned int num_channels)271{272	unsigned long delay_total_ms;273	int ret, num_steps, on;274	u8 ctrl_mask = 0;275	u8 ctrl_pwm1 = 0;276	u8 ctrl_on = 0;277	int i;278 279	mutex_lock(&led->chip->mutex);280 281	for (i = 0; i < num_channels; i++) {282		int channel = subleds[i].channel;283 284		ctrl_mask |= KTD202X_CHANNEL_CTRL_MASK(channel);285		ctrl_on |= KTD202X_CHANNEL_CTRL_ON(channel);286		ctrl_pwm1 |= KTD202X_CHANNEL_CTRL_PWM1(channel);287	}288 289	/* Never off - brightness is already set, disable blinking */290	if (!*delay_off) {291		ret = regmap_update_bits(led->chip->regmap, KTD202X_REG_CHANNEL_CTRL,292					 ctrl_mask, ctrl_on);293		goto out;294	}295 296	/* Convert into values the HW will understand. */297 298	/* Integer representation of time of flash period */299	num_steps = (*delay_on + *delay_off - KTD202X_FLASH_PERIOD_MIN_MS) /300		    KTD202X_FLASH_PERIOD_STEP_MS;301	num_steps = clamp(num_steps, 0, KTD202X_FLASH_PERIOD_MAX_STEPS);302 303	/* Integer representation of percentage of LED ON time */304	on = (*delay_on * KTD202X_FLASH_ON_MAX) / (*delay_on + *delay_off);305 306	/* Actually used delay_{on,off} values */307	delay_total_ms = num_steps * KTD202X_FLASH_PERIOD_STEP_MS + KTD202X_FLASH_PERIOD_MIN_MS;308	*delay_on = (delay_total_ms * on) / KTD202X_FLASH_ON_MAX;309	*delay_off = delay_total_ms - *delay_on;310 311	/* Set timings */312	ret = regmap_write(led->chip->regmap, KTD202X_REG_FLASH_PERIOD, num_steps);313	if (ret)314		goto out;315 316	ret = regmap_write(led->chip->regmap, KTD202X_REG_PWM1_TIMER, on);317	if (ret)318		goto out;319 320	ret = regmap_update_bits(led->chip->regmap, KTD202X_REG_CHANNEL_CTRL,321				 ctrl_mask, ctrl_pwm1);322out:323	mutex_unlock(&led->chip->mutex);324	return ret;325}326 327static int ktd202x_blink_single_set(struct led_classdev *cdev,328				    unsigned long *delay_on,329				    unsigned long *delay_off)330{331	struct ktd202x_led *led = container_of(cdev, struct ktd202x_led, cdev);332	struct mc_subled info;333	int ret;334 335	if (!cdev->brightness) {336		ret = ktd202x_brightness_single_set(cdev, KTD202X_MAX_BRIGHTNESS);337		if (ret)338			return ret;339	}340 341	/* If no blink specified, default to 1 Hz. */342	if (!*delay_off && !*delay_on) {343		*delay_off = 500;344		*delay_on = 500;345	}346 347	/* Never on - just set to off */348	if (!*delay_on)349		return ktd202x_brightness_single_set(cdev, LED_OFF);350 351	info.channel = led->index;352 353	return ktd202x_blink_set(led, delay_on, delay_off, &info, 1);354}355 356static int ktd202x_blink_mc_set(struct led_classdev *cdev,357				unsigned long *delay_on,358				unsigned long *delay_off)359{360	struct led_classdev_mc *mc = lcdev_to_mccdev(cdev);361	struct ktd202x_led *led = container_of(mc, struct ktd202x_led, mcdev);362	int ret;363 364	if (!cdev->brightness) {365		ret = ktd202x_brightness_mc_set(cdev, KTD202X_MAX_BRIGHTNESS);366		if (ret)367			return ret;368	}369 370	/* If no blink specified, default to 1 Hz. */371	if (!*delay_off && !*delay_on) {372		*delay_off = 500;373		*delay_on = 500;374	}375 376	/* Never on - just set to off */377	if (!*delay_on)378		return ktd202x_brightness_mc_set(cdev, LED_OFF);379 380	return ktd202x_blink_set(led, delay_on, delay_off, mc->subled_info,381				 mc->num_colors);382}383 384static int ktd202x_setup_led_rgb(struct ktd202x *chip, struct fwnode_handle *fwnode,385				 struct ktd202x_led *led, struct led_init_data *init_data)386{387	struct fwnode_handle *child;388	struct led_classdev *cdev;389	struct mc_subled *info;390	int num_channels;391	int i = 0;392 393	num_channels = 0;394	fwnode_for_each_available_child_node(fwnode, child)395		num_channels++;396 397	if (!num_channels || num_channels > chip->num_leds)398		return -EINVAL;399 400	info = devm_kcalloc(chip->dev, num_channels, sizeof(*info), GFP_KERNEL);401	if (!info)402		return -ENOMEM;403 404	fwnode_for_each_available_child_node(fwnode, child) {405		u32 mono_color;406		u32 reg;407		int ret;408 409		ret = fwnode_property_read_u32(child, "reg", &reg);410		if (ret != 0 || reg >= chip->num_leds) {411			dev_err(chip->dev, "invalid 'reg' of %pfw\n", child);412			fwnode_handle_put(child);413			return ret;414		}415 416		ret = fwnode_property_read_u32(child, "color", &mono_color);417		if (ret < 0 && ret != -EINVAL) {418			dev_err(chip->dev, "failed to parse 'color' of %pfw\n", child);419			fwnode_handle_put(child);420			return ret;421		}422 423		info[i].color_index = mono_color;424		info[i].channel = reg;425		info[i].intensity = KTD202X_MAX_BRIGHTNESS;426		i++;427	}428 429	led->mcdev.subled_info = info;430	led->mcdev.num_colors = num_channels;431 432	cdev = &led->mcdev.led_cdev;433	cdev->brightness_set_blocking = ktd202x_brightness_mc_set;434	cdev->blink_set = ktd202x_blink_mc_set;435 436	return devm_led_classdev_multicolor_register_ext(chip->dev, &led->mcdev, init_data);437}438 439static int ktd202x_setup_led_single(struct ktd202x *chip, struct fwnode_handle *fwnode,440				    struct ktd202x_led *led, struct led_init_data *init_data)441{442	struct led_classdev *cdev;443	u32 reg;444	int ret;445 446	ret = fwnode_property_read_u32(fwnode, "reg", &reg);447	if (ret != 0 || reg >= chip->num_leds) {448		dev_err(chip->dev, "invalid 'reg' of %pfw\n", fwnode);449		return -EINVAL;450	}451	led->index = reg;452 453	cdev = &led->cdev;454	cdev->brightness_set_blocking = ktd202x_brightness_single_set;455	cdev->blink_set = ktd202x_blink_single_set;456 457	return devm_led_classdev_register_ext(chip->dev, &led->cdev, init_data);458}459 460static int ktd202x_add_led(struct ktd202x *chip, struct fwnode_handle *fwnode, unsigned int index)461{462	struct ktd202x_led *led = &chip->leds[index];463	struct led_init_data init_data = {};464	struct led_classdev *cdev;465	u32 color;466	int ret;467 468	/* Color property is optional in single color case */469	ret = fwnode_property_read_u32(fwnode, "color", &color);470	if (ret < 0 && ret != -EINVAL) {471		dev_err(chip->dev, "failed to parse 'color' of %pfw\n", fwnode);472		return ret;473	}474 475	led->chip = chip;476	init_data.fwnode = fwnode;477 478	if (color == LED_COLOR_ID_RGB) {479		cdev = &led->mcdev.led_cdev;480		ret = ktd202x_setup_led_rgb(chip, fwnode, led, &init_data);481	} else {482		cdev = &led->cdev;483		ret = ktd202x_setup_led_single(chip, fwnode, led, &init_data);484	}485 486	if (ret) {487		dev_err(chip->dev, "unable to register %s\n", cdev->name);488		return ret;489	}490 491	cdev->max_brightness = KTD202X_MAX_BRIGHTNESS;492 493	return 0;494}495 496static int ktd202x_probe_fw(struct ktd202x *chip)497{498	struct fwnode_handle *child;499	struct device *dev = chip->dev;500	int count;501	int i = 0;502 503	count = device_get_child_node_count(dev);504	if (!count || count > chip->num_leds)505		return -EINVAL;506 507	regmap_write(chip->regmap, KTD202X_REG_RESET_CONTROL, KTD202X_RSTR_RESET);508 509	/* Allow the device to execute the complete reset */510	usleep_range(200, 300);511 512	device_for_each_child_node(dev, child) {513		int ret = ktd202x_add_led(chip, child, i);514 515		if (ret) {516			fwnode_handle_put(child);517			return ret;518		}519		i++;520	}521 522	return 0;523}524 525static const struct regmap_config ktd202x_regmap_config = {526	.reg_bits = 8,527	.val_bits = 8,528	.max_register = 0x09,529	.cache_type = REGCACHE_FLAT,530	.reg_defaults = ktd202x_reg_defaults,531	.num_reg_defaults = ARRAY_SIZE(ktd202x_reg_defaults),532};533 534static int ktd202x_probe(struct i2c_client *client)535{536	struct device *dev = &client->dev;537	struct ktd202x *chip;538	int count;539	int ret;540 541	count = device_get_child_node_count(dev);542	if (!count || count > KTD202X_MAX_LEDS)543		return dev_err_probe(dev, -EINVAL, "Incorrect number of leds (%d)", count);544 545	chip = devm_kzalloc(dev, struct_size(chip, leds, count), GFP_KERNEL);546	if (!chip)547		return -ENOMEM;548 549	chip->dev = dev;550	i2c_set_clientdata(client, chip);551 552	chip->regmap = devm_regmap_init_i2c(client, &ktd202x_regmap_config);553	if (IS_ERR(chip->regmap)) {554		ret = dev_err_probe(dev, PTR_ERR(chip->regmap),555				    "Failed to allocate register map.\n");556		return ret;557	}558 559	ret = devm_mutex_init(dev, &chip->mutex);560	if (ret)561		return ret;562 563	chip->num_leds = (unsigned long)i2c_get_match_data(client);564 565	chip->regulators[0].supply = "vin";566	chip->regulators[1].supply = "vio";567	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(chip->regulators), chip->regulators);568	if (ret < 0) {569		dev_err_probe(dev, ret, "Failed to request regulators.\n");570		return ret;571	}572 573	ret = regulator_bulk_enable(ARRAY_SIZE(chip->regulators), chip->regulators);574	if (ret) {575		dev_err_probe(dev, ret, "Failed to enable regulators.\n");576		return ret;577	}578 579	ret = ktd202x_probe_fw(chip);580	if (ret < 0) {581		regulator_bulk_disable(ARRAY_SIZE(chip->regulators), chip->regulators);582		return ret;583	}584 585	ret = regulator_bulk_disable(ARRAY_SIZE(chip->regulators), chip->regulators);586	if (ret) {587		dev_err_probe(dev, ret, "Failed to disable regulators.\n");588		return ret;589	}590 591	return 0;592}593 594static void ktd202x_remove(struct i2c_client *client)595{596	struct ktd202x *chip = i2c_get_clientdata(client);597 598	ktd202x_chip_disable(chip);599}600 601static void ktd202x_shutdown(struct i2c_client *client)602{603	struct ktd202x *chip = i2c_get_clientdata(client);604 605	/* Reset registers to make sure all LEDs are off before shutdown */606	regmap_write(chip->regmap, KTD202X_REG_RESET_CONTROL, KTD202X_RSTR_RESET);607}608 609static const struct i2c_device_id ktd202x_id[] = {610	{"ktd2026", KTD2026_NUM_LEDS},611	{"ktd2027", KTD2027_NUM_LEDS},612	{}613};614MODULE_DEVICE_TABLE(i2c, ktd202x_id);615 616static const struct of_device_id ktd202x_match_table[] = {617	{ .compatible = "kinetic,ktd2026", .data = (void *)KTD2026_NUM_LEDS },618	{ .compatible = "kinetic,ktd2027", .data = (void *)KTD2027_NUM_LEDS },619	{}620};621MODULE_DEVICE_TABLE(of, ktd202x_match_table);622 623static struct i2c_driver ktd202x_driver = {624	.driver = {625		.name = "leds-ktd202x",626		.of_match_table = ktd202x_match_table,627	},628	.probe = ktd202x_probe,629	.remove = ktd202x_remove,630	.shutdown = ktd202x_shutdown,631	.id_table = ktd202x_id,632};633module_i2c_driver(ktd202x_driver);634 635MODULE_AUTHOR("André Apitzsch <git@apitzsch.eu>");636MODULE_DESCRIPTION("Kinetic KTD2026/7 LED driver");637MODULE_LICENSE("GPL");638