diff options
Diffstat (limited to 'drivers/media/rc/meson-ir.c')
| -rw-r--r-- | drivers/media/rc/meson-ir.c | 644 |
1 files changed, 644 insertions, 0 deletions
diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c new file mode 100644 index 000000000000..272ebb0d97c8 --- /dev/null +++ b/drivers/media/rc/meson-ir.c @@ -0,0 +1,644 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Amlogic Meson IR remote receiver + * + * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> +#include <linux/bitfield.h> +#include <linux/regmap.h> + +#include <media/rc-core.h> + +#define DRIVER_NAME "meson-ir" + +#define IR_DEC_LDR_ACTIVE 0x00 +#define IR_DEC_LDR_ACTIVE_MAX GENMASK(28, 16) +#define IR_DEC_LDR_ACTIVE_MIN GENMASK(12, 0) +#define IR_DEC_LDR_IDLE 0x04 +#define IR_DEC_LDR_IDLE_MAX GENMASK(28, 16) +#define IR_DEC_LDR_IDLE_MIN GENMASK(12, 0) +#define IR_DEC_LDR_REPEAT 0x08 +#define IR_DEC_LDR_REPEAT_MAX GENMASK(25, 16) +#define IR_DEC_LDR_REPEAT_MIN GENMASK(9, 0) +#define IR_DEC_BIT_0 0x0c +#define IR_DEC_BIT_0_MAX GENMASK(25, 16) +#define IR_DEC_BIT_0_MIN GENMASK(9, 0) +#define IR_DEC_REG0 0x10 +#define IR_DEC_REG0_FILTER GENMASK(30, 28) +#define IR_DEC_REG0_FRAME_TIME_MAX GENMASK(24, 12) +#define IR_DEC_REG0_BASE_TIME GENMASK(11, 0) +#define IR_DEC_FRAME 0x14 +#define IR_DEC_STATUS 0x18 +#define IR_DEC_STATUS_BIT_1_ENABLE BIT(30) +#define IR_DEC_STATUS_BIT_1_MAX GENMASK(29, 20) +#define IR_DEC_STATUS_BIT_1_MIN GENMASK(19, 10) +#define IR_DEC_STATUS_PULSE BIT(8) +#define IR_DEC_STATUS_BUSY BIT(7) +#define IR_DEC_STATUS_FRAME_STATUS GENMASK(3, 0) +#define IR_DEC_REG1 0x1c +#define IR_DEC_REG1_TIME_IV GENMASK(28, 16) +#define IR_DEC_REG1_FRAME_LEN GENMASK(13, 8) +#define IR_DEC_REG1_ENABLE BIT(15) +#define IR_DEC_REG1_HOLD_CODE BIT(6) +#define IR_DEC_REG1_IRQSEL GENMASK(3, 2) +#define IR_DEC_REG1_RESET BIT(0) +/* Meson 6b uses REG1 to configure IR mode */ +#define IR_DEC_REG1_MODE GENMASK(8, 7) + +/* The following registers are only available on Meson 8b and newer */ +#define IR_DEC_REG2 0x20 +#define IR_DEC_REG2_TICK_MODE BIT(15) +#define IR_DEC_REG2_REPEAT_COUNTER BIT(13) +#define IR_DEC_REG2_REPEAT_TIME BIT(12) +#define IR_DEC_REG2_COMPARE_FRAME BIT(11) +#define IR_DEC_REG2_BIT_ORDER BIT(8) +/* Meson 8b / GXBB use REG2 to configure IR mode */ +#define IR_DEC_REG2_MODE GENMASK(3, 0) +#define IR_DEC_DURATN2 0x24 +#define IR_DEC_DURATN2_MAX GENMASK(25, 16) +#define IR_DEC_DURATN2_MIN GENMASK(9, 0) +#define IR_DEC_DURATN3 0x28 +#define IR_DEC_DURATN3_MAX GENMASK(25, 16) +#define IR_DEC_DURATN3_MIN GENMASK(9, 0) +#define IR_DEC_FRAME1 0x2c + +#define FRAME_MSB_FIRST true +#define FRAME_LSB_FIRST false + +#define DEC_MODE_NEC 0x0 +#define DEC_MODE_RAW 0x2 +#define DEC_MODE_RC6 0x9 +#define DEC_MODE_XMP 0xE +#define DEC_MODE_UNKNOW 0xFF + +#define DEC_STATUS_VALID BIT(3) +#define DEC_STATUS_DATA_CODE_ERR BIT(2) +#define DEC_STATUS_CUSTOM_CODE_ERR BIT(1) +#define DEC_STATUS_REPEAT BIT(0) + +#define IRQSEL_DEC_MODE 0 +#define IRQSEL_RISE_FALL 1 +#define IRQSEL_FALL 2 +#define IRQSEL_RISE 3 + +#define MESON_RAW_TRATE 10 /* us */ +#define MESON_HW_TRATE 20 /* us */ + +/** + * struct meson_ir_protocol - describe IR Protocol parameter + * + * @hw_protocol: select IR Protocol from IR Controller + * @repeat_counter_enable: enable frame-to-frame time counter, it should work + * with @repeat_compare_enable to detect the repeat frame + * @repeat_check_enable: enable repeat time check for repeat detection + * @repeat_compare_enable: enable to compare frame for repeat frame detection. + * Some IR Protocol send the same data as repeat frame. + * In this case, it should work with + * @repeat_counter_enable to detect the repeat frame. + * @bit_order: bit order, LSB or MSB + * @bit1_match_enable: enable to check bit 1 + * @hold_code_enable: hold frame code in register IR_DEC_FRAME1, the new one + * frame code will not be store in IR_DEC_FRAME1. + * until IR_DEC_FRAME1 has been read + * @count_tick_mode: increasing time unit of frame-to-frame time counter. + * 0 = 100us, 1 = 10us + * @code_length: length (N-1) of data frame + * @frame_time_max: max time for whole frame. Unit: MESON_HW_TRATE + * @leader_active_max: max time for NEC/RC6 leader active part. Unit: MESON_HW_TRATE + * @leader_active_min: min time for NEC/RC6 leader active part. Unit: MESON_HW_TRATE + * @leader_idle_max: max time for NEC/RC6 leader idle part. Unit: MESON_HW_TRATE + * @leader_idle_min: min time for NEC/RC6 leader idle part. Unit: MESON_HW_TRATE + * @repeat_leader_max: max time for NEC repeat leader idle part. Unit: MESON_HW_TRATE + * @repeat_leader_min: min time for NEC repeat leader idle part. Unit: MESON_HW_TRATE + * @bit0_max: max time for NEC Logic '0', half of RC6 trailer bit, XMP Logic '00' + * @bit0_min: min time for NEC Logic '0', half of RC6 trailer bit, XMP Logic '00' + * @bit1_max: max time for NEC Logic '1', whole of RC6 trailer bit, XMP Logic '01' + * @bit1_min: min time for NEC Logic '1', whole of RC6 trailer bit, XMP Logic '01' + * @duration2_max: max time for half of RC6 normal bit, XMP Logic '10' + * @duration2_min: min time for half of RC6 normal bit, XMP Logic '10' + * @duration3_max: max time for whole of RC6 normal bit, XMP Logic '11' + * @duration3_min: min time for whole of RC6 normal bit, XMP Logic '11' + */ + +struct meson_ir_protocol { + u8 hw_protocol; + bool repeat_counter_enable; + bool repeat_check_enable; + bool repeat_compare_enable; + bool bit_order; + bool bit1_match_enable; + bool hold_code_enable; + bool count_tick_mode; + u8 code_length; + u16 frame_time_max; + u16 leader_active_max; + u16 leader_active_min; + u16 leader_idle_max; + u16 leader_idle_min; + u16 repeat_leader_max; + u16 repeat_leader_min; + u16 bit0_max; + u16 bit0_min; + u16 bit1_max; + u16 bit1_min; + u16 duration2_max; + u16 duration2_min; + u16 duration3_max; + u16 duration3_min; +}; + +struct meson_ir_param { + bool support_hw_decoder; + unsigned int max_register; +}; + +struct meson_ir { + const struct meson_ir_param *param; + struct regmap *reg; + struct rc_dev *rc; + spinlock_t lock; +}; + +static struct regmap_config meson_ir_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static const struct meson_ir_protocol protocol_timings[] = { + /* protocol, repeat counter, repeat check, repeat compare, order */ + {DEC_MODE_NEC, false, false, false, FRAME_LSB_FIRST, + /* bit 1 match, hold code, count tick, len, frame time */ + true, false, false, 32, 4000, + /* leader active max/min, leader idle max/min, repeat leader max/min */ + 500, 400, 300, 200, 150, 80, + /* bit0 max/min, bit1 max/min, duration2 max/min, duration3 max/min */ + 72, 40, 134, 90, 0, 0, 0, 0} +}; + +static void meson_ir_nec_handler(struct meson_ir *ir) +{ + u32 code = 0; + u32 status = 0; + enum rc_proto proto; + + regmap_read(ir->reg, IR_DEC_STATUS, &status); + + if (status & DEC_STATUS_REPEAT) { + rc_repeat(ir->rc); + } else { + regmap_read(ir->reg, IR_DEC_FRAME, &code); + + code = ir_nec_bytes_to_scancode(code, code >> 8, + code >> 16, code >> 24, &proto); + rc_keydown(ir->rc, proto, code, 0); + } +} + +static void meson_ir_hw_handler(struct meson_ir *ir) +{ + if (ir->rc->enabled_protocols & RC_PROTO_BIT_NEC) + meson_ir_nec_handler(ir); +} + +static irqreturn_t meson_ir_irq(int irqno, void *dev_id) +{ + struct meson_ir *ir = dev_id; + u32 duration, status; + struct ir_raw_event rawir = {}; + + spin_lock(&ir->lock); + + regmap_read(ir->reg, IR_DEC_STATUS, &status); + + if (ir->rc->driver_type == RC_DRIVER_IR_RAW) { + rawir.pulse = !!(status & IR_DEC_STATUS_PULSE); + + regmap_read(ir->reg, IR_DEC_REG1, &duration); + duration = FIELD_GET(IR_DEC_REG1_TIME_IV, duration); + rawir.duration = duration * MESON_RAW_TRATE; + + ir_raw_event_store_with_timeout(ir->rc, &rawir); + } else if (ir->rc->driver_type == RC_DRIVER_SCANCODE) { + if (status & DEC_STATUS_VALID) + meson_ir_hw_handler(ir); + } + + spin_unlock(&ir->lock); + + return IRQ_HANDLED; +} + +static int meson_ir_hw_decoder_init(struct rc_dev *dev, u64 *rc_type) +{ + u8 protocol; + u32 regval; + int i; + unsigned long flags; + const struct meson_ir_protocol *timings; + struct meson_ir *ir = dev->priv; + + if (*rc_type & RC_PROTO_BIT_NEC) + protocol = DEC_MODE_NEC; + else + return 0; + + for (i = 0; i < ARRAY_SIZE(protocol_timings); i++) + if (protocol_timings[i].hw_protocol == protocol) + break; + + if (i == ARRAY_SIZE(protocol_timings)) { + dev_err(&dev->dev, "hw protocol isn't supported: %d\n", + protocol); + return -EINVAL; + } + timings = &protocol_timings[i]; + + spin_lock_irqsave(&ir->lock, flags); + + /* Clear controller status */ + regmap_read(ir->reg, IR_DEC_STATUS, ®val); + regmap_read(ir->reg, IR_DEC_FRAME, ®val); + + /* Reset ir decoder and disable decoder */ + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_ENABLE, 0); + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, + IR_DEC_REG1_RESET); + + /* Base time resolution, (19+1)*1us=20us */ + regval = FIELD_PREP(IR_DEC_REG0_BASE_TIME, MESON_HW_TRATE - 1); + regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_BASE_TIME, regval); + + /* Monitor timing for input filter */ + regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_FILTER, + FIELD_PREP(IR_DEC_REG0_FILTER, 7)); + + /* HW protocol */ + regval = FIELD_PREP(IR_DEC_REG2_MODE, timings->hw_protocol); + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_MODE, regval); + + /* Hold frame data until register was read */ + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_HOLD_CODE, + timings->hold_code_enable ? + IR_DEC_REG1_HOLD_CODE : 0); + + /* Bit order */ + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_BIT_ORDER, + timings->bit_order ? IR_DEC_REG2_BIT_ORDER : 0); + + /* Select tick mode */ + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_TICK_MODE, + timings->count_tick_mode ? + IR_DEC_REG2_TICK_MODE : 0); + + /* + * Some protocols transmit the same data frame as repeat frame + * when the key is pressing. In this case, it could be detected as + * repeat frame if the repeat checker was enabled. + */ + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_REPEAT_COUNTER, + timings->repeat_counter_enable ? + IR_DEC_REG2_REPEAT_COUNTER : 0); + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_REPEAT_TIME, + timings->repeat_check_enable ? + IR_DEC_REG2_REPEAT_TIME : 0); + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_COMPARE_FRAME, + timings->repeat_compare_enable ? + IR_DEC_REG2_COMPARE_FRAME : 0); + + /* + * FRAME_TIME_MAX should be larger than the time between + * data frame and repeat frame + */ + regval = FIELD_PREP(IR_DEC_REG0_FRAME_TIME_MAX, + timings->frame_time_max); + regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_FRAME_TIME_MAX, + regval); + + /* Length(N-1) of data frame */ + regval = FIELD_PREP(IR_DEC_REG1_FRAME_LEN, timings->code_length - 1); + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_FRAME_LEN, regval); + + /* Time for leader active part */ + regval = FIELD_PREP(IR_DEC_LDR_ACTIVE_MAX, + timings->leader_active_max) | + FIELD_PREP(IR_DEC_LDR_ACTIVE_MIN, + timings->leader_active_min); + regmap_update_bits(ir->reg, IR_DEC_LDR_ACTIVE, IR_DEC_LDR_ACTIVE_MAX | + IR_DEC_LDR_ACTIVE_MIN, regval); + + /* Time for leader idle part */ + regval = FIELD_PREP(IR_DEC_LDR_IDLE_MAX, timings->leader_idle_max) | + FIELD_PREP(IR_DEC_LDR_IDLE_MIN, timings->leader_idle_min); + regmap_update_bits(ir->reg, IR_DEC_LDR_IDLE, + IR_DEC_LDR_IDLE_MAX | IR_DEC_LDR_IDLE_MIN, regval); + + /* Time for repeat leader idle part */ + regval = FIELD_PREP(IR_DEC_LDR_REPEAT_MAX, timings->repeat_leader_max) | + FIELD_PREP(IR_DEC_LDR_REPEAT_MIN, timings->repeat_leader_min); + regmap_update_bits(ir->reg, IR_DEC_LDR_REPEAT, IR_DEC_LDR_REPEAT_MAX | + IR_DEC_LDR_REPEAT_MIN, regval); + + /* + * NEC: Time for logic '0' + * RC6: Time for half of trailer bit + */ + regval = FIELD_PREP(IR_DEC_BIT_0_MAX, timings->bit0_max) | + FIELD_PREP(IR_DEC_BIT_0_MIN, timings->bit0_min); + regmap_update_bits(ir->reg, IR_DEC_BIT_0, + IR_DEC_BIT_0_MAX | IR_DEC_BIT_0_MIN, regval); + + /* + * NEC: Time for logic '1' + * RC6: Time for whole of trailer bit + */ + regval = FIELD_PREP(IR_DEC_STATUS_BIT_1_MAX, timings->bit1_max) | + FIELD_PREP(IR_DEC_STATUS_BIT_1_MIN, timings->bit1_min); + regmap_update_bits(ir->reg, IR_DEC_STATUS, IR_DEC_STATUS_BIT_1_MAX | + IR_DEC_STATUS_BIT_1_MIN, regval); + + /* Enable to match logic '1' */ + regmap_update_bits(ir->reg, IR_DEC_STATUS, IR_DEC_STATUS_BIT_1_ENABLE, + timings->bit1_match_enable ? + IR_DEC_STATUS_BIT_1_ENABLE : 0); + + /* + * NEC: Unused + * RC6: Time for halt of logic 0/1 + */ + regval = FIELD_PREP(IR_DEC_DURATN2_MAX, timings->duration2_max) | + FIELD_PREP(IR_DEC_DURATN2_MIN, timings->duration2_min); + regmap_update_bits(ir->reg, IR_DEC_DURATN2, + IR_DEC_DURATN2_MAX | IR_DEC_DURATN2_MIN, regval); + + /* + * NEC: Unused + * RC6: Time for whole logic 0/1 + */ + regval = FIELD_PREP(IR_DEC_DURATN3_MAX, timings->duration3_max) | + FIELD_PREP(IR_DEC_DURATN3_MIN, timings->duration3_min); + regmap_update_bits(ir->reg, IR_DEC_DURATN3, + IR_DEC_DURATN3_MAX | IR_DEC_DURATN3_MIN, regval); + + /* Reset ir decoder and enable decode */ + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, + IR_DEC_REG1_RESET); + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, 0); + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_ENABLE, + IR_DEC_REG1_ENABLE); + + spin_unlock_irqrestore(&ir->lock, flags); + + dev_info(&dev->dev, "hw decoder init, protocol: %d\n", protocol); + + return 0; +} + +static void meson_ir_sw_decoder_init(struct rc_dev *dev) +{ + unsigned long flags; + struct meson_ir *ir = dev->priv; + + spin_lock_irqsave(&ir->lock, flags); + + /* Reset the decoder */ + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, + IR_DEC_REG1_RESET); + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_RESET, 0); + + /* Set general operation mode (= raw/software decoding) */ + if (of_device_is_compatible(dev->dev.of_node, "amlogic,meson6-ir")) + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_MODE, + FIELD_PREP(IR_DEC_REG1_MODE, + DEC_MODE_RAW)); + else + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_MODE, + FIELD_PREP(IR_DEC_REG2_MODE, + DEC_MODE_RAW)); + + /* Set rate */ + regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_BASE_TIME, + FIELD_PREP(IR_DEC_REG0_BASE_TIME, + MESON_RAW_TRATE - 1)); + /* IRQ on rising and falling edges */ + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_IRQSEL, + FIELD_PREP(IR_DEC_REG1_IRQSEL, IRQSEL_RISE_FALL)); + /* Enable the decoder */ + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_ENABLE, + IR_DEC_REG1_ENABLE); + + spin_unlock_irqrestore(&ir->lock, flags); + + dev_info(&dev->dev, "sw decoder init\n"); +} + +static int meson_ir_probe(struct platform_device *pdev) +{ + const struct meson_ir_param *match_data; + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + void __iomem *res_start; + const char *map_name; + struct meson_ir *ir; + int irq, ret; + + ir = devm_kzalloc(dev, sizeof(struct meson_ir), GFP_KERNEL); + if (!ir) + return -ENOMEM; + + match_data = of_device_get_match_data(dev); + if (!match_data) + return dev_err_probe(dev, -ENODEV, "failed to get match data\n"); + + ir->param = match_data; + + res_start = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(res_start)) + return PTR_ERR(res_start); + + meson_ir_regmap_config.max_register = ir->param->max_register; + ir->reg = devm_regmap_init_mmio(&pdev->dev, res_start, + &meson_ir_regmap_config); + if (IS_ERR(ir->reg)) + return PTR_ERR(ir->reg); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + if (ir->param->support_hw_decoder) + ir->rc = devm_rc_allocate_device(&pdev->dev, + RC_DRIVER_SCANCODE); + else + ir->rc = devm_rc_allocate_device(&pdev->dev, RC_DRIVER_IR_RAW); + + if (!ir->rc) { + dev_err(dev, "failed to allocate rc device\n"); + return -ENOMEM; + } + + if (ir->rc->driver_type == RC_DRIVER_IR_RAW) { + ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; + ir->rc->rx_resolution = MESON_RAW_TRATE; + ir->rc->min_timeout = 1; + ir->rc->timeout = IR_DEFAULT_TIMEOUT; + ir->rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT; + } else if (ir->rc->driver_type == RC_DRIVER_SCANCODE) { + ir->rc->allowed_protocols = RC_PROTO_BIT_NEC; + ir->rc->change_protocol = meson_ir_hw_decoder_init; + } + + ir->rc->priv = ir; + ir->rc->device_name = DRIVER_NAME; + ir->rc->input_phys = DRIVER_NAME "/input0"; + ir->rc->input_id.bustype = BUS_HOST; + map_name = of_get_property(node, "linux,rc-map-name", NULL); + ir->rc->map_name = map_name ? map_name : RC_MAP_EMPTY; + ir->rc->driver_name = DRIVER_NAME; + + spin_lock_init(&ir->lock); + platform_set_drvdata(pdev, ir); + + ret = devm_rc_register_device(dev, ir->rc); + if (ret) { + dev_err(dev, "failed to register rc device\n"); + return ret; + } + + if (ir->rc->driver_type == RC_DRIVER_IR_RAW) + meson_ir_sw_decoder_init(ir->rc); + + ret = devm_request_irq(dev, irq, meson_ir_irq, 0, "meson_ir", ir); + if (ret) { + dev_err(dev, "failed to request irq\n"); + return ret; + } + + dev_info(dev, "receiver initialized\n"); + + return 0; +} + +static void meson_ir_remove(struct platform_device *pdev) +{ + struct meson_ir *ir = platform_get_drvdata(pdev); + unsigned long flags; + + /* Disable the decoder */ + spin_lock_irqsave(&ir->lock, flags); + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_ENABLE, 0); + spin_unlock_irqrestore(&ir->lock, flags); +} + +static void meson_ir_shutdown(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct meson_ir *ir = platform_get_drvdata(pdev); + unsigned long flags; + + spin_lock_irqsave(&ir->lock, flags); + + /* + * Set operation mode to NEC/hardware decoding to give + * bootloader a chance to power the system back on + */ + if (of_device_is_compatible(node, "amlogic,meson6-ir")) + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_MODE, + FIELD_PREP(IR_DEC_REG1_MODE, DEC_MODE_NEC)); + else + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_MODE, + FIELD_PREP(IR_DEC_REG2_MODE, DEC_MODE_NEC)); + + /* Set rate to default value */ + regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_BASE_TIME, + FIELD_PREP(IR_DEC_REG0_BASE_TIME, + MESON_HW_TRATE - 1)); + + spin_unlock_irqrestore(&ir->lock, flags); +} + +static __maybe_unused int meson_ir_resume(struct device *dev) +{ + struct meson_ir *ir = dev_get_drvdata(dev); + + if (ir->param->support_hw_decoder) + meson_ir_hw_decoder_init(ir->rc, &ir->rc->enabled_protocols); + else + meson_ir_sw_decoder_init(ir->rc); + + return 0; +} + +static __maybe_unused int meson_ir_suspend(struct device *dev) +{ + struct meson_ir *ir = dev_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&ir->lock, flags); + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_ENABLE, 0); + spin_unlock_irqrestore(&ir->lock, flags); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(meson_ir_pm_ops, meson_ir_suspend, meson_ir_resume); + +static const struct meson_ir_param meson6_ir_param = { + .support_hw_decoder = false, + .max_register = IR_DEC_REG1, +}; + +static const struct meson_ir_param meson8b_ir_param = { + .support_hw_decoder = false, + .max_register = IR_DEC_REG2, +}; + +static const struct meson_ir_param meson_s4_ir_param = { + .support_hw_decoder = true, + .max_register = IR_DEC_FRAME1, +}; + +static const struct of_device_id meson_ir_match[] = { + { + .compatible = "amlogic,meson6-ir", + .data = &meson6_ir_param, + }, { + .compatible = "amlogic,meson8b-ir", + .data = &meson8b_ir_param, + }, { + .compatible = "amlogic,meson-gxbb-ir", + .data = &meson8b_ir_param, + }, { + .compatible = "amlogic,meson-s4-ir", + .data = &meson_s4_ir_param, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, meson_ir_match); + +static struct platform_driver meson_ir_driver = { + .probe = meson_ir_probe, + .remove = meson_ir_remove, + .shutdown = meson_ir_shutdown, + .driver = { + .name = DRIVER_NAME, + .of_match_table = meson_ir_match, + .pm = pm_ptr(&meson_ir_pm_ops), + }, +}; + +module_platform_driver(meson_ir_driver); + +MODULE_DESCRIPTION("Amlogic Meson IR remote receiver driver"); +MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>"); +MODULE_LICENSE("GPL v2"); |
