On 12/22/2015 00:18, [email protected] wrote:
Hello, do you still have that patch?

Haven't cleaned it up but you can find the sunxi lirc driver attached. Just drop it in drivers/input/keyboard/ and add it to the makefile.

Please note that I've only tested it on Mixtile(A31 SoC), other SoCs seem to have some differences in configuring the IR device.

If it's of any interest I can clean it up and submit it as a proper patch.

Regards



--
You received this message because you are subscribed to the Google Groups 
"linux-sunxi" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.
/****************************************************************
*
*VERSION 1.0 Inital Version
*note: when swith to real ic, need to define SYS_CLK_CFG_EN & undef FPGA_SIM_CONFIG, vice versa.
*****************************************************************/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/keyboard.h>
#include <linux/ioport.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/slab.h>
#include <linux/timer.h> 
#include <mach/clock.h>
#include <linux/gpio.h>
#include <linux/scenelock.h>
#include <linux/power/aw_pm.h>
#include <mach/sys_config.h>
#include <media/lirc.h>
#include <media/lirc_dev.h>
#include <media/rc-core.h>

#define LIRC_DRIVER_NAME "sunxi_lirc"
#define RBUF_LEN 512

static struct platform_device *lirc_sunxi_dev;


#include <mach/irqs.h>
#include <mach/hardware.h>
#include <linux/clk.h>
#include <mach/gpio.h>
#include <mach/ar100.h>
#undef CONFIG_HAS_EARLYSUSPEND
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif

#if defined(CONFIG_HAS_EARLYSUSPEND) || defined(CONFIG_PM)
#include <linux/pm.h>
#endif

#include "ir-keymap.h"

#define SYS_GPIO_CFG_EN
#define SYS_CLK_CFG_EN
#define SW_INT_IRQNO_IR0 (69)

#ifdef SYS_CLK_CFG_EN
static struct clk *ir_clk;
static struct clk *ir_clk_source;
#endif

#ifdef SYS_GPIO_CFG_EN
static struct gpio_hdle {
	script_item_u	val;
	script_item_value_type_e  type;		
}ir_gpio_hdle;
#endif

#define CIR_SAMPLE_PERIOD 
/* Registers */
#define IR_REG(x)        (x)
#define IR0_BASE         (0xf1f02000)
#define IR_BASE          IR0_BASE
#define IR_IRQNO         (SW_INT_IRQNO_IR0)

/* CCM register */
#define CCM_BASE         0xf1c20000
/* PIO register */
#define PI_BASE          0xf1c20800
                                    
#define IR_CTRL_REG      IR_REG(0x00)     /* IR Control */
#define IR_RXCFG_REG     IR_REG(0x10)     /* Rx Config */
#define IR_RXDAT_REG     IR_REG(0x20)     /* Rx Data */
#define IR_RXINTE_REG    IR_REG(0x2C)     /* Rx Interrupt Enable */
#define IR_RXINTS_REG    IR_REG(0x30)     /* Rx Interrupt Status */
#define IR_SPLCFG_REG    IR_REG(0x34)     /* IR Sample Config */

//Bit Definition of IR_RXINTS_REG Register
#define IR_RXINTS_RXOF   (0x1<<0)         /* Rx FIFO Overflow */
#define IR_RXINTS_RXPE   (0x1<<1)         /* Rx Packet End */
#define IR_RXINTS_RXDA   (0x1<<4)         /* Rx FIFO Data Available */

/* Helper */
#define PULSE_BIT_SHIFTER	(17)  /* from 0x80 to PULSE_BIT */
#define SAMPLES_TO_US(us)	(( ((unsigned long) us) * 1000000UL)/46875UL)

#define IR_FIFO_SIZE     (64)             /* 64Bytes */
/* Frequency of Sample Clock = 46875.Hz, Cycle is 21.3us */
#define IR_RXFILT_VAL	(8)	/* Filter Threshold = 8*21.3 = ~128us	< 200us */
#define IR_RXIDLE_VAL	(5)	/* Idle Threshold = (5+1)*128*21.3 = ~16.4ms > 9ms */

//#define IR_RXFILT_VAL    (16)             /* Filter Threshold = 8*42.7 = ~341us < 500us */
//#define IR_RXIDLE_VAL    (5)              /* Idle Threshold = (2+1)*128*42.7 = ~16.4ms > 9ms */

