kernel/prism: initial support for GFLT300

Color FiberJack (cFJ) is the new FiberJack being developed for the
Go-Long project. It is based on the GFLT110 SoC (Marvell 88F6601).

Change-Id: Id3ca9ec996ad377f5ba1857b79e3959ff8f647f4
diff --git a/arch/arm/configs/gflt110_defconfig b/arch/arm/configs/gflt110_defconfig
index cef0917..25bc9ca 100644
--- a/arch/arm/configs/gflt110_defconfig
+++ b/arch/arm/configs/gflt110_defconfig
@@ -1136,7 +1136,7 @@
 CONFIG_ARCH_REQUIRE_GPIOLIB=y
 CONFIG_GPIOLIB=y
 # CONFIG_DEBUG_GPIO is not set
-# CONFIG_GPIO_SYSFS is not set
+CONFIG_GPIO_SYSFS=y
 
 #
 # Memory mapped GPIO expanders:
diff --git a/arch/arm/mach-feroceon-kw2/Makefile b/arch/arm/mach-feroceon-kw2/Makefile
index bf5e8a9..3fecf47 100755
--- a/arch/arm/mach-feroceon-kw2/Makefile
+++ b/arch/arm/mach-feroceon-kw2/Makefile
@@ -243,6 +243,6 @@
 feroceon-$(CONFIG_THERMAL_SENSOR_KW2)	+= hwmon.o
 
 # Board
+obj-y += fiberjack.o
 obj-$(CONFIG_MACH_GFLT200)		+= board-gflt200.o
 obj-$(CONFIG_MACH_GFLT110)		+= board-gflt110.o
-
diff --git a/arch/arm/mach-feroceon-kw2/board-gflt110.c b/arch/arm/mach-feroceon-kw2/board-gflt110.c
index 5341efb..6d701dc 100644
--- a/arch/arm/mach-feroceon-kw2/board-gflt110.c
+++ b/arch/arm/mach-feroceon-kw2/board-gflt110.c
@@ -1,4 +1,5 @@
 #include <boardEnv/mvBoardEnvLib.h>
+#include <fiberjack.h>
 #include <gpp/mvGpp.h>
 #include <linux/device.h>
 #include <linux/err.h>
@@ -10,7 +11,7 @@
 #include <linux/platform_device.h>
 #include <linux/sysfs.h>
 
-#define BOARD_NAME		"gflt110"
+#define GPIO_PON_PWR_EN		37
 
 struct gflt_led_data {
 	unsigned gpio;
@@ -18,6 +19,56 @@
 	struct led_classdev cdev;
 };
 
+struct board_gpio {
+	unsigned	gpio;
+	const char	*label;
+};
+
+static struct board_gpio board_gpios[] = {
+	{
+		.gpio = GPIO_PON_PWR_EN,
+		.label = "power-enable",
+	},
+};
+
+static int board_gpio_export(struct board_gpio *gpio, struct device *dev)
+{
+	int rc;
+
+	rc = gpio_request(gpio->gpio, gpio->label);
+	if (rc) {
+		pr_err("%s: error %d requesting gpio %u (%s)\n",
+			get_model_name(), rc, gpio->gpio, gpio->label);
+		goto exit;
+	}
+
+	/* this is needed to set gpiolib's out flag for the gpio */
+	rc = gpio_direction_output(gpio->gpio, gpio_get_value(gpio->gpio));
+	if (rc) {
+		pr_err("%s: error %d setting gpio %u (%s) direction\n",
+			get_model_name(), rc, gpio->gpio, gpio->label);
+		goto exit;
+	}
+
+	rc = gpio_export(gpio->gpio, false);
+	if (rc) {
+		pr_err("%s: error %d exporting gpio %u (%s)\n",
+			get_model_name(), rc, gpio->gpio, gpio->label);
+		goto exit;
+	}
+
+	rc = gpio_export_link(dev, gpio->label, gpio->gpio);
+	if (rc) {
+		pr_err("%s: error %d linking gpio %u (%s)\n",
+			get_model_name(), rc, gpio->gpio, gpio->label);
+		goto exit;
+	}
+
+	rc = 0;
+exit:
+	return rc;
+}
+
 static ssize_t board_hw_ver_show(struct device *dev,
 				 struct device_attribute *attr,
 				 char *buf)
@@ -110,33 +161,47 @@
 
 int __init board_init(void)
 {
+	int i;
 	int rc;
 	struct platform_device *pdev;
 
+	printk("Detected board type: %s\n", get_model_name());
+
 	/* /sys/devices/platform/<board_name> */
-	pdev = platform_device_register_simple(BOARD_NAME, -1, NULL, 0);
+	pdev = platform_device_register_simple(get_model_name(), -1, NULL, 0);
 	if (IS_ERR(pdev)) {
 		rc = PTR_ERR(pdev);
-		pr_err(BOARD_NAME ": error %d registering device\n", rc);
+		pr_err("%s: error %d registering device\n",
+			get_model_name(), rc);
 		return rc;
 	}
 
 	/* /sys/devices/platform/board -> /sys/devices/platform/<board_name> */
 	rc = sysfs_create_link(&pdev->dev.parent->kobj, &pdev->dev.kobj,
-			       "board");
-	if (rc)
-		pr_err(BOARD_NAME ": error %d creating link 'board'\n", rc);
+				"board");
+	if (rc) {
+		pr_err("%s: error %d creating link 'board'\n",
+			get_model_name(), rc);
+	}
 
 	/* /sys/devices/platform/board/hw_ver */
 	rc = device_create_file(&pdev->dev, &dev_attr_hw_ver);
-	if (rc)
-		pr_err(BOARD_NAME ": error %d creating attribute 'hw_ver'\n",
-			rc);
+	if (rc) {
+		pr_err("%s: error %d creating attribute 'hw_ver'\n",
+			get_model_name(), rc);
+	}
+
+	if (is_gflt300() == 1) {
+		/* /sys/devices/platform/board/<gpio_name> */
+		for (i = 0; i < ARRAY_SIZE(board_gpios); i++)
+			board_gpio_export(&board_gpios[i], &pdev->dev);
+	}
 
 	rc = register_gfltleds(pdev, board_gpio_leds, ARRAY_SIZE(board_gpio_leds));
-	if (rc)
-		pr_err(BOARD_NAME ": error %d registering GFLT LED device\n",
-			rc);
+	if (rc) {
+		pr_err("%s: error %d registering GFLT LED device\n",
+			get_model_name(), rc);
+	}
 
 	return 0;
 }
diff --git a/arch/arm/mach-feroceon-kw2/fiberjack.c b/arch/arm/mach-feroceon-kw2/fiberjack.c
new file mode 100644
index 0000000..21d4823
--- /dev/null
+++ b/arch/arm/mach-feroceon-kw2/fiberjack.c
@@ -0,0 +1,23 @@
+#include <linux/init.h>
+#include <linux/string.h>
+#include "fiberjack.h"
+
+const char* get_model_name(void) {
+  if (strstr(boot_command_line, "model=gflt300") != NULL)
+    return "gflt300";
+  else if (strstr(boot_command_line, "model=gflt110") != NULL)
+    return "gflt110";
+  else
+    /* If we can't find a match, assume the default which is GFLT110 */
+    return "gflt110";
+}
+
+int parse_model_from_cmdline(const char* model) {
+  if (strstr(boot_command_line, model) != NULL)
+    return 1;
+  return 0;
+}
+
+int is_gflt300(void) {
+  return parse_model_from_cmdline("gflt300");
+}
diff --git a/arch/arm/mach-feroceon-kw2/fiberjack.h b/arch/arm/mach-feroceon-kw2/fiberjack.h
new file mode 100644
index 0000000..ccf89f3
--- /dev/null
+++ b/arch/arm/mach-feroceon-kw2/fiberjack.h
@@ -0,0 +1,6 @@
+#ifndef _FEROCEON_FIBERJACK_H_
+#define _FEROCEON_FIBERJACK_H_
+int is_gflt300(void);
+int parse_model_from_cmdline(char const* model);
+const char* get_model_name(void);
+#endif  /* _FEROCEON_FIBERJACK_H_ */
diff --git a/arch/arm/mach-feroceon-kw2/kw2_family/boardEnv/mvBoardEnvSpec.c b/arch/arm/mach-feroceon-kw2/kw2_family/boardEnv/mvBoardEnvSpec.c
index dbcdded..dc7e9e3 100755
--- a/arch/arm/mach-feroceon-kw2/kw2_family/boardEnv/mvBoardEnvSpec.c
+++ b/arch/arm/mach-feroceon-kw2/kw2_family/boardEnv/mvBoardEnvSpec.c
@@ -61,6 +61,7 @@
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 *******************************************************************************/
+#include "fiberjack.h"
 #include "mvCommon.h"
 #include "mvBoardEnvLib.h"
 #include "mvBoardEnvSpec.h"
