From: 张昊 Date: Wed, 23 Nov 2011 04:40:21 +0000 (+0800) Subject: Driver : add new modem driver sc8800 & tdsc8800 X-Git-Tag: firefly_0821_release~9734^2~2 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=d924261aacc5d5a2d81ba51feb2ec870ddb27c19;p=firefly-linux-kernel-4.4.55.git Driver : add new modem driver sc8800 & tdsc8800 --- diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index a9a94491b028..710153c51556 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -540,7 +540,8 @@ config STE config MTK23D bool "MTK6223D modem control driver" - + default n + config FM580X bool "FM rda580x driver" @@ -553,6 +554,15 @@ config MW100 config RK29_NEWTON bool "RK29_NEWTON misc driver" +config RK29_SC8800 + bool "SC8800 misc driver" + default n + +config TDSC8800 + bool "TDSC8800 modem control driver" + default n + + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index c4ed797a893b..3a67414ad023 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -61,3 +61,5 @@ obj-$(CONFIG_RK29_SUPPORT_MODEM) += rk29_modem/ obj-$(CONFIG_GPS_GNS7560) += gps/ obj-y += mpu3050/ obj-$(CONFIG_RK29_NEWTON) += newton.o +obj-$(CONFIG_TDSC8800) += tdsc8800.o +obj-$(CONFIG_RK29_SC8800) += sc8800.o diff --git a/drivers/misc/sc8800.c b/drivers/misc/sc8800.c new file mode 100755 index 000000000000..c8d26fed579d --- /dev/null +++ b/drivers/misc/sc8800.c @@ -0,0 +1,728 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 +#define sc8800_dbg(dev, format, arg...) \ + dev_printk(KERN_INFO , dev , format , ## arg) +//#define SC8800_PRINT_BUF +#else +#define sc8800_dbg(dev, format, arg...) +#endif + +#define READ_TIMEOUT 30000 //no use +#define WRITE_TIMEOUT 80 //80ms + +#define RD_BUF_SIZE (16*PAGE_SIZE) // 64K +#define WR_BUF_SIZE (2*PAGE_SIZE) // __get_free_pages(GFP_KERNEL, 1) ==> pages = 2^1 = 2 +#define MAX_RX_LIST 256 + +#define BP_PACKET_SIZE 64 +#define BP_PACKET_HEAD_LEN 16 +#define BP_PACKET_DATA_LEN 48 + +struct plat_sc8800 { + int slav_rts_pin; + int slav_rdy_pin; + int master_rts_pin; + int master_rdy_pin; + int poll_time; +}; +struct bp_head{ + u16 tag; //0x7e7f + u16 type; //0xaa55 + u32 length; //the length of data after head(8192-128 bytes) + u32 fram_num; //no used , always 0 + u32 reserved; ////reserved + char data[BP_PACKET_DATA_LEN]; +}; + +struct sc8800_data { + struct device *dev; + struct spi_device *spi; + struct workqueue_struct *rx_wq; + struct workqueue_struct *tx_wq; + struct work_struct rx_work; + struct work_struct tx_work; + struct wake_lock rx_wake; + struct wake_lock tx_wake; + + wait_queue_head_t waitrq; + wait_queue_head_t waitwq; + spinlock_t lock; + + int irq; + int slav_rts; + int slav_rdy; + int master_rts; + int master_rdy; + + int write_finished; + int write_tmo; + + char *rx_buf; + int rx_len; + + char *tx_buf; + int tx_len; + + int rw_enable; + + int is_suspend; +}; +static DEFINE_MUTEX(sc8800s_lock); +static DECLARE_RWSEM(sc8800_rsem); +static DECLARE_RWSEM(sc8800_wsem); +struct sc8800_data *g_sc8800 = NULL; + +char tmp_buf[1024]; +static int bp_rts(struct sc8800_data *sc8800) +{ + return gpio_get_value(sc8800->slav_rts); +} + +static int bp_rdy(struct sc8800_data *sc8800) +{ + return gpio_get_value(sc8800->slav_rdy); +} + +static void ap_rts(struct sc8800_data *sc8800, int value) +{ + gpio_set_value(sc8800->master_rts, value); +} + +static void ap_rdy(struct sc8800_data *sc8800, int value) +{ + gpio_set_value(sc8800->master_rdy, value); +} +static void sc8800_print_buf(struct sc8800_data *sc8800, char *buf, const char *func, int len) +{ +#ifdef SC8800_PRINT_BUF + int i; + char *tmp = NULL; + tmp = kzalloc(len*7, GFP_KERNEL); + sc8800_dbg(sc8800->dev, "%s buf[%d] = :\n", func, len); + for(i = 0; i < len; i++){ + if(i % 16 == 0 && i != 0) + sprintf(tmp, "%s\n", tmp); + sprintf(tmp, "%s[0x%2x] ", tmp, buf[i]); + } + printk("%s\n", tmp); + kfree(tmp); +#endif + return; +} +static void buf_swp(char *buf, int len) +{ + int i; + char temp; + + len = (len/2)*2; + for(i = 0; i < len; i += 2) + { + temp = buf[i]; + buf[i] = buf[i+1]; + buf[i+1] = temp; + } +} +static void spi_in(struct sc8800_data *sc8800, char *tx_buf, unsigned len, int* err) +{ + struct spi_message message; + struct spi_transfer tran; + + buf_swp(tx_buf, len); + + tran.tx_buf = (void *)tx_buf; + tran.rx_buf = tmp_buf; + tran.len = len; + tran.speed_hz = 0; + tran.bits_per_word = 16; + + spi_message_init(&message); + spi_message_add_tail(&tran, &message); + *err = spi_sync(sc8800->spi, &message); + sc8800_print_buf(sc8800, tx_buf, __func__, len); +} + +static void spi_out(struct sc8800_data *sc8800, char *rx_buf, unsigned len, int* err) +{ + struct spi_message message; + struct spi_transfer tran; + + memset(rx_buf, 0, len); + tran.tx_buf = tmp_buf; + tran.rx_buf = (void *)rx_buf; + tran.len = len; + tran.speed_hz = 0; + tran.bits_per_word = 16; + + spi_message_init(&message); + spi_message_add_tail(&tran, &message); + *err = spi_sync(sc8800->spi, &message); + sc8800_print_buf(sc8800, rx_buf, __func__, len); + + buf_swp(rx_buf, len); +} + +static int ap_get_head(struct sc8800_data *sc8800, struct bp_head *packet) +{ + int err = 0, count = 5; + char buf[BP_PACKET_SIZE]; + +retry: + spi_out(sc8800, buf, BP_PACKET_SIZE, &err); + + if(err < 0 && count > 0) + { + dev_warn(sc8800->dev, "%s spi_out return error, retry count = %d\n", + __func__, count); + count--; + mdelay(10); + goto retry; + } + if(err < 0) + return err; + + memcpy((char *)(packet), buf, BP_PACKET_SIZE); + + sc8800_dbg(sc8800->dev, "%s tag = 0x%4x, type = 0x%4x, length = %x\n", + __func__, packet->tag, packet->type, packet->length); + + if ((packet->tag != 0x7e7f) || (packet->type != 0xaa55)) + return -1; + else + return 0; +} + + +static int sc8800_rx(struct sc8800_data *sc8800) +{ + int ret = 0, len, real_len; + struct bp_head packet; + char *buf = NULL; + + ap_rdy(sc8800,0); + ret = ap_get_head(sc8800, &packet); + + if(ret < 0){ + dev_err(sc8800->dev, "ERR: %s ap_get_head err = %d\n", __func__, ret); + goto out; + } + len = packet.length; + if(len > BP_PACKET_DATA_LEN) + real_len = (((len -BP_PACKET_DATA_LEN-1)/BP_PACKET_SIZE)+2)*BP_PACKET_SIZE; + else + real_len = BP_PACKET_SIZE; + if(len > RD_BUF_SIZE){ + dev_err(sc8800->dev, "ERR: %s len[%d] is large than buffer size[%lu]\n", + __func__, real_len, RD_BUF_SIZE); + goto out; + } + buf = kzalloc(real_len, GFP_KERNEL); + if(!buf){ + dev_err(sc8800->dev,"ERR: %s no memmory for rx_buf\n", __func__); + goto out; + } + + memcpy(buf, packet.data, BP_PACKET_DATA_LEN); + if(len > BP_PACKET_DATA_LEN) + spi_out(sc8800, buf + BP_PACKET_DATA_LEN, real_len-BP_PACKET_SIZE, &ret); + + if(ret < 0){ + dev_err(sc8800->dev, "ERR: %s spi out err = %d\n", __func__, ret); + goto out; + } + + spin_lock(&sc8800->lock); + if(sc8800->rx_len + len > RD_BUF_SIZE){ + dev_warn(sc8800->dev, "WARN: %s read buffer is full\n", __func__); + }else + { + memcpy(sc8800->rx_buf+sc8800->rx_len, buf, len); + sc8800->rx_len += len; + } + spin_unlock(&sc8800->lock); + + sc8800_dbg(sc8800->dev, "%s rx_len = %d\n", __func__, sc8800->rx_len); + + ret = sc8800->rx_len; + +out: + ap_rdy(sc8800,1); + if(buf) + kfree(buf); + buf = NULL; + return ret; + +} + static int sc8800_data_packet(char *dst, char *src, int src_len) +{ + int dst_len = 0; + struct bp_head packet; + + if(src_len > BP_PACKET_DATA_LEN) + dst_len = (((src_len -BP_PACKET_DATA_LEN-1)/BP_PACKET_SIZE)+2)*BP_PACKET_SIZE; + else + dst_len = BP_PACKET_SIZE; + + packet.tag =0x7e7f; + packet.type = 0xaa55; + packet.length = src_len; + packet.fram_num = 0; + packet.reserved = 0; + + memcpy(packet.data, src, BP_PACKET_DATA_LEN); + memcpy(dst, (char *)&packet, BP_PACKET_SIZE); + if(src_len >= BP_PACKET_DATA_LEN) + memcpy(dst+BP_PACKET_SIZE, src+BP_PACKET_DATA_LEN, src_len - BP_PACKET_DATA_LEN); + + return dst_len; + } + +static int sc8800_tx(struct sc8800_data *sc8800) +{ + int ret = 0, len; + + char *buf = NULL; + + sc8800->write_tmo = 0; + buf = kzalloc(WR_BUF_SIZE + BP_PACKET_SIZE, GFP_KERNEL); + if(!buf){ + dev_err(sc8800->dev, "ERR: no memery for buf\n"); + return -ENOMEM; + } + while(!bp_rts(sc8800)){ + if(sc8800->write_tmo){ + sc8800_dbg(sc8800->dev, "bp_rts = 0\n"); + kfree(buf); + return -1; + } + schedule(); + } + mutex_lock(&sc8800s_lock); + ap_rts(sc8800,0); +#if 1 + while(bp_rdy(sc8800)){ + if(sc8800->write_tmo){ + ap_rts(sc8800,1); + sc8800_dbg(sc8800->dev, "ERR: %s write timeout ->bp not ready (bp_rdy = 1)\n", __func__); + kfree(buf); + mutex_unlock(&sc8800s_lock); + return -1; + } + schedule(); + } +#endif + len = sc8800_data_packet(buf, sc8800->tx_buf, sc8800->tx_len); + spi_in(sc8800, buf, len, &ret); + + if(ret < 0) + dev_err(sc8800->dev, "ERR: %s spi in err = %d\n", __func__, ret); + ap_rts(sc8800,1); + if(buf){ + kfree(buf); + buf = NULL; + } + + mutex_unlock(&sc8800s_lock); +#if 1 + while(!bp_rdy(sc8800)){ + if(sc8800->write_tmo){ + dev_err(sc8800->dev, "ERR: %s write timeout -> bp receiving (bp_rdy = 0)\n", __func__); + ret = -1; + } + schedule(); + } +#endif + return ret; +} + +static irqreturn_t sc8800_irq(int irq, void *dev_id) +{ + struct sc8800_data *sc8800 = (struct sc8800_data *)dev_id; + + sc8800_dbg(sc8800->dev, "%s\n", __func__); +#if 0 + if(sc8800->is_suspend) + rk28_send_wakeup_key(); +#endif + wake_lock(&sc8800->rx_wake); + queue_work(sc8800->rx_wq, &sc8800->rx_work); + return IRQ_HANDLED; +} + +static void sc8800_rx_work(struct work_struct *rx_work) +{ + struct sc8800_data *sc8800 = container_of(rx_work, struct sc8800_data, rx_work); + + sc8800_dbg(sc8800->dev, "%s\n", __func__); + mutex_lock(&sc8800s_lock); + sc8800->rx_len = sc8800_rx(sc8800); + wake_unlock(&sc8800->rx_wake); + if(sc8800->rx_len <= 0) + sc8800->rx_len = 0; + wake_up(&sc8800->waitrq); + mutex_unlock(&sc8800s_lock); +} +static void sc8800_tx_work(struct work_struct *tx_work) +{ + struct sc8800_data *sc8800 = container_of(tx_work, struct sc8800_data, tx_work); + + sc8800_dbg(sc8800->dev, "%s bp_rts = %d\n", __func__, bp_rts(sc8800)); + wake_lock(&sc8800->tx_wake); + if(sc8800_tx(sc8800) == 0){ + sc8800->write_finished = 1; + wake_up(&sc8800->waitwq); + } + wake_unlock(&sc8800->tx_wake); +} +static ssize_t sc8800_read(struct file *file, + char __user *buf, size_t count, loff_t *offset) +{ + int ret = 0; + ssize_t size = 0; + struct sc8800_data *sc8800 = (struct sc8800_data *)file->private_data; + + sc8800_dbg(sc8800->dev, "%s count = %d\n", __func__, count); + if(!buf){ + dev_err(sc8800->dev, "ERR: %s user_buf = NULL\n", __func__); + return -EFAULT; + } + down_write(&sc8800_rsem); + if(!(file->f_flags & O_NONBLOCK)){ + ret = wait_event_interruptible(sc8800->waitrq, (sc8800->rx_len > 0 || (sc8800->rw_enable <= 0))); + if (ret) { + up_write(&sc8800_rsem); + return ret; + } + } + if(sc8800->rw_enable <= 0){ + dev_err(sc8800->dev, "ERR: %s sc8800 is released\n", __func__); + up_write(&sc8800_rsem); + return -EFAULT; + } + if(sc8800->rx_len == 0){ + dev_warn(sc8800->dev, "WARN: %s nonblock read, rx_len = 0\n", __func__); + return 0; + } + spin_lock(&sc8800->lock); + sc8800_print_buf(sc8800, sc8800->rx_buf, __func__, sc8800->rx_len); + if(sc8800->rx_len > count){ + size = count; + ret = copy_to_user(buf, sc8800->rx_buf, count); + }else{ + size = sc8800->rx_len; + ret = copy_to_user(buf, sc8800->rx_buf, sc8800->rx_len); + } + + if(ret < 0){ + dev_err(sc8800->dev, "ERR: %s copy to user ret = %d\n", __func__, ret); + spin_unlock(&sc8800->lock); + up_write(&sc8800_rsem); + return -EFAULT; + } + if(sc8800->rx_len > count) + memmove(sc8800->rx_buf, sc8800->rx_buf + count, sc8800->rx_len - count); + + sc8800->rx_len -= size; + spin_unlock(&sc8800->lock); + up_write(&sc8800_rsem); + return size; +} +static ssize_t sc8800_write(struct file *file, + const char __user *buf, size_t count, loff_t *offset) +{ + int ret = 0; + struct sc8800_data *sc8800 = (struct sc8800_data *)file->private_data; + + sc8800_dbg(sc8800->dev, "%s count = %d\n", __func__, count); + if(count > WR_BUF_SIZE){ + dev_err(sc8800->dev, "ERR: %s count[%u] > WR_BUF_SIZE[%lu]\n", + __func__, count, WR_BUF_SIZE); + return -EFAULT; + } + down_write(&sc8800_wsem); + sc8800_print_buf(sc8800, sc8800->tx_buf, __func__, count); + memset(sc8800->tx_buf, 0, WR_BUF_SIZE); + ret = copy_from_user(sc8800->tx_buf, buf, count); + if(ret < 0){ + dev_err(sc8800->dev, "ERR: %s copy from user ret = %d\n", __func__, ret); + up_write(&sc8800_wsem); + return -EFAULT; + } + + sc8800->write_finished = 0; + sc8800->tx_len = count; + queue_work(sc8800->tx_wq, &sc8800->tx_work); + + ret = wait_event_timeout(sc8800->waitwq, + (sc8800->write_finished || sc8800->rw_enable <= 0), + msecs_to_jiffies(WRITE_TIMEOUT)); + if(sc8800->rw_enable <= 0){ + dev_err(sc8800->dev, "ERR: %ssc8800 is released\n", __func__); + up_write(&sc8800_wsem); + return -EFAULT; + } + if(ret == 0){ + sc8800->write_tmo = 1; + dev_err(sc8800->dev, "ERR: %swrite timeout\n", __func__); + up_write(&sc8800_wsem); + return -ETIMEDOUT; + //return count; + }else{ + up_write(&sc8800_wsem); + return count; + } +} + +static int sc8800_open(struct inode *inode, struct file *file) +{ + file->private_data = g_sc8800; + + sc8800_dbg(g_sc8800->dev, "%s\n", __func__); + g_sc8800->write_finished = 0; + g_sc8800->write_tmo = 0; + g_sc8800->rw_enable++; + return 0; +} +static int sc8800_release(struct inode *inode, struct file *file) +{ + struct sc8800_data *sc8800 = (struct sc8800_data *)file->private_data; + + sc8800_dbg(sc8800->dev, "%s\n", __func__); + if(sc8800->rw_enable > 0) + sc8800->rw_enable--; + wake_up(&sc8800->waitrq); + wake_up(&sc8800->waitwq); + + return 0; +} +static const struct file_operations sc8800_fops = { + .open = sc8800_open, + .release = sc8800_release, + .read = sc8800_read, + .write = sc8800_write, +}; +static struct miscdevice sc8800_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "sc8800", + .fops = &sc8800_fops, +}; + +static int __devinit sc8800_probe(struct spi_device *spi) +{ + int ret = 0; + unsigned long page; + struct sc8800_data *sc8800 = NULL; + struct plat_sc8800 *pdata = NULL; + + pdata = spi->dev.platform_data; + if (!pdata) { + dev_err(&spi->dev, "ERR: spi data missing\n"); + return -ENODEV; + } + + sc8800 = (struct sc8800_data *)kzalloc(sizeof(struct sc8800_data), GFP_KERNEL); + if(!sc8800){ + dev_err(&spi->dev, "ERR: no memory for sc8800\n"); + return -ENOMEM; + } + g_sc8800 = sc8800; + + page = __get_free_pages(GFP_KERNEL, 4); //2^4 * 4K = 64K + if(!page){ + dev_err(&spi->dev, "ERR: no memory for rx_buf\n"); + ret = -ENOMEM; + goto err_get_free_page1; + } + sc8800->rx_buf = (char *)page; + + page = __get_free_pages(GFP_KERNEL, 1);//2^1 * 4K = 8K + if(!page){ + dev_err(&spi->dev, "ERR: no memory for tx_buf\n"); + ret = -ENOMEM; + goto err_get_free_page2; + } + sc8800->tx_buf = (char *)page; + + sc8800->spi = spi; + sc8800->dev = &spi->dev; + dev_set_drvdata(sc8800->dev, sc8800); + + spi->bits_per_word = 16; + spi->mode = SPI_MODE_2; + spi->max_speed_hz = 1000*1000*8; + ret = spi_setup(spi); + if (ret < 0){ + dev_err(sc8800->dev, "ERR: fail to setup spi\n"); + goto err_spi_setup; + } + sc8800->irq = gpio_to_irq(pdata->slav_rts_pin); + sc8800->slav_rts = pdata->slav_rts_pin; + sc8800->slav_rdy = pdata->slav_rdy_pin; + sc8800->master_rts = pdata->master_rts_pin; + sc8800->master_rdy = pdata->master_rdy_pin; + + rk29_mux_api_set(GPIO1C1_UART0RTSN_SDMMC1WRITEPRT_NAME, GPIO1H_GPIO1C1); + rk29_mux_api_set(GPIO1C0_UART0CTSN_SDMMC1DETECTN_NAME, GPIO1H_GPIO1C0); + + ret = gpio_request(sc8800->slav_rts, "salv_rts"); + if(ret < 0){ + dev_err(sc8800->dev, "ERR: gpio request slav_rts[%d]\n", sc8800->slav_rts); + goto err_gpio_request_slav_rts; + } + ret = gpio_request(sc8800->slav_rdy, "slav_rdy"); + if(ret < 0){ + dev_err(sc8800->dev, "ERR: gpio request slav_rdy\n"); + goto err_gpio_request_slav_rdy; + } + ret = gpio_request(sc8800->master_rts, "master_rts"); + if(ret < 0){ + dev_err(sc8800->dev, "ERR: gpio request master_rts\n"); + goto err_gpio_request_master_rts; + } + ret = gpio_request(sc8800->master_rdy, "master_rdy"); + if(ret < 0){ + dev_err(sc8800->dev, "ERR: gpio request master_rdy\n"); + goto err_gpio_request_master_rdy; + } + gpio_direction_input(sc8800->slav_rts); + gpio_pull_updown(sc8800->slav_rts, GPIOPullUp); + gpio_direction_input(sc8800->slav_rdy); + gpio_pull_updown(sc8800->slav_rdy, GPIOPullUp); + gpio_direction_output(sc8800->master_rts, GPIO_HIGH); + gpio_direction_output(sc8800->master_rdy, GPIO_HIGH); + + + init_waitqueue_head(&sc8800->waitrq); + init_waitqueue_head(&sc8800->waitwq); + spin_lock_init(&sc8800->lock); + + ret = misc_register(&sc8800_device); + if(ret < 0){ + + dev_err(sc8800->dev, "ERR: fail to register misc device\n"); + goto err_misc_register; + } + ret = request_irq(sc8800->irq, sc8800_irq, IRQF_TRIGGER_FALLING, "sc8800", sc8800); + if(ret < 0){ + dev_err(sc8800->dev, "ERR: fail to request irq %d\n", sc8800->irq); + goto err_request_irq; + } + wake_lock_init(&sc8800->rx_wake, WAKE_LOCK_SUSPEND, "sc8800_rx_wake"); + wake_lock_init(&sc8800->tx_wake, WAKE_LOCK_SUSPEND, "sc8800_tx_wake"); + enable_irq_wake(sc8800->irq); + sc8800->rx_wq = create_workqueue("sc8800_rxwq"); + sc8800->tx_wq = create_workqueue("sc8800_txwq"); + INIT_WORK(&sc8800->rx_work, sc8800_rx_work); + INIT_WORK(&sc8800->tx_work, sc8800_tx_work); + dev_info(sc8800->dev, "sc8800 probe ok\n"); + return 0; + +err_request_irq: + gpio_free(sc8800->master_rdy); +err_misc_register: + misc_deregister(&sc8800_device); +err_gpio_request_master_rdy: + gpio_free(sc8800->master_rts); +err_gpio_request_master_rts: + gpio_free(sc8800->slav_rdy); +err_gpio_request_slav_rdy: + gpio_free(sc8800->slav_rts); +err_gpio_request_slav_rts: +err_spi_setup: + free_page((unsigned long)sc8800->tx_buf); +err_get_free_page2: + free_page((unsigned long)sc8800->rx_buf); +err_get_free_page1: + kfree(sc8800); + sc8800 = NULL; + g_sc8800 = NULL; + return ret; +} + +static int __devexit sc8800_remove(struct spi_device *spi) +{ + struct sc8800_data *sc8800 = dev_get_drvdata(&spi->dev); + + destroy_workqueue(sc8800->rx_wq); + destroy_workqueue(sc8800->tx_wq); + free_irq(sc8800->irq, sc8800); + gpio_free(sc8800->master_rdy); + gpio_free(sc8800->master_rts); + gpio_free(sc8800->slav_rdy); + gpio_free(sc8800->slav_rts); + free_page((unsigned long)sc8800->tx_buf); + free_page((unsigned long)sc8800->rx_buf); + kfree(sc8800); + sc8800 = NULL; + return 0; +} + +#ifdef CONFIG_PM + +static int sc8800_suspend(struct spi_device *spi, pm_message_t state) +{ + struct sc8800_data *sc8800 = dev_get_drvdata(&spi->dev); + + sc8800->is_suspend = 1; + return 0; +} + +static int sc8800_resume(struct spi_device *spi) +{ + struct sc8800_data *sc8800 = dev_get_drvdata(&spi->dev); + + + sc8800->is_suspend = 0; + return 0; +} + +#else +#define sc8800_suspend NULL +#define sc8800_resume NULL +#endif + +static struct spi_driver sc8800_driver = { + .driver = { + .name = "sc8800", + .bus = &spi_bus_type, + .owner = THIS_MODULE, + }, + + .probe = sc8800_probe, + .remove = __devexit_p(sc8800_remove), + .suspend = sc8800_suspend, + .resume = sc8800_resume, +}; + +static int __init sc8800_init(void) +{ + printk("sc8800_init\n"); + return spi_register_driver(&sc8800_driver); +} +module_init(sc8800_init); + +static void __exit sc8800_exit(void) +{ + spi_unregister_driver(&sc8800_driver); +} +module_exit(sc8800_exit); + +MODULE_DESCRIPTION("SC8800 driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:SC8800"); diff --git a/drivers/misc/tdsc8800.c b/drivers/misc/tdsc8800.c new file mode 100755 index 000000000000..d4ffb891cac3 --- /dev/null +++ b/drivers/misc/tdsc8800.c @@ -0,0 +1,186 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +MODULE_LICENSE("GPL"); + +#define DEBUG +#ifdef DEBUG +#define MODEMDBG(x...) printk(x) +#else +#define MODEMDBG(fmt,argss...) +#endif + +static bool wakelock_inited; +#define SLEEP 1 +#define READY 0 +struct rk2818_23d_data *gpdata = NULL; + + +int modem_poweron_off(int on_off) +{ + struct rk2818_23d_data *pdata = gpdata; + int result, error = 0, irq = 0; + + if(on_off) + { + printk("tdsc8800_poweron\n"); + gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_HIGH:GPIO_LOW); // power on enable + + } + else + { + printk("tdsc8800_poweroff\n"); + gpio_set_value(pdata->bp_power, pdata->bp_power_active_low? GPIO_LOW:GPIO_HIGH); + } +} +static int tdsc8800_open(struct inode *inode, struct file *file) +{ + struct rk2818_23d_data *pdata = gpdata; + //struct rk2818_23d_data *pdata = gpdata = pdev->dev.platform_data; + struct platform_data *pdev = container_of(pdata, struct device, platform_data); + + MODEMDBG("tdsc8800_open\n"); + + int ret = 0; + modem_poweron_off(1); + device_init_wakeup(&pdev, 1); + + return 0; +} + +static int tdsc8800_release(struct inode *inode, struct file *file) +{ + MODEMDBG("tdsc8800_release\n"); + + return 0; +} +static int tdsc8800_ioctl(struct inode *inode,struct file *file, unsigned int cmd, unsigned long arg) +{ + return 0; +} + +static struct file_operations tdsc8800_fops = { + .owner = THIS_MODULE, + .open =tdsc8800_open, + .release =tdsc8800_release, + .unlocked_ioctl = tdsc8800_ioctl +}; + +static struct miscdevice tdsc8800_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "tdsc8800", + .fops = &tdsc8800_fops +}; + +static int tdsc8800_probe(struct platform_device *pdev) +{ + struct rk2818_23d_data *pdata = gpdata = pdev->dev.platform_data; + struct modem_dev *tdsc8800_data = NULL; + int result, error = 0, irq = 0; + + MODEMDBG("tdsc8800_probe\n"); + + //pdata->io_init(); + + tdsc8800_data = kzalloc(sizeof(struct modem_dev), GFP_KERNEL); + if(NULL == tdsc8800_data) + { + printk("failed to request tdsc8800_data\n"); + goto err6; + } + platform_set_drvdata(pdev, tdsc8800_data); + + result = gpio_request(pdata->bp_power, "tdsc8800"); + if (result) { + printk("failed to request BP_POW_EN gpio\n"); + goto err1; + } + + + gpio_direction_output(pdata->bp_power, GPIO_LOW); + + gpio_set_value(pdata->bp_power, pdata->bp_reset_active_low? GPIO_LOW:GPIO_HIGH); + result = misc_register(&tdsc8800_misc); + if(result) + { + MODEMDBG("misc_register err\n"); + } + MODEMDBG("mtk23d_probe ok\n"); + + return result; +err1: + gpio_free(pdata->bp_power); +err6: + kfree(tdsc8800_data); +ret: + return result; +} + +int tdsc8800_suspend(struct platform_device *pdev) +{ + return 0; +} + +int tdsc8800_resume(struct platform_device *pdev) +{ + return 0; +} + +void tdsc8800_shutdown(struct platform_device *pdev, pm_message_t state) +{ + struct rk2818_23d_data *pdata = pdev->dev.platform_data; + struct modem_dev *mt6223d_data = platform_get_drvdata(pdev); + + MODEMDBG("%s \n", __FUNCTION__); + + modem_poweron_off(0); // power down + gpio_free(pdata->bp_power); + kfree(mt6223d_data); +} + +static struct platform_driver tdsc8800_driver = { + .probe = tdsc8800_probe, + .shutdown = tdsc8800_shutdown, + .suspend = tdsc8800_suspend, + .resume = tdsc8800_resume, + .driver = { + .name = "tdsc8800", + .owner = THIS_MODULE, + }, +}; + +static int __init tdsc8800_init(void) +{ + MODEMDBG("tdsc8800_init ret=%d\n"); + return platform_driver_register(&tdsc8800_driver); +} + +static void __exit tdsc8800_exit(void) +{ + MODEMDBG("tdsc8800_exit\n"); + platform_driver_unregister(&tdsc8800_driver); +} + +module_init(tdsc8800_init); +module_exit(tdsc8800_exit);