cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

leds-lm3642.c (10372B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3* Simple driver for Texas Instruments LM3642 LED Flash driver chip
      4* Copyright (C) 2012 Texas Instruments
      5*/
      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_FLASH
     62};
     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	NULL
    283};
    284ATTRIBUTE_GROUPS(lm3642_flash);
    285
    286static struct attribute *lm3642_torch_attrs[] = {
    287	&dev_attr_torch_pin.attr,
    288	NULL
    289};
    290ATTRIBUTE_GROUPS(lm3642_torch);
    291
    292static int lm3642_probe(struct i2c_client *client,
    293				  const struct i2c_device_id *id)
    294{
    295	struct lm3642_platform_data *pdata = dev_get_platdata(&client->dev);
    296	struct lm3642_chip_data *chip;
    297
    298	int err;
    299
    300	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
    301		dev_err(&client->dev, "i2c functionality check fail.\n");
    302		return -EOPNOTSUPP;
    303	}
    304
    305	if (pdata == NULL) {
    306		dev_err(&client->dev, "needs Platform Data.\n");
    307		return -ENODATA;
    308	}
    309
    310	chip = devm_kzalloc(&client->dev,
    311			    sizeof(struct lm3642_chip_data), GFP_KERNEL);
    312	if (!chip)
    313		return -ENOMEM;
    314
    315	chip->dev = &client->dev;
    316	chip->pdata = pdata;
    317
    318	chip->tx_pin = pdata->tx_pin;
    319	chip->torch_pin = pdata->torch_pin;
    320	chip->strobe_pin = pdata->strobe_pin;
    321
    322	chip->regmap = devm_regmap_init_i2c(client, &lm3642_regmap);
    323	if (IS_ERR(chip->regmap)) {
    324		err = PTR_ERR(chip->regmap);
    325		dev_err(&client->dev, "Failed to allocate register map: %d\n",
    326			err);
    327		return err;
    328	}
    329
    330	mutex_init(&chip->lock);
    331	i2c_set_clientdata(client, chip);
    332
    333	err = lm3642_chip_init(chip);
    334	if (err < 0)
    335		goto err_out;
    336
    337	/* flash */
    338	chip->cdev_flash.name = "flash";
    339	chip->cdev_flash.max_brightness = 16;
    340	chip->cdev_flash.brightness_set_blocking = lm3642_strobe_brightness_set;
    341	chip->cdev_flash.default_trigger = "flash";
    342	chip->cdev_flash.groups = lm3642_flash_groups;
    343	err = led_classdev_register(&client->dev, &chip->cdev_flash);
    344	if (err < 0) {
    345		dev_err(chip->dev, "failed to register flash\n");
    346		goto err_out;
    347	}
    348
    349	/* torch */
    350	chip->cdev_torch.name = "torch";
    351	chip->cdev_torch.max_brightness = 8;
    352	chip->cdev_torch.brightness_set_blocking = lm3642_torch_brightness_set;
    353	chip->cdev_torch.default_trigger = "torch";
    354	chip->cdev_torch.groups = lm3642_torch_groups;
    355	err = led_classdev_register(&client->dev, &chip->cdev_torch);
    356	if (err < 0) {
    357		dev_err(chip->dev, "failed to register torch\n");
    358		goto err_create_torch_file;
    359	}
    360
    361	/* indicator */
    362	chip->cdev_indicator.name = "indicator";
    363	chip->cdev_indicator.max_brightness = 8;
    364	chip->cdev_indicator.brightness_set_blocking =
    365						lm3642_indicator_brightness_set;
    366	err = led_classdev_register(&client->dev, &chip->cdev_indicator);
    367	if (err < 0) {
    368		dev_err(chip->dev, "failed to register indicator\n");
    369		goto err_create_indicator_file;
    370	}
    371
    372	dev_info(&client->dev, "LM3642 is initialized\n");
    373	return 0;
    374
    375err_create_indicator_file:
    376	led_classdev_unregister(&chip->cdev_torch);
    377err_create_torch_file:
    378	led_classdev_unregister(&chip->cdev_flash);
    379err_out:
    380	return err;
    381}
    382
    383static int lm3642_remove(struct i2c_client *client)
    384{
    385	struct lm3642_chip_data *chip = i2c_get_clientdata(client);
    386
    387	led_classdev_unregister(&chip->cdev_indicator);
    388	led_classdev_unregister(&chip->cdev_torch);
    389	led_classdev_unregister(&chip->cdev_flash);
    390	regmap_write(chip->regmap, REG_ENABLE, 0);
    391	return 0;
    392}
    393
    394static const struct i2c_device_id lm3642_id[] = {
    395	{LM3642_NAME, 0},
    396	{}
    397};
    398
    399MODULE_DEVICE_TABLE(i2c, lm3642_id);
    400
    401static struct i2c_driver lm3642_i2c_driver = {
    402	.driver = {
    403		   .name = LM3642_NAME,
    404		   .pm = NULL,
    405		   },
    406	.probe = lm3642_probe,
    407	.remove = lm3642_remove,
    408	.id_table = lm3642_id,
    409};
    410
    411module_i2c_driver(lm3642_i2c_driver);
    412
    413MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3642");
    414MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
    415MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
    416MODULE_LICENSE("GPL v2");