@@ -1501,6 +1502,18 @@
 	{BOARD_GPP_PON_XVR_TX_IND, 24},
 };
 
+/* TODO(cgibson): For GFLT200, these are set to:
+     {BOARD_GPP_PON_XVR_TX, 21, 1},
+     {BOARD_GPP_PON_XVR_TX_POWER, 37, 0},
+   Which is correct?
+*/
+MV_BOARD_GPP_INFO gflt300InfoBoardGppInfo[] = {
+	/* {{MV_BOARD_GPP_CLASS devClass, MV_U8 gppPinNum}} */
+	{BOARD_GPP_PON_XVR_TX, 17},
+	{BOARD_GPP_PON_XVR_TX_POWER, 11},
+	{BOARD_GPP_PON_XVR_TX_IND, 24},
+};
+
 MV_DEV_CS_INFO gflt110InfoBoardDeCsInfo[] = {
 	/*{deviceCS, params, devType, devWidth} */
 #ifdef MV_SPI
@@ -1522,25 +1535,44 @@
 	 }
 };
 
-/*
-MV_BOARD_SPEC_INIT gflt110BoardSpecInit[] = {
-	{
-		.reg = PMU_POWER_IF_POLARITY_REG,
-		.mask = (BIT1),
-		.val = 0
-	},
-	{
-		.reg = TBL_TERM,
-		.val = TBL_TERM
-	}
+MV_BOARD_MPP_INFO gflt300InfoBoardMppConfigValue[] = {
+	{{
+	  GFLT300_MPP0_7,
+	  GFLT300_MPP8_15,
+	  GFLT300_MPP16_23,
+	  GFLT300_MPP24_31,
+	  GFLT300_MPP32_37
+	  }
+	 }
 };
-*/
+
+static MV_VOID gfltBoardInit(MV_BOARD_INFO *pBoardInfo)
+{
+	if (is_gflt300() == 1) {
+		pBoardInfo->numBoardGppInfo = MV_ARRAY_SIZE(
+				gflt300InfoBoardGppInfo);
+		pBoardInfo->pBoardGppInfo = gflt300InfoBoardGppInfo;
+		pBoardInfo->numBoardMppConfigValue = MV_ARRAY_SIZE(
+				gflt300InfoBoardMppConfigValue);
+		pBoardInfo->pBoardMppConfigValue =
+				gflt300InfoBoardMppConfigValue;
+		pBoardInfo->gppOutEnValLow = GFLT300_GPP_OUT_ENA_LOW;
+	} else {
+		pBoardInfo->numBoardGppInfo = MV_ARRAY_SIZE(
+				gflt110InfoBoardGppInfo);
+		pBoardInfo->pBoardGppInfo = gflt110InfoBoardGppInfo;
+		pBoardInfo->numBoardMppConfigValue = MV_ARRAY_SIZE(
+				gflt110InfoBoardMppConfigValue);
+		pBoardInfo->pBoardMppConfigValue =
+				gflt110InfoBoardMppConfigValue;
+		pBoardInfo->gppOutEnValLow = GFLT110_GPP_OUT_ENA_LOW;
+	}
+}
+
 MV_BOARD_INFO gflt110Info = {
 	.boardName = "GFLT110",
-	.numBoardMppTypeValue = MV_ARRAY_SIZE(gflt110InfoBoardMppTypeInfo),
+	.pBoardInit = gfltBoardInit,
 	.pBoardMppTypeValue = gflt110InfoBoardMppTypeInfo,
-	.numBoardMppConfigValue = MV_ARRAY_SIZE(gflt110InfoBoardMppConfigValue),
-	.pBoardMppConfigValue = gflt110InfoBoardMppConfigValue,
 	.intsGppMaskLow = 0,
 	.intsGppMaskMid = 0,
 	.intsGppMaskHigh = 0,
@@ -1550,14 +1582,11 @@
 	.pBoardTwsiDev = gflt110InfoBoardTwsiDev,
 	.numBoardMacInfo = MV_ARRAY_SIZE(gflt110InfoBoardMacInfo),
 	.pBoardMacInfo = gflt110InfoBoardMacInfo,
-	.numBoardGppInfo = MV_ARRAY_SIZE(gflt110InfoBoardGppInfo),
-	.pBoardGppInfo = gflt110InfoBoardGppInfo,
 	.activeLedsNumber = 0,
 	.pLedGppPin = NULL,
 	.ledsPolarity = 0,
 
 	/* GPP values */
-	.gppOutEnValLow = GFLT110_GPP_OUT_ENA_LOW,
 	.gppOutEnValMid = GFLT110_GPP_OUT_ENA_MID,
 	.gppOutEnValHigh = 0,
 	.gppOutValLow = GFLT110_GPP_OUT_VAL_LOW,
diff --git a/arch/arm/mach-feroceon-kw2/kw2_family/boardEnv/mvBoardEnvSpec.h b/arch/arm/mach-feroceon-kw2/kw2_family/boardEnv/mvBoardEnvSpec.h
index 63e910b..64a804b 100755
--- a/arch/arm/mach-feroceon-kw2/kw2_family/boardEnv/mvBoardEnvSpec.h
+++ b/arch/arm/mach-feroceon-kw2/kw2_family/boardEnv/mvBoardEnvSpec.h
@@ -538,14 +538,21 @@
 #define GFLT200_EVT2_GPP_POL_MID	0x0
 
 /***************************************************************************
-** GFLT110
+** GFLT110 & GFLT300
 ****************************************************************************/
-#define GFLT110_MPP0_7		0x22222220
-#define GFLT110_MPP8_15		0x00000002
+#define GFLT110_MPP0_7			0x22222220
+#define GFLT110_MPP8_15			0x00000002
 #define GFLT110_MPP16_23		0x00400000
 #define GFLT110_MPP24_31		0x00200550
 #define GFLT110_MPP32_37		0x00000000
 
+/* GFLT300 */
+#define GFLT300_MPP0_7			0x22222220
+#define GFLT300_MPP8_15			0x00000002
+#define GFLT300_MPP16_23		0x00000000
+#define GFLT300_MPP24_31		0x40200504
+#define GFLT300_MPP32_37		0x00000004
+
 /* GPPs
  1 SPI0_MOSI (out)
  2 SPI0_SCK (out)
@@ -566,17 +573,21 @@
 37 TX_PD
 */
 
-#define GFLT110_GPP_OUT_ENA_LOW	(BIT0 | BIT14 | BIT16 | BIT17 | BIT18 | BIT19 | BIT22 | BIT23 | BIT24 | BIT27| BIT30 | BIT31)
-#define GFLT110_GPP_OUT_ENA_MID	(BIT0 | BIT3 | BIT4)
+#define GFLT110_GPP_OUT_ENA_LOW		(BIT0 | BIT14 | BIT16 | BIT17 | BIT18 | BIT19 | BIT22 | BIT23 | BIT24 | BIT27| BIT30 | BIT31)
+
+#define GFLT110_GPP_OUT_ENA_MID		(BIT0 | BIT3 | BIT4)
 
 // BIT12 turns the LED blue.
 // BIT13 turns the LED red.
-#define GFLT110_GPP_OUT_VAL_LOW	BIT13
-#define GFLT110_GPP_OUT_VAL_MID	0x0
+#define GFLT110_GPP_OUT_VAL_LOW		BIT13
+#define GFLT110_GPP_OUT_VAL_MID		0x0
 
 #define GFLT110_GPP_POL_LOW		(BIT23)
 #define GFLT110_GPP_POL_MID		0x0
 
+/* GFLT300 */
+#define GFLT300_GPP_OUT_ENA_LOW	(BIT0 | BIT14 | BIT16 | BIT17 | BIT19 | BIT22 | BIT23 | BIT24 | BIT27| BIT30 | BIT31)
+
 /***************************************************************************
 ** RD-88F6601MC2L
 ****************************************************************************/