2013-04-24 20:50:41

by Laurent Pinchart

[permalink] [raw]
Subject: [PATCH v2 00/11] Renesas TPU PWM support

Hello,

This is the second version of the Renesas TPU PWM unit support patches. The
patch series deprecates and removes the leds-renesas-tpu driver in favor of a
combination of leds-pwm and pwm-rmob. As an added bonus patches 9/11 and 10/11
remove function GPIOs support from the sh73a0 platform. Along with the other
PFC-related patches recently posted on the list, mach-shmobile is now free of
function GPIOs. We still need volunteer(s) to migrate arch/sh.

I've tested the code on Armadillo only as I don't have access to a kota2
board. This is why I've added backlight support to Armadillo as part of this
set.

The patches are based on a merge of "[PATCH 00/37] Fully migrate r8a7740 to
pinctrl", "[PATCH 0/4] sh73a0: Expose the PFC-controller SDHI power gate as a
regulator" and "[PATCH] sh-pfc: r8a7740: Add bias (pull-up/down) pinconf
support". I've pushed them to

git://linuxtv.org/pinchartl/fbdev.git pinmux/3.9/tpu

Changes compared to v1:

- Renamed the pwm-rmob driver to pwm-renesas-tpu, as TPU units are found in
Renesas SH-Mobile, R-Mobile and R-Car SoCs.
- Added TPU clock and pin groups for r8a7790.

Laurent Pinchart (11):
sh-pfc: sh73a0: Add TPU pin groups and functions
sh-pfc: r8a7740: Add TPU pin groups and functions
sh-pfc: r8a7790: Add TPU pin groups and functions
pwm: Add Renesas TPU PWM driver
ARM: mach-shmobile: clock-r8a7740: add TPU PWM support
ARM: mach-shmobile: clock-r8a7790: add TPU PWM support
ARM: mach-shmobile: armadillo800eva: Add backlight support
ARM: mach-shmobile: kota2: Use leds-pwm + pwm-rmob
sh-pfc: sh73a0: Remove function GPIOs
ARM: shmobile: sh73a0: Remove all GPIOs
leds: Remove leds-renesas-tpu driver

arch/arm/mach-shmobile/board-armadillo800eva.c | 51 ++-
arch/arm/mach-shmobile/board-kota2.c | 178 +++++---
arch/arm/mach-shmobile/clock-r8a7740.c | 4 +-
arch/arm/mach-shmobile/clock-r8a7790.c | 11 +-
arch/arm/mach-shmobile/clock-sh73a0.c | 8 +-
arch/arm/mach-shmobile/include/mach/sh73a0.h | 373 +--------------
drivers/leds/Kconfig | 12 -
drivers/leds/Makefile | 1 -
drivers/leds/leds-renesas-tpu.c | 336 --------------
drivers/pinctrl/sh-pfc/pfc-r8a7740.c | 50 ++
drivers/pinctrl/sh-pfc/pfc-r8a7790.c | 41 ++
drivers/pinctrl/sh-pfc/pfc-sh73a0.c | 608 +++++++++----------------
drivers/pwm/Kconfig | 7 +
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-renesas-tpu.c | 462 +++++++++++++++++++
include/linux/platform_data/leds-renesas-tpu.h | 14 -
include/linux/platform_data/pwm-renesas-tpu.h | 18 +
17 files changed, 963 insertions(+), 1212 deletions(-)
delete mode 100644 drivers/leds/leds-renesas-tpu.c
create mode 100644 drivers/pwm/pwm-renesas-tpu.c
delete mode 100644 include/linux/platform_data/leds-renesas-tpu.h
create mode 100644 include/linux/platform_data/pwm-renesas-tpu.h

--
Regards,

Laurent Pinchart


2013-04-24 20:50:42

by Laurent Pinchart

[permalink] [raw]
Subject: [PATCH v2 01/11] sh-pfc: sh73a0: Add TPU pin groups and functions

Signed-off-by: Laurent Pinchart <[email protected]>
---
drivers/pinctrl/sh-pfc/pfc-sh73a0.c | 213 ++++++++++++++++++++++++++++++++++++
1 file changed, 213 insertions(+)

diff --git a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
index ea1fcbe..e4e0c92 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
@@ -2542,6 +2542,157 @@ static const unsigned int sdhi2_ctrl_pins[] = {
static const unsigned int sdhi2_ctrl_mux[] = {
SDHICMD2_MARK, SDHICLK2_MARK,
};
+/* - TPU0 ------------------------------------------------------------------- */
+static const unsigned int tpu0_to0_pins[] = {
+ /* TO */
+ 55,
+};
+static const unsigned int tpu0_to0_mux[] = {
+ TPU0TO0_MARK,
+};
+static const unsigned int tpu0_to1_pins[] = {
+ /* TO */
+ 59,
+};
+static const unsigned int tpu0_to1_mux[] = {
+ TPU0TO1_MARK,
+};
+static const unsigned int tpu0_to2_pins[] = {
+ /* TO */
+ 140,
+};
+static const unsigned int tpu0_to2_mux[] = {
+ TPU0TO2_MARK,
+};
+static const unsigned int tpu0_to3_pins[] = {
+ /* TO */
+ 141,
+};
+static const unsigned int tpu0_to3_mux[] = {
+ TPU0TO3_MARK,
+};
+/* - TPU1 ------------------------------------------------------------------- */
+static const unsigned int tpu1_to0_pins[] = {
+ /* TO */
+ 246,
+};
+static const unsigned int tpu1_to0_mux[] = {
+ TPU1TO0_MARK,
+};
+static const unsigned int tpu1_to1_0_pins[] = {
+ /* TO */
+ 28,
+};
+static const unsigned int tpu1_to1_0_mux[] = {
+ PORT28_TPU1TO1_MARK,
+};
+static const unsigned int tpu1_to1_1_pins[] = {
+ /* TO */
+ 29,
+};
+static const unsigned int tpu1_to1_1_mux[] = {
+ PORT29_TPU1TO1_MARK,
+};
+static const unsigned int tpu1_to2_pins[] = {
+ /* TO */
+ 153,
+};
+static const unsigned int tpu1_to2_mux[] = {
+ TPU1TO2_MARK,
+};
+static const unsigned int tpu1_to3_pins[] = {
+ /* TO */
+ 145,
+};
+static const unsigned int tpu1_to3_mux[] = {
+ TPU1TO3_MARK,
+};
+/* - TPU2 ------------------------------------------------------------------- */
+static const unsigned int tpu2_to0_pins[] = {
+ /* TO */
+ 248,
+};
+static const unsigned int tpu2_to0_mux[] = {
+ TPU2TO0_MARK,
+};
+static const unsigned int tpu2_to1_pins[] = {
+ /* TO */
+ 197,
+};
+static const unsigned int tpu2_to1_mux[] = {
+ TPU2TO1_MARK,
+};
+static const unsigned int tpu2_to2_pins[] = {
+ /* TO */
+ 50,
+};
+static const unsigned int tpu2_to2_mux[] = {
+ TPU2TO2_MARK,
+};
+static const unsigned int tpu2_to3_pins[] = {
+ /* TO */
+ 51,
+};
+static const unsigned int tpu2_to3_mux[] = {
+ TPU2TO3_MARK,
+};
+/* - TPU3 ------------------------------------------------------------------- */
+static const unsigned int tpu3_to0_pins[] = {
+ /* TO */
+ 163,
+};
+static const unsigned int tpu3_to0_mux[] = {
+ TPU3TO0_MARK,
+};
+static const unsigned int tpu3_to1_pins[] = {
+ /* TO */
+ 247,
+};
+static const unsigned int tpu3_to1_mux[] = {
+ TPU3TO1_MARK,
+};
+static const unsigned int tpu3_to2_pins[] = {
+ /* TO */
+ 54,
+};
+static const unsigned int tpu3_to2_mux[] = {
+ TPU3TO2_MARK,
+};
+static const unsigned int tpu3_to3_pins[] = {
+ /* TO */
+ 53,
+};
+static const unsigned int tpu3_to3_mux[] = {
+ TPU3TO3_MARK,
+};
+/* - TPU4 ------------------------------------------------------------------- */
+static const unsigned int tpu4_to0_pins[] = {
+ /* TO */
+ 241,
+};
+static const unsigned int tpu4_to0_mux[] = {
+ TPU4TO0_MARK,
+};
+static const unsigned int tpu4_to1_pins[] = {
+ /* TO */
+ 199,
+};
+static const unsigned int tpu4_to1_mux[] = {
+ TPU4TO1_MARK,
+};
+static const unsigned int tpu4_to2_pins[] = {
+ /* TO */
+ 58,
+};
+static const unsigned int tpu4_to2_mux[] = {
+ TPU4TO2_MARK,
+};
+static const unsigned int tpu4_to3_pins[] = {
+ /* TO */
+};
+static const unsigned int tpu4_to3_mux[] = {
+ TPU4TO3_MARK,
+};
/* - USB -------------------------------------------------------------------- */
static const unsigned int usb_vbus_pins[] = {
/* VBUS */
@@ -2693,6 +2844,27 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(sdhi2_data1),
SH_PFC_PIN_GROUP(sdhi2_data4),
SH_PFC_PIN_GROUP(sdhi2_ctrl),
+ SH_PFC_PIN_GROUP(tpu0_to0),
+ SH_PFC_PIN_GROUP(tpu0_to1),
+ SH_PFC_PIN_GROUP(tpu0_to2),
+ SH_PFC_PIN_GROUP(tpu0_to3),
+ SH_PFC_PIN_GROUP(tpu1_to0),
+ SH_PFC_PIN_GROUP(tpu1_to1_0),
+ SH_PFC_PIN_GROUP(tpu1_to1_1),
+ SH_PFC_PIN_GROUP(tpu1_to2),
+ SH_PFC_PIN_GROUP(tpu1_to3),
+ SH_PFC_PIN_GROUP(tpu2_to0),
+ SH_PFC_PIN_GROUP(tpu2_to1),
+ SH_PFC_PIN_GROUP(tpu2_to2),
+ SH_PFC_PIN_GROUP(tpu2_to3),
+ SH_PFC_PIN_GROUP(tpu3_to0),
+ SH_PFC_PIN_GROUP(tpu3_to1),
+ SH_PFC_PIN_GROUP(tpu3_to2),
+ SH_PFC_PIN_GROUP(tpu3_to3),
+ SH_PFC_PIN_GROUP(tpu4_to0),
+ SH_PFC_PIN_GROUP(tpu4_to1),
+ SH_PFC_PIN_GROUP(tpu4_to2),
+ SH_PFC_PIN_GROUP(tpu4_to3),
SH_PFC_PIN_GROUP(usb_vbus),
};

@@ -2912,6 +3084,42 @@ static const char * const usb_groups[] = {
"usb_vbus",
};

+static const char * const tpu0_groups[] = {
+ "tpu0_to0",
+ "tpu0_to1",
+ "tpu0_to2",
+ "tpu0_to3",
+};
+
+static const char * const tpu1_groups[] = {
+ "tpu1_to0",
+ "tpu1_to1_0",
+ "tpu1_to1_1",
+ "tpu1_to2",
+ "tpu1_to3",
+};
+
+static const char * const tpu2_groups[] = {
+ "tpu2_to0",
+ "tpu2_to1",
+ "tpu2_to2",
+ "tpu2_to3",
+};
+
+static const char * const tpu3_groups[] = {
+ "tpu3_to0",
+ "tpu3_to1",
+ "tpu3_to2",
+ "tpu3_to3",
+};
+
+static const char * const tpu4_groups[] = {
+ "tpu4_to0",
+ "tpu4_to1",
+ "tpu4_to2",
+ "tpu4_to3",
+};
+
static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(bsc),
SH_PFC_FUNCTION(fsia),
@@ -2937,6 +3145,11 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(sdhi0),
SH_PFC_FUNCTION(sdhi1),
SH_PFC_FUNCTION(sdhi2),
+ SH_PFC_FUNCTION(tpu0),
+ SH_PFC_FUNCTION(tpu1),
+ SH_PFC_FUNCTION(tpu2),
+ SH_PFC_FUNCTION(tpu3),
+ SH_PFC_FUNCTION(tpu4),
SH_PFC_FUNCTION(usb),
};

--
1.8.1.5

2013-04-24 20:50:45

by Laurent Pinchart

[permalink] [raw]
Subject: [PATCH v2 05/11] ARM: mach-shmobile: clock-r8a7740: add TPU PWM support

Signed-off-by: Laurent Pinchart <[email protected]>
Tested-by: Simon Horman <[email protected]>
---
arch/arm/mach-shmobile/clock-r8a7740.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-shmobile/clock-r8a7740.c b/arch/arm/mach-shmobile/clock-r8a7740.c
index b12c476..6ad4640 100644
--- a/arch/arm/mach-shmobile/clock-r8a7740.c
+++ b/arch/arm/mach-shmobile/clock-r8a7740.c
@@ -461,7 +461,7 @@ enum {

MSTP329, MSTP328, MSTP323, MSTP320,
MSTP314, MSTP313, MSTP312,
- MSTP309,
+ MSTP309, MSTP304,

MSTP416, MSTP415, MSTP407, MSTP406,

@@ -499,6 +499,7 @@ static struct clk mstp_clks[MSTP_NR] = {
[MSTP313] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 13, 0), /* SDHI1 */
[MSTP312] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMC */
[MSTP309] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 9, 0), /* GEther */
+ [MSTP304] = SH_CLK_MSTP32(&div4_clks[DIV4_CP], SMSTPCR3, 4, 0), /* TPU0 */

[MSTP416] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR4, 16, 0), /* USBHOST */
[MSTP415] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR4, 15, 0), /* SDHI2 */
@@ -596,6 +597,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("e6bd0000.mmcif", &mstp_clks[MSTP312]),
CLKDEV_DEV_ID("sh-eth", &mstp_clks[MSTP309]),
CLKDEV_DEV_ID("e9a00000.sh-eth", &mstp_clks[MSTP309]),
+ CLKDEV_DEV_ID("renesas_tpu_pwm", &mstp_clks[MSTP304]),

CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP415]),
CLKDEV_DEV_ID("e6870000.sdhi", &mstp_clks[MSTP415]),
--
1.8.1.5

2013-04-24 20:50:44

by Laurent Pinchart

[permalink] [raw]
Subject: [PATCH v2 03/11] sh-pfc: r8a7790: Add TPU pin groups and functions

Signed-off-by: Laurent Pinchart <[email protected]>
---
drivers/pinctrl/sh-pfc/pfc-r8a7790.c | 41 ++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)

diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
index 1656915..5be2999 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
@@ -2342,6 +2342,35 @@ static const unsigned int scifb2_data_c_pins[] = {
static const unsigned int scifb2_data_c_mux[] = {
SCIFB2_RXD_C_MARK, SCIFB2_TXD_C_MARK,
};
+/* - TPU0 ------------------------------------------------------------------- */
+static const unsigned int tpu0_to0_pins[] = {
+ /* TO */
+ RCAR_GP_PIN(0, 20),
+};
+static const unsigned int tpu0_to0_mux[] = {
+ TPU0TO0_MARK,
+};
+static const unsigned int tpu0_to1_pins[] = {
+ /* TO */
+ RCAR_GP_PIN(0, 21),
+};
+static const unsigned int tpu0_to1_mux[] = {
+ TPU0TO1_MARK,
+};
+static const unsigned int tpu0_to2_pins[] = {
+ /* TO */
+ RCAR_GP_PIN(0, 22),
+};
+static const unsigned int tpu0_to2_mux[] = {
+ TPU0TO2_MARK,
+};
+static const unsigned int tpu0_to3_pins[] = {
+ /* TO */
+ RCAR_GP_PIN(0, 23),
+};
+static const unsigned int tpu0_to3_mux[] = {
+ TPU0TO3_MARK,
+};

static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(eth_link),
@@ -2416,6 +2445,10 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(scifb2_clk_b),
SH_PFC_PIN_GROUP(scifb2_ctrl_b),
SH_PFC_PIN_GROUP(scifb2_data_c),
+ SH_PFC_PIN_GROUP(tpu0_to0),
+ SH_PFC_PIN_GROUP(tpu0_to1),
+ SH_PFC_PIN_GROUP(tpu0_to2),
+ SH_PFC_PIN_GROUP(tpu0_to3),
};

static const char * const eth_groups[] = {
@@ -2520,6 +2553,13 @@ static const char * const scifb2_groups[] = {
"scifb2_data_c",
};

+static const char * const tpu0_groups[] = {
+ "tpu0_to0",
+ "tpu0_to1",
+ "tpu0_to2",
+ "tpu0_to3",
+};
+
static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(eth),
SH_PFC_FUNCTION(intc),
@@ -2531,6 +2571,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(scifb0),
SH_PFC_FUNCTION(scifb1),
SH_PFC_FUNCTION(scifb2),
+ SH_PFC_FUNCTION(tpu0),
};

