* [PATCH 0/5] SMP support for Armada XP
From: Gregory CLEMENT @ 2012-10-22 17:02 UTC (permalink / raw)
To: linux-arm-kernel
Hello,
The purpose of this patch set is to add the SMP support for the Armada
XP SoCs. Beside the SMP support itself brought by the last 3 patches,
this patch set also adds the support for the coherency fabric unit and
the power management service unit.
The coherency fabric is responsible for ensuring hardware coherency
between all CPUs and between CPUs and I/O masters. This unit is also
available for Armada 370 and will be used in an incoming patch set
for hardware I/O cache coherency.
The power management service unit is responsible for powering down and
waking up CPUs and other SOC units.
The original code is from Yehuda Yitschak, it was reworked by myself
and reviewed by Yehuda.
This patch set is based on 3.7-rc2 and depends one the framework clock
support (the last version was posted last week:
http://thread.gmane.org/gmane.linux.kernel/1375701). The git branch
called ArmadaXP-SMP-for-3.8 is also available at
https://github.com/MISL-EBU-System-SW/mainline-public.git.
Regards,
Yehuda Yitschak (5):
arm: mvebu: Added support for coherency fabric in mach-mvebu
arm: mvebu: Added initial support for power managmement service unit
arm: mvebu: Added IPI support via doorbells
arm: mm: Added support for PJ4B cpu and init routines
arm: mvebu: Added SMP support for Armada XP
.../devicetree/bindings/arm/armada-370-xp-pmsu.txt | 20 ++++
.../devicetree/bindings/arm/coherency-fabric.txt | 16 +++
arch/arm/boot/dts/armada-370-xp.dtsi | 5 +
arch/arm/boot/dts/armada-xp.dtsi | 12 +-
arch/arm/configs/mvebu_defconfig | 3 +
arch/arm/mach-mvebu/Kconfig | 3 +-
arch/arm/mach-mvebu/Makefile | 4 +-
arch/arm/mach-mvebu/armada-370-xp.c | 1 +
arch/arm/mach-mvebu/armada-370-xp.h | 10 ++
arch/arm/mach-mvebu/coherency.c | 92 +++++++++++++++
arch/arm/mach-mvebu/coherency.h | 20 ++++
arch/arm/mach-mvebu/common.h | 6 +
arch/arm/mach-mvebu/headsmp.S | 65 +++++++++++
arch/arm/mach-mvebu/hotplug.c | 30 +++++
arch/arm/mach-mvebu/irq-armada-370-xp.c | 92 ++++++++++++++-
arch/arm/mach-mvebu/platsmp.c | 123 ++++++++++++++++++++
arch/arm/mach-mvebu/pmsu.c | 78 +++++++++++++
arch/arm/mach-mvebu/pmsu.h | 16 +++
arch/arm/mm/Kconfig | 4 +
arch/arm/mm/proc-v7.S | 46 ++++++++
20 files changed, 637 insertions(+), 9 deletions(-)
create mode 100644 Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt
create mode 100644 Documentation/devicetree/bindings/arm/coherency-fabric.txt
create mode 100644 arch/arm/mach-mvebu/coherency.c
create mode 100644 arch/arm/mach-mvebu/coherency.h
create mode 100644 arch/arm/mach-mvebu/headsmp.S
create mode 100644 arch/arm/mach-mvebu/hotplug.c
create mode 100644 arch/arm/mach-mvebu/platsmp.c
create mode 100644 arch/arm/mach-mvebu/pmsu.c
create mode 100644 arch/arm/mach-mvebu/pmsu.h
--
1.7.9.5
^ permalink raw reply
* RT throttling and suspend/resume (was Re: [PATCH] i2c: omap: revert "i2c: omap: switch to threaded IRQ support")
From: Kevin Hilman @ 2012-10-22 16:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350899541.2768.82.camel@twins>
Peter Zijlstra <peterz@infradead.org> writes:
> On Fri, 2012-10-19 at 16:54 -0700, Kevin Hilman wrote:
>
>> So I did the same thing for my ARM SoC, and it definitley stops the RT
>> throttling.
>>
>> However, it has the undesriable (IMO) side effect of making timed printk
>> output rather unhelpful for debugging suspend/resume since printk time
>> stays constant throughout suspend/resume no matter how long you
>> sleep. :(
>>
>> So does that mean we have to choose between useful printk times during
>> suspend/resume or functioning IRQ threads during suspend/resume ?
>
> Urgh.. this was not something I considered. This being primarily the
> sched_clock infrastructure and such.
>
> So what exactly is the problem with the suspend resume thing (its not
> something I've ever debugged), is all you need a clean break between pre
> and post suspend, or do you need the actual time the machine was gone?
I think it's more a question of what people are used to. I think folks
used to debugging suspend/resume (at least on ARM) are used to having
the printk timestamps reflect the amount of time the machine was gone.
With a sched_clock() that counts during suspend, that feature doesn't
work anymore. I'm not sure that this feature is a deal breaker, but it
has been convenient. I see that on x86, it's already normal that
printk times don't reflect time spent in suspend, so I guess ARM needs
to adapt.
Kevin
^ permalink raw reply
* OMAP baseline test results for v3.7-rc2
From: Tony Lindgren @ 2012-10-22 16:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <50857444.9080308@ti.com>
* Jon Hunter <jon-hunter@ti.com> [121022 09:30]:
> On 10/20/2012 04:26 PM, Paul Walmsley wrote:
> >
> > * 2430sdp: vfp_reload_hw oops during MMC initialization
> > - Kernel attempts to save FP registers that don't exist; fix posted:
> > - http://www.spinics.net/lists/arm-kernel/msg200646.html
Has that one been posted to RMK's patch system?
> > * AM335x Beaglebone: omap2plus_defconfig kernels don't boot
> > - due to a GPMC bug
> > - Apparently fixed by http://www.spinics.net/lists/arm-kernel/msg200787.html
>
> This is now addressed and I have verified it is booting on v3.7-rc2. The
> following patch address this boot problem ...
>
> http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=8119024ef7363591fd958ec89ebfaee7c18209e3
That's in v3.7-rc2 already, is there some other problem too?
Regards,
Tony
^ permalink raw reply
* Retry writes on MMC/SD
From: Marco Lazzaroni @ 2012-10-22 16:33 UTC (permalink / raw)
To: linux-arm-kernel
Hello,
because of an unreliable hardware, writes to a SD Card fail every now
and then, and I get error -84 (EILSEQ).
Is there a way to retry writing a sector if it fails? Is there a number
of retries to set somewhere? If not, how could this be implemented?
Thanks.
Best regards,
Marco Lazzaroni
^ permalink raw reply
* OMAP baseline test results for v3.7-rc2
From: Jon Hunter @ 2012-10-22 16:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.00.1210202125300.774@utopia.booyaka.com>
Hi Paul,
On 10/20/2012 04:26 PM, Paul Walmsley wrote:
>
> Here are some basic OMAP test results for Linux v3.7-rc2.
> Logs and other details at:
>
> http://www.pwsan.com/omap/testlogs/test_v3.7-rc2/20121020134755/
>
>
> Passing tests
> -------------
>
> Boot to userspace: 3517evm, 3530es3beagle, 3730beaglexm, 37xxevm,
> 4430es2panda, 5912osk, am335xbone
>
> PM ret/off, suspend + dynamic idle: (none)
>
>
> Failing tests: fixed by posted patches
> --------------------------------------
>
> Boot tests:
>
> * 2430sdp: vfp_reload_hw oops during MMC initialization
> - Kernel attempts to save FP registers that don't exist; fix posted:
> - http://www.spinics.net/lists/arm-kernel/msg200646.html
>
> * 2420n800: boot hangs during UART initialization
> - http://lkml.org/lkml/2012/9/11/454
> - Apparently fixed by http://marc.info/?l=linux-omap&m=135068547918479&w=2
>
> * AM335x Beaglebone: omap2plus_defconfig kernels don't boot
> - due to a GPMC bug
> - Apparently fixed by http://www.spinics.net/lists/arm-kernel/msg200787.html
This is now addressed and I have verified it is booting on v3.7-rc2. The
following patch address this boot problem ...
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=8119024ef7363591fd958ec89ebfaee7c18209e3
> Other:
>
> * 2420N800: powers down 30 seconds after boot
> - Presumably due to missing CBUS patches for watchdog control
> - http://lkml.org/lkml/2012/9/3/265
>
> * 4430es2panda: omap_hwmod: mcpdm: cannot be enabled for reset (3)
> - clock source is from an external I2C-controlled source
> - must skip reset until the switchover to hwmod late init
> - http://www.spinics.net/lists/arm-kernel/msg178138.html
>
>
> Failing tests: needing investigation
> ------------------------------------
>
> Boot tests:
>
> * CM-T3517: L3 in-band error with IPSS during boot
> - Cause unknown but see http://marc.info/?l=linux-omap&m=134833869730129&w=2
> - Longstanding issue; does not occur on the 3517EVM
>
> * 3517EVM & CM-T3517: boot hangs with NFS root
> - Likely some Kconfig, board file, and PM issues with EMAC
>
> * CM-T3517: boot hangs with MMC boot
> - Due to missing MMC setup in board file
>
> * 4460pandaes: boot fails early
> - Appears to be timer-related
I tried v3.7-rc2 on my pandaES and it is booting fine for me.
I have an OMAP4460 ES1.1 and u-boot release 2012.10.
I don't wish to create more work for you, but it could be good to add
silicon revision, u-boot release (if applicable) and toolchain used for
any failures.
Cheers
Jon
^ permalink raw reply
* [PATCH V3 3/5] ARM: tegra: decouple uncompress.h and debug-macro.S
From: Stephen Warren @ 2012-10-22 16:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121022081830.GH3196@tbergstrom-lnx.Nvidia.com>
On 10/22/2012 02:18 AM, Peter De Schrijver wrote:
>> +
>> +#define checkuart(rp, rv, lhu, bit, uart) \
>> + /* Load address of CLK_RST register */ \
>> + movw rp, #TEGRA_CLK_RST_DEVICES_##lhu & 0xffff ; \
>> + movt rp, #TEGRA_CLK_RST_DEVICES_##lhu >> 16 ; \
>> + /* Load value from CLK_RST register */ \
>> + ldr rp, [rp, #0] ; \
>> + /* Test UART's reset bit */ \
>> + tst rp, #(1 << bit) ; \
>> + /* If set, can't use UART; jump to save no UART */ \
>> + bne 90f ; \
>> + /* Load address of CLK_OUT_ENB register */ \
>> + movw rp, #TEGRA_CLK_OUT_ENB_##lhu & 0xffff ; \
>> + movt rp, #TEGRA_CLK_OUT_ENB_##lhu >> 16 ; \
>> + /* Load value from CLK_OUT_ENB register */ \
>> + ldr rp, [rp, #0] ; \
>> + /* Test UART's clock enable bit */ \
>> + tst rp, #(1 << bit) ; \
>> + /* If clear, can't use UART; jump to save no UART */ \
>> + beq 90f ; \
>> + /* Passed all tests, load address of UART registers */ \
>> + movw rp, #TEGRA_UART##uart##_BASE & 0xffff ; \
>> + movt rp, #TEGRA_UART##uart##_BASE >> 16 ; \
>> + /* Jump to save UART address */ \
>> + b 91f
>>
>
> Maybe make this a subroutine?
The addruart macro (which in turn uses the checkuart macro) is only
allowed to use 3 registers; rp, rv, rtmp. I'm also not 100% sure if the
stack is guaranteed to be set up when addruart is called either. So, I
don't think making this a function is possible.
^ permalink raw reply
* [PATCH] arm: dts: omap4-sdp: pinmux configuration for keypad
From: Tony Lindgren @ 2012-10-22 16:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350890955-29553-1-git-send-email-sourav.poddar@ti.com>
* Sourav Poddar <sourav.poddar@ti.com> [121022 00:30]:
> --- a/arch/arm/boot/dts/omap4-sdp.dts
> +++ b/arch/arm/boot/dts/omap4-sdp.dts
> @@ -194,6 +194,27 @@
> 0xbc 0x100 /* abe_mcbsp2_fsx.abe_mcbsp2_fsx INPUT | MODE0 */
> >;
> };
> +
> + keypad_pins: pinmux_keypad_pins {
> + pinctrl-single,pins = <
> + 0x24 0x4119 /* gpmc_a18.kpd_row6 OMAP_PULL_ENA | OMAP_PULL_UP | OMAP_WAKEUP_EN | OMAP_MUX_MODE1 | OMAP_INPUT_EN */
> + 0x26 0x4119 /* gpmc_a19.kpd_row6 OMAP_PULL_ENA | OMAP_PULL_UP | OMAP_WAKEUP_EN | OMAP_MUX_MODE1 | OMAP_INPUT_EN */
> + 0x2c 0x4001 /* gpmc_a22.kpd_col6 OMAP_WAKEUP_EN | OMAP_MUX_MODE1 */
> + 0x2e 0x4001 /* gpmc_a23.kpd_col7 OMAP_WAKEUP_EN | OMAP_MUX_MODE1 */
> + 0x13c 0x4001 /* kpd_col0.kpd_col0 OMAP_WAKEUP_EN | OMAP_MUX_MODE1 */
> + 0x13e 0x4001 /* kpd_col1.kpd_col1 OMAP_WAKEUP_EN | OMAP_MUX_MODE1 */
> + 0x140 0x4001 /* kpd_col2.kpd_col2 OMAP_WAKEUP_EN | OMAP_MUX_MODE1 */
> + 0x142 0x10F /* kpd_col3.kpd_col3 OMAP_WAKEUP_EN | OMAP_MUX_MODE1 */
> + 0x144 0x4001 /* kpd_col4.kpd_col4 OMAP_WAKEUP_EN | OMAP_MUX_MODE1 */
> + 0x146 0x4001 /* kpd_col5.kpd_col5 OMAP_WAKEUP_EN | OMAP_MUX_MODE1 */
> + 0x148 0xc119 /* kpd_row0.kpd_row0 OMAP_PULL_ENA | OMAP_PULL_UP | OMAP_WAKEUP_EN | OMAP_MUX_MODE1 | OMAP_INPUT_EN */
> + 0x14a 0x4119 /* kpd_row1.kpd_row1 OMAP_PULL_ENA | OMAP_PULL_UP | OMAP_WAKEUP_EN | OMAP_MUX_MODE1 | OMAP_INPUT_EN */
> + 0x14c 0x4119 /* kpd_row2.kpd_row2 OMAP_PULL_ENA | OMAP_PULL_UP | OMAP_WAKEUP_EN | OMAP_MUX_MODE1 | OMAP_INPUT_EN */
> + 0x14e 0x4119 /* kpd_row3.kpd_row3 OMAP_PULL_ENA | OMAP_PULL_UP | OMAP_WAKEUP_EN | OMAP_MUX_MODE1 | OMAP_INPUT_EN */
> + 0x150 0x4119 /* kpd_row4.kpd_row4 OMAP_PULL_ENA | OMAP_PULL_UP | OMAP_WAKEUP_EN | OMAP_MUX_MODE1 | OMAP_INPUT_EN */
> + 0x152 0x4119 /* kpd_row5.kpd_row5 OMAP_PULL_ENA | OMAP_PULL_UP | OMAP_WAKEUP_EN | OMAP_MUX_MODE1 | OMAP_INPUT_EN */
> + >;
> + };
> };
Please shorten these to leave out OMAP_:
pinctrl-single,pins = <
0x24 0x4119 /* gpmc_a18.kpd_row6 PULL_ENA | PULL_UP | WAKEUP_EN | MUX_MODE1 | INPUT_EN */
0x26 0x4119 /* gpmc_a19.kpd_row6 PULL_ENA | PULL_UP | WAKEUP_EN | MUX_MODE1 | INPUT_EN */
...
When we convert them over to use the preprocessor, we can still
easily replace them.
Regards,
Tony
^ permalink raw reply
* [RFC] ARM: OMAP: hwmod: wait for sysreset complete after enabling hwmod
From: Tero Kristo @ 2012-10-22 16:15 UTC (permalink / raw)
To: linux-arm-kernel
When waking up from off-mode, some IP blocks are reset automatically by
hardware. For this reason, software must wait until the reset has
completed before attempting to access the IP block.
This patch fixes for example the bug introduced by commit
6c31b2150ff96755d24e0ab6d6fea08a7bf5c44c ("mmc: omap_hsmmc: remove access
to SYSCONFIG register"), in which the MMC IP block is reset during
off-mode entry, but the code expects the module to be already available
during the execution of context restore.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Cc: Paul Walmsley <paul@pwsan.com>
Cc: Benoit Cousson <b-cousson@ti.com>
Cc: Venkatraman S <svenkatr@ti.com>
---
arch/arm/mach-omap2/omap_hwmod.c | 22 ++++++++++++++++++++++
1 files changed, 22 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index b969ab1..523729b 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -1278,6 +1278,7 @@ static void _enable_sysc(struct omap_hwmod *oh)
u8 idlemode, sf;
u32 v;
bool clkdm_act;
+ int c;
if (!oh->class->sysc)
return;
@@ -1338,6 +1339,27 @@ static void _enable_sysc(struct omap_hwmod *oh)
_set_module_autoidle(oh, idlemode, &v);
_write_sysconfig(v, oh);
}
+
+ /*
+ * Wait until reset has completed, this is needed as the IP
+ * block is reset automatically by hardware in some cases
+ * (off-mode for example), and the drivers require the
+ * IP to be ready when they access it
+ */
+ if (sf & SYSS_HAS_RESET_STATUS)
+ omap_test_timeout((omap_hwmod_read(oh,
+ oh->class->sysc->syss_offs)
+ & SYSS_RESETDONE_MASK),
+ MAX_MODULE_SOFTRESET_WAIT, c);
+
+ if (sf & SYSC_HAS_RESET_STATUS) {
+ u32 softrst_mask =
+ (0x1 << oh->class->sysc->sysc_fields->srst_shift);
+ omap_test_timeout(!(omap_hwmod_read(oh,
+ oh->class->sysc->sysc_offs)
+ & softrst_mask),
+ MAX_MODULE_SOFTRESET_WAIT, c);
+ }
}
/**
--
1.7.4.1
^ permalink raw reply related
* OMAP baseline test results for v3.7-rc1
From: Tero Kristo @ 2012-10-22 16:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.00.1210201628420.24497@utopia.booyaka.com>
On Sat, 2012-10-20 at 17:20 +0000, Paul Walmsley wrote:
> Hello Venkatraman,
>
> On Thu, 18 Oct 2012, Paul Walmsley wrote:
>
> > Here are some basic OMAP test results for Linux v3.7-rc1.
> > Logs and other details at http://www.pwsan.com/omap/testlogs/test_v3.7-rc1/
>
> ...
>
> > Failing tests: needing investigation
> > ------------------------------------
>
> ...
>
> > PM tests:
> >
> > * 3530es3beagle: hangs during off-mode dynamic idle test
> > - Unknown cause; not investigated
>
> Looks like this commit is causing some of our power management tests to
> fail on v3.7-rc1:
>
> commit 6c31b2150ff96755d24e0ab6d6fea08a7bf5c44c
> Author: Venkatraman S <svenkatr@ti.com>
> Date: Wed Aug 8 14:26:52 2012 +0530
>
> mmc: omap_hsmmc: remove access to SYSCONFIG register
>
> ...
>
> The failure can be seen in the following test log:
>
> http://www.pwsan.com/omap/transcripts/20121020-3530es3beagle-off-mode-fail-pre-revert.txt
>
> and with commit 6c31b215 reverted, the test succeeds:
>
> http://www.pwsan.com/omap/transcripts/20121020-3530es3beagle-off-mode-fail-post-revert.txt
>
>
> Could you please take a look and fix the problem?
Root cause for this issue is that the MMC IP is reset during off-mode,
but the driver doesn't expect this in its current form. There are a
couple of alternative ways to fix this. Either add a reset timeout to
the MMC driver code (which was removed by the bisected patch), or
alternatively add a global reset check to the hwmod code. I'll send a
patch for the global reset purpose in a bit for commenting.
-Tero
^ permalink raw reply
* OMAP baseline test results for v3.7-rc1
From: Jean Pihet @ 2012-10-22 16:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.00.1210200611150.9865@utopia.booyaka.com>
Hi,
On Sat, Oct 20, 2012 at 8:14 AM, Paul Walmsley <paul@pwsan.com> wrote:
> Hi Jean
>
> On Fri, 19 Oct 2012, Paul Walmsley wrote:
>
>> On Thu, 18 Oct 2012, Paul Walmsley wrote:
>>
>> > Here are some basic OMAP test results for Linux v3.7-rc1.
>> > Logs and other details at http://www.pwsan.com/omap/testlogs/test_v3.7-rc1/
>
> ...
>
>> > Failing tests: needing investigation
>> > ------------------------------------
>> >
>> > Boot tests:
>>
>> * 3530ES3 Beagle: I2C timeouts during userspace init
>> - May be related to the threaded IRQ conversion of the I2C driver
>> - Unknown cause
>
> This one turned out to be caused by:
>
> commit 3db11feffc1ad2ab9dea27789e6b5b3032827adc
> Author: Jean Pihet <jean.pihet@newoldbits.com>
> Date: Thu Sep 20 18:08:03 2012 +0200
>
> ARM: OMAP: convert I2C driver to PM QoS for MPU latency constraints
>
>
> Reverting this commit causes the problem to go away, but since the OMAP PM
> constraint code was removed as well, it's unlikely that a simple revert is
> the right thing to do.
>
> Jean could you please investigate and fix this?
I tried the latest l-o with omap2plus defconfig on my Beagleboard B5
(ES2.1) and could not reproduce the problem.
I do not have the I2C error messages at boot, nor at user space start
up. I tried to read/write the TWL RTC, successfully.
Another difference is the bootloader images. I have the following:
- Texas Instruments X-Loader 1.4.2 (Feb 3 2009 - 15:34:17)
- U-Boot 2009.01-dirty (Feb 19 2009 - 12:22:31)
Could you send your bootloader images?
I noticed you have I2C error messages in U-Boot, could that be the
cause of the I2C lock-up?
On the PM QoS side the commit 3db11fef moves the I2C code from the
OMAP PM no-op layer to the PM QoS for CPU and DMA latency, which
influences the cpuidle states. However CPU_IDLE is not set in
omap2plus_defconfig so there should not be any effect.
Do you have CPU_IDLE enabled?
>
>
> - Paul
Regards,
Jean
^ permalink raw reply
* OMAP baseline test results for v3.7-rc2
From: Jon Hunter @ 2012-10-22 16:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.00.1210202125300.774@utopia.booyaka.com>
Hi Paul,
On 10/20/2012 04:26 PM, Paul Walmsley wrote:
...
> Other:
>
> * 4430es2panda: omap_hwmod: l3_instr: _wait_target_disable failed
> - Unknown cause; could be due to the lack of hierarchical enable/disable
> in hwmod code
I am not seeing this on my omap4430 panda. I have an OMAP4430 ES2.3 and
I am using u-boot release 2012.10. What do you have?
Cheers
Jon
^ permalink raw reply
* [PATCH v2 9/9] pinctrl: single: dump pinmux register value
From: Haojian Zhuang @ 2012-10-22 16:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350922139-3693-1-git-send-email-haojian.zhuang@gmail.com>
Dump pinmux register value, not only function part in the pinmux
register.
Also fix the issue on caluclating pin offset. The last parameter
should be pin number, not register offset.
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
drivers/pinctrl/pinctrl-single.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index a20da78..6ba2a5d 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -284,15 +284,15 @@ static int pcs_get_group_pins(struct pinctrl_dev *pctldev,
static void pcs_pin_dbg_show(struct pinctrl_dev *pctldev,
struct seq_file *s,
- unsigned offset)
+ unsigned pin)
{
struct pcs_device *pcs;
- unsigned val;
+ unsigned val, mux_bytes;
pcs = pinctrl_dev_get_drvdata(pctldev);
- val = pcs->read(pcs->base + offset);
- val &= pcs->fmask;
+ mux_bytes = pcs->width / BITS_PER_BYTE;
+ val = pcs_readl(pcs->base + pin * mux_bytes);
seq_printf(s, "%08x %s " , val, DRIVER_NAME);
}
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2 8/9] i2c: pxa: configure pinmux
From: Haojian Zhuang @ 2012-10-22 16:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350922139-3693-1-git-send-email-haojian.zhuang@gmail.com>
Configure pins by pinctrl driver.
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
drivers/i2c/busses/i2c-pxa.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 7c8b5d0..11e4a30 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -32,6 +32,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_i2c.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/clk.h>
@@ -1051,6 +1052,7 @@ static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c,
enum pxa_i2c_types *i2c_types)
{
struct device_node *np = pdev->dev.of_node;
+ struct pinctrl *pinctrl;
const struct of_device_id *of_id =
of_match_device(i2c_pxa_dt_ids, &pdev->dev);
int ret;
@@ -1063,6 +1065,9 @@ static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c,
return ret;
}
pdev->id = ret;
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl))
+ return -EPROBE_DEFER;
if (of_get_property(np, "mrvl,i2c-polling", NULL))
i2c->use_pio = 1;
if (of_get_property(np, "mrvl,i2c-fast-mode", NULL))
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2 7/9] i2c: pxa: use devm_kzalloc
From: Haojian Zhuang @ 2012-10-22 16:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350922139-3693-1-git-send-email-haojian.zhuang@gmail.com>
Use devm_kzalloc & add checking in probe() function.
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
drivers/i2c/busses/i2c-pxa.c | 26 ++++++++++----------------
1 files changed, 10 insertions(+), 16 deletions(-)
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 1034d93..7c8b5d0 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -1078,6 +1078,8 @@ static int i2c_pxa_probe_pdata(struct platform_device *pdev,
struct i2c_pxa_platform_data *plat = pdev->dev.platform_data;
const struct platform_device_id *id = platform_get_device_id(pdev);
+ if (!id)
+ return -EINVAL;
*i2c_types = id->driver_data;
if (plat) {
i2c->use_pio = plat->use_pio;
@@ -1094,29 +1096,23 @@ static int i2c_pxa_probe(struct platform_device *dev)
struct resource *res = NULL;
int ret, irq;
- i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL);
- if (!i2c) {
- ret = -ENOMEM;
- goto emalloc;
- }
+ i2c = devm_kzalloc(&dev->dev, sizeof(struct pxa_i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
ret = i2c_pxa_probe_dt(dev, i2c, &i2c_type);
if (ret > 0)
ret = i2c_pxa_probe_pdata(dev, i2c, &i2c_type);
if (ret < 0)
- goto eclk;
+ return ret;
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
irq = platform_get_irq(dev, 0);
- if (res == NULL || irq < 0) {
- ret = -ENODEV;
- goto eclk;
- }
+ if (res == NULL || irq < 0)
+ return -ENODEV;
- if (!request_mem_region(res->start, resource_size(res), res->name)) {
- ret = -ENOMEM;
- goto eclk;
- }
+ if (!request_mem_region(res->start, resource_size(res), res->name))
+ return -ENOMEM;
i2c->adap.owner = THIS_MODULE;
i2c->adap.retries = 5;
@@ -1209,8 +1205,6 @@ ereqirq:
eremap:
clk_put(i2c->clk);
eclk:
- kfree(i2c);
-emalloc:
release_mem_region(res->start, resource_size(res));
return ret;
}
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2 6/9] tty: pxa: configure pin
From: Haojian Zhuang @ 2012-10-22 16:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350922139-3693-1-git-send-email-haojian.zhuang@gmail.com>
Configure pins by pinctrl driver.
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
drivers/tty/serial/pxa.c | 8 +++++++-
1 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c
index 9033fc6..02dc771 100644
--- a/drivers/tty/serial/pxa.c
+++ b/drivers/tty/serial/pxa.c
@@ -37,6 +37,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -809,6 +810,7 @@ static int serial_pxa_probe_dt(struct platform_device *pdev,
struct uart_pxa_port *sport)
{
struct device_node *np = pdev->dev.of_node;
+ struct pinctrl *pinctrl;
int ret;
if (!np)
@@ -819,6 +821,10 @@ static int serial_pxa_probe_dt(struct platform_device *pdev,
dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
return ret;
}
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl))
+ return -EPROBE_DEFER;
+
sport->port.line = ret;
return 0;
}
@@ -857,7 +863,7 @@ static int serial_pxa_probe(struct platform_device *dev)
ret = serial_pxa_probe_dt(dev, sport);
if (ret > 0)
sport->port.line = dev->id;
- else if (ret < 0)
+ if (ret < 0)
goto err_clk;
snprintf(sport->name, PXA_NAME_LEN - 1, "UART%d", sport->port.line + 1);
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2 5/9] document: devicetree: bind pinconf with pin-single
From: Haojian Zhuang @ 2012-10-22 16:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350922139-3693-1-git-send-email-haojian.zhuang@gmail.com>
Add comments with pinconf & gpio range in the document of
pinctrl-single.
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
.../devicetree/bindings/pinctrl/pinctrl-single.txt | 52 ++++++++++++++++++++
arch/arm/boot/dts/pxa910.dtsi | 1 -
2 files changed, 52 insertions(+), 1 deletions(-)
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
index 2c81e45..6da2f13 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-single.txt
@@ -17,6 +17,36 @@ Optional properties:
- pinctrl-single,bit-per-mux : boolean to indicate that one register controls
more than one pin
+- pinctrl-single,gpio-ranges : gpio range list
+
+- pinctrl-single,gpio : array with gpio range start, size & register
+ offset
+
+- pinctrl-single,gpio-func : gpio function value in the pinmux register
+
+- pinctrl-single,power-source-mask : mask of setting power source in
+ the pinmux register
+
+- pinctrl-single,power-source : value of setting power source field
+ in the pinmux register
+
+- pinctrl-single,bias-mask : mask of setting bias value in the pinmux
+ register
+
+- pinctrl-single,bias-disable : value of disabling bias in the pinmux
+ register
+
+- pinctrl-single,bias-pull-down : value of setting bias pull down in
+ the pinmux register
+
+- pinctrl-single,bias-pull-up : value of setting bias pull up in the
+ pinmux register
+
+- pinctrl-single,bias : value of setting bias in the pinmux register
+
+- pinctrl-single,input-schmitt-mask : mask of setting input schmitt
+ in the pinmux register
+
This driver assumes that there is only one register for each pin (unless the
pinctrl-single,bit-per-mux is set), and uses the common pinctrl bindings as
specified in the pinctrl-bindings.txt document in this directory.
@@ -76,6 +106,28 @@ control_devconf0: pinmux at 48002274 {
pinctrl-single,function-mask = <0x5F>;
};
+/* third controller instance for pins in gpio domain */
+pmx_gpio: pinmux at d401e000 {
+ compatible = "pinctrl-single";
+ reg = <0xd401e000 0x0330>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-single,register-width = <32>;
+ pinctrl-single,function-mask = <7>;
+ pinctrl-single,gpio-ranges = <&gpiorange0 &gpiorange1>;
+};
+
+gpiorange0: gpiorange at d401e0dc {
+ pinctrl-single,gpio = <0 55 0x0dc>;
+ pinctrl-single,gpio-func = <0>;
+};
+
+gpiorange1: gpiorange at d401e2f0 {
+ pinctrl-single,gpio = <55 5 0x2f0>;
+ pinctrl-single,gpio-func = <1>;
+};
+
+
/* board specific .dts file */
&pmx_core {
diff --git a/arch/arm/boot/dts/pxa910.dtsi b/arch/arm/boot/dts/pxa910.dtsi
index cf807e8..a11a582 100644
--- a/arch/arm/boot/dts/pxa910.dtsi
+++ b/arch/arm/boot/dts/pxa910.dtsi
@@ -61,7 +61,6 @@
#size-cells = <0>;
pinctrl-single,register-width = <32>;
pinctrl-single,function-mask = <7>;
- pinctrl-single,gpio-mask = <7>;
pinctrl-single,gpio-ranges = <&gpiorange0 &gpiorange1
&gpiorange2 &gpiorange3
&gpiorange4 &gpiorange5
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2 4/9] ARM: dts: support pinctrl single in pxa910
From: Haojian Zhuang @ 2012-10-22 16:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350922139-3693-1-git-send-email-haojian.zhuang@gmail.com>
Add pinctrl-single support with device tree in pxa910 dkb platform.
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
arch/arm/boot/dts/pxa910-dkb.dts | 187 +++++++++++++++++++++++++++++++++++++-
arch/arm/boot/dts/pxa910.dtsi | 78 ++++++++++++++++
2 files changed, 264 insertions(+), 1 deletions(-)
diff --git a/arch/arm/boot/dts/pxa910-dkb.dts b/arch/arm/boot/dts/pxa910-dkb.dts
index 595492a..394396a 100644
--- a/arch/arm/boot/dts/pxa910-dkb.dts
+++ b/arch/arm/boot/dts/pxa910-dkb.dts
@@ -24,10 +24,195 @@
soc {
apb at d4000000 {
- uart1: uart at d4017000 {
+ pmx: pinmux at d401e000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&board_pins>;
+
+ board_pins: pinmux_board_pins {
+ /* pins not owned by device driver */
+ };
+ uart1_pins: pinmux_uart1_pins {
+ pinctrl-single,pins = <
+ 0x198 0x6 /* GPIO47_UART1_RXD */
+ 0x19c 0x6 /* GPIO48_UART1_TXD */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0x6>;
+ };
+ uart2_pins: pinmux_uart2_pins {
+ pinctrl-single,pins = <
+ 0x150 0x4 /* GPIO29_UART2_CTS */
+ 0x154 0x4 /* GPIO30_UART2_RTS */
+ 0x158 0x4 /* GPIO31_UART2_TXD */
+ 0x15c 0x4 /* GPIO32_UART2_RXD */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ uart3_pins: pinmux_uart3_pins {
+ pinctrl-single,pins = <
+ 0x188 0x7 /* GPIO43_UART3_RXD */
+ 0x18c 0x7 /* GPIO44_UART3_TXD */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ twsi1_pins: pinmux_twsi1_pins {
+ pinctrl-single,pins = <
+ 0x1b0 0x2 /* GPIO53_TWSI_SCL */
+ 0x1b4 0x2 /* GPIO54_TWSI_SDA */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ nand_pins: pinmux_nand_pins {
+ pinctrl-single,pins = <
+ 0x040 0x0 /* ND_IO0 */
+ 0x03c 0x0 /* ND_IO1 */
+ 0x038 0x0 /* ND_IO2 */
+ 0x034 0x0 /* ND_IO3 */
+ 0x030 0x0 /* ND_IO4 */
+ 0x02c 0x0 /* ND_IO5 */
+ 0x028 0x0 /* ND_IO6 */
+ 0x024 0x0 /* ND_IO7 */
+ 0x020 0x0 /* ND_IO8 */
+ 0x01c 0x0 /* ND_IO9 */
+ 0x018 0x0 /* ND_IO10 */
+ 0x014 0x0 /* ND_IO11 */
+ 0x010 0x0 /* ND_IO12 */
+ 0x00c 0x0 /* ND_IO13 */
+ 0x008 0x0 /* ND_IO14 */
+ 0x004 0x0 /* ND_IO15 */
+ 0x044 0x0 /* ND_nCS0 */
+ 0x060 0x1 /* ND_ALE */
+ 0x05c 0x0 /* ND_CLE */
+ 0x054 0x1 /* ND_nWE */
+ 0x058 0x1 /* ND_nRE */
+ 0x068 0x0 /* ND_RDY0 */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ mmc1_ldata_pins: pinmux_mmc1_ldata_pins {
+ pinctrl-single,pins = <
+ 0x0a0 0x0 /* MMC1_DATA0 */
+ 0x09c 0x0 /* MMC1_DATA1 */
+ 0x098 0x0 /* MMC1_DATA2 */
+ 0x094 0x0 /* MMC1_DATA3 */
+ >;
+ pinctrl-single,power-source = <0x3>;
+ pinctrl-single,bias = <0>;
+ };
+ mmc1_hdata_pins: pinmux_mmc1_hdata_pins {
+ pinctrl-single,pins = <
+ 0x090 0x0 /* MMC1_DATA4 */
+ 0x08c 0x0 /* MMC1_DATA5 */
+ 0x088 0x0 /* MMC1_DATA6 */
+ 0x084 0x0 /* MMC1_DATA7 */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ mmc1_clk_pins: pinmux_mmc1_clk_pins {
+ pinctrl-single,pins = <
+ 0x0a4 0x0 /* MMC1_CMD */
+ 0x0a8 0x0 /* MMC1_CLK */
+ >;
+ pinctrl-single,power-source = <0x3>;
+ pinctrl-single,bias = <0>;
+ };
+ mmc1_cd_pins: pinmux_mmc1_cd_pins {
+ pinctrl-single,pins = <
+ 0x0ac 0x0 /* MMC1_CD */
+ 0x0b0 0x0 /* MMC1_WP */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ mmc2_pins: pinmux_mmc2_pins {
+ pinctrl-single,pins = <
+ 0x180 0x1 /* MMC2_CMD */
+ 0x184 0x1 /* MMC2_CLK */
+ 0x17c 0x1 /* MMC2_DATA0 */
+ 0x178 0x1 /* MMC2_DATA1 */
+ 0x174 0x1 /* MMC2_DATA2 */
+ 0x170 0x1 /* MMC2_DATA3 */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ w1_pins: pinmux_w1_pins {
+ pinctrl-single,pins = <
+ 0x0cc 0x2 /* CLK_REQ_W1 */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ ssp1_pins: pinmux_ssp1_pins {
+ pinctrl-single,pins = <
+ 0x130 0x1 /* GPIO21_SSP1_SCLK */
+ 0x134 0x1 /* GPIO22_SSP1_FRM */
+ 0x138 0x1 /* GPIO23_SSP1_TXD */
+ 0x13c 0x1 /* GPIO24_SSP1_RXD */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ keypad_pins: pinmux_keypad_pins {
+ pinctrl-single,pins = <
+ 0x0dc 0x1 /* GPIO0_MKIN0 */
+ 0x0e0 0x1 /* GPIO1_MKOUT0 */
+ 0x0e4 0x1 /* GPIO2_MKIN1 */
+ 0x0e8 0x1 /* GPIO3_MKOUT1 */
+ 0x0ec 0x1 /* GPIO4_MKIN2 */
+ 0x0f0 0x1 /* GPIO5_MKOUT2 */
+ 0x0f4 0x1 /* GPIO6_MKIN3 */
+ 0x0f8 0x1 /* GPIO7_MKOUT3 */
+ 0x0fc 0x1 /* GPIO8_MKIN4 */
+ 0x100 0x1 /* GPIO9_MKOUT4 */
+ 0x10c 0x1 /* GPIO12_MKIN6 */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ nfc_pins: pinmux_nfc_pins {
+ pinctrl-single,pins = <
+ 0x120 0x0 /* GPIO17 */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ wlan_pins: pinmux_wlan_pins {
+ pinctrl-single,pins = <
+ 0x114 0x0 /* GPIO14 */
+ 0x12c 0x0 /* GPIO20 */
+ 0x160 0x0 /* GPIO33 */
+ 0x164 0x0 /* GPIO34 */
+ 0x168 0x0 /* GPIO35 */
+ 0x16c 0x0 /* GPIO36 */
+ >;
+ pinctrl-single,power-source = <0x2>;
+ pinctrl-single,bias = <0>;
+ };
+ };
+ uart1: uart at d4017000 { /* FFUART */
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>;
+ status = "okay";
+ };
+ uart2: uart at d4018000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+ status = "okay";
+ };
+ uart3: uart at d4036000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins>;
status = "okay";
};
twsi1: i2c at d4011000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&twsi1_pins>;
status = "okay";
pmic: 88pm860x at 34 {
diff --git a/arch/arm/boot/dts/pxa910.dtsi b/arch/arm/boot/dts/pxa910.dtsi
index 825aaca..cf807e8 100644
--- a/arch/arm/boot/dts/pxa910.dtsi
+++ b/arch/arm/boot/dts/pxa910.dtsi
@@ -54,6 +54,84 @@
reg = <0xd4000000 0x00200000>;
ranges;
+ pmx: pinmux at d401e000 {
+ compatible = "pinctrl-single";
+ reg = <0xd401e000 0x0330>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-single,register-width = <32>;
+ pinctrl-single,function-mask = <7>;
+ pinctrl-single,gpio-mask = <7>;
+ pinctrl-single,gpio-ranges = <&gpiorange0 &gpiorange1
+ &gpiorange2 &gpiorange3
+ &gpiorange4 &gpiorange5
+ &gpiorange6 &gpiorange7
+ &gpiorange8 &gpiorange9
+ &gpiorange10>;
+ pinctrl-single,power-source-mask = <0x1800>;
+ pinctrl-single,bias-mask = <0xe000>;
+ pinctrl-single,bias-disable = <0>;
+ pinctrl-single,bias-pull-down = <0xa000>;
+ pinctrl-single,bias-pull-up = <0xc000>;
+ pinctrl-single,input-schmitt-mask = <0x70>;
+
+ gpiorange0: gpiorange at d401e0dc {
+ /* GPIO0 ~ GPIO54 */
+ pinctrl-single,gpio = <0 55 0x0dc>;
+ pinctrl-single,gpio-func = <0>;
+ };
+ gpiorange1: gpiorange at d401e2f0 {
+ /* GPIO55 ~ GPIO59 */
+ pinctrl-single,gpio = <55 5 0x2f0>;
+ pinctrl-single,gpio-func = <1>;
+ };
+ gpiorange2: gpiorange at d401e304 {
+ /* GPIO60 ~ GPIO66 */
+ pinctrl-single,gpio = <60 7 0x304>;
+ pinctrl-single,gpio-func = <0>;
+ };
+ gpiorange3: gpiorange at d401e1b8 {
+ /* GPIO67 ~ GPIO109 */
+ pinctrl-single,gpio = <67 43 0x1b8>;
+ pinctrl-single,gpio-func = <0>;
+ };
+ gpiorange4: gpiorange at d401e298 {
+ /* GPIO110 ~ GPIO116 */
+ pinctrl-single,gpio = <110 7 0x298>;
+ pinctrl-single,gpio-func = <0>;
+ };
+ gpiorange5: gpiorange at d401e0b4 {
+ /* GPIO117 ~ GPIO120 */
+ pinctrl-single,gpio = <117 4 0x0b4>;
+ pinctrl-single,gpio-func = <1>;
+ };
+ gpiorange6: gpiorange at d401e32c {
+ /* GPIO121 */
+ pinctrl-single,gpio = <121 1 0x32c>;
+ pinctrl-single,gpio-func = <0>;
+ };
+ gpiorange7: gpiorange at d401e0c8 {
+ /* GPIO122 ~ GPIO123 */
+ pinctrl-single,gpio = <122 2 0x0c8>;
+ pinctrl-single,gpio-func = <1>;
+ };
+ gpiorange8: gpiorange at d401e0d0 {
+ /* GPIO124 */
+ pinctrl-single,gpio = <124 1 0x0d0>;
+ pinctrl-single,gpio-func = <0>;
+ };
+ gpiorange9: gpiorange at d401e0d4 {
+ /* GPIO125 */
+ pinctrl-single,gpio = <125 1 0x0d4>;
+ pinctrl-single,gpio-func = <1>;
+ };
+ gpiorange10: gpiorange at d401e06c {
+ /* GPIO126 ~ GPIO127 */
+ pinctrl-single,gpio = <126 2 0x06c>;
+ pinctrl-single,gpio-func = <0>;
+ };
+ };
+
timer0: timer at d4014000 {
compatible = "mrvl,mmp-timer";
reg = <0xd4014000 0x100>;
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2 3/9] pinctrl: single: support pinconf generic
From: Haojian Zhuang @ 2012-10-22 16:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350922139-3693-1-git-send-email-haojian.zhuang@gmail.com>
Add pinconf generic support with POWER SOURCE, BIAS PULL.
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
drivers/pinctrl/Kconfig | 1 +
drivers/pinctrl/pinctrl-single.c | 276 ++++++++++++++++++++++++++++++++++++--
2 files changed, 266 insertions(+), 11 deletions(-)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 7bf914d..e9f2d2d 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -139,6 +139,7 @@ config PINCTRL_SINGLE
depends on OF
select PINMUX
select PINCONF
+ select GENERIC_PINCONF
help
This selects the device tree based generic pinctrl driver.
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 6a0b24b..a20da78 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -20,6 +20,7 @@
#include <linux/of_device.h>
#include <linux/of_address.h>
+#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
@@ -29,6 +30,9 @@
#define PCS_MUX_PINS_NAME "pinctrl-single,pins"
#define PCS_MUX_BITS_NAME "pinctrl-single,bits"
#define PCS_GPIO_FUNC_NAME "pinctrl-single,gpio-func"
+#define PCS_BIAS_NAME "pinctrl-single,bias"
+#define PCS_POWER_SOURCE_NAME "pinctrl-single,power-source"
+#define PCS_SCHMITT_NAME "pinctrl-single,input-schmitt"
#define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 1)
#define PCS_OFF_DISABLED ~0U
#define PCS_MAX_GPIO_VALUES 3
@@ -131,6 +135,15 @@ struct pcs_name {
* @fshift: function register shift
* @foff: value to turn mux off
* @fmax: max number of functions in fmask
+ * @bmask: bias mask in pinconf
+ * @bshift: bias register shift
+ * @bdis: bias disable value in pinconf
+ * @bpullup: bias pull up value in pinconf
+ * @bpulldown: bias pull down value in pinconf
+ * @ismask: input schmitt mask in pinconf
+ * @isshift: input schmitt register shift
+ * @psmask: power source mask in pinconf
+ * @psshift: power source register shift
* @names: array of register names for pins
* @pins: physical pins on the SoC
* @pgtree: pingroup index radix tree
@@ -157,6 +170,15 @@ struct pcs_device {
unsigned fshift;
unsigned foff;
unsigned fmax;
+ unsigned bmask;
+ unsigned bshift;
+ unsigned bdis;
+ unsigned bpullup;
+ unsigned bpulldown;
+ unsigned ismask;
+ unsigned isshift;
+ unsigned psmask;
+ unsigned psshift;
bool bits_per_mux;
struct pcs_name *names;
struct pcs_data pins;
@@ -453,28 +475,163 @@ static struct pinmux_ops pcs_pinmux_ops = {
.gpio_request_enable = pcs_request_gpio,
};
+static void pcs_free_pingroups(struct pcs_device *pcs);
+
static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long *config)
{
+ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ unsigned data;
+ u32 offset;
+
+ offset = pin * (pcs->width / BITS_PER_BYTE);
+ data = pcs_readl(pcs->base + offset);
+
+ switch (param) {
+ case PIN_CONFIG_POWER_SOURCE:
+ if (pcs->psmask == PCS_OFF_DISABLED
+ || pcs->psshift == PCS_OFF_DISABLED)
+ return -ENOTSUPP;
+ data &= pcs->psmask;
+ data = data >> pcs->psshift;
+ *config = data;
+ return 0;
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ if (pcs->bmask == PCS_OFF_DISABLED
+ || pcs->bshift == PCS_OFF_DISABLED
+ || pcs->bdis == PCS_OFF_DISABLED)
+ return -ENOTSUPP;
+ data &= pcs->bmask;
+ *config = 0;
+ if (data == pcs->bdis)
+ return 0;
+ else
+ return -EINVAL;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (pcs->bmask == PCS_OFF_DISABLED
+ || pcs->bshift == PCS_OFF_DISABLED
+ || pcs->bpullup == PCS_OFF_DISABLED)
+ return -ENOTSUPP;
+ data &= pcs->bmask;
+ *config = 0;
+ if (data == pcs->bpullup)
+ return 0;
+ else
+ return -EINVAL;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (pcs->bmask == PCS_OFF_DISABLED
+ || pcs->bshift == PCS_OFF_DISABLED
+ || pcs->bpulldown == PCS_OFF_DISABLED)
+ return -ENOTSUPP;
+ data &= pcs->bmask;
+ *config = 0;
+ if (data == pcs->bpulldown)
+ return 0;
+ else
+ return -EINVAL;
+ break;
+ default:
+ break;
+ }
return -ENOTSUPP;
}
static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long config)
{
- return -ENOTSUPP;
+ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param config_param = pinconf_to_config_param(config);
+ unsigned ret, mask = ~0UL;
+ u32 offset, data;
+
+ switch (config_param) {
+ case PIN_CONFIG_POWER_SOURCE:
+ if (pcs->psmask == PCS_OFF_DISABLED
+ || pcs->psshift == PCS_OFF_DISABLED)
+ return 0;
+ mask = pcs->psmask;
+ data = (pinconf_to_config_argument(config) << pcs->psshift)
+ & pcs->psmask;
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ if (pcs->bmask == PCS_OFF_DISABLED
+ || pcs->bshift == PCS_OFF_DISABLED)
+ return 0;
+ mask = pcs->bmask;
+ data = (pinconf_to_config_argument(config) << pcs->bshift)
+ & pcs->bmask;
+ break;
+ default:
+ return 0;
+ }
+ offset = pin * (pcs->width / BITS_PER_BYTE);
+ ret = pcs_readl(pcs->base + offset) & ~mask;
+ pcs_writel(ret | data, pcs->base + offset);
+ return 0;
}
static int pcs_pinconf_group_get(struct pinctrl_dev *pctldev,
unsigned group, unsigned long *config)
{
- return -ENOTSUPP;
+ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+ struct pcs_pingroup *pins;
+
+ pins = radix_tree_lookup(&pcs->pgtree, group);
+ if (!pins) {
+ dev_err(pcs->dev, "%s could not find pingroup%i\n",
+ __func__, group);
+ return -EINVAL;
+ }
+ return pcs_pinconf_get(pctldev, pins->gpins[0], config);
}
static int pcs_pinconf_group_set(struct pinctrl_dev *pctldev,
unsigned group, unsigned long config)
{
- return -ENOTSUPP;
+ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param config_param = pinconf_to_config_param(config);
+ struct pcs_pingroup *pins;
+ u32 offset, data;
+ unsigned ret, mask = ~0UL;
+ int i;
+
+ switch (config_param) {
+ case PIN_CONFIG_POWER_SOURCE:
+ if (pcs->psmask == PCS_OFF_DISABLED
+ || pcs->psshift == PCS_OFF_DISABLED)
+ return 0;
+ mask = pcs->psmask;
+ data = (pinconf_to_config_argument(config) << pcs->psshift)
+ & pcs->psmask;
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ if (pcs->bmask == PCS_OFF_DISABLED
+ || pcs->bshift == PCS_OFF_DISABLED)
+ return 0;
+ mask = pcs->bmask;
+ data = (pinconf_to_config_argument(config) << pcs->bshift)
+ & pcs->bmask;
+ break;
+ default:
+ return 0;
+ }
+
+ pins = radix_tree_lookup(&pcs->pgtree, group);
+ if (!pins) {
+ dev_err(pcs->dev, "%s could not find pingroup%i\n",
+ __func__, group);
+ return -EINVAL;
+ }
+ for (i = 0; i < pins->ngpins; i++) {
+ offset = pins->gpins[i] * (pcs->width / BITS_PER_BYTE);
+ ret = pcs_readl(pcs->base + offset) & ~mask;
+ pcs_writel(ret | data, pcs->base + offset);
+ }
+ return 0;
}
static void pcs_pinconf_dbg_show(struct pinctrl_dev *pctldev,
@@ -488,6 +645,7 @@ static void pcs_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
}
static struct pinconf_ops pcs_pinconf_ops = {
+ .is_generic = true,
.pin_config_get = pcs_pinconf_get,
.pin_config_set = pcs_pinconf_set,
.pin_config_group_get = pcs_pinconf_group_get,
@@ -689,6 +847,7 @@ static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset)
* @pcs: pinctrl driver instance
* @np: device node of the mux entry
* @map: map entry
+ * @num_configs: number of pin configurations
* @pgnames: pingroup names
*
* Note that this binding currently supports only sets of one register + value.
@@ -705,12 +864,16 @@ static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset)
static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
struct device_node *np,
struct pinctrl_map **map,
+ unsigned num_configs,
const char **pgnames)
{
struct pcs_func_vals *vals;
+ struct pinctrl_map *p = *map;
const __be32 *mux;
int size, params, rows, *pins, index = 0, found = 0, res = -ENOMEM;
struct pcs_function *function;
+ unsigned long *config;
+ u32 value;
if (pcs->bits_per_mux) {
params = 3;
@@ -773,12 +936,42 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
if (res < 0)
goto free_function;
- (*map)->type = PIN_MAP_TYPE_MUX_GROUP;
- (*map)->data.mux.group = np->name;
- (*map)->data.mux.function = np->name;
+ p->type = PIN_MAP_TYPE_MUX_GROUP;
+ p->data.mux.group = np->name;
+ p->data.mux.function = np->name;
+
+ if (!num_configs)
+ return 0;
+ config = devm_kzalloc(pcs->dev, sizeof(*config) * num_configs,
+ GFP_KERNEL);
+ if (!config) {
+ res = -ENOMEM;
+ goto free_pingroup;
+ }
+ index = 0;
+ if (!of_property_read_u32(np, PCS_SCHMITT_NAME, &value))
+ config[index++] =
+ pinconf_to_config_packed(PIN_CONFIG_INPUT_SCHMITT,
+ value & 0xffff);
+ if (!of_property_read_u32(np, PCS_BIAS_NAME, &value))
+ config[index++] =
+ pinconf_to_config_packed(PIN_CONFIG_BIAS_DISABLE,
+ value & 0xffff);
+ if (!of_property_read_u32(np, PCS_POWER_SOURCE_NAME, &value))
+ config[index++] =
+ pinconf_to_config_packed(PIN_CONFIG_POWER_SOURCE,
+ value & 0xffff);
+ p++;
+ p->type = PIN_MAP_TYPE_CONFIGS_GROUP;
+ p->data.configs.group_or_pin = np->name;
+ p->data.configs.configs = config;
+ p->data.configs.num_configs = num_configs;
return 0;
+free_pingroup:
+ pcs_free_pingroups(pcs);
+
free_function:
pcs_remove_function(pcs, function);
@@ -790,6 +983,30 @@ free_vals:
return res;
}
+
+static int pcs_dt_check_maps(struct device_node *np, unsigned *num_maps,
+ unsigned *num_configs)
+{
+ unsigned size;
+
+ *num_maps = 0;
+ *num_configs = 0;
+ if (of_get_property(np, PCS_MUX_PINS_NAME, &size)
+ || of_get_property(np, PCS_MUX_BITS_NAME, &size))
+ (*num_maps)++;
+ if (of_get_property(np, PCS_SCHMITT_NAME, &size))
+ (*num_configs)++;
+ if (of_get_property(np, PCS_BIAS_NAME, &size))
+ (*num_configs)++;
+ if (of_get_property(np, PCS_POWER_SOURCE_NAME, &size))
+ (*num_configs)++;
+ if (*num_configs)
+ (*num_maps)++;
+ if (!(*num_maps))
+ return -EINVAL;
+ return 0;
+}
+
/**
* pcs_dt_node_to_map() - allocates and parses pinctrl maps
* @pctldev: pinctrl instance
@@ -803,29 +1020,32 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
{
struct pcs_device *pcs;
const char **pgnames;
+ unsigned num_configs;
int ret;
pcs = pinctrl_dev_get_drvdata(pctldev);
- *map = devm_kzalloc(pcs->dev, sizeof(**map), GFP_KERNEL);
+ ret = pcs_dt_check_maps(np_config, num_maps, &num_configs);
+ if (ret)
+ return ret;
+
+ *map = devm_kzalloc(pcs->dev, sizeof(**map) * (*num_maps), GFP_KERNEL);
if (!map)
return -ENOMEM;
- *num_maps = 0;
-
pgnames = devm_kzalloc(pcs->dev, sizeof(*pgnames), GFP_KERNEL);
if (!pgnames) {
ret = -ENOMEM;
goto free_map;
}
- ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map, pgnames);
+ ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map,
+ num_configs, pgnames);
if (ret < 0) {
dev_err(pcs->dev, "no pins entries for %s\n",
np_config->name);
goto free_pgnames;
}
- *num_maps = 1;
return 0;
@@ -1003,6 +1223,40 @@ static int __devinit pcs_probe(struct platform_device *pdev)
pcs->bits_per_mux = of_property_read_bool(np,
"pinctrl-single,bit-per-mux");
+ ret = of_property_read_u32(np, "pinctrl-single,power-source-mask",
+ &pcs->psmask);
+ if (ret) {
+ pcs->psmask = PCS_OFF_DISABLED;
+ pcs->psshift = PCS_OFF_DISABLED;
+ } else
+ pcs->psshift = ffs(pcs->psmask) - 1;
+ ret = of_property_read_u32(np, "pinctrl-single,bias-mask",
+ &pcs->bmask);
+ if (ret) {
+ pcs->bmask = PCS_OFF_DISABLED;
+ pcs->bshift = PCS_OFF_DISABLED;
+ } else
+ pcs->bshift = ffs(pcs->bmask) - 1;
+ ret = of_property_read_u32(np, "pinctrl-single,bias-disable",
+ &pcs->bdis);
+ if (ret)
+ pcs->bdis = PCS_OFF_DISABLED;
+ ret = of_property_read_u32(np, "pinctrl-single,bias-pull-up",
+ &pcs->bpullup);
+ if (ret)
+ pcs->bpullup = PCS_OFF_DISABLED;
+ ret = of_property_read_u32(np, "pinctrl-single,bias-pull-down",
+ &pcs->bpulldown);
+ if (ret)
+ pcs->bpulldown = PCS_OFF_DISABLED;
+ ret = of_property_read_u32(np, "pinctrl-single,input-schmitt-mask",
+ &pcs->ismask);
+ if (ret) {
+ pcs->ismask = PCS_OFF_DISABLED;
+ pcs->isshift = PCS_OFF_DISABLED;
+ } else
+ pcs->isshift = ffs(pcs->ismask) - 1;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(pcs->dev, "could not get resource\n");
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2 2/9] pinctrl: single: support gpio request and free
From: Haojian Zhuang @ 2012-10-22 16:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350922139-3693-1-git-send-email-haojian.zhuang@gmail.com>
Marvell's PXA/MMP silicon also match the behavior of pinctrl-single.
Each pin binds to one register. A lot of pins could be configured
as gpio.
Now add three properties in below.
pinctrl-single,gpio-ranges: gpio range array
pinctrl-single,gpio: <gpio base, npins in range, pin base in range>
pinctrl-single,gpio-func: <gpio function value in mux>
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
drivers/pinctrl/pinctrl-single.c | 94 +++++++++++++++++++++++++++++++++++++-
1 files changed, 92 insertions(+), 2 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index 726a729..6a0b24b 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -28,8 +28,10 @@
#define DRIVER_NAME "pinctrl-single"
#define PCS_MUX_PINS_NAME "pinctrl-single,pins"
#define PCS_MUX_BITS_NAME "pinctrl-single,bits"
+#define PCS_GPIO_FUNC_NAME "pinctrl-single,gpio-func"
#define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 1)
#define PCS_OFF_DISABLED ~0U
+#define PCS_MAX_GPIO_VALUES 3
/**
* struct pcs_pingroup - pingroups for a function
@@ -77,6 +79,18 @@ struct pcs_function {
};
/**
+ * struct pcs_gpio_range - pinctrl gpio range
+ * @range: subrange of the GPIO number space
+ * @gpio_func: gpio function value in the pinmux register
+ * @func_en: need to handle gpio function in the pinmux register
+ */
+struct pcs_gpio_range {
+ struct pinctrl_gpio_range range;
+ int gpio_func;
+ unsigned func_en:1;
+};
+
+/**
* struct pcs_data - wrapper for data needed by pinctrl framework
* @pa: pindesc array
* @cur: index to current element
@@ -123,8 +137,10 @@ struct pcs_name {
* @ftree: function index radix tree
* @pingroups: list of pingroups
* @functions: list of functions
+ * @ranges: list of gpio ranges
* @ngroups: number of pingroups
* @nfuncs: number of functions
+ * @nranges: number of gpio ranges
* @desc: pin controller descriptor
* @read: register read function to use
* @write: register write function to use
@@ -148,8 +164,10 @@ struct pcs_device {
struct radix_tree_root ftree;
struct list_head pingroups;
struct list_head functions;
+ struct list_head ranges;
unsigned ngroups;
unsigned nfuncs;
+ unsigned nranges;
struct pinctrl_desc desc;
unsigned (*read)(void __iomem *reg);
void (*write)(unsigned val, void __iomem *reg);
@@ -403,9 +421,27 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector,
}
static int pcs_request_gpio(struct pinctrl_dev *pctldev,
- struct pinctrl_gpio_range *range, unsigned offset)
+ struct pinctrl_gpio_range *range, unsigned pin)
{
- return -ENOTSUPP;
+ struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
+ struct pcs_gpio_range *gpio = NULL;
+ int end, mux_bytes;
+ unsigned data;
+
+ gpio = container_of(range, struct pcs_gpio_range, range);
+ if (!gpio->func_en)
+ return 0;
+ end = range->pin_base + range->npins - 1;
+ if (pin < range->pin_base || pin > end) {
+ dev_err(pctldev->dev, "pin %d isn't in the range of "
+ "%d to %d\n", pin, range->pin_base, end);
+ return -EINVAL;
+ }
+ mux_bytes = pcs->width / BITS_PER_BYTE;
+ data = pcs_readl(pcs->base + pin * mux_bytes) & ~pcs->fmask;
+ data |= gpio->gpio_func;
+ pcs_writel(data, pcs->base + pin * mux_bytes);
+ return 0;
}
static struct pinmux_ops pcs_pinmux_ops = {
@@ -879,6 +915,55 @@ static void pcs_free_resources(struct pcs_device *pcs)
static struct of_device_id pcs_of_match[];
+static int __devinit pcs_add_gpio_range(struct device_node *node,
+ struct pcs_device *pcs)
+{
+ struct pcs_gpio_range *gpio;
+ struct device_node *np;
+ const __be32 *list;
+ const char list_name[] = "pinctrl-single,gpio-ranges";
+ const char name[] = "pinctrl-single";
+ u32 gpiores[PCS_MAX_GPIO_VALUES];
+ int ret, size, i, mux_bytes = 0;
+
+ list = of_get_property(node, list_name, &size);
+ if (!list)
+ return -ENOENT;
+ size = size / sizeof(*list);
+ for (i = 0; i < size; i++) {
+ np = of_parse_phandle(node, list_name, i);
+ memset(gpiores, 0, sizeof(u32) * PCS_MAX_GPIO_VALUES);
+ ret = of_property_read_u32_array(np, "pinctrl-single,gpio",
+ gpiores, PCS_MAX_GPIO_VALUES);
+ if (ret < 0)
+ return -ENOENT;
+ gpio = devm_kzalloc(pcs->dev, sizeof(*gpio), GFP_KERNEL);
+ if (!gpio) {
+ dev_err(pcs->dev, "failed to allocate pcs gpio\n");
+ return -ENOMEM;
+ }
+ gpio->range.id = i;
+ gpio->range.base = gpiores[0];
+ gpio->range.npins = gpiores[1];
+ gpio->range.name = kmemdup(name, sizeof(name), GFP_KERNEL);
+ mux_bytes = pcs->width / BITS_PER_BYTE;
+ gpio->range.pin_base = gpiores[2] / mux_bytes;
+ memset(gpiores, 0, sizeof(u32) * PCS_MAX_GPIO_VALUES);
+ ret = of_property_read_u32(np, PCS_GPIO_FUNC_NAME,
+ &gpio->gpio_func);
+ if (!ret)
+ gpio->func_en = 1;
+
+ mutex_lock(&pcs->mutex);
+ list_add_tail(&gpio->range.node, &pcs->ranges);
+ pcs->nranges++;
+ mutex_unlock(&pcs->mutex);
+
+ pinctrl_add_gpio_range(pcs->pctl, &gpio->range);
+ }
+ return 0;
+}
+
static int __devinit pcs_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -900,6 +985,7 @@ static int __devinit pcs_probe(struct platform_device *pdev)
mutex_init(&pcs->mutex);
INIT_LIST_HEAD(&pcs->pingroups);
INIT_LIST_HEAD(&pcs->functions);
+ INIT_LIST_HEAD(&pcs->ranges);
PCS_GET_PROP_U32("pinctrl-single,register-width", &pcs->width,
"register width not specified\n");
@@ -975,6 +1061,10 @@ static int __devinit pcs_probe(struct platform_device *pdev)
goto free;
}
+ ret = pcs_add_gpio_range(np, pcs);
+ if (ret < 0)
+ return ret;
+
dev_info(pcs->dev, "%i pins at pa %p size %u\n",
pcs->desc.npins, pcs->base, pcs->size);
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2 1/9] ARM: mmp: select pinctrl driver
From: Haojian Zhuang @ 2012-10-22 16:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350922139-3693-1-git-send-email-haojian.zhuang@gmail.com>
Pinctrl driver is necessary for MMP DT & MMP2 DT platforms.
Signed-off-by: Haojian Zhuang <haojian.zhuang@gmail.com>
---
arch/arm/mach-mmp/Kconfig | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig
index 178d4da..ebdda83 100644
--- a/arch/arm/mach-mmp/Kconfig
+++ b/arch/arm/mach-mmp/Kconfig
@@ -89,6 +89,8 @@ config MACH_MMP_DT
select CPU_PXA168
select CPU_PXA910
select USE_OF
+ select PINCTRL
+ select PINCTRL_SINGLE
help
Include support for Marvell MMP2 based platforms using
the device tree. Needn't select any other machine while
@@ -99,6 +101,8 @@ config MACH_MMP2_DT
depends on !CPU_MOHAWK
select CPU_MMP2
select USE_OF
+ select PINCTRL
+ select PINCTRL_SINGLE
help
Include support for Marvell MMP2 based platforms using
the device tree.
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2 0/9] support pinctrl single in arch pxa/mmp
From: Haojian Zhuang @ 2012-10-22 16:08 UTC (permalink / raw)
To: linux-arm-kernel
Changelog:
v2:
1. Remove "pinctrl-single,gpio-mask". Since GPIO function is one of the
mux function in the pinmux register of both OMAP and PXA/MMP silicons.
Use "pinctrl-single,function-mask" instead.
2. Remove "pinctrl-single,gpio-enable" & "pinctrl-single,gpio-disable".
Use "pinctrl-single,gpio-func" instead. Because GPIO mode is only one
of the mux functions in the pinmux register. Defining "gpio-enable" &
"gpio-disable" are redundant.
3. Define register with __iomem, not u32 type.
4. Remove "pinctrl-single,input-schmit-shift",
"pinctrl-single,power-source-shift", "pinctrl-single,bias-shift". All
these properties could be calculated by mask fields.
5. Return -EPROBE_DEFER if pinmux could be got in device driver. And
the device driver would be probed again deferred.
^ permalink raw reply
* [PATCH v2 2/2] USB: doc: Binding document for ehci-platform driver
From: Stephen Warren @ 2012-10-22 16:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350771032-11527-3-git-send-email-linux@prisktech.co.nz>
On 10/20/2012 04:10 PM, Tony Prisk wrote:
> Add a binding document for ehci-platform driver.
>
> Signed-off-by: Tony Prisk <linux@prisktech.co.nz>
> ---
> .../devicetree/bindings/usb/ehci-platform.txt | 27 ++++++++++++++++++++
> 1 file changed, 27 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/usb/ehci-platform.txt
>
> diff --git a/Documentation/devicetree/bindings/usb/ehci-platform.txt b/Documentation/devicetree/bindings/usb/ehci-platform.txt
> new file mode 100644
> index 0000000..930b19e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/usb/ehci-platform.txt
> @@ -0,0 +1,27 @@
> +Generic Platform EHCI Controller
> +-----------------------------------------------------
> +
> +Required properties:
> +- compatible : "linux,ehci-platform"
That compatible value doesn't look right. The HW isn't defined by Linux.
The binding is supposed to represent HW, not any single OS's use of that
HW or the way its driver works.
Something like "usb,ehci" might be more appropriate. Certainly, the
value should not be "linux,", nor derived from Linux's driver name.
> +Optional properties:
> +- caps-offset : offset to the capabilities register (default = 0)
> +- has-tt : controller has transaction translator(s).
> +- has-synopsys-hc-bug : controller has the synopsys hc bug
That would normally be determined by the driver based on the particular
compatible value that is in device tree.
> +- no-io-watchdog : controller does not need io watchdog
> +
> +- big-endian : descriptors and registers are both big endian. This
> + is the equivalent of specifying big-endian-desc and big-endian-regs.
> +OR
> +- big-endian-desc : descriptors are in big-endian format
> +- big-endian-regs : mmio is in big-endian format
Hmmm. That looks odd. Presumably if those properties aren't specified,
the default is little-endian? Shouldn't this be a tri-state: big,
little, native, with default native? I don't know what the EHCI
specification mandates here (and if it does mandate something, the
default should match the specification). Isn't this something that
readl/writel would take care of, or are there cases where the register
endianness of just this one HW block mismatches all other HW blocks?
> +Example:
> + ehci at d8007c00 {
> + compatible = "ehci-platform";
> + reg = <0xd8007c00 0x200>;
> + interrupts = <43>;
> + has-tt;
> + };
>
^ permalink raw reply
* [PATCH] clk: Make the generic clock API available by default
From: Stephen Warren @ 2012-10-22 15:56 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350910970-9095-1-git-send-email-broonie@opensource.wolfsonmicro.com>
On 10/22/2012 07:02 AM, Mark Brown wrote:
> Rather than requiring platforms to select the generic clock API to make
> it available make the API available as a user selectable option unless the
> user either selects HAVE_CUSTOM_CLK (if they have their own implementation)
> or selects COMMON_CLK (if they depend on the generic implementation).
>
> All current architectures that HAVE_CLK but don't use the common clock
> framework have selects of HAVE_CUSTOM_CLK added.
>
> This allows drivers to use the generic API on platforms which have no need
> for the clock API at platform level.
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> @@ -632,6 +634,7 @@ config ARCH_TEGRA
> select GENERIC_CLOCKEVENTS
> select GENERIC_GPIO
> select HAVE_CLK
> + select HAVE_CUSTOM_CLK
> select HAVE_SMP
> select MIGHT_HAVE_CACHE_L2X0
> select SPARSE_IRQ
Since v3.7-rc1, Tegra uses common clock, so I don't think the change
above is right is it?
^ permalink raw reply
* [PATCH v2 1/5] clk: samsung: add common clock framework support for Samsung platforms
From: Sylwester Nawrocki @ 2012-10-22 15:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1349629855-4962-2-git-send-email-thomas.abraham@linaro.org>
Hi Thomas,
On 10/07/2012 07:10 PM, Thomas Abraham wrote:
> All Samsung platforms include several types of clocks including fixed-rate,
> mux, divider and gate clock types. There are typically hundreds of such clocks
> on each of the Samsung platforms. To enable Samsung platforms to register these
> clocks using the common clock framework, a bunch of utility functions are
> introduced here which simplify the clock registration process.
>
> In addition to the basic types of clock supported by common clock framework,
> a Samsung specific representation of the PLL clocks is also introduced.
>
> Both legacy and device tree based Samsung platforms are supported. On legacy
> platforms, the clocks are statically instantiated and registered with common
> clock framework. On device tree enabled platforms, the device tree is
> searched and all clock nodes found are registered. It is also possible to
> register statically instantiated clocks on device tree enabled platforms.
>
> Cc: Mike Turquette <mturquette@ti.com>
> Cc: Kukjin Kim <kgene.kim@samsung.com>
> Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
Thanks for the patch. I'm trying to use this series on an Exynos4412
SoC based board. I think it wasn't tested with Exynos4x12 (with FDT
support), was it ?
I have a few comments, please see below.
> ---
> drivers/clk/Makefile | 1 +
> drivers/clk/samsung/Makefile | 5 +
> drivers/clk/samsung/clk.c | 414 ++++++++++++++++++++++++++++++++++++++++++
> drivers/clk/samsung/clk.h | 212 +++++++++++++++++++++
> 4 files changed, 632 insertions(+), 0 deletions(-)
> create mode 100644 drivers/clk/samsung/Makefile
> create mode 100644 drivers/clk/samsung/clk.c
> create mode 100644 drivers/clk/samsung/clk.h
>
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 71a25b9..95644e3 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -19,6 +19,7 @@ endif
> obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
> obj-$(CONFIG_ARCH_U8500) += ux500/
> obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
> +obj-$(CONFIG_PLAT_SAMSUNG) += samsung/
>
> # Chip specific
> obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
> diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile
> new file mode 100644
> index 0000000..3f926b0
> --- /dev/null
> +++ b/drivers/clk/samsung/Makefile
> @@ -0,0 +1,5 @@
> +#
> +# Samsung Clock specific Makefile
> +#
> +
> +obj-$(CONFIG_PLAT_SAMSUNG) += clk.o
> diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
> new file mode 100644
> index 0000000..f5e269a
> --- /dev/null
> +++ b/drivers/clk/samsung/clk.c
> @@ -0,0 +1,414 @@
> +/*
> + * Copyright (c) 2012 Samsung Electronics Co., Ltd.
> + * Copyright (c) 2012 Linaro Ltd.
> + *
> + * 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.
> + *
> + * This file includes utility functions to register clocks to common
> + * clock framework for Samsung platforms. This includes an implementation
> + * of Samsung 'pll type' clock to represent the implementation of the
> + * pll found on Samsung platforms. In addition to that, utility functions
> + * to register mux, div, gate and fixed rate types of clocks are included.
> +*/
> +
> +#include <linux/of.h>
> +#include "clk.h"
> +
> +#define MAX_PARENT_CLKS 16
> +#define to_clk_pll(_hw) container_of(_hw, struct samsung_pll_clock, hw)
> +
> +static DEFINE_SPINLOCK(lock);
> +static void __iomem *reg_base;
> +static void __iomem *reg_fin_pll;
> +
> +void __init samsung_clk_set_ctrl_base(void __iomem *base)
> +{
> + reg_base = base;
> +}
> +
> +void __init samsung_clk_set_finpll_reg(void __iomem *reg)
> +{
> + reg_fin_pll = reg;
> +}
> +
> +/* determine the output clock speed of the pll */
> +static unsigned long samsung_pll_clock_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct samsung_pll_clock *clk_pll = to_clk_pll(hw);
> +
> + if (clk_pll->get_rate)
> + return to_clk_pll(hw)->get_rate(parent_rate);
> +
> + return 0;
> +}
> +
> +/* round operation not supported */
> +static long samsung_pll_clock_round_rate(struct clk_hw *hw, unsigned long drate,
> + unsigned long *prate)
> +{
> + return samsung_pll_clock_recalc_rate(hw, *prate);
> +}
> +
> +/* set the clock output rate of the pll */
> +static int samsung_pll_clock_set_rate(struct clk_hw *hw, unsigned long drate,
> + unsigned long prate)
> +{
> + struct samsung_pll_clock *clk_pll = to_clk_pll(hw);
> +
> + if (clk_pll->set_rate)
> + return to_clk_pll(hw)->set_rate(drate);
> +
> + return 0;
> +}
> +
> +/* clock operations for samsung pll clock type */
> +static const struct clk_ops samsung_pll_clock_ops = {
> + .recalc_rate = samsung_pll_clock_recalc_rate,
> + .round_rate = samsung_pll_clock_round_rate,
> + .set_rate = samsung_pll_clock_set_rate,
> +};
> +
> +/* register a samsung pll type clock */
> +void __init samsung_clk_register_pll(const char *name, const char **pnames,
> + struct device_node *np,
> + int (*set_rate)(unsigned long rate),
> + unsigned long (*get_rate)(unsigned long rate))
> +{
> + struct samsung_pll_clock *clk_pll;
> + struct clk *clk;
> + struct clk_init_data init;
> + int ret;
> +
> + clk_pll = kzalloc(sizeof(*clk_pll), GFP_KERNEL);
> + if (!clk_pll) {
> + pr_err("%s: could not allocate pll clk %s\n", __func__, name);
> + return;
> + }
> +
> + init.name = name;
> + init.ops = &samsung_pll_clock_ops;
> + init.flags = CLK_GET_RATE_NOCACHE;
> + init.parent_names = pnames;
> + init.num_parents = 1;
> +
> + clk_pll->set_rate = set_rate;
> + clk_pll->get_rate = get_rate;
> + clk_pll->hw.init = &init;
> +
> + /* register the clock */
> + clk = clk_register(NULL, &clk_pll->hw);
> + if (IS_ERR(clk)) {
> + pr_err("%s: failed to register pll clock %s\n", __func__,
> + name);
> + kfree(clk_pll);
> + return;
> + }
> +
> +#ifdef CONFIG_OF
> + if (np)
> + of_clk_add_provider(np, of_clk_src_simple_get, clk);
> +#endif
Is it really required to do clk_register() and of_clk_add_provider() for
each single clock ? This seems more heavy than it could be. Looking at
drivers/clk/mxs/clk-imx28.c, it registers only single clock provider for
whole group of clocks. Also, couldn't we statically define most of the
clocks and still register them so they can be used with platforms using
FDT ? Something along the lines of imx28 implementation (arch/arm/boot/dts
/imx28.dtsi), where a clock is specified at consumer device node by
a phandle to the clock controller node and a clock index ?
Besides that, what bothers me with in the current approach is the
clock consumers being defined through one big data structure together
with the actual clocks. Not all clock objects are going to have
consumers, some resources are waisted by using flat tables of those
big data structure objects. Perhaps we could use two tables, one for the
platform clocks and one for the consumers ? These common clock driver
is intended to cover all Samsung SoC, I would expect all samsung
sub-archs getting converted to use it eventually, with as many of them
as possible then reworked to support device tree. It's a lot of work
and is going to take some time, but it would be good to have it planned
in advance. That said I'm not sure the common samsung clock driver in
non-dt variant would be really a temporary thing.
> + /*
> + * Register a clock lookup for the pll-type clock even if this
> + * has been instantiated from device tree. This helps to do
> + * clk_get() lookup on this clock for pruposes of displaying its
> + * clock speed at boot time.
> + */
> + ret = clk_register_clkdev(clk, name, NULL);
> + if (ret)
> + pr_err("%s: failed to register clock lookup for %s", __func__,
> + name);
> +}
> +
> +#ifdef CONFIG_OF
> +/* register a samsung pll type clock instantiated from device tree */
> +void __init samsung_of_clk_register_pll(struct device_node *np)
> +{
> + const char *clk_name = np->name;
> + const char *parent_name;
> +
> + of_property_read_string(np, "clock-output-names", &clk_name);
> + parent_name = of_clk_get_parent_name(np, 0);
> + samsung_clk_register_pll(clk_name, &parent_name, np, NULL, NULL);
> +}
> +#endif
> +
> +/*
> + * Allow platform specific implementations to attach set_rate and get_rate
> + * callbacks for the pll type clock. Typical calling sequence..
> + *
> + * struct clk *clk = clk_get(NULL, "pll-clk-name");
> + * samsung_pll_clk_set_cb(clk, pll_set_rate, pll_get_rate);
> + */
> +void __init samsung_pll_clk_set_cb(struct clk *clk,
> + int (*set_rate)(unsigned long rate),
> + unsigned long (*get_rate)(unsigned long rate))
> +{
> + struct samsung_pll_clock *clk_pll;
> + struct clk_hw *hw = __clk_get_hw(clk);
> +
> + clk_pll = to_clk_pll(hw);
> + clk_pll->set_rate = set_rate;
> + clk_pll->get_rate = get_rate;
> +}
> +
> +/* register a list of fixed clocks (used only for non-dt platforms) */
> +void __init samsung_clk_register_fixed_rate(
> + struct samsung_fixed_rate_clock *clk_list, unsigned int nr_clk)
> +{
> + struct clk *clk;
> + unsigned int idx, ret;
> +
> + for (idx = 0; idx < nr_clk; idx++, clk_list++) {
> + clk = clk_register_fixed_rate(NULL, clk_list->name, NULL,
> + clk_list->flags, clk_list->fixed_rate);
> + if (IS_ERR(clk)) {
> + pr_err("%s: failed to register clock %s\n", __func__,
> + clk_list->name);
> + continue;
> + }
> +
> + /*
> + * Register a lookup which will help in clk_get() and
> + * printing the clock rate during clock initialization.
> + */
> + ret = clk_register_clkdev(clk, clk_list->name,
> + clk_list->dev_name);
> + if (ret)
> + pr_err("clock: failed to register clock lookup for %s",
> + clk_list->name);
> + }
> +}
> +
> +/* register a list of mux clocks */
> +void __init samsung_clk_register_mux(struct samsung_mux_clock *clk_list,
> + unsigned int nr_clk)
> +{
> + struct clk *clk;
> + unsigned int idx, ret;
> +
> + for (idx = 0; idx < nr_clk; idx++, clk_list++) {
> + clk = clk_register_mux(NULL, clk_list->name,
> + clk_list->parent_names, clk_list->num_parents,
> + clk_list->flags, clk_list->reg, clk_list->shift,
> + clk_list->width, clk_list->mux_flags, &lock);
> + if (IS_ERR(clk)) {
> + pr_err("%s: failed to register clock %s\n", __func__,
> + clk_list->name);
> + continue;
> + }
> +
> +#ifdef CONFIG_OF
> + if (clk_list->np)
> + of_clk_add_provider(clk_list->np, of_clk_src_simple_get,
> + clk);
> +#endif
> +
> + ret = clk_register_clkdev(clk, clk_list->name,
> + clk_list->dev_name);
> + if (ret)
> + pr_err("%s: failed to register clock lookup for %s",
> + __func__, clk_list->name);
> +
> + if (clk_list->alias) {
> + ret = clk_register_clkdev(clk, clk_list->alias,
> + clk_list->dev_name);
> + if (ret)
> + pr_err("%s: failed to register lookup %s\n",
> + __func__, clk_list->alias);
> + }
> + }
> +}
> +
> +#ifdef CONFIG_OF
> +/* register a samsung mux type clock instantiated from device tree */
> +void __init samsung_of_clk_register_mux(struct device_node *np)
> +{
> + struct samsung_mux_clock mux_clk;
> + const char *clk_name = np->name;
> + const char *parent_names[MAX_PARENT_CLKS];
> + u32 reg_info[3];
> + int idx = 0;
> +
> + of_property_read_string(np, "clock-output-names", &clk_name);
> + do {
> + /* get names of all parent clocks */
> + parent_names[idx] = of_clk_get_parent_name(np, idx);
> + idx++;
> + } while (parent_names[idx-1]);
> +
> + if (of_property_read_u32_array(np, "reg-info", reg_info, 3))
> + pr_err("%s: invalid register info in node\n", __func__);
> +
> + mux_clk.name = clk_name;
> + mux_clk.parent_names = parent_names;
> + mux_clk.num_parents = idx - 1;
> + mux_clk.reg = (void __iomem *)(reg_base + reg_info[0]);
> + mux_clk.shift = reg_info[1];
> + mux_clk.width = reg_info[2];
> + mux_clk.dev_name = NULL;
> + mux_clk.flags = 0;
> + mux_clk.mux_flags = 0;
> + mux_clk.alias = NULL;
> + mux_clk.np = np;
> +
> + if (!strcmp(mux_clk.name, "fin_pll"))
> + mux_clk.reg = reg_fin_pll;
> +
> + samsung_clk_register_mux(&mux_clk, 1);
> +}
> +#endif
> +
> +/* register a list of div clocks */
> +void __init samsung_clk_register_div(struct samsung_div_clock *clk_list,
> + unsigned int nr_clk)
> +{
> + struct clk *clk;
> + unsigned int idx, ret;
> +
> + for (idx = 0; idx < nr_clk; idx++, clk_list++) {
> + clk = clk_register_divider(NULL, clk_list->name,
> + clk_list->parent_name, clk_list->flags, clk_list->reg,
> + clk_list->shift, clk_list->width, clk_list->div_flags,
> + &lock);
> + if (IS_ERR(clk)) {
> + pr_err("clock: failed to register clock %s\n",
> + clk_list->name);
> + continue;
> + }
> +
> +#ifdef CONFIG_OF
> + if (clk_list->np)
> + of_clk_add_provider(clk_list->np, of_clk_src_simple_get,
> + clk);
> +#endif
> +
> + ret = clk_register_clkdev(clk, clk_list->name,
> + clk_list->dev_name);
> + if (ret)
> + pr_err("%s: failed to register clock lookup for %s",
> + __func__, clk_list->name);
> +
> + if (clk_list->alias) {
> + ret = clk_register_clkdev(clk, clk_list->alias,
> + clk_list->dev_name);
> + if (ret)
> + pr_err("%s: failed to register lookup %s\n",
> + __func__, clk_list->alias);
> + }
> + }
> +}
> +
> +#ifdef CONFIG_OF
> +/* register a samsung div type clock instantiated from device tree */
> +void __init samsung_of_clk_register_div(struct device_node *np)
> +{
> + struct samsung_div_clock clk_div;
> + const char *clk_name = np->name;
> + const char *parent_name;
> + u32 reg_info[3];
> +
> + of_property_read_string(np, "clock-output-names", &clk_name);
> + parent_name = of_clk_get_parent_name(np, 0);
> + if (of_property_read_u32_array(np, "reg-info", reg_info, 3))
> + pr_err("%s: invalid register info in node\n", __func__);
> +
> + clk_div.name = clk_name;
> + clk_div.parent_name = parent_name;
> + clk_div.reg = (void __iomem *)(reg_base + reg_info[0]);
> + clk_div.shift = reg_info[1];
> + clk_div.width = reg_info[2];
> + clk_div.dev_name = NULL;
> + clk_div.flags = 0;
> + clk_div.div_flags = 0;
> + clk_div.alias = NULL;
> + clk_div.np = np;
> +
> + samsung_clk_register_div(&clk_div, 1);
> +}
> +#endif
> +
> +/* register a list of gate clocks */
> +void __init samsung_clk_register_gate(struct samsung_gate_clock *clk_list,
> + unsigned int nr_clk)
> +{
> + struct clk *clk;
> + unsigned int idx, ret;
> +
> + for (idx = 0; idx < nr_clk; idx++, clk_list++) {
> + clk = clk_register_gate(NULL, clk_list->name,
> + clk_list->parent_name, clk_list->flags, clk_list->reg,
> + clk_list->bit_idx, clk_list->gate_flags, &lock);
> + if (IS_ERR(clk)) {
> + pr_err("clock: failed to register clock %s\n",
> + clk_list->name);
> + continue;
> + }
> +
> +#ifdef CONFIG_OF
> + if (clk_list->np)
> + of_clk_add_provider(clk_list->np, of_clk_src_simple_get,
> + clk);
> +#endif
> +
> + ret = clk_register_clkdev(clk, clk_list->name,
> + clk_list->dev_name);
> + if (ret)
> + pr_err("%s: failed to register clock lookup for %s",
> + __func__, clk_list->name);
> +
> + if (clk_list->alias) {
> + ret = clk_register_clkdev(clk, clk_list->alias,
> + clk_list->dev_name);
> + if (ret)
> + pr_err("%s: failed to register lookup %s\n",
> + __func__, clk_list->alias);
> + }
> + }
> +}
> +
> +#ifdef CONFIG_OF
> +/* register a samsung gate type clock instantiated from device tree */
> +void __init samsung_of_clk_register_gate(struct device_node *np)
> +{
> + struct samsung_gate_clock clk_gate;
> + const char *clk_name = np->name;
> + const char *parent_name;
> + u32 reg_info[2];
> +
> + of_property_read_string(np, "clock-output-names", &clk_name);
> + parent_name = of_clk_get_parent_name(np, 0);
> + if (of_property_read_u32_array(np, "reg-info", reg_info, 2))
> + pr_err("%s: invalid register info in node\n", __func__);
> +
> + clk_gate.name = clk_name;
> + clk_gate.parent_name = parent_name;
> + clk_gate.reg = (void __iomem *)(reg_base + reg_info[0]);
> + clk_gate.bit_idx = reg_info[1];
> + clk_gate.dev_name = NULL;
> + clk_gate.flags = 0;
> + clk_gate.gate_flags = 0;
Some clocks need CLK_SET_RATE_PARENT for the drivers to work
as before. So far it is not set for any mux, div nor gate clock.
> + clk_gate.alias = NULL;
> + clk_gate.np = np;
> +
> + samsung_clk_register_gate(&clk_gate, 1);
> +}
> +#endif
> +
--
Thanks,
Sylwester
^ permalink raw reply
* [PATCHv2] Input: omap4-keypad: Add pinctrl support
From: Dmitry Torokhov @ 2012-10-22 15:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350911580-20307-1-git-send-email-sourav.poddar@ti.com>
Hi Sourav,
On Mon, Oct 22, 2012 at 06:43:00PM +0530, Sourav Poddar wrote:
> Adapt keypad to use pinctrl framework.
>
> Tested on omap4430 sdp with 3.7-rc1 kernel.
I do not see anything in the driver that would directly use pinctrl. Is
there a better place to select default pin configuration; maybe when
instantiating platform device?
Thanks.
>
> Cc: Felipe Balbi <balbi@ti.com>
> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> Signed-off-by: Sourav Poddar <sourav.poddar@ti.com>
> ---
> v1->v2
> - Added "PROBE_DEFER" check
> drivers/input/keyboard/omap4-keypad.c | 11 +++++++++++
> 1 files changed, 11 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
> index c05f98c..502b832 100644
> --- a/drivers/input/keyboard/omap4-keypad.c
> +++ b/drivers/input/keyboard/omap4-keypad.c
> @@ -31,6 +31,7 @@
> #include <linux/input.h>
> #include <linux/slab.h>
> #include <linux/pm_runtime.h>
> +#include <linux/pinctrl/consumer.h>
>
> #include <linux/platform_data/omap4-keypad.h>
>
> @@ -76,6 +77,7 @@ enum {
>
> struct omap4_keypad {
> struct input_dev *input;
> + struct pinctrl *pins;
>
> void __iomem *base;
> unsigned int irq;
> @@ -298,6 +300,15 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
> goto err_release_mem;
> }
>
> + keypad_data->pins = devm_pinctrl_get_select_default(&pdev->dev);
> + if (IS_ERR(keypad_data->pins)) {
> + if (PTR_ERR(keypad_data->pins) == -EPROBE_DEFER)
> + return -EPROBE_DEFER;
> +
> + dev_warn(&pdev->dev, "did not get pins for keypad error: %li\n",
> + PTR_ERR(keypad_data->pins));
> + keypad_data->pins = NULL;
> + }
>
> /*
> * Enable clocks for the keypad module so that we can read
> --
> 1.7.1
>
--
Dmitry
^ 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