The Display Port Auxiliary (DPAUX) channel pads can be shared with an internal I2C controller. Add pinctrl support for these pads so that the I2C controller can request and use these pads.
This series has been tested with Thierry's patches for correcting the parent clock for the DPAUX devices [0].
Please note that I have kept the patch that adds the pinctrl function, pinconf_generic_dt_free_map(), in this series for completeness, although Linus W has already picked this up (as it is not in -next AFAICT yet).
Changes from initial RFC: - Dropped patches for adding sor-safe clocks to DPAUX in favour of the patches from Thierry [0]. - Split the DPAUX function to enable the DPAUX pads into two functions: one for turning on and one for turning off the pads. - Updated the description for the 'i2c-bus' node based upon Mark R's feedback. - Dropped the second test if the i2c-core when checking for the presence of the 'i2c-bus' node based upon Thierry's feedback. - Removed depedency on CONFIG_PINCTRL in the DPAUX driver in favour of using #ifdef's per Thierry's feedback (note by removing the dependency on CONFIG_PINCTRL I had to use #ifdefs as all the structures, function tables, and functions may not be defined). - Updated SOR power partition device-tree node to include all clocks and resets as described in the Tegra210 TRM.
[0] http://marc.info/?l=linux-tegra&m=146667915802019&w=2
Jon Hunter (12): soc/tegra: pmc: Initialise resets associated with a power partition drm/tegra: Clean-up if probing DPAUX fails drm/tegra: Add helper functions for setting up DPAUX pads dt-bindings: display: Update Tegra DPAUX documentation drm/tegra: Prepare DPAUX for supporting generic PM domains pinctrl: pinconf: Add generic helper function for freeing mappings dt-bindings: i2c: Add support for 'i2c-bus' subnode i2c: core: Add support for 'i2c-bus' subnode dt-bindings: Add bindings for Tegra DPAUX pinctrl driver drm/tegra: Add pinctrl support for DPAUX arm64: tegra: Add SOR power-domain node arm64: tegra: Add DPAUX pinctrl bindings
.../display/tegra/nvidia,tegra20-host1x.txt | 12 +- Documentation/devicetree/bindings/i2c/i2c.txt | 8 + .../pinctrl/nvidia,tegra124-dpaux-padctl.txt | 60 ++++++ arch/arm64/boot/dts/nvidia/tegra210.dtsi | 78 +++++++ drivers/gpu/drm/tegra/dpaux.c | 239 +++++++++++++++++---- drivers/i2c/i2c-core.c | 10 +- drivers/pinctrl/pinconf-generic.c | 8 + drivers/soc/tegra/pmc.c | 18 +- include/linux/pinctrl/pinconf-generic.h | 2 + 9 files changed, 383 insertions(+), 52 deletions(-) create mode 100644 Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-dpaux-padctl.txt
When registering the Tegra power partitions with the generic PM domain framework, the current state of the each partition is checked and used as the default state for the partition. However, the state of each reset associated with the partition is not initialised and so it is possible that the state of the resets are not in the expected state. For example, if a partition is on, then the resets should be de-asserted and if the partition is off, the resets should be asserted.
There have been cases where the bootloader has powered on a partition and only de-asserted some of the resets to some of the devices in the partition. This can cause accesses to these devices to hang the system when the kernel boots and attempts to probe these devices.
Ideally, the driver for the device should ensure the reset has been de-asserted when probing, but the resets cannot be shared between the PMC driver (that needs to de-assert/assert the reset when turning the partition on or off) and another driver because we cannot ensure the reset is in the correct state.
To ensure the resets are in the correct state, when using the generic PM domain framework, put each reset associated with the partition in the correct state (based upon the partition's current state) when obtaining the resets for a partition.
Signed-off-by: Jon Hunter jonathanh@nvidia.com --- drivers/soc/tegra/pmc.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index d13516981629..8a421a0b1ece 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -738,7 +738,7 @@ err: }
static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, - struct device_node *np) + struct device_node *np, bool off) { struct reset_control *rst; unsigned int i, count; @@ -758,6 +758,16 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, err = PTR_ERR(pg->resets[i]); goto error; } + + if (off) + err = reset_control_assert(pg->resets[i]); + else + err = reset_control_deassert(pg->resets[i]); + + if (err) { + reset_control_put(pg->resets[i]); + goto error; + } }
pg->num_resets = count; @@ -798,14 +808,14 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) pg->genpd.power_on = tegra_genpd_power_on; pg->pmc = pmc;
+ off = !tegra_powergate_is_powered(pg->id); + if (tegra_powergate_of_get_clks(pg, np)) goto set_available;
- if (tegra_powergate_of_get_resets(pg, np)) + if (tegra_powergate_of_get_resets(pg, np, off)) goto remove_clks;
- off = !tegra_powergate_is_powered(pg->id); - pm_genpd_init(&pg->genpd, NULL, off);
if (of_genpd_add_provider_simple(np, &pg->genpd))
If the probing of the DPAUX fails, then clocks are left enabled and the DPAUX reset de-asserted. Add code to perform the necessary clean-up on probe failure by disabling clocks and asserting the reset.
Signed-off-by: Jon Hunter jonathanh@nvidia.com --- drivers/gpu/drm/tegra/dpaux.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index b24a0f14821a..0874a7e5b37b 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -321,28 +321,30 @@ static int tegra_dpaux_probe(struct platform_device *pdev) if (IS_ERR(dpaux->clk_parent)) { dev_err(&pdev->dev, "failed to get parent clock: %ld\n", PTR_ERR(dpaux->clk_parent)); - return PTR_ERR(dpaux->clk_parent); + err = PTR_ERR(dpaux->clk_parent); + goto assert_reset; }
err = clk_prepare_enable(dpaux->clk_parent); if (err < 0) { dev_err(&pdev->dev, "failed to enable parent clock: %d\n", err); - return err; + goto assert_reset; }
err = clk_set_rate(dpaux->clk_parent, 270000000); if (err < 0) { dev_err(&pdev->dev, "failed to set clock to 270 MHz: %d\n", err); - return err; + goto disable_parent_clk; }
dpaux->vdd = devm_regulator_get(&pdev->dev, "vdd"); if (IS_ERR(dpaux->vdd)) { dev_err(&pdev->dev, "failed to get VDD supply: %ld\n", PTR_ERR(dpaux->vdd)); - return PTR_ERR(dpaux->vdd); + err = PTR_ERR(dpaux->vdd); + goto disable_parent_clk; }
err = devm_request_irq(dpaux->dev, dpaux->irq, tegra_dpaux_irq, 0, @@ -350,7 +352,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev) if (err < 0) { dev_err(dpaux->dev, "failed to request IRQ#%u: %d\n", dpaux->irq, err); - return err; + goto disable_parent_clk; }
disable_irq(dpaux->irq); @@ -360,7 +362,7 @@ static int tegra_dpaux_probe(struct platform_device *pdev)
err = drm_dp_aux_register(&dpaux->aux); if (err < 0) - return err; + goto disable_parent_clk;
/* * Assume that by default the DPAUX/I2C pads will be used for HDMI, @@ -393,6 +395,14 @@ static int tegra_dpaux_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dpaux);
return 0; + +disable_parent_clk: + clk_disable_unprepare(dpaux->clk_parent); +assert_reset: + reset_control_assert(dpaux->rst); + clk_disable_unprepare(dpaux->clk); + + return err; }
static int tegra_dpaux_remove(struct platform_device *pdev)
In preparation for adding pinctrl support for the DPAUX pads, add helpers functions for configuring the pads and controlling the power for the pads.
Please note that although a simple if-statement could be used instead of a case statement for configuring the pads as there are only two possible modes, a case statement is used because when integrating with the pinctrl framework, we need to be able to handle invalid modes that could be passed.
Signed-off-by: Jon Hunter jonathanh@nvidia.com --- drivers/gpu/drm/tegra/dpaux.c | 81 +++++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 30 deletions(-)
diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index 0874a7e5b37b..4014ec57ed31 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -267,6 +267,51 @@ static irqreturn_t tegra_dpaux_irq(int irq, void *data) return ret; }
+static void tegra_dpaux_pad_power_down(struct tegra_dpaux *dpaux) +{ + u32 value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); + + value |= DPAUX_HYBRID_SPARE_PAD_POWER_DOWN; + + tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE); +} + +static void tegra_dpaux_pad_power_up(struct tegra_dpaux *dpaux) +{ + u32 value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); + + value &= ~DPAUX_HYBRID_SPARE_PAD_POWER_DOWN; + + tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE); +} + +static int tegra_dpaux_pad_config(struct tegra_dpaux *dpaux, unsigned function) +{ + u32 value; + + switch (function) { + case DPAUX_HYBRID_PADCTL_MODE_AUX: + value = DPAUX_HYBRID_PADCTL_AUX_CMH(2) | + DPAUX_HYBRID_PADCTL_AUX_DRVZ(4) | + DPAUX_HYBRID_PADCTL_AUX_DRVI(0x18) | + DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV | + DPAUX_HYBRID_PADCTL_MODE_AUX; + break; + case DPAUX_HYBRID_PADCTL_MODE_I2C: + value = DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV | + DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV | + DPAUX_HYBRID_PADCTL_MODE_I2C; + break; + default: + return -ENOTSUPP; + } + + tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_PADCTL); + tegra_dpaux_pad_power_up(dpaux); + + return 0; +} + static int tegra_dpaux_probe(struct platform_device *pdev) { struct tegra_dpaux *dpaux; @@ -372,15 +417,9 @@ static int tegra_dpaux_probe(struct platform_device *pdev) * is no possibility to perform the I2C mode configuration in the * HDMI path. */ - value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); - value &= ~DPAUX_HYBRID_SPARE_PAD_POWER_DOWN; - tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE); - - value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_PADCTL); - value = DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV | - DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV | - DPAUX_HYBRID_PADCTL_MODE_I2C; - tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_PADCTL); + err = tegra_dpaux_pad_config(dpaux, DPAUX_HYBRID_PADCTL_MODE_I2C); + if (err < 0) + return err;
/* enable and clear all interrupts */ value = DPAUX_INTR_AUX_DONE | DPAUX_INTR_IRQ_EVENT | @@ -408,12 +447,9 @@ assert_reset: static int tegra_dpaux_remove(struct platform_device *pdev) { struct tegra_dpaux *dpaux = platform_get_drvdata(pdev); - u32 value;
/* make sure pads are powered down when not in use */ - value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); - value |= DPAUX_HYBRID_SPARE_PAD_POWER_DOWN; - tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE); + tegra_dpaux_pad_power_down(dpaux);
drm_dp_aux_unregister(&dpaux->aux);
@@ -538,30 +574,15 @@ enum drm_connector_status drm_dp_aux_detect(struct drm_dp_aux *aux) int drm_dp_aux_enable(struct drm_dp_aux *aux) { struct tegra_dpaux *dpaux = to_dpaux(aux); - u32 value; - - value = DPAUX_HYBRID_PADCTL_AUX_CMH(2) | - DPAUX_HYBRID_PADCTL_AUX_DRVZ(4) | - DPAUX_HYBRID_PADCTL_AUX_DRVI(0x18) | - DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV | - DPAUX_HYBRID_PADCTL_MODE_AUX; - tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_PADCTL);
- value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); - value &= ~DPAUX_HYBRID_SPARE_PAD_POWER_DOWN; - tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE); - - return 0; + return tegra_dpaux_pad_config(dpaux, DPAUX_HYBRID_PADCTL_MODE_AUX); }
int drm_dp_aux_disable(struct drm_dp_aux *aux) { struct tegra_dpaux *dpaux = to_dpaux(aux); - u32 value;
- value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); - value |= DPAUX_HYBRID_SPARE_PAD_POWER_DOWN; - tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE); + tegra_dpaux_pad_power_down(dpaux);
return 0; }
Update the DPAUX compatibility string information for Tegra124, Tegra132 and Tegra210.
Signed-off-by: Jon Hunter jonathanh@nvidia.com --- .../devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt index a3bd8c050c4e..275f45680892 100644 --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt @@ -226,9 +226,9 @@ of the following host1x client modules: - nvidia,dpaux: phandle to a DispayPort AUX interface
- dpaux: DisplayPort AUX interface - - compatible: For Tegra124, must contain "nvidia,tegra124-dpaux". Otherwise, - must contain '"nvidia,<chip>-dpaux", "nvidia,tegra124-dpaux"', where - <chip> is tegra132. + - compatible : Should contain one of the following: + - "nvidia,tegra124-dpaux": for Tegra124 and Tegra132 + - "nvidia,tegra210-dpaux": for Tegra210 - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt outputs from the controller. - clocks: Must contain an entry for each entry in clock-names.
On Thu, Jun 23, 2016 at 04:58:57PM +0100, Jon Hunter wrote:
Update the DPAUX compatibility string information for Tegra124, Tegra132 and Tegra210.
Signed-off-by: Jon Hunter jonathanh@nvidia.com
.../devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
Acked-by: Rob Herring robh@kernel.org
To utilise the DPAUX on Tegra, the SOR power partition must be enabled. Now that Tegra supports the generic PM domain framework we manage the SOR power partition via this framework for DPAUX. However, the sequence for gating/ungating the SOR power partition requires that the DPAUX reset is asserted/de-asserted at the time the SOR power partition is gated/ungated, respectively. Now that the reset control core assumes that resets are exclusive, the Tegra generic PM domain code and the DPAUX driver cannot request the same reset unless we mark the resets as shared. Sharing resets we will not work in this case because we cannot guarantee that the reset is asserted/de-asserted at the appropriate time. Therefore, given that the Tegra generic PM domain code will handle the DPAUX reset, do not request the reset in the DPAUX driver if the DPAUX device has a PM domain associated.
Signed-off-by: Jon Hunter jonathanh@nvidia.com --- drivers/gpu/drm/tegra/dpaux.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index 4014ec57ed31..61821f457209 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -339,11 +339,14 @@ static int tegra_dpaux_probe(struct platform_device *pdev) return -ENXIO; }
- dpaux->rst = devm_reset_control_get(&pdev->dev, "dpaux"); - if (IS_ERR(dpaux->rst)) { - dev_err(&pdev->dev, "failed to get reset control: %ld\n", - PTR_ERR(dpaux->rst)); - return PTR_ERR(dpaux->rst); + if (!pdev->dev.pm_domain) { + dpaux->rst = devm_reset_control_get(&pdev->dev, "dpaux"); + if (IS_ERR(dpaux->rst)) { + dev_err(&pdev->dev, + "failed to get reset control: %ld\n", + PTR_ERR(dpaux->rst)); + return PTR_ERR(dpaux->rst); + } }
dpaux->clk = devm_clk_get(&pdev->dev, NULL); @@ -360,7 +363,8 @@ static int tegra_dpaux_probe(struct platform_device *pdev) return err; }
- reset_control_deassert(dpaux->rst); + if (dpaux->rst) + reset_control_deassert(dpaux->rst);
dpaux->clk_parent = devm_clk_get(&pdev->dev, "parent"); if (IS_ERR(dpaux->clk_parent)) { @@ -438,7 +442,8 @@ static int tegra_dpaux_probe(struct platform_device *pdev) disable_parent_clk: clk_disable_unprepare(dpaux->clk_parent); assert_reset: - reset_control_assert(dpaux->rst); + if (dpaux->rst) + reset_control_assert(dpaux->rst); clk_disable_unprepare(dpaux->clk);
return err; @@ -460,7 +465,8 @@ static int tegra_dpaux_remove(struct platform_device *pdev) cancel_work_sync(&dpaux->work);
clk_disable_unprepare(dpaux->clk_parent); - reset_control_assert(dpaux->rst); + if (dpaux->rst) + reset_control_assert(dpaux->rst); clk_disable_unprepare(dpaux->clk);
return 0;
The pinconf-generic.h file exposes functions for creating generic mappings but it does not expose a function for freeing the mappings. Add a function for freeing generic mappings.
Signed-off-by: Jon Hunter jonathanh@nvidia.com Acked-by: Linus Walleij linus.walleij@linaro.org --- drivers/pinctrl/pinconf-generic.c | 8 ++++++++ include/linux/pinctrl/pinconf-generic.h | 2 ++ 2 files changed, 10 insertions(+)
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 34b601b06764..5020ae534479 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -395,4 +395,12 @@ exit: } EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map);
+void pinconf_generic_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, + unsigned num_maps) +{ + pinctrl_utils_free_map(pctldev, map, num_maps); +} +EXPORT_SYMBOL_GPL(pinconf_generic_dt_free_map); + #endif diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h index d921afd5f109..12343caa114e 100644 --- a/include/linux/pinctrl/pinconf-generic.h +++ b/include/linux/pinctrl/pinconf-generic.h @@ -175,6 +175,8 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, int pinconf_generic_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np_config, struct pinctrl_map **map, unsigned *num_maps, enum pinctrl_map_type type); +void pinconf_generic_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps);
static inline int pinconf_generic_dt_node_to_map_group( struct pinctrl_dev *pctldev, struct device_node *np_config,
The I2C driver core for boards using device-tree assumes any subnode of an I2C adapter in the device-tree blob as being a I2C slave device. Although this makes complete sense, some I2C adapters may have subnodes which are not I2C slaves but subnodes presenting other features. For example some Tegra devices have an I2C interface which may share its pins with other devices and to share these pins subnodes for representing these pins so they have be shared via the pinctrl framework are needed.
To allow I2C adapters to have non-I2C specific subnodes in device-tree that are not parsed by the I2C driver core by adding support for a 'i2c-bus' subnode where I2C slaves can be placed. If the 'i2c-bus' subnode is present then all I2C slaves must be placed under this subnode.
Signed-off-by: Jon Hunter jonathanh@nvidia.com Acked-by: Thierry Reding treding@nvidia.com --- Documentation/devicetree/bindings/i2c/i2c.txt | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt index f31b2ad1552b..71bea55d4c1b 100644 --- a/Documentation/devicetree/bindings/i2c/i2c.txt +++ b/Documentation/devicetree/bindings/i2c/i2c.txt @@ -32,6 +32,14 @@ wants to support one of the below features, it should adapt the bindings below. - clock-frequency frequency of bus clock in Hz.
+- i2c-bus + For I2C adapters that have child nodes that are a mixture of both I2C + devices and non-I2C devices (such as a pin controller), the 'i2c-bus' + subnode can be used for populating I2C devices. If the 'i2c-bus' + subnode is present, only subnodes of this will be considered as I2C + slaves. The properties, '#address-cells' and '#size-cells' must be + defined under this subnode if present. + - i2c-scl-falling-time-ns Number of nanoseconds the SCL signal takes to fall; t(f) in the I2C specification.
On Thu, Jun 23, 2016 at 04:59:00PM +0100, Jon Hunter wrote:
The I2C driver core for boards using device-tree assumes any subnode of an I2C adapter in the device-tree blob as being a I2C slave device. Although this makes complete sense, some I2C adapters may have subnodes which are not I2C slaves but subnodes presenting other features. For example some Tegra devices have an I2C interface which may share its pins with other devices and to share these pins subnodes for representing these pins so they have be shared via the pinctrl framework are needed.
To allow I2C adapters to have non-I2C specific subnodes in device-tree that are not parsed by the I2C driver core by adding support for a 'i2c-bus' subnode where I2C slaves can be placed. If the 'i2c-bus' subnode is present then all I2C slaves must be placed under this subnode.
Signed-off-by: Jon Hunter jonathanh@nvidia.com Acked-by: Thierry Reding treding@nvidia.com
Documentation/devicetree/bindings/i2c/i2c.txt | 8 ++++++++ 1 file changed, 8 insertions(+)
Acked-by: Rob Herring robh@kernel.org
On 2016-06-23 17:59, Jon Hunter wrote:
The I2C driver core for boards using device-tree assumes any subnode of an I2C adapter in the device-tree blob as being a I2C slave device. Although this makes complete sense, some I2C adapters may have subnodes which are not I2C slaves but subnodes presenting other features. For example some Tegra devices have an I2C interface which may share its pins with other devices and to share these pins subnodes for representing these pins so they have be shared via the pinctrl framework are needed.
To allow I2C adapters to have non-I2C specific subnodes in device-tree that are not parsed by the I2C driver core by adding support for a 'i2c-bus' subnode where I2C slaves can be placed. If the 'i2c-bus' subnode is present then all I2C slaves must be placed under this subnode.
Signed-off-by: Jon Hunter jonathanh@nvidia.com Acked-by: Thierry Reding treding@nvidia.com
Documentation/devicetree/bindings/i2c/i2c.txt | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt index f31b2ad1552b..71bea55d4c1b 100644 --- a/Documentation/devicetree/bindings/i2c/i2c.txt +++ b/Documentation/devicetree/bindings/i2c/i2c.txt @@ -32,6 +32,14 @@ wants to support one of the below features, it should adapt the bindings below.
- clock-frequency frequency of bus clock in Hz.
+- i2c-bus
- For I2C adapters that have child nodes that are a mixture of both I2C
- devices and non-I2C devices (such as a pin controller), the 'i2c-bus'
- subnode can be used for populating I2C devices. If the 'i2c-bus'
- subnode is present, only subnodes of this will be considered as I2C
- slaves. The properties, '#address-cells' and '#size-cells' must be
- defined under this subnode if present.
Hmmm, those #-properties are listed above, under "Required properties", which is no longer 100% true. Maybe rephrase to
slaves. The required properties '#address-cells' and '#size-cells' must be defined under this subnode instead, if this subnode is present.
to make the rules (even) clearer?
Cheers, Peter
- i2c-scl-falling-time-ns Number of nanoseconds the SCL signal takes to fall; t(f) in the I2C specification.
On 27/06/16 13:04, Peter Rosin wrote:
On 2016-06-23 17:59, Jon Hunter wrote:
The I2C driver core for boards using device-tree assumes any subnode of an I2C adapter in the device-tree blob as being a I2C slave device. Although this makes complete sense, some I2C adapters may have subnodes which are not I2C slaves but subnodes presenting other features. For example some Tegra devices have an I2C interface which may share its pins with other devices and to share these pins subnodes for representing these pins so they have be shared via the pinctrl framework are needed.
To allow I2C adapters to have non-I2C specific subnodes in device-tree that are not parsed by the I2C driver core by adding support for a 'i2c-bus' subnode where I2C slaves can be placed. If the 'i2c-bus' subnode is present then all I2C slaves must be placed under this subnode.
Signed-off-by: Jon Hunter jonathanh@nvidia.com Acked-by: Thierry Reding treding@nvidia.com
Documentation/devicetree/bindings/i2c/i2c.txt | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt index f31b2ad1552b..71bea55d4c1b 100644 --- a/Documentation/devicetree/bindings/i2c/i2c.txt +++ b/Documentation/devicetree/bindings/i2c/i2c.txt @@ -32,6 +32,14 @@ wants to support one of the below features, it should adapt the bindings below.
- clock-frequency frequency of bus clock in Hz.
+- i2c-bus
- For I2C adapters that have child nodes that are a mixture of both I2C
- devices and non-I2C devices (such as a pin controller), the 'i2c-bus'
- subnode can be used for populating I2C devices. If the 'i2c-bus'
- subnode is present, only subnodes of this will be considered as I2C
- slaves. The properties, '#address-cells' and '#size-cells' must be
- defined under this subnode if present.
Hmmm, those #-properties are listed above, under "Required properties", which is no longer 100% true. Maybe rephrase to
slaves. The required properties '#address-cells' and '#size-cells' must be defined under this subnode instead, if this subnode is present.
to make the rules (even) clearer?
I see what you are saying but I wonder if the following is better ...
slaves. The required properties '#address-cells' and '#size-cells' must be defined under this subnode if present and not the parent node.
Cheers Jon
On 2016-06-28 10:21, Jon Hunter wrote:
On 27/06/16 13:04, Peter Rosin wrote:
On 2016-06-23 17:59, Jon Hunter wrote:
The I2C driver core for boards using device-tree assumes any subnode of an I2C adapter in the device-tree blob as being a I2C slave device. Although this makes complete sense, some I2C adapters may have subnodes which are not I2C slaves but subnodes presenting other features. For example some Tegra devices have an I2C interface which may share its pins with other devices and to share these pins subnodes for representing these pins so they have be shared via the pinctrl framework are needed.
To allow I2C adapters to have non-I2C specific subnodes in device-tree that are not parsed by the I2C driver core by adding support for a 'i2c-bus' subnode where I2C slaves can be placed. If the 'i2c-bus' subnode is present then all I2C slaves must be placed under this subnode.
Signed-off-by: Jon Hunter jonathanh@nvidia.com Acked-by: Thierry Reding treding@nvidia.com
Documentation/devicetree/bindings/i2c/i2c.txt | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt index f31b2ad1552b..71bea55d4c1b 100644 --- a/Documentation/devicetree/bindings/i2c/i2c.txt +++ b/Documentation/devicetree/bindings/i2c/i2c.txt @@ -32,6 +32,14 @@ wants to support one of the below features, it should adapt the bindings below.
- clock-frequency frequency of bus clock in Hz.
+- i2c-bus
- For I2C adapters that have child nodes that are a mixture of both I2C
- devices and non-I2C devices (such as a pin controller), the 'i2c-bus'
- subnode can be used for populating I2C devices. If the 'i2c-bus'
- subnode is present, only subnodes of this will be considered as I2C
- slaves. The properties, '#address-cells' and '#size-cells' must be
- defined under this subnode if present.
Hmmm, those #-properties are listed above, under "Required properties", which is no longer 100% true. Maybe rephrase to
slaves. The required properties '#address-cells' and '#size-cells' must be defined under this subnode instead, if this subnode is present.
to make the rules (even) clearer?
I see what you are saying but I wonder if the following is better ...
slaves. The required properties '#address-cells' and '#size-cells' must be defined under this subnode if present and not the parent node.
Naaw, I don't like that either, I associate the last "and not" with the "if present" part and not the intended "under this subnode". Then I go WTF when I fail to parse. Maybe just add an example instead...
Or just forget me ever saying anything. Sorry for making a fuss over this.
Cheers, Peter
For example some Tegra devices have an I2C interface which may share its pins with other devices and to share these pins subnodes for representing these pins so they have be shared via the pinctrl framework are needed.
I think the above sentence is hard to grasp. Can you split it into more sentences perhaps?
+- i2c-bus
- For I2C adapters that have child nodes that are a mixture of both I2C
- devices and non-I2C devices (such as a pin controller), the 'i2c-bus'
I suggest to drop the phrase in the paranthesis. It is true for your case, but I don't think it's generic. So, it is not an obvious example like "Yes, sure, I see that a pin controller has I2C nodes and non-I2C nodes". At least for me, it was more like "It has what?"
On 28/06/16 22:32, Wolfram Sang wrote:
- PGP Signed by an unknown key
For example some Tegra devices have an I2C interface which may share its pins with other devices and to share these pins subnodes for representing these pins so they have be shared via the pinctrl framework are needed.
I think the above sentence is hard to grasp. Can you split it into more sentences perhaps?
OK, yes does seem a bit of a mouthful.
+- i2c-bus
- For I2C adapters that have child nodes that are a mixture of both I2C
- devices and non-I2C devices (such as a pin controller), the 'i2c-bus'
I suggest to drop the phrase in the paranthesis. It is true for your case, but I don't think it's generic. So, it is not an obvious example like "Yes, sure, I see that a pin controller has I2C nodes and non-I2C nodes". At least for me, it was more like "It has what?"
OK, will drop that part.
Cheers Jon
If the 'i2c-bus' device-tree node is present for an I2C adapter then parse this subnode for I2C slaves.
Signed-off-by: Jon Hunter jonathanh@nvidia.com --- drivers/i2c/i2c-core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 952d2f0c02c5..71ad532be1d8 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1452,7 +1452,7 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
static void of_i2c_register_devices(struct i2c_adapter *adap) { - struct device_node *node; + struct device_node *bus, *node;
/* Only register child devices if the adapter has a node pointer set */ if (!adap->dev.of_node) @@ -1460,11 +1460,17 @@ static void of_i2c_register_devices(struct i2c_adapter *adap)
dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
- for_each_available_child_of_node(adap->dev.of_node, node) { + bus = of_get_child_by_name(adap->dev.of_node, "i2c-bus"); + if (!bus) + bus = of_node_get(adap->dev.of_node); + + for_each_available_child_of_node(bus, node) { if (of_node_test_and_set_flag(node, OF_POPULATED)) continue; of_i2c_register_device(adap, node); } + + of_node_put(bus); }
static int of_dev_node_match(struct device *dev, void *data)
On Thu, Jun 23, 2016 at 04:59:01PM +0100, Jon Hunter wrote:
If the 'i2c-bus' device-tree node is present for an I2C adapter then parse this subnode for I2C slaves.
Signed-off-by: Jon Hunter jonathanh@nvidia.com
drivers/i2c/i2c-core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
Hi Wolfram,
are you okay with this change? I'd like to take this through the Tegra tree, with your Acked-by, to resolve the dependency of subsequent patches.
Would you be okay if I take this patch along with the device tree binding change into a stable branch and provide a tag for you to pull into the I2C tree?
Thierry
Would you be okay if I take this patch along with the device tree binding change into a stable branch and provide a tag for you to pull into the I2C tree?
Yes, once my comments to the previous patch are addressed, we can do that. For this patch already:
Acked-by: Wolfram Sang wsa@the-dreams.de
On 23 June 2016 at 17:59, Jon Hunter jonathanh@nvidia.com wrote:
If the 'i2c-bus' device-tree node is present for an I2C adapter then parse this subnode for I2C slaves.
Signed-off-by: Jon Hunter jonathanh@nvidia.com
drivers/i2c/i2c-core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 952d2f0c02c5..71ad532be1d8 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1452,7 +1452,7 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
static void of_i2c_register_devices(struct i2c_adapter *adap) {
struct device_node *node;
struct device_node *bus, *node; /* Only register child devices if the adapter has a node pointer set */ if (!adap->dev.of_node)
@@ -1460,11 +1460,17 @@ static void of_i2c_register_devices(struct i2c_adapter *adap)
dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
for_each_available_child_of_node(adap->dev.of_node, node) {
bus = of_get_child_by_name(adap->dev.of_node, "i2c-bus");
if (!bus)
bus = of_node_get(adap->dev.of_node);
for_each_available_child_of_node(bus, node) { if (of_node_test_and_set_flag(node, OF_POPULATED)) continue; of_i2c_register_device(adap, node); }
of_node_put(bus);
}
Sorry for not commenting earlier, but I only found the issue yesterday.
I'm bothered as well by the "modalias failure" error message but in my case the node doesn't have any i2c devices, so this patch isn't a complete solution to that problem.
Has this been considered already?
Thanks,
Tomeu
static int of_dev_node_match(struct device *dev, void *data)
2.1.4
-- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 02/08/16 07:26, Tomeu Vizoso wrote:
On 23 June 2016 at 17:59, Jon Hunter jonathanh@nvidia.com wrote:
If the 'i2c-bus' device-tree node is present for an I2C adapter then parse this subnode for I2C slaves.
Signed-off-by: Jon Hunter jonathanh@nvidia.com
drivers/i2c/i2c-core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 952d2f0c02c5..71ad532be1d8 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1452,7 +1452,7 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
static void of_i2c_register_devices(struct i2c_adapter *adap) {
struct device_node *node;
struct device_node *bus, *node; /* Only register child devices if the adapter has a node pointer set */ if (!adap->dev.of_node)
@@ -1460,11 +1460,17 @@ static void of_i2c_register_devices(struct i2c_adapter *adap)
dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
for_each_available_child_of_node(adap->dev.of_node, node) {
bus = of_get_child_by_name(adap->dev.of_node, "i2c-bus");
if (!bus)
bus = of_node_get(adap->dev.of_node);
for_each_available_child_of_node(bus, node) { if (of_node_test_and_set_flag(node, OF_POPULATED)) continue; of_i2c_register_device(adap, node); }
of_node_put(bus);
}
Sorry for not commenting earlier, but I only found the issue yesterday.
I'm bothered as well by the "modalias failure" error message but in my case the node doesn't have any i2c devices, so this patch isn't a complete solution to that problem.
But it is a i2c adapter correct? I guess I don't completely understand the problem?
Has this been considered already?
Why can't you add a place-holder 'i2c-bus' node for i2c devices so when they are adding in the future they are placed under this node? This is what I did for dpaux. See patch 12/12 of this series.
Jon
On 2 August 2016 at 08:49, Jon Hunter jonathanh@nvidia.com wrote:
On 02/08/16 07:26, Tomeu Vizoso wrote:
On 23 June 2016 at 17:59, Jon Hunter jonathanh@nvidia.com wrote:
If the 'i2c-bus' device-tree node is present for an I2C adapter then parse this subnode for I2C slaves.
Signed-off-by: Jon Hunter jonathanh@nvidia.com
drivers/i2c/i2c-core.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 952d2f0c02c5..71ad532be1d8 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1452,7 +1452,7 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
static void of_i2c_register_devices(struct i2c_adapter *adap) {
struct device_node *node;
struct device_node *bus, *node; /* Only register child devices if the adapter has a node pointer set */ if (!adap->dev.of_node)
@@ -1460,11 +1460,17 @@ static void of_i2c_register_devices(struct i2c_adapter *adap)
dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
for_each_available_child_of_node(adap->dev.of_node, node) {
bus = of_get_child_by_name(adap->dev.of_node, "i2c-bus");
if (!bus)
bus = of_node_get(adap->dev.of_node);
for_each_available_child_of_node(bus, node) { if (of_node_test_and_set_flag(node, OF_POPULATED)) continue; of_i2c_register_device(adap, node); }
of_node_put(bus);
}
Sorry for not commenting earlier, but I only found the issue yesterday.
I'm bothered as well by the "modalias failure" error message but in my case the node doesn't have any i2c devices, so this patch isn't a complete solution to that problem.
But it is a i2c adapter correct? I guess I don't completely understand the problem?
Has this been considered already?
Why can't you add a place-holder 'i2c-bus' node for i2c devices so when they are adding in the future they are placed under this node? This is what I did for dpaux. See patch 12/12 of this series.
Hadn't realized, and it sounds good enough to me.
Thanks,
Tomeu
On Tegra124, Tegra132 and Tegra210 devices the pads used by the Display Port Auxiliary (DPAUX) channel are multiplexed such that they can also be used by one of the internal I2C controllers. Note that this is different from I2C-over-AUX supported by the DPAUX controller. The register that configures these pads is part of the DPAUX controllers register set and so a pinctrl driver is being added for the DPAUX device to share these pads. Add the device-tree binding documentation for the DPAUX pad controller.
Although there is only one group of pads associated with the DPAUX that can be multiplexed, the group still needs to be described by the binding. If the 'groups' property is not present in the binding, then the pads will not be allocated by the pinctrl core for a client and this would allow another client to re-configure the same pads that may already be in-use.
Please note that although the "off" function for the DPAUX pads is not technically a pin-mux setting but more of a pin-conf setting it is simpler to expose these as a function so that the user can simply select either "aux", "i2c" or "off" as the current function/mode.
Update the main DPAUX binding documentation to reference the DPAUX pad controller binding document and add the 'i2c-bus' subnode. The 'i2c-bus' subnode is used for populating I2C slaves for the DPAUX device so that the I2C driver core does not attempt to add the DPAUX pad controller nodes as I2C slaves.
Signed-off-by: Jon Hunter jonathanh@nvidia.com --- .../display/tegra/nvidia,tegra20-host1x.txt | 6 +++ .../pinctrl/nvidia,tegra124-dpaux-padctl.txt | 60 ++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-dpaux-padctl.txt
diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt index 275f45680892..d0f1dc62550a 100644 --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt @@ -241,6 +241,12 @@ of the following host1x client modules: - reset-names: Must include the following entries: - dpaux - vdd-supply: phandle of a supply that powers the DisplayPort link + - i2c-bus: Subnode where I2C slave devices are listed. This subnode + must be always present. If there are no I2C slave devices, an empty + node should be added. See ../../i2c/i2c.txt for more information. + + See ../pinctrl/nvidia,tegra124-dpaux-padctl.txt for information + regarding the DPAUX pad controller bindings.
Example:
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-dpaux-padctl.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-dpaux-padctl.txt new file mode 100644 index 000000000000..656e0a04be8f --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-dpaux-padctl.txt @@ -0,0 +1,60 @@ +Device tree binding for NVIDIA Tegra DPAUX pad controller +======================================================== + +The Tegra Display Port Auxiliary (DPAUX) pad controller manages two pins +which can be assigned to either the DPAUX channel or to an I2C +controller. + +This document defines the device-specific binding for the DPAUX pad +controller. Refer to pinctrl-bindings.txt in this directory for generic +information about pin controller device tree bindings. Please refer to +the binding document ../display/tegra/nvidia,tegra20-host1x.txt for more +details on the DPAUX binding. + +Pin muxing: +----------- + +Child nodes contain the pinmux configurations following the conventions +from the pinctrl-bindings.txt document. + +Since only three configurations are possible, only three child nodes are +needed to describe the pin mux'ing options for the DPAUX pads. +Furthermore, given that the pad functions are only applicable to a +single set of pads, the child nodes only need to describe the pad group +the functions are being applied to rather than the individual pads. + +Required properties: +- groups: Must be "dpaux-io" +- function: Must be either "aux", "i2c" or "off". + +Example: +-------- + + dpaux@545c0000 { + ... + + state_dpaux_aux: pinmux_aux { + groups = "dpaux-io"; + function = "aux"; + }; + + state_dpaux_i2c: pinmux_i2c { + groups = "dpaux-io"; + function = "i2c"; + }; + + state_dpaux_off: pinmux_off { + groups = "dpaux-io"; + function = "off"; + }; + }; + + ... + + i2c@7000d100 { + ... + pinctrl-0 = <&state_dpaux_i2c>; + pinctrl-1 = <&state_dpaux_off>; + pinctrl-names = "default", "idle"; + status = "disabled"; + };
On Thu, Jun 23, 2016 at 04:59:02PM +0100, Jon Hunter wrote:
On Tegra124, Tegra132 and Tegra210 devices the pads used by the Display Port Auxiliary (DPAUX) channel are multiplexed such that they can also be used by one of the internal I2C controllers. Note that this is different from I2C-over-AUX supported by the DPAUX controller. The register that configures these pads is part of the DPAUX controllers register set and so a pinctrl driver is being added for the DPAUX device to share these pads. Add the device-tree binding documentation for the DPAUX pad controller.
Although there is only one group of pads associated with the DPAUX that can be multiplexed, the group still needs to be described by the binding. If the 'groups' property is not present in the binding, then the pads will not be allocated by the pinctrl core for a client and this would allow another client to re-configure the same pads that may already be in-use.
Please note that although the "off" function for the DPAUX pads is not technically a pin-mux setting but more of a pin-conf setting it is simpler to expose these as a function so that the user can simply select either "aux", "i2c" or "off" as the current function/mode.
Update the main DPAUX binding documentation to reference the DPAUX pad controller binding document and add the 'i2c-bus' subnode. The 'i2c-bus' subnode is used for populating I2C slaves for the DPAUX device so that the I2C driver core does not attempt to add the DPAUX pad controller nodes as I2C slaves.
Signed-off-by: Jon Hunter jonathanh@nvidia.com
.../display/tegra/nvidia,tegra20-host1x.txt | 6 +++ .../pinctrl/nvidia,tegra124-dpaux-padctl.txt | 60 ++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-dpaux-padctl.txt
diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt index 275f45680892..d0f1dc62550a 100644 --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt @@ -241,6 +241,12 @@ of the following host1x client modules:
- reset-names: Must include the following entries:
- dpaux
- vdd-supply: phandle of a supply that powers the DisplayPort link
- i2c-bus: Subnode where I2C slave devices are listed. This subnode
- must be always present. If there are no I2C slave devices, an empty
- node should be added. See ../../i2c/i2c.txt for more information.
- See ../pinctrl/nvidia,tegra124-dpaux-padctl.txt for information
- regarding the DPAUX pad controller bindings.
Example:
diff --git a/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-dpaux-padctl.txt b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-dpaux-padctl.txt new file mode 100644 index 000000000000..656e0a04be8f --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/nvidia,tegra124-dpaux-padctl.txt @@ -0,0 +1,60 @@ +Device tree binding for NVIDIA Tegra DPAUX pad controller +========================================================
+The Tegra Display Port Auxiliary (DPAUX) pad controller manages two pins +which can be assigned to either the DPAUX channel or to an I2C +controller.
+This document defines the device-specific binding for the DPAUX pad +controller. Refer to pinctrl-bindings.txt in this directory for generic +information about pin controller device tree bindings. Please refer to +the binding document ../display/tegra/nvidia,tegra20-host1x.txt for more +details on the DPAUX binding.
+Pin muxing: +-----------
+Child nodes contain the pinmux configurations following the conventions +from the pinctrl-bindings.txt document.
+Since only three configurations are possible, only three child nodes are +needed to describe the pin mux'ing options for the DPAUX pads. +Furthermore, given that the pad functions are only applicable to a +single set of pads, the child nodes only need to describe the pad group +the functions are being applied to rather than the individual pads.
+Required properties: +- groups: Must be "dpaux-io" +- function: Must be either "aux", "i2c" or "off".
+Example: +--------
- dpaux@545c0000 {
...
state_dpaux_aux: pinmux_aux {
Use '-' for node names. With that:
Acked-by: Rob Herring robh@kernel.org
groups = "dpaux-io";
function = "aux";
};
state_dpaux_i2c: pinmux_i2c {
groups = "dpaux-io";
function = "i2c";
};
state_dpaux_off: pinmux_off {
groups = "dpaux-io";
function = "off";
};
- };
- ...
- i2c@7000d100 {
...
pinctrl-0 = <&state_dpaux_i2c>;
pinctrl-1 = <&state_dpaux_off>;
pinctrl-names = "default", "idle";
status = "disabled";
- };
-- 2.1.4
The DPAUX pins are shared with an internal I2C controller. To allow these pins to be muxed to the I2C controller, register a pinctrl device for the DPAUX device. Make Tegra DRM support dependent on PINCTRL to avoid any compilation issues.
This is based upon work by Thierry Reding treding@nvidia.com.
Signed-off-by: Jon Hunter jonathanh@nvidia.com --- drivers/gpu/drm/tegra/dpaux.c | 122 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 119 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index 61821f457209..7b2abaf33a7a 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -12,6 +12,9 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/of_gpio.h> +#include <linux/pinctrl/pinconf-generic.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> #include <linux/platform_device.h> #include <linux/reset.h> #include <linux/regulator/consumer.h> @@ -44,6 +47,11 @@ struct tegra_dpaux { struct completion complete; struct work_struct work; struct list_head list; + +#ifdef CONFIG_PINCTRL + struct pinctrl_dev *pinctrl; + struct pinctrl_desc desc; +#endif };
static inline struct tegra_dpaux *to_dpaux(struct drm_dp_aux *aux) @@ -267,6 +275,12 @@ static irqreturn_t tegra_dpaux_irq(int irq, void *data) return ret; }
+enum tegra_dpaux_functions { + DPAUX_PADCTL_FUNC_AUX, + DPAUX_PADCTL_FUNC_I2C, + DPAUX_PADCTL_FUNC_OFF, +}; + static void tegra_dpaux_pad_power_down(struct tegra_dpaux *dpaux) { u32 value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); @@ -290,18 +304,21 @@ static int tegra_dpaux_pad_config(struct tegra_dpaux *dpaux, unsigned function) u32 value;
switch (function) { - case DPAUX_HYBRID_PADCTL_MODE_AUX: + case DPAUX_PADCTL_FUNC_AUX: value = DPAUX_HYBRID_PADCTL_AUX_CMH(2) | DPAUX_HYBRID_PADCTL_AUX_DRVZ(4) | DPAUX_HYBRID_PADCTL_AUX_DRVI(0x18) | DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV | DPAUX_HYBRID_PADCTL_MODE_AUX; break; - case DPAUX_HYBRID_PADCTL_MODE_I2C: + case DPAUX_PADCTL_FUNC_I2C: value = DPAUX_HYBRID_PADCTL_I2C_SDA_INPUT_RCV | DPAUX_HYBRID_PADCTL_I2C_SCL_INPUT_RCV | DPAUX_HYBRID_PADCTL_MODE_I2C; break; + case DPAUX_PADCTL_FUNC_OFF: + tegra_dpaux_pad_power_down(dpaux); + return 0; default: return -ENOTSUPP; } @@ -312,6 +329,91 @@ static int tegra_dpaux_pad_config(struct tegra_dpaux *dpaux, unsigned function) return 0; }
+#ifdef CONFIG_PINCTRL +static const struct pinctrl_pin_desc tegra_dpaux_pins[] = { + PINCTRL_PIN(0, "DP_AUX_CHx_P"), + PINCTRL_PIN(1, "DP_AUX_CHx_N"), +}; + +static const unsigned tegra_dpaux_pin_numbers[] = { 0, 1 }; + +static const char * const tegra_dpaux_groups[] = { + "dpaux-io", +}; + +static const char * const tegra_dpaux_functions[] = { + "aux", + "i2c", + "off", +}; + +static int tegra_dpaux_get_groups_count(struct pinctrl_dev *pinctrl) +{ + return ARRAY_SIZE(tegra_dpaux_groups); +} + +static const char *tegra_dpaux_get_group_name(struct pinctrl_dev *pinctrl, + unsigned int group) +{ + return tegra_dpaux_groups[group]; +} + +static int tegra_dpaux_get_group_pins(struct pinctrl_dev *pinctrl, + unsigned group, const unsigned **pins, + unsigned *num_pins) +{ + *pins = tegra_dpaux_pin_numbers; + *num_pins = ARRAY_SIZE(tegra_dpaux_pin_numbers); + + return 0; +} + +static const struct pinctrl_ops tegra_dpaux_pinctrl_ops = { + .get_groups_count = tegra_dpaux_get_groups_count, + .get_group_name = tegra_dpaux_get_group_name, + .get_group_pins = tegra_dpaux_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_group, + .dt_free_map = pinconf_generic_dt_free_map, +}; + +static int tegra_dpaux_get_functions_count(struct pinctrl_dev *pinctrl) +{ + return ARRAY_SIZE(tegra_dpaux_functions); +} + +static const char *tegra_dpaux_get_function_name(struct pinctrl_dev *pinctrl, + unsigned int function) +{ + return tegra_dpaux_functions[function]; +} + +static int tegra_dpaux_get_function_groups(struct pinctrl_dev *pinctrl, + unsigned int function, + const char * const **groups, + unsigned * const num_groups) +{ + *num_groups = ARRAY_SIZE(tegra_dpaux_groups); + *groups = tegra_dpaux_groups; + + return 0; +} + +static int tegra_dpaux_set_mux(struct pinctrl_dev *pinctrl, + unsigned int function, unsigned int group) +{ + struct tegra_dpaux *dpaux = pinctrl_dev_get_drvdata(pinctrl); + + return tegra_dpaux_pad_config(dpaux, function); +} + +static const struct pinmux_ops tegra_dpaux_pinmux_ops = { + .get_functions_count = tegra_dpaux_get_functions_count, + .get_function_name = tegra_dpaux_get_function_name, + .get_function_groups = tegra_dpaux_get_function_groups, + .set_mux = tegra_dpaux_set_mux, +}; +#endif + static int tegra_dpaux_probe(struct platform_device *pdev) { struct tegra_dpaux *dpaux; @@ -425,6 +527,20 @@ static int tegra_dpaux_probe(struct platform_device *pdev) if (err < 0) return err;
+#ifdef CONFIG_PINCTRL + dpaux->desc.name = dev_name(&pdev->dev); + dpaux->desc.pins = tegra_dpaux_pins; + dpaux->desc.npins = ARRAY_SIZE(tegra_dpaux_pins); + dpaux->desc.pctlops = &tegra_dpaux_pinctrl_ops; + dpaux->desc.pmxops = &tegra_dpaux_pinmux_ops; + dpaux->desc.owner = THIS_MODULE; + + dpaux->pinctrl = devm_pinctrl_register(&pdev->dev, &dpaux->desc, dpaux); + if (!dpaux->pinctrl) { + dev_err(&pdev->dev, "failed to register pincontrol\n"); + return -ENODEV; + } +#endif /* enable and clear all interrupts */ value = DPAUX_INTR_AUX_DONE | DPAUX_INTR_IRQ_EVENT | DPAUX_INTR_UNPLUG_EVENT | DPAUX_INTR_PLUG_EVENT; @@ -581,7 +697,7 @@ int drm_dp_aux_enable(struct drm_dp_aux *aux) { struct tegra_dpaux *dpaux = to_dpaux(aux);
- return tegra_dpaux_pad_config(dpaux, DPAUX_HYBRID_PADCTL_MODE_AUX); + return tegra_dpaux_pad_config(dpaux, DPAUX_PADCTL_FUNC_AUX); }
int drm_dp_aux_disable(struct drm_dp_aux *aux)
Add node for SOR power-domain for Tegra210 and populate the SOR power-domain phandle for SOR and DPAUX nodes that are dependent on this power-domain.
Please note that although neither the SOR or DPAUX drivers currently support runtime power-management, by populating the power-domain node the SOR power-domain will be turned on before probing SOR or DPAUX devices and kept on while the devices are bound.
Signed-off-by: Jon Hunter jonathanh@nvidia.com --- arch/arm64/boot/dts/nvidia/tegra210.dtsi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi index ebf44f4059f8..ef317f0d773f 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi @@ -34,6 +34,7 @@ clock-names = "dpaux", "parent"; resets = <&tegra_car 207>; reset-names = "dpaux"; + power-domains = <&pd_sor>; status = "disabled"; };
@@ -154,6 +155,7 @@ clock-names = "sor", "parent", "dp", "safe"; resets = <&tegra_car 182>; reset-names = "sor"; + power-domains = <&pd_sor>; status = "disabled"; };
@@ -168,6 +170,7 @@ clock-names = "sor", "parent", "dp", "safe"; resets = <&tegra_car 183>; reset-names = "sor"; + power-domains = <&pd_sor>; status = "disabled"; };
@@ -180,6 +183,7 @@ clock-names = "dpaux", "parent"; resets = <&tegra_car 181>; reset-names = "dpaux"; + power-domains = <&pd_sor>; status = "disabled"; };
@@ -592,6 +596,26 @@ resets = <&tegra_car 198>; #power-domain-cells = <0>; }; + + pd_sor: sor { + clocks = <&tegra_car TEGRA210_CLK_SOR0>, + <&tegra_car TEGRA210_CLK_SOR1>, + <&tegra_car TEGRA210_CLK_CSI>, + <&tegra_car TEGRA210_CLK_DSIA>, + <&tegra_car TEGRA210_CLK_DSIB>, + <&tegra_car TEGRA210_CLK_DPAUX>, + <&tegra_car TEGRA210_CLK_DPAUX1>, + <&tegra_car TEGRA210_CLK_MIPI_CAL>; + resets = <&tegra_car TEGRA210_CLK_SOR0>, + <&tegra_car TEGRA210_CLK_SOR1>, + <&tegra_car TEGRA210_CLK_CSI>, + <&tegra_car TEGRA210_CLK_DSIA>, + <&tegra_car TEGRA210_CLK_DSIB>, + <&tegra_car TEGRA210_CLK_DPAUX>, + <&tegra_car TEGRA210_CLK_DPAUX1>, + <&tegra_car TEGRA210_CLK_MIPI_CAL>; + #power-domain-cells = <0>; + }; }; };
Add the DPAUX pinctrl states for the DPAUX nodes defining all three possible states of "aux", "i2c" and "off". Also add the 'i2c-bus' node for the DPAUX nodes so that the I2C driver core does not attempt to parse the pinctrl state nodes.
Populate the nodes for the pinctrl clients of the DPAUX pin controller. There are two clients for each DPAUX instance, namely the SOR and one of the I2C adapters. The SOR clients may used the DPAUX pins in either AUX or I2C modes and so for these devices we don't define any of the generic pinctrl states (default, idle, etc) because the SOR driver will directly set the state needed. For I2C clients only the I2C mode is used and so we can simplify matters by using the generic pinctrl states for default and idle.
Signed-off-by: Jon Hunter jonathanh@nvidia.com --- arch/arm64/boot/dts/nvidia/tegra210.dtsi | 54 ++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+)
diff --git a/arch/arm64/boot/dts/nvidia/tegra210.dtsi b/arch/arm64/boot/dts/nvidia/tegra210.dtsi index ef317f0d773f..32af84e404d6 100644 --- a/arch/arm64/boot/dts/nvidia/tegra210.dtsi +++ b/arch/arm64/boot/dts/nvidia/tegra210.dtsi @@ -36,6 +36,26 @@ reset-names = "dpaux"; power-domains = <&pd_sor>; status = "disabled"; + + state_dpaux1_aux: pinmux_aux { + groups = "dpaux-io"; + function = "aux"; + }; + + state_dpaux1_i2c: pinmux_i2c { + groups = "dpaux-io"; + function = "i2c"; + }; + + state_dpaux1_off: pinmux_off { + groups = "dpaux-io"; + function = "off"; + }; + + i2c-bus { + #address-cells = <1>; + #size-cells = <0>; + }; };
vi@54080000 { @@ -155,6 +175,10 @@ clock-names = "sor", "parent", "dp", "safe"; resets = <&tegra_car 182>; reset-names = "sor"; + pinctrl-0 = <&state_dpaux_aux>; + pinctrl-1 = <&state_dpaux_i2c>; + pinctrl-2 = <&state_dpaux_off>; + pinctrl-names = "aux", "i2c", "off"; power-domains = <&pd_sor>; status = "disabled"; }; @@ -170,6 +194,10 @@ clock-names = "sor", "parent", "dp", "safe"; resets = <&tegra_car 183>; reset-names = "sor"; + pinctrl-0 = <&state_dpaux1_aux>; + pinctrl-1 = <&state_dpaux1_i2c>; + pinctrl-2 = <&state_dpaux1_off>; + pinctrl-names = "aux", "i2c", "off"; power-domains = <&pd_sor>; status = "disabled"; }; @@ -185,6 +213,26 @@ reset-names = "dpaux"; power-domains = <&pd_sor>; status = "disabled"; + + state_dpaux_aux: pinmux_aux { + groups = "dpaux-io"; + function = "aux"; + }; + + state_dpaux_i2c: pinmux_i2c { + groups = "dpaux-io"; + function = "i2c"; + }; + + state_dpaux_off: pinmux_off { + groups = "dpaux-io"; + function = "off"; + }; + + i2c-bus { + #address-cells = <1>; + #size-cells = <0>; + }; };
isp@54600000 { @@ -482,6 +530,9 @@ reset-names = "i2c"; dmas = <&apbdma 26>, <&apbdma 26>; dma-names = "rx", "tx"; + pinctrl-0 = <&state_dpaux1_i2c>; + pinctrl-1 = <&state_dpaux1_off>; + pinctrl-names = "default", "idle"; status = "disabled"; };
@@ -512,6 +563,9 @@ reset-names = "i2c"; dmas = <&apbdma 30>, <&apbdma 30>; dma-names = "rx", "tx"; + pinctrl-0 = <&state_dpaux_i2c>; + pinctrl-1 = <&state_dpaux_off>; + pinctrl-names = "default", "idle"; status = "disabled"; };
dri-devel@lists.freedesktop.org