* [PATCH v2] led: max77693: Add support for MAX77693 LED driver
@ 2012-06-01 3:56 Jonghwa Lee
2012-06-04 6:49 ` Bryan Wu
0 siblings, 1 reply; 2+ messages in thread
From: Jonghwa Lee @ 2012-06-01 3:56 UTC (permalink / raw)
To: linux-kernel
Cc: Bryan Wu, Richard Purdie, linux-leds, Jonghwa Lee, MyungJoo Ham,
Kyungmin Park
This patch supports max77693 LED driver. MAX77693 LED has 2 mode and 2 FLEDs.
The LED of each mode has seperate led data and handle it independently.
The 2 FLEDs can be activated by logic inputs (FLEDEN, TORCHEN) and also I2C interface.
This patch is based on mfd-2.6/for-next branch.
git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6.git for-next
Signed-off-by: Jonghwa Lee <jonghwa3.lee@samsung.com>
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
v2
- Transform the data structures which hold led's information.
- Move all macro and enum from header file to C file except platform_data strcure only.
And replace header file to include/linux/platform_data/ .
- Modify platform data in max77693.h to contain led's platform data.
drivers/leds/Kconfig | 7 +
drivers/leds/Makefile | 1 +
drivers/leds/leds-max77693.c | 282 +++++++++++++++++++++++++++
include/linux/mfd/max77693.h | 4 +
include/linux/platform_data/leds-max77693.h | 74 +++++++
5 files changed, 368 insertions(+), 0 deletions(-)
create mode 100644 drivers/leds/leds-max77693.c
create mode 100644 include/linux/platform_data/leds-max77693.h
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index ff4b8cf..d69be3c 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -394,6 +394,13 @@ config LEDS_MAX8997
This option enables support for on-chip LED drivers on
MAXIM MAX8997 PMIC.
+config LEDS_MAX77693
+ tristate "LED support for MAX77693 PMIC"
+ depends on LEDS_CLASS && MFD_MAX77693
+ help
+ This option enables support for on-chip LED drivers on
+ MAXIM MAX77693 PMIC.
+
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 890481c..ff4ff2c 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -45,6 +45,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_MAX77693) += leds-max77693.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
diff --git a/drivers/leds/leds-max77693.c b/drivers/leds/leds-max77693.c
new file mode 100644
index 0000000..38d4300
--- /dev/null
+++ b/drivers/leds/leds-max77693.c
@@ -0,0 +1,282 @@
+/*
+ * LED driver for Maxim MAX77693 - leds-max77673.c
+ *
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ * ByungChang Cha <bc.cha@samsung.com>
+ * Jonghwa Lee <jonghwa3.lee@samsung.com>
+ *
+ * This program is not provided / owned by Maxim Integrated Products.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/mfd/max77693.h>
+#include <linux/mfd/max77693-private.h>
+#include <linux/platform_data/leds-max77693.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+/* MAX77693_IFLASH1 */
+#define MAX77693_FLASH_IOUT1 0x3F
+
+/* MAX77693_IFLASH2 */
+#define MAX77693_FLASH_IOUT2 0x3F
+
+/* MAX77693_ITORCH */
+#define MAX77693_TORCH_IOUT1 0x0F
+#define MAX77693_TORCH_IOUT2 0xF0
+
+/* MAX77693_FLASH_EN */
+#define MAX77693_TORCH_FLED2_EN 0x03
+#define MAX77693_TORCH_FLED1_EN 0x0C
+#define MAX77693_FLASH_FLED2_EN 0x30
+#define MAX77693_FLASH_FLED1_EN 0xC0
+/* MAX77693 FLEDx_EN value */
+#define MAX77693_FLED_OFF 0x00
+#define MAX77693_FLED_FLASHEN 0x01
+#define MAX77693_FLED_TORCHEN 0x02
+#define MAX77693_FLED_I2C 0X03
+
+/* MAX77693_VOUT_CNTL */
+#define MAX77693_BOOST_FLASH_MODE 0x07
+#define MAX77693_BOOST_FLASH_FLEDNUM 0x80
+/* MAX77693_BOOST_FLASH_MODE vaule*/
+#define MAX77693_BOOST_FLASH_MODE_OFF 0x00
+#define MAX77693_BOOST_FLASH_MODE_FLED1 0x01
+#define MAX77693_BOOST_FLASH_MODE_FLED2 0x02
+#define MAX77693_BOOST_FLASH_MODE_BOTH 0x03
+#define MAX77693_BOOST_FLASH_MODE_FIXED 0x04
+/* MAX77693_BOOST_FLASH_FLEDNUM vaule*/
+#define MAX77693_BOOST_FLASH_FLEDNUM_1 0x00
+#define MAX77693_BOOST_FLASH_FLEDNUM_2 0x80
+
+/* MAX77693_VOUT_FLASH1 */
+#define MAX77693_BOOST_VOUT_FLASH 0x7F
+#define MAX77693_BOOST_VOUT_FLASH_FROM_VOLT(mV) \
+ ((mV) <= 3300 ? 0x00 : \
+ ((mV) <= 5500 ? (((mV) - 3300) / 25 + 0x0C) : 0x7F))
+
+#define MAX_FLASH_CURRENT 1000 /* 1000mA(0x1f) */
+#define MAX_TORCH_CURRENT 250 /* 250mA(0x0f) */
+#define MAX_FLASH_DRV_LEVEL 63 /* 15.625 + 15.625*63 mA */
+#define MAX_TORCH_DRV_LEVEL 15 /* 15.625 + 15.625*15 mA */
+
+#define MAX77693_LED_CTRL_BY_I2C 1
+#define MAX77693_TORCH_LED_2 3
+
+static u8 led_en_mask[MAX77693_LED_MAX] = {
+ MAX77693_FLASH_FLED1_EN,
+ MAX77693_FLASH_FLED2_EN,
+ MAX77693_TORCH_FLED1_EN,
+ MAX77693_TORCH_FLED2_EN
+};
+
+static u8 reg_led_timer[MAX77693_LED_MAX] = {
+ MAX77693_LED_REG_FLASH_TIMER,
+ MAX77693_LED_REG_FLASH_TIMER,
+ MAX77693_LED_REG_ITORCHTIMER,
+ MAX77693_LED_REG_ITORCHTIMER,
+};
+
+static u8 reg_led_current[MAX77693_LED_MAX] = {
+ MAX77693_LED_REG_IFLASH1,
+ MAX77693_LED_REG_IFLASH2,
+ MAX77693_LED_REG_ITORCH,
+ MAX77693_LED_REG_ITORCH,
+};
+
+static u8 led_current_mask[MAX77693_LED_MAX] = {
+ MAX77693_FLASH_IOUT1,
+ MAX77693_FLASH_IOUT2,
+ MAX77693_TORCH_IOUT1,
+ MAX77693_TORCH_IOUT2
+};
+
+static int max77693_led_get_en_value(struct max77693_led *led)
+{
+ if (led->cntrl_mode == MAX77693_LED_CTRL_BY_I2C)
+ return MAX77693_FLED_OFF;
+ else if (led->id < 2)
+ return MAX77693_FLED_FLASHEN;
+ else
+ return MAX77693_FLED_TORCHEN;
+}
+
+static void max77693_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct max77693_led *led
+ = container_of(led_cdev, struct max77693_led, cdev);
+
+ led->brightness = min_t(int, value, MAX77693_FLASH_IOUT1);
+ schedule_work(&led->work);
+}
+
+static void max77693_led_work(struct work_struct *work)
+{
+ struct max77693_led *led
+ = container_of(work, struct max77693_led, work);
+ int ret;
+ int en_val;
+ int id = led->id;
+ u8 shift = id == MAX77693_TORCH_LED_2 ? 4 : 0;
+
+
+ en_val = max77693_led_get_en_value(led);
+ ret = regmap_update_bits(led->max77693->regmap,
+ MAX77693_LED_REG_FLASH_EN,
+ led_en_mask[id],
+ en_val << (ffs(led_en_mask[id]) - 1));
+ if (unlikely(ret))
+ goto error_set_bits;
+
+ ret = regmap_update_bits(led->max77693->regmap,
+ reg_led_current[id],
+ led_current_mask[id],
+ led->brightness << shift);
+ if (unlikely(ret))
+ goto error_set_bits;
+
+ return;
+
+error_set_bits:
+ dev_err(led->max77693->dev, "%s: can't set led level %d\n", __func__, ret);
+ return;
+}
+
+static int max77693_led_setup(struct max77693_led *led)
+{
+ int ret = 0;
+ int id = led->id;
+ int value;
+ u8 shift = id == MAX77693_TORCH_LED_2 ? 4 : 0;
+
+ ret |= regmap_write(led->max77693->regmap, MAX77693_LED_REG_VOUT_CNTL,
+ MAX77693_BOOST_FLASH_FLEDNUM_2
+ | MAX77693_BOOST_FLASH_MODE_BOTH);
+ ret |= regmap_write(led->max77693->regmap, MAX77693_LED_REG_VOUT_FLASH1,
+ MAX77693_BOOST_VOUT_FLASH_FROM_VOLT(5000));
+ ret |= regmap_write(led->max77693->regmap,
+ MAX77693_LED_REG_MAX_FLASH1, 0xEC);
+ ret |= regmap_write(led->max77693->regmap,
+ MAX77693_LED_REG_MAX_FLASH2, 0x00);
+
+ value = max77693_led_get_en_value(led);
+
+ ret |= regmap_update_bits(led->max77693->regmap,
+ MAX77693_LED_REG_FLASH_EN,
+ led_en_mask[id],
+ value << (ffs(led_en_mask[id]) - 1));
+
+ /* Set TORCH_TMR_DUR or FLASH_TMR_DUR */
+ if (id < 2) {
+ ret |= regmap_write(led->max77693->regmap, reg_led_timer[id],
+ (led->timer | led->timer_mode << 7));
+ } else {
+ ret |= regmap_write(led->max77693->regmap, reg_led_timer[id],
+ 0xC0);
+ }
+ /* Set current */
+ ret |= regmap_update_bits(led->max77693->regmap, reg_led_current[id],
+ led_current_mask[id],
+ led->brightness << shift);
+
+ return ret;
+}
+
+static int max77693_led_probe(struct platform_device *pdev)
+{
+ struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent);
+ struct max77693_platform_data *max77693_pdata
+ = dev_get_platdata(max77693->dev);
+ struct max77693_led_platform_data *led_data
+ = max77693_pdata->led_data;
+ struct max77693_led *led;
+ int ret = 0;
+ int i;
+
+ if(!led_data) {
+ dev_err(&pdev->dev, "%s : No platform data\n", __func__);
+ return -ENODEV;
+ }
+
+ platform_set_drvdata(pdev, led_data);
+
+ for (i = 0; i < led_data->num_leds; i++) {
+ led = &(led_data->leds[i]);
+
+ led->max77693 = max77693;
+ led->cdev.name = led->name;
+ led->cdev.brightness_set = max77693_led_set;
+ led->cdev.brightness = LED_OFF;
+ led->cdev.flags = LED_CORE_SUSPENDRESUME;
+ led->cdev.max_brightness = led->id < 2
+ ? MAX_FLASH_DRV_LEVEL : MAX_TORCH_DRV_LEVEL;
+
+ INIT_WORK(&led->work, max77693_led_work);
+ ret = led_classdev_register(&pdev->dev, &led->cdev);
+ if (unlikely(ret)) {
+ dev_err(&pdev->dev, "unable to register LED\n");
+ ret = -EFAULT;
+ continue;
+ }
+
+ ret = max77693_led_setup(led);
+ if (unlikely(ret)) {
+ dev_err(&pdev->dev, "unable to setup LED\n");
+ led_classdev_unregister(&led->cdev);
+ ret = -EFAULT;
+ }
+ }
+ return ret;
+}
+
+static int __devexit max77693_led_remove(struct platform_device *pdev)
+{
+ struct max77693_led_platform_data *led_data = platform_get_drvdata(pdev);
+ struct max77693_led *led;
+ int i;
+
+ for (i = 0; i < led_data->num_leds; i++) {
+ led = &(led_data->leds[i]);
+ if (led == NULL)
+ continue;
+
+ led_classdev_unregister(&led->cdev);
+ }
+ return 0;
+}
+
+static struct platform_driver max77693_led_driver = {
+ .probe = max77693_led_probe,
+ .remove = __devexit_p(max77693_led_remove),
+ .driver = {
+ .name = "max77693-led",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init max77693_led_init(void)
+{
+ return platform_driver_register(&max77693_led_driver);
+}
+module_init(max77693_led_init);
+
+static void __exit max77693_led_exit(void)
+{
+ platform_driver_unregister(&max77693_led_driver);
+}
+module_exit(max77693_led_exit);
+
+MODULE_AUTHOR("ByungChang Cha <bc.cha@samsung.com>");
+MODULE_DESCRIPTION("MAX77693 LED driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/max77693.h b/include/linux/mfd/max77693.h
index 1d28ae9..b163e64 100644
--- a/include/linux/mfd/max77693.h
+++ b/include/linux/mfd/max77693.h
@@ -32,5 +32,9 @@
struct max77693_platform_data {
int wakeup;
+#ifdef CONFIG_LEDS_MAX77693
+ /* led (flash/torch) data */
+ struct max77693_led_platform_data *led_data;
+#endif
};
#endif /* __LINUX_MFD_MAX77693_H */
diff --git a/include/linux/platform_data/leds-max77693.h b/include/linux/platform_data/leds-max77693.h
new file mode 100644
index 0000000..24237c7
--- /dev/null
+++ b/include/linux/platform_data/leds-max77693.h
@@ -0,0 +1,74 @@
+/*
+ * leds-max77693.h - Flash-led driver for Maxim MAX77693
+ *
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ * ByungChang Cha <bc.cha@samsung.com>
+ *
+ * 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 __LEDS_MAX77693_H__
+#define __LEDS_MAX77693_H__
+
+#define MAX77693_LED_MAX 4
+
+/* struct max77693_led - struture containing led's information
+ * @name: led's name
+ * @id: integer id for each led.
+ * 0: FLED1 for FLASH Mode
+ * 1: FLED2 for FLASH Mode
+ * 2: FLED1 for TORCH Mode
+ * 3: FLED2 for TORCH Mode
+ * @timer: value of timer duration (ms) <= 15
+ * FLASH TORCH
+ * 0: 62.5 262
+ * 1: 125 524
+ * 2: 187.5 786
+ * 3: 250 1048
+ * 4: 312.5 1572
+ * 5: 375 2096
+ * 6: 437.5 2620
+ * 7: 500 3144
+ * 8: 562.5 4193
+ * 9: 625 5242
+ * 10: 687.5 6291
+ * 11: 750 7340
+ * 12: 812.5 9437
+ * 13: 875 11534
+ * 14: 937.5 13631
+ * 15: 1000 15728
+ * @brigthness
+ * @timer_mode: timer mode bit
+ * 0: One shot mode
+ * 1: Max timer mode
+ * @cntrl_mode: set led's control mode
+ 0: triggered by FLASHEN/TORCHEN
+ 1: triggered by I2C
+ * @cdev
+ * @max77693
+ * @work
+ */
+
+struct max77693_led
+{
+ const char *name;
+ int id;
+ int timer;
+ int brightness;
+ int timer_mode;
+ int cntrl_mode;
+
+ struct led_classdev cdev;
+ struct max77693_dev *max77693;
+ struct work_struct work;
+};
+
+struct max77693_led_platform_data
+{
+ int num_leds;
+ struct max77693_led leds[MAX77693_LED_MAX];
+};
+
+#endif
--
1.7.4.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH v2] led: max77693: Add support for MAX77693 LED driver
2012-06-01 3:56 [PATCH v2] led: max77693: Add support for MAX77693 LED driver Jonghwa Lee
@ 2012-06-04 6:49 ` Bryan Wu
0 siblings, 0 replies; 2+ messages in thread
From: Bryan Wu @ 2012-06-04 6:49 UTC (permalink / raw)
To: Jonghwa Lee
Cc: linux-kernel, Richard Purdie, linux-leds, MyungJoo Ham, Kyungmin Park
Hi Jonghwa,
I still found some coding style errors when I applied this patch on my
branch, please use scripts/checkpatch.pl to check and fix the coding
style issue.
On Fri, Jun 1, 2012 at 11:56 AM, Jonghwa Lee <jonghwa3.lee@samsung.com> wrote:
> This patch supports max77693 LED driver. MAX77693 LED has 2 mode and 2 FLEDs.
> The LED of each mode has seperate led data and handle it independently.
> The 2 FLEDs can be activated by logic inputs (FLEDEN, TORCHEN) and also I2C interface.
>
> This patch is based on mfd-2.6/for-next branch.
> git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6.git for-next
>
> Signed-off-by: Jonghwa Lee <jonghwa3.lee@samsung.com>
> Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
> v2
> - Transform the data structures which hold led's information.
> - Move all macro and enum from header file to C file except platform_data strcure only.
> And replace header file to include/linux/platform_data/ .
> - Modify platform data in max77693.h to contain led's platform data.
>
> drivers/leds/Kconfig | 7 +
> drivers/leds/Makefile | 1 +
> drivers/leds/leds-max77693.c | 282 +++++++++++++++++++++++++++
> include/linux/mfd/max77693.h | 4 +
> include/linux/platform_data/leds-max77693.h | 74 +++++++
> 5 files changed, 368 insertions(+), 0 deletions(-)
> create mode 100644 drivers/leds/leds-max77693.c
> create mode 100644 include/linux/platform_data/leds-max77693.h
>
> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
> index ff4b8cf..d69be3c 100644
> --- a/drivers/leds/Kconfig
> +++ b/drivers/leds/Kconfig
> @@ -394,6 +394,13 @@ config LEDS_MAX8997
> This option enables support for on-chip LED drivers on
> MAXIM MAX8997 PMIC.
>
> +config LEDS_MAX77693
> + tristate "LED support for MAX77693 PMIC"
> + depends on LEDS_CLASS && MFD_MAX77693
> + help
> + This option enables support for on-chip LED drivers on
> + MAXIM MAX77693 PMIC.
> +
> 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 890481c..ff4ff2c 100644
> --- a/drivers/leds/Makefile
> +++ b/drivers/leds/Makefile
> @@ -45,6 +45,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_MAX77693) += leds-max77693.o
>
> # LED SPI Drivers
> obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
> diff --git a/drivers/leds/leds-max77693.c b/drivers/leds/leds-max77693.c
> new file mode 100644
> index 0000000..38d4300
> --- /dev/null
> +++ b/drivers/leds/leds-max77693.c
> @@ -0,0 +1,282 @@
> +/*
> + * LED driver for Maxim MAX77693 - leds-max77673.c
> + *
> + * Copyright (C) 2012 Samsung Electronics Co.Ltd
> + * ByungChang Cha <bc.cha@samsung.com>
> + * Jonghwa Lee <jonghwa3.lee@samsung.com>
> + *
> + * This program is not provided / owned by Maxim Integrated Products.
> + *
> + * 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/kernel.h>
> +#include <linux/init.h>
> +#include <linux/platform_device.h>
> +#include <linux/leds.h>
> +#include <linux/workqueue.h>
> +#include <linux/spinlock.h>
> +#include <linux/slab.h>
> +#include <linux/mfd/max77693.h>
> +#include <linux/mfd/max77693-private.h>
> +#include <linux/platform_data/leds-max77693.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +
> +/* MAX77693_IFLASH1 */
> +#define MAX77693_FLASH_IOUT1 0x3F
> +
> +/* MAX77693_IFLASH2 */
> +#define MAX77693_FLASH_IOUT2 0x3F
> +
> +/* MAX77693_ITORCH */
> +#define MAX77693_TORCH_IOUT1 0x0F
> +#define MAX77693_TORCH_IOUT2 0xF0
> +
> +/* MAX77693_FLASH_EN */
> +#define MAX77693_TORCH_FLED2_EN 0x03
> +#define MAX77693_TORCH_FLED1_EN 0x0C
> +#define MAX77693_FLASH_FLED2_EN 0x30
> +#define MAX77693_FLASH_FLED1_EN 0xC0
> +/* MAX77693 FLEDx_EN value */
> +#define MAX77693_FLED_OFF 0x00
> +#define MAX77693_FLED_FLASHEN 0x01
> +#define MAX77693_FLED_TORCHEN 0x02
> +#define MAX77693_FLED_I2C 0X03
> +
> +/* MAX77693_VOUT_CNTL */
> +#define MAX77693_BOOST_FLASH_MODE 0x07
> +#define MAX77693_BOOST_FLASH_FLEDNUM 0x80
> +/* MAX77693_BOOST_FLASH_MODE vaule*/
> +#define MAX77693_BOOST_FLASH_MODE_OFF 0x00
> +#define MAX77693_BOOST_FLASH_MODE_FLED1 0x01
> +#define MAX77693_BOOST_FLASH_MODE_FLED2 0x02
> +#define MAX77693_BOOST_FLASH_MODE_BOTH 0x03
> +#define MAX77693_BOOST_FLASH_MODE_FIXED 0x04
> +/* MAX77693_BOOST_FLASH_FLEDNUM vaule*/
> +#define MAX77693_BOOST_FLASH_FLEDNUM_1 0x00
> +#define MAX77693_BOOST_FLASH_FLEDNUM_2 0x80
> +
> +/* MAX77693_VOUT_FLASH1 */
> +#define MAX77693_BOOST_VOUT_FLASH 0x7F
> +#define MAX77693_BOOST_VOUT_FLASH_FROM_VOLT(mV) \
> + ((mV) <= 3300 ? 0x00 : \
> + ((mV) <= 5500 ? (((mV) - 3300) / 25 + 0x0C) : 0x7F))
> +
> +#define MAX_FLASH_CURRENT 1000 /* 1000mA(0x1f) */
> +#define MAX_TORCH_CURRENT 250 /* 250mA(0x0f) */
> +#define MAX_FLASH_DRV_LEVEL 63 /* 15.625 + 15.625*63 mA */
> +#define MAX_TORCH_DRV_LEVEL 15 /* 15.625 + 15.625*15 mA */
> +
> +#define MAX77693_LED_CTRL_BY_I2C 1
> +#define MAX77693_TORCH_LED_2 3
> +
> +static u8 led_en_mask[MAX77693_LED_MAX] = {
> + MAX77693_FLASH_FLED1_EN,
> + MAX77693_FLASH_FLED2_EN,
> + MAX77693_TORCH_FLED1_EN,
> + MAX77693_TORCH_FLED2_EN
> +};
> +
> +static u8 reg_led_timer[MAX77693_LED_MAX] = {
> + MAX77693_LED_REG_FLASH_TIMER,
> + MAX77693_LED_REG_FLASH_TIMER,
> + MAX77693_LED_REG_ITORCHTIMER,
> + MAX77693_LED_REG_ITORCHTIMER,
> +};
> +
> +static u8 reg_led_current[MAX77693_LED_MAX] = {
> + MAX77693_LED_REG_IFLASH1,
> + MAX77693_LED_REG_IFLASH2,
> + MAX77693_LED_REG_ITORCH,
> + MAX77693_LED_REG_ITORCH,
> +};
> +
> +static u8 led_current_mask[MAX77693_LED_MAX] = {
> + MAX77693_FLASH_IOUT1,
> + MAX77693_FLASH_IOUT2,
> + MAX77693_TORCH_IOUT1,
> + MAX77693_TORCH_IOUT2
> +};
> +
> +static int max77693_led_get_en_value(struct max77693_led *led)
> +{
> + if (led->cntrl_mode == MAX77693_LED_CTRL_BY_I2C)
> + return MAX77693_FLED_OFF;
> + else if (led->id < 2)
> + return MAX77693_FLED_FLASHEN;
> + else
> + return MAX77693_FLED_TORCHEN;
> +}
> +
> +static void max77693_led_set(struct led_classdev *led_cdev,
> + enum led_brightness value)
> +{
> + struct max77693_led *led
> + = container_of(led_cdev, struct max77693_led, cdev);
> +
> + led->brightness = min_t(int, value, MAX77693_FLASH_IOUT1);
> + schedule_work(&led->work);
> +}
> +
> +static void max77693_led_work(struct work_struct *work)
> +{
> + struct max77693_led *led
> + = container_of(work, struct max77693_led, work);
> + int ret;
> + int en_val;
> + int id = led->id;
> + u8 shift = id == MAX77693_TORCH_LED_2 ? 4 : 0;
> +
> +
I think you need mutex_lock here to protect register accessing.
> + en_val = max77693_led_get_en_value(led);
> + ret = regmap_update_bits(led->max77693->regmap,
> + MAX77693_LED_REG_FLASH_EN,
> + led_en_mask[id],
> + en_val << (ffs(led_en_mask[id]) - 1));
> + if (unlikely(ret))
> + goto error_set_bits;
> +
> + ret = regmap_update_bits(led->max77693->regmap,
> + reg_led_current[id],
> + led_current_mask[id],
> + led->brightness << shift);
> + if (unlikely(ret))
> + goto error_set_bits;
> +
> + return;
> +
> +error_set_bits:
> + dev_err(led->max77693->dev, "%s: can't set led level %d\n", __func__, ret);
> + return;
> +}
> +
> +static int max77693_led_setup(struct max77693_led *led)
> +{
> + int ret = 0;
> + int id = led->id;
> + int value;
> + u8 shift = id == MAX77693_TORCH_LED_2 ? 4 : 0;
> +
> + ret |= regmap_write(led->max77693->regmap, MAX77693_LED_REG_VOUT_CNTL,
> + MAX77693_BOOST_FLASH_FLEDNUM_2
> + | MAX77693_BOOST_FLASH_MODE_BOTH);
> + ret |= regmap_write(led->max77693->regmap, MAX77693_LED_REG_VOUT_FLASH1,
> + MAX77693_BOOST_VOUT_FLASH_FROM_VOLT(5000));
> + ret |= regmap_write(led->max77693->regmap,
> + MAX77693_LED_REG_MAX_FLASH1, 0xEC);
> + ret |= regmap_write(led->max77693->regmap,
> + MAX77693_LED_REG_MAX_FLASH2, 0x00);
> +
> + value = max77693_led_get_en_value(led);
> +
> + ret |= regmap_update_bits(led->max77693->regmap,
> + MAX77693_LED_REG_FLASH_EN,
> + led_en_mask[id],
> + value << (ffs(led_en_mask[id]) - 1));
> +
> + /* Set TORCH_TMR_DUR or FLASH_TMR_DUR */
> + if (id < 2) {
> + ret |= regmap_write(led->max77693->regmap, reg_led_timer[id],
> + (led->timer | led->timer_mode << 7));
> + } else {
> + ret |= regmap_write(led->max77693->regmap, reg_led_timer[id],
> + 0xC0);
> + }
> + /* Set current */
> + ret |= regmap_update_bits(led->max77693->regmap, reg_led_current[id],
> + led_current_mask[id],
> + led->brightness << shift);
> +
> + return ret;
> +}
> +
> +static int max77693_led_probe(struct platform_device *pdev)
> +{
> + struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent);
> + struct max77693_platform_data *max77693_pdata
> + = dev_get_platdata(max77693->dev);
> + struct max77693_led_platform_data *led_data
> + = max77693_pdata->led_data;
> + struct max77693_led *led;
> + int ret = 0;
> + int i;
> +
> + if(!led_data) {
> + dev_err(&pdev->dev, "%s : No platform data\n", __func__);
> + return -ENODEV;
> + }
> +
> + platform_set_drvdata(pdev, led_data);
> +
> + for (i = 0; i < led_data->num_leds; i++) {
> + led = &(led_data->leds[i]);
> +
> + led->max77693 = max77693;
> + led->cdev.name = led->name;
> + led->cdev.brightness_set = max77693_led_set;
> + led->cdev.brightness = LED_OFF;
> + led->cdev.flags = LED_CORE_SUSPENDRESUME;
> + led->cdev.max_brightness = led->id < 2
> + ? MAX_FLASH_DRV_LEVEL : MAX_TORCH_DRV_LEVEL;
> +
> + INIT_WORK(&led->work, max77693_led_work);
> + ret = led_classdev_register(&pdev->dev, &led->cdev);
> + if (unlikely(ret)) {
> + dev_err(&pdev->dev, "unable to register LED\n");
> + ret = -EFAULT;
> + continue;
> + }
> +
> + ret = max77693_led_setup(led);
> + if (unlikely(ret)) {
> + dev_err(&pdev->dev, "unable to setup LED\n");
> + led_classdev_unregister(&led->cdev);
> + ret = -EFAULT;
> + }
> + }
> + return ret;
> +}
> +
> +static int __devexit max77693_led_remove(struct platform_device *pdev)
> +{
> + struct max77693_led_platform_data *led_data = platform_get_drvdata(pdev);
> + struct max77693_led *led;
> + int i;
> +
> + for (i = 0; i < led_data->num_leds; i++) {
> + led = &(led_data->leds[i]);
> + if (led == NULL)
> + continue;
> +
> + led_classdev_unregister(&led->cdev);
> + }
> + return 0;
> +}
> +
> +static struct platform_driver max77693_led_driver = {
> + .probe = max77693_led_probe,
> + .remove = __devexit_p(max77693_led_remove),
> + .driver = {
> + .name = "max77693-led",
> + .owner = THIS_MODULE,
> + },
> +};
> +
> +static int __init max77693_led_init(void)
> +{
> + return platform_driver_register(&max77693_led_driver);
> +}
> +module_init(max77693_led_init);
> +
> +static void __exit max77693_led_exit(void)
> +{
> + platform_driver_unregister(&max77693_led_driver);
> +}
> +module_exit(max77693_led_exit);
> +
> +MODULE_AUTHOR("ByungChang Cha <bc.cha@samsung.com>");
> +MODULE_DESCRIPTION("MAX77693 LED driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/max77693.h b/include/linux/mfd/max77693.h
> index 1d28ae9..b163e64 100644
> --- a/include/linux/mfd/max77693.h
> +++ b/include/linux/mfd/max77693.h
> @@ -32,5 +32,9 @@
>
> struct max77693_platform_data {
> int wakeup;
> +#ifdef CONFIG_LEDS_MAX77693
This doesn't work when leds-max77693 is a module,
> + /* led (flash/torch) data */
> + struct max77693_led_platform_data *led_data;
> +#endif
> };
> #endif /* __LINUX_MFD_MAX77693_H */
> diff --git a/include/linux/platform_data/leds-max77693.h b/include/linux/platform_data/leds-max77693.h
> new file mode 100644
> index 0000000..24237c7
> --- /dev/null
> +++ b/include/linux/platform_data/leds-max77693.h
> @@ -0,0 +1,74 @@
> +/*
> + * leds-max77693.h - Flash-led driver for Maxim MAX77693
> + *
> + * Copyright (C) 2012 Samsung Electronics Co.Ltd
> + * ByungChang Cha <bc.cha@samsung.com>
> + *
> + * 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 __LEDS_MAX77693_H__
> +#define __LEDS_MAX77693_H__
> +
> +#define MAX77693_LED_MAX 4
> +
> +/* struct max77693_led - struture containing led's information
> + * @name: led's name
> + * @id: integer id for each led.
> + * 0: FLED1 for FLASH Mode
> + * 1: FLED2 for FLASH Mode
> + * 2: FLED1 for TORCH Mode
> + * 3: FLED2 for TORCH Mode
> + * @timer: value of timer duration (ms) <= 15
> + * FLASH TORCH
> + * 0: 62.5 262
> + * 1: 125 524
> + * 2: 187.5 786
> + * 3: 250 1048
> + * 4: 312.5 1572
> + * 5: 375 2096
> + * 6: 437.5 2620
> + * 7: 500 3144
> + * 8: 562.5 4193
> + * 9: 625 5242
> + * 10: 687.5 6291
> + * 11: 750 7340
> + * 12: 812.5 9437
> + * 13: 875 11534
> + * 14: 937.5 13631
> + * 15: 1000 15728
> + * @brigthness
> + * @timer_mode: timer mode bit
> + * 0: One shot mode
> + * 1: Max timer mode
> + * @cntrl_mode: set led's control mode
> + 0: triggered by FLASHEN/TORCHEN
> + 1: triggered by I2C
> + * @cdev
> + * @max77693
> + * @work
> + */
> +
> +struct max77693_led
> +{
> + const char *name;
> + int id;
> + int timer;
> + int brightness;
> + int timer_mode;
> + int cntrl_mode;
> +
> + struct led_classdev cdev;
> + struct max77693_dev *max77693;
> + struct work_struct work;
> +};
> +
> +struct max77693_led_platform_data
> +{
> + int num_leds;
> + struct max77693_led leds[MAX77693_LED_MAX];
> +};
> +
> +#endif
> --
> 1.7.4.1
>
--
Bryan Wu <bryan.wu@canonical.com>
Kernel Developer +86.186-168-78255 Mobile
Canonical Ltd. www.canonical.com
Ubuntu - Linux for human beings | www.ubuntu.com
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2012-06-04 6:50 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-06-01 3:56 [PATCH v2] led: max77693: Add support for MAX77693 LED driver Jonghwa Lee
2012-06-04 6:49 ` Bryan Wu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).