2021-01-12 03:58:40 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright ( C ) 2020 Sean Anderson < seanga2 @ gmail . com >
* Copyright ( c ) 2020 Western Digital Corporation or its affiliates .
*/
2022-10-07 16:44:44 +03:00
# include <linux/bitfield.h>
2021-01-12 03:58:40 +03:00
# include <linux/clk.h>
2022-10-07 16:44:44 +03:00
# include <linux/io.h>
2021-01-12 03:58:40 +03:00
# include <linux/mfd/syscon.h>
2023-07-14 20:48:54 +03:00
# include <linux/of.h>
2021-01-12 03:58:40 +03:00
# include <linux/platform_device.h>
# include <linux/regmap.h>
2022-10-07 16:44:44 +03:00
# include <linux/seq_file.h>
2021-01-12 03:58:40 +03:00
# include <linux/slab.h>
2022-10-07 16:44:44 +03:00
# include <linux/pinctrl/pinconf-generic.h>
# include <linux/pinctrl/pinconf.h>
2021-01-12 03:58:40 +03:00
# include <linux/pinctrl/pinctrl.h>
# include <linux/pinctrl/pinmux.h>
# include <dt-bindings/pinctrl/k210-fpioa.h>
# include "core.h"
# include "pinconf.h"
# include "pinctrl-utils.h"
/*
* The K210 only implements 8 drive levels , even though
* there is register space for 16
*/
# define K210_PC_DRIVE_MASK GENMASK(11, 8)
# define K210_PC_DRIVE_SHIFT 8
# define K210_PC_DRIVE_0 (0 << K210_PC_DRIVE_SHIFT)
# define K210_PC_DRIVE_1 (1 << K210_PC_DRIVE_SHIFT)
# define K210_PC_DRIVE_2 (2 << K210_PC_DRIVE_SHIFT)
# define K210_PC_DRIVE_3 (3 << K210_PC_DRIVE_SHIFT)
# define K210_PC_DRIVE_4 (4 << K210_PC_DRIVE_SHIFT)
# define K210_PC_DRIVE_5 (5 << K210_PC_DRIVE_SHIFT)
# define K210_PC_DRIVE_6 (6 << K210_PC_DRIVE_SHIFT)
# define K210_PC_DRIVE_7 (7 << K210_PC_DRIVE_SHIFT)
# define K210_PC_DRIVE_MAX 7
# define K210_PC_MODE_MASK GENMASK(23, 12)
/*
* output enabled = = PC_OE & ( PC_OE_INV ^ FUNCTION_OE )
* where FUNCTION_OE is a physical signal from the function .
*/
# define K210_PC_OE BIT(12) /* Output Enable */
# define K210_PC_OE_INV BIT(13) /* INVert Output Enable */
# define K210_PC_DO_OE BIT(14) /* set Data Out to Output Enable sig */
# define K210_PC_DO_INV BIT(15) /* INVert final Data Output */
# define K210_PC_PU BIT(16) /* Pull Up */
# define K210_PC_PD BIT(17) /* Pull Down */
/* Strong pull up not implemented on K210 */
# define K210_PC_SL BIT(19) /* reduce SLew rate */
/* Same semantics as OE above */
# define K210_PC_IE BIT(20) /* Input Enable */
# define K210_PC_IE_INV BIT(21) /* INVert Input Enable */
# define K210_PC_DI_INV BIT(22) /* INVert Data Input */
# define K210_PC_ST BIT(23) /* Schmitt Trigger */
# define K210_PC_DI BIT(31) /* raw Data Input */
# define K210_PC_BIAS_MASK (K210_PC_PU & K210_PC_PD)
# define K210_PC_MODE_IN (K210_PC_IE | K210_PC_ST)
# define K210_PC_MODE_OUT (K210_PC_DRIVE_7 | K210_PC_OE)
# define K210_PC_MODE_I2C (K210_PC_MODE_IN | K210_PC_SL | \
K210_PC_OE | K210_PC_PU )
# define K210_PC_MODE_SCCB (K210_PC_MODE_I2C | \
K210_PC_OE_INV | K210_PC_IE_INV )
# define K210_PC_MODE_SPI (K210_PC_MODE_IN | K210_PC_IE_INV | \
K210_PC_MODE_OUT | K210_PC_OE_INV )
# define K210_PC_MODE_GPIO (K210_PC_MODE_IN | K210_PC_MODE_OUT)
# define K210_PG_FUNC GENMASK(7, 0)
# define K210_PG_DO BIT(8)
# define K210_PG_PIN GENMASK(22, 16)
/*
* struct k210_fpioa : Kendryte K210 FPIOA memory mapped registers
* @ pins : 48 32 - bits IO pin registers
* @ tie_en : 256 ( one per function ) input tie enable bits
* @ tie_val : 256 ( one per function ) input tie value bits
*/
struct k210_fpioa {
u32 pins [ 48 ] ;
u32 tie_en [ 8 ] ;
u32 tie_val [ 8 ] ;
} ;
struct k210_fpioa_data {
struct device * dev ;
struct pinctrl_dev * pctl ;
struct k210_fpioa __iomem * fpioa ;
struct regmap * sysctl_map ;
u32 power_offset ;
struct clk * clk ;
struct clk * pclk ;
} ;
# define K210_PIN_NAME(i) ("IO_" #i)
# define K210_PIN(i) [(i)] = PINCTRL_PIN((i), K210_PIN_NAME(i))
static const struct pinctrl_pin_desc k210_pins [ ] = {
K210_PIN ( 0 ) , K210_PIN ( 1 ) , K210_PIN ( 2 ) ,
K210_PIN ( 3 ) , K210_PIN ( 4 ) , K210_PIN ( 5 ) ,
K210_PIN ( 6 ) , K210_PIN ( 7 ) , K210_PIN ( 8 ) ,
K210_PIN ( 9 ) , K210_PIN ( 10 ) , K210_PIN ( 11 ) ,
K210_PIN ( 12 ) , K210_PIN ( 13 ) , K210_PIN ( 14 ) ,
K210_PIN ( 15 ) , K210_PIN ( 16 ) , K210_PIN ( 17 ) ,
K210_PIN ( 18 ) , K210_PIN ( 19 ) , K210_PIN ( 20 ) ,
K210_PIN ( 21 ) , K210_PIN ( 22 ) , K210_PIN ( 23 ) ,
K210_PIN ( 24 ) , K210_PIN ( 25 ) , K210_PIN ( 26 ) ,
K210_PIN ( 27 ) , K210_PIN ( 28 ) , K210_PIN ( 29 ) ,
K210_PIN ( 30 ) , K210_PIN ( 31 ) , K210_PIN ( 32 ) ,
K210_PIN ( 33 ) , K210_PIN ( 34 ) , K210_PIN ( 35 ) ,
K210_PIN ( 36 ) , K210_PIN ( 37 ) , K210_PIN ( 38 ) ,
K210_PIN ( 39 ) , K210_PIN ( 40 ) , K210_PIN ( 41 ) ,
K210_PIN ( 42 ) , K210_PIN ( 43 ) , K210_PIN ( 44 ) ,
K210_PIN ( 45 ) , K210_PIN ( 46 ) , K210_PIN ( 47 )
} ;
# define K210_NPINS ARRAY_SIZE(k210_pins)
/*
* Pin groups : each of the 48 programmable pins is a group .
* To this are added 8 power domain groups , which for the purposes of
* the pin subsystem , contain no pins . The power domain groups only exist
* to set the power level . The id should never be used ( since there are
* no pins 48 - 55 ) .
*/
static const char * const k210_group_names [ ] = {
/* The first 48 groups are for pins, one each */
K210_PIN_NAME ( 0 ) , K210_PIN_NAME ( 1 ) , K210_PIN_NAME ( 2 ) ,
K210_PIN_NAME ( 3 ) , K210_PIN_NAME ( 4 ) , K210_PIN_NAME ( 5 ) ,
K210_PIN_NAME ( 6 ) , K210_PIN_NAME ( 7 ) , K210_PIN_NAME ( 8 ) ,
K210_PIN_NAME ( 9 ) , K210_PIN_NAME ( 10 ) , K210_PIN_NAME ( 11 ) ,
K210_PIN_NAME ( 12 ) , K210_PIN_NAME ( 13 ) , K210_PIN_NAME ( 14 ) ,
K210_PIN_NAME ( 15 ) , K210_PIN_NAME ( 16 ) , K210_PIN_NAME ( 17 ) ,
K210_PIN_NAME ( 18 ) , K210_PIN_NAME ( 19 ) , K210_PIN_NAME ( 20 ) ,
K210_PIN_NAME ( 21 ) , K210_PIN_NAME ( 22 ) , K210_PIN_NAME ( 23 ) ,
K210_PIN_NAME ( 24 ) , K210_PIN_NAME ( 25 ) , K210_PIN_NAME ( 26 ) ,
K210_PIN_NAME ( 27 ) , K210_PIN_NAME ( 28 ) , K210_PIN_NAME ( 29 ) ,
K210_PIN_NAME ( 30 ) , K210_PIN_NAME ( 31 ) , K210_PIN_NAME ( 32 ) ,
K210_PIN_NAME ( 33 ) , K210_PIN_NAME ( 34 ) , K210_PIN_NAME ( 35 ) ,
K210_PIN_NAME ( 36 ) , K210_PIN_NAME ( 37 ) , K210_PIN_NAME ( 38 ) ,
K210_PIN_NAME ( 39 ) , K210_PIN_NAME ( 40 ) , K210_PIN_NAME ( 41 ) ,
K210_PIN_NAME ( 42 ) , K210_PIN_NAME ( 43 ) , K210_PIN_NAME ( 44 ) ,
K210_PIN_NAME ( 45 ) , K210_PIN_NAME ( 46 ) , K210_PIN_NAME ( 47 ) ,
[ 48 ] = " A0 " , [ 49 ] = " A1 " , [ 50 ] = " A2 " ,
[ 51 ] = " B3 " , [ 52 ] = " B4 " , [ 53 ] = " B5 " ,
[ 54 ] = " C6 " , [ 55 ] = " C7 "
} ;
# define K210_NGROUPS ARRAY_SIZE(k210_group_names)
enum k210_pinctrl_mode_id {
K210_PC_DEFAULT_DISABLED ,
K210_PC_DEFAULT_IN ,
K210_PC_DEFAULT_IN_TIE ,
K210_PC_DEFAULT_OUT ,
K210_PC_DEFAULT_I2C ,
K210_PC_DEFAULT_SCCB ,
K210_PC_DEFAULT_SPI ,
K210_PC_DEFAULT_GPIO ,
K210_PC_DEFAULT_INT13 ,
} ;
# define K210_PC_DEFAULT(mode) \
[ K210_PC_DEFAULT_ # # mode ] = K210_PC_MODE_ # # mode
static const u32 k210_pinconf_mode_id_to_mode [ ] = {
[ K210_PC_DEFAULT_DISABLED ] = 0 ,
K210_PC_DEFAULT ( IN ) ,
[ K210_PC_DEFAULT_IN_TIE ] = K210_PC_MODE_IN ,
K210_PC_DEFAULT ( OUT ) ,
K210_PC_DEFAULT ( I2C ) ,
K210_PC_DEFAULT ( SCCB ) ,
K210_PC_DEFAULT ( SPI ) ,
K210_PC_DEFAULT ( GPIO ) ,
[ K210_PC_DEFAULT_INT13 ] = K210_PC_MODE_IN | K210_PC_PU ,
} ;
# undef DEFAULT
/*
* Pin functions configuration information .
*/
struct k210_pcf_info {
char name [ 15 ] ;
u8 mode_id ;
} ;
# define K210_FUNC(id, mode) \
[ K210_PCF_ # # id ] = { \
. name = # id , \
. mode_id = K210_PC_DEFAULT_ # # mode \
}
static const struct k210_pcf_info k210_pcf_infos [ ] = {
K210_FUNC ( JTAG_TCLK , IN ) ,
K210_FUNC ( JTAG_TDI , IN ) ,
K210_FUNC ( JTAG_TMS , IN ) ,
K210_FUNC ( JTAG_TDO , OUT ) ,
K210_FUNC ( SPI0_D0 , SPI ) ,
K210_FUNC ( SPI0_D1 , SPI ) ,
K210_FUNC ( SPI0_D2 , SPI ) ,
K210_FUNC ( SPI0_D3 , SPI ) ,
K210_FUNC ( SPI0_D4 , SPI ) ,
K210_FUNC ( SPI0_D5 , SPI ) ,
K210_FUNC ( SPI0_D6 , SPI ) ,
K210_FUNC ( SPI0_D7 , SPI ) ,
K210_FUNC ( SPI0_SS0 , OUT ) ,
K210_FUNC ( SPI0_SS1 , OUT ) ,
K210_FUNC ( SPI0_SS2 , OUT ) ,
K210_FUNC ( SPI0_SS3 , OUT ) ,
K210_FUNC ( SPI0_ARB , IN_TIE ) ,
K210_FUNC ( SPI0_SCLK , OUT ) ,
K210_FUNC ( UARTHS_RX , IN ) ,
K210_FUNC ( UARTHS_TX , OUT ) ,
K210_FUNC ( RESV6 , IN ) ,
K210_FUNC ( RESV7 , IN ) ,
K210_FUNC ( CLK_SPI1 , OUT ) ,
K210_FUNC ( CLK_I2C1 , OUT ) ,
K210_FUNC ( GPIOHS0 , GPIO ) ,
K210_FUNC ( GPIOHS1 , GPIO ) ,
K210_FUNC ( GPIOHS2 , GPIO ) ,
K210_FUNC ( GPIOHS3 , GPIO ) ,
K210_FUNC ( GPIOHS4 , GPIO ) ,
K210_FUNC ( GPIOHS5 , GPIO ) ,
K210_FUNC ( GPIOHS6 , GPIO ) ,
K210_FUNC ( GPIOHS7 , GPIO ) ,
K210_FUNC ( GPIOHS8 , GPIO ) ,
K210_FUNC ( GPIOHS9 , GPIO ) ,
K210_FUNC ( GPIOHS10 , GPIO ) ,
K210_FUNC ( GPIOHS11 , GPIO ) ,
K210_FUNC ( GPIOHS12 , GPIO ) ,
K210_FUNC ( GPIOHS13 , GPIO ) ,
K210_FUNC ( GPIOHS14 , GPIO ) ,
K210_FUNC ( GPIOHS15 , GPIO ) ,
K210_FUNC ( GPIOHS16 , GPIO ) ,
K210_FUNC ( GPIOHS17 , GPIO ) ,
K210_FUNC ( GPIOHS18 , GPIO ) ,
K210_FUNC ( GPIOHS19 , GPIO ) ,
K210_FUNC ( GPIOHS20 , GPIO ) ,
K210_FUNC ( GPIOHS21 , GPIO ) ,
K210_FUNC ( GPIOHS22 , GPIO ) ,
K210_FUNC ( GPIOHS23 , GPIO ) ,
K210_FUNC ( GPIOHS24 , GPIO ) ,
K210_FUNC ( GPIOHS25 , GPIO ) ,
K210_FUNC ( GPIOHS26 , GPIO ) ,
K210_FUNC ( GPIOHS27 , GPIO ) ,
K210_FUNC ( GPIOHS28 , GPIO ) ,
K210_FUNC ( GPIOHS29 , GPIO ) ,
K210_FUNC ( GPIOHS30 , GPIO ) ,
K210_FUNC ( GPIOHS31 , GPIO ) ,
K210_FUNC ( GPIO0 , GPIO ) ,
K210_FUNC ( GPIO1 , GPIO ) ,
K210_FUNC ( GPIO2 , GPIO ) ,
K210_FUNC ( GPIO3 , GPIO ) ,
K210_FUNC ( GPIO4 , GPIO ) ,
K210_FUNC ( GPIO5 , GPIO ) ,
K210_FUNC ( GPIO6 , GPIO ) ,
K210_FUNC ( GPIO7 , GPIO ) ,
K210_FUNC ( UART1_RX , IN ) ,
K210_FUNC ( UART1_TX , OUT ) ,
K210_FUNC ( UART2_RX , IN ) ,
K210_FUNC ( UART2_TX , OUT ) ,
K210_FUNC ( UART3_RX , IN ) ,
K210_FUNC ( UART3_TX , OUT ) ,
K210_FUNC ( SPI1_D0 , SPI ) ,
K210_FUNC ( SPI1_D1 , SPI ) ,
K210_FUNC ( SPI1_D2 , SPI ) ,
K210_FUNC ( SPI1_D3 , SPI ) ,
K210_FUNC ( SPI1_D4 , SPI ) ,
K210_FUNC ( SPI1_D5 , SPI ) ,
K210_FUNC ( SPI1_D6 , SPI ) ,
K210_FUNC ( SPI1_D7 , SPI ) ,
K210_FUNC ( SPI1_SS0 , OUT ) ,
K210_FUNC ( SPI1_SS1 , OUT ) ,
K210_FUNC ( SPI1_SS2 , OUT ) ,
K210_FUNC ( SPI1_SS3 , OUT ) ,
K210_FUNC ( SPI1_ARB , IN_TIE ) ,
K210_FUNC ( SPI1_SCLK , OUT ) ,
K210_FUNC ( SPI2_D0 , SPI ) ,
K210_FUNC ( SPI2_SS , IN ) ,
K210_FUNC ( SPI2_SCLK , IN ) ,
K210_FUNC ( I2S0_MCLK , OUT ) ,
K210_FUNC ( I2S0_SCLK , OUT ) ,
K210_FUNC ( I2S0_WS , OUT ) ,
K210_FUNC ( I2S0_IN_D0 , IN ) ,
K210_FUNC ( I2S0_IN_D1 , IN ) ,
K210_FUNC ( I2S0_IN_D2 , IN ) ,
K210_FUNC ( I2S0_IN_D3 , IN ) ,
K210_FUNC ( I2S0_OUT_D0 , OUT ) ,
K210_FUNC ( I2S0_OUT_D1 , OUT ) ,
K210_FUNC ( I2S0_OUT_D2 , OUT ) ,
K210_FUNC ( I2S0_OUT_D3 , OUT ) ,
K210_FUNC ( I2S1_MCLK , OUT ) ,
K210_FUNC ( I2S1_SCLK , OUT ) ,
K210_FUNC ( I2S1_WS , OUT ) ,
K210_FUNC ( I2S1_IN_D0 , IN ) ,
K210_FUNC ( I2S1_IN_D1 , IN ) ,
K210_FUNC ( I2S1_IN_D2 , IN ) ,
K210_FUNC ( I2S1_IN_D3 , IN ) ,
K210_FUNC ( I2S1_OUT_D0 , OUT ) ,
K210_FUNC ( I2S1_OUT_D1 , OUT ) ,
K210_FUNC ( I2S1_OUT_D2 , OUT ) ,
K210_FUNC ( I2S1_OUT_D3 , OUT ) ,
K210_FUNC ( I2S2_MCLK , OUT ) ,
K210_FUNC ( I2S2_SCLK , OUT ) ,
K210_FUNC ( I2S2_WS , OUT ) ,
K210_FUNC ( I2S2_IN_D0 , IN ) ,
K210_FUNC ( I2S2_IN_D1 , IN ) ,
K210_FUNC ( I2S2_IN_D2 , IN ) ,
K210_FUNC ( I2S2_IN_D3 , IN ) ,
K210_FUNC ( I2S2_OUT_D0 , OUT ) ,
K210_FUNC ( I2S2_OUT_D1 , OUT ) ,
K210_FUNC ( I2S2_OUT_D2 , OUT ) ,
K210_FUNC ( I2S2_OUT_D3 , OUT ) ,
K210_FUNC ( RESV0 , DISABLED ) ,
K210_FUNC ( RESV1 , DISABLED ) ,
K210_FUNC ( RESV2 , DISABLED ) ,
K210_FUNC ( RESV3 , DISABLED ) ,
K210_FUNC ( RESV4 , DISABLED ) ,
K210_FUNC ( RESV5 , DISABLED ) ,
K210_FUNC ( I2C0_SCLK , I2C ) ,
K210_FUNC ( I2C0_SDA , I2C ) ,
K210_FUNC ( I2C1_SCLK , I2C ) ,
K210_FUNC ( I2C1_SDA , I2C ) ,
K210_FUNC ( I2C2_SCLK , I2C ) ,
K210_FUNC ( I2C2_SDA , I2C ) ,
K210_FUNC ( DVP_XCLK , OUT ) ,
K210_FUNC ( DVP_RST , OUT ) ,
K210_FUNC ( DVP_PWDN , OUT ) ,
K210_FUNC ( DVP_VSYNC , IN ) ,
K210_FUNC ( DVP_HSYNC , IN ) ,
K210_FUNC ( DVP_PCLK , IN ) ,
K210_FUNC ( DVP_D0 , IN ) ,
K210_FUNC ( DVP_D1 , IN ) ,
K210_FUNC ( DVP_D2 , IN ) ,
K210_FUNC ( DVP_D3 , IN ) ,
K210_FUNC ( DVP_D4 , IN ) ,
K210_FUNC ( DVP_D5 , IN ) ,
K210_FUNC ( DVP_D6 , IN ) ,
K210_FUNC ( DVP_D7 , IN ) ,
K210_FUNC ( SCCB_SCLK , SCCB ) ,
K210_FUNC ( SCCB_SDA , SCCB ) ,
K210_FUNC ( UART1_CTS , IN ) ,
K210_FUNC ( UART1_DSR , IN ) ,
K210_FUNC ( UART1_DCD , IN ) ,
K210_FUNC ( UART1_RI , IN ) ,
K210_FUNC ( UART1_SIR_IN , IN ) ,
K210_FUNC ( UART1_DTR , OUT ) ,
K210_FUNC ( UART1_RTS , OUT ) ,
K210_FUNC ( UART1_OUT2 , OUT ) ,
K210_FUNC ( UART1_OUT1 , OUT ) ,
K210_FUNC ( UART1_SIR_OUT , OUT ) ,
K210_FUNC ( UART1_BAUD , OUT ) ,
K210_FUNC ( UART1_RE , OUT ) ,
K210_FUNC ( UART1_DE , OUT ) ,
K210_FUNC ( UART1_RS485_EN , OUT ) ,
K210_FUNC ( UART2_CTS , IN ) ,
K210_FUNC ( UART2_DSR , IN ) ,
K210_FUNC ( UART2_DCD , IN ) ,
K210_FUNC ( UART2_RI , IN ) ,
K210_FUNC ( UART2_SIR_IN , IN ) ,
K210_FUNC ( UART2_DTR , OUT ) ,
K210_FUNC ( UART2_RTS , OUT ) ,
K210_FUNC ( UART2_OUT2 , OUT ) ,
K210_FUNC ( UART2_OUT1 , OUT ) ,
K210_FUNC ( UART2_SIR_OUT , OUT ) ,
K210_FUNC ( UART2_BAUD , OUT ) ,
K210_FUNC ( UART2_RE , OUT ) ,
K210_FUNC ( UART2_DE , OUT ) ,
K210_FUNC ( UART2_RS485_EN , OUT ) ,
K210_FUNC ( UART3_CTS , IN ) ,
K210_FUNC ( UART3_DSR , IN ) ,
K210_FUNC ( UART3_DCD , IN ) ,
K210_FUNC ( UART3_RI , IN ) ,
K210_FUNC ( UART3_SIR_IN , IN ) ,
K210_FUNC ( UART3_DTR , OUT ) ,
K210_FUNC ( UART3_RTS , OUT ) ,
K210_FUNC ( UART3_OUT2 , OUT ) ,
K210_FUNC ( UART3_OUT1 , OUT ) ,
K210_FUNC ( UART3_SIR_OUT , OUT ) ,
K210_FUNC ( UART3_BAUD , OUT ) ,
K210_FUNC ( UART3_RE , OUT ) ,
K210_FUNC ( UART3_DE , OUT ) ,
K210_FUNC ( UART3_RS485_EN , OUT ) ,
K210_FUNC ( TIMER0_TOGGLE1 , OUT ) ,
K210_FUNC ( TIMER0_TOGGLE2 , OUT ) ,
K210_FUNC ( TIMER0_TOGGLE3 , OUT ) ,
K210_FUNC ( TIMER0_TOGGLE4 , OUT ) ,
K210_FUNC ( TIMER1_TOGGLE1 , OUT ) ,
K210_FUNC ( TIMER1_TOGGLE2 , OUT ) ,
K210_FUNC ( TIMER1_TOGGLE3 , OUT ) ,
K210_FUNC ( TIMER1_TOGGLE4 , OUT ) ,
K210_FUNC ( TIMER2_TOGGLE1 , OUT ) ,
K210_FUNC ( TIMER2_TOGGLE2 , OUT ) ,
K210_FUNC ( TIMER2_TOGGLE3 , OUT ) ,
K210_FUNC ( TIMER2_TOGGLE4 , OUT ) ,
K210_FUNC ( CLK_SPI2 , OUT ) ,
K210_FUNC ( CLK_I2C2 , OUT ) ,
K210_FUNC ( INTERNAL0 , OUT ) ,
K210_FUNC ( INTERNAL1 , OUT ) ,
K210_FUNC ( INTERNAL2 , OUT ) ,
K210_FUNC ( INTERNAL3 , OUT ) ,
K210_FUNC ( INTERNAL4 , OUT ) ,
K210_FUNC ( INTERNAL5 , OUT ) ,
K210_FUNC ( INTERNAL6 , OUT ) ,
K210_FUNC ( INTERNAL7 , OUT ) ,
K210_FUNC ( INTERNAL8 , OUT ) ,
K210_FUNC ( INTERNAL9 , IN ) ,
K210_FUNC ( INTERNAL10 , IN ) ,
K210_FUNC ( INTERNAL11 , IN ) ,
K210_FUNC ( INTERNAL12 , IN ) ,
K210_FUNC ( INTERNAL13 , INT13 ) ,
K210_FUNC ( INTERNAL14 , I2C ) ,
K210_FUNC ( INTERNAL15 , IN ) ,
K210_FUNC ( INTERNAL16 , IN ) ,
K210_FUNC ( INTERNAL17 , IN ) ,
K210_FUNC ( CONSTANT , DISABLED ) ,
K210_FUNC ( INTERNAL18 , IN ) ,
K210_FUNC ( DEBUG0 , OUT ) ,
K210_FUNC ( DEBUG1 , OUT ) ,
K210_FUNC ( DEBUG2 , OUT ) ,
K210_FUNC ( DEBUG3 , OUT ) ,
K210_FUNC ( DEBUG4 , OUT ) ,
K210_FUNC ( DEBUG5 , OUT ) ,
K210_FUNC ( DEBUG6 , OUT ) ,
K210_FUNC ( DEBUG7 , OUT ) ,
K210_FUNC ( DEBUG8 , OUT ) ,
K210_FUNC ( DEBUG9 , OUT ) ,
K210_FUNC ( DEBUG10 , OUT ) ,
K210_FUNC ( DEBUG11 , OUT ) ,
K210_FUNC ( DEBUG12 , OUT ) ,
K210_FUNC ( DEBUG13 , OUT ) ,
K210_FUNC ( DEBUG14 , OUT ) ,
K210_FUNC ( DEBUG15 , OUT ) ,
K210_FUNC ( DEBUG16 , OUT ) ,
K210_FUNC ( DEBUG17 , OUT ) ,
K210_FUNC ( DEBUG18 , OUT ) ,
K210_FUNC ( DEBUG19 , OUT ) ,
K210_FUNC ( DEBUG20 , OUT ) ,
K210_FUNC ( DEBUG21 , OUT ) ,
K210_FUNC ( DEBUG22 , OUT ) ,
K210_FUNC ( DEBUG23 , OUT ) ,
K210_FUNC ( DEBUG24 , OUT ) ,
K210_FUNC ( DEBUG25 , OUT ) ,
K210_FUNC ( DEBUG26 , OUT ) ,
K210_FUNC ( DEBUG27 , OUT ) ,
K210_FUNC ( DEBUG28 , OUT ) ,
K210_FUNC ( DEBUG29 , OUT ) ,
K210_FUNC ( DEBUG30 , OUT ) ,
K210_FUNC ( DEBUG31 , OUT ) ,
} ;
# define PIN_CONFIG_OUTPUT_INVERT (PIN_CONFIG_END + 1)
# define PIN_CONFIG_INPUT_INVERT (PIN_CONFIG_END + 2)
static const struct pinconf_generic_params k210_pinconf_custom_params [ ] = {
{ " output-polarity-invert " , PIN_CONFIG_OUTPUT_INVERT , 1 } ,
{ " input-polarity-invert " , PIN_CONFIG_INPUT_INVERT , 1 } ,
} ;
/*
* Max drive strength in uA .
*/
static const int k210_pinconf_drive_strength [ ] = {
[ 0 ] = 11200 ,
[ 1 ] = 16800 ,
[ 2 ] = 22300 ,
[ 3 ] = 27800 ,
[ 4 ] = 33300 ,
[ 5 ] = 38700 ,
[ 6 ] = 44100 ,
[ 7 ] = 49500 ,
} ;
static int k210_pinconf_get_drive ( unsigned int max_strength_ua )
{
int i ;
2022-02-09 21:08:06 +03:00
for ( i = K210_PC_DRIVE_MAX ; i > = 0 ; i - - ) {
2021-01-12 03:58:40 +03:00
if ( k210_pinconf_drive_strength [ i ] < = max_strength_ua )
return i ;
}
return - EINVAL ;
}
static void k210_pinmux_set_pin_function ( struct pinctrl_dev * pctldev ,
u32 pin , u32 func )
{
struct k210_fpioa_data * pdata = pinctrl_dev_get_drvdata ( pctldev ) ;
const struct k210_pcf_info * info = & k210_pcf_infos [ func ] ;
u32 mode = k210_pinconf_mode_id_to_mode [ info - > mode_id ] ;
u32 val = func | mode ;
dev_dbg ( pdata - > dev , " set pin %u function %s (%u) -> 0x%08x \n " ,
pin , info - > name , func , val ) ;
writel ( val , & pdata - > fpioa - > pins [ pin ] ) ;
}
static int k210_pinconf_set_param ( struct pinctrl_dev * pctldev ,
unsigned int pin ,
unsigned int param , unsigned int arg )
{
struct k210_fpioa_data * pdata = pinctrl_dev_get_drvdata ( pctldev ) ;
u32 val = readl ( & pdata - > fpioa - > pins [ pin ] ) ;
int drive ;
dev_dbg ( pdata - > dev , " set pin %u param %u, arg 0x%x \n " ,
pin , param , arg ) ;
switch ( param ) {
case PIN_CONFIG_BIAS_DISABLE :
val & = ~ K210_PC_BIAS_MASK ;
break ;
case PIN_CONFIG_BIAS_PULL_DOWN :
if ( ! arg )
return - EINVAL ;
val | = K210_PC_PD ;
break ;
case PIN_CONFIG_BIAS_PULL_UP :
if ( ! arg )
return - EINVAL ;
2022-02-09 21:28:22 +03:00
val | = K210_PC_PU ;
2021-01-12 03:58:40 +03:00
break ;
case PIN_CONFIG_DRIVE_STRENGTH :
arg * = 1000 ;
fallthrough ;
case PIN_CONFIG_DRIVE_STRENGTH_UA :
drive = k210_pinconf_get_drive ( arg ) ;
if ( drive < 0 )
return drive ;
val & = ~ K210_PC_DRIVE_MASK ;
val | = FIELD_PREP ( K210_PC_DRIVE_MASK , drive ) ;
break ;
case PIN_CONFIG_INPUT_ENABLE :
if ( arg )
val | = K210_PC_IE ;
else
val & = ~ K210_PC_IE ;
break ;
case PIN_CONFIG_INPUT_SCHMITT_ENABLE :
if ( arg )
val | = K210_PC_ST ;
else
val & = ~ K210_PC_ST ;
break ;
case PIN_CONFIG_OUTPUT :
k210_pinmux_set_pin_function ( pctldev , pin , K210_PCF_CONSTANT ) ;
val = readl ( & pdata - > fpioa - > pins [ pin ] ) ;
val | = K210_PC_MODE_OUT ;
if ( ! arg )
val | = K210_PC_DO_INV ;
break ;
case PIN_CONFIG_OUTPUT_ENABLE :
if ( arg )
val | = K210_PC_OE ;
else
val & = ~ K210_PC_OE ;
break ;
case PIN_CONFIG_SLEW_RATE :
if ( arg )
val | = K210_PC_SL ;
else
val & = ~ K210_PC_SL ;
break ;
case PIN_CONFIG_OUTPUT_INVERT :
if ( arg )
val | = K210_PC_DO_INV ;
else
val & = ~ K210_PC_DO_INV ;
break ;
case PIN_CONFIG_INPUT_INVERT :
if ( arg )
val | = K210_PC_DI_INV ;
else
val & = ~ K210_PC_DI_INV ;
break ;
default :
return - EINVAL ;
}
writel ( val , & pdata - > fpioa - > pins [ pin ] ) ;
return 0 ;
}
static int k210_pinconf_set ( struct pinctrl_dev * pctldev , unsigned int pin ,
unsigned long * configs , unsigned int num_configs )
{
unsigned int param , arg ;
int i , ret ;
if ( WARN_ON ( pin > = K210_NPINS ) )
return - EINVAL ;
for ( i = 0 ; i < num_configs ; i + + ) {
param = pinconf_to_config_param ( configs [ i ] ) ;
arg = pinconf_to_config_argument ( configs [ i ] ) ;
ret = k210_pinconf_set_param ( pctldev , pin , param , arg ) ;
if ( ret )
return ret ;
}
return 0 ;
}
static void k210_pinconf_dbg_show ( struct pinctrl_dev * pctldev ,
struct seq_file * s , unsigned int pin )
{
struct k210_fpioa_data * pdata = pinctrl_dev_get_drvdata ( pctldev ) ;
seq_printf ( s , " %#x " , readl ( & pdata - > fpioa - > pins [ pin ] ) ) ;
}
static int k210_pinconf_group_set ( struct pinctrl_dev * pctldev ,
unsigned int selector , unsigned long * configs ,
unsigned int num_configs )
{
struct k210_fpioa_data * pdata = pinctrl_dev_get_drvdata ( pctldev ) ;
unsigned int param , arg ;
u32 bit ;
int i ;
/* Pins should be configured with pinmux, not groups*/
if ( selector < K210_NPINS )
return - EINVAL ;
/* Otherwise it's a power domain */
for ( i = 0 ; i < num_configs ; i + + ) {
param = pinconf_to_config_param ( configs [ i ] ) ;
if ( param ! = PIN_CONFIG_POWER_SOURCE )
return - EINVAL ;
arg = pinconf_to_config_argument ( configs [ i ] ) ;
bit = BIT ( selector - K210_NPINS ) ;
regmap_update_bits ( pdata - > sysctl_map ,
pdata - > power_offset ,
bit , arg ? bit : 0 ) ;
}
return 0 ;
}
static void k210_pinconf_group_dbg_show ( struct pinctrl_dev * pctldev ,
struct seq_file * s ,
unsigned int selector )
{
struct k210_fpioa_data * pdata = pinctrl_dev_get_drvdata ( pctldev ) ;
int ret ;
u32 val ;
if ( selector < K210_NPINS )
return k210_pinconf_dbg_show ( pctldev , s , selector ) ;
ret = regmap_read ( pdata - > sysctl_map , pdata - > power_offset , & val ) ;
if ( ret ) {
dev_err ( pdata - > dev , " Failed to read power reg \n " ) ;
return ;
}
seq_printf ( s , " %s: %s V " , k210_group_names [ selector ] ,
val & BIT ( selector - K210_NPINS ) ? " 1.8 " : " 3.3 " ) ;
}
static const struct pinconf_ops k210_pinconf_ops = {
. is_generic = true ,
. pin_config_set = k210_pinconf_set ,
. pin_config_group_set = k210_pinconf_group_set ,
. pin_config_dbg_show = k210_pinconf_dbg_show ,
. pin_config_group_dbg_show = k210_pinconf_group_dbg_show ,
} ;
static int k210_pinmux_get_function_count ( struct pinctrl_dev * pctldev )
{
return ARRAY_SIZE ( k210_pcf_infos ) ;
}
static const char * k210_pinmux_get_function_name ( struct pinctrl_dev * pctldev ,
unsigned int selector )
{
return k210_pcf_infos [ selector ] . name ;
}
static int k210_pinmux_get_function_groups ( struct pinctrl_dev * pctldev ,
unsigned int selector ,
const char * const * * groups ,
unsigned int * const num_groups )
{
/* Any function can be mapped to any pin */
* groups = k210_group_names ;
* num_groups = K210_NPINS ;
return 0 ;
}
static int k210_pinmux_set_mux ( struct pinctrl_dev * pctldev ,
unsigned int function ,
unsigned int group )
{
/* Can't mux power domains */
if ( group > = K210_NPINS )
return - EINVAL ;
k210_pinmux_set_pin_function ( pctldev , group , function ) ;
return 0 ;
}
static const struct pinmux_ops k210_pinmux_ops = {
. get_functions_count = k210_pinmux_get_function_count ,
. get_function_name = k210_pinmux_get_function_name ,
. get_function_groups = k210_pinmux_get_function_groups ,
. set_mux = k210_pinmux_set_mux ,
. strict = true ,
} ;
static int k210_pinctrl_get_groups_count ( struct pinctrl_dev * pctldev )
{
return K210_NGROUPS ;
}
static const char * k210_pinctrl_get_group_name ( struct pinctrl_dev * pctldev ,
unsigned int group )
{
return k210_group_names [ group ] ;
}
static int k210_pinctrl_get_group_pins ( struct pinctrl_dev * pctldev ,
unsigned int group ,
const unsigned int * * pins ,
unsigned int * npins )
{
if ( group > = K210_NPINS ) {
* pins = NULL ;
* npins = 0 ;
return 0 ;
}
* pins = & k210_pins [ group ] . number ;
* npins = 1 ;
return 0 ;
}
static void k210_pinctrl_pin_dbg_show ( struct pinctrl_dev * pctldev ,
struct seq_file * s , unsigned int offset )
{
seq_printf ( s , " %s " , dev_name ( pctldev - > dev ) ) ;
}
static int k210_pinctrl_dt_subnode_to_map ( struct pinctrl_dev * pctldev ,
struct device_node * np ,
struct pinctrl_map * * map ,
unsigned int * reserved_maps ,
unsigned int * num_maps )
{
struct property * prop ;
const __be32 * p ;
int ret , pinmux_groups ;
u32 pinmux_group ;
unsigned long * configs = NULL ;
unsigned int num_configs = 0 ;
unsigned int reserve = 0 ;
ret = of_property_count_strings ( np , " groups " ) ;
if ( ! ret )
return pinconf_generic_dt_subnode_to_map ( pctldev , np , map ,
reserved_maps , num_maps ,
PIN_MAP_TYPE_CONFIGS_GROUP ) ;
pinmux_groups = of_property_count_u32_elems ( np , " pinmux " ) ;
if ( pinmux_groups < = 0 ) {
/* Ignore this node */
return 0 ;
}
ret = pinconf_generic_parse_dt_config ( np , pctldev , & configs ,
& num_configs ) ;
if ( ret < 0 ) {
dev_err ( pctldev - > dev , " %pOF: could not parse node property \n " ,
np ) ;
return ret ;
}
reserve = pinmux_groups * ( 1 + num_configs ) ;
ret = pinctrl_utils_reserve_map ( pctldev , map , reserved_maps , num_maps ,
reserve ) ;
if ( ret < 0 )
goto exit ;
of_property_for_each_u32 ( np , " pinmux " , prop , p , pinmux_group ) {
const char * group_name , * func_name ;
u32 pin = FIELD_GET ( K210_PG_PIN , pinmux_group ) ;
u32 func = FIELD_GET ( K210_PG_FUNC , pinmux_group ) ;
if ( pin > = K210_NPINS ) {
ret = - EINVAL ;
goto exit ;
}
group_name = k210_group_names [ pin ] ;
func_name = k210_pcf_infos [ func ] . name ;
dev_dbg ( pctldev - > dev , " Pinmux %s: pin %u func %s \n " ,
np - > name , pin , func_name ) ;
ret = pinctrl_utils_add_map_mux ( pctldev , map , reserved_maps ,
num_maps , group_name ,
func_name ) ;
if ( ret < 0 ) {
dev_err ( pctldev - > dev , " %pOF add mux map failed %d \n " ,
np , ret ) ;
goto exit ;
}
if ( num_configs ) {
ret = pinctrl_utils_add_map_configs ( pctldev , map ,
reserved_maps , num_maps , group_name ,
configs , num_configs ,
PIN_MAP_TYPE_CONFIGS_PIN ) ;
if ( ret < 0 ) {
dev_err ( pctldev - > dev ,
" %pOF add configs map failed %d \n " ,
np , ret ) ;
goto exit ;
}
}
}
ret = 0 ;
exit :
kfree ( configs ) ;
return ret ;
}
static int k210_pinctrl_dt_node_to_map ( struct pinctrl_dev * pctldev ,
struct device_node * np_config ,
struct pinctrl_map * * map ,
unsigned int * num_maps )
{
unsigned int reserved_maps ;
struct device_node * np ;
int ret ;
reserved_maps = 0 ;
* map = NULL ;
* num_maps = 0 ;
ret = k210_pinctrl_dt_subnode_to_map ( pctldev , np_config , map ,
& reserved_maps , num_maps ) ;
if ( ret < 0 )
goto err ;
for_each_available_child_of_node ( np_config , np ) {
ret = k210_pinctrl_dt_subnode_to_map ( pctldev , np , map ,
& reserved_maps , num_maps ) ;
2022-11-22 10:58:53 +03:00
if ( ret < 0 ) {
of_node_put ( np ) ;
2021-01-12 03:58:40 +03:00
goto err ;
2022-11-22 10:58:53 +03:00
}
2021-01-12 03:58:40 +03:00
}
return 0 ;
err :
pinctrl_utils_free_map ( pctldev , * map , * num_maps ) ;
return ret ;
}
static const struct pinctrl_ops k210_pinctrl_ops = {
. get_groups_count = k210_pinctrl_get_groups_count ,
. get_group_name = k210_pinctrl_get_group_name ,
. get_group_pins = k210_pinctrl_get_group_pins ,
. pin_dbg_show = k210_pinctrl_pin_dbg_show ,
. dt_node_to_map = k210_pinctrl_dt_node_to_map ,
. dt_free_map = pinconf_generic_dt_free_map ,
} ;
static struct pinctrl_desc k210_pinctrl_desc = {
. name = " k210-pinctrl " ,
. pins = k210_pins ,
. npins = K210_NPINS ,
. pctlops = & k210_pinctrl_ops ,
. pmxops = & k210_pinmux_ops ,
. confops = & k210_pinconf_ops ,
. custom_params = k210_pinconf_custom_params ,
. num_custom_params = ARRAY_SIZE ( k210_pinconf_custom_params ) ,
} ;
static void k210_fpioa_init_ties ( struct k210_fpioa_data * pdata )
{
struct k210_fpioa __iomem * fpioa = pdata - > fpioa ;
u32 val ;
int i , j ;
dev_dbg ( pdata - > dev , " Init pin ties \n " ) ;
/* Init pin functions input ties */
for ( i = 0 ; i < ARRAY_SIZE ( fpioa - > tie_en ) ; i + + ) {
val = 0 ;
for ( j = 0 ; j < 32 ; j + + ) {
if ( k210_pcf_infos [ i * 32 + j ] . mode_id = =
K210_PC_DEFAULT_IN_TIE ) {
dev_dbg ( pdata - > dev ,
" tie_en function %d (%s) \n " ,
i * 32 + j ,
k210_pcf_infos [ i * 32 + j ] . name ) ;
val | = BIT ( j ) ;
}
}
/* Set value before enable */
writel ( val , & fpioa - > tie_val [ i ] ) ;
writel ( val , & fpioa - > tie_en [ i ] ) ;
}
}
static int k210_fpioa_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct device_node * np = dev - > of_node ;
struct k210_fpioa_data * pdata ;
int ret ;
dev_info ( dev , " K210 FPIOA pin controller \n " ) ;
pdata = devm_kzalloc ( dev , sizeof ( * pdata ) , GFP_KERNEL ) ;
if ( ! pdata )
return - ENOMEM ;
pdata - > dev = dev ;
platform_set_drvdata ( pdev , pdata ) ;
pdata - > fpioa = devm_platform_ioremap_resource ( pdev , 0 ) ;
if ( IS_ERR ( pdata - > fpioa ) )
return PTR_ERR ( pdata - > fpioa ) ;
pdata - > clk = devm_clk_get ( dev , " ref " ) ;
if ( IS_ERR ( pdata - > clk ) )
return PTR_ERR ( pdata - > clk ) ;
ret = clk_prepare_enable ( pdata - > clk ) ;
if ( ret )
return ret ;
pdata - > pclk = devm_clk_get_optional ( dev , " pclk " ) ;
2021-08-06 03:43:11 +03:00
if ( ! IS_ERR ( pdata - > pclk ) ) {
ret = clk_prepare_enable ( pdata - > pclk ) ;
if ( ret )
goto disable_clk ;
}
2021-01-12 03:58:40 +03:00
pdata - > sysctl_map =
syscon_regmap_lookup_by_phandle_args ( np ,
" canaan,k210-sysctl-power " ,
1 , & pdata - > power_offset ) ;
2021-08-06 03:43:11 +03:00
if ( IS_ERR ( pdata - > sysctl_map ) ) {
ret = PTR_ERR ( pdata - > sysctl_map ) ;
goto disable_pclk ;
}
2021-01-12 03:58:40 +03:00
k210_fpioa_init_ties ( pdata ) ;
pdata - > pctl = pinctrl_register ( & k210_pinctrl_desc , dev , ( void * ) pdata ) ;
2021-08-06 03:43:11 +03:00
if ( IS_ERR ( pdata - > pctl ) ) {
ret = PTR_ERR ( pdata - > pctl ) ;
goto disable_pclk ;
}
2021-01-12 03:58:40 +03:00
return 0 ;
2021-08-06 03:43:11 +03:00
disable_pclk :
clk_disable_unprepare ( pdata - > pclk ) ;
disable_clk :
clk_disable_unprepare ( pdata - > clk ) ;
return ret ;
2021-01-12 03:58:40 +03:00
}
static const struct of_device_id k210_fpioa_dt_ids [ ] = {
{ . compatible = " canaan,k210-fpioa " } ,
{ /* sentinel */ } ,
} ;
static struct platform_driver k210_fpioa_driver = {
. probe = k210_fpioa_probe ,
. driver = {
. name = " k210-fpioa " ,
. of_match_table = k210_fpioa_dt_ids ,
} ,
} ;
builtin_platform_driver ( k210_fpioa_driver ) ;