diff --git a/arch/arm64/boot/dts/amlogic/axg_a113x_skt.dts b/arch/arm64/boot/dts/amlogic/axg_a113x_skt.dts index 054b990ee724..42e01bcd04b9 100644 --- a/arch/arm64/boot/dts/amlogic/axg_a113x_skt.dts +++ b/arch/arm64/boot/dts/amlogic/axg_a113x_skt.dts @@ -316,14 +316,6 @@ pinctrl-0 = <&b_uart_pins>; }; - meson-irblaster { - compatible = "amlogic, am_irblaster"; - dev_name = "meson-irblaster"; - status = "disable"; - pinctrl-names = "default"; - pinctrl-0 = <&irblaster_pins>; - }; - /* Sound iomap */ aml_snd_iomap { compatible = "amlogic, snd-iomap"; diff --git a/arch/arm64/boot/dts/amlogic/axg_s400.dts b/arch/arm64/boot/dts/amlogic/axg_s400.dts index 9a6d91522a1b..49cfcf9eed05 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s400.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s400.dts @@ -425,14 +425,6 @@ pinctrl-0 = <&b_uart_pins>; }; - meson-irblaster { - compatible = "amlogic, am_irblaster"; - dev_name = "meson-irblaster"; - status = "disable"; - pinctrl-names = "default"; - pinctrl-0 = <&irblaster_pins>; - }; - vpu { compatible = "amlogic, vpu-axg"; dev_name = "vpu"; diff --git a/arch/arm64/boot/dts/amlogic/axg_s400_v03.dts b/arch/arm64/boot/dts/amlogic/axg_s400_v03.dts index b743d4e5732c..69a0f260bddc 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s400_v03.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s400_v03.dts @@ -425,14 +425,6 @@ pinctrl-0 = <&b_uart_pins>; }; - meson-irblaster { - compatible = "amlogic, am_irblaster"; - dev_name = "meson-irblaster"; - status = "disable"; - pinctrl-names = "default"; - pinctrl-0 = <&irblaster_pins>; - }; - vpu { compatible = "amlogic, vpu-axg"; dev_name = "vpu"; diff --git a/arch/arm64/boot/dts/amlogic/axg_s400emmc.dts b/arch/arm64/boot/dts/amlogic/axg_s400emmc.dts index bd22966953dc..77de81d9580c 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s400emmc.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s400emmc.dts @@ -413,14 +413,6 @@ pinctrl-0 = <&b_uart_pins>; }; - meson-irblaster { - compatible = "amlogic, am_irblaster"; - dev_name = "meson-irblaster"; - status = "disable"; - pinctrl-names = "default"; - pinctrl-0 = <&irblaster_pins>; - }; - vpu { compatible = "amlogic, vpu-axg"; dev_name = "vpu"; diff --git a/arch/arm64/boot/dts/amlogic/axg_s400emmc_512m.dts b/arch/arm64/boot/dts/amlogic/axg_s400emmc_512m.dts index ad4ab32abd85..6d88311d0d7d 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s400emmc_512m.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s400emmc_512m.dts @@ -434,14 +434,6 @@ pinctrl-0 = <&b_uart_pins>; }; - meson-irblaster { - compatible = "amlogic, am_irblaster"; - dev_name = "meson-irblaster"; - status = "disable"; - pinctrl-names = "default"; - pinctrl-0 = <&irblaster_pins>; - }; - vpu { compatible = "amlogic, vpu-axg"; dev_name = "vpu"; diff --git a/arch/arm64/boot/dts/amlogic/axg_s400emmc_v03.dts b/arch/arm64/boot/dts/amlogic/axg_s400emmc_v03.dts index 05861e24538a..16829a075fff 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s400emmc_v03.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s400emmc_v03.dts @@ -421,14 +421,6 @@ pinctrl-0 = <&b_uart_pins>; }; - meson-irblaster { - compatible = "amlogic, am_irblaster"; - dev_name = "meson-irblaster"; - status = "disable"; - pinctrl-names = "default"; - pinctrl-0 = <&irblaster_pins>; - }; - vpu { compatible = "amlogic, vpu-axg"; dev_name = "vpu"; diff --git a/arch/arm64/boot/dts/amlogic/axg_s420.dts b/arch/arm64/boot/dts/amlogic/axg_s420.dts index d6bfc39b053a..5d4c02177bc1 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s420.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s420.dts @@ -320,14 +320,6 @@ pinctrl-0 = <&b_uart_pins>; }; - meson-irblaster { - compatible = "amlogic, am_irblaster"; - dev_name = "meson-irblaster"; - status = "disable"; - pinctrl-names = "default"; - pinctrl-0 = <&irblaster_pins>; - }; - /* Sound iomap */ aml_snd_iomap { compatible = "amlogic, snd-iomap"; diff --git a/arch/arm64/boot/dts/amlogic/axg_s420_128m.dts b/arch/arm64/boot/dts/amlogic/axg_s420_128m.dts index 91649b564f8c..5b9e0eb29ef7 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s420_128m.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s420_128m.dts @@ -309,14 +309,6 @@ pinctrl-0 = <&b_uart_pins>; }; - meson-irblaster { - compatible = "amlogic, am_irblaster"; - dev_name = "meson-irblaster"; - status = "disable"; - pinctrl-names = "default"; - pinctrl-0 = <&irblaster_pins>; - }; - /* Sound iomap */ aml_snd_iomap { compatible = "amlogic, snd-iomap"; diff --git a/arch/arm64/boot/dts/amlogic/axg_s420_v03.dts b/arch/arm64/boot/dts/amlogic/axg_s420_v03.dts index f184fce0d2ad..8e302b61b518 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s420_v03.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s420_v03.dts @@ -320,14 +320,6 @@ pinctrl-0 = <&b_uart_pins>; }; - meson-irblaster { - compatible = "amlogic, am_irblaster"; - dev_name = "meson-irblaster"; - status = "disable"; - pinctrl-names = "default"; - pinctrl-0 = <&irblaster_pins>; - }; - /* Sound iomap */ aml_snd_iomap { compatible = "amlogic, snd-iomap"; diff --git a/arch/arm64/boot/dts/amlogic/mesonaxg.dtsi b/arch/arm64/boot/dts/amlogic/mesonaxg.dtsi index 49d84f32496b..14759a6ef0e3 100644 --- a/arch/arm64/boot/dts/amlogic/mesonaxg.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesonaxg.dtsi @@ -738,6 +738,16 @@ }; }; + irblaster: meson-irblaster { + compatible = "amlogic, meson_irblaster"; + reg = <0x0 0xff8000c0 0x0 0x10>, + <0x0 0xff800040 0x0 0x4>; + pinctrl-names = "default"; + pinctrl-0 = <&irblaster_pins>; + interrupts = <0 198 1>; + status = "disabled"; + }; + saradc:saradc { compatible = "amlogic,meson-axg-saradc"; status = "okay"; diff --git a/arch/arm64/boot/dts/amlogic/mesong12a.dtsi b/arch/arm64/boot/dts/amlogic/mesong12a.dtsi index a1d32cc59197..01c3e1727e81 100644 --- a/arch/arm64/boot/dts/amlogic/mesong12a.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesong12a.dtsi @@ -1324,11 +1324,11 @@ }; irblaster: meson-irblaster { compatible = "amlogic, meson_irblaster"; - dev_name = "meson-irblaster"; reg = <0x0 0xff80014c 0x0 0x10>, <0x0 0xff800040 0x0 0x4>; pinctrl-names = "default"; pinctrl-0 = <&irblaster_pins>; + interrupts = <0 198 1>; status = "okay"; }; diff --git a/arch/arm64/boot/dts/amlogic/mesong12b.dtsi b/arch/arm64/boot/dts/amlogic/mesong12b.dtsi index af2bcf90a7d6..ef203f22550c 100644 --- a/arch/arm64/boot/dts/amlogic/mesong12b.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesong12b.dtsi @@ -1371,12 +1371,12 @@ }; irblaster: meson-irblaster { compatible = "amlogic, meson_irblaster"; - dev_name = "meson-irblaster"; reg = <0x0 0xff80014c 0x0 0x10>, <0x0 0xff800040 0x0 0x4>; pinctrl-names = "default"; pinctrl-0 = <&irblaster_pins>; - status = "okay"; + interrupts = <0 198 1>; + status = "disabled"; }; sd_emmc_c: emmc@ffe07000 { diff --git a/drivers/amlogic/irblaster/meson-irblaster.c b/drivers/amlogic/irblaster/meson-irblaster.c index d79331645615..0ec658e3e49e 100644 --- a/drivers/amlogic/irblaster/meson-irblaster.c +++ b/drivers/amlogic/irblaster/meson-irblaster.c @@ -1,7 +1,7 @@ /* - * drivers/amlogic/irblaster/meson-irblaster.c + * drivers/amlogic/irblaster/irblaster.c * - * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * Copyright (C) 2015 Amlogic, Inc. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -13,10 +13,11 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - */ +*/ #include #include +#include #include #include #include @@ -30,405 +31,244 @@ #include #include #include -#include -#include -#include "meson-irblaster.h" -#include -#include -#include - -#include +#include #include #include +#include +#include "meson-irblaster.h" +#undef pr_fmt +#define pr_fmt(fmt) "irblaster: " fmt +#define BLASTER_NAME "meson-irblaster" -#define DEVICE_NAME "meson-irblaster" -#define DEIVE_COUNT 32 - -#define PS_SIZE 10 - -static dev_t am_irblaster_id; -static struct class *ir_blaster_class; -static struct device *ir_blaster_dev; -static struct cdev am_irblaster_device; -static struct blaster_window *irblaster_win; -static DEFINE_MUTEX(ir_blaster_file_mutex); static int debug_enable; +static DEFINE_MUTEX(blaster_mutex); -struct irtx_dev { - struct device *dev; - struct task_struct *thread; -#ifdef CONFIG_IRBLASTER_ENABLE_PIN - int enable_pin; -#endif -}; - - -#define IR_TX_EVENT_SIZE 4 -#define IR_TX_BUFFER_SIZE 1024 - -struct tx_event { - struct list_head list; - int size; - int buffer[IR_TX_BUFFER_SIZE]; -}; - -DECLARE_KFIFO(irblaster_fifo, struct tx_event *, IR_TX_EVENT_SIZE); -static struct irtx_dev *tx_dev; - -#define irblaster_dbg(format, arg...) \ -do { \ - if (debug_enable) \ - pr_info(format, ##arg); \ +#define irblaster_dbg(format, arg...) \ +do { \ + if (debug_enable) \ + pr_info(format, ##arg); \ } while (0) -static struct tx_event *irblaster_event_get(void) -{ - struct tx_event *ev = NULL; - - ev = devm_kzalloc(tx_dev->dev, - sizeof(struct tx_event), GFP_KERNEL); - irblaster_dbg("irblaster_event_get ev=0x%p\n", ev); - return ev; -} - -static void irblaster_event_put(struct tx_event *ev) -{ - irblaster_dbg("event_put ev=0x%p\n", ev); - devm_kfree(tx_dev->dev, ev); -} - -static int irblaster_send_bit(unsigned int hightime, unsigned int lowtime, - unsigned int cycle) +static int write_to_fifo(struct aml_irblaster_dev *dev, + unsigned int hightime, unsigned int lowtime) { unsigned int count_delay; + unsigned int cycle = 1000 / (dev->carrier_freqs / 1000); uint32_t val; int n = 0; int tb[3] = { 1, 10, 100 }; /* - *MODULATOR_TB: - * 00: system clock clk - * 01: mpeg_xtal3_tick - * 10: mpeg_1uS_tick - * 11: mpeg_10uS_tick - * lowtime<1024,n=0,timebase=1us - * 1024<=lowtime<10240,n=1,timebase=10us - * AO_IR_BLASTER_ADDR2 - * bit12: output level(or modulation enable/disable:1=enable) - * bit[11:10]: Timebase : - * 00=1us - * 01=10us - * 10=100us - * 11=Modulator clock - * bit[9:0]: Count of timebase units to delay - */ - count_delay = (((hightime + cycle/2) / cycle) - 1) & 0x3ff; - val = (0x10000 | (1 << 12)) | (3 << 10) | (count_delay << 0); - writel(val, irblaster_win->reg_base + AO_IR_BLASTER_ADDR2); + hightime: modulator signal. + MODULATOR_TB: + 00: system clock + 01: mpeg_xtal3_tick + 10: mpeg_1uS_tick + 11: mpeg_10uS_tick + + AO_IR_BLASTER_ADDR2 + bit12: output level(or modulation enable/disable:1=enable) + bit[11:10]: Timebase : + 00=1us + 01=10us + 10=100us + 11=Modulator clock + bit[9:0]: Count of timebase units to delay + */ + + count_delay = (((hightime + cycle/2) / cycle) - 1) & COUNT_DELAY_MASK; + val = (BLASTER_WRITE_FIFO | BLASTER_MODULATION_ENABLE | + BLASTER_TIMEBASE_MODULATION_CLOCK | (count_delay << 0)); + writel(val, dev->reg_base + AO_IR_BLASTER_ADDR2); + /* - * lowtime<1024,n=0,timebase=1us - * 1024<=lowtime<10240,n=1,timebase=10us - * 10240<=lowtime,n=2,timebase=100us - */ + lowtime<1024,n=0,timebase=1us + 1024<=lowtime<10240,n=1,timebase=10us + 10240<=lowtime,n=2,timebase=100us + */ n = lowtime >> 10; if (n > 0 && n < 10) n = 1; else if (n >= 10) n = 2; lowtime = (lowtime + (tb[n] >> 1))/tb[n]; - count_delay = (lowtime-1) & 0x3ff; - val = (0x10000 | (0 << 12)) | - (n << 10) | (count_delay << 0); - writel(val, irblaster_win->reg_base + AO_IR_BLASTER_ADDR2); + count_delay = (lowtime-1) & COUNT_DELAY_MASK; + val = (BLASTER_WRITE_FIFO & (~BLASTER_MODULATION_ENABLE)) | + (n << TIMEBASE_SHIFT) | (count_delay << 0); + writel(val, dev->reg_base + AO_IR_BLASTER_ADDR2); + return 0; } -static void irblaster_send_all_frame(struct blaster_window *cw) +static void send_all_data(struct aml_irblaster_dev *dev) { - int i, k; - int exp = 0x00; - unsigned int *pData; - unsigned int consumerir_cycle; - unsigned int high_ct, low_ct; - unsigned long cnt; + int i; + unsigned int *pdata = NULL; - irblaster_dbg("cw->winnum = %d\n", cw->winnum); - irblaster_dbg("cw->winarray = "); - for (i = 0; i < cw->winnum; i++) { - irblaster_dbg("%d,", cw->winarray[i]); - if (i % 10 == 9) - irblaster_dbg("\n"); - } - irblaster_dbg("\n"); - consumerir_cycle = 1000 / (irblaster_win->consumerir_freqs / 1000); - - /*reset*/ - writel(readl(irblaster_win->reset_base + - AO_RTI_GEN_CTNL_REG0) | (1 << 23), - irblaster_win->reset_base + AO_RTI_GEN_CTNL_REG0); - udelay(2); - writel(readl(irblaster_win->reset_base + - AO_RTI_GEN_CTNL_REG0) & ~(1 << 23), - irblaster_win->reset_base + AO_RTI_GEN_CTNL_REG0); - /* - *1.disable ir blaster - *2.set the modulator_tb = 2'10; mpeg_1uS_tick 1us - */ - writel((1 << 2) | (2 << 12) | (1<<2), - irblaster_win->reg_base + AO_IR_BLASTER_ADDR0); - /* - * 1. set mod_high_count = 13 - * 2. set mod_low_count = 13 - * 3. 60khz 8, 38k-13us, 12 - */ - high_ct = consumerir_cycle * irblaster_win->consumerir_dutycycle/100; - low_ct = consumerir_cycle - high_ct; - writel(((high_ct - 1) << 16) | ((low_ct - 1) << 0), - irblaster_win->reg_base + AO_IR_BLASTER_ADDR1); - - /* Setting this bit to 1 initializes the output to be high.*/ - writel(readl(irblaster_win->reg_base + AO_IR_BLASTER_ADDR0) & ~(1 << 2), - irblaster_win->reg_base + AO_IR_BLASTER_ADDR0); - /*enable irblaster_win*/ - writel(readl(irblaster_win->reg_base + AO_IR_BLASTER_ADDR0) | (1 << 0), - irblaster_win->reg_base + AO_IR_BLASTER_ADDR0); - k = cw->winnum; -#define SEND_BIT_NUM 64 - exp = cw->winnum / SEND_BIT_NUM; - pData = cw->winarray; - - while (exp) { - for (i = 0; i < SEND_BIT_NUM/2; i++) { - irblaster_send_bit(*pData, *(pData+1), - consumerir_cycle); - pData += 2; - } - cnt = jiffies + msecs_to_jiffies(1000); - while (!(readl(irblaster_win->reg_base + AO_IR_BLASTER_ADDR0) - & (1<<24)) && time_is_after_eq_jiffies(cnt)) - ; - cnt = jiffies + msecs_to_jiffies(1000); - while ((readl(irblaster_win->reg_base - + AO_IR_BLASTER_ADDR0) - & (1<<26)) && time_is_after_eq_jiffies(cnt)) - ; - /*reset*/ - writel(readl(irblaster_win->reset_base + - AO_RTI_GEN_CTNL_REG0) | (1 << 23), - irblaster_win->reset_base + AO_RTI_GEN_CTNL_REG0); - udelay(2); - writel(readl(irblaster_win->reset_base + - AO_RTI_GEN_CTNL_REG0) & ~(1 << 23), - irblaster_win->reset_base + AO_RTI_GEN_CTNL_REG0); - exp--; - } - exp = (cw->winnum % SEND_BIT_NUM) & (~(1)); - for (i = 0; i < exp; ) { - irblaster_send_bit(*pData, *(pData+1), consumerir_cycle); - pData += 2; + irblaster_dbg("dev->count = %d\n", dev->count); + pdata = &dev->buffer[dev->count]; + for (i = 0; (i < 120) && + (dev->count < dev->buffer_size);) { + write_to_fifo(dev, *pdata, *(pdata + 1)); + pdata += 2; + dev->count += 2; i += 2; } - - irblaster_dbg("The all frame finished !!\n"); - -} - - -static int irblaster_tx_thread(void *data) -{ -#ifdef CONFIG_IRBLASTER_ENABLE_PIN - struct irtx_dev *dev = (struct irtx_dev *)data; -#endif - struct tx_event *ev = NULL; - int retval; - int i; - unsigned long cnt; - - while (!kthread_should_stop()) { - irblaster_dbg("wakeup irblaster_tx_thread\n"); - retval = kfifo_len(&irblaster_fifo); - if (retval <= 0) { - set_current_state(TASK_INTERRUPTIBLE); - if (kthread_should_stop()) - set_current_state(TASK_RUNNING); - schedule(); - continue; - } - retval = kfifo_get(&irblaster_fifo, &ev); - irblaster_dbg("retval=%d,ev=%p\n", retval, ev); - if (retval) { - irblaster_win->winnum = ev->size; - for (i = 0; i < irblaster_win->winnum; i++) - irblaster_win->winarray[i] = ev->buffer[i]; - irblaster_dbg("irblaster_send_all_frame.size=%d\n", - ev->size); -#ifdef CONFIG_IRBLASTER_ENABLE_PIN - gpio_direction_output(dev->enable_pin, 1); -#endif - irblaster_send_all_frame(irblaster_win); - irblaster_event_put(ev); - cnt = jiffies + msecs_to_jiffies(1000); - while (!(readl(irblaster_win->reg_base - + AO_IR_BLASTER_ADDR0) & (1<<24)) - && time_is_after_eq_jiffies(cnt)) - ; - cnt = jiffies + msecs_to_jiffies(1000); - while ((readl(irblaster_win->reg_base - + AO_IR_BLASTER_ADDR0) & (1<<26)) - && time_is_after_eq_jiffies(cnt)) - ; -#ifdef CONFIG_IRBLASTER_ENABLE_PIN - gpio_direction_output(dev->enable_pin, 0); -#endif - } else - pr_err("kfifo_get fail\n"); + if (dev->count >= dev->buffer_size) { + irblaster_dbg("The all datas finished!\n"); + complete(&dev->blaster_completion); } - - return 0; } - /* - * Function to set the irblaster Carrier Frequency, - * The modulator is typically run between 32khz and 56khz. - * - * @param[in] pointer to irblaster structure. - * @param[in] carrirer freqs value. - * \return Reuturns 0 on success else return the error value. - */ -int set_irblaster_consumerir_freqs(struct blaster_window *irblaster_win, - int consumerir_freqs) +static irqreturn_t meson_blaster_interrupt(int irq, void *dev_id) { - return ((irblaster_win->consumerir_freqs = consumerir_freqs) >= 32000 - && (irblaster_win->consumerir_freqs <= 56000)) ? 0 : -1; + struct aml_irblaster_dev *dev = dev_id; + + irblaster_dbg("meson_blaster_interrupt !!\n"); + /*clear pending bit*/ + writel(readl(dev->reg_base + AO_IR_BLASTER_ADDR3) & + (~BLASTER_FIFO_THD_PENDING), + dev->reg_base + AO_IR_BLASTER_ADDR3); + schedule_work(&dev->blaster_work); + return IRQ_HANDLED; } - /* - * Function to get the irblaster_win cur Carrier Frequency. - * - * @param[in] pointer to irblaster_win structure. - * return Reuturns freqs. - */ - -static int get_irblaster_consumerir_freqs(struct blaster_window *irblaster_win) +int set_carrier_freqs(struct aml_irblaster_dev *dev, int carrier_freqs) { - return irblaster_win->consumerir_freqs; -} - -static int set_irblaster_duty_cycle(int duty_cycle) -{ - if (duty_cycle > 100 || duty_cycle < 0) + if (carrier_freqs > MAX_FREQ || carrier_freqs < LIMIT_FREQ) { + pr_info("freqs[%d,%d]\n", LIMIT_FREQ, MAX_FREQ); return -1; - irblaster_win->consumerir_dutycycle = duty_cycle; + } + dev->carrier_freqs = carrier_freqs; return 0; } -static int aml_ir_blaster_open(struct inode *inode, struct file *file) +static int get_carrier_freqs(struct aml_irblaster_dev *dev) { - irblaster_dbg("aml_ir_blaster_open()\n"); + return dev->carrier_freqs; +} + +static int set_duty_cycle(struct aml_irblaster_dev *dev, int duty_cycle) +{ + if (duty_cycle > MAX_DUTY || duty_cycle < LIMIT_DUTY) { + pr_info("duty_cycle[%d,%d]\n", LIMIT_DUTY, MAX_DUTY); + return -1; + } + dev->duty_cycle = duty_cycle; return 0; } -int irblaster_send(const char *buf, int len) +static int aml_irblaster_open(struct inode *inode, struct file *file) +{ + struct aml_irblaster_dev *dev = NULL; + + dev = container_of(inode->i_cdev, + struct aml_irblaster_dev, blaster_cdev); + file->private_data = dev; + return 0; +} + +static int send(struct aml_irblaster_dev *dev, const char *buf, int len) { - /*alloc memory*/ - struct tx_event *ev; int i = 0, j = 0, m = 0, ret = 0; int val; char tone[PS_SIZE]; - struct irtx_dev *irdev = tx_dev; + unsigned int sum_time = 0; - ev = irblaster_event_get(); - if (!ev) { - pr_info("please wait for send\n"); - return -ENOMEM; - } for (i = 0; i < len; i++) { - if (buf[i] == 's') { + if (buf[i] == '\0') { + break; + } else if (buf[i] == 's') { tone[j] = '\0'; ret = kstrtoint(tone, 10, &val); - pr_info("val is %d", val); - ev->buffer[m] = val * 10; + if (ret) { + pr_err("Invalid tone\n"); + return ret; + } + dev->buffer[m] = val*10; + sum_time = sum_time + val*10; j = 0; m++; - if (m >= IR_TX_BUFFER_SIZE) + if (m >= MAX_PLUSE) break; continue; } tone[j] = buf[i]; j++; - if (j >= PS_SIZE) { - irblaster_event_put(ev); pr_err("send timing value is out of range\n"); return -ENOMEM; } } - ev->size = m; - /*to send cycle to,*/ - kfifo_put(&irblaster_fifo, (const struct tx_event *)ev); - /*to wake up irblaster_tx_thread*/ - wake_up_process(irdev->thread); - return 0; + dev->buffer_size = m; + dev->count = 0; + send_all_data(dev); + ret = wait_for_completion_interruptible_timeout( + &dev->blaster_completion, msecs_to_jiffies(sum_time / 1000)); + if (ret) + pr_err("failed to send all data\n"); + return ret; } -static long aml_ir_blaster_ioctl(struct file *filp, unsigned int cmd, +static long aml_irblaster_ioctl(struct file *filp, unsigned int cmd, unsigned long args) { - - int consumerir_freqs = 0, duty_cycle = 0; + int carrier_freqs = 0, duty_cycle = 0; + static int psize; s32 r = 0; - char *sendcode; void __user *argp = (void __user *)args; + char *sendcode = NULL; + struct aml_irblaster_dev *dev = filp->private_data; - sendcode = kzalloc(MAX_PLUSE, GFP_KERNEL); - if (!sendcode) - return -ENOMEM; - - irblaster_dbg("aml_ir_blaster_ioctl() 0x%4x\n ", cmd); + irblaster_dbg("aml_irblaster_ioctl() 0x%4x\n ", cmd); switch (cmd) { case CONSUMERIR_TRANSMIT: - if (copy_from_user(sendcode, (char *)argp, - strlen((char *)argp))) { - kfree(sendcode); - return -EFAULT; + psize = psize ? psize:MAX_PLUSE; + sendcode = kcalloc(psize, sizeof(char), GFP_KERNEL); + if (sendcode == NULL) { + pr_err("can't get sendcode memory\n"); + return -ENOMEM; } + if (copy_from_user(sendcode, (char *)argp, + psize)) + return -EFAULT; pr_info("send code is %s\n", sendcode); - r = irblaster_send(sendcode, strlen(argp)); + mutex_lock(&blaster_mutex); + r = send(dev, sendcode, psize); + mutex_unlock(&blaster_mutex); + kfree(sendcode); break; case GET_CARRIER: pr_info("in get freq\n"); - consumerir_freqs = - get_irblaster_consumerir_freqs(irblaster_win); - put_user(consumerir_freqs, (int *)argp); - kfree(sendcode); - return consumerir_freqs; + carrier_freqs = get_carrier_freqs(dev); + put_user(carrier_freqs, (int *)argp); + return carrier_freqs; case SET_CARRIER: pr_info("in set freq\n"); - get_user(consumerir_freqs, (int *)argp); - r = set_irblaster_consumerir_freqs(irblaster_win, - consumerir_freqs); + if (get_user(carrier_freqs, (int *)argp) < 0) + return -EFAULT; + mutex_lock(&blaster_mutex); + r = set_carrier_freqs(dev, carrier_freqs); + mutex_unlock(&blaster_mutex); break; case SET_DUTYCYCLE: pr_info("in set duty_cycle\n"); - if (copy_from_user(&duty_cycle, argp, sizeof(int))) { - kfree(sendcode); + if (copy_from_user(&duty_cycle, argp, sizeof(int))) return -EFAULT; - } get_user(duty_cycle, (int *)argp); - r = set_irblaster_duty_cycle(duty_cycle); + mutex_lock(&blaster_mutex); + r = set_duty_cycle(dev, duty_cycle); + mutex_unlock(&blaster_mutex); break; - default: r = -ENOIOCTLCMD; break; } - - kfree(sendcode); return r; } -static int aml_ir_blaster_release(struct inode *inode, struct file *file) +static int aml_irblaster_release(struct inode *inode, struct file *file) { return 0; } @@ -456,77 +296,89 @@ static ssize_t store_debug(struct device *dev, return strlen(buf); } +static ssize_t show_carrier_freq(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aml_irblaster_dev *irblaster_dev = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", irblaster_dev->carrier_freqs); +} + static ssize_t store_carrier_freq(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int ret; + int ret = 0, val; + struct aml_irblaster_dev *irblaster_dev = dev_get_drvdata(dev); - mutex_lock(&irblaster_win->lock); - ret = kstrtoint(buf, 10, &irblaster_win->consumerir_freqs); + mutex_lock(&blaster_mutex); + ret = kstrtoint(buf, 10, &val); if (ret) { - pr_err("IR_OUT: Invalid input for carrier_freq\n"); + pr_err("Invalid input for carrier_freq\n"); + mutex_unlock(&blaster_mutex); return ret; } - irblaster_dbg("carrier_freq is %d\n", irblaster_win->consumerir_freqs); - mutex_unlock(&irblaster_win->lock); - return strlen(buf); + ret = set_carrier_freqs(irblaster_dev, val); + mutex_unlock(&blaster_mutex); + if (ret) + return ret; + pr_info("carrier_freq is %d\n", irblaster_dev->carrier_freqs); + return count; +} + +static ssize_t show_duty_cycle(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aml_irblaster_dev *irblaster_dev = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", irblaster_dev->duty_cycle); } static ssize_t store_duty_cycle(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int ret; + int ret = 0, val; + struct aml_irblaster_dev *irblaster_dev = dev_get_drvdata(dev); - mutex_lock(&irblaster_win->lock); - ret = kstrtoint(buf, 10, &irblaster_win->consumerir_dutycycle); + mutex_lock(&blaster_mutex); + ret = kstrtoint(buf, 10, &val); if (ret) { - pr_err("IR_OUT: Invalid input for carrier_freq\n"); + pr_err("Invalid input for duty_cycle\n"); + mutex_unlock(&blaster_mutex); return ret; } - irblaster_dbg("duty_cycle is %d\n", - irblaster_win->consumerir_dutycycle); - mutex_unlock(&irblaster_win->lock); - return strlen(buf); -} - -static ssize_t show_log(struct device *dev, - struct device_attribute *attr, char *buf) -{ - memset(buf, 0, PAGE_SIZE); - return strlen(buf); -} - -static ssize_t show_send_value(struct device *dev, - struct device_attribute *attr, char *buf) -{ - memset(buf, 0, PAGE_SIZE); - return strlen(buf); + ret = set_duty_cycle(irblaster_dev, val); + mutex_unlock(&blaster_mutex); + if (ret) + return ret; + pr_info("duty_cycle is %d\n", irblaster_dev->duty_cycle); + return count; } static ssize_t store_send(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - /*alloc memory*/ - struct tx_event *ev; + struct aml_irblaster_dev *irblaster_dev = dev_get_drvdata(dev); int i = 0, j = 0, m = 0, ret = 0; int val; char tone[PS_SIZE]; - struct irtx_dev *irdev = dev_get_drvdata(dev); + unsigned int sum_time = 0; - ev = irblaster_event_get(); - if (!ev) { - pr_err("please wait for send\n"); - return -ENOMEM; - } + mutex_lock(&blaster_mutex); while (buf[i] != '\0') { if (buf[i] == 's') { tone[j] = '\0'; ret = kstrtoint(tone, 10, &val); - ev->buffer[m] = val * 10; + if (ret) { + pr_err("Invalid tone\n"); + mutex_unlock(&blaster_mutex); + return ret; + } + irblaster_dev->buffer[m] = val*10; + sum_time = sum_time + val*10; j = 0; i++; m++; - if (m >= IR_TX_BUFFER_SIZE) + if (m >= MAX_PLUSE) break; continue; } @@ -535,194 +387,277 @@ static ssize_t store_send(struct device *dev, j++; if (j >= PS_SIZE) { pr_err("send timing value is out of range\n"); + mutex_unlock(&blaster_mutex); return -ENOMEM; } } - ev->size = m; - /*to send cycle to,*/ - kfifo_put(&irblaster_fifo, (const struct tx_event *)ev); - /*to wake up irblaster_tx_thread*/ - wake_up_process(irdev->thread); + + irblaster_dev->buffer_size = m; + irblaster_dbg("irblaster_dev->buffer_size = %d\n", + irblaster_dev->buffer_size); + irblaster_dbg("irblaster_dev->buffer =\n "); + for (i = 0; i < irblaster_dev->buffer_size; i++) + irblaster_dbg("%d\n", irblaster_dev->buffer[i]); + irblaster_dbg("sum_time = %d\n", sum_time); + irblaster_dev->count = 0; + send_all_data(irblaster_dev); + ret = wait_for_completion_interruptible_timeout( + &irblaster_dev->blaster_completion, + msecs_to_jiffies(sum_time / 1000)); + if (ret) + pr_err("failed to send all data\n"); + mutex_unlock(&blaster_mutex); return count; } static DEVICE_ATTR(debug, 0644, show_debug, store_debug); -static DEVICE_ATTR(log, 0444, show_log, NULL); -static DEVICE_ATTR(sendvalue, 0444, show_send_value, NULL); static DEVICE_ATTR(send, 0200, NULL, store_send); -static DEVICE_ATTR(carrier_freq, 0200, NULL, store_carrier_freq); -static DEVICE_ATTR(duty_cycle, 0200, NULL, store_duty_cycle); +static DEVICE_ATTR(carrier_freq, 0644, + show_carrier_freq, store_carrier_freq); +static DEVICE_ATTR(duty_cycle, 0644, + show_duty_cycle, store_duty_cycle); -static const struct file_operations aml_irblaster_fops = { - .owner = THIS_MODULE, - .open = aml_ir_blaster_open, - .compat_ioctl = aml_ir_blaster_ioctl, - .unlocked_ioctl = aml_ir_blaster_ioctl, - .release = aml_ir_blaster_release, +static struct attribute *irblaster_attributes[] = { + &dev_attr_debug.attr, + &dev_attr_send.attr, + &dev_attr_carrier_freq.attr, + &dev_attr_duty_cycle.attr, + NULL, }; -static int aml_ir_blaster_probe(struct platform_device *pdev) +static struct attribute_group irblaster_attribute_group = { + .attrs = irblaster_attributes, +}; + +const struct attribute_group *irblaster_attribute_groups[] = { + &irblaster_attribute_group, + NULL, +}; + +static const struct file_operations blaster_fops = { + .owner = THIS_MODULE, + .open = aml_irblaster_open, + .compat_ioctl = aml_irblaster_ioctl, + .unlocked_ioctl = aml_irblaster_ioctl, + .release = aml_irblaster_release, +}; + +static void do_blaster_send(struct work_struct *work) { - int r; - struct irtx_dev *dev = NULL; - struct pinctrl *p = NULL; + struct aml_irblaster_dev *dev = container_of(work, + struct aml_irblaster_dev, blaster_work); + + if (dev->count < dev->buffer_size) + send_all_data(dev); +} + +static void blaster_initialize(struct aml_irblaster_dev *dev) +{ + unsigned int carrier_cycle = 1000 / (dev->carrier_freqs / 1000); + unsigned int high_ct, low_ct; + + /* + *1. disable ir blaster + *2. set the modulator_tb = 2'10; mpeg_1uS_tick 1us + *3. set initializes the output to be high + */ + writel((~BLASTER_ENABLE) & (BLASTER_MODULATOR_TB_1US_TICK | + BLASTER_INIT_HIGH), dev->reg_base + AO_IR_BLASTER_ADDR0); + /* + *1. set mod_high_count = 13 + *2. set mod_low_count = 13 + *3. 60khz-8us, 38k-13us + */ + high_ct = carrier_cycle * dev->duty_cycle / 100; + low_ct = carrier_cycle - high_ct; + writel((BLASTER_MODULATION_LOW_COUNT(low_ct - 1) | + BLASTER_MODULATION_HIGH_COUNT(high_ct - 1)), + dev->reg_base + AO_IR_BLASTER_ADDR1); + /*mask initialize output to be high*/ + writel(readl(dev->reg_base + AO_IR_BLASTER_ADDR0) & + ~BLASTER_INIT_HIGH, + dev->reg_base + AO_IR_BLASTER_ADDR0); + /* + *1. set fifo irq enable + *2. set fifo irq threshold + */ + writel(BLASTER_FIFO_IRQ_ENABLE | + BLASTER_FIFO_IRQ_THRESHOLD(8), + dev->reg_base + AO_IR_BLASTER_ADDR3); + /*enable irblaster*/ + writel(readl(dev->reg_base + AO_IR_BLASTER_ADDR0) | + BLASTER_ENABLE, + dev->reg_base + AO_IR_BLASTER_ADDR0); +} + +static int aml_irblaster_probe(struct platform_device *pdev) +{ + int ret = 0; + struct aml_irblaster_dev *irblaster_dev = NULL; + struct pinctrl *irblaster_pinctrl = NULL; struct resource *reg_mem = NULL; + struct resource *res_irq = NULL; struct resource *reset_mem = NULL; void __iomem *reg_base = NULL; void __iomem *reset_base = NULL; - pr_info("irblaster probe\n"); - dev = devm_kzalloc(&pdev->dev, - sizeof(struct irtx_dev), GFP_KERNEL); - if (!dev) { - pr_info("faid to kzalloc irtx_dev"); - return -ENOMEM; - } - - irblaster_win = devm_kzalloc(&pdev->dev, - sizeof(struct blaster_window), GFP_KERNEL); - if (irblaster_win == NULL) - return -1; - - irblaster_win->consumerir_freqs = 38000; - irblaster_win->consumerir_dutycycle = 50; - + pr_info("probe\n"); if (!pdev->dev.of_node) { - pr_info("aml_irblaster: pdev->dev.of_node == NULL!\n"); + dev_err(&pdev->dev, "pdev->dev.of_node == NULL!\n"); return -1; } + irblaster_pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(irblaster_pinctrl)) { + dev_err(&pdev->dev, "pinctrl error.\n"); + return PTR_ERR(irblaster_pinctrl); + } + + irblaster_dev = devm_kzalloc(&pdev->dev, + sizeof(struct aml_irblaster_dev), GFP_KERNEL); + if (!irblaster_dev) + return -ENOMEM; + platform_set_drvdata(pdev, irblaster_dev); + irblaster_dev->dev = &pdev->dev; + + res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res_irq) + return -ENODEV; reg_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!IS_ERR_OR_NULL(reg_mem)) { reg_base = devm_ioremap_resource(&pdev->dev, reg_mem); if (IS_ERR(reg_base)) { - dev_err(&pdev->dev, "reg: cannot obtain I/O memory region"); + dev_err(&pdev->dev, "reg0: cannot obtain I/O memory region.\n"); return PTR_ERR(reg_base); } } else { - dev_err(&pdev->dev, "get IORESOURCE_MEM error"); + dev_err(&pdev->dev, "get IORESOURCE_MEM error.\n"); return PTR_ERR(reg_base); - } reset_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!IS_ERR_OR_NULL(reset_mem)) { reset_base = devm_ioremap_resource(&pdev->dev, - reset_mem); + reset_mem); if (IS_ERR(reset_base)) { - dev_err(&pdev->dev, "reg: cannot obtain I/O memory region"); + dev_err(&pdev->dev, "reg1: cannot obtain I/O memory region.\n"); return PTR_ERR(reset_base); } } else { - dev_err(&pdev->dev, "get IORESOURCE_MEM error"); + dev_err(&pdev->dev, "get IORESOURCE_MEM error.\n"); return PTR_ERR(reset_mem); } - dev->dev = &pdev->dev; - irblaster_win->reg_base = reg_base; - irblaster_win->reset_base = reset_base; + irblaster_dev->carrier_freqs = DEFAULT_CARRIER_FREQ; + irblaster_dev->duty_cycle = DEFAULT_DUTY_CYCLE; + irblaster_dev->reg_base = reg_base; + irblaster_dev->reset_base = reset_base; + irblaster_dev->irq = res_irq->start; - p = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(p)) { - dev_err(&pdev->dev, "pinctrl error, %ld\n", PTR_ERR(p)); - return -1; + ret = alloc_chrdev_region(&irblaster_dev->blaster_cdev.dev, 0, + BLASTER_DEVICE_COUNT, + BLASTER_NAME); + if (ret < 0) { + pr_err("Failed to alloc cdev major device\n"); + return ret; + } + cdev_init(&irblaster_dev->blaster_cdev, &blaster_fops); + irblaster_dev->blaster_cdev.owner = THIS_MODULE; + ret = cdev_add(&irblaster_dev->blaster_cdev, + irblaster_dev->blaster_cdev.dev, + BLASTER_DEVICE_COUNT); + if (ret) + goto err0; + irblaster_dev->blaster_class = class_create(THIS_MODULE, + BLASTER_NAME); + if (IS_ERR(irblaster_dev->blaster_class)) { + pr_err("Failed to class create\n"); + ret = PTR_ERR(irblaster_dev->blaster_class); + goto err1; } - r = alloc_chrdev_region(&am_irblaster_id, 0, DEIVE_COUNT, DEVICE_NAME); - if (r < 0) { - pr_err("Can't register major for ir irblaster device\n"); - return r; + irblaster_dev->dev = device_create_with_groups( + irblaster_dev->blaster_class, + NULL, + irblaster_dev->blaster_cdev.dev, + irblaster_dev, + irblaster_attribute_groups, + "irblaster%d", 1); + if (IS_ERR(irblaster_dev->dev)) { + pr_err("Failed to device create\n"); + ret = PTR_ERR(irblaster_dev->dev); + goto err2; } - cdev_init(&am_irblaster_device, &aml_irblaster_fops); - am_irblaster_device.owner = THIS_MODULE; - cdev_add(&(am_irblaster_device), am_irblaster_id, DEIVE_COUNT); - ir_blaster_class = class_create(THIS_MODULE, DEVICE_NAME); - if (IS_ERR(ir_blaster_class)) { - unregister_chrdev_region(am_irblaster_id, DEIVE_COUNT); - pr_info("Can't create class for ir irblaster device\n"); - return -1; - } - ir_blaster_dev = device_create(ir_blaster_class, NULL, - am_irblaster_id, dev, - "irblaster%d", 1); - if (ir_blaster_dev == NULL) { - pr_err("ir_blaster_dev create error\n"); - class_destroy(ir_blaster_class); - return -EEXIST; + init_completion(&irblaster_dev->blaster_completion); + INIT_WORK(&irblaster_dev->blaster_work, do_blaster_send); + ret = devm_request_irq(&pdev->dev, irblaster_dev->irq, + meson_blaster_interrupt, + IRQF_TRIGGER_RISING, + dev_name(&pdev->dev), + irblaster_dev); + if (ret) { + pr_err("Failed to request irq number\n"); + goto err2; } + /*initial blaster*/ + blaster_initialize(irblaster_dev); - mutex_init(&irblaster_win->lock); - device_create_file(ir_blaster_dev, &dev_attr_debug); - device_create_file(ir_blaster_dev, &dev_attr_log); - device_create_file(ir_blaster_dev, &dev_attr_sendvalue); - device_create_file(ir_blaster_dev, &dev_attr_send); - device_create_file(ir_blaster_dev, &dev_attr_duty_cycle); - device_create_file(ir_blaster_dev, &dev_attr_carrier_freq); - INIT_KFIFO(irblaster_fifo); - dev->thread = kthread_run(irblaster_tx_thread, dev, - "ir-blaster-thread"); - -#ifdef CONFIG_IRBLASTER_ENABLE_PIN - dev->enable_pin = of_get_named_gpio(pdev->dev.of_node, "enable_pin", 0); - gpio_request(dev->enable_pin, "ir enable pin"); - gpio_direction_output(dev->enable_pin, 0); -#endif - tx_dev = dev; return 0; + +err2: + class_destroy(irblaster_dev->blaster_class); +err1: + cdev_del(&irblaster_dev->blaster_cdev); +err0: + unregister_chrdev_region(irblaster_dev->blaster_cdev.dev, + BLASTER_DEVICE_COUNT); + + return ret; } -static int aml_ir_blaster_remove(struct platform_device *pdev) +static int aml_irblaster_remove(struct platform_device *pdev) { - pr_info("remove IRBLASTER\n"); - device_remove_file(ir_blaster_dev, &dev_attr_debug); - device_remove_file(ir_blaster_dev, &dev_attr_log); - device_remove_file(ir_blaster_dev, &dev_attr_sendvalue); - device_remove_file(ir_blaster_dev, &dev_attr_send); - device_remove_file(ir_blaster_dev, &dev_attr_carrier_freq); - device_remove_file(ir_blaster_dev, &dev_attr_duty_cycle); - kfree(irblaster_win); - cdev_del(&am_irblaster_device); - device_destroy(ir_blaster_class, am_irblaster_id); - class_destroy(ir_blaster_class); - unregister_chrdev_region(am_irblaster_id, DEIVE_COUNT); + struct aml_irblaster_dev *irblaster_dev = platform_get_drvdata(pdev); + + device_destroy(irblaster_dev->blaster_class, + irblaster_dev->blaster_cdev.dev); + class_destroy(irblaster_dev->blaster_class); + cdev_del(&irblaster_dev->blaster_cdev); + unregister_chrdev_region(irblaster_dev->blaster_cdev.dev, + BLASTER_DEVICE_COUNT); return 0; } -static const struct of_device_id ir_blaster_dt_match[] = { + +static const struct of_device_id irblaster_dt_match[] = { { .compatible = "amlogic, meson_irblaster", }, {}, }; -static struct platform_driver aml_ir_blaster_driver = { - .probe = aml_ir_blaster_probe, - .remove = aml_ir_blaster_remove, - .suspend = NULL, - .resume = NULL, +MODULE_DEVICE_TABLE(of, irblaster_dt_match); + +static struct platform_driver aml_irblaster_driver = { + .probe = aml_irblaster_probe, + .remove = aml_irblaster_remove, .driver = { - .name = "meson-ir_blaster", + .name = "meson_irblaster", .owner = THIS_MODULE, - .of_match_table = ir_blaster_dt_match, + .of_match_table = irblaster_dt_match, }, }; -static int __init aml_ir_blaster_init(void) +static int __init aml_irblaster_init(void) { - pr_info("BLASTER Driver Init\n"); - if (platform_driver_register(&aml_ir_blaster_driver)) { - irblaster_dbg("failed to register aml_ir_irblaster_driver module\n"); - return -ENODEV; - } - pr_info("BLASTER Driver End\n"); - return 0; + return platform_driver_register(&aml_irblaster_driver); } -static void __exit aml_ir_blaster_exit(void) +static void __exit aml_irblaster_exit(void) { - pr_info("IRBLASTER Driver exit\n"); - platform_driver_unregister(&aml_ir_blaster_driver); + platform_driver_unregister(&aml_irblaster_driver); } -module_init(aml_ir_blaster_init); -module_exit(aml_ir_blaster_exit); -MODULE_AUTHOR("platform-beijing"); -MODULE_DESCRIPTION("Irblaster Driver"); +module_init(aml_irblaster_init); +module_exit(aml_irblaster_exit); + +MODULE_AUTHOR("Amlogic, Inc."); +MODULE_DESCRIPTION("Amlogic Meson ir blaster driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/amlogic/irblaster/meson-irblaster.h b/drivers/amlogic/irblaster/meson-irblaster.h index 5927fe4ddcda..53cfdad10588 100644 --- a/drivers/amlogic/irblaster/meson-irblaster.h +++ b/drivers/amlogic/irblaster/meson-irblaster.h @@ -15,21 +15,78 @@ * */ -#ifndef AM_IRBLASTER_H -#define AM_IRBLASTER_H -#define MAX_PLUSE 1024 +#ifndef __LINUX_AML_IR_BLASTER_H +#define __LINUX_AML_IR_BLASTER_H + + +/* Amlogic AO_IR_BLASTER_ADDR0 bits */ +#define BLASTER_BUSY BIT(26) +#define BLASTER_FIFO_FULL BIT(25) +#define BLASTER_FIFO_EMPTY BIT(24) +#define BLASTER_FIFO_LEVEL (0xff << 16) +#define BLASTER_MODULATOR_TB_SYSTEM_CLOCK (0x0 << 12) +#define BLASTER_MODULATOR_TB_XTAL3_TICK (0x1 << 12) +#define BLASTER_MODULATOR_TB_1US_TICK (0x2 << 12) +#define BLASTER_MODULATOR_TB_10US_TICK (0x3 << 12) +#define BLASTER_SLOW_CLOCK_DIV (0xff << 4) +#define BLASTER_SLOW_CLOCK_MODE BIT(3) +#define BLASTER_INIT_HIGH BIT(2) +#define BLASTER_INIT_LOW BIT(1) +#define BLASTER_ENABLE BIT(0) + +/* Amlogic AO_IR_BLASTER_ADDR1 bits */ +#define BLASTER_MODULATION_LOW_COUNT(c) ((c) << 16) +#define BLASTER_MODULATION_HIGH_COUNT(c) ((c) << 0) + +/* Amlogic AO_IR_BLASTER_ADDR2 bits */ +#define BLASTER_WRITE_FIFO BIT(16) +#define BLASTER_MODULATION_ENABLE BIT(12) +#define BLASTER_TIMEBASE_1US (0x0 << 10) +#define BLASTER_TIMEBASE_10US (0x1 << 10) +#define BLASTER_TIMEBASE_100US (0x2 << 10) +#define BLASTER_TIMEBASE_MODULATION_CLOCK (0x3 << 10) + +/* Amlogic AO_IR_BLASTER_ADDR3 bits */ +#define BLASTER_FIFO_THD_PENDING BIT(16) +#define BLASTER_FIFO_IRQ_ENABLE BIT(8) +#define BLASTER_FIFO_IRQ_THRESHOLD(c) (((c) & 0xff) << 0) + +#define DEFAULT_CARRIER_FREQ (38000) +#define DEFAULT_DUTY_CYCLE (50) +#define BLASTER_DEVICE_COUNT (32) + +#define MAX_PLUSE (1024) +#define PS_SIZE (10) +#define LIMIT_DUTY (25) +#define MAX_DUTY (75) +#define LIMIT_FREQ (25000) +#define MAX_FREQ (60000) +#define COUNT_DELAY_MASK (0X3ff) +#define TIMEBASE_SHIFT (10) +#define BLASTER_KFIFO_SIZE (4) enum { /* Modulation level*/ fisrt_low = 0, fisrt_high = 1 }; -struct blaster_window { - unsigned int winnum; - unsigned int winarray[MAX_PLUSE]; - int consumerir_freqs; - unsigned int consumerir_dutycycle; - struct mutex lock; +struct blaster_kfifo { + int size; + unsigned int buffer[MAX_PLUSE]; +}; + +struct aml_irblaster_dev { + struct device *dev; + struct work_struct blaster_work; + struct class *blaster_class; + struct cdev blaster_cdev; + unsigned int count; + unsigned int irq; + unsigned int buffer_size; + unsigned int buffer[MAX_PLUSE]; + unsigned int carrier_freqs; + unsigned int duty_cycle; + struct completion blaster_completion; void __iomem *reg_base; void __iomem *reset_base; };