rk30_phonepad:add auto modem driver support

This commit is contained in:
luowei
2012-10-24 18:11:05 +08:00
parent d5551f9e90
commit 534cc41268
8 changed files with 1388 additions and 0 deletions

13
drivers/misc/bp/Kconfig Executable file
View File

@@ -0,0 +1,13 @@
#
# all auto modem control drivers configuration
#
menuconfig BP_AUTO
bool "auto modem control driver support"
default n
if BP_AUTO
source "drivers/misc/bp/chips/Kconfig"
endif

3
drivers/misc/bp/Makefile Executable file
View File

@@ -0,0 +1,3 @@
# auto modem control drivers
obj-$(CONFIG_BP_AUTO) += chips/
obj-$(CONFIG_BP_AUTO) += bp-auto.o

665
drivers/misc/bp/bp-auto.c Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
config BP_AUTO_MT6229
bool "modem mt6229"
default n
config BP_AUTO_MU509
bool "modem mu509"
default n

View File

@@ -0,0 +1,2 @@
obj-$(CONFIG_BP_AUTO_MT6229) += mt6229.o
obj-$(CONFIG_BP_AUTO_MU509) += mu509.o

282
drivers/misc/bp/chips/mt6229.c Executable file
View File

@@ -0,0 +1,282 @@
/* drivers/misc/bp/chips/mt6229.c
*
* Copyright (C) 2012-2015 ROCKCHIP.
* Author: luowei <lw@rock-chips.com>
*
* 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 <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/circ_buf.h>
#include <linux/interrupt.h>
#include <linux/miscdevice.h>
#include <mach/iomux.h>
#include <mach/gpio.h>
#include <asm/gpio.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/wait.h>
#include <linux/wakelock.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/earlysuspend.h>
#include <linux/bp-auto.h>
#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_en, GPIO_LOW);
gpio_direction_output(bp->ops->bp_usb_en, GPIO_HIGH);
gpio_direction_output(bp->ops->bp_uart_en, GPIO_LOW);
gpio_direction_output(bp->ops->ap_ready, GPIO_HIGH);
}
else
{
gpio_direction_output(bp->ops->bp_en, GPIO_HIGH);
gpio_direction_output(bp->ops->bp_usb_en, GPIO_LOW);
gpio_direction_output(bp->ops->bp_uart_en, GPIO_HIGH);
gpio_direction_output(bp->ops->ap_ready, GPIO_LOW);
}
return result;
}
static int ap_wake_bp(struct bp_private_data *bp, int wake)
{
int result = 0;
if(wake)
{
gpio_direction_output(bp->ops->bp_uart_en, GPIO_LOW);
msleep(2000);
gpio_direction_output(bp->ops->ap_ready, GPIO_HIGH);
gpio_direction_output(bp->ops->bp_usb_en, GPIO_HIGH);
}
else
{
gpio_direction_output(bp->ops->bp_usb_en, GPIO_HIGH);
gpio_direction_output(bp->ops->bp_uart_en, GPIO_HIGH);
gpio_direction_output(bp->ops->ap_ready, GPIO_LOW);
}
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);
}
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);
msleep(1000);
if(bp->ops->active)
bp->ops->active(bp, 1);
INIT_DELAYED_WORK(&bp->wakeup_work, ap_wake_bp_work);
return result;
}
static int bp_wake_ap(struct bp_private_data *bp)
{
int result = 0;
if(bp->suspend_status)
{
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);
cancel_delayed_work_sync(&bp->wakeup_work);
return result;
}
static int read_status(struct bp_private_data *bp)
{
int result = 0;
return result;
}
static int write_status(struct bp_private_data *bp)
{
int result = 0;
if (bp->status == BP_ON)
{
gpio_direction_output(bp->ops->bp_usb_en, GPIO_HIGH);
gpio_direction_output(bp->ops->bp_uart_en,GPIO_LOW);
}
else if(bp->status == BP_OFF)
{
gpio_direction_output(bp->ops->bp_usb_en, GPIO_LOW);
gpio_direction_output(bp->ops->bp_uart_en,GPIO_HIGH);
}
else
{
printk("%s, invalid parameter \n", __FUNCTION__);
}
return result;
}
static int bp_suspend(struct bp_private_data *bp)
{
int result = 0;
if(!bp->suspend_status)
{
bp->suspend_status = 1;
if(bp->ops->ap_wake_bp)
bp->ops->ap_wake_bp(bp, 0);
}
return result;
}
static int bp_resume(struct bp_private_data *bp)
{
if(bp->suspend_status)
{
bp->suspend_status = 0;
PREPARE_DELAYED_WORK(&bp->wakeup_work, ap_wake_bp_work);
schedule_delayed_work(&bp->wakeup_work, 0);
}
return 0;
}
struct bp_operate bp_mt6229_ops = {
.name = "mt6229",
.bp_id = BP_ID_MT6229,
.bp_bus = BP_BUS_TYPE_USB_UART,
.bp_pid = 0,
.bp_vid = 0,
.bp_power = RK30_PIN6_PB2, // 3g_power
.bp_en = RK30_PIN2_PB6, // 3g_en
.bp_reset = BP_UNKNOW_DATA,
.ap_ready = RK30_PIN2_PB7, //
.bp_ready = BP_UNKNOW_DATA,
.ap_wakeup_bp = BP_UNKNOW_DATA,
.bp_wakeup_ap = RK30_PIN6_PA1, //
.bp_uart_en = RK30_PIN2_PC1, //EINT9
.bp_usb_en = RK30_PIN2_PC0, //W_disable
.trig = IRQF_TRIGGER_RISING,
.active = bp_active,
.init = bp_init,
.ap_wake_bp = ap_wake_bp,
.bp_wake_ap = bp_wake_ap,
.shutdown = bp_shutdown,
.read_status = read_status,
.write_status = write_status,
.suspend = bp_suspend,
.resume = bp_resume,
.misc_name = "mt6229",
.private_miscdev = NULL,
};
/****************operate according to bp chip:end************/
//function name should not be changed
static struct bp_operate *bp_get_ops(void)
{
return &bp_mt6229_ops;
}
static int __init bp_mt6229_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_mt6229_exit(void)
{
//struct bp_operate *ops = bp_get_ops();
bp_unregister_slave(NULL, NULL, bp_get_ops);
}
subsys_initcall(bp_mt6229_init);
module_exit(bp_mt6229_exit);

