[PATCH] introduce-om-gta03-features.patch

Andy Green andy at openmoko.com
Thu Nov 20 23:30:46 CET 2008


This patch adds a single file that is intended to do the job of
the several neo1973_pm_* drivers used in GTA02.  It exposes the
/sys nodes

/sys/bus/platform/devices/om-gta03.0/gps_power
/sys/bus/platform/devices/om-gta03.0/gsm_power
/sys/bus/platform/devices/om-gta03.0/usbhost_power
/sys/bus/platform/devices/om-gta03.0/wlan_bt_power

at the moment which allow power control of these subsystems.

Signed-off-by: Andy Green <andy at openmoko.com>
---

 arch/arm/mach-s3c6410/Makefile                |    3 
 arch/arm/mach-s3c6410/include/mach/om-gta03.h |    8 -
 arch/arm/mach-s3c6410/mach-om-gta03.c         |   28 +-
 arch/arm/mach-s3c6410/om-gta03-features.c     |  304 +++++++++++++++++++++++++
 arch/arm/plat-s3c24xx/neo1973_pm_gps.c        |   10 -
 drivers/misc/Makefile                         |    1 
 6 files changed, 335 insertions(+), 19 deletions(-)
 create mode 100644 arch/arm/mach-s3c6410/om-gta03-features.c

diff --git a/arch/arm/mach-s3c6410/Makefile b/arch/arm/mach-s3c6410/Makefile
index 0159ea2..e9f30d4 100644
--- a/arch/arm/mach-s3c6410/Makefile
+++ b/arch/arm/mach-s3c6410/Makefile
@@ -21,5 +21,6 @@ obj-$(CONFIG_S3C6410_SETUP_SDHCI)	+= setup-sdhci.o
 # machine support
 
 obj-$(CONFIG_MACH_SMDK6410)	+= mach-smdk6410.o
-obj-$(CONFIG_MACH_OPENMOKO_GTA03)	+= mach-om-gta03.o
+obj-$(CONFIG_MACH_OPENMOKO_GTA03)	+= mach-om-gta03.o \
+					   om-gta03-features.o
 
diff --git a/arch/arm/mach-s3c6410/include/mach/om-gta03.h b/arch/arm/mach-s3c6410/include/mach/om-gta03.h
index c05e014..17a07dd 100644
--- a/arch/arm/mach-s3c6410/include/mach/om-gta03.h
+++ b/arch/arm/mach-s3c6410/include/mach/om-gta03.h
@@ -16,6 +16,9 @@
 
 #include <mach/gpio.h>
 #include <mach/irqs.h>
+#include <linux/mfd/pcf50633/core.h>
+
+extern struct pcf50633_platform_data om_gta03_pcf_pdata;
 
 /* ATAG_REVISION from bootloader */
 #define GTA03v1_SYSTEM_REV	0x00000001
@@ -41,11 +44,10 @@
 #define GTA03_GPIO_WLAN_RESET		S3C64XX_GPH(6)
 #define GTA03_GPIO_HDQ			S3C64XX_GPH(7)
 #define GTA03_GPIO_WLAN_PWRDN		S3C64XX_GPH(8)
-#define GTA03_GPIO_WLAN_OSC		S3C64XX_GPH(9)
 
-#define GTA03_GPIO_VERSION0		S3C64XX_GPI(0)
+#define GTA03_GPIO_VERSION2		S3C64XX_GPI(0)
 #define GTA03_GPIO_VERSION1		S3C64XX_GPI(1)
-#define GTA03_GPIO_VERSION2		S3C64XX_GPI(8)
+#define GTA03_GPIO_VERSION0		S3C64XX_GPI(8)
 
 #define GTA03_GPIO_NWLAN_POWER		S3C64XX_GPK(0)
 #define GTA03_GPIO_MODEN_ON		S3C64XX_GPK(2)
