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: devicetree-discuss@lists.ozlabs.org Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Acked-by: Heiko Stuebner <heiko@sntech.de> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
3a7f520e63
commit
fe1c9a822c
|
@ -0,0 +1,135 @@
|
|||
* Renesas Pin Function Controller (GPIO and Pin Mux/Config)
|
||||
|
||||
The Pin Function Controller (PFC) is a Pin Mux/Config controller. On SH7372,
|
||||
SH73A0, R8A73A4 and R8A7740 it also acts as a GPIO controller.
|
||||
|
||||
|
||||
Pin Control
|
||||
-----------
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: should be one of the following.
|
||||
- "renesas,pfc-r8a73a4": for R8A73A4 (R-Mobile APE6) compatible pin-controller.
|
||||
- "renesas,pfc-r8a7740": for R8A7740 (R-Mobile A1) compatible pin-controller.
|
||||
- "renesas,pfc-r8a7778": for R8A7778 (R-Mobile M1) compatible pin-controller.
|
||||
- "renesas,pfc-r8a7779": for R8A7779 (R-Car H1) compatible pin-controller.
|
||||
- "renesas,pfc-r8a7790": for R8A7790 (R-Car H2) compatible pin-controller.
|
||||
- "renesas,pfc-sh7372": for SH7372 (SH-Mobile AP4) compatible pin-controller.
|
||||
- "renesas,pfc-sh73a0": for SH73A0 (SH-Mobile AG5) compatible pin-controller.
|
||||
|
||||
- reg: Base address and length of each memory resource used by the pin
|
||||
controller hardware module.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- #gpio-range-cells: Mandatory when the PFC doesn't handle GPIO, forbidden
|
||||
otherwise. Should be 3.
|
||||
|
||||
The PFC node also acts as a container for pin configuration nodes. Please refer
|
||||
to pinctrl-bindings.txt in this directory for the definition of the term "pin
|
||||
configuration node" and for the common pinctrl bindings used by client devices.
|
||||
|
||||
Each pin configuration node represents desired functions to select on a pin
|
||||
group or a list of pin groups. The functions and pin groups can be specified
|
||||
directly in the pin configuration node, or grouped in child subnodes. Several
|
||||
functions can thus be referenced as a single pin configuration node by client
|
||||
devices.
|
||||
|
||||
A configuration node or subnode must contain a function and reference at least
|
||||
one pin group.
|
||||
|
||||
All pin configuration nodes and subnodes names are ignored. All of those nodes
|
||||
are parsed through phandles and processed purely based on their content.
|
||||
|
||||
Pin Configuration Node Properties:
|
||||
|
||||
- renesas,groups : An array of strings, each string containing the name of a pin
|
||||
group.
|
||||
|
||||
- renesas,function: A string containing the name of the function to mux to the
|
||||
pin group(s) specified by the renesas,groups property
|
||||
|
||||
Valid values for pin, group and function names can be found in the group and
|
||||
function arrays of the PFC data file corresponding to the SoC
|
||||
(drivers/pinctrl/sh-pfc/pfc-*.c)
|
||||
|
||||
|
||||
GPIO
|
||||
----
|
||||
|
||||
On SH7372, SH73A0, R8A73A4 and R8A7740 the PFC node is also a GPIO controller
|
||||
node.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- gpio-controller: Marks the device node as a gpio controller.
|
||||
|
||||
- #gpio-cells: Should be 2. The first cell is the GPIO number and the second
|
||||
cell specifies GPIO flags, as defined in <dt-bindings/gpio/gpio.h>. Only the
|
||||
GPIO_ACTIVE_HIGH and GPIO_ACTIVE_LOW flags are supported.
|
||||
|
||||
The syntax of the gpio specifier used by client nodes should be the following
|
||||
with values derived from the SoC user manual.
|
||||
|
||||
<[phandle of the gpio controller node]
|
||||
[pin number within the gpio controller]
|
||||
[flags]>
|
||||
|
||||
On other mach-shmobile platforms GPIO is handled by the gpio-rcar driver.
|
||||
Please refer to Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt
|
||||
for documentation of the GPIO device tree bindings on those platforms.
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Example 1: SH73A0 (SH-Mobile AG5) pin controller node
|
||||
|
||||
pfc: pfc@e6050000 {
|
||||
compatible = "renesas,pfc-sh73a0";
|
||||
reg = <0xe6050000 0x8000>,
|
||||
<0xe605801c 0x1c>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
};
|
||||
|
||||
Example 2: A GPIO LED node that references a GPIO
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
led1 {
|
||||
gpios = <&pfc 20 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
Example 3: KZM-A9-GT (SH-Mobile AG5) default pin state hog and pin control maps
|
||||
for the MMCIF and SCIFA4 devices
|
||||
|
||||
&pfc {
|
||||
pinctrl-0 = <&scifa4_pins>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
mmcif_pins: mmcif {
|
||||
renesas,groups = "mmc0_data8_0", "mmc0_ctrl_0";
|
||||
renesas,function = "mmc0";
|
||||
};
|
||||
|
||||
scifa4_pins: scifa4 {
|
||||
renesas,groups = "scifa4_data", "scifa4_ctrl";
|
||||
renesas,function = "scifa4";
|
||||
};
|
||||
};
|
||||
|
||||
Example 4: KZM-A9-GT (SH-Mobile AG5) default pin state for the MMCIF device
|
||||
|
||||
&mmcif {
|
||||
pinctrl-0 = <&mmcif_pins>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
bus-width = <8>;
|
||||
vmmc-supply = <®_1p8v>;
|
||||
status = "okay";
|
||||
};
|
|
@ -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 New Issue