2012-06-01 03:57:38

by Jonghwa Lee

[permalink] [raw]
Subject: [PATCH v2] led: max77693: Add support for MAX77693 LED driver

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 <[email protected]>
Signed-off-by: MyungJoo Ham <[email protected]>
Signed-off-by: Kyungmin Park <[email protected]>
---
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 <[email protected]>
+ * Jonghwa Lee <[email protected]>
+ *
+ * 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 <[email protected]>");
+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 <[email protected]>
+ *
+ * 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


2012-06-04 06:50:22

by Bryan Wu

[permalink] [raw]
Subject: Re: [PATCH v2] led: max77693: Add support for MAX77693 LED driver

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 <[email protected]> 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 <[email protected]>
> Signed-off-by: MyungJoo Ham <[email protected]>
> Signed-off-by: Kyungmin Park <[email protected]>
> ---
> 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 <[email protected]>
> + * Jonghwa Lee <[email protected]>
> + *
> + * 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 <[email protected]>");
> +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 <[email protected]>
> + *
> + * 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 <[email protected]>
Kernel Developer ? ?+86.186-168-78255 Mobile
Canonical Ltd. ? ? ?http://www.canonical.com
Ubuntu - Linux for human beings | http://www.ubuntu.com