#define IR_ACTIVE_T      (99)             /* Active Threshold */
#define IR_ACTIVE_T_C    (0)              /* Active Threshold */

#define IR_ERROR_CODE    (0xffffffff)
#define IR_REPEAT_CODE   (0x00000000)
#define DRV_VERSION      "1.00"

#define REPORT_REPEAT_KEY_VALUE

#ifdef CONFIG_HAS_EARLYSUSPEND	
struct sun6i_ir_data {
	struct early_suspend early_suspend;
};
#endif

struct ir_raw_buffer {
	unsigned long dcnt;                  		/*Packet Count*/
	#define	IR_RAW_BUF_SIZE		512
	unsigned char buf[IR_RAW_BUF_SIZE];	
};

static unsigned int ir_cnt = 0;
static unsigned long ir_code=0;
static int timer_used=0;
static struct ir_raw_buffer	ir_rawbuf;
static u32 power_key = 0;
extern unsigned int normal_standby_wakesource;
static u32 ir_addr_code = 0x9f00;

DEFINE_SPINLOCK(sunxi_lirc_spinlock);



#ifdef CONFIG_HAS_EARLYSUSPEND
static struct sun6i_ir_data *ir_data;
#else
#ifdef CONFIG_PM
struct dev_pm_domain ir_pm_domain;
#endif
#endif

enum {
	DEBUG_INIT = 1U << 0,
	DEBUG_INT = 1U << 1,
	DEBUG_DATA_INFO = 1U << 2,
	DEBUG_SUSPEND = 1U << 3,
};
static u32 debug_mask = 0;
#define dprintk(level_mask, fmt, arg...)	if (unlikely(debug_mask & level_mask)) \
	printk(KERN_DEBUG fmt , ## arg)

module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);



static inline void ir_reset_rawbuffer(void)
{
	ir_rawbuf.dcnt = 0;
}

static inline void ir_write_rawbuffer(unsigned char data)
{
	dprintk(DEBUG_DATA_INFO, "ir_write_rawbuffer: %02x\n", data);
	if (ir_rawbuf.dcnt < IR_RAW_BUF_SIZE) 
		ir_rawbuf.buf[ir_rawbuf.dcnt++] = data;
	else
		printk(KERN_DEBUG "ir_write_rawbuffer: IR Rx Buffer Full!!\n");
}

static inline unsigned char ir_read_rawbuffer(void)
{
	unsigned char data = 0x00;
	
	if (ir_rawbuf.dcnt > 0)
		data = ir_rawbuf.buf[--ir_rawbuf.dcnt];
		
	return data;
}

static inline int ir_rawbuffer_empty(void)
{
	return (ir_rawbuf.dcnt == 0);
}

static inline int ir_rawbuffer_full(void)
{
	return (ir_rawbuf.dcnt >= IR_RAW_BUF_SIZE);	
}

static void ir_clk_cfg(void)
{
#ifdef SYS_CLK_CFG_EN
	unsigned long rate = 3000000; /* 3Mhz */    
#else
	unsigned long tmp = 0;
#endif
	
#ifdef SYS_CLK_CFG_EN
	ir_clk_source = clk_get(NULL, CLK_SYS_HOSC);		
	if (!ir_clk_source || IS_ERR(ir_clk_source)) {
		printk(KERN_DEBUG "try to get ir_clk_source clock failed!\n");
		return;
	}

	rate = clk_get_rate(ir_clk_source);
	dprintk(DEBUG_INIT, "%s: get ir_clk_source rate %dHZ\n", __func__, (__u32)rate);

	ir_clk = clk_get(NULL, CLK_MOD_R_CIR);		
	if (!ir_clk || IS_ERR(ir_clk)) {
		printk(KERN_DEBUG "try to get ir clock failed!\n");
		return;
	}

	if(clk_set_parent(ir_clk, ir_clk_source))
		printk("%s: set ir_clk parent to ir_clk_source failed!\n", __func__);

	if (clk_set_rate(ir_clk, 3000000)) {
		printk(KERN_DEBUG "set ir clock freq to 3M failed!\n");
	}

	
	if (clk_enable(ir_clk)) {
			printk(KERN_DEBUG "try to enable ir_clk failed!\n");	
	}
	
	if (clk_reset(ir_clk, AW_CCU_CLK_NRESET)) {
			printk(KERN_DEBUG "try to nreset ir_clk failed!\n");	
	}
#else	
	/* Enable APB Clock for IR */	
	tmp = readl(CCM_BASE + 0x10);
	tmp |= 0x1<<10;  //IR	
	writel(tmp, CCM_BASE + 0x10);	

	/* config Special Clock for IR	(24/8=3MHz) */
	tmp = readl(CCM_BASE + 0x34);
	tmp &= ~(0x3<<8);  	
	tmp |= (0x1<<8);   	/* Select 24MHz */
	tmp |= (0x1<<7);   	/* Open Clock */
	tmp &= ~(0x3f<<0);  
	tmp |= (7<<0);	 	/* Divisor = 8 */
	writel(tmp, CCM_BASE + 0x34);
#endif

	return;
}

