From 9b82de99832187cbadf1a2627400f7ec1e64a204 Mon Sep 17 00:00:00 2001 From: llj Date: Mon, 3 Jun 2013 14:49:36 +0800 Subject: [PATCH] add u5501 modem --- drivers/misc/bp/chips/Kconfig | 3 + drivers/misc/bp/chips/Makefile | 1 + drivers/misc/bp/chips/u5501.c | 349 +++++++++++++++++++++++++++++++++ 3 files changed, 353 insertions(+) create mode 100755 drivers/misc/bp/chips/u5501.c diff --git a/drivers/misc/bp/chips/Kconfig b/drivers/misc/bp/chips/Kconfig index ba45f960ebef..bf2367482d4e 100755 --- a/drivers/misc/bp/chips/Kconfig +++ b/drivers/misc/bp/chips/Kconfig @@ -22,3 +22,6 @@ bool "modem sew290" config BP_AUTO_U7501 bool "modem u7501" default n +config BP_AUTO_U5501 +bool "modem u5501" + default n \ No newline at end of file diff --git a/drivers/misc/bp/chips/Makefile b/drivers/misc/bp/chips/Makefile index 1015c0bd7be9..56bc1b54c3af 100755 --- a/drivers/misc/bp/chips/Makefile +++ b/drivers/misc/bp/chips/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_BP_AUTO) += c66a.o obj-$(CONFIG_BP_AUTO) += sew290.o obj-$(CONFIG_BP_AUTO) += u7501.o obj-$(CONFIG_BP_AUTO) += a85xx.o +obj-$(CONFIG_BP_AUTO) += u5501.o diff --git a/drivers/misc/bp/chips/u5501.c b/drivers/misc/bp/chips/u5501.c new file mode 100755 index 000000000000..c5fa41a56104 --- /dev/null +++ b/drivers/misc/bp/chips/u5501.c @@ -0,0 +1,349 @@ +/* drivers/misc/bp/chips/u5501.c + * + * Copyright (C) 2012-2015 ROCKCHIP. + * Author: luowei + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#if 0 +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + + +/****************operate according to bp chip:start************/ +static int bp_active(struct bp_private_data *bp, int enable) +{ + int result = 0; + if(enable) + { +// gpio_direction_output(bp->ops->bp_power, GPIO_HIGH); +// msleep(500); + gpio_set_value(bp->ops->bp_reset, GPIO_HIGH); + msleep(100); + gpio_set_value(bp->ops->bp_reset, GPIO_LOW); + gpio_set_value(bp->ops->bp_en, GPIO_LOW); + msleep(1000); + gpio_set_value(bp->ops->bp_en, GPIO_HIGH); + msleep(700); + gpio_set_value(bp->ops->bp_en, GPIO_LOW); + gpio_set_value(bp->ops->ap_wakeup_bp, GPIO_LOW); + } + else + { +// gpio_direction_output(bp->ops->bp_power, GPIO_LOW); + gpio_set_value(bp->ops->bp_en, GPIO_LOW); + gpio_set_value(bp->ops->bp_en, GPIO_HIGH); + msleep(2500); + gpio_set_value(bp->ops->bp_en, GPIO_LOW); + } + + return result; +} + +static int ap_wake_bp(struct bp_private_data *bp, int wake) +{ + int result = 0; + + gpio_set_value(bp->ops->ap_wakeup_bp, wake); + + return result; + +} + +static void ap_wake_bp_work(struct work_struct *work) +{ + struct delayed_work *wakeup_work = container_of(work, struct delayed_work, work); + struct bp_private_data *bp = container_of(wakeup_work, struct bp_private_data, wakeup_work); + + if(bp->suspend_status) + { + if(bp->ops->ap_wake_bp) + bp->ops->ap_wake_bp(bp, 0); + bp->suspend_status = 0; + } + else + { + if(bp->ops->ap_wake_bp) + bp->ops->ap_wake_bp(bp, 1); + } +} + + +static int bp_init(struct bp_private_data *bp) +{ + int result = 0; + gpio_direction_output(bp->ops->bp_power, GPIO_HIGH); + gpio_set_value(bp->ops->bp_power, GPIO_HIGH); + msleep(500); + //if(bp->ops->active) + // bp->ops->active(bp, 1); + gpio_direction_input(bp->ops->bp_wakeup_ap); + gpio_pull_updown(bp->ops->bp_wakeup_ap, 1); + gpio_direction_output(bp->ops->bp_reset, GPIO_LOW); + gpio_direction_output(bp->ops->bp_en, GPIO_LOW); + gpio_direction_output(bp->ops->ap_wakeup_bp, GPIO_LOW); + INIT_DELAYED_WORK(&bp->wakeup_work, ap_wake_bp_work); + return result; +} + +static int bp_reset(struct bp_private_data *bp) +{ +// gpio_direction_output(bp->ops->bp_power, GPIO_HIGH); +// msleep(500); + gpio_set_value(bp->ops->bp_reset, GPIO_HIGH); + msleep(100); + gpio_set_value(bp->ops->bp_reset, GPIO_LOW); + gpio_set_value(bp->ops->bp_en, GPIO_LOW); + msleep(1000); + gpio_set_value(bp->ops->bp_en, GPIO_HIGH); + msleep(700); + gpio_set_value(bp->ops->bp_en, GPIO_LOW); + gpio_set_value(bp->ops->ap_wakeup_bp, GPIO_LOW); + + return 0; +} + +static int bp_wake_ap(struct bp_private_data *bp) +{ + int result = 0; + + bp->suspend_status = 0; + wake_lock_timeout(&bp->bp_wakelock, 10 * HZ); + + return result; +} + + +static int bp_shutdown(struct bp_private_data *bp) +{ + int result = 0; + + if(bp->ops->active) + bp->ops->active(bp, 0); + gpio_set_value(bp->ops->bp_power, GPIO_LOW); + cancel_delayed_work_sync(&bp->wakeup_work); + + return result; +} + + + +static int bp_suspend(struct bp_private_data *bp) +{ + int result = 0; + printk("<-----u5501 bp_suspend-------->\n"); + #if defined(CONFIG_ARCH_RK29) + rk29_mux_api_set(GPIO1C1_UART0RTSN_SDMMC1WRITEPRT_NAME, GPIO1H_GPIO1C1); + #elif defined(CONFIG_ARCH_RK30) + rk30_mux_api_set(GPIO1A7_UART1RTSN_SPI0TXD_NAME, GPIO1A_GPIO1A7); + #endif + + if(!bp->suspend_status) + { + bp->suspend_status = 1; + gpio_set_value(bp->ops->ap_wakeup_bp, GPIO_HIGH); + } + #if defined(CONFIG_ARCH_RK2928) + rk29_mux_api_set(GPIO1B1_SPI_TXD_UART1_SOUT_NAME, GPIO1B_GPIO1B1); + gpio_set_value(RK2928_PIN1_PB1, GPIO_LOW); + #elif defined(CONFIG_ARCH_RK30) + rk30_mux_api_set(GPIO1A5_UART1SOUT_SPI0CLK_NAME, GPIO1A_GPIO1A5); + gpio_set_value(RK30_PIN1_PA5, GPIO_LOW); + #endif + return result; +} + + + + +static int bp_resume(struct bp_private_data *bp) +{ + #if defined(CONFIG_ARCH_RK29) + rk29_mux_api_set(GPIO1C1_UART0RTSN_SDMMC1WRITEPRT_NAME, GPIO1H_UART0_RTS_N); + #elif defined(CONFIG_ARCH_RK30) + rk30_mux_api_set(GPIO1A7_UART1RTSN_SPI0TXD_NAME, GPIO1A_UART1_RTS_N); + #endif + + #if defined(CONFIG_ARCH_RK2928) + rk29_mux_api_set(GPIO1B1_SPI_TXD_UART1_SOUT_NAME, GPIO1B_UART1_SOUT); + #elif defined(CONFIG_ARCH_RK30) + rk30_mux_api_set(GPIO1A5_UART1SOUT_SPI0CLK_NAME, GPIO1A_UART1_SOUT); + #endif + //bp->suspend_status = 0; + //gpio_set_value(bp->ops->ap_wakeup_bp, GPIO_LOW); + schedule_delayed_work(&bp->wakeup_work, 4*HZ); + + + return 0; +} + + +struct bp_operate bp_u5501_ops = { +#if defined(CONFIG_ARCH_RK2928) + .name = "u5501", + .bp_id = BP_ID_U5501, + .bp_bus = BP_BUS_TYPE_USB_UART, + .bp_pid = 0, + .bp_vid = 0, + .bp_power = RK2928_PIN3_PC2, // 3g_power + .bp_en = BP_UNKNOW_DATA, // 3g_en + .bp_reset = RK2928_PIN1_PA3, + .ap_ready = BP_UNKNOW_DATA, // + .bp_ready = BP_UNKNOW_DATA, + .ap_wakeup_bp = RK2928_PIN3_PC4, + .bp_wakeup_ap = RK2928_PIN3_PC3, // + .bp_uart_en = BP_UNKNOW_DATA, //EINT9 + .bp_usb_en = BP_UNKNOW_DATA, //W_disable + .trig = IRQF_TRIGGER_FALLING, + + .active = bp_active, + .init = bp_init, + .reset = bp_reset, + .ap_wake_bp = ap_wake_bp, + .bp_wake_ap = bp_wake_ap, + .shutdown = bp_shutdown, + .read_status = NULL, + .write_status = NULL, + .suspend = bp_suspend, + .resume = bp_resume, + .misc_name = NULL, + .private_miscdev = NULL, +#elif defined(CONFIG_ARCH_RK30) + .name = "u5501", + .bp_id = BP_ID_U5501, + .bp_bus = BP_BUS_TYPE_USB_UART, + .bp_pid = 0, + .bp_vid = 0, + .bp_power = BP_UNKNOW_DATA,//RK2928_PIN3_PC2, // 3g_power + .bp_en = BP_UNKNOW_DATA, // 3g_en + .bp_reset = BP_UNKNOW_DATA,//RK2928_PIN1_PA3, + .ap_ready = BP_UNKNOW_DATA, // + .bp_ready = BP_UNKNOW_DATA, + .ap_wakeup_bp = BP_UNKNOW_DATA,//RK2928_PIN3_PC4, + .bp_wakeup_ap = BP_UNKNOW_DATA,//RK2928_PIN3_PC3, // + .bp_uart_en = BP_UNKNOW_DATA, //EINT9 + .bp_usb_en = BP_UNKNOW_DATA, //W_disable + .trig = IRQF_TRIGGER_FALLING, + + .active = bp_active, + .init = bp_init, + .reset = bp_reset, + .ap_wake_bp = ap_wake_bp, + .bp_wake_ap = bp_wake_ap, + .shutdown = bp_shutdown, + .read_status = NULL, + .write_status = NULL, + .suspend = bp_suspend, + .resume = bp_resume, + .misc_name = NULL, + .private_miscdev = NULL, +#else + .name = "u5501", + .bp_id = BP_ID_U5501, + .bp_bus = BP_BUS_TYPE_USB_UART, + .bp_pid = 0, + .bp_vid = 0, + .bp_power = BP_UNKNOW_DATA,//RK2928_PIN3_PC2, // 3g_power + .bp_en = BP_UNKNOW_DATA, // 3g_en + .bp_reset = BP_UNKNOW_DATA,//RK2928_PIN1_PA3, + .ap_ready = BP_UNKNOW_DATA, // + .bp_ready = BP_UNKNOW_DATA, + .ap_wakeup_bp = BP_UNKNOW_DATA,//RK2928_PIN3_PC4, + .bp_wakeup_ap = BP_UNKNOW_DATA,//RK2928_PIN3_PC3, // + .bp_uart_en = BP_UNKNOW_DATA, //EINT9 + .bp_usb_en = BP_UNKNOW_DATA, //W_disable + .trig = IRQF_TRIGGER_FALLING, + + .active = bp_active, + .init = bp_init, + .reset = bp_reset, + .ap_wake_bp = ap_wake_bp, + .bp_wake_ap = bp_wake_ap, + .shutdown = bp_shutdown, + .read_status = NULL, + .write_status = NULL, + .suspend = bp_suspend, + .resume = bp_resume, + .misc_name = NULL, + .private_miscdev = NULL, +#endif +}; + +/****************operate according to bp chip:end************/ + +//function name should not be changed +static struct bp_operate *bp_get_ops(void) +{ + return &bp_u5501_ops; +} + +static int __init bp_u5501_init(void) +{ + struct bp_operate *ops = bp_get_ops(); + int result = 0; + result = bp_register_slave(NULL, NULL, bp_get_ops); + if(result) + { + return result; + } + + if(ops->private_miscdev) + { + result = misc_register(ops->private_miscdev); + if (result < 0) { + printk("%s:misc_register err\n",__func__); + return result; + } + } + + DBG("%s\n",__func__); + return result; +} + +static void __exit bp_u5501_exit(void) +{ + //struct bp_operate *ops = bp_get_ops(); + bp_unregister_slave(NULL, NULL, bp_get_ops); +} + + +subsys_initcall(bp_u5501_init); +module_exit(bp_u5501_exit); + -- 2.34.1