mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-01 10:42:11 +00:00
2694868880
The build robot complains about unused code. Let's drop it, this can be restored with simple git revert when needed. Reported-by: kernel test robot <lkp@intel.com> Closes: https://lore.kernel.org/oe-kbuild-all/202410021136.ie3cFM2w-lkp@intel.com/ Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Link: https://lore.kernel.org/20241003-k320-unused-v1-1-72e65bc2f27b@linaro.org
642 lines
16 KiB
C
642 lines
16 KiB
C
// SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
|
/*
|
|
* Copyright (C) 2024 Canaan Bright Sight Co. Ltd
|
|
* Copyright (C) 2024 Ze Huang <18771902331@163.com>
|
|
*/
|
|
#include <linux/module.h>
|
|
#include <linux/device.h>
|
|
#include <linux/of.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/of_device.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/pinctrl/pinctrl.h>
|
|
#include <linux/pinctrl/pinmux.h>
|
|
#include <linux/pinctrl/pinconf.h>
|
|
#include <linux/pinctrl/pinconf-generic.h>
|
|
#include <linux/regmap.h>
|
|
#include <linux/seq_file.h>
|
|
|
|
#include "core.h"
|
|
#include "pinconf.h"
|
|
|
|
#define K230_NPINS 64
|
|
|
|
#define K230_SHIFT_ST (0)
|
|
#define K230_SHIFT_DS (1)
|
|
#define K230_SHIFT_BIAS (5)
|
|
#define K230_SHIFT_PD (5)
|
|
#define K230_SHIFT_PU (6)
|
|
#define K230_SHIFT_OE (7)
|
|
#define K230_SHIFT_IE (8)
|
|
#define K230_SHIFT_MSC (9)
|
|
#define K230_SHIFT_SL (10)
|
|
#define K230_SHIFT_SEL (11)
|
|
|
|
#define K230_PC_ST BIT(0)
|
|
#define K230_PC_DS GENMASK(4, 1)
|
|
#define K230_PC_PD BIT(5)
|
|
#define K230_PC_PU BIT(6)
|
|
#define K230_PC_BIAS GENMASK(6, 5)
|
|
#define K230_PC_OE BIT(7)
|
|
#define K230_PC_IE BIT(8)
|
|
#define K230_PC_MSC BIT(9)
|
|
#define K230_PC_SL BIT(10)
|
|
#define K230_PC_SEL GENMASK(13, 11)
|
|
|
|
struct k230_pin_conf {
|
|
unsigned int func;
|
|
unsigned long *configs;
|
|
unsigned int nconfigs;
|
|
};
|
|
|
|
struct k230_pin_group {
|
|
const char *name;
|
|
unsigned int *pins;
|
|
unsigned int num_pins;
|
|
|
|
struct k230_pin_conf *data;
|
|
};
|
|
|
|
struct k230_pmx_func {
|
|
const char *name;
|
|
const char **groups;
|
|
unsigned int *group_idx;
|
|
unsigned int ngroups;
|
|
};
|
|
|
|
struct k230_pinctrl {
|
|
struct pinctrl_desc pctl;
|
|
struct pinctrl_dev *pctl_dev;
|
|
struct regmap *regmap_base;
|
|
void __iomem *base;
|
|
struct k230_pin_group *groups;
|
|
unsigned int ngroups;
|
|
struct k230_pmx_func *functions;
|
|
unsigned int nfunctions;
|
|
};
|
|
|
|
static const struct regmap_config k230_regmap_config = {
|
|
.name = "canaan,pinctrl",
|
|
.reg_bits = 32,
|
|
.val_bits = 32,
|
|
.max_register = 0x100,
|
|
.reg_stride = 4,
|
|
};
|
|
|
|
static int k230_get_groups_count(struct pinctrl_dev *pctldev)
|
|
{
|
|
struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
return info->ngroups;
|
|
}
|
|
|
|
static const char *k230_get_group_name(struct pinctrl_dev *pctldev,
|
|
unsigned int selector)
|
|
{
|
|
struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
return info->groups[selector].name;
|
|
}
|
|
|
|
static int k230_get_group_pins(struct pinctrl_dev *pctldev,
|
|
unsigned int selector,
|
|
const unsigned int **pins,
|
|
unsigned int *num_pins)
|
|
{
|
|
struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
if (selector >= info->ngroups)
|
|
return -EINVAL;
|
|
|
|
*pins = info->groups[selector].pins;
|
|
*num_pins = info->groups[selector].num_pins;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline const struct k230_pmx_func *k230_name_to_funtion(
|
|
const struct k230_pinctrl *info, const char *name)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < info->nfunctions; i++) {
|
|
if (!strcmp(info->functions[i].name, name))
|
|
return &info->functions[i];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static struct pinctrl_pin_desc k230_pins[] = {
|
|
PINCTRL_PIN(0, "IO0"), PINCTRL_PIN(1, "IO1"), PINCTRL_PIN(2, "IO2"),
|
|
PINCTRL_PIN(3, "IO3"), PINCTRL_PIN(4, "IO4"), PINCTRL_PIN(5, "IO5"),
|
|
PINCTRL_PIN(6, "IO6"), PINCTRL_PIN(7, "IO7"), PINCTRL_PIN(8, "IO8"),
|
|
PINCTRL_PIN(9, "IO9"), PINCTRL_PIN(10, "IO10"), PINCTRL_PIN(11, "IO11"),
|
|
PINCTRL_PIN(12, "IO12"), PINCTRL_PIN(13, "IO13"), PINCTRL_PIN(14, "IO14"),
|
|
PINCTRL_PIN(15, "IO15"), PINCTRL_PIN(16, "IO16"), PINCTRL_PIN(17, "IO17"),
|
|
PINCTRL_PIN(18, "IO18"), PINCTRL_PIN(19, "IO19"), PINCTRL_PIN(20, "IO20"),
|
|
PINCTRL_PIN(21, "IO21"), PINCTRL_PIN(22, "IO22"), PINCTRL_PIN(23, "IO23"),
|
|
PINCTRL_PIN(24, "IO24"), PINCTRL_PIN(25, "IO25"), PINCTRL_PIN(26, "IO26"),
|
|
PINCTRL_PIN(27, "IO27"), PINCTRL_PIN(28, "IO28"), PINCTRL_PIN(29, "IO29"),
|
|
PINCTRL_PIN(30, "IO30"), PINCTRL_PIN(31, "IO31"), PINCTRL_PIN(32, "IO32"),
|
|
PINCTRL_PIN(33, "IO33"), PINCTRL_PIN(34, "IO34"), PINCTRL_PIN(35, "IO35"),
|
|
PINCTRL_PIN(36, "IO36"), PINCTRL_PIN(37, "IO37"), PINCTRL_PIN(38, "IO38"),
|
|
PINCTRL_PIN(39, "IO39"), PINCTRL_PIN(40, "IO40"), PINCTRL_PIN(41, "IO41"),
|
|
PINCTRL_PIN(42, "IO42"), PINCTRL_PIN(43, "IO43"), PINCTRL_PIN(44, "IO44"),
|
|
PINCTRL_PIN(45, "IO45"), PINCTRL_PIN(46, "IO46"), PINCTRL_PIN(47, "IO47"),
|
|
PINCTRL_PIN(48, "IO48"), PINCTRL_PIN(49, "IO49"), PINCTRL_PIN(50, "IO50"),
|
|
PINCTRL_PIN(51, "IO51"), PINCTRL_PIN(52, "IO52"), PINCTRL_PIN(53, "IO53"),
|
|
PINCTRL_PIN(54, "IO54"), PINCTRL_PIN(55, "IO55"), PINCTRL_PIN(56, "IO56"),
|
|
PINCTRL_PIN(57, "IO57"), PINCTRL_PIN(58, "IO58"), PINCTRL_PIN(59, "IO59"),
|
|
PINCTRL_PIN(60, "IO60"), PINCTRL_PIN(61, "IO61"), PINCTRL_PIN(62, "IO62"),
|
|
PINCTRL_PIN(63, "IO63")
|
|
};
|
|
|
|
static void k230_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
|
|
struct seq_file *s, unsigned int offset)
|
|
{
|
|
struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
|
u32 val, bias, drive, input, slew, schmitt, power;
|
|
struct k230_pin_group *grp = k230_pins[offset].drv_data;
|
|
static const char * const biasing[] = {
|
|
"pull none", "pull down", "pull up", "" };
|
|
static const char * const enable[] = {
|
|
"disable", "enable" };
|
|
static const char * const power_source[] = {
|
|
"3V3", "1V8" };
|
|
|
|
regmap_read(info->regmap_base, offset * 4, &val);
|
|
|
|
drive = (val & K230_PC_DS) >> K230_SHIFT_DS;
|
|
bias = (val & K230_PC_BIAS) >> K230_SHIFT_BIAS;
|
|
input = (val & K230_PC_IE) >> K230_SHIFT_IE;
|
|
slew = (val & K230_PC_SL) >> K230_SHIFT_SL;
|
|
schmitt = (val & K230_PC_ST) >> K230_SHIFT_ST;
|
|
power = (val & K230_PC_MSC) >> K230_SHIFT_MSC;
|
|
|
|
seq_printf(s, "%s - strength %d - %s - %s - slewrate %s - schmitt %s - %s",
|
|
grp ? grp->name : "unknown",
|
|
drive,
|
|
biasing[bias],
|
|
input ? "input" : "output",
|
|
enable[slew],
|
|
enable[schmitt],
|
|
power_source[power]);
|
|
}
|
|
|
|
static int k230_dt_node_to_map(struct pinctrl_dev *pctldev,
|
|
struct device_node *np_config,
|
|
struct pinctrl_map **map,
|
|
unsigned int *num_maps)
|
|
{
|
|
struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
|
struct device *dev = info->pctl_dev->dev;
|
|
const struct k230_pmx_func *func;
|
|
const struct k230_pin_group *grp;
|
|
struct pinctrl_map *new_map;
|
|
int map_num, i, j, idx;
|
|
unsigned int grp_id;
|
|
|
|
func = k230_name_to_funtion(info, np_config->name);
|
|
if (!func) {
|
|
dev_err(dev, "function %s not found\n", np_config->name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
map_num = 0;
|
|
for (i = 0; i < func->ngroups; ++i) {
|
|
grp_id = func->group_idx[i];
|
|
/* npins of config map plus a mux map */
|
|
map_num += info->groups[grp_id].num_pins + 1;
|
|
}
|
|
|
|
new_map = kcalloc(map_num, sizeof(*new_map), GFP_KERNEL);
|
|
if (!new_map)
|
|
return -ENOMEM;
|
|
*map = new_map;
|
|
*num_maps = map_num;
|
|
|
|
idx = 0;
|
|
for (i = 0; i < func->ngroups; ++i) {
|
|
grp_id = func->group_idx[i];
|
|
grp = &info->groups[grp_id];
|
|
new_map[idx].type = PIN_MAP_TYPE_MUX_GROUP;
|
|
new_map[idx].data.mux.group = grp->name;
|
|
new_map[idx].data.mux.function = np_config->name;
|
|
idx++;
|
|
|
|
for (j = 0; j < grp->num_pins; ++j) {
|
|
new_map[idx].type = PIN_MAP_TYPE_CONFIGS_PIN;
|
|
new_map[idx].data.configs.group_or_pin =
|
|
pin_get_name(pctldev, grp->pins[j]);
|
|
new_map[idx].data.configs.configs =
|
|
grp->data[j].configs;
|
|
new_map[idx].data.configs.num_configs =
|
|
grp->data[j].nconfigs;
|
|
idx++;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void k230_dt_free_map(struct pinctrl_dev *pctldev,
|
|
struct pinctrl_map *map, unsigned int num_maps)
|
|
{
|
|
kfree(map);
|
|
}
|
|
|
|
static const struct pinctrl_ops k230_pctrl_ops = {
|
|
.get_groups_count = k230_get_groups_count,
|
|
.get_group_name = k230_get_group_name,
|
|
.get_group_pins = k230_get_group_pins,
|
|
.pin_dbg_show = k230_pinctrl_pin_dbg_show,
|
|
.dt_node_to_map = k230_dt_node_to_map,
|
|
.dt_free_map = k230_dt_free_map,
|
|
};
|
|
|
|
static int k230_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin,
|
|
unsigned long *config)
|
|
{
|
|
struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
|
enum pin_config_param param = pinconf_to_config_param(*config);
|
|
unsigned int val, arg;
|
|
|
|
regmap_read(info->regmap_base, pin * 4, &val);
|
|
|
|
switch (param) {
|
|
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
|
|
arg = (val & K230_PC_ST) ? 1 : 0;
|
|
break;
|
|
case PIN_CONFIG_DRIVE_STRENGTH:
|
|
arg = (val & K230_PC_DS) >> K230_SHIFT_DS;
|
|
break;
|
|
case PIN_CONFIG_BIAS_DISABLE:
|
|
arg = (val & K230_PC_BIAS) ? 0 : 1;
|
|
break;
|
|
case PIN_CONFIG_BIAS_PULL_DOWN:
|
|
arg = (val & K230_PC_PD) ? 1 : 0;
|
|
break;
|
|
case PIN_CONFIG_BIAS_PULL_UP:
|
|
arg = (val & K230_PC_PU) ? 1 : 0;
|
|
break;
|
|
case PIN_CONFIG_OUTPUT_ENABLE:
|
|
arg = (val & K230_PC_OE) ? 1 : 0;
|
|
break;
|
|
case PIN_CONFIG_INPUT_ENABLE:
|
|
arg = (val & K230_PC_IE) ? 1 : 0;
|
|
break;
|
|
case PIN_CONFIG_POWER_SOURCE:
|
|
arg = (val & K230_PC_MSC) ? 1 : 0;
|
|
break;
|
|
case PIN_CONFIG_SLEW_RATE:
|
|
arg = (val & K230_PC_SL) ? 1 : 0;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
*config = pinconf_to_config_packed(param, arg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int k230_pinconf_set_param(struct pinctrl_dev *pctldev, unsigned int pin,
|
|
enum pin_config_param param, unsigned int arg)
|
|
{
|
|
struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
|
unsigned int val;
|
|
|
|
regmap_read(info->regmap_base, pin * 4, &val);
|
|
|
|
switch (param) {
|
|
case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
|
|
if (arg)
|
|
val |= K230_PC_ST;
|
|
else
|
|
val &= ~K230_PC_ST;
|
|
break;
|
|
case PIN_CONFIG_DRIVE_STRENGTH:
|
|
val &= ~K230_PC_DS;
|
|
val |= (arg << K230_SHIFT_DS) & K230_PC_DS;
|
|
break;
|
|
case PIN_CONFIG_BIAS_DISABLE:
|
|
val &= ~K230_PC_BIAS;
|
|
break;
|
|
case PIN_CONFIG_BIAS_PULL_DOWN:
|
|
if (!arg)
|
|
return -EINVAL;
|
|
val |= K230_PC_PD;
|
|
break;
|
|
case PIN_CONFIG_BIAS_PULL_UP:
|
|
if (!arg)
|
|
return -EINVAL;
|
|
val |= K230_PC_PU;
|
|
break;
|
|
case PIN_CONFIG_OUTPUT_ENABLE:
|
|
if (!arg)
|
|
return -EINVAL;
|
|
val |= K230_PC_OE;
|
|
break;
|
|
case PIN_CONFIG_INPUT_ENABLE:
|
|
if (!arg)
|
|
return -EINVAL;
|
|
val |= K230_PC_IE;
|
|
break;
|
|
case PIN_CONFIG_POWER_SOURCE:
|
|
if (arg)
|
|
val |= K230_PC_MSC;
|
|
else
|
|
val &= ~K230_PC_MSC;
|
|
break;
|
|
case PIN_CONFIG_SLEW_RATE:
|
|
if (arg)
|
|
val |= K230_PC_SL;
|
|
else
|
|
val &= ~K230_PC_SL;
|
|
break;
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
regmap_write(info->regmap_base, pin * 4, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int k230_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
|
|
unsigned long *configs, unsigned int num_configs)
|
|
{
|
|
struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
|
struct device *dev = info->pctl_dev->dev;
|
|
enum pin_config_param param;
|
|
unsigned int arg, i;
|
|
int ret;
|
|
|
|
if (pin >= K230_NPINS) {
|
|
dev_err(dev, "pin number out of range\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
for (i = 0; i < num_configs; i++) {
|
|
param = pinconf_to_config_param(configs[i]);
|
|
arg = pinconf_to_config_argument(configs[i]);
|
|
ret = k230_pinconf_set_param(pctldev, pin, param, arg);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void k230_pconf_dbg_show(struct pinctrl_dev *pctldev,
|
|
struct seq_file *s, unsigned int pin)
|
|
{
|
|
struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
|
unsigned int val;
|
|
|
|
regmap_read(info->regmap_base, pin * 4, &val);
|
|
|
|
seq_printf(s, " 0x%08x", val);
|
|
}
|
|
|
|
static const struct pinconf_ops k230_pinconf_ops = {
|
|
.is_generic = true,
|
|
.pin_config_get = k230_pinconf_get,
|
|
.pin_config_set = k230_pinconf_set,
|
|
.pin_config_dbg_show = k230_pconf_dbg_show,
|
|
};
|
|
|
|
static int k230_get_functions_count(struct pinctrl_dev *pctldev)
|
|
{
|
|
struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
return info->nfunctions;
|
|
}
|
|
|
|
static const char *k230_get_fname(struct pinctrl_dev *pctldev,
|
|
unsigned int selector)
|
|
{
|
|
struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
return info->functions[selector].name;
|
|
}
|
|
|
|
static int k230_get_groups(struct pinctrl_dev *pctldev, unsigned int selector,
|
|
const char * const **groups, unsigned int *num_groups)
|
|
{
|
|
struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
|
|
|
*groups = info->functions[selector].groups;
|
|
*num_groups = info->functions[selector].ngroups;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int k230_set_mux(struct pinctrl_dev *pctldev, unsigned int selector,
|
|
unsigned int group)
|
|
{
|
|
struct k230_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
|
const struct k230_pin_conf *data = info->groups[group].data;
|
|
struct k230_pin_group *grp = &info->groups[group];
|
|
const unsigned int *pins = grp->pins;
|
|
struct regmap *regmap;
|
|
unsigned int value, mask;
|
|
int cnt, reg;
|
|
|
|
regmap = info->regmap_base;
|
|
|
|
for (cnt = 0; cnt < grp->num_pins; cnt++) {
|
|
reg = pins[cnt] * 4;
|
|
value = data[cnt].func << K230_SHIFT_SEL;
|
|
mask = K230_PC_SEL;
|
|
regmap_update_bits(regmap, reg, mask, value);
|
|
k230_pins[pins[cnt]].drv_data = grp;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct pinmux_ops k230_pmxops = {
|
|
.get_functions_count = k230_get_functions_count,
|
|
.get_function_name = k230_get_fname,
|
|
.get_function_groups = k230_get_groups,
|
|
.set_mux = k230_set_mux,
|
|
.strict = true,
|
|
};
|
|
|
|
static int k230_pinctrl_parse_groups(struct device_node *np,
|
|
struct k230_pin_group *grp,
|
|
struct k230_pinctrl *info,
|
|
unsigned int index)
|
|
{
|
|
struct device *dev = info->pctl_dev->dev;
|
|
const __be32 *list;
|
|
int size, i, ret;
|
|
|
|
grp->name = np->name;
|
|
|
|
list = of_get_property(np, "pinmux", &size);
|
|
size /= sizeof(*list);
|
|
|
|
grp->num_pins = size;
|
|
grp->pins = devm_kcalloc(dev, grp->num_pins, sizeof(*grp->pins),
|
|
GFP_KERNEL);
|
|
grp->data = devm_kcalloc(dev, grp->num_pins, sizeof(*grp->data),
|
|
GFP_KERNEL);
|
|
if (!grp->pins || !grp->data)
|
|
return -ENOMEM;
|
|
|
|
for (i = 0; i < size; i++) {
|
|
unsigned int mux_data = be32_to_cpu(*list++);
|
|
|
|
grp->pins[i] = (mux_data >> 8);
|
|
grp->data[i].func = (mux_data & 0xff);
|
|
|
|
ret = pinconf_generic_parse_dt_config(np, NULL,
|
|
&grp->data[i].configs,
|
|
&grp->data[i].nconfigs);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int k230_pinctrl_parse_functions(struct device_node *np,
|
|
struct k230_pinctrl *info,
|
|
unsigned int index)
|
|
{
|
|
struct device *dev = info->pctl_dev->dev;
|
|
struct k230_pmx_func *func;
|
|
struct k230_pin_group *grp;
|
|
static unsigned int idx, i;
|
|
int ret;
|
|
|
|
func = &info->functions[index];
|
|
|
|
func->name = np->name;
|
|
func->ngroups = of_get_child_count(np);
|
|
if (func->ngroups <= 0)
|
|
return 0;
|
|
|
|
func->groups = devm_kcalloc(dev, func->ngroups,
|
|
sizeof(*func->groups), GFP_KERNEL);
|
|
func->group_idx = devm_kcalloc(dev, func->ngroups,
|
|
sizeof(*func->group_idx), GFP_KERNEL);
|
|
if (!func->groups || !func->group_idx)
|
|
return -ENOMEM;
|
|
|
|
i = 0;
|
|
|
|
for_each_child_of_node_scoped(np, child) {
|
|
func->groups[i] = child->name;
|
|
func->group_idx[i] = idx;
|
|
grp = &info->groups[idx];
|
|
idx++;
|
|
ret = k230_pinctrl_parse_groups(child, grp, info, i++);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void k230_pinctrl_child_count(struct k230_pinctrl *info,
|
|
struct device_node *np)
|
|
{
|
|
for_each_child_of_node_scoped(np, child) {
|
|
info->nfunctions++;
|
|
info->ngroups += of_get_child_count(child);
|
|
}
|
|
}
|
|
|
|
static int k230_pinctrl_parse_dt(struct platform_device *pdev,
|
|
struct k230_pinctrl *info)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct device_node *np = dev->of_node;
|
|
unsigned int i;
|
|
int ret;
|
|
|
|
k230_pinctrl_child_count(info, np);
|
|
|
|
info->functions = devm_kcalloc(dev, info->nfunctions,
|
|
sizeof(*info->functions), GFP_KERNEL);
|
|
info->groups = devm_kcalloc(dev, info->ngroups,
|
|
sizeof(*info->groups), GFP_KERNEL);
|
|
if (!info->functions || !info->groups)
|
|
return -ENOMEM;
|
|
|
|
i = 0;
|
|
|
|
for_each_child_of_node_scoped(np, child) {
|
|
ret = k230_pinctrl_parse_functions(child, info, i++);
|
|
if (ret) {
|
|
dev_err(dev, "failed to parse function\n");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int k230_pinctrl_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct k230_pinctrl *info;
|
|
struct pinctrl_desc *pctl;
|
|
|
|
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
|
|
if (!info)
|
|
return -ENOMEM;
|
|
|
|
pctl = &info->pctl;
|
|
|
|
pctl->name = "k230-pinctrl";
|
|
pctl->owner = THIS_MODULE;
|
|
pctl->pins = k230_pins;
|
|
pctl->npins = ARRAY_SIZE(k230_pins);
|
|
pctl->pctlops = &k230_pctrl_ops;
|
|
pctl->pmxops = &k230_pmxops;
|
|
pctl->confops = &k230_pinconf_ops;
|
|
|
|
info->base = devm_platform_ioremap_resource(pdev, 0);
|
|
if (IS_ERR(info->base))
|
|
return PTR_ERR(info->base);
|
|
|
|
info->regmap_base = devm_regmap_init_mmio(dev, info->base,
|
|
&k230_regmap_config);
|
|
if (IS_ERR(info->regmap_base))
|
|
return dev_err_probe(dev, PTR_ERR(info->regmap_base),
|
|
"failed to init regmap\n");
|
|
|
|
info->pctl_dev = devm_pinctrl_register(dev, pctl, info);
|
|
if (IS_ERR(info->pctl_dev))
|
|
return dev_err_probe(dev, PTR_ERR(info->pctl_dev),
|
|
"devm_pinctrl_register failed\n");
|
|
|
|
k230_pinctrl_parse_dt(pdev, info);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct of_device_id k230_dt_ids[] = {
|
|
{ .compatible = "canaan,k230-pinctrl", },
|
|
{ /* sintenel */ }
|
|
};
|
|
MODULE_DEVICE_TABLE(of, k230_dt_ids);
|
|
|
|
static struct platform_driver k230_pinctrl_driver = {
|
|
.probe = k230_pinctrl_probe,
|
|
.driver = {
|
|
.name = "k230-pinctrl",
|
|
.of_match_table = k230_dt_ids,
|
|
},
|
|
};
|
|
module_platform_driver(k230_pinctrl_driver);
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("Ze Huang <18771902331@163.com>");
|
|
MODULE_DESCRIPTION("Canaan K230 pinctrl driver");
|