public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/1 v1] leds: Add LED driver for lm3556 chip
@ 2012-04-09  2:00 Geon Si Jeong
  2012-04-09  2:00 ` [PATCH 1/1 " Geon Si Jeong
  0 siblings, 1 reply; 5+ messages in thread
From: Geon Si Jeong @ 2012-04-09  2:00 UTC (permalink / raw)
  To: Richard Purdie; +Cc: Daniel Jeong, linux-kernel, Andrew Morton, Geon Si Jeong

It is a simple driver for LM3556 Chip(Texas Instruments)
LM3556 :
The LM3556 is a 4 MHz fixed-frequency synchronous boost
converter plus 1.5A constant current driver for a high-current white LED.
Datasheet: www.national.com/ds/LM/LM3556.pdf

Tested on OMAP4430

Geon Si Jeong (1):
  leds: Add LED driver for lm3556 chip

 drivers/leds/Kconfig        |    9 +
 drivers/leds/Makefile       |    2 +-
 drivers/leds/leds-lm3556.c  |  471 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/leds-lm3556.h |  242 ++++++++++++++++++++++
 4 files changed, 723 insertions(+), 1 deletions(-)
 create mode 100644 drivers/leds/leds-lm3556.c
 create mode 100644 include/linux/leds-lm3556.h

-- 
1.7.5.4


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/1 v1] leds: Add LED driver for lm3556 chip
  2012-04-09  2:00 [PATCH 0/1 v1] leds: Add LED driver for lm3556 chip Geon Si Jeong
@ 2012-04-09  2:00 ` Geon Si Jeong
  2012-05-15 18:43   ` Johan Hovold
  0 siblings, 1 reply; 5+ messages in thread
From: Geon Si Jeong @ 2012-04-09  2:00 UTC (permalink / raw)
  To: Richard Purdie; +Cc: Daniel Jeong, linux-kernel, Andrew Morton, Geon Si Jeong

It is a simple driver for LM3556 Chip(Texas Instruments)
LM3556 :
The LM3556 is a 4 MHz fixed-frequency synchronous boost
converter plus 1.5A constant current driver for a high-current white LED.
Datasheet: www.national.com/ds/LM/LM3556.pdf

Tested on OMAP4430

Signed-off-by: Geon Si Jeong <gshark.jeong@gmail.com>
---
 drivers/leds/Kconfig        |    9 +
 drivers/leds/Makefile       |    2 +-
 drivers/leds/leds-lm3556.c  |  471 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/leds-lm3556.h |  242 ++++++++++++++++++++++
 4 files changed, 723 insertions(+), 1 deletions(-)
 create mode 100644 drivers/leds/leds-lm3556.c
 create mode 100644 include/linux/leds-lm3556.h

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 589ba02..8ebdb3f 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -401,6 +401,15 @@ config LEDS_MAX8997
 	  This option enables support for on-chip LED drivers on
 	  MAXIM MAX8997 PMIC.
 
+config LEDS_LM3556
+	tristate "LED Support for TI LM3556 Chip"
+	depends on LEDS_CLASS
+	depends on I2C
+	help
+	  This option enables support for LEDs connected to LM3556.
+	  LM3556 includes Torch, Flash and Indicator functions and
+	  controlled via I2C.
+
 config LEDS_OT200
 	tristate "LED support for the Bachmann OT200"
 	depends on LEDS_CLASS && HAS_IOMEM
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index fa0f428..8ad2a46 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -46,7 +46,7 @@ obj-$(CONFIG_LEDS_NETXBIG)		+= leds-netxbig.o
 obj-$(CONFIG_LEDS_ASIC3)		+= leds-asic3.o
 obj-$(CONFIG_LEDS_RENESAS_TPU)		+= leds-renesas-tpu.o
 obj-$(CONFIG_LEDS_MAX8997)		+= leds-max8997.o
-
+obj-$(CONFIG_LEDS_LM3556)		+= leds-lm3556.o
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)		+= leds-dac124s085.o
 
diff --git a/drivers/leds/leds-lm3556.c b/drivers/leds/leds-lm3556.c
new file mode 100644
index 0000000..1f0045c
--- /dev/null
+++ b/drivers/leds/leds-lm3556.c
@@ -0,0 +1,471 @@
+/*
+ * Simple driver for Texas Instruments LM3556 LED Flash driver chip (Rev0x03)
+ * Copyright (C) 2012 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/fs.h>
+#include <linux/leds-lm3556.h>
+
+#define	REG_FILT_TIME			(0x0)
+#define	REG_IVFM_MODE			(0x1)
+#define	REG_NTC				(0x2)
+#define	REG_INDIC_TIME			(0x3)
+#define	REG_INDIC_BLINK			(0x4)
+#define	REG_INDIC_PERIOD		(0x5)
+#define	REG_TORCH_TIME			(0x6)
+#define	REG_CONF			(0x7)
+#define	REG_FLASH			(0x8)
+#define	REG_I_CTRL			(0x9)
+#define	REG_ENABLE			(0xA)
+#define	REG_FLAG			(0xB)
+#define	REG_MAX				(0xC)
+
+#define	IVFM_FILTER_TIME_SHIFT		(3)
+#define	UVLO_EN_SHIFT			(7)
+#define	HYSTERSIS_SHIFT			(5)
+#define	IVM_D_TH_SHIFT			(2)
+#define	IVFM_ADJ_MODE_SHIFT		(0)
+#define	NTC_EVENT_LVL_SHIFT		(5)
+#define	NTC_TRIP_TH_SHIFT		(2)
+#define	NTC_BIAS_I_LVL_SHIFT		(0)
+#define	INDIC_RAMP_UP_TIME_SHIFT	(3)
+#define	INDIC_RAMP_DN_TIME_SHIFT	(0)
+#define	INDIC_N_BLANK_SHIFT		(4)
+#define	INDIC_PULSE_TIME_SHIFT		(0)
+#define	INDIC_N_PERIOD_SHIFT		(0)
+#define	TORCH_RAMP_UP_TIME_SHIFT	(3)
+#define	TORCH_RAMP_DN_TIME_SHIFT	(0)
+#define	STROBE_USUAGE_SHIFT		(7)
+#define	STROBE_PIN_POLARITY_SHIFT	(6)
+#define	TORCH_PIN_POLARITY_SHIFT	(5)
+#define	TX_PIN_POLARITY_SHIFT		(4)
+#define	TX_EVENT_LVL_SHIFT		(3)
+#define	IVFM_EN_SHIFT			(2)
+#define	NTC_MODE_SHIFT			(1)
+#define	INDIC_MODE_SHIFT		(0)
+#define	INDUCTOR_I_LIMIT_SHIFT		(6)
+#define	FLASH_RAMP_TIME_SHIFT		(3)
+#define	FLASH_TOUT_TIME_SHIFT		(0)
+#define	TORCH_I_SHIFT			(4)
+#define	FLASH_I_SHIFT			(0)
+#define	NTC_EN_SHIFT			(7)
+#define	TX_PIN_EN_SHIFT			(6)
+#define	STROBE_PIN_EN_SHIFT		(5)
+#define	TORCH_PIN_EN_SHIFT		(4)
+#define	PRECHG_MODE_EN_SHIFT		(3)
+#define	PASS_MODE_ONLY_EN_SHIFT		(2)
+#define	MODE_BITS_SHIFT			(0)
+
+#define	IVFM_FILTER_TIME_MASK		(0x3)
+#define	UVLO_EN_MASK			(0x1)
+#define	HYSTERSIS_MASK			(0x3)
+#define	IVM_D_TH_MASK			(0x7)
+#define	IVFM_ADJ_MODE_MASK		(0x3)
+#define	NTC_EVENT_LVL_MASK		(0x1)
+#define	NTC_TRIP_TH_MASK		(0x7)
+#define	NTC_BIAS_I_LVL_MASK		(0x3)
+#define	INDIC_RAMP_UP_TIME_MASK		(0x7)
+#define	INDIC_RAMP_DN_TIME_MASK		(0x7)
+#define	INDIC_N_BLANK_MASK		(0x7)
+#define	INDIC_PULSE_TIME_MASK		(0x7)
+#define	INDIC_N_PERIOD_MASK		(0x7)
+#define	TORCH_RAMP_UP_TIME_MASK		(0x7)
+#define	TORCH_RAMP_DN_TIME_MASK		(0x7)
+#define	STROBE_USUAGE_MASK		(0x1)
+#define	STROBE_PIN_POLARITY_MASK	(0x1)
+#define	TORCH_PIN_POLARITY_MASK		(0x1)
+#define	TX_PIN_POLARITY_MASK		(0x1)
+#define	TX_EVENT_LVL_MASK		(0x1)
+#define	IVFM_EN_MASK			(0x1)
+#define	NTC_MODE_MASK			(0x1)
+#define	INDIC_MODE_MASK			(0x1)
+#define	INDUCTOR_I_LIMIT_MASK		(0x3)
+#define	FLASH_RAMP_TIME_MASK		(0x7)
+#define	FLASH_TOUT_TIME_MASK		(0x7)
+#define	TORCH_I_MASK			(0x7)
+#define	FLASH_I_MASK			(0xF)
+#define	NTC_EN_MASK			(0x1)
+#define	TX_PIN_EN_MASK			(0x1)
+#define	STROBE_PIN_EN_MASK		(0x1)
+#define	TORCH_PIN_EN_MASK		(0x1)
+#define	PRECHG_MODE_EN_MASK		(0x1)
+#define	PASS_MODE_ONLY_EN_MASK		(0x1)
+#define	MODE_BITS_MASK			(0x13)
+#define EX_PIN_CONTROL_MASK		(0xF1)
+#define EX_PIN_ENABLE_MASK		(0x70)
+
+#define INDIC_PATTERN_SIZE 4
+
+struct indicator {
+	u8 blinking;
+	u8 period_cnt;
+};
+
+struct lm3556_chip_data {
+	struct i2c_client *client;
+
+	struct led_classdev cdev_flash;
+	struct led_classdev cdev_torch;
+	struct led_classdev cdev_indicator;
+
+	struct lm3556_platform_data *pdata;
+	struct mutex lock;
+
+	u8 last_flag;
+};
+
+/*Indicator Pattern*/
+static struct indicator indicator_pattern[INDIC_PATTERN_SIZE] = {
+	[0] = {(INDIC_N_BLANK_1 << INDIC_N_BLANK_SHIFT)
+	       | PULSE_TIME_32_MS, INDIC_PERIOD_1},
+	[1] = {(INDIC_N_BLANK_15 << INDIC_N_BLANK_SHIFT)
+	       | PULSE_TIME_32_MS, INDIC_PERIOD_2},
+	[2] = {(INDIC_N_BLANK_10 << INDIC_N_BLANK_SHIFT)
+	       | PULSE_TIME_32_MS, INDIC_PERIOD_4},
+	[3] = {(INDIC_N_BLANK_5 << INDIC_N_BLANK_SHIFT)
+	       | PULSE_TIME_32_MS, INDIC_PERIOD_7},
+};
+
+/* i2c access*/
+static int lm3556_read_reg(struct i2c_client *client, u8 reg, u8 * val)
+{
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(client, reg);
+	if (ret < 0) {
+		dev_err(&client->dev, "i2c reading fail at 0x%02x error %d\n",
+			reg, ret);
+		return ret;
+	}
+	*val = ret & 0xff;
+	return ret;
+}
+
+static int lm3556_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+	int ret = 0;
+
+	ret = i2c_smbus_write_byte_data(client, reg, val);
+
+	if (ret < 0)
+		dev_err(&client->dev, "i2c writting fail at 0x%02x\n", reg);
+	return ret;
+}
+
+static int lm3556_write_bits(struct i2c_client *client,
+			     u8 reg, u8 val, u8 mask, u8 shift)
+{
+	int ret;
+	u8 reg_val;
+	struct lm3556_chip_data *chip = i2c_get_clientdata(client);
+
+	mutex_lock(&chip->lock);
+	ret = lm3556_read_reg(client, reg, &reg_val);
+	if (ret < 0)
+		goto out;
+	reg_val &= (~(mask << shift));
+	reg_val |= ((val & mask) << shift);
+	ret = lm3556_write_reg(client, reg, reg_val);
+out:
+	mutex_unlock(&chip->lock);
+	return ret;
+}
+
+/* chip initialize*/
+static int lm3556_chip_init(struct lm3556_chip_data *chip)
+{
+	u8 reg_val;
+	int ret;
+	struct i2c_client *client = chip->client;
+	struct lm3556_platform_data *pdata = chip->pdata;
+
+	/*set config register */
+	ret = lm3556_read_reg(client, REG_CONF, &reg_val);
+	if (ret < 0)
+		goto out;
+	reg_val &= (~EX_PIN_CONTROL_MASK);
+	reg_val |= ((pdata->torch_pin_polarity & 0x01)
+		    << TORCH_PIN_POLARITY_SHIFT);
+	reg_val |= ((pdata->strobe_usuage & 0x01) << STROBE_USUAGE_SHIFT);
+	reg_val |= ((pdata->strobe_pin_polarity & 0x01)
+		    << STROBE_PIN_POLARITY_SHIFT);
+	reg_val |= ((pdata->tx_pin_polarity & 0x01) << TX_PIN_POLARITY_SHIFT);
+	reg_val |= ((pdata->indicator_mode & 0x01) << INDIC_MODE_SHIFT);
+	ret = lm3556_write_reg(client, REG_CONF, reg_val);
+	if (ret < 0)
+		goto out;
+
+	/*set enable register */
+	ret = lm3556_read_reg(client, REG_ENABLE, &reg_val);
+	if (ret < 0)
+		goto out;
+	reg_val &= (~EX_PIN_ENABLE_MASK);
+	reg_val |= ((pdata->torch_pin_en & 0x01) << TORCH_PIN_EN_SHIFT);
+	reg_val |= ((pdata->strobe_pin_en & 0x01) << STROBE_PIN_EN_SHIFT);
+	reg_val |= ((pdata->tx_pin_en & 0x01) << TX_PIN_EN_SHIFT);
+	ret = lm3556_write_reg(client, REG_ENABLE, reg_val);
+
+out:
+	return ret;
+}
+
+/* chip control*/
+static int lm3556_control(struct lm3556_chip_data *chip,
+			  u8 brightness, enum lm3556_mode opmode)
+{
+	int ret;
+	struct i2c_client *client = chip->client;
+	struct lm3556_platform_data *pdata = chip->pdata;
+
+	ret = lm3556_read_reg(client, REG_FLAG, &chip->last_flag);
+	if (ret < 0)
+		goto out;
+	if (chip->last_flag)
+		dev_info(&client->dev, "Last FLAG is 0x%x\n", chip->last_flag);
+
+	/*brightness 0 means off-state */
+	if (!brightness)
+		opmode = MODES_STASNDBY;
+
+	switch (opmode) {
+	case MODES_TORCH:
+		ret = lm3556_write_bits(client, REG_I_CTRL,
+					brightness - 1, TORCH_I_MASK,
+					TORCH_I_SHIFT);
+
+		if (pdata->torch_pin_en)
+			opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);
+		break;
+
+	case MODES_FLASH:
+		ret = lm3556_write_bits(client, REG_I_CTRL,
+					brightness - 1, FLASH_I_MASK,
+					FLASH_I_SHIFT);
+		break;
+
+	case MODES_INDIC:
+		ret = lm3556_write_bits(client, REG_I_CTRL,
+					brightness - 1, TORCH_I_MASK,
+					TORCH_I_SHIFT);
+		break;
+
+	case MODES_STASNDBY:
+		if (pdata->torch_pin_en)
+			opmode |= (TORCH_PIN_EN_MASK << TORCH_PIN_EN_SHIFT);
+		break;
+
+	default:
+		return ret;
+	}
+	if (ret < 0)
+		goto out;
+	ret = lm3556_write_bits(client, REG_ENABLE,
+				opmode, MODE_BITS_MASK, MODE_BITS_SHIFT);
+out:
+	return ret;
+}
+
+/*torch */
+static void lm3556_torch_brightness_set(struct led_classdev *cdev,
+					enum led_brightness brightness)
+{
+	struct lm3556_chip_data *chip =
+	    container_of(cdev, struct lm3556_chip_data, cdev_torch);
+
+	lm3556_control(chip, brightness, MODES_TORCH);
+	return;
+}
+
+/* flash */
+static void lm3556_strobe_brightness_set(struct led_classdev *cdev,
+					 enum led_brightness brightness)
+{
+	struct lm3556_chip_data *chip =
+	    container_of(cdev, struct lm3556_chip_data, cdev_flash);
+
+	lm3556_control(chip, brightness, MODES_FLASH);
+	return;
+}
+
+/* indicator */
+static void lm3556_indicator_brightness_set(struct led_classdev *cdev,
+					    enum led_brightness brightness)
+{
+	struct lm3556_chip_data *chip =
+	    container_of(cdev, struct lm3556_chip_data, cdev_indicator);
+
+	lm3556_control(chip, brightness, MODES_INDIC);
+	return;
+}
+
+static ssize_t lm3556_indicator_pattern_store(struct device *dev,
+					      struct device_attribute *devAttr,
+					      const char *buf, size_t size)
+{
+	ssize_t ret;
+	struct i2c_client *client = container_of(dev->parent,
+						 struct i2c_client, dev);
+	unsigned int state;
+
+	ret = kstrtouint(buf, 10, &state);
+	if (ret)
+		goto out;
+	if (state > INDIC_PATTERN_SIZE - 1)
+		state = INDIC_PATTERN_SIZE - 1;
+
+	ret = lm3556_write_reg(client, REG_INDIC_BLINK,
+			       indicator_pattern[state].blinking);
+	if (ret < 0)
+		goto out;
+	ret = lm3556_write_reg(client, REG_INDIC_PERIOD,
+			       indicator_pattern[state].period_cnt);
+	if (ret < 0)
+		goto out;
+	return size;
+out:
+	dev_err(&client->dev, "pattern doesn't saved\n");
+	return size;
+}
+
+static DEVICE_ATTR(pattern, 0644, NULL, lm3556_indicator_pattern_store);
+
+/* Module Initialize */
+static int lm3556_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct lm3556_platform_data *pdata = client->dev.platform_data;
+	struct lm3556_chip_data *chip;
+
+	int err;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "i2c functionality check fail.\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (pdata == NULL) {
+		dev_err(&client->dev, "Needs Platform Data.\n");
+		return -ENODATA;
+	}
+
+	chip =
+	    devm_kzalloc(&client->dev, sizeof(struct lm3556_chip_data),
+			 GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	chip->client = client;
+	chip->pdata = pdata;
+
+	mutex_init(&chip->lock);
+	i2c_set_clientdata(client, chip);
+
+	err = lm3556_chip_init(chip);
+	if (err < 0)
+		goto err_chip_init;
+
+	/*flash */
+	chip->cdev_flash.name = "flash";
+	chip->cdev_flash.max_brightness = 16;
+	chip->cdev_flash.brightness_set = lm3556_strobe_brightness_set;
+	err = led_classdev_register((struct device *)
+				    &client->dev, &chip->cdev_flash);
+	if (err < 0)
+		goto err_create_flash_file;
+	/*torch */
+	chip->cdev_torch.name = "torch";
+	chip->cdev_torch.max_brightness = 8;
+	chip->cdev_torch.brightness_set = lm3556_torch_brightness_set;
+	err = led_classdev_register((struct device *)
+				    &client->dev, &chip->cdev_torch);
+	if (err < 0)
+		goto err_create_torch_file;
+	/*indicator */
+	chip->cdev_indicator.name = "indicator";
+	chip->cdev_indicator.max_brightness = 8;
+	chip->cdev_indicator.brightness_set = lm3556_indicator_brightness_set;
+	err = led_classdev_register((struct device *)
+				    &client->dev, &chip->cdev_indicator);
+	if (err < 0)
+		goto err_create_indicator_file;
+
+	err = device_create_file(chip->cdev_indicator.dev, &dev_attr_pattern);
+	if (err < 0)
+		goto err_create_pattern_file;
+
+	return 0;
+
+err_create_pattern_file:
+	led_classdev_unregister(&chip->cdev_indicator);
+err_create_indicator_file:
+	led_classdev_unregister(&chip->cdev_torch);
+err_create_torch_file:
+	led_classdev_unregister(&chip->cdev_flash);
+err_create_flash_file:
+err_chip_init:
+	i2c_set_clientdata(client, NULL);
+	kfree(chip);
+	return err;
+}
+
+static int lm3556_remove(struct i2c_client *client)
+{
+	struct lm3556_chip_data *chip = i2c_get_clientdata(client);
+
+	device_remove_file(chip->cdev_indicator.dev, &dev_attr_pattern);
+	led_classdev_unregister(&chip->cdev_indicator);
+	led_classdev_unregister(&chip->cdev_torch);
+	led_classdev_unregister(&chip->cdev_flash);
+	lm3556_write_reg(client, REG_ENABLE, 0);
+
+	kfree(chip);
+	return 0;
+}
+
+static const struct i2c_device_id lm3556_id[] = {
+	{LM3556_NAME, 0},
+	{}
+};
+
+MODULE_DEVICE_TABLE(i2c, lm3556_id);
+
+static struct i2c_driver lm3556_i2c_driver = {
+	.driver = {
+		   .name = LM3556_NAME,
+		   .owner = THIS_MODULE,
+		   .pm = NULL,
+		   },
+	.probe = lm3556_probe,
+	.remove = __devexit_p(lm3556_remove),
+	.id_table = lm3556_id,
+};
+
+static int __init lm3556_init(void)
+{
+	return i2c_add_driver(&lm3556_i2c_driver);
+}
+
+static void __exit lm3556_exit(void)
+{
+	i2c_del_driver(&lm3556_i2c_driver);
+}
+
+module_init(lm3556_init);
+module_exit(lm3556_exit);
+
+MODULE_DESCRIPTION("Texas Instruments Flash Lighting driver for LM3556");
+MODULE_AUTHOR
+("Geon Si Jeong <daniel.jeong@ti.com>, Woogyom Kim <milo.kim@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/leds-lm3556.h b/include/linux/leds-lm3556.h
new file mode 100644
index 0000000..115ee65
--- /dev/null
+++ b/include/linux/leds-lm3556.h
@@ -0,0 +1,242 @@
+/*
+ * Simple driver for Texas Instruments LM3556 LED Flash driver chip (Rev0x03)
+ * Copyright (C) 2012 Texas Instruments
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef __LINUX_LM3556_H
+#define __LINUX_LM3556_H
+
+#define LM3556_NAME "leds-lm3556"
+
+enum lm3556_ivfm_filter_time {
+	IVFM_FILTER_TIME_HALF_CURRENT_STEP = 0,
+	IVFM_FILTER_TIME_256_USEC,
+	IVFM_FILTER_TIME_512_USEC,
+	IVFM_FILTER_TIME_1024_USEC
+};
+
+enum lm3556_ivfm_adj_mode {
+	IVFM_ADJ_MODE_REPORT = 0,
+	IVFM_ADJ_MODESTOP_HOLD,
+	IVFM_ADJ_MODE_DOWN,
+	IVFM_ADJ_MODE_UP_DOWN,
+};
+
+enum lm3556_ivfm_down_threshold {
+	IVFM_DN_TH_2_7_V = 0,
+	IVFM_DN_TH_2_8_V,
+	IVFM_DN_TH_2_9_V,
+	IVFM_DN_TH_3_0_V,
+	IVFM_DN_TH_3_1_V,
+	IVFM_DN_TH_3_2_V,
+	IVFM_DN_TH_3_3_V,
+	IVFM_DN_TH_3_4_V,
+};
+
+enum lm3556_ivfm_hyst {
+	IVFM_HYST_50_MV = 0,
+	IVFM_HYST_100_MV,
+	IVFM_HYST_150_MV,
+	IVFM_HYST_DIS
+};
+
+enum lm3556_ntc_curr_lvl {
+	NTC_CURR_LVL_25_UA = 0,
+	NTC_CURR_LVL_50_UA,
+	NTC_CURR_LVL_75_UA,
+	NTC_CURR_LVL_100_UA
+};
+
+enum lm3556_ntc_trip_threshold {
+	NTC_TRIP_THRESHOLD_200_MV = 0,
+	NTC_TRIP_THRESHOLD_300_MV,
+	NTC_TRIP_THRESHOLD_400_MV,
+	NTC_TRIP_THRESHOLD_500_MV,
+	NTC_TRIP_THRESHOLD_600_MV,
+	NTC_TRIP_THRESHOLD_700_MV,
+	NTC_TRIP_THRESHOLD_800_MV,
+	NTC_TRIP_THRESHOLD_900_MV
+};
+
+enum lm3556_ntc_event_lvl {
+	NTC_EVENT_LVL_STANDBY = 0,
+	NTC_EVENT_LVL_REDUCE_MIN_TORCH
+};
+
+enum lm3556_torch_indic_ramp_time {
+	TORCH_INDIC_RAMP_TIME_16_MS = 0,
+	TORCH_INDIC_RAMP_TIME_32_MS,
+	TORCH_INDIC_RAMP_TIME_64_MS,
+	TORCH_INDIC_RAMP_TIME_128_MS,
+	TORCH_INDIC_RAMP_TIME_256_MS,
+	TORCH_INDIC_RAMP_TIME_512_MS,
+	TORCH_INDIC_RAMP_TIME_1024_MS,
+	TORCH_INDIC_RAMP_TIME_2048_MS,
+};
+
+enum lm3556_indic_pulse_time {
+	PULSE_TIME_0_MS = 0,
+	PULSE_TIME_32_MS,
+	PULSE_TIME_64_MS,
+	PULSE_TIME_92_MS,
+	PULSE_TIME_128_MS,
+	PULSE_TIME_160_MS,
+	PULSE_TIME_196_MS,
+	PULSE_TIME_224_MS,
+	PULSE_TIME_256_MS,
+	PULSE_TIME_288_MS,
+	PULSE_TIME_320_MS,
+	PULSE_TIME_352_MS,
+	PULSE_TIME_384_MS,
+	PULSE_TIME_416_MS,
+	PULSE_TIME_448_MS,
+	PULSE_TIME_480_MS,
+};
+
+enum lm3556_indic_n_blank {
+	INDIC_N_BLANK_0 = 0,
+	INDIC_N_BLANK_1,
+	INDIC_N_BLANK_2,
+	INDIC_N_BLANK_3,
+	INDIC_N_BLANK_4,
+	INDIC_N_BLANK_5,
+	INDIC_N_BLANK_6,
+	INDIC_N_BLANK_7,
+	INDIC_N_BLANK_8,
+	INDIC_N_BLANK_9,
+	INDIC_N_BLANK_10,
+	INDIC_N_BLANK_11,
+	INDIC_N_BLANK_12,
+	INDIC_N_BLANK_13,
+	INDIC_N_BLANK_14,
+	INDIC_N_BLANK_15,
+};
+
+enum lm3556_indic_period {
+	INDIC_PERIOD_0 = 0,
+	INDIC_PERIOD_1,
+	INDIC_PERIOD_2,
+	INDIC_PERIOD_3,
+	INDIC_PERIOD_4,
+	INDIC_PERIOD_5,
+	INDIC_PERIOD_6,
+	INDIC_PERIOD_7,
+};
+
+enum lm3556_indic_mode {
+	INDIC_MODE_INTERNAL = 0,
+	INDIC_MODE_EXTERNAL,
+};
+
+enum lm3556_flash_timeout {
+	FLASH_TIMEOUT_50_MS = 0,
+	FLASH_TIMEOUT_100_MS,
+	FLASH_TIMEOUT_150_MS,
+	FLASH_TIMEOUT_200_MS,
+	FLASH_TIMEOUT_250_MS,
+	FLASH_TIMEOUT_300_MS,
+	FLASH_TIMEOUT_350_MS,
+	FLASH_TIMEOUT_400_MS,
+};
+
+enum lm3556_flash_ramp_time {
+	FLASH_RAMP_TIME_256_US = 0,
+	FLASH_RAMP_TIME_512_US,
+	FLASH_RAMP_TIME_1024_US,
+	FLASH_RAMP_TIME_2048_US,
+	FLASH_RAMP_TIME_4096_US,
+	FLASH_RAMP_TIME_8192_US,
+	FLASH_RAMP_TIME_16384_US,
+	FLASH_RAMP_TIME_32768_US,
+};
+
+enum lm3556_inductor_current_limit {
+	INDIC_I_LIMIT_1500_MA = 0,
+	INDIC_I_LIMIT_2000_MA,
+	INDIC_I_LIMIT_2500_MA,
+	INDIC_I_LIMIT_3000_MA
+};
+
+enum lm3556_flash_current {
+	FLASH_I_93750_UA = 0,
+	FLASH_I_187500_UA,
+	FLASH_I_281250_UA,
+	FLASH_I_375000_UA,
+	FLASH_I_468750_UA,
+	FLASH_I_562500_UA,
+	FLASH_I_656250_UA,
+	FLASH_I_750000_UA,
+	FLASH_I_843750_UA,
+	FLASH_I_937500_UA,
+	FLASH_I_1031250_UA,
+	FLASH_I_1125000_UA,
+	FLASH_I_1218750_UA,
+	FLASH_I_1312500_UA,
+	FLASH_I_1406250_UA,
+	FLASH_I_1500000_UA,
+
+};
+
+enum lm3556_torch_current {
+	TORCH_I_46880_UA = 0,
+	TORCH_I_93750_UA,
+	TORCH_I_1406300_UA,
+	TORCH_I_187500_UA,
+	TORCH_I_234380_UA,
+	TORCH_I_281250_UA,
+	TORCH_I_328130_UA,
+	TORCH_I_375000_UA,
+};
+
+enum lm3556_mode {
+	MODES_STASNDBY = 0,
+	MODES_INDIC,
+	MODES_TORCH,
+	MODES_FLASH
+};
+
+enum lm3556_pass_mode {
+	PASS_MODE_NORMAL = 0,
+	PASS_MODE_PASS_ONLY
+};
+
+enum lm3556_prechg_mode {
+	PRE_CHARGE_MODE_NORMAL = 0,
+	PRE_CHARGE_MODE_PRE_CHARGE
+};
+
+enum lm3556_pin_polarity {
+	PIN_LOW_ACTIVE = 0,
+	PIN_HIGH_ACTIVE,
+};
+
+enum lm3556_pin_enable {
+	PIN_DISABLED = 0,
+	PIN_ENABLED,
+};
+
+enum lm3556_strobe_usuage {
+	STROBE_EDGE_DETECT = 0,
+	STROBE_LEVEL_DETECT,
+};
+
+struct lm3556_platform_data {
+	enum lm3556_pin_enable torch_pin_en;
+	enum lm3556_pin_polarity torch_pin_polarity;
+
+	enum lm3556_strobe_usuage strobe_usuage;
+	enum lm3556_pin_enable strobe_pin_en;
+	enum lm3556_pin_polarity strobe_pin_polarity;
+
+	enum lm3556_pin_enable tx_pin_en;
+	enum lm3556_pin_polarity tx_pin_polarity;
+
+	enum lm3556_indic_mode indicator_mode;
+};
+
+#endif /* __LINUX_LM3556_H */
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/1 v1] leds: Add LED driver for lm3556 chip
  2012-04-09  2:00 ` [PATCH 1/1 " Geon Si Jeong
@ 2012-05-15 18:43   ` Johan Hovold
  2012-05-22 10:48     ` Johan Hovold
  0 siblings, 1 reply; 5+ messages in thread
From: Johan Hovold @ 2012-05-15 18:43 UTC (permalink / raw)
  To: Geon Si Jeong
  Cc: Richard Purdie, Daniel Jeong, linux-kernel, Andrew Morton,
	Wolfram Sang

On Mon, Apr 09, 2012 at 11:00:55AM +0900, Geon Si Jeong wrote:
> It is a simple driver for LM3556 Chip(Texas Instruments)
> LM3556 :
> The LM3556 is a 4 MHz fixed-frequency synchronous boost
> converter plus 1.5A constant current driver for a high-current white LED.
> Datasheet: www.national.com/ds/LM/LM3556.pdf
> 
> Tested on OMAP4430
> 
> Signed-off-by: Geon Si Jeong <gshark.jeong@gmail.com>

[...]

> +/* i2c access*/
> +static int lm3556_read_reg(struct i2c_client *client, u8 reg, u8 * val)
> +{
> +	int ret;
> +
> +	ret = i2c_smbus_read_byte_data(client, reg);
> +	if (ret < 0) {
> +		dev_err(&client->dev, "i2c reading fail at 0x%02x error %d\n",
> +			reg, ret);
> +		return ret;
> +	}
> +	*val = ret & 0xff;
> +	return ret;
> +}
> +
> +static int lm3556_write_reg(struct i2c_client *client, u8 reg, u8 val)
> +{
> +	int ret = 0;
> +
> +	ret = i2c_smbus_write_byte_data(client, reg, val);
> +
> +	if (ret < 0)
> +		dev_err(&client->dev, "i2c writting fail at 0x%02x\n", reg);
> +	return ret;
> +}
> +
> +static int lm3556_write_bits(struct i2c_client *client,
> +			     u8 reg, u8 val, u8 mask, u8 shift)
> +{
> +	int ret;
> +	u8 reg_val;
> +	struct lm3556_chip_data *chip = i2c_get_clientdata(client);
> +
> +	mutex_lock(&chip->lock);
> +	ret = lm3556_read_reg(client, reg, &reg_val);
> +	if (ret < 0)
> +		goto out;
> +	reg_val &= (~(mask << shift));
> +	reg_val |= ((val & mask) << shift);
> +	ret = lm3556_write_reg(client, reg, reg_val);
> +out:
> +	mutex_unlock(&chip->lock);
> +	return ret;
> +}

The register io-locking above is broken. You need to protect both 
write_reg and write_bits using the mutex (but you must restructure
your code because write_bits currently calls write_reg). This is
required to avoid register corruption due to concurrent write_reg and
write_bits.

As has been suggested elsewhere, you could consider using regmap.

Thanks,
Johan

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/1 v1] leds: Add LED driver for lm3556 chip
  2012-05-15 18:43   ` Johan Hovold
@ 2012-05-22 10:48     ` Johan Hovold
  2012-05-22 10:58       ` Jeong, Daniel
  0 siblings, 1 reply; 5+ messages in thread
From: Johan Hovold @ 2012-05-22 10:48 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Richard Purdie, Daniel Jeong, linux-kernel, Wolfram Sang,
	Geon Si Jeong

On Tue, May 15, 2012 at 08:43:30PM +0200, Johan Hovold wrote:
> On Mon, Apr 09, 2012 at 11:00:55AM +0900, Geon Si Jeong wrote:
> > It is a simple driver for LM3556 Chip(Texas Instruments)
> > LM3556 :
> > The LM3556 is a 4 MHz fixed-frequency synchronous boost
> > converter plus 1.5A constant current driver for a high-current white LED.
> > Datasheet: www.national.com/ds/LM/LM3556.pdf
> > 
> > Tested on OMAP4430
> > 
> > Signed-off-by: Geon Si Jeong <gshark.jeong@gmail.com>
> 
> [...]
> 
> > +/* i2c access*/
> > +static int lm3556_read_reg(struct i2c_client *client, u8 reg, u8 * val)
> > +{
> > +	int ret;
> > +
> > +	ret = i2c_smbus_read_byte_data(client, reg);
> > +	if (ret < 0) {
> > +		dev_err(&client->dev, "i2c reading fail at 0x%02x error %d\n",
> > +			reg, ret);
> > +		return ret;
> > +	}
> > +	*val = ret & 0xff;
> > +	return ret;
> > +}
> > +
> > +static int lm3556_write_reg(struct i2c_client *client, u8 reg, u8 val)
> > +{
> > +	int ret = 0;
> > +
> > +	ret = i2c_smbus_write_byte_data(client, reg, val);
> > +
> > +	if (ret < 0)
> > +		dev_err(&client->dev, "i2c writting fail at 0x%02x\n", reg);
> > +	return ret;
> > +}
> > +
> > +static int lm3556_write_bits(struct i2c_client *client,
> > +			     u8 reg, u8 val, u8 mask, u8 shift)
> > +{
> > +	int ret;
> > +	u8 reg_val;
> > +	struct lm3556_chip_data *chip = i2c_get_clientdata(client);
> > +
> > +	mutex_lock(&chip->lock);
> > +	ret = lm3556_read_reg(client, reg, &reg_val);
> > +	if (ret < 0)
> > +		goto out;
> > +	reg_val &= (~(mask << shift));
> > +	reg_val |= ((val & mask) << shift);
> > +	ret = lm3556_write_reg(client, reg, reg_val);
> > +out:
> > +	mutex_unlock(&chip->lock);
> > +	return ret;
> > +}
> 
> The register io-locking above is broken. You need to protect both 
> write_reg and write_bits using the mutex (but you must restructure
> your code because write_bits currently calls write_reg). This is
> required to avoid register corruption due to concurrent write_reg and
> write_bits.
> 
> As has been suggested elsewhere, you could consider using regmap.

Andrew, just wanted to remind you that this driver is still in your
tree. Do you want to drop it or should someone else fix the locking?

Johan

^ permalink raw reply	[flat|nested] 5+ messages in thread

* RE: [PATCH 1/1 v1] leds: Add LED driver for lm3556 chip
  2012-05-22 10:48     ` Johan Hovold
