brintos

brintos / linux-shallow public Read only

0
0
Text · 10.1 KiB · 61629d5 Raw
415 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3* Simple driver for Texas Instruments LM3642 LED Flash driver chip4* Copyright (C) 2012 Texas Instruments5*/6#include <linux/module.h>7#include <linux/delay.h>8#include <linux/i2c.h>9#include <linux/leds.h>10#include <linux/slab.h>11#include <linux/platform_device.h>12#include <linux/fs.h>13#include <linux/regmap.h>14#include <linux/platform_data/leds-lm3642.h>15 16#define	REG_FILT_TIME			(0x0)17#define	REG_IVFM_MODE			(0x1)18#define	REG_TORCH_TIME			(0x6)19#define	REG_FLASH			(0x8)20#define	REG_I_CTRL			(0x9)21#define	REG_ENABLE			(0xA)22#define	REG_FLAG			(0xB)23#define	REG_MAX				(0xB)24 25#define	UVLO_EN_SHIFT			(7)26#define	IVM_D_TH_SHIFT			(2)27#define	TORCH_RAMP_UP_TIME_SHIFT	(3)28#define	TORCH_RAMP_DN_TIME_SHIFT	(0)29#define	INDUCTOR_I_LIMIT_SHIFT		(6)30#define	FLASH_RAMP_TIME_SHIFT		(3)31#define	FLASH_TOUT_TIME_SHIFT		(0)32#define	TORCH_I_SHIFT			(4)33#define	FLASH_I_SHIFT			(0)34#define	IVFM_SHIFT			(7)35#define	TX_PIN_EN_SHIFT			(6)36#define	STROBE_PIN_EN_SHIFT		(5)37#define	TORCH_PIN_EN_SHIFT		(4)38#define	MODE_BITS_SHIFT			(0)39 40#define	UVLO_EN_MASK			(0x1)41#define	IVM_D_TH_MASK			(0x7)42#define	TORCH_RAMP_UP_TIME_MASK		(0x7)43#define	TORCH_RAMP_DN_TIME_MASK		(0x7)44#define	INDUCTOR_I_LIMIT_MASK		(0x1)45#define	FLASH_RAMP_TIME_MASK		(0x7)46#define	FLASH_TOUT_TIME_MASK		(0x7)47#define	TORCH_I_MASK			(0x7)48#define	FLASH_I_MASK			(0xF)49#define	IVFM_MASK			(0x1)50#define	TX_PIN_EN_MASK			(0x1)51#define	STROBE_PIN_EN_MASK		(0x1)52#define	TORCH_PIN_EN_MASK		(0x1)53#define	MODE_BITS_MASK			(0x73)54#define EX_PIN_CONTROL_MASK		(0x71)55#define EX_PIN_ENABLE_MASK		(0x70)56 57enum lm3642_mode {58	MODES_STASNDBY = 0,59	MODES_INDIC,60	MODES_TORCH,61	MODES_FLASH62};63 64struct lm3642_chip_data {65	struct device *dev;66 67	struct led_classdev cdev_flash;68	struct led_classdev cdev_torch;69	struct led_classdev cdev_indicator;70 71	u8 br_flash;72	u8 br_torch;73	u8 br_indicator;74 75	enum lm3642_torch_pin_enable torch_pin;76	enum lm3642_strobe_pin_enable strobe_pin;77	enum lm3642_tx_pin_enable tx_pin;78 79	struct lm3642_platform_data *pdata;80	struct regmap *regmap;81	struct mutex lock;82 83	unsigned int last_flag;84};85 86/* chip initialize */87static int lm3642_chip_init(struct lm3642_chip_data *chip)88{89	int ret;90	struct lm3642_platform_data *pdata = chip->pdata;91 92	/* set enable register */93	ret = regmap_update_bits(chip->regmap, REG_ENABLE, EX_PIN_ENABLE_MASK,94				 pdata->tx_pin);95	if (ret < 0)96		dev_err(chip->dev, "Failed to update REG_ENABLE Register\n");97	return ret;98}99 100/* chip control */101static int lm3642_control(struct lm3642_chip_data *chip,102			  u8 brightness, enum lm3642_mode opmode)103{104	int ret;105 106	ret = regmap_read(chip->regmap, REG_FLAG, &chip->last_flag);107	if (ret < 0) {108		dev_err(chip->dev, "Failed to read REG_FLAG Register\n");109		return ret;110	}111 112	if (chip->last_flag)113		dev_info(chip->dev, "Last FLAG is 0x%x\n", chip->last_flag);114 115	/* brightness 0 means off-state */116	if (!brightness)117		opmode = MODES_STASNDBY;118 119	switch (opmode) {120	case MODES_TORCH:121		ret = regmap_update_bits(chip->regmap, REG_I_CTRL,122					 TORCH_I_MASK << TORCH_I_SHIFT,123					 (brightness - 1) << TORCH_I_SHIFT);124 125		if (chip->torch_pin)126			opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);127		break;128 129	case MODES_FLASH:130		ret = regmap_update_bits(chip->regmap, REG_I_CTRL,131					 FLASH_I_MASK << FLASH_I_SHIFT,132					 (brightness - 1) << FLASH_I_SHIFT);133 134		if (chip->strobe_pin)135			opmode |= (STROBE_PIN_EN_MASK << STROBE_PIN_EN_SHIFT);136		break;137 138	case MODES_INDIC:139		ret = regmap_update_bits(chip->regmap, REG_I_CTRL,140					 TORCH_I_MASK << TORCH_I_SHIFT,141					 (brightness - 1) << TORCH_I_SHIFT);142		break;143 144	case MODES_STASNDBY:145 146		break;147 148	default:149		return -EINVAL;150	}151	if (ret < 0) {152		dev_err(chip->dev, "Failed to write REG_I_CTRL Register\n");153		return ret;154	}155 156	if (chip->tx_pin)157		opmode |= (TX_PIN_EN_MASK << TX_PIN_EN_SHIFT);158 159	ret = regmap_update_bits(chip->regmap, REG_ENABLE,160				 MODE_BITS_MASK << MODE_BITS_SHIFT,161				 opmode << MODE_BITS_SHIFT);162	return ret;163}164 165/* torch */166 167/* torch pin config for lm3642 */168static ssize_t torch_pin_store(struct device *dev,169			       struct device_attribute *attr,170			       const char *buf, size_t size)171{172	ssize_t ret;173	struct led_classdev *led_cdev = dev_get_drvdata(dev);174	struct lm3642_chip_data *chip =175	    container_of(led_cdev, struct lm3642_chip_data, cdev_indicator);176	unsigned int state;177 178	ret = kstrtouint(buf, 10, &state);179	if (ret)180		return ret;181	if (state != 0)182		state = 0x01 << TORCH_PIN_EN_SHIFT;183 184	chip->torch_pin = state;185	ret = regmap_update_bits(chip->regmap, REG_ENABLE,186				 TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT,187				 state);188	if (ret < 0) {189		dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);190		return ret;191	}192 193	return size;194}195 196static DEVICE_ATTR_WO(torch_pin);197 198static int lm3642_torch_brightness_set(struct led_classdev *cdev,199					enum led_brightness brightness)200{201	struct lm3642_chip_data *chip =202	    container_of(cdev, struct lm3642_chip_data, cdev_torch);203	int ret;204 205	mutex_lock(&chip->lock);206	chip->br_torch = brightness;207	ret = lm3642_control(chip, chip->br_torch, MODES_TORCH);208	mutex_unlock(&chip->lock);209	return ret;210}211 212/* flash */213 214/* strobe pin config for lm3642*/215static ssize_t strobe_pin_store(struct device *dev,216				struct device_attribute *attr,217				const char *buf, size_t size)218{219	ssize_t ret;220	struct led_classdev *led_cdev = dev_get_drvdata(dev);221	struct lm3642_chip_data *chip =222	    container_of(led_cdev, struct lm3642_chip_data, cdev_indicator);223	unsigned int state;224 225	ret = kstrtouint(buf, 10, &state);226	if (ret)227		return ret;228	if (state != 0)229		state = 0x01 << STROBE_PIN_EN_SHIFT;230 231	chip->strobe_pin = state;232	ret = regmap_update_bits(chip->regmap, REG_ENABLE,233				 STROBE_PIN_EN_MASK << STROBE_PIN_EN_SHIFT,234				 state);235	if (ret < 0) {236		dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);237		return ret;238	}239 240	return size;241}242 243static DEVICE_ATTR_WO(strobe_pin);244 245static int lm3642_strobe_brightness_set(struct led_classdev *cdev,246					 enum led_brightness brightness)247{248	struct lm3642_chip_data *chip =249	    container_of(cdev, struct lm3642_chip_data, cdev_flash);250	int ret;251 252	mutex_lock(&chip->lock);253	chip->br_flash = brightness;254	ret = lm3642_control(chip, chip->br_flash, MODES_FLASH);255	mutex_unlock(&chip->lock);256	return ret;257}258 259/* indicator */260static int lm3642_indicator_brightness_set(struct led_classdev *cdev,261					    enum led_brightness brightness)262{263	struct lm3642_chip_data *chip =264	    container_of(cdev, struct lm3642_chip_data, cdev_indicator);265	int ret;266 267	mutex_lock(&chip->lock);268	chip->br_indicator = brightness;269	ret = lm3642_control(chip, chip->br_indicator, MODES_INDIC);270	mutex_unlock(&chip->lock);271	return ret;272}273 274static const struct regmap_config lm3642_regmap = {275	.reg_bits = 8,276	.val_bits = 8,277	.max_register = REG_MAX,278};279 280static struct attribute *lm3642_flash_attrs[] = {281	&dev_attr_strobe_pin.attr,282	NULL283};284ATTRIBUTE_GROUPS(lm3642_flash);285 286static struct attribute *lm3642_torch_attrs[] = {287	&dev_attr_torch_pin.attr,288	NULL289};290ATTRIBUTE_GROUPS(lm3642_torch);291 292static int lm3642_probe(struct i2c_client *client)293{294	struct lm3642_platform_data *pdata = dev_get_platdata(&client->dev);295	struct lm3642_chip_data *chip;296 297	int err;298 299	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {300		dev_err(&client->dev, "i2c functionality check fail.\n");301		return -EOPNOTSUPP;302	}303 304	if (pdata == NULL) {305		dev_err(&client->dev, "needs Platform Data.\n");306		return -ENODATA;307	}308 309	chip = devm_kzalloc(&client->dev,310			    sizeof(struct lm3642_chip_data), GFP_KERNEL);311	if (!chip)312		return -ENOMEM;313 314	chip->dev = &client->dev;315	chip->pdata = pdata;316 317	chip->tx_pin = pdata->tx_pin;318	chip->torch_pin = pdata->torch_pin;319	chip->strobe_pin = pdata->strobe_pin;320 321	chip->regmap = devm_regmap_init_i2c(client, &lm3642_regmap);322	if (IS_ERR(chip->regmap)) {323		err = PTR_ERR(chip->regmap);324		dev_err(&client->dev, "Failed to allocate register map: %d\n",325			err);326		return err;327	}328 329	mutex_init(&chip->lock);330	i2c_set_clientdata(client, chip);331 332	err = lm3642_chip_init(chip);333	if (err < 0)334		goto err_out;335 336	/* flash */337	chip->cdev_flash.name = "flash";338	chip->cdev_flash.max_brightness = 16;339	chip->cdev_flash.brightness_set_blocking = lm3642_strobe_brightness_set;340	chip->cdev_flash.default_trigger = "flash";341	chip->cdev_flash.groups = lm3642_flash_groups;342	err = led_classdev_register(&client->dev, &chip->cdev_flash);343	if (err < 0) {344		dev_err(chip->dev, "failed to register flash\n");345		goto err_out;346	}347 348	/* torch */349	chip->cdev_torch.name = "torch";350	chip->cdev_torch.max_brightness = 8;351	chip->cdev_torch.brightness_set_blocking = lm3642_torch_brightness_set;352	chip->cdev_torch.default_trigger = "torch";353	chip->cdev_torch.groups = lm3642_torch_groups;354	err = led_classdev_register(&client->dev, &chip->cdev_torch);355	if (err < 0) {356		dev_err(chip->dev, "failed to register torch\n");357		goto err_create_torch_file;358	}359 360	/* indicator */361	chip->cdev_indicator.name = "indicator";362	chip->cdev_indicator.max_brightness = 8;363	chip->cdev_indicator.brightness_set_blocking =364						lm3642_indicator_brightness_set;365	err = led_classdev_register(&client->dev, &chip->cdev_indicator);366	if (err < 0) {367		dev_err(chip->dev, "failed to register indicator\n");368		goto err_create_indicator_file;369	}370 371	dev_info(&client->dev, "LM3642 is initialized\n");372	return 0;373 374err_create_indicator_file:375	led_classdev_unregister(&chip->cdev_torch);376err_create_torch_file:377	led_classdev_unregister(&chip->cdev_flash);378err_out:379	return err;380}381 382static void lm3642_remove(struct i2c_client *client)383{384	struct lm3642_chip_data *chip = i2c_get_clientdata(client);385 386	led_classdev_unregister(&chip->cdev_indicator);387	led_classdev_unregister(&chip->cdev_torch);388	led_classdev_unregister(&chip->cdev_flash);389	regmap_write(chip->regmap, REG_ENABLE, 0);390}391 392static const struct i2c_device_id lm3642_id[] = {393	{ LM3642_NAME },394	{}395};396 397MODULE_DEVICE_TABLE(i2c, lm3642_id);398 399static struct i2c_driver lm3642_i2c_driver = {400	.driver = {401		   .name = LM3642_NAME,402		   .pm = NULL,403		   },404	.probe = lm3642_probe,405	.remove = lm3642_remove,406	.id_table = lm3642_id,407};408 409module_i2c_driver(lm3642_i2c_driver);410 411MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3642");412MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");413MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");414MODULE_LICENSE("GPL v2");415