static void ir_clk_uncfg(void)
{
#ifdef SYS_CLK_CFG_EN
	if(NULL == ir_clk || IS_ERR(ir_clk)) {
		printk("ir_clk handle is invalid, just return!\n");
		return;
	} else {
		clk_disable(ir_clk);
		clk_put(ir_clk);
		ir_clk = NULL;
	}

	if(NULL == ir_clk_source || IS_ERR(ir_clk_source)) {
		printk("ir_clk_source handle is invalid, just return!\n");
		return;
	} else {	
		clk_put(ir_clk_source);
		ir_clk_source = NULL;
	}
#else	
#endif
 
	return;
}
static void ir_sys_cfg(void)
{
#ifdef SYS_GPIO_CFG_EN
	ir_gpio_hdle.type = script_get_item("ir_para", "ir_rx", &(ir_gpio_hdle.val));
	
	if(SCIRPT_ITEM_VALUE_TYPE_PIO != ir_gpio_hdle.type)
		printk(KERN_ERR "IR gpio type err! \n");
	
	dprintk(DEBUG_INIT, "value is: gpio %d, mul_sel %d, pull %d, drv_level %d, data %d\n", 
		ir_gpio_hdle.val.gpio.gpio, ir_gpio_hdle.val.gpio.mul_sel, ir_gpio_hdle.val.gpio.pull,  
		ir_gpio_hdle.val.gpio.drv_level, ir_gpio_hdle.val.gpio.data);
	 
	if(0 != gpio_request(ir_gpio_hdle.val.gpio.gpio, NULL)) {	
		printk(KERN_ERR "ERROR: IR Gpio_request is failed\n");
	}

	
	if (0 != sw_gpio_setall_range(&ir_gpio_hdle.val.gpio, 1)) {
		printk(KERN_ERR "IR gpio set err!");
		goto end;
	}
#else
	unsigned long tmp;
	/* config IO: PIOB4 to IR_Rx */
	tmp = readl(PI_BASE + 0x24); /* PIOB_CFG0_REG */
	tmp &= ~(0xf<<16);
	tmp |= (0x2<<16);
	writel(tmp, PI_BASE + 0x24);
#endif

	ir_clk_cfg();

	return;	
#ifdef SYS_GPIO_CFG_EN
end:
	gpio_free(ir_gpio_hdle.val.gpio.gpio);
	return;
#endif
	
}

static void ir_sys_uncfg(void)
{
#ifdef SYS_GPIO_CFG_EN
	gpio_free(ir_gpio_hdle.val.gpio.gpio);
#else
#endif

	ir_clk_uncfg();

	return;	
}

