brintos

brintos / linux-shallow public Read only

0
0
Text · 9.5 KiB · 99de2a3 Raw
388 lines · c
1// SPDX-License-Identifier: GPL-2.02// TI LM3697 LED chip family driver3// Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/4 5#include <linux/bits.h>6#include <linux/gpio/consumer.h>7#include <linux/i2c.h>8#include <linux/mod_devicetable.h>9#include <linux/module.h>10#include <linux/property.h>11#include <linux/regmap.h>12#include <linux/regulator/consumer.h>13#include <linux/types.h>14 15#include <linux/leds-ti-lmu-common.h>16 17#define LM3697_REV			0x018#define LM3697_RESET			0x119#define LM3697_OUTPUT_CONFIG		0x1020#define LM3697_CTRL_A_RAMP		0x1121#define LM3697_CTRL_B_RAMP		0x1222#define LM3697_CTRL_A_B_RT_RAMP		0x1323#define LM3697_CTRL_A_B_RAMP_CFG	0x1424#define LM3697_CTRL_A_B_BRT_CFG		0x1625#define LM3697_CTRL_A_FS_CURR_CFG	0x1726#define LM3697_CTRL_B_FS_CURR_CFG	0x1827#define LM3697_PWM_CFG			0x1c28#define LM3697_CTRL_A_BRT_LSB		0x2029#define LM3697_CTRL_A_BRT_MSB		0x2130#define LM3697_CTRL_B_BRT_LSB		0x2231#define LM3697_CTRL_B_BRT_MSB		0x2332#define LM3697_CTRL_ENABLE		0x2433 34#define LM3697_SW_RESET		BIT(0)35 36#define LM3697_CTRL_A_EN	BIT(0)37#define LM3697_CTRL_B_EN	BIT(1)38#define LM3697_CTRL_A_B_EN	(LM3697_CTRL_A_EN | LM3697_CTRL_B_EN)39 40#define LM3697_MAX_LED_STRINGS	341 42#define LM3697_CONTROL_A	043#define LM3697_CONTROL_B	144#define LM3697_MAX_CONTROL_BANKS 245 46/**47 * struct lm3697_led -48 * @hvled_strings: Array of LED strings associated with a control bank49 * @label: LED label50 * @led_dev: LED class device51 * @priv: Pointer to the device struct52 * @lmu_data: Register and setting values for common code53 * @control_bank: Control bank the LED is associated to. 0 is control bank A54 *		   1 is control bank B55 * @enabled: LED brightness level (or LED_OFF)56 * @num_leds: Number of LEDs available57 */58struct lm3697_led {59	u32 hvled_strings[LM3697_MAX_LED_STRINGS];60	char label[LED_MAX_NAME_SIZE];61	struct led_classdev led_dev;62	struct lm3697 *priv;63	struct ti_lmu_bank lmu_data;64	int control_bank;65	int enabled;66	int num_leds;67};68 69/**70 * struct lm3697 -71 * @enable_gpio: Hardware enable gpio72 * @regulator: LED supply regulator pointer73 * @client: Pointer to the I2C client74 * @regmap: Devices register map75 * @dev: Pointer to the devices device struct76 * @lock: Lock for reading/writing the device77 * @leds: Array of LED strings78 * @bank_cfg: OUTPUT_CONFIG register values79 * @num_banks: Number of control banks80 */81struct lm3697 {82	struct gpio_desc *enable_gpio;83	struct regulator *regulator;84	struct i2c_client *client;85	struct regmap *regmap;86	struct device *dev;87	struct mutex lock;88 89	int bank_cfg;90	int num_banks;91 92	struct lm3697_led leds[] __counted_by(num_banks);93};94 95static const struct reg_default lm3697_reg_defs[] = {96	{LM3697_OUTPUT_CONFIG, 0x6},97	{LM3697_CTRL_A_RAMP, 0x0},98	{LM3697_CTRL_B_RAMP, 0x0},99	{LM3697_CTRL_A_B_RT_RAMP, 0x0},100	{LM3697_CTRL_A_B_RAMP_CFG, 0x0},101	{LM3697_CTRL_A_B_BRT_CFG, 0x0},102	{LM3697_CTRL_A_FS_CURR_CFG, 0x13},103	{LM3697_CTRL_B_FS_CURR_CFG, 0x13},104	{LM3697_PWM_CFG, 0xc},105	{LM3697_CTRL_A_BRT_LSB, 0x0},106	{LM3697_CTRL_A_BRT_MSB, 0x0},107	{LM3697_CTRL_B_BRT_LSB, 0x0},108	{LM3697_CTRL_B_BRT_MSB, 0x0},109	{LM3697_CTRL_ENABLE, 0x0},110};111 112static const struct regmap_config lm3697_regmap_config = {113	.reg_bits = 8,114	.val_bits = 8,115 116	.max_register = LM3697_CTRL_ENABLE,117	.reg_defaults = lm3697_reg_defs,118	.num_reg_defaults = ARRAY_SIZE(lm3697_reg_defs),119	.cache_type = REGCACHE_FLAT,120};121 122static int lm3697_brightness_set(struct led_classdev *led_cdev,123				enum led_brightness brt_val)124{125	struct lm3697_led *led = container_of(led_cdev, struct lm3697_led,126					      led_dev);127	int ctrl_en_val = (1 << led->control_bank);128	struct device *dev = led->priv->dev;129	int ret;130 131	mutex_lock(&led->priv->lock);132 133	if (brt_val == LED_OFF) {134		ret = regmap_update_bits(led->priv->regmap, LM3697_CTRL_ENABLE,135					 ctrl_en_val, ~ctrl_en_val);136		if (ret) {137			dev_err(dev, "Cannot write ctrl register\n");138			goto brightness_out;139		}140 141		led->enabled = LED_OFF;142	} else {143		ret = ti_lmu_common_set_brightness(&led->lmu_data, brt_val);144		if (ret) {145			dev_err(dev, "Cannot write brightness\n");146			goto brightness_out;147		}148 149		if (!led->enabled) {150			ret = regmap_update_bits(led->priv->regmap,151						 LM3697_CTRL_ENABLE,152						 ctrl_en_val, ctrl_en_val);153			if (ret) {154				dev_err(dev, "Cannot enable the device\n");155				goto brightness_out;156			}157 158			led->enabled = brt_val;159		}160	}161 162brightness_out:163	mutex_unlock(&led->priv->lock);164	return ret;165}166 167static int lm3697_init(struct lm3697 *priv)168{169	struct device *dev = priv->dev;170	struct lm3697_led *led;171	int i, ret;172 173	if (priv->enable_gpio) {174		gpiod_direction_output(priv->enable_gpio, 1);175	} else {176		ret = regmap_write(priv->regmap, LM3697_RESET, LM3697_SW_RESET);177		if (ret) {178			dev_err(dev, "Cannot reset the device\n");179			goto out;180		}181	}182 183	ret = regmap_write(priv->regmap, LM3697_CTRL_ENABLE, 0x0);184	if (ret) {185		dev_err(dev, "Cannot write ctrl enable\n");186		goto out;187	}188 189	ret = regmap_write(priv->regmap, LM3697_OUTPUT_CONFIG, priv->bank_cfg);190	if (ret)191		dev_err(dev, "Cannot write OUTPUT config\n");192 193	for (i = 0; i < priv->num_banks; i++) {194		led = &priv->leds[i];195		ret = ti_lmu_common_set_ramp(&led->lmu_data);196		if (ret)197			dev_err(dev, "Setting the ramp rate failed\n");198	}199out:200	return ret;201}202 203static int lm3697_probe_dt(struct lm3697 *priv)204{205	struct fwnode_handle *child = NULL;206	struct device *dev = priv->dev;207	struct lm3697_led *led;208	int ret = -EINVAL;209	int control_bank;210	size_t i = 0;211	int j;212 213	priv->enable_gpio = devm_gpiod_get_optional(dev, "enable",214						    GPIOD_OUT_LOW);215	if (IS_ERR(priv->enable_gpio))216		return dev_err_probe(dev, PTR_ERR(priv->enable_gpio),217					  "Failed to get enable GPIO\n");218 219	priv->regulator = devm_regulator_get(dev, "vled");220	if (IS_ERR(priv->regulator))221		priv->regulator = NULL;222 223	device_for_each_child_node(dev, child) {224		struct led_init_data init_data = {};225 226		ret = fwnode_property_read_u32(child, "reg", &control_bank);227		if (ret) {228			dev_err(dev, "reg property missing\n");229			goto child_out;230		}231 232		if (control_bank > LM3697_CONTROL_B) {233			dev_err(dev, "reg property is invalid\n");234			ret = -EINVAL;235			goto child_out;236		}237 238		led = &priv->leds[i];239 240		ret = ti_lmu_common_get_brt_res(dev, child, &led->lmu_data);241		if (ret)242			dev_warn(dev,243				 "brightness resolution property missing\n");244 245		led->control_bank = control_bank;246		led->lmu_data.regmap = priv->regmap;247		led->lmu_data.runtime_ramp_reg = LM3697_CTRL_A_RAMP +248						 control_bank;249		led->lmu_data.msb_brightness_reg = LM3697_CTRL_A_BRT_MSB +250						   led->control_bank * 2;251		led->lmu_data.lsb_brightness_reg = LM3697_CTRL_A_BRT_LSB +252						   led->control_bank * 2;253 254		led->num_leds = fwnode_property_count_u32(child, "led-sources");255		if (led->num_leds > LM3697_MAX_LED_STRINGS) {256			dev_err(dev, "Too many LED strings defined\n");257			continue;258		}259 260		ret = fwnode_property_read_u32_array(child, "led-sources",261						    led->hvled_strings,262						    led->num_leds);263		if (ret) {264			dev_err(dev, "led-sources property missing\n");265			goto child_out;266		}267 268		for (j = 0; j < led->num_leds; j++)269			priv->bank_cfg |=270				(led->control_bank << led->hvled_strings[j]);271 272		ret = ti_lmu_common_get_ramp_params(dev, child, &led->lmu_data);273		if (ret)274			dev_warn(dev, "runtime-ramp properties missing\n");275 276		init_data.fwnode = child;277		init_data.devicename = priv->client->name;278		/* for backwards compatibility if `label` is not present */279		init_data.default_label = ":";280 281		led->priv = priv;282		led->led_dev.max_brightness = led->lmu_data.max_brightness;283		led->led_dev.brightness_set_blocking = lm3697_brightness_set;284 285		ret = devm_led_classdev_register_ext(dev, &led->led_dev,286						     &init_data);287		if (ret) {288			dev_err(dev, "led register err: %d\n", ret);289			goto child_out;290		}291 292		i++;293	}294 295	return ret;296 297child_out:298	fwnode_handle_put(child);299	return ret;300}301 302static int lm3697_probe(struct i2c_client *client)303{304	struct device *dev = &client->dev;305	struct lm3697 *led;306	int count;307	int ret;308 309	count = device_get_child_node_count(dev);310	if (!count || count > LM3697_MAX_CONTROL_BANKS) {311		dev_err(dev, "Strange device tree!");312		return -ENODEV;313	}314 315	led = devm_kzalloc(dev, struct_size(led, leds, count), GFP_KERNEL);316	if (!led)317		return -ENOMEM;318 319	mutex_init(&led->lock);320	i2c_set_clientdata(client, led);321 322	led->client = client;323	led->dev = dev;324	led->num_banks = count;325	led->regmap = devm_regmap_init_i2c(client, &lm3697_regmap_config);326	if (IS_ERR(led->regmap)) {327		ret = PTR_ERR(led->regmap);328		dev_err(dev, "Failed to allocate register map: %d\n", ret);329		return ret;330	}331 332	ret = lm3697_probe_dt(led);333	if (ret)334		return ret;335 336	return lm3697_init(led);337}338 339static void lm3697_remove(struct i2c_client *client)340{341	struct lm3697 *led = i2c_get_clientdata(client);342	struct device *dev = &led->client->dev;343	int ret;344 345	ret = regmap_update_bits(led->regmap, LM3697_CTRL_ENABLE,346				 LM3697_CTRL_A_B_EN, 0);347	if (ret)348		dev_err(dev, "Failed to disable the device\n");349 350	if (led->enable_gpio)351		gpiod_direction_output(led->enable_gpio, 0);352 353	if (led->regulator) {354		ret = regulator_disable(led->regulator);355		if (ret)356			dev_err(dev, "Failed to disable regulator\n");357	}358 359	mutex_destroy(&led->lock);360}361 362static const struct i2c_device_id lm3697_id[] = {363	{ "lm3697" },364	{ }365};366MODULE_DEVICE_TABLE(i2c, lm3697_id);367 368static const struct of_device_id of_lm3697_leds_match[] = {369	{ .compatible = "ti,lm3697", },370	{},371};372MODULE_DEVICE_TABLE(of, of_lm3697_leds_match);373 374static struct i2c_driver lm3697_driver = {375	.driver = {376		.name	= "lm3697",377		.of_match_table = of_lm3697_leds_match,378	},379	.probe		= lm3697_probe,380	.remove		= lm3697_remove,381	.id_table	= lm3697_id,382};383module_i2c_driver(lm3697_driver);384 385MODULE_DESCRIPTION("Texas Instruments LM3697 LED driver");386MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");387MODULE_LICENSE("GPL v2");388