398 lines
11 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* serdes-pinctrl.c -- serdes pin control driver.
*
* Copyright (c) 2023-2028 Rockchip Electronics Co., Ltd.
*
* Author: luowei <lw@rock-chips.com>
*/
#include "core.h"
static const struct mfd_cell serdes_gpio_bu18tl82_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "rohm,bu18tl82-gpio",
},
};
static const struct mfd_cell serdes_gpio_bu18rl82_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "rohm,bu18rl82-gpio",
},
};
static const struct mfd_cell serdes_gpio_max96745_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "maxim,max96745-gpio",
},
};
static const struct mfd_cell serdes_gpio_max96755_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "maxim,max96755-gpio",
},
};
static const struct mfd_cell serdes_gpio_max96789_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "maxim,max96789-gpio",
},
};
static const struct mfd_cell serdes_gpio_max96752_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "maxim,max96752-gpio",
},
};
static const struct mfd_cell serdes_gpio_max96772_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "maxim,max96772-gpio",
},
};
static const struct mfd_cell serdes_gpio_rkx111_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "rockchip,rkx111-gpio",
},
};
static const struct mfd_cell serdes_gpio_rkx121_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "rockchip,rkx121-gpio",
},
};
static const struct mfd_cell serdes_gpio_nca9539_devs[] = {
{
.name = "serdes-gpio",
.of_compatible = "novo,nca9539-gpio",
},
};
static int serdes_pinmux_set_mux(struct pinctrl_dev *pctldev,
unsigned int function, unsigned int group)
{
struct serdes_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
struct serdes *serdes = pinctrl->parent;
int ret = 0;
if (serdes->chip_data->pinctrl_ops->set_mux)
ret = serdes->chip_data->pinctrl_ops->set_mux(serdes, function, group);
SERDES_DBG_MFD("%s: %s function=%d,group=%d\n", __func__,
serdes->chip_data->name, function, group);
return ret;
}
static int serdes_pinconf_get(struct pinctrl_dev *pctldev,
unsigned int pin, unsigned long *config)
{
struct serdes_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
//enum pin_config_param param = pinconf_to_config_param(*config);
struct serdes *serdes = pinctrl->parent;
int ret = 0;
if (serdes->chip_data->pinctrl_ops->pin_config_get)
ret = serdes->chip_data->pinctrl_ops->pin_config_get(serdes,
pin - pinctrl->pin_base,
config);
SERDES_DBG_MFD("%s: %s pin=%d,config=%d\n", __func__,
serdes->chip_data->name,
pin - pinctrl->pin_base, pinconf_to_config_param(*config));
return ret;
}
static int serdes_pinconf_set(struct pinctrl_dev *pctldev,
unsigned int pin, unsigned long *configs,
unsigned int num_configs)
{
struct serdes_pinctrl *pinctrl = pinctrl_dev_get_drvdata(pctldev);
//enum pin_config_param param = pinconf_to_config_param(*configs);
struct serdes *serdes = pinctrl->parent;
int ret = 0;
if (serdes->chip_data->pinctrl_ops->pin_config_set)
ret = serdes->chip_data->pinctrl_ops->pin_config_set(serdes,
pin - pinctrl->pin_base,
configs, num_configs);
SERDES_DBG_MFD("%s: %s pin=%d,config=%d\n", __func__, serdes->chip_data->name,
pin - pinctrl->pin_base, pinconf_to_config_param(*configs));
return ret;
}
static const struct pinconf_ops serdes_pinconf_ops = {
.pin_config_get = serdes_pinconf_get,
.pin_config_set = serdes_pinconf_set,
};
static const struct pinmux_ops serdes_pinmux_ops = {
.get_functions_count = pinmux_generic_get_function_count,
.get_function_name = pinmux_generic_get_function_name,
.get_function_groups = pinmux_generic_get_function_groups,
.set_mux = serdes_pinmux_set_mux,
};
static const struct pinctrl_ops serdes_pinctrl_ops = {
.get_groups_count = pinctrl_generic_get_group_count,
.get_group_name = pinctrl_generic_get_group_name,
.get_group_pins = pinctrl_generic_get_group_pins,
.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
.dt_free_map = pinconf_generic_dt_free_map,
};
static int serdes_pinctrl_gpio_init(struct serdes *serdes)
{
struct serdes_chip_data *chip_data = serdes->chip_data;
struct serdes_pinctrl *pinctrl = serdes->pinctrl;
const struct mfd_cell *serdes_devs = NULL;
int ret = 0;
int mfd_num = 0;
switch (chip_data->serdes_id) {
case ROHM_ID_BU18TL82:
serdes_devs = serdes_gpio_bu18tl82_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_bu18tl82_devs);
break;
case ROHM_ID_BU18RL82:
serdes_devs = serdes_gpio_bu18rl82_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_bu18rl82_devs);
break;
case MAXIM_ID_MAX96745:
serdes_devs = serdes_gpio_max96745_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_max96745_devs);
break;
case MAXIM_ID_MAX96752:
serdes_devs = serdes_gpio_max96752_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_max96752_devs);
break;
case MAXIM_ID_MAX96755:
serdes_devs = serdes_gpio_max96755_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_max96755_devs);
break;
case MAXIM_ID_MAX96772:
serdes_devs = serdes_gpio_max96772_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_max96772_devs);
break;
case MAXIM_ID_MAX96789:
serdes_devs = serdes_gpio_max96789_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_max96789_devs);
break;
case ROCKCHIP_ID_RKX111:
serdes_devs = serdes_gpio_rkx111_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_rkx111_devs);
break;
case ROCKCHIP_ID_RKX121:
serdes_devs = serdes_gpio_rkx121_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_rkx121_devs);
break;
case NOVO_ID_NCA9539:
serdes_devs = serdes_gpio_nca9539_devs;
mfd_num = ARRAY_SIZE(serdes_gpio_nca9539_devs);
break;
default:
dev_info(serdes->dev, "%s: unknown device\n", __func__);
break;
}
ret = devm_mfd_add_devices(pinctrl->dev, PLATFORM_DEVID_AUTO, serdes_devs,
mfd_num, NULL, 0, NULL);
if (ret != 0)
dev_err(pinctrl->dev, "Failed to add serdes children\n");
return ret;
}
static int serdes_pinctrl_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct serdes *serdes = dev_get_drvdata(pdev->dev.parent);
const struct serdes_chip_data *chip_data = serdes->chip_data;
struct serdes_pinctrl *serdes_pinctrl;
struct pinctrl_desc *pinctrl_desc;
const struct serdes_chip_pinctrl_info *pinctrl_info;
struct device_node *child;
const char *list_name = "gpio-ranges";
struct of_phandle_args of_args;
int pin_base = 0;
int i, j, ret;
if (!serdes->dev || !serdes->chip_data)
return -1;
pinctrl_info = chip_data->pinctrl_info;
serdes_pinctrl = devm_kzalloc(dev, sizeof(*serdes_pinctrl), GFP_KERNEL);
if (!serdes_pinctrl)
return -ENOMEM;
serdes_pinctrl->dev = dev;
serdes_pinctrl->parent = serdes;
serdes->pinctrl = serdes_pinctrl;
platform_set_drvdata(pdev, serdes_pinctrl);
serdes_pinctrl->regmap = dev_get_regmap(dev->parent, NULL);
if (!serdes_pinctrl->regmap)
return dev_err_probe(dev, -ENODEV, "failed to get serdes regmap\n");
pinctrl_desc = devm_kzalloc(dev, sizeof(*pinctrl_desc), GFP_KERNEL);
if (!pinctrl_desc)
return -ENOMEM;
pinctrl_desc->name = dev_name(dev);
pinctrl_desc->owner = THIS_MODULE;
pinctrl_desc->pctlops = &serdes_pinctrl_ops;
pinctrl_desc->pmxops = &serdes_pinmux_ops;
pinctrl_desc->confops = &serdes_pinconf_ops;
pinctrl_desc->npins = pinctrl_info->num_pins;
serdes_pinctrl->pdesc = devm_kcalloc(dev,
pinctrl_info->num_pins,
sizeof(*serdes_pinctrl->pdesc),
GFP_KERNEL);
pinctrl_desc->pins = serdes_pinctrl->pdesc;
if (!serdes_pinctrl->pdesc)
return -ENOMEM;
serdes_pinctrl->pinctrl_desc = pinctrl_desc;
for_each_available_child_of_node(dev->of_node, child) {
ret = of_parse_phandle_with_fixed_args(child, list_name, 3, 0, &of_args);
if (ret) {
dev_err(dev, "Unable to parse %s list property in %s node\n",
list_name, child->name);
} else {
pin_base = of_args.args[1];
SERDES_DBG_MFD("%s:gpio-range=<%d %d>\n", __func__, pin_base,
pin_base + of_args.args[2]);
}
}
if (pin_base) {
for (i = 0; i < pinctrl_info->num_pins; i++) {
serdes_pinctrl->pdesc[i].number = pinctrl_info->pins[i].number + pin_base;
serdes_pinctrl->pdesc[i].name = kasprintf(GFP_KERNEL, "%s-gpio%d",
pinctrl_info->pins[i].name,
serdes_pinctrl->pdesc[i].number);
SERDES_DBG_MFD("%s:pdesc number=%d, name=%s\n", __func__,
serdes_pinctrl->pdesc[i].number,
serdes_pinctrl->pdesc[i].name);
}
} else {
dev_info(serdes->dev, "no pinctrl setting\n");
return 0;
}
serdes_pinctrl->pin_base = pin_base;
/* Add pinctrl */
ret = devm_pinctrl_register_and_init(dev, pinctrl_desc, serdes_pinctrl,
&serdes_pinctrl->pctl);
if (ret)
return dev_err_probe(dev, ret, "failed to register serdes pinctrl\n");
for (i = 0; i < pinctrl_info->num_groups; i++) {
struct group_desc *group = &pinctrl_info->groups[i];
int *grp_pins = devm_kcalloc(dev,
group->num_pins, sizeof(*group->pins), GFP_KERNEL);
for (j = 0; j < group->num_pins; j++) {
grp_pins[j] = pinctrl_info->groups[i].pins[j] + pin_base;
SERDES_DBG_MFD("%s group name %s pin=%d base=%d\n", __func__,
pinctrl_info->groups[i].name, grp_pins[j], pin_base);
}
ret = pinctrl_generic_add_group(serdes_pinctrl->pctl, group->name,
grp_pins, group->num_pins, group->data);
if (ret < 0) {
dev_err(dev, "Failed to register serdes group %s\n",
group->name);
return ret;
}
}
for (i = 0; i < pinctrl_info->num_functions; i++) {
const struct function_desc *func = &pinctrl_info->functions[i];
ret = pinmux_generic_add_function(serdes_pinctrl->pctl, func->name,
func->group_names, func->num_group_names,
func->data);
if (ret < 0) {
dev_err(dev, "Failed to register serdes function %s\n",
func->name);
return ret;
}
}
if (!serdes->route_enable)
ret = pinctrl_enable(serdes_pinctrl->pctl);
ret = serdes_pinctrl_gpio_init(serdes);
/* pinctrl state*/
serdes->pinctrl_node = devm_pinctrl_get(dev);
if (!IS_ERR(serdes->pinctrl_node)) {
serdes->pins_default =
pinctrl_lookup_state(serdes->pinctrl_node, PINCTRL_STATE_DEFAULT);
serdes->pins_init =
pinctrl_lookup_state(serdes->pinctrl_node, PINCTRL_STATE_INIT);
serdes->pins_sleep =
pinctrl_lookup_state(serdes->pinctrl_node, PINCTRL_STATE_SLEEP);
}
dev_info(dev, "%s %s serdes_pinctrl_probe successful, pin_base=%d\n",
dev_name(dev->parent), serdes->chip_data->name, pin_base);
return ret;
}
static const struct of_device_id serdes_pinctrl_of_match[] = {
{ .compatible = "rohm,bu18tl82-pinctrl" },
{ .compatible = "rohm,bu18rl82-pinctrl" },
{ .compatible = "maxim,max96745-pinctrl" },
{ .compatible = "maxim,max96752-pinctrl" },
{ .compatible = "maxim,max96755-pinctrl" },
{ .compatible = "maxim,max96772-pinctrl" },
{ .compatible = "maxim,max96789-pinctrl" },
{ .compatible = "rockchip,rkx111-pinctrl" },
{ .compatible = "rockchip,rkx121-pinctrl" },
{ .compatible = "novo,nca9539-pinctrl" },
{ }
};
static struct platform_driver serdes_pinctrl_driver = {
.driver = {
.name = "serdes-pinctrl",
.of_match_table = of_match_ptr(serdes_pinctrl_of_match),
},
.probe = serdes_pinctrl_probe,
};
static int __init serdes_pinctrl_init(void)
{
return platform_driver_register(&serdes_pinctrl_driver);
}
subsys_initcall_sync(serdes_pinctrl_init);
static void __exit serdes_pinctrl_exit(void)
{
platform_driver_unregister(&serdes_pinctrl_driver);
}
module_exit(serdes_pinctrl_exit);
MODULE_AUTHOR("Luo Wei <lw@rock-chips.com>");
MODULE_DESCRIPTION("display pinctrl interface for different serdes");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:serdes-pinctrl");