leds-pm8xxx: Pass LED flags from board file

Instead of hard coding the flag into led driver, pass it
from board file.
While at it, re-factor the code to separate led upstream
core data with board specific data.

Signed-off-by: Jay Chokshi <jchokshi@codeaurora.org>

Conflicts:

	drivers/mfd/pm8921-core.c
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index 365121c..ae85aff 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -3896,40 +3896,41 @@
 
 #define	PM8921_LC_LED_MAX_CURRENT	4	/* I = 4mA */
 
-/**
- * 'flag' stores three values; led id, led mode, and max current of led.
- * The bit packing format is as follow,
- * reserved (1 byte) | max_current (2 bytes) | led_mode (1 nibble) |
- * led_id (1 nibble)
- */
-#define PM8XXX_SET_FLAG(led_id, led_mode, led_max_current)	\
-	(((led_id << PM8XXX_LED_ID_SHIFT) & PM8XXX_LED_ID_MASK) |\
-	((led_mode << PM8XXX_LED_MODE_SHIFT) & PM8XXX_LED_MODE_MASK) |\
-	((led_max_current << PM8XXX_LED_MAX_CURRENT_SHIFT) & \
-			PM8XXX_LED_MAX_CURRENT_MASK))
-
 static struct led_info pm8921_led_info[] = {
 	[0] = {
 		.name			= "led:usb",
 		.default_trigger	= "usb-online",
-		.flags			= PM8XXX_SET_FLAG(PM8XXX_ID_LED_0,
-						PM8XXX_LED_MODE_MANUAL,
-						PM8921_LC_LED_MAX_CURRENT),
 	},
 	[1] = {
 		.name			= "led:ac",
 		.default_trigger	= "ac-online",
-		.flags			= PM8XXX_SET_FLAG(PM8XXX_ID_LED_1,
-						PM8XXX_LED_MODE_MANUAL,
-						PM8921_LC_LED_MAX_CURRENT),
 	},
 };
 
-static struct led_platform_data pm8xxx_leds_pdata = {
+static struct led_platform_data pm8921_led_core_pdata = {
 	.num_leds = ARRAY_SIZE(pm8921_led_info),
 	.leds = pm8921_led_info,
 };
 
+static struct pm8xxx_led_config pm8921_led_configs[] = {
+	[0] = {
+		.id = PM8XXX_ID_LED_0,
+		.mode = PM8XXX_LED_MODE_MANUAL,
+		.max_current = PM8921_LC_LED_MAX_CURRENT,
+	},
+	[1] = {
+		.id = PM8XXX_ID_LED_1,
+		.mode = PM8XXX_LED_MODE_MANUAL,
+		.max_current = PM8921_LC_LED_MAX_CURRENT,
+	},
+};
+
+static struct pm8xxx_led_platform_data pm8xxx_leds_pdata = {
+		.led_core = &pm8921_led_core_pdata,
+		.configs = pm8921_led_configs,
+		.num_configs = ARRAY_SIZE(pm8921_led_configs),
+};
+
 static struct pm8921_platform_data pm8921_platform_data __devinitdata = {
 	.irq_pdata		= &pm8xxx_irq_pdata,
 	.gpio_pdata		= &pm8xxx_gpio_pdata,
diff --git a/drivers/leds/leds-pm8xxx.c b/drivers/leds/leds-pm8xxx.c
index 47ac04d..94af3ce 100644
--- a/drivers/leds/leds-pm8xxx.c
+++ b/drivers/leds/leds-pm8xxx.c
@@ -54,13 +54,6 @@
 
 #define PM8XXX_LED_OFFSET(id) ((id) - PM8XXX_ID_LED_0)
 
-#define PM8XXX_GET_LED_ID(flag) (flag & PM8XXX_LED_ID_MASK >>	\
-						PM8XXX_LED_ID_SHIFT)
-#define PM8XXX_GET_LED_MODE(flag) ((flag & PM8XXX_LED_MODE_MASK) >>	\
-						PM8XXX_LED_MODE_SHIFT)
-#define PM8XXX_GET_LED_MAX_CURRENT(flag) ((flag & PM8XXX_LED_MAX_CURRENT_MASK)\
-						>> PM8XXX_LED_MAX_CURRENT_SHIFT)
-
 /**
  * struct pm8xxx_led_data - internal led data structure
  * @led_classdev - led class device
@@ -279,30 +272,38 @@
 
 static int __devinit pm8xxx_led_probe(struct platform_device *pdev)
 {
-	const struct led_platform_data *pdata = pdev->dev.platform_data;
+	const struct pm8xxx_led_platform_data *pdata = pdev->dev.platform_data;
+	const struct led_platform_data *pcore_data;
 	struct led_info *curr_led;
 	struct pm8xxx_led_data *led, *led_dat;
-	int rc, i, led_mode;
+	struct pm8xxx_led_config *led_cfg;
+	int rc, i;
 
 	if (pdata == NULL) {
 		dev_err(&pdev->dev, "platform data not supplied\n");
 		return -EINVAL;
 	}
 
-	/* Let the last member of the list be zero to
-	 * mark the end of the list.
-	 */
-	led = kcalloc(pdata->num_leds + 1, sizeof(*led), GFP_KERNEL);
+	pcore_data = pdata->led_core;
+
+	if (pcore_data->num_leds != pdata->num_configs) {
+		dev_err(&pdev->dev, "#no. of led configs and #no. of led"
+				"entries are not equal\n");
+		return -EINVAL;
+	}
+
+	led = kcalloc(pcore_data->num_leds, sizeof(*led), GFP_KERNEL);
 	if (led == NULL) {
 		dev_err(&pdev->dev, "failed to alloc memory\n");
 		return -ENOMEM;
 	}
 
