mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
pinctrl: ambarella: add CV75 pin controller
Add an Ambarella pinmux-only pinctrl driver with CV75 function/group tables. GPIO is handled by the PL061 driver. Signed-off-by: Long Zhao <longzhao@ambarella.com> Signed-off-by: Linus Walleij <linusw@kernel.org>
This commit is contained in:
parent
c1fb14e022
commit
b40e9d140c
|
|
@ -37,6 +37,23 @@ config DEBUG_PINCTRL
|
||||||
help
|
help
|
||||||
Say Y here to add some extra checks and diagnostics to PINCTRL calls.
|
Say Y here to add some extra checks and diagnostics to PINCTRL calls.
|
||||||
|
|
||||||
|
config PINCTRL_AMB
|
||||||
|
bool "Ambarella pin controller support"
|
||||||
|
depends on ARCH_AMBARELLA || COMPILE_TEST
|
||||||
|
depends on HAS_IOMEM
|
||||||
|
default y if ARCH_AMBARELLA
|
||||||
|
select GENERIC_PINCONF
|
||||||
|
select GENERIC_PINCTRL_GROUPS
|
||||||
|
select GENERIC_PINMUX_FUNCTIONS
|
||||||
|
select GPIOLIB
|
||||||
|
select GPIO_PL061
|
||||||
|
select MFD_SYSCON
|
||||||
|
select PINCONF
|
||||||
|
select PINMUX
|
||||||
|
help
|
||||||
|
Say Y here to enable the Ambarella pinmux/pinconf controller.
|
||||||
|
GPIO is provided by the PL061 driver.
|
||||||
|
|
||||||
config PINCTRL_AMD
|
config PINCTRL_AMD
|
||||||
bool "AMD GPIO pin control"
|
bool "AMD GPIO pin control"
|
||||||
depends on HAS_IOMEM
|
depends on HAS_IOMEM
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
|
||||||
obj-$(CONFIG_GENERIC_PINCTRL) += pinctrl-generic.o
|
obj-$(CONFIG_GENERIC_PINCTRL) += pinctrl-generic.o
|
||||||
obj-$(CONFIG_OF) += devicetree.o
|
obj-$(CONFIG_OF) += devicetree.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_PINCTRL_AMB) += pinctrl-ambarella.o
|
||||||
|
obj-$(CONFIG_PINCTRL_AMB) += pinctrl-ambarella-cv75.o
|
||||||
obj-$(CONFIG_PINCTRL_AMD) += pinctrl-amd.o
|
obj-$(CONFIG_PINCTRL_AMD) += pinctrl-amd.o
|
||||||
obj-$(CONFIG_PINCTRL_AMDISP) += pinctrl-amdisp.o
|
obj-$(CONFIG_PINCTRL_AMDISP) += pinctrl-amdisp.o
|
||||||
obj-$(CONFIG_PINCTRL_APPLE_GPIO) += pinctrl-apple-gpio.o
|
obj-$(CONFIG_PINCTRL_APPLE_GPIO) += pinctrl-apple-gpio.o
|
||||||
|
|
|
||||||
587
drivers/pinctrl/pinctrl-ambarella-cv75.c
Normal file
587
drivers/pinctrl/pinctrl-ambarella-cv75.c
Normal file
|
|
@ -0,0 +1,587 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* Ambarella CV75 pinctrl data
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026, Ambarella, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/array_size.h>
|
||||||
|
#include <linux/build_bug.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#include <linux/pinctrl/pinctrl.h>
|
||||||
|
|
||||||
|
#include "pinctrl-ambarella.h"
|
||||||
|
|
||||||
|
#define CV75_EXPAND(...) __VA_ARGS__
|
||||||
|
#define CV75_GROUP_PINS_ALTS(_name, _pin_list, _alt_list) \
|
||||||
|
static const unsigned int cv75_##_name##_pins[] = { CV75_EXPAND _pin_list }; \
|
||||||
|
static const u8 cv75_##_name##_alts[] = { CV75_EXPAND _alt_list }; \
|
||||||
|
static const struct pingroup cv75_##_name##_grp = \
|
||||||
|
PINCTRL_PINGROUP(#_name, cv75_##_name##_pins, \
|
||||||
|
ARRAY_SIZE(cv75_##_name##_pins)); \
|
||||||
|
static_assert(ARRAY_SIZE(cv75_##_name##_pins) == \
|
||||||
|
ARRAY_SIZE(cv75_##_name##_alts))
|
||||||
|
|
||||||
|
#define CV75_GROUP(_name) \
|
||||||
|
{ \
|
||||||
|
.grp = &cv75_##_name##_grp, \
|
||||||
|
.alts = cv75_##_name##_alts, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CV75_FUNCTION(_name) \
|
||||||
|
PINCTRL_PINFUNCTION(#_name, cv75_##_name##_groups, ARRAY_SIZE(cv75_##_name##_groups))
|
||||||
|
|
||||||
|
/* UART */
|
||||||
|
CV75_GROUP_PINS_ALTS(uart0, (44, 45), (1, 1));
|
||||||
|
CV75_GROUP_PINS_ALTS(uart1, (46, 47), (1, 1));
|
||||||
|
CV75_GROUP_PINS_ALTS(uart1_flow, (48, 49), (1, 1));
|
||||||
|
CV75_GROUP_PINS_ALTS(uart2_a, (46, 47), (2, 2));
|
||||||
|
CV75_GROUP_PINS_ALTS(uart2_b, (50, 51), (2, 2));
|
||||||
|
CV75_GROUP_PINS_ALTS(uart2_c, (66, 68), (2, 2));
|
||||||
|
CV75_GROUP_PINS_ALTS(uart2_flow_a, (48, 49), (2, 2));
|
||||||
|
CV75_GROUP_PINS_ALTS(uart2_flow_b, (65, 67), (3, 3));
|
||||||
|
CV75_GROUP_PINS_ALTS(uart3_a, (70, 72), (3, 3));
|
||||||
|
CV75_GROUP_PINS_ALTS(uart3_b, (80, 79), (3, 3));
|
||||||
|
CV75_GROUP_PINS_ALTS(uart3_flow_a, (71, 69), (3, 3));
|
||||||
|
CV75_GROUP_PINS_ALTS(uart3_flow_b, (81, 82), (3, 3));
|
||||||
|
CV75_GROUP_PINS_ALTS(uart4_a, (29, 30), (3, 3));
|
||||||
|
CV75_GROUP_PINS_ALTS(uart4_b, (76, 77), (3, 3));
|
||||||
|
CV75_GROUP_PINS_ALTS(uart4_flow_a, (28, 31), (3, 3));
|
||||||
|
CV75_GROUP_PINS_ALTS(uart4_flow_b, (74, 75), (3, 3));
|
||||||
|
|
||||||
|
/* Flash */
|
||||||
|
CV75_GROUP_PINS_ALTS(snand, (79, 80, 81, 82, 83, 84), (1, 1, 1, 1, 1, 1));
|
||||||
|
CV75_GROUP_PINS_ALTS(spinor, (79, 80, 81, 82, 83, 84, 85),
|
||||||
|
(2, 2, 2, 2, 2, 2, 2));
|
||||||
|
|
||||||
|
/* SD/MMC */
|
||||||
|
CV75_GROUP_PINS_ALTS(sdmmc0_cd, (6), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(sdmmc0_wp, (7), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(sdmmc0_reset, (8), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(sdmmc0_hs_sel, (93), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(sdmmc0_1bit, (0, 4, 5), (1, 1, 1));
|
||||||
|
CV75_GROUP_PINS_ALTS(sdmmc0_4bit, (0, 1, 2, 3, 4, 5), (1, 1, 1, 1, 1, 1));
|
||||||
|
CV75_GROUP_PINS_ALTS(sdmmc1_cd, (15), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(sdmmc1_wp, (16), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(sdmmc1_reset, (17), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(sdmmc1_hs_sel, (94), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(sdmmc1_1bit, (9, 13, 14), (1, 1, 1));
|
||||||
|
CV75_GROUP_PINS_ALTS(sdmmc1_4bit, (9, 10, 11, 12, 13, 14), (1, 1, 1, 1, 1, 1));
|
||||||
|
|
||||||
|
/* Ethernet */
|
||||||
|
CV75_GROUP_PINS_ALTS(enet_ext_osc_clk, (77), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(enet_2nd_ref_clk_a, (78), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(enet_2nd_ref_clk_b, (76), (2));
|
||||||
|
CV75_GROUP_PINS_ALTS(enet0_ptp_pps_o, (74), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(rgmii0, (62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 75, 76),
|
||||||
|
(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1));
|
||||||
|
CV75_GROUP_PINS_ALTS(rmii0, (62, 63, 64, 67, 68, 71, 72, 73, 75),
|
||||||
|
(1, 1, 1, 1, 1, 1, 1, 1, 2));
|
||||||
|
|
||||||
|
/* I2C */
|
||||||
|
CV75_GROUP_PINS_ALTS(i2c0_a, (67, 68), (2, 2));
|
||||||
|
CV75_GROUP_PINS_ALTS(i2c0_b, (86, 87), (1, 1));
|
||||||
|
CV75_GROUP_PINS_ALTS(i2c1_a, (22, 23), (2, 2));
|
||||||
|
CV75_GROUP_PINS_ALTS(i2c1_b, (69, 70), (2, 2));
|
||||||
|
CV75_GROUP_PINS_ALTS(i2c2, (88, 89), (1, 1));
|
||||||
|
CV75_GROUP_PINS_ALTS(i2c3_a, (24, 25), (2, 2));
|
||||||
|
CV75_GROUP_PINS_ALTS(i2c3_b, (48, 49), (3, 3));
|
||||||
|
CV75_GROUP_PINS_ALTS(i2c3_c, (58, 59), (3, 3));
|
||||||
|
CV75_GROUP_PINS_ALTS(i2cs_a, (19, 21), (2, 2));
|
||||||
|
CV75_GROUP_PINS_ALTS(i2cs_b, (60, 61), (3, 3));
|
||||||
|
CV75_GROUP_PINS_ALTS(i2cs_c, (71, 72), (2, 2));
|
||||||
|
CV75_GROUP_PINS_ALTS(i2cs_d, (86, 87), (2, 2));
|
||||||
|
|
||||||
|
/* CAN, IR, WDT */
|
||||||
|
CV75_GROUP_PINS_ALTS(can0, (50, 51), (1, 1));
|
||||||
|
CV75_GROUP_PINS_ALTS(can1, (52, 53), (1, 1));
|
||||||
|
CV75_GROUP_PINS_ALTS(ir, (18), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(wdt_a, (20), (2));
|
||||||
|
CV75_GROUP_PINS_ALTS(wdt_b, (27), (3));
|
||||||
|
CV75_GROUP_PINS_ALTS(wdt_c, (39), (2));
|
||||||
|
CV75_GROUP_PINS_ALTS(wdt_d, (83), (3));
|
||||||
|
CV75_GROUP_PINS_ALTS(wdt_e, (85), (4));
|
||||||
|
CV75_GROUP_PINS_ALTS(wdt_f, (90), (1));
|
||||||
|
|
||||||
|
/* I2S */
|
||||||
|
CV75_GROUP_PINS_ALTS(i2s0, (54, 55, 56, 57), (1, 1, 1, 1));
|
||||||
|
CV75_GROUP_PINS_ALTS(i2s1, (58, 59, 60, 61), (1, 1, 1, 1));
|
||||||
|
CV75_GROUP_PINS_ALTS(dmic0, (54, 55), (2, 2));
|
||||||
|
|
||||||
|
/* PWM */
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm0, (40), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm1, (41), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm2, (42), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm3, (43), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm4_a, (19), (3));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm4_b, (32), (4));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm5_a, (20), (3));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm5_b, (33), (4));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm6_a, (21), (3));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm6_b, (34), (4));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm7_a, (22), (3));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm7_b, (35), (4));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm8_a, (23), (3));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm8_b, (36), (4));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm9_a, (24), (3));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm9_b, (37), (4));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm10_a, (25), (3));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm10_b, (38), (4));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm11_a, (26), (3));
|
||||||
|
CV75_GROUP_PINS_ALTS(pwm11_b, (39), (4));
|
||||||
|
|
||||||
|
/* SPI */
|
||||||
|
CV75_GROUP_PINS_ALTS(spi0, (19, 20, 21), (1, 1, 1));
|
||||||
|
CV75_GROUP_PINS_ALTS(spi1, (24, 25, 26), (1, 1, 1));
|
||||||
|
CV75_GROUP_PINS_ALTS(spi2, (28, 29, 30), (1, 1, 1));
|
||||||
|
CV75_GROUP_PINS_ALTS(spi3_a, (32, 33, 34), (5, 5, 5));
|
||||||
|
CV75_GROUP_PINS_ALTS(spi3_b, (40, 41, 43), (2, 2, 2));
|
||||||
|
CV75_GROUP_PINS_ALTS(spi3_c, (58, 59, 60), (2, 2, 2));
|
||||||
|
CV75_GROUP_PINS_ALTS(spi_slave_a, (24, 25, 26, 27), (4, 4, 4, 4));
|
||||||
|
CV75_GROUP_PINS_ALTS(spi_slave_b, (28, 29, 30, 31), (2, 2, 2, 2));
|
||||||
|
CV75_GROUP_PINS_ALTS(spi_slave_c, (36, 37, 38, 39), (5, 5, 5, 5));
|
||||||
|
CV75_GROUP_PINS_ALTS(spi_slave_d, (50, 51, 52, 53), (3, 3, 3, 3));
|
||||||
|
CV75_GROUP_PINS_ALTS(spi_slave_e, (81, 82, 83, 84), (4, 4, 4, 4));
|
||||||
|
|
||||||
|
/* VIN master sync */
|
||||||
|
CV75_GROUP_PINS_ALTS(vin_master_sync_a, (91, 92), (1, 1));
|
||||||
|
CV75_GROUP_PINS_ALTS(vin_master_sync_b, (91, 92), (2, 2));
|
||||||
|
CV75_GROUP_PINS_ALTS(vin_master_sync_c, (40, 41), (3, 3));
|
||||||
|
CV75_GROUP_PINS_ALTS(vin_master_sync_d, (46, 47), (3, 3));
|
||||||
|
CV75_GROUP_PINS_ALTS(vin_master_sync_e, (79, 80), (4, 4));
|
||||||
|
CV75_GROUP_PINS_ALTS(vsync0, (32), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(vsync1, (33), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(vsync2, (34), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(vsync3, (35), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(hsync0, (36), (1));
|
||||||
|
CV75_GROUP_PINS_ALTS(hsync1, (37), (1));
|
||||||
|
|
||||||
|
static const struct amb_pinmux_group cv75_pin_groups[] = {
|
||||||
|
/* UART */
|
||||||
|
CV75_GROUP(uart0),
|
||||||
|
CV75_GROUP(uart1),
|
||||||
|
CV75_GROUP(uart1_flow),
|
||||||
|
CV75_GROUP(uart2_a),
|
||||||
|
CV75_GROUP(uart2_b),
|
||||||
|
CV75_GROUP(uart2_c),
|
||||||
|
CV75_GROUP(uart2_flow_a),
|
||||||
|
CV75_GROUP(uart2_flow_b),
|
||||||
|
CV75_GROUP(uart3_a),
|
||||||
|
CV75_GROUP(uart3_b),
|
||||||
|
CV75_GROUP(uart3_flow_a),
|
||||||
|
CV75_GROUP(uart3_flow_b),
|
||||||
|
CV75_GROUP(uart4_a),
|
||||||
|
CV75_GROUP(uart4_b),
|
||||||
|
CV75_GROUP(uart4_flow_a),
|
||||||
|
CV75_GROUP(uart4_flow_b),
|
||||||
|
/* Flash */
|
||||||
|
CV75_GROUP(snand),
|
||||||
|
CV75_GROUP(spinor),
|
||||||
|
/* SD/MMC */
|
||||||
|
CV75_GROUP(sdmmc0_cd),
|
||||||
|
CV75_GROUP(sdmmc0_wp),
|
||||||
|
CV75_GROUP(sdmmc0_reset),
|
||||||
|
CV75_GROUP(sdmmc0_hs_sel),
|
||||||
|
CV75_GROUP(sdmmc0_1bit),
|
||||||
|
CV75_GROUP(sdmmc0_4bit),
|
||||||
|
CV75_GROUP(sdmmc1_cd),
|
||||||
|
CV75_GROUP(sdmmc1_wp),
|
||||||
|
CV75_GROUP(sdmmc1_reset),
|
||||||
|
CV75_GROUP(sdmmc1_hs_sel),
|
||||||
|
CV75_GROUP(sdmmc1_1bit),
|
||||||
|
CV75_GROUP(sdmmc1_4bit),
|
||||||
|
/* Ethernet */
|
||||||
|
CV75_GROUP(enet_ext_osc_clk),
|
||||||
|
CV75_GROUP(enet_2nd_ref_clk_a),
|
||||||
|
CV75_GROUP(enet_2nd_ref_clk_b),
|
||||||
|
CV75_GROUP(enet0_ptp_pps_o),
|
||||||
|
CV75_GROUP(rgmii0),
|
||||||
|
CV75_GROUP(rmii0),
|
||||||
|
/* I2C */
|
||||||
|
CV75_GROUP(i2c0_a),
|
||||||
|
CV75_GROUP(i2c0_b),
|
||||||
|
CV75_GROUP(i2c1_a),
|
||||||
|
CV75_GROUP(i2c1_b),
|
||||||
|
CV75_GROUP(i2c2),
|
||||||
|
CV75_GROUP(i2c3_a),
|
||||||
|
CV75_GROUP(i2c3_b),
|
||||||
|
CV75_GROUP(i2c3_c),
|
||||||
|
CV75_GROUP(i2cs_a),
|
||||||
|
CV75_GROUP(i2cs_b),
|
||||||
|
CV75_GROUP(i2cs_c),
|
||||||
|
CV75_GROUP(i2cs_d),
|
||||||
|
/* CAN, IR, WDT */
|
||||||
|
CV75_GROUP(can0),
|
||||||
|
CV75_GROUP(can1),
|
||||||
|
CV75_GROUP(ir),
|
||||||
|
CV75_GROUP(wdt_a),
|
||||||
|
CV75_GROUP(wdt_b),
|
||||||
|
CV75_GROUP(wdt_c),
|
||||||
|
CV75_GROUP(wdt_d),
|
||||||
|
CV75_GROUP(wdt_e),
|
||||||
|
CV75_GROUP(wdt_f),
|
||||||
|
/* I2S */
|
||||||
|
CV75_GROUP(i2s0),
|
||||||
|
CV75_GROUP(i2s1),
|
||||||
|
CV75_GROUP(dmic0),
|
||||||
|
/* PWM */
|
||||||
|
CV75_GROUP(pwm0),
|
||||||
|
CV75_GROUP(pwm1),
|
||||||
|
CV75_GROUP(pwm2),
|
||||||
|
CV75_GROUP(pwm3),
|
||||||
|
CV75_GROUP(pwm4_a),
|
||||||
|
CV75_GROUP(pwm4_b),
|
||||||
|
CV75_GROUP(pwm5_a),
|
||||||
|
CV75_GROUP(pwm5_b),
|
||||||
|
CV75_GROUP(pwm6_a),
|
||||||
|
CV75_GROUP(pwm6_b),
|
||||||
|
CV75_GROUP(pwm7_a),
|
||||||
|
CV75_GROUP(pwm7_b),
|
||||||
|
CV75_GROUP(pwm8_a),
|
||||||
|
CV75_GROUP(pwm8_b),
|
||||||
|
CV75_GROUP(pwm9_a),
|
||||||
|
CV75_GROUP(pwm9_b),
|
||||||
|
CV75_GROUP(pwm10_a),
|
||||||
|
CV75_GROUP(pwm10_b),
|
||||||
|
CV75_GROUP(pwm11_a),
|
||||||
|
CV75_GROUP(pwm11_b),
|
||||||
|
/* SPI */
|
||||||
|
CV75_GROUP(spi0),
|
||||||
|
CV75_GROUP(spi1),
|
||||||
|
CV75_GROUP(spi2),
|
||||||
|
CV75_GROUP(spi3_a),
|
||||||
|
CV75_GROUP(spi3_b),
|
||||||
|
CV75_GROUP(spi3_c),
|
||||||
|
CV75_GROUP(spi_slave_a),
|
||||||
|
CV75_GROUP(spi_slave_b),
|
||||||
|
CV75_GROUP(spi_slave_c),
|
||||||
|
CV75_GROUP(spi_slave_d),
|
||||||
|
CV75_GROUP(spi_slave_e),
|
||||||
|
/* VIN master sync */
|
||||||
|
CV75_GROUP(vin_master_sync_a),
|
||||||
|
CV75_GROUP(vin_master_sync_b),
|
||||||
|
CV75_GROUP(vin_master_sync_c),
|
||||||
|
CV75_GROUP(vin_master_sync_d),
|
||||||
|
CV75_GROUP(vin_master_sync_e),
|
||||||
|
CV75_GROUP(vsync0),
|
||||||
|
CV75_GROUP(vsync1),
|
||||||
|
CV75_GROUP(vsync2),
|
||||||
|
CV75_GROUP(vsync3),
|
||||||
|
CV75_GROUP(hsync0),
|
||||||
|
CV75_GROUP(hsync1),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_uart0_groups[] = {
|
||||||
|
"uart0",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_uart1_groups[] = {
|
||||||
|
"uart1",
|
||||||
|
"uart1_flow",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_uart2_groups[] = {
|
||||||
|
"uart2_a",
|
||||||
|
"uart2_b",
|
||||||
|
"uart2_c",
|
||||||
|
"uart2_flow_a",
|
||||||
|
"uart2_flow_b",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_uart3_groups[] = {
|
||||||
|
"uart3_a",
|
||||||
|
"uart3_b",
|
||||||
|
"uart3_flow_a",
|
||||||
|
"uart3_flow_b",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_uart4_groups[] = {
|
||||||
|
"uart4_a",
|
||||||
|
"uart4_b",
|
||||||
|
"uart4_flow_a",
|
||||||
|
"uart4_flow_b",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_snand_groups[] = {
|
||||||
|
"snand",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_spinor_groups[] = {
|
||||||
|
"spinor",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_sdmmc0_groups[] = {
|
||||||
|
"sdmmc0_cd",
|
||||||
|
"sdmmc0_wp",
|
||||||
|
"sdmmc0_reset",
|
||||||
|
"sdmmc0_hs_sel",
|
||||||
|
"sdmmc0_1bit",
|
||||||
|
"sdmmc0_4bit",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_sdmmc1_groups[] = {
|
||||||
|
"sdmmc1_cd",
|
||||||
|
"sdmmc1_wp",
|
||||||
|
"sdmmc1_reset",
|
||||||
|
"sdmmc1_hs_sel",
|
||||||
|
"sdmmc1_1bit",
|
||||||
|
"sdmmc1_4bit",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_enet0_groups[] = {
|
||||||
|
"enet_ext_osc_clk",
|
||||||
|
"enet_2nd_ref_clk_a",
|
||||||
|
"enet_2nd_ref_clk_b",
|
||||||
|
"enet0_ptp_pps_o",
|
||||||
|
"rgmii0",
|
||||||
|
"rmii0",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_i2c0_groups[] = {
|
||||||
|
"i2c0_a",
|
||||||
|
"i2c0_b",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_i2c1_groups[] = {
|
||||||
|
"i2c1_a",
|
||||||
|
"i2c1_b",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_i2c2_groups[] = {
|
||||||
|
"i2c2",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_i2c3_groups[] = {
|
||||||
|
"i2c3_a",
|
||||||
|
"i2c3_b",
|
||||||
|
"i2c3_c",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_i2cs_groups[] = {
|
||||||
|
"i2cs_a",
|
||||||
|
"i2cs_b",
|
||||||
|
"i2cs_c",
|
||||||
|
"i2cs_d",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_can0_groups[] = {
|
||||||
|
"can0",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_can1_groups[] = {
|
||||||
|
"can1",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_ir_groups[] = {
|
||||||
|
"ir",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_wdt_groups[] = {
|
||||||
|
"wdt_a",
|
||||||
|
"wdt_b",
|
||||||
|
"wdt_c",
|
||||||
|
"wdt_d",
|
||||||
|
"wdt_e",
|
||||||
|
"wdt_f",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_i2s0_groups[] = {
|
||||||
|
"i2s0",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_i2s1_groups[] = {
|
||||||
|
"i2s1",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_dmic0_groups[] = {
|
||||||
|
"dmic0",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_pwm0_groups[] = {
|
||||||
|
"pwm0",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_pwm1_groups[] = {
|
||||||
|
"pwm1",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_pwm2_groups[] = {
|
||||||
|
"pwm2",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_pwm3_groups[] = {
|
||||||
|
"pwm3",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_pwm4_groups[] = {
|
||||||
|
"pwm4_a",
|
||||||
|
"pwm4_b",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_pwm5_groups[] = {
|
||||||
|
"pwm5_a",
|
||||||
|
"pwm5_b",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_pwm6_groups[] = {
|
||||||
|
"pwm6_a",
|
||||||
|
"pwm6_b",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_pwm7_groups[] = {
|
||||||
|
"pwm7_a",
|
||||||
|
"pwm7_b",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_pwm8_groups[] = {
|
||||||
|
"pwm8_a",
|
||||||
|
"pwm8_b",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_pwm9_groups[] = {
|
||||||
|
"pwm9_a",
|
||||||
|
"pwm9_b",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_pwm10_groups[] = {
|
||||||
|
"pwm10_a",
|
||||||
|
"pwm10_b",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_pwm11_groups[] = {
|
||||||
|
"pwm11_a",
|
||||||
|
"pwm11_b",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_spi0_groups[] = {
|
||||||
|
"spi0",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_spi1_groups[] = {
|
||||||
|
"spi1",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_spi2_groups[] = {
|
||||||
|
"spi2",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_spi3_groups[] = {
|
||||||
|
"spi3_a",
|
||||||
|
"spi3_b",
|
||||||
|
"spi3_c",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_spi_slave_groups[] = {
|
||||||
|
"spi_slave_a",
|
||||||
|
"spi_slave_b",
|
||||||
|
"spi_slave_c",
|
||||||
|
"spi_slave_d",
|
||||||
|
"spi_slave_e",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_vin_master_sync_groups[] = {
|
||||||
|
"vin_master_sync_a",
|
||||||
|
"vin_master_sync_b",
|
||||||
|
"vin_master_sync_c",
|
||||||
|
"vin_master_sync_d",
|
||||||
|
"vin_master_sync_e",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_vsync0_groups[] = {
|
||||||
|
"vsync0",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_vsync1_groups[] = {
|
||||||
|
"vsync1",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_vsync2_groups[] = {
|
||||||
|
"vsync2",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_vsync3_groups[] = {
|
||||||
|
"vsync3",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_hsync0_groups[] = {
|
||||||
|
"hsync0",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const cv75_hsync1_groups[] = {
|
||||||
|
"hsync1",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct pinfunction cv75_pin_functions[] = {
|
||||||
|
CV75_FUNCTION(uart0),
|
||||||
|
CV75_FUNCTION(uart1),
|
||||||
|
CV75_FUNCTION(uart2),
|
||||||
|
CV75_FUNCTION(uart3),
|
||||||
|
CV75_FUNCTION(uart4),
|
||||||
|
CV75_FUNCTION(snand),
|
||||||
|
CV75_FUNCTION(spinor),
|
||||||
|
CV75_FUNCTION(sdmmc0),
|
||||||
|
CV75_FUNCTION(sdmmc1),
|
||||||
|
CV75_FUNCTION(enet0),
|
||||||
|
CV75_FUNCTION(i2c0),
|
||||||
|
CV75_FUNCTION(i2c1),
|
||||||
|
CV75_FUNCTION(i2c2),
|
||||||
|
CV75_FUNCTION(i2c3),
|
||||||
|
CV75_FUNCTION(i2cs),
|
||||||
|
CV75_FUNCTION(can0),
|
||||||
|
CV75_FUNCTION(can1),
|
||||||
|
CV75_FUNCTION(ir),
|
||||||
|
CV75_FUNCTION(wdt),
|
||||||
|
CV75_FUNCTION(i2s0),
|
||||||
|
CV75_FUNCTION(i2s1),
|
||||||
|
CV75_FUNCTION(dmic0),
|
||||||
|
CV75_FUNCTION(pwm0),
|
||||||
|
CV75_FUNCTION(pwm1),
|
||||||
|
CV75_FUNCTION(pwm2),
|
||||||
|
CV75_FUNCTION(pwm3),
|
||||||
|
CV75_FUNCTION(pwm4),
|
||||||
|
CV75_FUNCTION(pwm5),
|
||||||
|
CV75_FUNCTION(pwm6),
|
||||||
|
CV75_FUNCTION(pwm7),
|
||||||
|
CV75_FUNCTION(pwm8),
|
||||||
|
CV75_FUNCTION(pwm9),
|
||||||
|
CV75_FUNCTION(pwm10),
|
||||||
|
CV75_FUNCTION(pwm11),
|
||||||
|
CV75_FUNCTION(spi0),
|
||||||
|
CV75_FUNCTION(spi1),
|
||||||
|
CV75_FUNCTION(spi2),
|
||||||
|
CV75_FUNCTION(spi3),
|
||||||
|
CV75_FUNCTION(spi_slave),
|
||||||
|
CV75_FUNCTION(vin_master_sync),
|
||||||
|
CV75_FUNCTION(vsync0),
|
||||||
|
CV75_FUNCTION(vsync1),
|
||||||
|
CV75_FUNCTION(vsync2),
|
||||||
|
CV75_FUNCTION(vsync3),
|
||||||
|
CV75_FUNCTION(hsync0),
|
||||||
|
CV75_FUNCTION(hsync1),
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct amb_pinctrl_data ambarella_cv75_pinctrl_data = {
|
||||||
|
.groups = cv75_pin_groups,
|
||||||
|
.functions = cv75_pin_functions,
|
||||||
|
.ngroups = ARRAY_SIZE(cv75_pin_groups),
|
||||||
|
.nfunctions = ARRAY_SIZE(cv75_pin_functions),
|
||||||
|
.nr_banks = 3,
|
||||||
|
.npins = 96,
|
||||||
|
.ds0 = {
|
||||||
|
0x314, 0x320, 0x32c,
|
||||||
|
},
|
||||||
|
.ds1 = {
|
||||||
|
0x318, 0x324, 0x330,
|
||||||
|
},
|
||||||
|
.ds2 = {
|
||||||
|
0x31c, 0x328, 0x334,
|
||||||
|
},
|
||||||
|
.pull_en = {
|
||||||
|
0x60, 0x64, 0x68,
|
||||||
|
},
|
||||||
|
.pull_dir = {
|
||||||
|
0x7c, 0x80, 0x84,
|
||||||
|
},
|
||||||
|
.have_ds2 = true,
|
||||||
|
};
|
||||||
533
drivers/pinctrl/pinctrl-ambarella.c
Normal file
533
drivers/pinctrl/pinctrl-ambarella.c
Normal file
|
|
@ -0,0 +1,533 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
/*
|
||||||
|
* Pinctrl driver for Ambarella SoCs
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012-2026, Ambarella, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/array_size.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/bits.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/mfd/syscon.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/string_helpers.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#include <linux/pinctrl/pinconf-generic.h>
|
||||||
|
#include <linux/pinctrl/pinconf.h>
|
||||||
|
#include <linux/pinctrl/pinctrl.h>
|
||||||
|
#include <linux/pinctrl/pinmux.h>
|
||||||
|
|
||||||
|
#include "core.h"
|
||||||
|
#include "pinmux.h"
|
||||||
|
#include "pinctrl-ambarella.h"
|
||||||
|
|
||||||
|
#define IOMUX_REG(bank, n) (((bank) * 0xc) + ((n) * 4))
|
||||||
|
#define IOMUX_CTRL_SET 0xf0
|
||||||
|
|
||||||
|
#define PINID_TO_BANK(p) ((p) >> 5)
|
||||||
|
#define PINID_TO_OFFSET(p) ((p) & 0x1f)
|
||||||
|
|
||||||
|
struct amb_pinctrl {
|
||||||
|
struct pinctrl_desc desc;
|
||||||
|
void __iomem *iomux_base;
|
||||||
|
struct regmap *ds_regmap;
|
||||||
|
struct regmap *pull_regmap;
|
||||||
|
const struct amb_pinctrl_data *data;
|
||||||
|
struct device *dev;
|
||||||
|
struct pinctrl_dev *pctl;
|
||||||
|
spinlock_t lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int amb_ds1_ma[] = { 2, 4, 8, 12 };
|
||||||
|
static const int amb_ds2_ma[] = { 3, 4, 6, 8, 9, 12 };
|
||||||
|
|
||||||
|
static const struct pinctrl_ops amb_pctrl_ops = {
|
||||||
|
.get_groups_count = pinctrl_generic_get_group_count,
|
||||||
|
.get_group_name = pinctrl_generic_get_group_name,
|
||||||
|
.get_group_pins = pinctrl_generic_get_group_pins,
|
||||||
|
.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
|
||||||
|
.dt_free_map = pinconf_generic_dt_free_map,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void amb_iomux_commit(struct amb_pinctrl *ipc)
|
||||||
|
{
|
||||||
|
writel(0x1, ipc->iomux_base + IOMUX_CTRL_SET);
|
||||||
|
writel(0x0, ipc->iomux_base + IOMUX_CTRL_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void amb_pinmux_set_altfunc(struct amb_pinctrl *ipc, u32 bank,
|
||||||
|
u32 offset, u32 altfunc)
|
||||||
|
{
|
||||||
|
if (bank >= ipc->data->nr_banks)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < 3; i++) {
|
||||||
|
unsigned long data;
|
||||||
|
|
||||||
|
data = readl_relaxed(ipc->iomux_base + IOMUX_REG(bank, i));
|
||||||
|
__assign_bit(offset, &data, altfunc & BIT(i));
|
||||||
|
writel_relaxed(data, ipc->iomux_base + IOMUX_REG(bank, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int amb_pinmux_set_mux(struct pinctrl_dev *pctldev,
|
||||||
|
unsigned int selector, unsigned int group)
|
||||||
|
{
|
||||||
|
struct amb_pinctrl *ipc = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
struct group_desc *grp;
|
||||||
|
const u8 *alts;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
(void)selector;
|
||||||
|
|
||||||
|
grp = pinctrl_generic_get_group(pctldev, group);
|
||||||
|
if (!grp || !grp->data)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
alts = grp->data;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&ipc->lock, flags);
|
||||||
|
for (unsigned int i = 0; i < grp->grp.npins; i++) {
|
||||||
|
unsigned int pin = grp->grp.pins[i];
|
||||||
|
|
||||||
|
amb_pinmux_set_altfunc(ipc, PINID_TO_BANK(pin),
|
||||||
|
PINID_TO_OFFSET(pin), alts[i]);
|
||||||
|
}
|
||||||
|
amb_iomux_commit(ipc);
|
||||||
|
spin_unlock_irqrestore(&ipc->lock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int amb_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev,
|
||||||
|
struct pinctrl_gpio_range *range,
|
||||||
|
unsigned int pin)
|
||||||
|
{
|
||||||
|
struct amb_pinctrl *ipc = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
if (!range || !range->gc)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (pin >= ipc->data->npins)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&ipc->lock, flags);
|
||||||
|
amb_pinmux_set_altfunc(ipc, PINID_TO_BANK(pin), PINID_TO_OFFSET(pin), 0);
|
||||||
|
amb_iomux_commit(ipc);
|
||||||
|
spin_unlock_irqrestore(&ipc->lock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pinmux_ops amb_pinmux_ops = {
|
||||||
|
.get_functions_count = pinmux_generic_get_function_count,
|
||||||
|
.get_function_name = pinmux_generic_get_function_name,
|
||||||
|
.get_function_groups = pinmux_generic_get_function_groups,
|
||||||
|
.set_mux = amb_pinmux_set_mux,
|
||||||
|
.gpio_request_enable = amb_pinmux_gpio_request_enable,
|
||||||
|
.strict = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int amb_drive_strength_to_reg_ds1(u32 strength)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < ARRAY_SIZE(amb_ds1_ma); i++) {
|
||||||
|
if (amb_ds1_ma[i] == strength)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int amb_drive_strength_to_reg_ds2(u32 strength)
|
||||||
|
{
|
||||||
|
/* Hardware steps are 3, 4, 6, 8, 9, 12 mA; 5 and 7 are accepted aliases */
|
||||||
|
if (strength == 5)
|
||||||
|
strength = 4;
|
||||||
|
else if (strength == 7)
|
||||||
|
strength = 8;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < ARRAY_SIZE(amb_ds2_ma); i++) {
|
||||||
|
if (amb_ds2_ma[i] == strength)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int amb_drive_strength_to_reg(const struct amb_pinctrl *ipc, u32 strength)
|
||||||
|
{
|
||||||
|
if (ipc->data->have_ds2)
|
||||||
|
return amb_drive_strength_to_reg_ds2(strength);
|
||||||
|
|
||||||
|
return amb_drive_strength_to_reg_ds1(strength);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int amb_reg_to_drive_strength(const struct amb_pinctrl *ipc, u32 ds)
|
||||||
|
{
|
||||||
|
if (ipc->data->have_ds2) {
|
||||||
|
if (ds >= ARRAY_SIZE(amb_ds2_ma))
|
||||||
|
return -EINVAL;
|
||||||
|
return amb_ds2_ma[ds];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ds >= ARRAY_SIZE(amb_ds1_ma))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return amb_ds1_ma[ds];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int amb_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
|
||||||
|
unsigned long *configs, unsigned int num_configs)
|
||||||
|
{
|
||||||
|
struct amb_pinctrl *ipc = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
u32 bank = PINID_TO_BANK(pin);
|
||||||
|
u32 offset = PINID_TO_OFFSET(pin);
|
||||||
|
unsigned int mask = BIT(offset);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (bank >= ipc->data->nr_banks)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < num_configs; i++) {
|
||||||
|
enum pin_config_param param = pinconf_to_config_param(configs[i]);
|
||||||
|
u32 arg = pinconf_to_config_argument(configs[i]);
|
||||||
|
int ds;
|
||||||
|
|
||||||
|
switch (param) {
|
||||||
|
case PIN_CONFIG_BIAS_DISABLE:
|
||||||
|
ret = regmap_assign_bits(ipc->pull_regmap, ipc->data->pull_en[bank],
|
||||||
|
mask, false);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
break;
|
||||||
|
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||||
|
case PIN_CONFIG_BIAS_PULL_UP:
|
||||||
|
ret = regmap_assign_bits(ipc->pull_regmap, ipc->data->pull_dir[bank],
|
||||||
|
mask, param == PIN_CONFIG_BIAS_PULL_UP);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = regmap_assign_bits(ipc->pull_regmap, ipc->data->pull_en[bank],
|
||||||
|
mask, true);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
break;
|
||||||
|
case PIN_CONFIG_DRIVE_STRENGTH:
|
||||||
|
ds = amb_drive_strength_to_reg(ipc, arg);
|
||||||
|
if (ds < 0)
|
||||||
|
return ds;
|
||||||
|
if (ipc->data->have_ds2) {
|
||||||
|
ret = regmap_assign_bits(ipc->ds_regmap, ipc->data->ds0[bank],
|
||||||
|
mask, ds & BIT(0));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = regmap_assign_bits(ipc->ds_regmap, ipc->data->ds1[bank],
|
||||||
|
mask, ds & BIT(1));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = regmap_assign_bits(ipc->ds_regmap, ipc->data->ds2[bank],
|
||||||
|
mask, ds & BIT(2));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
ret = regmap_assign_bits(ipc->ds_regmap, ipc->data->ds0[bank],
|
||||||
|
mask, ds & BIT(1));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = regmap_assign_bits(ipc->ds_regmap, ipc->data->ds1[bank],
|
||||||
|
mask, ds & BIT(0));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int amb_pinconf_group_set(struct pinctrl_dev *pctldev,
|
||||||
|
unsigned int selector,
|
||||||
|
unsigned long *configs,
|
||||||
|
unsigned int num_configs)
|
||||||
|
{
|
||||||
|
const unsigned int *pins;
|
||||||
|
unsigned int npins;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = pinctrl_generic_get_group_pins(pctldev, selector, &pins, &npins);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < npins; i++) {
|
||||||
|
ret = amb_pinconf_set(pctldev, pins[i], configs, num_configs);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int amb_pinconf_get(struct pinctrl_dev *pctldev,
|
||||||
|
unsigned int pin, unsigned long *config)
|
||||||
|
{
|
||||||
|
struct amb_pinctrl *ipc = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
enum pin_config_param param = pinconf_to_config_param(*config);
|
||||||
|
u32 bank = PINID_TO_BANK(pin);
|
||||||
|
u32 offset = PINID_TO_OFFSET(pin);
|
||||||
|
u32 pull_en, pull_dir, ds0, ds1, ds2, ds;
|
||||||
|
bool en, dir, b0, b1, b2;
|
||||||
|
int ret, strength;
|
||||||
|
|
||||||
|
if (bank >= ipc->data->nr_banks)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
switch (param) {
|
||||||
|
case PIN_CONFIG_BIAS_DISABLE:
|
||||||
|
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||||
|
case PIN_CONFIG_BIAS_PULL_UP:
|
||||||
|
ret = regmap_read(ipc->pull_regmap, ipc->data->pull_en[bank],
|
||||||
|
&pull_en);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = regmap_read(ipc->pull_regmap, ipc->data->pull_dir[bank],
|
||||||
|
&pull_dir);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
en = !!(pull_en & BIT(offset));
|
||||||
|
dir = !!(pull_dir & BIT(offset));
|
||||||
|
|
||||||
|
if (param == PIN_CONFIG_BIAS_DISABLE) {
|
||||||
|
if (en)
|
||||||
|
return -EINVAL;
|
||||||
|
*config = pinconf_to_config_packed(param, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!en)
|
||||||
|
return -EINVAL;
|
||||||
|
if (param == PIN_CONFIG_BIAS_PULL_UP && !dir)
|
||||||
|
return -EINVAL;
|
||||||
|
if (param == PIN_CONFIG_BIAS_PULL_DOWN && dir)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
*config = pinconf_to_config_packed(param, 1);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case PIN_CONFIG_DRIVE_STRENGTH:
|
||||||
|
ret = regmap_read(ipc->ds_regmap, ipc->data->ds0[bank], &ds0);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = regmap_read(ipc->ds_regmap, ipc->data->ds1[bank], &ds1);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
b0 = !!(ds0 & BIT(offset));
|
||||||
|
b1 = !!(ds1 & BIT(offset));
|
||||||
|
if (ipc->data->have_ds2) {
|
||||||
|
ret = regmap_read(ipc->ds_regmap, ipc->data->ds2[bank],
|
||||||
|
&ds2);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
b2 = !!(ds2 & BIT(offset));
|
||||||
|
ds = (b2 << 2) | (b1 << 1) | b0;
|
||||||
|
} else {
|
||||||
|
ds = (b0 << 1) | b1;
|
||||||
|
}
|
||||||
|
|
||||||
|
strength = amb_reg_to_drive_strength(ipc, ds);
|
||||||
|
if (strength < 0)
|
||||||
|
return strength;
|
||||||
|
|
||||||
|
*config = pinconf_to_config_packed(param, strength);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pinconf_ops amb_pinconf_ops = {
|
||||||
|
.is_generic = true,
|
||||||
|
.pin_config_get = amb_pinconf_get,
|
||||||
|
.pin_config_set = amb_pinconf_set,
|
||||||
|
.pin_config_group_set = amb_pinconf_group_set,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int amb_pinctrl_add_groups(struct amb_pinctrl *ipc)
|
||||||
|
{
|
||||||
|
const struct amb_pinctrl_data *data = ipc->data;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < data->ngroups; i++) {
|
||||||
|
const struct amb_pinmux_group *g = &data->groups[i];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!g->grp || !g->grp->name || !g->grp->pins ||
|
||||||
|
!g->grp->npins || !g->alts)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < g->grp->npins; j++) {
|
||||||
|
if (g->grp->pins[j] >= data->npins)
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = pinctrl_generic_add_group(ipc->pctl, g->grp->name,
|
||||||
|
g->grp->pins, g->grp->npins,
|
||||||
|
(void *)g->alts);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int amb_pinctrl_add_functions(struct amb_pinctrl *ipc)
|
||||||
|
{
|
||||||
|
const struct amb_pinctrl_data *data = ipc->data;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < data->nfunctions; i++) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = pinmux_generic_add_pinfunction(ipc->pctl,
|
||||||
|
&data->functions[i], NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int amb_pinctrl_register(struct amb_pinctrl *ipc)
|
||||||
|
{
|
||||||
|
struct pinctrl_pin_desc *pindesc;
|
||||||
|
char **names;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
pindesc = devm_kcalloc(ipc->dev, ipc->data->npins, sizeof(*pindesc),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!pindesc)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
names = devm_kasprintf_strarray(ipc->dev, "io", ipc->data->npins);
|
||||||
|
if (!names)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
for (unsigned int pin = 0; pin < ipc->data->npins; pin++) {
|
||||||
|
pindesc[pin].number = pin;
|
||||||
|
pindesc[pin].name = names[pin];
|
||||||
|
}
|
||||||
|
|
||||||
|
ipc->desc.name = dev_name(ipc->dev);
|
||||||
|
ipc->desc.pins = pindesc;
|
||||||
|
ipc->desc.npins = ipc->data->npins;
|
||||||
|
ipc->desc.pctlops = &amb_pctrl_ops;
|
||||||
|
ipc->desc.pmxops = &amb_pinmux_ops;
|
||||||
|
ipc->desc.confops = &amb_pinconf_ops;
|
||||||
|
ipc->desc.owner = THIS_MODULE;
|
||||||
|
|
||||||
|
ret = devm_pinctrl_register_and_init(ipc->dev, &ipc->desc, ipc, &ipc->pctl);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = amb_pinctrl_add_groups(ipc);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = amb_pinctrl_add_functions(ipc);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return pinctrl_enable(ipc->pctl);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int amb_pinctrl_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct amb_pinctrl *ipc;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ipc = devm_kzalloc(dev, sizeof(*ipc), GFP_KERNEL);
|
||||||
|
if (!ipc)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ipc->dev = dev;
|
||||||
|
ipc->data = device_get_match_data(dev);
|
||||||
|
if (!ipc->data)
|
||||||
|
return dev_err_probe(dev, -ENODATA, "missing SoC data\n");
|
||||||
|
|
||||||
|
if (!ipc->data->nr_banks || ipc->data->nr_banks > AMBA_MAX_BANKS ||
|
||||||
|
!ipc->data->npins ||
|
||||||
|
!ipc->data->groups || !ipc->data->ngroups ||
|
||||||
|
!ipc->data->functions || !ipc->data->nfunctions)
|
||||||
|
return dev_err_probe(dev, -EINVAL, "invalid SoC data\n");
|
||||||
|
|
||||||
|
ipc->iomux_base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
|
if (IS_ERR(ipc->iomux_base))
|
||||||
|
return PTR_ERR(ipc->iomux_base);
|
||||||
|
|
||||||
|
ipc->ds_regmap = syscon_regmap_lookup_by_phandle(dev_of_node(dev),
|
||||||
|
"ambarella,drive-strength-syscon");
|
||||||
|
if (IS_ERR(ipc->ds_regmap))
|
||||||
|
return dev_err_probe(dev, PTR_ERR(ipc->ds_regmap),
|
||||||
|
"missing drive-strength syscon\n");
|
||||||
|
|
||||||
|
ipc->pull_regmap = syscon_regmap_lookup_by_phandle(dev_of_node(dev),
|
||||||
|
"ambarella,pull-syscon");
|
||||||
|
if (IS_ERR(ipc->pull_regmap))
|
||||||
|
return dev_err_probe(dev, PTR_ERR(ipc->pull_regmap),
|
||||||
|
"missing pull syscon\n");
|
||||||
|
|
||||||
|
spin_lock_init(&ipc->lock);
|
||||||
|
|
||||||
|
ret = amb_pinctrl_register(ipc);
|
||||||
|
if (ret)
|
||||||
|
return dev_err_probe(dev, ret, "failed to register pinctrl\n");
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, ipc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id amb_pinctrl_dt_match[] = {
|
||||||
|
{
|
||||||
|
.compatible = "ambarella,cv75-pinctrl",
|
||||||
|
.data = &ambarella_cv75_pinctrl_data,
|
||||||
|
},
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, amb_pinctrl_dt_match);
|
||||||
|
|
||||||
|
static struct platform_driver amb_pinctrl_driver = {
|
||||||
|
.probe = amb_pinctrl_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "ambarella-pinctrl",
|
||||||
|
.of_match_table = amb_pinctrl_dt_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init amb_pinctrl_drv_register(void)
|
||||||
|
{
|
||||||
|
return platform_driver_register(&amb_pinctrl_driver);
|
||||||
|
}
|
||||||
|
arch_initcall(amb_pinctrl_drv_register);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Cao Rongrong <rrcao@ambarella.com>");
|
||||||
|
MODULE_DESCRIPTION("Ambarella SoC pinctrl driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
40
drivers/pinctrl/pinctrl-ambarella.h
Normal file
40
drivers/pinctrl/pinctrl-ambarella.h
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
/*
|
||||||
|
* Ambarella pinctrl SoC data
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012-2026, Ambarella, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PINCTRL_AMBARELLA_H
|
||||||
|
#define _PINCTRL_AMBARELLA_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#define AMBA_MAX_BANKS 8
|
||||||
|
|
||||||
|
struct pingroup;
|
||||||
|
struct pinfunction;
|
||||||
|
|
||||||
|
struct amb_pinmux_group {
|
||||||
|
const struct pingroup *grp;
|
||||||
|
const u8 *alts;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct amb_pinctrl_data {
|
||||||
|
const struct amb_pinmux_group *groups;
|
||||||
|
const struct pinfunction *functions;
|
||||||
|
unsigned int ngroups;
|
||||||
|
unsigned int nfunctions;
|
||||||
|
unsigned int nr_banks;
|
||||||
|
unsigned int npins;
|
||||||
|
unsigned int ds0[AMBA_MAX_BANKS];
|
||||||
|
unsigned int ds1[AMBA_MAX_BANKS];
|
||||||
|
unsigned int ds2[AMBA_MAX_BANKS];
|
||||||
|
unsigned int pull_en[AMBA_MAX_BANKS];
|
||||||
|
unsigned int pull_dir[AMBA_MAX_BANKS];
|
||||||
|
bool have_ds2;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct amb_pinctrl_data ambarella_cv75_pinctrl_data;
|
||||||
|
|
||||||
|
#endif /* _PINCTRL_AMBARELLA_H */
|
||||||
Loading…
Reference in New Issue
Block a user