281
drivers/misc/bp/chips/mu509.c Executable file
View File

@@ -0,0 +1,281 @@
/* drivers/misc/bp/chips/mu509.c
*
* Copyright (C) 2012-2015 ROCKCHIP.
* Author: luowei <lw@rock-chips.com>
*
* 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 <linux/module.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/circ_buf.h>
#include <linux/interrupt.h>
#include <linux/miscdevice.h>
#include <mach/iomux.h>
#include <mach/gpio.h>
#include <asm/gpio.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/wait.h>
#include <linux/wakelock.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/earlysuspend.h>
#include <linux/bp-auto.h>
#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_reset, GPIO_HIGH);
msleep(100);
gpio_direction_output(bp->ops->bp_reset, GPIO_LOW);
gpio_direction_output(bp->ops->bp_en, GPIO_LOW);
msleep(1000);
gpio_direction_output(bp->ops->bp_en, GPIO_HIGH);
msleep(700);
gpio_direction_output(bp->ops->bp_en, GPIO_LOW);
gpio_direction_output(bp->ops->ap_wakeup_bp, GPIO_LOW);
}
else
{
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_direction_output(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);
}
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);
msleep(1000);
if(bp->ops->active)
bp->ops->active(bp, 1);
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(100);
gpio_direction_output(bp->ops->bp_power, GPIO_LOW);
return 0;
}
static int bp_wake_ap(struct bp_private_data *bp)
{
int result = 0;
if(bp->suspend_status)
{
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);
cancel_delayed_work_sync(&bp->wakeup_work);
return result;
}
static int read_status(struct bp_private_data *bp)
{
int result = 0;
return result;
}
static int write_status(struct bp_private_data *bp)
{
int result = 0;
if (bp->status == BP_ON)
{
gpio_direction_output(bp->ops->bp_usb_en, GPIO_HIGH);
gpio_direction_output(bp->ops->bp_uart_en,GPIO_LOW);
}
else if(bp->status == BP_OFF)
{
gpio_direction_output(bp->ops->bp_usb_en, GPIO_LOW);
gpio_direction_output(bp->ops->bp_uart_en,GPIO_HIGH);
}
else
{
printk("%s, invalid parameter \n", __FUNCTION__);
}
return result;
}
static int bp_suspend(struct bp_private_data *bp)
{
int result = 0;
if(!bp->suspend_status)
{
bp->suspend_status = 1;
}
return result;
}
static int bp_resume(struct bp_private_data *bp)
{
if(bp->suspend_status)
{
bp->suspend_status = 0;
gpio_set_value(bp->ops->ap_wakeup_bp, GPIO_LOW);
}
return 0;
}
struct bp_operate bp_mu509_ops = {
.name = "mu509",
.bp_id = BP_ID_MU509,
.bp_bus = BP_BUS_TYPE_USB_UART,
.bp_pid = 0,
.bp_vid = 0,
.bp_power = RK30_PIN6_PB2, // 3g_power
.bp_en = RK30_PIN2_PB6, // 3g_en
.bp_reset = RK30_PIN2_PC1,
.ap_ready = BP_UNKNOW_DATA, //
.bp_ready = BP_UNKNOW_DATA,
.ap_wakeup_bp = RK30_PIN2_PB7,
.bp_wakeup_ap = RK30_PIN6_PA1, //
.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 = read_status,
.write_status = write_status,
.suspend = bp_suspend,
.resume = bp_resume,
.misc_name = "mu509",
.private_miscdev = NULL,
};
/****************operate according to bp chip:end************/
//function name should not be changed
static struct bp_operate *bp_get_ops(void)
{
return &bp_mu509_ops;
}
static int __init bp_mu509_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_mu509_exit(void)
{
//struct bp_operate *ops = bp_get_ops();
bp_unregister_slave(NULL, NULL, bp_get_ops);
}
subsys_initcall(bp_mu509_init);
module_exit(bp_mu509_exit);

135
include/linux/bp-auto.h Normal file
View File

@@ -0,0 +1,135 @@
#ifndef _BP_AUTO_H
#define _BP_AUTO_H
#include <linux/miscdevice.h>
#include <linux/wakelock.h>
struct bp_private_data;
#define BP_UNKNOW_DATA -1
#define BP_OFF 0
#define BP_ON 1
#define BP_SUSPEND 2
#define BP_WAKE 3
#define BP_IOCTL_BASE 'm'
#define BP_IOCTL_RESET _IOW(BP_IOCTL_BASE, 0x00, int)
#define BP_IOCTL_POWON _IOW(BP_IOCTL_BASE, 0x01, int)
#define BP_IOCTL_POWOFF _IOW(BP_IOCTL_BASE, 0x02, int)
#define BP_IOCTL_WRITE_STATUS _IOW(BP_IOCTL_BASE, 0x03, int)
#define BP_IOCTL_GET_STATUS _IOR(BP_IOCTL_BASE, 0x04, int)
#define BP_IOCTL_SET_PVID _IOW(BP_IOCTL_BASE, 0x05, int)
#define BP_IOCTL_GET_BPID _IOR(BP_IOCTL_BASE, 0x06, int)
enum bp_id{
BP_ID_INVALID = 0,
BP_ID_MT6229,
BP_ID_MU509,
BP_ID_MI700,
BP_ID_MW100,
BP_ID_TD8801,
BP_ID_NUM,
};
enum bp_bus_type{
BP_BUS_TYPE_INVALID = 0,
BP_BUS_TYPE_UART,
BP_BUS_TYPE_SPI,
BP_BUS_TYPE_USB,
BP_BUS_TYPE_SDIO,
BP_BUS_TYPE_USB_UART,
BP_BUS_TYPE_SPI_UART,
BP_BUS_TYPE_SDIO_UART,
BP_BUS_TYPE_NUM_ID,
};
struct bp_platform_data {
int board_id;
int bp_id;
int (*init_platform_hw)(void);
int (*exit_platform_hw)(void);
int bp_power;
int bp_en;
int bp_reset;
int ap_ready;
int bp_ready;
int ap_wakeup_bp;
int bp_wakeup_ap;
int bp_usb_en;
int bp_uart_en;
int gpio_valid;
};
struct bp_operate {
char *name;
int bp_id;
int bp_bus;
int bp_pid;
int bp_vid;
int bp_power;
int bp_en;
int bp_reset;
int ap_ready;
int bp_ready;
int ap_wakeup_bp;
int bp_wakeup_ap;
int bp_usb_en;
int bp_uart_en;
int trig;
int (*active)(struct bp_private_data *bp, int enable);
int (*init)(struct bp_private_data *bp);
int (*reset)(struct bp_private_data *bp);
int (*ap_wake_bp)(struct bp_private_data *bp, int wake);
int (*bp_wake_ap)(struct bp_private_data *bp);
int (*shutdown)(struct bp_private_data *bp);
int (*read_status)(struct bp_private_data *bp);
int (*write_status)(struct bp_private_data *bp);
int (*suspend)(struct bp_private_data *bp);
int (*resume)(struct bp_private_data *bp);
char *misc_name;
struct miscdevice *private_miscdev;
};
struct bp_private_data {
struct device *dev;
int status;
int suspend_status;
struct wake_lock bp_wakelock;
struct delayed_work wakeup_work; /*report second event*/
struct bp_platform_data *pdata;
struct bp_operate *ops;
struct file_operations fops;
struct miscdevice miscdev;
struct file_operations id_fops;
struct miscdevice id_miscdev;
#ifdef CONFIG_HAS_EARLYSUSPEND
struct early_suspend early_suspend;
#endif
};
extern int bp_register_slave(struct bp_private_data *bp,
struct bp_platform_data *slave_pdata,
struct bp_operate *(*get_bp_ops)(void));
extern int bp_unregister_slave(struct bp_private_data *bp,
struct bp_platform_data *slave_pdata,
struct bp_operate *(*get_bp_ops)(void));
#endif