static struct pinmux_cfg_reg pinmux_config_regs[] = {
--
1.8.1.5

2013-04-24 20:51:07

by Laurent Pinchart

[permalink] [raw]
Subject: [PATCH v2 11/11] leds: Remove leds-renesas-tpu driver

The driver is superseded by the generic rmob-tpu-pwm driver used with
leds-pwm.

Signed-off-by: Laurent Pinchart <[email protected]>
---
drivers/leds/Kconfig | 12 -
drivers/leds/Makefile | 1 -
drivers/leds/leds-renesas-tpu.c | 336 -------------------------
include/linux/platform_data/leds-renesas-tpu.h | 14 --
4 files changed, 363 deletions(-)
delete mode 100644 drivers/leds/leds-renesas-tpu.c
delete mode 100644 include/linux/platform_data/leds-renesas-tpu.h

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index ec50824..da2ac5c 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -419,18 +419,6 @@ config LEDS_ASIC3
cannot be used. This driver supports hardware blinking with an on+off
period from 62ms to 125s. Say Y to enable LEDs on the HP iPAQ hx4700.

-config LEDS_RENESAS_TPU
- bool "LED support for Renesas TPU"
- depends on LEDS_CLASS=y && HAVE_CLK && GENERIC_GPIO
- help
- This option enables build of the LED TPU platform driver,
- suitable to drive any TPU channel on newer Renesas SoCs.
- The driver controls the GPIO pin connected to the LED via
- the GPIO framework and expects the LED to be connected to
- a pin that can be driven in both GPIO mode and using TPU
- pin function. The latter to support brightness control.
- Brightness control is supported but hardware blinking is not.
-
config LEDS_TCA6507
tristate "LED Support for TCA6507 I2C chip"
depends on LEDS_CLASS && I2C
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 215e7e3..dd80c1a 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -48,7 +48,6 @@ obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o
obj-$(CONFIG_LEDS_NS2) += leds-ns2.o
obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o
obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o
-obj-$(CONFIG_LEDS_RENESAS_TPU) += leds-renesas-tpu.o
obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o
obj-$(CONFIG_LEDS_LM355x) += leds-lm355x.o
obj-$(CONFIG_LEDS_BLINKM) += leds-blinkm.o
diff --git a/drivers/leds/leds-renesas-tpu.c b/drivers/leds/leds-renesas-tpu.c
deleted file mode 100644
index d3c2b7e..0000000
--- a/drivers/leds/leds-renesas-tpu.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * LED control using Renesas TPU
- *
- * Copyright (C) 2011 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/printk.h>
-#include <linux/ioport.h>
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/leds.h>
-#include <linux/platform_data/leds-renesas-tpu.h>
-#include <linux/gpio.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-#include <linux/workqueue.h>
-
-enum r_tpu_pin { R_TPU_PIN_UNUSED, R_TPU_PIN_GPIO, R_TPU_PIN_GPIO_FN };
-enum r_tpu_timer { R_TPU_TIMER_UNUSED, R_TPU_TIMER_ON };
-
-struct r_tpu_priv {
- struct led_classdev ldev;
- void __iomem *mapbase;
- struct clk *clk;
- struct platform_device *pdev;
- enum r_tpu_pin pin_state;
- enum r_tpu_timer timer_state;
- unsigned long min_rate;
- unsigned int refresh_rate;
- struct work_struct work;
- enum led_brightness new_brightness;
-};
-
-static DEFINE_SPINLOCK(r_tpu_lock);
-
-#define TSTR -1 /* Timer start register (shared register) */
-#define TCR 0 /* Timer control register (+0x00) */
-#define TMDR 1 /* Timer mode register (+0x04) */
-#define TIOR 2 /* Timer I/O control register (+0x08) */
-#define TIER 3 /* Timer interrupt enable register (+0x0c) */
-#define TSR 4 /* Timer status register (+0x10) */
-#define TCNT 5 /* Timer counter (+0x14) */
-#define TGRA 6 /* Timer general register A (+0x18) */
-#define TGRB 7 /* Timer general register B (+0x1c) */
-#define TGRC 8 /* Timer general register C (+0x20) */
-#define TGRD 9 /* Timer general register D (+0x24) */
-
-static inline unsigned short r_tpu_read(struct r_tpu_priv *p, int reg_nr)
-{
- struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
- void __iomem *base = p->mapbase;
- unsigned long offs = reg_nr << 2;
-
- if (reg_nr == TSTR)
- return ioread16(base - cfg->channel_offset);
-
- return ioread16(base + offs);
-}
-
-static inline void r_tpu_write(struct r_tpu_priv *p, int reg_nr,
- unsigned short value)
-{
- struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
- void __iomem *base = p->mapbase;
- unsigned long offs = reg_nr << 2;
-
- if (reg_nr == TSTR) {
- iowrite16(value, base - cfg->channel_offset);
- return;
- }
-
- iowrite16(value, base + offs);
-}
-
-static void r_tpu_start_stop_ch(struct r_tpu_priv *p, int start)
-{
- struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
- unsigned long flags, value;
-
- /* start stop register shared by multiple timer channels */
- spin_lock_irqsave(&r_tpu_lock, flags);
- value = r_tpu_read(p, TSTR);
-
- if (start)
- value |= 1 << cfg->timer_bit;
- else
- value &= ~(1 << cfg->timer_bit);
-
- r_tpu_write(p, TSTR, value);
- spin_unlock_irqrestore(&r_tpu_lock, flags);
-}
-
-static int r_tpu_enable(struct r_tpu_priv *p, enum led_brightness brightness)
-{
- struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
- int prescaler[] = { 1, 4, 16, 64 };
- int k, ret;
- unsigned long rate, tmp;
-
- if (p->timer_state == R_TPU_TIMER_ON)
- return 0;
-
- /* wake up device and enable clock */
- pm_runtime_get_sync(&p->pdev->dev);
- ret = clk_enable(p->clk);
- if (ret) {
- dev_err(&p->pdev->dev, "cannot enable clock\n");
- return ret;
- }
-
- /* make sure channel is disabled */
- r_tpu_start_stop_ch(p, 0);
-
- /* get clock rate after enabling it */
- rate = clk_get_rate(p->clk);
-
- /* pick the lowest acceptable rate */
- for (k = ARRAY_SIZE(prescaler) - 1; k >= 0; k--)
- if ((rate / prescaler[k]) >= p->min_rate)
- break;
-
- if (k < 0) {
- dev_err(&p->pdev->dev, "clock rate mismatch\n");
- goto err0;
- }
- dev_dbg(&p->pdev->dev, "rate = %lu, prescaler %u\n",
- rate, prescaler[k]);
-
- /* clear TCNT on TGRB match, count on rising edge, set prescaler */
- r_tpu_write(p, TCR, 0x0040 | k);
-
- /* output 0 until TGRA, output 1 until TGRB */
- r_tpu_write(p, TIOR, 0x0002);
-
- rate /= prescaler[k] * p->refresh_rate;
- r_tpu_write(p, TGRB, rate);
- dev_dbg(&p->pdev->dev, "TRGB = 0x%04lx\n", rate);
-
- tmp = (cfg->max_brightness - brightness) * rate;
- r_tpu_write(p, TGRA, tmp / cfg->max_brightness);
- dev_dbg(&p->pdev->dev, "TRGA = 0x%04lx\n", tmp / cfg->max_brightness);
-
- /* PWM mode */
- r_tpu_write(p, TMDR, 0x0002);
-
- /* enable channel */
- r_tpu_start_stop_ch(p, 1);
-
- p->timer_state = R_TPU_TIMER_ON;
- return 0;
- err0:
- clk_disable(p->clk);
- pm_runtime_put_sync(&p->pdev->dev);
- return -ENOTSUPP;
-}
-
-static void r_tpu_disable(struct r_tpu_priv *p)
-{
- if (p->timer_state == R_TPU_TIMER_UNUSED)
- return;
-
- /* disable channel */
- r_tpu_start_stop_ch(p, 0);
-
- /* stop clock and mark device as idle */
- clk_disable(p->clk);
- pm_runtime_put_sync(&p->pdev->dev);
-
- p->timer_state = R_TPU_TIMER_UNUSED;
-}
-
-static void r_tpu_set_pin(struct r_tpu_priv *p, enum r_tpu_pin new_state,
- enum led_brightness brightness)
-{
- struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
-
- if (p->pin_state == new_state) {
- if (p->pin_state == R_TPU_PIN_GPIO)
- gpio_set_value(cfg->pin_gpio, brightness);
- return;
- }
-
- if (p->pin_state == R_TPU_PIN_GPIO)
- gpio_free(cfg->pin_gpio);
-
- if (p->pin_state == R_TPU_PIN_GPIO_FN)
- gpio_free(cfg->pin_gpio_fn);
-
- if (new_state == R_TPU_PIN_GPIO)
- gpio_request_one(cfg->pin_gpio, GPIOF_DIR_OUT | !!brightness,
- cfg->name);
-
- if (new_state == R_TPU_PIN_GPIO_FN)
- gpio_request(cfg->pin_gpio_fn, cfg->name);
-
- p->pin_state = new_state;
-}
-
-static void r_tpu_work(struct work_struct *work)
-{
- struct r_tpu_priv *p = container_of(work, struct r_tpu_priv, work);
- enum led_brightness brightness = p->new_brightness;
-
- r_tpu_disable(p);
-
- /* off and maximum are handled as GPIO pins, in between PWM */
- if ((brightness == 0) || (brightness == p->ldev.max_brightness))
- r_tpu_set_pin(p, R_TPU_PIN_GPIO, brightness);
- else {
- r_tpu_set_pin(p, R_TPU_PIN_GPIO_FN, 0);
- r_tpu_enable(p, brightness);
- }
-}
-
-static void r_tpu_set_brightness(struct led_classdev *ldev,
- enum led_brightness brightness)
-{
- struct r_tpu_priv *p = container_of(ldev, struct r_tpu_priv, ldev);
- p->new_brightness = brightness;
- schedule_work(&p->work);
-}
-
-static int r_tpu_probe(struct platform_device *pdev)
-{
- struct led_renesas_tpu_config *cfg = pdev->dev.platform_data;
- struct r_tpu_priv *p;
- struct resource *res;
- int ret;
-
- if (!cfg) {
- dev_err(&pdev->dev, "missing platform data\n");
- return -ENODEV;
- }
-
- p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
- if (p == NULL) {
- dev_err(&pdev->dev, "failed to allocate driver data\n");
- return -ENOMEM;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "failed to get I/O memory\n");
- return -ENXIO;
- }
-
- /* map memory, let mapbase point to our channel */
- p->mapbase = devm_ioremap_nocache(&pdev->dev, res->start,
- resource_size(res));
- if (p->mapbase == NULL) {
- dev_err(&pdev->dev, "failed to remap I/O memory\n");
- return -ENXIO;
- }
-
- /* get hold of clock */
- p->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(p->clk)) {
- dev_err(&pdev->dev, "cannot get clock\n");
- return PTR_ERR(p->clk);
- }
-
- p->pdev = pdev;
- p->pin_state = R_TPU_PIN_UNUSED;
- p->timer_state = R_TPU_TIMER_UNUSED;
- p->refresh_rate = cfg->refresh_rate ? cfg->refresh_rate : 100;
- r_tpu_set_pin(p, R_TPU_PIN_GPIO, LED_OFF);
- platform_set_drvdata(pdev, p);
-
- INIT_WORK(&p->work, r_tpu_work);
-
- p->ldev.name = cfg->name;
- p->ldev.brightness = LED_OFF;
- p->ldev.max_brightness = cfg->max_brightness;
- p->ldev.brightness_set = r_tpu_set_brightness;
- p->ldev.flags |= LED_CORE_SUSPENDRESUME;
- ret = led_classdev_register(&pdev->dev, &p->ldev);
- if (ret < 0)
- goto err0;
-
- /* max_brightness may be updated by the LED core code */
- p->min_rate = p->ldev.max_brightness * p->refresh_rate;
-
- pm_runtime_enable(&pdev->dev);
- return 0;
-
- err0:
- r_tpu_set_pin(p, R_TPU_PIN_UNUSED, LED_OFF);
- return ret;
-}
-
-static int r_tpu_remove(struct platform_device *pdev)
-{
- struct r_tpu_priv *p = platform_get_drvdata(pdev);
-
- r_tpu_set_brightness(&p->ldev, LED_OFF);
- led_classdev_unregister(&p->ldev);
- cancel_work_sync(&p->work);
- r_tpu_disable(p);
- r_tpu_set_pin(p, R_TPU_PIN_UNUSED, LED_OFF);
-
- pm_runtime_disable(&pdev->dev);
-
- return 0;
-}
-
-static struct platform_driver r_tpu_device_driver = {
- .probe = r_tpu_probe,
- .remove = r_tpu_remove,
- .driver = {
- .name = "leds-renesas-tpu",
- }
-};
-
-module_platform_driver(r_tpu_device_driver);
-
-MODULE_AUTHOR("Magnus Damm");
-MODULE_DESCRIPTION("Renesas TPU LED Driver");
-MODULE_LICENSE("GPL v2");
diff --git a/include/linux/platform_data/leds-renesas-tpu.h b/include/linux/platform_data/leds-renesas-tpu.h
deleted file mode 100644
index 0553870..0000000
--- a/include/linux/platform_data/leds-renesas-tpu.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __LEDS_RENESAS_TPU_H__
-#define __LEDS_RENESAS_TPU_H__
-
-struct led_renesas_tpu_config {
- char *name;
- unsigned pin_gpio_fn;
- unsigned pin_gpio;
- unsigned int channel_offset;
- unsigned int timer_bit;
- unsigned int max_brightness;
- unsigned int refresh_rate;
-};
-
-#endif /* __LEDS_RENESAS_TPU_H__ */
--
1.8.1.5

2013-04-24 20:51:35

by Laurent Pinchart

[permalink] [raw]
Subject: [PATCH v2 10/11] ARM: shmobile: sh73a0: Remove all GPIOs

Function GPIOs are not used anymore, and all code use the GPIO numbers
directly. Remove the GPIOs enumeration.

Signed-off-by: Laurent Pinchart <[email protected]>
---
arch/arm/mach-shmobile/include/mach/sh73a0.h | 373 +--------------------------
1 file changed, 1 insertion(+), 372 deletions(-)

diff --git a/arch/arm/mach-shmobile/include/mach/sh73a0.h b/arch/arm/mach-shmobile/include/mach/sh73a0.h
index eb7a432..680dc5f 100644
--- a/arch/arm/mach-shmobile/include/mach/sh73a0.h
+++ b/arch/arm/mach-shmobile/include/mach/sh73a0.h
@@ -1,378 +1,7 @@
#ifndef __ASM_SH73A0_H__
#define __ASM_SH73A0_H__