static void ir_reg_cfg(void)
{
	unsigned long tmp = 0;
	/* Enable IR Mode */
	tmp = 0x3<<4;
	writel(tmp, IR_BASE+IR_CTRL_REG);
	
	/* Config IR Smaple Register */
	tmp = 0x0 << 0; /* Fsample = 3MHz/64 =46875Hz (21.3us) */
 
        
	tmp |= (IR_RXFILT_VAL&0x3f)<<2;		/* Set Filter Threshold */
	tmp |= (IR_RXIDLE_VAL&0xff)<<8; 	/* Set Idle Threshold */
	tmp |= (IR_ACTIVE_T&0xff)<<16;          /* Set Active Threshold */
	tmp |= (IR_ACTIVE_T_C&0xff)<<23;
	writel(tmp, IR_BASE+IR_SPLCFG_REG);
	
	/* Invert Input Signal */
	writel(0x1<<2, IR_BASE+IR_RXCFG_REG);
	
	/* Clear All Rx Interrupt Status */
	writel(0xff, IR_BASE+IR_RXINTS_REG);
	
	/* Set Rx Interrupt Enable */
	tmp = (0x1<<4)|0x3;
	//tmp |= ((IR_FIFO_SIZE>>1)-1)<<8; 	/* Rx FIFO Threshold = FIFOsz/2; */
	tmp |= ((IR_FIFO_SIZE>>2)-1)<<8;	/* Rx FIFO Threshold = FIFOsz/4; */
	
	writel(tmp, IR_BASE+IR_RXINTE_REG);
	
	/* Enable IR Module */
	tmp = readl(IR_BASE+IR_CTRL_REG);
	tmp |= 0x3;
	writel(tmp, IR_BASE+IR_CTRL_REG);

	return;
}

static void ir_setup(void)
{	
	dprintk(DEBUG_INIT, "ir_setup: ir setup start!!\n");

	ir_code = 0;
	timer_used = 0;
	ir_reset_rawbuffer();	
	ir_sys_cfg();	
	ir_reg_cfg();
	
	dprintk(DEBUG_INIT, "ir_setup: ir setup end!!\n");

	return;
}

static inline unsigned char ir_get_data(void)
{
	return (unsigned char)(readl(IR_BASE + IR_RXDAT_REG));
}

static inline unsigned long ir_get_intsta(void)
{
	return (readl(IR_BASE + IR_RXINTS_REG));
}

static inline void ir_clr_intsta(unsigned long bitmap)
{
	unsigned long tmp = readl(IR_BASE + IR_RXINTS_REG);

	tmp &= ~0xff;
	tmp |= bitmap&0xff;
	writel(tmp, IR_BASE + IR_RXINTS_REG);
}



void ir_packet_handler(unsigned char *buf, unsigned int dcnt)
{
	DEFINE_IR_RAW_EVENT(rawir);
	struct rc_dev *rdev = lirc_sunxi_dev->dev.platform_data;
	unsigned int i;
	unsigned int lirc_val;
	bool pulse;
	dprintk(DEBUG_DATA_INFO, "Buffer length: %d",dcnt);

	for(i = 0; i < dcnt; i++) {
		pulse = (buf[i] & 0x80) != 0;
		lirc_val= buf[i] & 0x7f;
#if 0
		/* to do, write to lirc buffer */
	    if (lirc_buffer_full(&rbuf)) {
	            /* no new signals will be accepted */
	            dprintk(DEBUG_DATA_INFO, "Buffer overrun\n");
	            return;
	    }
#endif
		init_ir_raw_event(&rawir);
		rawir.pulse = pulse;
		rawir.duration = US_TO_NS(SAMPLES_TO_US(lirc_val));
		ir_raw_event_store_with_filter(rdev, &rawir);
	}
	ir_raw_event_handle(rdev);
	return;
}

static irqreturn_t ir_irq_service(int irqno, void *dev_id)
{
	unsigned int dcnt;
	unsigned int i = 0;
	unsigned long intsta;

	intsta = ir_get_intsta();

	ir_clr_intsta(intsta);
	
	dprintk(DEBUG_DATA_INFO, "ir_irq_service: interrupt\n");

	/* Read Data Every Time Enter this Routine*/
	dcnt = (unsigned int) (ir_get_intsta() >> 8) & 0x3f;

	/* Read FIFO */
	for (i = 0; i < dcnt; i++) {
		if (ir_rawbuffer_full()) {
			dprintk(DEBUG_DATA_INFO, "ir_irq_service: raw buffer full\n");
			break;
		} else {
			ir_write_rawbuffer(ir_get_data());
		}
	}

	if (intsta & IR_RXINTS_RXPE) { /* Packet End */
		ir_packet_handler(ir_rawbuf.buf, ir_rawbuf.dcnt);
		dprintk(DEBUG_DATA_INFO, "Buffer written\n");
		ir_rawbuf.dcnt = 0;
	}

	if (intsta & IR_RXINTS_RXOF) {/* FIFO Overflow */
		/* flush raw buffer */
		ir_reset_rawbuffer();
		dprintk(DEBUG_DATA_INFO, "ir_irq_service: Rx FIFO Overflow!!\n");
	}

	return IRQ_HANDLED;
}

static void ir_get_powerkey()
{
	script_item_u script_val;
	script_item_value_type_e type;
	type = script_get_item("ir_para", "ir_power_key_code", &script_val);
	if (SCIRPT_ITEM_VALUE_TYPE_INT != type) {
		printk("#########  ir power key code config type err!  ######");
		return;
	}
	power_key = script_val.val;
	//get ir addr code
	type = script_get_item("ir_para", "ir_addr_code", &script_val);
	if (SCIRPT_ITEM_VALUE_TYPE_INT != type) {
		printk("#########  ir ir_addr_code config type err!  ######");
		return;
	}
	ir_addr_code = script_val.val;
	printk("ir_addr_code = 0x%x     power_key=0x%x\n ",ir_addr_code,power_key);
}

/* Í£ÓÃÉ豸 */
#ifdef CONFIG_HAS_EARLYSUSPEND
static void sun6i_ir_early_suspend(struct early_suspend *h)
{
	//unsigned long tmp = 0;
	//int ret;
	//struct sun6i_ir_data *ts = container_of(h, struct sun6i_ir_data, early_suspend);

	dprintk(DEBUG_SUSPEND, "enter earlysuspend: sun6i_ir_suspend. \n");

	//tmp = readl(IR_BASE+IR_CTRL_REG);
	//tmp &= 0xfffffffc;
	//writel(tmp, IR_BASE+IR_CTRL_REG);
#ifdef SYS_CLK_CFG_EN
	if(NULL == ir_clk || IS_ERR(ir_clk)) {
		printk("ir_clk handle is invalid, just return!\n");
		return;
	} else {	
		clk_disable(ir_clk);
	}
#endif
	return ;
}

/* ÖØÐ»½ÐÑ */
static void sun6i_ir_late_resume(struct early_suspend *h)
{
	//unsigned long tmp = 0;
	//int ret;
	//struct sun6i_ir_data *ts = container_of(h, struct sun6i_ir_data, early_suspend);

	dprintk(DEBUG_SUSPEND, "enter laterresume: sun6i_ir_resume. \n");

	ir_code = 0;
	timer_used = 0;	
	ir_reset_rawbuffer();	
	ir_clk_cfg();	
	ir_reg_cfg();

	return ; 
}
#else
#ifdef CONFIG_PM
static int sun6i_ir_suspend(struct device *dev)
{

	dprintk(DEBUG_SUSPEND, "enter earlysuspend: sun6i_ir_suspend. \n");

	//tmp = readl(IR_BASE+IR_CTRL_REG);
	//tmp &= 0xfffffffc;
	//writel(tmp, IR_BASE+IR_CTRL_REG);
#ifdef SYS_CLK_CFG_EN
	if(NULL == ir_clk || IS_ERR(ir_clk)) {
		printk("ir_clk handle is invalid, just return!\n");
		return -1;
	} else {	
		clk_disable(ir_clk);
	}
#endif 
	return 0;
}

/* ÖØÐ»½ÐÑ */
static int sun6i_ir_resume(struct device *dev)
{
    unsigned long ir_event = 0;
	dprintk(DEBUG_SUSPEND, "enter laterresume: sun6i_ir_resume. \n");

	ir_code = 0;
	timer_used = 0;	
	ir_reset_rawbuffer();	
	ir_clk_cfg();	
	ir_reg_cfg();

	ar100_query_wakeup_source(&ir_event);
	dprintk(DEBUG_SUSPEND, "%s: event 0x%lx\n", __func__, ir_event);
	return 0; 
}
#endif
#endif


static int set_use_inc(void* data) {
	return 0;
}

static void set_use_dec(void* data) {

}

/* end of lirc device/driver stuff */

/* now comes THIS driver, above is lirc */
static struct platform_driver lirc_sunxi_driver = {
		.driver = {
				.name   = LIRC_DRIVER_NAME,
				.owner  = THIS_MODULE,
		},
};

