* [PATCH V3 3/3] clocksource: time-armada-370-xp converted to clk framework
From: Gregory CLEMENT @ 2012-10-15 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350303499-30868-1-git-send-email-gregory.clement@free-electrons.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
arch/arm/boot/dts/armada-370-db.dts | 4 ----
arch/arm/boot/dts/armada-370-xp.dtsi | 1 +
drivers/clocksource/time-armada-370-xp.c | 11 ++++++-----
3 files changed, 7 insertions(+), 9 deletions(-)
diff --git a/arch/arm/boot/dts/armada-370-db.dts b/arch/arm/boot/dts/armada-370-db.dts
index fffd5c2..4a31b03 100644
--- a/arch/arm/boot/dts/armada-370-db.dts
+++ b/arch/arm/boot/dts/armada-370-db.dts
@@ -34,9 +34,5 @@
clock-frequency = <200000000>;
status = "okay";
};
- timer at d0020300 {
- clock-frequency = <600000000>;
- status = "okay";
- };
};
};
diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi
index 16cc82c..94b4b9e 100644
--- a/arch/arm/boot/dts/armada-370-xp.dtsi
+++ b/arch/arm/boot/dts/armada-370-xp.dtsi
@@ -62,6 +62,7 @@
compatible = "marvell,armada-370-xp-timer";
reg = <0xd0020300 0x30>;
interrupts = <37>, <38>, <39>, <40>;
+ clocks = <&coreclk 2>;
};
addr-decoding at d0020000 {
diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c
index 4674f94..a4605fd 100644
--- a/drivers/clocksource/time-armada-370-xp.c
+++ b/drivers/clocksource/time-armada-370-xp.c
@@ -18,6 +18,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
+#include <linux/clk.h>
#include <linux/timer.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h>
@@ -167,7 +168,6 @@ void __init armada_370_xp_timer_init(void)
u32 u;
struct device_node *np;
unsigned int timer_clk;
- int ret;
np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer");
timer_base = of_iomap(np, 0);
WARN_ON(!timer_base);
@@ -179,13 +179,14 @@ void __init armada_370_xp_timer_init(void)
timer_base + TIMER_CTRL_OFF);
timer_clk = 25000000;
} else {
- u32 clk = 0;
- ret = of_property_read_u32(np, "clock-frequency", &clk);
- WARN_ON(!clk || ret < 0);
+ unsigned long rate = 0;
+ struct clk *clk = of_clk_get(np, 0);
+ WARN_ON(IS_ERR(clk));
+ rate = clk_get_rate(clk);
u = readl(timer_base + TIMER_CTRL_OFF);
writel(u & ~(TIMER0_25MHZ | TIMER1_25MHZ),
timer_base + TIMER_CTRL_OFF);
- timer_clk = clk / TIMER_DIVIDER;
+ timer_clk = rate / TIMER_DIVIDER;
}
/* We use timer 0 as clocksource, and timer 1 for
--
1.7.9.5
^ permalink raw reply related
* [PATCH V3 2/3] clk: armada-370-xp: add support for clock framework
From: Gregory CLEMENT @ 2012-10-15 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350303499-30868-1-git-send-email-gregory.clement@free-electrons.com>
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
arch/arm/boot/dts/armada-370.dtsi | 12 +++++++++
arch/arm/boot/dts/armada-xp.dtsi | 48 +++++++++++++++++++++++++++++++++++
arch/arm/mach-mvebu/Kconfig | 5 ++++
arch/arm/mach-mvebu/armada-370-xp.c | 8 +++++-
arch/arm/mach-mvebu/common.h | 1 +
5 files changed, 73 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/armada-370.dtsi b/arch/arm/boot/dts/armada-370.dtsi
index 2069151..ac495b4 100644
--- a/arch/arm/boot/dts/armada-370.dtsi
+++ b/arch/arm/boot/dts/armada-370.dtsi
@@ -75,5 +75,17 @@
#interrupts-cells = <2>;
interrupts = <91>;
};
+ coreclk: mvebu-sar at d0018230 {
+ #clock-cells = <1>;
+ reg = <0xd0018230 0x08>;
+ compatible = "marvell,armada-370-core-clockctrl";
+ clock-output-names =
+ "tclk", /* 0 */
+ "pclk", /* 1 */
+ "nbclk", /* 2 */
+ "hclk", /* 3 */
+ "dramclk"; /* 4 */
+ };
+
};
};
diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi
index 71d6b5d..a564b52 100644
--- a/arch/arm/boot/dts/armada-xp.dtsi
+++ b/arch/arm/boot/dts/armada-xp.dtsi
@@ -27,6 +27,35 @@
<0xd0021870 0x58>;
};
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu at 0 {
+ compatible = "marvell,sheeva-v7";
+ reg = <0>;
+ clocks = <&cpuclk 0>;
+ };
+
+ cpu at 1 {
+ compatible = "marvell,sheeva-v7";
+ reg = <1>;
+ clocks = <&cpuclk 1>;
+ };
+
+ cpu at 2 {
+ compatible = "marvell,sheeva-v7";
+ reg = <2>;
+ clocks = <&cpuclk 2>;
+ };
+
+ cpu at 3 {
+ compatible = "marvell,sheeva-v7";
+ reg = <3>;
+ clocks = <&cpuclk 3>;
+ };
+ };
+
soc {
serial at d0012200 {
compatible = "ns16550";
@@ -47,6 +76,25 @@
marvell,timer-25Mhz;
};
+ coreclk: mvebu-sar at d0018230 {
+ #clock-cells = <1>;
+ reg = <0xd0018230 0x08>;
+ compatible = "marvell,armada-xp-core-clockctrl";
+ clock-output-names =
+ "tclk", /* 0 */
+ "pclk", /* 1 */
+ "nbclk", /* 2 */
+ "hclk", /* 3 */
+ "dramclk"; /* 4 */
+ };
+
+ cpuclk: clock-complex at d0018700 {
+ #clock-cells = <1>;
+ compatible = "marvell,armada-xp-cpu-clockctrl";
+ reg = <0xd0018700 0xA0>;
+ clocks = <&coreclk 1>;
+ };
+
system-controller at d0018200 {
compatible = "marvell,armada-370-xp-system-controller";
reg = <0xd0018200 0x500>;
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index 416d46e..17d246b 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -9,11 +9,16 @@ config ARCH_MVEBU
select PINCTRL
select PLAT_ORION
select SPARSE_IRQ
+ select CLKDEV_LOOKUP
+ select MVEBU_CLK_CPU
if ARCH_MVEBU
menu "Marvell SOC with device tree"
+config MVEBU_CLK_CPU
+ bool
+
config MACH_ARMADA_370_XP
bool
select ARMADA_370_XP_TIMER
diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c
index 49d7915..2af6ce5 100644
--- a/arch/arm/mach-mvebu/armada-370-xp.c
+++ b/arch/arm/mach-mvebu/armada-370-xp.c
@@ -37,8 +37,14 @@ void __init armada_370_xp_map_io(void)
iotable_init(armada_370_xp_io_desc, ARRAY_SIZE(armada_370_xp_io_desc));
}
+void __init armada_370_xp_timer_and_clk_init(void)
+{
+ mvebu_clocks_init();
+ armada_370_xp_timer_init();
+}
+
struct sys_timer armada_370_xp_timer = {
- .init = armada_370_xp_timer_init,
+ .init = armada_370_xp_timer_and_clk_init,
};
static void __init armada_370_xp_dt_init(void)
diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h
index 02f89ea..281fab3 100644
--- a/arch/arm/mach-mvebu/common.h
+++ b/arch/arm/mach-mvebu/common.h
@@ -16,6 +16,7 @@
#define __ARCH_MVEBU_COMMON_H
void mvebu_restart(char mode, const char *cmd);
+void mvebu_clocks_init(void);
void armada_370_xp_init_irq(void);
void armada_370_xp_handle_irq(struct pt_regs *regs);
--
1.7.9.5
^ permalink raw reply related
* [PATCH V3 1/3] clk: mvebu: add armada-370-xp specific clocks
From: Gregory CLEMENT @ 2012-10-15 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350303499-30868-1-git-send-email-gregory.clement@free-electrons.com>
Add Armada 370/XP specific clocks: core clocks and CPU clocks.
The CPU clocks are only for Armada XP for the SMP mode.
The core clocks are clocks which have their rate set during reset. The
code was written with the other SoCs of the mvebu family in
mind. Adding them should be pretty straight forward. For a new
SoC, only 3 binding have to be added:
- one to provide the tclk frequency
- one to provde the pclk frequency
- and one to provide the ratio between the pclk and the children
clocks
Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
.../devicetree/bindings/clock/mvebu-core-clock.txt | 40 +++
.../devicetree/bindings/clock/mvebu-cpu-clock.txt | 21 ++
drivers/clk/Makefile | 1 +
drivers/clk/mvebu/Makefile | 2 +
drivers/clk/mvebu/clk-core.c | 312 ++++++++++++++++++++
drivers/clk/mvebu/clk-core.h | 19 ++
drivers/clk/mvebu/clk-cpu.c | 155 ++++++++++
drivers/clk/mvebu/clk-cpu.h | 19 ++
drivers/clk/mvebu/clk.c | 36 +++
9 files changed, 605 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
create mode 100644 Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt
create mode 100644 drivers/clk/mvebu/Makefile
create mode 100644 drivers/clk/mvebu/clk-core.c
create mode 100644 drivers/clk/mvebu/clk-core.h
create mode 100644 drivers/clk/mvebu/clk-cpu.c
create mode 100644 drivers/clk/mvebu/clk-cpu.h
create mode 100644 drivers/clk/mvebu/clk.c
diff --git a/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
new file mode 100644
index 0000000..d2e0965
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
@@ -0,0 +1,40 @@
+Device Tree Clock bindings for core clock of Marvell EBU platforms
+
+This is the binding for the "core" clock of the mvebu SoCs, the rate
+of this clocks are fixed during reset. Their value or ratio are taken
+from the Sample at Reset(SAR) register.
+
+Required properties:
+- compatible : shall be one of the following:
+ "marvell,armada-370-core-clockctrl" - core clock for Armada 370
+ "marvell,armada-xp-core-clockctrl" - core clock for Armada XP
+- reg : Address and length of the SAR register set
+- #clock-cells : should be set to 1.
+- clock-output-names: A list of clock output names that mvebu core
+ clocks provides. The full list of all valid clock names, IDs and
+ description are below.
+ Name ID Description
+ tclk 0 Peripheral clock
+ pclk 1 CPU clock
+ nbclk 2 L2 clock
+ hclk 3 DRAM control clock
+ dramclk 4 DDR clock
+
+coreclk: mvebu-sar at d0018230 {
+ #clock-cells = <1>;
+ reg = <0xd0018230 0x08>;
+ compatible = "marvell,armada-370-core-clockctrl";
+ clock-output-names =
+ "tclk", /* 0 */
+ "pclk", /* 1 */
+ "nbclk", /* 2 */
+ "hclk", /* 3 */
+ "dramclk", /* 4 */
+};
+
+timer at d0020300 {
+ compatible = "marvell,armada-370-xp-timer";
+ reg = <0xd0020300 0x30>;
+ interrupts = <37>, <38>, <39>, <40>;
+ clocks = <&coreclk 0>;
+};
diff --git a/Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt
new file mode 100644
index 0000000..c524618
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt
@@ -0,0 +1,21 @@
+Device Tree Clock bindings for cpu clock of Marvell EBU platforms
+
+Required properties:
+- compatible : shall be one of the following:
+ "marvell,armada-xp-cpu-clockctrl" - cpu clocks for Armada XP
+- reg : Address and length of the clock complex register set
+- #clock-cells : should be set to 1.
+- clocks : shall be the input parent clock phandle for the clock.
+
+cpuclk: clock-complex at d0018700 {
+ #clock-cells = <1>;
+ compatible = "marvell,armada-xp-cpu-clockctrl";
+ reg = <0xd0018700 0xA0>;
+ clocks = <&coreclk 1>;
+}
+
+cpu at 0 {
+ compatible = "marvell,sheeva-v7";
+ reg = <0>;
+ clocks = <&cpuclk 0>;
+};
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 71a25b9..9c91d6c 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_PLAT_SPEAR) += spear/
obj-$(CONFIG_ARCH_U300) += clk-u300.o
obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/
obj-$(CONFIG_ARCH_PRIMA2) += clk-prima2.o
+obj-$(CONFIG_ARCH_MVEBU) += mvebu/
ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/
endif
diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile
new file mode 100644
index 0000000..de94a87
--- /dev/null
+++ b/drivers/clk/mvebu/Makefile
@@ -0,0 +1,2 @@
+obj-y += clk.o clk-core.o
+obj-$(CONFIG_MVEBU_CLK_CPU) += clk-cpu.o
diff --git a/drivers/clk/mvebu/clk-core.c b/drivers/clk/mvebu/clk-core.c
new file mode 100644
index 0000000..155f493
--- /dev/null
+++ b/drivers/clk/mvebu/clk-core.c
@@ -0,0 +1,312 @@
+/*
+ * Marvell EBU clock core handling defined at reset
+ *
+ * Copyright (C) 2012 Marvell
+ *
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+/* Sample At Reset is a 64 bit bitfiled split in two register of 32
+ * bits*/
+
+#define SARL 0 /* Low part [0:31] */
+#define SARL_AXP_PCLK_FREQ_OPT 21
+#define SARL_AXP_PCLK_FREQ_OPT_MASK 0x7
+#define SARL_A370_PCLK_FREQ_OPT 11
+#define SARL_A370_PCLK_FREQ_OPT_MASK 0xF
+#define SARL_AXP_FAB_FREQ_OPT 24
+#define SARL_AXP_FAB_FREQ_OPT_MASK 0xF
+#define SARL_A370_FAB_FREQ_OPT 15
+#define SARL_A370_FAB_FREQ_OPT_MASK 0x1F
+#define SARL_A370_TCLK_FREQ_OPT 20
+#define SARL_A370_TCLK_FREQ_OPT_MASK 0x1
+#define SARH 4 /* High part [32:63] */
+#define SARH_AXP_PCLK_FREQ_OPT (52-32)
+#define SARH_AXP_PCLK_FREQ_OPT_MASK 0x1
+#define SARH_AXP_PCLK_FREQ_OPT_SHIFT 3
+#define SARH_AXP_FAB_FREQ_OPT (51-32)
+#define SARH_AXP_FAB_FREQ_OPT_MASK 0x1
+#define SARH_AXP_FAB_FREQ_OPT_SHIFT 4
+
+u32 *sar_reg;
+int sar_reg_size;
+
+enum core_clk {
+ tclk, pclk, nbclk, hclk, dramclk, clk_max
+};
+
+struct core_clk_fn {
+ u32(*get_tclk_freq) (void);
+ u32(*get_pck_freq) (void);
+ const int *(*get_fab_freq_opt) (void);
+};
+
+/* Ratio between VCO and each of the member in the following order:
+ CPU clock, L2 clock, DRAM controler clock, DDR clcok */
+static const int reset_core_ratio[32][4] = {
+ [0x01] = {1, 2, 2, 2},
+ [0x02] = {2, 2, 6, 3},
+ [0x03] = {2, 2, 3, 3},
+ [0x04] = {1, 2, 3, 3},
+ [0x05] = {1, 2, 4, 2},
+ [0x06] = {1, 1, 2, 2},
+ [0x07] = {2, 3, 6, 6},
+ [0x09] = {1, 2, 6, 3},
+ [0x0A] = {2, 4, 10, 5},
+ [0x0C] = {1, 2, 4, 4},
+ [0x0F] = {2, 2, 5, 5},
+ [0x13] = {1, 1, 2, 1},
+ [0x14] = {2, 3, 6, 3},
+ [0x1B] = {1, 1, 1, 1},
+};
+
+static struct clk *clks[clk_max];
+
+static struct clk_onecell_data clk_data;
+
+/* Frequency in MHz*/
+static u32 armada_370_pclk[] = { 400, 533, 667, 800, 1000, 1067, 1200 };
+
+static u32 armada_xp_pclk[] = { 1000, 1066, 1200, 1333, 1500, 1666,
+ 1800, 2000, 667, 0, 800, 1600
+};
+
+static u32 armada_370_tclk[] = { 166, 200 };
+
+static const int *__init armada_370_get_fab_freq_opt(void)
+{
+ u8 fab_freq_opt = 0;
+
+ fab_freq_opt = ((sar_reg[0] >> SARL_A370_FAB_FREQ_OPT) &
+ SARL_A370_FAB_FREQ_OPT_MASK);
+
+ if (reset_core_ratio[fab_freq_opt][0] == 0)
+ return NULL;
+ else
+ return reset_core_ratio[fab_freq_opt];
+}
+
+static u32 __init armada_370_get_pck_freq(void)
+{
+ u32 cpu_freq;
+ u8 cpu_freq_select = 0;
+
+ cpu_freq_select = ((sar_reg[0] >> SARL_A370_PCLK_FREQ_OPT) &
+ SARL_A370_PCLK_FREQ_OPT_MASK);
+ if (cpu_freq_select > ARRAY_SIZE(armada_370_pclk)) {
+ pr_err("CPU freq select unsuported %d\n", cpu_freq_select);
+ cpu_freq = 0;
+ } else
+ cpu_freq = armada_370_pclk[cpu_freq_select];
+
+ return cpu_freq * 1000 * 1000;
+}
+
+static u32 __init armada_370_get_tclk_freq(void)
+{
+ u32 tclk_freq;
+ u8 tclk_freq_select = 0;
+
+ tclk_freq_select = ((sar_reg[0] >> SARL_A370_TCLK_FREQ_OPT) &
+ SARL_A370_TCLK_FREQ_OPT_MASK);
+ if (tclk_freq_select > ARRAY_SIZE(armada_370_tclk)) {
+ pr_err("TCLK freq select unsuported %d\n", tclk_freq_select);
+ tclk_freq = 0;
+ } else
+ tclk_freq = armada_370_tclk[tclk_freq_select];
+
+ return tclk_freq * 1000 * 1000;
+}
+
+static const int *__init armada_xp_get_fab_freq_opt(void)
+{
+ u8 fab_freq_opt = 0;
+
+ fab_freq_opt = ((sar_reg[0] >> SARL_AXP_FAB_FREQ_OPT) &
+ SARL_AXP_FAB_FREQ_OPT_MASK);
+ /* The upper bit is not contiguous to the other ones
+ * and located in the high part of the SAR
+ * registers */
+ fab_freq_opt |= (((sar_reg[1] >> SARH_AXP_FAB_FREQ_OPT) &
+ SARH_AXP_FAB_FREQ_OPT_MASK)
+ << SARH_AXP_FAB_FREQ_OPT_SHIFT);
+
+ if (reset_core_ratio[fab_freq_opt][0] == 0)
+ return NULL;
+ else
+ return reset_core_ratio[fab_freq_opt];
+}
+
+static u32 __init armada_xp_get_pck_freq(void)
+{
+ u32 cpu_freq;
+ u8 cpu_freq_select = 0;
+
+ cpu_freq_select = ((sar_reg[0] >> SARL_AXP_PCLK_FREQ_OPT) &
+ SARL_AXP_PCLK_FREQ_OPT_MASK);
+ /* The upper bit is not contiguous to the other ones
+ * and located in the high part of the SAR
+ * registers */
+ cpu_freq_select |= (((sar_reg[1] >> SARH_AXP_PCLK_FREQ_OPT) &
+ SARH_AXP_PCLK_FREQ_OPT_MASK)
+ << SARH_AXP_PCLK_FREQ_OPT_SHIFT);
+ if (cpu_freq_select > ARRAY_SIZE(armada_xp_pclk)) {
+ pr_err("CPU freq select unsuported: %d\n", cpu_freq_select);
+ cpu_freq = 0;
+ } else
+ cpu_freq = armada_xp_pclk[cpu_freq_select];
+
+ return cpu_freq * 1000 * 1000;
+}
+
+/* For Armada XP TCLK frequency is fix: 250MHz */
+static u32 __init armada_xp_get_tclk_freq(void)
+{
+ return 250 * 1000 * 1000;
+}
+
+void __init of_core_clk_setup(struct device_node *node,
+ struct core_clk_fn clk_fn)
+{
+ struct clk *clk;
+ unsigned long rate;
+ const char *clk_name;
+ int i;
+
+ /* clock 0 is tclk */
+ of_property_read_string_index(node, "clock-output-names", tclk,
+ &clk_name);
+ rate = clk_fn.get_tclk_freq();
+ if (rate != 0)
+ clk = clk_register_fixed_rate(NULL, clk_name, NULL,
+ CLK_IS_ROOT, rate);
+ else {
+ pr_err("Invalid freq for %s\n", clk_name);
+ return;
+ }
+
+ if (WARN_ON(IS_ERR(clk)))
+ return;
+ clks[tclk] = clk;
+
+ /* clock 1 is pclk */
+ of_property_read_string_index(node, "clock-output-names", pclk,
+ &clk_name);
+ rate = clk_fn.get_pck_freq();
+ if (rate != 0)
+ clk = clk_register_fixed_rate(NULL, clk_name, NULL,
+ CLK_IS_ROOT, rate);
+ else {
+ pr_err("Invalid freq for %s\n", clk_name);
+ return;
+ }
+ if (WARN_ON(IS_ERR(clk)))
+ return;
+ clks[pclk] = clk;
+
+ /* the clocks 2 to 4 are nbclk, hclk and dramclk and are all
+ * derivated from the clock 1: pclk */
+
+ for (i = nbclk; i <= dramclk; i++) {
+ const int *ratio = clk_fn.get_fab_freq_opt();
+ const char *parent_clk_name;
+
+ of_property_read_string_index(node, "clock-output-names",
+ i, &clk_name);
+ of_property_read_string_index(node, "clock-output-names",
+ pclk, &parent_clk_name);
+
+ if (ratio != NULL)
+ clk = clk_register_fixed_factor(NULL, clk_name,
+ parent_clk_name, 0,
+ ratio[0],
+ ratio[i - nbclk + 1]);
+ else {
+ pr_err("Invalid clk ratio for %s\n", clk_name);
+ return;
+ }
+
+ if (WARN_ON(IS_ERR(clk)))
+ return;
+ clks[i] = clk;
+ }
+ clk_data.clk_num = ARRAY_SIZE(clks);
+ clk_data.clks = clks;
+ of_clk_add_provider(node, of_clk_src_onecell_get, &clk_data);
+}
+
+static struct core_clk_fn armada_370_clk_fn = {
+ .get_tclk_freq = armada_370_get_tclk_freq,
+ .get_pck_freq = armada_370_get_pck_freq,
+ .get_fab_freq_opt = armada_370_get_fab_freq_opt,
+};
+
+static struct core_clk_fn armada_xp_clk_fn = {
+ .get_tclk_freq = armada_xp_get_tclk_freq,
+ .get_pck_freq = armada_xp_get_pck_freq,
+ .get_fab_freq_opt = armada_xp_get_fab_freq_opt,
+};
+
+static const __initconst struct of_device_id clk_match[] = {
+ {
+ .compatible = "marvell,armada-370-core-clockctrl",
+ .data = &armada_370_clk_fn,
+ },
+
+ {
+ .compatible = "marvell,armada-xp-core-clockctrl",
+ .data = &armada_xp_clk_fn,
+ },
+ {
+ /* sentinel */
+ }
+};
+
+void __init mvebu_core_clocks_init(void)
+{
+ struct device_node *np;
+ struct resource res;
+ void __iomem *sar_base;
+ int i;
+
+ np = of_find_node_by_name(NULL, "mvebu-sar");
+
+ if (!np)
+ goto err;
+
+ if (of_address_to_resource(np, 0, &res))
+ goto err;
+
+ sar_reg_size = resource_size(&res);
+ sar_reg = kmalloc(sar_reg_size, GFP_KERNEL);
+
+ sar_base = ioremap(res.start, sar_reg_size);
+ if (sar_base == NULL)
+ goto err;
+ for (i = 0; i < sar_reg_size; i += sizeof(*sar_reg))
+ sar_reg[i] = readl(sar_base + i);
+
+ iounmap(sar_base);
+
+ for_each_matching_node(np, clk_match) {
+ const struct of_device_id *match = of_match_node(clk_match, np);
+ struct core_clk_fn *clk_fn = (struct core_clk_fn *)match->data;
+ of_core_clk_setup(np, *clk_fn);
+ }
+
+ return;
+err:
+ pr_err("%s:SAR base adresse not set in DT\n", __func__);
+ return;
+}
diff --git a/drivers/clk/mvebu/clk-core.h b/drivers/clk/mvebu/clk-core.h
new file mode 100644
index 0000000..a04f80b
--- /dev/null
+++ b/drivers/clk/mvebu/clk-core.h
@@ -0,0 +1,19 @@
+/*
+ * * Marvell EBU clock core handling defined at reset
+ *
+ * Copyright (C) 2012 Marvell
+ *
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MVEBU_CLK_CORE_H
+#define __MVEBU_CLK_CORE_H
+
+void __init of_core_clk_setup(struct device_node *node);
+void __init mvebu_core_clocks_init(void);
+
+#endif
diff --git a/drivers/clk/mvebu/clk-cpu.c b/drivers/clk/mvebu/clk-cpu.c
new file mode 100644
index 0000000..6b5c841
--- /dev/null
+++ b/drivers/clk/mvebu/clk-cpu.c
@@ -0,0 +1,155 @@
+/*
+ * Marvell MVEBU CPU clock handling.
+ *
+ * Copyright (C) 2012 Marvell
+ *
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+
+#define SYS_CTRL_CLK_DIVIDER_CTRL_OFFSET 0x0
+#define SYS_CTRL_CLK_DIVIDER_VALUE_OFFSET 0xC
+#define SYS_CTRL_CLK_DIVIDER_MASK 0x3F
+
+#define MAX_CPU 4
+struct cpu_clk {
+ struct clk_hw hw;
+ int cpu;
+ const char *clk_name;
+ const char *parent_name;
+ void __iomem *reg_base;
+};
+
+static struct clk **clks;
+
+static struct clk_onecell_data clk_data;
+
+#define to_cpu_clk(p) container_of(p, struct cpu_clk, hw)
+
+static unsigned long clk_cpu_recalc_rate(struct clk_hw *hwclk,
+ unsigned long parent_rate)
+{
+ struct cpu_clk *cpuclk = to_cpu_clk(hwclk);
+ u32 reg, div;
+
+ reg = readl(cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_VALUE_OFFSET);
+ div = (reg >> (cpuclk->cpu * 8)) & SYS_CTRL_CLK_DIVIDER_MASK;
+ return parent_rate / div;
+}
+
+static long clk_cpu_round_rate(struct clk_hw *hwclk, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ /* Valid ratio are 1:1, 1:2 and 1:3 */
+ u32 div;
+
+ div = *parent_rate / rate;
+ if (div == 0)
+ div = 1;
+ else if (div > 3)
+ div = 3;
+
+ return *parent_rate / div;
+}
+
+static int clk_cpu_set_rate(struct clk_hw *hwclk, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct cpu_clk *cpuclk = to_cpu_clk(hwclk);
+ u32 reg, div;
+ u32 reload_mask;
+
+ div = parent_rate / rate;
+ reg = (readl(cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_VALUE_OFFSET)
+ & (~(SYS_CTRL_CLK_DIVIDER_MASK << (cpuclk->cpu * 8))))
+ | (div << (cpuclk->cpu * 8));
+ writel(reg, cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_VALUE_OFFSET);
+ /* Set clock divider reload smooth bit mask */
+ reload_mask = 1 << (20 + cpuclk->cpu);
+
+ reg = readl(cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_CTRL_OFFSET)
+ | reload_mask;
+ writel(reg, cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_CTRL_OFFSET);
+
+ /* Now trigger the clock update */
+ reg = readl(cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_CTRL_OFFSET)
+ | 1 << 24;
+ writel(reg, cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_CTRL_OFFSET);
+
+ /* Wait for clocks to settle down then clear reload request */
+ udelay(1000);
+ reg &= ~(reload_mask | 1 << 24);
+ writel(reg, cpuclk->reg_base + SYS_CTRL_CLK_DIVIDER_CTRL_OFFSET);
+ udelay(1000);
+
+ return 0;
+}
+
+static const struct clk_ops cpu_ops = {
+ .recalc_rate = clk_cpu_recalc_rate,
+ .round_rate = clk_cpu_round_rate,
+ .set_rate = clk_cpu_set_rate,
+};
+
+void __init of_cpu_clk_setup(struct device_node *node)
+{
+ struct cpu_clk *cpuclk;
+ void __iomem *clock_complex_base = of_iomap(node, 0);
+ int cpu;
+ if (clock_complex_base == NULL) {
+ pr_err("%s: clock-complex base register not set\n",
+ __func__);
+ return;
+ }
+
+ cpuclk = kzalloc(MAX_CPU * sizeof(*cpuclk), GFP_KERNEL);
+ clks = kzalloc(MAX_CPU * sizeof(*clks), GFP_KERNEL);
+
+ if (WARN_ON(!cpuclk))
+ return;
+ for (cpu = 0; cpu < MAX_CPU; cpu++) {
+ struct clk_init_data init;
+ struct clk *clk;
+ struct clk *parent_clk;
+ char *clk_name = kzalloc(5, GFP_KERNEL);
+
+ sprintf(clk_name, "cpu%d", cpu);
+ parent_clk = of_clk_get(node, 0);
+
+ cpuclk[cpu].parent_name = __clk_get_name(parent_clk);
+ cpuclk[cpu].clk_name = clk_name;
+ cpuclk[cpu].cpu = cpu;
+ cpuclk[cpu].reg_base = clock_complex_base;
+ cpuclk[cpu].hw.init = &init;
+
+ init.name = cpuclk[cpu].clk_name;
+ init.ops = &cpu_ops;
+ init.flags = 0;
+ init.parent_names = &cpuclk[cpu].parent_name;
+ init.num_parents = 1;
+
+ clk = clk_register(NULL, &cpuclk[cpu].hw);
+ if (WARN_ON(IS_ERR(clk)))
+ goto bail_out;
+ clks[cpu] = clk;
+ }
+ clk_data.clk_num = MAX_CPU;
+ clk_data.clks = clks;
+ of_clk_add_provider(node, of_clk_src_onecell_get, &clk_data);
+
+ return;
+bail_out:
+ kfree(clks);
+ kfree(cpuclk);
+}
diff --git a/drivers/clk/mvebu/clk-cpu.h b/drivers/clk/mvebu/clk-cpu.h
new file mode 100644
index 0000000..5d28356
--- /dev/null
+++ b/drivers/clk/mvebu/clk-cpu.h
@@ -0,0 +1,19 @@
+/*
+ * Marvell MVEBU CPU clock handling.
+ *
+ * Copyright (C) 2012 Marvell
+ *
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MVEBU_CLK_CPU_H
+#define __MVEBU_CLK_CPU_H
+
+void __init of_cpu_clk_setup(struct device_node *node);
+void __init mvebu_cpu_clocks_init(void);
+
+#endif
diff --git a/drivers/clk/mvebu/clk.c b/drivers/clk/mvebu/clk.c
new file mode 100644
index 0000000..0864df7
--- /dev/null
+++ b/drivers/clk/mvebu/clk.c
@@ -0,0 +1,36 @@
+/*
+ * Marvell EBU SoC clock handling.
+ *
+ * Copyright (C) 2012 Marvell
+ *
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/of.h>
+#include "clk-cpu.h"
+#include "clk-core.h"
+
+static const __initconst struct of_device_id clk_match[] = {
+#ifdef CONFIG_MVEBU_CLK_CPU
+ {
+ .compatible = "marvell,armada-xp-cpu-clockctrl",
+ .data = of_cpu_clk_setup,
+ },
+#endif
+ {
+ /* sentinel */
+ }
+};
+
+void __init mvebu_clocks_init(void)
+{
+ mvebu_core_clocks_init();
+ of_clk_init(clk_match);
+}
--
1.7.9.5
^ permalink raw reply related
* [PATCH V3 0/3] Add clock framework for armada 370/XP
From: Gregory CLEMENT @ 2012-10-15 12:18 UTC (permalink / raw)
To: linux-arm-kernel
Hello Mike,
The v3.7-rc1 was released yesterday. So here it is the updated version
of my patch set. The rebase was flawless. An I have just fixed a typo
in the device tree and warnings from checkpatch. I built and test it
for the Armada 370 and Armada XP evaluation board.
The purpose of this patch set is to add support for clock framework
for Armada 370 and Armada XP SoCs. All the support is done under the
directory drivers/clk/mvebu/ as the support for other mvebu SoCs was
in mind during the writing of the code.
Two kinds of clocks are added:
- The CPU clocks are only for Armada XP (which is multi-core)
- The core clocks are clocks which have their rate fixed during
reset.
Many thanks to Thomas Petazzoni and Sebastian Hesselbarth for their
review and feedback. The device tree bindings were really improved
with the advices of Sebastian.
Changelog:
V2 -> V3:
- Rebased on top of v3.7-rc1
- Fixed a typo in device trees
- Fixed warning from checkpatch
V1 -> V2:
- Improved the spelling and the wording of the documentation and the
1st commit log
- Removed the "end_of_list" name which are unused here.
- Fix the cpu clock by using of_clk_src_onecell_get in the same way it
was used for the core clocks
Regards,
Gregory CLEMENT (3):
clk: mvebu: add armada-370-xp specific clocks
clk: armada-370-xp: add support for clock framework
clocksource: time-armada-370-xp converted to clk framework
.../devicetree/bindings/clock/mvebu-core-clock.txt | 40 +++
.../devicetree/bindings/clock/mvebu-cpu-clock.txt | 21 ++
arch/arm/boot/dts/armada-370-db.dts | 4 -
arch/arm/boot/dts/armada-370-xp.dtsi | 1 +
arch/arm/boot/dts/armada-370.dtsi | 12 +
arch/arm/boot/dts/armada-xp.dtsi | 48 +++
arch/arm/mach-mvebu/Kconfig | 5 +
arch/arm/mach-mvebu/armada-370-xp.c | 8 +-
arch/arm/mach-mvebu/common.h | 1 +
drivers/clk/Makefile | 1 +
drivers/clk/mvebu/Makefile | 2 +
drivers/clk/mvebu/clk-core.c | 312 ++++++++++++++++++++
drivers/clk/mvebu/clk-core.h | 19 ++
drivers/clk/mvebu/clk-cpu.c | 155 ++++++++++
drivers/clk/mvebu/clk-cpu.h | 19 ++
drivers/clk/mvebu/clk.c | 36 +++
drivers/clocksource/time-armada-370-xp.c | 11 +-
17 files changed, 685 insertions(+), 10 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/mvebu-core-clock.txt
create mode 100644 Documentation/devicetree/bindings/clock/mvebu-cpu-clock.txt
create mode 100644 drivers/clk/mvebu/Makefile
create mode 100644 drivers/clk/mvebu/clk-core.c
create mode 100644 drivers/clk/mvebu/clk-core.h
create mode 100644 drivers/clk/mvebu/clk-cpu.c
create mode 100644 drivers/clk/mvebu/clk-cpu.h
create mode 100644 drivers/clk/mvebu/clk.c
--
1.7.9.5
^ permalink raw reply
* [GIT PULL] OMAP-GPMC cleanup for common zImage
From: Afzal Mohammed @ 2012-10-15 12:14 UTC (permalink / raw)
To: linux-arm-kernel
The following changes since commit ddffeb8c4d0331609ef2581d84de4d763607bd37:
Linux 3.7-rc1 (2012-10-14 14:41:04 -0700)
are available in the git repository at:
git at gitorious.org:x0148406-public/linux-kernel.git tags/gpmc-czimage
for you to fetch changes up to 3ef5d0071cf6c8b9a00b559232bb700ad59999d7:
ARM: OMAP2+: gpmc: localize gpmc header (2012-10-15 14:42:15 +0530)
----------------------------------------------------------------
gpmc cleanup for common ARM zImage
----------------------------------------------------------------
Afzal Mohammed (16):
ARM: OMAP2+: nand: unify init functions
ARM: OMAP2+: onenand: refactor for clarity
ARM: OMAP2+: gpmc: remove cs# in sync clk div calc
mtd: onenand: omap: cleanup gpmc dependency
mtd: nand: omap: free region as per resource size
mtd: nand: omap: read nand using register address
ARM: OMAP2+: onenand: connected soc info in pdata
mtd: onenand: omap: use pdata info instead of cpu_is
ARM: OMAP2+: onenand: header cleanup
ARM: OMAP2+: nand: header cleanup
mtd: nand: omap: bring in gpmc nand macros
ARM: OMAP2+: nand: bch capability check
ARM: OMAP2+: gpmc: nand register helper bch update
mtd: nand: omap: handle gpmc bch[48]
ARM: OMAP2+: gpmc: remove exported nand functions
ARM: OMAP2+: gpmc: localize gpmc header
Jon Hunter (1):
ARM: OMAP2+: GPMC: Remove unused OneNAND get_freq() platform function
arch/arm/mach-omap2/board-2430sdp.c | 2 +-
arch/arm/mach-omap2/board-3430sdp.c | 2 +-
arch/arm/mach-omap2/board-apollon.c | 2 +-
arch/arm/mach-omap2/board-cm-t35.c | 5 +-
arch/arm/mach-omap2/board-cm-t3517.c | 5 +-
arch/arm/mach-omap2/board-devkit8000.c | 10 +-
arch/arm/mach-omap2/board-flash.c | 50 +--
arch/arm/mach-omap2/board-flash.h | 8 +-
arch/arm/mach-omap2/board-h4.c | 2 +-
arch/arm/mach-omap2/board-igep0020.c | 5 +-
arch/arm/mach-omap2/board-ldp.c | 6 +-
arch/arm/mach-omap2/board-n8x0.c | 1 +
arch/arm/mach-omap2/board-omap3beagle.c | 10 +-
arch/arm/mach-omap2/board-omap3evm.c | 8 +-
arch/arm/mach-omap2/board-omap3logic.c | 2 +-
arch/arm/mach-omap2/board-omap3pandora.c | 3 +-
arch/arm/mach-omap2/board-omap3stalker.c | 2 +-
arch/arm/mach-omap2/board-omap3touchbook.c | 10 +-
arch/arm/mach-omap2/board-overo.c | 9 +-
arch/arm/mach-omap2/board-rm680.c | 3 +-
arch/arm/mach-omap2/board-rx51-peripherals.c | 3 +-
arch/arm/mach-omap2/board-rx51.c | 2 +-
arch/arm/mach-omap2/board-zoom-debugboard.c | 2 +-
arch/arm/mach-omap2/board-zoom.c | 5 +-
arch/arm/mach-omap2/common-board-devices.c | 46 ---
arch/arm/mach-omap2/common-board-devices.h | 1 -
arch/arm/mach-omap2/gpmc-nand.c | 85 ++--
arch/arm/mach-omap2/gpmc-nand.h | 27 ++
arch/arm/mach-omap2/gpmc-onenand.c | 214 +++++-----
arch/arm/mach-omap2/gpmc-onenand.h | 24 ++
arch/arm/mach-omap2/gpmc-smc91x.c | 2 +-
arch/arm/mach-omap2/gpmc-smsc911x.c | 2 +-
arch/arm/mach-omap2/gpmc.c | 459 +--------------------
.../{plat-omap/include/plat => mach-omap2}/gpmc.h | 61 +--
arch/arm/mach-omap2/pm34xx.c | 2 +-
arch/arm/mach-omap2/usb-tusb6010.c | 2 +-
drivers/mtd/nand/omap2.c | 125 +++++-
drivers/mtd/onenand/omap2.c | 9 +-
include/linux/platform_data/mtd-nand-omap2.h | 46 ++-
include/linux/platform_data/mtd-onenand-omap2.h | 28 +-
40 files changed, 493 insertions(+), 797 deletions(-)
create mode 100644 arch/arm/mach-omap2/gpmc-nand.h
create mode 100644 arch/arm/mach-omap2/gpmc-onenand.h
rename arch/arm/{plat-omap/include/plat => mach-omap2}/gpmc.h (67%)
^ permalink raw reply
* [PATCH 9/9] ARM: add uprobes support
From: Rabin Vincent @ 2012-10-15 11:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121015111443.GA2006@linaro.org>
2012/10/15 Dave Martin <dave.martin@linaro.org>:
> On Sun, Oct 14, 2012 at 09:23:13PM +0200, Rabin Vincent wrote:
>> Add basic uprobes support for ARM.
>>
>> perf probe --exec and SystemTap's userspace probing work. The ARM
>> kprobes test code has also been run in a userspace harness to test the
>> uprobe instruction decoding.
>
> The assumption that the target code is ARM appears to be buried all over
> the place.
Right, as stated:
>> Caveats:
>> - Thumb is not supported
> Certainly this code as currently written must depend on !THUMB2_KERNEL.
Why? It currently works for ARM userspace even if the kernel is
Thumb-2.
> However, there's an underlying problem here which we'd need to solve.
> The kprobes code can take advantage of the fact that the kernel is all
> ARM or (almost) all Thumb code. So there is no support for kprobes
> supporting ARM and Thumb at the same time.
>
> With userspace, we don't have this luxury. With Debian armhf, Ubuntu
> and Linaro building Thumb-2 userspaces, it may be an increasingly common
> configuration independently of whether the kernel is built in Thumb-2
> or not.
>
> Furthermode, there is no such thing as a pure Thumb-2 system in practice:
> PLTs are always ARM, for example. For uprobes to work well in userspace,
> both should be supported together.
Right. I don't think it's difficult to support both of them together,
my thought was just to have userspace tell us if they want to probe a
Thumb instruction via the usual 0th-bit set convention, and then take it
from there. I didn't do the Thumb handling currently because I didn't
really look into modifying the kprobes Thumb instruction decoding and
the IT handling for uprobes.
^ permalink raw reply
* [PATCH RESEND] serial/amba-pl011: use devm_* managed resources
From: Linus Walleij @ 2012-10-15 11:36 UTC (permalink / raw)
To: linux-arm-kernel
From: Linus Walleij <linus.walleij@linaro.org>
This switches a bunch of allocation and remapping to use the
devm_* garbage collected methods and cleans up the error
path and remove() paths consequently.
devm_ioremap() is only in <linux/io.h> so fix up the
erroneous <asm/*> include as well.
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
drivers/tty/serial/amba-pl011.c | 25 +++++++++----------------
1 file changed, 9 insertions(+), 16 deletions(-)
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index d7e1ede..7fca402 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -56,8 +56,7 @@
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/sizes.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
#define UART_NR 14
@@ -1973,7 +1972,8 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
goto out;
}
- uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
+ uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port),
+ GFP_KERNEL);
if (uap == NULL) {
ret = -ENOMEM;
goto out;
@@ -1981,16 +1981,17 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
i = pl011_probe_dt_alias(i, &dev->dev);
- base = ioremap(dev->res.start, resource_size(&dev->res));
+ base = devm_ioremap(&dev->dev, dev->res.start,
+ resource_size(&dev->res));
if (!base) {
ret = -ENOMEM;
- goto free;
+ goto out;
}
uap->pinctrl = devm_pinctrl_get(&dev->dev);
if (IS_ERR(uap->pinctrl)) {
ret = PTR_ERR(uap->pinctrl);
- goto unmap;
+ goto out;
}
uap->pins_default = pinctrl_lookup_state(uap->pinctrl,
PINCTRL_STATE_DEFAULT);
@@ -2002,10 +2003,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
if (IS_ERR(uap->pins_sleep))
dev_dbg(&dev->dev, "could not get sleep pinstate\n");
- uap->clk = clk_get(&dev->dev, NULL);
+ uap->clk = devm_clk_get(&dev->dev, NULL);
if (IS_ERR(uap->clk)) {
ret = PTR_ERR(uap->clk);
- goto unmap;
+ goto out;
}
uap->vendor = vendor;
@@ -2038,11 +2039,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
amba_set_drvdata(dev, NULL);
amba_ports[i] = NULL;
pl011_dma_remove(uap);
- clk_put(uap->clk);
- unmap:
- iounmap(base);
- free:
- kfree(uap);
}
out:
return ret;
@@ -2062,9 +2058,6 @@ static int pl011_remove(struct amba_device *dev)
amba_ports[i] = NULL;
pl011_dma_remove(uap);
- iounmap(uap->port.membase);
- clk_put(uap->clk);
- kfree(uap);
return 0;
}
--
1.7.11.3
^ permalink raw reply related
* [PATCH 9/9] ARM: add uprobes support
From: Dave Martin @ 2012-10-15 11:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350242593-17761-9-git-send-email-rabin@rab.in>
On Sun, Oct 14, 2012 at 09:23:13PM +0200, Rabin Vincent wrote:
> Add basic uprobes support for ARM.
>
> perf probe --exec and SystemTap's userspace probing work. The ARM
> kprobes test code has also been run in a userspace harness to test the
> uprobe instruction decoding.
The assumption that the target code is ARM appears to be buried all over
the place.
Certainly this code as currently written must depend on !THUMB2_KERNEL.
However, there's an underlying problem here which we'd need to solve.
The kprobes code can take advantage of the fact that the kernel is all
ARM or (almost) all Thumb code. So there is no support for kprobes
supporting ARM and Thumb at the same time.
With userspace, we don't have this luxury. With Debian armhf, Ubuntu
and Linaro building Thumb-2 userspaces, it may be an increasingly common
configuration independently of whether the kernel is built in Thumb-2
or not.
Furthermode, there is no such thing as a pure Thumb-2 system in practice:
PLTs are always ARM, for example. For uprobes to work well in userspace,
both should be supported together.
I only skimmed the patches fairly quickly, so apologies if you do in fact
handle this -- but I don't see any evidence of it right now.
Cheers
---Dave
>
> Caveats:
>
> - Thumb is not supported
> - XOL abort/trap handling is not implemented
>
> Signed-off-by: Rabin Vincent <rabin@rab.in>
> ---
> arch/arm/Kconfig | 4 +
> arch/arm/include/asm/ptrace.h | 6 ++
> arch/arm/include/asm/thread_info.h | 5 +-
> arch/arm/include/asm/uprobes.h | 34 +++++++
> arch/arm/kernel/Makefile | 1 +
> arch/arm/kernel/signal.c | 4 +
> arch/arm/kernel/uprobes.c | 191 ++++++++++++++++++++++++++++++++++++
> 7 files changed, 244 insertions(+), 1 deletion(-)
> create mode 100644 arch/arm/include/asm/uprobes.h
> create mode 100644 arch/arm/kernel/uprobes.c
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 272c3a1..2191b61d 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -168,6 +168,10 @@ config ZONE_DMA
> config NEED_DMA_MAP_STATE
> def_bool y
>
> +config ARCH_SUPPORTS_UPROBES
> + depends on KPROBES
> + def_bool y
> +
> config ARCH_HAS_DMA_SET_COHERENT_MASK
> bool
>
> diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
> index 142d6ae..297936a 100644
> --- a/arch/arm/include/asm/ptrace.h
> +++ b/arch/arm/include/asm/ptrace.h
> @@ -197,6 +197,12 @@ static inline long regs_return_value(struct pt_regs *regs)
>
> #define instruction_pointer(regs) (regs)->ARM_pc
>
> +static inline void instruction_pointer_set(struct pt_regs *regs,
> + unsigned long val)
> +{
> + instruction_pointer(regs) = val;
> +}
> +
> #ifdef CONFIG_SMP
> extern unsigned long profile_pc(struct pt_regs *regs);
> #else
> diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
> index 8477b4c..7bedaee 100644
> --- a/arch/arm/include/asm/thread_info.h
> +++ b/arch/arm/include/asm/thread_info.h
> @@ -148,6 +148,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
> #define TIF_SIGPENDING 0
> #define TIF_NEED_RESCHED 1
> #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */
> +#define TIF_UPROBE 7
> #define TIF_SYSCALL_TRACE 8
> #define TIF_SYSCALL_AUDIT 9
> #define TIF_SYSCALL_TRACEPOINT 10
> @@ -160,6 +161,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
> #define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
> #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
> #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
> +#define _TIF_UPROBE (1 << TIF_UPROBE)
> #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
> #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
> #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)
> @@ -172,7 +174,8 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
> /*
> * Change these and you break ASM code in entry-common.S
> */
> -#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | _TIF_NOTIFY_RESUME)
> +#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
> + _TIF_NOTIFY_RESUME | _TIF_UPROBE)
>
> #endif /* __KERNEL__ */
> #endif /* __ASM_ARM_THREAD_INFO_H */
> diff --git a/arch/arm/include/asm/uprobes.h b/arch/arm/include/asm/uprobes.h
> new file mode 100644
> index 0000000..fa4b81e
> --- /dev/null
> +++ b/arch/arm/include/asm/uprobes.h
> @@ -0,0 +1,34 @@
> +#ifndef _ASM_UPROBES_H
> +#define _ASM_UPROBES_H
> +
> +#include <asm/probes.h>
> +
> +typedef u32 uprobe_opcode_t;
> +
> +#define MAX_UINSN_BYTES 4
> +#define UPROBE_XOL_SLOT_BYTES 64
> +
> +#define UPROBE_SWBP_INSN 0x07f001f9
> +#define UPROBE_SS_INSN 0x07f001fa
> +#define UPROBE_SWBP_INSN_SIZE 4
> +
> +struct arch_uprobe_task {
> + u32 backup;
> +};
> +
> +struct arch_uprobe {
> + u8 insn[MAX_UINSN_BYTES];
> + uprobe_opcode_t modinsn;
> + uprobe_opcode_t bpinsn;
> + bool simulate;
> + u32 pcreg;
> + void (*prehandler)(struct arch_uprobe *auprobe,
> + struct arch_uprobe_task *autask,
> + struct pt_regs *regs);
> + void (*posthandler)(struct arch_uprobe *auprobe,
> + struct arch_uprobe_task *autask,
> + struct pt_regs *regs);
> + struct arch_specific_insn asi;
> +};
> +
> +#endif
> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
> index 5bbec7b..a39f634 100644
> --- a/arch/arm/kernel/Makefile
> +++ b/arch/arm/kernel/Makefile
> @@ -40,6 +40,7 @@ obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o
> obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o
> obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o
> obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
> +obj-$(CONFIG_UPROBES) += uprobes.o uprobes-arm.o kprobes-arm.o
> obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o patch.o
> ifdef CONFIG_THUMB2_KERNEL
> obj-$(CONFIG_KPROBES) += kprobes-thumb.o
> diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
> index 56f72d2..3b1e88e 100644
> --- a/arch/arm/kernel/signal.c
> +++ b/arch/arm/kernel/signal.c
> @@ -12,6 +12,7 @@
> #include <linux/personality.h>
> #include <linux/uaccess.h>
> #include <linux/tracehook.h>
> +#include <linux/uprobes.h>
>
> #include <asm/elf.h>
> #include <asm/cacheflush.h>
> @@ -655,6 +656,9 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
> return restart;
> }
> syscall = 0;
> + } else if (thread_flags & _TIF_UPROBE) {
> + clear_thread_flag(TIF_UPROBE);
> + uprobe_notify_resume(regs);
> } else {
> clear_thread_flag(TIF_NOTIFY_RESUME);
> tracehook_notify_resume(regs);
> diff --git a/arch/arm/kernel/uprobes.c b/arch/arm/kernel/uprobes.c
> new file mode 100644
> index 0000000..f25a4af
> --- /dev/null
> +++ b/arch/arm/kernel/uprobes.c
> @@ -0,0 +1,191 @@
> +/*
> + * Copyright (C) 2012 Rabin Vincent <rabin@rab.in>
> + *
> + * 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.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/sched.h>
> +#include <linux/uprobes.h>
> +#include <linux/notifier.h>
> +#include <linux/kprobes.h>
> +
> +#include <asm/opcodes.h>
> +#include <asm/traps.h>
> +
> +#include "kprobes.h"
> +
> +bool is_swbp_insn(uprobe_opcode_t *insn)
> +{
> + return (__mem_to_opcode_arm(*insn) & 0x0fffffff) == UPROBE_SWBP_INSN;
> +}
> +
> +bool arch_uprobe_ignore(struct arch_uprobe *auprobe, struct pt_regs *regs)
> +{
> + if (!auprobe->asi.insn_check_cc(regs->ARM_cpsr)) {
> + regs->ARM_pc += 4;
> + return true;
> + }
> +
> + return false;
> +}
> +
> +bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
> +{
> + struct kprobe kp;
> +
> + if (!auprobe->simulate)
> + return false;
> +
> + kp.addr = (void *) regs->ARM_pc;
> + kp.opcode = __mem_to_opcode_arm(*(unsigned int *) auprobe->insn);
> + kp.ainsn.insn_handler = auprobe->asi.insn_handler;
> +
> + auprobe->asi.insn_singlestep(&kp, regs);
> +
> + return true;
> +}
> +
> +int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
> + unsigned long addr)
> +{
> + unsigned int insn;
> + unsigned int bpinsn;
> + enum kprobe_insn ret;
> +
> + /* Thumb not yet support */
> + if (addr & 0x3)
> + return -EINVAL;
> +
> + insn = __mem_to_opcode_arm(*(unsigned int *)auprobe->insn);
> + auprobe->modinsn = insn;
> +
> + ret = arm_kprobe_decode_insn(insn, &auprobe->asi, true);
> + switch (ret) {
> + case INSN_REJECTED:
> + return -EINVAL;
> +
> + case INSN_GOOD_NO_SLOT:
> + auprobe->simulate = true;
> + break;
> +
> + case INSN_GOOD:
> + default:
> + break;
> + }
> +
> + bpinsn = UPROBE_SWBP_INSN;
> + if (insn >= 0xe0000000)
> + bpinsn |= 0xe0000000; /* Unconditional instruction */
> + else
> + bpinsn |= insn & 0xf0000000; /* Copy condition from insn */
> +
> + auprobe->bpinsn = bpinsn;
> +
> + return 0;
> +}
> +
> +void arch_uprobe_write_opcode(struct arch_uprobe *auprobe, void *vaddr,
> + uprobe_opcode_t opcode)
> +{
> + unsigned long *addr = vaddr;
> +
> + if (opcode == UPROBE_SWBP_INSN)
> + opcode = __opcode_to_mem_arm(auprobe->bpinsn);
> +
> + *addr = opcode;
> +}
> +
> +void arch_uprobe_xol_copy(struct arch_uprobe *auprobe, void *vaddr)
> +{
> + unsigned long *addr = vaddr;
> +
> + addr[0] = __opcode_to_mem_arm(auprobe->modinsn);
> + addr[1] = __opcode_to_mem_arm(0xe0000000 | UPROBE_SS_INSN);
> +}
> +
> +int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
> +{
> + struct uprobe_task *utask = current->utask;
> +
> + if (auprobe->prehandler)
> + auprobe->prehandler(auprobe, &utask->autask, regs);
> +
> + regs->ARM_pc = utask->xol_vaddr;
> +
> + return 0;
> +}
> +
> +int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
> +{
> + struct uprobe_task *utask = current->utask;
> +
> + regs->ARM_pc = utask->vaddr + 4;
> +
> + if (auprobe->posthandler)
> + auprobe->posthandler(auprobe, &utask->autask, regs);
> +
> + return 0;
> +}
> +
> +bool arch_uprobe_xol_was_trapped(struct task_struct *t)
> +{
> + /* TODO: implement */
> + return false;
> +}
> +
> +void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
> +{
> + /* TODO: implement */
> +}
> +
> +int arch_uprobe_exception_notify(struct notifier_block *self,
> + unsigned long val, void *data)
> +{
> + return NOTIFY_DONE;
> +}
> +
> +static int uprobe_trap_handler(struct pt_regs *regs, unsigned int instr)
> +{
> + unsigned long flags;
> +
> + local_irq_save(flags);
> + if ((instr & 0x0fffffff) == UPROBE_SWBP_INSN)
> + uprobe_pre_sstep_notifier(regs);
> + else
> + uprobe_post_sstep_notifier(regs);
> + local_irq_restore(flags);
> +
> + return 0;
> +}
> +
> +unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
> +{
> + return instruction_pointer(regs);
> +}
> +
> +static struct undef_hook uprobes_arm_break_hook = {
> + .instr_mask = 0x0fffffff,
> + .instr_val = UPROBE_SWBP_INSN,
> + .cpsr_mask = MODE_MASK,
> + .cpsr_val = USR_MODE,
> + .fn = uprobe_trap_handler,
> +};
> +
> +static struct undef_hook uprobes_arm_ss_hook = {
> + .instr_mask = 0x0fffffff,
> + .instr_val = UPROBE_SS_INSN,
> + .cpsr_mask = MODE_MASK,
> + .cpsr_val = USR_MODE,
> + .fn = uprobe_trap_handler,
> +};
> +
> +int arch_uprobes_init(void)
> +{
> + register_undef_hook(&uprobes_arm_break_hook);
> + register_undef_hook(&uprobes_arm_ss_hook);
> +
> + return 0;
> +}
> --
> 1.7.9.5
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH] [media] s5p-csis: Added RAW data format as the supported format.
From: Sylwester Nawrocki @ 2012-10-15 11:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350294483-7417-1-git-send-email-r.solanki@samsung.com>
Hi Ritesh,
On 10/15/2012 11:48 AM, Ritesh Kumar Solanki wrote:
> csis can support jpeg, yuv and raw data format.
>
> Signed-off-by: Ritesh Kumar Solanki <r.solanki@samsung.com>
Thanks for the patch. I already have a patch adding all three
raw Bayer formats (SGRBG8/10/12) at the driver and I plan it
for v3.8. So I'd like to use it instead of your patch.
I'll post it as soon as I get my development branch cleaned up.
Regards,
Sylwester
> ---
> drivers/media/platform/s5p-fimc/mipi-csis.c | 4 ++++
> 1 files changed, 4 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c
> index 2f73d9e..0205ae4 100644
> --- a/drivers/media/platform/s5p-fimc/mipi-csis.c
> +++ b/drivers/media/platform/s5p-fimc/mipi-csis.c
> @@ -145,6 +145,10 @@ static const struct csis_pix_format s5pcsis_formats[] = {
> .code = V4L2_MBUS_FMT_JPEG_1X8,
> .fmt_reg = S5PCSIS_CFG_FMT_USER(1),
> .data_alignment = 32,
> + }, {
> + .code = V4L2_MBUS_FMT_SGRBG10_1X10,
> + .fmt_reg = S5PCSIS_CFG_FMT_RAW10,
> + .data_alignment = 24,
> },
> };
^ permalink raw reply
* [PATCH] MMC: fix sdhci-dove removal
From: Russell King - ARM Linux @ 2012-10-15 10:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121015103725.GQ21164@n2100.arm.linux.org.uk>
On Mon, Oct 15, 2012 at 11:37:25AM +0100, Russell King - ARM Linux wrote:
> On Mon, Oct 15, 2012 at 10:43:48AM +0100, Russell King - ARM Linux wrote:
> > 1. Unregister the device _BEFORE_ taking away any resources it may
> > be using.
> > 2. Don't check clks against NULL.
> >
> > Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
>
> Looking at this driver some more, who the hell came up with the sdhci
> registration interface? It violates one of the most fundamental
> principles of kernel driver programming. You do _NOT_ publish your
> driver interfaces _UNTIL_ you have finished setting your device up.
> Otherwise, in a preemptible or SMP kernel, your driver can be used
> before the initialization has completed.
>
> As this driver calls sdhci_pltfm_register() before it has obtained the
> clock for the interface, and this function does:
> sdhci_pltfm_init
> sdhci_add_host
> mmc_add_host
> mmc_start_host
> mmc_power_up
> mmc_set_ios
> sdhci_set_ios
>
> See, we're trying to power up and clock the card _before_ the dove
> sdhci driver has even claimed the clock let alone enabled it. This
> is total bollocks. The sdhci platform interface is total crap for
> creating this broken design in the first place. This is why MMC has
> the init + add interfaces, they're there to allow drivers to do stuff
> the Right(tm) way and avoid shit like the above.
>
> This should have been picked up at review time before the driver went
> into mainline. In any case, it needs to be fixed.
Here's an updated patch which just about fixes the sdhci-dove driver.
I would not be surprised given the idiotic sdhci-pltfm API if many
other drivers suffered the same bug.
8<====
From: Russell King <rmk+kernel@arm.linux.org.uk>
Subject: [PATCH] MMC: fix sdhci-dove probe/removal
1. Never ever publish a device in the system before it has been setup
to a usable state.
2. Unregister the device _BEFORE_ taking away any resources it may be
using.
3. Don't check clks against NULL.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/mmc/host/sdhci-dove.c | 36 ++++++++++++++++++------------------
1 files changed, 18 insertions(+), 18 deletions(-)
diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c
index a6e53a1..7d3a4e4 100644
--- a/drivers/mmc/host/sdhci-dove.c
+++ b/drivers/mmc/host/sdhci-dove.c
@@ -83,30 +83,31 @@ static int __devinit sdhci_dove_probe(struct platform_device *pdev)
struct sdhci_dove_priv *priv;
int ret;
- ret = sdhci_pltfm_register(pdev, &sdhci_dove_pdata);
- if (ret)
- goto sdhci_dove_register_fail;
-
priv = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_dove_priv),
GFP_KERNEL);
if (!priv) {
dev_err(&pdev->dev, "unable to allocate private data");
- ret = -ENOMEM;
- goto sdhci_dove_allocate_fail;
+ return -ENOMEM;
}
+ priv->clk = clk_get(&pdev->dev, NULL);
+ if (!IS_ERR(priv->clk))
+ clk_prepare_enable(priv->clk);
+
+ ret = sdhci_pltfm_register(pdev, &sdhci_dove_pdata);
+ if (ret)
+ goto sdhci_dove_register_fail;
+
host = platform_get_drvdata(pdev);
pltfm_host = sdhci_priv(host);
pltfm_host->priv = priv;
- priv->clk = clk_get(&pdev->dev, NULL);
- if (!IS_ERR(priv->clk))
- clk_prepare_enable(priv->clk);
return 0;
-sdhci_dove_allocate_fail:
- sdhci_pltfm_unregister(pdev);
sdhci_dove_register_fail:
+ clk_unprepare_disable(priv->clk);
+ clk_put(priv->clk);
+sdhci_dove_allocate_fail:
return ret;
}
@@ -116,14 +117,13 @@ static int __devexit sdhci_dove_remove(struct platform_device *pdev)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_dove_priv *priv = pltfm_host->priv;
- if (priv->clk) {
- if (!IS_ERR(priv->clk)) {
- clk_disable_unprepare(priv->clk);
- clk_put(priv->clk);
- }
- devm_kfree(&pdev->dev, priv->clk);
+ sdhci_pltfm_unregister(pdev);
+
+ if (!IS_ERR(priv->clk)) {
+ clk_disable_unprepare(priv->clk);
+ clk_put(priv->clk);
}
- return sdhci_pltfm_unregister(pdev);
+ return 0;
}
static struct platform_driver sdhci_dove_driver = {
--
1.7.4.4
^ permalink raw reply related
* [PATCH 1/1] MTD: atmel_nand: use devm_xxx gpio kzalloc, gpio and ioremap
From: Josh Wu @ 2012-10-15 10:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350129982-12106-1-git-send-email-plagnioj@jcrosoft.com>
Hi, J.C.
On 10/13/2012 8:06 PM, Jean-Christophe PLAGNIOL-VILLARD wrote:
> this will allow to simply the error and remove path
>
> Cc: linux-mtd at lists.infradead.org
> Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> ---
> drivers/mtd/nand/atmel_nand.c | 163 ++++++++++++++---------------------------
> 1 file changed, 54 insertions(+), 109 deletions(-)
>
> diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
> index 92623ac..2b43656 100644
> --- a/drivers/mtd/nand/atmel_nand.c
> +++ b/drivers/mtd/nand/atmel_nand.c
> @@ -364,43 +364,33 @@ static void __devinit __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
> table_size * sizeof(int16_t);
> }
>
> -static void pmecc_data_free(struct atmel_nand_host *host)
> -{
> - kfree(host->pmecc_partial_syn);
> - kfree(host->pmecc_si);
> - kfree(host->pmecc_lmu);
> - kfree(host->pmecc_smu);
> - kfree(host->pmecc_mu);
> - kfree(host->pmecc_dmu);
> - kfree(host->pmecc_delta);
> -}
> -
> static int __devinit pmecc_data_alloc(struct atmel_nand_host *host)
> {
> const int cap = host->pmecc_corr_cap;
> + int size;
> +
> + size = (2 * cap + 1) * sizeof(int16_t);
> + host->pmecc_partial_syn = devm_kzalloc(host->dev, size, GFP_KERNEL);
> + host->pmecc_si = devm_kzalloc(host->dev, size, GFP_KERNEL);
> + host->pmecc_lmu = devm_kzalloc(host->dev,
> + (cap + 1) * sizeof(int16_t), GFP_KERNEL);
> + host->pmecc_smu = devm_kzalloc(host->dev,
> + (cap + 2) * (2 * cap + 1) * sizeof(int16_t), GFP_KERNEL);
> + size = (cap + 1) * sizeof(int);
> + host->pmecc_mu = devm_kzalloc(host->dev, size, GFP_KERNEL);
> + host->pmecc_dmu = devm_kzalloc(host->dev, size, GFP_KERNEL);
> + host->pmecc_delta = devm_kzalloc(host->dev, size, GFP_KERNEL);
> +
> + if (!host->pmecc_partial_syn ||
> + !host->pmecc_si ||
> + !host->pmecc_lmu ||
> + !host->pmecc_smu ||
> + !host->pmecc_mu ||
> + !host->pmecc_dmu ||
> + !host->pmecc_delta)
> + return -ENOMEM;
>
> - host->pmecc_partial_syn = kzalloc((2 * cap + 1) * sizeof(int16_t),
> - GFP_KERNEL);
> - host->pmecc_si = kzalloc((2 * cap + 1) * sizeof(int16_t), GFP_KERNEL);
> - host->pmecc_lmu = kzalloc((cap + 1) * sizeof(int16_t), GFP_KERNEL);
> - host->pmecc_smu = kzalloc((cap + 2) * (2 * cap + 1) * sizeof(int16_t),
> - GFP_KERNEL);
> - host->pmecc_mu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
> - host->pmecc_dmu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
> - host->pmecc_delta = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
> -
> - if (host->pmecc_partial_syn &&
> - host->pmecc_si &&
> - host->pmecc_lmu &&
> - host->pmecc_smu &&
> - host->pmecc_mu &&
> - host->pmecc_dmu &&
> - host->pmecc_delta)
> - return 0;
> -
> - /* error happened */
> - pmecc_data_free(host);
> - return -ENOMEM;
> + return 0;
> }
>
> static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
> @@ -923,27 +913,25 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
> return 0;
> }
>
> - host->ecc = ioremap(regs->start, resource_size(regs));
> + host->ecc = devm_request_and_ioremap(&pdev->dev, regs);
> if (host->ecc == NULL) {
> dev_err(host->dev, "ioremap failed\n");
> err_no = -EIO;
> - goto err_pmecc_ioremap;
> + goto err;
> }
>
> regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2);
> regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
> if (regs_pmerr && regs_rom) {
> - host->pmerrloc_base = ioremap(regs_pmerr->start,
> - resource_size(regs_pmerr));
> - host->pmecc_rom_base = ioremap(regs_rom->start,
> - resource_size(regs_rom));
> + host->pmerrloc_base = devm_request_and_ioremap(&pdev->dev, regs_pmerr);
> + host->pmecc_rom_base = devm_request_and_ioremap(&pdev->dev, regs_rom);
> }
>
> if (!host->pmerrloc_base || !host->pmecc_rom_base) {
> dev_err(host->dev,
> "Can not get I/O resource for PMECC ERRLOC controller or ROM!\n");
> err_no = -EIO;
> - goto err_pmloc_ioremap;
> + goto err;
> }
>
> /* ECC is calculated for the whole page (1 step) */
> @@ -968,7 +956,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
> if (nand_chip->ecc.bytes > mtd->oobsize - 2) {
> dev_err(host->dev, "No room for ECC bytes\n");
> err_no = -EINVAL;
> - goto err_no_ecc_room;
> + goto err;
> }
> pmecc_config_ecc_layout(&atmel_pmecc_oobinfo,
> mtd->oobsize,
> @@ -993,7 +981,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
> if (err_no) {
> dev_err(host->dev,
> "Cannot allocate memory for PMECC computation!\n");
> - goto err_pmecc_data_alloc;
> + goto err;
> }
>
> nand_chip->ecc.read_page = atmel_nand_pmecc_read_page;
> @@ -1003,15 +991,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
>
> return 0;
>
> -err_pmecc_data_alloc:
> -err_no_ecc_room:
> -err_pmloc_ioremap:
> - iounmap(host->ecc);
> - if (host->pmerrloc_base)
> - iounmap(host->pmerrloc_base);
> - if (host->pmecc_rom_base)
> - iounmap(host->pmecc_rom_base);
> -err_pmecc_ioremap:
> +err:
> return err_no;
> }
>
> @@ -1315,7 +1295,7 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
> return 0;
> }
>
> - host->ecc = ioremap(regs->start, resource_size(regs));
> + host->ecc = devm_request_and_ioremap(&pdev->dev, regs);
> if (host->ecc == NULL) {
> dev_err(host->dev, "ioremap failed\n");
> return -EIO;
> @@ -1380,20 +1360,19 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
> }
>
> /* Allocate memory for the device structure (and zero it) */
> - host = kzalloc(sizeof(struct atmel_nand_host), GFP_KERNEL);
> + host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
> if (!host) {
> printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n");
> return -ENOMEM;
> }
>
> - host->io_phys = (dma_addr_t)mem->start;
> -
> - host->io_base = ioremap(mem->start, resource_size(mem));
> + host->io_base = devm_request_and_ioremap(&pdev->dev, mem);
> if (host->io_base == NULL) {
> printk(KERN_ERR "atmel_nand: ioremap failed\n");
> res = -EIO;
> goto err_nand_ioremap;
> }
> + host->io_phys = (dma_addr_t)mem->start;
>
> mtd = &host->mtd;
> nand_chip = &host->nand_chip;
> @@ -1401,7 +1380,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
> if (pdev->dev.of_node) {
> res = atmel_of_init_port(host, pdev->dev.of_node);
> if (res)
> - goto err_ecc_ioremap;
> + goto err_nand_ioremap;
> } else {
> memcpy(&host->board, pdev->dev.platform_data,
> sizeof(struct atmel_nand_data));
> @@ -1420,44 +1399,42 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
> if (IS_ERR(pinctrl)) {
> dev_err(host->dev, "Failed to request pinctrl\n");
> res = PTR_ERR(pinctrl);
I cannot apply the patch in latest l2-mtd git tree since above line of
code doesn't committed.
Seems that code is pinctrl related. Am I missing some patches?
Best Regards,
Josh Wu
> - goto err_ecc_ioremap;
> + goto err_nand_ioremap;
> }
>
> if (gpio_is_valid(host->board.rdy_pin)) {
> - res = gpio_request(host->board.rdy_pin, "nand_rdy");
> + res = devm_gpio_request(&pdev->dev,
> + host->board.rdy_pin, "nand_rdy");
> if (res < 0) {
> dev_err(&pdev->dev,
> - "can't request rdy gpio %d\n",
> - host->board.rdy_pin);
> - goto err_ecc_ioremap;
> + "can't request rdy gpio %d\n", host->board.rdy_pin);
> + goto err_nand_ioremap;
> }
>
> res = gpio_direction_input(host->board.rdy_pin);
> if (res < 0) {
> dev_err(&pdev->dev,
> - "can't request input direction rdy gpio %d\n",
> - host->board.rdy_pin);
> - goto err_ecc_ioremap;
> + "can't request input direction rdy gpio %d\n", host->board.rdy_pin);
> + goto err_nand_ioremap;
> }
>
> nand_chip->dev_ready = atmel_nand_device_ready;
> }
>
> if (gpio_is_valid(host->board.enable_pin)) {
> - res = gpio_request(host->board.enable_pin, "nand_enable");
> + res = devm_gpio_request(&pdev->dev,
> + host->board.enable_pin, "nand_enable");
> if (res < 0) {
> dev_err(&pdev->dev,
> - "can't request enable gpio %d\n",
> - host->board.enable_pin);
> - goto err_ecc_ioremap;
> + "can't request enable gpio %d\n", host->board.enable_pin);
> + goto err_nand_ioremap;
> }
>
> res = gpio_direction_output(host->board.enable_pin, 1);
> if (res < 0) {
> dev_err(&pdev->dev,
> - "can't request output direction enable gpio %d\n",
> - host->board.enable_pin);
> - goto err_ecc_ioremap;
> + "can't request output direction enable gpio %d\n", host->board.enable_pin);
> + goto err_nand_ioremap;
> }
> }
>
> @@ -1474,19 +1451,18 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
> atmel_nand_enable(host);
>
> if (gpio_is_valid(host->board.det_pin)) {
> - res = gpio_request(host->board.det_pin, "nand_det");
> + res = devm_gpio_request(&pdev->dev,
> + host->board.det_pin, "nand_det");
> if (res < 0) {
> dev_err(&pdev->dev,
> - "can't request det gpio %d\n",
> - host->board.det_pin);
> + "can't request det gpio %d\n", host->board.det_pin);
> goto err_no_card;
> }
>
> res = gpio_direction_input(host->board.det_pin);
> if (res < 0) {
> dev_err(&pdev->dev,
> - "can't request input direction det gpio %d\n",
> - host->board.det_pin);
> + "can't request input direction det gpio %d\n", host->board.det_pin);
> goto err_no_card;
> }
>
> @@ -1552,16 +1528,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
> return res;
>
> err_scan_tail:
> - if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) {
> + if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW)
> pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
> - pmecc_data_free(host);
> - }
> - if (host->ecc)
> - iounmap(host->ecc);
> - if (host->pmerrloc_base)
> - iounmap(host->pmerrloc_base);
> - if (host->pmecc_rom_base)
> - iounmap(host->pmecc_rom_base);
> err_hw_ecc:
> err_scan_ident:
> err_no_card:
> @@ -1569,10 +1537,7 @@ err_no_card:
> platform_set_drvdata(pdev, NULL);
> if (host->dma_chan)
> dma_release_channel(host->dma_chan);
> -err_ecc_ioremap:
> - iounmap(host->io_base);
> err_nand_ioremap:
> - kfree(host);
> return res;
> }
>
> @@ -1592,31 +1557,11 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
> pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
> pmerrloc_writel(host->pmerrloc_base, ELDIS,
> PMERRLOC_DISABLE);
> - pmecc_data_free(host);
> }
>
> - if (gpio_is_valid(host->board.det_pin))
> - gpio_free(host->board.det_pin);
> -
> - if (gpio_is_valid(host->board.enable_pin))
> - gpio_free(host->board.enable_pin);
> -
> - if (gpio_is_valid(host->board.rdy_pin))
> - gpio_free(host->board.rdy_pin);
> -
> - if (host->ecc)
> - iounmap(host->ecc);
> - if (host->pmecc_rom_base)
> - iounmap(host->pmecc_rom_base);
> - if (host->pmerrloc_base)
> - iounmap(host->pmerrloc_base);
> -
> if (host->dma_chan)
> dma_release_channel(host->dma_chan);
>
> - iounmap(host->io_base);
> - kfree(host);
> -
> return 0;
> }
>
^ permalink raw reply
* [PATCHv4] Input: keypad: Add smsc ece1099 keypad driver
From: Sourav @ 2012-10-15 10:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1349421986-12467-1-git-send-email-sourav.poddar@ti.com>
Hi Dmitry,
On Friday 05 October 2012 12:56 PM, Sourav Poddar wrote:
> From: G, Manjunath Kondaiah <manjugk@ti.com>
>
> SMSC ECE1099 is a keyboard scan or GPIO expansion device.The device
> supports a keypad scan matrix of 23*8.This driver uses this
> device as a keypad driver.
>
> Tested on omap5430 evm with 3.6-rc6 custom kernel.
>
> Cc: Benoit Cousson <b-cousson@ti.com>
> Cc: Felipe Balbi <balbi@ti.com>
> Cc: Santosh Shilimkar <santosh.shilimkar@ti.com>
> Signed-off-by: G, Manjunath Kondaiah <manjugk@ti.com>
> Signed-off-by: Sourav Poddar <sourav.poddar@ti.com>
> Acked-by: Felipe Balbi <balbi@ti.com>
> ---
> This patch was posted as a series initially
> http://www.spinics.net/lists/linux-omap/msg78772.html
>
> But the parent mfd driver has beeen already picked by mfd maintainer.
> So this patch can now posted as an standalone patch.
>
> v3->v4:
> Fix Dmitry's comments:
> - Error patch(input_free_device/input_unregister_device).
> - Few cleanups.
> - Included INPUT_MATRIXKMAP
> drivers/input/keyboard/Kconfig | 12 +
> drivers/input/keyboard/Makefile | 1 +
> drivers/input/keyboard/smsc-ece1099-keypad.c | 303 ++++++++++++++++++++++++++
> 3 files changed, 316 insertions(+), 0 deletions(-)
> create mode 100644 drivers/input/keyboard/smsc-ece1099-keypad.c
>
> diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
> index c50fa75..e370b03 100644
> --- a/drivers/input/keyboard/Kconfig
> +++ b/drivers/input/keyboard/Kconfig
> @@ -593,6 +593,18 @@ config KEYBOARD_TWL4030
> To compile this driver as a module, choose M here: the
> module will be called twl4030_keypad.
>
> +config KEYBOARD_SMSC
> + tristate "SMSC ECE1099 keypad support"
> + depends on I2C
> + select INPUT_MATRIXKMAP
> + help
> + Say Y here if your board use the smsc keypad controller
> + for omap5 defconfig. It's safe to say enable this
> + even on boards that don't use the keypad controller.
> +
> + To compile this driver as a module, choose M here: the
> + module will be called smsc-ece1099-keypad.
> +
> config KEYBOARD_XTKBD
> tristate "XT keyboard"
> select SERIO
> diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
> index 44e7600..0f2aa26 100644
> --- a/drivers/input/keyboard/Makefile
> +++ b/drivers/input/keyboard/Makefile
> @@ -52,5 +52,6 @@ obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o
> obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o
> obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o
> obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
> +obj-$(CONFIG_KEYBOARD_SMSC) += smsc-ece1099-keypad.o
> obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
> obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o
> diff --git a/drivers/input/keyboard/smsc-ece1099-keypad.c b/drivers/input/keyboard/smsc-ece1099-keypad.c
> new file mode 100644
> index 0000000..a4a0dfe
> --- /dev/null
> +++ b/drivers/input/keyboard/smsc-ece1099-keypad.c
> @@ -0,0 +1,303 @@
> +/*
> + * SMSC_ECE1099 Keypad driver
> + *
> + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
> + *
> + * 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.
> + */
> +
> +#include <linux/i2c.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/input.h>
> +#include <linux/gpio.h>
> +#include <linux/slab.h>
> +#include <linux/jiffies.h>
> +#include <linux/input/matrix_keypad.h>
> +#include <linux/delay.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/smsc.h>
> +#include <linux/of_gpio.h>
> +#include <linux/of.h>
> +
> +#define KEYPRESS_TIME 200
> +
> +struct smsc_keypad {
> + struct smsc *smsc;
> + struct matrix_keymap_data *keymap_data;
> + unsigned int last_key_state[16];
> + unsigned int last_col;
> + unsigned int last_key_ms[16];
> + unsigned short *keymap;
> + struct i2c_client *client;
> + struct input_dev *input;
> + int rows, cols;
> + int row_shift;
> + bool no_autorepeat;
> + unsigned irq;
> + struct device *dev;
> +};
> +
> +static void smsc_kp_scan(struct smsc_keypad *kp)
> +{
> + struct input_dev *input = kp->input;
> + int i, j;
> + int row, col;
> + int temp, code;
> + unsigned int new_state[16];
> + unsigned int bits_changed;
> + int this_ms;
> +
> + smsc_write(kp->dev, SMSC_KP_INT_MASK, 0x00);
> + smsc_write(kp->dev, SMSC_KP_INT_STAT, 0xFF);
> +
> + /* Scan for row and column */
> + for (i = 0; i < kp->cols; i++) {
> + smsc_write(kp->dev, SMSC_KP_OUT, SMSC_KSO_EVAL + i);
> + /* Read Row Status */
> + smsc_read(kp->dev, SMSC_KP_IN, &temp);
> + if (temp == 0xFF)
> + continue;
> +
> + col = i;
> + for (j = 0; j < kp->rows; j++) {
> + if ((temp & 0x01) != 0x00) {
> + temp = temp >> 1;
> + continue;
> + }
> +
> + row = j;
> + new_state[col] = (1 << row);
> + bits_changed = kp->last_key_state[col] ^ new_state[col];
> + this_ms = jiffies_to_msecs(jiffies);
> + if (bits_changed != 0 || (!bits_changed &&
> + ((this_ms - kp->last_key_ms[col]) >= KEYPRESS_TIME))) {
> + code = MATRIX_SCAN_CODE(row, col, kp->row_shift);
> + input_event(input, EV_MSC, MSC_SCAN, code);
> + input_report_key(input, kp->keymap[code], 1);
> + input_report_key(input, kp->keymap[code], 0);
> + kp->last_key_state[col] = new_state[col];
> + if (kp->last_col != col)
> + kp->last_key_state[kp->last_col] = 0;
> + kp->last_key_ms[col] = this_ms;
> + }
> + temp = temp >> 1;
> + }
> + }
> + input_sync(input);
> +
> + smsc_write(kp->dev, SMSC_KP_INT_MASK, 0xFF);
> +
> + /* Set up Low Power Mode (Wake-up) (0xFB) */
> + smsc_write(kp->dev, SMSC_WKUP_CTRL, SMSC_KP_SET_LOW_PWR);
> +
> + /*Enable Keypad Scan (generate interrupt on key press) (0x40)*/
> + smsc_write(kp->dev, SMSC_KP_OUT, SMSC_KSO_ALL_LOW);
> +}
> +
> +static irqreturn_t do_kp_irq(int irq, void *_kp)
> +{
> + struct smsc_keypad *kp = _kp;
> + int int_status;
> +
> + smsc_read(kp->dev, SMSC_KP_INT_STAT, &int_status);
> + if (int_status)
> + smsc_kp_scan(kp);
> +
> + return IRQ_HANDLED;
> +}
> +
> +#ifdef CONFIG_OF
> +static int __devinit smsc_keypad_parse_dt(struct device *dev,
> + struct smsc_keypad *kp)
> +{
> + struct device_node *np = dev->of_node;
> +
> + if (!np) {
> + dev_err(dev, "missing DT data");
> + return -EINVAL;
> + }
> +
> + of_property_read_u32(np, "keypad,num-rows", &kp->rows);
> + of_property_read_u32(np, "keypad,num-columns", &kp->cols);
> + if (!kp->rows || !kp->cols) {
> + dev_err(dev, "number of keypad rows/columns not specified\n");
> + return -EINVAL;
> + }
> +
> + if (of_property_read_bool(np, "linux,input-no-autorepeat"))
> + kp->no_autorepeat = true;
> +
> + return 0;
> +}
> +#else
> +static inline int smsc_keypad_parse_dt(struct device *dev,
> + struct smsc_keypad *kp)
> +{
> + return -ENOSYS;
> +}
> +#endif
> +
> +static int __devinit
> +smsc_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct smsc *smsc = dev_get_drvdata(pdev->dev.parent);
> + struct input_dev *input;
> + struct smsc_keypad *kp;
> + int ret = 0;
> + int i, max_keys, row_shift;
> + int irq;
> + int addr;
> +
> + kp = devm_kzalloc(dev, sizeof(*kp), GFP_KERNEL);
> +
> + input = input_allocate_device();
> + if (!kp || !input) {
> + ret = -ENOMEM;
> + goto err1;
> + }
> +
> + ret = smsc_keypad_parse_dt(&pdev->dev, kp);
> + if (ret)
> + goto err1;
> +
> + /* Get the debug Device */
> + kp->input = input;
> + kp->smsc = smsc;
> + kp->irq = platform_get_irq(pdev, 0);
> + kp->dev = dev;
> +
> + /* setup input device */
> + __set_bit(EV_KEY, input->evbit);
> +
> + /* Enable auto repeat feature of Linux input subsystem */
> + if (!kp->no_autorepeat)
> + __set_bit(EV_REP, input->evbit);
> +
> + input_set_capability(input, EV_MSC, MSC_SCAN);
> + input->name = "SMSC Keypad";
> + input->phys = "smsc_keypad/input0";
> + input->dev.parent = &pdev->dev;
> + input->id.bustype = BUS_HOST;
> + input->id.vendor = 0x0001;
> + input->id.product = 0x0001;
> + input->id.version = 0x0003;
> +
> + /* Mask all GPIO interrupts (0x37-0x3B) */
> + for (addr = SMSC_GPIO_INT_MASK_START;
> + addr < SMSC_GPIO_INT_MASK_START + 4; addr++)
> + smsc_write(dev, addr, 0);
> +
> + /* Set all outputs high (0x05-0x09) */
> + for (addr = SMSC_GPIO_DATA_OUT_START;
> + addr < SMSC_GPIO_DATA_OUT_START + 4; addr++)
> + smsc_write(dev, addr, 0xff);
> +
> + /* Clear all GPIO interrupts (0x32-0x36) */
> + for (addr = SMSC_GPIO_INT_STAT_START;
> + addr < SMSC_GPIO_INT_STAT_START + 4; addr++)
> + smsc_write(dev, addr, 0xff);
> +
> + /* Configure the smsc pins as Keyboard scan Input */
> + for (i = 0; i <= kp->rows; i++) {
> + addr = 0x12 + i;
> + smsc_write(dev, addr, SMSC_KP_KSI);
> + }
> +
> + /* Configure the smsc pins as Keyboard scan output */
> + for (i = 0; i <= kp->cols; i++) {
> + addr = 0x1A + i;
> + smsc_write(dev, addr, SMSC_KP_KSO);
> + }
> +
> + smsc_write(dev, SMSC_KP_INT_STAT, SMSC_KP_SET_HIGH);
> + smsc_write(dev, SMSC_WKUP_CTRL, SMSC_KP_SET_LOW_PWR);
> + smsc_write(dev, SMSC_KP_OUT, SMSC_KSO_ALL_LOW);
> +
> + row_shift = get_count_order(kp->cols);
> + max_keys = kp->rows << row_shift;
> +
> + kp->row_shift = row_shift;
> + kp->keymap = devm_kzalloc(dev, max_keys * sizeof(kp->keymap[0]),
> + GFP_KERNEL);
> + if (!kp->keymap) {
> + dev_err(&pdev->dev, "Not enough memory for keymap\n");
> + ret = -ENOMEM;
> + }
> +
> + ret = matrix_keypad_build_keymap(NULL, NULL, kp->rows,
> + kp->cols, kp->keymap, input);
> + if (ret) {
> + dev_err(&pdev->dev, "failed to build keymap\n");
> + goto err1;
> + }
> +
> + /*
> + * This ISR will always execute in kernel thread context because of
> + * the need to access the SMSC over the I2C bus.
> + */
> + ret = devm_request_threaded_irq(dev, kp->irq, NULL, do_kp_irq,
> + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, pdev->name, kp);
> + if (ret) {
> + dev_dbg(&pdev->dev, "request_irq failed for irq no=%d\n",
> + irq);
> + goto err1;
> + }
> +
> + /* Enable smsc keypad interrupts */
> + ret = smsc_write(dev, SMSC_KP_INT_MASK, 0xff);
> + if (ret < 0)
> + goto err2;
> +
> + ret = input_register_device(input);
> + if (ret) {
> + dev_err(kp->dev,
> + "Unable to register twl4030 keypad device\n");
> + goto err2;
> + }
> +
> + return 0;
> +
> +err2:
> + free_irq(kp->irq, kp);
> +err1:
> + input_free_device(input);
> + return ret;
> +}
> +
> +static int __devexit smsc_remove(struct platform_device *pdev)
> +{
> + struct smsc_keypad *kp = platform_get_drvdata(pdev);
> + input_unregister_device(kp->input);
> +
> + return 0;
> +}
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id smsc_keypad_dt_match[] = {
> + { .compatible = "smsc,keypad" },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, smsc_keypad_dt_match);
> +#endif
> +
> +static struct platform_driver smsc_driver = {
> + .driver = {
> + .name = "smsc-keypad",
> + .of_match_table = of_match_ptr(smsc_keypad_dt_match),
> + .owner = THIS_MODULE,
> + },
> + .probe = smsc_probe,
> + .remove = __devexit_p(smsc_remove),
> +};
> +
> +module_platform_driver(smsc_driver);
> +
> +MODULE_AUTHOR("G Kondaiah Manjunath <manjugk@ti.com>");
> +MODULE_DESCRIPTION("SMSC ECE1099 Keypad driver");
> +MODULE_LICENSE("GPL v2");
ping on this?
~Sourav
^ permalink raw reply
* [PATCH] MMC: fix sdhci-dove removal
From: Russell King - ARM Linux @ 2012-10-15 10:37 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20121015094348.GP21164@n2100.arm.linux.org.uk>
On Mon, Oct 15, 2012 at 10:43:48AM +0100, Russell King - ARM Linux wrote:
> 1. Unregister the device _BEFORE_ taking away any resources it may
> be using.
> 2. Don't check clks against NULL.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Looking at this driver some more, who the hell came up with the sdhci
registration interface? It violates one of the most fundamental
principles of kernel driver programming. You do _NOT_ publish your
driver interfaces _UNTIL_ you have finished setting your device up.
Otherwise, in a preemptible or SMP kernel, your driver can be used
before the initialization has completed.
As this driver calls sdhci_pltfm_register() before it has obtained the
clock for the interface, and this function does:
sdhci_pltfm_init
sdhci_add_host
mmc_add_host
mmc_start_host
mmc_power_up
mmc_set_ios
sdhci_set_ios
See, we're trying to power up and clock the card _before_ the dove
sdhci driver has even claimed the clock let alone enabled it. This
is total bollocks. The sdhci platform interface is total crap for
creating this broken design in the first place. This is why MMC has
the init + add interfaces, they're there to allow drivers to do stuff
the Right(tm) way and avoid shit like the above.
This should have been picked up at review time before the driver went
into mainline. In any case, it needs to be fixed.
^ permalink raw reply
* 答复: Hardcoded instruction causes certain features to fail on ARM platfrom due to endianness
From: Yangfei (Felix) @ 2012-10-15 10:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20603.47887.262025.941051@pilspetsen.it.uu.se>
Hi Mikael & Russell,
Thanks for the suggestions. I tried to replace ".word" with ".inst" and the cpu-hotplug feature now works on big-endian (BE-8) ARM platform. And illegal instruction exception disappears.
And the following is my small patch to fix the problem,
diff -urN linux-3.7-rc1/arch/arm/mach-exynos/hotplug.c linux/arch/arm/mach-exynos/hotplug.c
--- linux-3.7-rc1/arch/arm/mach-exynos/hotplug.c 2012-10-15 05:41:04.000000000 +0800
+++ linux/arch/arm/mach-exynos/hotplug.c 2012-10-15 17:47:28.177103266 +0800
@@ -72,7 +72,7 @@
/*
* here's the WFI
*/
- asm(".word 0xe320f003\n"
+ asm(".inst 0xe320f003\n"
:
:
: "memory", "cc");
diff -urN linux-3.7-rc1/arch/arm/mach-realview/hotplug.c linux/arch/arm/mach-realview/hotplug.c
--- linux-3.7-rc1/arch/arm/mach-realview/hotplug.c 2012-10-15 05:41:04.000000000 +0800
+++ linux/arch/arm/mach-realview/hotplug.c 2012-10-15 17:44:55.915942976 +0800
@@ -64,7 +64,7 @@
/*
* here's the WFI
*/
- asm(".word 0xe320f003\n"
+ asm(".inst 0xe320f003\n"
:
:
: "memory", "cc");
diff -urN linux-3.7-rc1/arch/arm/mach-shmobile/hotplug.c linux/arch/arm/mach-shmobile/hotplug.c
--- linux-3.7-rc1/arch/arm/mach-shmobile/hotplug.c 2012-10-15 05:41:04.000000000 +0800
+++ linux/arch/arm/mach-shmobile/hotplug.c 2012-10-15 17:45:20.509879863 +0800
@@ -39,7 +39,7 @@
/*
* here's the WFI
*/
- asm(".word 0xe320f003\n"
+ asm(".inst 0xe320f003\n"
:
:
: "memory", "cc");
Since ARM processor can be configured to work in BE-8 big-endian, I thinks this patch is necessary. Any suggestions is welcomed.
Thanks
Yangfei (Felix) writes:
> Hi all,
>
> I found that hardcoded instruction in inline asm can cause certains certain features fail to work on ARM platform due to endianness.
> As an example, consider the following code snippet of platform_do_lowpower function from arch/arm/mach-realview/hotplug.c:
> / *
> * here's the WFI
> */
> asm(".word 0xe320f003\n"
> :
> :
> : "memory", "cc");
>
> The instruction generated from this inline asm will not work on big-endian ARM platform, such as ARM BE-8 format. Instead, an exception will be generated.
>
> Here the code should be:
> / *
> * here's the WFI
> */
> asm("WFI\n"
> :
> :
> : "memory", "cc");
>
> Seems the kernel doesn't support ARM BE-8 well. I don't know why this problem happens.
> Can anyone tell me who owns this part? I can prepare a patch then.
> Thanks.
Questions regarding the ARM kernel should go to the linux-arm-kernel mailing list
(see the MAINTAINERS file), with an optional cc: to the regular LKML.
BE-8 is, if I recall correctly, ARMv7's broken format where code and data have
different endianess. GAS supports an ".inst" directive which is like ".word"
except the data is assumed to be code. This matters for disassembly, and may
also be required for BE-8.
That is, just s/.word/.inst/g above and report back if that works or not.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* [PATCH] mmc: mmci: Support non-power-of-two block sizes for ux500v2 variant
From: Johan Rudholm @ 2012-10-15 10:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350050522-8852-1-git-send-email-ulf.hansson@stericsson.com>
2012/10/12 Ulf Hansson <ulf.hansson@stericsson.com>:
> From: Ulf Hansson <ulf.hansson@linaro.org>
>
> For the ux500v2 variant non power of two block sizes are supported.
> This will make it possible to decrease data overhead for SDIO
> transfers. Although we need to put some constraints to the alignment
> of the buffers when enabling this feature.
>
> Buffers must be 4 bytes aligned due to restrictions that the PL18x
> FIFO accesses must be done in a 4 byte aligned manner. Moreover we
> need to enable DMA_REQCTL for SDIO to support write of non 32 bytes
> aligned sg element lengths. In PIO mode any buffer length can be
> handled as long as the buffer address is 4 byte aligned.
>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> Signed-off-by: Per Forlin <per.forlin@stericsson.com>
Acked-By: Johan Rudholm <johan.rudholm@stericsson.com>
^ permalink raw reply
* [PATCH] ARM: OMAP4: hwmod data: gpmc main clk
From: Benoit Cousson @ 2012-10-15 10:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350280063-27422-1-git-send-email-afzal@ti.com>
Hi Afzal,
On 10/15/2012 07:47 AM, Afzal Mohammed wrote:
> gpmc has been converted to a driver. It requests clock with
> con-id "fck", if not available, probe fails. Clock for gpmc
> device with con-id "fck" is created (aliased) along with
> hwmod device, and for that to happen, main_clk needs to be
> specified in hwmod entry, add it for OMAP4.
Well, in this case, this is not the preferred way. The hwmod data are supposed to reflect the real HW capabilities.
We'd better add the alias in the already existing dummy clock node.
Here is the patch to do that.
Thanks,
Benoit
---
From: Benoit Cousson <b-cousson@ti.com>
Date: Mon, 15 Oct 2012 11:41:42 +0200
Subject: [PATCH] ARM: OMAP2+: clock data: Add dev-id for the omap-gpmc dummy fck
The GPMC code has been converted to a driver by the following commit:
commit da496873970c57c4b31e186d967933da0ffa0d7c
Author: Afzal Mohammed <afzal@ti.com>
Date: Sun Sep 23 17:28:25 2012 -0600
ARM: OMAP2+: gpmc: minimal driver support
It now requests a clock with con-id "fck" otherwise the probe will fails.
[ 0.342010] omap-gpmc omap-gpmc: error: clk_get
[ 0.346771] omap-gpmc: probe of omap-gpmc failed with error -2
Add the "omap-gmpc" dev-id and fck con-id to the already existing
gmpc-fck dummy clock.
Reported-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Benoit Cousson <b-cousson@ti.com>
Cc: Afzal Mohammed <afzal@ti.com>
---
arch/arm/mach-omap2/clock44xx_data.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
index d661d13..6efc30c 100644
--- a/arch/arm/mach-omap2/clock44xx_data.c
+++ b/arch/arm/mach-omap2/clock44xx_data.c
@@ -3294,7 +3294,7 @@ static struct omap_clk omap44xx_clks[] = {
CLK(NULL, "auxclk5_src_ck", &auxclk5_src_ck, CK_443X),
CLK(NULL, "auxclk5_ck", &auxclk5_ck, CK_443X),
CLK(NULL, "auxclkreq5_ck", &auxclkreq5_ck, CK_443X),
- CLK(NULL, "gpmc_ck", &dummy_ck, CK_443X),
+ CLK("omap-gpmc", "fck", &dummy_ck, CK_443X),
CLK("omap_i2c.1", "ick", &dummy_ck, CK_443X),
CLK("omap_i2c.2", "ick", &dummy_ck, CK_443X),
CLK("omap_i2c.3", "ick", &dummy_ck, CK_443X),
--
1.7.0.4
^ permalink raw reply related
* [PATCH] [media] s5p-csis: Added RAW data format as the supported format.
From: Ritesh Kumar Solanki @ 2012-10-15 9:48 UTC (permalink / raw)
To: linux-arm-kernel
csis can support jpeg, yuv and raw data format.
Signed-off-by: Ritesh Kumar Solanki <r.solanki@samsung.com>
---
drivers/media/platform/s5p-fimc/mipi-csis.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c
index 2f73d9e..0205ae4 100644
--- a/drivers/media/platform/s5p-fimc/mipi-csis.c
+++ b/drivers/media/platform/s5p-fimc/mipi-csis.c
@@ -145,6 +145,10 @@ static const struct csis_pix_format s5pcsis_formats[] = {
.code = V4L2_MBUS_FMT_JPEG_1X8,
.fmt_reg = S5PCSIS_CFG_FMT_USER(1),
.data_alignment = 32,
+ }, {
+ .code = V4L2_MBUS_FMT_SGRBG10_1X10,
+ .fmt_reg = S5PCSIS_CFG_FMT_RAW10,
+ .data_alignment = 24,
},
};
--
1.7.2.3
^ permalink raw reply related
* [PATCH 3/6] DRIVERS: ATA: SATA PHY utility framework
From: Vasanth Ananthan @ 2012-10-15 9:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <2368802.eUtXvopXao@flatron>
Hi Tomasz,
On Sat, Oct 13, 2012 at 4:00 AM, Tomasz Figa <tomasz.figa@gmail.com> wrote:
> Hi Vasanth,
>
> On Tuesday 09 of October 2012 17:18:49 Vasanth Ananthan wrote:
>> This patch adds SATA PHY utility framework APIs. The framework acts as
>> an interface between the SATA device and the PHY device. The SATA PHY
>> device registers itself with the framework through the APIs provided
>> and the SATA device finds and requests for an appropriate PHY device.
>>
>> Signed-off-by: Vasanth Ananthan <vasanth.a@samsung.com>
>> ---
>> drivers/ata/Kconfig | 9 ++++
>> drivers/ata/Makefile | 1 +
>> drivers/ata/sata_phy.c | 99
>> ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/ata/sata_phy.h
>> | 44 +++++++++++++++++++++
>> 4 files changed, 153 insertions(+), 0 deletions(-)
>> create mode 100644 drivers/ata/sata_phy.c
>> create mode 100644 drivers/ata/sata_phy.h
>>
>> diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
>> index 27cecd3..0344b78 100644
>> --- a/drivers/ata/Kconfig
>> +++ b/drivers/ata/Kconfig
>> @@ -83,6 +83,15 @@ config SATA_AHCI_PLATFORM
>>
>> If unsure, say N.
>>
>> +config SATA_EXYNOS
>> + bool "Exynos SATA AHCI support"
>> + depends on I2C_S3C2410
>> + help
>> + This option enables support for Exynos AHCI Serial ATA
>> + controllers.
>> +
>> + If unsure, say N.
>> +
>> config SATA_FSL
>> tristate "Freescale 3.0Gbps SATA support"
>> depends on FSL_SOC
>> diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
>> index a454a13..bf3fd91 100644
>> --- a/drivers/ata/Makefile
>> +++ b/drivers/ata/Makefile
>> @@ -9,6 +9,7 @@ obj-$(CONFIG_SATA_FSL) += sata_fsl.o
>> obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
>> obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
>> obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
>> +obj-$(CONFIG_SATA_EXYNOS) += sata_phy.o libahci.o
>
>
> If the framework introduced by this patch is supposed to be generic, maybe
> a new Kconfig entry should be created for it, like CONFIG_SATA_PHY, which
> would be selected by any drivers using it?
>
>> +int sata_add_phy(struct sata_phy *phy, enum sata_phy_type type)
>> +{
>> + unsigned long flag;
>> + unsigned int ret = -EINVAL;
>> + struct sata_phy *x;
>
> If you need to handle the situation when phy is NULL here, then why not
> to:
>
> if (!phy)
> return -EINVAL;
>
> and then make the code below unconditional?
>
I'll incorporate the suggestions.
--
Vasanth
^ permalink raw reply
* dma_alloc_coherent fails in framebuffer
From: Mel Gorman @ 2012-10-15 9:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350246895.11504.6.camel@gitbox>
On Mon, Oct 15, 2012 at 09:34:55AM +1300, Tony Prisk wrote:
> On Sun, 2012-10-14 at 18:28 +1300, Tony Prisk wrote:
> > Up until 07 Oct, drivers/video/wm8505-fb.c was working fine, but on the
> > 11 Oct when I did another pull from linus all of a sudden
> > dma_alloc_coherent is failing to allocate the framebuffer any longer.
> >
> > I did a quick look back and found this:
> >
> > ARM: add coherent dma ops
> >
> > arch_is_coherent is problematic as it is a global symbol. This
> > doesn't work for multi-platform kernels or platforms which can support
> > per device coherent DMA.
> >
> > This adds arm_coherent_dma_ops to be used for devices which connected
> > coherently (i.e. to the ACP port on Cortex-A9 or A15). The arm_dma_ops
> > are modified at boot when arch_is_coherent is true.
> >
> > Signed-off-by: Rob Herring <rob.herring@calxeda.com>
> > Cc: Russell King <linux@arm.linux.org.uk>
> > Cc: Marek Szyprowski <m.szyprowski@samsung.com>
> > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> >
> >
> > This is the only patch lately that I could find (not that I would claim
> > to be any good at finding things) that is related to the problem. Could
> > it have caused the allocations to fail?
> >
> > Regards
> > Tony P
>
> Have done a bit more digging and found the cause - not Rob's patch so
> apologies.
>
> The cause of the regression is this patch:
>
> From f40d1e42bb988d2a26e8e111ea4c4c7bac819b7e Mon Sep 17 00:00:00 2001
> From: Mel Gorman <mgorman@suse.de>
> Date: Mon, 8 Oct 2012 16:32:36 -0700
> Subject: [PATCH 2/3] mm: compaction: acquire the zone->lock as late as
> possible
>
> Up until then, the framebuffer allocation with dma_alloc_coherent(...)
> was fine. From this patch onwards, allocations fail.
>
Was this found through bisection or some other means?
There was a bug in that series that broke CMA but it was commit bb13ffeb
(mm: compaction: cache if a pageblock was scanned and no pages were
isolated) and it was fixed by 62726059 (mm: compaction: fix bit ranges
in {get,clear,set}_pageblock_skip()). So it should have been fixed by
3.7-rc1 and probably was included by the time you pulled in October 11th
but bisection would be a pain. There were problems with that series during
development but tests were completing for other people.
Just in case, is this still broken in 3.7-rc1?
> I don't know how this patch would effect CMA allocations, but it seems
> to be causing the issue (or at least, it's caused an error in
> arch-vt8500 to become visible).
>
> Perhaps someone who understand -mm could explain the best way to
> troubleshoot the cause of this problem?
>
If you are comfortable with ftrace, it can be used to narrow down where
the exact failure is occurring but if you're not comfortable with that
then the easiest is a bunch of printks starting in alloc_contig_range()
to see at what point and why it returns failure.
It's not obvious at the moment why that patch would cause an allocation
problem. It's the type of patch that if it was wrong it would fail every
time for everyone, not just for a single driver.
--
Mel Gorman
SUSE Labs
^ permalink raw reply
* [PATCH] MMC: fix sdhci-dove removal
From: Russell King - ARM Linux @ 2012-10-15 9:43 UTC (permalink / raw)
To: linux-arm-kernel
1. Unregister the device _BEFORE_ taking away any resources it may
be using.
2. Don't check clks against NULL.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
I noticed this while merging v3.6 into Rabeeh's cubox kernel.
drivers/mmc/host/sdhci-dove.c | 13 ++++++-------
1 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c
index 90140eb..c11db64 100644
--- a/drivers/mmc/host/sdhci-dove.c
+++ b/drivers/mmc/host/sdhci-dove.c
@@ -117,14 +117,13 @@ static int __devexit sdhci_dove_remove(struct platform_device *pdev)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_dove_priv *priv = pltfm_host->priv;
- if (priv->clk) {
- if (!IS_ERR(priv->clk)) {
- clk_disable_unprepare(priv->clk);
- clk_put(priv->clk);
- }
- devm_kfree(&pdev->dev, priv->clk);
+ sdhci_pltfm_unregister(pdev);
+
+ if (!IS_ERR(priv->clk)) {
+ clk_disable_unprepare(priv->clk);
+ clk_put(priv->clk);
}
- return sdhci_pltfm_unregister(pdev);
+ return 0;
}
static const struct of_device_id sdhci_dove_of_match_table[] __devinitdata = {
^ permalink raw reply related
* [PATCH v3 2/2] i2c: change id to let i2c-at91 work
From: Bo Shen @ 2012-10-15 9:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350293428-24551-1-git-send-email-voice.shen@atmel.com>
The i2c core driver will turn the platform device ID to busnum
When using platfrom device ID as -1, it means dynamically assigned
the busnum. When writing code, we need to make sure the busnum,
and call i2c_register_board_info(int busnum, ...) to register device
if using -1, we do not know the value of busnum
In order to solve this issue, set the platform device ID as a fix number
Here using 0 to match the busnum used in i2c_regsiter_board_info()
Signed-off-by: Bo Shen <voice.shen@atmel.com>
---
arch/arm/mach-at91/at91rm9200.c | 2 +-
arch/arm/mach-at91/at91rm9200_devices.c | 2 +-
arch/arm/mach-at91/at91sam9260.c | 4 ++--
arch/arm/mach-at91/at91sam9260_devices.c | 2 +-
arch/arm/mach-at91/at91sam9261.c | 4 ++--
arch/arm/mach-at91/at91sam9261_devices.c | 2 +-
arch/arm/mach-at91/at91sam9263.c | 2 +-
arch/arm/mach-at91/at91sam9263_devices.c | 2 +-
arch/arm/mach-at91/at91sam9rl_devices.c | 2 +-
9 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index b4f0565..5269825 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -187,7 +187,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200", &twi_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200.0", &twi_clk),
/* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
CLKDEV_CON_ID("pioA", &pioA_clk),
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index 7cd8053..1e122bc 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -512,7 +512,7 @@ static struct resource twi_resources[] = {
static struct platform_device at91rm9200_twi_device = {
.name = "i2c-at91rm9200",
- .id = -1,
+ .id = 0,
.resource = twi_resources,
.num_resources = ARRAY_SIZE(twi_resources),
};
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index ad29f93..f820261 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -211,8 +211,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20", &twi_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260.0", &twi_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi_clk),
/* more usart lookup table for DT entries */
CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk),
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index 805ef95..46edfaf 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -421,7 +421,7 @@ static struct resource twi_resources[] = {
};
static struct platform_device at91sam9260_twi_device = {
- .id = -1,
+ .id = 0,
.resource = twi_resources,
.num_resources = ARRAY_SIZE(twi_resources),
};
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index 8d999eb..04295c0 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -178,8 +178,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261", &twi_clk),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10", &twi_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261.0", &twi_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.0", &twi_clk),
CLKDEV_CON_ID("pioA", &pioA_clk),
CLKDEV_CON_ID("pioB", &pioB_clk),
CLKDEV_CON_ID("pioC", &pioC_clk),
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 0256a00..b948769 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -317,7 +317,7 @@ static struct resource twi_resources[] = {
};
static struct platform_device at91sam9261_twi_device = {
- .id = -1,
+ .id = 0,
.resource = twi_resources,
.num_resources = ARRAY_SIZE(twi_resources),
};
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index 6a01d03..d6f9c23 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -193,7 +193,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260.0", &twi_clk),
/* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
CLKDEV_CON_ID("pioA", &pioA_clk),
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index 23b6384..cb85da2 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -600,7 +600,7 @@ static struct resource twi_resources[] = {
static struct platform_device at91sam9263_twi_device = {
.name = "i2c-at91sam9260",
- .id = -1,
+ .id = 0,
.resource = twi_resources,
.num_resources = ARRAY_SIZE(twi_resources),
};
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index 3d2c81d..5047bdc 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -347,7 +347,7 @@ static struct resource twi_resources[] = {
static struct platform_device at91sam9rl_twi_device = {
.name = "i2c-at91sam9g20",
- .id = -1,
+ .id = 0,
.resource = twi_resources,
.num_resources = ARRAY_SIZE(twi_resources),
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 1/2] i2c: change id to let i2c-gpio work
From: Bo Shen @ 2012-10-15 9:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1350293428-24551-1-git-send-email-voice.shen@atmel.com>
The i2c core driver will turn the platform device ID to busnum
When using platfrom device ID as -1, it means dynamically assigned
the busnum. When writing code, we need to make sure the busnum,
and call i2c_register_board_info(int busnum, ...) to register device
if using -1, we do not know the value of busnum
In order to solve this issue, set the platform device ID as a fix number
Here using 0 to match the busnum used in i2c_regsiter_board_info()
Signed-off-by: Bo Shen <voice.shen@atmel.com>
---
Change since v2
Fix this issue for more boards
Change since v1
Make the commit message more clear
---
arch/arm/mach-at91/at91rm9200_devices.c | 2 +-
arch/arm/mach-at91/at91sam9260_devices.c | 2 +-
arch/arm/mach-at91/at91sam9261_devices.c | 2 +-
arch/arm/mach-at91/at91sam9263_devices.c | 2 +-
arch/arm/mach-at91/at91sam9rl_devices.c | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index a563189..7cd8053 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -479,7 +479,7 @@ static struct i2c_gpio_platform_data pdata = {
static struct platform_device at91rm9200_twi_device = {
.name = "i2c-gpio",
- .id = -1,
+ .id = 0,
.dev.platform_data = &pdata,
};
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index 0f24cfb..805ef95 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -389,7 +389,7 @@ static struct i2c_gpio_platform_data pdata = {
static struct platform_device at91sam9260_twi_device = {
.name = "i2c-gpio",
- .id = -1,
+ .id = 0,
.dev.platform_data = &pdata,
};
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 9752f17..0256a00 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -285,7 +285,7 @@ static struct i2c_gpio_platform_data pdata = {
static struct platform_device at91sam9261_twi_device = {
.name = "i2c-gpio",
- .id = -1,
+ .id = 0,
.dev.platform_data = &pdata,
};
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index 8dde220..23b6384 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -567,7 +567,7 @@ static struct i2c_gpio_platform_data pdata = {
static struct platform_device at91sam9263_twi_device = {
.name = "i2c-gpio",
- .id = -1,
+ .id = 0,
.dev.platform_data = &pdata,
};
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index d6ca054..3d2c81d 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -314,7 +314,7 @@ static struct i2c_gpio_platform_data pdata = {
static struct platform_device at91sam9rl_twi_device = {
.name = "i2c-gpio",
- .id = -1,
+ .id = 0,
.dev.platform_data = &pdata,
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 0/2] i2c: change id to let i2c-gpio work
From: Bo Shen @ 2012-10-15 9:30 UTC (permalink / raw)
To: linux-arm-kernel
The i2c core driver will turn the platform device ID to busnum
When using platfrom device ID as -1, it means dynamically assigned
the busnum. When writing code, we need to make sure the busnum,
and call i2c_register_board_info(int busnum, ...) to register device
if using -1, we do not know the value of busnum
In order to solve this issue, set the platform device ID as a fix number
Here using 0 to match the busnum used in i2c_regsiter_board_info()
Bo Shen (2):
i2c: change id to let i2c-gpio work
i2c: change id to let i2c-at91 work
arch/arm/mach-at91/at91rm9200.c | 2 +-
arch/arm/mach-at91/at91rm9200_devices.c | 4 ++--
arch/arm/mach-at91/at91sam9260.c | 4 ++--
arch/arm/mach-at91/at91sam9260_devices.c | 4 ++--
arch/arm/mach-at91/at91sam9261.c | 4 ++--
arch/arm/mach-at91/at91sam9261_devices.c | 4 ++--
arch/arm/mach-at91/at91sam9263.c | 2 +-
arch/arm/mach-at91/at91sam9263_devices.c | 4 ++--
arch/arm/mach-at91/at91sam9rl_devices.c | 4 ++--
9 files changed, 16 insertions(+), 16 deletions(-)
--
1.7.9.5
^ permalink raw reply
* [PATCH] DMA: AT91: Get residual bytes in dma buffer
From: Song, Elen @ 2012-10-15 9:18 UTC (permalink / raw)
To: linux-arm-kernel
The main purpose of atc_tx_status is to get residual bytes when dma transfer in progress or complete.
Residual bytes is the number of bytes left to read from DMA source.
During transfer, residual bytes is changing as DMA read from its source.
When transfer complete, the residual bytes is zero.
atc_get_bytes_left will dynamically get bytes left in dma buffer.
It reads count register bit btsize to get residue, the btsize only indicate current descriptor receive data.
So we should let atc_get_bytes_left know when descriptor switch or dma transfer done.
DMA_CTRL_ACK is a useful ack, it means current descriptor can not be reused when clear.
The atc_get_bytes_left will find out whether move to next descriptor or transfer done.
So in dma handler, we get residue like below:
dma_handler() {
async_tx_clear_ack; //clear ack, tell driver it is time to switch descriptor
read residue;
async_tx_ack; //move to next descriptor
// no need to set ack when dma transfer done }
DMA should be pause so that we can trust data count.
Signed-off-by: Elen Song <elen.song@atmel.com>
---
drivers/dma/at_hdmac.c | 127 +++++++++++++++++++++++++++++++++++++++----
drivers/dma/at_hdmac_regs.h | 4 ++
2 files changed, 120 insertions(+), 11 deletions(-)
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 13a02f4..b0aa783 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -229,6 +229,101 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first)
vdbg_dump_regs(atchan);
}
+/*
+ * atc_get_current_descriptors - get descriptor which equal to
+ * physical address in DSCR.
+ * @atchan: the channel we want to start
+ * @dscr_addr: physical descriptor address in DSCR */ static struct
+at_desc *atc_get_current_descriptors(struct at_dma_chan *atchan,
+ u32 dscr_addr)
+{
+ struct at_desc *desc, *_desc, *child, *desc_cur = NULL;
+
+ list_for_each_entry_safe(desc, _desc, &atchan->active_list, desc_node)
+{
+
+ if (desc->lli.dscr == dscr_addr) {
+ desc_cur = desc;
+ break;
+ }
+
+ list_for_each_entry(child, &desc->tx_list, desc_node) {
+
+ if (child->lli.dscr == dscr_addr) {
+ desc_cur = child;
+ break;
+ }
+ }
+ }
+
+ return desc_cur;
+}
+
+/*
+ * atc_get_bytes_left - Get the number of bytes
+ * residue in dma buffer,
+ * it is unwise to call this before stopping the channel for
+ * absolute measures.
+ * @atchan: the channel we want to start */ static int
+atc_get_bytes_left(struct at_dma_chan *atchan) {
+ struct at_desc *desc_first;
+ int left = 0, count = 0;
+ u32 dscr_addr;
+
+ /* First descriptor embedds additional information */
+ desc_first = atc_first_active(atchan);
+ if (!desc_first)
+ return -EINVAL;
+
+ /* Initialize necessary value in the first time.
+ * We use desc_cur to save current descriptor,
+ * save_len record residual dma buffer length.
+ */
+ if (!atchan->desc_cur &&
+ !atchan->save_len) {
+ atchan->desc_cur = desc_first;
+ atchan->save_len = desc_first->len;
+ }
+
+ /* This happend in the end of dma transfer or descriptor switch,
+ * during the dma interrupt handler, DMA_CTRL_ACK should be cleared.
+ * We trigger this flag to get residual values.
+ * To be aware of, two conditions should be taken into consideration:
+ * at the end of a dma transfer, or descriptors switch.
+ */
+ if (!(desc_first->txd.flags & DMA_CTRL_ACK)) {
+ dscr_addr = channel_readl(atchan, DSCR);
+ /* End of a single or cyclic transfer */
+ if (dscr_addr == 0 || dscr_addr == desc_first->lli.dscr) {
+ atchan->desc_cur = NULL;
+ atchan->save_len = 0;
+ /* Switch between two descriptor.
+ * Current descriptor transfer done.
+ * The residual buffer length should reduce current descriptor.
+ */
+ } else {
+ atchan->desc_cur = atc_get_current_descriptors(atchan,
+ dscr_addr);
+ if (!atchan->desc_cur)
+ return -EINVAL;
+ atchan->save_len -= (atchan->desc_cur->lli.ctrla
+ & ATC_BTSIZE_MAX);
+ }
+
+ left = atchan->save_len;
+ }
+
+ /* Get residual value during a descriptor transfer */
+ if (atchan->desc_cur) {
+ count = channel_readl(atchan, CTRLA) & ATC_BTSIZE_MAX;
+ left = atchan->save_len - count;
+ }
+
+ return left;
+}
+
/**
* atc_chain_complete - finish work for one transaction chain
* @atchan: channel we work on
@@ -1034,23 +1129,33 @@ atc_tx_status(struct dma_chan *chan,
dma_cookie_t last_complete;
unsigned long flags;
enum dma_status ret;
-
- spin_lock_irqsave(&atchan->lock, flags);
+ int bytes = 0;
ret = dma_cookie_status(chan, cookie, txstate);
- if (ret != DMA_SUCCESS) {
- atc_cleanup_descriptors(atchan);
-
- ret = dma_cookie_status(chan, cookie, txstate);
+ /* Residue is zero while transactions complete */
+ if (ret == DMA_SUCCESS) {
+ dma_set_residue(txstate, 0);
+ return ret;
+ }
+ /*
+ * There's no point calculating the residue if there's
+ * no txstate to store the value.
+ */
+ if (!txstate) {
+ if (atc_chan_is_paused(atchan))
+ ret = DMA_PAUSED;
+ return ret;
}
- last_complete = chan->completed_cookie;
- last_used = chan->cookie;
+ spin_lock_irqsave(&atchan->lock, flags);
- spin_unlock_irqrestore(&atchan->lock, flags);
+ /* Get number of bytes left in the active transactions */
+ bytes = atc_get_bytes_left(atchan);
+ if (bytes < 0)
+ dev_err(chan2dev(chan), "get residue value error\n");
+ dma_set_residue(txstate, bytes);
- if (ret != DMA_SUCCESS)
- dma_set_residue(txstate, atc_first_active(atchan)->len);
+ spin_unlock_irqrestore(&atchan->lock, flags);
if (atc_chan_is_paused(atchan))
ret = DMA_PAUSED;
diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h index 116e4ad..ea8d747 100644
--- a/drivers/dma/at_hdmac_regs.h
+++ b/drivers/dma/at_hdmac_regs.h
@@ -226,12 +226,14 @@ enum atc_status {
* @save_cfg: configuration register that is saved on suspend/resume cycle
* @save_dscr: for cyclic operations, preserve next descriptor address in
* the cyclic list on suspend/resume cycle
+ * @save_len: to record dma buffer length
* @dma_sconfig: configuration for slave transfers, passed via DMA_SLAVE_CONFIG
* @lock: serializes enqueue/dequeue operations to descriptors lists
* @active_list: list of descriptors dmaengine is being running on
* @queue: list of descriptors ready to be submitted to engine
* @free_list: list of descriptors usable by the channel
* @descs_allocated: records the actual size of the descriptor pool
+ * @desc_cur: current descriptor
*/
struct at_dma_chan {
struct dma_chan chan_common;
@@ -242,6 +244,7 @@ struct at_dma_chan {
struct tasklet_struct tasklet;
u32 save_cfg;
u32 save_dscr;
+ u32 save_len;
struct dma_slave_config dma_sconfig;
spinlock_t lock;
@@ -251,6 +254,7 @@ struct at_dma_chan {
struct list_head queue;
struct list_head free_list;
unsigned int descs_allocated;
+ struct at_desc *desc_cur;
};
#define channel_readl(atchan, name) \
--
1.7.9.5
^ permalink raw reply
* [PATCH] pinctrl/nomadik: debugfs display of other alternate-C functions
From: Linus Walleij @ 2012-10-15 9:04 UTC (permalink / raw)
To: linux-arm-kernel
From: Jean-Nicolas Graux <jean-nicolas.graux@stericsson.com>
In pinctrl debug pins file, enable display of AltCx functions.
Signed-off-by: Jean-Nicolas Graux <jean-nicolas.graux@stericsson.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
drivers/pinctrl/pinctrl-nomadik.c | 45 +++++++++++++++++++++++++++++++++++----
1 file changed, 41 insertions(+), 4 deletions(-)
diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c
index 2bf6049..0a712c2 100644
--- a/drivers/pinctrl/pinctrl-nomadik.c
+++ b/drivers/pinctrl/pinctrl-nomadik.c
@@ -658,6 +658,35 @@ int nmk_gpio_set_mode(int gpio, int gpio_mode)
}
EXPORT_SYMBOL(nmk_gpio_set_mode);
+static int nmk_prcm_gpiocr_get_mode(struct pinctrl_dev *pctldev, int gpio)
+{
+ int i;
+ u16 reg;
+ u8 bit;
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+ const struct prcm_gpiocr_altcx_pin_desc *pin_desc;
+ const u16 *gpiocr_regs;
+
+ for (i = 0; i < npct->soc->npins_altcx; i++) {
+ if (npct->soc->altcx_pins[i].pin == gpio)
+ break;
+ }
+ if (i == npct->soc->npins_altcx)
+ return NMK_GPIO_ALT_C;
+
+ pin_desc = npct->soc->altcx_pins + i;
+ gpiocr_regs = npct->soc->prcm_gpiocr_registers;
+ for (i = 0; i < PRCM_IDX_GPIOCR_ALTC_MAX; i++) {
+ if (pin_desc->altcx[i].used == true) {
+ reg = gpiocr_regs[pin_desc->altcx[i].reg_index];
+ bit = pin_desc->altcx[i].control_bit;
+ if (prcmu_read(reg) & BIT(bit))
+ return NMK_GPIO_ALT_C+i+1;
+ }
+ }
+ return NMK_GPIO_ALT_C;
+}
+
int nmk_gpio_get_mode(int gpio)
{
struct nmk_gpio_chip *nmk_chip;
@@ -1046,8 +1075,9 @@ static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
#include <linux/seq_file.h>
-static void nmk_gpio_dbg_show_one(struct seq_file *s, struct gpio_chip *chip,
- unsigned offset, unsigned gpio)
+static void nmk_gpio_dbg_show_one(struct seq_file *s,
+ struct pinctrl_dev *pctldev, struct gpio_chip *chip,
+ unsigned offset, unsigned gpio)
{
const char *label = gpiochip_is_requested(chip, offset);
struct nmk_gpio_chip *nmk_chip =
@@ -1061,12 +1091,18 @@ static void nmk_gpio_dbg_show_one(struct seq_file *s, struct gpio_chip *chip,
[NMK_GPIO_ALT_A] = "altA",
[NMK_GPIO_ALT_B] = "altB",
[NMK_GPIO_ALT_C] = "altC",
+ [NMK_GPIO_ALT_C+1] = "altC1",
+ [NMK_GPIO_ALT_C+2] = "altC2",
+ [NMK_GPIO_ALT_C+3] = "altC3",
+ [NMK_GPIO_ALT_C+4] = "altC4",
};
clk_enable(nmk_chip->clk);
is_out = !!(readl(nmk_chip->addr + NMK_GPIO_DIR) & bit);
pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit);
mode = nmk_gpio_get_mode(gpio);
+ if ((mode == NMK_GPIO_ALT_C) && pctldev)
+ mode = nmk_prcm_gpiocr_get_mode(pctldev, gpio);
seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s",
gpio, label ?: "(none)",
@@ -1110,13 +1146,14 @@ static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
unsigned gpio = chip->base;
for (i = 0; i < chip->ngpio; i++, gpio++) {
- nmk_gpio_dbg_show_one(s, chip, i, gpio);
+ nmk_gpio_dbg_show_one(s, NULL, chip, i, gpio);
seq_printf(s, "\n");
}
}
#else
static inline void nmk_gpio_dbg_show_one(struct seq_file *s,
+ struct pinctrl_dev *pctldev,
struct gpio_chip *chip,
unsigned offset, unsigned gpio)
{
@@ -1454,7 +1491,7 @@ static void nmk_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
return;
}
chip = range->gc;
- nmk_gpio_dbg_show_one(s, chip, offset - chip->base, offset);
+ nmk_gpio_dbg_show_one(s, pctldev, chip, offset - chip->base, offset);
}
static struct pinctrl_ops nmk_pinctrl_ops = {
--
1.7.11.3
^ permalink raw reply related
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