Message ID | 20230302063402.42708-2-zelong.dong@amlogic.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | media: rc: meson-s4: support RC_DRIVER_SCANCODE driver | expand |
Hi, On 02/03/2023 07:34, zelong dong wrote: > From: Zelong Dong <zelong.dong@amlogic.com> > > Meson IR Controller supports hardware decoder in Meson-8B and later > SoC. So far, protocol NEC/RC-6/XMP could be decoded in hardware. > DTS property 'amlogic,ir-support-hw-decode' can enable this feature. Thamks for your submittion, it's appeciated ! But, The change is too hard to review since you migrate to regmap at the same time, please separate the migration to regmap first, then add HW decoding in a separate change. Same for suspend/resume addition and any other hw-decoding unrelated changes. Neil > > Signed-off-by: Zelong Dong <zelong.dong@amlogic.com> > --- > drivers/media/rc/meson-ir.c | 713 ++++++++++++++++++++++++++++++++---- > 1 file changed, 632 insertions(+), 81 deletions(-) > > diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c > index 4b769111f78e..1bfdce1c1864 100644 > --- a/drivers/media/rc/meson-ir.c > +++ b/drivers/media/rc/meson-ir.c > @@ -14,6 +14,7 @@ > #include <linux/platform_device.h> > #include <linux/spinlock.h> > #include <linux/bitfield.h> > +#include <linux/regmap.h> > > #include <media/rc-core.h> > > @@ -21,87 +22,598 @@ > > /* valid on all Meson platforms */ > #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 > -/* only available on Meson 8b and newer */ > + #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 the 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 the 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 DECODE_MODE_NEC 0x0 > +#define DECODE_MODE_RAW 0x2 > +#define DECODE_MODE_RC6 0x9 > +#define DECODE_MODE_XMP 0xE > + > +#define DECODER_STATUS_VALID BIT(3) > +#define DECODER_STATUS_DATA_CODE_ERR BIT(2) > +#define DECODER_STATUS_CUSTOM_CODE_ERR BIT(1) > +#define DECODER_STATUS_REPEAT BIT(0) > + > +#define IRQSEL_NEC_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 */ > + > +#define MESON_IR_TIMINGS(proto, r_cnt, r_chk, r_comp, b1_e, hc, cnt_tick, ori, \ > + flt, len, f_max, la_max, la_min, li_max, li_min, \ > + rl_max, rl_min, b0_max, b0_min, b1_max, b1_min, \ > + d2_max, d2_min, d3_max, d3_min) \ > + { \ > + .hw_protocol = proto, \ > + .repeat_counter_enable = r_cnt, \ > + .repeat_check_enable = r_chk, \ > + .repeat_compare_enable = r_comp, \ > + .bit1_match_enable = b1_e, \ > + .hold_code_enable = hc, \ > + .count_tick_mode = cnt_tick, \ > + .bit_order = ori, \ > + .filter_cnt = flt, \ > + .code_length = len, \ > + .frame_time_max = f_max, \ > + .leader_active_max = la_max, \ > + .leader_active_min = la_min, \ > + .leader_idle_max = li_max, \ > + .leader_idle_min = li_min, \ > + .repeat_leader_max = rl_max, \ > + .repeat_leader_min = rl_min, \ > + .bit0_max = b0_max, \ > + .bit0_min = b0_min, \ > + .bit1_max = b1_max, \ > + .bit1_min = b1_min, \ > + .duration2_max = d2_max, \ > + .duration2_min = d2_min, \ > + .duration3_max = d3_max, \ > + .duration3_min = d3_min, \ > + } \ > + > +/** > + * struct meson_ir_param - 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. > + * @filter_cnt: input filter, to filter burr > + * @code_length: length (N-1) of frame's data part. > + * @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'. > + */ > > -#define REG0_RATE_MASK GENMASK(11, 0) > +struct meson_ir_param { > + 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 filter_cnt; > + 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; > +}; > > -#define DECODE_MODE_NEC 0x0 > -#define DECODE_MODE_RAW 0x2 > +struct meson_ir { > + struct regmap *reg; > + struct rc_dev *rc; > + spinlock_t lock; > + bool support_hw_dec; > +}; > > -/* Meson 6b uses REG1 to configure the mode */ > -#define REG1_MODE_MASK GENMASK(8, 7) > -#define REG1_MODE_SHIFT 7 > +static struct regmap_config meson_ir_regmap_config = { > + .reg_bits = 32, > + .val_bits = 32, > + .reg_stride = 4, > +}; > > -/* Meson 8b / GXBB use REG2 to configure the mode */ > -#define REG2_MODE_MASK GENMASK(3, 0) > -#define REG2_MODE_SHIFT 0 > +static const struct meson_ir_param protocol_timings[] = { > + /* protocol, repeat counter, repeat check, repeat compare, bit 1 match */ > + MESON_IR_TIMINGS(DECODE_MODE_NEC, false, false, false, true, > + /* hold code, count tick, order, filter cnt, len, frame time */ > + false, false, FRAME_LSB_FIRST, 7, 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), > + MESON_IR_TIMINGS(DECODE_MODE_XMP, true, false, true, false, > + false, true, FRAME_MSB_FIRST, 7, 32, 1500, > + 0, 0, 0, 0, 0, 0, > + 52, 45, 86, 80, 121, 114, 7, 7), > + MESON_IR_TIMINGS(DECODE_MODE_RC6, true, false, true, false, > + true, false, FRAME_MSB_FIRST, 7, 37, 4000, > + 210, 125, 50, 38, 145, 125, > + 51, 38, 94, 82, 28, 16, 51, 38) > +}; > > -#define REG1_TIME_IV_MASK GENMASK(28, 16) > +static void meson_ir_rc6_handler(struct meson_ir *ir) > +{ > + u32 code0, code1; > > -#define REG1_IRQSEL_MASK GENMASK(3, 2) > -#define REG1_IRQSEL_NEC_MODE 0 > -#define REG1_IRQSEL_RISE_FALL 1 > -#define REG1_IRQSEL_FALL 2 > -#define REG1_IRQSEL_RISE 3 > + regmap_read(ir->reg, IR_DEC_FRAME, &code0); > + regmap_read(ir->reg, IR_DEC_FRAME1, &code1); > > -#define REG1_RESET BIT(0) > -#define REG1_ENABLE BIT(15) > + rc_keydown(ir->rc, RC_PROTO_RC6_6A_32, code0, code1 & 0x1); > +} > > -#define STATUS_IR_DEC_IN BIT(8) > +static void meson_ir_xmp_handler(struct meson_ir *ir) > +{ > + static u32 last_xmp_code; > + int i; > + u32 code = 0; > + u32 scancode, checksum = 0; > + u8 addr, subaddr, subaddr2, toggle, oem, obc1, obc2; > + > + regmap_read(ir->reg, IR_DEC_FRAME, &code); > + > + for (i = 0; i < 32; i += 4) > + checksum += ((code >> i) & 0xf); > + checksum = ~(checksum + 0xf - ((code >> 24) & 0xf)) & 0xf; > + > + if (checksum != ((code >> 24) & 0xf)) { > + last_xmp_code = 0; > + dev_err(&ir->rc->dev, "xmp checksum error, framecode= 0x%x\n", > + code); > + return; > + } > > -#define MESON_TRATE 10 /* us */ > + subaddr = (last_xmp_code >> 24 & 0xf0) | (last_xmp_code >> 20 & 0x0f); > + subaddr2 = (code >> 24 & 0xf0) | (code >> 16 & 0x0f); > + oem = last_xmp_code >> 8; > + addr = last_xmp_code; > + toggle = code >> 20 & 0xf; > + obc1 = code >> 8; > + obc2 = code; > + > + if (subaddr != subaddr2) { > + last_xmp_code = code; > + dev_dbg(&ir->rc->dev, "subaddress nibbles mismatch 0x%02X != 0x%02X\n", > + subaddr, subaddr2); > + return; > + } > + if (oem != 0x44) > + dev_dbg(&ir->rc->dev, "Warning: OEM nibbles 0x%02X. Expected 0x44\n", > + oem); > > -struct meson_ir { > - void __iomem *reg; > - struct rc_dev *rc; > - spinlock_t lock; > -}; > + scancode = addr << 24 | subaddr << 16 | obc1 << 8 | obc2; > + dev_dbg(&ir->rc->dev, "XMP scancode 0x%06x\n", scancode); > + > + if (toggle == 0) > + rc_keydown(ir->rc, RC_PROTO_XMP, scancode, 0); > + else > + rc_repeat(ir->rc); > + > + last_xmp_code = code; > +} > > -static void meson_ir_set_mask(struct meson_ir *ir, unsigned int reg, > - u32 mask, u32 value) > +static void meson_ir_nec_handler(struct meson_ir *ir) > { > - u32 data; > + u32 code = 0; > + u32 status = 0; > + enum rc_proto proto; > + > + regmap_read(ir->reg, IR_DEC_STATUS, &status); > + > + if (status & DECODER_STATUS_REPEAT) { > + rc_repeat(ir->rc); > + } else { > + regmap_read(ir->reg, IR_DEC_FRAME, &code); > > - data = readl(ir->reg + reg); > - data &= ~mask; > - data |= (value & mask); > - writel(data, ir->reg + reg); > + code = ir_nec_bytes_to_scancode(code, code >> 8, > + code >> 16, code >> 24, &proto); > + rc_keydown(ir->rc, proto, code, 0); > + } > } > > static irqreturn_t meson_ir_irq(int irqno, void *dev_id) > +{ > + struct meson_ir *ir = dev_id; > + u32 status = 0; > + > + if (ir->support_hw_dec) { > + regmap_read(ir->reg, IR_DEC_STATUS, &status); > + > + if (!(status & DECODER_STATUS_VALID)) > + return IRQ_NONE; > + } > + > + return IRQ_WAKE_THREAD; > +} > + > +static irqreturn_t meson_ir_irq_thread(int irq, void *dev_id) > { > struct meson_ir *ir = dev_id; > u32 duration, status; > struct ir_raw_event rawir = {}; > > - spin_lock(&ir->lock); > + if (ir->support_hw_dec) { > + if (ir->rc->enabled_protocols & RC_PROTO_BIT_NEC) > + meson_ir_nec_handler(ir); > + else if (ir->rc->enabled_protocols & RC_PROTO_BIT_XMP) > + meson_ir_xmp_handler(ir); > + else if (ir->rc->enabled_protocols & RC_PROTO_BIT_RC6_6A_32) > + meson_ir_rc6_handler(ir); > + } else { > + spin_lock(&ir->lock); > > - duration = readl_relaxed(ir->reg + IR_DEC_REG1); > - duration = FIELD_GET(REG1_TIME_IV_MASK, duration); > - rawir.duration = duration * MESON_TRATE; > + regmap_read(ir->reg, IR_DEC_REG1, &duration); > + duration = FIELD_GET(IR_DEC_REG1_TIME_IV, duration); > + rawir.duration = duration * MESON_RAW_TRATE; > > - status = readl_relaxed(ir->reg + IR_DEC_STATUS); > - rawir.pulse = !!(status & STATUS_IR_DEC_IN); > + regmap_read(ir->reg, IR_DEC_STATUS, &status); > + rawir.pulse = !!(status & IR_DEC_STATUS_PULSE); > > - ir_raw_event_store_with_timeout(ir->rc, &rawir); > + ir_raw_event_store_with_timeout(ir->rc, &rawir); > > - spin_unlock(&ir->lock); > + spin_unlock(&ir->lock); > + } > > return IRQ_HANDLED; > } > > +static int meson_ir_change_hw_protocol(struct rc_dev *dev, u8 protocol) > +{ > + struct meson_ir *ir = dev->priv; > + int i; > + unsigned long flags; > + u32 regval; > + const struct meson_ir_param *timings; > + > + 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); > + > + /* 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); > + > + /* Monitor timing for input filter */ > + regval = FIELD_PREP(IR_DEC_REG0_FILTER, timings->filter_cnt); > + regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_FILTER, 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 IR formats transer 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 check 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 large than the time between > + * data frame and repeat code > + */ > + 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 frame data */ > + 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 > + * RC5/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 > + * RC5/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); > + > + spin_unlock_irqrestore(&ir->lock, flags); > + > + return 0; > +} > + > +static void meson_ir_hw_decoder_init(struct rc_dev *dev) > +{ > + u32 regval; > + unsigned long flags; > + struct meson_ir *ir = dev->priv; > + > + 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); > + > + spin_unlock_irqrestore(&ir->lock, flags); > +} > + > +static int meson_ir_change_protocol(struct rc_dev *dev, u64 *rc_type) > +{ > + unsigned long flags; > + struct meson_ir *ir = dev->priv; > + > + meson_ir_hw_decoder_init(dev); > + > + if (*rc_type & RC_PROTO_BIT_NEC) > + meson_ir_change_hw_protocol(dev, DECODE_MODE_NEC); > + else if (*rc_type & RC_PROTO_BIT_XMP) > + meson_ir_change_hw_protocol(dev, DECODE_MODE_XMP); > + else if (*rc_type & RC_PROTO_BIT_RC6_6A_32) > + meson_ir_change_hw_protocol(dev, DECODE_MODE_RC6); > + > + spin_lock_irqsave(&ir->lock, flags); > + > + /* 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); > + > + 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, > + DECODE_MODE_RAW)); > + else > + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_MODE, > + FIELD_PREP(IR_DEC_REG2_MODE, > + DECODE_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); > +} > + > +static int meson_ir_rc_allocate_device(struct platform_device *pdev) > +{ > + struct meson_ir *ir = platform_get_drvdata(pdev); > + > + if (ir->support_hw_dec) { > + ir->rc = devm_rc_allocate_device(&pdev->dev, > + RC_DRIVER_SCANCODE); > + if (!ir->rc) { > + dev_err(&pdev->dev, "failed to allocate rc device\n"); > + return -ENOMEM; > + } > + > + ir->rc->allowed_protocols = RC_PROTO_BIT_NEC | > + RC_PROTO_BIT_RC6_6A_32 | > + RC_PROTO_BIT_XMP; > + ir->rc->change_protocol = meson_ir_change_protocol; > + } else { > + ir->rc = devm_rc_allocate_device(&pdev->dev, RC_DRIVER_IR_RAW); > + if (!ir->rc) { > + dev_err(&pdev->dev, "failed to allocate rc device\n"); > + return -ENOMEM; > + } > + > + 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; > + } > + > + return 0; > +} > + > static int meson_ir_probe(struct platform_device *pdev) > { > struct device *dev = &pdev->dev; > struct device_node *node = dev->of_node; > + struct resource *res; > + void __iomem *res_start; > const char *map_name; > struct meson_ir *ir; > int irq, ret; > @@ -110,7 +622,19 @@ static int meson_ir_probe(struct platform_device *pdev) > if (!ir) > return -ENOMEM; > > - ir->reg = devm_platform_ioremap_resource(pdev, 0); > + platform_set_drvdata(pdev, ir); > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (IS_ERR_OR_NULL(res)) { > + dev_err(&pdev->dev, "get mem resource error, %ld\n", > + PTR_ERR(res)); > + return PTR_ERR(res); > + } > + > + res_start = devm_ioremap_resource(&pdev->dev, res); > + meson_ir_regmap_config.max_register = resource_size(res) - 4; > + ir->reg = devm_regmap_init_mmio(&pdev->dev, res_start, > + &meson_ir_regmap_config); > if (IS_ERR(ir->reg)) > return PTR_ERR(ir->reg); > > @@ -118,27 +642,28 @@ static int meson_ir_probe(struct platform_device *pdev) > if (irq < 0) > return irq; > > - ir->rc = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW); > - if (!ir->rc) { > - dev_err(dev, "failed to allocate rc device\n"); > - return -ENOMEM; > + if (of_device_is_compatible(node, "amlogic,meson6-ir")) { > + ir->support_hw_dec = false; > + } else { > + if (of_property_read_bool(node, > + "amlogic,ir-support-hw-decode")) > + ir->support_hw_dec = true; > + else > + ir->support_hw_dec = false; > } > > + if (meson_ir_rc_allocate_device(pdev)) > + return -ENOMEM; > + > 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->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; > - ir->rc->rx_resolution = MESON_TRATE; > - ir->rc->min_timeout = 1; > - ir->rc->timeout = IR_DEFAULT_TIMEOUT; > - ir->rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT; > 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) { > @@ -146,33 +671,20 @@ static int meson_ir_probe(struct platform_device *pdev) > return ret; > } > > - ret = devm_request_irq(dev, irq, meson_ir_irq, 0, NULL, ir); > + if (!ir->support_hw_dec) > + meson_ir_sw_decoder_init(ir->rc); > + > + ret = devm_request_threaded_irq(dev, irq, meson_ir_irq, > + meson_ir_irq_thread, > + IRQF_SHARED | IRQF_NO_SUSPEND, > + "meson_ir", ir); > if (ret) { > dev_err(dev, "failed to request irq\n"); > return ret; > } > > - /* Reset the decoder */ > - meson_ir_set_mask(ir, IR_DEC_REG1, REG1_RESET, REG1_RESET); > - meson_ir_set_mask(ir, IR_DEC_REG1, REG1_RESET, 0); > - > - /* Set general operation mode (= raw/software decoding) */ > - if (of_device_is_compatible(node, "amlogic,meson6-ir")) > - meson_ir_set_mask(ir, IR_DEC_REG1, REG1_MODE_MASK, > - FIELD_PREP(REG1_MODE_MASK, DECODE_MODE_RAW)); > - else > - meson_ir_set_mask(ir, IR_DEC_REG2, REG2_MODE_MASK, > - FIELD_PREP(REG2_MODE_MASK, DECODE_MODE_RAW)); > - > - /* Set rate */ > - meson_ir_set_mask(ir, IR_DEC_REG0, REG0_RATE_MASK, MESON_TRATE - 1); > - /* IRQ on rising and falling edges */ > - meson_ir_set_mask(ir, IR_DEC_REG1, REG1_IRQSEL_MASK, > - FIELD_PREP(REG1_IRQSEL_MASK, REG1_IRQSEL_RISE_FALL)); > - /* Enable the decoder */ > - meson_ir_set_mask(ir, IR_DEC_REG1, REG1_ENABLE, REG1_ENABLE); > - > - dev_info(dev, "receiver initialized\n"); > + dev_info(dev, "meson ir %s decoder was initialized\n", > + ir->support_hw_dec ? "hw" : "sw"); > > return 0; > } > @@ -184,7 +696,7 @@ static int meson_ir_remove(struct platform_device *pdev) > > /* Disable the decoder */ > spin_lock_irqsave(&ir->lock, flags); > - meson_ir_set_mask(ir, IR_DEC_REG1, REG1_ENABLE, 0); > + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_ENABLE, 0); > spin_unlock_irqrestore(&ir->lock, flags); > > return 0; > @@ -193,7 +705,6 @@ static int meson_ir_remove(struct platform_device *pdev) > 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; > > @@ -203,27 +714,64 @@ static void meson_ir_shutdown(struct platform_device *pdev) > * 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")) > - meson_ir_set_mask(ir, IR_DEC_REG1, REG1_MODE_MASK, > - DECODE_MODE_NEC << REG1_MODE_SHIFT); > + if (of_device_is_compatible(dev->of_node, "amlogic,meson6-ir")) > + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_MODE, > + FIELD_PREP(IR_DEC_REG1_MODE, > + DECODE_MODE_NEC)); > else > - meson_ir_set_mask(ir, IR_DEC_REG2, REG2_MODE_MASK, > - DECODE_MODE_NEC << REG2_MODE_SHIFT); > + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_MODE, > + FIELD_PREP(IR_DEC_REG2_MODE, > + DECODE_MODE_NEC)); > > /* Set rate to default value */ > - meson_ir_set_mask(ir, IR_DEC_REG0, REG0_RATE_MASK, 0x13); > + regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_BASE_TIME, > + FIELD_PREP(IR_DEC_REG0_BASE_TIME, MESON_HW_TRATE)); > > spin_unlock_irqrestore(&ir->lock, flags); > } > > +#ifdef CONFIG_PM > +static int meson_ir_resume(struct device *dev) > +{ > + struct meson_ir *ir = dev_get_drvdata(dev); > + > + if (ir->support_hw_dec) > + meson_ir_change_protocol(ir->rc, &ir->rc->enabled_protocols); > + else > + meson_ir_sw_decoder_init(ir->rc); > + > + return 0; > +} > + > +static 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; > +} > +#endif > + > static const struct of_device_id meson_ir_match[] = { > { .compatible = "amlogic,meson6-ir" }, > { .compatible = "amlogic,meson8b-ir" }, > { .compatible = "amlogic,meson-gxbb-ir" }, > + { .compatible = "amlogic,meson-s4-ir" }, > { }, > }; > MODULE_DEVICE_TABLE(of, meson_ir_match); > > +#ifdef CONFIG_PM > +static const struct dev_pm_ops meson_ir_pm_ops = { > + .suspend_late = meson_ir_suspend, > + .resume_early = meson_ir_resume, > +}; > +#endif > + > static struct platform_driver meson_ir_driver = { > .probe = meson_ir_probe, > .remove = meson_ir_remove, > @@ -231,6 +779,9 @@ static struct platform_driver meson_ir_driver = { > .driver = { > .name = DRIVER_NAME, > .of_match_table = meson_ir_match, > +#ifdef CONFIG_PM > + .pm = &meson_ir_pm_ops, > +#endif > }, > }; >
Hello Zelong, On Thu, Mar 02, 2023 at 02:34:00PM +0800, zelong dong wrote: > From: Zelong Dong <zelong.dong@amlogic.com> > > Meson IR Controller supports hardware decoder in Meson-8B and later > SoC. So far, protocol NEC/RC-6/XMP could be decoded in hardware. > DTS property 'amlogic,ir-support-hw-decode' can enable this feature. > > Signed-off-by: Zelong Dong <zelong.dong@amlogic.com> > --- > drivers/media/rc/meson-ir.c | 713 ++++++++++++++++++++++++++++++++---- > 1 file changed, 632 insertions(+), 81 deletions(-) > > diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c > index 4b769111f78e..1bfdce1c1864 100644 > --- a/drivers/media/rc/meson-ir.c > +++ b/drivers/media/rc/meson-ir.c > @@ -14,6 +14,7 @@ > #include <linux/platform_device.h> > #include <linux/spinlock.h> > #include <linux/bitfield.h> > +#include <linux/regmap.h> > > #include <media/rc-core.h> > > @@ -21,87 +22,598 @@ > > /* valid on all Meson platforms */ > #define IR_DEC_LDR_ACTIVE 0x00 > + #define IR_DEC_LDR_ACTIVE_MAX GENMASK(28, 16) > + #define IR_DEC_LDR_ACTIVE_MIN GENMASK(12, 0) Extra tabs before #define statement. The same problem is located in the whole patchset. [...] > +#define MESON_IR_TIMINGS(proto, r_cnt, r_chk, r_comp, b1_e, hc, cnt_tick, ori, \ > + flt, len, f_max, la_max, la_min, li_max, li_min, \ > + rl_max, rl_min, b0_max, b0_min, b1_max, b1_min, \ > + d2_max, d2_min, d3_max, d3_min) \ > + { \ > + .hw_protocol = proto, \ > + .repeat_counter_enable = r_cnt, \ > + .repeat_check_enable = r_chk, \ > + .repeat_compare_enable = r_comp, \ > + .bit1_match_enable = b1_e, \ > + .hold_code_enable = hc, \ > + .count_tick_mode = cnt_tick, \ > + .bit_order = ori, \ > + .filter_cnt = flt, \ > + .code_length = len, \ > + .frame_time_max = f_max, \ > + .leader_active_max = la_max, \ > + .leader_active_min = la_min, \ > + .leader_idle_max = li_max, \ > + .leader_idle_min = li_min, \ > + .repeat_leader_max = rl_max, \ > + .repeat_leader_min = rl_min, \ > + .bit0_max = b0_max, \ > + .bit0_min = b0_min, \ > + .bit1_max = b1_max, \ > + .bit1_min = b1_min, \ > + .duration2_max = d2_max, \ > + .duration2_min = d2_min, \ > + .duration3_max = d3_max, \ > + .duration3_min = d3_min, \ > + } \ Extra tabs for back slash alignment > + > +/** > + * struct meson_ir_param - 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. > + * @filter_cnt: input filter, to filter burr > + * @code_length: length (N-1) of frame's data part. > + * @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'. > + */ > Did you run checkpatch and kernel-doc checker for above struct documentation? > -#define REG0_RATE_MASK GENMASK(11, 0) > +struct meson_ir_param { > + 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 filter_cnt; > + 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; > +}; Why do you need tab alignment between type and variable? [...] > +#ifdef CONFIG_PM > +static int meson_ir_resume(struct device *dev) > +{ > + struct meson_ir *ir = dev_get_drvdata(dev); > + > + if (ir->support_hw_dec) > + meson_ir_change_protocol(ir->rc, &ir->rc->enabled_protocols); > + else > + meson_ir_sw_decoder_init(ir->rc); > + > + return 0; > +} > + > +static 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; > +} > +#endif > + > static const struct of_device_id meson_ir_match[] = { > { .compatible = "amlogic,meson6-ir" }, > { .compatible = "amlogic,meson8b-ir" }, > { .compatible = "amlogic,meson-gxbb-ir" }, > + { .compatible = "amlogic,meson-s4-ir" }, > { }, > }; > MODULE_DEVICE_TABLE(of, meson_ir_match); > > +#ifdef CONFIG_PM > +static const struct dev_pm_ops meson_ir_pm_ops = { > + .suspend_late = meson_ir_suspend, > + .resume_early = meson_ir_resume, > +}; > +#endif > + > static struct platform_driver meson_ir_driver = { > .probe = meson_ir_probe, > .remove = meson_ir_remove, > @@ -231,6 +779,9 @@ static struct platform_driver meson_ir_driver = { > .driver = { > .name = DRIVER_NAME, > .of_match_table = meson_ir_match, > +#ifdef CONFIG_PM > + .pm = &meson_ir_pm_ops, > +#endif You can use pm_ptr() and DEFINE_SIMPLE_DEV_PM_OPS instead of checking of CONFIG_PM definition. [...]
diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index 4b769111f78e..1bfdce1c1864 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c @@ -14,6 +14,7 @@ #include <linux/platform_device.h> #include <linux/spinlock.h> #include <linux/bitfield.h> +#include <linux/regmap.h> #include <media/rc-core.h> @@ -21,87 +22,598 @@ /* valid on all Meson platforms */ #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 -/* only available on Meson 8b and newer */ + #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 the 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 the 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 DECODE_MODE_NEC 0x0 +#define DECODE_MODE_RAW 0x2 +#define DECODE_MODE_RC6 0x9 +#define DECODE_MODE_XMP 0xE + +#define DECODER_STATUS_VALID BIT(3) +#define DECODER_STATUS_DATA_CODE_ERR BIT(2) +#define DECODER_STATUS_CUSTOM_CODE_ERR BIT(1) +#define DECODER_STATUS_REPEAT BIT(0) + +#define IRQSEL_NEC_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 */ + +#define MESON_IR_TIMINGS(proto, r_cnt, r_chk, r_comp, b1_e, hc, cnt_tick, ori, \ + flt, len, f_max, la_max, la_min, li_max, li_min, \ + rl_max, rl_min, b0_max, b0_min, b1_max, b1_min, \ + d2_max, d2_min, d3_max, d3_min) \ + { \ + .hw_protocol = proto, \ + .repeat_counter_enable = r_cnt, \ + .repeat_check_enable = r_chk, \ + .repeat_compare_enable = r_comp, \ + .bit1_match_enable = b1_e, \ + .hold_code_enable = hc, \ + .count_tick_mode = cnt_tick, \ + .bit_order = ori, \ + .filter_cnt = flt, \ + .code_length = len, \ + .frame_time_max = f_max, \ + .leader_active_max = la_max, \ + .leader_active_min = la_min, \ + .leader_idle_max = li_max, \ + .leader_idle_min = li_min, \ + .repeat_leader_max = rl_max, \ + .repeat_leader_min = rl_min, \ + .bit0_max = b0_max, \ + .bit0_min = b0_min, \ + .bit1_max = b1_max, \ + .bit1_min = b1_min, \ + .duration2_max = d2_max, \ + .duration2_min = d2_min, \ + .duration3_max = d3_max, \ + .duration3_min = d3_min, \ + } \ + +/** + * struct meson_ir_param - 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. + * @filter_cnt: input filter, to filter burr + * @code_length: length (N-1) of frame's data part. + * @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'. + */ -#define REG0_RATE_MASK GENMASK(11, 0) +struct meson_ir_param { + 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 filter_cnt; + 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; +}; -#define DECODE_MODE_NEC 0x0 -#define DECODE_MODE_RAW 0x2 +struct meson_ir { + struct regmap *reg; + struct rc_dev *rc; + spinlock_t lock; + bool support_hw_dec; +}; -/* Meson 6b uses REG1 to configure the mode */ -#define REG1_MODE_MASK GENMASK(8, 7) -#define REG1_MODE_SHIFT 7 +static struct regmap_config meson_ir_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; -/* Meson 8b / GXBB use REG2 to configure the mode */ -#define REG2_MODE_MASK GENMASK(3, 0) -#define REG2_MODE_SHIFT 0 +static const struct meson_ir_param protocol_timings[] = { + /* protocol, repeat counter, repeat check, repeat compare, bit 1 match */ + MESON_IR_TIMINGS(DECODE_MODE_NEC, false, false, false, true, + /* hold code, count tick, order, filter cnt, len, frame time */ + false, false, FRAME_LSB_FIRST, 7, 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), + MESON_IR_TIMINGS(DECODE_MODE_XMP, true, false, true, false, + false, true, FRAME_MSB_FIRST, 7, 32, 1500, + 0, 0, 0, 0, 0, 0, + 52, 45, 86, 80, 121, 114, 7, 7), + MESON_IR_TIMINGS(DECODE_MODE_RC6, true, false, true, false, + true, false, FRAME_MSB_FIRST, 7, 37, 4000, + 210, 125, 50, 38, 145, 125, + 51, 38, 94, 82, 28, 16, 51, 38) +}; -#define REG1_TIME_IV_MASK GENMASK(28, 16) +static void meson_ir_rc6_handler(struct meson_ir *ir) +{ + u32 code0, code1; -#define REG1_IRQSEL_MASK GENMASK(3, 2) -#define REG1_IRQSEL_NEC_MODE 0 -#define REG1_IRQSEL_RISE_FALL 1 -#define REG1_IRQSEL_FALL 2 -#define REG1_IRQSEL_RISE 3 + regmap_read(ir->reg, IR_DEC_FRAME, &code0); + regmap_read(ir->reg, IR_DEC_FRAME1, &code1); -#define REG1_RESET BIT(0) -#define REG1_ENABLE BIT(15) + rc_keydown(ir->rc, RC_PROTO_RC6_6A_32, code0, code1 & 0x1); +} -#define STATUS_IR_DEC_IN BIT(8) +static void meson_ir_xmp_handler(struct meson_ir *ir) +{ + static u32 last_xmp_code; + int i; + u32 code = 0; + u32 scancode, checksum = 0; + u8 addr, subaddr, subaddr2, toggle, oem, obc1, obc2; + + regmap_read(ir->reg, IR_DEC_FRAME, &code); + + for (i = 0; i < 32; i += 4) + checksum += ((code >> i) & 0xf); + checksum = ~(checksum + 0xf - ((code >> 24) & 0xf)) & 0xf; + + if (checksum != ((code >> 24) & 0xf)) { + last_xmp_code = 0; + dev_err(&ir->rc->dev, "xmp checksum error, framecode= 0x%x\n", + code); + return; + } -#define MESON_TRATE 10 /* us */ + subaddr = (last_xmp_code >> 24 & 0xf0) | (last_xmp_code >> 20 & 0x0f); + subaddr2 = (code >> 24 & 0xf0) | (code >> 16 & 0x0f); + oem = last_xmp_code >> 8; + addr = last_xmp_code; + toggle = code >> 20 & 0xf; + obc1 = code >> 8; + obc2 = code; + + if (subaddr != subaddr2) { + last_xmp_code = code; + dev_dbg(&ir->rc->dev, "subaddress nibbles mismatch 0x%02X != 0x%02X\n", + subaddr, subaddr2); + return; + } + if (oem != 0x44) + dev_dbg(&ir->rc->dev, "Warning: OEM nibbles 0x%02X. Expected 0x44\n", + oem); -struct meson_ir { - void __iomem *reg; - struct rc_dev *rc; - spinlock_t lock; -}; + scancode = addr << 24 | subaddr << 16 | obc1 << 8 | obc2; + dev_dbg(&ir->rc->dev, "XMP scancode 0x%06x\n", scancode); + + if (toggle == 0) + rc_keydown(ir->rc, RC_PROTO_XMP, scancode, 0); + else + rc_repeat(ir->rc); + + last_xmp_code = code; +} -static void meson_ir_set_mask(struct meson_ir *ir, unsigned int reg, - u32 mask, u32 value) +static void meson_ir_nec_handler(struct meson_ir *ir) { - u32 data; + u32 code = 0; + u32 status = 0; + enum rc_proto proto; + + regmap_read(ir->reg, IR_DEC_STATUS, &status); + + if (status & DECODER_STATUS_REPEAT) { + rc_repeat(ir->rc); + } else { + regmap_read(ir->reg, IR_DEC_FRAME, &code); - data = readl(ir->reg + reg); - data &= ~mask; - data |= (value & mask); - writel(data, ir->reg + reg); + code = ir_nec_bytes_to_scancode(code, code >> 8, + code >> 16, code >> 24, &proto); + rc_keydown(ir->rc, proto, code, 0); + } } static irqreturn_t meson_ir_irq(int irqno, void *dev_id) +{ + struct meson_ir *ir = dev_id; + u32 status = 0; + + if (ir->support_hw_dec) { + regmap_read(ir->reg, IR_DEC_STATUS, &status); + + if (!(status & DECODER_STATUS_VALID)) + return IRQ_NONE; + } + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t meson_ir_irq_thread(int irq, void *dev_id) { struct meson_ir *ir = dev_id; u32 duration, status; struct ir_raw_event rawir = {}; - spin_lock(&ir->lock); + if (ir->support_hw_dec) { + if (ir->rc->enabled_protocols & RC_PROTO_BIT_NEC) + meson_ir_nec_handler(ir); + else if (ir->rc->enabled_protocols & RC_PROTO_BIT_XMP) + meson_ir_xmp_handler(ir); + else if (ir->rc->enabled_protocols & RC_PROTO_BIT_RC6_6A_32) + meson_ir_rc6_handler(ir); + } else { + spin_lock(&ir->lock); - duration = readl_relaxed(ir->reg + IR_DEC_REG1); - duration = FIELD_GET(REG1_TIME_IV_MASK, duration); - rawir.duration = duration * MESON_TRATE; + regmap_read(ir->reg, IR_DEC_REG1, &duration); + duration = FIELD_GET(IR_DEC_REG1_TIME_IV, duration); + rawir.duration = duration * MESON_RAW_TRATE; - status = readl_relaxed(ir->reg + IR_DEC_STATUS); - rawir.pulse = !!(status & STATUS_IR_DEC_IN); + regmap_read(ir->reg, IR_DEC_STATUS, &status); + rawir.pulse = !!(status & IR_DEC_STATUS_PULSE); - ir_raw_event_store_with_timeout(ir->rc, &rawir); + ir_raw_event_store_with_timeout(ir->rc, &rawir); - spin_unlock(&ir->lock); + spin_unlock(&ir->lock); + } return IRQ_HANDLED; } +static int meson_ir_change_hw_protocol(struct rc_dev *dev, u8 protocol) +{ + struct meson_ir *ir = dev->priv; + int i; + unsigned long flags; + u32 regval; + const struct meson_ir_param *timings; + + 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); + + /* 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); + + /* Monitor timing for input filter */ + regval = FIELD_PREP(IR_DEC_REG0_FILTER, timings->filter_cnt); + regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_FILTER, 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 IR formats transer 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 check 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 large than the time between + * data frame and repeat code + */ + 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 frame data */ + 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 + * RC5/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 + * RC5/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); + + spin_unlock_irqrestore(&ir->lock, flags); + + return 0; +} + +static void meson_ir_hw_decoder_init(struct rc_dev *dev) +{ + u32 regval; + unsigned long flags; + struct meson_ir *ir = dev->priv; + + 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); + + spin_unlock_irqrestore(&ir->lock, flags); +} + +static int meson_ir_change_protocol(struct rc_dev *dev, u64 *rc_type) +{ + unsigned long flags; + struct meson_ir *ir = dev->priv; + + meson_ir_hw_decoder_init(dev); + + if (*rc_type & RC_PROTO_BIT_NEC) + meson_ir_change_hw_protocol(dev, DECODE_MODE_NEC); + else if (*rc_type & RC_PROTO_BIT_XMP) + meson_ir_change_hw_protocol(dev, DECODE_MODE_XMP); + else if (*rc_type & RC_PROTO_BIT_RC6_6A_32) + meson_ir_change_hw_protocol(dev, DECODE_MODE_RC6); + + spin_lock_irqsave(&ir->lock, flags); + + /* 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); + + 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, + DECODE_MODE_RAW)); + else + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_MODE, + FIELD_PREP(IR_DEC_REG2_MODE, + DECODE_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); +} + +static int meson_ir_rc_allocate_device(struct platform_device *pdev) +{ + struct meson_ir *ir = platform_get_drvdata(pdev); + + if (ir->support_hw_dec) { + ir->rc = devm_rc_allocate_device(&pdev->dev, + RC_DRIVER_SCANCODE); + if (!ir->rc) { + dev_err(&pdev->dev, "failed to allocate rc device\n"); + return -ENOMEM; + } + + ir->rc->allowed_protocols = RC_PROTO_BIT_NEC | + RC_PROTO_BIT_RC6_6A_32 | + RC_PROTO_BIT_XMP; + ir->rc->change_protocol = meson_ir_change_protocol; + } else { + ir->rc = devm_rc_allocate_device(&pdev->dev, RC_DRIVER_IR_RAW); + if (!ir->rc) { + dev_err(&pdev->dev, "failed to allocate rc device\n"); + return -ENOMEM; + } + + 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; + } + + return 0; +} + static int meson_ir_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; + struct resource *res; + void __iomem *res_start; const char *map_name; struct meson_ir *ir; int irq, ret; @@ -110,7 +622,19 @@ static int meson_ir_probe(struct platform_device *pdev) if (!ir) return -ENOMEM; - ir->reg = devm_platform_ioremap_resource(pdev, 0); + platform_set_drvdata(pdev, ir); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (IS_ERR_OR_NULL(res)) { + dev_err(&pdev->dev, "get mem resource error, %ld\n", + PTR_ERR(res)); + return PTR_ERR(res); + } + + res_start = devm_ioremap_resource(&pdev->dev, res); + meson_ir_regmap_config.max_register = resource_size(res) - 4; + ir->reg = devm_regmap_init_mmio(&pdev->dev, res_start, + &meson_ir_regmap_config); if (IS_ERR(ir->reg)) return PTR_ERR(ir->reg); @@ -118,27 +642,28 @@ static int meson_ir_probe(struct platform_device *pdev) if (irq < 0) return irq; - ir->rc = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW); - if (!ir->rc) { - dev_err(dev, "failed to allocate rc device\n"); - return -ENOMEM; + if (of_device_is_compatible(node, "amlogic,meson6-ir")) { + ir->support_hw_dec = false; + } else { + if (of_property_read_bool(node, + "amlogic,ir-support-hw-decode")) + ir->support_hw_dec = true; + else + ir->support_hw_dec = false; } + if (meson_ir_rc_allocate_device(pdev)) + return -ENOMEM; + 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->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; - ir->rc->rx_resolution = MESON_TRATE; - ir->rc->min_timeout = 1; - ir->rc->timeout = IR_DEFAULT_TIMEOUT; - ir->rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT; 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) { @@ -146,33 +671,20 @@ static int meson_ir_probe(struct platform_device *pdev) return ret; } - ret = devm_request_irq(dev, irq, meson_ir_irq, 0, NULL, ir); + if (!ir->support_hw_dec) + meson_ir_sw_decoder_init(ir->rc); + + ret = devm_request_threaded_irq(dev, irq, meson_ir_irq, + meson_ir_irq_thread, + IRQF_SHARED | IRQF_NO_SUSPEND, + "meson_ir", ir); if (ret) { dev_err(dev, "failed to request irq\n"); return ret; } - /* Reset the decoder */ - meson_ir_set_mask(ir, IR_DEC_REG1, REG1_RESET, REG1_RESET); - meson_ir_set_mask(ir, IR_DEC_REG1, REG1_RESET, 0); - - /* Set general operation mode (= raw/software decoding) */ - if (of_device_is_compatible(node, "amlogic,meson6-ir")) - meson_ir_set_mask(ir, IR_DEC_REG1, REG1_MODE_MASK, - FIELD_PREP(REG1_MODE_MASK, DECODE_MODE_RAW)); - else - meson_ir_set_mask(ir, IR_DEC_REG2, REG2_MODE_MASK, - FIELD_PREP(REG2_MODE_MASK, DECODE_MODE_RAW)); - - /* Set rate */ - meson_ir_set_mask(ir, IR_DEC_REG0, REG0_RATE_MASK, MESON_TRATE - 1); - /* IRQ on rising and falling edges */ - meson_ir_set_mask(ir, IR_DEC_REG1, REG1_IRQSEL_MASK, - FIELD_PREP(REG1_IRQSEL_MASK, REG1_IRQSEL_RISE_FALL)); - /* Enable the decoder */ - meson_ir_set_mask(ir, IR_DEC_REG1, REG1_ENABLE, REG1_ENABLE); - - dev_info(dev, "receiver initialized\n"); + dev_info(dev, "meson ir %s decoder was initialized\n", + ir->support_hw_dec ? "hw" : "sw"); return 0; } @@ -184,7 +696,7 @@ static int meson_ir_remove(struct platform_device *pdev) /* Disable the decoder */ spin_lock_irqsave(&ir->lock, flags); - meson_ir_set_mask(ir, IR_DEC_REG1, REG1_ENABLE, 0); + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_ENABLE, 0); spin_unlock_irqrestore(&ir->lock, flags); return 0; @@ -193,7 +705,6 @@ static int meson_ir_remove(struct platform_device *pdev) 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; @@ -203,27 +714,64 @@ static void meson_ir_shutdown(struct platform_device *pdev) * 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")) - meson_ir_set_mask(ir, IR_DEC_REG1, REG1_MODE_MASK, - DECODE_MODE_NEC << REG1_MODE_SHIFT); + if (of_device_is_compatible(dev->of_node, "amlogic,meson6-ir")) + regmap_update_bits(ir->reg, IR_DEC_REG1, IR_DEC_REG1_MODE, + FIELD_PREP(IR_DEC_REG1_MODE, + DECODE_MODE_NEC)); else - meson_ir_set_mask(ir, IR_DEC_REG2, REG2_MODE_MASK, - DECODE_MODE_NEC << REG2_MODE_SHIFT); + regmap_update_bits(ir->reg, IR_DEC_REG2, IR_DEC_REG2_MODE, + FIELD_PREP(IR_DEC_REG2_MODE, + DECODE_MODE_NEC)); /* Set rate to default value */ - meson_ir_set_mask(ir, IR_DEC_REG0, REG0_RATE_MASK, 0x13); + regmap_update_bits(ir->reg, IR_DEC_REG0, IR_DEC_REG0_BASE_TIME, + FIELD_PREP(IR_DEC_REG0_BASE_TIME, MESON_HW_TRATE)); spin_unlock_irqrestore(&ir->lock, flags); } +#ifdef CONFIG_PM +static int meson_ir_resume(struct device *dev) +{ + struct meson_ir *ir = dev_get_drvdata(dev); + + if (ir->support_hw_dec) + meson_ir_change_protocol(ir->rc, &ir->rc->enabled_protocols); + else + meson_ir_sw_decoder_init(ir->rc); + + return 0; +} + +static 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; +} +#endif + static const struct of_device_id meson_ir_match[] = { { .compatible = "amlogic,meson6-ir" }, { .compatible = "amlogic,meson8b-ir" }, { .compatible = "amlogic,meson-gxbb-ir" }, + { .compatible = "amlogic,meson-s4-ir" }, { }, }; MODULE_DEVICE_TABLE(of, meson_ir_match); +#ifdef CONFIG_PM +static const struct dev_pm_ops meson_ir_pm_ops = { + .suspend_late = meson_ir_suspend, + .resume_early = meson_ir_resume, +}; +#endif + static struct platform_driver meson_ir_driver = { .probe = meson_ir_probe, .remove = meson_ir_remove, @@ -231,6 +779,9 @@ static struct platform_driver meson_ir_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = meson_ir_match, +#ifdef CONFIG_PM + .pm = &meson_ir_pm_ops, +#endif }, };