-/* Pin Function Controller:
- * GPIO_FN_xx - GPIO used to select pin function and MSEL switch
- * GPIO_PORTxx - GPIO mapped to real I/O pin on CPU
- */
-enum {
- /* Hardware manual Table 25-1 (GPIO) */
- GPIO_PORT0, GPIO_PORT1, GPIO_PORT2, GPIO_PORT3, GPIO_PORT4,
- GPIO_PORT5, GPIO_PORT6, GPIO_PORT7, GPIO_PORT8, GPIO_PORT9,
-
- GPIO_PORT10, GPIO_PORT11, GPIO_PORT12, GPIO_PORT13, GPIO_PORT14,
- GPIO_PORT15, GPIO_PORT16, GPIO_PORT17, GPIO_PORT18, GPIO_PORT19,
-
- GPIO_PORT20, GPIO_PORT21, GPIO_PORT22, GPIO_PORT23, GPIO_PORT24,
- GPIO_PORT25, GPIO_PORT26, GPIO_PORT27, GPIO_PORT28, GPIO_PORT29,
-
- GPIO_PORT30, GPIO_PORT31, GPIO_PORT32, GPIO_PORT33, GPIO_PORT34,
- GPIO_PORT35, GPIO_PORT36, GPIO_PORT37, GPIO_PORT38, GPIO_PORT39,
-
- GPIO_PORT40, GPIO_PORT41, GPIO_PORT42, GPIO_PORT43, GPIO_PORT44,
- GPIO_PORT45, GPIO_PORT46, GPIO_PORT47, GPIO_PORT48, GPIO_PORT49,
-
- GPIO_PORT50, GPIO_PORT51, GPIO_PORT52, GPIO_PORT53, GPIO_PORT54,
- GPIO_PORT55, GPIO_PORT56, GPIO_PORT57, GPIO_PORT58, GPIO_PORT59,
-
- GPIO_PORT60, GPIO_PORT61, GPIO_PORT62, GPIO_PORT63, GPIO_PORT64,
- GPIO_PORT65, GPIO_PORT66, GPIO_PORT67, GPIO_PORT68, GPIO_PORT69,
-
- GPIO_PORT70, GPIO_PORT71, GPIO_PORT72, GPIO_PORT73, GPIO_PORT74,
- GPIO_PORT75, GPIO_PORT76, GPIO_PORT77, GPIO_PORT78, GPIO_PORT79,
-
- GPIO_PORT80, GPIO_PORT81, GPIO_PORT82, GPIO_PORT83, GPIO_PORT84,
- GPIO_PORT85, GPIO_PORT86, GPIO_PORT87, GPIO_PORT88, GPIO_PORT89,
-
- GPIO_PORT90, GPIO_PORT91, GPIO_PORT92, GPIO_PORT93, GPIO_PORT94,
- GPIO_PORT95, GPIO_PORT96, GPIO_PORT97, GPIO_PORT98, GPIO_PORT99,
-
- GPIO_PORT100, GPIO_PORT101, GPIO_PORT102, GPIO_PORT103, GPIO_PORT104,
- GPIO_PORT105, GPIO_PORT106, GPIO_PORT107, GPIO_PORT108, GPIO_PORT109,
-
- GPIO_PORT110, GPIO_PORT111, GPIO_PORT112, GPIO_PORT113, GPIO_PORT114,
- GPIO_PORT115, GPIO_PORT116, GPIO_PORT117, GPIO_PORT118,
-
- GPIO_PORT128, GPIO_PORT129,
-
- GPIO_PORT130, GPIO_PORT131, GPIO_PORT132, GPIO_PORT133, GPIO_PORT134,
- GPIO_PORT135, GPIO_PORT136, GPIO_PORT137, GPIO_PORT138, GPIO_PORT139,
-
- GPIO_PORT140, GPIO_PORT141, GPIO_PORT142, GPIO_PORT143, GPIO_PORT144,
- GPIO_PORT145, GPIO_PORT146, GPIO_PORT147, GPIO_PORT148, GPIO_PORT149,
-
- GPIO_PORT150, GPIO_PORT151, GPIO_PORT152, GPIO_PORT153, GPIO_PORT154,
- GPIO_PORT155, GPIO_PORT156, GPIO_PORT157, GPIO_PORT158, GPIO_PORT159,
-
- GPIO_PORT160, GPIO_PORT161, GPIO_PORT162, GPIO_PORT163, GPIO_PORT164,
-
- GPIO_PORT192, GPIO_PORT193, GPIO_PORT194,
- GPIO_PORT195, GPIO_PORT196, GPIO_PORT197, GPIO_PORT198, GPIO_PORT199,
-
- GPIO_PORT200, GPIO_PORT201, GPIO_PORT202, GPIO_PORT203, GPIO_PORT204,
- GPIO_PORT205, GPIO_PORT206, GPIO_PORT207, GPIO_PORT208, GPIO_PORT209,
-
- GPIO_PORT210, GPIO_PORT211, GPIO_PORT212, GPIO_PORT213, GPIO_PORT214,
- GPIO_PORT215, GPIO_PORT216, GPIO_PORT217, GPIO_PORT218, GPIO_PORT219,
-
- GPIO_PORT220, GPIO_PORT221, GPIO_PORT222, GPIO_PORT223, GPIO_PORT224,
- GPIO_PORT225, GPIO_PORT226, GPIO_PORT227, GPIO_PORT228, GPIO_PORT229,
-
- GPIO_PORT230, GPIO_PORT231, GPIO_PORT232, GPIO_PORT233, GPIO_PORT234,
- GPIO_PORT235, GPIO_PORT236, GPIO_PORT237, GPIO_PORT238, GPIO_PORT239,
-
- GPIO_PORT240, GPIO_PORT241, GPIO_PORT242, GPIO_PORT243, GPIO_PORT244,
- GPIO_PORT245, GPIO_PORT246, GPIO_PORT247, GPIO_PORT248, GPIO_PORT249,
-
- GPIO_PORT250, GPIO_PORT251, GPIO_PORT252, GPIO_PORT253, GPIO_PORT254,
- GPIO_PORT255, GPIO_PORT256, GPIO_PORT257, GPIO_PORT258, GPIO_PORT259,
-
- GPIO_PORT260, GPIO_PORT261, GPIO_PORT262, GPIO_PORT263, GPIO_PORT264,
- GPIO_PORT265, GPIO_PORT266, GPIO_PORT267, GPIO_PORT268, GPIO_PORT269,
-
- GPIO_PORT270, GPIO_PORT271, GPIO_PORT272, GPIO_PORT273, GPIO_PORT274,
- GPIO_PORT275, GPIO_PORT276, GPIO_PORT277, GPIO_PORT278, GPIO_PORT279,
-
- GPIO_PORT280, GPIO_PORT281, GPIO_PORT282,
-
- GPIO_PORT288, GPIO_PORT289,
-
- GPIO_PORT290, GPIO_PORT291, GPIO_PORT292, GPIO_PORT293, GPIO_PORT294,
- GPIO_PORT295, GPIO_PORT296, GPIO_PORT297, GPIO_PORT298, GPIO_PORT299,
-
- GPIO_PORT300, GPIO_PORT301, GPIO_PORT302, GPIO_PORT303, GPIO_PORT304,
- GPIO_PORT305, GPIO_PORT306, GPIO_PORT307, GPIO_PORT308, GPIO_PORT309,
-
- /* Table 25-1 (Function 0-7) */
- GPIO_FN_GPI0 = 310,
- GPIO_FN_GPI1,
- GPIO_FN_GPI2,
- GPIO_FN_GPI3,
- GPIO_FN_GPI4,
- GPIO_FN_GPI5,
- GPIO_FN_GPI6,
- GPIO_FN_GPI7,
- GPIO_FN_GPO7, GPIO_FN_MFG0_OUT2,
- GPIO_FN_GPO6, GPIO_FN_MFG1_OUT2,
- GPIO_FN_GPO5,
- GPIO_FN_PORT16_VIO_CKOR,
- GPIO_FN_PORT19_VIO_CKO2,
- GPIO_FN_GPO0,
- GPIO_FN_GPO1,
- GPIO_FN_GPO2, GPIO_FN_STATUS0,
- GPIO_FN_GPO3, GPIO_FN_STATUS1,
- GPIO_FN_GPO4, GPIO_FN_STATUS2,
- GPIO_FN_VINT,
- GPIO_FN_TCKON,
- GPIO_FN_XDVFS1,
- GPIO_FN_MFG0_OUT1, GPIO_FN_PORT27_IROUT,
- GPIO_FN_XDVFS2,
- GPIO_FN_PORT28_TPU1TO1,
- GPIO_FN_SIM_RST, GPIO_FN_PORT29_TPU1TO1,
- GPIO_FN_SIM_CLK, GPIO_FN_PORT30_VIO_CKOR,
- GPIO_FN_SIM_D, GPIO_FN_PORT31_IROUT,
- GPIO_FN_XWUP,
- GPIO_FN_VACK,
- GPIO_FN_XTAL1L,
- GPIO_FN_PORT49_IROUT,
- GPIO_FN_BBIF2_TSYNC2, GPIO_FN_TPU2TO2,
-
- GPIO_FN_BBIF2_TSCK2, GPIO_FN_TPU2TO3,
- GPIO_FN_BBIF2_TXD2,
- GPIO_FN_TPU3TO3,
- GPIO_FN_TPU3TO2,
- GPIO_FN_TPU0TO0,
- GPIO_FN_A0, GPIO_FN_BS_,
- GPIO_FN_A12, GPIO_FN_TPU4TO2,
- GPIO_FN_A13, GPIO_FN_TPU0TO1,
- GPIO_FN_A14,
- GPIO_FN_A15,
- GPIO_FN_A16, GPIO_FN_MSIOF0_SS1,
- GPIO_FN_A17, GPIO_FN_MSIOF0_TSYNC,
- GPIO_FN_A18, GPIO_FN_MSIOF0_TSCK,
- GPIO_FN_A19, GPIO_FN_MSIOF0_TXD,
- GPIO_FN_A20, GPIO_FN_MSIOF0_RSCK,
- GPIO_FN_A21, GPIO_FN_MSIOF0_RSYNC,
- GPIO_FN_A22, GPIO_FN_MSIOF0_MCK0,
- GPIO_FN_A23, GPIO_FN_MSIOF0_MCK1,
- GPIO_FN_A24, GPIO_FN_MSIOF0_RXD,
- GPIO_FN_A25, GPIO_FN_MSIOF0_SS2,
- GPIO_FN_A26,
- GPIO_FN_FCE1_,
- GPIO_FN_DACK0,
- GPIO_FN_FCE0_,
- GPIO_FN_WAIT_, GPIO_FN_DREQ0,
- GPIO_FN_FRB,
- GPIO_FN_CKO,
- GPIO_FN_NBRSTOUT_,
- GPIO_FN_NBRST_,
- GPIO_FN_BBIF2_TXD,
- GPIO_FN_BBIF2_RXD,
- GPIO_FN_BBIF2_SYNC,
- GPIO_FN_BBIF2_SCK,
- GPIO_FN_MFG3_IN2,
- GPIO_FN_MFG3_IN1,
- GPIO_FN_BBIF1_SS2, GPIO_FN_MFG3_OUT1,
- GPIO_FN_HSI_RX_DATA, GPIO_FN_BBIF1_RXD,
- GPIO_FN_HSI_TX_WAKE, GPIO_FN_BBIF1_TSCK,
- GPIO_FN_HSI_TX_DATA, GPIO_FN_BBIF1_TSYNC,
- GPIO_FN_HSI_TX_READY, GPIO_FN_BBIF1_TXD,
- GPIO_FN_HSI_RX_READY, GPIO_FN_BBIF1_RSCK,
- GPIO_FN_HSI_RX_WAKE, GPIO_FN_BBIF1_RSYNC,
- GPIO_FN_HSI_RX_FLAG, GPIO_FN_BBIF1_SS1, GPIO_FN_BBIF1_FLOW,
- GPIO_FN_HSI_TX_FLAG,
- GPIO_FN_VIO_VD, GPIO_FN_VIO2_VD,
-
- GPIO_FN_VIO_HD,
- GPIO_FN_VIO2_HD,
- GPIO_FN_VIO_D0, GPIO_FN_PORT130_MSIOF2_RXD,
- GPIO_FN_VIO_D1, GPIO_FN_PORT131_MSIOF2_SS1,
- GPIO_FN_VIO_D2, GPIO_FN_PORT132_MSIOF2_SS2,
- GPIO_FN_VIO_D3, GPIO_FN_MSIOF2_TSYNC,
- GPIO_FN_VIO_D4, GPIO_FN_MSIOF2_TXD,
- GPIO_FN_VIO_D5, GPIO_FN_MSIOF2_TSCK,
- GPIO_FN_VIO_D6,
- GPIO_FN_VIO_D7,
- GPIO_FN_VIO_D8, GPIO_FN_VIO2_D0,
- GPIO_FN_VIO_D9, GPIO_FN_VIO2_D1,
- GPIO_FN_VIO_D10, GPIO_FN_TPU0TO2, GPIO_FN_VIO2_D2,
- GPIO_FN_VIO_D11, GPIO_FN_TPU0TO3, GPIO_FN_VIO2_D3,
- GPIO_FN_VIO_D12, GPIO_FN_VIO2_D4,
- GPIO_FN_VIO_D13,
- GPIO_FN_VIO2_D5,
- GPIO_FN_VIO_D14, GPIO_FN_VIO2_D6,
- GPIO_FN_VIO_D15, GPIO_FN_TPU1TO3,
- GPIO_FN_VIO2_D7,
- GPIO_FN_VIO_CLK,
- GPIO_FN_VIO2_CLK,
- GPIO_FN_VIO_FIELD, GPIO_FN_VIO2_FIELD,
- GPIO_FN_VIO_CKO,
- GPIO_FN_A27, GPIO_FN_MFG0_IN1,
- GPIO_FN_MFG0_IN2,
- GPIO_FN_TS_SPSYNC3, GPIO_FN_MSIOF2_RSCK,
- GPIO_FN_TS_SDAT3, GPIO_FN_MSIOF2_RSYNC,
- GPIO_FN_TPU1TO2, GPIO_FN_TS_SDEN3, GPIO_FN_PORT153_MSIOF2_SS1,
- GPIO_FN_MSIOF2_MCK0,
- GPIO_FN_MSIOF2_MCK1,
- GPIO_FN_PORT156_MSIOF2_SS2,
- GPIO_FN_PORT157_MSIOF2_RXD,
- GPIO_FN_DINT_, GPIO_FN_TS_SCK3,
- GPIO_FN_NMI,
- GPIO_FN_TPU3TO0,
- GPIO_FN_BBIF2_TSYNC1,
- GPIO_FN_BBIF2_TSCK1,
- GPIO_FN_BBIF2_TXD1,
- GPIO_FN_MFG2_OUT2,
- GPIO_FN_TPU2TO1,
- GPIO_FN_TPU4TO1, GPIO_FN_MFG4_OUT2,
- GPIO_FN_D16,
- GPIO_FN_D17,
- GPIO_FN_D18,
- GPIO_FN_D19,
- GPIO_FN_D20,
- GPIO_FN_D21,
- GPIO_FN_D22,
- GPIO_FN_PORT207_MSIOF0L_SS1, GPIO_FN_D23,
- GPIO_FN_PORT208_MSIOF0L_SS2, GPIO_FN_D24,
- GPIO_FN_D25,
- GPIO_FN_DREQ2, GPIO_FN_PORT210_MSIOF0L_SS1, GPIO_FN_D26,
- GPIO_FN_PORT211_MSIOF0L_SS2, GPIO_FN_D27,
- GPIO_FN_TS_SPSYNC1, GPIO_FN_MSIOF0L_MCK0, GPIO_FN_D28,
- GPIO_FN_TS_SDAT1, GPIO_FN_MSIOF0L_MCK1, GPIO_FN_D29,
- GPIO_FN_TS_SDEN1, GPIO_FN_MSIOF0L_RSCK, GPIO_FN_D30,
- GPIO_FN_TS_SCK1, GPIO_FN_MSIOF0L_RSYNC, GPIO_FN_D31,
- GPIO_FN_DACK2,
- GPIO_FN_MSIOF0L_TSYNC, GPIO_FN_VIO2_FIELD3,
- GPIO_FN_DACK3,
- GPIO_FN_PORT218_VIO_CKOR,
- GPIO_FN_DREQ3, GPIO_FN_MSIOF0L_TSCK, GPIO_FN_VIO2_CLK3, \
- GPIO_FN_DREQ1,
- GPIO_FN_PWEN, GPIO_FN_MSIOF0L_RXD, GPIO_FN_VIO2_HD3, \
- GPIO_FN_DACK1, GPIO_FN_OVCN,
- GPIO_FN_MSIOF0L_TXD, GPIO_FN_VIO2_VD3,
-
- GPIO_FN_OVCN2,
- GPIO_FN_EXTLP, GPIO_FN_PORT226_VIO_CKO2,
- GPIO_FN_IDIN,
- GPIO_FN_MFG1_IN1,
- GPIO_FN_MSIOF1_TXD,
- GPIO_FN_MSIOF1_TSYNC,
- GPIO_FN_MSIOF1_TSCK,
- GPIO_FN_MSIOF1_RXD,
- GPIO_FN_MSIOF1_RSCK, GPIO_FN_VIO2_CLK2,
- GPIO_FN_MSIOF1_RSYNC, GPIO_FN_MFG1_IN2, GPIO_FN_VIO2_VD2, \
- GPIO_FN_MSIOF1_MCK0,
- GPIO_FN_MSIOF1_MCK1,
- GPIO_FN_MSIOF1_SS1, GPIO_FN_VIO2_FIELD2,
- GPIO_FN_MSIOF1_SS2, GPIO_FN_VIO2_HD2,
- GPIO_FN_PORT241_IROUT, GPIO_FN_MFG4_OUT1, \
- GPIO_FN_TPU4TO0,
- GPIO_FN_MFG4_IN2,
- GPIO_FN_PORT243_VIO_CKO2,
- GPIO_FN_MFG2_IN1,
- GPIO_FN_MSIOF2R_RXD,
- GPIO_FN_MFG2_IN2,
- GPIO_FN_MSIOF2R_TXD,
- GPIO_FN_MFG1_OUT1,
- GPIO_FN_TPU1TO0,
- GPIO_FN_MFG3_OUT2,
- GPIO_FN_TPU3TO1,
- GPIO_FN_MFG2_OUT1,
- GPIO_FN_TPU2TO0,
- GPIO_FN_MSIOF2R_TSCK,
- GPIO_FN_PORT249_IROUT, GPIO_FN_MFG4_IN1, \
- GPIO_FN_MSIOF2R_TSYNC,
- GPIO_FN_SDHICLK0,
- GPIO_FN_SDHICD0,
- GPIO_FN_SDHID0_0,
- GPIO_FN_SDHID0_1,
- GPIO_FN_SDHID0_2,
- GPIO_FN_SDHID0_3,
- GPIO_FN_SDHICMD0,
- GPIO_FN_SDHIWP0,
- GPIO_FN_SDHICLK1,
- GPIO_FN_SDHID1_0, GPIO_FN_TS_SPSYNC2,
- GPIO_FN_SDHID1_1, GPIO_FN_TS_SDAT2,
- GPIO_FN_SDHID1_2, GPIO_FN_TS_SDEN2,
- GPIO_FN_SDHID1_3, GPIO_FN_TS_SCK2,
- GPIO_FN_SDHICMD1,
- GPIO_FN_SDHICLK2,
- GPIO_FN_SDHID2_0, GPIO_FN_TS_SPSYNC4,
- GPIO_FN_SDHID2_1, GPIO_FN_TS_SDAT4,
- GPIO_FN_SDHID2_2, GPIO_FN_TS_SDEN4,
- GPIO_FN_SDHID2_3, GPIO_FN_TS_SCK4,
- GPIO_FN_SDHICMD2,
- GPIO_FN_MMCCLK0,
- GPIO_FN_MMCD0_0,
- GPIO_FN_MMCD0_1,
- GPIO_FN_MMCD0_2,
- GPIO_FN_MMCD0_3,
- GPIO_FN_MMCD0_4, GPIO_FN_TS_SPSYNC5,
- GPIO_FN_MMCD0_5, GPIO_FN_TS_SDAT5,
- GPIO_FN_MMCD0_6, GPIO_FN_TS_SDEN5,
- GPIO_FN_MMCD0_7, GPIO_FN_TS_SCK5,
- GPIO_FN_MMCCMD0,
- GPIO_FN_RESETOUTS_, GPIO_FN_EXTAL2OUT,
- GPIO_FN_MCP_WAIT__MCP_FRB,
- GPIO_FN_MCP_CKO, GPIO_FN_MMCCLK1,
- GPIO_FN_MCP_D15_MCP_NAF15,
- GPIO_FN_MCP_D14_MCP_NAF14,
- GPIO_FN_MCP_D13_MCP_NAF13,
- GPIO_FN_MCP_D12_MCP_NAF12,
- GPIO_FN_MCP_D11_MCP_NAF11,
- GPIO_FN_MCP_D10_MCP_NAF10,
- GPIO_FN_MCP_D9_MCP_NAF9,
- GPIO_FN_MCP_D8_MCP_NAF8, GPIO_FN_MMCCMD1,
- GPIO_FN_MCP_D7_MCP_NAF7, GPIO_FN_MMCD1_7,
-
- GPIO_FN_MCP_D6_MCP_NAF6, GPIO_FN_MMCD1_6,
- GPIO_FN_MCP_D5_MCP_NAF5, GPIO_FN_MMCD1_5,
- GPIO_FN_MCP_D4_MCP_NAF4, GPIO_FN_MMCD1_4,
- GPIO_FN_MCP_D3_MCP_NAF3, GPIO_FN_MMCD1_3,
- GPIO_FN_MCP_D2_MCP_NAF2, GPIO_FN_MMCD1_2,
- GPIO_FN_MCP_D1_MCP_NAF1, GPIO_FN_MMCD1_1,
- GPIO_FN_MCP_D0_MCP_NAF0, GPIO_FN_MMCD1_0,
- GPIO_FN_MCP_NBRSTOUT_,
- GPIO_FN_MCP_WE0__MCP_FWE, GPIO_FN_MCP_RDWR_MCP_FWE,
-
- /* MSEL2 special case */
- GPIO_FN_TSIF2_TS_XX1,
- GPIO_FN_TSIF2_TS_XX2,
- GPIO_FN_TSIF2_TS_XX3,
- GPIO_FN_TSIF2_TS_XX4,
- GPIO_FN_TSIF2_TS_XX5,
- GPIO_FN_TSIF1_TS_XX1,
- GPIO_FN_TSIF1_TS_XX2,
- GPIO_FN_TSIF1_TS_XX3,
- GPIO_FN_TSIF1_TS_XX4,
- GPIO_FN_TSIF1_TS_XX5,
- GPIO_FN_TSIF0_TS_XX1,
- GPIO_FN_TSIF0_TS_XX2,
- GPIO_FN_TSIF0_TS_XX3,
- GPIO_FN_TSIF0_TS_XX4,
- GPIO_FN_TSIF0_TS_XX5,
- GPIO_FN_MST1_TS_XX1,
- GPIO_FN_MST1_TS_XX2,
- GPIO_FN_MST1_TS_XX3,
- GPIO_FN_MST1_TS_XX4,
- GPIO_FN_MST1_TS_XX5,
- GPIO_FN_MST0_TS_XX1,
- GPIO_FN_MST0_TS_XX2,
- GPIO_FN_MST0_TS_XX3,
- GPIO_FN_MST0_TS_XX4,
- GPIO_FN_MST0_TS_XX5,
-
- /* MSEL3 special cases */
- GPIO_FN_SDHI0_VCCQ_MC0_ON,
- GPIO_FN_SDHI0_VCCQ_MC0_OFF,
- GPIO_FN_DEBUG_MON_VIO,
- GPIO_FN_DEBUG_MON_LCDD,
- GPIO_FN_LCDC_LCDC0,
- GPIO_FN_LCDC_LCDC1,
-
- /* MSEL4 special cases */
- GPIO_FN_IRQ9_MEM_INT,
- GPIO_FN_IRQ9_MCP_INT,
- GPIO_FN_A11,
- GPIO_FN_TPU4TO3,
- GPIO_FN_RESETA_N_PU_ON,
- GPIO_FN_RESETA_N_PU_OFF,
- GPIO_FN_EDBGREQ_PD,
- GPIO_FN_EDBGREQ_PU,
-
- /* end of GPIO */
- GPIO_NR,
-};
+#define GPIO_NR 310

/* DMA slave IDs */
enum {
--
1.8.1.5

2013-04-24 20:51:54

by Laurent Pinchart

[permalink] [raw]
Subject: [PATCH v2 09/11] sh-pfc: sh73a0: Remove function GPIOs

No sh73a0 platform use the function GPIOs API. Remove it.

Signed-off-by: Laurent Pinchart <[email protected]>
---
drivers/pinctrl/sh-pfc/pfc-sh73a0.c | 395 ------------------------------------
1 file changed, 395 deletions(-)

diff --git a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
index e4e0c92..88e5b10 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
@@ -26,7 +26,6 @@
#include <linux/regulator/machine.h>
#include <linux/slab.h>

-#include <mach/sh73a0.h>
#include <mach/irqs.h>

#include "core.h"
@@ -3153,397 +3152,6 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(usb),
};

-#define PINMUX_FN_BASE GPIO_FN_GPI0
-
-static const struct pinmux_func pinmux_func_gpios[] = {
- /* Table 25-1 (Functions 0-7) */
- GPIO_FN(GPI0),
- GPIO_FN(GPI1),
- GPIO_FN(GPI2),
- GPIO_FN(GPI3),
- GPIO_FN(GPI4),
- GPIO_FN(GPI5),
- GPIO_FN(GPI6),
- GPIO_FN(GPI7),
- GPIO_FN(GPO7), \
- GPIO_FN(MFG0_OUT2),
- GPIO_FN(GPO6), \
- GPIO_FN(MFG1_OUT2),
- GPIO_FN(GPO5), \
- GPIO_FN(PORT16_VIO_CKOR),
- GPIO_FN(PORT19_VIO_CKO2),
- GPIO_FN(GPO0),
- GPIO_FN(GPO1),
- GPIO_FN(GPO2), \
- GPIO_FN(STATUS0),
- GPIO_FN(GPO3), \
- GPIO_FN(STATUS1),
- GPIO_FN(GPO4), \
- GPIO_FN(STATUS2),
- GPIO_FN(VINT),
- GPIO_FN(TCKON),
- GPIO_FN(XDVFS1), \
- GPIO_FN(MFG0_OUT1), \
- GPIO_FN(PORT27_IROUT),
- GPIO_FN(XDVFS2), \
- GPIO_FN(PORT28_TPU1TO1),
- GPIO_FN(SIM_RST), \
- GPIO_FN(PORT29_TPU1TO1),
- GPIO_FN(SIM_CLK), \
- GPIO_FN(PORT30_VIO_CKOR),
- GPIO_FN(SIM_D), \
- GPIO_FN(PORT31_IROUT),
- GPIO_FN(XWUP),
- GPIO_FN(VACK),
- GPIO_FN(XTAL1L),
- GPIO_FN(PORT49_IROUT), \
- GPIO_FN(BBIF2_TSYNC2), \
- GPIO_FN(TPU2TO2), \
-
- GPIO_FN(BBIF2_TSCK2), \
- GPIO_FN(TPU2TO3), \
- GPIO_FN(BBIF2_TXD2),
- GPIO_FN(TPU3TO3), \
- GPIO_FN(TPU3TO2), \
- GPIO_FN(TPU0TO0),
- GPIO_FN(A0), \
- GPIO_FN(BS_),
- GPIO_FN(A12), \
- GPIO_FN(TPU4TO2),
- GPIO_FN(A13), \
- GPIO_FN(TPU0TO1),
- GPIO_FN(A14), \
- GPIO_FN(A15), \
- GPIO_FN(A16), \
- GPIO_FN(MSIOF0_SS1),
- GPIO_FN(A17), \
- GPIO_FN(MSIOF0_TSYNC),
- GPIO_FN(A18), \
- GPIO_FN(MSIOF0_TSCK),
- GPIO_FN(A19), \
- GPIO_FN(MSIOF0_TXD),
- GPIO_FN(A20), \
- GPIO_FN(MSIOF0_RSCK),
- GPIO_FN(A21), \
- GPIO_FN(MSIOF0_RSYNC),
- GPIO_FN(A22), \
- GPIO_FN(MSIOF0_MCK0),
- GPIO_FN(A23), \
- GPIO_FN(MSIOF0_MCK1),
- GPIO_FN(A24), \
- GPIO_FN(MSIOF0_RXD),
- GPIO_FN(A25), \
- GPIO_FN(MSIOF0_SS2),
- GPIO_FN(A26), \
- GPIO_FN(FCE1_),
- GPIO_FN(DACK0),
- GPIO_FN(FCE0_), \
- GPIO_FN(WAIT_), \
- GPIO_FN(DREQ0),
- GPIO_FN(FRB),
- GPIO_FN(CKO),
- GPIO_FN(NBRSTOUT_),
- GPIO_FN(NBRST_),
- GPIO_FN(BBIF2_TXD),
- GPIO_FN(BBIF2_RXD),
- GPIO_FN(BBIF2_SYNC),
- GPIO_FN(BBIF2_SCK),
- GPIO_FN(MFG3_IN2),
- GPIO_FN(MFG3_IN1),
- GPIO_FN(BBIF1_SS2), \
- GPIO_FN(MFG3_OUT1),
- GPIO_FN(HSI_RX_DATA), \
- GPIO_FN(BBIF1_RXD),
- GPIO_FN(HSI_TX_WAKE), \
- GPIO_FN(BBIF1_TSCK),
- GPIO_FN(HSI_TX_DATA), \
- GPIO_FN(BBIF1_TSYNC),
- GPIO_FN(HSI_TX_READY), \
- GPIO_FN(BBIF1_TXD),
- GPIO_FN(HSI_RX_READY), \
- GPIO_FN(BBIF1_RSCK), \
- GPIO_FN(HSI_RX_WAKE), \
- GPIO_FN(BBIF1_RSYNC), \
- GPIO_FN(HSI_RX_FLAG), \
- GPIO_FN(BBIF1_SS1), \
- GPIO_FN(BBIF1_FLOW),
- GPIO_FN(HSI_TX_FLAG),
- GPIO_FN(VIO_VD), \
- GPIO_FN(VIO2_VD), \
-
- GPIO_FN(VIO_HD), \
- GPIO_FN(VIO2_HD), \
- GPIO_FN(VIO_D0), \
- GPIO_FN(PORT130_MSIOF2_RXD), \
- GPIO_FN(VIO_D1), \
- GPIO_FN(PORT131_MSIOF2_SS1), \
- GPIO_FN(VIO_D2), \
- GPIO_FN(PORT132_MSIOF2_SS2), \
- GPIO_FN(VIO_D3), \
- GPIO_FN(MSIOF2_TSYNC), \
- GPIO_FN(VIO_D4), \
- GPIO_FN(MSIOF2_TXD), \
- GPIO_FN(VIO_D5), \
- GPIO_FN(MSIOF2_TSCK), \
- GPIO_FN(VIO_D6), \
- GPIO_FN(VIO_D7), \
- GPIO_FN(VIO_D8), \
- GPIO_FN(VIO2_D0), \
- GPIO_FN(VIO_D9), \
- GPIO_FN(VIO2_D1), \
- GPIO_FN(VIO_D10), \
- GPIO_FN(TPU0TO2), \
- GPIO_FN(VIO2_D2), \
- GPIO_FN(VIO_D11), \
- GPIO_FN(TPU0TO3), \
- GPIO_FN(VIO2_D3), \
- GPIO_FN(VIO_D12), \
- GPIO_FN(VIO2_D4), \
- GPIO_FN(VIO_D13), \
- GPIO_FN(VIO2_D5), \
- GPIO_FN(VIO_D14), \
- GPIO_FN(VIO2_D6), \
- GPIO_FN(VIO_D15), \
- GPIO_FN(TPU1TO3), \
- GPIO_FN(VIO2_D7), \
- GPIO_FN(VIO_CLK), \
- GPIO_FN(VIO2_CLK), \
- GPIO_FN(VIO_FIELD), \
- GPIO_FN(VIO2_FIELD), \
- GPIO_FN(VIO_CKO),
- GPIO_FN(A27), \
- GPIO_FN(MFG0_IN1), \
- GPIO_FN(MFG0_IN2),
- GPIO_FN(TS_SPSYNC3), \
- GPIO_FN(MSIOF2_RSCK),
- GPIO_FN(TS_SDAT3), \
- GPIO_FN(MSIOF2_RSYNC),
- GPIO_FN(TPU1TO2), \
- GPIO_FN(TS_SDEN3), \
- GPIO_FN(PORT153_MSIOF2_SS1),
- GPIO_FN(MSIOF2_MCK0),
- GPIO_FN(MSIOF2_MCK1),
- GPIO_FN(PORT156_MSIOF2_SS2),
- GPIO_FN(PORT157_MSIOF2_RXD),
- GPIO_FN(DINT_), \
- GPIO_FN(TS_SCK3),
- GPIO_FN(NMI),
- GPIO_FN(TPU3TO0),
- GPIO_FN(BBIF2_TSYNC1),
- GPIO_FN(BBIF2_TSCK1),
- GPIO_FN(BBIF2_TXD1),
- GPIO_FN(MFG2_OUT2), \
- GPIO_FN(TPU2TO1),
- GPIO_FN(TPU4TO1), \
- GPIO_FN(MFG4_OUT2),
- GPIO_FN(D16),
- GPIO_FN(D17),
- GPIO_FN(D18),
- GPIO_FN(D19),
- GPIO_FN(D20),
- GPIO_FN(D21),
- GPIO_FN(D22),
- GPIO_FN(PORT207_MSIOF0L_SS1), \
- GPIO_FN(D23),
- GPIO_FN(PORT208_MSIOF0L_SS2), \
- GPIO_FN(D24),
- GPIO_FN(D25),
- GPIO_FN(DREQ2), \
- GPIO_FN(PORT210_MSIOF0L_SS1), \
- GPIO_FN(D26),
- GPIO_FN(PORT211_MSIOF0L_SS2), \
- GPIO_FN(D27),
- GPIO_FN(TS_SPSYNC1), \
- GPIO_FN(MSIOF0L_MCK0), \
- GPIO_FN(D28),
- GPIO_FN(TS_SDAT1), \
- GPIO_FN(MSIOF0L_MCK1), \
- GPIO_FN(D29),
- GPIO_FN(TS_SDEN1), \
- GPIO_FN(MSIOF0L_RSCK), \
- GPIO_FN(D30),
- GPIO_FN(TS_SCK1), \
- GPIO_FN(MSIOF0L_RSYNC), \
- GPIO_FN(D31),
- GPIO_FN(DACK2), \
- GPIO_FN(MSIOF0L_TSYNC), \
- GPIO_FN(VIO2_FIELD3), \
- GPIO_FN(DACK3), \
- GPIO_FN(PORT218_VIO_CKOR),
- GPIO_FN(DREQ3), \
- GPIO_FN(MSIOF0L_TSCK), \
- GPIO_FN(VIO2_CLK3), \
- GPIO_FN(DREQ1), \
- GPIO_FN(PWEN), \
- GPIO_FN(MSIOF0L_RXD), \
- GPIO_FN(VIO2_HD3), \
- GPIO_FN(DACK1), \
- GPIO_FN(OVCN), \
- GPIO_FN(MSIOF0L_TXD), \
- GPIO_FN(VIO2_VD3), \
-
- GPIO_FN(OVCN2),
- GPIO_FN(EXTLP), \
- GPIO_FN(PORT226_VIO_CKO2),
- GPIO_FN(IDIN),
- GPIO_FN(MFG1_IN1),
- GPIO_FN(MSIOF1_TXD), \
- GPIO_FN(MSIOF1_TSYNC), \
- GPIO_FN(MSIOF1_TSCK), \
- GPIO_FN(MSIOF1_RXD), \
- GPIO_FN(MSIOF1_RSCK), \
- GPIO_FN(VIO2_CLK2), \
- GPIO_FN(MSIOF1_RSYNC), \
- GPIO_FN(MFG1_IN2), \
- GPIO_FN(VIO2_VD2), \
- GPIO_FN(MSIOF1_MCK0), \
- GPIO_FN(MSIOF1_MCK1), \
- GPIO_FN(MSIOF1_SS1), \
- GPIO_FN(VIO2_FIELD2), \
- GPIO_FN(MSIOF1_SS2), \
- GPIO_FN(VIO2_HD2), \
- GPIO_FN(PORT241_IROUT), \
- GPIO_FN(MFG4_OUT1), \
- GPIO_FN(TPU4TO0),
- GPIO_FN(MFG4_IN2),
- GPIO_FN(PORT243_VIO_CKO2),
- GPIO_FN(MFG2_IN1), \
- GPIO_FN(MSIOF2R_RXD),
- GPIO_FN(MFG2_IN2), \
- GPIO_FN(MSIOF2R_TXD),
- GPIO_FN(MFG1_OUT1), \
- GPIO_FN(TPU1TO0),
- GPIO_FN(MFG3_OUT2), \
- GPIO_FN(TPU3TO1),
- GPIO_FN(MFG2_OUT1), \
- GPIO_FN(TPU2TO0), \
- GPIO_FN(MSIOF2R_TSCK),
- GPIO_FN(PORT249_IROUT), \
- GPIO_FN(MFG4_IN1), \
- GPIO_FN(MSIOF2R_TSYNC),
- GPIO_FN(SDHICLK0),
- GPIO_FN(SDHICD0),
- GPIO_FN(SDHID0_0),
- GPIO_FN(SDHID0_1),
- GPIO_FN(SDHID0_2),
- GPIO_FN(SDHID0_3),
- GPIO_FN(SDHICMD0),
- GPIO_FN(SDHIWP0),
- GPIO_FN(SDHICLK1),
- GPIO_FN(SDHID1_0), \
- GPIO_FN(TS_SPSYNC2),
- GPIO_FN(SDHID1_1), \
- GPIO_FN(TS_SDAT2),
- GPIO_FN(SDHID1_2), \
- GPIO_FN(TS_SDEN2),
- GPIO_FN(SDHID1_3), \
- GPIO_FN(TS_SCK2),
- GPIO_FN(SDHICMD1),
- GPIO_FN(SDHICLK2),
- GPIO_FN(SDHID2_0), \
- GPIO_FN(TS_SPSYNC4),
- GPIO_FN(SDHID2_1), \
- GPIO_FN(TS_SDAT4),
- GPIO_FN(SDHID2_2), \
- GPIO_FN(TS_SDEN4),
- GPIO_FN(SDHID2_3), \
- GPIO_FN(TS_SCK4),
- GPIO_FN(SDHICMD2),
- GPIO_FN(MMCCLK0),
- GPIO_FN(MMCD0_0),
- GPIO_FN(MMCD0_1),
- GPIO_FN(MMCD0_2),
- GPIO_FN(MMCD0_3),
- GPIO_FN(MMCD0_4), \
- GPIO_FN(TS_SPSYNC5),
- GPIO_FN(MMCD0_5), \
- GPIO_FN(TS_SDAT5),
- GPIO_FN(MMCD0_6), \
- GPIO_FN(TS_SDEN5),
- GPIO_FN(MMCD0_7), \
- GPIO_FN(TS_SCK5),
- GPIO_FN(MMCCMD0),
- GPIO_FN(RESETOUTS_), \
- GPIO_FN(EXTAL2OUT),
- GPIO_FN(MCP_WAIT__MCP_FRB),
- GPIO_FN(MCP_CKO), \
- GPIO_FN(MMCCLK1),
- GPIO_FN(MCP_D15_MCP_NAF15),
- GPIO_FN(MCP_D14_MCP_NAF14),
- GPIO_FN(MCP_D13_MCP_NAF13),
- GPIO_FN(MCP_D12_MCP_NAF12),
- GPIO_FN(MCP_D11_MCP_NAF11),
- GPIO_FN(MCP_D10_MCP_NAF10),
- GPIO_FN(MCP_D9_MCP_NAF9),
- GPIO_FN(MCP_D8_MCP_NAF8), \
- GPIO_FN(MMCCMD1),
- GPIO_FN(MCP_D7_MCP_NAF7), \
- GPIO_FN(MMCD1_7),
-
- GPIO_FN(MCP_D6_MCP_NAF6), \
- GPIO_FN(MMCD1_6),
- GPIO_FN(MCP_D5_MCP_NAF5), \
- GPIO_FN(MMCD1_5),
- GPIO_FN(MCP_D4_MCP_NAF4), \
- GPIO_FN(MMCD1_4),
- GPIO_FN(MCP_D3_MCP_NAF3), \
- GPIO_FN(MMCD1_3),
- GPIO_FN(MCP_D2_MCP_NAF2), \
- GPIO_FN(MMCD1_2),
- GPIO_FN(MCP_D1_MCP_NAF1), \
- GPIO_FN(MMCD1_1),
- GPIO_FN(MCP_D0_MCP_NAF0), \
- GPIO_FN(MMCD1_0),
- GPIO_FN(MCP_NBRSTOUT_),
- GPIO_FN(MCP_WE0__MCP_FWE), \
- GPIO_FN(MCP_RDWR_MCP_FWE),
-
- /* MSEL2 special cases */
- GPIO_FN(TSIF2_TS_XX1),
- GPIO_FN(TSIF2_TS_XX2),
- GPIO_FN(TSIF2_TS_XX3),
- GPIO_FN(TSIF2_TS_XX4),
- GPIO_FN(TSIF2_TS_XX5),
- GPIO_FN(TSIF1_TS_XX1),
- GPIO_FN(TSIF1_TS_XX2),
- GPIO_FN(TSIF1_TS_XX3),
- GPIO_FN(TSIF1_TS_XX4),
- GPIO_FN(TSIF1_TS_XX5),
- GPIO_FN(TSIF0_TS_XX1),
- GPIO_FN(TSIF0_TS_XX2),
- GPIO_FN(TSIF0_TS_XX3),
- GPIO_FN(TSIF0_TS_XX4),
- GPIO_FN(TSIF0_TS_XX5),
- GPIO_FN(MST1_TS_XX1),
- GPIO_FN(MST1_TS_XX2),
- GPIO_FN(MST1_TS_XX3),
- GPIO_FN(MST1_TS_XX4),
- GPIO_FN(MST1_TS_XX5),
- GPIO_FN(MST0_TS_XX1),
- GPIO_FN(MST0_TS_XX2),
- GPIO_FN(MST0_TS_XX3),
- GPIO_FN(MST0_TS_XX4),
- GPIO_FN(MST0_TS_XX5),
-
- /* MSEL3 special cases */
- GPIO_FN(SDHI0_VCCQ_MC0_ON),
- GPIO_FN(SDHI0_VCCQ_MC0_OFF),
- GPIO_FN(DEBUG_MON_VIO),
- GPIO_FN(DEBUG_MON_LCDD),
- GPIO_FN(LCDC_LCDC0),
- GPIO_FN(LCDC_LCDC1),
-
- /* MSEL4 special cases */
- GPIO_FN(IRQ9_MEM_INT),
- GPIO_FN(IRQ9_MCP_INT),
- GPIO_FN(A11),
- GPIO_FN(TPU4TO3),
- GPIO_FN(RESETA_N_PU_ON),
- GPIO_FN(RESETA_N_PU_OFF),
- GPIO_FN(EDBGREQ_PD),
- GPIO_FN(EDBGREQ_PU),
-};
-
#undef PORTCR
#define PORTCR(nr, reg) \
{ \
@@ -4303,9 +3911,6 @@ const struct sh_pfc_soc_info sh73a0_pinmux_info = {
.functions = pinmux_functions,
.nr_functions = ARRAY_SIZE(pinmux_functions),

- .func_gpios = pinmux_func_gpios,
- .nr_func_gpios = ARRAY_SIZE(pinmux_func_gpios),
-
.cfg_regs = pinmux_config_regs,
.data_regs = pinmux_data_regs,

--
1.8.1.5

2013-04-24 20:52:17

by Laurent Pinchart

[permalink] [raw]
Subject: [PATCH v2 08/11] ARM: mach-shmobile: kota2: Use leds-pwm + pwm-rmob

Instead of using the LED-specific TPU PWM driver, switch to the generic
TPU PWM driver with leds-pwm.

Signed-off-by: Laurent Pinchart <[email protected]>
---
arch/arm/mach-shmobile/board-kota2.c | 178 ++++++++++++++++++++--------------
arch/arm/mach-shmobile/clock-sh73a0.c | 8 +-
2 files changed, 109 insertions(+), 77 deletions(-)

diff --git a/arch/arm/mach-shmobile/board-kota2.c b/arch/arm/mach-shmobile/board-kota2.c
index ef5ca0e..97a1f7d 100644
--- a/arch/arm/mach-shmobile/board-kota2.c
+++ b/arch/arm/mach-shmobile/board-kota2.c
@@ -26,6 +26,7 @@
#include <linux/irq.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/platform_data/pwm-renesas-tpu.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/io.h>
@@ -37,8 +38,8 @@
#include <linux/input/sh_keysc.h>
#include <linux/gpio_keys.h>
#include <linux/leds.h>
+#include <linux/leds_pwm.h>
#include <linux/irqchip/arm-gic.h>
-#include <linux/platform_data/leds-renesas-tpu.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sh_mmcif.h>
#include <linux/mfd/tmio.h>
@@ -186,116 +187,137 @@ static struct platform_device gpio_leds_device = {
};

/* TPU LED */
-static struct led_renesas_tpu_config led_renesas_tpu12_pdata = {
- .name = "V2513",
- .pin_gpio_fn = GPIO_FN_TPU1TO2,
- .pin_gpio = 153,
- .channel_offset = 0x90,
- .timer_bit = 2,
- .max_brightness = 1000,
+static struct tpu_pwm_platform_data tpu1_pwm_pdata = {
+ .channels[2] = {
+ .enabled = true,
+ .active_low = false,
+ },
};

-static struct resource tpu12_resources[] = {
+static struct resource tpu1_pwm_resources[] = {
[0] = {
- .name = "TPU12",
- .start = 0xe6610090,
- .end = 0xe66100b5,
+ .start = 0xe6610000,
+ .end = 0xe66100ff,
.flags = IORESOURCE_MEM,
},
};

-static struct platform_device leds_tpu12_device = {
- .name = "leds-renesas-tpu",
- .id = 12,
+static struct platform_device tpu1_pwm_device = {
+ .name = "renesas_tpu_pwm",
+ .id = 1,
.dev = {
- .platform_data = &led_renesas_tpu12_pdata,
+ .platform_data = &tpu1_pwm_pdata,
},
- .num_resources = ARRAY_SIZE(tpu12_resources),
- .resource = tpu12_resources,
+ .num_resources = ARRAY_SIZE(tpu1_pwm_resources),
+ .resource = tpu1_pwm_resources,
};

-static struct led_renesas_tpu_config led_renesas_tpu41_pdata = {
- .name = "V2514",
- .pin_gpio_fn = GPIO_FN_TPU4TO1,
- .pin_gpio = 199,
- .channel_offset = 0x50,
- .timer_bit = 1,
- .max_brightness = 1000,
+static struct tpu_pwm_platform_data tpu2_pwm_pdata = {
+ .channels[1] = {
+ .enabled = true,
+ .active_low = false,
+ },
};

-static struct resource tpu41_resources[] = {
+static struct resource tpu2_pwm_resources[] = {
[0] = {
- .name = "TPU41",
- .start = 0xe6640050,
- .end = 0xe6640075,
+ .start = 0xe6620000,
+ .end = 0xe66200ff,
.flags = IORESOURCE_MEM,
},
};

-static struct platform_device leds_tpu41_device = {
- .name = "leds-renesas-tpu",
- .id = 41,
+static struct platform_device tpu2_pwm_device = {
+ .name = "renesas_tpu_pwm",
+ .id = 2,
.dev = {
- .platform_data = &led_renesas_tpu41_pdata,
+ .platform_data = &tpu2_pwm_pdata,
},
- .num_resources = ARRAY_SIZE(tpu41_resources),
- .resource = tpu41_resources,
+ .num_resources = ARRAY_SIZE(tpu2_pwm_resources),
+ .resource = tpu2_pwm_resources,
};

-static struct led_renesas_tpu_config led_renesas_tpu21_pdata = {
- .name = "V2515",
- .pin_gpio_fn = GPIO_FN_TPU2TO1,
- .pin_gpio = 197,
- .channel_offset = 0x50,
- .timer_bit = 1,
- .max_brightness = 1000,
+static struct tpu_pwm_platform_data tpu3_pwm_pdata = {
+ .channels[0] = {
+ .enabled = true,
+ .active_low = false,
+ },
};

-static struct resource tpu21_resources[] = {
+static struct resource tpu3_pwm_resources[] = {
[0] = {
- .name = "TPU21",
- .start = 0xe6620050,
- .end = 0xe6620075,
+ .start = 0xe6630000,
+ .end = 0xe66300ff,
.flags = IORESOURCE_MEM,
},
};

-static struct platform_device leds_tpu21_device = {
- .name = "leds-renesas-tpu",
- .id = 21,
+static struct platform_device tpu3_pwm_device = {
+ .name = "renesas_tpu_pwm",
+ .id = 3,
.dev = {
- .platform_data = &led_renesas_tpu21_pdata,
+ .platform_data = &tpu3_pwm_pdata,
},
- .num_resources = ARRAY_SIZE(tpu21_resources),
- .resource = tpu21_resources,
+ .num_resources = ARRAY_SIZE(tpu3_pwm_resources),
+ .resource = tpu3_pwm_resources,
};

-static struct led_renesas_tpu_config led_renesas_tpu30_pdata = {
- .name = "KEYLED",
- .pin_gpio_fn = GPIO_FN_TPU3TO0,
- .pin_gpio = 163,
- .channel_offset = 0x10,
- .timer_bit = 0,
- .max_brightness = 1000,
+static struct tpu_pwm_platform_data tpu4_pwm_pdata = {
+ .channels[1] = {
+ .enabled = true,
+ .active_low = false,
+ },
};

-static struct resource tpu30_resources[] = {
+static struct resource tpu4_pwm_resources[] = {
[0] = {
- .name = "TPU30",
- .start = 0xe6630010,
- .end = 0xe6630035,
+ .start = 0xe6640000,
+ .end = 0xe66400ff,
.flags = IORESOURCE_MEM,
},
};

-static struct platform_device leds_tpu30_device = {
- .name = "leds-renesas-tpu",
- .id = 30,
+static struct platform_device tpu4_pwm_device = {
+ .name = "renesas_tpu_pwm",
+ .id = 4,
+ .dev = {
+ .platform_data = &tpu4_pwm_pdata,
+ },
+ .num_resources = ARRAY_SIZE(tpu4_pwm_resources),
+ .resource = tpu4_pwm_resources,
+};
+
+static struct led_pwm tpu_pwm_leds[] = {
+ {
+ .name = "V2513",
+ .pwm_id = TPU_PWM_ID(1, 2),
+ .max_brightness = 1000,
+ }, {
+ .name = "V2515",
+ .pwm_id = TPU_PWM_ID(2, 1),
+ .max_brightness = 1000,
+ }, {
+ .name = "KEYLED",
+ .pwm_id = TPU_PWM_ID(3, 0),
+ .max_brightness = 1000,
+ }, {
+ .name = "V2514",
+ .pwm_id = TPU_PWM_ID(4, 1),
+ .max_brightness = 1000,
+ },
+};
+
+static struct led_pwm_platform_data leds_pwm_pdata = {
+ .num_leds = ARRAY_SIZE(tpu_pwm_leds),
+ .leds = tpu_pwm_leds,
+};
+
+static struct platform_device leds_pwm_device = {
+ .name = "leds-pwm",
+ .id = 0,
.dev = {
- .platform_data = &led_renesas_tpu30_pdata,
+ .platform_data = &leds_pwm_pdata,
},
- .num_resources = ARRAY_SIZE(tpu30_resources),
- .resource = tpu30_resources,
};

/* Fixed 1.8V regulator to be used by MMCIF */
@@ -426,10 +448,11 @@ static struct platform_device *kota2_devices[] __initdata = {
&keysc_device,
&gpio_keys_device,
&gpio_leds_device,
- &leds_tpu12_device,
- &leds_tpu41_device,
- &leds_tpu21_device,
- &leds_tpu30_device,
+ &tpu1_pwm_device,
+ &tpu2_pwm_device,
+ &tpu3_pwm_device,
+ &tpu4_pwm_device,
+ &leds_pwm_device,
&mmcif_device,
&sdhi0_device,
&sdhi1_device,
@@ -512,6 +535,15 @@ static const struct pinctrl_map kota2_pinctrl_map[] = {
"bsc_cs5_a", "bsc"),
PIN_MAP_MUX_GROUP_DEFAULT("smsc911x.0", "pfc-sh73a0",
"bsc_we0", "bsc"),
+ /* TPU */
+ PIN_MAP_MUX_GROUP_DEFAULT("renesas_tpu_pwm.1", "pfc-sh73a0",
+ "tpu1_to2", "tpu1"),
+ PIN_MAP_MUX_GROUP_DEFAULT("renesas_tpu_pwm.2", "pfc-sh73a0",
+ "tpu2_to1", "tpu2"),
+ PIN_MAP_MUX_GROUP_DEFAULT("renesas_tpu_pwm.3", "pfc-sh73a0",
+ "tpu3_to0", "tpu3"),
+ PIN_MAP_MUX_GROUP_DEFAULT("renesas_tpu_pwm.4", "pfc-sh73a0",
+ "tpu4_to1", "tpu4"),
};

static void __init kota2_init(void)
diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c
index f222837..c454dc7 100644
--- a/arch/arm/mach-shmobile/clock-sh73a0.c
+++ b/arch/arm/mach-shmobile/clock-sh73a0.c
@@ -656,10 +656,10 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("e6bd0000.mmcif", &mstp_clks[MSTP312]), /* MMCIF0 */
CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP311]), /* SDHI2 */
CLKDEV_DEV_ID("ee140000.sdhi", &mstp_clks[MSTP311]), /* SDHI2 */
- CLKDEV_DEV_ID("leds-renesas-tpu.12", &mstp_clks[MSTP303]), /* TPU1 */
- CLKDEV_DEV_ID("leds-renesas-tpu.21", &mstp_clks[MSTP302]), /* TPU2 */
- CLKDEV_DEV_ID("leds-renesas-tpu.30", &mstp_clks[MSTP301]), /* TPU3 */
- CLKDEV_DEV_ID("leds-renesas-tpu.41", &mstp_clks[MSTP300]), /* TPU4 */
+ CLKDEV_DEV_ID("rmob_tpu_pwm.1", &mstp_clks[MSTP303]), /* TPU1 */
+ CLKDEV_DEV_ID("rmob_tpu_pwm.2", &mstp_clks[MSTP302]), /* TPU2 */
+ CLKDEV_DEV_ID("rmob_tpu_pwm.3", &mstp_clks[MSTP301]), /* TPU3 */
+ CLKDEV_DEV_ID("rmob_tpu_pwm.4", &mstp_clks[MSTP300]), /* TPU4 */
CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* I2C3 */
CLKDEV_DEV_ID("e6826000.i2c", &mstp_clks[MSTP411]), /* I2C3 */
CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* I2C4 */
--
1.8.1.5

2013-04-24 20:52:36

by Laurent Pinchart

[permalink] [raw]
Subject: [PATCH v2 07/11] ARM: mach-shmobile: armadillo800eva: Add backlight support

The flat panel backlight on the Armadillo 800 EVA board is driven by the
TPU PWM output.

Signed-off-by: Laurent Pinchart <[email protected]>
Tested-by: Simon Horman <[email protected]>
---
arch/arm/mach-shmobile/board-armadillo800eva.c | 51 +++++++++++++++++++++++++-
1 file changed, 49 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c
index ff04d1e..fca1817 100644
--- a/arch/arm/mach-shmobile/board-armadillo800eva.c
+++ b/arch/arm/mach-shmobile/board-armadillo800eva.c
@@ -30,6 +30,8 @@
#include <linux/gpio_keys.h>
#include <linux/regulator/driver.h>
#include <linux/pinctrl/machine.h>
+#include <linux/platform_data/pwm-renesas-tpu.h>
+#include <linux/pwm_backlight.h>
#include <linux/regulator/fixed.h>
#include <linux/regulator/gpio-regulator.h>
#include <linux/regulator/machine.h>
@@ -381,7 +383,48 @@ static struct platform_device sh_eth_device = {
.num_resources = ARRAY_SIZE(sh_eth_resources),
};

-/* LCDC */
+/* PWM */
+static struct resource pwm_resources[] = {
+ [0] = {
+ .start = 0xe6600000,
+ .end = 0xe66000ff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct tpu_pwm_platform_data pwm_device_data = {
+ .channels[2] = {
+ .enabled = true,
+ .active_low = 1,
+ }
+};
+
+static struct platform_device pwm_device = {
+ .name = "renesas_tpu_pwm",
+ .id = -1,
+ .dev = {
+ .platform_data = &pwm_device_data,
+ },
+ .num_resources = ARRAY_SIZE(pwm_resources),
+ .resource = pwm_resources,
+};
+
+/* LCDC and backlight */
+static struct platform_pwm_backlight_data pwm_backlight_data = {
+ .pwm_id = TPU_PWM_ID(0, 2),
+ .lth_brightness = 50,
+ .max_brightness = 255,
+ .dft_brightness = 255,
+ .pwm_period_ns = 33333, /* 30kHz */
+};
+
+static struct platform_device pwm_backlight_device = {
+ .name = "pwm-backlight",
+ .dev = {
+ .platform_data = &pwm_backlight_data,
+ },
+};
+
static struct fb_videomode lcdc0_mode = {
.name = "AMPIER/AM-800480",
.xres = 800,
@@ -1019,6 +1062,8 @@ static struct i2c_board_info i2c2_devices[] = {
*/
static struct platform_device *eva_devices[] __initdata = {
&lcdc0_device,
+ &pwm_device,
+ &pwm_backlight_device,
&gpio_keys_device,
&sh_eth_device,
&vcc_sdhi0,
@@ -1090,6 +1135,9 @@ static const struct pinctrl_map eva_pinctrl_map[] = {
/* ST1232 */
PIN_MAP_MUX_GROUP_DEFAULT("0-0055", "pfc-r8a7740",
"intc_irq10", "intc"),
+ /* TPU0 */
+ PIN_MAP_MUX_GROUP_DEFAULT("renesas_tpu_pwm", "pfc-r8a7740",
+ "tpu0_to2_1", "tpu0"),
/* USBHS */
PIN_MAP_MUX_GROUP_DEFAULT("renesas_usbhs", "pfc-r8a7740",
"intc_irq7_1", "intc"),
@@ -1149,7 +1197,6 @@ static void __init eva_init(void)

/* LCDC0 */
gpio_request_one(61, GPIOF_OUT_INIT_HIGH, NULL); /* LCDDON */
- gpio_request_one(202, GPIOF_OUT_INIT_LOW, NULL); /* LCD0_LED_CONT */

/* Touchscreen */
gpio_request_one(166, GPIOF_OUT_INIT_HIGH, NULL); /* TP_RST_B */
--
1.8.1.5

2013-04-24 20:52:56

by Laurent Pinchart

[permalink] [raw]
Subject: [PATCH v2 06/11] ARM: mach-shmobile: clock-r8a7790: add TPU PWM support

Signed-off-by: Laurent Pinchart <[email protected]>
---
arch/arm/mach-shmobile/clock-r8a7790.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-shmobile/clock-r8a7790.c b/arch/arm/mach-shmobile/clock-r8a7790.c
index bedd20c..b393592 100644
--- a/arch/arm/mach-shmobile/clock-r8a7790.c
+++ b/arch/arm/mach-shmobile/clock-r8a7790.c
@@ -48,6 +48,7 @@
#define CPG_LEN 0x1000

#define SMSTPCR2 0xe6150138
+#define SMSTPCR3 0xe615013c
#define SMSTPCR7 0xe615014c

#define MODEMR 0xE6160060
@@ -178,11 +179,17 @@ static struct clk div6_clks[DIV6_NR] = {
};

/* MSTP */
-enum { MSTP721, MSTP720,
- MSTP216, MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP_NR };
+enum {
+ MSTP721, MSTP720,
+ MSTP304,
+ MSTP216, MSTP207, MSTP206, MSTP204, MSTP203, MSTP202,
+ MSTP_NR
+};
+
static struct clk mstp_clks[MSTP_NR] = {
[MSTP721] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 21, 0), /* SCIF0 */
[MSTP720] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 20, 0), /* SCIF1 */
+ [MSTP304] = SH_CLK_MSTP32(&cp_clk, SMSTPCR3, 4, 0), /* TPU0 */
[MSTP216] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 16, 0), /* SCIFB2 */
[MSTP207] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 7, 0), /* SCIFB1 */
[MSTP206] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 6, 0), /* SCIFB0 */
--
1.8.1.5

2013-04-24 20:53:15

by Laurent Pinchart

[permalink] [raw]
Subject: [PATCH v2 04/11] pwm: Add Renesas TPU PWM driver

The Timer Pulse Unit (TPU is a 4-channels 16-bit timer used to generate
waveforms. This driver exposes PWM functions through the PWM API for
other drivers to use.

The code is loosely based on the leds-renesas-tpu driver by Magnus Damm
and the TPU PWM driver shipped in the Armadillo EVA 800 kernel sources.

Signed-off-by: Laurent Pinchart <[email protected]>
Tested-by: Simon Horman <[email protected]>
---
drivers/pwm/Kconfig | 7 +
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-renesas-tpu.c | 462 ++++++++++++++++++++++++++
include/linux/platform_data/pwm-renesas-tpu.h | 18 +
4 files changed, 488 insertions(+)
create mode 100644 drivers/pwm/pwm-renesas-tpu.c
create mode 100644 include/linux/platform_data/pwm-renesas-tpu.h

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 0e0bfa0..d57ef66 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -115,6 +115,13 @@ config PWM_PXA
To compile this driver as a module, choose M here: the module
will be called pwm-pxa.

+config PWM_RENESAS_TPU
+ tristate "Renesas TPU PWM support"
+ depends on ARCH_SHMOBILE
+ help
+ This driver exposes the Timer Pulse Unit (TPU) PWM controller found
+ in Renesas chips through the PWM API.
+
config PWM_SAMSUNG
tristate "Samsung PWM support"
depends on PLAT_SAMSUNG
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 94ba21e..5aa815f 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o
obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o
obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
+obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o
obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c
new file mode 100644
index 0000000..8e6d8d7
--- /dev/null
+++ b/drivers/pwm/pwm-renesas-tpu.c
@@ -0,0 +1,462 @@
+/*
+ * R-Mobile TPU PWM driver
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_data/pwm-renesas-tpu.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#define TPU_TSTR 0x00 /* Timer start register (shared) */
+
+#define TPU_TCRn 0x00 /* Timer control register */
+#define TPU_TCR_CCLR_NONE (0 << 5)
+#define TPU_TCR_CCLR_TGRA (1 << 5)
+#define TPU_TCR_CCLR_TGRB (2 << 5)
+#define TPU_TCR_CCLR_TGRC (5 << 5)
+#define TPU_TCR_CCLR_TGRD (6 << 5)
+#define TPU_TCR_CKEG_RISING (0 << 3)
+#define TPU_TCR_CKEG_FALLING (1 << 3)
+#define TPU_TCR_CKEG_BOTH (2 << 3)
+#define TPU_TMDRn 0x04 /* Timer mode register */
+#define TPU_TMDR_BFWT (1 << 6)
+#define TPU_TMDR_BFB (1 << 5)
+#define TPU_TMDR_BFA (1 << 4)
+#define TPU_TMDR_MD_NORMAL (0 << 0)
+#define TPU_TMDR_MD_PWM (2 << 0)
+#define TPU_TIORn 0x08 /* Timer I/O control register */
+#define TPU_TIOR_IOA_0 (0 << 0)
+#define TPU_TIOR_IOA_0_CLR (1 << 0)
+#define TPU_TIOR_IOA_0_SET (2 << 0)
+#define TPU_TIOR_IOA_0_TOGGLE (3 << 0)
+#define TPU_TIOR_IOA_1 (4 << 0)
+#define TPU_TIOR_IOA_1_CLR (5 << 0)
+#define TPU_TIOR_IOA_1_SET (6 << 0)
+#define TPU_TIOR_IOA_1_TOGGLE (7 << 0)
+#define TPU_TIERn 0x0c /* Timer interrupt enable register */
+#define TPU_TSRn 0x10 /* Timer status register */
+#define TPU_TCNTn 0x14 /* Timer counter */
+#define TPU_TGRAn 0x18 /* Timer general register A */
+#define TPU_TGRBn 0x1c /* Timer general register B */
+#define TPU_TGRCn 0x20 /* Timer general register C */
+#define TPU_TGRDn 0x24 /* Timer general register D */
+
+#define TPU_CHANNEL_OFFSET 0x10
+#define TPU_CHANNEL_SIZE 0x40
+
+enum tpu_pin_state {
+ TPU_PIN_INACTIVE, /* Pin is driven inactive */
+ TPU_PIN_PWM, /* Pin is driven by PWM */
+ TPU_PIN_ACTIVE, /* Pin is driven active */
+};
+
+struct tpu_device;
+
+struct tpu_pwm_device {
+ bool timer_on; /* Whether the timer is running */
+
+ struct tpu_pwm_channel_data *pdata;
+ struct tpu_device *tpu;
+ unsigned int channel; /* Channel number in the TPU */
+
+ unsigned int prescaler;
+ u16 period;
+ u16 duty;
+};
+
+struct tpu_device {
+ struct platform_device *pdev;
+ struct pwm_chip chip;
+ spinlock_t lock;
+
+ void __iomem *base;
+ struct clk *clk;
+
+ struct tpu_pwm_device pwms[TPU_CHANNEL_MAX];
+};
+
+#define to_tpu_device(c) container_of(c, struct tpu_device, chip)
+
+static void tpu_pwm_write(struct tpu_pwm_device *pwm, int reg_nr, u16 value)
+{
+ void __iomem *base = pwm->tpu->base + TPU_CHANNEL_OFFSET
+ + pwm->channel * TPU_CHANNEL_SIZE;
+
+ iowrite16(value, base + reg_nr);
+}
+
+static void tpu_pwm_set_pin(struct tpu_pwm_device *pwm,
+ enum tpu_pin_state state)
+{
+ static const char * const states[] = { "inactive", "PWM", "active" };
+
+ dev_dbg(&pwm->tpu->pdev->dev, "%u: configuring pin as %s\n",
+ pwm->channel, states[state]);
+
+ switch (state) {
+ case TPU_PIN_INACTIVE:
+ tpu_pwm_write(pwm, TPU_TIORn, pwm->pdata->active_low ?
+ TPU_TIOR_IOA_1 : TPU_TIOR_IOA_0);
+ break;
+ case TPU_PIN_PWM:
+ tpu_pwm_write(pwm, TPU_TIORn, pwm->pdata->active_low ?
+ TPU_TIOR_IOA_0_SET : TPU_TIOR_IOA_1_CLR);
+ break;
+ case TPU_PIN_ACTIVE:
+ tpu_pwm_write(pwm, TPU_TIORn, pwm->pdata->active_low ?
+ TPU_TIOR_IOA_0 : TPU_TIOR_IOA_1);
+ break;
+ }
+}
+
+static void tpu_pwm_start_stop(struct tpu_pwm_device *pwm, int start)
+{
+ unsigned long flags;
+ u16 value;
+
+ spin_lock_irqsave(&pwm->tpu->lock, flags);
+ value = ioread16(pwm->tpu->base + TPU_TSTR);
+
+ if (start)
+ value |= 1 << pwm->channel;
+ else
+ value &= ~(1 << pwm->channel);
+
+ iowrite16(value, pwm->tpu->base + TPU_TSTR);
+ spin_unlock_irqrestore(&pwm->tpu->lock, flags);
+}
+
+static int tpu_pwm_timer_start(struct tpu_pwm_device *pwm)
+{
+ int ret;
+
+ if (!pwm->timer_on) {
+ /* Wake up device and enable clock. */
+ pm_runtime_get_sync(&pwm->tpu->pdev->dev);
+ ret = clk_prepare_enable(pwm->tpu->clk);
+ if (ret) {
+ dev_err(&pwm->tpu->pdev->dev, "cannot enable clock\n");
+ return ret;
+ }
+ pwm->timer_on = true;
+ }
+
+ /* Make sure the channel is stopped, as we need to reconfigure it
+ * completely. First drive the pin to the inactive state to avoid
+ * glitches.
+ */
+ tpu_pwm_set_pin(pwm, TPU_PIN_INACTIVE);
+ tpu_pwm_start_stop(pwm, false);
+
+ /*
+ * - Clear TCNT on TGRB match
+ * - Count on rising edge
+ * - Set prescaler
+ * - Output 0 until TGRA, output 1 until TGRB (active low polarity)
+ * - Output 1 until TGRA, output 0 until TGRB (active high polarity
+ * - PWM mode
+ */
+ tpu_pwm_write(pwm, TPU_TCRn, TPU_TCR_CCLR_TGRB | TPU_TCR_CKEG_RISING |
+ pwm->prescaler);
+ tpu_pwm_write(pwm, TPU_TMDRn, TPU_TMDR_MD_PWM);
+ tpu_pwm_set_pin(pwm, TPU_PIN_PWM);
+ tpu_pwm_write(pwm, TPU_TGRAn, pwm->duty);
+ tpu_pwm_write(pwm, TPU_TGRBn, pwm->period);
+
+ dev_dbg(&pwm->tpu->pdev->dev, "%u: TGRA 0x%04x TGRB 0x%04x\n",
+ pwm->channel, pwm->duty, pwm->period);
+
+ /* Start the channel. */
+ tpu_pwm_start_stop(pwm, true);
+
+ return 0;
+}
+
+static void tpu_pwm_timer_stop(struct tpu_pwm_device *pwm)
+{
+ if (!pwm->timer_on)
+ return;
+
+ /* Disable channel. */
+ tpu_pwm_start_stop(pwm, false);
+
+ /* Stop clock and mark device as idle. */
+ clk_disable_unprepare(pwm->tpu->clk);
+ pm_runtime_put(&pwm->tpu->pdev->dev);
+
+ pwm->timer_on = false;
+}
+
+/* -----------------------------------------------------------------------------
+ * PWM API
+ */
+
+static int tpu_pwm_request(struct pwm_chip *chip, struct pwm_device *_pwm)
+{
+ struct tpu_device *tpu = to_tpu_device(chip);
+ struct tpu_pwm_device *pwm = &tpu->pwms[_pwm->hwpwm];
+
+ return pwm->pdata == NULL ? -EPROBE_DEFER : 0;
+}
+
+static int tpu_pwm_config(struct pwm_chip *chip, struct pwm_device *_pwm,
+ int duty_ns, int period_ns)
+{
+ static const unsigned int prescalers[] = { 1, 4, 16, 64 };
+ struct tpu_device *tpu = to_tpu_device(chip);
+ struct tpu_pwm_device *pwm = &tpu->pwms[_pwm->hwpwm];
+ unsigned int prescaler;
+ bool duty_only;
+ u32 clk_rate;
+ u32 period;
+ u32 duty;
+ int ret;
+
+ if (period_ns <= 0 || duty_ns < 0 || duty_ns > period_ns)
+ return -EINVAL;
+
+ /* Pick a prescaler to avoid overflowing the counter.
+ * TODO: Pick the highest acceptable prescaler.
+ */
+ clk_prepare_enable(tpu->clk);
+ clk_rate = clk_get_rate(tpu->clk);
+ clk_disable_unprepare(pwm->tpu->clk);
+
+ for (prescaler = 0; prescaler < ARRAY_SIZE(prescalers); ++prescaler) {
+ period = clk_rate / prescalers[prescaler]
+ / (NSEC_PER_SEC / period_ns);
+ if (period <= 0xffff)
+ break;
+ }
+
+ if (prescaler == ARRAY_SIZE(prescalers) || period == 0) {
+ dev_err(&tpu->pdev->dev, "clock rate mismatch\n");
+ return -ENOTSUPP;
+ }
+
+ if (duty_ns) {
+ duty = clk_rate / prescalers[prescaler]
+ / (NSEC_PER_SEC / duty_ns);
+ if (duty > period)
+ return -EINVAL;
+ } else {
+ duty = 0;
+ }
+
+ dev_dbg(&tpu->pdev->dev,
+ "rate %u, prescaler %u, period %u, duty %u\n",
+ clk_rate, prescalers[prescaler], period, duty);
+
+ duty_only = pwm->prescaler == prescaler && pwm->period == period;
+
+ pwm->prescaler = prescaler;
+ pwm->period = period;
+ pwm->duty = duty;
+
+ /* If the channel is disabled we're done. */
+ if (!test_bit(PWMF_ENABLED, &_pwm->flags))
+ return 0;
+
+ if (duty_only && pwm->timer_on) {
+ /* If only the duty cycle changed and the timer is already
+ * running, there's no need to reconfigure it completely, Just
+ * modify the duty cycle.
+ */
+ tpu_pwm_write(pwm, TPU_TGRAn, pwm->duty);
+ dev_dbg(&tpu->pdev->dev, "%u: TGRA 0x%04x\n", pwm->channel,
+ pwm->duty);
+ } else {
+ /* Otherwise perform a full reconfiguration. */
+ ret = tpu_pwm_timer_start(pwm);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (duty == 0 || duty == period) {
+ /* To avoid running the timer when not strictly required, handle
+ * 0% and 100% duty cycles as fixed levels and stop the timer.
+ */
+ tpu_pwm_set_pin(pwm, duty ? TPU_PIN_ACTIVE : TPU_PIN_INACTIVE);
+ tpu_pwm_timer_stop(pwm);
+ }
+
+ return 0;
+}
+
+static int tpu_pwm_enable(struct pwm_chip *chip, struct pwm_device *_pwm)
+{
+ struct tpu_device *tpu = to_tpu_device(chip);
+ struct tpu_pwm_device *pwm = &tpu->pwms[_pwm->hwpwm];
+ int ret;
+
+ ret = tpu_pwm_timer_start(pwm);
+ if (ret < 0)
+ return ret;
+
+ /* To avoid running the timer when not strictly required, handle 0% and
+ * 100% duty cycles as fixed levels and stop the timer.
+ */
+ if (pwm->duty == 0 || pwm->duty == pwm->period) {
+ tpu_pwm_set_pin(pwm, pwm->duty ?
+ TPU_PIN_ACTIVE : TPU_PIN_INACTIVE);
+ tpu_pwm_timer_stop(pwm);
+ }
+
+ return 0;
+}
+
+static void tpu_pwm_disable(struct pwm_chip *chip, struct pwm_device *_pwm)
+{
+ struct tpu_device *tpu = to_tpu_device(chip);
+ struct tpu_pwm_device *pwm = &tpu->pwms[_pwm->hwpwm];
+
+ /* The timer must be running to modify the pin output configuration. */
+ tpu_pwm_timer_start(pwm);
+ tpu_pwm_set_pin(pwm, TPU_PIN_INACTIVE);
+ tpu_pwm_timer_stop(pwm);
+}
+
+static const struct pwm_ops tpu_pwm_ops = {
+ .request = tpu_pwm_request,
+ .config = tpu_pwm_config,
+ .enable = tpu_pwm_enable,
+ .disable = tpu_pwm_disable,
+ .owner = THIS_MODULE,
+};
+
+/* -----------------------------------------------------------------------------
+ * Probe and remove
+ */
+
+static int tpu_probe(struct platform_device *pdev)
+{
+ struct tpu_pwm_platform_data *pdata = pdev->dev.platform_data;
+ struct tpu_device *tpu;
+ struct resource *res;
+ unsigned int i;
+ int ret;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "missing platform data\n");
+ return -ENXIO;
+ }
+
+ tpu = devm_kzalloc(&pdev->dev, sizeof(*tpu), GFP_KERNEL);
+ if (tpu == NULL) {
+ dev_err(&pdev->dev, "failed to allocate driver data\n");
+ return -ENOMEM;
+ }
+
+ /* Map memory, get clock and pin control. */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get I/O memory\n");
+ return -ENXIO;
+ }
+
+ tpu->base = devm_ioremap_nocache(&pdev->dev, res->start,
+ resource_size(res));
+ if (tpu->base == NULL) {
+ dev_err(&pdev->dev, "failed to remap I/O memory\n");
+ return -ENXIO;
+ }
+
+ tpu->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(tpu->clk)) {
+ dev_err(&pdev->dev, "cannot get clock\n");
+ return PTR_ERR(tpu->clk);
+ }
+
+ /* Initialize and register the device. */
+ platform_set_drvdata(pdev, tpu);
+
+ spin_lock_init(&tpu->lock);
+ tpu->pdev = pdev;
+
+ for (i = 0; i < ARRAY_SIZE(tpu->pwms); ++i) {
+ struct tpu_pwm_device *pwm = &tpu->pwms[i];
+
+ if (!pdata->channels[i].enabled)
+ continue;
+
+ pwm->tpu = tpu;
+ pwm->channel = i;
+ pwm->pdata = &pdata->channels[i];
+
+ pwm->prescaler = 0;
+ pwm->period = 0;
+ pwm->duty = 0;
+
+ pwm->timer_on = false;
+ }
+
+ tpu->chip.dev = &pdev->dev;
+ tpu->chip.ops = &tpu_pwm_ops;
+ tpu->chip.base = -1;
+ tpu->chip.npwm = TPU_CHANNEL_MAX;
+
+ ret = pwmchip_add(&tpu->chip);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register PWM chip\n");
+ return ret;
+ }
+
+ dev_info(&pdev->dev, "TPU PWM %d registered\n", tpu->pdev->id);
+
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+}
+
+static int tpu_remove(struct platform_device *pdev)
+{
+ struct tpu_device *tpu = platform_get_drvdata(pdev);
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(tpu->pwms); ++i) {
+ struct tpu_pwm_device *pwm = &tpu->pwms[i];
+
+ if (!pwm->tpu)
+ continue;
+
+ tpu_pwm_timer_stop(pwm);
+ }
+
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static struct platform_driver tpu_driver = {
+ .probe = tpu_probe,
+ .remove = tpu_remove,
+ .driver = {
+ .name = "renesas_tpu_pwm",
+ }
+};
+
+module_platform_driver(tpu_driver);
+
+MODULE_AUTHOR("Laurent Pinchart <[email protected]>");
+MODULE_DESCRIPTION("Renesas TPU PWM Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/platform_data/pwm-renesas-tpu.h b/include/linux/platform_data/pwm-renesas-tpu.h
new file mode 100644
index 0000000..7f68efb
--- /dev/null
+++ b/include/linux/platform_data/pwm-renesas-tpu.h
@@ -0,0 +1,18 @@
+#ifndef __PWM_RENESAS_TPU_H__
+#define __PWM_RENESAS_TPU_H__
+
+#define TPU_CHANNEL_MAX 4
+
+#define TPU_PWM_ID(device, channel) \
+ ((device) * TPU_CHANNEL_MAX + (channel))
+
+struct tpu_pwm_channel_data {
+ bool enabled;
+ bool active_low;
+};
+
+struct tpu_pwm_platform_data {
+ struct tpu_pwm_channel_data channels[TPU_CHANNEL_MAX];
+};
+
+#endif /* __PWM_RENESAS_TPU_H__ */
--
1.8.1.5

2013-04-24 20:53:35

by Laurent Pinchart

[permalink] [raw]
Subject: [PATCH v2 02/11] sh-pfc: r8a7740: Add TPU pin groups and functions

Signed-off-by: Laurent Pinchart <[email protected]>
---
drivers/pinctrl/sh-pfc/pfc-r8a7740.c | 50 ++++++++++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)

diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
index e5ef587..f6ea47c 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
@@ -2745,6 +2745,42 @@ static const unsigned int sdhi2_wp_1_pins[] = {
static const unsigned int sdhi2_wp_1_mux[] = {
SDHI2_WP_PORT25_MARK,
};
+/* - TPU0 ------------------------------------------------------------------- */
+static const unsigned int tpu0_to0_pins[] = {
+ /* TO */
+ 23,
+};
+static const unsigned int tpu0_to0_mux[] = {
+ TPU0TO0_MARK,
+};
+static const unsigned int tpu0_to1_pins[] = {
+ /* TO */
+ 21,
+};
+static const unsigned int tpu0_to1_mux[] = {
+ TPU0TO1_MARK,
+};
+static const unsigned int tpu0_to2_0_pins[] = {
+ /* TO */
+ 66,
+};
+static const unsigned int tpu0_to2_0_mux[] = {
+ TPU0TO2_PORT66_MARK,
+};
+static const unsigned int tpu0_to2_1_pins[] = {
+ /* TO */
+ 202,
+};
+static const unsigned int tpu0_to2_1_mux[] = {
+ TPU0TO2_PORT202_MARK,
+};
+static const unsigned int tpu0_to3_pins[] = {
+ /* TO */
+ 180,
+};
+static const unsigned int tpu0_to3_mux[] = {
+ TPU0TO3_MARK,
+};

static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(bsc_data8),
@@ -2926,6 +2962,11 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(sdhi2_wp_0),
SH_PFC_PIN_GROUP(sdhi2_cd_1),
SH_PFC_PIN_GROUP(sdhi2_wp_1),
+ SH_PFC_PIN_GROUP(tpu0_to0),
+ SH_PFC_PIN_GROUP(tpu0_to1),
+ SH_PFC_PIN_GROUP(tpu0_to2_0),
+ SH_PFC_PIN_GROUP(tpu0_to2_1),
+ SH_PFC_PIN_GROUP(tpu0_to3),
};

static const char * const bsc_groups[] = {
@@ -3176,6 +3217,14 @@ static const char * const sdhi2_groups[] = {
"sdhi2_wp_1",
};

+static const char * const tpu0_groups[] = {
+ "tpu0_to0",
+ "tpu0_to1",
+ "tpu0_to2_0",
+ "tpu0_to2_1",
+ "tpu0_to3",
+};
+
static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(bsc),
SH_PFC_FUNCTION(ceu0),
@@ -3200,6 +3249,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(sdhi0),
SH_PFC_FUNCTION(sdhi1),
SH_PFC_FUNCTION(sdhi2),
+ SH_PFC_FUNCTION(tpu0),
};

#undef PORTCR
--
1.8.1.5

2013-04-24 21:00:19

by Bryan Wu

[permalink] [raw]
Subject: Re: [PATCH v2 11/11] leds: Remove leds-renesas-tpu driver

On Wed, Apr 24, 2013 at 1:50 PM, Laurent Pinchart
<[email protected]> wrote:
> The driver is superseded by the generic rmob-tpu-pwm driver used with
> leds-pwm.
>
> Signed-off-by: Laurent Pinchart <[email protected]>


It's nice to move to generic driver.

Acked-by: Bryan Wu <[email protected]>

> ---
> drivers/leds/Kconfig | 12 -
> drivers/leds/Makefile | 1 -
> drivers/leds/leds-renesas-tpu.c | 336 -------------------------
> include/linux/platform_data/leds-renesas-tpu.h | 14 --
> 4 files changed, 363 deletions(-)
> delete mode 100644 drivers/leds/leds-renesas-tpu.c
> delete mode 100644 include/linux/platform_data/leds-renesas-tpu.h
>
> diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
> index ec50824..da2ac5c 100644
> --- a/drivers/leds/Kconfig
> +++ b/drivers/leds/Kconfig
> @@ -419,18 +419,6 @@ config LEDS_ASIC3
> cannot be used. This driver supports hardware blinking with an on+off
> period from 62ms to 125s. Say Y to enable LEDs on the HP iPAQ hx4700.
>
> -config LEDS_RENESAS_TPU
> - bool "LED support for Renesas TPU"
> - depends on LEDS_CLASS=y && HAVE_CLK && GENERIC_GPIO
> - help
> - This option enables build of the LED TPU platform driver,
> - suitable to drive any TPU channel on newer Renesas SoCs.
> - The driver controls the GPIO pin connected to the LED via
> - the GPIO framework and expects the LED to be connected to
> - a pin that can be driven in both GPIO mode and using TPU
> - pin function. The latter to support brightness control.
> - Brightness control is supported but hardware blinking is not.
> -
> config LEDS_TCA6507
> tristate "LED Support for TCA6507 I2C chip"
> depends on LEDS_CLASS && I2C
> diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
> index 215e7e3..dd80c1a 100644
> --- a/drivers/leds/Makefile
> +++ b/drivers/leds/Makefile
> @@ -48,7 +48,6 @@ obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o
> obj-$(CONFIG_LEDS_NS2) += leds-ns2.o
> obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o
> obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o
> -obj-$(CONFIG_LEDS_RENESAS_TPU) += leds-renesas-tpu.o
> obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o
> obj-$(CONFIG_LEDS_LM355x) += leds-lm355x.o
> obj-$(CONFIG_LEDS_BLINKM) += leds-blinkm.o
> diff --git a/drivers/leds/leds-renesas-tpu.c b/drivers/leds/leds-renesas-tpu.c
> deleted file mode 100644
> index d3c2b7e..0000000
> --- a/drivers/leds/leds-renesas-tpu.c
> +++ /dev/null
> @@ -1,336 +0,0 @@
> -/*
> - * LED control using Renesas TPU
> - *
> - * Copyright (C) 2011 Magnus Damm
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * You should have received a copy of the GNU General Public License
> - * along with this program; if not, write to the Free Software
> - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> - */
> -
> -#include <linux/module.h>
> -#include <linux/init.h>
> -#include <linux/platform_device.h>
> -#include <linux/spinlock.h>
> -#include <linux/printk.h>
> -#include <linux/ioport.h>
> -#include <linux/io.h>
> -#include <linux/clk.h>
> -#include <linux/leds.h>
> -#include <linux/platform_data/leds-renesas-tpu.h>
> -#include <linux/gpio.h>
> -#include <linux/err.h>
> -#include <linux/slab.h>
> -#include <linux/pm_runtime.h>
> -#include <linux/workqueue.h>
> -
> -enum r_tpu_pin { R_TPU_PIN_UNUSED, R_TPU_PIN_GPIO, R_TPU_PIN_GPIO_FN };
> -enum r_tpu_timer { R_TPU_TIMER_UNUSED, R_TPU_TIMER_ON };
> -
> -struct r_tpu_priv {
> - struct led_classdev ldev;
> - void __iomem *mapbase;
> - struct clk *clk;
> - struct platform_device *pdev;
> - enum r_tpu_pin pin_state;
> - enum r_tpu_timer timer_state;
> - unsigned long min_rate;
> - unsigned int refresh_rate;
> - struct work_struct work;
> - enum led_brightness new_brightness;
> -};
> -
> -static DEFINE_SPINLOCK(r_tpu_lock);
> -
> -#define TSTR -1 /* Timer start register (shared register) */
> -#define TCR 0 /* Timer control register (+0x00) */
> -#define TMDR 1 /* Timer mode register (+0x04) */
> -#define TIOR 2 /* Timer I/O control register (+0x08) */
> -#define TIER 3 /* Timer interrupt enable register (+0x0c) */
> -#define TSR 4 /* Timer status register (+0x10) */
> -#define TCNT 5 /* Timer counter (+0x14) */
> -#define TGRA 6 /* Timer general register A (+0x18) */
> -#define TGRB 7 /* Timer general register B (+0x1c) */
> -#define TGRC 8 /* Timer general register C (+0x20) */
> -#define TGRD 9 /* Timer general register D (+0x24) */
> -
> -static inline unsigned short r_tpu_read(struct r_tpu_priv *p, int reg_nr)
> -{
> - struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
> - void __iomem *base = p->mapbase;
> - unsigned long offs = reg_nr << 2;
> -
> - if (reg_nr == TSTR)
> - return ioread16(base - cfg->channel_offset);
> -
> - return ioread16(base + offs);
> -}
> -
> -static inline void r_tpu_write(struct r_tpu_priv *p, int reg_nr,
> - unsigned short value)
> -{
> - struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
> - void __iomem *base = p->mapbase;
> - unsigned long offs = reg_nr << 2;
> -
> - if (reg_nr == TSTR) {
> - iowrite16(value, base - cfg->channel_offset);
> - return;
> - }
> -
> - iowrite16(value, base + offs);
> -}
> -
> -static void r_tpu_start_stop_ch(struct r_tpu_priv *p, int start)
> -{
> - struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
> - unsigned long flags, value;
> -
> - /* start stop register shared by multiple timer channels */
> - spin_lock_irqsave(&r_tpu_lock, flags);
> - value = r_tpu_read(p, TSTR);
> -
> - if (start)
> - value |= 1 << cfg->timer_bit;
> - else
> - value &= ~(1 << cfg->timer_bit);
> -
> - r_tpu_write(p, TSTR, value);
> - spin_unlock_irqrestore(&r_tpu_lock, flags);
> -}
> -
> -static int r_tpu_enable(struct r_tpu_priv *p, enum led_brightness brightness)
> -{
> - struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
> - int prescaler[] = { 1, 4, 16, 64 };
> - int k, ret;
> - unsigned long rate, tmp;
> -
> - if (p->timer_state == R_TPU_TIMER_ON)
> - return 0;
> -
> - /* wake up device and enable clock */
> - pm_runtime_get_sync(&p->pdev->dev);
> - ret = clk_enable(p->clk);
> - if (ret) {
> - dev_err(&p->pdev->dev, "cannot enable clock\n");
> - return ret;
> - }
> -
> - /* make sure channel is disabled */
> - r_tpu_start_stop_ch(p, 0);
> -
> - /* get clock rate after enabling it */
> - rate = clk_get_rate(p->clk);
> -
> - /* pick the lowest acceptable rate */
> - for (k = ARRAY_SIZE(prescaler) - 1; k >= 0; k--)
> - if ((rate / prescaler[k]) >= p->min_rate)
> - break;
> -
> - if (k < 0) {
> - dev_err(&p->pdev->dev, "clock rate mismatch\n");
> - goto err0;
> - }
> - dev_dbg(&p->pdev->dev, "rate = %lu, prescaler %u\n",
> - rate, prescaler[k]);
> -
> - /* clear TCNT on TGRB match, count on rising edge, set prescaler */
> - r_tpu_write(p, TCR, 0x0040 | k);
> -
> - /* output 0 until TGRA, output 1 until TGRB */
> - r_tpu_write(p, TIOR, 0x0002);
> -
> - rate /= prescaler[k] * p->refresh_rate;
> - r_tpu_write(p, TGRB, rate);
> - dev_dbg(&p->pdev->dev, "TRGB = 0x%04lx\n", rate);
> -
> - tmp = (cfg->max_brightness - brightness) * rate;
> - r_tpu_write(p, TGRA, tmp / cfg->max_brightness);
> - dev_dbg(&p->pdev->dev, "TRGA = 0x%04lx\n", tmp / cfg->max_brightness);
> -
> - /* PWM mode */
> - r_tpu_write(p, TMDR, 0x0002);
> -
> - /* enable channel */
> - r_tpu_start_stop_ch(p, 1);
> -
> - p->timer_state = R_TPU_TIMER_ON;
> - return 0;
> - err0:
> - clk_disable(p->clk);
> - pm_runtime_put_sync(&p->pdev->dev);
> - return -ENOTSUPP;
> -}
> -
> -static void r_tpu_disable(struct r_tpu_priv *p)
> -{
> - if (p->timer_state == R_TPU_TIMER_UNUSED)
> - return;
> -
> - /* disable channel */
> - r_tpu_start_stop_ch(p, 0);
> -
> - /* stop clock and mark device as idle */
> - clk_disable(p->clk);
> - pm_runtime_put_sync(&p->pdev->dev);
> -
> - p->timer_state = R_TPU_TIMER_UNUSED;
> -}
> -
> -static void r_tpu_set_pin(struct r_tpu_priv *p, enum r_tpu_pin new_state,
> - enum led_brightness brightness)
> -{
> - struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data;
> -
> - if (p->pin_state == new_state) {
> - if (p->pin_state == R_TPU_PIN_GPIO)
> - gpio_set_value(cfg->pin_gpio, brightness);
> - return;
> - }
> -
> - if (p->pin_state == R_TPU_PIN_GPIO)
> - gpio_free(cfg->pin_gpio);
> -
> - if (p->pin_state == R_TPU_PIN_GPIO_FN)
> - gpio_free(cfg->pin_gpio_fn);
> -
> - if (new_state == R_TPU_PIN_GPIO)
> - gpio_request_one(cfg->pin_gpio, GPIOF_DIR_OUT | !!brightness,
> - cfg->name);
> -
> - if (new_state == R_TPU_PIN_GPIO_FN)
> - gpio_request(cfg->pin_gpio_fn, cfg->name);
> -
> - p->pin_state = new_state;
> -}
> -
> -static void r_tpu_work(struct work_struct *work)
> -{
> - struct r_tpu_priv *p = container_of(work, struct r_tpu_priv, work);
> - enum led_brightness brightness = p->new_brightness;
> -
> - r_tpu_disable(p);
> -
> - /* off and maximum are handled as GPIO pins, in between PWM */
> - if ((brightness == 0) || (brightness == p->ldev.max_brightness))
> - r_tpu_set_pin(p, R_TPU_PIN_GPIO, brightness);
> - else {
> - r_tpu_set_pin(p, R_TPU_PIN_GPIO_FN, 0);
> - r_tpu_enable(p, brightness);
> - }
> -}
> -
> -static void r_tpu_set_brightness(struct led_classdev *ldev,
> - enum led_brightness brightness)
> -{
> - struct r_tpu_priv *p = container_of(ldev, struct r_tpu_priv, ldev);
> - p->new_brightness = brightness;
> - schedule_work(&p->work);
> -}
> -
> -static int r_tpu_probe(struct platform_device *pdev)
> -{
> - struct led_renesas_tpu_config *cfg = pdev->dev.platform_data;
> - struct r_tpu_priv *p;
> - struct resource *res;
> - int ret;
> -
> - if (!cfg) {
> - dev_err(&pdev->dev, "missing platform data\n");
> - return -ENODEV;
> - }
> -
> - p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
> - if (p == NULL) {
> - dev_err(&pdev->dev, "failed to allocate driver data\n");
> - return -ENOMEM;
> - }
> -
> - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - if (!res) {
> - dev_err(&pdev->dev, "failed to get I/O memory\n");
> - return -ENXIO;
> - }
> -
> - /* map memory, let mapbase point to our channel */
> - p->mapbase = devm_ioremap_nocache(&pdev->dev, res->start,
> - resource_size(res));
> - if (p->mapbase == NULL) {
> - dev_err(&pdev->dev, "failed to remap I/O memory\n");
> - return -ENXIO;
> - }
> -
> - /* get hold of clock */
> - p->clk = devm_clk_get(&pdev->dev, NULL);
> - if (IS_ERR(p->clk)) {
> - dev_err(&pdev->dev, "cannot get clock\n");
> - return PTR_ERR(p->clk);
> - }
> -
> - p->pdev = pdev;
> - p->pin_state = R_TPU_PIN_UNUSED;
> - p->timer_state = R_TPU_TIMER_UNUSED;
> - p->refresh_rate = cfg->refresh_rate ? cfg->refresh_rate : 100;
> - r_tpu_set_pin(p, R_TPU_PIN_GPIO, LED_OFF);
> - platform_set_drvdata(pdev, p);
> -
> - INIT_WORK(&p->work, r_tpu_work);
> -
> - p->ldev.name = cfg->name;
> - p->ldev.brightness = LED_OFF;
> - p->ldev.max_brightness = cfg->max_brightness;
> - p->ldev.brightness_set = r_tpu_set_brightness;
> - p->ldev.flags |= LED_CORE_SUSPENDRESUME;
> - ret = led_classdev_register(&pdev->dev, &p->ldev);
> - if (ret < 0)
> - goto err0;
> -
> - /* max_brightness may be updated by the LED core code */
> - p->min_rate = p->ldev.max_brightness * p->refresh_rate;
> -
> - pm_runtime_enable(&pdev->dev);
> - return 0;
> -
> - err0:
> - r_tpu_set_pin(p, R_TPU_PIN_UNUSED, LED_OFF);
> - return ret;
> -}
> -
> -static int r_tpu_remove(struct platform_device *pdev)
> -{
> - struct r_tpu_priv *p = platform_get_drvdata(pdev);
> -
> - r_tpu_set_brightness(&p->ldev, LED_OFF);
> - led_classdev_unregister(&p->ldev);
> - cancel_work_sync(&p->work);
> - r_tpu_disable(p);
> - r_tpu_set_pin(p, R_TPU_PIN_UNUSED, LED_OFF);
> -
> - pm_runtime_disable(&pdev->dev);
> -
> - return 0;
> -}
> -
> -static struct platform_driver r_tpu_device_driver = {
> - .probe = r_tpu_probe,
> - .remove = r_tpu_remove,
> - .driver = {
> - .name = "leds-renesas-tpu",
> - }
> -};
> -
> -module_platform_driver(r_tpu_device_driver);
> -
> -MODULE_AUTHOR("Magnus Damm");
> -MODULE_DESCRIPTION("Renesas TPU LED Driver");
> -MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/platform_data/leds-renesas-tpu.h b/include/linux/platform_data/leds-renesas-tpu.h
> deleted file mode 100644
> index 0553870..0000000
> --- a/include/linux/platform_data/leds-renesas-tpu.h
> +++ /dev/null
> @@ -1,14 +0,0 @@
> -#ifndef __LEDS_RENESAS_TPU_H__
> -#define __LEDS_RENESAS_TPU_H__
> -
> -struct led_renesas_tpu_config {
> - char *name;
> - unsigned pin_gpio_fn;
> - unsigned pin_gpio;
> - unsigned int channel_offset;
> - unsigned int timer_bit;
> - unsigned int max_brightness;
> - unsigned int refresh_rate;
> -};
> -
> -#endif /* __LEDS_RENESAS_TPU_H__ */
> --
> 1.8.1.5
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-leds" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

2013-05-23 21:45:28

by Thierry Reding

[permalink] [raw]
Subject: Re: [PATCH v2 04/11] pwm: Add Renesas TPU PWM driver

On Wed, Apr 24, 2013 at 10:50:09PM +0200, Laurent Pinchart wrote:
> The Timer Pulse Unit (TPU is a 4-channels 16-bit timer used to generate
> waveforms. This driver exposes PWM functions through the PWM API for
> other drivers to use.
>
> The code is loosely based on the leds-renesas-tpu driver by Magnus Damm
> and the TPU PWM driver shipped in the Armadillo EVA 800 kernel sources.
>
> Signed-off-by: Laurent Pinchart <[email protected]>
> Tested-by: Simon Horman <[email protected]>

Sorry for taking so long to look at this...

> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> index 0e0bfa0..d57ef66 100644
> --- a/drivers/pwm/Kconfig
> +++ b/drivers/pwm/Kconfig
> @@ -115,6 +115,13 @@ config PWM_PXA
> To compile this driver as a module, choose M here: the module
> will be called pwm-pxa.
>
> +config PWM_RENESAS_TPU
> + tristate "Renesas TPU PWM support"
> + depends on ARCH_SHMOBILE
> + help
> + This driver exposes the Timer Pulse Unit (TPU) PWM controller found
> + in Renesas chips through the PWM API.

If the driver can be built, it'd be good to include a short sentence
saying what it will be called, just like for the other drivers.

> diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c
[...]
> +struct tpu_pwm_device {
> + bool timer_on; /* Whether the timer is running */
> +
> + struct tpu_pwm_channel_data *pdata;
> + struct tpu_device *tpu;
> + unsigned int channel; /* Channel number in the TPU */

I don't think you need this. The pwm_device.hwpwm field carries the same
information.

> +
> + unsigned int prescaler;
> + u16 period;
> + u16 duty;
> +};
> +
> +struct tpu_device {
> + struct platform_device *pdev;
> + struct pwm_chip chip;
> + spinlock_t lock;
> +
> + void __iomem *base;
> + struct clk *clk;
> +
> + struct tpu_pwm_device pwms[TPU_CHANNEL_MAX];
> +};

Can't you reuse the infrastructure built into the PWM subsystem? You can
associate chip-specific data with each PWM device. You can look at the
pwm-atmel-tcb and pwm-bfin drivers for usage examples. In a nutshell you
hook the .request() function and setup the driver-specific structure and
associate them with the PWM using pwm_set_chip_data().

This has the advantage that you don't need the pwms array in tpu_device
and you also don't need TPU_CHANNEL_MAX because only the pwm_chip.npwm
field needs to contain the number of channels.

> +static int tpu_pwm_timer_start(struct tpu_pwm_device *pwm)
> +{
> + int ret;
> +
> + if (!pwm->timer_on) {
> + /* Wake up device and enable clock. */
> + pm_runtime_get_sync(&pwm->tpu->pdev->dev);
> + ret = clk_prepare_enable(pwm->tpu->clk);
> + if (ret) {
> + dev_err(&pwm->tpu->pdev->dev, "cannot enable clock\n");
> + return ret;
> + }
> + pwm->timer_on = true;
> + }
> +
> + /* Make sure the channel is stopped, as we need to reconfigure it
> + * completely. First drive the pin to the inactive state to avoid
> + * glitches.
> + */

Can you please stick to the standard coding style for block comments?
That is:

/*
* Make sure...
* ...
* glitches.
*/

> +/* -----------------------------------------------------------------------------
> + * PWM API
> + */

I find these separators more distracting than helpful. But if you have a
strong preference for them I can live with it.

> +
> +static int tpu_pwm_request(struct pwm_chip *chip, struct pwm_device *_pwm)
> +{
> + struct tpu_device *tpu = to_tpu_device(chip);
> + struct tpu_pwm_device *pwm = &tpu->pwms[_pwm->hwpwm];
> +
> + return pwm->pdata == NULL ? -EPROBE_DEFER : 0;
> +}

If you use the same method as the pwm-bfin or pwm-atmel-tcb drivers, you
could initialize each PWM channel here and associated them with the PWM
device using pwm_set_chip_data() (as I hinted at earlier).

> +static int tpu_pwm_config(struct pwm_chip *chip, struct pwm_device *_pwm,
> + int duty_ns, int period_ns)
[...]
> + if (period_ns <= 0 || duty_ns < 0 || duty_ns > period_ns)
> + return -EINVAL;

The core already performs these checks so they can be dropped.

> + /* Pick a prescaler to avoid overflowing the counter.
> + * TODO: Pick the highest acceptable prescaler.
> + */
> + clk_prepare_enable(tpu->clk);

Shouldn't you check the return value here?

> + clk_rate = clk_get_rate(tpu->clk);
> + clk_disable_unprepare(pwm->tpu->clk);

And does the clock really need to be enabled to obtain the rate?

> + for (prescaler = 0; prescaler < ARRAY_SIZE(prescalers); ++prescaler) {
> + period = clk_rate / prescalers[prescaler]
> + / (NSEC_PER_SEC / period_ns);

I prefer to have the operator on the previous line, as in:

period = clk_rate / prescalers[prescaler] /
(NSEC_PER_SEC / period_ns);

> + duty_only = pwm->prescaler == prescaler && pwm->period == period;

Maybe the following would be easier to read?

if (prescaler == pwm->prescaler && period == pwm->period)
duty_only = true;

And initialize duty_only = false when declaring it.

> +static int tpu_probe(struct platform_device *pdev)
> +{
> + struct tpu_pwm_platform_data *pdata = pdev->dev.platform_data;
> + struct tpu_device *tpu;
> + struct resource *res;
> + unsigned int i;
> + int ret;
> +
> + if (!pdata) {
> + dev_err(&pdev->dev, "missing platform data\n");
> + return -ENXIO;
> + }
> +
> + tpu = devm_kzalloc(&pdev->dev, sizeof(*tpu), GFP_KERNEL);
> + if (tpu == NULL) {
> + dev_err(&pdev->dev, "failed to allocate driver data\n");
> + return -ENOMEM;
> + }
> +
> + /* Map memory, get clock and pin control. */
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + if (!res) {
> + dev_err(&pdev->dev, "failed to get I/O memory\n");
> + return -ENXIO;
> + }
> +
> + tpu->base = devm_ioremap_nocache(&pdev->dev, res->start,
> + resource_size(res));
> + if (tpu->base == NULL) {
> + dev_err(&pdev->dev, "failed to remap I/O memory\n");
> + return -ENXIO;
> + }

Isn't this mising a request_mem_region()? Couldn't you just use a call
to devm_ioremap_resource() instead?

> +static struct platform_driver tpu_driver = {
> + .probe = tpu_probe,
> + .remove = tpu_remove,
> + .driver = {
> + .name = "renesas_tpu_pwm",

Can this perhaps be renamed to "renesas-tpu-pwm" for consistency with
other drivers?

And I think this is missing

.owner = THIS_MODULE,

as well. I know not all drivers have this either, but I have that on my
TODO already.

> diff --git a/include/linux/platform_data/pwm-renesas-tpu.h b/include/linux/platform_data/pwm-renesas-tpu.h
[...]
> +#define TPU_CHANNEL_MAX 4
> +
> +#define TPU_PWM_ID(device, channel) \
> + ((device) * TPU_CHANNEL_MAX + (channel))

Please don't do this. It assumes a global namespace for PWM devices.
However the global namespace is only for compatibility with legacy code
and shouldn't be depended on by new drivers. You should be using either
DT to dynamically refer to PWM devices or use a PWM lookup table. Refer
to Documentation/pwm.txt for details.

> +struct tpu_pwm_channel_data {
> + bool enabled;
> + bool active_low;

Maybe this should be enum pwm_polarity?

> +};
> +
> +struct tpu_pwm_platform_data {
> + struct tpu_pwm_channel_data channels[TPU_CHANNEL_MAX];
> +};

This could be a little difficult to handle in the absence of
TPU_CHANNEL_MAX. Depending on the hardware, I suppose you could just
handle it via the .request() function. In that case all channels would
be disabled by default and enabled automatically when requested by a
user driver.

Thierry


Attachments:
(No filename) (7.24 kB)
(No filename) (836.00 B)
Download all attachments

2013-05-29 15:49:15

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH v2 04/11] pwm: Add Renesas TPU PWM driver

Hi Thierry,

On Thursday 23 May 2013 23:45:17 Thierry Reding wrote:
> On Wed, Apr 24, 2013 at 10:50:09PM +0200, Laurent Pinchart wrote:
> > The Timer Pulse Unit (TPU is a 4-channels 16-bit timer used to generate
> > waveforms. This driver exposes PWM functions through the PWM API for
> > other drivers to use.
> >
> > The code is loosely based on the leds-renesas-tpu driver by Magnus Damm
> > and the TPU PWM driver shipped in the Armadillo EVA 800 kernel sources.
> >
> > Signed-off-by: Laurent Pinchart
> > <[email protected]>
> > Tested-by: Simon Horman <[email protected]>
>
> Sorry for taking so long to look at this...

No worries. Thank you for the review.

> > diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> > index 0e0bfa0..d57ef66 100644
> > --- a/drivers/pwm/Kconfig
> > +++ b/drivers/pwm/Kconfig
> > @@ -115,6 +115,13 @@ config PWM_PXA
> >
> > To compile this driver as a module, choose M here: the module
> > will be called pwm-pxa.
> >
> > +config PWM_RENESAS_TPU
> > + tristate "Renesas TPU PWM support"
> > + depends on ARCH_SHMOBILE
> > + help
> > + This driver exposes the Timer Pulse Unit (TPU) PWM controller found
> > + in Renesas chips through the PWM API.
>
> If the driver can be built, it'd be good to include a short sentence
> saying what it will be called, just like for the other drivers.

OK.

> > diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c
>
> [...]
>
> > +struct tpu_pwm_device {
> > + bool timer_on; /* Whether the timer is running */
> > +
> > + struct tpu_pwm_channel_data *pdata;
> > + struct tpu_device *tpu;
> > + unsigned int channel; /* Channel number in the TPU */
>
> I don't think you need this. The pwm_device.hwpwm field carries the same
> information.
>
> > +
> > + unsigned int prescaler;
> > + u16 period;
> > + u16 duty;
> > +};
> > +
> > +struct tpu_device {
> > + struct platform_device *pdev;
> > + struct pwm_chip chip;
> > + spinlock_t lock;
> > +
> > + void __iomem *base;
> > + struct clk *clk;
> > +
> > + struct tpu_pwm_device pwms[TPU_CHANNEL_MAX];
> > +};
>
> Can't you reuse the infrastructure built into the PWM subsystem? You can
> associate chip-specific data with each PWM device. You can look at the
> pwm-atmel-tcb and pwm-bfin drivers for usage examples. In a nutshell you
> hook the .request() function and setup the driver-specific structure and
> associate them with the PWM using pwm_set_chip_data().
>
> This has the advantage that you don't need the pwms array in tpu_device
> and you also don't need TPU_CHANNEL_MAX because only the pwm_chip.npwm
> field needs to contain the number of channels.

I've actually thought about that, but decided not to do so. It looked pretty
weird to allocate PWM devices at .request() time, so I decided to allocate the
devices once only at probe time. Is it considered better to allocate/free PWM
devices every time they're requested/released ?

> > +static int tpu_pwm_timer_start(struct tpu_pwm_device *pwm)
> > +{
> > + int ret;
> > +
> > + if (!pwm->timer_on) {
> > + /* Wake up device and enable clock. */
> > + pm_runtime_get_sync(&pwm->tpu->pdev->dev);
> > + ret = clk_prepare_enable(pwm->tpu->clk);
> > + if (ret) {
> > + dev_err(&pwm->tpu->pdev->dev, "cannot enable clock\n");
> > + return ret;
> > + }
> > + pwm->timer_on = true;
> > + }
> > +
> > + /* Make sure the channel is stopped, as we need to reconfigure it
> > + * completely. First drive the pin to the inactive state to avoid
> > + * glitches.
> > + */
>
> Can you please stick to the standard coding style for block comments?
> That is:
>
> /*
> * Make sure...
> * ...
> * glitches.
> */

Sure.

> > +/* ----------------------------------------------------------------------
> > + * PWM API
> > + */
>
> I find these separators more distracting than helpful. But if you have a
> strong preference for them I can live with it.

I wouldn't have put them here if they didn't help me reading the code :-) I
can remove them if you have a strong objection.

> > +
> > +static int tpu_pwm_request(struct pwm_chip *chip, struct pwm_device
> > *_pwm)
> > +{
> > + struct tpu_device *tpu = to_tpu_device(chip);
> > + struct tpu_pwm_device *pwm = &tpu->pwms[_pwm->hwpwm];
> > +
> > + return pwm->pdata == NULL ? -EPROBE_DEFER : 0;
> > +}
>
> If you use the same method as the pwm-bfin or pwm-atmel-tcb drivers, you
> could initialize each PWM channel here and associated them with the PWM
> device using pwm_set_chip_data() (as I hinted at earlier).
>
> > +static int tpu_pwm_config(struct pwm_chip *chip, struct pwm_device *_pwm,
> > + int duty_ns, int period_ns)
>
> [...]
>
> > + if (period_ns <= 0 || duty_ns < 0 || duty_ns > period_ns)
> > + return -EINVAL;
>
> The core already performs these checks so they can be dropped.

Good point.

> > + /* Pick a prescaler to avoid overflowing the counter.
> > + * TODO: Pick the highest acceptable prescaler.
> > + */
> > + clk_prepare_enable(tpu->clk);
>
> Shouldn't you check the return value here?

I will.

> > + clk_rate = clk_get_rate(tpu->clk);
> > + clk_disable_unprepare(pwm->tpu->clk);
>
> And does the clock really need to be enabled to obtain the rate?

Actually it doesn't seem so. I'll test that and remove the enable/disable
calls if possible.

> > + for (prescaler = 0; prescaler < ARRAY_SIZE(prescalers); ++prescaler)
{
> > + period = clk_rate / prescalers[prescaler]
> > + / (NSEC_PER_SEC / period_ns);
>
> I prefer to have the operator on the previous line, as in:
>
> period = clk_rate / prescalers[prescaler] /
> (NSEC_PER_SEC / period_ns);

And I prefer the opposite :-) I can change that if you insist.

> > + duty_only = pwm->prescaler == prescaler && pwm->period == period;
>
> Maybe the following would be easier to read?
>
> if (prescaler == pwm->prescaler && period == pwm->period)
> duty_only = true;
>
> And initialize duty_only = false when declaring it.

I agree, I'll change that.

> > +static int tpu_probe(struct platform_device *pdev)
> > +{
> > + struct tpu_pwm_platform_data *pdata = pdev->dev.platform_data;
> > + struct tpu_device *tpu;
> > + struct resource *res;
> > + unsigned int i;
> > + int ret;
> > +
> > + if (!pdata) {
> > + dev_err(&pdev->dev, "missing platform data\n");
> > + return -ENXIO;
> > + }
> > +
> > + tpu = devm_kzalloc(&pdev->dev, sizeof(*tpu), GFP_KERNEL);
> > + if (tpu == NULL) {
> > + dev_err(&pdev->dev, "failed to allocate driver data\n");
> > + return -ENOMEM;
> > + }
> > +
> > + /* Map memory, get clock and pin control. */
> > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > + if (!res) {
> > + dev_err(&pdev->dev, "failed to get I/O memory\n");
> > + return -ENXIO;
> > + }
> > +
> > + tpu->base = devm_ioremap_nocache(&pdev->dev, res->start,
> > + resource_size(res));
> > + if (tpu->base == NULL) {
> > + dev_err(&pdev->dev, "failed to remap I/O memory\n");
> > + return -ENXIO;
> > + }
>
> Isn't this mising a request_mem_region()? Couldn't you just use a call
> to devm_ioremap_resource() instead?

I will do so.

> > +static struct platform_driver tpu_driver = {
> > + .probe = tpu_probe,
> > + .remove = tpu_remove,
> > + .driver = {
> > + .name = "renesas_tpu_pwm",
>
> Can this perhaps be renamed to "renesas-tpu-pwm" for consistency with
> other drivers?

Sure.

> And I think this is missing
>
> .owner = THIS_MODULE,
>
> as well. I know not all drivers have this either, but I have that on my
> TODO already.

Indeed. There was a discussion not too long ago on the linux arm kernel
mailing list about setting the owner field in the module_platform_driver()
macro (possibly by turning platform_register_driver() into a macro that sets
the owner field). I think that's a good idea, but I'll initialize .owner here
in the meantime.

> > diff --git a/include/linux/platform_data/pwm-renesas-tpu.h
> > b/include/linux/platform_data/pwm-renesas-tpu.h
> [...]
>
> > +#define TPU_CHANNEL_MAX 4
> > +
> > +#define TPU_PWM_ID(device, channel) \
> > + ((device) * TPU_CHANNEL_MAX + (channel))
>
> Please don't do this. It assumes a global namespace for PWM devices.
> However the global namespace is only for compatibility with legacy code
> and shouldn't be depended on by new drivers. You should be using either
> DT to dynamically refer to PWM devices or use a PWM lookup table. Refer
> to Documentation/pwm.txt for details.

The goal is to move everything to DT. In the meantime I'll use a lookup table.
>
> > +struct tpu_pwm_channel_data {
> > + bool enabled;
> > + bool active_low;
>
> Maybe this should be enum pwm_polarity?

Good idea. I will also add support for the .set_polarity() operation.

> > +};
> > +
> > +struct tpu_pwm_platform_data {
> > + struct tpu_pwm_channel_data channels[TPU_CHANNEL_MAX];
> > +};
>
> This could be a little difficult to handle in the absence of
> TPU_CHANNEL_MAX. Depending on the hardware, I suppose you could just
> handle it via the .request() function. In that case all channels would
> be disabled by default and enabled automatically when requested by a
> user driver.

I would still need to pass the initial polarity configuration for each
channel, although we could argue that the client driver should be responsible
for configuring the polarity.

--
Regards,

Laurent Pinchart

2013-06-12 10:06:55

by Thierry Reding

[permalink] [raw]
Subject: Re: [PATCH v2 04/11] pwm: Add Renesas TPU PWM driver

On Wed, May 29, 2013 at 05:48:50PM +0200, Laurent Pinchart wrote:
> Hi Thierry,
>
> On Thursday 23 May 2013 23:45:17 Thierry Reding wrote:
> > On Wed, Apr 24, 2013 at 10:50:09PM +0200, Laurent Pinchart wrote:
[...]
> > > +struct tpu_device {
> > > + struct platform_device *pdev;
> > > + struct pwm_chip chip;
> > > + spinlock_t lock;
> > > +
> > > + void __iomem *base;
> > > + struct clk *clk;
> > > +
> > > + struct tpu_pwm_device pwms[TPU_CHANNEL_MAX];
> > > +};
> >
> > Can't you reuse the infrastructure built into the PWM subsystem? You can
> > associate chip-specific data with each PWM device. You can look at the
> > pwm-atmel-tcb and pwm-bfin drivers for usage examples. In a nutshell you
> > hook the .request() function and setup the driver-specific structure and
> > associate them with the PWM using pwm_set_chip_data().
> >
> > This has the advantage that you don't need the pwms array in tpu_device
> > and you also don't need TPU_CHANNEL_MAX because only the pwm_chip.npwm
> > field needs to contain the number of channels.
>
> I've actually thought about that, but decided not to do so. It looked pretty
> weird to allocate PWM devices at .request() time, so I decided to allocate the
> devices once only at probe time. Is it considered better to allocate/free PWM
> devices every time they're requested/released ?

Well, I consider it better because it postpones memory allocation until
it is actually used. Typically requesting a PWM device happens at probe
time of other drivers so it isn't actually as bad as it may sound. Also
allocating at request time allows you to easily associate the data with
the PWM device using pwm_set_chip_data(), which was intended to be used
for exactly this purpose.

Doing so will keep the driver-specific data in a well-defined location
instead of putting it somewhere driver-specific.

Thierry


Attachments:
(No filename) (1.81 kB)
(No filename) (836.00 B)
Download all attachments

2013-06-13 15:32:21

by Laurent Pinchart

[permalink] [raw]
Subject: Re: [PATCH v2 04/11] pwm: Add Renesas TPU PWM driver

Hi Thierry,

On Wednesday 12 June 2013 12:06:49 Thierry Reding wrote:
> On Wed, May 29, 2013 at 05:48:50PM +0200, Laurent Pinchart wrote:
> > On Thursday 23 May 2013 23:45:17 Thierry Reding wrote:
> > > On Wed, Apr 24, 2013 at 10:50:09PM +0200, Laurent Pinchart wrote:
> [...]
>
> > > > +struct tpu_device {
> > > > + struct platform_device *pdev;
> > > > + struct pwm_chip chip;
> > > > + spinlock_t lock;
> > > > +
> > > > + void __iomem *base;
> > > > + struct clk *clk;
> > > > +
> > > > + struct tpu_pwm_device pwms[TPU_CHANNEL_MAX];
> > > > +};
> > >
> > > Can't you reuse the infrastructure built into the PWM subsystem? You can
> > > associate chip-specific data with each PWM device. You can look at the
> > > pwm-atmel-tcb and pwm-bfin drivers for usage examples. In a nutshell you
> > > hook the .request() function and setup the driver-specific structure and
> > > associate them with the PWM using pwm_set_chip_data().
> > >
> > > This has the advantage that you don't need the pwms array in tpu_device
> > > and you also don't need TPU_CHANNEL_MAX because only the pwm_chip.npwm
> > > field needs to contain the number of channels.
> >
> > I've actually thought about that, but decided not to do so. It looked
> > pretty weird to allocate PWM devices at .request() time, so I decided to
> > allocate the devices once only at probe time. Is it considered better to
> > allocate/free PWM devices every time they're requested/released ?
>
> Well, I consider it better because it postpones memory allocation until
> it is actually used. Typically requesting a PWM device happens at probe
> time of other drivers so it isn't actually as bad as it may sound. Also
> allocating at request time allows you to easily associate the data with
> the PWM device using pwm_set_chip_data(), which was intended to be used
> for exactly this purpose.
>
> Doing so will keep the driver-specific data in a well-defined location
> instead of putting it somewhere driver-specific.

OK, I'll try to fix that. For now I'll still need to expose TPU_CHANNEL_MAX to
boards for polarity configuration in platform data. That will go away when all
users will be converted to DT.

--
Regards,

Laurent Pinchart


Attachments:
signature.asc (490.00 B)
This is a digitally signed message part.