2021-12-01 12:56:26 +05:30
// SPDX-License-Identifier: GPL-2.0
/*
* Intel Thunder Bay SOC pinctrl / GPIO driver
*
* Copyright ( C ) 2021 Intel Corporation
*/
# include <linux/device.h>
# include <linux/err.h>
# include <linux/gpio/driver.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/irq.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/of_irq.h>
# include <linux/pinctrl/pinconf.h>
# include <linux/pinctrl/pinconf-generic.h>
# include <linux/pinctrl/pinctrl.h>
# include <linux/pinctrl/pinmux.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
# include "core.h"
# include "pinconf.h"
# include "pinctrl-utils.h"
# include "pinmux.h"
/* Bit 0:2 and 4:6 should be used for mode selection */
# define THB_GPIO_PINMUX_MODE_0 0x00
# define THB_GPIO_PINMUX_MODE_1 0x11
# define THB_GPIO_PINMUX_MODE_2 0x22
# define THB_GPIO_PINMUX_MODE_3 0x33
# define THB_GPIO_PINMUX_MODE_4 0x44
# define THB_GPIO_PORT_SELECT_MASK BIT(8)
# define THB_GPIO_PAD_DIRECTION_MASK BIT(10)
# define THB_GPIO_SPU_MASK BIT(11)
# define THB_GPIO_PULL_ENABLE_MASK BIT(12)
# define THB_GPIO_PULL_UP_MASK BIT(13)
# define THB_GPIO_PULL_DOWN_MASK BIT(14)
# define THB_GPIO_ENAQ_MASK BIT(15)
/* bit 16-19: Drive Strength for the Pad */
# define THB_GPIO_DRIVE_STRENGTH_MASK (0xF0000)
# define THB_GPIO_SLEW_RATE_MASK BIT(20)
# define THB_GPIO_SCHMITT_TRIGGER_MASK BIT(21)
# define THB_GPIO_REG_OFFSET(pin_num) ((pin_num) * (0x4))
# define THB_MAX_MODE_SUPPORTED (5u)
# define THB_MAX_NPINS_SUPPORTED (67u)
/* store Pin status */
static u32 thb_pinx_status [ THB_MAX_NPINS_SUPPORTED ] ;
struct thunderbay_mux_desc {
u8 mode ;
const char * name ;
} ;
# define THUNDERBAY_PIN_DESC(pin_number, pin_name, ...) { \
. number = pin_number , \
. name = pin_name , \
. drv_data = & ( struct thunderbay_mux_desc [ ] ) { \
__VA_ARGS__ , { } } , \
}
# define THUNDERBAY_MUX(pin_mode, pin_function) { \
. mode = pin_mode , \
. name = pin_function , \
}
struct thunderbay_pin_soc {
const struct pinctrl_pin_desc * pins ;
unsigned int npins ;
} ;
/**
* struct thunderbay_pinctrl - Intel Thunderbay pinctrl structure
* @ pctrl : Pointer to the pin controller device
* @ base0 : First register base address
* @ dev : Pointer to the device structure
* @ chip : GPIO chip used by this pin controller
* @ soc : Pin control configuration data based on SoC
* @ ngroups : Number of pin groups available
* @ nfuncs : Number of pin functions available
*/
struct thunderbay_pinctrl {
struct pinctrl_dev * pctrl ;
void __iomem * base0 ;
struct device * dev ;
struct gpio_chip chip ;
const struct thunderbay_pin_soc * soc ;
unsigned int ngroups ;
unsigned int nfuncs ;
} ;
static const struct pinctrl_pin_desc thunderbay_pins [ ] = {
THUNDERBAY_PIN_DESC ( 0 , " GPIO0 " ,
THUNDERBAY_MUX ( 0 X0 , " I2C0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 1 , " GPIO1 " ,
THUNDERBAY_MUX ( 0 X0 , " I2C0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 2 , " GPIO2 " ,
THUNDERBAY_MUX ( 0 X0 , " I2C1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 3 , " GPIO3 " ,
THUNDERBAY_MUX ( 0 X0 , " I2C1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 4 , " GPIO4 " ,
THUNDERBAY_MUX ( 0 X0 , " I2C2_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 5 , " GPIO5 " ,
THUNDERBAY_MUX ( 0 X0 , " I2C2_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 6 , " GPIO6 " ,
THUNDERBAY_MUX ( 0 X0 , " I2C3_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 7 , " GPIO7 " ,
THUNDERBAY_MUX ( 0 X0 , " I2C3_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 8 , " GPIO8 " ,
THUNDERBAY_MUX ( 0 X0 , " I2C4_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 9 , " GPIO9 " ,
THUNDERBAY_MUX ( 0 X0 , " I2C4_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 10 , " GPIO10 " ,
THUNDERBAY_MUX ( 0 X0 , " UART0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " RT0_DSU_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 11 , " GPIO11 " ,
THUNDERBAY_MUX ( 0 X0 , " UART0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " RT0_DSU_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 12 , " GPIO12 " ,
THUNDERBAY_MUX ( 0 X0 , " UART0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " RT1_DSU_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 13 , " GPIO13 " ,
THUNDERBAY_MUX ( 0 X0 , " UART0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " RT1_DSU_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 14 , " GPIO14 " ,
THUNDERBAY_MUX ( 0 X0 , " UART1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " RT2_DSU_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " TRIGGER_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 15 , " GPIO15 " ,
THUNDERBAY_MUX ( 0 X0 , " UART1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " RT2_DSU_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " TRIGGER_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 16 , " GPIO16 " ,
THUNDERBAY_MUX ( 0 X0 , " UART1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " RT3_DSU_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 17 , " GPIO17 " ,
THUNDERBAY_MUX ( 0 X0 , " UART1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " RT3_DSU_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 18 , " GPIO18 " ,
THUNDERBAY_MUX ( 0 X0 , " SPI0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 19 , " GPIO19 " ,
THUNDERBAY_MUX ( 0 X0 , " SPI0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 20 , " GPIO20 " ,
THUNDERBAY_MUX ( 0 X0 , " SPI0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_TRACE_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 21 , " GPIO21 " ,
THUNDERBAY_MUX ( 0 X0 , " SPI0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_TRACE_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 22 , " GPIO22 " ,
THUNDERBAY_MUX ( 0 X0 , " SPI1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M0 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 23 , " GPIO23 " ,
THUNDERBAY_MUX ( 0 X0 , " SPI1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 24 , " GPIO24 " ,
THUNDERBAY_MUX ( 0 X0 , " SPI1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_TRACE_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 25 , " GPIO25 " ,
THUNDERBAY_MUX ( 0 X0 , " SPI1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_TRACE_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 26 , " GPIO26 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DEBUG_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 27 , " GPIO27 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DEBUG_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 28 , " GPIO28 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DEBUG_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 29 , " GPIO29 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DEBUG_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 30 , " GPIO30 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DEBUG_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 31 , " GPIO31 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DEBUG_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 32 , " GPIO32 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DEBUG_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 33 , " GPIO33 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DEBUG_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 34 , " GPIO34 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DIG_VIEW_0 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 35 , " GPIO35 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DIG_VIEW_1 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 36 , " GPIO36 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " CPR_IO_OUT_CLK_0 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 37 , " GPIO37 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " CPR_IO_OUT_CLK_1 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 38 , " GPIO38 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " CPR_IO_OUT_CLK_2 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 39 , " GPIO39 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " CPR_IO_OUT_CLK_3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 40 , " GPIO40 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER0_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 41 , " GPIO41 " ,
THUNDERBAY_MUX ( 0 X0 , " POWER_INTERRUPT_MAX_PLATFORM_POWER_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 42 , " GPIO42 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DEBUG_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 43 , " GPIO43 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DEBUG_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 44 , " GPIO44 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DEBUG_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 45 , " GPIO45 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DEBUG_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 46 , " GPIO46 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DEBUG_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 47 , " GPIO47 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DEBUG_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 48 , " GPIO48 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DEBUG_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 49 , " GPIO49 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DEBUG_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 50 , " GPIO50 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DIG_VIEW_0 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 51 , " GPIO51 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " DIG_VIEW_1 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 52 , " GPIO52 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " CPR_IO_OUT_CLK_0 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 53 , " GPIO53 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " CPR_IO_OUT_CLK_1 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 54 , " GPIO54 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " CPR_IO_OUT_CLK_2 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 55 , " GPIO55 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " CPR_IO_OUT_CLK_3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 56 , " GPIO56 " ,
THUNDERBAY_MUX ( 0 X0 , " ETHER1_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " POWER_INTERRUPT_ICCMAX_VDDD_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 57 , " GPIO57 " ,
THUNDERBAY_MUX ( 0 X0 , " POWER_INTERRUPT_ICCMAX_VPU_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " TPIU_DATA_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " TPIU_DATA_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 58 , " GPIO58 " ,
THUNDERBAY_MUX ( 0 X0 , " THERMTRIP_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 59 , " GPIO59 " ,
THUNDERBAY_MUX ( 0 X0 , " THERMTRIP_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 60 , " GPIO60 " ,
THUNDERBAY_MUX ( 0 X0 , " SMBUS_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 61 , " GPIO61 " ,
THUNDERBAY_MUX ( 0 X0 , " SMBUS_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " POWER_INTERRUPT_ICCMAX_VDDD_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 62 , " GPIO62 " ,
THUNDERBAY_MUX ( 0 X0 , " PLATFORM_RESET_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 63 , " GPIO63 " ,
THUNDERBAY_MUX ( 0 X0 , " PLATFORM_RESET_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 64 , " GPIO64 " ,
THUNDERBAY_MUX ( 0 X0 , " PLATFORM_SHUTDOWN_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 65 , " GPIO65 " ,
THUNDERBAY_MUX ( 0 X0 , " PLATFORM_SHUTDOWN_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
THUNDERBAY_PIN_DESC ( 66 , " GPIO66 " ,
THUNDERBAY_MUX ( 0 X0 , " POWER_INTERRUPT_ICCMAX_MEDIA_M0 " ) ,
THUNDERBAY_MUX ( 0 X1 , " EMPTY_M1 " ) ,
THUNDERBAY_MUX ( 0 X2 , " EMPTY_M2 " ) ,
THUNDERBAY_MUX ( 0 X3 , " EMPTY_M3 " ) ,
THUNDERBAY_MUX ( 0 X4 , " GPIO_M4 " ) ) ,
} ;
static const struct thunderbay_pin_soc thunderbay_data = {
. pins = thunderbay_pins ,
. npins = ARRAY_SIZE ( thunderbay_pins ) ,
} ;
static u32 thb_gpio_read_reg ( struct gpio_chip * chip , unsigned int pinnr )
{
struct thunderbay_pinctrl * tpc = gpiochip_get_data ( chip ) ;
return readl ( tpc - > base0 + THB_GPIO_REG_OFFSET ( pinnr ) ) ;
}
static u32 thb_gpio_write_reg ( struct gpio_chip * chip , unsigned int pinnr , u32 value )
{
struct thunderbay_pinctrl * tpc = gpiochip_get_data ( chip ) ;
writel ( value , ( tpc - > base0 + THB_GPIO_REG_OFFSET ( pinnr ) ) ) ;
return 0 ;
}
static int thb_read_gpio_data ( struct gpio_chip * chip , unsigned int offset , unsigned int pad_dir )
{
int data_offset ;
u32 data_reg ;
/* as per GPIO Spec = pad_dir 0:input, 1:output */
data_offset = 0x2000u + ( offset / 32 ) ;
if ( ! pad_dir )
data_offset + = 4 ;
data_reg = thb_gpio_read_reg ( chip , data_offset ) ;
return data_reg & BIT ( offset % 32 ) ;
}
static int thb_write_gpio_data ( struct gpio_chip * chip , unsigned int offset , unsigned int value )
{
int data_offset ;
u32 data_reg ;
data_offset = 0x2000u + ( offset / 32 ) ;
data_reg = thb_gpio_read_reg ( chip , data_offset ) ;
if ( value > 0 )
data_reg | = BIT ( offset % 32 ) ;
else
data_reg & = ~ BIT ( offset % 32 ) ;
return thb_gpio_write_reg ( chip , data_offset , data_reg ) ;
}
static int thunderbay_gpio_get_direction ( struct gpio_chip * chip , unsigned int offset )
{
u32 reg = thb_gpio_read_reg ( chip , offset ) ;
/* Return direction only if configured as GPIO else negative error */
if ( reg & THB_GPIO_PORT_SELECT_MASK )
return ! ( reg & THB_GPIO_PAD_DIRECTION_MASK ) ;
return - EINVAL ;
}
static int thunderbay_gpio_set_direction_input ( struct gpio_chip * chip , unsigned int offset )
{
u32 reg = thb_gpio_read_reg ( chip , offset ) ;
/* set pin as input only if it is GPIO else error */
if ( reg & THB_GPIO_PORT_SELECT_MASK ) {
reg & = ( ~ THB_GPIO_PAD_DIRECTION_MASK ) ;
thb_gpio_write_reg ( chip , offset , reg ) ;
return 0 ;
}
return - EINVAL ;
}
static void thunderbay_gpio_set_value ( struct gpio_chip * chip , unsigned int offset , int value )
{
u32 reg = thb_gpio_read_reg ( chip , offset ) ;
/* update pin value only if it is GPIO-output else error */
if ( ( reg & THB_GPIO_PORT_SELECT_MASK ) & & ( reg & THB_GPIO_PAD_DIRECTION_MASK ) )
thb_write_gpio_data ( chip , offset , value ) ;
}
static int thunderbay_gpio_set_direction_output ( struct gpio_chip * chip ,
unsigned int offset , int value )
{
u32 reg = thb_gpio_read_reg ( chip , offset ) ;
/* set pin as output only if it is GPIO else error */
if ( reg & THB_GPIO_PORT_SELECT_MASK ) {
reg | = THB_GPIO_PAD_DIRECTION_MASK ;
thb_gpio_write_reg ( chip , offset , reg ) ;
thunderbay_gpio_set_value ( chip , offset , value ) ;
return 0 ;
}
return - EINVAL ;
}
static int thunderbay_gpio_get_value ( struct gpio_chip * chip , unsigned int offset )
{
u32 reg = thb_gpio_read_reg ( chip , offset ) ;
int gpio_dir = 0 ;
/* Read pin value only if it is GPIO else error */
if ( reg & THB_GPIO_PORT_SELECT_MASK ) {
/* 0=in, 1=out */
gpio_dir = ( reg & THB_GPIO_PAD_DIRECTION_MASK ) > 0 ;
/* Returns negative value when pin is configured as PORT */
return thb_read_gpio_data ( chip , offset , gpio_dir ) ;
}
return - EINVAL ;
}
static int thunderbay_gpiochip_probe ( struct thunderbay_pinctrl * tpc )
{
struct gpio_chip * chip = & tpc - > chip ;
int ret ;
chip - > label = dev_name ( tpc - > dev ) ;
chip - > parent = tpc - > dev ;
chip - > request = gpiochip_generic_request ;
chip - > free = gpiochip_generic_free ;
chip - > get_direction = thunderbay_gpio_get_direction ;
chip - > direction_input = thunderbay_gpio_set_direction_input ;
chip - > direction_output = thunderbay_gpio_set_direction_output ;
chip - > get = thunderbay_gpio_get_value ;
chip - > set = thunderbay_gpio_set_value ;
chip - > set_config = gpiochip_generic_config ;
/* identifies the first GPIO number handled by this chip; or,
* if negative during registration , requests dynamic ID allocation .
* Please pass - 1 as base to let gpiolib select the chip base in all possible cases .
* We want to get rid of the static GPIO number space in the long run .
*/
chip - > base = - 1 ;
/* Number of GPIOs handled by this controller; the last GPIO handled is (base + ngpio - 1)*/
chip - > ngpio = THB_MAX_NPINS_SUPPORTED ;
/* Register/add Thunder Bay GPIO chip with Linux framework */
ret = gpiochip_add_data ( chip , tpc ) ;
if ( ret )
dev_err ( tpc - > dev , " Failed to add gpiochip \n " ) ;
return ret ;
}
static int thunderbay_request_gpio ( struct pinctrl_dev * pctldev ,
struct pinctrl_gpio_range * range ,
unsigned int pin )
{
struct thunderbay_pinctrl * tpc = pinctrl_dev_get_drvdata ( pctldev ) ;
struct gpio_chip * chip = & tpc - > chip ;
u32 reg = 0 ;
if ( thb_pinx_status [ pin ] = = 0u ) {
reg = thb_gpio_read_reg ( chip , pin ) ;
/* Updates PIN configuration as GPIO and sets GPIO to MODE-4*/
reg | = ( THB_GPIO_PORT_SELECT_MASK | THB_GPIO_PINMUX_MODE_4 ) ;
thb_gpio_write_reg ( chip , pin , reg ) ;
/* update pin status as busy */
thb_pinx_status [ pin ] = 1u ;
return 0 ;
}
return - EINVAL ;
}
static void thunderbay_free_gpio ( struct pinctrl_dev * pctldev ,
struct pinctrl_gpio_range * range ,
unsigned int pin )
{
struct thunderbay_pinctrl * tpc = pinctrl_dev_get_drvdata ( pctldev ) ;
struct gpio_chip * chip = & tpc - > chip ;
u32 reg = 0 ;
if ( thb_pinx_status [ pin ] = = 1u ) {
reg = thb_gpio_read_reg ( chip , pin ) ;
/* Updates PIN configuration from GPIO to PORT */
reg & = ( ~ THB_GPIO_PORT_SELECT_MASK ) ;
/* Change Port/gpio mode to default mode-0 */
reg & = ( ~ THB_GPIO_PINMUX_MODE_4 ) ;
thb_gpio_write_reg ( chip , pin , reg ) ;
/* update pin status as free */
thb_pinx_status [ pin ] = 0u ;
}
}
static int thb_pinctrl_set_mux ( struct pinctrl_dev * pctldev ,
unsigned int func_select , unsigned int group_select )
{
struct thunderbay_pinctrl * tpc = pinctrl_dev_get_drvdata ( pctldev ) ;
struct gpio_chip * chip = & tpc - > chip ;
struct function_desc * function ;
unsigned int i , pin_mode ;
struct group_desc * group ;
int ret = - EINVAL ;
u32 reg = 0u ;
group = pinctrl_generic_get_group ( pctldev , group_select ) ;
if ( ! group )
return - EINVAL ;
function = pinmux_generic_get_function ( pctldev , func_select ) ;
if ( ! function )
return - EINVAL ;
pin_mode = * ( unsigned int * ) ( function - > data ) ;
/* Change modes for pins in the selected group */
for ( i = 0 ; i < group - > num_pins ; i + + ) {
reg = thb_gpio_read_reg ( chip , group - > pins [ i ] ) ;
switch ( pin_mode ) {
case 0u :
reg | = THB_GPIO_PINMUX_MODE_0 ;
break ;
case 1u :
reg | = THB_GPIO_PINMUX_MODE_1 ;
break ;
case 2u :
reg | = THB_GPIO_PINMUX_MODE_2 ;
break ;
case 3u :
reg | = THB_GPIO_PINMUX_MODE_3 ;
break ;
case 4u :
reg | = THB_GPIO_PINMUX_MODE_4 ;
break ;
default :
return - EINVAL ;
}
ret = thb_gpio_write_reg ( chip , group - > pins [ i ] , reg ) ;
if ( ~ ret ) {
/* update pin status as busy */
thb_pinx_status [ group - > pins [ i ] ] = 1u ;
}
}
return ret ;
}
static int thunderbay_build_groups ( struct thunderbay_pinctrl * tpc )
{
struct group_desc * thunderbay_groups ;
int i ;
tpc - > ngroups = tpc - > soc - > npins ;
thunderbay_groups = devm_kcalloc ( tpc - > dev , tpc - > ngroups ,
sizeof ( * thunderbay_groups ) , GFP_KERNEL ) ;
if ( ! thunderbay_groups )
return - ENOMEM ;
for ( i = 0 ; i < tpc - > ngroups ; i + + ) {
struct group_desc * group = thunderbay_groups + i ;
const struct pinctrl_pin_desc * pin_info = thunderbay_pins + i ;
group - > name = pin_info - > name ;
group - > pins = ( int * ) & pin_info - > number ;
pinctrl_generic_add_group ( tpc - > pctrl , group - > name ,
group - > pins , 1 , NULL ) ;
}
return 0 ;
}
static int thunderbay_add_functions ( struct thunderbay_pinctrl * tpc , struct function_desc * funcs )
{
struct function_desc * function = funcs ;
int i ;
/* Assign the groups for each function */
for ( i = 0 ; i < tpc - > soc - > npins ; i + + ) {
const struct pinctrl_pin_desc * pin_info = thunderbay_pins + i ;
struct thunderbay_mux_desc * pin_mux = pin_info - > drv_data ;
while ( pin_mux - > name ) {
const char * * grp ;
int j , grp_num , match = 0 ;
size_t grp_size ;
struct function_desc * func ;
for ( j = 0 ; j < tpc - > nfuncs ; j + + ) {
if ( ! strcmp ( pin_mux - > name , function [ j ] . name ) ) {
match = 1 ;
break ;
}
}
if ( ! match )
return - EINVAL ;
func = function + j ;
grp_num = func - > num_group_names ;
grp_size = sizeof ( * func - > group_names ) ;
if ( ! func - > group_names ) {
func - > group_names = devm_kcalloc ( tpc - > dev ,
grp_num ,
grp_size ,
GFP_KERNEL ) ;
if ( ! func - > group_names ) {
kfree ( func ) ;
return - ENOMEM ;
}
}
grp = func - > group_names ;
while ( * grp )
grp + + ;
* grp = pin_info - > name ;
pin_mux + + ;
}
}
/* Add all functions */
for ( i = 0 ; i < tpc - > nfuncs ; i + + ) {
pinmux_generic_add_function ( tpc - > pctrl ,
function [ i ] . name ,
function [ i ] . group_names ,
function [ i ] . num_group_names ,
function [ i ] . data ) ;
}
kfree ( function ) ;
return 0 ;
}
static int thunderbay_build_functions ( struct thunderbay_pinctrl * tpc )
{
struct function_desc * thunderbay_funcs ;
void * ptr ;
int pin ;
2022-01-11 18:29:18 +01:00
/*
* Allocate maximum possible number of functions . Assume every pin
* being part of 8 ( hw maximum ) globally unique muxes .
*/
2021-12-01 12:56:26 +05:30
tpc - > nfuncs = 0 ;
thunderbay_funcs = kcalloc ( tpc - > soc - > npins * 8 ,
sizeof ( * thunderbay_funcs ) , GFP_KERNEL ) ;
if ( ! thunderbay_funcs )
return - ENOMEM ;
2022-01-11 18:29:18 +01:00
/* Setup 1 function for each unique mux */
2021-12-01 12:56:26 +05:30
for ( pin = 0 ; pin < tpc - > soc - > npins ; pin + + ) {
const struct pinctrl_pin_desc * pin_info = thunderbay_pins + pin ;
2022-01-11 18:29:18 +01:00
struct thunderbay_mux_desc * pin_mux ;
2021-12-01 12:56:26 +05:30
2022-01-11 18:29:18 +01:00
for ( pin_mux = pin_info - > drv_data ; pin_mux - > name ; pin_mux + + ) {
struct function_desc * func ;
2021-12-01 12:56:26 +05:30
2022-01-11 18:29:18 +01:00
/* Check if we already have function for this mux */
for ( func = thunderbay_funcs ; func - > name ; func + + ) {
2021-12-01 12:56:26 +05:30
if ( ! strcmp ( pin_mux - > name , func - > name ) ) {
func - > num_group_names + + ;
break ;
}
}
if ( ! func - > name ) {
func - > name = pin_mux - > name ;
func - > num_group_names = 1 ;
func - > data = ( int * ) & pin_mux - > mode ;
tpc - > nfuncs + + ;
}
}
}
/* Reallocate memory based on actual number of functions */
ptr = krealloc ( thunderbay_funcs ,
tpc - > nfuncs * sizeof ( * thunderbay_funcs ) , GFP_KERNEL ) ;
if ( ! ptr )
return - ENOMEM ;
thunderbay_funcs = ptr ;
return thunderbay_add_functions ( tpc , thunderbay_funcs ) ;
}
static int thunderbay_pinconf_set_tristate ( struct thunderbay_pinctrl * tpc ,
unsigned int pin , u32 config )
{
struct gpio_chip * chip = & tpc - > chip ;
u32 reg ;
reg = thb_gpio_read_reg ( chip , pin ) ;
if ( config > 0 )
reg | = THB_GPIO_ENAQ_MASK ;
else
reg & = ~ THB_GPIO_ENAQ_MASK ;
return thb_gpio_write_reg ( chip , pin , reg ) ;
}
static int thunderbay_pinconf_get_tristate ( struct thunderbay_pinctrl * tpc ,
unsigned int pin , u32 * config )
{
struct gpio_chip * chip = & tpc - > chip ;
u32 reg ;
reg = thb_gpio_read_reg ( chip , pin ) ;
* config = ( reg & THB_GPIO_ENAQ_MASK ) > 0 ;
return 0 ;
}
static int thunderbay_pinconf_set_pulldown ( struct thunderbay_pinctrl * tpc ,
unsigned int pin , u32 config )
{
struct gpio_chip * chip = & tpc - > chip ;
u32 reg ;
reg = thb_gpio_read_reg ( chip , pin ) ;
if ( config > 0 )
reg | = THB_GPIO_PULL_DOWN_MASK ;
else
reg & = ~ THB_GPIO_PULL_DOWN_MASK ;
return thb_gpio_write_reg ( chip , pin , reg ) ;
}
static int thunderbay_pinconf_get_pulldown ( struct thunderbay_pinctrl * tpc ,
unsigned int pin , u32 * config )
{
struct gpio_chip * chip = & tpc - > chip ;
u32 reg = 0 ;
reg = thb_gpio_read_reg ( chip , pin ) ;
* config = ( ( reg & THB_GPIO_PULL_DOWN_MASK ) > 0 ) ? 1 : 0 ;
return 0 ;
}
static int thunderbay_pinconf_set_pullup ( struct thunderbay_pinctrl * tpc ,
unsigned int pin , u32 config )
{
struct gpio_chip * chip = & tpc - > chip ;
u32 reg ;
reg = thb_gpio_read_reg ( chip , pin ) ;
if ( config > 0 )
reg & = ~ THB_GPIO_PULL_UP_MASK ;
else
reg | = THB_GPIO_PULL_UP_MASK ;
return thb_gpio_write_reg ( chip , pin , reg ) ;
}
static int thunderbay_pinconf_get_pullup ( struct thunderbay_pinctrl * tpc ,
unsigned int pin , u32 * config )
{
struct gpio_chip * chip = & tpc - > chip ;
u32 reg ;
reg = thb_gpio_read_reg ( chip , pin ) ;
* config = ( ( reg & THB_GPIO_PULL_UP_MASK ) = = 0 ) ? 1 : 0 ;
return 0 ;
}
static int thunderbay_pinconf_set_opendrain ( struct thunderbay_pinctrl * tpc ,
unsigned int pin , u32 config )
{
struct gpio_chip * chip = & tpc - > chip ;
u32 reg ;
reg = thb_gpio_read_reg ( chip , pin ) ;
if ( config > 0 )
reg & = ~ THB_GPIO_PULL_ENABLE_MASK ;
else
reg | = THB_GPIO_PULL_ENABLE_MASK ;
return thb_gpio_write_reg ( chip , pin , reg ) ;
}
static int thunderbay_pinconf_get_opendrain ( struct thunderbay_pinctrl * tpc ,
unsigned int pin , u32 * config )
{
struct gpio_chip * chip = & tpc - > chip ;
u32 reg ;
reg = thb_gpio_read_reg ( chip , pin ) ;
* config = ( ( reg & THB_GPIO_PULL_ENABLE_MASK ) = = 0 ) ? 1 : 0 ;
return 0 ;
}
static int thunderbay_pinconf_set_pushpull ( struct thunderbay_pinctrl * tpc ,
unsigned int pin , u32 config )
{
struct gpio_chip * chip = & tpc - > chip ;
u32 reg ;
reg = thb_gpio_read_reg ( chip , pin ) ;
if ( config > 0 )
reg | = THB_GPIO_PULL_ENABLE_MASK ;
else
reg & = ~ THB_GPIO_PULL_ENABLE_MASK ;
return thb_gpio_write_reg ( chip , pin , reg ) ;
}
static int thunderbay_pinconf_get_pushpull ( struct thunderbay_pinctrl * tpc ,
unsigned int pin , u32 * config )
{
struct gpio_chip * chip = & tpc - > chip ;
u32 reg ;
reg = thb_gpio_read_reg ( chip , pin ) ;
* config = ( ( reg & THB_GPIO_PULL_ENABLE_MASK ) > 0 ) ? 1 : 0 ;
return 0 ;
}
static int thunderbay_pinconf_set_drivestrength ( struct thunderbay_pinctrl * tpc ,
unsigned int pin , u32 config )
{
struct gpio_chip * chip = & tpc - > chip ;
u32 reg ;
reg = thb_gpio_read_reg ( chip , pin ) ;
/* Drive Strength: 0x0 to 0xF */
if ( config < = 0xF ) {
reg = ( reg | config ) ;
return thb_gpio_write_reg ( chip , pin , reg ) ;
}
return - EINVAL ;
}
static int thunderbay_pinconf_get_drivestrength ( struct thunderbay_pinctrl * tpc ,
unsigned int pin , u32 * config )
{
struct gpio_chip * chip = & tpc - > chip ;
u32 reg ;
reg = thb_gpio_read_reg ( chip , pin ) ;
reg = ( reg & THB_GPIO_DRIVE_STRENGTH_MASK ) > > 16 ;
* config = ( reg > 0 ) ? reg : 0 ;
return 0 ;
}
static int thunderbay_pinconf_set_schmitt ( struct thunderbay_pinctrl * tpc ,
unsigned int pin , u32 config )
{
struct gpio_chip * chip = & tpc - > chip ;
u32 reg ;
reg = thb_gpio_read_reg ( chip , pin ) ;
if ( config > 0 )
reg | = THB_GPIO_SCHMITT_TRIGGER_MASK ;
else
reg & = ~ THB_GPIO_SCHMITT_TRIGGER_MASK ;
return thb_gpio_write_reg ( chip , pin , reg ) ;
}
static int thunderbay_pinconf_get_schmitt ( struct thunderbay_pinctrl * tpc ,
unsigned int pin , u32 * config )
{
struct gpio_chip * chip = & tpc - > chip ;
u32 reg ;
reg = thb_gpio_read_reg ( chip , pin ) ;
* config = ( ( reg & THB_GPIO_SCHMITT_TRIGGER_MASK ) > 0 ) ? 1 : 0 ;
return 0 ;
}
static int thunderbay_pinconf_set_slew_rate ( struct thunderbay_pinctrl * tpc ,
unsigned int pin , u32 config )
{
struct gpio_chip * chip = & tpc - > chip ;
u32 reg = 0 ;
reg = thb_gpio_read_reg ( chip , pin ) ;
if ( config > 0 )
reg | = THB_GPIO_SLEW_RATE_MASK ;
else
reg & = ~ THB_GPIO_SLEW_RATE_MASK ;
return thb_gpio_write_reg ( chip , pin , reg ) ;
}
static int thunderbay_pinconf_get_slew_rate ( struct thunderbay_pinctrl * tpc ,
unsigned int pin , u32 * config )
{
struct gpio_chip * chip = & tpc - > chip ;
u32 reg ;
reg = thb_gpio_read_reg ( chip , pin ) ;
* config = ( ( reg & THB_GPIO_SLEW_RATE_MASK ) > 0 ) ? 1 : 0 ;
return 0 ;
}
static int thunderbay_pinconf_get ( struct pinctrl_dev * pctldev , unsigned int pin ,
unsigned long * config )
{
struct thunderbay_pinctrl * tpc = pinctrl_dev_get_drvdata ( pctldev ) ;
enum pin_config_param param = pinconf_to_config_param ( * config ) ;
u32 arg ;
int ret ;
switch ( param ) {
case PIN_CONFIG_BIAS_HIGH_IMPEDANCE :
ret = thunderbay_pinconf_get_tristate ( tpc , pin , & arg ) ;
break ;
case PIN_CONFIG_BIAS_PULL_DOWN :
ret = thunderbay_pinconf_get_pulldown ( tpc , pin , & arg ) ;
break ;
case PIN_CONFIG_BIAS_PULL_UP :
ret = thunderbay_pinconf_get_pullup ( tpc , pin , & arg ) ;
break ;
case PIN_CONFIG_DRIVE_OPEN_DRAIN :
ret = thunderbay_pinconf_get_opendrain ( tpc , pin , & arg ) ;
break ;
case PIN_CONFIG_DRIVE_PUSH_PULL :
ret = thunderbay_pinconf_get_pushpull ( tpc , pin , & arg ) ;
break ;
case PIN_CONFIG_DRIVE_STRENGTH :
ret = thunderbay_pinconf_get_drivestrength ( tpc , pin , & arg ) ;
break ;
case PIN_CONFIG_INPUT_SCHMITT_ENABLE :
ret = thunderbay_pinconf_get_schmitt ( tpc , pin , & arg ) ;
break ;
case PIN_CONFIG_SLEW_RATE :
ret = thunderbay_pinconf_get_slew_rate ( tpc , pin , & arg ) ;
break ;
default :
return - ENOTSUPP ;
}
* config = pinconf_to_config_packed ( param , arg ) ;
return ret ;
}
static int thunderbay_pinconf_set ( struct pinctrl_dev * pctldev , unsigned int pin ,
unsigned long * configs , unsigned int num_configs )
{
struct thunderbay_pinctrl * tpc = pinctrl_dev_get_drvdata ( pctldev ) ;
enum pin_config_param param ;
unsigned int pinconf ;
int ret = 0 ;
u32 arg ;
for ( pinconf = 0 ; pinconf < num_configs ; pinconf + + ) {
param = pinconf_to_config_param ( configs [ pinconf ] ) ;
arg = pinconf_to_config_argument ( configs [ pinconf ] ) ;
switch ( param ) {
case PIN_CONFIG_BIAS_HIGH_IMPEDANCE :
ret = thunderbay_pinconf_set_tristate ( tpc , pin , arg ) ;
break ;
case PIN_CONFIG_BIAS_PULL_DOWN :
ret = thunderbay_pinconf_set_pulldown ( tpc , pin , arg ) ;
break ;
case PIN_CONFIG_BIAS_PULL_UP :
ret = thunderbay_pinconf_set_pullup ( tpc , pin , arg ) ;
break ;
case PIN_CONFIG_DRIVE_OPEN_DRAIN :
ret = thunderbay_pinconf_set_opendrain ( tpc , pin , arg ) ;
break ;
case PIN_CONFIG_DRIVE_PUSH_PULL :
ret = thunderbay_pinconf_set_pushpull ( tpc , pin , arg ) ;
break ;
case PIN_CONFIG_DRIVE_STRENGTH :
ret = thunderbay_pinconf_set_drivestrength ( tpc , pin , arg ) ;
break ;
case PIN_CONFIG_INPUT_SCHMITT_ENABLE :
ret = thunderbay_pinconf_set_schmitt ( tpc , pin , arg ) ;
break ;
case PIN_CONFIG_SLEW_RATE :
ret = thunderbay_pinconf_set_slew_rate ( tpc , pin , arg ) ;
break ;
default :
return - ENOTSUPP ;
}
}
return ret ;
}
static const struct pinctrl_ops thunderbay_pctlops = {
. 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 const struct pinmux_ops thunderbay_pmxops = {
. 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 = thb_pinctrl_set_mux ,
. gpio_request_enable = thunderbay_request_gpio ,
. gpio_disable_free = thunderbay_free_gpio ,
} ;
static const struct pinconf_ops thunderbay_confops = {
. is_generic = true ,
. pin_config_get = thunderbay_pinconf_get ,
. pin_config_set = thunderbay_pinconf_set ,
} ;
static struct pinctrl_desc thunderbay_pinctrl_desc = {
. name = " thunderbay-pinmux " ,
. pctlops = & thunderbay_pctlops ,
. pmxops = & thunderbay_pmxops ,
. confops = & thunderbay_confops ,
. owner = THIS_MODULE ,
} ;
static const struct of_device_id thunderbay_pinctrl_match [ ] = {
{
. compatible = " intel,thunderbay-pinctrl " ,
. data = & thunderbay_data
} ,
{ }
} ;
static int thunderbay_pinctrl_probe ( struct platform_device * pdev )
{
const struct of_device_id * of_id ;
struct device * dev = & pdev - > dev ;
struct thunderbay_pinctrl * tpc ;
struct resource * iomem ;
int ret ;
of_id = of_match_node ( thunderbay_pinctrl_match , pdev - > dev . of_node ) ;
if ( ! of_id )
return - ENODEV ;
tpc = devm_kzalloc ( dev , sizeof ( * tpc ) , GFP_KERNEL ) ;
if ( ! tpc )
return - ENOMEM ;
tpc - > dev = dev ;
tpc - > soc = of_id - > data ;
iomem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! iomem )
return - ENXIO ;
tpc - > base0 = devm_ioremap_resource ( dev , iomem ) ;
if ( IS_ERR ( tpc - > base0 ) )
return PTR_ERR ( tpc - > base0 ) ;
thunderbay_pinctrl_desc . pins = tpc - > soc - > pins ;
thunderbay_pinctrl_desc . npins = tpc - > soc - > npins ;
/* Register pinctrl */
tpc - > pctrl = devm_pinctrl_register ( dev , & thunderbay_pinctrl_desc , tpc ) ;
if ( IS_ERR ( tpc - > pctrl ) )
return PTR_ERR ( tpc - > pctrl ) ;
/* Setup pinmux groups */
ret = thunderbay_build_groups ( tpc ) ;
if ( ret )
return ret ;
/* Setup pinmux functions */
ret = thunderbay_build_functions ( tpc ) ;
if ( ret )
return ret ;
/* Setup GPIO */
ret = thunderbay_gpiochip_probe ( tpc ) ;
if ( ret < 0 )
return ret ;
platform_set_drvdata ( pdev , tpc ) ;
return 0 ;
}
static int thunderbay_pinctrl_remove ( struct platform_device * pdev )
{
/* thunderbay_pinctrl_remove function to clear the assigned memory */
return 0 ;
}
static struct platform_driver thunderbay_pinctrl_driver = {
. driver = {
. name = " thunderbay-pinctrl " ,
. of_match_table = thunderbay_pinctrl_match ,
} ,
. probe = thunderbay_pinctrl_probe ,
. remove = thunderbay_pinctrl_remove ,
} ;
builtin_platform_driver ( thunderbay_pinctrl_driver ) ;
MODULE_AUTHOR ( " Lakshmi Sowjanya D <lakshmi.sowjanya.d@intel.com> " ) ;
MODULE_AUTHOR ( " Kiran Kumar S <kiran.kumar1.s@intel.com> " ) ;
MODULE_DESCRIPTION ( " Intel Thunder Bay Pinctrl/GPIO Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;