mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-14 15:23:07 +00:00
aa34e13346
Using bias-pull-up would actually cause the pin to have its pull-down
enabled. Fix this.
Original Linux patch by Sean Anderson:
https://lore.kernel.org/linux-gpio/20220209182822.640905-1-seanga2@gmail.com/
Fixes: 7224d5ccf8
("pinctrl: Add support for Kendryte K210 FPIOA")
Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com>
Reviewed-by: Sean Anderson <seanga2@gmail.com>
749 lines
19 KiB
C
749 lines
19 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright (C) 2020 Sean Anderson <seanga2@gmail.com>
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <clk.h>
|
|
#include <dm.h>
|
|
#include <dm/pinctrl.h>
|
|
#include <dt-bindings/pinctrl/k210-pinctrl.h>
|
|
#include <mapmem.h>
|
|
#include <regmap.h>
|
|
#include <syscon.h>
|
|
#include <asm/io.h>
|
|
#include <linux/err.h>
|
|
#include <linux/bitfield.h>
|
|
#include <linux/bitops.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 function-controlled Output Enable */
|
|
#define K210_PC_DO_OE BIT(14) /* set Data Out to the Output Enable signal */
|
|
#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 to prevent overshoot */
|
|
/* Same semantics as OE above */
|
|
#define K210_PC_IE BIT(20) /* Input Enable */
|
|
#define K210_PC_IE_INV BIT(21) /* INVert function-controlled 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)
|
|
|
|
#define PIN_CONFIG_OUTPUT_INVERT (PIN_CONFIG_END + 1)
|
|
#define PIN_CONFIG_INPUT_INVERT (PIN_CONFIG_END + 2)
|
|
|
|
struct k210_fpioa {
|
|
u32 pins[48];
|
|
u32 tie_en[8];
|
|
u32 tie_val[8];
|
|
};
|
|
|
|
struct k210_pc_priv {
|
|
struct clk clk;
|
|
struct k210_fpioa __iomem *fpioa; /* FPIOA register */
|
|
struct regmap *sysctl; /* Sysctl regmap */
|
|
u32 power_offset; /* Power bank register offset */
|
|
};
|
|
|
|
#ifdef CONFIG_CMD_PINMUX
|
|
static const char k210_pc_pin_names[][6] = {
|
|
#define PIN(i) \
|
|
[i] = "IO_" #i
|
|
PIN(0),
|
|
PIN(1),
|
|
PIN(2),
|
|
PIN(3),
|
|
PIN(4),
|
|
PIN(5),
|
|
PIN(6),
|
|
PIN(7),
|
|
PIN(8),
|
|
PIN(9),
|
|
PIN(10),
|
|
PIN(11),
|
|
PIN(12),
|
|
PIN(13),
|
|
PIN(14),
|
|
PIN(15),
|
|
PIN(16),
|
|
PIN(17),
|
|
PIN(18),
|
|
PIN(19),
|
|
PIN(20),
|
|
PIN(21),
|
|
PIN(22),
|
|
PIN(23),
|
|
PIN(24),
|
|
PIN(25),
|
|
PIN(26),
|
|
PIN(27),
|
|
PIN(28),
|
|
PIN(29),
|
|
PIN(30),
|
|
PIN(31),
|
|
PIN(32),
|
|
PIN(33),
|
|
PIN(34),
|
|
PIN(35),
|
|
PIN(36),
|
|
PIN(37),
|
|
PIN(38),
|
|
PIN(39),
|
|
PIN(40),
|
|
PIN(41),
|
|
PIN(42),
|
|
PIN(43),
|
|
PIN(44),
|
|
PIN(45),
|
|
PIN(46),
|
|
PIN(47),
|
|
#undef PIN
|
|
};
|
|
|
|
static int k210_pc_get_pins_count(struct udevice *dev)
|
|
{
|
|
return ARRAY_SIZE(k210_pc_pin_names);
|
|
};
|
|
|
|
static const char *k210_pc_get_pin_name(struct udevice *dev, unsigned selector)
|
|
{
|
|
return k210_pc_pin_names[selector];
|
|
}
|
|
#endif /* CONFIG_CMD_PINMUX */
|
|
|
|
/* These are just power domains */
|
|
static const char k210_pc_group_names[][3] = {
|
|
[0] = "A0",
|
|
[1] = "A1",
|
|
[2] = "A2",
|
|
[3] = "B3",
|
|
[4] = "B4",
|
|
[5] = "B5",
|
|
[6] = "C6",
|
|
[7] = "C7",
|
|
};
|
|
|
|
static int k210_pc_get_groups_count(struct udevice *dev)
|
|
{
|
|
return ARRAY_SIZE(k210_pc_group_names);
|
|
}
|
|
|
|
static const char *k210_pc_get_group_name(struct udevice *dev,
|
|
unsigned selector)
|
|
{
|
|
return k210_pc_group_names[selector];
|
|
}
|
|
|
|
enum k210_pc_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,
|
|
};
|
|
|
|
static const u32 k210_pc_mode_id_to_mode[] = {
|
|
#define DEFAULT(mode) \
|
|
[K210_PC_DEFAULT_##mode] = K210_PC_MODE_##mode
|
|
[K210_PC_DEFAULT_DISABLED] = 0,
|
|
DEFAULT(IN),
|
|
[K210_PC_DEFAULT_IN_TIE] = K210_PC_MODE_IN,
|
|
DEFAULT(OUT),
|
|
DEFAULT(I2C),
|
|
DEFAULT(SCCB),
|
|
DEFAULT(SPI),
|
|
DEFAULT(GPIO),
|
|
[K210_PC_DEFAULT_INT13] = K210_PC_MODE_IN | K210_PC_PU,
|
|
#undef DEFAULT
|
|
};
|
|
|
|
/* This saves around 2K vs having a pointer+mode */
|
|
struct k210_pcf_info {
|
|
#ifdef CONFIG_CMD_PINMUX
|
|
char name[15];
|
|
#endif
|
|
u8 mode_id;
|
|
};
|
|
|
|
static const struct k210_pcf_info k210_pcf_infos[] = {
|
|
#ifdef CONFIG_CMD_PINMUX
|
|
#define FUNC(id, mode) \
|
|
[K210_PCF_##id] = { \
|
|
.name = #id, \
|
|
.mode_id = K210_PC_DEFAULT_##mode \
|
|
}
|
|
#else
|
|
#define FUNC(id, mode) \
|
|
[K210_PCF_##id] = { \
|
|
.mode_id = K210_PC_DEFAULT_##mode \
|
|
}
|
|
#endif
|
|
FUNC(JTAG_TCLK, IN),
|
|
FUNC(JTAG_TDI, IN),
|
|
FUNC(JTAG_TMS, IN),
|
|
FUNC(JTAG_TDO, OUT),
|
|
FUNC(SPI0_D0, SPI),
|
|
FUNC(SPI0_D1, SPI),
|
|
FUNC(SPI0_D2, SPI),
|
|
FUNC(SPI0_D3, SPI),
|
|
FUNC(SPI0_D4, SPI),
|
|
FUNC(SPI0_D5, SPI),
|
|
FUNC(SPI0_D6, SPI),
|
|
FUNC(SPI0_D7, SPI),
|
|
FUNC(SPI0_SS0, OUT),
|
|
FUNC(SPI0_SS1, OUT),
|
|
FUNC(SPI0_SS2, OUT),
|
|
FUNC(SPI0_SS3, OUT),
|
|
FUNC(SPI0_ARB, IN_TIE),
|
|
FUNC(SPI0_SCLK, OUT),
|
|
FUNC(UARTHS_RX, IN),
|
|
FUNC(UARTHS_TX, OUT),
|
|
FUNC(RESV6, IN),
|
|
FUNC(RESV7, IN),
|
|
FUNC(CLK_SPI1, OUT),
|
|
FUNC(CLK_I2C1, OUT),
|
|
FUNC(GPIOHS0, GPIO),
|
|
FUNC(GPIOHS1, GPIO),
|
|
FUNC(GPIOHS2, GPIO),
|
|
FUNC(GPIOHS3, GPIO),
|
|
FUNC(GPIOHS4, GPIO),
|
|
FUNC(GPIOHS5, GPIO),
|
|
FUNC(GPIOHS6, GPIO),
|
|
FUNC(GPIOHS7, GPIO),
|
|
FUNC(GPIOHS8, GPIO),
|
|
FUNC(GPIOHS9, GPIO),
|
|
FUNC(GPIOHS10, GPIO),
|
|
FUNC(GPIOHS11, GPIO),
|
|
FUNC(GPIOHS12, GPIO),
|
|
FUNC(GPIOHS13, GPIO),
|
|
FUNC(GPIOHS14, GPIO),
|
|
FUNC(GPIOHS15, GPIO),
|
|
FUNC(GPIOHS16, GPIO),
|
|
FUNC(GPIOHS17, GPIO),
|
|
FUNC(GPIOHS18, GPIO),
|
|
FUNC(GPIOHS19, GPIO),
|
|
FUNC(GPIOHS20, GPIO),
|
|
FUNC(GPIOHS21, GPIO),
|
|
FUNC(GPIOHS22, GPIO),
|
|
FUNC(GPIOHS23, GPIO),
|
|
FUNC(GPIOHS24, GPIO),
|
|
FUNC(GPIOHS25, GPIO),
|
|
FUNC(GPIOHS26, GPIO),
|
|
FUNC(GPIOHS27, GPIO),
|
|
FUNC(GPIOHS28, GPIO),
|
|
FUNC(GPIOHS29, GPIO),
|
|
FUNC(GPIOHS30, GPIO),
|
|
FUNC(GPIOHS31, GPIO),
|
|
FUNC(GPIO0, GPIO),
|
|
FUNC(GPIO1, GPIO),
|
|
FUNC(GPIO2, GPIO),
|
|
FUNC(GPIO3, GPIO),
|
|
FUNC(GPIO4, GPIO),
|
|
FUNC(GPIO5, GPIO),
|
|
FUNC(GPIO6, GPIO),
|
|
FUNC(GPIO7, GPIO),
|
|
FUNC(UART1_RX, IN),
|
|
FUNC(UART1_TX, OUT),
|
|
FUNC(UART2_RX, IN),
|
|
FUNC(UART2_TX, OUT),
|
|
FUNC(UART3_RX, IN),
|
|
FUNC(UART3_TX, OUT),
|
|
FUNC(SPI1_D0, SPI),
|
|
FUNC(SPI1_D1, SPI),
|
|
FUNC(SPI1_D2, SPI),
|
|
FUNC(SPI1_D3, SPI),
|
|
FUNC(SPI1_D4, SPI),
|
|
FUNC(SPI1_D5, SPI),
|
|
FUNC(SPI1_D6, SPI),
|
|
FUNC(SPI1_D7, SPI),
|
|
FUNC(SPI1_SS0, OUT),
|
|
FUNC(SPI1_SS1, OUT),
|
|
FUNC(SPI1_SS2, OUT),
|
|
FUNC(SPI1_SS3, OUT),
|
|
FUNC(SPI1_ARB, IN_TIE),
|
|
FUNC(SPI1_SCLK, OUT),
|
|
FUNC(SPI2_D0, SPI),
|
|
FUNC(SPI2_SS, IN),
|
|
FUNC(SPI2_SCLK, IN),
|
|
FUNC(I2S0_MCLK, OUT),
|
|
FUNC(I2S0_SCLK, OUT),
|
|
FUNC(I2S0_WS, OUT),
|
|
FUNC(I2S0_IN_D0, IN),
|
|
FUNC(I2S0_IN_D1, IN),
|
|
FUNC(I2S0_IN_D2, IN),
|
|
FUNC(I2S0_IN_D3, IN),
|
|
FUNC(I2S0_OUT_D0, OUT),
|
|
FUNC(I2S0_OUT_D1, OUT),
|
|
FUNC(I2S0_OUT_D2, OUT),
|
|
FUNC(I2S0_OUT_D3, OUT),
|
|
FUNC(I2S1_MCLK, OUT),
|
|
FUNC(I2S1_SCLK, OUT),
|
|
FUNC(I2S1_WS, OUT),
|
|
FUNC(I2S1_IN_D0, IN),
|
|
FUNC(I2S1_IN_D1, IN),
|
|
FUNC(I2S1_IN_D2, IN),
|
|
FUNC(I2S1_IN_D3, IN),
|
|
FUNC(I2S1_OUT_D0, OUT),
|
|
FUNC(I2S1_OUT_D1, OUT),
|
|
FUNC(I2S1_OUT_D2, OUT),
|
|
FUNC(I2S1_OUT_D3, OUT),
|
|
FUNC(I2S2_MCLK, OUT),
|
|
FUNC(I2S2_SCLK, OUT),
|
|
FUNC(I2S2_WS, OUT),
|
|
FUNC(I2S2_IN_D0, IN),
|
|
FUNC(I2S2_IN_D1, IN),
|
|
FUNC(I2S2_IN_D2, IN),
|
|
FUNC(I2S2_IN_D3, IN),
|
|
FUNC(I2S2_OUT_D0, OUT),
|
|
FUNC(I2S2_OUT_D1, OUT),
|
|
FUNC(I2S2_OUT_D2, OUT),
|
|
FUNC(I2S2_OUT_D3, OUT),
|
|
FUNC(RESV0, DISABLED),
|
|
FUNC(RESV1, DISABLED),
|
|
FUNC(RESV2, DISABLED),
|
|
FUNC(RESV3, DISABLED),
|
|
FUNC(RESV4, DISABLED),
|
|
FUNC(RESV5, DISABLED),
|
|
FUNC(I2C0_SCLK, I2C),
|
|
FUNC(I2C0_SDA, I2C),
|
|
FUNC(I2C1_SCLK, I2C),
|
|
FUNC(I2C1_SDA, I2C),
|
|
FUNC(I2C2_SCLK, I2C),
|
|
FUNC(I2C2_SDA, I2C),
|
|
FUNC(DVP_XCLK, OUT),
|
|
FUNC(DVP_RST, OUT),
|
|
FUNC(DVP_PWDN, OUT),
|
|
FUNC(DVP_VSYNC, IN),
|
|
FUNC(DVP_HSYNC, IN),
|
|
FUNC(DVP_PCLK, IN),
|
|
FUNC(DVP_D0, IN),
|
|
FUNC(DVP_D1, IN),
|
|
FUNC(DVP_D2, IN),
|
|
FUNC(DVP_D3, IN),
|
|
FUNC(DVP_D4, IN),
|
|
FUNC(DVP_D5, IN),
|
|
FUNC(DVP_D6, IN),
|
|
FUNC(DVP_D7, IN),
|
|
FUNC(SCCB_SCLK, SCCB),
|
|
FUNC(SCCB_SDA, SCCB),
|
|
FUNC(UART1_CTS, IN),
|
|
FUNC(UART1_DSR, IN),
|
|
FUNC(UART1_DCD, IN),
|
|
FUNC(UART1_RI, IN),
|
|
FUNC(UART1_SIR_IN, IN),
|
|
FUNC(UART1_DTR, OUT),
|
|
FUNC(UART1_RTS, OUT),
|
|
FUNC(UART1_OUT2, OUT),
|
|
FUNC(UART1_OUT1, OUT),
|
|
FUNC(UART1_SIR_OUT, OUT),
|
|
FUNC(UART1_BAUD, OUT),
|
|
FUNC(UART1_RE, OUT),
|
|
FUNC(UART1_DE, OUT),
|
|
FUNC(UART1_RS485_EN, OUT),
|
|
FUNC(UART2_CTS, IN),
|
|
FUNC(UART2_DSR, IN),
|
|
FUNC(UART2_DCD, IN),
|
|
FUNC(UART2_RI, IN),
|
|
FUNC(UART2_SIR_IN, IN),
|
|
FUNC(UART2_DTR, OUT),
|
|
FUNC(UART2_RTS, OUT),
|
|
FUNC(UART2_OUT2, OUT),
|
|
FUNC(UART2_OUT1, OUT),
|
|
FUNC(UART2_SIR_OUT, OUT),
|
|
FUNC(UART2_BAUD, OUT),
|
|
FUNC(UART2_RE, OUT),
|
|
FUNC(UART2_DE, OUT),
|
|
FUNC(UART2_RS485_EN, OUT),
|
|
FUNC(UART3_CTS, IN),
|
|
FUNC(UART3_DSR, IN),
|
|
FUNC(UART3_DCD, IN),
|
|
FUNC(UART3_RI, IN),
|
|
FUNC(UART3_SIR_IN, IN),
|
|
FUNC(UART3_DTR, OUT),
|
|
FUNC(UART3_RTS, OUT),
|
|
FUNC(UART3_OUT2, OUT),
|
|
FUNC(UART3_OUT1, OUT),
|
|
FUNC(UART3_SIR_OUT, OUT),
|
|
FUNC(UART3_BAUD, OUT),
|
|
FUNC(UART3_RE, OUT),
|
|
FUNC(UART3_DE, OUT),
|
|
FUNC(UART3_RS485_EN, OUT),
|
|
FUNC(TIMER0_TOGGLE1, OUT),
|
|
FUNC(TIMER0_TOGGLE2, OUT),
|
|
FUNC(TIMER0_TOGGLE3, OUT),
|
|
FUNC(TIMER0_TOGGLE4, OUT),
|
|
FUNC(TIMER1_TOGGLE1, OUT),
|
|
FUNC(TIMER1_TOGGLE2, OUT),
|
|
FUNC(TIMER1_TOGGLE3, OUT),
|
|
FUNC(TIMER1_TOGGLE4, OUT),
|
|
FUNC(TIMER2_TOGGLE1, OUT),
|
|
FUNC(TIMER2_TOGGLE2, OUT),
|
|
FUNC(TIMER2_TOGGLE3, OUT),
|
|
FUNC(TIMER2_TOGGLE4, OUT),
|
|
FUNC(CLK_SPI2, OUT),
|
|
FUNC(CLK_I2C2, OUT),
|
|
FUNC(INTERNAL0, OUT),
|
|
FUNC(INTERNAL1, OUT),
|
|
FUNC(INTERNAL2, OUT),
|
|
FUNC(INTERNAL3, OUT),
|
|
FUNC(INTERNAL4, OUT),
|
|
FUNC(INTERNAL5, OUT),
|
|
FUNC(INTERNAL6, OUT),
|
|
FUNC(INTERNAL7, OUT),
|
|
FUNC(INTERNAL8, OUT),
|
|
FUNC(INTERNAL9, IN),
|
|
FUNC(INTERNAL10, IN),
|
|
FUNC(INTERNAL11, IN),
|
|
FUNC(INTERNAL12, IN),
|
|
FUNC(INTERNAL13, INT13),
|
|
FUNC(INTERNAL14, I2C),
|
|
FUNC(INTERNAL15, IN),
|
|
FUNC(INTERNAL16, IN),
|
|
FUNC(INTERNAL17, IN),
|
|
FUNC(CONSTANT, DISABLED),
|
|
FUNC(INTERNAL18, IN),
|
|
FUNC(DEBUG0, OUT),
|
|
FUNC(DEBUG1, OUT),
|
|
FUNC(DEBUG2, OUT),
|
|
FUNC(DEBUG3, OUT),
|
|
FUNC(DEBUG4, OUT),
|
|
FUNC(DEBUG5, OUT),
|
|
FUNC(DEBUG6, OUT),
|
|
FUNC(DEBUG7, OUT),
|
|
FUNC(DEBUG8, OUT),
|
|
FUNC(DEBUG9, OUT),
|
|
FUNC(DEBUG10, OUT),
|
|
FUNC(DEBUG11, OUT),
|
|
FUNC(DEBUG12, OUT),
|
|
FUNC(DEBUG13, OUT),
|
|
FUNC(DEBUG14, OUT),
|
|
FUNC(DEBUG15, OUT),
|
|
FUNC(DEBUG16, OUT),
|
|
FUNC(DEBUG17, OUT),
|
|
FUNC(DEBUG18, OUT),
|
|
FUNC(DEBUG19, OUT),
|
|
FUNC(DEBUG20, OUT),
|
|
FUNC(DEBUG21, OUT),
|
|
FUNC(DEBUG22, OUT),
|
|
FUNC(DEBUG23, OUT),
|
|
FUNC(DEBUG24, OUT),
|
|
FUNC(DEBUG25, OUT),
|
|
FUNC(DEBUG26, OUT),
|
|
FUNC(DEBUG27, OUT),
|
|
FUNC(DEBUG28, OUT),
|
|
FUNC(DEBUG29, OUT),
|
|
FUNC(DEBUG30, OUT),
|
|
FUNC(DEBUG31, OUT),
|
|
#undef FUNC
|
|
};
|
|
|
|
static int k210_pc_pinmux_set(struct udevice *dev, u32 pinmux_group)
|
|
{
|
|
unsigned pin = FIELD_GET(K210_PG_PIN, pinmux_group);
|
|
bool do_oe = FIELD_GET(K210_PG_DO, pinmux_group);
|
|
unsigned func = FIELD_GET(K210_PG_FUNC, pinmux_group);
|
|
struct k210_pc_priv *priv = dev_get_priv(dev);
|
|
const struct k210_pcf_info *info = &k210_pcf_infos[func];
|
|
u32 mode = k210_pc_mode_id_to_mode[info->mode_id];
|
|
u32 val = func | mode | (do_oe ? K210_PC_DO_OE : 0);
|
|
|
|
debug("%s(%.8x): IO_%.2u = %3u | %.8x\n", __func__, pinmux_group, pin,
|
|
func, mode);
|
|
|
|
writel(val, &priv->fpioa->pins[pin]);
|
|
return pin;
|
|
}
|
|
|
|
/* Max drive strength in uA */
|
|
static const int k210_pc_drive_strength[] = {
|
|
[0] = 11200,
|
|
[1] = 16800,
|
|
[2] = 22300,
|
|
[3] = 27800,
|
|
[4] = 33300,
|
|
[5] = 38700,
|
|
[6] = 44100,
|
|
[7] = 49500,
|
|
};
|
|
|
|
static int k210_pc_get_drive(unsigned max_strength_ua)
|
|
{
|
|
int i;
|
|
|
|
for (i = K210_PC_DRIVE_MAX; i >= 0; i--)
|
|
if (k210_pc_drive_strength[i] < max_strength_ua)
|
|
return i;
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int k210_pc_pinconf_set(struct udevice *dev, unsigned pin_selector,
|
|
unsigned param, unsigned argument)
|
|
{
|
|
struct k210_pc_priv *priv = dev_get_priv(dev);
|
|
u32 val = readl(&priv->fpioa->pins[pin_selector]);
|
|
|
|
switch (param) {
|
|
case PIN_CONFIG_BIAS_DISABLE:
|
|
val &= ~K210_PC_BIAS_MASK;
|
|
break;
|
|
case PIN_CONFIG_BIAS_PULL_DOWN:
|
|
if (argument)
|
|
val |= K210_PC_PD;
|
|
else
|
|
return -EINVAL;
|
|
break;
|
|
case PIN_CONFIG_BIAS_PULL_UP:
|
|
if (argument)
|
|
val |= K210_PC_PU;
|
|
else
|
|
return -EINVAL;
|
|
break;
|
|
case PIN_CONFIG_DRIVE_STRENGTH:
|
|
argument *= 1000;
|
|
case PIN_CONFIG_DRIVE_STRENGTH_UA: {
|
|
int drive = k210_pc_get_drive(argument);
|
|
|
|
if (IS_ERR_VALUE(drive))
|
|
return drive;
|
|
val &= ~K210_PC_DRIVE_MASK;
|
|
val |= FIELD_PREP(K210_PC_DRIVE_MASK, drive);
|
|
break;
|
|
}
|
|
case PIN_CONFIG_INPUT_ENABLE:
|
|
if (argument)
|
|
val |= K210_PC_IE;
|
|
else
|
|
val &= ~K210_PC_IE;
|
|
break;
|
|
case PIN_CONFIG_INPUT_SCHMITT:
|
|
argument = 1;
|
|
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
|
|
if (argument)
|
|
val |= K210_PC_ST;
|
|
else
|
|
val &= ~K210_PC_ST;
|
|
break;
|
|
case PIN_CONFIG_OUTPUT:
|
|
k210_pc_pinmux_set(dev,
|
|
K210_FPIOA(pin_selector, K210_PCF_CONSTANT));
|
|
val = readl(&priv->fpioa->pins[pin_selector]);
|
|
val |= K210_PC_MODE_OUT;
|
|
|
|
if (!argument)
|
|
val |= K210_PC_DO_INV;
|
|
break;
|
|
case PIN_CONFIG_OUTPUT_ENABLE:
|
|
if (argument)
|
|
val |= K210_PC_OE;
|
|
else
|
|
val &= ~K210_PC_OE;
|
|
break;
|
|
case PIN_CONFIG_SLEW_RATE:
|
|
if (argument)
|
|
val |= K210_PC_SL;
|
|
else
|
|
val &= ~K210_PC_SL;
|
|
break;
|
|
case PIN_CONFIG_OUTPUT_INVERT:
|
|
if (argument)
|
|
val |= K210_PC_DO_INV;
|
|
else
|
|
val &= ~K210_PC_DO_INV;
|
|
break;
|
|
case PIN_CONFIG_INPUT_INVERT:
|
|
if (argument)
|
|
val |= K210_PC_DI_INV;
|
|
else
|
|
val &= ~K210_PC_DI_INV;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
writel(val, &priv->fpioa->pins[pin_selector]);
|
|
return 0;
|
|
}
|
|
|
|
static int k210_pc_pinconf_group_set(struct udevice *dev,
|
|
unsigned group_selector, unsigned param,
|
|
unsigned argument)
|
|
{
|
|
struct k210_pc_priv *priv = dev_get_priv(dev);
|
|
|
|
if (param == PIN_CONFIG_POWER_SOURCE) {
|
|
u32 bit = BIT(group_selector);
|
|
|
|
regmap_update_bits(priv->sysctl, priv->power_offset, bit,
|
|
argument ? bit : 0);
|
|
} else {
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_CMD_PINMUX
|
|
static int k210_pc_get_pin_muxing(struct udevice *dev, unsigned int selector,
|
|
char *buf, int size)
|
|
{
|
|
struct k210_pc_priv *priv = dev_get_priv(dev);
|
|
u32 val = readl(&priv->fpioa->pins[selector]);
|
|
const struct k210_pcf_info *info = &k210_pcf_infos[val & K210_PCF_MASK];
|
|
|
|
strncpy(buf, info->name, min((size_t)size, sizeof(info->name)));
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static const struct pinconf_param k210_pc_pinconf_params[] = {
|
|
{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
|
|
{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
|
|
{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
|
|
{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, U32_MAX },
|
|
{ "drive-strength-ua", PIN_CONFIG_DRIVE_STRENGTH_UA, U32_MAX },
|
|
{ "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
|
|
{ "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
|
|
{ "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
|
|
{ "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
|
|
{ "power-source", PIN_CONFIG_POWER_SOURCE, K210_PC_POWER_1V8 },
|
|
{ "output-low", PIN_CONFIG_OUTPUT, 0 },
|
|
{ "output-high", PIN_CONFIG_OUTPUT, 1 },
|
|
{ "output-enable", PIN_CONFIG_OUTPUT_ENABLE, 1 },
|
|
{ "output-disable", PIN_CONFIG_OUTPUT_ENABLE, 0 },
|
|
{ "slew-rate", PIN_CONFIG_SLEW_RATE, 1 },
|
|
{ "output-polarity-invert", PIN_CONFIG_OUTPUT_INVERT, 1},
|
|
{ "input-polarity-invert", PIN_CONFIG_INPUT_INVERT, 1},
|
|
};
|
|
|
|
static const struct pinctrl_ops k210_pc_pinctrl_ops = {
|
|
#ifdef CONFIG_CMD_PINMUX
|
|
.get_pins_count = k210_pc_get_pins_count,
|
|
.get_pin_name = k210_pc_get_pin_name,
|
|
#endif
|
|
.get_groups_count = k210_pc_get_groups_count,
|
|
.get_group_name = k210_pc_get_group_name,
|
|
.pinmux_property_set = k210_pc_pinmux_set,
|
|
.pinconf_num_params = ARRAY_SIZE(k210_pc_pinconf_params),
|
|
.pinconf_params = k210_pc_pinconf_params,
|
|
.pinconf_set = k210_pc_pinconf_set,
|
|
.pinconf_group_set = k210_pc_pinconf_group_set,
|
|
.set_state = pinctrl_generic_set_state,
|
|
#ifdef CONFIG_CMD_PINMUX
|
|
.get_pin_muxing = k210_pc_get_pin_muxing,
|
|
#endif
|
|
};
|
|
|
|
static int k210_pc_probe(struct udevice *dev)
|
|
{
|
|
int ret, i, j;
|
|
struct k210_pc_priv *priv = dev_get_priv(dev);
|
|
struct ofnode_phandle_args args;
|
|
|
|
priv->fpioa = dev_read_addr_ptr(dev);
|
|
if (!priv->fpioa)
|
|
return -EINVAL;
|
|
|
|
ret = clk_get_by_index(dev, 0, &priv->clk);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = clk_enable(&priv->clk);
|
|
if (ret && ret != -ENOSYS && ret != -ENOTSUPP)
|
|
goto err;
|
|
|
|
ret = dev_read_phandle_with_args(dev, "canaan,k210-sysctl-power",
|
|
NULL, 1, 0, &args);
|
|
if (ret)
|
|
goto err;
|
|
|
|
if (args.args_count != 1) {
|
|
ret = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
priv->sysctl = syscon_node_to_regmap(args.node);
|
|
if (IS_ERR(priv->sysctl)) {
|
|
ret = PTR_ERR(priv->sysctl);
|
|
goto err;
|
|
}
|
|
|
|
priv->power_offset = args.args[0];
|
|
|
|
debug("%s: fpioa = %p sysctl = %p power offset = %x\n", __func__,
|
|
priv->fpioa, (void *)priv->sysctl->ranges[0].start,
|
|
priv->power_offset);
|
|
|
|
/* Init input ties */
|
|
for (i = 0; i < ARRAY_SIZE(priv->fpioa->tie_en); i++) {
|
|
u32 val = 0;
|
|
|
|
for (j = 0; j < 32; j++)
|
|
if (k210_pcf_infos[i * 32 + j].mode_id ==
|
|
K210_PC_DEFAULT_IN_TIE)
|
|
val |= BIT(j);
|
|
writel(val, &priv->fpioa->tie_en[i]);
|
|
writel(val, &priv->fpioa->tie_val[i]);
|
|
}
|
|
|
|
return 0;
|
|
|
|
err:
|
|
clk_free(&priv->clk);
|
|
return ret;
|
|
}
|
|
|
|
static const struct udevice_id k210_pc_ids[] = {
|
|
{ .compatible = "canaan,k210-fpioa" },
|
|
{ }
|
|
};
|
|
|
|
U_BOOT_DRIVER(pinctrl_k210) = {
|
|
.name = "pinctrl_k210",
|
|
.id = UCLASS_PINCTRL,
|
|
.of_match = k210_pc_ids,
|
|
.probe = k210_pc_probe,
|
|
.priv_auto = sizeof(struct k210_pc_priv),
|
|
.ops = &k210_pc_pinctrl_ops,
|
|
};
|