static int __init ir_init(void)
{
	struct rc_dev *rdev;
	int i,ret;
	int err = 0;

	/* input device for IR remote (and tx) */
	rdev = rc_allocate_device();
	if (!rdev)
		return -ENOMEM;

	err = platform_driver_register(&lirc_sunxi_driver);
	if (err) {
			printk(KERN_ERR LIRC_DRIVER_NAME
					": lirc register returned %d\n", err);
			goto exit_buffer_free;
	}

	lirc_sunxi_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0);
	if (!lirc_sunxi_dev) {
			err = -ENOMEM;
			goto exit_driver_unregister;
	}

	err = platform_device_add(lirc_sunxi_dev);
	if (err) {
		platform_device_put(lirc_sunxi_dev);
		goto exit_driver_unregister;
	}
		
	if (request_irq(IR_IRQNO, ir_irq_service, 0, "RemoteIR",
			lirc_sunxi_dev)) {
		err = -EBUSY;
		goto exit_device_unregister;
	}
	lirc_sunxi_dev->dev.platform_data = rdev;
	ir_setup();

#ifdef CONFIG_HAS_EARLYSUSPEND
#else
#ifdef CONFIG_PM
	ir_pm_domain.ops.suspend = sun6i_ir_suspend;
	ir_pm_domain.ops.resume = sun6i_ir_resume;
	lirc_sunxi_dev->dev.pm_domain = &ir_pm_domain;	
#endif
#endif

	/* Set up the rc device */
	rdev->priv = lirc_sunxi_dev;
	rdev->driver_type = RC_DRIVER_IR_RAW;
	rdev->allowed_protos = RC_TYPE_ALL;
	rdev->input_name = LIRC_DRIVER_NAME;
	rdev->input_phys = "sunxi/cir0";
	rdev->input_id.bustype = BUS_HOST;
	rdev->input_id.version = 1;
	rdev->dev.parent = &lirc_sunxi_dev->dev;
	rdev->driver_name = LIRC_DRIVER_NAME;
	rdev->map_name = RC_MAP_RC6_MCE;
	rdev->timeout = US_TO_NS(1000);
	/* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */
	rdev->rx_resolution = SAMPLES_TO_US(1);
	
	err = rc_register_device(rdev);
	if (err)
		goto exit_free_irq;

	printk(KERN_INFO LIRC_DRIVER_NAME ": driver registered!\n");

	printk("IR Initial OK\n");

#ifdef CONFIG_HAS_EARLYSUSPEND	
	dprintk(DEBUG_INIT, "==register_early_suspend =\n");
	ir_data = kzalloc(sizeof(*ir_data), GFP_KERNEL);
	if (ir_data == NULL) {
		err = -ENOMEM;
		goto err_alloc_data_failed;
	}

	ir_data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;	
	ir_data->early_suspend.suspend = sun6i_ir_early_suspend;
	ir_data->early_suspend.resume	= sun6i_ir_late_resume;	
	register_early_suspend(&ir_data->early_suspend);
#endif
	dprintk(DEBUG_INIT, "ir_init end\n");

	return 0;

#ifdef CONFIG_HAS_EARLYSUSPEND
err_alloc_data_failed:
#endif
exit_free_irq:
	free_irq(IR_IRQNO, NULL);

exit_device_unregister:
    platform_device_unregister(lirc_sunxi_dev);

exit_driver_unregister:
    platform_driver_unregister(&lirc_sunxi_driver);

exit_buffer_free:
	rc_free_device(rdev);

	return err;
}

static void __exit ir_exit(void)
{
	struct rc_dev *rdev = lirc_sunxi_dev->dev.platform_data;
#ifdef CONFIG_HAS_EARLYSUSPEND	
	unregister_early_suspend(&ir_data->early_suspend);	
#endif

	free_irq(IR_IRQNO, lirc_sunxi_dev);
	ir_sys_uncfg();
	rc_free_device(rdev);

	platform_device_unregister(lirc_sunxi_dev);

	platform_driver_unregister(&lirc_sunxi_driver);

	printk(KERN_INFO LIRC_DRIVER_NAME ": cleaned up module\n");
}

module_init(ir_init);
module_exit(ir_exit);

MODULE_DESCRIPTION("Remote IR driver");
MODULE_AUTHOR("DanielWang");
MODULE_LICENSE("GPL");

Reply via email to