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 X-Spam-Level: X-Spam-Status: No, score=-17.5 required=3.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED,DKIM_SIGNED,DKIM_VALID,FREEMAIL_FORGED_FROMDOMAIN, FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER, INCLUDES_PATCH,MAILING_LIST_MULTI,MENTIONS_GIT_HOSTING,NICE_REPLY_A, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_SANE_1 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D223AC433DB for ; Fri, 15 Jan 2021 00:39:37 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 53A2323A53 for ; Fri, 15 Jan 2021 00:39:37 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 53A2323A53 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-riscv-bounces+linux-riscv=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Type: Content-Transfer-Encoding:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:In-Reply-To:MIME-Version:Date:Message-ID:From: References:To:Subject:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=3DoixzNe2W/ofFM6/hP14zEIngAIVjvnTspWGhJWCyY=; b=xhDIjdrZAqSsuZZK5nuUc+jmD 2UjrVgFkw4Ts28X/nMTa76H+5wocOPe8NxOjnsaQj24UFt5N/afUXUDkGLe1btC1BxrjPpMCue4pD 7kodYgYOWVG1LJ7hZnfF7jUtXkfy4CdVVP99PRmBZXomv8ticV6JLyhkhYmFpqIb4kp6eVlZl9ryT 3pvVc0GVUKFveMuE2R4jB0yUSzJB4V98yyXoQhv/gdskT7Z2L4cqQONnG0L4eNKb5t7ksrHW/DkBw CsaWjwCtOzvaWU9EY35nTeFU69rssZIheiw3OhRm+SvMEkltkuTsFvgRQOJy7ZyPnQM9zcZcOeTFx wr90GgSmw==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1l0D98-0001gk-Gq; Fri, 15 Jan 2021 00:39:22 +0000 Received: from mail-qk1-x729.google.com ([2607:f8b0:4864:20::729]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1l0D94-0001gK-53 for linux-riscv@lists.infradead.org; Fri, 15 Jan 2021 00:39:19 +0000 Received: by mail-qk1-x729.google.com with SMTP id f26so10245606qka.0 for ; Thu, 14 Jan 2021 16:39:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language:content-transfer-encoding; bh=x8eP+t0lKYhMRqPj57W7Lv0n6Pas2FXlucG3vsxt/M8=; b=Do1FmF3iBJ6l7nunt1yy+EwMqSAdvskFrwY5elFCrHBqVUzRq1grrxSDdmPzBLV6/+ ik64npi3VAPFABWFFRcjeRA7WaYBnOAeQ3JVwteIlrKvglZf8MB7Ig7VWZ+D8F0scbAN vEafoUc4MGDouah7KlZl+Gigc1od1Y8d2j9+obd08nYP7K8zis4Rrz/1izKF6XALISvu JlCkC5m6K+ewi4QDp956LcSKWqyzooNAe9lxGTe7FdObJgsw5n1jE85fSKm6AnT7GsLs ZD9uzMkhASFqJCybWo2cIku7ytQhpqzwhIK5zWMFfTQmCSFm+/hEQBbq2QydSot9zf9R gQiA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=x8eP+t0lKYhMRqPj57W7Lv0n6Pas2FXlucG3vsxt/M8=; b=hInHeHIzSnLGVY7ZDIaTiz84RFU2C+X49qBICP7qvlwWCbnUdQIo9RSPJZO4V0GcBb lpVyqXCOTCFF3GgXJuaA+X/T9XhQ6G/2MymgdgSprH+lTi9gx+7rV71DPPWvHEweOGdX 1NzEYYzsfcfZ6XHNwPYTDYqmHd4X3DxNzue1/TBLrxGJM+k91gk4Zeuaai5USXSC3K1H MF1PgV5lSVlxs6nP40XjZtZyG69YkSkm/VqdRpEyaHAutEkxa5C5jDEoA/H36V1GUmnW Umgglu2BfSsDs5qnfEXvwmPDlc3cPOiaAuUUH+vho24DA6ua8eEYOnE6sUrbU47XOZI8 Fm9g== X-Gm-Message-State: AOAM530G7AudixnJdncZWD3FoMkEnBSBlCBJXOHJgkfs5x/IawNht0eZ +jV1xCYp8kUNjwGpHhwds1msq6Bzbl0= X-Google-Smtp-Source: ABdhPJw1gGftVdIrTfh8hAi7e21iiEWgiwBI0IWfr6rLsM9Rdo8E3UsTEi3DvKj97fQU+AXfeDsxAA== X-Received: by 2002:a37:9001:: with SMTP id s1mr9715163qkd.193.1610671155822; Thu, 14 Jan 2021 16:39:15 -0800 (PST) Received: from [192.168.1.201] (pool-108-51-35-162.washdc.fios.verizon.net. [108.51.35.162]) by smtp.googlemail.com with ESMTPSA id o30sm3809765qtd.24.2021.01.14.16.39.14 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 14 Jan 2021 16:39:15 -0800 (PST) Subject: Re: [PATCH v11 02/10] pinctrl: Add RISC-V Canaan Kendryte K210 FPIOA driver To: Damien Le Moal , Palmer Dabbelt , "linus.walleij@linaro.org" References: From: Sean Anderson Message-ID: <029fd211-a2c9-b3cf-7cb3-47eab456cc37@gmail.com> Date: Thu, 14 Jan 2021 19:39:14 -0500 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.12.0 MIME-Version: 1.0 In-Reply-To: Content-Language: en-US X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210114_193918_265674_21A59B3E X-CRM114-Status: GOOD ( 32.89 ) X-BeenThere: linux-riscv@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: "linux-riscv@lists.infradead.org" Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="us-ascii"; Format="flowed" Sender: "linux-riscv" Errors-To: linux-riscv-bounces+linux-riscv=archiver.kernel.org@lists.infradead.org On 1/14/21 7:17 PM, Damien Le Moal wrote: > On 2021/01/15 8:32, Palmer Dabbelt wrote: >> On Mon, 11 Jan 2021 16:58:40 PST (-0800), Damien Le Moal wrote: >>> Add the pinctrl-k210.c pinctrl driver for the Canaan Kendryte K210 >>> field programmable IO array (FPIOA) to allow configuring the SoC pin >>> functions. The K210 has 48 programmable pins which can take any of 256 >>> possible functions. >>> >>> This patch is inspired from the k210 pinctrl driver for the u-boot >>> project and contains many direct contributions from Sean Anderson. >>> >>> The MAINTAINERS file is updated, adding the entry "CANAAN/KENDRYTE K210 >>> SOC FPIOA DRIVER" with myself listed as maintainer for this driver. >>> >>> Cc: Linus Walleij >>> Cc: linux-gpio@vger.kernel.org >> >> IDK if something's screwed up on my end, but I don't see these CCs locally. > > It's me who messed up my git-send-email command. I can't get it to send a patch > series using only the CC per patch instead of coalescing all the CC references > and sending all patches to everyone, which I would like to avoid. Still digging > the option usage to figure that one out. I was doing --dry-run tests but the > patches still were sent... Anyway, I sent this and the clock driver patch > separately to the gpio and clk lists. There's always u-boot's patman. I find it very helpful for CC-ing relevant people and managing changelogs. https://gitlab.denx.de/u-boot/u-boot/blob/master/tools/patman/README --Sean > >> Lore does have it in the GPIO list, though, so maybe it made it. Either way, >> if I'm going to take this through the RISC-V tree then I'd much prefer to have >> at least an Ack. I'd also be happy to have it go through the GPIO tree, as >> this is largely stand-alone -- the DT bindings are on riscv/for-next, but I'd >> be happy to split them out into a shared tag or just put them in through your >> tree if that's easier. > > Yes, I think this one can go through the gpio tree. > > Linus, > > Could you review this patch please ? > >> >>> Signed-off-by: Sean Anderson >>> Signed-off-by: Damien Le Moal >>> --- >>> MAINTAINERS | 7 + >>> arch/riscv/Kconfig.socs | 1 + >>> drivers/pinctrl/Kconfig | 13 + >>> drivers/pinctrl/Makefile | 1 + >>> drivers/pinctrl/pinctrl-k210.c | 985 +++++++++++++++++++++++++++++++++ >>> 5 files changed, 1007 insertions(+) >>> create mode 100644 drivers/pinctrl/pinctrl-k210.c >>> >>> diff --git a/MAINTAINERS b/MAINTAINERS >>> index 637b79eba693..1a7a1e4092e2 100644 >>> --- a/MAINTAINERS >>> +++ b/MAINTAINERS >>> @@ -3860,6 +3860,13 @@ W: https://github.com/Cascoda/ca8210-linux.git >>> F: Documentation/devicetree/bindings/net/ieee802154/ca8210.txt >>> F: drivers/net/ieee802154/ca8210.c >>> >>> +CANAAN/KENDRYTE K210 SOC FPIOA DRIVER >>> +M: Damien Le Moal >>> +L: linux-riscv@lists.infradead.org >>> +L: linux-gpio@vger.kernel.org (pinctrl driver) >>> +F: Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml >>> +F: drivers/pinctrl/pinctrl-k210.c >>> + >>> CANAAN/KENDRYTE K210 SOC RESET CONTROLLER DRIVER >>> M: Damien Le Moal >>> L: linux-kernel@vger.kernel.org >>> diff --git a/arch/riscv/Kconfig.socs b/arch/riscv/Kconfig.socs >>> index 57e53219c500..6402746c68f3 100644 >>> --- a/arch/riscv/Kconfig.socs >>> +++ b/arch/riscv/Kconfig.socs >>> @@ -30,6 +30,7 @@ config SOC_CANAAN >>> select SERIAL_SIFIVE_CONSOLE if TTY >>> select SIFIVE_PLIC >>> select ARCH_HAS_RESET_CONTROLLER >>> + select PINCTRL >>> help >>> This enables support for Canaan Kendryte K210 SoC platform hardware. >>> >>> diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig >>> index d4b2f2e2ed75..cd437e3cc255 100644 >>> --- a/drivers/pinctrl/Kconfig >>> +++ b/drivers/pinctrl/Kconfig >>> @@ -394,6 +394,19 @@ config PINCTRL_MICROCHIP_SGPIO >>> connect control signals from SFP modules and to act as an >>> LED controller. >>> >>> +config PINCTRL_K210 >>> + bool "Pinctrl driver for the Canaan Kendryte K210 SoC" >>> + depends on RISCV && SOC_CANAAN && OF >>> + select GENERIC_PINMUX_FUNCTIONS >>> + select GENERIC_PINCONF >>> + select GPIOLIB >>> + select OF_GPIO >>> + select REGMAP_MMIO >>> + default SOC_CANAAN >>> + help >>> + Add support for the Canaan Kendryte K210 RISC-V SOC Field >>> + Programmable IO Array (FPIOA) controller. >>> + >>> source "drivers/pinctrl/actions/Kconfig" >>> source "drivers/pinctrl/aspeed/Kconfig" >>> source "drivers/pinctrl/bcm/Kconfig" >>> diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile >>> index 5bb9bb6cc3ce..152c8fe51726 100644 >>> --- a/drivers/pinctrl/Makefile >>> +++ b/drivers/pinctrl/Makefile >>> @@ -48,6 +48,7 @@ obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o >>> obj-$(CONFIG_PINCTRL_OCELOT) += pinctrl-ocelot.o >>> obj-$(CONFIG_PINCTRL_MICROCHIP_SGPIO) += pinctrl-microchip-sgpio.o >>> obj-$(CONFIG_PINCTRL_EQUILIBRIUM) += pinctrl-equilibrium.o >>> +obj-$(CONFIG_PINCTRL_K210) += pinctrl-k210.o >>> >>> obj-y += actions/ >>> obj-$(CONFIG_ARCH_ASPEED) += aspeed/ >>> diff --git a/drivers/pinctrl/pinctrl-k210.c b/drivers/pinctrl/pinctrl-k210.c >>> new file mode 100644 >>> index 000000000000..8a733cf77ba0 >>> --- /dev/null >>> +++ b/drivers/pinctrl/pinctrl-k210.c >>> @@ -0,0 +1,985 @@ >>> +// SPDX-License-Identifier: GPL-2.0-or-later >>> +/* >>> + * Copyright (C) 2020 Sean Anderson >>> + * Copyright (c) 2020 Western Digital Corporation or its affiliates. >>> + */ >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> +#include >>> + >>> +#include >>> + >>> +#include "core.h" >>> +#include "pinconf.h" >>> +#include "pinctrl-utils.h" >>> + >>> +/* >>> + * The K210 only implements 8 drive levels, even though >>> + * there is register space for 16 >>> + */ >>> +#define K210_PC_DRIVE_MASK GENMASK(11, 8) >>> +#define K210_PC_DRIVE_SHIFT 8 >>> +#define K210_PC_DRIVE_0 (0 << K210_PC_DRIVE_SHIFT) >>> +#define K210_PC_DRIVE_1 (1 << K210_PC_DRIVE_SHIFT) >>> +#define K210_PC_DRIVE_2 (2 << K210_PC_DRIVE_SHIFT) >>> +#define K210_PC_DRIVE_3 (3 << K210_PC_DRIVE_SHIFT) >>> +#define K210_PC_DRIVE_4 (4 << K210_PC_DRIVE_SHIFT) >>> +#define K210_PC_DRIVE_5 (5 << K210_PC_DRIVE_SHIFT) >>> +#define K210_PC_DRIVE_6 (6 << K210_PC_DRIVE_SHIFT) >>> +#define K210_PC_DRIVE_7 (7 << K210_PC_DRIVE_SHIFT) >>> +#define K210_PC_DRIVE_MAX 7 >>> +#define K210_PC_MODE_MASK GENMASK(23, 12) >>> + >>> +/* >>> + * output enabled == PC_OE & (PC_OE_INV ^ FUNCTION_OE) >>> + * where FUNCTION_OE is a physical signal from the function. >>> + */ >>> +#define K210_PC_OE BIT(12) /* Output Enable */ >>> +#define K210_PC_OE_INV BIT(13) /* INVert Output Enable */ >>> +#define K210_PC_DO_OE BIT(14) /* set Data Out to Output Enable sig */ >>> +#define K210_PC_DO_INV BIT(15) /* INVert final Data Output */ >>> +#define K210_PC_PU BIT(16) /* Pull Up */ >>> +#define K210_PC_PD BIT(17) /* Pull Down */ >>> +/* Strong pull up not implemented on K210 */ >>> +#define K210_PC_SL BIT(19) /* reduce SLew rate */ >>> +/* Same semantics as OE above */ >>> +#define K210_PC_IE BIT(20) /* Input Enable */ >>> +#define K210_PC_IE_INV BIT(21) /* INVert Input Enable */ >>> +#define K210_PC_DI_INV BIT(22) /* INVert Data Input */ >>> +#define K210_PC_ST BIT(23) /* Schmitt Trigger */ >>> +#define K210_PC_DI BIT(31) /* raw Data Input */ >>> + >>> +#define K210_PC_BIAS_MASK (K210_PC_PU & K210_PC_PD) >>> + >>> +#define K210_PC_MODE_IN (K210_PC_IE | K210_PC_ST) >>> +#define K210_PC_MODE_OUT (K210_PC_DRIVE_7 | K210_PC_OE) >>> +#define K210_PC_MODE_I2C (K210_PC_MODE_IN | K210_PC_SL | \ >>> + K210_PC_OE | K210_PC_PU) >>> +#define K210_PC_MODE_SCCB (K210_PC_MODE_I2C | \ >>> + K210_PC_OE_INV | K210_PC_IE_INV) >>> +#define K210_PC_MODE_SPI (K210_PC_MODE_IN | K210_PC_IE_INV | \ >>> + K210_PC_MODE_OUT | K210_PC_OE_INV) >>> +#define K210_PC_MODE_GPIO (K210_PC_MODE_IN | K210_PC_MODE_OUT) >>> + >>> +#define K210_PG_FUNC GENMASK(7, 0) >>> +#define K210_PG_DO BIT(8) >>> +#define K210_PG_PIN GENMASK(22, 16) >>> + >>> +/* >>> + * struct k210_fpioa: Kendryte K210 FPIOA memory mapped registers >>> + * @pins: 48 32-bits IO pin registers >>> + * @tie_en: 256 (one per function) input tie enable bits >>> + * @tie_val: 256 (one per function) input tie value bits >>> + */ >>> +struct k210_fpioa { >>> + u32 pins[48]; >>> + u32 tie_en[8]; >>> + u32 tie_val[8]; >>> +}; >>> + >>> +struct k210_fpioa_data { >>> + >>> + struct device *dev; >>> + struct pinctrl_dev *pctl; >>> + >>> + struct k210_fpioa __iomem *fpioa; >>> + struct regmap *sysctl_map; >>> + u32 power_offset; >>> + struct clk *clk; >>> + struct clk *pclk; >>> +}; >>> + >>> +#define K210_PIN_NAME(i) ("IO_" #i) >>> +#define K210_PIN(i) [(i)] = PINCTRL_PIN((i), K210_PIN_NAME(i)) >>> + >>> +static const struct pinctrl_pin_desc k210_pins[] = { >>> + K210_PIN(0), K210_PIN(1), K210_PIN(2), >>> + K210_PIN(3), K210_PIN(4), K210_PIN(5), >>> + K210_PIN(6), K210_PIN(7), K210_PIN(8), >>> + K210_PIN(9), K210_PIN(10), K210_PIN(11), >>> + K210_PIN(12), K210_PIN(13), K210_PIN(14), >>> + K210_PIN(15), K210_PIN(16), K210_PIN(17), >>> + K210_PIN(18), K210_PIN(19), K210_PIN(20), >>> + K210_PIN(21), K210_PIN(22), K210_PIN(23), >>> + K210_PIN(24), K210_PIN(25), K210_PIN(26), >>> + K210_PIN(27), K210_PIN(28), K210_PIN(29), >>> + K210_PIN(30), K210_PIN(31), K210_PIN(32), >>> + K210_PIN(33), K210_PIN(34), K210_PIN(35), >>> + K210_PIN(36), K210_PIN(37), K210_PIN(38), >>> + K210_PIN(39), K210_PIN(40), K210_PIN(41), >>> + K210_PIN(42), K210_PIN(43), K210_PIN(44), >>> + K210_PIN(45), K210_PIN(46), K210_PIN(47) >>> +}; >>> + >>> +#define K210_NPINS ARRAY_SIZE(k210_pins) >>> + >>> +/* >>> + * Pin groups: each of the 48 programmable pins is a group. >>> + * To this are added 8 power domain groups, which for the purposes of >>> + * the pin subsystem, contain no pins. The power domain groups only exist >>> + * to set the power level. The id should never be used (since there are >>> + * no pins 48-55). >>> + */ >>> +static const char *const k210_group_names[] = { >>> + /* The first 48 groups are for pins, one each */ >>> + K210_PIN_NAME(0), K210_PIN_NAME(1), K210_PIN_NAME(2), >>> + K210_PIN_NAME(3), K210_PIN_NAME(4), K210_PIN_NAME(5), >>> + K210_PIN_NAME(6), K210_PIN_NAME(7), K210_PIN_NAME(8), >>> + K210_PIN_NAME(9), K210_PIN_NAME(10), K210_PIN_NAME(11), >>> + K210_PIN_NAME(12), K210_PIN_NAME(13), K210_PIN_NAME(14), >>> + K210_PIN_NAME(15), K210_PIN_NAME(16), K210_PIN_NAME(17), >>> + K210_PIN_NAME(18), K210_PIN_NAME(19), K210_PIN_NAME(20), >>> + K210_PIN_NAME(21), K210_PIN_NAME(22), K210_PIN_NAME(23), >>> + K210_PIN_NAME(24), K210_PIN_NAME(25), K210_PIN_NAME(26), >>> + K210_PIN_NAME(27), K210_PIN_NAME(28), K210_PIN_NAME(29), >>> + K210_PIN_NAME(30), K210_PIN_NAME(31), K210_PIN_NAME(32), >>> + K210_PIN_NAME(33), K210_PIN_NAME(34), K210_PIN_NAME(35), >>> + K210_PIN_NAME(36), K210_PIN_NAME(37), K210_PIN_NAME(38), >>> + K210_PIN_NAME(39), K210_PIN_NAME(40), K210_PIN_NAME(41), >>> + K210_PIN_NAME(42), K210_PIN_NAME(43), K210_PIN_NAME(44), >>> + K210_PIN_NAME(45), K210_PIN_NAME(46), K210_PIN_NAME(47), >>> + [48] = "A0", [49] = "A1", [50] = "A2", >>> + [51] = "B3", [52] = "B4", [53] = "B5", >>> + [54] = "C6", [55] = "C7" >>> +}; >>> + >>> +#define K210_NGROUPS ARRAY_SIZE(k210_group_names) >>> + >>> +enum k210_pinctrl_mode_id { >>> + K210_PC_DEFAULT_DISABLED, >>> + K210_PC_DEFAULT_IN, >>> + K210_PC_DEFAULT_IN_TIE, >>> + K210_PC_DEFAULT_OUT, >>> + K210_PC_DEFAULT_I2C, >>> + K210_PC_DEFAULT_SCCB, >>> + K210_PC_DEFAULT_SPI, >>> + K210_PC_DEFAULT_GPIO, >>> + K210_PC_DEFAULT_INT13, >>> +}; >>> + >>> +#define K210_PC_DEFAULT(mode) \ >>> + [K210_PC_DEFAULT_##mode] = K210_PC_MODE_##mode >>> + >>> +static const u32 k210_pinconf_mode_id_to_mode[] = { >>> + [K210_PC_DEFAULT_DISABLED] = 0, >>> + K210_PC_DEFAULT(IN), >>> + [K210_PC_DEFAULT_IN_TIE] = K210_PC_MODE_IN, >>> + K210_PC_DEFAULT(OUT), >>> + K210_PC_DEFAULT(I2C), >>> + K210_PC_DEFAULT(SCCB), >>> + K210_PC_DEFAULT(SPI), >>> + K210_PC_DEFAULT(GPIO), >>> + [K210_PC_DEFAULT_INT13] = K210_PC_MODE_IN | K210_PC_PU, >>> +}; >>> + >>> +#undef DEFAULT >>> + >>> +/* >>> + * Pin functions configuration information. >>> + */ >>> +struct k210_pcf_info { >>> + char name[15]; >>> + u8 mode_id; >>> +}; >>> + >>> +#define K210_FUNC(id, mode) \ >>> + [K210_PCF_##id] = { \ >>> + .name = #id, \ >>> + .mode_id = K210_PC_DEFAULT_##mode \ >>> + } >>> + >>> +static const struct k210_pcf_info k210_pcf_infos[] = { >>> + K210_FUNC(JTAG_TCLK, IN), >>> + K210_FUNC(JTAG_TDI, IN), >>> + K210_FUNC(JTAG_TMS, IN), >>> + K210_FUNC(JTAG_TDO, OUT), >>> + K210_FUNC(SPI0_D0, SPI), >>> + K210_FUNC(SPI0_D1, SPI), >>> + K210_FUNC(SPI0_D2, SPI), >>> + K210_FUNC(SPI0_D3, SPI), >>> + K210_FUNC(SPI0_D4, SPI), >>> + K210_FUNC(SPI0_D5, SPI), >>> + K210_FUNC(SPI0_D6, SPI), >>> + K210_FUNC(SPI0_D7, SPI), >>> + K210_FUNC(SPI0_SS0, OUT), >>> + K210_FUNC(SPI0_SS1, OUT), >>> + K210_FUNC(SPI0_SS2, OUT), >>> + K210_FUNC(SPI0_SS3, OUT), >>> + K210_FUNC(SPI0_ARB, IN_TIE), >>> + K210_FUNC(SPI0_SCLK, OUT), >>> + K210_FUNC(UARTHS_RX, IN), >>> + K210_FUNC(UARTHS_TX, OUT), >>> + K210_FUNC(RESV6, IN), >>> + K210_FUNC(RESV7, IN), >>> + K210_FUNC(CLK_SPI1, OUT), >>> + K210_FUNC(CLK_I2C1, OUT), >>> + K210_FUNC(GPIOHS0, GPIO), >>> + K210_FUNC(GPIOHS1, GPIO), >>> + K210_FUNC(GPIOHS2, GPIO), >>> + K210_FUNC(GPIOHS3, GPIO), >>> + K210_FUNC(GPIOHS4, GPIO), >>> + K210_FUNC(GPIOHS5, GPIO), >>> + K210_FUNC(GPIOHS6, GPIO), >>> + K210_FUNC(GPIOHS7, GPIO), >>> + K210_FUNC(GPIOHS8, GPIO), >>> + K210_FUNC(GPIOHS9, GPIO), >>> + K210_FUNC(GPIOHS10, GPIO), >>> + K210_FUNC(GPIOHS11, GPIO), >>> + K210_FUNC(GPIOHS12, GPIO), >>> + K210_FUNC(GPIOHS13, GPIO), >>> + K210_FUNC(GPIOHS14, GPIO), >>> + K210_FUNC(GPIOHS15, GPIO), >>> + K210_FUNC(GPIOHS16, GPIO), >>> + K210_FUNC(GPIOHS17, GPIO), >>> + K210_FUNC(GPIOHS18, GPIO), >>> + K210_FUNC(GPIOHS19, GPIO), >>> + K210_FUNC(GPIOHS20, GPIO), >>> + K210_FUNC(GPIOHS21, GPIO), >>> + K210_FUNC(GPIOHS22, GPIO), >>> + K210_FUNC(GPIOHS23, GPIO), >>> + K210_FUNC(GPIOHS24, GPIO), >>> + K210_FUNC(GPIOHS25, GPIO), >>> + K210_FUNC(GPIOHS26, GPIO), >>> + K210_FUNC(GPIOHS27, GPIO), >>> + K210_FUNC(GPIOHS28, GPIO), >>> + K210_FUNC(GPIOHS29, GPIO), >>> + K210_FUNC(GPIOHS30, GPIO), >>> + K210_FUNC(GPIOHS31, GPIO), >>> + K210_FUNC(GPIO0, GPIO), >>> + K210_FUNC(GPIO1, GPIO), >>> + K210_FUNC(GPIO2, GPIO), >>> + K210_FUNC(GPIO3, GPIO), >>> + K210_FUNC(GPIO4, GPIO), >>> + K210_FUNC(GPIO5, GPIO), >>> + K210_FUNC(GPIO6, GPIO), >>> + K210_FUNC(GPIO7, GPIO), >>> + K210_FUNC(UART1_RX, IN), >>> + K210_FUNC(UART1_TX, OUT), >>> + K210_FUNC(UART2_RX, IN), >>> + K210_FUNC(UART2_TX, OUT), >>> + K210_FUNC(UART3_RX, IN), >>> + K210_FUNC(UART3_TX, OUT), >>> + K210_FUNC(SPI1_D0, SPI), >>> + K210_FUNC(SPI1_D1, SPI), >>> + K210_FUNC(SPI1_D2, SPI), >>> + K210_FUNC(SPI1_D3, SPI), >>> + K210_FUNC(SPI1_D4, SPI), >>> + K210_FUNC(SPI1_D5, SPI), >>> + K210_FUNC(SPI1_D6, SPI), >>> + K210_FUNC(SPI1_D7, SPI), >>> + K210_FUNC(SPI1_SS0, OUT), >>> + K210_FUNC(SPI1_SS1, OUT), >>> + K210_FUNC(SPI1_SS2, OUT), >>> + K210_FUNC(SPI1_SS3, OUT), >>> + K210_FUNC(SPI1_ARB, IN_TIE), >>> + K210_FUNC(SPI1_SCLK, OUT), >>> + K210_FUNC(SPI2_D0, SPI), >>> + K210_FUNC(SPI2_SS, IN), >>> + K210_FUNC(SPI2_SCLK, IN), >>> + K210_FUNC(I2S0_MCLK, OUT), >>> + K210_FUNC(I2S0_SCLK, OUT), >>> + K210_FUNC(I2S0_WS, OUT), >>> + K210_FUNC(I2S0_IN_D0, IN), >>> + K210_FUNC(I2S0_IN_D1, IN), >>> + K210_FUNC(I2S0_IN_D2, IN), >>> + K210_FUNC(I2S0_IN_D3, IN), >>> + K210_FUNC(I2S0_OUT_D0, OUT), >>> + K210_FUNC(I2S0_OUT_D1, OUT), >>> + K210_FUNC(I2S0_OUT_D2, OUT), >>> + K210_FUNC(I2S0_OUT_D3, OUT), >>> + K210_FUNC(I2S1_MCLK, OUT), >>> + K210_FUNC(I2S1_SCLK, OUT), >>> + K210_FUNC(I2S1_WS, OUT), >>> + K210_FUNC(I2S1_IN_D0, IN), >>> + K210_FUNC(I2S1_IN_D1, IN), >>> + K210_FUNC(I2S1_IN_D2, IN), >>> + K210_FUNC(I2S1_IN_D3, IN), >>> + K210_FUNC(I2S1_OUT_D0, OUT), >>> + K210_FUNC(I2S1_OUT_D1, OUT), >>> + K210_FUNC(I2S1_OUT_D2, OUT), >>> + K210_FUNC(I2S1_OUT_D3, OUT), >>> + K210_FUNC(I2S2_MCLK, OUT), >>> + K210_FUNC(I2S2_SCLK, OUT), >>> + K210_FUNC(I2S2_WS, OUT), >>> + K210_FUNC(I2S2_IN_D0, IN), >>> + K210_FUNC(I2S2_IN_D1, IN), >>> + K210_FUNC(I2S2_IN_D2, IN), >>> + K210_FUNC(I2S2_IN_D3, IN), >>> + K210_FUNC(I2S2_OUT_D0, OUT), >>> + K210_FUNC(I2S2_OUT_D1, OUT), >>> + K210_FUNC(I2S2_OUT_D2, OUT), >>> + K210_FUNC(I2S2_OUT_D3, OUT), >>> + K210_FUNC(RESV0, DISABLED), >>> + K210_FUNC(RESV1, DISABLED), >>> + K210_FUNC(RESV2, DISABLED), >>> + K210_FUNC(RESV3, DISABLED), >>> + K210_FUNC(RESV4, DISABLED), >>> + K210_FUNC(RESV5, DISABLED), >>> + K210_FUNC(I2C0_SCLK, I2C), >>> + K210_FUNC(I2C0_SDA, I2C), >>> + K210_FUNC(I2C1_SCLK, I2C), >>> + K210_FUNC(I2C1_SDA, I2C), >>> + K210_FUNC(I2C2_SCLK, I2C), >>> + K210_FUNC(I2C2_SDA, I2C), >>> + K210_FUNC(DVP_XCLK, OUT), >>> + K210_FUNC(DVP_RST, OUT), >>> + K210_FUNC(DVP_PWDN, OUT), >>> + K210_FUNC(DVP_VSYNC, IN), >>> + K210_FUNC(DVP_HSYNC, IN), >>> + K210_FUNC(DVP_PCLK, IN), >>> + K210_FUNC(DVP_D0, IN), >>> + K210_FUNC(DVP_D1, IN), >>> + K210_FUNC(DVP_D2, IN), >>> + K210_FUNC(DVP_D3, IN), >>> + K210_FUNC(DVP_D4, IN), >>> + K210_FUNC(DVP_D5, IN), >>> + K210_FUNC(DVP_D6, IN), >>> + K210_FUNC(DVP_D7, IN), >>> + K210_FUNC(SCCB_SCLK, SCCB), >>> + K210_FUNC(SCCB_SDA, SCCB), >>> + K210_FUNC(UART1_CTS, IN), >>> + K210_FUNC(UART1_DSR, IN), >>> + K210_FUNC(UART1_DCD, IN), >>> + K210_FUNC(UART1_RI, IN), >>> + K210_FUNC(UART1_SIR_IN, IN), >>> + K210_FUNC(UART1_DTR, OUT), >>> + K210_FUNC(UART1_RTS, OUT), >>> + K210_FUNC(UART1_OUT2, OUT), >>> + K210_FUNC(UART1_OUT1, OUT), >>> + K210_FUNC(UART1_SIR_OUT, OUT), >>> + K210_FUNC(UART1_BAUD, OUT), >>> + K210_FUNC(UART1_RE, OUT), >>> + K210_FUNC(UART1_DE, OUT), >>> + K210_FUNC(UART1_RS485_EN, OUT), >>> + K210_FUNC(UART2_CTS, IN), >>> + K210_FUNC(UART2_DSR, IN), >>> + K210_FUNC(UART2_DCD, IN), >>> + K210_FUNC(UART2_RI, IN), >>> + K210_FUNC(UART2_SIR_IN, IN), >>> + K210_FUNC(UART2_DTR, OUT), >>> + K210_FUNC(UART2_RTS, OUT), >>> + K210_FUNC(UART2_OUT2, OUT), >>> + K210_FUNC(UART2_OUT1, OUT), >>> + K210_FUNC(UART2_SIR_OUT, OUT), >>> + K210_FUNC(UART2_BAUD, OUT), >>> + K210_FUNC(UART2_RE, OUT), >>> + K210_FUNC(UART2_DE, OUT), >>> + K210_FUNC(UART2_RS485_EN, OUT), >>> + K210_FUNC(UART3_CTS, IN), >>> + K210_FUNC(UART3_DSR, IN), >>> + K210_FUNC(UART3_DCD, IN), >>> + K210_FUNC(UART3_RI, IN), >>> + K210_FUNC(UART3_SIR_IN, IN), >>> + K210_FUNC(UART3_DTR, OUT), >>> + K210_FUNC(UART3_RTS, OUT), >>> + K210_FUNC(UART3_OUT2, OUT), >>> + K210_FUNC(UART3_OUT1, OUT), >>> + K210_FUNC(UART3_SIR_OUT, OUT), >>> + K210_FUNC(UART3_BAUD, OUT), >>> + K210_FUNC(UART3_RE, OUT), >>> + K210_FUNC(UART3_DE, OUT), >>> + K210_FUNC(UART3_RS485_EN, OUT), >>> + K210_FUNC(TIMER0_TOGGLE1, OUT), >>> + K210_FUNC(TIMER0_TOGGLE2, OUT), >>> + K210_FUNC(TIMER0_TOGGLE3, OUT), >>> + K210_FUNC(TIMER0_TOGGLE4, OUT), >>> + K210_FUNC(TIMER1_TOGGLE1, OUT), >>> + K210_FUNC(TIMER1_TOGGLE2, OUT), >>> + K210_FUNC(TIMER1_TOGGLE3, OUT), >>> + K210_FUNC(TIMER1_TOGGLE4, OUT), >>> + K210_FUNC(TIMER2_TOGGLE1, OUT), >>> + K210_FUNC(TIMER2_TOGGLE2, OUT), >>> + K210_FUNC(TIMER2_TOGGLE3, OUT), >>> + K210_FUNC(TIMER2_TOGGLE4, OUT), >>> + K210_FUNC(CLK_SPI2, OUT), >>> + K210_FUNC(CLK_I2C2, OUT), >>> + K210_FUNC(INTERNAL0, OUT), >>> + K210_FUNC(INTERNAL1, OUT), >>> + K210_FUNC(INTERNAL2, OUT), >>> + K210_FUNC(INTERNAL3, OUT), >>> + K210_FUNC(INTERNAL4, OUT), >>> + K210_FUNC(INTERNAL5, OUT), >>> + K210_FUNC(INTERNAL6, OUT), >>> + K210_FUNC(INTERNAL7, OUT), >>> + K210_FUNC(INTERNAL8, OUT), >>> + K210_FUNC(INTERNAL9, IN), >>> + K210_FUNC(INTERNAL10, IN), >>> + K210_FUNC(INTERNAL11, IN), >>> + K210_FUNC(INTERNAL12, IN), >>> + K210_FUNC(INTERNAL13, INT13), >>> + K210_FUNC(INTERNAL14, I2C), >>> + K210_FUNC(INTERNAL15, IN), >>> + K210_FUNC(INTERNAL16, IN), >>> + K210_FUNC(INTERNAL17, IN), >>> + K210_FUNC(CONSTANT, DISABLED), >>> + K210_FUNC(INTERNAL18, IN), >>> + K210_FUNC(DEBUG0, OUT), >>> + K210_FUNC(DEBUG1, OUT), >>> + K210_FUNC(DEBUG2, OUT), >>> + K210_FUNC(DEBUG3, OUT), >>> + K210_FUNC(DEBUG4, OUT), >>> + K210_FUNC(DEBUG5, OUT), >>> + K210_FUNC(DEBUG6, OUT), >>> + K210_FUNC(DEBUG7, OUT), >>> + K210_FUNC(DEBUG8, OUT), >>> + K210_FUNC(DEBUG9, OUT), >>> + K210_FUNC(DEBUG10, OUT), >>> + K210_FUNC(DEBUG11, OUT), >>> + K210_FUNC(DEBUG12, OUT), >>> + K210_FUNC(DEBUG13, OUT), >>> + K210_FUNC(DEBUG14, OUT), >>> + K210_FUNC(DEBUG15, OUT), >>> + K210_FUNC(DEBUG16, OUT), >>> + K210_FUNC(DEBUG17, OUT), >>> + K210_FUNC(DEBUG18, OUT), >>> + K210_FUNC(DEBUG19, OUT), >>> + K210_FUNC(DEBUG20, OUT), >>> + K210_FUNC(DEBUG21, OUT), >>> + K210_FUNC(DEBUG22, OUT), >>> + K210_FUNC(DEBUG23, OUT), >>> + K210_FUNC(DEBUG24, OUT), >>> + K210_FUNC(DEBUG25, OUT), >>> + K210_FUNC(DEBUG26, OUT), >>> + K210_FUNC(DEBUG27, OUT), >>> + K210_FUNC(DEBUG28, OUT), >>> + K210_FUNC(DEBUG29, OUT), >>> + K210_FUNC(DEBUG30, OUT), >>> + K210_FUNC(DEBUG31, OUT), >>> +}; >>> + >>> +#define PIN_CONFIG_OUTPUT_INVERT (PIN_CONFIG_END + 1) >>> +#define PIN_CONFIG_INPUT_INVERT (PIN_CONFIG_END + 2) >>> + >>> +static const struct pinconf_generic_params k210_pinconf_custom_params[] = { >>> + { "output-polarity-invert", PIN_CONFIG_OUTPUT_INVERT, 1 }, >>> + { "input-polarity-invert", PIN_CONFIG_INPUT_INVERT, 1 }, >>> +}; >>> + >>> +/* >>> + * Max drive strength in uA. >>> + */ >>> +static const int k210_pinconf_drive_strength[] = { >>> + [0] = 11200, >>> + [1] = 16800, >>> + [2] = 22300, >>> + [3] = 27800, >>> + [4] = 33300, >>> + [5] = 38700, >>> + [6] = 44100, >>> + [7] = 49500, >>> +}; >>> + >>> +static int k210_pinconf_get_drive(unsigned int max_strength_ua) >>> +{ >>> + int i; >>> + >>> + for (i = K210_PC_DRIVE_MAX; i; i--) { >>> + if (k210_pinconf_drive_strength[i] <= max_strength_ua) >>> + return i; >>> + } >>> + >>> + return -EINVAL; >>> +} >>> + >>> +static void k210_pinmux_set_pin_function(struct pinctrl_dev *pctldev, >>> + u32 pin, u32 func) >>> +{ >>> + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); >>> + const struct k210_pcf_info *info = &k210_pcf_infos[func]; >>> + u32 mode = k210_pinconf_mode_id_to_mode[info->mode_id]; >>> + u32 val = func | mode; >>> + >>> + dev_dbg(pdata->dev, "set pin %u function %s (%u) -> 0x%08x\n", >>> + pin, info->name, func, val); >>> + >>> + writel(val, &pdata->fpioa->pins[pin]); >>> +} >>> + >>> +static int k210_pinconf_set_param(struct pinctrl_dev *pctldev, >>> + unsigned int pin, >>> + unsigned int param, unsigned int arg) >>> +{ >>> + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); >>> + u32 val = readl(&pdata->fpioa->pins[pin]); >>> + int drive; >>> + >>> + dev_dbg(pdata->dev, "set pin %u param %u, arg 0x%x\n", >>> + pin, param, arg); >>> + >>> + switch (param) { >>> + case PIN_CONFIG_BIAS_DISABLE: >>> + val &= ~K210_PC_BIAS_MASK; >>> + break; >>> + case PIN_CONFIG_BIAS_PULL_DOWN: >>> + if (!arg) >>> + return -EINVAL; >>> + val |= K210_PC_PD; >>> + break; >>> + case PIN_CONFIG_BIAS_PULL_UP: >>> + if (!arg) >>> + return -EINVAL; >>> + val |= K210_PC_PD; >>> + break; >>> + case PIN_CONFIG_DRIVE_STRENGTH: >>> + arg *= 1000; >>> + fallthrough; >>> + case PIN_CONFIG_DRIVE_STRENGTH_UA: >>> + drive = k210_pinconf_get_drive(arg); >>> + if (drive < 0) >>> + return drive; >>> + val &= ~K210_PC_DRIVE_MASK; >>> + val |= FIELD_PREP(K210_PC_DRIVE_MASK, drive); >>> + break; >>> + case PIN_CONFIG_INPUT_ENABLE: >>> + if (arg) >>> + val |= K210_PC_IE; >>> + else >>> + val &= ~K210_PC_IE; >>> + break; >>> + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: >>> + if (arg) >>> + val |= K210_PC_ST; >>> + else >>> + val &= ~K210_PC_ST; >>> + break; >>> + case PIN_CONFIG_OUTPUT: >>> + k210_pinmux_set_pin_function(pctldev, pin, K210_PCF_CONSTANT); >>> + val = readl(&pdata->fpioa->pins[pin]); >>> + val |= K210_PC_MODE_OUT; >>> + if (!arg) >>> + val |= K210_PC_DO_INV; >>> + break; >>> + case PIN_CONFIG_OUTPUT_ENABLE: >>> + if (arg) >>> + val |= K210_PC_OE; >>> + else >>> + val &= ~K210_PC_OE; >>> + break; >>> + case PIN_CONFIG_SLEW_RATE: >>> + if (arg) >>> + val |= K210_PC_SL; >>> + else >>> + val &= ~K210_PC_SL; >>> + break; >>> + case PIN_CONFIG_OUTPUT_INVERT: >>> + if (arg) >>> + val |= K210_PC_DO_INV; >>> + else >>> + val &= ~K210_PC_DO_INV; >>> + break; >>> + case PIN_CONFIG_INPUT_INVERT: >>> + if (arg) >>> + val |= K210_PC_DI_INV; >>> + else >>> + val &= ~K210_PC_DI_INV; >>> + break; >>> + default: >>> + return -EINVAL; >>> + } >>> + >>> + writel(val, &pdata->fpioa->pins[pin]); >>> + >>> + return 0; >>> +} >>> + >>> +static int k210_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, >>> + unsigned long *configs, unsigned int num_configs) >>> +{ >>> + unsigned int param, arg; >>> + int i, ret; >>> + >>> + if (WARN_ON(pin >= K210_NPINS)) >>> + return -EINVAL; >>> + >>> + for (i = 0; i < num_configs; i++) { >>> + param = pinconf_to_config_param(configs[i]); >>> + arg = pinconf_to_config_argument(configs[i]); >>> + ret = k210_pinconf_set_param(pctldev, pin, param, arg); >>> + if (ret) >>> + return ret; >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +static void k210_pinconf_dbg_show(struct pinctrl_dev *pctldev, >>> + struct seq_file *s, unsigned int pin) >>> +{ >>> + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); >>> + >>> + seq_printf(s, "%#x", readl(&pdata->fpioa->pins[pin])); >>> +} >>> + >>> +static int k210_pinconf_group_set(struct pinctrl_dev *pctldev, >>> + unsigned int selector, unsigned long *configs, >>> + unsigned int num_configs) >>> +{ >>> + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); >>> + unsigned int param, arg; >>> + u32 bit; >>> + int i; >>> + >>> + /* Pins should be configured with pinmux, not groups*/ >>> + if (selector < K210_NPINS) >>> + return -EINVAL; >>> + >>> + /* Otherwise it's a power domain */ >>> + for (i = 0; i < num_configs; i++) { >>> + param = pinconf_to_config_param(configs[i]); >>> + if (param != PIN_CONFIG_POWER_SOURCE) >>> + return -EINVAL; >>> + >>> + arg = pinconf_to_config_argument(configs[i]); >>> + bit = BIT(selector - K210_NPINS); >>> + regmap_update_bits(pdata->sysctl_map, >>> + pdata->power_offset, >>> + bit, arg ? bit : 0); >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +static void k210_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, >>> + struct seq_file *s, >>> + unsigned int selector) >>> +{ >>> + struct k210_fpioa_data *pdata = pinctrl_dev_get_drvdata(pctldev); >>> + int ret; >>> + u32 val; >>> + >>> + if (selector < K210_NPINS) >>> + return k210_pinconf_dbg_show(pctldev, s, selector); >>> + >>> + ret = regmap_read(pdata->sysctl_map, pdata->power_offset, &val); >>> + if (ret) { >>> + dev_err(pdata->dev, "Failed to read power reg\n"); >>> + return; >>> + } >>> + >>> + seq_printf(s, "%s: %s V", k210_group_names[selector], >>> + val & BIT(selector - K210_NPINS) ? "1.8" : "3.3"); >>> +} >>> + >>> +static const struct pinconf_ops k210_pinconf_ops = { >>> + .is_generic = true, >>> + .pin_config_set = k210_pinconf_set, >>> + .pin_config_group_set = k210_pinconf_group_set, >>> + .pin_config_dbg_show = k210_pinconf_dbg_show, >>> + .pin_config_group_dbg_show = k210_pinconf_group_dbg_show, >>> +}; >>> + >>> +static int k210_pinmux_get_function_count(struct pinctrl_dev *pctldev) >>> +{ >>> + return ARRAY_SIZE(k210_pcf_infos); >>> +} >>> + >>> +static const char *k210_pinmux_get_function_name(struct pinctrl_dev *pctldev, >>> + unsigned int selector) >>> +{ >>> + return k210_pcf_infos[selector].name; >>> +} >>> + >>> +static int k210_pinmux_get_function_groups(struct pinctrl_dev *pctldev, >>> + unsigned int selector, >>> + const char * const **groups, >>> + unsigned int * const num_groups) >>> +{ >>> + /* Any function can be mapped to any pin */ >>> + *groups = k210_group_names; >>> + *num_groups = K210_NPINS; >>> + >>> + return 0; >>> +} >>> + >>> +static int k210_pinmux_set_mux(struct pinctrl_dev *pctldev, >>> + unsigned int function, >>> + unsigned int group) >>> +{ >>> + /* Can't mux power domains */ >>> + if (group >= K210_NPINS) >>> + return -EINVAL; >>> + >>> + k210_pinmux_set_pin_function(pctldev, group, function); >>> + >>> + return 0; >>> +} >>> + >>> +static const struct pinmux_ops k210_pinmux_ops = { >>> + .get_functions_count = k210_pinmux_get_function_count, >>> + .get_function_name = k210_pinmux_get_function_name, >>> + .get_function_groups = k210_pinmux_get_function_groups, >>> + .set_mux = k210_pinmux_set_mux, >>> + .strict = true, >>> +}; >>> + >>> +static int k210_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) >>> +{ >>> + return K210_NGROUPS; >>> +} >>> + >>> +static const char *k210_pinctrl_get_group_name(struct pinctrl_dev *pctldev, >>> + unsigned int group) >>> +{ >>> + return k210_group_names[group]; >>> +} >>> + >>> +static int k210_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, >>> + unsigned int group, >>> + const unsigned int **pins, >>> + unsigned int *npins) >>> +{ >>> + if (group >= K210_NPINS) { >>> + *pins = NULL; >>> + *npins = 0; >>> + return 0; >>> + } >>> + >>> + *pins = &k210_pins[group].number; >>> + *npins = 1; >>> + >>> + return 0; >>> +} >>> + >>> +static void k210_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, >>> + struct seq_file *s, unsigned int offset) >>> +{ >>> + seq_printf(s, "%s", dev_name(pctldev->dev)); >>> +} >>> + >>> +static int k210_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, >>> + struct device_node *np, >>> + struct pinctrl_map **map, >>> + unsigned int *reserved_maps, >>> + unsigned int *num_maps) >>> +{ >>> + struct property *prop; >>> + const __be32 *p; >>> + int ret, pinmux_groups; >>> + u32 pinmux_group; >>> + unsigned long *configs = NULL; >>> + unsigned int num_configs = 0; >>> + unsigned int reserve = 0; >>> + >>> + ret = of_property_count_strings(np, "groups"); >>> + if (!ret) >>> + return pinconf_generic_dt_subnode_to_map(pctldev, np, map, >>> + reserved_maps, num_maps, >>> + PIN_MAP_TYPE_CONFIGS_GROUP); >>> + >>> + pinmux_groups = of_property_count_u32_elems(np, "pinmux"); >>> + if (pinmux_groups <= 0) { >>> + /* Ignore this node */ >>> + return 0; >>> + } >>> + >>> + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, >>> + &num_configs); >>> + if (ret < 0) { >>> + dev_err(pctldev->dev, "%pOF: could not parse node property\n", >>> + np); >>> + return ret; >>> + } >>> + >>> + reserve = pinmux_groups * (1 + num_configs); >>> + ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps, >>> + reserve); >>> + if (ret < 0) >>> + goto exit; >>> + >>> + of_property_for_each_u32(np, "pinmux", prop, p, pinmux_group) { >>> + const char *group_name, *func_name; >>> + u32 pin = FIELD_GET(K210_PG_PIN, pinmux_group); >>> + u32 func = FIELD_GET(K210_PG_FUNC, pinmux_group); >>> + >>> + if (pin >= K210_NPINS) { >>> + ret = -EINVAL; >>> + goto exit; >>> + } >>> + >>> + group_name = k210_group_names[pin]; >>> + func_name = k210_pcf_infos[func].name; >>> + >>> + dev_dbg(pctldev->dev, "Pinmux %s: pin %u func %s\n", >>> + np->name, pin, func_name); >>> + >>> + ret = pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, >>> + num_maps, group_name, >>> + func_name); >>> + if (ret < 0) { >>> + dev_err(pctldev->dev, "%pOF add mux map failed %d\n", >>> + np, ret); >>> + goto exit; >>> + } >>> + >>> + if (num_configs) { >>> + ret = pinctrl_utils_add_map_configs(pctldev, map, >>> + reserved_maps, num_maps, group_name, >>> + configs, num_configs, >>> + PIN_MAP_TYPE_CONFIGS_PIN); >>> + if (ret < 0) { >>> + dev_err(pctldev->dev, >>> + "%pOF add configs map failed %d\n", >>> + np, ret); >>> + goto exit; >>> + } >>> + } >>> + } >>> + >>> + ret = 0; >>> + >>> +exit: >>> + kfree(configs); >>> + return ret; >>> +} >>> + >>> +static int k210_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, >>> + struct device_node *np_config, >>> + struct pinctrl_map **map, >>> + unsigned int *num_maps) >>> +{ >>> + unsigned int reserved_maps; >>> + struct device_node *np; >>> + int ret; >>> + >>> + reserved_maps = 0; >>> + *map = NULL; >>> + *num_maps = 0; >>> + >>> + ret = k210_pinctrl_dt_subnode_to_map(pctldev, np_config, map, >>> + &reserved_maps, num_maps); >>> + if (ret < 0) >>> + goto err; >>> + >>> + for_each_available_child_of_node(np_config, np) { >>> + ret = k210_pinctrl_dt_subnode_to_map(pctldev, np, map, >>> + &reserved_maps, num_maps); >>> + if (ret < 0) >>> + goto err; >>> + } >>> + return 0; >>> + >>> +err: >>> + pinctrl_utils_free_map(pctldev, *map, *num_maps); >>> + return ret; >>> +} >>> + >>> + >>> +static const struct pinctrl_ops k210_pinctrl_ops = { >>> + .get_groups_count = k210_pinctrl_get_groups_count, >>> + .get_group_name = k210_pinctrl_get_group_name, >>> + .get_group_pins = k210_pinctrl_get_group_pins, >>> + .pin_dbg_show = k210_pinctrl_pin_dbg_show, >>> + .dt_node_to_map = k210_pinctrl_dt_node_to_map, >>> + .dt_free_map = pinconf_generic_dt_free_map, >>> +}; >>> + >>> +static struct pinctrl_desc k210_pinctrl_desc = { >>> + .name = "k210-pinctrl", >>> + .pins = k210_pins, >>> + .npins = K210_NPINS, >>> + .pctlops = &k210_pinctrl_ops, >>> + .pmxops = &k210_pinmux_ops, >>> + .confops = &k210_pinconf_ops, >>> + .custom_params = k210_pinconf_custom_params, >>> + .num_custom_params = ARRAY_SIZE(k210_pinconf_custom_params), >>> +}; >>> + >>> +static void k210_fpioa_init_ties(struct k210_fpioa_data *pdata) >>> +{ >>> + struct k210_fpioa __iomem *fpioa = pdata->fpioa; >>> + u32 val; >>> + int i, j; >>> + >>> + dev_dbg(pdata->dev, "Init pin ties\n"); >>> + >>> + /* Init pin functions input ties */ >>> + for (i = 0; i < ARRAY_SIZE(fpioa->tie_en); i++) { >>> + val = 0; >>> + for (j = 0; j < 32; j++) { >>> + if (k210_pcf_infos[i * 32 + j].mode_id == >>> + K210_PC_DEFAULT_IN_TIE) { >>> + dev_dbg(pdata->dev, >>> + "tie_en function %d (%s)\n", >>> + i * 32 + j, >>> + k210_pcf_infos[i * 32 + j].name); >>> + val |= BIT(j); >>> + } >>> + } >>> + >>> + /* Set value before enable */ >>> + writel(val, &fpioa->tie_val[i]); >>> + writel(val, &fpioa->tie_en[i]); >>> + } >>> +} >>> + >>> +static int k210_fpioa_probe(struct platform_device *pdev) >>> +{ >>> + struct device *dev = &pdev->dev; >>> + struct device_node *np = dev->of_node; >>> + struct k210_fpioa_data *pdata; >>> + int ret; >>> + >>> + dev_info(dev, "K210 FPIOA pin controller\n"); >>> + >>> + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); >>> + if (!pdata) >>> + return -ENOMEM; >>> + >>> + pdata->dev = dev; >>> + platform_set_drvdata(pdev, pdata); >>> + >>> + pdata->fpioa = devm_platform_ioremap_resource(pdev, 0); >>> + if (IS_ERR(pdata->fpioa)) >>> + return PTR_ERR(pdata->fpioa); >>> + >>> + pdata->clk = devm_clk_get(dev, "ref"); >>> + if (IS_ERR(pdata->clk)) >>> + return PTR_ERR(pdata->clk); >>> + >>> + ret = clk_prepare_enable(pdata->clk); >>> + if (ret) >>> + return ret; >>> + >>> + pdata->pclk = devm_clk_get_optional(dev, "pclk"); >>> + if (!IS_ERR(pdata->pclk)) >>> + clk_prepare_enable(pdata->pclk); >>> + >>> + pdata->sysctl_map = >>> + syscon_regmap_lookup_by_phandle_args(np, >>> + "canaan,k210-sysctl-power", >>> + 1, &pdata->power_offset); >>> + if (IS_ERR(pdata->sysctl_map)) >>> + return PTR_ERR(pdata->sysctl_map); >>> + >>> + k210_fpioa_init_ties(pdata); >>> + >>> + pdata->pctl = pinctrl_register(&k210_pinctrl_desc, dev, (void *)pdata); >>> + if (IS_ERR(pdata->pctl)) >>> + return PTR_ERR(pdata->pctl); >>> + >>> + return 0; >>> +} >>> + >>> +static const struct of_device_id k210_fpioa_dt_ids[] = { >>> + { .compatible = "canaan,k210-fpioa" }, >>> + { /* sentinel */ }, >>> +}; >>> + >>> +static struct platform_driver k210_fpioa_driver = { >>> + .probe = k210_fpioa_probe, >>> + .driver = { >>> + .name = "k210-fpioa", >>> + .of_match_table = k210_fpioa_dt_ids, >>> + }, >>> +}; >>> +builtin_platform_driver(k210_fpioa_driver); >> > > _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv