From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 43445C6FA8E for ; Thu, 2 Mar 2023 09:28:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:Content-Type: Content-Transfer-Encoding:Reply-To:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:In-Reply-To:References:Cc:To:Subject: From:MIME-Version:Date:Message-ID:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=zkBx2C5FIj8oS8K/287v8evecIwqFBTEPWQN0hScgYs=; b=hpJm6Owalw4SP/gJz8khoPtMVA RtS+H23/w6I7RVDVleTkMoqWCHby6wVvxlUMXETDaVVcW5iLjgdkViTGO1wq4dUQZng3+hT1Ouoti k50H20ifqmkt7x0dH6UWri+bTDX8GOFRBvAqJpxdlF23kBiBxM2bCHBk7OE2CFN0rmrRPLX7DbFSW CERDatkigSfeMite9KsDaBpJR31uG9MNmLfAtY2+d2105yafkWaFJHjGxcaOp9BzYuI+7FglxHON0 faY2Z+5UT7j0jdlAf8YRUVP5ghPYPbXWHzsP7IBMaqka6yfnbMF8P0EyRoNwXXgbX/EKAnvMSRHpH U5hcoK3g==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1pXfEM-001PLe-Oo; Thu, 02 Mar 2023 09:28:06 +0000 Received: from mail-wr1-x42f.google.com ([2a00:1450:4864:20::42f]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1pXfEH-001PKe-IN for linux-amlogic@lists.infradead.org; Thu, 02 Mar 2023 09:28:05 +0000 Received: by mail-wr1-x42f.google.com with SMTP id r18so15848759wrx.1 for ; Thu, 02 Mar 2023 01:28:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1677749279; h=content-transfer-encoding:in-reply-to:organization:references:cc:to :content-language:subject:reply-to:from:user-agent:mime-version:date :message-id:from:to:cc:subject:date:message-id:reply-to; bh=vpLe6rb8hMe/7fVqD3idCIuKOETuKhZIvbVmieMqv7E=; b=jL/OYAj11vUHl+u4m51SfUjCukSFqxmv39QK4qQNUDh8XYs3ilWfiO+FQi3C3zuOSD TC5D7zTCFzo9gbphan9jpaJmOwWCaimEbIPqLH4S7MVwbtDknR5onPNbB1gdguDIiHcG f3nHD95vzp5cbA2Kj47F2ixQZG8DMcUViJD8axmyw0gNZPZfNNxuU9FuCNgolQCNFFAb 1Q2x9Jf5fCJSkWmVxPsBBZdZgpaG8JFJGHd5t00M6LgjFK2KafbqwLIboWZjBz/WXDBT phcEqUnqcOMk0A8sukUt6xqGhmjohPvLAMHOHus0BLWYqHWbPnkYgN3TXyh5Vhzktm7Z 71pA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1677749279; h=content-transfer-encoding:in-reply-to:organization:references:cc:to :content-language:subject:reply-to:from:user-agent:mime-version:date :message-id:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=vpLe6rb8hMe/7fVqD3idCIuKOETuKhZIvbVmieMqv7E=; b=0xKEr9R32J7w0PnkrFA8JrdXjseHDJ+qUKMNsfp8J92kZrHzSM8V0sUjM3suxK4jax drJe996cWonr4DcnwY9pQ7T66UNxEG3MrSyZr7mqyupV5Q9QzUfBoXALFKmg2k4XdIPy ZuRMgm9RIYpemlMFgOezvTZXFYFcOPP7zO/wsxOsHKOaPGC5gKSD/DES96GBa3SWDcA+ TdgnYiFC45sJaiU3B0DwACS55qRIWG0mKDdYtTiHxdFHUvCyH/u6Hl11/IvU1rLZ3D5p ra5II6IzKIlD4G+G7wUAvMKYmZX/WSfuR4j+nTVpRRDI/gXcJeqJW0DvXKWA39oapSsv bEZQ== X-Gm-Message-State: AO0yUKVIZqB3qXcHGcGcGwQRg2KEUWA6G3J3zPqToNpFk6pvqGq3ajct rbr4wWLNmq0q63CBpmRb1rca1A== X-Google-Smtp-Source: AK7set89dnttIQct6VZk/lrX8l8HmZ/wL6pLW8uPt5j1hy7xUVajNd8ZqWRZUL8mi9TB9+Dn4gMg3Q== X-Received: by 2002:adf:de92:0:b0:2cd:f2c6:5d37 with SMTP id w18-20020adfde92000000b002cdf2c65d37mr610735wrl.5.1677749278904; Thu, 02 Mar 2023 01:27:58 -0800 (PST) Received: from ?IPV6:2a01:e0a:982:cbb0:217a:db24:fe27:6b35? ([2a01:e0a:982:cbb0:217a:db24:fe27:6b35]) by smtp.gmail.com with ESMTPSA id e29-20020a5d595d000000b002cde25fba30sm1350796wri.1.2023.03.02.01.27.57 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 02 Mar 2023 01:27:58 -0800 (PST) Message-ID: <48aea529-fe95-bb56-2fad-2e0220c398fc@linaro.org> Date: Thu, 2 Mar 2023 10:27:57 +0100 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.7.2 From: Neil Armstrong Subject: Re: [PATCH 1/3] media: rc: meson-ir: support rc driver type RC_DRIVER_SCANCODE Content-Language: en-US To: zelong dong , Sean Young , Mauro Carvalho Chehab , Rob Herring , Jerome Brunet , Kevin Hilman , Martin Blumenstingl Cc: linux-media@vger.kernel.org, linux-amlogic@lists.infradead.org, devicetree@vger.kernel.org References: <20230302063402.42708-1-zelong.dong@amlogic.com> <20230302063402.42708-2-zelong.dong@amlogic.com> Organization: Linaro Developer Services In-Reply-To: <20230302063402.42708-2-zelong.dong@amlogic.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20230302_012801_884773_D0C8F37F X-CRM114-Status: GOOD ( 31.94 ) X-BeenThere: linux-amlogic@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: neil.armstrong@linaro.org Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="us-ascii"; Format="flowed" Sender: "linux-amlogic" Errors-To: linux-amlogic-bounces+linux-amlogic=archiver.kernel.org@lists.infradead.org Hi, On 02/03/2023 07:34, zelong dong wrote: > From: Zelong Dong > > 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 > --- > 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 > #include > #include > +#include > > #include > > @@ -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 > }, > }; > _______________________________________________ linux-amlogic mailing list linux-amlogic@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-amlogic