Merge branch 'ib-ambarella-pinctrl' into devel

This commit is contained in:
Linus Walleij 2026-10-01 09:05:50 +02:00
commit 97af3153f0
6 changed files with 1416 additions and 0 deletions

View File

@ -0,0 +1,237 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/pinctrl/ambarella,cv75-pinctrl.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Ambarella CV75 Pin Controller
maintainers:
- Long Zhao <longzhao@ambarella.com>
description:
The Ambarella CV75 pin controller configures pin multiplexing, bias and
drive strength for the main GPIO banks. Pin groups and their mux settings
are defined by the pin controller driver and selected by function and group
names.
allOf:
- $ref: pinctrl.yaml#
properties:
compatible:
const: ambarella,cv75-pinctrl
reg:
maxItems: 1
description: IOMUX registers
ambarella,drive-strength-syscon:
$ref: /schemas/types.yaml#/definitions/phandle
description: RCT syscon containing the drive-strength registers.
ambarella,pull-syscon:
$ref: /schemas/types.yaml#/definitions/phandle
description: Secure scratchpad syscon containing the pull registers.
patternProperties:
"^[a-z0-9-]+-pins$":
type: object
allOf:
- $ref: pinmux-node.yaml#
- $ref: pincfg-node.yaml#
additionalProperties: false
properties:
function:
enum:
- can0
- can1
- dmic0
- enet0
- hsync0
- hsync1
- i2c0
- i2c1
- i2c2
- i2c3
- i2cs
- i2s0
- i2s1
- ir
- pwm0
- pwm1
- pwm2
- pwm3
- pwm4
- pwm5
- pwm6
- pwm7
- pwm8
- pwm9
- pwm10
- pwm11
- sdmmc0
- sdmmc1
- snand
- spi0
- spi1
- spi2
- spi3
- spi_slave
- spinor
- uart0
- uart1
- uart2
- uart3
- uart4
- vin_master_sync
- vsync0
- vsync1
- vsync2
- vsync3
- wdt
groups:
items:
enum:
- can0
- can1
- dmic0
- enet_2nd_ref_clk_a
- enet_2nd_ref_clk_b
- enet_ext_osc_clk
- enet0_ptp_pps_o
- hsync0
- hsync1
- i2c0_a
- i2c0_b
- i2c1_a
- i2c1_b
- i2c2
- i2c3_a
- i2c3_b
- i2c3_c
- i2cs_a
- i2cs_b
- i2cs_c
- i2cs_d
- i2s0
- i2s1
- ir
- pwm0
- pwm1
- pwm2
- pwm3
- pwm4_a
- pwm4_b
- pwm5_a
- pwm5_b
- pwm6_a
- pwm6_b
- pwm7_a
- pwm7_b
- pwm8_a
- pwm8_b
- pwm9_a
- pwm9_b
- pwm10_a
- pwm10_b
- pwm11_a
- pwm11_b
- rgmii0
- rmii0
- sdmmc0_1bit
- sdmmc0_4bit
- sdmmc0_cd
- sdmmc0_hs_sel
- sdmmc0_reset
- sdmmc0_wp
- sdmmc1_1bit
- sdmmc1_4bit
- sdmmc1_cd
- sdmmc1_hs_sel
- sdmmc1_reset
- sdmmc1_wp
- snand
- spi0
- spi1
- spi2
- spi3_a
- spi3_b
- spi3_c
- spi_slave_a
- spi_slave_b
- spi_slave_c
- spi_slave_d
- spi_slave_e
- spinor
- uart0
- uart1
- uart1_flow
- uart2_a
- uart2_b
- uart2_c
- uart2_flow_a
- uart2_flow_b
- uart3_a
- uart3_b
- uart3_flow_a
- uart3_flow_b
- uart4_a
- uart4_b
- uart4_flow_a
- uart4_flow_b
- vin_master_sync_a
- vin_master_sync_b
- vin_master_sync_c
- vin_master_sync_d
- vin_master_sync_e
- vsync0
- vsync1
- vsync2
- vsync3
- wdt_a
- wdt_b
- wdt_c
- wdt_d
- wdt_e
- wdt_f
minItems: 1
maxItems: 6
uniqueItems: true
bias-disable: true
bias-pull-down: true
bias-pull-up: true
drive-strength:
enum: [3, 4, 5, 6, 7, 8, 9, 12]
required:
- function
- groups
required:
- compatible
- reg
- ambarella,drive-strength-syscon
- ambarella,pull-syscon
unevaluatedProperties: false
examples:
- |
pinctrl: pinctrl@e4010000 {
compatible = "ambarella,cv75-pinctrl";
reg = <0xe4010000 0x1000>;
ambarella,drive-strength-syscon = <&rct>;
ambarella,pull-syscon = <&scratchpad>;
uart0-pins {
function = "uart0";
groups = "uart0";
bias-disable;
drive-strength = <8>;
};
};

View File

@ -37,6 +37,23 @@ config DEBUG_PINCTRL
help
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
bool "AMD GPIO pin control"
depends on HAS_IOMEM

View File

@ -10,6 +10,8 @@ obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o
obj-$(CONFIG_GENERIC_PINCTRL) += pinctrl-generic.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_AMDISP) += pinctrl-amdisp.o
obj-$(CONFIG_PINCTRL_APPLE_GPIO) += pinctrl-apple-gpio.o

View 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,
};

View 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");

View 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 */