-	for (i = 0; i < pdata->num_leds; i++) {
-		curr_led	= &pdata->leds[i];
+	for (i = 0; i < pcore_data->num_leds; i++) {
+		curr_led	= &pcore_data->leds[i];
 		led_dat		= &led[i];
-		/* the flags variable is used for led-id */
-		led_dat->id     = PM8XXX_GET_LED_ID(curr_led->flags);
+		led_cfg		= &pdata->configs[i];
+
+		led_dat->id     = led_cfg->id;
 
 		if (!((led_dat->id >= PM8XXX_ID_LED_KB_LIGHT) &&
 				(led_dat->id <= PM8XXX_ID_FLASH_LED_1))) {
@@ -317,17 +318,15 @@
 		led_dat->cdev.brightness_set    = pm8xxx_led_set;
 		led_dat->cdev.brightness_get    = pm8xxx_led_get;
 		led_dat->cdev.brightness	= LED_OFF;
-		led_dat->cdev.flags		= LED_CORE_SUSPENDRESUME;
+		led_dat->cdev.flags		= curr_led->flags;
 		led_dat->dev			= &pdev->dev;
 
 		rc =  get_init_value(led_dat, &led_dat->reg);
 		if (rc < 0)
 			goto fail_id_check;
 
-		led_mode = PM8XXX_GET_LED_MODE(curr_led->flags);
-
-		rc = pm8xxx_set_led_mode_and_max_brightness(led_dat, led_mode,
-				PM8XXX_GET_LED_MAX_CURRENT(curr_led->flags));
+		rc = pm8xxx_set_led_mode_and_max_brightness(led_dat,
+					led_cfg->mode, led_cfg->max_current);
 		if (rc < 0)
 			goto fail_id_check;
 
@@ -341,7 +340,7 @@
 			goto fail_id_check;
 		}
 
-		if (led_mode != PM8XXX_LED_MODE_MANUAL)
+		if (led_cfg->mode != PM8XXX_LED_MODE_MANUAL)
 			__pm8xxx_led_work(led_dat,
 					led_dat->cdev.max_brightness);
 		else
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index fa07d6b..f05fb8e 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -529,7 +529,7 @@
 
 	if (pdata->leds_pdata) {
 		leds_cell.platform_data = pdata->leds_pdata;
-		leds_cell.pdata_size = sizeof(struct led_platform_data);
+		leds_cell.pdata_size = sizeof(struct pm8xxx_led_platform_data);
 		ret = mfd_add_devices(pmic->dev, 0, &leds_cell, 1, NULL, 0);
 		if (ret) {
 			pr_err("Failed to add leds subdevice ret=%d\n", ret);
diff --git a/include/linux/leds-pm8xxx.h b/include/linux/leds-pm8xxx.h
index 4096355..edd3c28 100644
--- a/include/linux/leds-pm8xxx.h
+++ b/include/linux/leds-pm8xxx.h
@@ -13,16 +13,10 @@
 #ifndef __LEDS_PM8XXX_H__
 #define __LEDS_PM8XXX_H__
 
+#include <linux/kernel.h>
 
 #define PM8XXX_LEDS_DEV_NAME	"pm8xxx-led"
 
-#define PM8XXX_LED_ID_SHIFT		0
-#define PM8XXX_LED_MODE_SHIFT		4
-#define PM8XXX_LED_MAX_CURRENT_SHIFT	8
-#define PM8XXX_LED_ID_MASK		0xF
-#define PM8XXX_LED_MODE_MASK		0xF0
-#define PM8XXX_LED_MAX_CURRENT_MASK	0xFFFF00
-
 /**
  * enum pm8xxx_leds - PMIC8XXX supported led ids
  * @PM8XXX_ID_LED_KB_LIGHT - keyboard backlight led
@@ -55,4 +49,30 @@
 	PM8XXX_LED_MODE_DTEST4
 };
 
+/**
+ * pm8xxx_led_config - led configuration parameters
+ * id - LED id
+ * mode - LED mode
+ * max_current - maximum current that LED can sustain
+ */
+struct pm8xxx_led_config {
+	u8	id;
+	u8	mode;
+	u16	max_current;
+};
+
+/**
+ * pm8xxx_led_platform_data - platform data for LED
+ * led_core - array of LEDs. Each datum in array contains
+ *	core data for the LED
+ * configs - array of platform configuration parameters
+ *	for each LED. It maps one-to-one with
+ *	array of LEDs
+ * num_configs - count of members of configs array
+ */
+struct pm8xxx_led_platform_data {
+	struct	led_platform_data	*led_core;
+	struct	pm8xxx_led_config	*configs;
+	u32				num_configs;
+};
 #endif /* __LEDS_PM8XXX_H__ */
diff --git a/include/linux/mfd/pm8xxx/pm8921.h b/include/linux/mfd/pm8xxx/pm8921.h
index bde5bbc..64bdab1 100644
--- a/include/linux/mfd/pm8xxx/pm8921.h
+++ b/include/linux/mfd/pm8xxx/pm8921.h
@@ -33,7 +33,7 @@
 #include <linux/mfd/pm8xxx/pm8921-charger.h>
 #include <linux/mfd/pm8xxx/pm8921-adc.h>
 #include <linux/mfd/pm8xxx/pm8921-bms.h>
-#include <linux/leds.h>
+#include <linux/leds-pm8xxx.h>
 #include <linux/mfd/pm8xxx/vibrator.h>
 
 #define PM8921_NR_IRQS		256
@@ -126,7 +126,7 @@
 	struct pm8921_regulator_platform_data	*regulator_pdatas;
 	int					num_regulators;
 	struct pm8921_adc_platform_data		*adc_pdata;
-	struct led_platform_data		*leds_pdata;
+	struct pm8xxx_led_platform_data		*leds_pdata;
 	struct pm8xxx_vibrator_platform_data	*vibrator_pdata;
 };