* [PATCH resend 0/1] input: touchscreen: silead: Add regulator support
From: Hans de Goede @ 2016-11-14 14:45 UTC (permalink / raw)
To: linux-arm-kernel
Hi Dmitri,
This one seems to have fallen through the cracks, can you pick it up
please ?
Regards,
Hans
^ permalink raw reply
* [PATCH resend] input: touchscreen: silead: Add regulator support
From: Hans de Goede @ 2016-11-14 14:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161114144502.10595-1-hdegoede@redhat.com>
On some tablets the touchscreen controller is powered by seperate
regulators, add support for this.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Rob Herring <robh@kernel.org>
---
.../bindings/input/touchscreen/silead_gsl1680.txt | 2 +
drivers/input/touchscreen/silead.c | 51 ++++++++++++++++++++--
2 files changed, 49 insertions(+), 4 deletions(-)
diff --git a/Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt b/Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt
index e844c3f..b726823 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt
@@ -22,6 +22,8 @@ Optional properties:
- touchscreen-inverted-y : See touchscreen.txt
- touchscreen-swapped-x-y : See touchscreen.txt
- silead,max-fingers : maximum number of fingers the touchscreen can detect
+- vddio-supply : regulator phandle for controller VDDIO
+- avdd-supply : regulator phandle for controller AVDD
Example:
diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
index f502c84..c6a1ae9 100644
--- a/drivers/input/touchscreen/silead.c
+++ b/drivers/input/touchscreen/silead.c
@@ -29,6 +29,7 @@
#include <linux/input/touchscreen.h>
#include <linux/pm.h>
#include <linux/irq.h>
+#include <linux/regulator/consumer.h>
#include <asm/unaligned.h>
@@ -72,6 +73,8 @@ enum silead_ts_power {
struct silead_ts_data {
struct i2c_client *client;
struct gpio_desc *gpio_power;
+ struct regulator *vddio;
+ struct regulator *avdd;
struct input_dev *input;
char fw_name[64];
struct touchscreen_properties prop;
@@ -465,21 +468,52 @@ static int silead_ts_probe(struct i2c_client *client,
if (client->irq <= 0)
return -ENODEV;
+ data->vddio = devm_regulator_get_optional(dev, "vddio");
+ if (IS_ERR(data->vddio)) {
+ if (PTR_ERR(data->vddio) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ data->vddio = NULL;
+ }
+
+ data->avdd = devm_regulator_get_optional(dev, "avdd");
+ if (IS_ERR(data->avdd)) {
+ if (PTR_ERR(data->avdd) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ data->avdd = NULL;
+ }
+
+ /*
+ * Enable regulators at probe and disable them at remove, we need
+ * to keep the chip powered otherwise it forgets its firmware.
+ */
+ if (data->vddio) {
+ error = regulator_enable(data->vddio);
+ if (error)
+ return error;
+ }
+
+ if (data->avdd) {
+ error = regulator_enable(data->avdd);
+ if (error)
+ goto disable_vddio;
+ }
+
/* Power GPIO pin */
data->gpio_power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
if (IS_ERR(data->gpio_power)) {
if (PTR_ERR(data->gpio_power) != -EPROBE_DEFER)
dev_err(dev, "Shutdown GPIO request failed\n");
- return PTR_ERR(data->gpio_power);
+ error = PTR_ERR(data->gpio_power);
+ goto disable_avdd;
}
error = silead_ts_setup(client);
if (error)
- return error;
+ goto disable_avdd;
error = silead_ts_request_input_dev(data);
if (error)
- return error;
+ goto disable_avdd;
error = devm_request_threaded_irq(dev, client->irq,
NULL, silead_ts_threaded_irq_handler,
@@ -487,10 +521,19 @@ static int silead_ts_probe(struct i2c_client *client,
if (error) {
if (error != -EPROBE_DEFER)
dev_err(dev, "IRQ request failed %d\n", error);
- return error;
+ goto disable_avdd;
}
return 0;
+
+disable_avdd:
+ if (data->avdd)
+ regulator_disable(data->avdd);
+disable_vddio:
+ if (data->vddio)
+ regulator_disable(data->vddio);
+
+ return error;
}
static int __maybe_unused silead_ts_suspend(struct device *dev)
--
2.9.3
^ permalink raw reply related
* [PATCH v2 1/9] arm64: dts: rockchip: add eMMC's power domain support for rk3399
From: Heiko Stuebner @ 2016-11-14 14:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478697721-2323-2-git-send-email-wxt@rock-chips.com>
Am Mittwoch, 9. November 2016, 21:21:53 CET schrieb Caesar Wang:
> From: Ziyuan Xu <xzy.xu@rock-chips.com>
>
> Control power domain for eMMC via genpd to reduce power consumption.
>
> Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
> Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
> Signed-off-by: Caesar Wang <wxt@rock-chips.com>
Authorship / Signed-off mismatch. From above suggest Ziyuan is the author
while first Signed-off-by indicates Elaine as author. Please clarify.
Thanks
Heiko
> ---
>
> Changes in v2:
> - Reviewed-on: https://chromium-review.googlesource.com/376558
> - Verified on ChromeOS kernel4.4
>
> arch/arm64/boot/dts/rockchip/rk3399.dtsi | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index cbb7f8b..b401176 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> @@ -269,6 +269,7 @@
> #clock-cells = <0>;
> phys = <&emmc_phy>;
> phy-names = "phy_arasan";
> + power-domains = <&power RK3399_PD_EMMC>;
> status = "disabled";
> };
>
> @@ -690,6 +691,11 @@
> status = "disabled";
> };
>
> + qos_emmc: qos at ffa58000 {
> + compatible = "syscon";
> + reg = <0x0 0xffa58000 0x0 0x20>;
> + };
> +
> qos_gmac: qos at ffa5c000 {
> compatible = "syscon";
> reg = <0x0 0xffa5c000 0x0 0x20>;
> @@ -823,6 +829,11 @@
> };
>
> /* These power domains are grouped by VD_LOGIC */
> + pd_emmc at RK3399_PD_EMMC {
> + reg = <RK3399_PD_EMMC>;
> + clocks = <&cru ACLK_EMMC>;
> + pm_qos = <&qos_emmc>;
> + };
> pd_gmac at RK3399_PD_GMAC {
> reg = <RK3399_PD_GMAC>;
> clocks = <&cru ACLK_GMAC>;
^ permalink raw reply
* [PATCH 01/16] ARM: scu: Provide support for parsing SCU device node to enable SCU
From: Russell King - ARM Linux @ 2016-11-14 14:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <6787744.7DRFf7p3US@wuerfel>
On Mon, Nov 14, 2016 at 03:37:44PM +0100, Arnd Bergmann wrote:
> On Monday, November 14, 2016 1:50:18 PM CET Russell King - ARM Linux wrote:
> > On Mon, Nov 14, 2016 at 01:03:09PM +0100, Arnd Bergmann wrote:
> > > On Monday, November 14, 2016 2:10:16 PM CET pankaj.dubey wrote:
> > > > >> + scu_base = of_iomap(np, 0);
> > > > >> + of_node_put(np);
> > > > >> + if (!scu_base) {
> > > > >> + pr_err("%s failed to map scu_base via DT\n", __func__);
> > > > >
> > > > > For non-ca5, non-ca9 based SoCs, we'll see this error msg. We understand
> > > > > what does it mean, but it may confuse normal users. In current version,
> > > > > berlin doesn't complain like this for non-ca9 SoCs
> > > > >
> > > >
> > > > OK, let me see other reviewer's comment on this. Then we will decide if
> > > > this error message is required or can be omitted.
> > >
> > > We need to look at all callers here, to see if the function ever gets
> > > called for a CPU that doesn't have an SCU. I'd say we should warn if
> > > we know there is an SCU but we cannot map it, but never warn on
> > > any of the CPU cores that don't support an SCU.
> >
> > Maybe there should be two helpers:
> >
> > of_scu_enable() which _only_ looks up the SCU address in DT and enables
> > it if it finds it, otherwise returning failure.
> >
> > a9_scu_enable() which tries to use the A9 provided SCU address and
> > enables it if it finds it, otherwise returning failure.
> >
> > Then callers can decide which of these to call, and what error messages
> > to print on their failures.
>
> Splitting the function in two is probably simpler overall, but
> we may still have to look at all the callers: Any platform that
> currently tries to map it on any CPU and doesn't warn about the
> absence of the device node (or about scu_a9_has_base() == false)
> should really continue not to warn about that.
Did you miss the bit where none of of_scu_enable() or a9_scu_enable()
should produce any warnings or errors to be printed. It's up to the
caller to report the failure, otherwise doing this doesn't make sense:
if (of_scu_enable() < 0 && a9_scu_enable() < 0)
pr_err("Failed to map and enable the SCU\n");
because if of_scu_enable() prints a warning/error, then it's patently
misleading.
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently@9.6Mbps down 400kbps up
according to speedtest.net.
^ permalink raw reply
* [GIT PULL] ARM: OXNAS SoC updates for 4.10
From: Neil Armstrong @ 2016-11-14 14:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <0b12c093-4be4-8f1c-2b46-ffaa54c5520b@baylibre.com>
On 11/08/2016 12:21 PM, Neil Armstrong wrote:
> On 11/07/2016 10:26 PM, Olof Johansson wrote:
>> On Mon, Oct 31, 2016 at 10:52:53AM +0100, Neil Armstrong wrote:
[...]
>> Hi Neil,
> Hi Olof,
>
>>
>> Sorry for being picky here, please be patient with us. :-)
> Seems legit !
>
>>
>> Overall comments on this patch set:
>>
>> 1) Copyrights seem to be a bit varied. All 3 new source files have
>> different copyright holders. Only one has yours, one is from 2003, one
>> is also from 2013. Is this expected? Seems like it's worth mentioning
>> in commit messages at least.
>
> Yes, the files comes from various places :
> - hotplug.c was taken from versatile by Ma Haijun and left verbatim, so I left the original header
> - headsmp.S was taken from the versatile code and adapted by Ma Haijun
> - platsmp.c is a mix from versatile code, Ma Haijun code and my code for DT
>
> The two first file were only modified in order to build and pass checkpatch actually.
>
> I tried to find the *real* copyright holders, but it was not easy...
>
>>
>> 2) Please remove the linux/arch/... lines from the top of the files. It's
>> something we've been trying to remove for a while and don't want to
>> introduce more occurrances of.
>>
>> I'd say (2) is fine to do incremental, but please provide clarification on (1).
>> I could just add that to the merge commit message so don't respin the branch
>> yet, depending on what we hear back!
>>
>
> Ok, please tell me if/when I need to send a new pull for the (2) fix.
>
>>> arch/arm/Makefile | 1 +
>>> arch/arm/mach-oxnas/Kconfig | 30 +++++++++++++++++++---------
>>> arch/arm/mach-oxnas/Makefile | 2 ++
>>> arch/arm/mach-oxnas/headsmp.S | 28 ++++++++++++++++++++++++++
>>> arch/arm/mach-oxnas/hotplug.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>> arch/arm/mach-oxnas/platsmp.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>
>> Git tip: If you redirect the output to a file (or pipe through cat), the
>> diffstat will be limited to 80 characters and look better in email.
>>
>>
>> Thanks,
>>
>> -Olof
>>
>
> Thanks,
> Neil
>
Hi Olof,
Is a new pull request needed finally ?
Best regards,
Neil
^ permalink raw reply
* [PATCH v2 5/9] arm64: dts: rockchip: add backlight support for rk3399 evb board
From: Heiko Stuebner @ 2016-11-14 14:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478697721-2323-6-git-send-email-wxt@rock-chips.com>
Am Mittwoch, 9. November 2016, 21:21:57 CET schrieb Caesar Wang:
> From: Yakir Yang <ykk@rock-chips.com>
>
> Add backlight node for evb board, perpare for panel device node.
>
> Signed-off-by: Yakir Yang <ykk@rock-chips.com>
> Signed-off-by: Caesar Wang <wxt@rock-chips.com>
applied to my dts64 branch
Thanks
Heiko
^ permalink raw reply
* [PATCH RFC] ARM: dts: add support for Turris Omnia
From: tomas.hlavacek at nic.cz @ 2016-11-14 14:59 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161114131010.GC26710@lunn.ch>
Hi Andrew!
(Sorry for re-posting the previous e-mail, that most likely didn't get
through.)
On Mon, Nov 14, 2016 at 2:10 PM, Andrew Lunn <andrew@lunn.ch> wrote:
>> Actually SFP is connected to SGMII interface of eth1, which is
>> routed through SERDES 5.
>
> You say eth1 here. Yet lower down you say got eth0 and eth1 are
> connected to the switch?
Oh sorry, this was a NIC name based on probing order derived from base
address of NIC registers:
eth1: ethernet at 30000 - probes as eth0
eth2: ethernet at 34000 - probes as eth1
eth0: ethernet at 70000 - probes as eth2
It is a bit confusing. I meant eth2 in DTS. Sorry.
>
>
>> We have our proprietary support hacked onto mvneta driver for
>> disconnecting PHY on the fly. It is a bit nasty, so I suggest to
>> ignore SFP in this DTS altogether and let's wait till "phylink based
>> SFP module support" or something alike hits upstream, so we can base
>> the SFP support on solid code;
>
> It would be great if you could work on getting the phylink patches
> into mainline. It is something i have wanted to do for a long time,
> but it is too low down on my priority list to get to. The code is high
> quality, so i don't think there will be too many issues. It probably
> just needs splitting up into smaller batches, submitting, and working
> on any comments.
That is exactly what I thought when I saw the patches for the first
time. I will try to merge the patches to the current kernel and see
what happens. I still need to learn a lot about PHY subsystem.
>
>
>> Actually eth0 and eth1 (both are RGMII) are connected to the 88E6176
>> switch. The problem is that from what I have read so far the switch
>> can not operate in DSA mode with two CPU ports.
>
> Again, this is something i wanted to do, and i did have a prototype at
> one point. But again, not enough time. If you have resources to work
> on this, i can find my code, explain my ideas, and let you complete
> it.
I am definitely interested, though I didn't have time to read and
absorb DSA yet, but I definitely want to try to hack 88E6176 support. I
would be really grateful if you can provide some pointers and/or code
to start from.
Thanks,
Tomas
^ permalink raw reply
* [PATCH v2 1/9] arm64: dts: rockchip: add eMMC's power domain support for rk3399
From: Caesar Wang @ 2016-11-14 15:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <2342292.tK2jqRKrXH@phil>
On 2016?11?14? 22:45, Heiko Stuebner wrote:
> Am Mittwoch, 9. November 2016, 21:21:53 CET schrieb Caesar Wang:
>> From: Ziyuan Xu <xzy.xu@rock-chips.com>
>>
>> Control power domain for eMMC via genpd to reduce power consumption.
>>
>> Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
>> Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
>> Signed-off-by: Caesar Wang <wxt@rock-chips.com>
> Authorship / Signed-off mismatch. From above suggest Ziyuan is the author
> while first Signed-off-by indicates Elaine as author. Please clarify.
I believe the Elaine is the first author. Sorry for this kind of
question to brother you again. :(
-
Caesar
>
> Thanks
> Heiko
>
>> ---
>>
>> Changes in v2:
>> - Reviewed-on: https://chromium-review.googlesource.com/376558
>> - Verified on ChromeOS kernel4.4
>>
>> arch/arm64/boot/dts/rockchip/rk3399.dtsi | 11 +++++++++++
>> 1 file changed, 11 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
>> b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index cbb7f8b..b401176 100644
>> --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
>> +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
>> @@ -269,6 +269,7 @@
>> #clock-cells = <0>;
>> phys = <&emmc_phy>;
>> phy-names = "phy_arasan";
>> + power-domains = <&power RK3399_PD_EMMC>;
>> status = "disabled";
>> };
>>
>> @@ -690,6 +691,11 @@
>> status = "disabled";
>> };
>>
>> + qos_emmc: qos at ffa58000 {
>> + compatible = "syscon";
>> + reg = <0x0 0xffa58000 0x0 0x20>;
>> + };
>> +
>> qos_gmac: qos at ffa5c000 {
>> compatible = "syscon";
>> reg = <0x0 0xffa5c000 0x0 0x20>;
>> @@ -823,6 +829,11 @@
>> };
>>
>> /* These power domains are grouped by VD_LOGIC */
>> + pd_emmc at RK3399_PD_EMMC {
>> + reg = <RK3399_PD_EMMC>;
>> + clocks = <&cru ACLK_EMMC>;
>> + pm_qos = <&qos_emmc>;
>> + };
>> pd_gmac at RK3399_PD_GMAC {
>> reg = <RK3399_PD_GMAC>;
>> clocks = <&cru ACLK_GMAC>;
>
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
--
caesar wang | software engineer | wxt at rock-chip.com
^ permalink raw reply
* [PATCH v2 1/9] arm64: dts: rockchip: add eMMC's power domain support for rk3399
From: Caesar Wang @ 2016-11-14 15:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <bce1a5eb-fbb3-9ed9-46b9-72a95eefed3e@rock-chips.com>
On 2016?11?12? 12:22, Shawn Lin wrote:
> On 2016/11/9 21:21, Caesar Wang wrote:
>> From: Ziyuan Xu <xzy.xu@rock-chips.com>
>>
>> Control power domain for eMMC via genpd to reduce power consumption.
>>
>> Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
>> Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
>> Signed-off-by: Caesar Wang <wxt@rock-chips.com>
>
> It was verified on my rk3399 evb with kernel4.4, so
> free feel to add my tag,
>
> Tested-by: Shawn Lin <shawn.lin@rock-chips.com>
>
Thanks the tests.
> BTW, it seems my reply is bounced form Yakir's address, so please
> remove him from CC list if he changed his mail address.
Right, Yakir's (ykk at rock-chips.com) address had left this world.;-)
But the patman tool is auto sending with the Cc people.
-
Caesar
>
>> ---
>>
>> Changes in v2:
>> - Reviewed-on: https://chromium-review.googlesource.com/376558
>> - Verified on ChromeOS kernel4.4
>>
>> arch/arm64/boot/dts/rockchip/rk3399.dtsi | 11 +++++++++++
>> 1 file changed, 11 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
>> b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
>> index cbb7f8b..b401176 100644
>> --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
>> +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
>> @@ -269,6 +269,7 @@
>> #clock-cells = <0>;
>> phys = <&emmc_phy>;
>> phy-names = "phy_arasan";
>> + power-domains = <&power RK3399_PD_EMMC>;
>> status = "disabled";
>> };
>>
>> @@ -690,6 +691,11 @@
>> status = "disabled";
>> };
>>
>> + qos_emmc: qos at ffa58000 {
>> + compatible = "syscon";
>> + reg = <0x0 0xffa58000 0x0 0x20>;
>> + };
>> +
>> qos_gmac: qos at ffa5c000 {
>> compatible = "syscon";
>> reg = <0x0 0xffa5c000 0x0 0x20>;
>> @@ -823,6 +829,11 @@
>> };
>>
>> /* These power domains are grouped by VD_LOGIC */
>> + pd_emmc at RK3399_PD_EMMC {
>> + reg = <RK3399_PD_EMMC>;
>> + clocks = <&cru ACLK_EMMC>;
>> + pm_qos = <&qos_emmc>;
>> + };
>> pd_gmac at RK3399_PD_GMAC {
>> reg = <RK3399_PD_GMAC>;
>> clocks = <&cru ACLK_GMAC>;
>>
>
>
--
caesar wang | software engineer | wxt at rock-chip.com
^ permalink raw reply
* [PATCH] ARM: zynq: Reserve correct amount of non-DMA RAM
From: Michal Simek @ 2016-11-14 15:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CA+aJhH2yZqrwR=U2pgWZfxuF63FF75-NVwGHbDU=fFs7cmcg9w@mail.gmail.com>
On 10.11.2016 10:57, Nathan Rossi wrote:
> On 10 November 2016 at 19:33, Nathan Rossi <nathan@nathanrossi.com> wrote:
>> On 10 November 2016 at 18:41, Michal Simek <monstr@monstr.eu> wrote:
>>> + Nathan
>>>
>>> 2016-10-31 17:26 GMT+01:00 Kyle Roeschley <kyle.roeschley@ni.com>:
>>>>
>>>> On Zynq, we haven't been reserving the correct amount of DMA-incapable
>>>> RAM to keep DMA away from it (per the Zynq TRM Section 4.1, it should be
>>>> the first 512k). In older kernels, this was masked by the
>>>> memblock_reserve call in arm_memblock_init(). Now, reserve the correct
>>>> amount excplicitly rather than relying on swapper_pg_dir, which is an
>>>> address and not a size anyway.
>>>>
>>>> Fixes: 46f5b96 ("ARM: zynq: Reserve not DMAable space in front of the
>>>> kernel")
>>>>
>>>> Signed-off-by: Kyle Roeschley <kyle.roeschley@ni.com>
>>
>> Tested-by: Nathan Rossi <nathan@nathanrossi.com>
>>
>> For reference this causes problems with DEBUG_RODATA (which changed to
>
> Sorry typo -> s/causes/caused/, as in "... this [incorrect reserving
> of the lower 512K] caused ...".
>
> Regards,
> Nathan
>
>> default yes for CPU_V7 in v4.6) due to padding memory between
>> .head.text and .text, allowing memory below 0x80000 to be available
>> for allocation as non-reserved memory.
Applied to zynq/soc
https://github.com/Xilinx/linux-xlnx/commits/zynq/soc
Thanks,
Michal
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20161114/08ba1daa/attachment.sig>
^ permalink raw reply
* [PATCH RESEND] spi: atmel: Fix scheduling while atomic
From: Ben Whitten @ 2016-11-14 15:13 UTC (permalink / raw)
To: linux-arm-kernel
A call to clk_get_rate appears to be called in the context of an interrupt,
cache the bus clock for the frequency calculations in transmission.
This fixes a 'BUG: scheduling while atomic' and
'WARNING: CPU: 0 PID: 777 at kernel/sched/core.c:2960 atmel_spi_unlock'
Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
Signed-off-by: Steve deRosier <steve.derosier@lairdtech.com>
---
Resending due to missing off the subsystem maintainer in initial submission,
pointed out by Alexandre Belloni, thanks.
---
drivers/spi/spi-atmel.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 8feac59..c281d1a 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -295,6 +295,7 @@ struct atmel_spi {
int irq;
struct clk *clk;
struct platform_device *pdev;
+ unsigned long spi_clk;
struct spi_transfer *current_transfer;
int current_remaining_bytes;
@@ -864,7 +865,7 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
unsigned long bus_hz;
/* v1 chips start out at half the peripheral bus speed. */
- bus_hz = clk_get_rate(as->clk);
+ bus_hz = as->spi_clk;
if (!atmel_spi_is_v2(as))
bus_hz /= 2;
@@ -1606,6 +1607,9 @@ static int atmel_spi_probe(struct platform_device *pdev)
ret = clk_prepare_enable(clk);
if (ret)
goto out_free_irq;
+
+ as->spi_clk = clk_get_rate(clk);
+
spi_writel(as, CR, SPI_BIT(SWRST));
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
if (as->caps.has_wdrbt) {
--
2.7.4
^ permalink raw reply related
* [PATCH fpga 5/9] fpga zynq: Remove priv->dev
From: atull @ 2016-11-14 15:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478732303-13718-6-git-send-email-jgunthorpe@obsidianresearch.com>
On Wed, 9 Nov 2016, Jason Gunthorpe wrote:
Hi Jason,
Acked-by: Alan Tull <atull@opensource.altera.com>
Alan
> socfpga uses mgr->dev for debug prints, there should be consistency
> here, so standardize on that. The only other use was for dma
> which can be replaced with mgr->dev.parent.
>
> Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
> ---
> drivers/fpga/zynq-fpga.c | 22 ++++++++++------------
> 1 file changed, 10 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c
> index 3ffc5fcc3072..ac2deae92dbd 100644
> --- a/drivers/fpga/zynq-fpga.c
> +++ b/drivers/fpga/zynq-fpga.c
> @@ -118,7 +118,6 @@
> #define FPGA_RST_NONE_MASK 0x0
>
> struct zynq_fpga_priv {
> - struct device *dev;
> int irq;
> struct clk *clk;
>
> @@ -188,7 +187,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, u32 flags,
> * least the sync word and something else to do anything.
> */
> if (count <= 4 || (count % 4) != 0) {
> - dev_err(priv->dev,
> + dev_err(&mgr->dev,
> "Invalid bitstream size, must be multiples of 4 bytes\n");
> return -EINVAL;
> }
> @@ -200,7 +199,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, u32 flags,
> /* don't globally reset PL if we're doing partial reconfig */
> if (!(flags & FPGA_MGR_PARTIAL_RECONFIG)) {
> if (!zynq_fpga_has_sync(buf, count)) {
> - dev_err(priv->dev,
> + dev_err(&mgr->dev,
> "Invalid bitstream, could not find a sync word. Bitstream must be a byte swaped .bin file\n");
> err = -EINVAL;
> goto out_err;
> @@ -233,7 +232,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, u32 flags,
> INIT_POLL_DELAY,
> INIT_POLL_TIMEOUT);
> if (err) {
> - dev_err(priv->dev, "Timeout waiting for PCFG_INIT\n");
> + dev_err(&mgr->dev, "Timeout waiting for PCFG_INIT\n");
> goto out_err;
> }
>
> @@ -247,7 +246,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, u32 flags,
> INIT_POLL_DELAY,
> INIT_POLL_TIMEOUT);
> if (err) {
> - dev_err(priv->dev, "Timeout waiting for !PCFG_INIT\n");
> + dev_err(&mgr->dev, "Timeout waiting for !PCFG_INIT\n");
> goto out_err;
> }
>
> @@ -261,7 +260,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, u32 flags,
> INIT_POLL_DELAY,
> INIT_POLL_TIMEOUT);
> if (err) {
> - dev_err(priv->dev, "Timeout waiting for PCFG_INIT\n");
> + dev_err(&mgr->dev, "Timeout waiting for PCFG_INIT\n");
> goto out_err;
> }
> }
> @@ -278,7 +277,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, u32 flags,
> /* check that we have room in the command queue */
> status = zynq_fpga_read(priv, STATUS_OFFSET);
> if (status & STATUS_DMA_Q_F) {
> - dev_err(priv->dev, "DMA command queue full\n");
> + dev_err(&mgr->dev, "DMA command queue full\n");
> err = -EBUSY;
> goto out_err;
> }
> @@ -309,7 +308,8 @@ static int zynq_fpga_ops_write(struct fpga_manager *mgr,
>
> priv = mgr->priv;
>
> - kbuf = dma_alloc_coherent(priv->dev, count, &dma_addr, GFP_KERNEL);
> + kbuf =
> + dma_alloc_coherent(mgr->dev.parent, count, &dma_addr, GFP_KERNEL);
> if (!kbuf)
> return -ENOMEM;
>
> @@ -356,7 +356,7 @@ static int zynq_fpga_ops_write(struct fpga_manager *mgr,
> goto out_clk;
>
> out_report:
> - dev_err(priv->dev,
> + dev_err(&mgr->dev,
> "%s: INT_STS:0x%x CTRL:0x%x LOCK:0x%x INT_MASK:0x%x STATUS:0x%x MCTRL:0x%x\n",
> why,
> intr_status,
> @@ -368,7 +368,7 @@ out_report:
> out_clk:
> clk_disable(priv->clk);
> out_free:
> - dma_free_coherent(priv->dev, count, kbuf, dma_addr);
> + dma_free_coherent(mgr->dev.parent, count, kbuf, dma_addr);
> return err;
> }
>
> @@ -445,8 +445,6 @@ static int zynq_fpga_probe(struct platform_device *pdev)
> if (!priv)
> return -ENOMEM;
>
> - priv->dev = dev;
> -
> res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> priv->io_base = devm_ioremap_resource(dev, res);
> if (IS_ERR(priv->io_base))
> --
> 2.1.4
>
>
^ permalink raw reply
* [PATCH RESEND] spi: atmel: Fix scheduling while atomic
From: Nicolas Ferre @ 2016-11-14 15:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479136400-10285-1-git-send-email-ben.whitten@lairdtech.com>
Le 14/11/2016 ? 16:13, Ben Whitten a ?crit :
> A call to clk_get_rate appears to be called in the context of an interrupt,
> cache the bus clock for the frequency calculations in transmission.
>
> This fixes a 'BUG: scheduling while atomic' and
> 'WARNING: CPU: 0 PID: 777 at kernel/sched/core.c:2960 atmel_spi_unlock'
>
> Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
> Signed-off-by: Steve deRosier <steve.derosier@lairdtech.com>
Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com>
> ---
>
> Resending due to missing off the subsystem maintainer in initial submission,
> pointed out by Alexandre Belloni, thanks.
BTW, it's actually more a "v2" than a "RESEND".
Thanks a lot for your patch.
Best regards,
> ---
> drivers/spi/spi-atmel.c | 6 +++++-
> 1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
> index 8feac59..c281d1a 100644
> --- a/drivers/spi/spi-atmel.c
> +++ b/drivers/spi/spi-atmel.c
> @@ -295,6 +295,7 @@ struct atmel_spi {
> int irq;
> struct clk *clk;
> struct platform_device *pdev;
> + unsigned long spi_clk;
>
> struct spi_transfer *current_transfer;
> int current_remaining_bytes;
> @@ -864,7 +865,7 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
> unsigned long bus_hz;
>
> /* v1 chips start out at half the peripheral bus speed. */
> - bus_hz = clk_get_rate(as->clk);
> + bus_hz = as->spi_clk;
> if (!atmel_spi_is_v2(as))
> bus_hz /= 2;
>
> @@ -1606,6 +1607,9 @@ static int atmel_spi_probe(struct platform_device *pdev)
> ret = clk_prepare_enable(clk);
> if (ret)
> goto out_free_irq;
> +
> + as->spi_clk = clk_get_rate(clk);
> +
> spi_writel(as, CR, SPI_BIT(SWRST));
> spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
> if (as->caps.has_wdrbt) {
>
--
Nicolas Ferre
^ permalink raw reply
* Summary of LPC guest MSI discussion in Santa Fe
From: Joerg Roedel @ 2016-11-14 15:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161111090543.57623f2d@t450s.home>
On Fri, Nov 11, 2016 at 09:05:43AM -0700, Alex Williamson wrote:
> On Fri, 11 Nov 2016 08:50:56 -0700
> Alex Williamson <alex.williamson@redhat.com> wrote:
> >
> > It's really just a happenstance that we don't map RAM over the x86 MSI
> > range though. That property really can't be guaranteed once we mix
> > architectures, such as running an aarch64 VM on x86 host via TCG.
> > AIUI, the MSI range is actually handled differently than other DMA
> > ranges, so a iommu_map() overlapping a range that the iommu cannot map
> > should fail just like an attempt to map beyond the address width of the
> > iommu.
>
> (clarification, this is x86 specific, the MSI controller - interrupt
> remapper - is embedded in the iommu AIUI, so the iommu is actually not
> able to provide DMA translation for this range.
Right, on x86 the MSI range can be covered by page-tables, but those are
ignored by the IOMMU hardware. But what I am trying to say is, that
checking for these ranges happens already on a higher level (in the
dma-api implementations by marking these regions as allocted) so that
there is no need to check for them again in the iommu_map/unmap path.
Joerg
^ permalink raw reply
* [RFCv2 PATCH 0/5] CEC drivers for iMX6 and TDA9950
From: Hans Verkuil @ 2016-11-14 15:22 UTC (permalink / raw)
To: linux-arm-kernel
From: Hans Verkuil <hans.verkuil@cisco.com>
This patch series is an update to this RFC series from Russell:
https://lists.freedesktop.org/archives/dri-devel/2016-August/115733.html
I have not seen any updates to this, so I hope that that series is still
the latest version.
The main problem with that original series was that the notifier didn't
store the state, so if a CEC driver registered with the notifier, then
it wouldn't be informed of the current state.
The hdmi-notifier code has been changed to a per-HDMI-device and refcounted
block_notifier that stores the state and will report the current state
upon registration.
The other four patches have been adapted to the new notifier code, but
no other changes were made.
It has *only* been compile-tested. I might be able to verify it next week
with an actual i.MX6 device, but it will take time to set that up.
If someone has a ready-to-test setup, then I would very much appreciate
it if this series can be tested.
The patches are also available in my branch:
https://git.linuxtv.org/hverkuil/media_tree.git/log/?h=cec-notifiers
It is on top of my patch series that moves CEC out of staging. This
is planned for 4.10.
Regards,
Hans
Hans Verkuil (1):
video: add HDMI state notifier support
Russell King (4):
drm/bridge: dw_hdmi: remove CEC engine register definitions
drm/bridge: dw_hdmi: add HDMI notifier support
drm/bridge: add dw-hdmi cec driver using Hans Verkuil's CEC code
drm/i2c: add tda998x/tda9950 CEC driver
drivers/gpu/drm/bridge/Kconfig | 8 +
drivers/gpu/drm/bridge/Makefile | 1 +
drivers/gpu/drm/bridge/dw-hdmi-cec.c | 346 ++++++++++++++++++++
drivers/gpu/drm/bridge/dw-hdmi.c | 89 +++++-
drivers/gpu/drm/bridge/dw-hdmi.h | 45 ---
drivers/gpu/drm/i2c/Kconfig | 5 +
drivers/gpu/drm/i2c/Makefile | 1 +
drivers/gpu/drm/i2c/tda9950.c | 516 ++++++++++++++++++++++++++++++
drivers/video/Kconfig | 3 +
drivers/video/Makefile | 1 +
drivers/video/hdmi-notifier.c | 136 ++++++++
include/linux/hdmi-notifier.h | 43 +++
include/linux/platform_data/dw_hdmi-cec.h | 16 +
include/linux/platform_data/tda9950.h | 15 +
14 files changed, 1168 insertions(+), 57 deletions(-)
create mode 100644 drivers/gpu/drm/bridge/dw-hdmi-cec.c
create mode 100644 drivers/gpu/drm/i2c/tda9950.c
create mode 100644 drivers/video/hdmi-notifier.c
create mode 100644 include/linux/hdmi-notifier.h
create mode 100644 include/linux/platform_data/dw_hdmi-cec.h
create mode 100644 include/linux/platform_data/tda9950.h
--
2.8.1
^ permalink raw reply
* [RFCv2 PATCH 1/5] video: add HDMI state notifier support
From: Hans Verkuil @ 2016-11-14 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479136968-24477-1-git-send-email-hverkuil@xs4all.nl>
From: Hans Verkuil <hans.verkuil@cisco.com>
Add support for HDMI hotplug and EDID notifiers, which is used to convey
information from HDMI drivers to their CEC and audio counterparts.
Based on an earlier version from Russell King:
https://patchwork.kernel.org/patch/9277043/
The hdmi_notifier is a reference counted object containing the HDMI state
of an HDMI device.
When a new notifier is registered the current state will be reported to
that notifier at registration time.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
drivers/video/Kconfig | 3 +
drivers/video/Makefile | 1 +
drivers/video/hdmi-notifier.c | 136 ++++++++++++++++++++++++++++++++++++++++++
include/linux/hdmi-notifier.h | 43 +++++++++++++
4 files changed, 183 insertions(+)
create mode 100644 drivers/video/hdmi-notifier.c
create mode 100644 include/linux/hdmi-notifier.h
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 3c20af9..1ee7b9f 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -36,6 +36,9 @@ config VIDEOMODE_HELPERS
config HDMI
bool
+config HDMI_NOTIFIERS
+ bool
+
if VT
source "drivers/video/console/Kconfig"
endif
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 9ad3c17..65f5649 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_VGASTATE) += vgastate.o
obj-$(CONFIG_HDMI) += hdmi.o
+obj-$(CONFIG_HDMI_NOTIFIERS) += hdmi-notifier.o
obj-$(CONFIG_VT) += console/
obj-$(CONFIG_LOGO) += logo/
diff --git a/drivers/video/hdmi-notifier.c b/drivers/video/hdmi-notifier.c
new file mode 100644
index 0000000..c2a4f1b
--- /dev/null
+++ b/drivers/video/hdmi-notifier.c
@@ -0,0 +1,136 @@
+#include <linux/export.h>
+#include <linux/hdmi-notifier.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+
+struct hdmi_notifiers {
+ struct list_head head;
+ struct device *dev;
+ struct hdmi_notifier *n;
+};
+
+static LIST_HEAD(hdmi_notifiers);
+static DEFINE_MUTEX(hdmi_notifiers_lock);
+
+struct hdmi_notifier *hdmi_notifier_get(struct device *dev)
+{
+ struct hdmi_notifier *n;
+
+ mutex_lock(&hdmi_notifiers_lock);
+ list_for_each_entry(n, &hdmi_notifiers, head) {
+ if (n->dev == dev) {
+ mutex_unlock(&hdmi_notifiers_lock);
+ kref_get(&n->kref);
+ return n;
+ }
+ }
+ n = kzalloc(sizeof(*n), GFP_KERNEL);
+ if (!n)
+ goto unlock;
+ mutex_init(&n->lock);
+ BLOCKING_INIT_NOTIFIER_HEAD(&n->notifiers);
+ kref_init(&n->kref);
+ list_add_tail(&n->head, &hdmi_notifiers);
+unlock:
+ mutex_unlock(&hdmi_notifiers_lock);
+ return n;
+}
+EXPORT_SYMBOL_GPL(hdmi_notifier_get);
+
+static void hdmi_notifier_release(struct kref *kref)
+{
+ struct hdmi_notifier *n =
+ container_of(kref, struct hdmi_notifier, kref);
+
+ kfree(n->edid);
+ kfree(n);
+}
+
+void hdmi_notifier_put(struct hdmi_notifier *n)
+{
+ kref_put(&n->kref, hdmi_notifier_release);
+}
+EXPORT_SYMBOL_GPL(hdmi_notifier_put);
+
+int hdmi_notifier_register(struct hdmi_notifier *n, struct notifier_block *nb)
+{
+ int ret = blocking_notifier_chain_register(&n->notifiers, nb);
+
+ if (ret)
+ return ret;
+ kref_get(&n->kref);
+ mutex_lock(&n->lock);
+ if (n->connected) {
+ blocking_notifier_call_chain(&n->notifiers, HDMI_CONNECTED, n);
+ if (n->edid_size)
+ blocking_notifier_call_chain(&n->notifiers, HDMI_NEW_EDID, n);
+ if (n->has_eld)
+ blocking_notifier_call_chain(&n->notifiers, HDMI_NEW_ELD, n);
+ }
+ mutex_unlock(&n->lock);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hdmi_notifier_register);
+
+int hdmi_notifier_unregister(struct hdmi_notifier *n, struct notifier_block *nb)
+{
+ int ret = blocking_notifier_chain_unregister(&n->notifiers, nb);
+
+ if (ret == 0)
+ hdmi_notifier_put(n);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(hdmi_notifier_unregister);
+
+void hdmi_event_connect(struct hdmi_notifier *n)
+{
+ mutex_lock(&n->lock);
+ n->connected = true;
+ blocking_notifier_call_chain(&n->notifiers, HDMI_CONNECTED, n);
+ mutex_unlock(&n->lock);
+}
+EXPORT_SYMBOL_GPL(hdmi_event_connect);
+
+void hdmi_event_disconnect(struct hdmi_notifier *n)
+{
+ mutex_lock(&n->lock);
+ n->connected = false;
+ n->has_eld = false;
+ n->edid_size = 0;
+ blocking_notifier_call_chain(&n->notifiers, HDMI_DISCONNECTED, n);
+ mutex_unlock(&n->lock);
+}
+EXPORT_SYMBOL_GPL(hdmi_event_disconnect);
+
+int hdmi_event_new_edid(struct hdmi_notifier *n, const void *edid, size_t size)
+{
+ mutex_lock(&n->lock);
+ if (n->edid_allocated_size < size) {
+ void *p = kmalloc(size, GFP_KERNEL);
+
+ if (p == NULL) {
+ mutex_unlock(&n->lock);
+ return -ENOMEM;
+ }
+ kfree(n->edid);
+ n->edid = p;
+ n->edid_allocated_size = size;
+ }
+ memcpy(n->edid, edid, size);
+ n->edid_size = size;
+ blocking_notifier_call_chain(&n->notifiers, HDMI_NEW_EDID, n);
+ mutex_unlock(&n->lock);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hdmi_event_new_edid);
+
+void hdmi_event_new_eld(struct hdmi_notifier *n, const u8 eld[128])
+{
+ mutex_lock(&n->lock);
+ memcpy(n->eld, eld, sizeof(n->eld));
+ n->has_eld = true;
+ blocking_notifier_call_chain(&n->notifiers, HDMI_NEW_ELD, n);
+ mutex_unlock(&n->lock);
+}
+EXPORT_SYMBOL_GPL(hdmi_event_new_eld);
diff --git a/include/linux/hdmi-notifier.h b/include/linux/hdmi-notifier.h
new file mode 100644
index 0000000..f7fc405
--- /dev/null
+++ b/include/linux/hdmi-notifier.h
@@ -0,0 +1,43 @@
+#ifndef LINUX_HDMI_NOTIFIER_H
+#define LINUX_HDMI_NOTIFIER_H
+
+#include <linux/types.h>
+#include <linux/notifier.h>
+#include <linux/kref.h>
+
+enum {
+ HDMI_CONNECTED,
+ HDMI_DISCONNECTED,
+ HDMI_NEW_EDID,
+ HDMI_NEW_ELD,
+};
+
+struct device;
+
+struct hdmi_notifier {
+ struct mutex lock;
+ struct list_head head;
+ struct kref kref;
+ struct blocking_notifier_head notifiers;
+ struct device *dev;
+
+ /* Current state */
+ bool connected;
+ bool has_eld;
+ unsigned char eld[128];
+ void *edid;
+ size_t edid_size;
+ size_t edid_allocated_size;
+};
+
+struct hdmi_notifier *hdmi_notifier_get(struct device *dev);
+void hdmi_notifier_put(struct hdmi_notifier *n);
+int hdmi_notifier_register(struct hdmi_notifier *n, struct notifier_block *nb);
+int hdmi_notifier_unregister(struct hdmi_notifier *n, struct notifier_block *nb);
+
+void hdmi_event_connect(struct hdmi_notifier *n);
+void hdmi_event_disconnect(struct hdmi_notifier *n);
+int hdmi_event_new_edid(struct hdmi_notifier *n, const void *edid, size_t size);
+void hdmi_event_new_eld(struct hdmi_notifier *n, const u8 eld[128]);
+
+#endif
--
2.8.1
^ permalink raw reply related
* [RFCv2 PATCH 2/5] drm/bridge: dw_hdmi: remove CEC engine register definitions
From: Hans Verkuil @ 2016-11-14 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479136968-24477-1-git-send-email-hverkuil@xs4all.nl>
From: Russell King <rmk+kernel@arm.linux.org.uk>
We don't need the CEC engine register definitions, so let's remove them.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/gpu/drm/bridge/dw-hdmi.h | 45 ----------------------------------------
1 file changed, 45 deletions(-)
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h
index fc9a560..26d6845 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.h
+++ b/drivers/gpu/drm/bridge/dw-hdmi.h
@@ -478,51 +478,6 @@
#define HDMI_A_PRESETUP 0x501A
#define HDMI_A_SRM_BASE 0x5020
-/* CEC Engine Registers */
-#define HDMI_CEC_CTRL 0x7D00
-#define HDMI_CEC_STAT 0x7D01
-#define HDMI_CEC_MASK 0x7D02
-#define HDMI_CEC_POLARITY 0x7D03
-#define HDMI_CEC_INT 0x7D04
-#define HDMI_CEC_ADDR_L 0x7D05
-#define HDMI_CEC_ADDR_H 0x7D06
-#define HDMI_CEC_TX_CNT 0x7D07
-#define HDMI_CEC_RX_CNT 0x7D08
-#define HDMI_CEC_TX_DATA0 0x7D10
-#define HDMI_CEC_TX_DATA1 0x7D11
-#define HDMI_CEC_TX_DATA2 0x7D12
-#define HDMI_CEC_TX_DATA3 0x7D13
-#define HDMI_CEC_TX_DATA4 0x7D14
-#define HDMI_CEC_TX_DATA5 0x7D15
-#define HDMI_CEC_TX_DATA6 0x7D16
-#define HDMI_CEC_TX_DATA7 0x7D17
-#define HDMI_CEC_TX_DATA8 0x7D18
-#define HDMI_CEC_TX_DATA9 0x7D19
-#define HDMI_CEC_TX_DATA10 0x7D1a
-#define HDMI_CEC_TX_DATA11 0x7D1b
-#define HDMI_CEC_TX_DATA12 0x7D1c
-#define HDMI_CEC_TX_DATA13 0x7D1d
-#define HDMI_CEC_TX_DATA14 0x7D1e
-#define HDMI_CEC_TX_DATA15 0x7D1f
-#define HDMI_CEC_RX_DATA0 0x7D20
-#define HDMI_CEC_RX_DATA1 0x7D21
-#define HDMI_CEC_RX_DATA2 0x7D22
-#define HDMI_CEC_RX_DATA3 0x7D23
-#define HDMI_CEC_RX_DATA4 0x7D24
-#define HDMI_CEC_RX_DATA5 0x7D25
-#define HDMI_CEC_RX_DATA6 0x7D26
-#define HDMI_CEC_RX_DATA7 0x7D27
-#define HDMI_CEC_RX_DATA8 0x7D28
-#define HDMI_CEC_RX_DATA9 0x7D29
-#define HDMI_CEC_RX_DATA10 0x7D2a
-#define HDMI_CEC_RX_DATA11 0x7D2b
-#define HDMI_CEC_RX_DATA12 0x7D2c
-#define HDMI_CEC_RX_DATA13 0x7D2d
-#define HDMI_CEC_RX_DATA14 0x7D2e
-#define HDMI_CEC_RX_DATA15 0x7D2f
-#define HDMI_CEC_LOCK 0x7D30
-#define HDMI_CEC_WKUPCTRL 0x7D31
-
/* I2C Master Registers (E-DDC) */
#define HDMI_I2CM_SLAVE 0x7E00
#define HDMI_I2CM_ADDRESS 0x7E01
--
2.8.1
^ permalink raw reply related
* [RFCv2 PATCH 3/5] drm/bridge: dw_hdmi: add HDMI notifier support
From: Hans Verkuil @ 2016-11-14 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479136968-24477-1-git-send-email-hverkuil@xs4all.nl>
From: Russell King <rmk+kernel@arm.linux.org.uk>
Add HDMI notifiers to the HDMI bridge driver.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/gpu/drm/bridge/Kconfig | 1 +
drivers/gpu/drm/bridge/dw-hdmi.c | 25 ++++++++++++++++++++++++-
2 files changed, 25 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 10e12e7..5f4ebe9 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -27,6 +27,7 @@ config DRM_DUMB_VGA_DAC
config DRM_DW_HDMI
tristate
select DRM_KMS_HELPER
+ select HDMI_NOTIFIERS
config DRM_DW_HDMI_AHB_AUDIO
tristate "Synopsis Designware AHB Audio interface"
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index ab7023e..bd02da5 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -16,6 +16,7 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/hdmi.h>
+#include <linux/hdmi-notifier.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/spinlock.h>
@@ -114,6 +115,7 @@ struct dw_hdmi {
struct hdmi_data_info hdmi_data;
const struct dw_hdmi_plat_data *plat_data;
+ struct hdmi_notifier *n;
int vic;
@@ -1448,9 +1450,11 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid);
hdmi->sink_has_audio = drm_detect_monitor_audio(edid);
drm_mode_connector_update_edid_property(connector, edid);
+ hdmi_event_new_edid(hdmi->n, edid, 0);
ret = drm_add_edid_modes(connector, edid);
/* Store the ELD */
drm_edid_to_eld(connector, edid);
+ hdmi_event_new_eld(hdmi->n, connector->eld);
kfree(edid);
} else {
dev_dbg(hdmi->dev, "failed to get edid\n");
@@ -1579,6 +1583,12 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
dw_hdmi_update_phy_mask(hdmi);
}
mutex_unlock(&hdmi->mutex);
+
+ if ((phy_stat & (HDMI_PHY_RX_SENSE | HDMI_PHY_HPD)) == 0)
+ hdmi_event_disconnect(hdmi->n);
+ else if ((phy_stat & (HDMI_PHY_RX_SENSE | HDMI_PHY_HPD)) ==
+ (HDMI_IH_PHY_STAT0_RX_SENSE | HDMI_PHY_HPD))
+ hdmi_event_connect(hdmi->n);
}
if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
@@ -1732,11 +1742,17 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
initialize_hdmi_ih_mutes(hdmi);
+ hdmi->n = hdmi_notifier_get(dev);
+ if (!hdmi->n) {
+ ret = -ENOMEM;
+ goto err_iahb;
+ }
+
ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq,
dw_hdmi_irq, IRQF_SHARED,
dev_name(dev), hdmi);
if (ret)
- goto err_iahb;
+ goto err_hdmi_not;
/*
* To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator
@@ -1788,6 +1804,8 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
return 0;
+err_hdmi_not:
+ hdmi_notifier_put(hdmi->n);
err_iahb:
clk_disable_unprepare(hdmi->iahb_clk);
err_isfr:
@@ -1804,6 +1822,11 @@ void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
if (hdmi->audio && !IS_ERR(hdmi->audio))
platform_device_unregister(hdmi->audio);
+ hdmi_notifier_put(hdmi->n);
+
+ if (!IS_ERR(hdmi->cec))
+ platform_device_unregister(hdmi->cec);
+
/* Disable all interrupts */
hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
--
2.8.1
^ permalink raw reply related
* [RFCv2 PATCH 4/5] drm/bridge: add dw-hdmi cec driver using Hans Verkuil's CEC code
From: Hans Verkuil @ 2016-11-14 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479136968-24477-1-git-send-email-hverkuil@xs4all.nl>
From: Russell King <rmk+kernel@arm.linux.org.uk>
Add a CEC driver for the dw-hdmi hardware using Hans Verkuil's CEC
implementation.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/gpu/drm/bridge/Kconfig | 7 +
drivers/gpu/drm/bridge/Makefile | 1 +
drivers/gpu/drm/bridge/dw-hdmi-cec.c | 346 ++++++++++++++++++++++++++++++
drivers/gpu/drm/bridge/dw-hdmi.c | 64 +++++-
include/linux/platform_data/dw_hdmi-cec.h | 16 ++
5 files changed, 423 insertions(+), 11 deletions(-)
create mode 100644 drivers/gpu/drm/bridge/dw-hdmi-cec.c
create mode 100644 include/linux/platform_data/dw_hdmi-cec.h
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 5f4ebe9..4ab137e 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -40,6 +40,13 @@ config DRM_DW_HDMI_AHB_AUDIO
Designware HDMI block. This is used in conjunction with
the i.MX6 HDMI driver.
+config DRM_DW_HDMI_CEC
+ tristate "Synopsis Designware CEC interface"
+ depends on DRM_DW_HDMI && MEDIA_CEC_SUPPORT
+ help
+ Support the CE interface which is part of the Synopsis
+ Designware HDMI block.
+
config DRM_NXP_PTN3460
tristate "NXP PTN3460 DP/LVDS bridge"
depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index cdf3a3c..6bdd8b9 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o
obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o
obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o
+obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o
obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o
obj-$(CONFIG_DRM_SII902X) += sii902x.o
diff --git a/drivers/gpu/drm/bridge/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/dw-hdmi-cec.c
new file mode 100644
index 0000000..e7e12b5
--- /dev/null
+++ b/drivers/gpu/drm/bridge/dw-hdmi-cec.c
@@ -0,0 +1,346 @@
+/* http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/
+ * tree/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c?h=imx_3.0.35_4.1.0 */
+#include <linux/hdmi-notifier.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/platform_data/dw_hdmi-cec.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <drm/drm_edid.h>
+
+#include <media/cec.h>
+#include <media/cec-edid.h>
+
+#define DEV_NAME "mxc_hdmi_cec"
+
+enum {
+ HDMI_IH_CEC_STAT0 = 0x0106,
+ HDMI_IH_MUTE_CEC_STAT0 = 0x0186,
+
+ HDMI_CEC_CTRL = 0x7d00,
+ CEC_CTRL_START = BIT(0),
+ CEC_CTRL_NORMAL = 1 << 1,
+
+ HDMI_CEC_STAT = 0x7d01,
+ CEC_STAT_DONE = BIT(0),
+ CEC_STAT_EOM = BIT(1),
+ CEC_STAT_NACK = BIT(2),
+ CEC_STAT_ARBLOST = BIT(3),
+ CEC_STAT_ERROR_INIT = BIT(4),
+ CEC_STAT_ERROR_FOLL = BIT(5),
+ CEC_STAT_WAKEUP = BIT(6),
+
+ HDMI_CEC_MASK = 0x7d02,
+ HDMI_CEC_POLARITY = 0x7d03,
+ HDMI_CEC_INT = 0x7d04,
+ HDMI_CEC_ADDR_L = 0x7d05,
+ HDMI_CEC_ADDR_H = 0x7d06,
+ HDMI_CEC_TX_CNT = 0x7d07,
+ HDMI_CEC_RX_CNT = 0x7d08,
+ HDMI_CEC_TX_DATA0 = 0x7d10,
+ HDMI_CEC_RX_DATA0 = 0x7d20,
+ HDMI_CEC_LOCK = 0x7d30,
+ HDMI_CEC_WKUPCTRL = 0x7d31,
+};
+
+struct dw_hdmi_cec {
+ void __iomem *base;
+ u32 addresses;
+ struct cec_adapter *adap;
+ struct cec_msg rx_msg;
+ unsigned int tx_status;
+ bool tx_done;
+ bool rx_done;
+ const struct dw_hdmi_cec_ops *ops;
+ void *ops_data;
+ int retries;
+ int irq;
+ struct hdmi_notifier *n;
+ struct notifier_block nb;
+};
+
+static int dw_hdmi_cec_log_addr(struct cec_adapter *adap, u8 logical_addr)
+{
+ struct dw_hdmi_cec *cec = adap->priv;
+ u32 addresses;
+
+ if (logical_addr == CEC_LOG_ADDR_INVALID)
+ addresses = cec->addresses = BIT(15);
+ else
+ addresses = cec->addresses |= BIT(logical_addr);
+
+ writeb_relaxed(addresses & 255, cec->base + HDMI_CEC_ADDR_L);
+ writeb_relaxed(addresses >> 8, cec->base + HDMI_CEC_ADDR_H);
+
+ return 0;
+}
+
+static int dw_hdmi_cec_transmit(struct cec_adapter *adap, u8 attempts,
+ u32 signal_free_time, struct cec_msg *msg)
+{
+ struct dw_hdmi_cec *cec = adap->priv;
+ unsigned i;
+
+ cec->retries = attempts;
+
+ for (i = 0; i < msg->len; i++)
+ writeb_relaxed(msg->msg[i], cec->base + HDMI_CEC_TX_DATA0 + i);
+
+ writeb_relaxed(msg->len, cec->base + HDMI_CEC_TX_CNT);
+ writeb_relaxed(CEC_CTRL_NORMAL | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL);
+
+ return 0;
+}
+
+static irqreturn_t dw_hdmi_cec_hardirq(int irq, void *data)
+{
+ struct cec_adapter *adap = data;
+ struct dw_hdmi_cec *cec = adap->priv;
+ unsigned stat = readb_relaxed(cec->base + HDMI_IH_CEC_STAT0);
+ irqreturn_t ret = IRQ_HANDLED;
+
+ if (stat == 0)
+ return IRQ_NONE;
+
+ writeb_relaxed(stat, cec->base + HDMI_IH_CEC_STAT0);
+
+ if (stat & CEC_STAT_ERROR_INIT) {
+ if (cec->retries) {
+ unsigned v = readb_relaxed(cec->base + HDMI_CEC_CTRL);
+ writeb_relaxed(v | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL);
+ cec->retries -= 1;
+ } else {
+ cec->tx_status = CEC_TX_STATUS_MAX_RETRIES;
+ cec->tx_done = true;
+ ret = IRQ_WAKE_THREAD;
+ }
+ } else if (stat & CEC_STAT_DONE) {
+ cec->tx_status = CEC_TX_STATUS_OK;
+ cec->tx_done = true;
+ ret = IRQ_WAKE_THREAD;
+ } else if (stat & CEC_STAT_NACK) {
+ cec->tx_status = CEC_TX_STATUS_NACK;
+ cec->tx_done = true;
+ ret = IRQ_WAKE_THREAD;
+ }
+
+ if (stat & CEC_STAT_EOM) {
+ unsigned len, i;
+ void *base = cec->base;
+
+ len = readb_relaxed(base + HDMI_CEC_RX_CNT);
+ if (len > sizeof(cec->rx_msg.msg))
+ len = sizeof(cec->rx_msg.msg);
+
+ for (i = 0; i < len; i++)
+ cec->rx_msg.msg[i] =
+ readb_relaxed(base + HDMI_CEC_RX_DATA0 + i);
+
+ writeb_relaxed(0, base + HDMI_CEC_LOCK);
+
+ cec->rx_msg.len = len;
+ smp_wmb();
+ cec->rx_done = true;
+
+ ret = IRQ_WAKE_THREAD;
+ }
+
+ return ret;
+}
+
+static irqreturn_t dw_hdmi_cec_thread(int irq, void *data)
+{
+ struct cec_adapter *adap = data;
+ struct dw_hdmi_cec *cec = adap->priv;
+
+ if (cec->tx_done) {
+ cec->tx_done = false;
+ cec_transmit_done(adap, cec->tx_status, 0, 0, 0, 0);
+ }
+ if (cec->rx_done) {
+ cec->rx_done = false;
+ smp_rmb();
+ cec_received_msg(adap, &cec->rx_msg);
+ }
+ return IRQ_HANDLED;
+}
+
+static int dw_hdmi_cec_enable(struct cec_adapter *adap, bool enable)
+{
+ struct dw_hdmi_cec *cec = adap->priv;
+
+ if (!enable) {
+ writeb_relaxed(~0, cec->base + HDMI_CEC_MASK);
+ writeb_relaxed(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0);
+ writeb_relaxed(0, cec->base + HDMI_CEC_POLARITY);
+
+ cec->ops->disable(cec->ops_data);
+ } else {
+ unsigned irqs;
+
+ writeb_relaxed(0, cec->base + HDMI_CEC_CTRL);
+ writeb_relaxed(~0, cec->base + HDMI_IH_CEC_STAT0);
+ writeb_relaxed(0, cec->base + HDMI_CEC_LOCK);
+
+ dw_hdmi_cec_log_addr(cec->adap, CEC_LOG_ADDR_INVALID);
+
+ cec->ops->enable(cec->ops_data);
+
+ irqs = CEC_STAT_ERROR_INIT | CEC_STAT_NACK | CEC_STAT_EOM |
+ CEC_STAT_DONE;
+ writeb_relaxed(irqs, cec->base + HDMI_CEC_POLARITY);
+ writeb_relaxed(~irqs, cec->base + HDMI_CEC_MASK);
+ writeb_relaxed(~irqs, cec->base + HDMI_IH_MUTE_CEC_STAT0);
+ }
+ return 0;
+}
+
+static const struct cec_adap_ops dw_hdmi_cec_ops = {
+ .adap_enable = dw_hdmi_cec_enable,
+ .adap_log_addr = dw_hdmi_cec_log_addr,
+ .adap_transmit = dw_hdmi_cec_transmit,
+};
+
+static unsigned int parse_hdmi_addr(const struct edid *edid)
+{
+ if (!edid || edid->extensions == 0)
+ return (u16)~0;
+
+ return cec_get_edid_phys_addr((u8 *)edid,
+ EDID_LENGTH * (edid->extensions + 1), NULL);
+}
+
+static int dw_hdmi_cec_notify(struct notifier_block *nb, unsigned long event,
+ void *data)
+{
+ struct dw_hdmi_cec *cec = container_of(nb, struct dw_hdmi_cec, nb);
+ struct hdmi_notifier *n = data;
+ unsigned int phys;
+
+ dev_info(cec->adap->devnode.parent, "event %lu\n", event);
+
+ switch (event) {
+ case HDMI_CONNECTED:
+ break;
+
+ case HDMI_DISCONNECTED:
+ cec_s_phys_addr(cec->adap, CEC_PHYS_ADDR_INVALID, false);
+ break;
+
+ case HDMI_NEW_EDID:
+ phys = parse_hdmi_addr(n->edid);
+ cec_s_phys_addr(cec->adap, phys, false);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static void dw_hdmi_cec_del(void *data)
+{
+ struct dw_hdmi_cec *cec = data;
+
+ cec_delete_adapter(cec->adap);
+}
+
+static int dw_hdmi_cec_probe(struct platform_device *pdev)
+{
+ struct dw_hdmi_cec_data *data = dev_get_platdata(&pdev->dev);
+ struct dw_hdmi_cec *cec;
+ int ret;
+
+ if (!data)
+ return -ENXIO;
+
+ /*
+ * Our device is just a convenience - we want to link to the real
+ * hardware device here, so that userspace can see the association
+ * between the HDMI hardware and its associated CEC chardev.
+ */
+ cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL);
+ if (!cec)
+ return -ENOMEM;
+
+ cec->base = data->base;
+ cec->irq = data->irq;
+ cec->ops = data->ops;
+ cec->ops_data = data->ops_data;
+ cec->nb.notifier_call = dw_hdmi_cec_notify;
+
+ platform_set_drvdata(pdev, cec);
+
+ writeb_relaxed(0, cec->base + HDMI_CEC_TX_CNT);
+ writeb_relaxed(~0, cec->base + HDMI_CEC_MASK);
+ writeb_relaxed(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0);
+ writeb_relaxed(0, cec->base + HDMI_CEC_POLARITY);
+
+ cec->adap = cec_allocate_adapter(&dw_hdmi_cec_ops, cec, "dw_hdmi",
+ CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT |
+ CEC_CAP_RC, CEC_MAX_LOG_ADDRS,
+ pdev->dev.parent);
+ if (IS_ERR(cec->adap))
+ return PTR_ERR(cec->adap);
+
+ /* override the module pointer */
+ cec->adap->owner = THIS_MODULE;
+
+ ret = devm_add_action(&pdev->dev, dw_hdmi_cec_del, cec);
+ if (ret) {
+ cec_delete_adapter(cec->adap);
+ return ret;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, cec->irq,
+ dw_hdmi_cec_hardirq,
+ dw_hdmi_cec_thread, IRQF_SHARED,
+ DEV_NAME, cec->adap);
+ if (ret < 0)
+ return ret;
+
+ ret = cec_register_adapter(cec->adap);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * CEC documentation says we must not call cec_delete_adapter
+ * after a successful call to cec_register_adapter().
+ */
+ devm_remove_action(&pdev->dev, dw_hdmi_cec_del, cec);
+
+ cec->n = hdmi_notifier_get(cec->adap->devnode.parent);
+ if (!cec->n)
+ return -ENOMEM;
+ hdmi_notifier_register(cec->n, &cec->nb);
+
+ return 0;
+}
+
+static int dw_hdmi_cec_remove(struct platform_device *pdev)
+{
+ struct dw_hdmi_cec *cec = platform_get_drvdata(pdev);
+
+ hdmi_notifier_unregister(cec->n, &cec->nb);
+ hdmi_notifier_put(cec->n);
+ cec_unregister_adapter(cec->adap);
+
+ return 0;
+}
+
+static struct platform_driver dw_hdmi_cec_driver = {
+ .probe = dw_hdmi_cec_probe,
+ .remove = dw_hdmi_cec_remove,
+ .driver = {
+ .name = "dw-hdmi-cec",
+ .owner = THIS_MODULE,
+ },
+};
+module_platform_driver(dw_hdmi_cec_driver);
+
+MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
+MODULE_DESCRIPTION("Synopsis Designware HDMI CEC driver for i.MX");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS(PLATFORM_MODULE_PREFIX "dw-hdmi-cec");
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index bd02da5..06191b4 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -19,6 +19,7 @@
#include <linux/hdmi-notifier.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
+#include <linux/platform_data/dw_hdmi-cec.h>
#include <linux/spinlock.h>
#include <drm/drm_of.h>
@@ -108,6 +109,7 @@ struct dw_hdmi {
struct drm_bridge *bridge;
struct platform_device *audio;
+ struct platform_device *cec;
enum dw_hdmi_devtype dev_type;
struct device *dev;
struct clk *isfr_clk;
@@ -120,6 +122,7 @@ struct dw_hdmi {
int vic;
u8 edid[HDMI_EDID_LEN];
+ u8 mc_clkdis;
bool cable_plugin;
bool phy_enabled;
@@ -1110,8 +1113,6 @@ static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi)
/* HDMI Initialization Step B.4 */
static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
{
- u8 clkdis;
-
/* control period minimum duration */
hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR);
hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR);
@@ -1123,23 +1124,28 @@ static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM);
/* Enable pixel clock and tmds data path */
- clkdis = 0x7F;
- clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+ hdmi->mc_clkdis |= HDMI_MC_CLKDIS_HDCPCLK_DISABLE |
+ HDMI_MC_CLKDIS_CSCCLK_DISABLE |
+ HDMI_MC_CLKDIS_AUDCLK_DISABLE |
+ HDMI_MC_CLKDIS_PREPCLK_DISABLE |
+ HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
+ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
+ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
- clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
+ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
/* Enable csc path */
if (is_color_space_conversion(hdmi)) {
- clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
+ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
}
}
static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi)
{
- hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
+ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
+ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
}
/* Workaround to clear the overflow condition */
@@ -1299,7 +1305,6 @@ static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi)
hdmi_writeb(hdmi, 0xff, HDMI_AUD_HBR_MASK);
hdmi_writeb(hdmi, 0xff, HDMI_GP_MASK);
hdmi_writeb(hdmi, 0xff, HDMI_A_APIINTMSK);
- hdmi_writeb(hdmi, 0xff, HDMI_CEC_MASK);
hdmi_writeb(hdmi, 0xff, HDMI_I2CM_INT);
hdmi_writeb(hdmi, 0xff, HDMI_I2CM_CTLINT);
@@ -1640,6 +1645,27 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
return 0;
}
+static void dw_hdmi_cec_enable(void *data)
+{
+ struct dw_hdmi *hdmi = data;
+
+ hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CECCLK_DISABLE;
+ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
+}
+
+static void dw_hdmi_cec_disable(void *data)
+{
+ struct dw_hdmi *hdmi = data;
+
+ hdmi->mc_clkdis |= HDMI_MC_CLKDIS_CECCLK_DISABLE;
+ hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
+}
+
+static const struct dw_hdmi_cec_ops dw_hdmi_cec_ops = {
+ .enable = dw_hdmi_cec_enable,
+ .disable = dw_hdmi_cec_disable,
+};
+
int dw_hdmi_bind(struct device *dev, struct device *master,
void *data, struct drm_encoder *encoder,
struct resource *iores, int irq,
@@ -1650,6 +1676,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
struct platform_device_info pdevinfo;
struct device_node *ddc_node;
struct dw_hdmi_audio_data audio;
+ struct dw_hdmi_cec_data cec;
struct dw_hdmi *hdmi;
int ret;
u32 val = 1;
@@ -1668,6 +1695,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
hdmi->disabled = true;
hdmi->rxsense = true;
hdmi->phy_mask = (u8)~(HDMI_PHY_HPD | HDMI_PHY_RX_SENSE);
+ hdmi->mc_clkdis = 0x7f;
mutex_init(&hdmi->mutex);
mutex_init(&hdmi->audio_mutex);
@@ -1800,6 +1828,18 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
hdmi->audio = platform_device_register_full(&pdevinfo);
}
+ cec.base = hdmi->regs;
+ cec.irq = irq;
+ cec.ops = &dw_hdmi_cec_ops;
+ cec.ops_data = hdmi;
+
+ pdevinfo.name = "dw-hdmi-cec";
+ pdevinfo.data = &cec;
+ pdevinfo.size_data = sizeof(cec);
+ pdevinfo.dma_mask = 0;
+
+ hdmi->cec = platform_device_register_full(&pdevinfo);
+
dev_set_drvdata(dev, hdmi);
return 0;
@@ -1821,6 +1861,8 @@ void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
if (hdmi->audio && !IS_ERR(hdmi->audio))
platform_device_unregister(hdmi->audio);
+ if (!IS_ERR(hdmi->cec))
+ platform_device_unregister(hdmi->cec);
hdmi_notifier_put(hdmi->n);
diff --git a/include/linux/platform_data/dw_hdmi-cec.h b/include/linux/platform_data/dw_hdmi-cec.h
new file mode 100644
index 0000000..5ff40cc
--- /dev/null
+++ b/include/linux/platform_data/dw_hdmi-cec.h
@@ -0,0 +1,16 @@
+#ifndef DW_HDMI_CEC_H
+#define DW_HDMI_CEC_H
+
+struct dw_hdmi_cec_ops {
+ void (*enable)(void *);
+ void (*disable)(void *);
+};
+
+struct dw_hdmi_cec_data {
+ void __iomem *base;
+ int irq;
+ const struct dw_hdmi_cec_ops *ops;
+ void *ops_data;
+};
+
+#endif
--
2.8.1
^ permalink raw reply related
* [RFCv2 PATCH 5/5] drm/i2c: add tda998x/tda9950 CEC driver
From: Hans Verkuil @ 2016-11-14 15:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479136968-24477-1-git-send-email-hverkuil@xs4all.nl>
From: Russell King <rmk+kernel@armlinux.org.uk>
Add a CEC driver for the TDA9950, which is a stand-alone I2C CEC device.
The TDA9950 contains a command processor which handles retransmissions
and the low level bus protocol. The driver just has to read and write
the messages, and handle error conditions.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/gpu/drm/i2c/Kconfig | 5 +
drivers/gpu/drm/i2c/Makefile | 1 +
drivers/gpu/drm/i2c/tda9950.c | 516 ++++++++++++++++++++++++++++++++++
include/linux/platform_data/tda9950.h | 15 +
4 files changed, 537 insertions(+)
create mode 100644 drivers/gpu/drm/i2c/tda9950.c
create mode 100644 include/linux/platform_data/tda9950.h
diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig
index a6c92be..b30ea3b 100644
--- a/drivers/gpu/drm/i2c/Kconfig
+++ b/drivers/gpu/drm/i2c/Kconfig
@@ -26,4 +26,9 @@ config DRM_I2C_NXP_TDA998X
help
Support for NXP Semiconductors TDA998X HDMI encoders.
+config DRM_I2C_NXP_TDA9950
+ tristate "NXP Semiconductors TDA9950/TDA998X HDMI CEC"
+ depends on MEDIA_CEC_SUPPORT
+ select HDMI_NOTIFIERS
+
endmenu
diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile
index 43aa33b..8a6e13e 100644
--- a/drivers/gpu/drm/i2c/Makefile
+++ b/drivers/gpu/drm/i2c/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_DRM_I2C_SIL164) += sil164.o
tda998x-y := tda998x_drv.o
obj-$(CONFIG_DRM_I2C_NXP_TDA998X) += tda998x.o
+obj-$(CONFIG_DRM_I2C_NXP_TDA9950) += tda9950.o
diff --git a/drivers/gpu/drm/i2c/tda9950.c b/drivers/gpu/drm/i2c/tda9950.c
new file mode 100644
index 0000000..601da7c
--- /dev/null
+++ b/drivers/gpu/drm/i2c/tda9950.c
@@ -0,0 +1,516 @@
+/*
+ * TDA9950 Consumer Electronics Control driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The NXP TDA9950 implements the HDMI Consumer Electronics Control
+ * interface. The host interface is similar to a mailbox: the data
+ * registers starting at REG_CDR0 are written to send a command to the
+ * internal CPU, and replies are read from these registers.
+ *
+ * As the data registers represent a mailbox, they must be accessed
+ * as a single I2C transaction. See the TDA9950 data sheet for details.
+ */
+#include <linux/delay.h>
+#include <linux/hdmi-notifier.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/platform_data/tda9950.h>
+#include <linux/slab.h>
+#include <drm/drm_edid.h>
+#include <media/cec.h>
+
+enum {
+ REG_CSR = 0x00,
+ CSR_BUSY = BIT(7),
+ CSR_INT = BIT(6),
+ CSR_ERR = BIT(5),
+
+ REG_CER = 0x01,
+
+ REG_CVR = 0x02,
+
+ REG_CCR = 0x03,
+ CCR_RESET = BIT(7),
+ CCR_ON = BIT(6),
+
+ REG_ACKH = 0x04,
+ REG_ACKL = 0x05,
+
+ REG_CCONR = 0x06,
+ CCONR_ENABLE_ERROR = BIT(4),
+
+ REG_CDR0 = 0x07,
+
+ CDR1_REQ = 0x00,
+ CDR1_CNF = 0x01,
+ CDR1_IND = 0x81,
+ CDR1_ERR = 0x82,
+ CDR1_IER = 0x83,
+
+ CDR2_CNF_SUCCESS = 0x00,
+ CDR2_CNF_OFF_STATE = 0x80,
+ CDR2_CNF_BAD_REQ = 0x81,
+ CDR2_CNF_CEC_ACCESS = 0x82,
+ CDR2_CNF_ARB_ERROR = 0x83,
+ CDR2_CNF_BAD_TIMING = 0x84,
+ CDR2_CNF_NACK_ADDR = 0x85,
+ CDR2_CNF_NACK_DATA = 0x86,
+};
+
+struct tda9950_priv {
+ struct i2c_client *client;
+ struct device *hdmi;
+ struct cec_adapter *adap;
+ struct tda9950_glue *glue;
+ u16 addresses;
+ struct cec_msg rx_msg;
+ struct hdmi_notifier *n;
+ struct notifier_block nb;
+ bool open;
+};
+
+static int tda9950_write_range(struct i2c_client *client, u8 addr, u8 *p, int cnt)
+{
+ struct i2c_msg msg;
+ u8 buf[cnt + 1];
+ int ret;
+
+ buf[0] = addr;
+ memcpy(buf + 1, p, cnt);
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = cnt + 1;
+ msg.buf = buf;
+
+ dev_dbg(&client->dev, "wr 0x%02x: %*ph\n", addr, cnt, p);
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret < 0)
+ dev_err(&client->dev, "Error %d writing to cec:0x%x\n", ret, addr);
+ return ret < 0 ? ret : 0;
+}
+
+static void tda9950_write(struct i2c_client *client, u8 addr, u8 val)
+{
+ tda9950_write_range(client, addr, &val, 1);
+}
+
+static int tda9950_read_range(struct i2c_client *client, u8 addr, u8 *p, int cnt)
+{
+ struct i2c_msg msg[2];
+ int ret;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = &addr;
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = cnt;
+ msg[1].buf = p;
+
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret < 0)
+ dev_err(&client->dev, "Error %d reading from cec:0x%x\n", ret, addr);
+
+ dev_dbg(&client->dev, "rd 0x%02x: %*ph\n", addr, cnt, p);
+
+ return ret;
+}
+
+static u8 tda9950_read(struct i2c_client *client, u8 addr)
+{
+ int ret;
+ u8 val;
+
+ ret = tda9950_read_range(client, addr, &val, 1);
+ if (ret < 0)
+ val = 0;
+
+ return val;
+}
+
+static irqreturn_t tda9950_irq(int irq, void *data)
+{
+ struct tda9950_priv *priv = data;
+ unsigned int tx_status;
+ u8 csr, buf[19];
+
+ if (!priv->open)
+ return IRQ_NONE;
+
+ csr = tda9950_read(priv->client, REG_CSR);
+ if (!(csr & CSR_INT))
+ return IRQ_NONE;
+
+ tda9950_read_range(priv->client, REG_CDR0, buf, sizeof(buf));
+
+ /*
+ * This should never happen: the data sheet says that there will
+ * always be a valid message if the interrupt line is asserted.
+ */
+ if (buf[0] == 0) {
+ dev_warn(&priv->client->dev, "interrupt pending, but no message?\n");
+ return IRQ_NONE;
+ }
+
+ switch (buf[1]) {
+ case CDR1_CNF: /* transmit result */
+ switch (buf[2]) {
+ case CDR2_CNF_SUCCESS:
+ tx_status = CEC_TX_STATUS_OK;
+ break;
+
+ case CDR2_CNF_NACK_ADDR:
+ tx_status = CEC_TX_STATUS_NACK;
+ break;
+
+ default: /* some other error, refer to TDA9950 docs */
+ dev_err(&priv->client->dev, "CNF reply error 0x%02x\n",
+ buf[2]);
+ tx_status = CEC_TX_STATUS_ERROR;
+ break;
+ }
+ cec_transmit_done(priv->adap, tx_status, 0, 0, 0, 0);
+ break;
+
+ case CDR1_IND:
+ priv->rx_msg.len = buf[0] - 2;
+ memcpy(priv->rx_msg.msg, buf + 2, priv->rx_msg.len);
+ cec_received_msg(priv->adap, &priv->rx_msg);
+ break;
+
+ default: /* unknown */
+ dev_err(&priv->client->dev, "unknown service id 0x%02x\n",
+ buf[1]);
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int tda9950_cec_transmit(struct cec_adapter *adap, u8 attempts,
+ u32 signal_free_time, struct cec_msg *msg)
+{
+ struct tda9950_priv *priv = adap->priv;
+ u8 buf[16 + 2];
+
+ buf[0] = 2 + msg->len;
+ buf[1] = CDR1_REQ;
+ memcpy(buf + 2, msg->msg, msg->len);
+
+ return tda9950_write_range(priv->client, REG_CDR0, buf, 2 + msg->len);
+}
+
+static int tda9950_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)
+{
+ struct tda9950_priv *priv = adap->priv;
+ u16 addresses;
+ u8 buf[2];
+
+ if (addr == CEC_LOG_ADDR_INVALID)
+ addresses = priv->addresses = BIT(15);
+ else
+ addresses = priv->addresses |= BIT(addr);
+
+ /* TDA9950 doesn't want address 15 set */
+ addr &= 0x7fff;
+ buf[0] = addresses >> 8;
+ buf[1] = addresses;
+
+ return tda9950_write_range(priv->client, REG_ACKH, buf, 2);
+}
+
+/*
+ * When operating as part of the TDA998x, we need additional handling
+ * to initialise and shut down the TDA9950 part of the device. These
+ * two hooks are provided to allow the TDA998x code to perform those
+ * activities.
+ */
+static int tda9950_glue_open(struct tda9950_priv *priv)
+{
+ int ret = 0;
+
+ if (priv->glue && priv->glue->open)
+ ret = priv->glue->open(priv->glue->data);
+
+ priv->open = true;
+
+ return ret;
+}
+
+static void tda9950_glue_release(struct tda9950_priv *priv)
+{
+ priv->open = false;
+
+ if (priv->glue && priv->glue->release)
+ priv->glue->release(priv->glue->data);
+}
+
+static int tda9950_open(struct tda9950_priv *priv)
+{
+ struct i2c_client *client = priv->client;
+ int ret;
+
+ ret = tda9950_glue_open(priv);
+ if (ret)
+ return ret;
+
+ /* Reset the TDA9950, and wait 250ms for it to recover */
+ tda9950_write(client, REG_CCR, CCR_RESET);
+ msleep(250);
+
+ /* Configure for the standard 5 retries */
+ tda9950_write(client, REG_CCONR, 5);
+ tda9950_cec_adap_log_addr(priv->adap, CEC_LOG_ADDR_INVALID);
+
+ /* Start the command processor */
+ tda9950_write(client, REG_CCR, CCR_ON);
+
+ return 0;
+}
+
+static void tda9950_release(struct tda9950_priv *priv)
+{
+ struct i2c_client *client = priv->client;
+ int timeout = 50;
+ u8 csr;
+
+ /* Stop the command processor */
+ tda9950_write(client, REG_CCR, 0);
+
+ /* Wait up to .5s for it to signal non-busy */
+ do {
+ csr = tda9950_read(client, REG_CSR);
+ if (!(csr & CSR_BUSY) || --timeout)
+ break;
+ msleep(10);
+ } while (1);
+
+ /* Warn the user that their IRQ may die if it's shared. */
+ if (csr & CSR_BUSY)
+ dev_warn(&client->dev, "command processor failed to stop, irq%d may die (csr=0x%02x)\n",
+ client->irq, csr);
+
+ tda9950_glue_release(priv);
+}
+
+static int tda9950_cec_adap_enable(struct cec_adapter *adap, bool enable)
+{
+ struct tda9950_priv *priv = adap->priv;
+
+ if (!enable) {
+ tda9950_release(priv);
+ return 0;
+ } else {
+ return tda9950_open(priv);
+ }
+}
+
+static const struct cec_adap_ops tda9950_cec_ops = {
+ .adap_enable = tda9950_cec_adap_enable,
+ .adap_log_addr = tda9950_cec_adap_log_addr,
+ .adap_transmit = tda9950_cec_transmit,
+};
+
+static unsigned int parse_hdmi_addr(const struct edid *edid)
+{
+ if (!edid || edid->extensions == 0)
+ return (u16)~0;
+
+ return cec_get_edid_phys_addr((u8 *)edid,
+ EDID_LENGTH * (edid->extensions + 1), NULL);
+}
+
+static int tda9950_cec_notify(struct notifier_block *nb, unsigned long event,
+ void *data)
+{
+ struct tda9950_priv *priv = container_of(nb, struct tda9950_priv, nb);
+ struct hdmi_notifier *n = data;
+ unsigned int phys;
+
+ switch (event) {
+ case HDMI_DISCONNECTED:
+ cec_s_phys_addr(priv->adap, CEC_PHYS_ADDR_INVALID, false);
+ break;
+
+ case HDMI_NEW_EDID:
+ phys = parse_hdmi_addr(n->edid);
+ cec_s_phys_addr(priv->adap, phys, false);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+/*
+ * When operating as part of the TDA998x, we need to claim additional
+ * resources. These two hooks permit the management of those resources.
+ */
+static void tda9950_devm_glue_exit(void *data)
+{
+ struct tda9950_glue *glue = data;
+
+ if (glue && glue->exit)
+ glue->exit(glue->data);
+}
+
+static int tda9950_devm_glue_init(struct device *dev, struct tda9950_glue *glue)
+{
+ int ret;
+
+ if (glue && glue->init) {
+ ret = glue->init(glue->data);
+ if (ret)
+ return ret;
+ }
+
+ ret = devm_add_action(dev, tda9950_devm_glue_exit, glue);
+ if (ret)
+ tda9950_devm_glue_exit(glue);
+
+ return ret;
+}
+
+static void tda9950_cec_del(void *data)
+{
+ struct tda9950_priv *priv = data;
+
+ cec_delete_adapter(priv->adap);
+}
+
+static int tda9950_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct tda9950_glue *glue = client->dev.platform_data;
+ struct device *dev = &client->dev;
+ struct tda9950_priv *priv;
+ int ret;
+ u8 cvr;
+
+ /*
+ * We must have I2C functionality: our multi-byte accesses
+ * must be performed as a single contiguous transaction.
+ */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev,
+ "adapter does not support I2C functionality\n");
+ return -ENXIO;
+ }
+
+ /* We must have an interrupt to be functional. */
+ if (client->irq <= 0) {
+ dev_err(&client->dev, "driver requires an interrupt\n");
+ return -ENXIO;
+ }
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->client = client;
+ priv->glue = glue;
+ priv->nb.notifier_call = tda9950_cec_notify;
+
+ i2c_set_clientdata(client, priv);
+
+ /*
+ * If we're part of a TDA998x, we want the class devices to be
+ * associated with the HDMI Tx so we have a tight relationship
+ * between the HDMI interface and the CEC interface.
+ */
+ priv->hdmi = dev;
+ if (glue && glue->parent)
+ priv->hdmi = glue->parent;
+
+ priv->adap = cec_allocate_adapter(&tda9950_cec_ops, priv, "tda9950",
+ CEC_CAP_LOG_ADDRS |
+ CEC_CAP_TRANSMIT | CEC_CAP_RC,
+ CEC_MAX_LOG_ADDRS, priv->hdmi);
+ if (IS_ERR(priv->adap))
+ return PTR_ERR(priv->adap);
+
+ ret = devm_add_action(dev, tda9950_cec_del, priv);
+ if (ret) {
+ cec_delete_adapter(priv->adap);
+ return ret;
+ }
+
+ ret = tda9950_devm_glue_init(dev, glue);
+ if (ret)
+ return ret;
+
+ ret = tda9950_glue_open(priv);
+ if (ret)
+ return ret;
+
+ cvr = tda9950_read(client, REG_CVR);
+
+ dev_info(&client->dev,
+ "TDA9950 CEC interface, hardware version %u.%u\n",
+ cvr >> 4, cvr & 15);
+
+ tda9950_glue_release(priv);
+
+ ret = devm_request_threaded_irq(dev, client->irq, NULL, tda9950_irq,
+ IRQF_TRIGGER_FALLING | IRQF_SHARED |
+ IRQF_ONESHOT,
+ dev_name(&client->dev), priv);
+ if (ret < 0)
+ return ret;
+
+ ret = cec_register_adapter(priv->adap);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * CEC documentation says we must not call cec_delete_adapter
+ * after a successful call to cec_register_adapter().
+ */
+ devm_remove_action(dev, tda9950_cec_del, priv);
+
+ priv->n = hdmi_notifier_get(priv->hdmi);
+ if (!priv->n)
+ return -ENOMEM;
+ hdmi_notifier_register(priv->n, &priv->nb);
+
+ return ret;
+}
+
+static int tda9950_remove(struct i2c_client *client)
+{
+ struct tda9950_priv *priv = i2c_get_clientdata(client);
+
+ hdmi_notifier_unregister(priv->n, &priv->nb);
+ hdmi_notifier_put(priv->n);
+ cec_unregister_adapter(priv->adap);
+
+ return 0;
+}
+
+static struct i2c_device_id tda9950_ids[] = {
+ { "tda9950", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, tda9950_ids);
+
+static struct i2c_driver tda9950_driver = {
+ .probe = tda9950_probe,
+ .remove = tda9950_remove,
+ .driver = {
+ .name = "tda9950",
+ },
+ .id_table = tda9950_ids,
+};
+
+module_i2c_driver(tda9950_driver);
+
+MODULE_AUTHOR("Russell King <rmk+kernel@armlinux.org.uk>");
+MODULE_DESCRIPTION("TDA9950/TDA998x Consumer Electronics Control Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/platform_data/tda9950.h b/include/linux/platform_data/tda9950.h
new file mode 100644
index 0000000..08da9c9
--- /dev/null
+++ b/include/linux/platform_data/tda9950.h
@@ -0,0 +1,15 @@
+#ifndef LINUX_PLATFORM_DATA_TDA9950_H
+#define LINUX_PLATFORM_DATA_TDA9950_H
+
+struct device;
+
+struct tda9950_glue {
+ struct device *parent;
+ void *data;
+ int (*init)(void *);
+ void (*exit)(void *);
+ int (*open)(void *);
+ void (*release)(void *);
+};
+
+#endif
--
2.8.1
^ permalink raw reply related
* [PATCH v2 1/9] arm64: dts: rockchip: add eMMC's power domain support for rk3399
From: Heiko Stuebner @ 2016-11-14 15:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5829D1C7.9020105@rock-chips.com>
Am Montag, 14. November 2016, 23:01:27 CET schrieb Caesar Wang:
> On 2016?11?14? 22:45, Heiko Stuebner wrote:
> > Am Mittwoch, 9. November 2016, 21:21:53 CET schrieb Caesar Wang:
> >> From: Ziyuan Xu <xzy.xu@rock-chips.com>
> >>
> >> Control power domain for eMMC via genpd to reduce power consumption.
> >>
> >> Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
> >> Signed-off-by: Ziyuan Xu <xzy.xu@rock-chips.com>
> >> Signed-off-by: Caesar Wang <wxt@rock-chips.com>
> >
> > Authorship / Signed-off mismatch. From above suggest Ziyuan is the author
> > while first Signed-off-by indicates Elaine as author. Please clarify.
>
> I believe the Elaine is the first author. Sorry for this kind of
> question to brother you again. :(
no problem :-) and thanks for the very fast reply.
Applied to my dts64 branch.
Thanks
Heiko
^ permalink raw reply
* [PATCH] arm64: dts: juno: fix cluster sleep state entry latency on all SoC versions
From: Sudeep Holla @ 2016-11-14 15:26 UTC (permalink / raw)
To: linux-arm-kernel
The core and the cluster sleep state entry latencies can't be same as
cluster sleep involves more work compared to core level e.g. shared
cache maintenance.
Experiments have shown on an average about 100us more latency for the
cluster sleep state compared to the core level sleep. This patch fixes
the entry latency for the cluster sleep state.
Fixes: 28e10a8f3a03 ("arm64: dts: juno: Add idle-states to device tree")
Cc: Liviu Dudau <liviu.dudau@arm.com>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: "Jon Medhurst (Tixy)" <tixy@linaro.org>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
---
arch/arm64/boot/dts/arm/juno-r1.dts | 2 +-
arch/arm64/boot/dts/arm/juno-r2.dts | 2 +-
arch/arm64/boot/dts/arm/juno.dts | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
Hi,
This was found recently when I found that core sleep was chosen when
entering suspend-to-idle state on Juno. Since the wakeup(entry+exit)
latency matched for the both states, cpu sleep state was chosen to enter
in suspend-to-idle.
Regards,
Sudeep
diff --git a/arch/arm64/boot/dts/arm/juno-r1.dts b/arch/arm64/boot/dts/arm/juno-r1.dts
index 3be8a3ef671c..eec37feee8fc 100644
--- a/arch/arm64/boot/dts/arm/juno-r1.dts
+++ b/arch/arm64/boot/dts/arm/juno-r1.dts
@@ -76,7 +76,7 @@
compatible = "arm,idle-state";
arm,psci-suspend-param = <0x1010000>;
local-timer-stop;
- entry-latency-us = <300>;
+ entry-latency-us = <400>;
exit-latency-us = <1200>;
min-residency-us = <2500>;
};
diff --git a/arch/arm64/boot/dts/arm/juno-r2.dts b/arch/arm64/boot/dts/arm/juno-r2.dts
index 614fc9227943..28f40ec44090 100644
--- a/arch/arm64/boot/dts/arm/juno-r2.dts
+++ b/arch/arm64/boot/dts/arm/juno-r2.dts
@@ -76,7 +76,7 @@
compatible = "arm,idle-state";
arm,psci-suspend-param = <0x1010000>;
local-timer-stop;
- entry-latency-us = <300>;
+ entry-latency-us = <400>;
exit-latency-us = <1200>;
min-residency-us = <2500>;
};
diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts
index 6b4135e9cfe5..ac5ceb73f45f 100644
--- a/arch/arm64/boot/dts/arm/juno.dts
+++ b/arch/arm64/boot/dts/arm/juno.dts
@@ -76,7 +76,7 @@
compatible = "arm,idle-state";
arm,psci-suspend-param = <0x1010000>;
local-timer-stop;
- entry-latency-us = <300>;
+ entry-latency-us = <400>;
exit-latency-us = <1200>;
min-residency-us = <2500>;
};
--
2.7.4
^ permalink raw reply related
* [PATCH v2 2/9] arm64: dts: rockchip: add pd_sd power node for rk3399
From: Heiko Stuebner @ 2016-11-14 15:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478697721-2323-3-git-send-email-wxt@rock-chips.com>
Am Mittwoch, 9. November 2016, 21:21:54 CET schrieb Caesar Wang:
> From: zhangqing <zhangqing@rock-chips.com>
>
> 1.add pd node for RK3399 Soc
> 2.create power domain tree
> 3.add qos node for domain
> 4.add the pd_sd consumers node
>
> Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
> Signed-off-by: Caesar Wang <wxt@rock-chips.com>
Applied to my dts64 branch after some tweaks to patch subject and commit
message.
Thanks
Heiko
^ permalink raw reply
* [PATCH RESEND] spi: atmel: Fix scheduling while atomic
From: Alexandre Belloni @ 2016-11-14 15:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479136400-10285-1-git-send-email-ben.whitten@lairdtech.com>
On 14/11/2016 at 15:13:20 +0000, Ben Whitten wrote :
> A call to clk_get_rate appears to be called in the context of an interrupt,
> cache the bus clock for the frequency calculations in transmission.
>
> This fixes a 'BUG: scheduling while atomic' and
> 'WARNING: CPU: 0 PID: 777 at kernel/sched/core.c:2960 atmel_spi_unlock'
>
> Signed-off-by: Ben Whitten <ben.whitten@lairdtech.com>
> Signed-off-by: Steve deRosier <steve.derosier@lairdtech.com>
Acked-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
> ---
>
> Resending due to missing off the subsystem maintainer in initial submission,
> pointed out by Alexandre Belloni, thanks.
>
> ---
> drivers/spi/spi-atmel.c | 6 +++++-
> 1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
> index 8feac59..c281d1a 100644
> --- a/drivers/spi/spi-atmel.c
> +++ b/drivers/spi/spi-atmel.c
> @@ -295,6 +295,7 @@ struct atmel_spi {
> int irq;
> struct clk *clk;
> struct platform_device *pdev;
> + unsigned long spi_clk;
>
> struct spi_transfer *current_transfer;
> int current_remaining_bytes;
> @@ -864,7 +865,7 @@ static int atmel_spi_set_xfer_speed(struct atmel_spi *as,
> unsigned long bus_hz;
>
> /* v1 chips start out at half the peripheral bus speed. */
> - bus_hz = clk_get_rate(as->clk);
> + bus_hz = as->spi_clk;
> if (!atmel_spi_is_v2(as))
> bus_hz /= 2;
>
> @@ -1606,6 +1607,9 @@ static int atmel_spi_probe(struct platform_device *pdev)
> ret = clk_prepare_enable(clk);
> if (ret)
> goto out_free_irq;
> +
> + as->spi_clk = clk_get_rate(clk);
> +
> spi_writel(as, CR, SPI_BIT(SWRST));
> spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
> if (as->caps.has_wdrbt) {
> --
> 2.7.4
>
--
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* [RFC v2 8/8] iommu/arm-smmu: implement add_reserved_regions callback
From: Joerg Roedel @ 2016-11-14 15:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <634ac375-3507-6926-164f-e67f7c798c98@redhat.com>
Hi Eric,
On Fri, Nov 11, 2016 at 05:45:19PM +0100, Auger Eric wrote:
> On 11/11/2016 17:22, Joerg Roedel wrote:
> > So I think we need a way to tell userspace about the reserved regions
> > (per iommu-group) so that userspace knows where it can not map anything,
> Current plan is to expose that info through an iommu-group sysfs
> attribute, as you and Robin advised.
Great.
> > and VFIO can enforce that. But the right struct here is not an
> > iova-allocator rb-tree, a ordered linked list should be sufficient.
> I plan a linked list to store the reserved regions (P2P regions, MSI
> region, ...). get_dma_regions is called with a list local to a function
> for that. Might be needed to move that list head in the iommu_group to
> avoid calling the get_dm_regions again in the attribute show function?
You can re-use the get_dm_regions() call-back available in the iommu-ops
already. Just rename it and add a flag to it which tells the iommu-core
whether that region needs to be mapped or not.
> But to allocate the IOVAs within the MSI reserved region, I understand
> you don't want us to use the iova.c allocator, is that correct? We need
> an allocator though, even a very basic one based on bitmap or whatever.
> There potentially have several different physical MSI frame pages to map.
I don't get this, what do you need and address-allocator for?
Joerg
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox