msm: 8064: Configure SX1509 gpio expander chip

On MPQ variants of 8064, the gpio expander chip SX1509
is used via i2c bus to provid various functionalities such
as voltage regulators, AVC tuners, external keyboard, etc.

Add the platform data for the available expander chips,
initialize them, and enable the i2c bus.

While at it, fix the EPM expander values.

Change-Id: Id9efbfcde10515b24143e2b0d6978ff5a0794cac
Signed-off-by: Jay Chokshi <jchokshi@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 7b8e7c1..73b2e54 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -32,6 +32,7 @@
 #include <linux/i2c/isa1200.h>
 #include <linux/gpio_keys.h>
 #include <linux/epm_adc.h>
+#include <linux/i2c/sx150x.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/hardware/gic.h>
@@ -97,14 +98,6 @@
 #define MSM_ION_HEAP_NUM	1
 #endif
 
-#define GPIO_EXPANDER_IRQ_BASE	(PM8821_IRQ_BASE + PM8821_NR_IRQS)
-#define GPIO_EXPANDER_GPIO_BASE	(PM8821_MPP_BASE + PM8821_NR_MPPS)
-#define GPIO_EPM_EXPANDER_BASE	GPIO_EXPANDER_GPIO_BASE
-
-enum {
-	SX150X_EPM,
-};
-
 #ifdef CONFIG_KERNEL_PMEM_EBI_REGION
 static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
 static int __init pmem_kernel_ebi1_size_setup(char *p)
@@ -2205,6 +2198,9 @@
 #define I2C_RUMI (1 << 2)
 #define I2C_SIM  (1 << 3)
 #define I2C_LIQUID (1 << 4)
+#define I2C_MPQ_CDP	BIT(5)
+#define I2C_MPQ_HRD	BIT(6)
+#define I2C_MPQ_DTV	BIT(7)
 
 struct i2c_registry {
 	u8                     machs;
@@ -2240,6 +2236,75 @@
 	},
 };
 
+struct sx150x_platform_data mpq8064_sx150x_pdata[] = {
+	[SX150X_EXP1] = {
+		.gpio_base	= SX150X_EXP1_GPIO_BASE,
+		.oscio_is_gpo	= false,
+		.io_pullup_ena	= 0x0,
+		.io_pulldn_ena	= 0x0,
+		.io_open_drain_ena = 0x0,
+		.io_polarity	= 0,
+		.irq_summary	= -1,
+	},
+	[SX150X_EXP2] = {
+		.gpio_base	= SX150X_EXP2_GPIO_BASE,
+		.oscio_is_gpo	= false,
+		.io_pullup_ena	= 0x0,
+		.io_pulldn_ena	= 0x0,
+		.io_open_drain_ena = 0x0,
+		.io_polarity	= 0,
+		.irq_summary	= -1,
+	},
+	[SX150X_EXP3] = {
+		.gpio_base	= SX150X_EXP3_GPIO_BASE,
+		.oscio_is_gpo	= false,
+		.io_pullup_ena	= 0x0,
+		.io_pulldn_ena	= 0x0,
+		.io_open_drain_ena = 0x0,
+		.io_polarity	= 0,
+		.irq_summary	= -1,
+	},
+	[SX150X_EXP4] = {
+		.gpio_base	= SX150X_EXP4_GPIO_BASE,
+		.oscio_is_gpo	= false,
+		.io_pullup_ena	= 0x0,
+		.io_pulldn_ena	= 0x0,
+		.io_open_drain_ena = 0x0,
+		.io_polarity	= 0,
+		.irq_summary	= -1,
+	},
+};
+
+static struct i2c_board_info sx150x_gpio_exp_info[] = {
+	{
+		I2C_BOARD_INFO("sx1509q", 0x70),
+		.platform_data = &mpq8064_sx150x_pdata[SX150X_EXP1],
+	},
+	{
+		I2C_BOARD_INFO("sx1508q", 0x23),
+		.platform_data = &mpq8064_sx150x_pdata[SX150X_EXP2],
+	},
+	{
+		I2C_BOARD_INFO("sx1508q", 0x22),
+		.platform_data = &mpq8064_sx150x_pdata[SX150X_EXP3],
+	},
+	{
+		I2C_BOARD_INFO("sx1509q", 0x3E),
+		.platform_data = &mpq8064_sx150x_pdata[SX150X_EXP4],
+	},
+};
+
+#define MPQ8064_I2C_GSBI5_BUS_ID	5
+
+static struct i2c_registry mpq8064_i2c_devices[] __initdata = {
+	{
+		I2C_MPQ_CDP,
+		MPQ8064_I2C_GSBI5_BUS_ID,
+		sx150x_gpio_exp_info,
+		ARRAY_SIZE(sx150x_gpio_exp_info),
+	},
+};
+
 static void __init register_i2c_devices(void)
 {
 	u8 mach_mask = 0;
@@ -2264,6 +2329,8 @@
 		mach_mask = I2C_RUMI;
 	else if (machine_is_apq8064_sim())
 		mach_mask = I2C_SIM;
+	else if (PLATFORM_IS_MPQ8064())
+		mach_mask = I2C_MPQ_CDP;
 	else
 		pr_err("unmatched machine ID in register_i2c_devices\n");
 
@@ -2280,6 +2347,14 @@
 			apq8064_camera_i2c_devices.info,
 			apq8064_camera_i2c_devices.len);
 #endif
