diff options
author | Balaji Rao <balajirrao@openmoko.org> | 2009-01-27 14:38:49 +0000 |
---|---|---|
committer | Andy Green <agreen@octopus.localdomain> | 2009-01-27 14:38:49 +0000 |
commit | 57a4af9be7051302edc51c878ecfbd90466827ff (patch) | |
tree | 51c5f9149184b63de61af0ba5dc79fa931c5aab7 /arch | |
parent | cc0a09e9e49f6121622d8579b23018e378a29e23 (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.
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-s3c2410/Kconfig | 12 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/include/mach/gta01.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-s3c2410/mach-gta01.c | 470 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/neo1973_pm_bt.c | 188 | ||||
-rw-r--r-- | arch/arm/plat-s3c24xx/neo1973_pm_gps.c | 4 |
5 files changed, 464 insertions, 212 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 = >a01_pm_gps_dev.dev, + .supply = "GPS_2V8", + }, +}; + +static struct regulator_consumer_supply d1reg_consumers[] = { + { + .dev = >a01_pm_gps_dev.dev, + .supply = "GPS_3V", + }, + { + .dev = >a01_pm_bt_dev.dev, + .supply = "BT_3V1", + }, +}; + +static struct regulator_consumer_supply dcd_consumers[] = { + { + .dev = >a01_pm_gps_dev.dev, + .supply = "GPS_3V3", + }, + { + .dev = >a01_pm_gps_dev.dev, + .supply = "GPS_1V5", + }, +}; + +static struct regulator_consumer_supply d2reg_consumers[] = { + { + .dev = >a01_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 = >a01_bat_pdata, + } +}; + +static void gta01_pcf_probe_done(struct pcf50606 *pcf) +{ + gta01_pcf = pcf; + gta01_bat.dev.parent = pcf->dev; + platform_device_register(>a01_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(>a01_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(>a01_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(>a01_pcf_pdata.rails[PCF50606_REGULATOR_DCUD], - "core_1v8", PMU_VRAIL_F_SUSPEND_ON, 1800, 1800); - cfg_pmu_vrail(>a01_pcf_pdata.rails[PCF50606_REGULATOR_D1REG], - "vrf_3v", 0, 3000, 3000); - cfg_pmu_vrail(>a01_pcf_pdata.rails[PCF50606_REGULATOR_D3REG], - "vtcxo_2v8", 0, 2800, 2800); - cfg_pmu_vrail(>a01_pcf_pdata.rails[PCF50606_REGULATOR_DCD], - "gl_3v5", 0, 3500, 3500); + cfg_pmu_vrail(®_init_data[PCF50606_REGULATOR_DCUD], + 1, 18000000, 1800000); + cfg_pmu_vrail(®_init_data[PCF50606_REGULATOR_D1REG], + 0, 3000000, 3000000); + cfg_pmu_vrail(®_init_data[PCF50606_REGULATOR_D3REG], + 0, 2800000, 2800000); + cfg_pmu_vrail(®_init_data[PCF50606_REGULATOR_DCD], + 0, 3500000, 3500000); break; case GTA01v3_SYSTEM_REV: - cfg_pmu_vrail(>a01_pcf_pdata.rails[PCF50606_REGULATOR_D1REG], - "vrf_3v", 0, 3000, 3000); - cfg_pmu_vrail(>a01_pcf_pdata.rails[PCF50606_REGULATOR_D2REG], - "sd_3v3", 0, 3300, 3300); - cfg_pmu_vrail(>a01_pcf_pdata.rails[PCF50606_REGULATOR_D3REG], - "codec_3v3", 0, 3300, 3300); - cfg_pmu_vrail(>a01_pcf_pdata.rails[PCF50606_REGULATOR_DCD], - "gpsio_3v3", 0, 3300, 3300); - cfg_pmu_vrail(>a01_pcf_pdata.rails[PCF50606_REGULATOR_DCUD], - "core_1v8", PMU_VRAIL_F_SUSPEND_ON, 1800, 1800); - cfg_pmu_vrail(>a01_pcf_pdata.rails[PCF50606_REGULATOR_IOREG], - "vtcxo_2v8", 0, 2800, 2800); + cfg_pmu_vrail(®_init_data[PCF50606_REGULATOR_D1REG], + 0, 3000000, 3000000); + cfg_pmu_vrail(®_init_data[PCF50606_REGULATOR_D2REG], + 0, 3300000, 3300000); + cfg_pmu_vrail(®_init_data[PCF50606_REGULATOR_D3REG], + 0, 3300000, 3300000); + cfg_pmu_vrail(®_init_data[PCF50606_REGULATOR_DCD], + 0, 3300000, 3300000); + cfg_pmu_vrail(®_init_data[PCF50606_REGULATOR_DCUD], + 1, 1800000, 1800000); + cfg_pmu_vrail(®_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 = >a01_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 = >a01_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 = >a01_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(>a01_pmu_dev); + i2c_register_board_info(0, gta01_i2c_devs, ARRAY_SIZE(gta01_i2c_devs)); + platform_device_register(>a01_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 = >a01_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, >a01_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, >a01_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); |