Merge "msm: mdm: Add mdm2 driver." into msm-3.0

This commit is contained in:
Linux Build Service Account
2011-11-23 18:39:26 -08:00
committed by QuIC Gerrit Code Review
5 changed files with 761 additions and 0 deletions
+2
View File
@@ -301,3 +301,5 @@ obj-$(CONFIG_MACH_MSM7X27_FFA) += board-msm7627-regulator.o
obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30-regulator.o
obj-$(CONFIG_ARCH_MSM7X27A) += board-msm7x27a-regulator.o
endif
obj-$(CONFIG_ARCH_MSM8960) += mdm2.o mdm_common.o
+21
View File
@@ -0,0 +1,21 @@
/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#ifndef _ARCH_ARM_MACH_MSM_MDM2_H
#define _ARCH_ARM_MACH_MSM_MDM2_H
struct mdm_platform_data {
char *mdm_version;
};
#endif
+176
View File
@@ -0,0 +1,176 @@
/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/ioctl.h>
#include <linux/delay.h>
#include <linux/reboot.h>
#include <linux/debugfs.h>
#include <linux/completion.h>
#include <linux/workqueue.h>
#include <linux/clk.h>
#include <linux/mfd/pmic8058.h>
#include <asm/mach-types.h>
#include <asm/uaccess.h>
#include <mach/mdm2.h>
#include <mach/restart.h>
#include <mach/subsystem_notif.h>
#include <mach/subsystem_restart.h>
#include <linux/msm_charm.h>
#include "msm_watchdog.h"
#include "devices.h"
#include "clock.h"
#include "mdm_private.h"
#define MDM_MODEM_TIMEOUT 6000
#define MDM_HOLD_TIME 4000
#define MDM_MODEM_DELTA 100
#define IFLINE_UP 1
#define IFLINE_DOWN 0
static int mdm_debug_on;
static int ifline_status = IFLINE_UP;
static struct mdm_callbacks mdm_cb;
#define MDM_DBG(...) do { if (mdm_debug_on) \
pr_info(__VA_ARGS__); \
} while (0);
static void power_on_mdm(struct mdm_modem_drv *mdm_drv)
{
/* Remove hsic driver before powering on the modem. */
if (ifline_status == IFLINE_UP) {
MDM_DBG("%s: Removing hsic device\n", __func__);
platform_device_del(&msm_device_hsic_host);
ifline_status = IFLINE_DOWN;
}
/* Pull both ERR_FATAL and RESET low */
MDM_DBG("Pulling PWR and RESET gpio's low\n");
gpio_direction_output(mdm_drv->ap2mdm_pmic_reset_n_gpio, 0);
gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 0);
/* Wait for them to settle. */
usleep(1000);
/* Deassert RESET first and wait for ir to settle. */
MDM_DBG("%s: Pulling RESET gpio high\n", __func__);
gpio_direction_output(mdm_drv->ap2mdm_pmic_reset_n_gpio, 1);
usleep(1000);
/* Pull PWR gpio high and wait for it to settle. */
MDM_DBG("%s: Powering on mdm modem\n", __func__);
gpio_direction_output(mdm_drv->ap2mdm_kpdpwr_n_gpio, 1);
usleep(1000);
/* Add back hsic device after modem power up */
MDM_DBG("%s: Adding hsic device\n", __func__);
platform_device_add(&msm_device_hsic_host);
ifline_status = IFLINE_UP;
msleep(200);
}
static void power_down_mdm(struct mdm_modem_drv *mdm_drv)
{
int i;
for (i = MDM_MODEM_TIMEOUT; i > 0; i -= MDM_MODEM_DELTA) {
pet_watchdog();
msleep(MDM_MODEM_DELTA);
if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
break;
}
if (i <= 0) {
pr_err("%s: MDM2AP_STATUS never went low.\n",
__func__);
gpio_direction_output(mdm_drv->ap2mdm_pmic_reset_n_gpio, 0);
for (i = MDM_HOLD_TIME; i > 0; i -= MDM_MODEM_DELTA) {
pet_watchdog();
msleep(MDM_MODEM_DELTA);
}
}
/* Also remove the hsic device on 9k power down. */
MDM_DBG("%s: Removing hsic device\n", __func__);
if (ifline_status == IFLINE_UP) {
platform_device_del(&msm_device_hsic_host);
ifline_status = IFLINE_DOWN;
}
}
static void normal_boot_done(struct mdm_modem_drv *mdm_drv)
{
}
static void debug_state_changed(int value)
{
mdm_debug_on = value;
}
static int __init mdm_modem_probe(struct platform_device *pdev)
{
/* Instantiate driver object. */
mdm_cb.power_on_mdm_cb = power_on_mdm;
mdm_cb.power_down_mdm_cb = power_down_mdm;
mdm_cb.normal_boot_done_cb = normal_boot_done;
mdm_cb.debug_state_changed_cb = debug_state_changed;
return mdm_common_create(pdev, &mdm_cb);
}
static int __devexit mdm_modem_remove(struct platform_device *pdev)
{
return mdm_common_modem_remove(pdev);
}
static void mdm_modem_shutdown(struct platform_device *pdev)
{
mdm_common_modem_shutdown(pdev);
}
static struct platform_driver mdm_modem_driver = {
.remove = mdm_modem_remove,
.shutdown = mdm_modem_shutdown,
.driver = {
.name = "mdm2_modem",
.owner = THIS_MODULE
},
};
static int __init mdm_modem_init(void)
{
return platform_driver_probe(&mdm_modem_driver, mdm_modem_probe);
}
static void __exit mdm_modem_exit(void)
{
platform_driver_unregister(&mdm_modem_driver);
}
module_init(mdm_modem_init);
module_exit(mdm_modem_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("mdm modem driver");
MODULE_VERSION("2.0");
MODULE_ALIAS("mdm_modem");
+505
View File
@@ -0,0 +1,505 @@
/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/ioctl.h>
#include <linux/delay.h>
#include <linux/reboot.h>
#include <linux/debugfs.h>
#include <linux/completion.h>
#include <linux/workqueue.h>
#include <linux/clk.h>
#include <linux/mfd/pmic8058.h>
#include <asm/mach-types.h>
#include <asm/uaccess.h>
#include <mach/mdm2.h>
#include <mach/restart.h>
#include <mach/subsystem_notif.h>
#include <mach/subsystem_restart.h>
#include <linux/msm_charm.h>
#include "msm_watchdog.h"
#include "mdm_private.h"
#define MDM_MODEM_TIMEOUT 6000
#define MDM_MODEM_DELTA 100
static int mdm_debug_on;
static struct workqueue_struct *mdm_queue;
#define EXTERNAL_MODEM "external_modem"
#define MDM_DBG(...) do { if (mdm_debug_on) \
pr_info(__VA_ARGS__); \
} while (0);
static struct mdm_modem_drv *mdm_drv;
DECLARE_COMPLETION(mdm_needs_reload);
DECLARE_COMPLETION(mdm_boot);
DECLARE_COMPLETION(mdm_ram_dumps);
static int first_boot = 1;
long mdm_modem_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int status, ret = 0;
if (_IOC_TYPE(cmd) != CHARM_CODE) {
pr_err("%s: invalid ioctl code\n", __func__);
return -EINVAL;
}
MDM_DBG("%s: Entering ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
switch (cmd) {
case WAKE_CHARM:
MDM_DBG("%s: Powering on\n", __func__);
mdm_drv->power_on_mdm_cb(mdm_drv);
break;
case CHECK_FOR_BOOT:
if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
put_user(1, (unsigned long __user *) arg);
else
put_user(0, (unsigned long __user *) arg);
break;
case NORMAL_BOOT_DONE:
MDM_DBG("%s: check if mdm is booted up\n", __func__);
get_user(status, (unsigned long __user *) arg);
if (status)
mdm_drv->mdm_boot_status = -EIO;
else
mdm_drv->mdm_boot_status = 0;
mdm_drv->mdm_ready = 1;
if (mdm_drv->normal_boot_done_cb != NULL)
mdm_drv->normal_boot_done_cb(mdm_drv);
if (!first_boot)
complete(&mdm_boot);
else
first_boot = 0;
break;
case RAM_DUMP_DONE:
MDM_DBG("%s: mdm done collecting RAM dumps\n", __func__);
get_user(status, (unsigned long __user *) arg);
if (status)
mdm_drv->mdm_ram_dump_status = -EIO;
else
mdm_drv->mdm_ram_dump_status = 0;
complete(&mdm_ram_dumps);
break;
case WAIT_FOR_RESTART:
MDM_DBG("%s: wait for mdm to need images reloaded\n",
__func__);
ret = wait_for_completion_interruptible(&mdm_needs_reload);
if (!ret)
put_user(mdm_drv->boot_type,
(unsigned long __user *) arg);
INIT_COMPLETION(mdm_needs_reload);
break;
default:
pr_err("%s: invalid ioctl cmd = %d\n", __func__, _IOC_NR(cmd));
ret = -EINVAL;
break;
}
return ret;
}
static void mdm_fatal_fn(struct work_struct *work)
{
MDM_DBG("%s: Reseting the mdm due to an errfatal\n", __func__);
subsystem_restart(EXTERNAL_MODEM);
}
static DECLARE_WORK(mdm_fatal_work, mdm_fatal_fn);
static void mdm_status_fn(struct work_struct *work)
{
MDM_DBG("%s: Reseting the mdm because status changed\n", __func__);
subsystem_restart(EXTERNAL_MODEM);
}
static DECLARE_WORK(mdm_status_work, mdm_status_fn);
static void mdm_disable_irqs(void)
{
disable_irq_nosync(mdm_drv->mdm_errfatal_irq);
disable_irq_nosync(mdm_drv->mdm_status_irq);
}
static irqreturn_t mdm_errfatal(int irq, void *dev_id)
{
MDM_DBG("%s: mdm got errfatal interrupt\n", __func__);
if (mdm_drv->mdm_ready &&
(gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 1)) {
MDM_DBG("%s: scheduling work now\n", __func__);
queue_work(mdm_queue, &mdm_fatal_work);
}
return IRQ_HANDLED;
}
static int mdm_modem_open(struct inode *inode, struct file *file)
{
return 0;
}
static const struct file_operations mdm_modem_fops = {
.owner = THIS_MODULE,
.open = mdm_modem_open,
.unlocked_ioctl = mdm_modem_ioctl,
};
static struct miscdevice mdm_modem_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "mdm",
.fops = &mdm_modem_fops
};
static int mdm_panic_prep(struct notifier_block *this,
unsigned long event, void *ptr)
{
int i;
MDM_DBG("%s: setting AP2MDM_ERRFATAL high for a non graceful reset\n",
__func__);
mdm_disable_irqs();
gpio_set_value(mdm_drv->ap2mdm_errfatal_gpio, 1);
if (mdm_drv->ap2mdm_wakeup_gpio > 0)
gpio_set_value(mdm_drv->ap2mdm_wakeup_gpio, 1);
for (i = MDM_MODEM_TIMEOUT; i > 0; i -= MDM_MODEM_DELTA) {
pet_watchdog();
mdelay(MDM_MODEM_DELTA);
if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
break;
}
if (i <= 0)
pr_err("%s: MDM2AP_STATUS never went low\n", __func__);
return NOTIFY_DONE;
}
static struct notifier_block mdm_panic_blk = {
.notifier_call = mdm_panic_prep,
};
static irqreturn_t mdm_status_change(int irq, void *dev_id)
{
MDM_DBG("%s: mdm sent status change interrupt\n", __func__);
if ((gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
&& mdm_drv->mdm_ready) {
MDM_DBG("%s: scheduling work now\n", __func__);
queue_work(mdm_queue, &mdm_status_work);
} else if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 1) {
MDM_DBG("%s: mdm is now ready\n", __func__);
}
return IRQ_HANDLED;
}
static int mdm_subsys_shutdown(const struct subsys_data *crashed_subsys)
{
mdm_drv->mdm_ready = 0;
gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
mdm_drv->power_down_mdm_cb(mdm_drv);
return 0;
}
static int mdm_subsys_powerup(const struct subsys_data *crashed_subsys)
{
mdm_drv->power_on_mdm_cb(mdm_drv);
mdm_drv->boot_type = CHARM_NORMAL_BOOT;
complete(&mdm_needs_reload);
wait_for_completion(&mdm_boot);
pr_info("%s: mdm modem has been restarted\n", __func__);
INIT_COMPLETION(mdm_boot);
return mdm_drv->mdm_boot_status;
}
static int mdm_subsys_ramdumps(int want_dumps,
const struct subsys_data *crashed_subsys)
{
mdm_drv->mdm_ram_dump_status = 0;
if (want_dumps) {
mdm_drv->boot_type = CHARM_RAM_DUMPS;
complete(&mdm_needs_reload);
wait_for_completion(&mdm_ram_dumps);
INIT_COMPLETION(mdm_ram_dumps);
gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 1);
mdm_drv->power_down_mdm_cb(mdm_drv);
}
return mdm_drv->mdm_ram_dump_status;
}
static struct subsys_data mdm_subsystem = {
.shutdown = mdm_subsys_shutdown,
.ramdump = mdm_subsys_ramdumps,
.powerup = mdm_subsys_powerup,
.name = EXTERNAL_MODEM,
};
static int mdm_debug_on_set(void *data, u64 val)
{
mdm_debug_on = val;
if (mdm_drv->debug_state_changed_cb)
mdm_drv->debug_state_changed_cb(mdm_debug_on);
return 0;
}
static int mdm_debug_on_get(void *data, u64 *val)
{
*val = mdm_debug_on;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(mdm_debug_on_fops,
mdm_debug_on_get,
mdm_debug_on_set, "%llu\n");
static int mdm_debugfs_init(void)
{
struct dentry *dent;
dent = debugfs_create_dir("mdm_dbg", 0);
if (IS_ERR(dent))
return PTR_ERR(dent);
debugfs_create_file("debug_on", 0644, dent, NULL,
&mdm_debug_on_fops);
return 0;
}
static void mdm_modem_initialize_data(struct platform_device *pdev,
struct mdm_callbacks *p_mdm_cb)
{
struct resource *pres;
/* MDM2AP_ERRFATAL */
pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
"MDM2AP_ERRFATAL");
if (pres)
mdm_drv->mdm2ap_errfatal_gpio = pres->start;
/* AP2MDM_ERRFATAL */
pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
"AP2MDM_ERRFATAL");
if (pres)
mdm_drv->ap2mdm_errfatal_gpio = pres->start;
/* MDM2AP_STATUS */
pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
"MDM2AP_STATUS");
if (pres)
mdm_drv->mdm2ap_status_gpio = pres->start;
/* AP2MDM_STATUS */
pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
"AP2MDM_STATUS");
if (pres)
mdm_drv->ap2mdm_status_gpio = pres->start;
/* MDM2AP_WAKEUP */
pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
"MDM2AP_WAKEUP");
if (pres)
mdm_drv->mdm2ap_wakeup_gpio = pres->start;
/* AP2MDM_WAKEUP */
pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
"AP2MDM_WAKEUP");
if (pres)
mdm_drv->ap2mdm_wakeup_gpio = pres->start;
/* AP2MDM_PMIC_RESET_N */
pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
"AP2MDM_PMIC_RESET_N");
if (pres)
mdm_drv->ap2mdm_pmic_reset_n_gpio = pres->start;
/* AP2MDM_KPDPWR_N */
pres = platform_get_resource_byname(pdev, IORESOURCE_IO,
"AP2MDM_KPDPWR_N");
if (pres)
mdm_drv->ap2mdm_kpdpwr_n_gpio = pres->start;
mdm_drv->boot_type = CHARM_NORMAL_BOOT;
mdm_drv->power_on_mdm_cb = p_mdm_cb->power_on_mdm_cb;
mdm_drv->power_down_mdm_cb = p_mdm_cb->power_down_mdm_cb;
mdm_drv->normal_boot_done_cb = p_mdm_cb->normal_boot_done_cb;
mdm_drv->debug_state_changed_cb = p_mdm_cb->debug_state_changed_cb;
}
int mdm_common_create(struct platform_device *pdev,
struct mdm_callbacks *p_mdm_cb)
{
int ret = -1, irq;
mdm_drv = kzalloc(sizeof(struct mdm_modem_drv), GFP_KERNEL);
if (mdm_drv == NULL) {
pr_err("%s: kzalloc fail.\n", __func__);
goto alloc_err;
}
mdm_modem_initialize_data(pdev, p_mdm_cb);
if (mdm_drv->debug_state_changed_cb)
mdm_drv->debug_state_changed_cb(mdm_debug_on);
gpio_request(mdm_drv->ap2mdm_status_gpio, "AP2MDM_STATUS");
gpio_request(mdm_drv->ap2mdm_errfatal_gpio, "AP2MDM_ERRFATAL");
gpio_request(mdm_drv->ap2mdm_kpdpwr_n_gpio, "AP2MDM_KPDPWR_N");
gpio_request(mdm_drv->ap2mdm_pmic_reset_n_gpio, "AP2MDM_PMIC_RESET_N");
gpio_request(mdm_drv->mdm2ap_status_gpio, "MDM2AP_STATUS");
gpio_request(mdm_drv->mdm2ap_errfatal_gpio, "MDM2AP_ERRFATAL");
if (mdm_drv->ap2mdm_wakeup_gpio > 0)
gpio_request(mdm_drv->ap2mdm_wakeup_gpio, "AP2MDM_WAKEUP");
gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
if (mdm_drv->ap2mdm_wakeup_gpio > 0)
gpio_direction_output(mdm_drv->ap2mdm_wakeup_gpio, 0);
gpio_direction_input(mdm_drv->mdm2ap_status_gpio);
gpio_direction_input(mdm_drv->mdm2ap_errfatal_gpio);
mdm_queue = create_singlethread_workqueue("mdm_queue");
if (!mdm_queue) {
pr_err("%s: could not create workqueue. All mdm "
"functionality will be disabled\n",
__func__);
ret = -ENOMEM;
goto fatal_err;
}
atomic_notifier_chain_register(&panic_notifier_list, &mdm_panic_blk);
mdm_debugfs_init();
/* Register subsystem handlers */
ssr_register_subsystem(&mdm_subsystem);
/* ERR_FATAL irq. */
irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_errfatal_gpio);
if (irq < 0) {
pr_err("%s: could not get MDM2AP_ERRFATAL IRQ resource. "
"error=%d No IRQ will be generated on errfatal.",
__func__, irq);
goto errfatal_err;
}
ret = request_irq(irq, mdm_errfatal,
IRQF_TRIGGER_RISING , "mdm errfatal", NULL);
if (ret < 0) {
pr_err("%s: MDM2AP_ERRFATAL IRQ#%d request failed with error=%d"
". No IRQ will be generated on errfatal.",
__func__, irq, ret);
goto errfatal_err;
}
mdm_drv->mdm_errfatal_irq = irq;
errfatal_err:
/* status irq */
irq = MSM_GPIO_TO_INT(mdm_drv->mdm2ap_status_gpio);
if (irq < 0) {
pr_err("%s: could not get MDM2AP_STATUS IRQ resource. "
"error=%d No IRQ will be generated on status change.",
__func__, irq);
goto status_err;
}
ret = request_threaded_irq(irq, NULL, mdm_status_change,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"mdm status", NULL);
if (ret < 0) {
pr_err("%s: MDM2AP_STATUS IRQ#%d request failed with error=%d"
". No IRQ will be generated on status change.",
__func__, irq, ret);
goto status_err;
}
mdm_drv->mdm_status_irq = irq;
status_err:
pr_info("%s: Registering mdm modem\n", __func__);
return misc_register(&mdm_modem_misc);
fatal_err:
gpio_free(mdm_drv->ap2mdm_status_gpio);
gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
gpio_free(mdm_drv->ap2mdm_pmic_reset_n_gpio);
gpio_free(mdm_drv->mdm2ap_status_gpio);
gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
if (mdm_drv->ap2mdm_wakeup_gpio > 0)
gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
kfree(mdm_drv);
ret = -ENODEV;
alloc_err:
return ret;
}
int mdm_common_modem_remove(struct platform_device *pdev)
{
int ret;
gpio_free(mdm_drv->ap2mdm_status_gpio);
gpio_free(mdm_drv->ap2mdm_errfatal_gpio);
gpio_free(mdm_drv->ap2mdm_kpdpwr_n_gpio);
gpio_free(mdm_drv->ap2mdm_pmic_reset_n_gpio);
gpio_free(mdm_drv->mdm2ap_status_gpio);
gpio_free(mdm_drv->mdm2ap_errfatal_gpio);
if (mdm_drv->ap2mdm_wakeup_gpio > 0)
gpio_free(mdm_drv->ap2mdm_wakeup_gpio);
kfree(mdm_drv);
ret = misc_deregister(&mdm_modem_misc);
return ret;
}
void mdm_common_modem_shutdown(struct platform_device *pdev)
{
MDM_DBG("%s: setting AP2MDM_STATUS low for a graceful restart\n",
__func__);
mdm_disable_irqs();
gpio_set_value(mdm_drv->ap2mdm_status_gpio, 0);
if (mdm_drv->ap2mdm_wakeup_gpio > 0)
gpio_set_value(mdm_drv->ap2mdm_wakeup_gpio, 1);
mdm_drv->power_down_mdm_cb(mdm_drv);
if (mdm_drv->ap2mdm_wakeup_gpio > 0)
gpio_set_value(mdm_drv->ap2mdm_wakeup_gpio, 0);
}
+57
View File
@@ -0,0 +1,57 @@
/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#ifndef _ARCH_ARM_MACH_MSM_MDM_PRIVATE_H
#define _ARCH_ARM_MACH_MSM_MDM_PRIVATE_H
struct mdm_modem_drv;
/* Private mdm2 data structure */
struct mdm_modem_drv {
unsigned mdm2ap_errfatal_gpio;
unsigned ap2mdm_errfatal_gpio;
unsigned mdm2ap_status_gpio;
unsigned ap2mdm_status_gpio;
unsigned mdm2ap_wakeup_gpio;
unsigned ap2mdm_wakeup_gpio;
unsigned ap2mdm_pmic_reset_n_gpio;
unsigned ap2mdm_kpdpwr_n_gpio;
int mdm_errfatal_irq;
int mdm_status_irq;
int mdm_ready;
int mdm_boot_status;
int mdm_ram_dump_status;
enum charm_boot_type boot_type;
int mdm_debug_on;
void (*power_on_mdm_cb)(struct mdm_modem_drv *mdm_drv);
void (*normal_boot_done_cb)(struct mdm_modem_drv *mdm_drv);
void (*power_down_mdm_cb)(struct mdm_modem_drv *mdm_drv);
void (*debug_state_changed_cb)(int value);
};
struct mdm_callbacks {
void (*power_on_mdm_cb)(struct mdm_modem_drv *mdm_drv);
void (*normal_boot_done_cb)(struct mdm_modem_drv *mdm_drv);
void (*power_down_mdm_cb)(struct mdm_modem_drv *mdm_drv);
void (*debug_state_changed_cb)(int value);
};
int mdm_common_create(struct platform_device *pdev,
struct mdm_callbacks *mdm_cb);
int mdm_common_modem_remove(struct platform_device *pdev);
void mdm_common_modem_shutdown(struct platform_device *pdev);
void mdm_common_set_debug_state(int value);
#endif