diff options
author | Seshendra Gadagottu <sgadagottu@nvidia.com> | 2011-08-25 11:23:33 +0530 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:48:36 -0800 |
commit | db37f4fd1cef2f0ccc537c43c659ef541e609471 (patch) | |
tree | f890464358434a575ac4462239d6098226100724 /arch/arm/mach-tegra/baseband-xmm-power.c | |
parent | 937fe80954484d276bd55db8745718985ac8f2c3 (diff) |
arm : tegra: sysfs interface for xmm power module on/off
Now xmm power module made static part of the kernel.
xmm modem can be on/off using the sysfs interface.
BUG 828389
Original-Change-Id: Icfbe83beeac43f88418eee29f71ccd58d9b840c2
Reviewed-on: http://git-master/r/47773
Tested-by: Seshendra Gadagottu <sgadagottu@nvidia.com>
Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Rebase-Id: R3adb92f2a3f3523c1006969a42499263dd0fa6fb
Diffstat (limited to 'arch/arm/mach-tegra/baseband-xmm-power.c')
-rw-r--r-- | arch/arm/mach-tegra/baseband-xmm-power.c | 150 |
1 files changed, 147 insertions, 3 deletions
diff --git a/arch/arm/mach-tegra/baseband-xmm-power.c b/arch/arm/mach-tegra/baseband-xmm-power.c index a8df78bf20b2..b9ad58e89c70 100644 --- a/arch/arm/mach-tegra/baseband-xmm-power.c +++ b/arch/arm/mach-tegra/baseband-xmm-power.c @@ -23,6 +23,8 @@ #include <linux/interrupt.h> #include <linux/workqueue.h> #include <linux/delay.h> +#include <linux/fs.h> +#include <linux/uaccess.h> #include <mach/usb_phy.h> #include "board.h" #include "devices.h" @@ -37,6 +39,8 @@ module_param(enum_delay_ms, ulong, 0644); MODULE_PARM_DESC(enum_delay_ms, "baseband xmm power" " - delay in ms between modem on and enumeration"); +#define TEGRA_EHCI_DEVICE "/sys/devices/platform/tegra-ehci.1/ehci_power" + /* Currently no baseband initiated suspend */ #define BB_INITIATED_L2_SUSPEND 0 @@ -85,6 +89,132 @@ static struct workqueue_struct *workqueue; static struct work_struct init1_work; static struct work_struct init2_work; static struct baseband_power_platform_data *baseband_power_driver_data; +static bool register_hsic_device; + +/* static functions */ +static int baseband_xmm_power_on(struct platform_device *device); +static int baseband_xmm_power_off(struct platform_device *device); + +static ssize_t baseband_xmm_onoff(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int power_onoff; + struct platform_device *device = to_platform_device(dev); + + pr_debug("%s\n", __func__); + + if (sscanf(buf, "%d", &power_onoff) != 1) + return -EINVAL; + + if (power_onoff == 0) + baseband_xmm_power_off(device); + else if (power_onoff == 1) + baseband_xmm_power_on(device); + return count; +} + +static DEVICE_ATTR(xmm_onoff, S_IRUSR | S_IWUSR | S_IRGRP, + NULL, baseband_xmm_onoff); + +static int baseband_xmm_power_on(struct platform_device *device) +{ + int value; + struct baseband_power_platform_data *data + = (struct baseband_power_platform_data *) device->dev.platform_data; + + pr_debug("%s{\n", __func__); + + /* check for platform data */ + if (!baseband_power_driver_data) + return -EINVAL; + + /* check if IPC_HSIC_ACTIVE low */ + value = gpio_get_value(baseband_power_driver_data-> + modem.xmm.ipc_hsic_active); + if (value != 0) { + pr_err("%s - expected IPC_HSIC_ACTIVE low!\n", __func__); + return -EINVAL; + } + + /* reset the state machine */ + baseband_xmm_powerstate = BBXMM_PS_INIT; + ipc_ap_wake_state = IPC_AP_WAKE_IRQ_READY; + + /* set IPC_HSIC_ACTIVE high */ + gpio_set_value(baseband_power_driver_data-> + modem.xmm.ipc_hsic_active, 1); + + /* wait 20 ms */ + mdelay(20); + + /* reset / power on sequence */ + mdelay(40); + gpio_set_value(data->modem.xmm.bb_rst, 1); + mdelay(1); + gpio_set_value(data->modem.xmm.bb_on, 1); + udelay(40); + gpio_set_value(data->modem.xmm.bb_on, 0); + + if (enum_delay_ms) + mdelay(enum_delay_ms); + + /* turn on usb host controller */ + { + mm_segment_t oldfs; + struct file *filp; + oldfs = get_fs(); + set_fs(KERNEL_DS); + filp = filp_open(TEGRA_EHCI_DEVICE, O_RDWR, 0); + if (!filp) { + pr_err("open ehci_power failed\n"); + } else { + filp->f_op->write(filp, "1", 1, &filp->f_pos); + filp_close(filp, NULL); + } + set_fs(oldfs); + } + + pr_debug("%s }\n", __func__); + + return 0; +} + +static int baseband_xmm_power_off(struct platform_device *device) +{ + struct baseband_power_platform_data *data + = (struct baseband_power_platform_data *) device->dev.platform_data; + + pr_debug("%s\n", __func__); + + /* turn off usb host controller */ + { + mm_segment_t oldfs; + struct file *filp; + oldfs = get_fs(); + set_fs(KERNEL_DS); + filp = filp_open(TEGRA_EHCI_DEVICE, O_RDWR, 0); + if (!filp) { + pr_err("open ehci_power failed\n"); + } else { + filp->f_op->write(filp, "0", 1, &filp->f_pos); + filp_close(filp, NULL); + } + set_fs(oldfs); + } + + /* set IPC_HSIC_ACTIVE low */ + gpio_set_value(baseband_power_driver_data-> + modem.xmm.ipc_hsic_active, 0); + /* wait 20 ms */ + mdelay(20); + + /* drive bb_rst low */ + gpio_set_value(data->modem.xmm.bb_rst, 0); + mdelay(1); + + return 0; +} static void baseband_xmm_set_power_status(unsigned int status) { @@ -213,9 +343,12 @@ static void baseband_xmm_power_init2_work(struct work_struct *work) { pr_debug("%s\n", __func__); - /* register usb host controller */ - platform_device_register(baseband_power_driver_data-> - modem.xmm.hsic_device); + /* register usb host controller only once */ + if (register_hsic_device) { + platform_device_register(baseband_power_driver_data-> + modem.xmm.hsic_device); + register_hsic_device = false; + } baseband_xmm_set_power_status(BBXMM_PS_L0); @@ -223,12 +356,14 @@ static void baseband_xmm_power_init2_work(struct work_struct *work) static int baseband_xmm_power_driver_probe(struct platform_device *device) { + struct device *dev = &device->dev; struct baseband_power_platform_data *data = (struct baseband_power_platform_data *) device->dev.platform_data; int err; pr_debug("%s\n", __func__); + register_hsic_device = true; baseband_xmm_powerstate = BBXMM_PS_UNINIT; /* check if supported modem */ if (data->baseband_type != BASEBAND_XMM) { @@ -236,6 +371,12 @@ static int baseband_xmm_power_driver_probe(struct platform_device *device) return -ENODEV; } + err = device_create_file(dev, &dev_attr_xmm_onoff); + if (err < 0) { + pr_err("%s - device_create_file failed\n", __func__); + return -ENODEV; + } + /* save platform data */ baseband_power_driver_data = data; @@ -324,6 +465,7 @@ static int baseband_xmm_power_driver_probe(struct platform_device *device) static int baseband_xmm_power_driver_remove(struct platform_device *device) { + struct device *dev = &device->dev; struct baseband_power_platform_data *data = (struct baseband_power_platform_data *) device->dev.platform_data; @@ -341,6 +483,8 @@ static int baseband_xmm_power_driver_remove(struct platform_device *device) gpio_free_array(tegra_baseband_gpios, ARRAY_SIZE(tegra_baseband_gpios)); + device_remove_file(dev, &dev_attr_xmm_onoff); + /* unregister usb host controller */ platform_device_unregister(baseband_power_driver_data-> modem.xmm.hsic_device); |