mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
irblaster: meson: refactored irblaster driver [1/1]
PD#SWPL-1856 Problem: refactored irblaster code Solution: 1. Refactor the code according to the core, provider, and consumer frameworks. 2. Provide software encode to let irblaster work according to different protocols 3. Provide a unified consumer interface to allow other consumer drivers to use irblaster. Verify: test pass on g12a_u200_v1 Change-Id: Ifd841ef0ed741b7fd721defc25691744ea2103f0 Signed-off-by: Bichao Zheng <bichao.zheng@amlogic.com>
This commit is contained in:
committed by
Jianxin Pan
parent
754ec0f2e8
commit
849e419957
13
MAINTAINERS
13
MAINTAINERS
@@ -14053,13 +14053,6 @@ AMLOGIC AXG ADD AO CLK
|
||||
M: Yun Cai <yun.cai@amlogic.com>
|
||||
F: drivers/amlogic/clk/axg/axg_ao.c
|
||||
|
||||
AMLOGIC Irblaster driver
|
||||
M: Zan Peng <zan.peng@amlogic.com>
|
||||
F: drivers/amlogic/irblaster/irblaster.c
|
||||
F: drivers/amlogic/irblaster/irblaster.h
|
||||
F: drivers/amlogic/irblaster/Kconfig
|
||||
F: drivers/amlogic/irblaster/Makefile
|
||||
|
||||
AMLOGIC AXG ADD CLKMSR INTERFACE
|
||||
M: wang xing <xing.wang@amlogic.com>
|
||||
F: include/linux/amlogic/clk_measure.h
|
||||
@@ -14415,9 +14408,9 @@ F: drivers/amlogic/cpufreq/meson-cpufreq.c
|
||||
F: drivers/amlogic/clk/clk-cpu-fclk-composite.c
|
||||
|
||||
AMLOGIC Irblaster driver
|
||||
M: yu.tu <yu.tu@amlogic.com>
|
||||
F: drivers/amlogic/irblaster/meson-irblaster.c
|
||||
F: drivers/amlogic/irblaster/meson-irblaster.h
|
||||
M: Bichao.Zheng <bichao.zheng@amlogic.com>
|
||||
F: drivers/amlogic/irblaster/*
|
||||
F: include/linux/amlogic/irblaster*
|
||||
|
||||
AMLOGIC THERMAL DRIVER
|
||||
M: Huan Biao <huan.biao@amlogic.com>
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -468,6 +468,16 @@
|
||||
clock-names = "clk_i2c";
|
||||
clock-frequency = <100000>;
|
||||
};
|
||||
|
||||
irblaster: meson-irblaster@c0 {
|
||||
compatible = "amlogic, aml_irblaster";
|
||||
reg = <0xc0 0xc>,
|
||||
<0x40 0x4>;
|
||||
#irblaster-cells = <2>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&irblaster_pins>;
|
||||
status = "disabled";
|
||||
};
|
||||
};/* end of aobus */
|
||||
|
||||
periphs: periphs@ff634400 {
|
||||
@@ -743,16 +753,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
irblaster: meson-irblaster {
|
||||
compatible = "amlogic, meson_irblaster";
|
||||
reg = <0xff8000c0 0x10>,
|
||||
<0xff800040 0x4>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&irblaster_pins>;
|
||||
interrupts = <0 198 1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
saradc:saradc {
|
||||
compatible = "amlogic,meson-axg-saradc";
|
||||
status = "okay";
|
||||
|
||||
@@ -746,6 +746,17 @@
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&ao_b_uart_pins>;
|
||||
};
|
||||
|
||||
irblaster: meson-irblaster@14c {
|
||||
compatible = "amlogic, meson_irblaster";
|
||||
reg = <0x14c 0x10>,
|
||||
<0x40 0x4>;
|
||||
#irblaster-cells = <2>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&irblaster_pins>;
|
||||
interrupts = <GIC_SPI 198 IRQ_TYPE_EDGE_RISING>;
|
||||
status = "disabled";
|
||||
};
|
||||
};/* end of aobus */
|
||||
|
||||
periphs: periphs@ff634400 {
|
||||
@@ -1323,15 +1334,6 @@
|
||||
clocks = <&clkc CLKID_VPU_CLKC_MUX>;
|
||||
clock-names = "vpu_clkc";
|
||||
};
|
||||
irblaster: meson-irblaster {
|
||||
compatible = "amlogic, meson_irblaster";
|
||||
reg = <0xff80014c 0x10>,
|
||||
<0xff800040 0x4>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&irblaster_pins>;
|
||||
interrupts = <0 198 1>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
sd_emmc_c: emmc@ffe07000 {
|
||||
status = "disabled";
|
||||
|
||||
@@ -802,6 +802,15 @@
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&ao_b_uart_pins>;
|
||||
};
|
||||
|
||||
irblaster: meson-irblaster@14c {
|
||||
compatible = "amlogic, meson_irblaster";
|
||||
reg = <0x14c 0x10>,
|
||||
<0x40 0x4>;
|
||||
#irblaster-cells = <2>;
|
||||
interrupts = <GIC_SPI 198 IRQ_TYPE_EDGE_RISING>;
|
||||
status = "disabled";
|
||||
};
|
||||
};/* end of aobus */
|
||||
|
||||
periphs: periphs@ff634400 {
|
||||
@@ -1424,15 +1433,6 @@
|
||||
clocks = <&clkc CLKID_VPU_CLKC_MUX>;
|
||||
clock-names = "vpu_clkc";
|
||||
};
|
||||
irblaster: meson-irblaster {
|
||||
compatible = "amlogic, meson_irblaster";
|
||||
reg = <0xff80014c 0x10>,
|
||||
<0xff800040 0x4>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&irblaster_pins>;
|
||||
interrupts = <0 198 1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
sd_emmc_c: emmc@ffe07000 {
|
||||
status = "disabled";
|
||||
|
||||
@@ -522,6 +522,14 @@
|
||||
clocks = <&clkc CLKID_I2C>;
|
||||
clock-names = "clk_i2c";
|
||||
};
|
||||
|
||||
irblaster: meson-irblaster@c0 {
|
||||
compatible = "amlogic, aml_irblaster";
|
||||
reg = <0xc0 0xc>,
|
||||
<0x40 0x4>;
|
||||
#irblaster-cells = <2>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
periphs: periphs@c8834000 {
|
||||
@@ -634,6 +642,20 @@
|
||||
function = "ee_cec";
|
||||
};
|
||||
};
|
||||
|
||||
irblaster_pins:irblaster_pin {
|
||||
mux {
|
||||
groups = "ir_out_ao7";
|
||||
function = "ir_out";
|
||||
};
|
||||
};
|
||||
|
||||
irblaster_pins1:irblaster_pin1 {
|
||||
mux {
|
||||
groups = "ir_out_ao9";
|
||||
function = "ir_out";
|
||||
};
|
||||
};
|
||||
}; /* end of pinctrl_aobus*/
|
||||
|
||||
&pinctrl_periphs {
|
||||
|
||||
@@ -629,6 +629,14 @@
|
||||
clocks = <&clkc CLKID_I2C>;
|
||||
clock-names = "clk_i2c";
|
||||
};
|
||||
|
||||
irblaster: meson-irblaster@c0 {
|
||||
compatible = "amlogic, aml_irblaster";
|
||||
reg = <0xc0 0xc>,
|
||||
<0x40 0x4>;
|
||||
#irblaster-cells = <2>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
periphs: periphs@c8834000 {
|
||||
@@ -734,6 +742,20 @@
|
||||
function = "ee_cec";
|
||||
};
|
||||
};
|
||||
|
||||
irblaster_pins:irblaster_pin {
|
||||
mux {
|
||||
groups = "ir_out_ao7";
|
||||
function = "ir_out";
|
||||
};
|
||||
};
|
||||
|
||||
irblaster_pins1:irblaster_pin1 {
|
||||
mux {
|
||||
groups = "ir_out_ao9";
|
||||
function = "ir_out";
|
||||
};
|
||||
};
|
||||
}; /* end of pinctrl_aobus*/
|
||||
|
||||
&pinctrl_periphs {
|
||||
|
||||
@@ -897,11 +897,12 @@
|
||||
max_frame_time = <200>;
|
||||
};
|
||||
|
||||
meson_irblaster: irblaster@14c {
|
||||
irblaster: meson-irblaster@14c {
|
||||
compatible = "amlogic, meson_irblaster";
|
||||
reg = <0x14c 0x10>,
|
||||
<0x40 0x4>;
|
||||
interrupts = <0 198 1>;
|
||||
#irblaster-cells = <2>;
|
||||
interrupts = <GIC_SPI 198 IRQ_TYPE_EDGE_RISING>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
||||
@@ -645,6 +645,14 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
irblaster: meson-irblaster@c0 {
|
||||
compatible = "amlogic, aml_irblaster";
|
||||
reg = <0xc0 0xc>,
|
||||
<0x40 0x4>;
|
||||
#irblaster-cells = <2>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
remote:rc@0580 {
|
||||
compatible = "amlogic, aml_remote";
|
||||
dev_name = "meson-remote";
|
||||
@@ -1186,6 +1194,20 @@
|
||||
function = "gpio_aobus";
|
||||
};
|
||||
};
|
||||
|
||||
irblaster_pins:irblaster_pin {
|
||||
mux {
|
||||
groups = "remote_out_ao2";
|
||||
function = "ir_out";
|
||||
};
|
||||
};
|
||||
|
||||
irblaster_pins1:irblaster_pin1 {
|
||||
mux {
|
||||
groups = "remote_out_ao6";
|
||||
function = "ir_out";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&pinctrl_periphs {
|
||||
|
||||
@@ -840,12 +840,12 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
meson-irblaster {
|
||||
compatible = "amlogic, am_irblaster";
|
||||
dev_name = "meson-irblaster";
|
||||
status = "disable";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&irblaster_pins>;
|
||||
irblaster: meson-irblaster@c0 {
|
||||
compatible = "amlogic, aml_irblaster";
|
||||
reg = <0xc0 0xc>,
|
||||
<0x40 0x4>;
|
||||
#irblaster-cells = <2>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
||||
@@ -1030,6 +1030,13 @@
|
||||
};
|
||||
};
|
||||
|
||||
irblaster_pins1:irblaster_pin1 {
|
||||
mux {
|
||||
groups = "remote_out_ao6";
|
||||
function = "ir_out";
|
||||
};
|
||||
};
|
||||
|
||||
pwmleds_pins:pwmleds {
|
||||
|
||||
mux {
|
||||
|
||||
@@ -362,7 +362,9 @@ CONFIG_AMLOGIC_ESM=y
|
||||
CONFIG_AMLOGIC_WIFI=y
|
||||
CONFIG_AMLOGIC_BT_DEVICE=y
|
||||
CONFIG_AMLOGIC_PCIE=y
|
||||
CONFIG_AMLOGIC_IRBLASTER=y
|
||||
CONFIG_AMLOGIC_IRBLASTER_CORE=y
|
||||
CONFIG_AMLOGIC_IRBLASTER_MESON=y
|
||||
CONFIG_AMLOGIC_IRBLASTER_PROTOCOL=y
|
||||
CONFIG_AMLOGIC_IIO=y
|
||||
CONFIG_AMLOGIC_SARADC=y
|
||||
CONFIG_AMLOGIC_DDR_TOOL=y
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -414,14 +414,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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -474,6 +474,16 @@
|
||||
clock-names = "clk_i2c";
|
||||
clock-frequency = <100000>;
|
||||
};
|
||||
|
||||
irblaster: meson-irblaster@c0 {
|
||||
compatible = "amlogic, aml_irblaster";
|
||||
reg = <0x0 0xc0 0x0 0xc>,
|
||||
<0x0 0x40 0x0 0x4>;
|
||||
#irblaster-cells = <2>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&irblaster_pins>;
|
||||
status = "disabled";
|
||||
};
|
||||
};/* end of aobus */
|
||||
|
||||
periphs: periphs@ff634400 {
|
||||
@@ -749,16 +759,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
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";
|
||||
|
||||
@@ -746,6 +746,17 @@
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&ao_b_uart_pins>;
|
||||
};
|
||||
|
||||
irblaster: meson-irblaster@14c {
|
||||
compatible = "amlogic, meson_irblaster";
|
||||
reg = <0x0 0x14c 0x0 0x10>,
|
||||
<0x0 0x40 0x0 0x4>;
|
||||
#irblaster-cells = <2>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&irblaster_pins>;
|
||||
interrupts = <GIC_SPI 198 IRQ_TYPE_EDGE_RISING>;
|
||||
status = "disabled";
|
||||
};
|
||||
};/* end of aobus */
|
||||
|
||||
periphs: periphs@ff634400 {
|
||||
@@ -1323,15 +1334,6 @@
|
||||
clocks = <&clkc CLKID_VPU_CLKC_MUX>;
|
||||
clock-names = "vpu_clkc";
|
||||
};
|
||||
irblaster: meson-irblaster {
|
||||
compatible = "amlogic, meson_irblaster";
|
||||
reg = <0x0 0xff80014c 0x0 0x10>,
|
||||
<0x0 0xff800040 0x0 0x4>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&irblaster_pins>;
|
||||
interrupts = <0 198 1>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
sd_emmc_c: emmc@ffe07000 {
|
||||
status = "disabled";
|
||||
|
||||
@@ -802,6 +802,15 @@
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&ao_b_uart_pins>;
|
||||
};
|
||||
|
||||
irblaster: meson-irblaster@14c {
|
||||
compatible = "amlogic, meson_irblaster";
|
||||
reg = <0x0 0x14c 0x0 0x10>,
|
||||
<0x0 0x40 0x0 0x4>;
|
||||
#irblaster-cells = <2>;
|
||||
interrupts = <GIC_SPI 198 IRQ_TYPE_EDGE_RISING>;
|
||||
status = "disabled";
|
||||
};
|
||||
};/* end of aobus */
|
||||
|
||||
periphs: periphs@ff634400 {
|
||||
@@ -1424,15 +1433,6 @@
|
||||
clocks = <&clkc CLKID_VPU_CLKC_MUX>;
|
||||
clock-names = "vpu_clkc";
|
||||
};
|
||||
irblaster: meson-irblaster {
|
||||
compatible = "amlogic, meson_irblaster";
|
||||
reg = <0x0 0xff80014c 0x0 0x10>,
|
||||
<0x0 0xff800040 0x0 0x4>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&irblaster_pins>;
|
||||
interrupts = <0 198 1>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
sd_emmc_c: emmc@ffe07000 {
|
||||
status = "disabled";
|
||||
|
||||
@@ -509,6 +509,14 @@
|
||||
clocks = <&clkc CLKID_I2C>;
|
||||
clock-names = "clk_i2c";
|
||||
};
|
||||
|
||||
irblaster: meson-irblaster@c0 {
|
||||
compatible = "amlogic, aml_irblaster";
|
||||
reg = <0x0 0xc0 0x0 0xc>,
|
||||
<0x0 0x40 0x0 0x4>;
|
||||
#irblaster-cells = <2>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
periphs: periphs@c8834000 {
|
||||
@@ -622,6 +630,19 @@
|
||||
};
|
||||
};
|
||||
|
||||
irblaster_pins:irblaster_pin {
|
||||
mux {
|
||||
groups = "ir_out_ao7";
|
||||
function = "ir_out";
|
||||
};
|
||||
};
|
||||
|
||||
irblaster_pins1:irblaster_pin1 {
|
||||
mux {
|
||||
groups = "ir_out_ao9";
|
||||
function = "ir_out";
|
||||
};
|
||||
};
|
||||
}; /* end of pinctrl_aobus*/
|
||||
|
||||
&pinctrl_periphs {
|
||||
|
||||
@@ -629,6 +629,14 @@
|
||||
clocks = <&clkc CLKID_I2C>;
|
||||
clock-names = "clk_i2c";
|
||||
};
|
||||
|
||||
irblaster: meson-irblaster@c0 {
|
||||
compatible = "amlogic, aml_irblaster";
|
||||
reg = <0x0 0xc0 0x0 0xc>,
|
||||
<0x0 0x40 0x0 0x4>;
|
||||
#irblaster-cells = <2>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
periphs: periphs@c8834000 {
|
||||
@@ -734,6 +742,20 @@
|
||||
function = "ee_cec";
|
||||
};
|
||||
};
|
||||
|
||||
irblaster_pins:irblaster_pin {
|
||||
mux {
|
||||
groups = "ir_out_ao7";
|
||||
function = "ir_out";
|
||||
};
|
||||
};
|
||||
|
||||
irblaster_pins1:irblaster_pin1 {
|
||||
mux {
|
||||
groups = "ir_out_ao9";
|
||||
function = "ir_out";
|
||||
};
|
||||
};
|
||||
}; /* end of pinctrl_aobus*/
|
||||
|
||||
&pinctrl_periphs {
|
||||
|
||||
@@ -878,11 +878,12 @@
|
||||
max_frame_time = <200>;
|
||||
};
|
||||
|
||||
meson_irblaster: irblaster@14c {
|
||||
irblaster: meson-irblaster@14c {
|
||||
compatible = "amlogic, meson_irblaster";
|
||||
reg = <0x0 0x14c 0x0 0x10>,
|
||||
<0x0 0x40 0x0 0x4>;
|
||||
interrupts = <0 198 1>;
|
||||
#irblaster-cells = <2>;
|
||||
interrupts = <GIC_SPI 198 IRQ_TYPE_EDGE_RISING>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
||||
@@ -645,6 +645,14 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
irblaster: meson-irblaster@c0 {
|
||||
compatible = "amlogic, aml_irblaster";
|
||||
reg = <0x0 0xc0 0x0 0xc>,
|
||||
<0x0 0x40 0x0 0x4>;
|
||||
#irblaster-cells = <2>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
remote:rc@0580 {
|
||||
compatible = "amlogic, aml_remote";
|
||||
dev_name = "meson-remote";
|
||||
@@ -1186,6 +1194,20 @@
|
||||
function = "gpio_aobus";
|
||||
};
|
||||
};
|
||||
|
||||
irblaster_pins:irblaster_pin {
|
||||
mux {
|
||||
groups = "remote_out_ao2";
|
||||
function = "ir_out";
|
||||
};
|
||||
};
|
||||
|
||||
irblaster_pins1:irblaster_pin1 {
|
||||
mux {
|
||||
groups = "remote_out_ao6";
|
||||
function = "ir_out";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&pinctrl_periphs {
|
||||
|
||||
@@ -840,15 +840,14 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
meson-irblaster {
|
||||
compatible = "amlogic, am_irblaster";
|
||||
dev_name = "meson-irblaster";
|
||||
status = "disable";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&irblaster_pins>;
|
||||
irblaster: meson-irblaster@c0 {
|
||||
compatible = "amlogic, aml_irblaster";
|
||||
reg = <0x0 0xc0 0x0 0xc>,
|
||||
<0x0 0x40 0x0 0x4>;
|
||||
#irblaster-cells = <2>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
||||
remote: rc@8040 {
|
||||
compatible = "amlogic, aml_remote";
|
||||
dev_name = "meson-remote";
|
||||
@@ -1030,6 +1029,13 @@
|
||||
};
|
||||
};
|
||||
|
||||
irblaster_pins1:irblaster_pin1 {
|
||||
mux {
|
||||
groups = "remote_out_ao6";
|
||||
function = "ir_out";
|
||||
};
|
||||
};
|
||||
|
||||
pwmleds_pins:pwmleds {
|
||||
|
||||
mux {
|
||||
|
||||
@@ -357,7 +357,9 @@ CONFIG_AMLOGIC_ESM=y
|
||||
CONFIG_AMLOGIC_WIFI=y
|
||||
CONFIG_AMLOGIC_BT_DEVICE=y
|
||||
CONFIG_AMLOGIC_PCIE=y
|
||||
CONFIG_AMLOGIC_IRBLASTER=y
|
||||
CONFIG_AMLOGIC_IRBLASTER_CORE=y
|
||||
CONFIG_AMLOGIC_IRBLASTER_MESON=y
|
||||
CONFIG_AMLOGIC_IRBLASTER_PROTOCOL=y
|
||||
CONFIG_AMLOGIC_IIO=y
|
||||
CONFIG_AMLOGIC_SARADC=y
|
||||
CONFIG_AMLOGIC_DDR_TOOL=y
|
||||
|
||||
@@ -108,7 +108,7 @@ obj-$(CONFIG_AMLOGIC_POWER) += power/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_PCIE) += pci/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_IRBLASTER) += irblaster/
|
||||
obj-$(CONFIG_AMLOGIC_IRBLASTER_CORE) += irblaster/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_IIO) += iio/
|
||||
|
||||
|
||||
@@ -1,11 +1,34 @@
|
||||
#
|
||||
# Input core configuration
|
||||
# Amlogic IRBLASTER
|
||||
#
|
||||
config AMLOGIC_IRBLASTER
|
||||
bool "Amlogic irblaster device surport"
|
||||
|
||||
menuconfig AMLOGIC_IRBLASTER_CORE
|
||||
tristate "Amlogic IRBLASTER Support"
|
||||
default n
|
||||
help
|
||||
Say Y here if you want to use the amlogic irblaster.
|
||||
This is the core code of amlogic irblaster. Say Y you
|
||||
can use the core api to implement the irblaster controller driver
|
||||
and use the api in the core to control the irblaster.
|
||||
This option alone add core code.
|
||||
|
||||
if AMLOGIC_IRBLASTER_CORE
|
||||
|
||||
config AMLOGIC_IRBLASTER_MESON
|
||||
tristate "Amlogic Meson SoC irblaster driver"
|
||||
default n
|
||||
help
|
||||
This enable irblaster support for soc mesom (irblaster communication
|
||||
controller) available in Amlogic Meson SoCs.
|
||||
If you want to use meson irblaster interface,
|
||||
say Y here.If you are not sure, say N.
|
||||
|
||||
config AMLOGIC_IRBLASTER_PROTOCOL
|
||||
tristate "Add Amlogic Meson irblaster encode"
|
||||
default n
|
||||
help
|
||||
This enables encode mode support for the irblaster (communication
|
||||
controller) available in Amlogic Meson SoCs.
|
||||
If you want to use meson irblaster interface,
|
||||
say Y here.If you are not sure, say N.
|
||||
|
||||
endif
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#
|
||||
# Makefile for the remote control drivers
|
||||
#
|
||||
|
||||
# Each configuration option enables a list of files.
|
||||
obj-$(CONFIG_AMLOGIC_IRBLASTER) += irblaster.o meson-irblaster.o
|
||||
obj-$(CONFIG_AMLOGIC_IRBLASTER_CORE) += core.o sysfs.o
|
||||
obj-$(CONFIG_AMLOGIC_IRBLASTER_MESON) += irblaster-meson.o aml-irblaster.o
|
||||
obj-$(CONFIG_AMLOGIC_IRBLASTER_PROTOCOL) += encoder.o irblaster-nec-encoder.o \
|
||||
irblaster-rca-encoder.o
|
||||
|
||||
430
drivers/amlogic/irblaster/aml-irblaster.c
Normal file
430
drivers/amlogic/irblaster/aml-irblaster.c
Normal file
@@ -0,0 +1,430 @@
|
||||
/*
|
||||
* drivers/amlogic/irblaster/aml-irblaster.c
|
||||
*
|
||||
* Copyright (C) 2017 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/kfifo.h>
|
||||
#include <linux/amlogic/irblaster.h>
|
||||
#include <linux/amlogic/irblaster_consumer.h>
|
||||
#include <linux/amlogic/irblaster_encoder.h>
|
||||
|
||||
#define AO_IR_BLASTER_ADDR0 (0x0)
|
||||
#define AO_IR_BLASTER_ADDR1 (0x4)
|
||||
#define AO_IR_BLASTER_ADDR2 (0x8)
|
||||
#define AO_IR_BLASTER_ADDR3 (0xc)
|
||||
|
||||
#define DEFAULT_CARRIER_FREQ (38000)
|
||||
#define DEFAULT_DUTY_CYCLE (50)
|
||||
#define BLASTER_DEVICE_COUNT (32)
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_IRBLASTER_PROTOCOL
|
||||
#define DEFAULT_IRBLASTER_PROTOCOL IRBLASTER_PROTOCOL_NEC
|
||||
#endif
|
||||
|
||||
#define IR_TX_EVENT_SIZE 4
|
||||
#define IR_TX_BUFFER_SIZE 1024
|
||||
|
||||
struct tx_event {
|
||||
struct list_head list;
|
||||
unsigned int size;
|
||||
unsigned int buffer[IR_TX_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
DECLARE_KFIFO(fifo, struct tx_event *, IR_TX_EVENT_SIZE);
|
||||
|
||||
struct aml_irblaster_dev {
|
||||
struct irblaster_chip chip;
|
||||
struct device *dev;
|
||||
struct task_struct *thread;
|
||||
struct completion blaster_completion;
|
||||
struct mutex lock;
|
||||
spinlock_t irblaster_lock; /* use to send data */
|
||||
void __iomem *reg_base;
|
||||
void __iomem *reset_base;
|
||||
unsigned int winnum;
|
||||
unsigned int winarray[MAX_PLUSE];
|
||||
};
|
||||
|
||||
static struct aml_irblaster_dev *
|
||||
to_aml_irblaster(struct irblaster_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct aml_irblaster_dev, chip);
|
||||
}
|
||||
|
||||
static struct tx_event *event_get(struct aml_irblaster_dev *cw)
|
||||
{
|
||||
struct tx_event *ev = NULL;
|
||||
|
||||
ev = devm_kzalloc(cw->dev,
|
||||
sizeof(struct tx_event), GFP_KERNEL);
|
||||
return ev;
|
||||
}
|
||||
|
||||
static void event_put(struct aml_irblaster_dev *cw, struct tx_event *ev)
|
||||
{
|
||||
devm_kfree(cw->dev, ev);
|
||||
}
|
||||
|
||||
static int send_bit(struct aml_irblaster_dev *cw, unsigned int hightime,
|
||||
unsigned int lowtime, unsigned int cycle)
|
||||
{
|
||||
unsigned int count_delay;
|
||||
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_relaxed(val, cw->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
|
||||
*/
|
||||
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_relaxed(val, cw->reg_base + AO_IR_BLASTER_ADDR2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void send_all_frame(struct aml_irblaster_dev *cw)
|
||||
{
|
||||
int i, k;
|
||||
int exp = 0x00;
|
||||
unsigned int *pData;
|
||||
unsigned int consumerir_cycle;
|
||||
unsigned int high_ct, low_ct;
|
||||
unsigned long cnt, flags;
|
||||
|
||||
consumerir_cycle = 1000 / (cw->chip.state.freq / 1000);
|
||||
|
||||
/*reset*/
|
||||
writel_relaxed(readl_relaxed(cw->reset_base) |
|
||||
(1 << 23), cw->reset_base);
|
||||
udelay(2);
|
||||
writel_relaxed(readl_relaxed(cw->reset_base) &
|
||||
~(1 << 23), cw->reset_base);
|
||||
|
||||
/*
|
||||
* 1.disable ir blaster
|
||||
* 2.set the modulator_tb = 2'10; mpeg_1uS_tick 1us
|
||||
*/
|
||||
writel_relaxed((1 << 2) | (2 << 12) | (1<<2),
|
||||
cw->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 * cw->chip.state.duty/100;
|
||||
low_ct = consumerir_cycle - high_ct;
|
||||
writel_relaxed(((high_ct - 1) << 16) | ((low_ct - 1) << 0),
|
||||
cw->reg_base + AO_IR_BLASTER_ADDR1);
|
||||
|
||||
/* Setting this bit to 1 initializes the output to be high.*/
|
||||
writel_relaxed(readl_relaxed(cw->reg_base + AO_IR_BLASTER_ADDR0) &
|
||||
~(1 << 2), cw->reg_base + AO_IR_BLASTER_ADDR0);
|
||||
|
||||
/*enable irblaster*/
|
||||
writel_relaxed(readl_relaxed(cw->reg_base + AO_IR_BLASTER_ADDR0) |
|
||||
(1 << 0), cw->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) {
|
||||
spin_lock_irqsave(&cw->irblaster_lock, flags);
|
||||
for (i = 0; i < SEND_BIT_NUM/2; i++) {
|
||||
send_bit(cw, *pData, *(pData+1), consumerir_cycle);
|
||||
pData += 2;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&cw->irblaster_lock, flags);
|
||||
cnt = jiffies + msecs_to_jiffies(1000);
|
||||
while (!(readl_relaxed(cw->reg_base + AO_IR_BLASTER_ADDR0) &
|
||||
(1<<24)) && time_is_after_eq_jiffies(cnt))
|
||||
;
|
||||
|
||||
cnt = jiffies + msecs_to_jiffies(1000);
|
||||
while ((readl_relaxed(cw->reg_base + AO_IR_BLASTER_ADDR0) &
|
||||
(1<<26)) && time_is_after_eq_jiffies(cnt))
|
||||
;
|
||||
|
||||
/*reset*/
|
||||
writel_relaxed(readl_relaxed(cw->reset_base) | (1 << 23),
|
||||
cw->reset_base);
|
||||
udelay(2);
|
||||
writel_relaxed(readl_relaxed(cw->reset_base) & ~(1 << 23),
|
||||
cw->reset_base);
|
||||
exp--;
|
||||
}
|
||||
|
||||
exp = (cw->winnum % SEND_BIT_NUM) & (~(1));
|
||||
spin_lock_irqsave(&cw->irblaster_lock, flags);
|
||||
for (i = 0; i < exp; ) {
|
||||
send_bit(cw, *pData, *(pData+1), consumerir_cycle);
|
||||
pData += 2;
|
||||
i += 2;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&cw->irblaster_lock, flags);
|
||||
cnt = jiffies + msecs_to_jiffies(1000);
|
||||
while (!(readl_relaxed(cw->reg_base + AO_IR_BLASTER_ADDR0) &
|
||||
(1<<24)) && time_is_after_eq_jiffies(cnt))
|
||||
;
|
||||
|
||||
cnt = jiffies + msecs_to_jiffies(1000);
|
||||
while ((readl_relaxed(cw->reg_base + AO_IR_BLASTER_ADDR0) &
|
||||
(1<<26)) && time_is_after_eq_jiffies(cnt))
|
||||
;
|
||||
|
||||
complete(&cw->blaster_completion);
|
||||
}
|
||||
|
||||
int aml_irblaster_send(struct irblaster_chip *chip,
|
||||
unsigned int *data,
|
||||
unsigned int len)
|
||||
{
|
||||
int i, ret;
|
||||
struct tx_event *ev;
|
||||
struct aml_irblaster_dev *irblaster_dev = to_aml_irblaster(chip);
|
||||
|
||||
init_completion(&irblaster_dev->blaster_completion);
|
||||
ev = event_get(irblaster_dev);
|
||||
ev->size = len;
|
||||
for (i = 0; i < ev->size; i++)
|
||||
ev->buffer[i] = data[i];
|
||||
|
||||
/* to send cycle */
|
||||
kfifo_put(&fifo, (const struct tx_event *)ev);
|
||||
/* to wake up ir_tx_thread */
|
||||
wake_up_process(irblaster_dev->thread);
|
||||
/* return after processing */
|
||||
ret = wait_for_completion_interruptible_timeout
|
||||
(&irblaster_dev->blaster_completion,
|
||||
msecs_to_jiffies(chip->sum_time / 1000));
|
||||
if (!ret) {
|
||||
pr_err("failed to send all data ret = %d\n", ret);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ir_tx_thread(void *data)
|
||||
{
|
||||
int retval, i;
|
||||
unsigned long cnt;
|
||||
struct aml_irblaster_dev *irblaster_dev
|
||||
= (struct aml_irblaster_dev *)data;
|
||||
struct tx_event *ev = NULL;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
retval = kfifo_len(&fifo);
|
||||
if (retval <= 0) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (kthread_should_stop())
|
||||
set_current_state(TASK_RUNNING);
|
||||
schedule();
|
||||
continue;
|
||||
}
|
||||
|
||||
retval = kfifo_get(&fifo, &ev);
|
||||
if (retval) {
|
||||
irblaster_dev->winnum = ev->size;
|
||||
for (i = 0; i < irblaster_dev->winnum; i++)
|
||||
irblaster_dev->winarray[i] = ev->buffer[i];
|
||||
|
||||
send_all_frame(irblaster_dev);
|
||||
event_put(irblaster_dev, ev);
|
||||
cnt = jiffies + msecs_to_jiffies(1000);
|
||||
while (!(readl_relaxed(irblaster_dev->reg_base +
|
||||
AO_IR_BLASTER_ADDR0) & (1<<24)) &&
|
||||
time_is_after_eq_jiffies(cnt))
|
||||
;
|
||||
|
||||
cnt = jiffies + msecs_to_jiffies(1000);
|
||||
while ((readl_relaxed(irblaster_dev->reg_base +
|
||||
AO_IR_BLASTER_ADDR0) & (1<<26)) &&
|
||||
time_is_after_eq_jiffies(cnt))
|
||||
;
|
||||
|
||||
} else
|
||||
pr_err("kfifo_get fail\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irblaster_ops aml_irblaster_ops = {
|
||||
.send = aml_irblaster_send,
|
||||
};
|
||||
|
||||
static int aml_irblaster_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct aml_irblaster_dev *irblaster_dev = NULL;
|
||||
struct resource *reg_mem = NULL;
|
||||
struct resource *reset_mem = NULL;
|
||||
void __iomem *reg_base = NULL;
|
||||
void __iomem *reset_base = NULL;
|
||||
int err;
|
||||
|
||||
if (!pdev->dev.of_node) {
|
||||
dev_err(&pdev->dev, "pdev->dev.of_node == NULL!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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, "reg0: cannot obtain I/O memory region.\n");
|
||||
return PTR_ERR(reg_base);
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
if (IS_ERR(reset_base)) {
|
||||
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.\n");
|
||||
return PTR_ERR(reset_mem);
|
||||
}
|
||||
|
||||
spin_lock_init(&irblaster_dev->irblaster_lock);
|
||||
init_completion(&irblaster_dev->blaster_completion);
|
||||
irblaster_dev->reg_base = reg_base;
|
||||
irblaster_dev->reset_base = reset_base;
|
||||
irblaster_dev->chip.dev = &pdev->dev;
|
||||
irblaster_dev->chip.ops = &aml_irblaster_ops;
|
||||
irblaster_dev->chip.of_irblaster_n_cells = 2;
|
||||
irblaster_dev->chip.state.freq = DEFAULT_CARRIER_FREQ;
|
||||
irblaster_dev->chip.state.duty = DEFAULT_DUTY_CYCLE;
|
||||
#ifdef CONFIG_AMLOGIC_IRBLASTER_PROTOCOL
|
||||
irblaster_dev->chip.state.protocol = DEFAULT_IRBLASTER_PROTOCOL;
|
||||
irblaster_set_protocol(&irblaster_dev->chip,
|
||||
DEFAULT_IRBLASTER_PROTOCOL);
|
||||
#endif
|
||||
err = irblasterchip_add(&irblaster_dev->chip);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed to register irblaster chip: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
irblaster_dev->thread = kthread_run(ir_tx_thread, irblaster_dev,
|
||||
"ir-blaster-thread");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aml_irblaster_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct aml_irblaster_dev *irblaster_dev = platform_get_drvdata(pdev);
|
||||
|
||||
irblasterchip_remove(&irblaster_dev->chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id irblaster_dt_match[] = {
|
||||
{
|
||||
.compatible = "amlogic, aml_irblaster",
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver aml_irblaster_driver = {
|
||||
.probe = aml_irblaster_probe,
|
||||
.remove = aml_irblaster_remove,
|
||||
.suspend = NULL,
|
||||
.resume = NULL,
|
||||
.driver = {
|
||||
.name = "aml-irblaster",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = irblaster_dt_match,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init aml_irblaster_init(void)
|
||||
{
|
||||
return platform_driver_register(&aml_irblaster_driver);
|
||||
}
|
||||
|
||||
static void __exit aml_irblaster_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&aml_irblaster_driver);
|
||||
}
|
||||
|
||||
fs_initcall_sync(aml_irblaster_init);
|
||||
module_exit(aml_irblaster_exit);
|
||||
MODULE_AUTHOR("Amlogic, Inc.");
|
||||
MODULE_DESCRIPTION("Amlogic ir blaster driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
366
drivers/amlogic/irblaster/core.c
Normal file
366
drivers/amlogic/irblaster/core.c
Normal file
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* drivers/amlogic/irblaster/core.c
|
||||
*
|
||||
* Copyright (C) 2017 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/amlogic/irblaster.h>
|
||||
|
||||
void irblaster_chip_data_clear(struct irblaster_chip *chip)
|
||||
{
|
||||
chip->buffer = NULL;
|
||||
chip->buffer_len = 0;
|
||||
chip->sum_time = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* irblaster_send() - send raw level data
|
||||
* @chip: irblaster controller
|
||||
* @data: raw level data (us)
|
||||
* @len: raw len
|
||||
*/
|
||||
int irblaster_send(struct irblaster_chip *chip, unsigned int *data,
|
||||
unsigned int len)
|
||||
{
|
||||
unsigned int sum_time = 0;
|
||||
int err, i;
|
||||
|
||||
if (!chip || (len % 2 == 1) || len == 0 || len > MAX_PLUSE) {
|
||||
pr_err("%s(): parameter error\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
sum_time += data[i];
|
||||
|
||||
chip->buffer = data;
|
||||
chip->buffer_len = len;
|
||||
chip->sum_time = sum_time;
|
||||
|
||||
if (chip->ops->send) {
|
||||
err = chip->ops->send(chip, data, len);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
pr_err("%s(): irblaster func %s not found\n",
|
||||
__func__, __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
irblaster_chip_data_clear(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* irblaster_set_freq() - set irblaster freq
|
||||
* @chip: irblaster controller
|
||||
* @freq: irblaster freq (HZ)
|
||||
*/
|
||||
int irblaster_set_freq(struct irblaster_chip *chip, unsigned int freq)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!chip || freq <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (chip->ops->set_freq) {
|
||||
ret = chip->ops->set_freq(chip, freq);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chip->state.freq = freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* irblaster_get_freq() - get irblaster freq
|
||||
* @chip: irblaster controller
|
||||
*/
|
||||
unsigned int irblaster_get_freq(struct irblaster_chip *chip)
|
||||
{
|
||||
unsigned int freq;
|
||||
|
||||
if (!chip)
|
||||
return -EINVAL;
|
||||
|
||||
if (chip->ops->get_freq) {
|
||||
freq = chip->ops->get_freq(chip);
|
||||
if (freq == 0)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
freq = chip->state.freq;
|
||||
}
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
/**
|
||||
* irblaster_set_duty() - set irblaster duty
|
||||
* @chip: irblaster controller
|
||||
* @duty: irblaster duty
|
||||
*/
|
||||
int irblaster_set_duty(struct irblaster_chip *chip, unsigned int duty)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!chip || duty <= 0 || duty > 100)
|
||||
return -EINVAL;
|
||||
|
||||
if (chip->ops->set_duty) {
|
||||
ret = chip->ops->set_duty(chip, duty);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
chip->state.duty = duty;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* irblaster_set_duty() - set irblaster duty
|
||||
* @chip: irblaster controller
|
||||
* @duty: irblaster duty
|
||||
*/
|
||||
unsigned int irblaster_get_duty(struct irblaster_chip *chip)
|
||||
{
|
||||
unsigned int duty;
|
||||
|
||||
if (chip->ops->get_duty) {
|
||||
duty = chip->ops->get_duty(chip);
|
||||
if (duty == 0)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
duty = chip->state.duty;
|
||||
}
|
||||
|
||||
return duty;
|
||||
}
|
||||
|
||||
/**
|
||||
* irblasterchip_remove() - remove a irblaster Controller
|
||||
* @chip: the irblaster chip to remove
|
||||
* @Returns: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int irblasterchip_remove(struct irblaster_chip *chip)
|
||||
{
|
||||
mutex_lock(&irblaster_lock);
|
||||
list_del_init(&chip->list);
|
||||
|
||||
if (chip->dev)
|
||||
of_node_put(chip->dev->of_node);
|
||||
|
||||
irblasterchip_sysfs_unexport(chip);
|
||||
mutex_unlock(&irblaster_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irblasterchip_remove);
|
||||
|
||||
static bool irblaster_ops_check(struct irblaster_ops *ops)
|
||||
{
|
||||
/* These one interfaces are the most basic of the irblaster */
|
||||
if (ops->send)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* irblasterchip_add() - register a new irblaster Controller
|
||||
* @chip: the irblaster chip to add
|
||||
* @Returns: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int irblasterchip_add(struct irblaster_chip *chip)
|
||||
{
|
||||
if (!chip || !chip->dev || !chip->ops)
|
||||
return -EINVAL;
|
||||
|
||||
if (!irblaster_ops_check(chip->ops))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&irblaster_lock);
|
||||
atomic_set(&chip->request, IRBLASTER_EXPORTED);
|
||||
INIT_LIST_HEAD(&chip->list);
|
||||
list_add(&chip->list, &irblaster_chips);
|
||||
irblasterchip_sysfs_export(chip);
|
||||
mutex_unlock(&irblaster_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irblasterchip_add);
|
||||
|
||||
/**
|
||||
* irblaster_put() - release a irblaster controller
|
||||
* @chip: irblaster controller
|
||||
*/
|
||||
void irblaster_put(struct irblaster_chip *chip)
|
||||
{
|
||||
if (!chip)
|
||||
return;
|
||||
|
||||
mutex_lock(&irblaster_lock);
|
||||
atomic_set(&chip->request, IRBLASTER_EXPORTED);
|
||||
irblaster_chip_data_clear(chip);
|
||||
irblasterchip_sysfs_export(chip);
|
||||
mutex_unlock(&irblaster_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irblaster_put);
|
||||
|
||||
static struct irblaster_chip *of_node_to_irblasterchip(struct device_node *np)
|
||||
{
|
||||
struct irblaster_chip *chip;
|
||||
|
||||
mutex_lock(&irblaster_lock);
|
||||
list_for_each_entry(chip, &irblaster_chips, list)
|
||||
if (chip->dev && chip->dev->of_node == np) {
|
||||
mutex_unlock(&irblaster_lock);
|
||||
if (atomic_read(&chip->request) == IRBLASTER_REQUESTED)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
return chip;
|
||||
}
|
||||
|
||||
mutex_unlock(&irblaster_lock);
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
||||
static int irblaster_set_default_state(struct irblaster_chip *pc,
|
||||
const struct of_phandle_args *args)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (pc->of_irblaster_n_cells < 2 ||
|
||||
args->args[0] <= 0 || args->args[1] > 100)
|
||||
return -EINVAL;
|
||||
|
||||
pc->state.freq = args->args[0];
|
||||
pc->state.duty = args->args[1];
|
||||
|
||||
ret = irblaster_set_freq(pc, pc->state.freq);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
ret = irblaster_set_duty(pc, pc->state.duty);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_irblaster_get() - request a irblaster via the irblaster framework
|
||||
* @np: device node to get the irblaster from
|
||||
* @con_id: consumer name
|
||||
*
|
||||
* Returns the irblaster controller parsed from the phandle and index
|
||||
* specified in the "irblaster-config" property of a device tree node
|
||||
* or a negative error-code on failure. Values parsed from the device
|
||||
* tree are stored in the returned irblaster device object.
|
||||
*
|
||||
* Returns: A pointer to the requested irblaster controller or an ERR_PTR()
|
||||
* -encoded error code on failure.
|
||||
*/
|
||||
struct irblaster_chip *of_irblaster_get(struct device_node *np,
|
||||
const char *con_id)
|
||||
{
|
||||
struct of_phandle_args args;
|
||||
struct irblaster_chip *pc;
|
||||
int err, index = 0;
|
||||
|
||||
err = of_parse_phandle_with_args(np, "irblaster-config",
|
||||
"#irblaster-cells", index,
|
||||
&args);
|
||||
if (err) {
|
||||
pr_err("%s(): can't parse \"irblaster-config\" property\n",
|
||||
__func__);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
pc = of_node_to_irblasterchip(args.np);
|
||||
if (IS_ERR(pc)) {
|
||||
pr_err("%s(): irblaster chip not found\n", __func__);
|
||||
pc = ERR_PTR(-EINVAL);
|
||||
goto put;
|
||||
}
|
||||
|
||||
if (args.args_count != pc->of_irblaster_n_cells) {
|
||||
pr_err("%s: wrong #irblaster-cells for %s\n", np->full_name,
|
||||
args.np->full_name);
|
||||
pc = ERR_PTR(-EINVAL);
|
||||
goto put;
|
||||
}
|
||||
|
||||
err = irblaster_set_default_state(pc, &args);
|
||||
if (err < 0) {
|
||||
pr_err("%s(): irblaster get state fail\n", __func__);
|
||||
pc = ERR_PTR(-EINVAL);
|
||||
goto put;
|
||||
}
|
||||
|
||||
atomic_set(&pc->request, IRBLASTER_REQUESTED);
|
||||
irblasterchip_sysfs_unexport(pc);
|
||||
put:
|
||||
of_node_put(args.np);
|
||||
|
||||
return pc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_irblaster_get);
|
||||
|
||||
static void devm_irblaster_release(struct device *dev, void *res)
|
||||
{
|
||||
irblaster_put(*(struct irblaster_chip **)res);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_of_irblaster_get() - resource managed of_irblaster_get()
|
||||
* @dev: device for irblaster consumer
|
||||
* @np: device node to get the irblaster from
|
||||
* @con_id: consumer name
|
||||
*
|
||||
* This function performs like of_irblaster_get() but the acquired irblaster
|
||||
* device will automatically be released on driver detach.
|
||||
*
|
||||
* Returns: A pointer to the requested irblaster device or an ERR_PTR()-encoded
|
||||
* error code on failure.
|
||||
*/
|
||||
struct irblaster_chip *devm_of_irblaster_get(struct device *dev,
|
||||
struct device_node *np,
|
||||
const char *con_id)
|
||||
{
|
||||
struct irblaster_chip **dr, *chip;
|
||||
|
||||
dr = devres_alloc(devm_irblaster_release, sizeof(*dr), GFP_KERNEL);
|
||||
if (!dr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
chip = of_irblaster_get(np, con_id);
|
||||
if (!IS_ERR(chip)) {
|
||||
*dr = chip;
|
||||
devres_add(dev, dr);
|
||||
} else {
|
||||
devres_free(dr);
|
||||
}
|
||||
|
||||
return chip;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_of_irblaster_get);
|
||||
267
drivers/amlogic/irblaster/encoder.c
Normal file
267
drivers/amlogic/irblaster/encoder.c
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* drivers/amlogic/irblaster/encoder.c
|
||||
*
|
||||
* Copyright (C) 2017 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/amlogic/irblaster.h>
|
||||
#include <linux/amlogic/irblaster_encoder.h>
|
||||
|
||||
static int irblaster_raw_gen_pulse_space(unsigned int *data,
|
||||
unsigned int *max,
|
||||
unsigned int pulse_width,
|
||||
unsigned int space_width,
|
||||
unsigned int len)
|
||||
{
|
||||
if (!*max)
|
||||
return -ENOBUFS;
|
||||
data[len - *max] = pulse_width;
|
||||
if (!--*max)
|
||||
return -ENOBUFS;
|
||||
data[len - *max] = space_width;
|
||||
--*max;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* irblaster_raw_gen() - Encode data to raw events with pulse-length modulation.
|
||||
* @data: Pointer to data
|
||||
* @timings: Pulse distance modulation timings.
|
||||
* @raw: Data bits to encode.
|
||||
* @Returns: buff len on success.
|
||||
*
|
||||
* Encodes the @n least significant bits of @data using space-distance
|
||||
* modulation with the timing characteristics described by @timings, writing up
|
||||
* to data using the *data pointer.
|
||||
*/
|
||||
int irblaster_raw_gen(unsigned int *data,
|
||||
const struct irblaster_raw_timings *timings,
|
||||
u32 raw)
|
||||
{
|
||||
int i, ret, max;
|
||||
int len = timings->data_size;
|
||||
unsigned int space;
|
||||
|
||||
max = len;
|
||||
if (timings->header_pulse) {
|
||||
ret = irblaster_raw_gen_pulse_space(data, &max,
|
||||
timings->header_pulse,
|
||||
timings->header_space,
|
||||
len);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (timings->msb_first) {
|
||||
for (i = timings->raw_nbits - 1; i >= 0; --i) {
|
||||
space = timings->bit_space[(raw >> i) & 1];
|
||||
ret = irblaster_raw_gen_pulse_space(data, &max,
|
||||
timings->bit_pulse,
|
||||
space, len);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < timings->raw_nbits; ++i, raw >>= 1) {
|
||||
space = timings->bit_space[raw & 1];
|
||||
ret = irblaster_raw_gen_pulse_space(data, &max,
|
||||
timings->bit_pulse,
|
||||
space, len);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = irblaster_raw_gen_pulse_space(data, &max,
|
||||
timings->trailer_pulse,
|
||||
timings->trailer_space,
|
||||
len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
unsigned int protocol_show_select(struct irblaster_chip *chip, char *buf)
|
||||
{
|
||||
struct irblaster_raw_handler *protocol;
|
||||
unsigned int len = 0;
|
||||
|
||||
mutex_lock(&irblaster_raw_handler_lock);
|
||||
list_for_each_entry(protocol, &irblaster_raw_handler_list, list) {
|
||||
if (chip->protocol &&
|
||||
chip->state.protocol == protocol->protocol)
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "[%s] ",
|
||||
protocol->name);
|
||||
else
|
||||
len += scnprintf(buf + len, PAGE_SIZE - len, "%s ",
|
||||
protocol->name);
|
||||
}
|
||||
|
||||
len += scnprintf(len + buf, PAGE_SIZE - len, "\n");
|
||||
mutex_unlock(&irblaster_raw_handler_lock);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
unsigned int protocol_store_select(const char *buf)
|
||||
{
|
||||
struct irblaster_raw_handler *protocol;
|
||||
|
||||
mutex_lock(&irblaster_raw_handler_lock);
|
||||
list_for_each_entry(protocol, &irblaster_raw_handler_list, list) {
|
||||
if (sysfs_streq(buf, protocol->name)) {
|
||||
mutex_unlock(&irblaster_raw_handler_lock);
|
||||
return protocol->protocol;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&irblaster_raw_handler_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* irblaster_raw_handler_register()
|
||||
* - register a new raw_handle
|
||||
* @ir_raw_handler: the raw_handle to add
|
||||
* @Returns: 0 on success
|
||||
*/
|
||||
int irblaster_raw_handler_register(struct irblaster_raw_handler *ir_raw_handler)
|
||||
{
|
||||
mutex_lock(&irblaster_raw_handler_lock);
|
||||
list_add_tail(&ir_raw_handler->list, &irblaster_raw_handler_list);
|
||||
mutex_unlock(&irblaster_raw_handler_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(irblaster_raw_handler_register);
|
||||
|
||||
/**
|
||||
* irblaster_raw_handler_unregister()
|
||||
* - unregister a raw_handle
|
||||
* @ir_raw_handler: the raw_handle to remove
|
||||
*/
|
||||
void irblaster_raw_handler_unregister(struct irblaster_raw_handler
|
||||
*ir_raw_handler)
|
||||
{
|
||||
mutex_lock(&irblaster_raw_handler_lock);
|
||||
list_del(&ir_raw_handler->list);
|
||||
mutex_unlock(&irblaster_raw_handler_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(irblaster_raw_handler_unregister);
|
||||
|
||||
/**
|
||||
* irblaster_send_key() - send key with addr and commmand
|
||||
* @chip: irblaster controller
|
||||
* @addr: remote control ID
|
||||
* @commmand: key
|
||||
*/
|
||||
int irblaster_send_key(struct irblaster_chip *chip, unsigned int addr,
|
||||
unsigned int commmand)
|
||||
{
|
||||
int ret;
|
||||
unsigned int *data;
|
||||
|
||||
if (!chip)
|
||||
return -EINVAL;
|
||||
|
||||
if (chip->ops->send_key) {
|
||||
ret = chip->ops->send_key(chip, addr, commmand);
|
||||
if (ret) {
|
||||
pr_err("%s(): irblaster_send fail\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
data = kzalloc(sizeof(uint32_t) * MAX_PLUSE, GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
if (chip->protocol->encode) {
|
||||
ret = chip->protocol->encode(chip->state.protocol,
|
||||
addr, commmand, data);
|
||||
if (ret <= 0) {
|
||||
pr_err("%s(): irblaster encode fail\n",
|
||||
__func__);
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
pr_err("%s(): irblaster func %s not found\n",
|
||||
__func__, __func__);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = irblaster_send(chip, data,
|
||||
chip->protocol->timing->data_size);
|
||||
if (ret) {
|
||||
pr_err("%s(): irblaster_send fail\n", __func__);
|
||||
goto err;
|
||||
}
|
||||
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
kfree(data);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* irblaster_set_protocol() - set irblaster protocol
|
||||
* @chip: irblaster controller
|
||||
* @ir_protocol: irblaster protocol
|
||||
*/
|
||||
int irblaster_set_protocol(struct irblaster_chip *chip,
|
||||
enum irblaster_protocol ir_protocol)
|
||||
{
|
||||
struct irblaster_raw_handler *protocol;
|
||||
|
||||
if (!chip || ir_protocol < 0 || ir_protocol >= IRBLASTER_PROTOCOL_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&irblaster_raw_handler_lock);
|
||||
|
||||
list_for_each_entry(protocol, &irblaster_raw_handler_list, list)
|
||||
if (protocol->protocol == ir_protocol) {
|
||||
chip->state.protocol = ir_protocol;
|
||||
chip->protocol = protocol;
|
||||
mutex_unlock(&irblaster_raw_handler_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
mutex_unlock(&irblaster_raw_handler_lock);
|
||||
pr_err("%s(): irblaster protocol is not found\n", __func__);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* irblaster_get_protocol() - get irblaster protocol
|
||||
* @chip: irblaster controller
|
||||
*/
|
||||
enum irblaster_protocol irblaster_get_protocol(struct irblaster_chip *chip)
|
||||
{
|
||||
if (!chip)
|
||||
return -EINVAL;
|
||||
|
||||
return chip->state.protocol;
|
||||
}
|
||||
415
drivers/amlogic/irblaster/irblaster-meson.c
Normal file
415
drivers/amlogic/irblaster/irblaster-meson.c
Normal file
@@ -0,0 +1,415 @@
|
||||
/*
|
||||
* drivers/amlogic/irblaster/irblaster-meson.c
|
||||
*
|
||||
* Copyright (C) 2017 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/amlogic/irblaster.h>
|
||||
#include <linux/amlogic/irblaster_consumer.h>
|
||||
#include <linux/amlogic/irblaster_encoder.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)
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_IRBLASTER_PROTOCOL
|
||||
#define DEFAULT_IRBLASTER_PROTOCOL IRBLASTER_PROTOCOL_NEC
|
||||
#endif
|
||||
|
||||
#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)
|
||||
|
||||
#define AO_IR_BLASTER_ADDR0 (0x0)
|
||||
#define AO_IR_BLASTER_ADDR1 (0x4)
|
||||
#define AO_IR_BLASTER_ADDR2 (0x8)
|
||||
#define AO_IR_BLASTER_ADDR3 (0xc)
|
||||
#define AO_RTI_GEN_CTNL_REG0 (0x0)
|
||||
|
||||
#define CONSUMERIR_TRANSMIT 0x5500
|
||||
#define GET_CARRIER 0x5501
|
||||
#define SET_CARRIER 0x5502
|
||||
#define SET_DUTYCYCLE 0x5503
|
||||
|
||||
struct meson_irblaster_dev {
|
||||
struct device *dev;
|
||||
struct work_struct blaster_work;
|
||||
struct irblaster_chip chip;
|
||||
struct completion blaster_completion;
|
||||
unsigned int count;
|
||||
unsigned int irq;
|
||||
unsigned int buffer_size;
|
||||
unsigned int *buffer;
|
||||
spinlock_t irblaster_lock; /* use to send data */
|
||||
void __iomem *reg_base;
|
||||
void __iomem *reset_base;
|
||||
};
|
||||
|
||||
static void meson_irblaster_tasklet(unsigned long data);
|
||||
DECLARE_TASKLET_DISABLED(irblaster_tasklet, meson_irblaster_tasklet, 0);
|
||||
|
||||
static struct meson_irblaster_dev *
|
||||
to_meson_irblaster(struct irblaster_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct meson_irblaster_dev, chip);
|
||||
}
|
||||
|
||||
static void blaster_initialize(struct meson_irblaster_dev *dev)
|
||||
{
|
||||
unsigned int carrier_cycle = 1000 / (dev->chip.state.freq / 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_relaxed((~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->chip.state.duty / 100;
|
||||
low_ct = carrier_cycle - high_ct;
|
||||
writel_relaxed((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_relaxed(readl_relaxed(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_relaxed(BLASTER_FIFO_IRQ_ENABLE |
|
||||
BLASTER_FIFO_IRQ_THRESHOLD(8),
|
||||
dev->reg_base + AO_IR_BLASTER_ADDR3);
|
||||
/*enable irblaster*/
|
||||
writel_relaxed(readl_relaxed(dev->reg_base + AO_IR_BLASTER_ADDR0) |
|
||||
BLASTER_ENABLE,
|
||||
dev->reg_base + AO_IR_BLASTER_ADDR0);
|
||||
}
|
||||
|
||||
static int write_to_fifo(struct meson_irblaster_dev *dev,
|
||||
unsigned int hightime,
|
||||
unsigned int lowtime)
|
||||
{
|
||||
unsigned int count_delay;
|
||||
unsigned int cycle = 1000 / (dev->chip.state.freq / 1000);
|
||||
u32 val;
|
||||
int n = 0;
|
||||
int tb[3] = {
|
||||
1, 10, 100
|
||||
};
|
||||
|
||||
/*
|
||||
* 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_relaxed(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
|
||||
*/
|
||||
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) & COUNT_DELAY_MASK;
|
||||
val = (BLASTER_WRITE_FIFO & (~BLASTER_MODULATION_ENABLE)) |
|
||||
(n << TIMEBASE_SHIFT) | (count_delay << 0);
|
||||
writel_relaxed(val, dev->reg_base + AO_IR_BLASTER_ADDR2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void send_all_data(struct meson_irblaster_dev *dev)
|
||||
{
|
||||
int i;
|
||||
unsigned int *pdata = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
pdata = &dev->buffer[dev->count];
|
||||
spin_lock_irqsave(&dev->irblaster_lock, flags);
|
||||
for (i = 0; (i < 120) && (dev->count < dev->buffer_size);) {
|
||||
write_to_fifo(dev, *pdata, *(pdata + 1));
|
||||
pdata += 2;
|
||||
dev->count += 2;
|
||||
i += 2;
|
||||
}
|
||||
spin_unlock_irqrestore(&dev->irblaster_lock, flags);
|
||||
}
|
||||
|
||||
int meson_irblaster_send(struct irblaster_chip *chip,
|
||||
unsigned int *data,
|
||||
unsigned int len)
|
||||
{
|
||||
int ret, i, sum_time = 0;
|
||||
unsigned int high_ct, low_ct;
|
||||
unsigned int cycle;
|
||||
struct meson_irblaster_dev *irblaster_dev = to_meson_irblaster(chip);
|
||||
|
||||
init_completion(&irblaster_dev->blaster_completion);
|
||||
irblaster_dev->buffer = data;
|
||||
irblaster_dev->buffer_size = len;
|
||||
irblaster_dev->count = 0;
|
||||
|
||||
for (i = 0; i < irblaster_dev->buffer_size; i++)
|
||||
sum_time = sum_time + data[i];
|
||||
|
||||
/*
|
||||
* 1. set mod_high_count = 13
|
||||
* 2. set mod_low_count = 13
|
||||
* 3. 60khz-8us, 38k-13us
|
||||
*/
|
||||
cycle = 1000 / (irblaster_dev->chip.state.freq / 1000);
|
||||
high_ct = cycle * irblaster_dev->chip.state.duty / 100;
|
||||
low_ct = cycle - high_ct;
|
||||
writel_relaxed((BLASTER_MODULATION_LOW_COUNT(low_ct - 1) |
|
||||
BLASTER_MODULATION_HIGH_COUNT(high_ct - 1)),
|
||||
irblaster_dev->reg_base + AO_IR_BLASTER_ADDR1);
|
||||
|
||||
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 ret = %d\n", ret);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irblaster_ops meson_irblaster_ops = {
|
||||
.send = meson_irblaster_send,
|
||||
};
|
||||
|
||||
static void meson_irblaster_tasklet(unsigned long data)
|
||||
{
|
||||
struct meson_irblaster_dev *dev = (struct meson_irblaster_dev *)data;
|
||||
|
||||
if (dev->count < dev->buffer_size)
|
||||
send_all_data(dev);
|
||||
}
|
||||
|
||||
static irqreturn_t meson_blaster_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct meson_irblaster_dev *dev = dev_id;
|
||||
|
||||
/*clear pending bit*/
|
||||
writel_relaxed(readl_relaxed(dev->reg_base + AO_IR_BLASTER_ADDR3) &
|
||||
(~BLASTER_FIFO_THD_PENDING),
|
||||
dev->reg_base + AO_IR_BLASTER_ADDR3);
|
||||
|
||||
if (dev->count >= dev->buffer_size) {
|
||||
complete(&dev->blaster_completion);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
tasklet_schedule(&irblaster_tasklet);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int meson_irblaster_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct meson_irblaster_dev *irblaster_dev = NULL;
|
||||
struct resource *reg_mem = NULL;
|
||||
void __iomem *reg_base = NULL;
|
||||
int err, ret;
|
||||
|
||||
if (!pdev->dev.of_node) {
|
||||
dev_err(&pdev->dev, "pdev->dev.of_node == NULL!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
irblaster_dev = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct meson_irblaster_dev),
|
||||
GFP_KERNEL);
|
||||
if (!irblaster_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&irblaster_dev->irblaster_lock);
|
||||
platform_set_drvdata(pdev, irblaster_dev);
|
||||
irblaster_dev->dev = &pdev->dev;
|
||||
|
||||
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, "reg0: cannot obtain I/O memory region.\n");
|
||||
return PTR_ERR(reg_base);
|
||||
}
|
||||
} else {
|
||||
dev_err(&pdev->dev, "get IORESOURCE_MEM error.\n");
|
||||
return PTR_ERR(reg_base);
|
||||
}
|
||||
|
||||
irblaster_dev->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
|
||||
if (!irblaster_dev->irq) {
|
||||
dev_err(&pdev->dev, "irq: Failed to request irq number.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
init_completion(&irblaster_dev->blaster_completion);
|
||||
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.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
irblaster_dev->reg_base = reg_base;
|
||||
irblaster_dev->chip.dev = &pdev->dev;
|
||||
irblaster_dev->chip.ops = &meson_irblaster_ops;
|
||||
irblaster_dev->chip.of_irblaster_n_cells = 2;
|
||||
irblaster_dev->chip.state.freq = DEFAULT_CARRIER_FREQ;
|
||||
irblaster_dev->chip.state.duty = DEFAULT_DUTY_CYCLE;
|
||||
#ifdef CONFIG_AMLOGIC_IRBLASTER_PROTOCOL
|
||||
irblaster_dev->chip.state.protocol = DEFAULT_IRBLASTER_PROTOCOL;
|
||||
irblaster_set_protocol(&irblaster_dev->chip,
|
||||
DEFAULT_IRBLASTER_PROTOCOL);
|
||||
#endif
|
||||
err = irblasterchip_add(&irblaster_dev->chip);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed to register irblaster chip: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
irblaster_tasklet.data = (unsigned long)irblaster_dev;
|
||||
tasklet_enable(&irblaster_tasklet);
|
||||
|
||||
/*initial blaster*/
|
||||
blaster_initialize(irblaster_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meson_irblaster_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct meson_irblaster_dev *irblaster_dev = platform_get_drvdata(pdev);
|
||||
|
||||
tasklet_disable(&irblaster_tasklet);
|
||||
tasklet_kill(&irblaster_tasklet);
|
||||
irblasterchip_remove(&irblaster_dev->chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id irblaster_dt_match[] = {
|
||||
{
|
||||
.compatible = "amlogic, meson_irblaster",
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, irblaster_dt_match);
|
||||
|
||||
static struct platform_driver meson_irblaster_driver = {
|
||||
.probe = meson_irblaster_probe,
|
||||
.remove = meson_irblaster_remove,
|
||||
.driver = {
|
||||
.name = "meson_irblaster",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = irblaster_dt_match,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init meson_irblaster_init(void)
|
||||
{
|
||||
return platform_driver_register(&meson_irblaster_driver);
|
||||
}
|
||||
|
||||
static void __exit meson_irblaster_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&meson_irblaster_driver);
|
||||
}
|
||||
|
||||
fs_initcall_sync(meson_irblaster_init);
|
||||
module_exit(meson_irblaster_exit);
|
||||
MODULE_AUTHOR("Amlogic, Inc.");
|
||||
MODULE_DESCRIPTION("Amlogic ir blaster driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
180
drivers/amlogic/irblaster/irblaster-nec-encoder.c
Normal file
180
drivers/amlogic/irblaster/irblaster-nec-encoder.c
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* drivers/amlogic/irblaster/irblaster-nec-encoder.c
|
||||
*
|
||||
* Copyright (C) 2017 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/amlogic/irblaster_encoder.h>
|
||||
|
||||
#define NEC_NBITS 32
|
||||
#define NEC_UNIT 562 /* ns */
|
||||
#define NEC_HEADER_PULSE 9000
|
||||
#define NEC_HEADER_SPACE 4500
|
||||
#define NEC_BIT_PULSE 560
|
||||
#define NEC_BIT_0_SPACE 560
|
||||
#define NEC_BIT_1_SPACE 1690
|
||||
#define NEC_TRAILER_PULSE 560
|
||||
#define NEC_TRAILER_SPACE 5600 /* even longer in reality */
|
||||
|
||||
static struct irblaster_raw_timings irblaster_nec_timings = {
|
||||
.header_pulse = NEC_HEADER_PULSE,
|
||||
.header_space = NEC_HEADER_SPACE,
|
||||
.bit_pulse = NEC_BIT_PULSE,
|
||||
.bit_space[0] = NEC_BIT_0_SPACE,
|
||||
.bit_space[1] = NEC_BIT_1_SPACE,
|
||||
.trailer_pulse = NEC_TRAILER_PULSE,
|
||||
.trailer_space = NEC_TRAILER_SPACE,
|
||||
.msb_first = 0,
|
||||
.raw_nbits = NEC_NBITS,
|
||||
.data_size = (NEC_NBITS + 2) * 2,
|
||||
};
|
||||
|
||||
static u32 irblaster_nec32_scancode_to_raw(enum irblaster_protocol protocol,
|
||||
unsigned int addrs,
|
||||
unsigned int commmand)
|
||||
{
|
||||
unsigned int addr = 0, addr_inv, data, data_inv;
|
||||
|
||||
data = commmand & 0xff;
|
||||
addr_inv = addr & 0xff;
|
||||
addr = addrs & 0xff;
|
||||
data_inv = data & 0xff;
|
||||
|
||||
return data_inv << 24 |
|
||||
data << 16 |
|
||||
addr_inv << 8 |
|
||||
addr;
|
||||
}
|
||||
|
||||
static u32 irblaster_necx_scancode_to_raw(enum irblaster_protocol protocol,
|
||||
unsigned int addrs,
|
||||
unsigned int commmand)
|
||||
{
|
||||
unsigned int addr, addr_inv, data, data_inv;
|
||||
|
||||
data = commmand & 0xff;
|
||||
addr = addrs & 0xff;
|
||||
addr_inv = addr & 0xff;
|
||||
data_inv = data ^ 0xff;
|
||||
|
||||
return data_inv << 24 |
|
||||
data << 16 |
|
||||
addr_inv << 8 |
|
||||
addr;
|
||||
}
|
||||
|
||||
static u32 irblaster_nec_scancode_to_raw(enum irblaster_protocol protocol,
|
||||
unsigned int addrs,
|
||||
unsigned int commmand)
|
||||
{
|
||||
unsigned int addr, addr_inv, data, data_inv;
|
||||
|
||||
data = commmand & 0xff;
|
||||
addr = addrs & 0xff;
|
||||
addr_inv = addr ^ 0xff;
|
||||
data_inv = data ^ 0xff;
|
||||
|
||||
return data_inv << 24 |
|
||||
data << 16 |
|
||||
addr_inv << 8 |
|
||||
addr;
|
||||
}
|
||||
|
||||
int irblaster_nec_encode(enum irblaster_protocol protocol,
|
||||
unsigned int addr,
|
||||
unsigned int commmand,
|
||||
unsigned int *data)
|
||||
{
|
||||
u32 raw, ret;
|
||||
|
||||
if (protocol >= IRBLASTER_PROTOCOL_MAX)
|
||||
return -ENODEV;
|
||||
|
||||
/* Convert a NEC scancode to raw NEC data */
|
||||
switch (protocol) {
|
||||
case IRBLASTER_PROTOCOL_NEC:
|
||||
raw = irblaster_nec_scancode_to_raw(protocol, addr, commmand);
|
||||
break;
|
||||
case IRBLASTER_PROTOCOL_NECX:
|
||||
raw = irblaster_necx_scancode_to_raw(protocol, addr, commmand);
|
||||
break;
|
||||
case IRBLASTER_PROTOCOL_NEC32:
|
||||
raw = irblaster_nec32_scancode_to_raw(protocol, addr, commmand);
|
||||
break;
|
||||
default:
|
||||
raw = irblaster_nec_scancode_to_raw(protocol, addr, commmand);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Modulate the raw data using a pulse distance modulation */
|
||||
ret = irblaster_raw_gen(data, &irblaster_nec_timings, raw);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct irblaster_raw_handler irblaster_nec_handler[] = {
|
||||
{
|
||||
.name = "NEC",
|
||||
.protocol = IRBLASTER_PROTOCOL_NEC,
|
||||
.encode = irblaster_nec_encode,
|
||||
.freq = 38000,
|
||||
.duty = 50,
|
||||
.timing = &irblaster_nec_timings,
|
||||
},
|
||||
{
|
||||
.name = "NECX",
|
||||
.protocol = IRBLASTER_PROTOCOL_NECX,
|
||||
.encode = irblaster_nec_encode,
|
||||
.freq = 38000,
|
||||
.duty = 50,
|
||||
.timing = &irblaster_nec_timings,
|
||||
},
|
||||
{
|
||||
.name = "NEC32",
|
||||
.protocol = IRBLASTER_PROTOCOL_NEC32,
|
||||
.encode = irblaster_nec_encode,
|
||||
.freq = 38000,
|
||||
.duty = 50,
|
||||
.timing = &irblaster_nec_timings,
|
||||
}
|
||||
};
|
||||
|
||||
static int __init irblaster_nec_decode_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(irblaster_nec_handler) /
|
||||
sizeof(struct irblaster_raw_handler); i++)
|
||||
irblaster_raw_handler_register(irblaster_nec_handler + i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit irblaster_nec_decode_exit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(irblaster_nec_handler) /
|
||||
sizeof(struct irblaster_raw_handler); i++)
|
||||
irblaster_raw_handler_unregister(irblaster_nec_handler + i);
|
||||
}
|
||||
|
||||
fs_initcall(irblaster_nec_decode_init);
|
||||
module_exit(irblaster_nec_decode_exit);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("NEC IR protocol decoder");
|
||||
99
drivers/amlogic/irblaster/irblaster-rca-encoder.c
Normal file
99
drivers/amlogic/irblaster/irblaster-rca-encoder.c
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* drivers/amlogic/irblaster/irblaster-rca-encoder.c
|
||||
*
|
||||
* Copyright (C) 2017 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/amlogic/irblaster_encoder.h>
|
||||
|
||||
#define RCA_NBITS 24
|
||||
#define RCA_UNIT 500 /* ns */
|
||||
#define RCA_HEADER_PULSE 4000
|
||||
#define RCA_HEADER_SPACE 4000
|
||||
#define RCA_BIT_PULSE 500
|
||||
#define RCA_BIT_0_SPACE 1000
|
||||
#define RCA_BIT_1_SPACE 2000
|
||||
#define RCA_TRAILER_PULSE 500
|
||||
#define RCA_TRAILER_SPACE 5600 /* even longer in reality */
|
||||
|
||||
static struct irblaster_raw_timings irblaster_rca_timings = {
|
||||
.header_pulse = RCA_HEADER_PULSE,
|
||||
.header_space = RCA_HEADER_SPACE,
|
||||
.bit_pulse = RCA_BIT_PULSE,
|
||||
.bit_space[0] = RCA_BIT_0_SPACE,
|
||||
.bit_space[1] = RCA_BIT_1_SPACE,
|
||||
.trailer_pulse = RCA_TRAILER_PULSE,
|
||||
.trailer_space = RCA_TRAILER_SPACE,
|
||||
.msb_first = 1,
|
||||
.raw_nbits = RCA_NBITS,
|
||||
.data_size = (RCA_NBITS + 2) * 2,
|
||||
};
|
||||
|
||||
static u32 irblaster_rca_scancode_to_raw(enum irblaster_protocol protocol,
|
||||
unsigned int addrs,
|
||||
unsigned int commmand)
|
||||
{
|
||||
unsigned int addr, addr_inv, data, data_inv;
|
||||
|
||||
data = commmand & 0xff;
|
||||
addr = addrs & 0x0f;
|
||||
addr_inv = addr ^ 0x0f;
|
||||
data_inv = data ^ 0xff;
|
||||
|
||||
return addr << 20 |
|
||||
data << 12 |
|
||||
addr_inv << 8 |
|
||||
data_inv;
|
||||
}
|
||||
|
||||
int irblaster_rca_encode(enum irblaster_protocol protocol, unsigned int addr,
|
||||
unsigned int commmand, unsigned int *data)
|
||||
{
|
||||
u32 raw, ret;
|
||||
|
||||
/* Convert a RCA scancode to raw rca data */
|
||||
raw = irblaster_rca_scancode_to_raw(protocol, addr, commmand);
|
||||
|
||||
/* Modulate the raw data using a pulse distance modulation */
|
||||
ret = irblaster_raw_gen(data, &irblaster_rca_timings, raw);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct irblaster_raw_handler irblaster_rca_handler = {
|
||||
.name = "RCA",
|
||||
.protocol = IRBLASTER_PROTOCOL_RCA,
|
||||
.encode = irblaster_rca_encode,
|
||||
.freq = 38000,
|
||||
.duty = 50,
|
||||
.timing = &irblaster_rca_timings,
|
||||
};
|
||||
|
||||
static int __init irblaster_rca_decode_init(void)
|
||||
{
|
||||
return irblaster_raw_handler_register(&irblaster_rca_handler);
|
||||
}
|
||||
|
||||
static void __exit irblaster_rca_decode_exit(void)
|
||||
{
|
||||
irblaster_raw_handler_unregister(&irblaster_rca_handler);
|
||||
}
|
||||
|
||||
fs_initcall(irblaster_rca_decode_init);
|
||||
module_exit(irblaster_rca_decode_exit);
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("RCA IR protocol decoder");
|
||||
275
drivers/amlogic/irblaster/sysfs.c
Normal file
275
drivers/amlogic/irblaster/sysfs.c
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* drivers/amlogic/irblaster/sysfs.c
|
||||
*
|
||||
* Copyright (C) 2017 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/amlogic/irblaster.h>
|
||||
#include <linux/amlogic/irblaster_consumer.h>
|
||||
#ifdef CONFIG_AMLOGIC_IRBLASTER_PROTOCOL
|
||||
#include <linux/amlogic/irblaster_encoder.h>
|
||||
#endif
|
||||
static ssize_t send_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct irblaster_chip *chip = dev_get_drvdata(dev);
|
||||
int i = 0, j = 0, m = 0;
|
||||
int val, ret;
|
||||
char tone[PS_SIZE];
|
||||
unsigned int *buffer;
|
||||
|
||||
buffer = kzalloc(sizeof(uint32_t) * MAX_PLUSE, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&chip->sys_lock);
|
||||
while (buf[i] != '\0') {
|
||||
if (buf[i] == 's') {
|
||||
tone[j] = '\0';
|
||||
ret = kstrtoint(tone, 10, &val);
|
||||
if (ret) {
|
||||
pr_err("Invalid tone\n");
|
||||
mutex_unlock(&chip->sys_lock);
|
||||
return ret;
|
||||
}
|
||||
buffer[m] = val * 10;
|
||||
j = 0;
|
||||
i++;
|
||||
m++;
|
||||
if (m >= MAX_PLUSE)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
tone[j] = buf[i];
|
||||
i++;
|
||||
j++;
|
||||
if (j >= PS_SIZE) {
|
||||
pr_err("send timing value is out of range\n");
|
||||
mutex_unlock(&chip->sys_lock);
|
||||
kfree(buffer);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
ret = irblaster_send(chip, buffer, m);
|
||||
if (ret)
|
||||
pr_err("send raw data fail\n");
|
||||
|
||||
irblaster_chip_data_clear(chip);
|
||||
mutex_unlock(&chip->sys_lock);
|
||||
kfree(buffer);
|
||||
|
||||
return ret ? : count;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_IRBLASTER_PROTOCOL
|
||||
static ssize_t send_key_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct irblaster_chip *chip = dev_get_drvdata(dev);
|
||||
unsigned int addr, command;
|
||||
int ret;
|
||||
|
||||
ret = sscanf(buf, "%x %x", &addr, &command);
|
||||
if (ret != 2) {
|
||||
pr_err("Can't parse addr and command,usage:[addr command]\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
mutex_lock(&chip->sys_lock);
|
||||
ret = irblaster_send_key(chip, addr, command);
|
||||
if (ret)
|
||||
pr_err("send key fail\n");
|
||||
|
||||
mutex_unlock(&chip->sys_lock);
|
||||
|
||||
return ret ? : count;
|
||||
}
|
||||
#endif
|
||||
|
||||
static ssize_t carrier_freq_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct irblaster_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", chip->state.freq);
|
||||
}
|
||||
|
||||
static ssize_t carrier_freq_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct irblaster_chip *chip = dev_get_drvdata(dev);
|
||||
int ret = 0, val;
|
||||
|
||||
ret = kstrtoint(buf, 10, &val);
|
||||
if (ret) {
|
||||
pr_err("Invalid input for carrier_freq\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_lock(&chip->sys_lock);
|
||||
ret = irblaster_set_freq(chip, val);
|
||||
if (ret)
|
||||
pr_err("set freq fail\n");
|
||||
|
||||
mutex_unlock(&chip->sys_lock);
|
||||
|
||||
return ret ? : count;
|
||||
}
|
||||
|
||||
static ssize_t duty_cycle_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct irblaster_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", chip->state.duty);
|
||||
}
|
||||
|
||||
static ssize_t duty_cycle_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct irblaster_chip *chip = dev_get_drvdata(dev);
|
||||
int ret = 0, val;
|
||||
|
||||
ret = kstrtoint(buf, 10, &val);
|
||||
if (ret) {
|
||||
pr_err("Invalid input for duty_cycle\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_lock(&chip->sys_lock);
|
||||
ret = irblaster_set_duty(chip, val);
|
||||
if (ret)
|
||||
pr_err("set duty fail\n");
|
||||
|
||||
mutex_unlock(&chip->sys_lock);
|
||||
|
||||
return ret ? : count;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_IRBLASTER_PROTOCOL
|
||||
static ssize_t protocol_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct irblaster_chip *chip = dev_get_drvdata(dev);
|
||||
unsigned int len;
|
||||
|
||||
len = protocol_show_select(chip, buf);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t protocol_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct irblaster_chip *chip = dev_get_drvdata(dev);
|
||||
unsigned int ret, protocol;
|
||||
|
||||
protocol = protocol_store_select(buf);
|
||||
if (protocol >= IRBLASTER_PROTOCOL_MAX)
|
||||
pr_err("protocol is not found\n");
|
||||
|
||||
ret = irblaster_set_protocol(chip, protocol);
|
||||
if (ret)
|
||||
pr_err("set protocol fail\n");
|
||||
|
||||
return ret ? : count;
|
||||
}
|
||||
#endif
|
||||
|
||||
//static DEVICE_ATTR(debug, 0644, show_debug, store_debug);
|
||||
static DEVICE_ATTR_WO(send);
|
||||
#ifdef CONFIG_AMLOGIC_IRBLASTER_PROTOCOL
|
||||
static DEVICE_ATTR_WO(send_key);
|
||||
#endif
|
||||
static DEVICE_ATTR_RW(carrier_freq);
|
||||
static DEVICE_ATTR_RW(duty_cycle);
|
||||
#ifdef CONFIG_AMLOGIC_IRBLASTER_PROTOCOL
|
||||
static DEVICE_ATTR_RW(protocol);
|
||||
#endif
|
||||
|
||||
static struct attribute *irblaster_chip_attrs[] = {
|
||||
// &dev_attr_debug.attr,
|
||||
&dev_attr_send.attr,
|
||||
#ifdef CONFIG_AMLOGIC_IRBLASTER_PROTOCOL
|
||||
&dev_attr_send_key.attr,
|
||||
#endif
|
||||
&dev_attr_carrier_freq.attr,
|
||||
&dev_attr_duty_cycle.attr,
|
||||
#ifdef CONFIG_AMLOGIC_IRBLASTER_PROTOCOL
|
||||
&dev_attr_protocol.attr,
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(irblaster_chip);
|
||||
|
||||
static struct class irblaster_class = {
|
||||
.name = "irblaster",
|
||||
.owner = THIS_MODULE,
|
||||
.dev_groups = irblaster_chip_groups,
|
||||
};
|
||||
|
||||
static int irblasterchip_sysfs_match(struct device *parent, const void *data)
|
||||
{
|
||||
return dev_get_drvdata(parent) == data;
|
||||
}
|
||||
|
||||
void irblasterchip_sysfs_export(struct irblaster_chip *chip)
|
||||
{
|
||||
struct device *parent;
|
||||
|
||||
/*
|
||||
* If device_create() fails the irblaster_chip is still usable by
|
||||
* the kernel its just not exported.
|
||||
*/
|
||||
parent = device_create(&irblaster_class, chip->dev, MKDEV(0, 0), chip,
|
||||
"irblaster%d", chip->base);
|
||||
if (IS_ERR(parent)) {
|
||||
dev_warn(chip->dev,
|
||||
"device_create failed for irblaster_chip sysfs export\n");
|
||||
}
|
||||
|
||||
mutex_init(&chip->sys_lock);
|
||||
}
|
||||
|
||||
void irblasterchip_sysfs_unexport(struct irblaster_chip *chip)
|
||||
{
|
||||
struct device *parent;
|
||||
|
||||
parent = class_find_device(&irblaster_class, NULL, chip,
|
||||
irblasterchip_sysfs_match);
|
||||
if (parent) {
|
||||
/* for class_find_device() */
|
||||
put_device(parent);
|
||||
device_unregister(parent);
|
||||
}
|
||||
}
|
||||
|
||||
static int __init irblaster_sysfs_init(void)
|
||||
{
|
||||
return class_register(&irblaster_class);
|
||||
}
|
||||
subsys_initcall(irblaster_sysfs_init);
|
||||
121
include/linux/amlogic/irblaster.h
Normal file
121
include/linux/amlogic/irblaster.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* include/linux/amlogic/irblaster.h
|
||||
*
|
||||
* Copyright (C) 2017 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_IRBLASTER_H
|
||||
#define __LINUX_IRBLASTER_H
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#ifdef CONFIG_AMLOGIC_IRBLASTER_PROTOCOL
|
||||
#include <linux/amlogic/irblaster_encoder.h>
|
||||
#endif
|
||||
|
||||
#define MAX_PLUSE 256
|
||||
#define PS_SIZE 10
|
||||
|
||||
struct irblaster_chip;
|
||||
|
||||
static DEFINE_MUTEX(irblaster_lock);
|
||||
static LIST_HEAD(irblaster_chips);
|
||||
|
||||
/**
|
||||
* enum irblaster_idle - Whether the controller is occupied
|
||||
* @IRBLASTER_EXPORTED: Controlled by the sysfs sys/class/irblaster
|
||||
* @IRBLASTER_REQUESTED: Controlled by consumer driver
|
||||
*/
|
||||
enum irblaster_idle {
|
||||
IRBLASTER_EXPORTED,
|
||||
IRBLASTER_REQUESTED
|
||||
};
|
||||
|
||||
/**
|
||||
* struct irblaster_ops - irblaster controller operations
|
||||
* @send: send raw level data
|
||||
* @send_key: send key according to the protocol
|
||||
* @set_freq: set irblaster freq
|
||||
* @get_freq: get irblaster freq
|
||||
* @set_duty: set irblaster duty
|
||||
* @get_duty: get irblaster duty
|
||||
*/
|
||||
struct irblaster_ops {
|
||||
int (*send)(struct irblaster_chip *chip,
|
||||
unsigned int *data, unsigned int len);
|
||||
#ifdef CONFIG_AMLOGIC_IRBLASTER_PROTOCOL
|
||||
int (*send_key)(struct irblaster_chip *chip,
|
||||
unsigned int addr, int commmand);
|
||||
/* int (*set_protocol)(struct irblaster_chip *chip, */
|
||||
/* enum irblaster_protocol protocol);*/
|
||||
#endif
|
||||
int (*set_freq)(struct irblaster_chip *chip, unsigned int freq);
|
||||
unsigned int (*get_freq)(struct irblaster_chip *chip);
|
||||
int (*set_duty)(struct irblaster_chip *chip, unsigned int duty);
|
||||
unsigned int (*get_duty)(struct irblaster_chip *chip);
|
||||
};
|
||||
|
||||
struct irblaster_state {
|
||||
unsigned int freq;
|
||||
unsigned int duty;
|
||||
int enabled;
|
||||
int idle;
|
||||
#ifdef CONFIG_AMLOGIC_IRBLASTER_PROTOCOL
|
||||
enum irblaster_protocol protocol;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* struct irblaster_chip - abstract a irblaster controller
|
||||
* @dev: device providing the irblaster
|
||||
* @list: list node for internal use
|
||||
* @ops: callbacks for this irblaster controller
|
||||
* @base: number of first irblaster controlled by this chip
|
||||
* @of_irblaster_n_cells: number of cells expected in the device tree
|
||||
* irblaster specifier
|
||||
* @state: irblaster controller status
|
||||
* @buffer: data
|
||||
* @buffer_len: data len
|
||||
* @sum_time: total time
|
||||
* @request: whether the controller is occupied
|
||||
*/
|
||||
struct irblaster_chip {
|
||||
struct device *dev;
|
||||
struct list_head list;
|
||||
struct irblaster_ops *ops;
|
||||
#ifdef CONFIG_AMLOGIC_IRBLASTER_PROTOCOL
|
||||
struct irblaster_raw_handler *protocol;
|
||||
#endif
|
||||
struct irblaster_state state;
|
||||
struct mutex sys_lock; /* use to sysfs */
|
||||
unsigned int base;
|
||||
unsigned int of_irblaster_n_cells;
|
||||
/* unsigned int buffer[MAX_PLUSE]; */
|
||||
unsigned int *buffer;
|
||||
unsigned int buffer_len;
|
||||
unsigned int sum_time;
|
||||
atomic_t request;
|
||||
};
|
||||
|
||||
/* irblaster sysfs APIs */
|
||||
void irblasterchip_sysfs_export(struct irblaster_chip *chip);
|
||||
void irblasterchip_sysfs_unexport(struct irblaster_chip *chip);
|
||||
|
||||
/* irblaster provider APIs */
|
||||
int irblasterchip_add(struct irblaster_chip *chip);
|
||||
int irblasterchip_remove(struct irblaster_chip *chip);
|
||||
void irblaster_chip_data_clear(struct irblaster_chip *chip);
|
||||
|
||||
#endif /* __LINUX_IRBLASTER_H */
|
||||
55
include/linux/amlogic/irblaster_consumer.h
Normal file
55
include/linux/amlogic/irblaster_consumer.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* include/linux/amlogic/irblaster_consumer.h
|
||||
*
|
||||
* Copyright (C) 2017 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_IRBLASTER_CONSUMER_H
|
||||
#define __LINUX_IRBLASTER_CONSUMER_H
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#ifdef CONFIG_AMLOGIC_IRBLASTER_PROTOCOL
|
||||
#include <linux/amlogic/irblaster_encoder.h>
|
||||
#endif
|
||||
|
||||
struct irblaster_chip;
|
||||
|
||||
/* irblaster user APIs */
|
||||
int irblaster_send(struct irblaster_chip *chip,
|
||||
unsigned int *data,
|
||||
unsigned int len);
|
||||
int irblaster_set_freq(struct irblaster_chip *chip,
|
||||
unsigned int freq);
|
||||
unsigned int irblaster_get_freq(struct irblaster_chip *chip);
|
||||
int irblaster_set_duty(struct irblaster_chip *chip, unsigned int duty);
|
||||
unsigned int irblaster_get_duty(struct irblaster_chip *chip);
|
||||
struct irblaster_chip *of_irblaster_get(struct device_node *np,
|
||||
const char *con_id);
|
||||
struct irblaster_chip *devm_of_irblaster_get(struct device *dev,
|
||||
struct device_node *np,
|
||||
const char *con_id);
|
||||
void irblaster_put(struct irblaster_chip *chip);
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_IRBLASTER_PROTOCOL
|
||||
int irblaster_send_key(struct irblaster_chip *chip,
|
||||
unsigned int addr,
|
||||
unsigned int commmand);
|
||||
int irblaster_set_protocol(struct irblaster_chip *chip,
|
||||
enum irblaster_protocol ir_protocol);
|
||||
enum irblaster_protocol irblaster_get_protocol(struct irblaster_chip *chip);
|
||||
#endif
|
||||
|
||||
#endif /* __LINUX_IRBLASTER_CONSUMER_H */
|
||||
97
include/linux/amlogic/irblaster_encoder.h
Normal file
97
include/linux/amlogic/irblaster_encoder.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* include/linux/amlogic/irblaster_encoder.h
|
||||
*
|
||||
* Copyright (C) 2017 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_ENCODER_H
|
||||
#define __LINUX_ENCODER_H
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
struct irblaster_chip;
|
||||
int irblaster_send(struct irblaster_chip *chip, unsigned int *data,
|
||||
unsigned int len);
|
||||
|
||||
static DEFINE_MUTEX(irblaster_raw_handler_lock);
|
||||
static LIST_HEAD(irblaster_raw_handler_list);
|
||||
|
||||
/**
|
||||
* enum irblaster_protocol - protocol of irblaster
|
||||
* add a new protocol here
|
||||
* @IRBLASTER_PROTOCOL_MAX: Maximum number of support protocol
|
||||
* please add a new protocol before this
|
||||
*/
|
||||
enum irblaster_protocol {
|
||||
IRBLASTER_PROTOCOL_NEC,
|
||||
IRBLASTER_PROTOCOL_NECX,
|
||||
IRBLASTER_PROTOCOL_NEC32,
|
||||
IRBLASTER_PROTOCOL_RCA,
|
||||
IRBLASTER_PROTOCOL_MAX
|
||||
};
|
||||
|
||||
#define IRBLASTER_PROTOCOL_BIT_NEC BIT_ULL(IRBLASTER_PROTOCOL_NEC)
|
||||
#define IRBLASTER_PROTOCOL_BIT_NECX BIT_ULL(IRBLASTER_PROTOCOL_NECX)
|
||||
#define IRBLASTER_PROTOCOL_BIT_NEC32 BIT_ULL(IRBLASTER_PROTOCOL_NEC32)
|
||||
#define IRBLASTER_PROTOCOL_BIT_RCA BIT_ULL(IRBLASTER_PROTOCOL_RCA)
|
||||
|
||||
/**
|
||||
* struct irblaster_raw_timings - pulse-length modulation timings
|
||||
* @header_pulse: duration of header pulse in ns (0 for none)
|
||||
* @bit_space: duration of bit space in ns
|
||||
* @bit_pulse: duration of bit pulse (for logic 0 and 1) in ns
|
||||
* @trailer_space: duration of trailer space in ns
|
||||
* @msb_first: 1 if most significant bit is sent first
|
||||
* @raw_nbits: raw bit len
|
||||
* @data_size: the total length of the array
|
||||
*/
|
||||
struct irblaster_raw_timings {
|
||||
unsigned int header_pulse;
|
||||
unsigned int header_space;
|
||||
unsigned int bit_pulse;
|
||||
unsigned int bit_space[2];
|
||||
unsigned int trailer_pulse;
|
||||
unsigned int trailer_space;
|
||||
unsigned int msb_first:1;
|
||||
unsigned int raw_nbits;
|
||||
unsigned int data_size;
|
||||
};
|
||||
|
||||
struct irblaster_raw_handler {
|
||||
struct list_head list;
|
||||
char *name;
|
||||
int protocol; /* which are handled by this handler */
|
||||
int (*encode)(enum irblaster_protocol protocol, unsigned int addr,
|
||||
unsigned int commmand, unsigned int *data);
|
||||
struct irblaster_raw_timings *timing;
|
||||
struct mutex encode_lock; /* use to function encode */
|
||||
u32 freq;
|
||||
u32 duty;
|
||||
};
|
||||
|
||||
/* irblaster encode APIs */
|
||||
int irblaster_raw_handler_register(struct irblaster_raw_handler
|
||||
*ir_raw_handler);
|
||||
void irblaster_raw_handler_unregister(struct irblaster_raw_handler
|
||||
*ir_raw_handler);
|
||||
int irblaster_raw_gen(unsigned int *data,
|
||||
const struct irblaster_raw_timings *timings,
|
||||
u32 raw);
|
||||
|
||||
unsigned int protocol_store_select(const char *buf);
|
||||
unsigned int protocol_show_select(struct irblaster_chip *chip, char *buf);
|
||||
|
||||
#endif /* __LINUX_ENCODER_H */
|
||||
Reference in New Issue
Block a user