@ 2012-05-22 10:58       ` Jeong, Daniel
  0 siblings, 0 replies; 5+ messages in thread
From: Jeong, Daniel @ 2012-05-22 10:58 UTC (permalink / raw)
  To: Johan Hovold, Andrew Morton
  Cc: Richard Purdie, linux-kernel@vger.kernel.org, Wolfram Sang,
	Geon Si Jeong

Hi Andrew and Johan. 

Please drop it from current tree.
It will be replaced to "regmap"  and patched soon. 

Regards,
Daniel Jeong

-----Original Message-----
From: Johan Hovold [mailto:jhovold@gmail.com] 
Sent: Tuesday, May 22, 2012 7:48 PM
To: Andrew Morton
Cc: Richard Purdie; Jeong, Daniel; linux-kernel@vger.kernel.org; Wolfram Sang; Geon Si Jeong
Subject: Re: [PATCH 1/1 v1] leds: Add LED driver for lm3556 chip

On Tue, May 15, 2012 at 08:43:30PM +0200, Johan Hovold wrote:
> On Mon, Apr 09, 2012 at 11:00:55AM +0900, Geon Si Jeong wrote:
> > It is a simple driver for LM3556 Chip(Texas Instruments)
> > LM3556 :
> > The LM3556 is a 4 MHz fixed-frequency synchronous boost converter 
> > plus 1.5A constant current driver for a high-current white LED.
> > Datasheet: www.national.com/ds/LM/LM3556.pdf
> > 
> > Tested on OMAP4430
> > 
> > Signed-off-by: Geon Si Jeong <gshark.jeong@gmail.com>
> 
> [...]
> 
> > +/* i2c access*/
> > +static int lm3556_read_reg(struct i2c_client *client, u8 reg, u8 * 
> > +val) {
> > +	int ret;
> > +
> > +	ret = i2c_smbus_read_byte_data(client, reg);
> > +	if (ret < 0) {
> > +		dev_err(&client->dev, "i2c reading fail at 0x%02x error %d\n",
> > +			reg, ret);
> > +		return ret;
> > +	}
> > +	*val = ret & 0xff;
> > +	return ret;
> > +}
> > +
> > +static int lm3556_write_reg(struct i2c_client *client, u8 reg, u8 
> > +val) {
> > +	int ret = 0;
> > +
> > +	ret = i2c_smbus_write_byte_data(client, reg, val);
> > +
> > +	if (ret < 0)
> > +		dev_err(&client->dev, "i2c writting fail at 0x%02x\n", reg);
> > +	return ret;
> > +}
> > +
> > +static int lm3556_write_bits(struct i2c_client *client,
> > +			     u8 reg, u8 val, u8 mask, u8 shift) {
> > +	int ret;
> > +	u8 reg_val;
> > +	struct lm3556_chip_data *chip = i2c_get_clientdata(client);
> > +
> > +	mutex_lock(&chip->lock);
> > +	ret = lm3556_read_reg(client, reg, &reg_val);
> > +	if (ret < 0)
> > +		goto out;
> > +	reg_val &= (~(mask << shift));
> > +	reg_val |= ((val & mask) << shift);
> > +	ret = lm3556_write_reg(client, reg, reg_val);
> > +out:
> > +	mutex_unlock(&chip->lock);
> > +	return ret;
> > +}
> 
> The register io-locking above is broken. You need to protect both 
> write_reg and write_bits using the mutex (but you must restructure 
> your code because write_bits currently calls write_reg). This is 
> required to avoid register corruption due to concurrent write_reg and 
> write_bits.
> 
> As has been suggested elsewhere, you could consider using regmap.

Andrew, just wanted to remind you that this driver is still in your tree. Do you want to drop it or should someone else fix the locking?

Johan

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2012-05-22 10:58 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-04-09  2:00 [PATCH 0/1 v1] leds: Add LED driver for lm3556 chip Geon Si Jeong
2012-04-09  2:00 ` [PATCH 1/1 " Geon Si Jeong
2012-05-15 18:43   ` Johan Hovold
2012-05-22 10:48     ` Johan Hovold
2012-05-22 10:58       ` Jeong, Daniel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox