aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBalaji Rao <balajirrao@openmoko.org>2009-01-27 14:38:49 +0000
committerAndy Green <agreen@octopus.localdomain>2009-01-27 14:38:49 +0000
commit57a4af9be7051302edc51c878ecfbd90466827ff (patch)
tree51c5f9149184b63de61af0ba5dc79fa931c5aab7
parentcc0a09e9e49f6121622d8579b23018e378a29e23 (diff)
Subject: pcf50606_rebase_changes,patch
X-Git-Url: http://git.openmoko.org/?p=kernel.git;a=commitdiff_plain;h=445395c9fcfb78ea62ab5a69b84c2c12efe01cff pcf50606_rebase_changes,patch This patch brings into andy-tracking all changes related to pcf50606 from old balaji-tracking.
-rw-r--r--arch/arm/mach-s3c2410/Kconfig12
-rw-r--r--arch/arm/mach-s3c2410/include/mach/gta01.h2
-rw-r--r--arch/arm/mach-s3c2410/mach-gta01.c470
-rw-r--r--arch/arm/plat-s3c24xx/neo1973_pm_bt.c188
-rw-r--r--arch/arm/plat-s3c24xx/neo1973_pm_gps.c4
-rw-r--r--drivers/input/misc/pcf50606-input.c113
6 files changed, 529 insertions, 260 deletions
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index 25ebd38539e..ba58f9cac95 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -143,7 +143,17 @@ config MACH_NEO1973_GTA01
bool "FIC Neo1973 GSM Phone (GTA01 Hardware)"
select CPU_S3C2410
select MACH_NEO1973
- select SENSORS_PCF50606
+ select MFD_PCF50606
+ select INPUT_PCF50606_PMU
+ select PCF50606_ADC
+ select PCF50606_GPIO
+ select RTC_DRV_PCF50606
+ select REGULATOR_PCF50606
+ select CHARGER_PCF50606
+ select PCF50606_WATCHDOG
+ select POWER_SUPPLY
+ select BATTERY_GTA01
+
help
Say Y here if you are using the FIC Neo1973 GSM Phone
diff --git a/arch/arm/mach-s3c2410/include/mach/gta01.h b/arch/arm/mach-s3c2410/include/mach/gta01.h
index 7af36a1bc86..99181170624 100644
--- a/arch/arm/mach-s3c2410/include/mach/gta01.h
+++ b/arch/arm/mach-s3c2410/include/mach/gta01.h
@@ -71,4 +71,6 @@ struct gta01bl_machinfo {
#define GTA01Bv4_IRQ_PCF50606 IRQ_EINT9
+extern struct pcf50606 *gta01_pcf;
+
#endif /* _GTA01_H */
diff --git a/arch/arm/mach-s3c2410/mach-gta01.c b/arch/arm/mach-s3c2410/mach-gta01.c
index 117062c959f..629fb7a49b6 100644
--- a/arch/arm/mach-s3c2410/mach-gta01.c
+++ b/arch/arm/mach-s3c2410/mach-gta01.c
@@ -47,7 +47,16 @@
#include <linux/mmc/host.h>
-#include <linux/pcf50606.h>
+#include <linux/mfd/pcf50606/core.h>
+#include <linux/mfd/pcf50606/pmic.h>
+#include <linux/mfd/pcf50606/mbc.h>
+#include <linux/mfd/pcf50606/adc.h>
+
+#include <linux/gta01_battery.h>
+
+#include <linux/regulator/machine.h>
+#include <linux/regulator/consumer.h>
+
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -60,7 +69,6 @@
#include <mach/regs-gpio.h>
#include <mach/fb.h>
-#include <mach/mci.h>
#include <mach/spi.h>
#include <mach/spi-gpio.h>
#include <mach/usb-control.h>
@@ -74,14 +82,14 @@
#include <plat/pm.h>
#include <plat/udc.h>
#include <plat/iic.h>
+#include <plat/mci.h>
#include <asm/plat-s3c24xx/neo1973.h>
#include <mach/neo1973-pm-gsm.h>
#include <linux/jbt6k74.h>
-#include <linux/ts_filter_mean.h>
-#include <linux/ts_filter_median.h>
-
+#include <../drivers/input/touchscreen/ts_filter_mean.h>
+#include <../drivers/input/touchscreen/ts_filter_median.h>
static struct map_desc gta01_iodesc[] __initdata = {
{
@@ -115,8 +123,14 @@ static struct s3c2410_uartcfg gta01_uartcfgs[] = {
},
};
-/* PMU driver info */
+/* TODO */
+static void gta01_pmu_event_callback(struct pcf50606 *pcf, int irq)
+{
+ /*TODO : Handle ACD here */
+}
+/* FIXME : Goes away when ACD is handled above */
+#if 0
static int pmu_callback(struct device *dev, unsigned int feature,
enum pmu_event event)
{
@@ -139,152 +153,316 @@ static int pmu_callback(struct device *dev, unsigned int feature,
return 0;
}
+#endif
+
+struct pcf50606 *gta01_pcf;
+
+static struct platform_device gta01_pm_gsm_dev = {
+ .name = "neo1973-pm-gsm",
+};
+
+static struct platform_device gta01_pm_bt_dev = {
+ .name = "neo1973-pm-bt",
+};
+static struct platform_device gta01_pm_gps_dev = {
+ .name = "neo1973-pm-gps",
+};
+
+static struct regulator_consumer_supply ioreg_consumers[] = {
+ {
+ .dev = &gta01_pm_gps_dev.dev,
+ .supply = "GPS_2V8",
+ },
+};
+
+static struct regulator_consumer_supply d1reg_consumers[] = {
+ {
+ .dev = &gta01_pm_gps_dev.dev,
+ .supply = "GPS_3V",
+ },
+ {
+ .dev = &gta01_pm_bt_dev.dev,
+ .supply = "BT_3V1",
+ },
+};
+
+static struct regulator_consumer_supply dcd_consumers[] = {
+ {
+ .dev = &gta01_pm_gps_dev.dev,
+ .supply = "GPS_3V3",
+ },
+ {
+ .dev = &gta01_pm_gps_dev.dev,
+ .supply = "GPS_1V5",
+ },
+};
+
+static struct regulator_consumer_supply d2reg_consumers[] = {
+ {
+ .dev = &gta01_pm_gps_dev.dev,
+ .supply = "GPS_2V5",
+ },
+ {
+ .dev = &s3c_device_sdi.dev,
+ .supply = "SD_3V3",
+ },
+};
+
+static int gta01_bat_get_charging_status(void)
+{
+ struct pcf50606 *pcf = gta01_pcf;
+ u8 mbcc1, chgmod;
+
+ mbcc1 = pcf50606_reg_read(pcf, PCF50606_REG_MBCC1);
+ chgmod = mbcc1 & PCF50606_MBCC1_CHGMOD_MASK;
+
+ if (chgmod == PCF50606_MBCC1_CHGMOD_IDLE)
+ return 0;
+ else
+ return 1;
+}
+
+static int gta01_bat_get_voltage(void)
+{
+ struct pcf50606 *pcf = gta01_pcf;
+ u16 adc, mv = 0;
+
+ adc = pcf50606_adc_sync_read(pcf, PCF50606_ADCMUX_BATVOLT_RES);
+ mv = (adc * 6000) / 1024;
+
+ return mv;
+}
+
+static int gta01_bat_get_current(void)
+{
+ struct pcf50606 *pcf = gta01_pcf;
+ u16 adc_battvolt, adc_adcin1;
+ s32 res;
+
+ adc_battvolt = pcf50606_adc_sync_read(pcf, PCF50606_ADCMUX_BATVOLT_SUBTR);
+ adc_adcin1 = pcf50606_adc_sync_read(pcf, PCF50606_ADCMUX_ADCIN1_SUBTR);
+ res = (adc_adcin1 - adc_battvolt) * 2400;
+
+ /*rsense is 220 milli */
+ return (res * 1000) / (220 * 1024);
+}
+
+static struct gta01_bat_platform_data gta01_bat_pdata = {
+ .get_charging_status = gta01_bat_get_charging_status,
+ .get_voltage = gta01_bat_get_voltage,
+ .get_current = gta01_bat_get_current,
+};
+
+struct platform_device gta01_bat = {
+ .name = "gta01_battery",
+ .id = -1,
+ .dev = {
+ .platform_data = &gta01_bat_pdata,
+ }
+};
+
+static void gta01_pcf_probe_done(struct pcf50606 *pcf)
+{
+ gta01_pcf = pcf;
+ gta01_bat.dev.parent = pcf->dev;
+ platform_device_register(&gta01_bat);
+}
+
+static int gps_registered_regulators = 0;
+
+static void gta01_pmu_regulator_registered(struct pcf50606 *pcf, int id)
+{
+ switch(id) {
+ case PCF50606_REGULATOR_D1REG:
+ platform_device_register(&gta01_pm_bt_dev);
+ gps_registered_regulators++;
+ break;
+ case PCF50606_REGULATOR_D2REG:
+ gps_registered_regulators++;
+ platform_device_register(&s3c_device_sdi);
+ break;
+ case PCF50606_REGULATOR_IOREG:
+ case PCF50606_REGULATOR_DCD:
+ gps_registered_regulators++;
+ break;
+ }
+
+ /* All GPS related regulators registered ? */
+ if (gps_registered_regulators == 4)
+ platform_device_register(&gta01_pm_gps_dev);
+
+}
static struct pcf50606_platform_data gta01_pcf_pdata = {
- .used_features = PCF50606_FEAT_EXTON |
- PCF50606_FEAT_MBC |
- PCF50606_FEAT_BBC |
- PCF50606_FEAT_RTC |
- PCF50606_FEAT_WDT |
- PCF50606_FEAT_CHGCUR |
- PCF50606_FEAT_BATVOLT |
- PCF50606_FEAT_BATTEMP,
- .onkey_seconds_required = 3,
- .cb = &pmu_callback,
- .r_fix_batt = 10000,
- .r_fix_batt_par = 10000,
- .r_sense_milli = 220,
- .rails = {
+ .resumers = {
+ [0] = PCF50606_INT1_ALARM |
+ PCF50606_INT1_ONKEYF |
+ PCF50606_INT1_EXTONR,
+ [1] = PCF50606_INT2_CHGWD10S |
+ PCF50606_INT2_CHGPROT |
+ PCF50606_INT2_CHGERR,
+ [2] = PCF50606_INT3_LOWBAT |
+ PCF50606_INT3_HIGHTMP |
+ PCF50606_INT3_ACDINS,
+ },
+ .mbc_event_callback = gta01_pmu_event_callback,
+ .reg_init_data = {
[PCF50606_REGULATOR_D1REG] = {
- .name = "bt_3v15",
- .voltage = {
- .init = 3150,
- .max = 3150,
+ .constraints = {
+ .min_uV = 3000000,
+ .max_uV = 3150000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
},
+ .num_consumer_supplies = ARRAY_SIZE(d1reg_consumers),
+ .consumer_supplies = d1reg_consumers,
},
+
[PCF50606_REGULATOR_D2REG] = {
- .name = "gl_2v5",
- .voltage = {
- .init = 2500,
- .max = 2500,
+ .constraints = {
+ .min_uV = 1650000,
+ .max_uV = 3300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .apply_uV = 1,
},
+ .num_consumer_supplies = ARRAY_SIZE(d2reg_consumers),
+ .consumer_supplies = d2reg_consumers,
+
},
+
[PCF50606_REGULATOR_D3REG] = {
- .name = "stby_1v8",
- .flags = PMU_VRAIL_F_SUSPEND_ON,
- .voltage = {
- .init = 1800,
- .max = 2100,
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 2100000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .state_mem = {
+ .enabled = 1,
+ },
},
+ .num_consumer_supplies = 0,
},
+
[PCF50606_REGULATOR_DCD] = {
- .name = "gl_1v5",
- .voltage = {
- .init = 1500,
- .max = 1500,
+ .constraints = {
+ .min_uV = 1500000,
+ .max_uV = 1500000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
},
+ .num_consumer_supplies = ARRAY_SIZE(dcd_consumers),
+ .consumer_supplies = dcd_consumers,
},
+
[PCF50606_REGULATOR_DCDE] = {
- .name = "io_3v3",
- .flags = PMU_VRAIL_F_SUSPEND_ON,
- .voltage = {
- .init = 3300,
- .max = 3330,
+ .constraints = {
+ .min_uV = 3300000,
+ .max_uV = 3300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
+ .state_mem = {
+ .enabled = 1,
+ },
},
+ .num_consumer_supplies = 0,
},
+
[PCF50606_REGULATOR_DCUD] = {
- .name = "core_1v8",
- .flags = PMU_VRAIL_F_SUSPEND_ON,
- .voltage = {
- .init = 2100,
- .max = 2100,
+ .constraints = {
+ .min_uV = 2100000,
+ .max_uV = 2100000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
+ .state_mem = {
+ .enabled = 1,
+ },
},
+ .num_consumer_supplies = 0,
},
+
[PCF50606_REGULATOR_IOREG] = {
- .name = "codec_3v3",
- .voltage = {
- .init = 3300,
- .max = 3300,
+ .constraints = {
+ .min_uV = 3300000,
+ .max_uV = 3300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
},
+ .num_consumer_supplies = ARRAY_SIZE(ioreg_consumers),
+ .consumer_supplies = ioreg_consumers,
+
},
+
[PCF50606_REGULATOR_LPREG] = {
- .name = "lcm_3v3",
- .voltage = {
- .init = 3300,
- .max = 3300,
+ .constraints = {
+ .min_uV = 3300000,
+ .max_uV = 3300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .apply_uV = 1,
},
- }
+ .num_consumer_supplies = 0,
+ },
},
+ .probe_done = gta01_pcf_probe_done,
+ .regulator_registered = gta01_pmu_regulator_registered,
};
-static void cfg_pmu_vrail(struct pmu_voltage_rail *vrail, char *name,
- unsigned int flags, unsigned int init,
+static void cfg_pmu_vrail(struct regulator_init_data *vrail,
+ unsigned int suspend_on, unsigned int min,
unsigned int max)
{
- vrail->name = name;
- vrail->flags = flags;
- vrail->voltage.init = init;
- vrail->voltage.max = max;
+ vrail->constraints.state_mem.enabled = suspend_on;
+ vrail->constraints.min_uV = min;
+ vrail->constraints.max_uV = min;
+ vrail->constraints.apply_uV = 1;
}
static void mangle_pmu_pdata_by_system_rev(void)
{
+ struct regulator_init_data *reg_init_data;
+
+ reg_init_data = gta01_pcf_pdata.reg_init_data;
+
switch (system_rev) {
case GTA01Bv4_SYSTEM_REV:
- gta01_pcf_pdata.used_features |= PCF50606_FEAT_ACD;
+
+ /* FIXME : gta01_pcf_pdata.used_features |= PCF50606_FEAT_ACD; */
break;
case GTA01Bv3_SYSTEM_REV:
case GTA01Bv2_SYSTEM_REV:
- gta01_pcf_pdata.rails[PCF50606_REGULATOR_D3REG]
- .name = "user1";
- gta01_pcf_pdata.rails[PCF50606_REGULATOR_D3REG]
- .flags &= ~PMU_VRAIL_F_SUSPEND_ON;
- gta01_pcf_pdata.rails[PCF50606_REGULATOR_D3REG]
- .flags = PMU_VRAIL_F_UNUSED;
+ reg_init_data[PCF50606_REGULATOR_D3REG].constraints.state_mem.enabled = 1;
break;
case GTA01v4_SYSTEM_REV:
- cfg_pmu_vrail(&gta01_pcf_pdata.rails[PCF50606_REGULATOR_DCUD],
- "core_1v8", PMU_VRAIL_F_SUSPEND_ON, 1800, 1800);
- cfg_pmu_vrail(&gta01_pcf_pdata.rails[PCF50606_REGULATOR_D1REG],
- "vrf_3v", 0, 3000, 3000);
- cfg_pmu_vrail(&gta01_pcf_pdata.rails[PCF50606_REGULATOR_D3REG],
- "vtcxo_2v8", 0, 2800, 2800);
- cfg_pmu_vrail(&gta01_pcf_pdata.rails[PCF50606_REGULATOR_DCD],
- "gl_3v5", 0, 3500, 3500);
+ cfg_pmu_vrail(&reg_init_data[PCF50606_REGULATOR_DCUD],
+ 1, 18000000, 1800000);
+ cfg_pmu_vrail(&reg_init_data[PCF50606_REGULATOR_D1REG],
+ 0, 3000000, 3000000);
+ cfg_pmu_vrail(&reg_init_data[PCF50606_REGULATOR_D3REG],
+ 0, 2800000, 2800000);
+ cfg_pmu_vrail(&reg_init_data[PCF50606_REGULATOR_DCD],
+ 0, 3500000, 3500000);
break;
case GTA01v3_SYSTEM_REV:
- cfg_pmu_vrail(&gta01_pcf_pdata.rails[PCF50606_REGULATOR_D1REG],
- "vrf_3v", 0, 3000, 3000);
- cfg_pmu_vrail(&gta01_pcf_pdata.rails[PCF50606_REGULATOR_D2REG],
- "sd_3v3", 0, 3300, 3300);
- cfg_pmu_vrail(&gta01_pcf_pdata.rails[PCF50606_REGULATOR_D3REG],
- "codec_3v3", 0, 3300, 3300);
- cfg_pmu_vrail(&gta01_pcf_pdata.rails[PCF50606_REGULATOR_DCD],
- "gpsio_3v3", 0, 3300, 3300);
- cfg_pmu_vrail(&gta01_pcf_pdata.rails[PCF50606_REGULATOR_DCUD],
- "core_1v8", PMU_VRAIL_F_SUSPEND_ON, 1800, 1800);
- cfg_pmu_vrail(&gta01_pcf_pdata.rails[PCF50606_REGULATOR_IOREG],
- "vtcxo_2v8", 0, 2800, 2800);
+ cfg_pmu_vrail(&reg_init_data[PCF50606_REGULATOR_D1REG],
+ 0, 3000000, 3000000);
+ cfg_pmu_vrail(&reg_init_data[PCF50606_REGULATOR_D2REG],
+ 0, 3300000, 3300000);
+ cfg_pmu_vrail(&reg_init_data[PCF50606_REGULATOR_D3REG],
+ 0, 3300000, 3300000);
+ cfg_pmu_vrail(&reg_init_data[PCF50606_REGULATOR_DCD],
+ 0, 3300000, 3300000);
+ cfg_pmu_vrail(&reg_init_data[PCF50606_REGULATOR_DCUD],
+ 1, 1800000, 1800000);
+ cfg_pmu_vrail(&reg_init_data[PCF50606_REGULATOR_IOREG],
+ 0, 2800000, 2800000);
break;
}
}
-static struct resource gta01_pmu_resources[] = {
- [0] = {
- .flags = IORESOURCE_IRQ,
- .start = GTA01_IRQ_PCF50606,
- .end = GTA01_IRQ_PCF50606,
- },
-};
-
-struct platform_device gta01_pmu_dev = {
- .name = "pcf50606",
- .num_resources = ARRAY_SIZE(gta01_pmu_resources),
- .resource = gta01_pmu_resources,
- .dev = {
- .platform_data = &gta01_pcf_pdata,
- },
-};
+static void gta01_power_off(void)
+{
+ pcf50606_reg_write(gta01_pcf, PCF50606_REG_OOCC1,
+ PCF50606_OOCC1_GOSTDBY);
+}
/* LCD driver info */
@@ -373,7 +551,6 @@ static struct platform_device *gta01_devices[] __initdata = {
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
- &s3c_device_sdi,
&s3c_device_usbgadget,
&s3c_device_nand,
&s3c_device_ts,
@@ -395,52 +572,8 @@ static struct s3c2410_platform_nand gta01_nand_info = {
.sets = gta01_nand_sets,
};
-static void gta01_mmc_set_power(unsigned char power_mode, unsigned short vdd)
-{
- int bit;
- int mv = 1700; /* 1.7V for MMC_VDD_165_195 */
-
- printk(KERN_DEBUG "mmc_set_power(power_mode=%u, vdd=%u)\n",
- power_mode, vdd);
-
- switch (system_rev) {
- case GTA01v3_SYSTEM_REV:
- switch (power_mode) {
- case MMC_POWER_OFF:
- pcf50606_onoff_set(pcf50606_global,
- PCF50606_REGULATOR_D2REG, 0);
- break;
- case MMC_POWER_ON:
- /* translate MMC_VDD_* VDD bit to mv */
- for (bit = 8; bit != 24; bit++)
- if (vdd == (1 << bit))
- mv += 100 * (bit - 4);
- pcf50606_voltage_set(pcf50606_global,
- PCF50606_REGULATOR_D2REG, mv);
- pcf50606_onoff_set(pcf50606_global,
- PCF50606_REGULATOR_D2REG, 1);
- break;
- }
- break;
- case GTA01v4_SYSTEM_REV:
- case GTA01Bv2_SYSTEM_REV:
- case GTA01Bv3_SYSTEM_REV:
- case GTA01Bv4_SYSTEM_REV:
- switch (power_mode) {
- case MMC_POWER_OFF:
- neo1973_gpb_setpin(GTA01_GPIO_SDMMC_ON, 1);
- break;
- case MMC_POWER_ON:
- neo1973_gpb_setpin(GTA01_GPIO_SDMMC_ON, 0);
- break;
- }
- break;
- }
-}
-
static struct s3c24xx_mci_pdata gta01_mmc_cfg = {
.gpio_detect = GTA01_GPIO_nSD_DETECT,
- .set_power = &gta01_mmc_set_power,
.ocr_avail = MMC_VDD_165_195|MMC_VDD_20_21|
MMC_VDD_21_22|MMC_VDD_22_23|MMC_VDD_23_24|
MMC_VDD_24_25|MMC_VDD_25_26|MMC_VDD_26_27|
@@ -478,17 +611,17 @@ static void __gta01_udc_vbus_draw(struct work_struct *work)
/* this is a fix to work around boot-time ordering problems if the
* s3c2410_udc is initialized before the pcf50606 driver has defined
* pcf50606_global */
- if (!pcf50606_global)
+ if (!gta01_pcf)
return;
if (gta01_udc_vbus_drawer.ma >= 500) {
/* enable fast charge */
printk(KERN_DEBUG "udc: enabling fast charge\n");
- pcf50606_charge_fast(pcf50606_global, 1);
+ pcf50606_charge_fast(gta01_pcf, 1);
} else {
/* disable fast charge */
printk(KERN_DEBUG "udc: disabling fast charge\n");
- pcf50606_charge_fast(pcf50606_global, 0);
+ pcf50606_charge_fast(gta01_pcf, 1);
}
}
@@ -661,14 +794,6 @@ static struct resource gta01_button_resources[] = {
.start = GTA01_GPIO_JACK_INSERT,
.end = GTA01_GPIO_JACK_INSERT,
},
- [3] = {
- .start = 0,
- .end = 0,
- },
- [4] = {
- .start = 0,
- .end = 0,
- },
};
struct platform_device gta01_button_dev = {
@@ -677,10 +802,6 @@ struct platform_device gta01_button_dev = {
.resource = gta01_button_resources,
};
-static struct platform_device gta01_pm_gsm_dev = {
- .name = "neo1973-pm-gsm",
-};
-
/* USB */
static struct s3c2410_hcd_info gta01_usb_info = {
.port[0] = {
@@ -705,6 +826,17 @@ static irqreturn_t gta01_modem_irq(int irq, void *param)
return IRQ_HANDLED;
}
+static struct i2c_board_info gta01_i2c_devs[] __initdata = {
+ {
+ I2C_BOARD_INFO("pcf50606", 0x08),
+ .irq = GTA01_IRQ_PCF50606,
+ .platform_data = &gta01_pcf_pdata,
+ },
+ {
+ I2C_BOARD_INFO("lm4587", 0x7c),
+ }
+};
+
static void __init gta01_machine_init(void)
{
int rc;
@@ -753,14 +885,14 @@ static void __init gta01_machine_init(void)
gta01_led_resources[0].end = GTA01Bv2_GPIO_VIBRATOR_ON;
break;
case GTA01Bv4_SYSTEM_REV:
- gta01_pmu_resources[0].start =
- gta01_pmu_resources[0].end = GTA01Bv4_IRQ_PCF50606;
+ gta01_i2c_devs[0].irq = GTA01Bv4_IRQ_PCF50606;
gta01_led_resources[0].start =
gta01_led_resources[0].end = GTA01Bv4_GPIO_VIBRATOR_ON;
break;
}
mangle_pmu_pdata_by_system_rev();
- platform_device_register(&gta01_pmu_dev);
+ i2c_register_board_info(0, gta01_i2c_devs, ARRAY_SIZE(gta01_i2c_devs));
+
platform_device_register(&gta01_led_dev);
platform_add_devices(gta01_devices, ARRAY_SIZE(gta01_devices));
@@ -773,6 +905,8 @@ static void __init gta01_machine_init(void)
enable_irq_wake(GTA01_IRQ_MODEM);
printk(KERN_DEBUG "Enabled GSM wakeup IRQ %d (rc=%d)\n",
GTA01_IRQ_MODEM, rc);
+
+ pm_power_off = &gta01_power_off;
}
MACHINE_START(NEO1973_GTA01, "GTA01")
diff --git a/arch/arm/plat-s3c24xx/neo1973_pm_bt.c b/arch/arm/plat-s3c24xx/neo1973_pm_bt.c
index 96af7c544d7..53d3c02b9d5 100644
--- a/arch/arm/plat-s3c24xx/neo1973_pm_bt.c
+++ b/arch/arm/plat-s3c24xx/neo1973_pm_bt.c
@@ -16,6 +16,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/rfkill.h>
+#include <linux/err.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
@@ -27,24 +28,27 @@
/* For GTA02 */
#include <mach/gta02.h>
-#include <linux/pcf50633.h>
+#include <linux/mfd/pcf50633/gpio.h>
+#include <linux/regulator/consumer.h>
#define DRVMSG "FIC Neo1973 Bluetooth Power Management"
+struct gta01_pm_bt_data {
+ struct regulator *regulator;
+ struct rfkill *rfkill;
+ int pre_resume_state;
+};
+
static ssize_t bt_read(struct device *dev, struct device_attribute *attr,
char *buf)
{
int ret = 0;
+ struct gta01_pm_bt_data *bt_data = dev_get_drvdata(dev);
if (!strcmp(attr->attr.name, "power_on")) {
-
if (machine_is_neo1973_gta01()) {
- if (pcf50606_onoff_get(pcf50606_global,
- PCF50606_REGULATOR_D1REG) &&
- pcf50606_voltage_get(pcf50606_global,
- PCF50606_REGULATOR_D1REG) == 3100)
- ret = 1;
+ ret = regulator_is_enabled(bt_data->regulator);
} else if (machine_is_neo1973_gta02()) {
if (s3c2410_gpio_getpin(GTA02_GPIO_BT_EN))
ret = 1;
@@ -66,37 +70,51 @@ static ssize_t bt_read(struct device *dev, struct device_attribute *attr,
}
}
+static void __gta02_pm_bt_toggle_radio(struct device *dev, unsigned int on)
+{
+ struct gta01_pm_bt_data *bt_data = dev_get_drvdata(dev);
+
+ dev_info(dev, "__gta02_pm_bt_toggle_radio %d\n", on);
+
+ if (machine_is_neo1973_gta02()) {
+
+ bt_data = dev_get_drvdata(dev);
+
+ neo1973_gpb_setpin(GTA02_GPIO_BT_EN, !on);
+
+ if (on) {
+ if (!regulator_is_enabled(bt_data->regulator))
+ regulator_enable(bt_data->regulator);
+ } else {
+ if (regulator_is_enabled(bt_data->regulator))
+ regulator_disable(bt_data->regulator);
+ }
+
+ neo1973_gpb_setpin(GTA02_GPIO_BT_EN, on);
+ }
+}
+
+
static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state)
{
struct device *dev = data;
unsigned long on = (state == RFKILL_STATE_ON);
- unsigned int vol;
+ struct gta01_pm_bt_data *bt_data = dev_get_drvdata(dev);
if (machine_is_neo1973_gta01()) {
/* if we are powering up, assert reset, then power,
* then release reset */
if (on) {
neo1973_gpb_setpin(GTA01_GPIO_BT_EN, 0);
- pcf50606_voltage_set(pcf50606_global,
- PCF50606_REGULATOR_D1REG,
- 3100);
+ if (!regulator_is_enabled(bt_data->regulator))
+ regulator_enable(bt_data->regulator);
+ } else {
+ if (regulator_is_enabled(bt_data->regulator))
+ regulator_disable(bt_data->regulator);
}
- pcf50606_onoff_set(pcf50606_global,
- PCF50606_REGULATOR_D1REG, on);
neo1973_gpb_setpin(GTA01_GPIO_BT_EN, on);
- } else if (machine_is_neo1973_gta02()) {
- if (s3c2410_gpio_getpin(GTA02_GPIO_BT_EN) == on)
- return 0;
- neo1973_gpb_setpin(GTA02_GPIO_BT_EN, !on);
- pcf50633_voltage_set(pcf50633_global,
- PCF50633_REGULATOR_LDO4, on ? 3200 : 0);
- pcf50633_onoff_set(pcf50633_global,
- PCF50633_REGULATOR_LDO4, on);
- vol = pcf50633_voltage_get(pcf50633_global,
- PCF50633_REGULATOR_LDO4);
- dev_info(dev, "GTA02 Set PCF50633 LDO4 = %d\n", vol);
- neo1973_gpb_setpin(GTA02_GPIO_BT_EN, on);
- }
+ } else if (machine_is_neo1973_gta02())
+ __gta02_pm_bt_toggle_radio(dev, on);
return 0;
}
@@ -105,12 +123,29 @@ static ssize_t bt_write(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned long on = simple_strtoul(buf, NULL, 10);
+ struct gta01_pm_bt_data *bt_data = dev_get_drvdata(dev);
if (!strcmp(attr->attr.name, "power_on")) {
- struct rfkill *rfkill = dev_get_drvdata(dev);
enum rfkill_state state = on ? RFKILL_STATE_ON : RFKILL_STATE_OFF;
bt_rfkill_toggle_radio(dev, state);
- rfkill->state = state;
+ bt_data->rfkill->state = state;
+
+ if (machine_is_neo1973_gta01()) {
+ /* if we are powering up, assert reset, then power,
+ * then release reset */
+ if (on) {
+ neo1973_gpb_setpin(GTA01_GPIO_BT_EN, 0);
+ if (!regulator_is_enabled(bt_data->regulator))
+ regulator_enable(bt_data->regulator);
+ } else {
+ if (regulator_is_enabled(bt_data->regulator))
+ regulator_disable(bt_data->regulator);
+ }
+
+ neo1973_gpb_setpin(GTA01_GPIO_BT_EN, on);
+ } else if (machine_is_neo1973_gta02())
+ __gta02_pm_bt_toggle_radio(dev, on);
+
} else if (!strcmp(attr->attr.name, "reset")) {
/* reset is low-active, so we need to invert */
if (machine_is_neo1973_gta01()) {
@@ -129,18 +164,32 @@ static DEVICE_ATTR(reset, 0644, bt_read, bt_write);
#ifdef CONFIG_PM
static int gta01_bt_suspend(struct platform_device *pdev, pm_message_t state)
{
+ struct gta01_pm_bt_data *bt_data = dev_get_drvdata(&pdev->dev);
+
dev_dbg(&pdev->dev, DRVMSG ": suspending\n");
- /* FIXME: The PMU should save the PMU status, and the GPIO code should
- * preserve the GPIO level, so there shouldn't be anything left to do
- * for us, should there? */
+
+ if (machine_is_neo1973_gta01()) {
+ if (regulator_is_enabled(bt_data->regulator))
+ regulator_disable(bt_data->regulator);
+ } else if (machine_is_neo1973_gta02()) {
+ bt_data->pre_resume_state =
+ s3c2410_gpio_getpin(GTA02_GPIO_BT_EN);
+ __gta02_pm_bt_toggle_radio(&pdev->dev, 0);
+ }
return 0;
}
static int gta01_bt_resume(struct platform_device *pdev)
{
+ struct gta01_pm_bt_data *bt_data = dev_get_drvdata(&pdev->dev);
dev_dbg(&pdev->dev, DRVMSG ": resuming\n");
+ if (machine_is_neo1973_gta02()) {
+ __gta02_pm_bt_toggle_radio(&pdev->dev,
+ bt_data->pre_resume_state);
+ }
+
return 0;
}
#else
@@ -162,19 +211,55 @@ static struct attribute_group gta01_bt_attr_group = {
static int __init gta01_bt_probe(struct platform_device *pdev)
{
struct rfkill *rfkill;
+ struct regulator *regulator;
+ struct gta01_pm_bt_data *bt_data;
+ int ret;
+
dev_info(&pdev->dev, DRVMSG ": starting\n");
+ bt_data = kzalloc(sizeof(*bt_data), GFP_KERNEL);
+ dev_set_drvdata(&pdev->dev, bt_data);
+
if (machine_is_neo1973_gta01()) {
/* we make sure that the voltage is off */
- pcf50606_onoff_set(pcf50606_global,
- PCF50606_REGULATOR_D1REG, 0);
+ regulator = regulator_get(&pdev->dev, "BT_3V1");
+ if (IS_ERR(regulator))
+ return -ENODEV;
+
+ bt_data->regulator = regulator;
+
+ /* this tests the true physical state of the regulator... */
+ if (regulator_is_enabled(regulator)) {
+ /*
+ * but these only operate on the logical state of the
+ * regulator... so we need to logicaly "adopt" it on
+ * to turn it off
+ */
+ regulator_enable(regulator);
+ regulator_disable(regulator);
+ }
+
/* we pull reset to low to make sure that the chip doesn't
* drain power through the reset line */
neo1973_gpb_setpin(GTA01_GPIO_BT_EN, 0);
} else if (machine_is_neo1973_gta02()) {
- /* we make sure that the voltage is off */
- pcf50633_onoff_set(pcf50633_global,
- PCF50633_REGULATOR_LDO4, 0);
+ regulator = regulator_get(&pdev->dev, "BT_3V2");
+ if (IS_ERR(regulator))
+ return -ENODEV;
+
+ bt_data->regulator = regulator;
+
+ /* this tests the true physical state of the regulator... */
+ if (regulator_is_enabled(regulator)) {
+ /*
+ * but these only operate on the logical state of the
+ * regulator... so we need to logicaly "adopt" it on
+ * to turn it off
+ */
+ regulator_enable(regulator);
+ regulator_disable(regulator);
+ }
+
/* we pull reset to low to make sure that the chip doesn't
* drain power through the reset line */
neo1973_gpb_setpin(GTA02_GPIO_BT_EN, 0);
@@ -187,25 +272,42 @@ static int __init gta01_bt_probe(struct platform_device *pdev)
rfkill->state = RFKILL_STATE_OFF;
rfkill->toggle_radio = bt_rfkill_toggle_radio;
- if (rfkill_register(rfkill) < 0) {
- /* We can live if it fails to register, but report it. */
- dev_dbg(&pdev->dev, DRVMSG ": RFKILL registration failed\n");
+ ret = rfkill_register(rfkill);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register rfkill\n");
+ return ret;
}
- platform_set_drvdata(pdev, rfkill);
+ bt_data->rfkill = rfkill;
return sysfs_create_group(&pdev->dev.kobj, &gta01_bt_attr_group);
}
static int gta01_bt_remove(struct platform_device *pdev)
{
- struct rfkill *rfkill = platform_get_drvdata(pdev);
+ struct gta01_pm_bt_data *bt_data = dev_get_drvdata(&pdev->dev);
+ struct regulator *regulator;
sysfs_remove_group(&pdev->dev.kobj, &gta01_bt_attr_group);
- rfkill_unregister(rfkill);
- rfkill_free(rfkill);
+ if (bt_data->rfkill) {
+ rfkill_unregister(bt_data->rfkill);
+ rfkill_free(bt_data->rfkill);
+ }
+
+ if (!bt_data || !bt_data->regulator)
+ return 0;
+
+ regulator = bt_data->regulator;
+
+ /* Make sure regulator is disabled before calling regulator_put */
+ if (regulator_is_enabled(regulator))
+ regulator_disable(regulator);
+
+ regulator_put(regulator);
+ kfree(bt_data);
+
return 0;
}
diff --git a/arch/arm/plat-s3c24xx/neo1973_pm_gps.c b/arch/arm/plat-s3c24xx/neo1973_pm_gps.c
index 26a49d4fbd4..84785dfa52a 100644
--- a/arch/arm/plat-s3c24xx/neo1973_pm_gps.c
+++ b/arch/arm/plat-s3c24xx/neo1973_pm_gps.c
@@ -422,6 +422,8 @@ static ssize_t power_gps_write(struct device *dev,
/* This is the nRESET pin */
static void gps_rst_set(int on)
{
+ struct regulator *regulator = neo1973_gps.regulator[GTA01_GPS_REG_2V5];
+
switch (system_rev) {
case GTA01v3_SYSTEM_REV:
pcf50606_gpo_set_active(gta01_pcf, PCF50606_GPO1, on);
@@ -437,6 +439,8 @@ static void gps_rst_set(int on)
static int gps_rst_get(void)
{
+ struct regulator *regulator = neo1973_gps.regulator[GTA01_GPS_REG_1V5];
+
switch (system_rev) {
case GTA01v3_SYSTEM_REV:
return pcf50606_gpo_get_active(gta01_pcf, PCF50606_GPO1);
diff --git a/drivers/input/misc/pcf50606-input.c b/drivers/input/misc/pcf50606-input.c
index 0e4564c4c82..044438ed662 100644
--- a/drivers/input/misc/pcf50606-input.c
+++ b/drivers/input/misc/pcf50606-input.c
@@ -12,92 +12,109 @@
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 060, Boston,
- * MA 02111-1307 USA
*/
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/mfd/pcf50606/core.h>
-#include <linux/mfd/pcf50606/input.h>
+
+#define PCF50606_OOCS_ONKEY 0x01
+#define PCF50606_OOCS_EXTON 0x02
+
+#define PCF50606_OOCC2_ONKEYDB_NONE 0x00
+#define PCF50606_OOCC2_ONKEYDB_14ms 0x01
+#define PCF50606_OOCC2_ONKEYDB_62ms 0x02
+#define PCF50606_OOCC2_ONKEYDB_500ms 0x03
+#define PCF50606_OOCC2_EXTONDB_NONE 0x00
+#define PCF50606_OOCC2_EXTONDB_14ms 0x04
+#define PCF50606_OOCC2_EXTONDB_62ms 0x08
+#define PCF50606_OOCC2_EXTONDB_500ms 0x0c
+
+#define PCF50606_REG_OOCS 0x01
+
+struct pcf50606_input {
+ struct pcf50606 *pcf;
+ struct input_dev *input_dev;
+};
static void
-pcf50606_input_irq(struct pcf50606 *pcf, int irq, void *data)
+pcf50606_input_irq(int irq, void *data)
{
- struct input_dev *input_dev = pcf->input.input_dev;
+ struct pcf50606_input *input;
int onkey_released;
- /* We report only one event depending on if the key status */
- onkey_released = pcf50606_reg_read(pcf, PCF50606_REG_OOCS) &
- PCF50606_OOCS_ONKEY;
+ input = data;
+ onkey_released = pcf50606_reg_read(input->pcf, PCF50606_REG_OOCS) &
+ PCF50606_OOCS_ONKEY;
if (irq == PCF50606_IRQ_ONKEYF && !onkey_released)
- input_report_key(input_dev, KEY_POWER, 1);
+ input_report_key(input->input_dev, KEY_POWER, 1);
else if (irq == PCF50606_IRQ_ONKEYR && onkey_released)
- input_report_key(input_dev, KEY_POWER, 0);
+ input_report_key(input->input_dev, KEY_POWER, 0);
- input_sync(input_dev);
+ input_sync(input->input_dev);
}
-int __init pcf50606_input_probe(struct platform_device *pdev)
+static int __devinit pcf50606_input_probe(struct platform_device *pdev)
{
- struct pcf50606 *pcf;
+ struct pcf50606_input *input;
+ struct pcf50606_subdev_pdata *pdata = pdev->dev.platform_data;
struct input_dev *input_dev;
int ret;
- pcf = platform_get_drvdata(pdev);
+
+ input = kzalloc(sizeof(*input), GFP_KERNEL);
+ if (!input)
+ return -ENOMEM;
input_dev = input_allocate_device();
- if (!input_dev)
- return -ENODEV;
+ if (!input_dev) {
+ kfree(input);
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, input);
+ input->pcf = pdata->pcf;
+ input->input_dev = input_dev;
input_dev->name = "PCF50606 PMU events";
input_dev->id.bustype = BUS_I2C;
-
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_PWR);
set_bit(KEY_POWER, input_dev->keybit);
- set_bit(KEY_POWER2, input_dev->keybit);
ret = input_register_device(input_dev);
- if (ret)
- goto out;
-
- pcf->input.input_dev = input_dev;
-
- /* Currently we care only about ONKEY and USBINS/USBREM
- *
- * USBINS/USBREM are told to us by mbc driver as we can't setup
- * two handlers for an IRQ
- */
- pcf->irq_handler[PCF50606_IRQ_ONKEYR].handler = pcf50606_input_irq;
-
- pcf->irq_handler[PCF50606_IRQ_ONKEYF].handler = pcf50606_input_irq;
+ if (ret) {
+ input_free_device(input_dev);
+ kfree(input);
+ return ret;
+ }
+ pcf50606_register_irq(pdata->pcf, PCF50606_IRQ_ONKEYR,
+ pcf50606_input_irq, input);
+ pcf50606_register_irq(pdata->pcf, PCF50606_IRQ_ONKEYF,
+ pcf50606_input_irq, input);
return 0;
-
-out:
- input_free_device(input_dev);
- return ret;
}
static int __devexit pcf50606_input_remove(struct platform_device *pdev)
{
- struct pcf50606 *pcf;
+ struct pcf50606_input *input = platform_get_drvdata(pdev);
+
+ input_unregister_device(input->input_dev);
+ pcf50606_free_irq(input->pcf, PCF50606_IRQ_ONKEYR);
+ pcf50606_free_irq(input->pcf, PCF50606_IRQ_ONKEYF);
- pcf = platform_get_drvdata(pdev);
- input_unregister_device(pcf->input.input_dev);
+ kfree(input);
return 0;
}
-struct platform_driver pcf50606_input_driver = {
+static struct platform_driver pcf50606_input_driver = {
.driver = {
.name = "pcf50606-input",
},
@@ -107,13 +124,13 @@ struct platform_driver pcf50606_input_driver = {
static int __init pcf50606_input_init(void)
{
- return platform_driver_register(&pcf50606_input_driver);
+ return platform_driver_register(&pcf50606_input_driver);
}
module_init(pcf50606_input_init);
static void __exit pcf50606_input_exit(void)
{
- platform_driver_unregister(&pcf50606_input_driver);
+ platform_driver_unregister(&pcf50606_input_driver);
}
module_exit(pcf50606_input_exit);