+/*\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the BSD Licence, GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2 of the\r
+ * License, or (at your option) any later version\r
+ */\r
+#include <linux/module.h>\r
+#include <linux/delay.h>\r
+#include <linux/errno.h>\r
+#include <linux/platform_device.h>\r
+#include <linux/fs.h>\r
+#include <linux/kernel.h>\r
+#include <linux/slab.h>\r
+#include <linux/mm.h>\r
+#include <linux/ioport.h>\r
+#include <linux/init.h>\r
+#include <linux/sched.h>\r
+#include <linux/pci.h>\r
+#include <linux/random.h>\r
+#include <linux/version.h>\r
+#include <linux/mutex.h>\r
+#include <linux/videodev2.h>\r
+#include <linux/dma-mapping.h>\r
+#include <linux/interrupt.h>\r
+#include <linux/kthread.h>\r
+#include <linux/highmem.h>\r
+#include <linux/freezer.h>\r
+#include <linux/netdevice.h>\r
+#include <linux/etherdevice.h>\r
+#include <linux/irq.h>\r
+#include <linux/wakelock.h>\r
+\r
+#include <mach/iomux.h>\r
+#include <mach/gpio.h>\r
+#include <mach/board.h>\r
+#include <mach/rk29_iomap.h>\r
+#include <mach/pmu.h>\r
+#include <mach/rk29-dma-pl330.h>\r
+\r
+#include "rk29_ir.h"\r
+\r
+#if 0\r
+#define RK29IR_DBG(x...) printk(x)\r
+#else\r
+#define RK29IR_DBG(x...)\r
+#endif\r
+\r
+#if 0\r
+#define RK29IR_DATA_DBG(x...) printk(x)\r
+#else\r
+#define RK29IR_DATA_DBG(x...)\r
+#endif\r
+\r
+#define IRDA_NAME "rk_irda"\r
+\r
+struct irda_driver {\r
+ struct irda_info *pin_info;\r
+ struct device *dev;\r
+};\r
+\r
+#define IS_FIR(si) ((si)->speed >= 4000000)\r
+static int max_rate = 115200;\r
+#define IRDA_FRAME_SIZE_LIMIT BU92725GUW_FIFO_SIZE\r
+\r
+#define RK29_MAX_RXLEN 2047\r
+\r
+static void rk29_irda_fir_test(struct work_struct *work);\r
+static DECLARE_DELAYED_WORK(dwork, rk29_irda_fir_test);\r
+\r
+\r
+/*\r
+ * Allocate and map the receive buffer, unless it is already allocated.\r
+ */\r
+static int rk29_irda_rx_alloc(struct rk29_irda *si)\r
+{\r
+ if (si->rxskb)\r
+ return 0;\r
+\r
+ si->rxskb = alloc_skb(RK29_MAX_RXLEN + 1, GFP_ATOMIC);\r
+\r
+ if (!si->rxskb) {\r
+ printk(KERN_ERR "rk29_ir: out of memory for RX SKB\n");\r
+ return -ENOMEM;\r
+ }\r
+\r
+ si->rxskb->len = 0;\r
+\r
+ /*\r
+ * Align any IP headers that may be contained\r
+ * within the frame.\r
+ */\r
+ skb_reserve(si->rxskb, 1);\r
+\r
+ return 0;\r
+}\r
+\r
+/*\r
+ * Set the IrDA communications speed.\r
+ */\r
+static int rk29_irda_set_speed(struct rk29_irda *si, int speed)\r
+{\r
+ unsigned long flags;\r
+ int ret = -EINVAL;\r
+ \r
+ printk("[%s][%d], speed=%d\n",__FUNCTION__,__LINE__,speed);\r
+\r
+ switch (speed) {\r
+ case 9600: case 19200: case 38400:\r
+ case 57600: case 115200:\r
+ \r
+ local_irq_save(flags);\r
+ \r
+ irda_hw_set_speed(speed);\r
+\r
+ si->speed = speed;\r
+\r
+ local_irq_restore(flags);\r
+ ret = 0;\r
+ break;\r
+\r
+ case 4000000:\r
+ local_irq_save(flags);\r
+\r
+ si->speed = speed;\r
+ \r
+ irda_hw_set_speed(speed);\r
+ \r
+ rk29_irda_rx_alloc(si);\r
+\r
+ local_irq_restore(flags);\r
+ ret = 0;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+static irqreturn_t rk29_irda_irq(int irq, void *dev_id)\r
+{\r
+ struct net_device *dev = (struct net_device *)dev_id;\r
+ struct rk29_irda *si = netdev_priv(dev);\r
+ u8 data[2048]={0,0};\r
+ int tmp_len=0;\r
+ int i=0;\r
+ u32 irq_src = 0; \r
+ u32 irda_setptn = 0;\r
+ \r
+ irq_src = irda_hw_get_irqsrc();\r
+ \r
+ printk("[%s][%d], 0x%x\n",__FUNCTION__,__LINE__, irq_src);\r
+ \r
+ //disable_irq(dev->irq);\r
+ \r
+ /* EIR 1, 3, 11, 12 */\r
+ irda_setptn |= irq_src & (REG_INT_EOFRX | REG_INT_TXE | REG_INT_WRE | REG_INT_RDE |\r
+ REG_INT_CRC | REG_INT_OE | REG_INT_FE | REG_INT_AC | \r
+ REG_INT_DECE | REG_INT_RDOE | REG_INT_DEX) ;\r
+\r
+ /* error */\r
+ if (irq_src & (REG_INT_TO| REG_INT_CRC | REG_INT_OE | REG_INT_FE | \r
+ REG_INT_AC | REG_INT_DECE | REG_INT_RDOE | REG_INT_DEX)) {\r
+ RK29IR_DBG("[%s][%d]: do err\n",__FUNCTION__,__LINE__);\r
+ BU92725GUW_clr_fifo();\r
+ BU92725GUW_reset();\r
+ }\r
+\r
+ if (IS_FIR(si)) //FIR\r
+ {\r
+ RK29IR_DBG("[%s][%d]: FIR\n",__FUNCTION__,__LINE__);\r
+ if(irda_hw_get_mode() == BU92725GUW_AUTO_MULTI_REV) {//rx\r
+ struct sk_buff *skb = si->rxskb;\r
+ RK29IR_DBG("[%s][%d]: rx\n",__FUNCTION__,__LINE__);\r
+ if (irda_setptn & (REG_INT_FE | REG_INT_OE | REG_INT_CRC | REG_INT_DECE)) {\r
+ if (irda_setptn & REG_INT_FE) {\r
+ printk(KERN_DEBUG "pxa_ir: fir receive frame error\n");\r
+ dev->stats.rx_frame_errors++;\r
+ } else {\r
+ printk(KERN_DEBUG "pxa_ir: fir receive abort\n");\r
+ dev->stats.rx_errors++;\r
+ }\r
+ }\r
+ if ((irda_setptn & (FRM_EVT_RX_EOFRX | FRM_EVT_RX_RDE | REG_INT_EOF))) {\r
+ tmp_len = BU92725GUW_get_data(skb->data+skb->len);\r
+ skb->len += tmp_len; \r
+ }\r
+ if (irda_setptn & (REG_INT_EOF | FRM_EVT_RX_EOFRX)) { \r
+ RK29IR_DBG("[%s][%d]: report data:\n",__FUNCTION__,__LINE__);\r
+ si->rxskb = NULL;\r
+ RK29IR_DATA_DBG("[%s][%d]: fir report data:\n",__FUNCTION__,__LINE__);\r
+ for (i=0;i<skb->len;i++) {\r
+ RK29IR_DATA_DBG("0x%2x ", skb->data[i]);\r
+ }\r
+ RK29IR_DATA_DBG("\n");\r
+ \r
+ skb_put(skb, skb->len);\r
+ \r
+ /* Feed it to IrLAP */\r
+ skb->dev = dev;\r
+ skb_reset_mac_header(skb);\r
+ skb->protocol = htons(ETH_P_IRDA);\r
+ dev->stats.rx_packets++;\r
+ dev->stats.rx_bytes += skb->len;\r
+ \r
+ /*\r
+ * Before we pass the buffer up, allocate a new one.\r
+ */\r
+ rk29_irda_rx_alloc(si);\r
+ \r
+ netif_rx(skb);\r
+ } \r
+ }\r
+ else if (irda_hw_get_mode() == BU92725GUW_MULTI_SEND) {//tx\r
+ struct sk_buff *skb = si->txskb; \r
+ si->txskb = NULL;\r
+ RK29IR_DBG("[%s][%d]: tx\n",__FUNCTION__,__LINE__);\r
+ if (irda_setptn & (FRM_EVT_TX_TXE | FRM_EVT_TX_WRE)) {\r
+ /*\r
+ * Do we need to change speed? Note that we're lazy\r
+ * here - we don't free the old rxskb. We don't need\r
+ * to allocate a buffer either.\r
+ */\r
+ if (si->newspeed) {\r
+ rk29_irda_set_speed(si, si->newspeed);\r
+ si->newspeed = 0;\r
+ }\r
+ \r
+ /*\r
+ * Account and free the packet.\r
+ */\r
+ if (skb) {\r
+ dev->stats.tx_packets ++;\r
+ dev->stats.tx_bytes += skb->len;\r
+ dev_kfree_skb_irq(skb);\r
+ }\r
+ \r
+ /*\r
+ * Make sure that the TX queue is available for sending\r
+ * (for retries). TX has priority over RX at all times.\r
+ */\r
+ netif_wake_queue(dev);\r
+ \r
+ irda_hw_set_moderx();\r
+ }\r
+ }\r
+ }\r
+ else //SIR\r
+ {\r
+ RK29IR_DBG("[%d][%s], sir\n", __LINE__, __FUNCTION__);\r
+ if(irda_hw_get_mode() == BU92725GUW_REV) //rx\r
+ {\r
+ RK29IR_DBG("[%d][%s], receive data:\n", __LINE__, __FUNCTION__);\r
+ if(irda_setptn & (REG_INT_OE | REG_INT_FE ))\r
+ {\r
+ dev->stats.rx_errors++;\r
+ if (irda_setptn & REG_INT_FE)\r
+ dev->stats.rx_frame_errors++;\r
+ if (irda_setptn & REG_INT_OE)\r
+ dev->stats.rx_fifo_errors++;\r
+ }\r
+ if((irda_setptn & ( FRM_EVT_RX_EOFRX| REG_INT_EOF /*|FRM_EVT_RX_RDE*/)))\r
+ {\r
+ tmp_len = BU92725GUW_get_data(data);\r
+ RK29IR_DATA_DBG("[%d][%s], sir receive data:\n", __LINE__, __FUNCTION__);\r
+ for(i=0;i<=tmp_len;i++)\r
+ {\r
+ RK29IR_DATA_DBG("0x%2x ",data[i]);\r
+ async_unwrap_char(dev, &dev->stats, &si->rx_buff, data[i]);\r
+ }\r
+ RK29IR_DATA_DBG("\n");\r
+ //BU92725GUW_clr_fifo();\r
+ }\r
+ }\r
+ else if(irda_hw_get_mode() == BU92725GUW_SEND) //tx\r
+ {\r
+ RK29IR_DBG("[%d][%s], transmit data\n", __LINE__, __FUNCTION__);\r
+ if((irda_setptn & FRM_EVT_TX_TXE) && (si->tx_buff.len)) {\r
+ RK29IR_DATA_DBG("[%d][%s], sir transmit data:\n", __LINE__, __FUNCTION__);\r
+ for (i=0;i<si->tx_buff.len;i++) {\r
+ RK29IR_DATA_DBG("0x%2x ", *(si->tx_buff.data)++);\r
+ }\r
+ RK29IR_DATA_DBG("\n");\r
+\r
+ BU92725GUW_send_data(si->tx_buff.data, si->tx_buff.len, NULL, 0);\r
+ si->tx_buff.len = 0;\r
+ }\r
+ else if (si->tx_buff.len == 0) {\r
+ dev->stats.tx_packets++;\r
+ dev->stats.tx_bytes += si->tx_buff.data - si->tx_buff.head;\r
+\r
+ /*\r
+ * Ok, we've finished transmitting. Now enable\r
+ * the receiver. Sometimes we get a receive IRQ\r
+ * immediately after a transmit...\r
+ */\r
+ if (si->newspeed) {\r
+ rk29_irda_set_speed(si, si->newspeed);\r
+ si->newspeed = 0;\r
+ } \r
+\r
+ irda_hw_set_moderx();\r
+ \r
+ /* I'm hungry! */\r
+ netif_wake_queue(dev);\r
+ }\r
+ }\r
+ }\r
+ //enable_irq(dev->irq);\r
+\r
+ return IRQ_HANDLED;\r
+}\r
+\r
+static int rk29_irda_start(struct net_device *dev)\r
+{\r
+ struct rk29_irda *si = netdev_priv(dev);\r
+ int err = 0;\r
+ \r
+ RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);\r
+ \r
+ si->speed = 9600;\r
+ \r
+ /*\r
+ * irda module power up\r
+ */\r
+ if (si->pdata->irda_pwr_ctl)\r
+ si->pdata->irda_pwr_ctl(1);\r
+ si->power = 1;\r
+ \r
+ err = request_irq(dev->irq, rk29_irda_irq, IRQ_TYPE_LEVEL_LOW, dev->name, dev);//\r
+ if (err) {\r
+ printk("line %d: %s request_irq failed\n", __LINE__, __func__);\r
+ goto err_irq;\r
+ }\r
+\r
+ /*\r
+ * The interrupt must remain disabled for now.\r
+ */\r
+ disable_irq(dev->irq);\r
+\r
+ /*\r
+ * Setup the smc port for the specified speed.\r
+ */\r
+ err = irda_hw_startup(si);\r
+ if (err) { \r
+ printk("line %d: %s irda_hw_startup err\n", __LINE__, __func__);\r
+ goto err_startup;\r
+ }\r
+ irda_hw_set_moderx();\r
+\r
+ /*\r
+ * Open a new IrLAP layer instance.\r
+ */\r
+ si->irlap = irlap_open(dev, &si->qos, "rk29");\r
+ err = -ENOMEM;\r
+ if (!si->irlap) {\r
+ printk("line %d: %s irlap_open err\n", __LINE__, __func__);\r
+ goto err_irlap;\r
+ }\r
+ \r
+ /*\r
+ * Now enable the interrupt and start the queue\r
+ */\r
+ si->open = 1;\r
+ enable_irq(dev->irq);\r
+ netif_start_queue(dev);\r
+ \r
+ printk("rk29_ir: irda driver opened\n");\r
+\r
+ //test\r
+ //rk29_irda_set_speed(si, 4000000);\r
+ //schedule_delayed_work(&dwork, msecs_to_jiffies(5000));\r
+\r
+ return 0;\r
+\r
+err_irlap:\r
+ si->open = 0;\r
+ irda_hw_shutdown(si);\r
+err_startup:\r
+ free_irq(dev->irq, dev);\r
+err_irq:\r
+ return err;\r
+}\r
+\r
+static int rk29_irda_stop(struct net_device *dev)\r
+{\r
+ struct rk29_irda *si = netdev_priv(dev);\r
+ \r
+ RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);\r
+\r
+ disable_irq(dev->irq);\r
+ irda_hw_shutdown(si);\r
+\r
+ /*\r
+ * If we have been doing DMA receive, make sure we\r
+ * tidy that up cleanly.\r
+ */\r
+ if (si->rxskb) {\r
+ dev_kfree_skb(si->rxskb);\r
+ si->rxskb = NULL;\r
+ }\r
+\r
+ /* Stop IrLAP */\r
+ if (si->irlap) {\r
+ irlap_close(si->irlap);\r
+ si->irlap = NULL;\r
+ }\r
+\r
+ netif_stop_queue(dev);\r
+ si->open = 0;\r
+\r
+ /*\r
+ * Free resources\r
+ */\r
+ free_irq(dev->irq, dev);\r
+\r
+ //irda module power down\r
+ if (si->pdata->irda_pwr_ctl)\r
+ si->pdata->irda_pwr_ctl(0);\r
+\r
+ si->power = 0;\r
+\r
+ return 0;\r
+}\r
+\r
+static int rk29_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)\r
+{\r
+ struct rk29_irda *si = netdev_priv(dev);\r
+ int speed = irda_get_next_speed(skb);\r
+ int i;\r
+\r
+ RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);\r
+ /*\r
+ * Does this packet contain a request to change the interface\r
+ * speed? If so, remember it until we complete the transmission\r
+ * of this frame.\r
+ */\r
+ if (speed != si->speed && speed != -1)\r
+ si->newspeed = speed;\r
+\r
+ /*\r
+ * If this is an empty frame, we can bypass a lot.\r
+ */\r
+ if (skb->len == 0) {\r
+ if (si->newspeed) {\r
+ si->newspeed = 0;\r
+ rk29_irda_set_speed(si, speed);\r
+ }\r
+ dev_kfree_skb(skb);\r
+ return NETDEV_TX_OK;\r
+ }\r
+\r
+ netif_stop_queue(dev);\r
+\r
+ if (!IS_FIR(si)) {\r
+ si->tx_buff.data = si->tx_buff.head;\r
+ si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data, si->tx_buff.truesize);\r
+\r
+ /* Disable STUART interrupts and switch to transmit mode. */\r
+ /* enable STUART and transmit interrupts */\r
+ irda_hw_tx_enable_irq(BU92725GUW_SIR);\r
+\r
+ RK29IR_DATA_DBG("[%d][%s], sir transmit data:\n", __LINE__, __FUNCTION__);\r
+ for (i=0;i<si->tx_buff.len;i++) {\r
+ RK29IR_DATA_DBG("0x%2x ", *(si->tx_buff.data)++);\r
+ }\r
+ RK29IR_DATA_DBG("\n");\r
+\r
+ dev_kfree_skb(skb);\r
+ dev->trans_start = jiffies;\r
+ BU92725GUW_send_data(si->tx_buff.data, si->tx_buff.len, NULL, 0);\r
+ si->tx_buff.len = 0;\r
+\r
+ } \r
+ else {\r
+ unsigned long mtt = irda_get_mtt(skb);\r
+ si->txskb = skb;\r
+ \r
+ irda_hw_tx_enable_irq(BU92725GUW_FIR);\r
+\r
+ RK29IR_DATA_DBG("[%d][%s], fir transmit data:\n", __LINE__, __FUNCTION__);\r
+ for (i=0;i<skb->len;i++) {\r
+ RK29IR_DATA_DBG("0x%2x ", skb->data[i]);\r
+ }\r
+ RK29IR_DATA_DBG("\n");\r
+ \r
+ dev->trans_start = jiffies; \r
+ BU92725GUW_send_data(skb->data, skb->len, NULL, 0);\r
+ }\r
+\r
+ return NETDEV_TX_OK;\r
+}\r
+\r
+static int\r
+rk29_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)\r
+{\r
+ struct if_irda_req *rq = (struct if_irda_req *)ifreq;\r
+ struct rk29_irda *si = netdev_priv(dev);\r
+ int ret = -EOPNOTSUPP;\r
+\r
+ RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);\r
+\r
+ switch (cmd) {\r
+ case SIOCSBANDWIDTH:\r
+ if (capable(CAP_NET_ADMIN)) {\r
+ /*\r
+ * We are unable to set the speed if the\r
+ * device is not running.\r
+ */\r
+ if (si->open) {\r
+ ret = rk29_irda_set_speed(si, rq->ifr_baudrate );\r
+ } else {\r
+ printk("rk29_irda_ioctl: SIOCSBANDWIDTH: !netif_running\n");\r
+ ret = 0;\r
+ }\r
+ }\r
+ break;\r
+\r
+ case SIOCSMEDIABUSY:\r
+ ret = -EPERM;\r
+ if (capable(CAP_NET_ADMIN)) {\r
+ irda_device_set_media_busy(dev, TRUE);\r
+ ret = 0;\r
+ }\r
+ break;\r
+\r
+ case SIOCGRECEIVING:\r
+ rq->ifr_receiving = IS_FIR(si) ? 0\r
+ : si->rx_buff.state != OUTSIDE_FRAME;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+\r
+ return ret;\r
+}\r
+\r
+static const struct net_device_ops rk29_irda_netdev_ops = {\r
+ .ndo_open = rk29_irda_start,\r
+ .ndo_stop = rk29_irda_stop,\r
+ .ndo_start_xmit = rk29_irda_hard_xmit,\r
+ .ndo_do_ioctl = rk29_irda_ioctl,\r
+};\r
+\r
+\r
+static int rk29_irda_init_iobuf(iobuff_t *io, int size)\r
+{\r
+ io->head = kmalloc(size, GFP_KERNEL | GFP_DMA);\r
+ if (io->head != NULL) {\r
+ io->truesize = size;\r
+ io->in_frame = FALSE;\r
+ io->state = OUTSIDE_FRAME;\r
+ io->data = io->head;\r
+ }\r
+ return io->head ? 0 : -ENOMEM;\r
+}\r
+\r
+static void rk29_irda_fir_test(struct work_struct *work)\r
+{\r
+ char send_data[4] = {0,0,0,0};\r
+ irda_hw_tx_enable_irq(BU92725GUW_FIR);\r
+ \r
+ BU92725GUW_send_data(send_data, 4, NULL, 0);\r
+ \r
+ schedule_delayed_work(&dwork, msecs_to_jiffies(5000));\r
+ return ;\r
+}\r
+\r
+static int rk29_irda_probe(struct platform_device *pdev)\r
+{\r
+ struct irda_info *mach_info = NULL;\r
+ struct net_device *dev;\r
+ struct rk29_irda *si;\r
+ unsigned int baudrate_mask;\r
+ int err = -ENOMEM;\r
+\r
+ RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);\r
+\r
+ mach_info = pdev->dev.platform_data;\r
+\r
+ if (mach_info)\r
+ mach_info->iomux_init();\r
+\r
+ dev = alloc_irdadev(sizeof(struct rk29_irda));\r
+ if (!dev) {\r
+ printk("line %d: rk29_ir malloc failed\n", __LINE__);\r
+ goto err_mem_1;\r
+ }\r
+ SET_NETDEV_DEV(dev, &pdev->dev);\r
+ si = netdev_priv(dev);\r
+ si->dev = &pdev->dev;\r
+ si->pdata = pdev->dev.platform_data;\r
+\r
+ /*\r
+ * Initialise the HP-SIR buffers\r
+ */\r
+ err = rk29_irda_init_iobuf(&si->rx_buff, 14384);\r
+ if (err) {\r
+ printk("line %d: rk29_ir malloc failed\n", __LINE__);\r
+ goto err_mem_2;\r
+ }\r
+ err = rk29_irda_init_iobuf(&si->tx_buff, 4000);\r
+ if (err) { \r
+ printk("line %d: rk29_ir malloc failed\n", __LINE__);\r
+ goto err_mem_3;\r
+ }\r
+ dev->netdev_ops = &rk29_irda_netdev_ops;\r
+ dev->irq = gpio_to_irq(mach_info->intr_pin);\r
+\r
+ irda_init_max_qos_capabilies(&si->qos);\r
+\r
+ /*\r
+ * We support original IRDA up to 115k2. (we don't currently\r
+ * support 4Mbps). Min Turn Time set to 1ms or greater.\r
+ */\r
+ baudrate_mask = IR_9600;\r
+\r
+ switch (max_rate) {\r
+ case 4000000: baudrate_mask |= IR_4000000 << 8;\r
+ case 115200: baudrate_mask |= IR_115200;\r
+ case 57600: baudrate_mask |= IR_57600;\r
+ case 38400: baudrate_mask |= IR_38400;\r
+ case 19200: baudrate_mask |= IR_19200;\r
+ }\r
+\r
+ si->qos.baud_rate.bits &= baudrate_mask;\r
+ si->qos.min_turn_time.bits = 7;\r
+\r
+ irda_qos_bits_to_value(&si->qos);\r
+\r
+ /*\r
+ * Initially enable HP-SIR modulation, and ensure that the port\r
+ * is disabled.\r
+ */\r
+ irda_hw_init(si);\r
+\r
+ err = register_netdev(dev);\r
+ if (err) { \r
+ printk("line %d: rk29_ir register_netdev failed\n", __LINE__);\r
+ goto err_register;\r
+ }\r
+ platform_set_drvdata(pdev, dev);\r
+\r
+ //test\r
+ //wake_lock_init(&w_lock, WAKE_LOCK_SUSPEND, "rk29_cir");\r
+ //wake_lock(&w_lock);\r
+ \r
+ return 0;\r
+ \r
+err_register:\r
+ irda_hw_deinit(si);\r
+ kfree(si->tx_buff.head);\r
+err_mem_3:\r
+ kfree(si->rx_buff.head);\r
+err_mem_2:\r
+ free_netdev(dev);\r
+err_mem_1:\r
+ return err;\r
+\r
+}\r
+\r
+static int rk29_irda_remove(struct platform_device *pdev)\r
+{\r
+ struct net_device *dev = platform_get_drvdata(pdev);\r
+ RK29IR_DBG("line %d: enter %s\n", __LINE__, __FUNCTION__);\r
+\r
+ if (dev) {\r
+ struct rk29_irda *si = netdev_priv(dev);\r
+ unregister_netdev(dev);\r
+ kfree(si->tx_buff.head);\r
+ kfree(si->rx_buff.head);\r
+ free_netdev(dev);\r
+ irda_hw_deinit(si);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+static struct platform_driver irda_driver = {\r
+ .driver = {\r
+ .name = IRDA_NAME,\r
+ .owner = THIS_MODULE,\r
+ },\r
+ .probe = rk29_irda_probe,\r
+ .remove = rk29_irda_remove,\r
+ //.suspend = rk29_irda_suspend,\r
+ //.resume = rk29_irda_resume,\r
+};\r
+\r
+static int __init irda_init(void)\r
+{\r
+ if (platform_driver_register(&irda_driver) != 0) {\r
+ printk("Could not register irda driver\n");\r
+ return -EINVAL;\r
+ }\r
+ return 0;\r
+}\r
+\r
+static void __exit irda_exit(void)\r
+{\r
+ platform_driver_unregister(&irda_driver);\r
+}\r
+\r
+module_init(irda_init);\r
+module_exit(irda_exit);\r
+MODULE_AUTHOR(" zyw@rock-chips.com");\r
+MODULE_DESCRIPTION("Driver for irda device");\r
+MODULE_LICENSE("GPL");\r
+\r