diff --git a/arch/arm/mach-s3c6410/mach-om-gta03.c b/arch/arm/mach-s3c6410/mach-om-gta03.c
index 8ff5082..80543d3 100644
--- a/arch/arm/mach-s3c6410/mach-om-gta03.c
+++ b/arch/arm/mach-s3c6410/mach-om-gta03.c
@@ -224,14 +224,18 @@ static struct regulator_consumer_supply ldo4_consumers[] = {
 		.supply = "SD_3V",
 	},
 };
-#if 0
+
+static struct platform_device om_gta03_features_dev = {
+	.name		= "om-gta03",
+};
+
 static struct regulator_consumer_supply ldo5_consumers[] = {
 	{
-		.dev = &gta01_pm_gps_dev.dev,
+		.dev = &om_gta03_features_dev.dev,
 		.supply = "RF_3V",
 	},
 };
-#endif
+
 
 static void om_gta03_pmu_event_callback(struct pcf50633 *pcf, int irq)
 {
@@ -361,8 +365,8 @@ struct pcf50633_platform_data om_gta03_pcf_pdata = {
 				.valid_modes_mask = REGULATOR_MODE_NORMAL,
 				.apply_uV = 1,
 			},
-			.num_consumer_supplies = 0,
-/*			.consumer_supplies = ldo5_consumers, */
+			.num_consumer_supplies = 1,
+			.consumer_supplies = ldo5_consumers,
 		},
 		/* GTA03: LCM 3V */
 		[PCF50633_REGULATOR_LDO6] = {
@@ -411,6 +415,7 @@ static struct platform_device *om_gta03_devices[] __initdata = {
 	&s3c_device_hsmmc1, /* SDIO to WLAN */
 };
 
+
 static void om_gta03_pmu_regulator_registered(struct pcf50633 *pcf, int id)
 {
 	struct platform_device *regulator, *pdev;
@@ -434,6 +439,7 @@ static void om_gta03_pmu_regulator_registered(struct pcf50633 *pcf, int id)
 
 static struct platform_device *om_gta03_devices_pmu_children[] = {
 	&om_gta03_button_dev,
+	&om_gta03_features_dev,
 };
 
 /* this is called when pc50633 is probed, unfortunately quite late in the
@@ -504,12 +510,12 @@ static void __init om_gta03_machine_init(void)
 
 	s3c_gpio_setpull(S3C64XX_GPJ(8), S3C_GPIO_PULL_NONE);
 	s3c_gpio_cfgpin(S3C64XX_GPJ(8), S3C_GPIO_SFN(2));
-	s3c_gpio_setpull(S3C64XX_GPK(9), S3C_GPIO_PULL_NONE);
-	s3c_gpio_cfgpin(S3C64XX_GPK(9), S3C_GPIO_SFN(1));
-	s3c_gpio_setpull(S3C64XX_GPK(10), S3C_GPIO_PULL_NONE);
-	s3c_gpio_cfgpin(S3C64XX_GPK(10), S3C_GPIO_SFN(1));
-	s3c_gpio_setpull(S3C64XX_GPK(11), S3C_GPIO_PULL_NONE);
-	s3c_gpio_cfgpin(S3C64XX_GPK(11), S3C_GPIO_SFN(1));
+	s3c_gpio_setpull(S3C64XX_GPJ(9), S3C_GPIO_PULL_NONE);
+	s3c_gpio_cfgpin(S3C64XX_GPJ(9), S3C_GPIO_SFN(2));
+	s3c_gpio_setpull(S3C64XX_GPJ(10), S3C_GPIO_PULL_NONE);
+	s3c_gpio_cfgpin(S3C64XX_GPJ(10), S3C_GPIO_SFN(2));
+	s3c_gpio_setpull(S3C64XX_GPJ(11), S3C_GPIO_PULL_NONE);
+	s3c_gpio_cfgpin(S3C64XX_GPJ(11), S3C_GPIO_SFN(2));
 
 
 	i2c_register_board_info(0, om_gta03_i2c_devs,
diff --git a/arch/arm/mach-s3c6410/om-gta03-features.c b/arch/arm/mach-s3c6410/om-gta03-features.c
new file mode 100644
index 0000000..612d705
--- /dev/null
+++ b/arch/arm/mach-s3c6410/om-gta03-features.c
@@ -0,0 +1,304 @@
+/*
+ * Support for features of Openmoko GTA03
+ *
+ * (C) 2008 by Openmoko Inc.
+ * Author: Andy Green <andy at openmoko.com>
+ * All rights reserved.
+ *
+ * Somewhat based on the GTA01 / 02 neo1973_pm_ stuff mainly by Harald Welte
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#include <mach/hardware.h>
+#include <mach/om-gta03.h>
+#include <asm/mach-types.h>
+
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/pcf50633/core.h>
+
+#include <plat/gpio-cfg.h>
+
+struct om_gta03_features_data {
+	int gps_power_was_on;
+	struct regulator *gps_regulator;
+
+	int wlan_bt_power_was_on;
+
+	int gsm_power_was_on;
+
+	int usbhost_power_was_on;
+
+};
+
+static struct om_gta03_features_data om_gta03_features;
+
+/* GPS power */
+
+static void om_gta03_gps_pwron_set(int on)
+{
+	if ((on) && (!om_gta03_features.gps_power_was_on)) {
+		regulator_enable(om_gta03_features.gps_regulator);
+		/* enable LNA */
+		gpio_direction_output(GTA03_GPIO_GPS_LNA_EN, 1);
+	}
+
+	if ((!on) && (om_gta03_features.gps_power_was_on)) {
+		/* disable LNA */
+		gpio_direction_output(GTA03_GPIO_GPS_LNA_EN, 0);
+		regulator_disable(om_gta03_features.gps_regulator);
+	}
+}
+
+static ssize_t om_gta03_gps_power_read(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	if (regulator_is_enabled(om_gta03_features.gps_regulator))
+		return strlcpy(buf, "1\n", 3);
+	else
+		return strlcpy(buf, "0\n", 3);
+}
+
+static ssize_t om_gta03_gps_power_write(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int on = !!simple_strtoul(buf, NULL, 10);
+
+	om_gta03_gps_pwron_set(on);
+	om_gta03_features.gps_power_was_on = on;
+
+	return count;
+}
+
+static DEVICE_ATTR(gps_power, 0644, om_gta03_gps_power_read,
+						      om_gta03_gps_power_write);
+
+/* WLAN / BT power */
+
+static void om_gta03_wlan_bt_pwron_set(int on)
+{
+	if (!on) {
+		/* remove power from WLAN / BT module */
+		gpio_direction_output(GTA03_GPIO_NWLAN_POWER, 1);
+		s3c_gpio_setpull(GTA03_GPIO_NWLAN_POWER, S3C_GPIO_PULL_NONE);
+		s3c_gpio_cfgpin(GTA03_GPIO_NWLAN_POWER, S3C_GPIO_SFN(1));
+
+		return;
+	}
+
+	/* give power to WLAN / BT module */
+	s3c_gpio_setpull(GTA03_GPIO_WLAN_RESET, S3C_GPIO_PULL_NONE);
+	s3c_gpio_cfgpin(GTA03_GPIO_WLAN_RESET, S3C_GPIO_SFN(1));
+	gpio_direction_output(GTA03_GPIO_WLAN_RESET, 0);
+
+	gpio_direction_output(GTA03_GPIO_NWLAN_POWER, 0);
+	s3c_gpio_setpull(GTA03_GPIO_NWLAN_POWER, S3C_GPIO_PULL_NONE);
+	s3c_gpio_cfgpin(GTA03_GPIO_NWLAN_POWER, S3C_GPIO_SFN(1));
+	msleep(1);
+	gpio_direction_output(GTA03_GPIO_WLAN_RESET, 1);
+}
+
+static ssize_t om_gta03_wlan_bt_power_read(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	if (om_gta03_features.wlan_bt_power_was_on)
+		return strlcpy(buf, "1\n", 3);
+	else
+		return strlcpy(buf, "0\n", 3);
+}
+
+static ssize_t om_gta03_wlan_bt_power_write(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	om_gta03_wlan_bt_pwron_set(simple_strtoul(buf, NULL, 10));
+
+	return count;
+}
+
+static DEVICE_ATTR(wlan_bt_power, 0644, om_gta03_wlan_bt_power_read,
+						  om_gta03_wlan_bt_power_write);
+
+
+/* GSM Module on / off */
+
+static void om_gta03_gsm_pwron_set(int on)
+{
+	if (!on) {
+		/* remove power from WLAN / BT module */
+		gpio_direction_output(GTA03_GPIO_MODEN_ON, 0);
+		s3c_gpio_setpull(GTA03_GPIO_MODEN_ON, S3C_GPIO_PULL_NONE);
+		s3c_gpio_cfgpin(GTA03_GPIO_MODEN_ON, S3C_GPIO_SFN(1));
+
+		return;
+	}
+
+	/* give power to GSM module */
+	s3c_gpio_setpull(GTA03_GPIO_N_MODEM_RESET, S3C_GPIO_PULL_NONE);
+	s3c_gpio_cfgpin(GTA03_GPIO_N_MODEM_RESET, S3C_GPIO_SFN(1));
+	gpio_direction_output(GTA03_GPIO_N_MODEM_RESET, 0);
+
+	gpio_direction_output(GTA03_GPIO_MODEN_ON, 1);
+	s3c_gpio_setpull(GTA03_GPIO_MODEN_ON, S3C_GPIO_PULL_NONE);
+	s3c_gpio_cfgpin(GTA03_GPIO_MODEN_ON, S3C_GPIO_SFN(1));
+	msleep(1);
+	gpio_direction_output(GTA03_GPIO_N_MODEM_RESET, 1);
+}
+
+static ssize_t om_gta03_gsm_power_read(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	if (om_gta03_features.gsm_power_was_on)
+		return strlcpy(buf, "1\n", 3);
+	else
+		return strlcpy(buf, "0\n", 3);
+}
+
+static ssize_t om_gta03_gsm_power_write(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int on = !!simple_strtoul(buf, NULL, 10);
+
+	om_gta03_gsm_pwron_set(on);
+	om_gta03_features.gsm_power_was_on = on;
+
+	return count;
+}
+
+static DEVICE_ATTR(gsm_power, 0644, om_gta03_gsm_power_read,
+						  om_gta03_gsm_power_write);
+
+
+/* USB host power on / off */
+
+static void om_gta03_usbhost_pwron_set(int on)
+{
+	pcf50633_gpio_set(om_gta03_pcf_pdata.pcf, PCF50633_GPO, on);
+}
+
+static ssize_t om_gta03_usbhost_power_read(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	if (pcf50633_gpio_get(om_gta03_pcf_pdata.pcf, PCF50633_GPO))
+		return strlcpy(buf, "1\n", 3);
+	else
+		return strlcpy(buf, "0\n", 3);
+}
+
+static ssize_t om_gta03_usbhost_power_write(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int on = !!simple_strtoul(buf, NULL, 10);
+
+	om_gta03_usbhost_pwron_set(on);
+	om_gta03_features.usbhost_power_was_on = on;
+
+	return count;
+}
+
+static DEVICE_ATTR(usbhost_power, 0644, om_gta03_usbhost_power_read,
+						  om_gta03_usbhost_power_write);
+
+
+
+
+static struct attribute *om_gta03_features_sysfs_entries[] = {
+	&dev_attr_gps_power.attr,
+	&dev_attr_wlan_bt_power.attr,
+	&dev_attr_gsm_power.attr,
+	&dev_attr_usbhost_power.attr,
+	NULL
+};
+
+static struct attribute_group om_gta03_features_attr_group = {
+	.name	= NULL,
+	.attrs	= om_gta03_features_sysfs_entries,
+};
+
+static int __init om_gta03_features_probe(struct platform_device *pdev)
+{
+	om_gta03_features.gps_regulator = regulator_get(&pdev->dev, "RF_3V");
+	dev_info(&pdev->dev, "starting\n");
+
+	om_gta03_features.wlan_bt_power_was_on = 1; /* defaults to on */
+
+	return sysfs_create_group(&pdev->dev.kobj, &om_gta03_features_attr_group);
+}
+
+static int om_gta03_features_remove(struct platform_device *pdev)
+{
+
+	regulator_put(om_gta03_features.gps_regulator);
+	sysfs_remove_group(&pdev->dev.kobj, &om_gta03_features_attr_group);
+
+	return 0;
+}
+
+
+#ifdef CONFIG_PM
+static int om_gta03_features_suspend(struct platform_device *pdev,
+				     pm_message_t state)
+{
+	om_gta03_gps_pwron_set(0);
+	om_gta03_wlan_bt_pwron_set(0);
+	om_gta03_usbhost_pwron_set(0);
+
+	return 0;
+}
+
+static int om_gta03_features_resume(struct platform_device *pdev)
+{
+	if (om_gta03_features.gps_power_was_on)
+		om_gta03_gps_pwron_set(1);
+
+	if (om_gta03_features.wlan_bt_power_was_on)
+		om_gta03_wlan_bt_pwron_set(1);
+
+	if (om_gta03_features.usbhost_power_was_on)
+		om_gta03_usbhost_pwron_set(1);
+
+	return 0;
+}
+#else
+#define om_gta03_features_suspend	NULL
+#define om_gta03_features_resume	NULL
+#endif
+
+static struct platform_driver om_gta03_features_driver = {
+	.probe		= om_gta03_features_probe,
+	.remove		= om_gta03_features_remove,
+	.suspend	= om_gta03_features_suspend,
+	.resume		= om_gta03_features_resume,
+	.driver		= {
+		.name		= "om-gta03",
+	},
+};
+
+static int __devinit om_gta03_features_init(void)
+{
+	return platform_driver_register(&om_gta03_features_driver);
+}
+
+static void om_gta03_features_exit(void)
+{
+	platform_driver_unregister(&om_gta03_features_driver);
+}
+
+module_init(om_gta03_features_init);
+module_exit(om_gta03_features_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Andy Green <andy at openmoko.com>");
+MODULE_DESCRIPTION("Openmoko GTA03 Feature Driver");
diff --git a/arch/arm/plat-s3c24xx/neo1973_pm_gps.c b/arch/arm/plat-s3c24xx/neo1973_pm_gps.c
index 8907569..8f0a629 100644
--- a/arch/arm/plat-s3c24xx/neo1973_pm_gps.c
+++ b/arch/arm/plat-s3c24xx/neo1973_pm_gps.c
@@ -29,6 +29,7 @@
 
 /* For GTA02 */
 #include <mach/gta02.h>
+#include <linux/pcf50633.h>
 
 #include <linux/regulator/consumer.h>
 
@@ -275,6 +276,8 @@ static int gps_power_1v5_get(void)
 static void gps_pwron_set(int on)
 {
 
+	neo1973_gps.power_was_on = !!on;
+
 	if (machine_is_neo1973_gta01())
 		neo1973_gpb_setpin(GTA01_GPIO_GPS_PWRON, on);
 
@@ -294,13 +297,12 @@ static void gps_pwron_set(int on)
 			/* don't let RX from unpowered GPS float */
 			s3c2410_gpio_pullup(S3C2410_GPH5, 1);
 		}
-		if (on && !neo1973_gps.power_was_on)
+		if ((on) && (!neo1973_gps.power_was_on))
 			regulator_enable(neo1973_gps.regulator);
-		else if (!on && neo1973_gps.power_was_on)
+
+		if ((!on) && (neo1973_gps.power_was_on))
 			regulator_disable(neo1973_gps.regulator);
 	}
-
-	neo1973_gps.power_was_on = !!on;
 }
 
 static int gps_pwron_get(void)
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 90ce025..94b8fea 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -35,3 +35,4 @@ obj-$(CONFIG_LOW_MEMORY_KILLER)	+= lowmemorykiller.o
 obj-$(CONFIG_MACH_NEO1973)      += neo1973_version.o \
                                    neo1973_pm_host.o \
                                    neo1973_pm_resume_reason.o
+




More information about the openmoko-kernel mailing list