summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorSeshendra Gadagottu <sgadagottu@nvidia.com>2011-08-25 11:23:33 +0530
committerVarun Colbert <vcolbert@nvidia.com>2011-08-25 17:04:17 -0700
commite6c9a8d0f9ac779f14b09fdf80732615b41f878f (patch)
treee0409bf92dbd5d00d09a4bf200853933eb99c65c /arch
parent9b70b4ab5f94852229937055cd8ea7526a2e2f63 (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 Change-Id: Icfbe83beeac43f88418eee29f71ccd58d9b840c2 Reviewed-on: http://git-master/r/47773 Tested-by: Seshendra Gadagottu <sgadagottu@nvidia.com> Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-tegra/Makefile2
-rw-r--r--arch/arm/mach-tegra/baseband-xmm-power.c150
2 files changed, 148 insertions, 4 deletions
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 469753761171..8f509f537ee8 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -143,7 +143,7 @@ obj-${CONFIG_MACH_CARDHU} += board-cardhu-sensors.o
obj-${CONFIG_MACH_CARDHU} += board-touch.o
obj-${CONFIG_MACH_CARDHU} += board-cardhu-memory.o
obj-${CONFIG_MACH_CARDHU} += board-cardhu-powermon.o
-obj-m += baseband-xmm-power.o
+obj-${CONFIG_MACH_CARDHU} += baseband-xmm-power.o
obj-m += baseband-xmm-power2.o
obj-${CONFIG_MACH_TEGRA_ENTERPRISE} += board-enterprise.o
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);