+
+	for (i = 0; i < ARRAY_SIZE(mpq8064_i2c_devices); ++i) {
+		if (mpq8064_i2c_devices[i].machs & mach_mask)
+			i2c_register_board_info(
+					mpq8064_i2c_devices[i].bus,
+					mpq8064_i2c_devices[i].info,
+					mpq8064_i2c_devices[i].len);
+	}
 }
 
 static void enable_ddr3_regulator(void)
@@ -2296,6 +2371,19 @@
 	}
 }
 
+static void enable_avc_i2c_bus(void)
+{
+	int avc_i2c_en_mpp = PM8921_MPP_PM_TO_SYS(8);
+	int rc;
+
+	rc = gpio_request(avc_i2c_en_mpp, "avc_i2c_en");
+	if (rc)
+		pr_err("request for avc_i2c_en mpp failed,"
+						 "rc=%d\n", rc);
+	else
+		gpio_set_value_cansleep(avc_i2c_en_mpp, 1);
+}
+
 static void __init apq8064_common_init(void)
 {
 	msm_tsens_early_init(&apq_tsens_pdata);
@@ -2380,6 +2468,7 @@
 	apq8064_common_init();
 	if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
 		machine_is_mpq8064_dtv()) {
+		enable_avc_i2c_bus();
 		platform_add_devices(mpq_devices, ARRAY_SIZE(mpq_devices));
 	} else {
 		ethernet_init();
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 23ca39f..d1cc31e 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -81,4 +81,54 @@
 void apq8064_init_gpu(void);
 void apq8064_pm8xxx_gpio_mpp_init(void);
 
+#define PLATFORM_IS_MPQ8064() \
+	(machine_is_mpq8064_hrd() || \
+	 machine_is_mpq8064_dtv() || \
+	 machine_is_mpq8064_cdp() \
+	)
+
+
+#define GPIO_EXPANDER_IRQ_BASE	(TABLA_INTERRUPT_BASE + \
+					NR_TABLA_IRQS)
+#define GPIO_EXPANDER_GPIO_BASE	(PM8821_MPP_BASE + PM8821_NR_MPPS)
+
+#define GPIO_EPM_EXPANDER_BASE	GPIO_EXPANDER_GPIO_BASE
+#define SX150X_EPM_NR_GPIOS	16
+#define SX150X_EPM_NR_IRQS	8
+
+#define SX150X_EXP1_GPIO_BASE	(GPIO_EPM_EXPANDER_BASE + \
+					SX150X_EPM_NR_GPIOS)
+#define SX150X_EXP1_IRQ_BASE	(GPIO_EXPANDER_IRQ_BASE + \
+				SX150X_EPM_NR_IRQS)
+#define SX150X_EXP1_NR_IRQS	16
+#define SX150X_EXP1_NR_GPIOS	16
+
+#define SX150X_EXP2_GPIO_BASE	(SX150X_EXP1_GPIO_BASE + \
+					SX150X_EXP1_NR_GPIOS)
+#define SX150X_EXP2_IRQ_BASE	(SX150X_EXP1_IRQ_BASE + SX150X_EXP1_NR_IRQS)
+#define SX150X_EXP2_NR_IRQS	8
+#define SX150X_EXP2_NR_GPIOS	8
+
+#define SX150X_EXP3_GPIO_BASE	(SX150X_EXP2_GPIO_BASE + \
+					SX150X_EXP2_NR_GPIOS)
+#define SX150X_EXP3_IRQ_BASE	(SX150X_EXP2_IRQ_BASE + SX150X_EXP2_NR_IRQS)
+#define SX150X_EXP3_NR_IRQS	8
+#define SX150X_EXP3_NR_GPIOS	8
+
+#define SX150X_EXP4_GPIO_BASE	(SX150X_EXP3_GPIO_BASE + \
+					SX150X_EXP3_NR_GPIOS)
+#define SX150X_EXP4_IRQ_BASE	(SX150X_EXP3_IRQ_BASE + SX150X_EXP3_NR_IRQS)
+#define SX150X_EXP4_NR_IRQS	16
+#define SX150X_EXP4_NR_GPIOS	16
+
+#define SX150X_GPIO(_expander, _pin) (SX150X_EXP##_expander##_GPIO_BASE + _pin)
+
+enum {
+	SX150X_EPM,
+	SX150X_EXP1,
+	SX150X_EXP2,
+	SX150X_EXP3,
+	SX150X_EXP4,
+};
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h
index 5385f35..0492e65 100644
--- a/arch/arm/mach-msm/include/mach/gpio.h
+++ b/arch/arm/mach-msm/include/mach/gpio.h
@@ -16,9 +16,7 @@
 #ifndef __ASM_ARCH_MSM_GPIO_H
 #define __ASM_ARCH_MSM_GPIO_H
 
-#ifdef CONFIG_ARCH_MSM8X60
 #define ARCH_NR_GPIOS 512
-#endif
 
 #include <linux/interrupt.h>
 #include <asm-generic/gpio.h>
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index dcbabfa..ff011a8 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -44,7 +44,7 @@
 #define NR_PM8821_IRQS 64
 #define NR_WCD9XXX_IRQS 49
 #define NR_TABLA_IRQS NR_WCD9XXX_IRQS
-#define NR_GPIO_EXPANDER_IRQS 16
+#define NR_GPIO_EXPANDER_IRQS 64
 #define NR_BOARD_IRQS (NR_PM8921_IRQS + NR_PM8821_IRQS + \
 		NR_WCD9XXX_IRQS + NR_GPIO_EXPANDER_IRQS)
 #define NR_TLMM_MSM_DIR_CONN_IRQ 8 /*Need to Verify this Count*/