#include <linux/array_size.h>
#include <linux/auxiliary_bus.h>
#include <linux/bits.h>
#include <linux/bug.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/seq_file.h>
#include <linux/slab.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 "pinctrl-utils.h"
enum eq5p_regs {
EQ5P_PD,
EQ5P_PU,
EQ5P_DS_LOW,
EQ5P_DS_HIGH,
EQ5P_IOCR,
EQ5P_REG_COUNT,
};
struct eq5p_bank {
const unsigned int npins;
const unsigned int regs[EQ5P_REG_COUNT];
};
struct eq5p_match_data {
const unsigned int npins;
const unsigned int nfunctions;
const unsigned int nbanks;
const struct pinctrl_pin_desc *pins;
const struct pinfunction *functions;
const struct eq5p_bank *banks;
};
struct eq5p_pinctrl {
struct pinctrl_desc desc;
void __iomem *base;
const struct eq5p_match_data *data;
};
#define EQ5P_DS_MASK GENMASK(1, 0)
#define EQ5P_GPIO_FUNC_SELECTOR 0
#define EQ5P_PINFUNCTION(func, groups) PINCTRL_PINFUNCTION(func, groups, ARRAY_SIZE(groups))
static const struct pinctrl_pin_desc eq5p_eyeq5_pins[] = {
PINCTRL_PIN(0, "PA0"),
PINCTRL_PIN(1, "PA1"),
PINCTRL_PIN(2, "PA2"),
PINCTRL_PIN(3, "PA3"),
PINCTRL_PIN(4, "PA4"),
PINCTRL_PIN(5, "PA5"),
PINCTRL_PIN(6, "PA6"),
PINCTRL_PIN(7, "PA7"),
PINCTRL_PIN(8, "PA8"),
PINCTRL_PIN(9, "PA9"),
PINCTRL_PIN(10, "PA10"),
PINCTRL_PIN(11, "PA11"),
PINCTRL_PIN(12, "PA12"),
PINCTRL_PIN(13, "PA13"),
PINCTRL_PIN(14, "PA14"),
PINCTRL_PIN(15, "PA15"),
PINCTRL_PIN(16, "PA16"),
PINCTRL_PIN(17, "PA17"),
PINCTRL_PIN(18, "PA18"),
PINCTRL_PIN(19, "PA19"),
PINCTRL_PIN(20, "PA20"),
PINCTRL_PIN(21, "PA21"),
PINCTRL_PIN(22, "PA22"),
PINCTRL_PIN(23, "PA23"),
PINCTRL_PIN(24, "PA24"),
PINCTRL_PIN(25, "PA25"),
PINCTRL_PIN(26, "PA26"),
PINCTRL_PIN(27, "PA27"),
PINCTRL_PIN(28, "PA28"),
#define EQ5P_EYEQ5_PIN_OFFSET_BANK_B 29
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 0, "PB0"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 1, "PB1"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 2, "PB2"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 3, "PB3"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 4, "PB4"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 5, "PB5"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 6, "PB6"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 7, "PB7"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 8, "PB8"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 9, "PB9"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 10, "PB10"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 11, "PB11"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 12, "PB12"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 13, "PB13"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 14, "PB14"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 15, "PB15"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 16, "PB16"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 17, "PB17"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 18, "PB18"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 19, "PB19"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 20, "PB20"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 21, "PB21"),
PINCTRL_PIN(EQ5P_EYEQ5_PIN_OFFSET_BANK_B + 22, "PB22"),
};
static const char * const eq5p_eyeq5_gpio_groups[] = {
"PA0", "PA1", "PA2", "PA3", "PA4", "PA5", "PA6", "PA7",
"PA8", "PA9", "PA10", "PA11", "PA12", "PA13", "PA14", "PA15",
"PA16", "PA17", "PA18", "PA19", "PA20", "PA21", "PA22", "PA23",
"PA24", "PA25", "PA26", "PA27", "PA28",
"PB0", "PB1", "PB2", "PB3", "PB4", "PB5", "PB6", "PB7",
"PB8", "PB9", "PB10", "PB11", "PB12", "PB13", "PB14", "PB15",
"PB16", "PB17", "PB18", "PB19", "PB20", "PB21", "PB22",
};
static const char * const eq5p_eyeq5_timer0_groups[] = { "PA0", "PA1" };
static const char * const eq5p_eyeq5_timer1_groups[] = { "PA2", "PA3" };
static const char * const eq5p_eyeq5_timer2_groups[] = { "PA4", "PA5" };
static const char * const eq5p_eyeq5_timer5_groups[] = { "PA6", "PA7", "PA8", "PA9" };
static const char * const eq5p_eyeq5_uart0_groups[] = { "PA10", "PA11" };
static const char * const eq5p_eyeq5_uart1_groups[] = { "PA12", "PA13" };
static const char * const eq5p_eyeq5_can0_groups[] = { "PA14", "PA15" };
static const char * const eq5p_eyeq5_can1_groups[] = { "PA16", "PA17" };
static const char * const eq5p_eyeq5_spi0_groups[] = { "PA18", "PA19", "PA20", "PA21", "PA22" };
static const char * const eq5p_eyeq5_spi1_groups[] = { "PA23", "PA24", "PA25", "PA26", "PA27" };
static const char * const eq5p_eyeq5_refclk0_groups[] = { "PA28" };
static const char * const eq5p_eyeq5_timer3_groups[] = { "PB0", "PB1" };
static const char * const eq5p_eyeq5_timer4_groups[] = { "PB2", "PB3" };
static const char * const eq5p_eyeq5_timer6_groups[] = { "PB4", "PB5", "PB6", "PB7" };
static const char * const eq5p_eyeq5_uart2_groups[] = { "PB8", "PB9" };
static const char * const eq5p_eyeq5_can2_groups[] = { "PB10", "PB11" };
static const char * const eq5p_eyeq5_spi2_groups[] = { "PB12", "PB13", "PB14", "PB15", "PB16" };
static const char * const eq5p_eyeq5_spi3_groups[] = { "PB17", "PB18", "PB19", "PB20", "PB21" };
static const char * const eq5p_eyeq5_mclk0_groups[] = { "PB22" };
static const struct pinfunction eq5p_eyeq5_functions[] = {
EQ5P_PINFUNCTION("gpio", eq5p_eyeq5_gpio_groups),
EQ5P_PINFUNCTION("timer0", eq5p_eyeq5_timer0_groups),
EQ5P_PINFUNCTION("timer1", eq5p_eyeq5_timer1_groups),
EQ5P_PINFUNCTION("timer2", eq5p_eyeq5_timer2_groups),
EQ5P_PINFUNCTION("timer5", eq5p_eyeq5_timer5_groups),
EQ5P_PINFUNCTION("uart0", eq5p_eyeq5_uart0_groups),
EQ5P_PINFUNCTION("uart1", eq5p_eyeq5_uart1_groups),
EQ5P_PINFUNCTION("can0", eq5p_eyeq5_can0_groups),
EQ5P_PINFUNCTION("can1", eq5p_eyeq5_can1_groups),
EQ5P_PINFUNCTION("spi0", eq5p_eyeq5_spi0_groups),
EQ5P_PINFUNCTION("spi1", eq5p_eyeq5_spi1_groups),
EQ5P_PINFUNCTION("refclk0", eq5p_eyeq5_refclk0_groups),
EQ5P_PINFUNCTION("timer3", eq5p_eyeq5_timer3_groups),
EQ5P_PINFUNCTION("timer4", eq5p_eyeq5_timer4_groups),
EQ5P_PINFUNCTION("timer6", eq5p_eyeq5_timer6_groups),
EQ5P_PINFUNCTION("uart2", eq5p_eyeq5_uart2_groups),
EQ5P_PINFUNCTION("can2", eq5p_eyeq5_can2_groups),
EQ5P_PINFUNCTION("spi2", eq5p_eyeq5_spi2_groups),
EQ5P_PINFUNCTION("spi3", eq5p_eyeq5_spi3_groups),
EQ5P_PINFUNCTION("mclk0", eq5p_eyeq5_mclk0_groups),
};
static const struct eq5p_bank eq5p_eyeq5_banks[] = {
{
.npins = EQ5P_EYEQ5_PIN_OFFSET_BANK_B,
.regs = {0x0C0, 0x0C4, 0x0D0, 0x0D4, 0x0B0},
},
{
.npins = ARRAY_SIZE(eq5p_eyeq5_pins) - EQ5P_EYEQ5_PIN_OFFSET_BANK_B,
.regs = {0x0C8, 0x0CC, 0x0D8, 0x0DC, 0x0B4},
},
};
static const struct eq5p_match_data eq5p_eyeq5_data = {
.npins = ARRAY_SIZE(eq5p_eyeq5_pins),
.nfunctions = ARRAY_SIZE(eq5p_eyeq5_functions),
.nbanks = ARRAY_SIZE(eq5p_eyeq5_banks),
.pins = eq5p_eyeq5_pins,
.functions = eq5p_eyeq5_functions,
.banks = eq5p_eyeq5_banks,
};
static const struct pinctrl_pin_desc eq5p_eyeq6lplus_pins[] = {
PINCTRL_PIN(0, "PA0"),
PINCTRL_PIN(1, "PA1"),
PINCTRL_PIN(2, "PA2"),
PINCTRL_PIN(3, "PA3"),
PINCTRL_PIN(4, "PA4"),
PINCTRL_PIN(5, "PA5"),
PINCTRL_PIN(6, "PA6"),
PINCTRL_PIN(7, "PA7"),
PINCTRL_PIN(8, "PA8"),
PINCTRL_PIN(9, "PA9"),
PINCTRL_PIN(10, "PA10"),
PINCTRL_PIN(11, "PA11"),
PINCTRL_PIN(12, "PA12"),
PINCTRL_PIN(13, "PA13"),
PINCTRL_PIN(14, "PA14"),
PINCTRL_PIN(15, "PA15"),
PINCTRL_PIN(16, "PA16"),
PINCTRL_PIN(17, "PA17"),
PINCTRL_PIN(18, "PA18"),
PINCTRL_PIN(19, "PA19"),
PINCTRL_PIN(20, "PA20"),
PINCTRL_PIN(21, "PA21"),
PINCTRL_PIN(22, "PA22"),
PINCTRL_PIN(23, "PA23"),
PINCTRL_PIN(24, "PA24"),
PINCTRL_PIN(25, "PA25"),
PINCTRL_PIN(26, "PA26"),
PINCTRL_PIN(27, "PA27"),
PINCTRL_PIN(28, "PA28"),
PINCTRL_PIN(29, "PA29"),
PINCTRL_PIN(30, "PA30"),
PINCTRL_PIN(31, "PA31"),
};
static const char * const eq5p_eyeq6lplus_gpio_groups[] = {
"PA0", "PA1", "PA2", "PA3", "PA4", "PA5", "PA6", "PA7",
"PA8", "PA9", "PA10", "PA11", "PA12", "PA13", "PA14", "PA15",
"PA16", "PA17", "PA18", "PA19", "PA20", "PA21", "PA22", "PA23",
"PA24", "PA25", "PA26", "PA27", "PA28", "PA29", "PA30", "PA31",
};
static const char * const eq5p_eyeq6lplus_timer0_groups[] = { "PA0", "PA1" };
static const char * const eq5p_eyeq6lplus_timer1_groups[] = { "PA2", "PA3" };
static const char * const eq5p_eyeq6lplus_uart_ssi_groups[] = { "PA4", "PA5" };
static const char * const eq5p_eyeq6lplus_spi0_groups[] = { "PA6", "PA7", "PA8", "PA9", "PA10" };
static const char * const eq5p_eyeq6lplus_uart0_groups[] = { "PA11", "PA12" };
static const char * const eq5p_eyeq6lplus_timer2_groups[] = { "PA13", "PA14" };
static const char * const eq5p_eyeq6lplus_timer3_groups[] = { "PA15", "PA16" };
static const char * const eq5p_eyeq6lplus_timer_ext0_groups[] = { "PA17", "PA18", "PA19", "PA20" };
static const char * const eq5p_eyeq6lplus_spi1_groups[] = {
"PA21", "PA22", "PA23", "PA24", "PA25"
};
static const char * const eq5p_eyeq6lplus_timer_ext1_groups[] = { "PA26", "PA27", "PA28", "PA29" };
static const char * const eq5p_eyeq6lplus_ext_ref_clk_groups[] = { "PA30" };
static const char * const eq5p_eyeq6lplus_mipi_ref_clk_groups[] = { "PA31" };
static const struct pinfunction eq5p_eyeq6lplus_functions[] = {
EQ5P_PINFUNCTION("gpio", eq5p_eyeq6lplus_gpio_groups),
EQ5P_PINFUNCTION("timer0", eq5p_eyeq6lplus_timer0_groups),
EQ5P_PINFUNCTION("timer1", eq5p_eyeq6lplus_timer1_groups),
EQ5P_PINFUNCTION("uart_ssi", eq5p_eyeq6lplus_uart_ssi_groups),
EQ5P_PINFUNCTION("spi0", eq5p_eyeq6lplus_spi0_groups),
EQ5P_PINFUNCTION("uart0", eq5p_eyeq6lplus_uart0_groups),
EQ5P_PINFUNCTION("timer2", eq5p_eyeq6lplus_timer2_groups),
EQ5P_PINFUNCTION("timer3", eq5p_eyeq6lplus_timer3_groups),
EQ5P_PINFUNCTION("timer_ext0", eq5p_eyeq6lplus_timer_ext0_groups),
EQ5P_PINFUNCTION("spi1", eq5p_eyeq6lplus_spi1_groups),
EQ5P_PINFUNCTION("timer_ext1", eq5p_eyeq6lplus_timer_ext1_groups),
EQ5P_PINFUNCTION("ext_ref_clk", eq5p_eyeq6lplus_ext_ref_clk_groups),
EQ5P_PINFUNCTION("mipi_ref_clk", eq5p_eyeq6lplus_mipi_ref_clk_groups),
};
static const struct eq5p_bank eq5p_eyeq6lplus_banks[] = {
{
.npins = ARRAY_SIZE(eq5p_eyeq6lplus_pins),
.regs = {0x0C0, 0x0C4, 0x0D0, 0x0D4, 0x0B0},
},
};
static const struct eq5p_match_data eq5p_eyeq6lplus_data = {
.npins = ARRAY_SIZE(eq5p_eyeq6lplus_pins),
.nfunctions = ARRAY_SIZE(eq5p_eyeq6lplus_functions),
.nbanks = ARRAY_SIZE(eq5p_eyeq6lplus_banks),
.pins = eq5p_eyeq6lplus_pins,
.functions = eq5p_eyeq6lplus_functions,
.banks = eq5p_eyeq6lplus_banks,
};
static void eq5p_update_bits(const struct eq5p_pinctrl *pctrl,
const struct eq5p_bank *bank,
enum eq5p_regs reg, u32 mask, u32 val)
{
void __iomem *ptr = pctrl->base + bank->regs[reg];
writel((readl(ptr) & ~mask) | (val & mask), ptr);
}
static bool eq5p_test_bit(const struct eq5p_pinctrl *pctrl,
const struct eq5p_bank *bank,
enum eq5p_regs reg, int offset)
{
u32 val = readl(pctrl->base + bank->regs[reg]);
if (WARN_ON(offset > 31))
return false;
return (val & BIT(offset)) != 0;
}
static int eq5p_pin_to_bank_offset(const struct eq5p_pinctrl *pctrl, unsigned int pin,
const struct eq5p_bank **bank, unsigned int *offset)
{
for (unsigned int i = 0; i < pctrl->data->nbanks; i++) {
const struct eq5p_bank *_bank = &pctrl->data->banks[i];
unsigned int npins = _bank->npins;
if (pin < npins) {
*bank = _bank;
*offset = pin;
return 0;
}
pin -= npins;
}
return -EINVAL;
}
static int eq5p_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
{
struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
return pctrl->data->npins;
}
static const char *eq5p_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
unsigned int selector)
{
return pctldev->desc->pins[selector].name;
}
static int eq5p_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
unsigned int selector,
const unsigned int **pins,
unsigned int *num_pins)
{
*pins = &pctldev->desc->pins[selector].number;
*num_pins = 1;
return 0;
}
static int eq5p_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *config)
{
enum pin_config_param param = pinconf_to_config_param(*config);
struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
const struct eq5p_bank *bank;
unsigned int offset;
u32 val_ds, arg;
bool pd, pu;
int ret;
ret = eq5p_pin_to_bank_offset(pctrl, pin, &bank, &offset);
if (ret)
return ret;
pd = eq5p_test_bit(pctrl, bank, EQ5P_PD, offset);
pu = eq5p_test_bit(pctrl, bank, EQ5P_PU, offset);
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
arg = !(pd || pu);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
arg = pd;
break;
case PIN_CONFIG_BIAS_PULL_UP:
arg = pu;
break;
case PIN_CONFIG_DRIVE_STRENGTH:
offset *= 2;
if (offset >= 32) {
val_ds = readl(pctrl->base + bank->regs[EQ5P_DS_HIGH]);
offset -= 32;
} else {
val_ds = readl(pctrl->base + bank->regs[EQ5P_DS_LOW]);
}
arg = (val_ds >> offset) & EQ5P_DS_MASK;
break;
default:
return -ENOTSUPP;
}
*config = pinconf_to_config_packed(param, arg);
return 0;
}
static void eq5p_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
struct seq_file *s,
unsigned int pin)
{
struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
const char *pin_name = pctrl->desc.pins[pin].name;
const struct eq5p_bank *bank;
const char *func_name, *bias;
unsigned long ds_config;
unsigned int offset;
u32 drive_strength;
bool pd, pu;
int i, j;
if (eq5p_pin_to_bank_offset(pctrl, pin, &bank, &offset)) {
seq_puts(s, "unknown pin");
return;
}
if (eq5p_test_bit(pctrl, bank, EQ5P_IOCR, offset)) {
func_name = NULL;
for (i = 0; i < pctrl->data->nfunctions; i++) {
if (i == EQ5P_GPIO_FUNC_SELECTOR)
continue;
for (j = 0; j < pctrl->data->functions[i].ngroups; j++) {
const char *x = pctrl->data->functions[i].groups[j];
if (strcmp(x, pin_name) == 0) {
func_name = pctrl->data->functions[i].name;
break;
}
}
if (func_name)
break;
}
if (!func_name)
func_name = "unknown";
} else {
func_name = pctrl->data->functions[EQ5P_GPIO_FUNC_SELECTOR].name;
}
pd = eq5p_test_bit(pctrl, bank, EQ5P_PD, offset);
pu = eq5p_test_bit(pctrl, bank, EQ5P_PU, offset);
if (pd && pu)
bias = "both";
else if (pd && !pu)
bias = "pulldown";
else if (!pd && pu)
bias = "pullup";
else
bias = "none";
ds_config = pinconf_to_config_packed(PIN_CONFIG_DRIVE_STRENGTH, 0);
eq5p_pinconf_get(pctldev, pin, &ds_config);
drive_strength = pinconf_to_config_argument(ds_config);
seq_printf(s, "function=%s bias=%s drive_strength=%d",
func_name, bias, drive_strength);
}
static const struct pinctrl_ops eq5p_pinctrl_ops = {
.get_groups_count = eq5p_pinctrl_get_groups_count,
.get_group_name = eq5p_pinctrl_get_group_name,
.get_group_pins = eq5p_pinctrl_get_group_pins,
.pin_dbg_show = eq5p_pinctrl_pin_dbg_show,
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.dt_free_map = pinctrl_utils_free_map,
};
static int eq5p_pinmux_get_functions_count(struct pinctrl_dev *pctldev)
{
struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
return pctrl->data->nfunctions;
}
static const char *eq5p_pinmux_get_function_name(struct pinctrl_dev *pctldev,
unsigned int selector)
{
struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
return pctrl->data->functions[selector].name;
}
static int eq5p_pinmux_get_function_groups(struct pinctrl_dev *pctldev,
unsigned int selector,
const char * const **groups,
unsigned int *num_groups)
{
struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
*groups = pctrl->data->functions[selector].groups;
*num_groups = pctrl->data->functions[selector].ngroups;
return 0;
}
static int eq5p_pinmux_set_mux(struct pinctrl_dev *pctldev,
unsigned int func_selector, unsigned int pin)
{
struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
const char *func_name = pctrl->data->functions[func_selector].name;
const char *group_name = pctldev->desc->pins[pin].name;
bool is_gpio = func_selector == EQ5P_GPIO_FUNC_SELECTOR;
const struct eq5p_bank *bank;
unsigned int offset;
u32 mask, val;
int ret;
ret = eq5p_pin_to_bank_offset(pctrl, pin, &bank, &offset);
if (ret)
return ret;
dev_dbg(pctldev->dev, "func=%s group=%s\n", func_name, group_name);
mask = BIT(offset);
val = is_gpio ? 0 : mask;
eq5p_update_bits(pctrl, bank, EQ5P_IOCR, mask, val);
return 0;
}
static int eq5p_pinmux_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned int pin)
{
return eq5p_pinmux_set_mux(pctldev, EQ5P_GPIO_FUNC_SELECTOR, pin);
}
static const struct pinmux_ops eq5p_pinmux_ops = {
.get_functions_count = eq5p_pinmux_get_functions_count,
.get_function_name = eq5p_pinmux_get_function_name,
.get_function_groups = eq5p_pinmux_get_function_groups,
.set_mux = eq5p_pinmux_set_mux,
.gpio_request_enable = eq5p_pinmux_gpio_request_enable,
.strict = true,
};
static int eq5p_pinconf_set_drive_strength(struct pinctrl_dev *pctldev,
unsigned int pin, u32 arg)
{
struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
const struct eq5p_bank *bank;
unsigned int offset;
unsigned int reg;
u32 mask, val;
int ret;
ret = eq5p_pin_to_bank_offset(pctrl, pin, &bank, &offset);
if (ret)
return ret;
if (arg & ~EQ5P_DS_MASK) {
dev_err(pctldev->dev, "Unsupported drive strength: %u\n", arg);
return -EINVAL;
}
offset *= 2;
if (offset >= 32) {
reg = EQ5P_DS_HIGH;
offset -= 32;
} else {
reg = EQ5P_DS_LOW;
}
mask = EQ5P_DS_MASK << offset;
val = arg << offset;
eq5p_update_bits(pctrl, bank, reg, mask, val);
return 0;
}
static int eq5p_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *configs, unsigned int num_configs)
{
struct eq5p_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
const char *pin_name = pctldev->desc->pins[pin].name;
struct device *dev = pctldev->dev;
const struct eq5p_bank *bank;
unsigned int offset;
unsigned int i;
u32 val;
int ret;
ret = eq5p_pin_to_bank_offset(pctrl, pin, &bank, &offset);
if (ret)
return ret;
val = BIT(offset);
for (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]);
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
dev_dbg(dev, "pin=%s bias_disable\n", pin_name);
eq5p_update_bits(pctrl, bank, EQ5P_PD, val, 0);
eq5p_update_bits(pctrl, bank, EQ5P_PU, val, 0);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
dev_dbg(dev, "pin=%s bias_pull_down arg=%u\n",
pin_name, arg);
if (arg == 0)
return -ENOTSUPP;
eq5p_update_bits(pctrl, bank, EQ5P_PD, val, val);
eq5p_update_bits(pctrl, bank, EQ5P_PU, val, 0);
break;
case PIN_CONFIG_BIAS_PULL_UP:
dev_dbg(dev, "pin=%s bias_pull_up arg=%u\n",
pin_name, arg);
if (arg == 0)
return -ENOTSUPP;
eq5p_update_bits(pctrl, bank, EQ5P_PD, val, 0);
eq5p_update_bits(pctrl, bank, EQ5P_PU, val, val);
break;
case PIN_CONFIG_DRIVE_STRENGTH:
dev_dbg(dev, "pin=%s drive_strength arg=%u\n",
pin_name, arg);
eq5p_pinconf_set_drive_strength(pctldev, pin, arg);
break;
default:
dev_err(dev, "Unsupported pinconf %u\n", param);
return -ENOTSUPP;
}
}
return 0;
}
static const struct pinconf_ops eq5p_pinconf_ops = {
.is_generic = true,
.pin_config_get = eq5p_pinconf_get,
.pin_config_set = eq5p_pinconf_set,
.pin_config_group_get = eq5p_pinconf_get,
.pin_config_group_set = eq5p_pinconf_set,
};
static int eq5p_probe(struct auxiliary_device *adev,
const struct auxiliary_device_id *id)
{
const struct of_device_id *match;
struct device *dev = &adev->dev;
struct pinctrl_dev *pctldev;
struct eq5p_pinctrl *pctrl;
int ret;
match = of_match_node(dev->driver->of_match_table, dev->of_node);
if (!match || !match->data)
return -ENODEV;
pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL);
if (!pctrl)
return -ENOMEM;
pctrl->base = (void __iomem *)dev_get_platdata(dev);
pctrl->data = match->data;
pctrl->desc.name = dev_name(dev);
pctrl->desc.pins = pctrl->data->pins;
pctrl->desc.npins = pctrl->data->npins;
pctrl->desc.pctlops = &eq5p_pinctrl_ops;
pctrl->desc.pmxops = &eq5p_pinmux_ops;
pctrl->desc.confops = &eq5p_pinconf_ops;
pctrl->desc.owner = THIS_MODULE;
ret = devm_pinctrl_register_and_init(dev, &pctrl->desc, pctrl, &pctldev);
if (ret)
return dev_err_probe(dev, ret, "failed registering pinctrl device\n");
ret = pinctrl_enable(pctldev);
if (ret)
return dev_err_probe(dev, ret, "failed enabling pinctrl device\n");
return 0;
}
static const struct of_device_id eq5p_match_table[] = {
{ .compatible = "mobileye,eyeq5-olb", .data = &eq5p_eyeq5_data },
{ .compatible = "mobileye,eyeq6lplus-olb", .data = &eq5p_eyeq6lplus_data },
{}
};
MODULE_DEVICE_TABLE(of, eq5p_match_table);
static const struct auxiliary_device_id eq5p_id_table[] = {
{ .name = "clk_eyeq.pinctrl" },
{}
};
MODULE_DEVICE_TABLE(auxiliary, eq5p_id_table);
static struct auxiliary_driver eq5p_driver = {
.probe = eq5p_probe,
.id_table = eq5p_id_table,
.driver = {
.of_match_table = eq5p_match_table,
}
};
module_auxiliary_driver(eq5p_driver);