mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
sh-pfc: Add DT support
Support device instantiation through the device tree. The compatible property is used to select the SoC pinmux information. Set the gpio_chip device field to the PFC device to enable automatic GPIO OF support. Cc: [email protected] Signed-off-by: Laurent Pinchart <[email protected]> Acked-by: Heiko Stuebner <[email protected]> Signed-off-by: Linus Walleij <[email protected]>
This commit is contained in:
parent
3a7f520e63
commit
fe1c9a822c
3 changed files with 314 additions and 1 deletions
|
|
@ -18,6 +18,8 @@
|
|||
#include <linux/ioport.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/machine.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -348,13 +350,72 @@ int sh_pfc_config_mux(struct sh_pfc *pfc, unsigned mark, int pinmux_type)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id sh_pfc_of_table[] = {
|
||||
#ifdef CONFIG_PINCTRL_PFC_R8A73A4
|
||||
{
|
||||
.compatible = "renesas,pfc-r8a73a4",
|
||||
.data = &r8a73a4_pinmux_info,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_PINCTRL_PFC_R8A7740
|
||||
{
|
||||
.compatible = "renesas,pfc-r8a7740",
|
||||
.data = &r8a7740_pinmux_info,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_PINCTRL_PFC_R8A7778
|
||||
{
|
||||
.compatible = "renesas,pfc-r8a7778",
|
||||
.data = &r8a7778_pinmux_info,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_PINCTRL_PFC_R8A7779
|
||||
{
|
||||
.compatible = "renesas,pfc-r8a7779",
|
||||
.data = &r8a7779_pinmux_info,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_PINCTRL_PFC_R8A7790
|
||||
{
|
||||
.compatible = "renesas,pfc-r8a7790",
|
||||
.data = &r8a7790_pinmux_info,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_PINCTRL_PFC_SH7372
|
||||
{
|
||||
.compatible = "renesas,pfc-sh7372",
|
||||
.data = &sh7372_pinmux_info,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_PINCTRL_PFC_SH73A0
|
||||
{
|
||||
.compatible = "renesas,pfc-sh73a0",
|
||||
.data = &sh73a0_pinmux_info,
|
||||
},
|
||||
#endif
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sh_pfc_of_table);
|
||||
#endif
|
||||
|
||||
static int sh_pfc_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct platform_device_id *platid = platform_get_device_id(pdev);
|
||||
#ifdef CONFIG_OF
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
#endif
|
||||
const struct sh_pfc_soc_info *info;
|
||||
struct sh_pfc *pfc;
|
||||
int ret;
|
||||
|
||||
info = (void *)pdev->id_entry->driver_data;
|
||||
#ifdef CONFIG_OF
|
||||
if (np)
|
||||
info = of_match_device(sh_pfc_of_table, &pdev->dev)->data;
|
||||
else
|
||||
#endif
|
||||
info = platid ? (const void *)platid->driver_data : NULL;
|
||||
|
||||
if (info == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
|
|
@ -480,6 +541,7 @@ static struct platform_driver sh_pfc_driver = {
|
|||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(sh_pfc_of_table),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pinctrl/machine.h>
|
||||
#include <linux/pinctrl/pinconf.h>
|
||||
#include <linux/pinctrl/pinconf-generic.h>
|
||||
#include <linux/pinctrl/pinctrl.h>
|
||||
|
|
@ -72,11 +74,125 @@ static void sh_pfc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
|
|||
seq_printf(s, "%s", DRV_NAME);
|
||||
}
|
||||
|
||||
static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np,
|
||||
struct pinctrl_map **map,
|
||||
unsigned int *num_maps, unsigned int *index)
|
||||
{
|
||||
struct pinctrl_map *maps = *map;
|
||||
unsigned int nmaps = *num_maps;
|
||||
unsigned int idx = *index;
|
||||
const char *function = NULL;
|
||||
struct property *prop;
|
||||
const char *group;
|
||||
int ret;
|
||||
|
||||
/* Parse the function and configuration properties. At least a function
|
||||
* or one configuration must be specified.
|
||||
*/
|
||||
ret = of_property_read_string(np, "renesas,function", &function);
|
||||
if (ret < 0 && ret != -EINVAL) {
|
||||
dev_err(dev, "Invalid function in DT\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!function) {
|
||||
dev_err(dev, "DT node must contain at least one function\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Count the number of groups and reallocate mappings. */
|
||||
ret = of_property_count_strings(np, "renesas,groups");
|
||||
if (ret < 0 && ret != -EINVAL) {
|
||||
dev_err(dev, "Invalid pin groups list in DT\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
dev_err(dev, "No group provided in DT node\n");
|
||||
ret = -ENODEV;
|
||||
goto done;
|
||||
}
|
||||
|
||||
nmaps += ret;
|
||||
|
||||
maps = krealloc(maps, sizeof(*maps) * nmaps, GFP_KERNEL);
|
||||
if (maps == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*map = maps;
|
||||
*num_maps = nmaps;
|
||||
|
||||
/* Iterate over pins and groups and create the mappings. */
|
||||
of_property_for_each_string(np, "renesas,groups", prop, group) {
|
||||
maps[idx].type = PIN_MAP_TYPE_MUX_GROUP;
|
||||
maps[idx].data.mux.group = group;
|
||||
maps[idx].data.mux.function = function;
|
||||
idx++;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
*index = idx;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sh_pfc_dt_free_map(struct pinctrl_dev *pctldev,
|
||||
struct pinctrl_map *map, unsigned num_maps)
|
||||
{
|
||||
kfree(map);
|
||||
}
|
||||
|
||||
static int sh_pfc_dt_node_to_map(struct pinctrl_dev *pctldev,
|
||||
struct device_node *np,
|
||||
struct pinctrl_map **map, unsigned *num_maps)
|
||||
{
|
||||
struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
|
||||
struct device *dev = pmx->pfc->dev;
|
||||
struct device_node *child;
|
||||
unsigned int index;
|
||||
int ret;
|
||||
|
||||
*map = NULL;
|
||||
*num_maps = 0;
|
||||
index = 0;
|
||||
|
||||
for_each_child_of_node(np, child) {
|
||||
ret = sh_pfc_dt_subnode_to_map(dev, child, map, num_maps,
|
||||
&index);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* If no mapping has been found in child nodes try the config node. */
|
||||
if (*num_maps == 0) {
|
||||
ret = sh_pfc_dt_subnode_to_map(dev, np, map, num_maps, &index);
|
||||
if (ret < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (*num_maps)
|
||||
return 0;
|
||||
|
||||
dev_err(dev, "no mapping found in node %s\n", np->full_name);
|
||||
ret = -EINVAL;
|
||||
|
||||
done:
|
||||
if (ret < 0)
|
||||
sh_pfc_dt_free_map(pctldev, *map, *num_maps);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct pinctrl_ops sh_pfc_pinctrl_ops = {
|
||||
.get_groups_count = sh_pfc_get_groups_count,
|
||||
.get_group_name = sh_pfc_get_group_name,
|
||||
.get_group_pins = sh_pfc_get_group_pins,
|
||||
.pin_dbg_show = sh_pfc_pin_dbg_show,
|
||||
.dt_node_to_map = sh_pfc_dt_node_to_map,
|
||||
.dt_free_map = sh_pfc_dt_free_map,
|
||||
};
|
||||
|
||||
static int sh_pfc_get_functions_count(struct pinctrl_dev *pctldev)
|
||||
|
|
|
|||
Loading…
Reference in a new issue