Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* [PATCH] backlight: pwm_bl: Simplify usage of devm_gpiod_get_optional
From: Axel Lin @ 2015-05-16 14:08 UTC (permalink / raw)
  To: linux-pwm, linux-fbdev
  Cc: Thierry Reding, Alexandre Courbot, Jingoo Han, Lee Jones

Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions),
the gpiod_get* functions take an additional parameter that allows to
specify direction and initial value for output.
Simplify the usage of devm_gpiod_get_optional accordingly.

Signed-off-by: Axel Lin <axel.lin@ingics.com>
---
 drivers/video/backlight/pwm_bl.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 3a145a6..57cb9ec 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -241,7 +241,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 	pb->dev = &pdev->dev;
 	pb->enabled = false;
 
-	pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable");
+	pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
+						  GPIOD_OUT_HIGH);
 	if (IS_ERR(pb->enable_gpio)) {
 		ret = PTR_ERR(pb->enable_gpio);
 		goto err_alloc;
@@ -263,9 +264,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 		pb->enable_gpio = gpio_to_desc(data->enable_gpio);
 	}
 
-	if (pb->enable_gpio)
-		gpiod_direction_output(pb->enable_gpio, 1);
-
 	pb->power_supply = devm_regulator_get(&pdev->dev, "power");
 	if (IS_ERR(pb->power_supply)) {
 		ret = PTR_ERR(pb->power_supply);
-- 
2.1.0




^ permalink raw reply related

* [PATCH] staging: sm750fb: fix typo in fb_videomode Array
From: Michel von Czettritz @ 2015-05-16 19:31 UTC (permalink / raw)
  To: linux-fbdev

It appears that 'FB_SYNC_HOR_HIGH_ACT' should be assined to 'sync'
and 'FB_VMODE_NONINTERLACED' is a flag for 'vmode'.

In line 96 these flags are ORed and assigned to 'sync'.
Since 'FB_VMODE_NONINTERLACED' is zero, 'sync' will stay the same,
and due to C99 'vmode' is initialized to zero too.
Therefore this doesn't have any implications for runtime-behavior,
but seems to be semantically wrong.

The Patch simply changes the | to a coma. Please check if this is correct.

Signed-off-by: Michel von Czettritz <michel.von.czettritz@gmail.com>
---
 drivers/staging/sm750fb/sm750.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c
index 77310ff..8ff29c6 100644
--- a/drivers/staging/sm750fb/sm750.c
+++ b/drivers/staging/sm750fb/sm750.c
@@ -94,7 +94,8 @@ static const struct fb_videomode lynx750_ext[] = {
 	 FB_VMODE_NONINTERLACED},
 
 	{NULL, 60, 1360, 768, 11804, 208, 64, 23, 1, 144, 3,
-	 FB_SYNC_HOR_HIGH_ACT|FB_VMODE_NONINTERLACED},
+	 FB_SYNC_HOR_HIGH_ACT,
+	 FB_VMODE_NONINTERLACED},
 
 	/*	1360 x 768	[1.77083:1]	*/
 	{NULL,  60, 1360, 768, 11804, 208,  64, 23, 1, 144, 3,
-- 
2.3.7


^ permalink raw reply related

* [PATCH] uvesafb: make scaling configurable on Nvidia cards
From: Mikulas Patocka @ 2015-05-17  6:56 UTC (permalink / raw)
  To: Michal Januszewski
  Cc: linux-fbdev, Jean-Christophe Plagniol-Villard, Tomi Valkeinen,
	linux-kernel

uvesafb: make scaling configurable on Nvidia cards

Nvidia cards have a BIOS function 0x4f14 that allows to set flat panel
scaling. This patch adds a module parameter "scaling" that uses this
function to set the scaling. By default, the parameter is -1, so that the
driver doesn't attempt to call the scaling function.

This patch is useful when using the binary Nvidia graphics driver - in
that case, the console may be only in text mode or VESA mode. By default,
the video card does scaling that degrades font quality and changes aspect
ratio. This patch makes it possible to turn off the scaling and improve
font quality on the console.

The allowed values depend on VESA BIOS. On my card, the following values
are allowed:
-1	- do not change the scaling
0	- scale to full screen
1, 2	- don't scale
3	- scale and preserve aspect ratio
4	- scale with black border around

Example use:
echo 1 >/sys/module/uvesafb/parameters/scaling; fbset 1280x1024-60 -depth 32 -a
- this sets unscaled 1280x1024 video mode that has much sharper font than
  the scaled modes.

I'm suggesting to backport this to stable kernels. The patch doesn't
really fix a bug, but it enhances user experience significantly - the
unscaled console font looks much better than the scaled font. By default,
the patch does nothing, so it can't break any existing system.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Cc: stable@vger.kernel.org

Index: linux-2.6/drivers/video/fbdev/uvesafb.c
=================================--- linux-2.6.orig/drivers/video/fbdev/uvesafb.c
+++ linux-2.6/drivers/video/fbdev/uvesafb.c
@@ -52,6 +52,7 @@ static u16 maxclk;		/* maximum pixel clo
 static u16 maxvf;		/* maximum vertical frequency */
 static u16 maxhf;		/* maximum horizontal frequency */
 static u16 vbemode;		/* force use of a specific VBE mode */
+static short scaling = -1;
 static char *mode_option;
 static u8  dac_width	= 6;
 
@@ -1245,7 +1246,22 @@ static int uvesafb_set_par(struct fb_inf
 	task = uvesafb_prep();
 	if (!task)
 		return -ENOMEM;
+
+	if (scaling > 0) {
+		/*
+		 * We must first reset scaling state with 0. This is workaround
+		 * for some supposed BIOS bug - without this, scaling mode 4
+		 * could not be set.
+		 */
+		uvesafb_reset(task);
+		task->t.regs.eax = 0x4f14;
+		task->t.regs.ebx = 0x0102;
+		task->t.regs.ecx = 0;
+		uvesafb_exec(task);
+	}
+
 setmode:
+	uvesafb_reset(task);
 	task->t.regs.eax = 0x4f02;
 	task->t.regs.ebx = mode->mode_id | 0x4000;	/* use LFB */
 
@@ -1296,7 +1312,6 @@ setmode:
 			printk(KERN_WARNING "uvesafb: mode switch failed "
 				"(eax=0x%x, err=%d). Trying again with "
 				"default timings.\n", task->t.regs.eax, err);
-			uvesafb_reset(task);
 			kfree(crtc);
 			crtc = NULL;
 			info->var.pixclock = 0;
@@ -1330,6 +1345,14 @@ setmode:
 				FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
 	info->fix.line_length = mode->bytes_per_scan_line;
 
+	if (scaling >= 0) {
+		uvesafb_reset(task);
+		task->t.regs.eax = 0x4f14;
+		task->t.regs.ebx = 0x0102;
+		task->t.regs.ecx = scaling;
+		uvesafb_exec(task);
+	}
+
 out:
 	kfree(crtc);
 	uvesafb_free(task);
@@ -2019,6 +2042,9 @@ MODULE_PARM_DESC(vbemode,
 	"VBE mode number to set, overrides the 'mode' option");
 module_param_string(v86d, v86d_path, PATH_MAX, 0660);
 MODULE_PARM_DESC(v86d, "Path to the v86d userspace helper.");
+module_param(scaling, short, 0660);
+MODULE_PARM_DESC(scaling,
+	"Scaling option for nvidia (0 - scaled, 1 - unscaled centered, 2 - unscaled in left corner");
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Michal Januszewski <spock@gentoo.org>");
Index: linux-2.6/Documentation/fb/uvesafb.txt
=================================--- linux-2.6.orig/Documentation/fb/uvesafb.txt
+++ linux-2.6/Documentation/fb/uvesafb.txt
@@ -128,6 +128,14 @@ v86d:path
         need to use it and have uvesafb built into the kernel, use
         uvesafb.v86d="path".
 
+scaling:n
+	Set scaling on Nvidia cards. Possible values depend on card's BIOS.
+		-1	- do not change the scaling
+		0	- scale to full screen
+		1, 2	- don't scale
+		3	- scale and preserve aspect ratio
+		4	- scale with black border around
+
 Additionally, the following parameters may be provided.  They all override the
 EDID-provided values and BIOS defaults.  Refer to your monitor's specs to get
 the correct values for maxhf, maxvf and maxclk for your hardware.

^ permalink raw reply

* [PATCH v3 00/17] new LoCoMo driver set
From: Dmitry Eremin-Solenikov @ 2015-05-17 16:27 UTC (permalink / raw)
  To: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Dmitry Torokhov, Bryan Wu,
	Richard Purdie, Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami
  Cc: linux-arm-kernel, linux-gpio, linux-input, linux-leds, linux-spi,
	linux-fbdev, alsa-devel

Sharp Zaurus SL-5500 and SL-5600 use special companion Gate Array.
With this patchset I tried to modernise and restructure the LoCoMo drivers.

* Use platform bus and mfd core code
* Use GPIO API instead of custom locomo GPIO code
* Use irqdomains to manage IRQs
* Split mixed locomolcd driver to lcd and backlight parts
* Implement IRQ handling in GPIO driver
* Implement SPI driver used as a host for mmc_spi device to control SD cards

Changes since V2:
* Implemented most of review findings (lots of small changes)
* Added comments where the review feedback was ignored

The following changes since commit b787f68c36d49bb1d9236f403813641efa74a031:

  Linux 4.1-rc1 (2015-04-26 17:59:10 -0700)

are available in the git repository at:

  git://git.infradead.org/users/dbaryshkov/zaurus.git locomo-v3

for you to fetch changes up to c7405f110836863287c505650ac2133fecabea7b:

  ARM: drop old LoCoMo driver (2015-05-17 19:23:20 +0300)

----------------------------------------------------------------
Dmitry Eremin-Solenikov (17):
      mfd: add new driver for Sharp LoCoMo
      leds: port locomo leds driver to new locomo core
      input: convert LoCoMo keyboard driver to use new locomo core
      input: make LoCoMo keyboard driver support both poodle and collie
      video: backlight: add new locomo backlight driver
      video: lcd: add LoCoMo LCD driver
      gpio: port LoCoMo gpio support from old driver
      gpio: locomo: implement per-pin irq handling
      spi: add locomo SPI driver
      i2c: add locomo i2c driver
      ARM: sa1100: make collie use new locomo drivers
      ARM: sa1100: don't preallocate IRQ space for locomo
      ASoC: pxa: poodle: make use of new locomo GPIO interface
      ARM: pxa: poodle: use new LoCoMo driver
      ARM: pxa: poodle: don't preallocate IRQ space for locomo
      video: backlight: drop old locomo bl/lcd driver
      ARM: drop old LoCoMo driver

 arch/arm/common/Kconfig                    |   3 -
 arch/arm/common/Makefile                   |   1 -
 arch/arm/common/locomo.c                   | 914 -----------------------------
 arch/arm/include/asm/hardware/locomo.h     | 221 -------
 arch/arm/mach-pxa/Kconfig                  |   1 -
 arch/arm/mach-pxa/include/mach/poodle.h    |   8 +-
 arch/arm/mach-pxa/poodle.c                 |  58 +-
 arch/arm/mach-sa1100/Kconfig               |   1 -
 arch/arm/mach-sa1100/collie.c              | 213 +++++--
 arch/arm/mach-sa1100/include/mach/collie.h |  16 +-
 arch/arm/mach-sa1100/include/mach/irqs.h   |  19 +-
 drivers/gpio/Kconfig                       |  13 +
 drivers/gpio/Makefile                      |   1 +
 drivers/gpio/gpio-locomo.c                 | 285 +++++++++
 drivers/i2c/busses/Kconfig                 |  12 +
 drivers/i2c/busses/Makefile                |   1 +
 drivers/i2c/busses/i2c-locomo.c            | 135 +++++
 drivers/input/keyboard/Kconfig             |   2 +-
 drivers/input/keyboard/locomokbd.c         | 264 ++++-----
 drivers/leds/Kconfig                       |   2 +-
 drivers/leds/leds-locomo.c                 | 117 ++--
 drivers/mfd/Kconfig                        |  10 +
 drivers/mfd/Makefile                       |   1 +
 drivers/mfd/locomo.c                       | 346 +++++++++++
 drivers/spi/Kconfig                        |  10 +
 drivers/spi/Makefile                       |   1 +
 drivers/spi/spi-locomo.c                   | 332 +++++++++++
 drivers/video/backlight/Kconfig            |  16 +-
 drivers/video/backlight/Makefile           |   3 +-
 drivers/video/backlight/locomo_bl.c        | 153 +++++
 drivers/video/backlight/locomo_lcd.c       | 285 +++++++++
 drivers/video/backlight/locomolcd.c        | 255 --------
 include/linux/mfd/locomo.h                 | 167 ++++++
 sound/soc/pxa/poodle.c                     |  52 +-
 34 files changed, 2216 insertions(+), 1702 deletions(-)
 delete mode 100644 arch/arm/common/locomo.c
 delete mode 100644 arch/arm/include/asm/hardware/locomo.h
 create mode 100644 drivers/gpio/gpio-locomo.c
 create mode 100644 drivers/i2c/busses/i2c-locomo.c
 create mode 100644 drivers/mfd/locomo.c
 create mode 100644 drivers/spi/spi-locomo.c
 create mode 100644 drivers/video/backlight/locomo_bl.c
 create mode 100644 drivers/video/backlight/locomo_lcd.c
 delete mode 100644 drivers/video/backlight/locomolcd.c
 create mode 100644 include/linux/mfd/locomo.h

-- 
With best wishes
Dmitry


^ permalink raw reply

* [PATCH v3 02/17] leds: port locomo leds driver to new locomo core
From: Dmitry Eremin-Solenikov @ 2015-05-17 16:27 UTC (permalink / raw)
  To: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Dmitry Torokhov, Bryan Wu,
	Richard Purdie, Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami
  Cc: linux-arm-kernel, linux-gpio, linux-input, linux-leds, linux-spi,
	linux-fbdev, alsa-devel
In-Reply-To: <1431880077-26321-1-git-send-email-dbaryshkov@gmail.com>

Adapt locomo leds driver to new locomo core setup.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
 drivers/leds/Kconfig       |   2 +-
 drivers/leds/leds-locomo.c | 117 +++++++++++++++++++++++----------------------
 2 files changed, 61 insertions(+), 58 deletions(-)

diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 966b960..d086aac 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -79,7 +79,7 @@ config LEDS_LM3642
 config LEDS_LOCOMO
 	tristate "LED Support for Locomo device"
 	depends on LEDS_CLASS
-	depends on SHARP_LOCOMO
+	depends on MFD_LOCOMO
 	help
 	  This option enables support for the LEDs on Sharp Locomo.
 	  Zaurus models SL-5500 and SL-5600.
diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c
index 80ba048..a4286e9 100644
--- a/drivers/leds/leds-locomo.c
+++ b/drivers/leds/leds-locomo.c
@@ -9,89 +9,92 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
 #include <linux/leds.h>
+#include <linux/mfd/locomo.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
 
-#include <mach/hardware.h>
-#include <asm/hardware/locomo.h>
+struct locomo_led {
+	struct led_classdev led;
+	struct regmap *regmap;
+	unsigned int reg;
+};
 
 static void locomoled_brightness_set(struct led_classdev *led_cdev,
-				enum led_brightness value, int offset)
-{
-	struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->dev->parent);
-	unsigned long flags;
-
-	local_irq_save(flags);
-	if (value)
-		locomo_writel(LOCOMO_LPT_TOFH, locomo_dev->mapbase + offset);
-	else
-		locomo_writel(LOCOMO_LPT_TOFL, locomo_dev->mapbase + offset);
-	local_irq_restore(flags);
-}
-
-static void locomoled_brightness_set0(struct led_classdev *led_cdev,
 				enum led_brightness value)
 {
-	locomoled_brightness_set(led_cdev, value, LOCOMO_LPT0);
+	struct locomo_led *led = container_of(led_cdev, struct locomo_led, led);
+
+	regmap_write(led->regmap, led->reg,
+			value ? LOCOMO_LPT_TOFH : LOCOMO_LPT_TOFL);
 }
 
-static void locomoled_brightness_set1(struct led_classdev *led_cdev,
-				enum led_brightness value)
+static int locomo_led_register(
+		struct device *dev,
+		struct locomo_led *led,
+		const char *name,
+		const char *trigger,
+		struct regmap *regmap,
+		unsigned int reg)
 {
-	locomoled_brightness_set(led_cdev, value, LOCOMO_LPT1);
+	led->led.name = name;
+	led->led.flags = LED_CORE_SUSPENDRESUME;
+	led->led.default_trigger = trigger;
+	led->led.brightness_set = locomoled_brightness_set;
+	led->regmap = regmap;
+	led->reg = reg;
+
+	return devm_led_classdev_register(dev, &led->led);
 }
 
-static struct led_classdev locomo_led0 = {
-	.name			= "locomo:amber:charge",
-	.default_trigger	= "main-battery-charging",
-	.brightness_set		= locomoled_brightness_set0,
-};
-
-static struct led_classdev locomo_led1 = {
-	.name			= "locomo:green:mail",
-	.default_trigger	= "nand-disk",
-	.brightness_set		= locomoled_brightness_set1,
-};
-
-static int locomoled_probe(struct locomo_dev *ldev)
+static int locomoled_probe(struct platform_device *pdev)
 {
 	int ret;
-
-	ret = led_classdev_register(&ldev->dev, &locomo_led0);
+	struct locomo_led *leds;
+	struct regmap *regmap;
+
+	leds = devm_kzalloc(&pdev->dev, 2 * sizeof(*leds), GFP_KERNEL);
+	if (!leds)
+		return -ENOMEM;
+
+	regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!regmap)
+		return -ENODEV;
+
+	ret = locomo_led_register(
+			&pdev->dev,
+			leds,
+			"locomo:amber:charge",
+			"main-battery-charging",
+			regmap,
+			LOCOMO_LPT0);
 	if (ret < 0)
 		return ret;
 
-	ret = led_classdev_register(&ldev->dev, &locomo_led1);
+	ret = locomo_led_register(
+			&pdev->dev,
+			leds + 1,
+			"locomo:green:mail",
+			"mmc0",
+			regmap,
+			LOCOMO_LPT1);
 	if (ret < 0)
-		led_classdev_unregister(&locomo_led0);
-
-	return ret;
-}
+		return ret;
 
-static int locomoled_remove(struct locomo_dev *dev)
-{
-	led_classdev_unregister(&locomo_led0);
-	led_classdev_unregister(&locomo_led1);
 	return 0;
 }
 
-static struct locomo_driver locomoled_driver = {
-	.drv = {
-		.name = "locomoled"
+static struct platform_driver locomoled_driver = {
+	.driver = {
+		.name = "locomo-led"
 	},
-	.devid	= LOCOMO_DEVID_LED,
 	.probe	= locomoled_probe,
-	.remove	= locomoled_remove,
 };
 
-static int __init locomoled_init(void)
-{
-	return locomo_driver_register(&locomoled_driver);
-}
-module_init(locomoled_init);
+module_platform_driver(locomoled_driver);
 
 MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
 MODULE_DESCRIPTION("Locomo LED driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:locomo-led");
-- 
2.1.4


^ permalink raw reply related

* [PATCH v3 03/17] input: convert LoCoMo keyboard driver to use new locomo core
From: Dmitry Eremin-Solenikov @ 2015-05-17 16:27 UTC (permalink / raw)
  To: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Dmitry Torokhov, Bryan Wu,
	Richard Purdie, Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami
  Cc: linux-arm-kernel, linux-gpio, linux-input, linux-leds, linux-spi,
	linux-fbdev, alsa-devel
In-Reply-To: <1431880077-26321-1-git-send-email-dbaryshkov@gmail.com>

As LoCoMo is switching to new device model, adapt keyboard driver to
support new locomo core driver.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
 drivers/input/keyboard/Kconfig     |   2 +-
 drivers/input/keyboard/locomokbd.c | 256 ++++++++++++++++++-------------------
 2 files changed, 125 insertions(+), 133 deletions(-)

diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 106fbac..9a20487 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -337,7 +337,7 @@ config KEYBOARD_LM8333
 
 config KEYBOARD_LOCOMO
 	tristate "LoCoMo Keyboard Support"
-	depends on SHARP_LOCOMO
+	depends on MFD_LOCOMO
 	help
 	  Say Y here if you are running Linux on a Sharp Zaurus Collie or Poodle based PDA
 
diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
index c94d610..1657bc0 100644
--- a/drivers/input/keyboard/locomokbd.c
+++ b/drivers/input/keyboard/locomokbd.c
@@ -23,28 +23,25 @@
  *
  */
 
-#include <linux/slab.h>
-#include <linux/module.h>
+#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/input.h>
-#include <linux/delay.h>
-#include <linux/device.h>
 #include <linux/interrupt.h>
-#include <linux/ioport.h>
-
-#include <asm/hardware/locomo.h>
-#include <asm/irq.h>
-
-MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
-MODULE_DESCRIPTION("LoCoMo keyboard driver");
-MODULE_LICENSE("GPL");
-
-#define LOCOMOKBD_NUMKEYS	128
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/mfd/locomo.h>
 
 #define KEY_ACTIVITY		KEY_F16
 #define KEY_CONTACT		KEY_F18
 #define KEY_CENTER		KEY_F15
 
+#define KB_ROWS			16
+#define KB_COLS			8
+#define LOCOMOKBD_NUMKEYS	(KB_ROWS * KB_COLS)
+#define SCANCODE(c, r)		(((c)<<4) + (r) + 1)
+
 static const unsigned char
 locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
 	0, KEY_ESC, KEY_ACTIVITY, 0, 0, 0, 0, 0, 0, 0,				/* 0 - 9 */
@@ -53,7 +50,7 @@ locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
 	0, 0, 0, KEY_CENTER, 0, KEY_MAIL, 0, 0, 0, 0,				/* 30 - 39 */
 	0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RIGHT,					/* 40 - 49 */
 	KEY_UP, KEY_LEFT, 0, 0, KEY_P, 0, KEY_O, KEY_I, KEY_Y, KEY_T,		/* 50 - 59 */
-	KEY_E, KEY_W, 0, 0, 0, 0, KEY_DOWN, KEY_ENTER, 0, 0,			/* 60 - 69 */
+	KEY_E, KEY_W, 0, 0, 0, 0, KEY_DOWN, KEY_KPENTER, 0, 0,			/* 60 - 69 */
 	KEY_BACKSPACE, 0, KEY_L, KEY_U, KEY_H, KEY_R, KEY_D, KEY_Q, 0, 0,	/* 70 - 79 */
 	0, 0, 0, 0, 0, 0, KEY_ENTER, KEY_RIGHTSHIFT, KEY_K, KEY_J,		/* 80 - 89 */
 	KEY_G, KEY_F, KEY_X, KEY_S, 0, 0, 0, 0, 0, 0,				/* 90 - 99 */
@@ -62,20 +59,14 @@ locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
 	KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0		/* 120 - 128 */
 };
 
-#define KB_ROWS			16
-#define KB_COLS			8
-#define KB_ROWMASK(r)		(1 << (r))
-#define SCANCODE(c,r)		( ((c)<<4) + (r) + 1 )
-
 #define KB_DELAY		8
-#define SCAN_INTERVAL		(HZ/10)
 
 struct locomokbd {
 	unsigned char keycode[LOCOMOKBD_NUMKEYS];
 	struct input_dev *input;
-	char phys[32];
 
-	unsigned long base;
+	struct regmap *regmap;
+	int irq;
 	spinlock_t lock;
 
 	struct timer_list timer;
@@ -84,37 +75,33 @@ struct locomokbd {
 };
 
 /* helper functions for reading the keyboard matrix */
-static inline void locomokbd_charge_all(unsigned long membase)
+static void locomokbd_charge_all(struct locomokbd *locomokbd)
 {
-	locomo_writel(0x00FF, membase + LOCOMO_KSC);
+	regmap_write(locomokbd->regmap, LOCOMO_KSC, 0x00ff);
 }
 
-static inline void locomokbd_activate_all(unsigned long membase)
+static void locomokbd_activate_all(struct locomokbd *locomokbd)
 {
-	unsigned long r;
-
-	locomo_writel(0, membase + LOCOMO_KSC);
-	r = locomo_readl(membase + LOCOMO_KIC);
-	r &= 0xFEFF;
-	locomo_writel(r, membase + LOCOMO_KIC);
+	regmap_write(locomokbd->regmap, LOCOMO_KSC, 0);
+	regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x100, 0);
 }
 
-static inline void locomokbd_activate_col(unsigned long membase, int col)
+static void locomokbd_activate_col(struct locomokbd *locomokbd, int col)
 {
 	unsigned short nset;
 	unsigned short nbset;
 
-	nset = 0xFF & ~(1 << col);
+	nset = 0xFF & ~BIT(col);
 	nbset = (nset << 8) + nset;
-	locomo_writel(nbset, membase + LOCOMO_KSC);
+	regmap_write(locomokbd->regmap, LOCOMO_KSC, nbset);
 }
 
-static inline void locomokbd_reset_col(unsigned long membase, int col)
+static void locomokbd_reset_col(struct locomokbd *locomokbd, int col)
 {
 	unsigned short nbset;
 
-	nbset = ((0xFF & ~(1 << col)) << 8) + 0xFF;
-	locomo_writel(nbset, membase + LOCOMO_KSC);
+	nbset = ((0xFF & ~BIT(col)) << 8) + 0xFF;
+	regmap_write(locomokbd->regmap, LOCOMO_KSC, nbset);
 }
 
 /*
@@ -129,24 +116,25 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd)
 	unsigned int row, col, rowd;
 	unsigned long flags;
 	unsigned int num_pressed;
-	unsigned long membase = locomokbd->base;
+	bool esc_pressed = false;
 
 	spin_lock_irqsave(&locomokbd->lock, flags);
 
-	locomokbd_charge_all(membase);
+	locomokbd_charge_all(locomokbd);
 
 	num_pressed = 0;
 	for (col = 0; col < KB_COLS; col++) {
-
-		locomokbd_activate_col(membase, col);
+		udelay(KB_DELAY);
+		locomokbd_activate_col(locomokbd, col);
 		udelay(KB_DELAY);
 
-		rowd = ~locomo_readl(membase + LOCOMO_KIB);
+		regmap_read(locomokbd->regmap, LOCOMO_KIB, &rowd);
+		rowd = ~rowd;
 		for (row = 0; row < KB_ROWS; row++) {
 			unsigned int scancode, pressed, key;
 
 			scancode = SCANCODE(col, row);
-			pressed = rowd & KB_ROWMASK(row);
+			pressed = rowd & BIT(row);
 			key = locomokbd->keycode[scancode];
 
 			input_report_key(locomokbd->input, key, pressed);
@@ -158,30 +146,32 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd)
 			/* The "Cancel/ESC" key is labeled "On/Off" on
 			 * Collie and Poodle and should suspend the device
 			 * if it was pressed for more than a second. */
-			if (unlikely(key = KEY_ESC)) {
-				if (!time_after(jiffies,
-					locomokbd->suspend_jiffies + HZ))
-					continue;
-				if (locomokbd->count_cancel++
-					!= (HZ/SCAN_INTERVAL + 1))
-					continue;
-				input_event(locomokbd->input, EV_PWR,
-					KEY_SUSPEND, 1);
-				locomokbd->suspend_jiffies = jiffies;
-			} else
-				locomokbd->count_cancel = 0;
+			if (unlikely(key = KEY_ESC))
+				esc_pressed = true;
 		}
-		locomokbd_reset_col(membase, col);
+		locomokbd_reset_col(locomokbd, col);
 	}
-	locomokbd_activate_all(membase);
+	locomokbd_activate_all(locomokbd);
 
 	input_sync(locomokbd->input);
 
 	/* if any keys are pressed, enable the timer */
 	if (num_pressed)
-		mod_timer(&locomokbd->timer, jiffies + SCAN_INTERVAL);
+		mod_timer(&locomokbd->timer, jiffies + msecs_to_jiffies(100));
 	else
+		regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x10, 0x10);
+
+
+	if (esc_pressed && time_after(jiffies,
+		    locomokbd->suspend_jiffies + msecs_to_jiffies(1000))) {
+		if (locomokbd->count_cancel++ > 20) {
+			input_event(locomokbd->input, EV_PWR,
+					KEY_SUSPEND, 1);
+			locomokbd->suspend_jiffies = jiffies;
+		}
+	} else {
 		locomokbd->count_cancel = 0;
+	}
 
 	spin_unlock_irqrestore(&locomokbd->lock, flags);
 }
@@ -192,18 +182,17 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd)
 static irqreturn_t locomokbd_interrupt(int irq, void *dev_id)
 {
 	struct locomokbd *locomokbd = dev_id;
-	u16 r;
+	unsigned int r;
 
-	r = locomo_readl(locomokbd->base + LOCOMO_KIC);
+	regmap_read(locomokbd->regmap, LOCOMO_KIC, &r);
 	if ((r & 0x0001) = 0)
 		return IRQ_HANDLED;
 
-	locomo_writel(r & ~0x0100, locomokbd->base + LOCOMO_KIC); /* Ack */
+	/* Mask and Ack */
+	regmap_write(locomokbd->regmap, LOCOMO_KIC, r & ~0x110);
 
-	/** wait chattering delay **/
-	udelay(100);
+	mod_timer(&locomokbd->timer, jiffies + msecs_to_jiffies(1));
 
-	locomokbd_scankeyboard(locomokbd);
 	return IRQ_HANDLED;
 }
 
@@ -220,47 +209,39 @@ static void locomokbd_timer_callback(unsigned long data)
 static int locomokbd_open(struct input_dev *dev)
 {
 	struct locomokbd *locomokbd = input_get_drvdata(dev);
-	u16 r;
-	
-	r = locomo_readl(locomokbd->base + LOCOMO_KIC) | 0x0010;
-	locomo_writel(r, locomokbd->base + LOCOMO_KIC);
-	return 0;
+
+	return regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x10, 0x10);
 }
 
 static void locomokbd_close(struct input_dev *dev)
 {
 	struct locomokbd *locomokbd = input_get_drvdata(dev);
-	u16 r;
-	
-	r = locomo_readl(locomokbd->base + LOCOMO_KIC) & ~0x0010;
-	locomo_writel(r, locomokbd->base + LOCOMO_KIC);
+
+	regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x10, 0x0);
+
+	del_timer_sync(&locomokbd->timer);
 }
 
-static int locomokbd_probe(struct locomo_dev *dev)
+static int locomokbd_probe(struct platform_device *dev)
 {
 	struct locomokbd *locomokbd;
 	struct input_dev *input_dev;
 	int i, err;
 
-	locomokbd = kzalloc(sizeof(struct locomokbd), GFP_KERNEL);
-	input_dev = input_allocate_device();
-	if (!locomokbd || !input_dev) {
-		err = -ENOMEM;
-		goto err_free_mem;
-	}
+	locomokbd = devm_kzalloc(&dev->dev, sizeof(struct locomokbd),
+			GFP_KERNEL);
+	if (!locomokbd)
+		return -ENOMEM;
 
-	/* try and claim memory region */
-	if (!request_mem_region((unsigned long) dev->mapbase,
-				dev->length,
-				LOCOMO_DRIVER_NAME(dev))) {
-		err = -EBUSY;
-		printk(KERN_ERR "locomokbd: Can't acquire access to io memory for keyboard\n");
-		goto err_free_mem;
-	}
+	locomokbd->regmap = dev_get_regmap(dev->dev.parent, NULL);
+	if (!locomokbd->regmap)
+		return -EINVAL;
 
-	locomo_set_drvdata(dev, locomokbd);
+	locomokbd->irq = platform_get_irq(dev, 0);
+	if (locomokbd->irq < 0)
+		return -ENXIO;
 
-	locomokbd->base = (unsigned long) dev->mapbase;
+	platform_set_drvdata(dev, locomokbd);
 
 	spin_lock_init(&locomokbd->lock);
 
@@ -270,11 +251,13 @@ static int locomokbd_probe(struct locomo_dev *dev)
 
 	locomokbd->suspend_jiffies = jiffies;
 
-	locomokbd->input = input_dev;
-	strcpy(locomokbd->phys, "locomokbd/input0");
+	input_dev = devm_input_allocate_device(&dev->dev);
+	if (!input_dev)
+		return -ENOMEM;
 
+	locomokbd->input = input_dev;
 	input_dev->name = "LoCoMo keyboard";
-	input_dev->phys = locomokbd->phys;
+	input_dev->phys = "locomokbd/input0";
 	input_dev->id.bustype = BUS_HOST;
 	input_dev->id.vendor = 0x0001;
 	input_dev->id.product = 0x0001;
@@ -291,72 +274,81 @@ static int locomokbd_probe(struct locomo_dev *dev)
 
 	input_set_drvdata(input_dev, locomokbd);
 
-	memcpy(locomokbd->keycode, locomokbd_keycode, sizeof(locomokbd->keycode));
+	memcpy(locomokbd->keycode,
+			locomokbd_keycode,
+			sizeof(locomokbd->keycode));
+
 	for (i = 0; i < LOCOMOKBD_NUMKEYS; i++)
-		set_bit(locomokbd->keycode[i], input_dev->keybit);
-	clear_bit(0, input_dev->keybit);
+		input_set_capability(input_dev, EV_KEY, locomokbd->keycode[i]);
+	input_set_capability(input_dev, EV_PWR, KEY_SUSPEND);
+	__set_bit(EV_REP, input_dev->evbit);
+
+	regmap_write(locomokbd->regmap, LOCOMO_KCMD, 1);
+	regmap_write(locomokbd->regmap, LOCOMO_KSC, 0x0);
+	regmap_write(locomokbd->regmap, LOCOMO_KIC, 0x0);
 
 	/* attempt to get the interrupt */
-	err = request_irq(dev->irq[0], locomokbd_interrupt, 0, "locomokbd", locomokbd);
+	err = devm_request_irq(&dev->dev, locomokbd->irq, locomokbd_interrupt,
+			0, "locomokbd", locomokbd);
 	if (err) {
-		printk(KERN_ERR "locomokbd: Can't get irq for keyboard\n");
-		goto err_release_region;
+		dev_err(&dev->dev, "locomokbd: Can't get irq for keyboard\n");
+		return err;
 	}
 
 	err = input_register_device(locomokbd->input);
 	if (err)
-		goto err_free_irq;
+		return err;
 
 	return 0;
 
- err_free_irq:
-	free_irq(dev->irq[0], locomokbd);
- err_release_region:
-	release_mem_region((unsigned long) dev->mapbase, dev->length);
-	locomo_set_drvdata(dev, NULL);
- err_free_mem:
-	input_free_device(input_dev);
-	kfree(locomokbd);
-
 	return err;
 }
 
-static int locomokbd_remove(struct locomo_dev *dev)
+static int locomokbd_remove(struct platform_device *dev)
+{
+	return 0;
+}
+
+static int __maybe_unused locomokbd_suspend(struct device *dev)
 {
-	struct locomokbd *locomokbd = locomo_get_drvdata(dev);
+	struct locomokbd *locomokbd = dev_get_drvdata(dev);
 
-	free_irq(dev->irq[0], locomokbd);
+	regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x10, 0x0);
 
 	del_timer_sync(&locomokbd->timer);
 
-	input_unregister_device(locomokbd->input);
-	locomo_set_drvdata(dev, NULL);
+	return 0;
+}
 
-	release_mem_region((unsigned long) dev->mapbase, dev->length);
+static int __maybe_unused locomokbd_resume(struct device *dev)
+{
+	struct locomokbd *locomokbd = dev_get_drvdata(dev);
 
-	kfree(locomokbd);
+	regmap_write(locomokbd->regmap, LOCOMO_KCMD, 1);
+	regmap_write(locomokbd->regmap, LOCOMO_KSC, 0);
+	regmap_write(locomokbd->regmap, LOCOMO_KIC, 0x0);
+
+	/* Rescan keyboard only if we are open by somebody */
+	if (locomokbd->input->users)
+		locomokbd_scankeyboard(locomokbd);
 
 	return 0;
 }
 
-static struct locomo_driver keyboard_driver = {
-	.drv = {
-		.name = "locomokbd"
+static SIMPLE_DEV_PM_OPS(locomo_kbd_pm, locomokbd_suspend, locomokbd_resume);
+
+static struct platform_driver locomokbd_driver = {
+	.driver = {
+		.name	= "locomo-kbd",
+		.pm	= &locomo_kbd_pm,
 	},
-	.devid	= LOCOMO_DEVID_KEYBOARD,
 	.probe	= locomokbd_probe,
 	.remove	= locomokbd_remove,
 };
 
-static int __init locomokbd_init(void)
-{
-	return locomo_driver_register(&keyboard_driver);
-}
-
-static void __exit locomokbd_exit(void)
-{
-	locomo_driver_unregister(&keyboard_driver);
-}
+module_platform_driver(locomokbd_driver);
 
-module_init(locomokbd_init);
-module_exit(locomokbd_exit);
+MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
+MODULE_DESCRIPTION("LoCoMo keyboard driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:locomo-kbd");
-- 
2.1.4


^ permalink raw reply related

* [PATCH v3 04/17] input: make LoCoMo keyboard driver support both poodle and collie
From: Dmitry Eremin-Solenikov @ 2015-05-17 16:27 UTC (permalink / raw)
  To: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Dmitry Torokhov, Bryan Wu,
	Richard Purdie, Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw
In-Reply-To: <1431880077-26321-1-git-send-email-dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

Keyboards on collie and poodle differ only in wiring of 'Home' key.
Instead of complicating the driver with platform data, just check for
the machine for the time being. This will be converted to DTS property
sometime in the future.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
 drivers/input/keyboard/locomokbd.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
index 1657bc0..b422608 100644
--- a/drivers/input/keyboard/locomokbd.c
+++ b/drivers/input/keyboard/locomokbd.c
@@ -33,6 +33,9 @@
 #include <linux/slab.h>
 #include <linux/mfd/locomo.h>
 
+/* There is one minor difference between mappings on poodle and collie */
+#include <asm/mach-types.h>
+
 #define KEY_ACTIVITY		KEY_F16
 #define KEY_CONTACT		KEY_F18
 #define KEY_CENTER		KEY_F15
@@ -45,7 +48,7 @@
 static const unsigned char
 locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
 	0, KEY_ESC, KEY_ACTIVITY, 0, 0, 0, 0, 0, 0, 0,				/* 0 - 9 */
-	0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_HOME, KEY_CONTACT,			/* 10 - 19 */
+	0, 0, 0, 0, 0, 0, 0, KEY_MENU, 0, KEY_CONTACT,				/* 10 - 19 */
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,						/* 20 - 29 */
 	0, 0, 0, KEY_CENTER, 0, KEY_MAIL, 0, 0, 0, 0,				/* 30 - 39 */
 	0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RIGHT,					/* 40 - 49 */
@@ -278,6 +281,11 @@ static int locomokbd_probe(struct platform_device *dev)
 			locomokbd_keycode,
 			sizeof(locomokbd->keycode));
 
+	if (machine_is_collie())
+		locomokbd->keycode[18] = KEY_HOME;
+	else
+		locomokbd->keycode[3] = KEY_HOME;
+
 	for (i = 0; i < LOCOMOKBD_NUMKEYS; i++)
 		input_set_capability(input_dev, EV_KEY, locomokbd->keycode[i]);
 	input_set_capability(input_dev, EV_PWR, KEY_SUSPEND);
-- 
2.1.4


^ permalink raw reply related

* [PATCH v3 05/17] video: backlight: add new locomo backlight driver
From: Dmitry Eremin-Solenikov @ 2015-05-17 16:27 UTC (permalink / raw)
  To: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Dmitry Torokhov, Bryan Wu,
	Richard Purdie, Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami
  Cc: linux-arm-kernel, linux-gpio, linux-input, linux-leds, linux-spi,
	linux-fbdev, alsa-devel
In-Reply-To: <1431880077-26321-1-git-send-email-dbaryshkov@gmail.com>

Add new simple backlight driver - it cares only about PWM/frontlight
part of LoCoMo, it does not touch TFT settings and does not export TFT
power control.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
 drivers/video/backlight/Kconfig     |   6 +-
 drivers/video/backlight/Makefile    |   2 +-
 drivers/video/backlight/locomo_bl.c | 153 ++++++++++++++++++++++++++++++++++++
 3 files changed, 157 insertions(+), 4 deletions(-)
 create mode 100644 drivers/video/backlight/locomo_bl.c

diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 2d9923a..6c093e2 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -217,12 +217,12 @@ config BACKLIGHT_LM3533
 	  levels.
 
 config BACKLIGHT_LOCOMO
-	tristate "Sharp LOCOMO LCD/Backlight Driver"
-	depends on SHARP_LOCOMO
+	tristate "Sharp LOCOMO Backlight Driver"
+	depends on MFD_LOCOMO
 	default y
 	help
 	  If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to
-	  enable the LCD/backlight driver.
+	  enable the backlight driver.
 
 config BACKLIGHT_OMAP1
 	tristate "OMAP1 PWL-based LCD Backlight"
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index d67073f..2de73d2 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -39,7 +39,7 @@ obj-$(CONFIG_BACKLIGHT_IPAQ_MICRO)	+= ipaq_micro_bl.o
 obj-$(CONFIG_BACKLIGHT_LM3533)		+= lm3533_bl.o
 obj-$(CONFIG_BACKLIGHT_LM3630A)		+= lm3630a_bl.o
 obj-$(CONFIG_BACKLIGHT_LM3639)		+= lm3639_bl.o
-obj-$(CONFIG_BACKLIGHT_LOCOMO)		+= locomolcd.o
+obj-$(CONFIG_BACKLIGHT_LOCOMO)		+= locomo_bl.o
 obj-$(CONFIG_BACKLIGHT_LP855X)		+= lp855x_bl.o
 obj-$(CONFIG_BACKLIGHT_LP8788)		+= lp8788_bl.o
 obj-$(CONFIG_BACKLIGHT_LV5207LP)	+= lv5207lp.o
diff --git a/drivers/video/backlight/locomo_bl.c b/drivers/video/backlight/locomo_bl.c
new file mode 100644
index 0000000..cc60022
--- /dev/null
+++ b/drivers/video/backlight/locomo_bl.c
@@ -0,0 +1,153 @@
+/*
+ * Backlight control code for Sharp Zaurus SL-5500
+ *
+ * Copyright 2005 John Lenz <lenz@cs.wisc.edu>
+ * Maintainer: Pavel Machek <pavel@ucw.cz> (unless John wants to :-)
+ * GPL v2
+ *
+ * This driver assumes single CPU. That's okay, because collie is
+ * slightly old hardware, and no one is going to retrofit second CPU to
+ * old PDA.
+ */
+
+#include <linux/backlight.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/gpio/consumer.h>
+#include <linux/mfd/locomo.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+struct locomo_bl {
+	struct regmap *regmap;
+	int current_intensity;
+	struct gpio_desc *fl_vr;
+};
+
+static const struct {
+	u16 duty, bpwf;
+	bool vr;
+} locomo_bl_pwm[] = {
+	{ 0, 161, false },
+	{ 117, 161, false },
+	{ 163, 148, false },
+	{ 194, 161, false },
+	{ 194, 161, true },
+};
+
+static int locomo_bl_set_intensity(struct backlight_device *bd)
+{
+	int intensity = bd->props.brightness;
+	struct locomo_bl *bl = dev_get_drvdata(&bd->dev);
+
+	if (bd->props.power != FB_BLANK_UNBLANK)
+		intensity = 0;
+	if (bd->props.fb_blank != FB_BLANK_UNBLANK)
+		intensity = 0;
+	if (bd->props.state & BL_CORE_SUSPENDED)
+		intensity = 0;
+
+	gpiod_set_value(bl->fl_vr, locomo_bl_pwm[intensity].vr);
+
+	regmap_write(bl->regmap, LOCOMO_ALS, locomo_bl_pwm[intensity].bpwf);
+	usleep_range(100, 200);
+	regmap_write(bl->regmap, LOCOMO_ALD, locomo_bl_pwm[intensity].duty);
+	usleep_range(100, 200);
+	regmap_write(bl->regmap, LOCOMO_ALS, locomo_bl_pwm[intensity].bpwf |
+			LOCOMO_ALS_EN);
+
+	bl->current_intensity = intensity;
+	if (bd->props.state & BL_CORE_SUSPENDED)
+		regmap_write(bl->regmap, LOCOMO_ALS, 0x00);
+
+	return 0;
+}
+
+static int locomo_bl_get_intensity(struct backlight_device *bd)
+{
+	struct locomo_bl *bl = dev_get_drvdata(&bd->dev);
+
+	return bl->current_intensity;
+}
+
+static const struct backlight_ops locomo_bl_ops = {
+	.options	= BL_CORE_SUSPENDRESUME,
+	.get_brightness = locomo_bl_get_intensity,
+	.update_status  = locomo_bl_set_intensity,
+};
+
+static int locomo_bl_probe(struct platform_device *dev)
+{
+	struct backlight_properties props;
+	struct locomo_bl *bl;
+	struct backlight_device *locomo_bl_device;
+
+	bl = devm_kmalloc(&dev->dev, sizeof(struct locomo_bl), GFP_KERNEL);
+	if (!bl)
+		return -ENOMEM;
+
+	bl->regmap = dev_get_regmap(dev->dev.parent, NULL);
+	if (!bl->regmap)
+		return -ENODEV;
+
+	bl->fl_vr = devm_gpiod_get(&dev->dev, "flvr", GPIOD_OUT_LOW);
+	if (IS_ERR(bl->fl_vr))
+		return PTR_ERR(bl->fl_vr);
+
+	regmap_write(bl->regmap, LOCOMO_ALS, 0);
+	regmap_write(bl->regmap, LOCOMO_ALD, 0);
+
+	memset(&props, 0, sizeof(struct backlight_properties));
+	props.type = BACKLIGHT_RAW;
+	props.max_brightness = ARRAY_SIZE(locomo_bl_pwm) - 1;
+	props.brightness = props.max_brightness / 2;
+	locomo_bl_device = devm_backlight_device_register(&dev->dev,
+						"locomo-bl",
+						&dev->dev, bl,
+						&locomo_bl_ops, &props);
+
+	if (IS_ERR(locomo_bl_device))
+		return PTR_ERR(locomo_bl_device);
+
+	platform_set_drvdata(dev, locomo_bl_device);
+
+	/* Set up frontlight so that screen is readable */
+	backlight_update_status(locomo_bl_device);
+
+	return 0;
+}
+
+static void locomo_bl_shutdown(struct platform_device *dev)
+{
+	struct backlight_device *locomo_bl_device = platform_get_drvdata(dev);
+
+	locomo_bl_device->props.brightness = 0;
+	locomo_bl_device->props.power = 0;
+	locomo_bl_set_intensity(locomo_bl_device);
+}
+
+static int locomo_bl_remove(struct platform_device *dev)
+{
+	locomo_bl_shutdown(dev);
+
+	return 0;
+}
+
+static struct platform_driver locomo_bl_driver = {
+	.driver = {
+		.name	= "locomo-backlight",
+	},
+	.probe	= locomo_bl_probe,
+	.remove	= locomo_bl_remove,
+	/* Turn off bl on power off/reboot */
+	.shutdown = locomo_bl_shutdown,
+};
+
+module_platform_driver(locomo_bl_driver);
+
+MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
+MODULE_AUTHOR("Pavel Machek <pavel@ucw.cz>");
+MODULE_DESCRIPTION("LoCoMo Backlight driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:locomo-backlight");
-- 
2.1.4


^ permalink raw reply related

* [PATCH v3 06/17] video: lcd: add LoCoMo LCD driver
From: Dmitry Eremin-Solenikov @ 2015-05-17 16:27 UTC (permalink / raw)
  To: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Dmitry Torokhov, Bryan Wu,
	Richard Purdie, Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami
  Cc: linux-arm-kernel, linux-gpio, linux-input, linux-leds, linux-spi,
	linux-fbdev, alsa-devel
In-Reply-To: <1431880077-26321-1-git-send-email-dbaryshkov@gmail.com>

LoCoMo has some special handling for TFT screens attached to Collie and
Poodle. Implement that as a separate driver.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
 drivers/video/backlight/Kconfig      |  10 ++
 drivers/video/backlight/Makefile     |   1 +
 drivers/video/backlight/locomo_lcd.c | 285 +++++++++++++++++++++++++++++++++++
 3 files changed, 296 insertions(+)
 create mode 100644 drivers/video/backlight/locomo_lcd.c

diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 6c093e2..b2f995c 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -48,6 +48,16 @@ config LCD_LMS283GF05
 	  SPI driver for Samsung LMS283GF05. This provides basic support
 	  for powering the LCD up/down through a sysfs interface.
 
+config LCD_LOCOMO
+	tristate "Sharp LOCOMO LCD Driver"
+	depends on MFD_LOCOMO
+	select IIO
+	help
+	  If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to
+	  enable the LCD driver.  The panel starts up in power
+	  off state, so you need this driver in order to see any
+	  output.
+
 config LCD_LTV350QV
 	tristate "Samsung LTV350QV LCD Panel"
 	depends on SPI_MASTER
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 2de73d2..686cf1a 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_LCD_L4F00242T03)		+= l4f00242t03.o
 obj-$(CONFIG_LCD_LD9040)		+= ld9040.o
 obj-$(CONFIG_LCD_LMS283GF05)		+= lms283gf05.o
 obj-$(CONFIG_LCD_LMS501KF03)		+= lms501kf03.o
+obj-$(CONFIG_LCD_LOCOMO)		+= locomo_lcd.o
 obj-$(CONFIG_LCD_LTV350QV)		+= ltv350qv.o
 obj-$(CONFIG_LCD_PLATFORM)		+= platform_lcd.o
 obj-$(CONFIG_LCD_S6E63M0)		+= s6e63m0.o
diff --git a/drivers/video/backlight/locomo_lcd.c b/drivers/video/backlight/locomo_lcd.c
new file mode 100644
index 0000000..dc316cb
--- /dev/null
+++ b/drivers/video/backlight/locomo_lcd.c
@@ -0,0 +1,285 @@
+/*
+ * Backlight control code for Sharp Zaurus SL-5500
+ *
+ * Copyright 2005 John Lenz <lenz@cs.wisc.edu>
+ * Maintainer: Pavel Machek <pavel@ucw.cz> (unless John wants to :-)
+ * GPL v2
+ *
+ * This driver assumes single CPU. That's okay, because collie is
+ * slightly old hardware, and no one is going to retrofit second CPU to
+ * old PDA.
+ */
+
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/consumer.h>
+#include <linux/lcd.h>
+#include <linux/mfd/locomo.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+struct locomo_lcd {
+	struct regmap *regmap;
+	struct platform_device *dev;
+	struct locomo_lcd_platform_data *data;
+	int power;
+	struct iio_channel *comadj;
+	struct gpio_desc *vsha, *vshd, *vee, *mod;
+};
+
+static void locomo_lcd_on(struct locomo_lcd *lcd)
+{
+	gpiod_set_value(lcd->vsha, 1);
+	usleep_range(2000, 3000);
+
+	gpiod_set_value(lcd->vshd, 1);
+	usleep_range(2000, 3000);
+
+	iio_write_channel_raw(lcd->comadj, lcd->data->comadj);
+	usleep_range(5000, 6000);
+
+	gpiod_set_value(lcd->vee, 1);
+	usleep_range(10000, 11000);
+
+	/* TFTCRST | CPSOUT=0 | CPSEN */
+	regmap_write(lcd->regmap, LOCOMO_TC, 0x01);
+
+	/* Set CPSD */
+	regmap_write(lcd->regmap, LOCOMO_CPSD, 6);
+
+	/* TFTCRST | CPSOUT=0 | CPSEN */
+	regmap_write(lcd->regmap, LOCOMO_TC, 0x04 | 0x01);
+	usleep_range(10000, 11000);
+
+	gpiod_set_value(lcd->mod, 1);
+}
+
+static void locomo_lcd_off(struct locomo_lcd *lcd)
+{
+	/* TFTCRST=1 | CPSOUT=1 | CPSEN = 0 */
+	regmap_write(lcd->regmap, LOCOMO_TC, 0x06);
+	usleep_range(1000, 2000);
+
+	gpiod_set_value(lcd->vsha, 0);
+	msleep(110);
+
+	gpiod_set_value(lcd->vee, 0);
+	msleep(700);
+
+	iio_write_channel_raw(lcd->comadj, 0);
+	usleep_range(5000, 6000);
+
+	/* TFTCRST=0 | CPSOUT=0 | CPSEN = 0 */
+	regmap_write(lcd->regmap, LOCOMO_TC, 0);
+	gpiod_set_value(lcd->mod, 0);
+	gpiod_set_value(lcd->vshd, 0);
+}
+
+static void locomo_lcd_program_adsync(struct locomo_lcd *lcd)
+{
+	regmap_write(lcd->regmap, LOCOMO_ASD,
+			6 + 8 + 320 + 30 - 10);
+	regmap_update_bits(lcd->regmap, LOCOMO_ASD,
+		0x8000,
+		0x8000);
+
+	regmap_write(lcd->regmap, LOCOMO_HSD,
+			6 + 8 + 320 + 30 - 10 - 128 + 4);
+	regmap_update_bits(lcd->regmap, LOCOMO_HSD,
+		0x8000,
+		0x8000);
+
+	regmap_write(lcd->regmap, LOCOMO_HSC, 128 / 8);
+
+	/* XON */
+	regmap_write(lcd->regmap, LOCOMO_TADC, 0x80);
+	usleep_range(1000, 1100);
+
+	/* CLK9MEN */
+	regmap_update_bits(lcd->regmap, LOCOMO_TADC,
+		0x10,
+		0x10);
+	usleep_range(100, 200);
+}
+
+static void locomo_lcd_disable_adsync(struct locomo_lcd *lcd)
+{
+	/* ADSTART */
+	regmap_write(lcd->regmap, LOCOMO_ASD, 0x00);
+
+	/* 18MHz clock off*/
+	regmap_write(lcd->regmap, LOCOMO_TADC, 0x00);
+}
+
+int locomo_lcd_set_power(struct lcd_device *ldev, int power)
+{
+	struct locomo_lcd *lcd = lcd_get_data(ldev);
+
+	dev_dbg(&ldev->dev, "LCD power %d (is %d)\n", power, lcd->power);
+
+	if (!power && lcd->power)
+		locomo_lcd_on(lcd);
+
+	if (power && !lcd->power)
+		locomo_lcd_off(lcd);
+
+	lcd->power = power;
+
+	return 0;
+}
+
+static int locomo_lcd_get_power(struct lcd_device *ldev)
+{
+	struct locomo_lcd *lcd = lcd_get_data(ldev);
+
+	return lcd->power;
+}
+
+static struct lcd_ops locomo_lcd_ops = {
+	.set_power = locomo_lcd_set_power,
+	.get_power = locomo_lcd_get_power,
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int locomo_lcd_suspend(struct device *dev)
+{
+	struct lcd_device *ldev = dev_get_drvdata(dev);
+	struct locomo_lcd *lcd = lcd_get_data(ldev);
+
+	locomo_lcd_off(lcd);
+
+	locomo_lcd_disable_adsync(lcd);
+
+	return 0;
+}
+
+static int locomo_lcd_resume(struct device *dev)
+{
+	struct lcd_device *ldev = dev_get_drvdata(dev);
+	struct locomo_lcd *lcd = lcd_get_data(ldev);
+
+	locomo_lcd_program_adsync(lcd);
+
+	if (!lcd->power)
+		locomo_lcd_on(lcd);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(locomo_lcd_pm, locomo_lcd_suspend, locomo_lcd_resume);
+#define LOCOMOLCD_PM	(&locomo_lcd_pm)
+#else
+#define LOCOMOLCD_PM	NULL
+#endif
+
+static int locomo_lcd_probe(struct platform_device *dev)
+{
+	struct lcd_device *lcd_dev;
+	struct locomo_lcd *lcd;
+	int rc;
+
+	lcd = devm_kmalloc(&dev->dev, sizeof(struct locomo_lcd), GFP_KERNEL);
+	if (!lcd)
+		return -ENOMEM;
+
+	lcd->dev = dev;
+	lcd->power = FB_BLANK_NORMAL;
+
+	lcd->regmap = dev_get_regmap(dev->dev.parent, NULL);
+	if (!lcd->regmap)
+		return -ENODEV;
+
+	lcd->data = dev_get_platdata(&dev->dev);
+	if (!lcd->data)
+		return -EINVAL;
+
+	lcd->vsha = devm_gpiod_get(&dev->dev, "VSHA", GPIOD_OUT_LOW);
+	if (IS_ERR(lcd->vsha))
+		return PTR_ERR(lcd->vsha);
+
+	lcd->vshd = devm_gpiod_get(&dev->dev, "VSHD", GPIOD_OUT_LOW);
+	if (IS_ERR(lcd->vshd))
+		return PTR_ERR(lcd->vshd);
+
+	lcd->vee = devm_gpiod_get(&dev->dev, "Vee", GPIOD_OUT_LOW);
+	if (IS_ERR(lcd->vee))
+		return PTR_ERR(lcd->vee);
+
+	lcd->mod = devm_gpiod_get(&dev->dev, "MOD", GPIOD_OUT_LOW);
+	if (IS_ERR(lcd->mod))
+		return PTR_ERR(lcd->mod);
+
+	lcd->comadj = iio_channel_get(&dev->dev, "comadj");
+	if (IS_ERR(lcd->comadj)) {
+		rc = PTR_ERR(lcd->comadj);
+		if (rc = -ENODEV)
+			rc = -EPROBE_DEFER;
+
+		return rc;
+	}
+
+	locomo_lcd_program_adsync(lcd);
+
+	lcd_dev = devm_lcd_device_register(&dev->dev, "locomo", &dev->dev, lcd,
+			&locomo_lcd_ops);
+	if (IS_ERR(lcd_dev)) {
+		rc = PTR_ERR(lcd_dev);
+		goto err;
+	}
+
+	platform_set_drvdata(dev, lcd_dev);
+
+	lcd_set_power(lcd_dev, FB_BLANK_UNBLANK);
+
+	return 0;
+
+err:
+	locomo_lcd_disable_adsync(lcd);
+	iio_channel_release(lcd->comadj);
+
+	return rc;
+}
+
+static int locomo_lcd_remove(struct platform_device *dev)
+{
+	struct lcd_device *ldev = platform_get_drvdata(dev);
+	struct locomo_lcd *lcd = lcd_get_data(ldev);
+
+	locomo_lcd_off(lcd);
+
+	locomo_lcd_disable_adsync(lcd);
+
+	iio_channel_release(lcd->comadj);
+
+	return 0;
+}
+
+static void locomo_lcd_shutdown(struct platform_device *dev)
+{
+	struct lcd_device *ldev = platform_get_drvdata(dev);
+	struct locomo_lcd *lcd = lcd_get_data(ldev);
+
+	locomo_lcd_off(lcd);
+
+	locomo_lcd_disable_adsync(lcd);
+}
+
+static struct platform_driver locomo_lcd_driver = {
+	.driver = {
+		.name	= "locomo-lcd",
+		.pm	= LOCOMOLCD_PM,
+	},
+	.probe	= locomo_lcd_probe,
+	.remove	= locomo_lcd_remove,
+	.shutdown = locomo_lcd_shutdown,
+};
+
+module_platform_driver(locomo_lcd_driver);
+
+MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
+MODULE_AUTHOR("Pavel Machek <pavel@ucw.cz>");
+MODULE_DESCRIPTION("LoCoMo LCD driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:locomo-lcd");
-- 
2.1.4


^ permalink raw reply related

* [PATCH v3 07/17] gpio: port LoCoMo gpio support from old driver
From: Dmitry Eremin-Solenikov @ 2015-05-17 16:27 UTC (permalink / raw)
  To: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Dmitry Torokhov, Bryan Wu,
	Richard Purdie, Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami
  Cc: linux-arm-kernel, linux-gpio, linux-input, linux-leds, linux-spi,
	linux-fbdev, alsa-devel
In-Reply-To: <1431880077-26321-1-git-send-email-dbaryshkov@gmail.com>

Add gpiolib driver for gpio pins placed on the LoCoMo GA.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
---
 drivers/gpio/Kconfig       |  12 ++++
 drivers/gpio/Makefile      |   1 +
 drivers/gpio/gpio-locomo.c | 170 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 183 insertions(+)
 create mode 100644 drivers/gpio/gpio-locomo.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index caefe80..4542684 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -734,6 +734,18 @@ config GPIO_KEMPLD
 	  This driver can also be built as a module. If so, the module will be
 	  called gpio-kempld.
 
+config GPIO_LOCOMO
+	bool "Sharp LoCoMo GPIO support"
+	depends on MFD_LOCOMO
+	help
+	  Select this to support GPIO pins on Sharp LoCoMo Grid Array found
+	  in Sharp Zaurus collie and poodle models.
+
+	  Sat Yes if you have such PDA, say No otherwise.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called gpio-locomo.
+
 config GPIO_LP3943
 	tristate "TI/National Semiconductor LP3943 GPIO expander"
 	depends on MFD_LP3943
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index f71bb97..98655ae 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_GPIO_JANZ_TTL)	+= gpio-janz-ttl.o
 obj-$(CONFIG_GPIO_KEMPLD)	+= gpio-kempld.o
 obj-$(CONFIG_ARCH_KS8695)	+= gpio-ks8695.o
 obj-$(CONFIG_GPIO_INTEL_MID)	+= gpio-intel-mid.o
+obj-$(CONFIG_GPIO_LOCOMO)	+= gpio-locomo.o
 obj-$(CONFIG_GPIO_LOONGSON)	+= gpio-loongson.o
 obj-$(CONFIG_GPIO_LP3943)	+= gpio-lp3943.o
 obj-$(CONFIG_ARCH_LPC32XX)	+= gpio-lpc32xx.o
diff --git a/drivers/gpio/gpio-locomo.c b/drivers/gpio/gpio-locomo.c
new file mode 100644
index 0000000..dd9a1ca
--- /dev/null
+++ b/drivers/gpio/gpio-locomo.c
@@ -0,0 +1,170 @@
+/*
+ * Sharp LoCoMo support for GPIO
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This file contains all generic LoCoMo support.
+ *
+ * All initialization functions provided here are intended to be called
+ * from machine specific code with proper arguments when required.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/regmap.h>
+#include <linux/mfd/locomo.h>
+
+struct locomo_gpio {
+	struct regmap *regmap;
+
+	struct gpio_chip gpio;
+
+	u16 rising_edge;
+	u16 falling_edge;
+
+	unsigned int save_gpo;
+	unsigned int save_gpe;
+};
+
+static int locomo_gpio_get(struct gpio_chip *chip,
+		unsigned offset)
+{
+	struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio);
+	unsigned int gpl;
+
+	regmap_read(lg->regmap, LOCOMO_GPL, &gpl);
+
+	return gpl & BIT(offset);
+}
+
+static void locomo_gpio_set(struct gpio_chip *chip,
+		unsigned offset, int value)
+{
+	struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio);
+
+	regmap_update_bits(lg->regmap, LOCOMO_GPO,
+			BIT(offset),
+			value ? BIT(offset) : 0);
+}
+
+static int locomo_gpio_direction_input(struct gpio_chip *chip,
+			unsigned offset)
+{
+	struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio);
+
+	regmap_update_bits(lg->regmap, LOCOMO_GPD, BIT(offset), BIT(offset));
+	regmap_update_bits(lg->regmap, LOCOMO_GPE, BIT(offset), BIT(offset));
+
+	return 0;
+}
+
+static int locomo_gpio_direction_output(struct gpio_chip *chip,
+			unsigned offset, int value)
+{
+	struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio);
+
+	regmap_update_bits(lg->regmap, LOCOMO_GPO,
+			BIT(offset),
+			value ? BIT(offset) : 0);
+	regmap_update_bits(lg->regmap, LOCOMO_GPD, BIT(offset), 0);
+	regmap_update_bits(lg->regmap, LOCOMO_GPE, BIT(offset), 0);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int locomo_gpio_suspend(struct device *dev)
+{
+	struct locomo_gpio *lg = dev_get_drvdata(dev);
+
+	regmap_read(lg->regmap, LOCOMO_GPO, &lg->save_gpo);
+	regmap_write(lg->regmap, LOCOMO_GPO, 0x00);
+	regmap_read(lg->regmap, LOCOMO_GPE, &lg->save_gpe);
+	regmap_write(lg->regmap, LOCOMO_GPE, 0x00);
+
+	return 0;
+}
+
+static int locomo_gpio_resume(struct device *dev)
+{
+	struct locomo_gpio *lg = dev_get_drvdata(dev);
+
+	regmap_write(lg->regmap, LOCOMO_GPO, lg->save_gpo);
+	regmap_write(lg->regmap, LOCOMO_GPE, lg->save_gpe);
+
+	return 0;
+}
+static SIMPLE_DEV_PM_OPS(locomo_gpio_pm,
+		locomo_gpio_suspend, locomo_gpio_resume);
+#define LOCOMO_GPIO_PM	(&locomo_gpio_pm)
+#else
+#define LOCOMO_GPIO_PM	NULL
+#endif
+
+static int locomo_gpio_probe(struct platform_device *pdev)
+{
+	struct locomo_gpio *lg;
+	int ret;
+	struct locomo_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
+
+	lg = devm_kzalloc(&pdev->dev, sizeof(struct locomo_gpio),
+			GFP_KERNEL);
+	if (!lg)
+		return -ENOMEM;
+
+	lg->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!lg->regmap)
+		return -EINVAL;
+
+	platform_set_drvdata(pdev, lg);
+
+	regmap_write(lg->regmap, LOCOMO_GPO, 0x00);
+	regmap_write(lg->regmap, LOCOMO_GPE, 0x00);
+	regmap_write(lg->regmap, LOCOMO_GPD, 0x00);
+	regmap_write(lg->regmap, LOCOMO_GIE, 0x00);
+
+	lg->gpio.base = pdata ? pdata->gpio_base : -1;
+	lg->gpio.label = "locomo-gpio";
+	lg->gpio.ngpio = 16;
+	lg->gpio.set = locomo_gpio_set;
+	lg->gpio.get = locomo_gpio_get;
+	lg->gpio.direction_input = locomo_gpio_direction_input;
+	lg->gpio.direction_output = locomo_gpio_direction_output;
+
+	ret = gpiochip_add(&lg->gpio);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int locomo_gpio_remove(struct platform_device *pdev)
+{
+	struct locomo_gpio *lg = platform_get_drvdata(pdev);
+
+	gpiochip_remove(&lg->gpio);
+
+	return 0;
+}
+
+static struct platform_driver locomo_gpio_driver = {
+	.probe		= locomo_gpio_probe,
+	.remove		= locomo_gpio_remove,
+	.driver		= {
+		.name	= "locomo-gpio",
+		.pm	= LOCOMO_GPIO_PM,
+	},
+};
+module_platform_driver(locomo_gpio_driver);
+
+MODULE_DESCRIPTION("Sharp LoCoMo GPIO driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
+MODULE_ALIAS("platform:locomo-gpio");
-- 
2.1.4


^ permalink raw reply related

* [PATCH v3 08/17] gpio: locomo: implement per-pin irq handling
From: Dmitry Eremin-Solenikov @ 2015-05-17 16:27 UTC (permalink / raw)
  To: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Dmitry Torokhov, Bryan Wu,
	Richard Purdie, Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami
  Cc: linux-arm-kernel, linux-gpio, linux-input, linux-leds, linux-spi,
	linux-fbdev, alsa-devel
In-Reply-To: <1431880077-26321-1-git-send-email-dbaryshkov@gmail.com>

LoCoMo has a possibility to generate per-GPIO edge irqs. Support for
that was there in old locomo driver, got 'cleaned up' during old driver
IRQ cascading cleanup and is now reimplemented. It is expected that
SL-5500 (collie) will use locomo gpio irqs for mmc detection irq.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
---
 drivers/gpio/Kconfig       |   1 +
 drivers/gpio/gpio-locomo.c | 117 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 117 insertions(+), 1 deletion(-)

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 4542684..6b77614 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -737,6 +737,7 @@ config GPIO_KEMPLD
 config GPIO_LOCOMO
 	bool "Sharp LoCoMo GPIO support"
 	depends on MFD_LOCOMO
+	select GPIOLIB_IRQCHIP
 	help
 	  Select this to support GPIO pins on Sharp LoCoMo Grid Array found
 	  in Sharp Zaurus collie and poodle models.
diff --git a/drivers/gpio/gpio-locomo.c b/drivers/gpio/gpio-locomo.c
index dd9a1ca..75dbf6b 100644
--- a/drivers/gpio/gpio-locomo.c
+++ b/drivers/gpio/gpio-locomo.c
@@ -16,13 +16,15 @@
 #include <linux/slab.h>
 #include <linux/bitops.h>
 #include <linux/err.h>
-#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
 #include <linux/io.h>
+#include <linux/irq.h>
 #include <linux/regmap.h>
 #include <linux/mfd/locomo.h>
 
 struct locomo_gpio {
 	struct regmap *regmap;
+	int irq;
 
 	struct gpio_chip gpio;
 
@@ -79,6 +81,99 @@ static int locomo_gpio_direction_output(struct gpio_chip *chip,
 	return 0;
 }
 
+static void
+locomo_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	struct gpio_chip *chip = irq_get_handler_data(irq);
+	struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio);
+	struct irq_chip *irqchip = irq_desc_get_chip(desc);
+	unsigned int gir;
+	unsigned int gpd;
+	unsigned int req;
+
+	chained_irq_enter(irqchip, desc);
+
+	while (1) {
+		regmap_read(lg->regmap, LOCOMO_GIR, &gir);
+		regmap_read(lg->regmap, LOCOMO_GPD, &gpd);
+		req = gir & gpd;
+
+		if (!req)
+			break;
+
+		generic_handle_irq(irq_find_mapping(lg->gpio.irqdomain,
+					ffs(req) - 1));
+	}
+
+	chained_irq_exit(irqchip, desc);
+}
+
+static void locomo_gpio_ack_irq(struct irq_data *d)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio);
+	unsigned int mask = BIT(d->hwirq);
+
+	regmap_update_bits(lg->regmap, LOCOMO_GWE, mask, mask);
+	regmap_update_bits(lg->regmap, LOCOMO_GIS, mask, 0);
+	regmap_update_bits(lg->regmap, LOCOMO_GWE, mask, 0);
+}
+
+static void locomo_gpio_mask_irq(struct irq_data *d)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio);
+	unsigned int mask = BIT(d->hwirq);
+
+	regmap_update_bits(lg->regmap, LOCOMO_GIE, mask, 0);
+}
+
+static void locomo_gpio_unmask_irq(struct irq_data *d)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio);
+	unsigned int mask = BIT(d->hwirq);
+
+	regmap_update_bits(lg->regmap, LOCOMO_GIE, mask, mask);
+}
+
+static int locomo_gpio_type_irq(struct irq_data *d, unsigned int type)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio);
+	unsigned int mask;
+
+	mask = BIT(d->hwirq);
+
+	if (type = IRQ_TYPE_PROBE) {
+		if ((lg->rising_edge | lg->falling_edge) & mask)
+			return 0;
+		type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+	}
+
+	if (type & IRQ_TYPE_EDGE_RISING)
+		lg->rising_edge |= mask;
+	else
+		lg->rising_edge &= ~mask;
+	if (type & IRQ_TYPE_EDGE_FALLING)
+		lg->falling_edge |= mask;
+	else
+		lg->falling_edge &= ~mask;
+
+	regmap_write(lg->regmap, LOCOMO_GRIE, lg->rising_edge);
+	regmap_write(lg->regmap, LOCOMO_GFIE, lg->falling_edge);
+
+	return 0;
+}
+
+static struct irq_chip locomo_gpio_irq_chip = {
+	.name		= "locomo-GPIO",
+	.irq_ack	= locomo_gpio_ack_irq,
+	.irq_mask	= locomo_gpio_mask_irq,
+	.irq_unmask	= locomo_gpio_unmask_irq,
+	.irq_set_type	= locomo_gpio_type_irq,
+};
+
 #ifdef CONFIG_PM_SLEEP
 static int locomo_gpio_suspend(struct device *dev)
 {
@@ -119,6 +214,10 @@ static int locomo_gpio_probe(struct platform_device *pdev)
 	if (!lg)
 		return -ENOMEM;
 
+	lg->irq = platform_get_irq(pdev, 0);
+	if (lg->irq < 0)
+		return -ENXIO;
+
 	lg->regmap = dev_get_regmap(pdev->dev.parent, NULL);
 	if (!lg->regmap)
 		return -EINVAL;
@@ -130,6 +229,7 @@ static int locomo_gpio_probe(struct platform_device *pdev)
 	regmap_write(lg->regmap, LOCOMO_GPD, 0x00);
 	regmap_write(lg->regmap, LOCOMO_GIE, 0x00);
 
+	lg->gpio.dev = &pdev->dev;
 	lg->gpio.base = pdata ? pdata->gpio_base : -1;
 	lg->gpio.label = "locomo-gpio";
 	lg->gpio.ngpio = 16;
@@ -142,7 +242,22 @@ static int locomo_gpio_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	ret = gpiochip_irqchip_add(&lg->gpio, &locomo_gpio_irq_chip, 0,
+				   handle_level_irq, IRQ_TYPE_NONE);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to add irq chip\n");
+		goto err_rm_gpiochip;
+	}
+
+	gpiochip_set_chained_irqchip(&lg->gpio, &locomo_gpio_irq_chip, lg->irq,
+				     locomo_gpio_irq_handler);
+
 	return 0;
+
+err_rm_gpiochip:
+	gpiochip_remove(&lg->gpio);
+
+	return ret;
 }
 
 static int locomo_gpio_remove(struct platform_device *pdev)
-- 
2.1.4


^ permalink raw reply related

* [PATCH v3 09/17] spi: add locomo SPI driver
From: Dmitry Eremin-Solenikov @ 2015-05-17 16:27 UTC (permalink / raw)
  To: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Dmitry Torokhov, Bryan Wu,
	Richard Purdie, Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami
  Cc: linux-arm-kernel, linux-gpio, linux-input, linux-leds, linux-spi,
	linux-fbdev, alsa-devel
In-Reply-To: <1431880077-26321-1-git-send-email-dbaryshkov@gmail.com>

LoCoMo chip has a built-in simple SPI controller. On Sharp SL-5500 PDDAs
it is connected to external MMC slot.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
 drivers/spi/Kconfig      |  10 ++
 drivers/spi/Makefile     |   1 +
 drivers/spi/spi-locomo.c | 332 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 343 insertions(+)
 create mode 100644 drivers/spi/spi-locomo.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 198f96b..c9e3176 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -258,6 +258,16 @@ config SPI_LM70_LLP
 	  which interfaces to an LM70 temperature sensor using
 	  a parallel port.
 
+config SPI_LOCOMO
+	tristate "Locomo SPI master"
+	depends on MFD_LOCOMO
+	help
+	  This enables using the SPI controller as present in the LoCoMo
+	  chips. It is probably only useful on the Sharp SL-5x00 PDA family.
+
+	  On SL-5500 and SL-5000 devices this controller is used for
+	  MMC/SD cards.
+
 config SPI_MPC52xx
 	tristate "Freescale MPC52xx SPI (non-PSC) controller support"
 	depends on PPC_MPC52xx
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index d8cbf65..623c463 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_SPI_GPIO)			+= spi-gpio.o
 obj-$(CONFIG_SPI_IMG_SPFI)		+= spi-img-spfi.o
 obj-$(CONFIG_SPI_IMX)			+= spi-imx.o
 obj-$(CONFIG_SPI_LM70_LLP)		+= spi-lm70llp.o
+obj-$(CONFIG_SPI_LOCOMO)		+= spi-locomo.o
 obj-$(CONFIG_SPI_MESON_SPIFC)		+= spi-meson-spifc.o
 obj-$(CONFIG_SPI_MPC512x_PSC)		+= spi-mpc512x-psc.o
 obj-$(CONFIG_SPI_MPC52xx_PSC)		+= spi-mpc52xx-psc.o
diff --git a/drivers/spi/spi-locomo.c b/drivers/spi/spi-locomo.c
new file mode 100644
index 0000000..bef0354
--- /dev/null
+++ b/drivers/spi/spi-locomo.c
@@ -0,0 +1,332 @@
+/*
+ * 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; 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/delay.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/mfd/locomo.h>
+
+struct locomospi_dev {
+	struct regmap *regmap;
+
+	int clock_base;
+	int clock_div;
+	unsigned nsecs;
+
+	unsigned int save_ct;
+	unsigned int save_md;
+};
+
+static void locomospi_chipselect(struct spi_device *spi, bool enable)
+{
+	struct locomospi_dev *spidev;
+
+	dev_dbg(&spi->dev, "SPI cs: %s\n", enable ? "enable" : "disable");
+
+	spidev = spi_master_get_devdata(spi->master);
+
+	regmap_update_bits(spidev->regmap, LOCOMO_SPICT, LOCOMO_SPICT_CS,
+			enable ? LOCOMO_SPICT_CS : 0);
+}
+
+static u32 locomospi_txrx_word(struct spi_device *spi,
+		unsigned nsecs,
+		u32 word)
+{
+	struct locomospi_dev *spidev;
+	int wait;
+	int j;
+	unsigned int rx;
+	unsigned int r;
+
+	spidev = spi_master_get_devdata(spi->master);
+
+	if (spidev->clock_div = DIV_64)
+		wait = 0x10000;
+	else
+		wait = 8;
+
+	for (j = 0; j < wait; j++) {
+		regmap_read(spidev->regmap, LOCOMO_SPIST, &r);
+		if (r & LOCOMO_SPI_RFW)
+			break;
+	}
+	if (j = wait)
+		dev_err_ratelimited(&spi->dev, "rfw timeout\n");
+
+	regmap_write(spidev->regmap, LOCOMO_SPITD, word);
+	ndelay(nsecs);
+
+	for (j = 0; j < wait; j++) {
+		regmap_read(spidev->regmap, LOCOMO_SPIST, &r);
+		if (r & LOCOMO_SPI_RFR)
+			break;
+	}
+	if (j = wait)
+		dev_err_ratelimited(&spi->dev, "rfr timeout\n");
+
+	regmap_read(spidev->regmap, LOCOMO_SPIRD, &rx);
+	ndelay(nsecs);
+
+	dev_dbg(&spi->dev, "SPI txrx: %02x/%02x\n", word, rx);
+
+	return rx;
+}
+
+static void locomo_spi_set_speed(struct locomospi_dev *spidev, u32 hz)
+{
+	spidev->nsecs = (1000000000/2) / hz;
+
+	if (hz >= 24576000) {
+		spidev->clock_base = CLOCK_25MHZ;
+		spidev->clock_div = DIV_1;
+	} else if (hz >= 22579200) {
+		spidev->clock_base = CLOCK_22MHZ;
+		spidev->clock_div = DIV_1;
+	} else if (hz >= 18432000) {
+		spidev->clock_base = CLOCK_18MHZ;
+		spidev->clock_div = DIV_1;
+	} else if (hz >= 12288000) {
+		spidev->clock_base = CLOCK_25MHZ;
+		spidev->clock_div = DIV_2;
+	} else if (hz >= 11289600) {
+		spidev->clock_base = CLOCK_22MHZ;
+		spidev->clock_div = DIV_2;
+	} else if (hz >= 9216000) {
+		spidev->clock_base = CLOCK_18MHZ;
+		spidev->clock_div = DIV_2;
+	} else if (hz >= 6144000) {
+		spidev->clock_base = CLOCK_25MHZ;
+		spidev->clock_div = DIV_4;
+	} else if (hz >= 5644800) {
+		spidev->clock_base = CLOCK_22MHZ;
+		spidev->clock_div = DIV_4;
+	} else if (hz >= 4608000) {
+		spidev->clock_base = CLOCK_18MHZ;
+		spidev->clock_div = DIV_4;
+	} else if (hz >= 3072000) {
+		spidev->clock_base = CLOCK_25MHZ;
+		spidev->clock_div = DIV_8;
+	} else if (hz >= 2822400) {
+		spidev->clock_base = CLOCK_22MHZ;
+		spidev->clock_div = DIV_8;
+	} else if (hz >= 2304000) {
+		spidev->clock_base = CLOCK_18MHZ;
+		spidev->clock_div = DIV_8;
+	} else if (hz >= 384000) {
+		spidev->clock_base = CLOCK_25MHZ;
+		spidev->clock_div = DIV_64;
+	} else if (hz >= 352800) {
+		spidev->clock_base = CLOCK_22MHZ;
+		spidev->clock_div = DIV_64;
+	} else {		/* set to 288 Khz */
+		spidev->clock_base = CLOCK_18MHZ;
+		spidev->clock_div = DIV_64;
+	}
+
+	regmap_update_bits(spidev->regmap, LOCOMO_SPIMD,
+			LOCOMO_SPIMD_XSEL | LOCOMO_SPIMD_CLKSEL |
+				LOCOMO_SPIMD_XEN,
+			0);
+	regmap_update_bits(spidev->regmap, LOCOMO_SPIMD,
+			LOCOMO_SPIMD_XSEL | LOCOMO_SPIMD_CLKSEL |
+				LOCOMO_SPIMD_XEN,
+			spidev->clock_div | (spidev->clock_base << 3) |
+				LOCOMO_SPIMD_XEN);
+
+	usleep_range(300, 400);
+}
+
+static int locomo_spi_setup_transfer(struct spi_device *spi,
+		struct spi_transfer *t)
+{
+	struct locomospi_dev *spidev;
+
+	spidev = spi_master_get_devdata(spi->master);
+
+	regmap_update_bits(spidev->regmap, LOCOMO_SPIMD,
+			LOCOMO_SPIMD_XON,
+			LOCOMO_SPIMD_XON);
+
+	locomo_spi_set_speed(spidev, t->speed_hz);
+
+	return 0;
+}
+
+static int locomospi_transfer_one(struct spi_master *master,
+		struct spi_device *spi,
+		struct spi_transfer *t)
+{
+	struct locomospi_dev *spidev = spi_master_get_devdata(spi->master);
+	int rc;
+	unsigned count;
+	const u8 *tx = t->tx_buf;
+	u8 *rx = t->rx_buf;
+
+	rc = locomo_spi_setup_transfer(spi, t);
+	if (rc < 0)
+		return rc;
+
+	if (!t->len)
+		return 0;
+
+	for (count = t->len; likely(count > 0); count--) {
+		u8 word = 0;
+
+		if (tx)
+			word = *tx++;
+		word = locomospi_txrx_word(spi, spidev->nsecs, word);
+
+		if (rx)
+			*rx++ = word;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int locomo_spi_suspend(struct device *dev)
+{
+	struct spi_master *master = dev_get_drvdata(dev);
+	struct locomospi_dev *spidev = spi_master_get_devdata(master);
+	int ret;
+
+	/* Stop the queue running */
+	ret = spi_master_suspend(master);
+	if (ret) {
+		dev_warn(dev, "cannot suspend master\n");
+		return ret;
+	}
+
+	regmap_read(spidev->regmap, LOCOMO_SPICT, &spidev->save_ct);
+	regmap_write(spidev->regmap, LOCOMO_SPICT, LOCOMO_SPICT_CS);
+	regmap_read(spidev->regmap, LOCOMO_SPIMD, &spidev->save_md);
+	regmap_write(spidev->regmap, LOCOMO_SPIMD,
+			LOCOMO_SPIMD_MSB1ST | LOCOMO_SPIMD_DOSTAT |
+			LOCOMO_SPIMD_RCPOL | LOCOMO_SPIMD_TCPOL |
+			(CLOCK_25MHZ << 3) | DIV_64);
+
+	return 0;
+}
+
+static int locomo_spi_resume(struct device *dev)
+{
+	struct spi_master *master = dev_get_drvdata(dev);
+	struct locomospi_dev *spidev = spi_master_get_devdata(master);
+	int ret;
+
+	regmap_write(spidev->regmap, LOCOMO_SPIMD, spidev->save_md);
+	regmap_write(spidev->regmap, LOCOMO_SPICT, spidev->save_ct);
+
+	/* Start the queue running */
+	ret = spi_master_resume(master);
+	if (ret)
+		dev_err(dev, "problem starting queue (%d)\n", ret);
+
+	return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(locomo_spi_pm_ops,
+		locomo_spi_suspend, locomo_spi_resume);
+
+#define LOCOMO_SPI_PM_OPS	(&locomo_spi_pm_ops)
+#else
+#define LOCOMO_SPI_PM_OPS	NULL
+#endif
+
+static int locomo_spi_probe(struct platform_device *pdev)
+{
+	struct spi_master *master;
+	struct locomospi_dev *spidev;
+	int ret = -ENODEV;
+
+	master = spi_alloc_master(&pdev->dev, sizeof(struct locomospi_dev));
+	if (!master)
+		return -ENOMEM;
+
+	master->bus_num = 0;
+	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
+	master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 8);
+	master->max_speed_hz = 24576000;
+	master->num_chipselect = 1;
+	master->set_cs = locomospi_chipselect;
+	master->transfer_one = locomospi_transfer_one;
+
+	spidev = spi_master_get_devdata(master);
+
+	spidev->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+	if (!spidev->regmap)
+		goto out_put;
+
+	spidev->clock_div = DIV_1;
+	spidev->clock_base = CLOCK_25MHZ;
+
+	platform_set_drvdata(pdev, master);
+
+	regmap_write(spidev->regmap, LOCOMO_SPIMD,
+			LOCOMO_SPIMD_MSB1ST | LOCOMO_SPIMD_DOSTAT |
+			LOCOMO_SPIMD_RCPOL | LOCOMO_SPIMD_TCPOL |
+			LOCOMO_SPIMD_XON);
+
+	regmap_write(spidev->regmap, LOCOMO_SPIMD,
+			LOCOMO_SPIMD_MSB1ST | LOCOMO_SPIMD_DOSTAT |
+			LOCOMO_SPIMD_RCPOL | LOCOMO_SPIMD_TCPOL |
+			LOCOMO_SPIMD_XON | LOCOMO_SPIMD_XEN |
+			(spidev->clock_base << 3) | spidev->clock_div);
+
+	regmap_write(spidev->regmap, LOCOMO_SPICT, LOCOMO_SPICT_CS |
+			LOCOMO_SPICT_CEN | LOCOMO_SPICT_RXUEN |
+			LOCOMO_SPICT_ALIGNEN);
+
+	ret = devm_spi_register_master(&pdev->dev, master);
+	if (ret) {
+		dev_err(&pdev->dev, "bitbang start failed with %d\n", ret);
+		goto out_put;
+	}
+
+	return 0;
+
+out_put:
+	spi_master_put(master);
+	return ret;
+}
+
+static int locomo_spi_remove(struct platform_device *pdev)
+{
+	struct spi_master *master = platform_get_drvdata(pdev);
+	struct locomospi_dev *spidev = spi_master_get_devdata(master);
+
+	regmap_update_bits(spidev->regmap, LOCOMO_SPICT, LOCOMO_SPICT_CEN, 0);
+	regmap_update_bits(spidev->regmap, LOCOMO_SPIMD, LOCOMO_SPIMD_XEN, 0);
+	regmap_update_bits(spidev->regmap, LOCOMO_SPIMD, LOCOMO_SPIMD_XON, 0);
+	regmap_update_bits(spidev->regmap, LOCOMO_SPICT,
+			LOCOMO_SPICT_CS,
+			LOCOMO_SPICT_CS);
+
+	return 0;
+}
+
+static struct platform_driver locomo_spi_driver = {
+	.probe = locomo_spi_probe,
+	.remove = locomo_spi_remove,
+	.driver = {
+		.name = "locomo-spi",
+		.pm = LOCOMO_SPI_PM_OPS,
+	},
+};
+module_platform_driver(locomo_spi_driver);
+
+MODULE_AUTHOR("Thomas Kunze thommy@tabao.de");
+MODULE_DESCRIPTION("LoCoMo SPI driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:locomo-spi");
-- 
2.1.4


^ permalink raw reply related

* [PATCH v3 10/17] i2c: add locomo i2c driver
From: Dmitry Eremin-Solenikov @ 2015-05-17 16:27 UTC (permalink / raw)
  To: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Dmitry Torokhov, Bryan Wu,
	Richard Purdie, Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami
  Cc: linux-arm-kernel, linux-gpio, linux-input, linux-leds, linux-spi,
	linux-fbdev, alsa-devel
In-Reply-To: <1431880077-26321-1-git-send-email-dbaryshkov@gmail.com>

LoCoMo chip contains a tiny i2c controller destined to control
M62332 DAC. Provide a separate I2C driver for this cell.

Reviewed-by: Wolfram Sang <wsa@the-dreams.de>
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
 drivers/i2c/busses/Kconfig      |  12 ++++
 drivers/i2c/busses/Makefile     |   1 +
 drivers/i2c/busses/i2c-locomo.c | 135 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 148 insertions(+)
 create mode 100644 drivers/i2c/busses/i2c-locomo.c

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 2255af2..114d9da 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -602,6 +602,18 @@ config I2C_KEMPLD
 	  This driver can also be built as a module. If so, the module
 	  will be called i2c-kempld.
 
+config I2C_LOCOMO
+	tristate "I2C bus support for LoCoMo chips"
+	depends on MFD_LOCOMO
+	select I2C_ALGOBIT
+	help
+	  Say yes if you will run the kernel on Sharp SL-5x00 family of devices.
+
+	  If you don't know what to do here, say N.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-locomo.
+
 config I2C_MESON
 	tristate "Amlogic Meson I2C controller"
 	depends on ARCH_MESON
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index cdf941d..e09dcf6 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_I2C_IMX)		+= i2c-imx.o
 obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o
 obj-$(CONFIG_I2C_JZ4780)	+= i2c-jz4780.o
 obj-$(CONFIG_I2C_KEMPLD)	+= i2c-kempld.o
+obj-$(CONFIG_I2C_LOCOMO)	+= i2c-locomo.o
 obj-$(CONFIG_I2C_MESON)		+= i2c-meson.o
 obj-$(CONFIG_I2C_MPC)		+= i2c-mpc.o
 obj-$(CONFIG_I2C_MV64XXX)	+= i2c-mv64xxx.o
diff --git a/drivers/i2c/busses/i2c-locomo.c b/drivers/i2c/busses/i2c-locomo.c
new file mode 100644
index 0000000..d520513
--- /dev/null
+++ b/drivers/i2c/busses/i2c-locomo.c
@@ -0,0 +1,135 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/kernel.h>
+#include <linux/mfd/locomo.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+struct locomo_i2c {
+	struct regmap		*regmap;
+	struct i2c_adapter	 adap;
+	struct i2c_algo_bit_data bit;
+};
+
+static void locomo_i2c_setsda(void *data, int state)
+{
+	struct locomo_i2c *li2c = data;
+
+	regmap_update_bits(li2c->regmap, LOCOMO_DAC,
+			LOCOMO_DAC_SDAOEB,
+			state ? LOCOMO_DAC_SDAOEB : 0);
+}
+
+static void locomo_i2c_setscl(void *data, int state)
+{
+	struct locomo_i2c *li2c = data;
+
+	regmap_update_bits(li2c->regmap, LOCOMO_DAC,
+			LOCOMO_DAC_SCLOEB,
+			state ? LOCOMO_DAC_SCLOEB : 0);
+}
+
+static int locomo_i2c_getsda(void *data)
+{
+	struct locomo_i2c *li2c = data;
+	unsigned int r;
+
+	regmap_read(li2c->regmap, LOCOMO_DAC, &r);
+
+	return !!(r & LOCOMO_DAC_SDA);
+}
+
+static int locomo_i2c_probe(struct platform_device *dev)
+{
+	struct locomo_i2c *li2c;
+	int ret;
+
+	li2c = devm_kzalloc(&dev->dev, sizeof(struct locomo_i2c), GFP_KERNEL);
+	if (li2c = NULL)
+		return -ENOMEM;
+
+	li2c->regmap = dev_get_regmap(dev->dev.parent, NULL);
+	if (!li2c->regmap)
+		return -ENODEV;
+
+	li2c->adap.owner = THIS_MODULE;
+	li2c->adap.dev.parent = &dev->dev;
+	li2c->adap.dev.of_node = dev->dev.of_node;
+	li2c->adap.algo_data = &li2c->bit;
+	li2c->adap.nr = 1; /* On poodle, 0 is pxa internal bus */
+
+	strlcpy(li2c->adap.name, "LoCoMo I2C", sizeof(li2c->adap.name));
+
+	li2c->bit.data = li2c;
+	li2c->bit.setsda = locomo_i2c_setsda;
+	li2c->bit.setscl = locomo_i2c_setscl;
+	li2c->bit.getsda = locomo_i2c_getsda;
+	li2c->bit.udelay = 6;
+	li2c->bit.timeout = HZ;
+
+	ret = i2c_bit_add_numbered_bus(&li2c->adap);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(dev, li2c);
+
+	return 0;
+}
+
+static int locomo_i2c_remove(struct platform_device *dev)
+{
+	struct locomo_i2c *li2c = platform_get_drvdata(dev);
+
+	i2c_del_adapter(&li2c->adap);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int locomo_i2c_suspend(struct device *dev)
+{
+	struct locomo_i2c *li2c = dev_get_drvdata(dev);
+
+	regmap_write(li2c->regmap, LOCOMO_DAC, 0x00);
+
+	return 0;
+}
+
+static int locomo_i2c_resume(struct device *dev)
+{
+	struct locomo_i2c *li2c = dev_get_drvdata(dev);
+
+	regmap_write(li2c->regmap, LOCOMO_DAC,
+			LOCOMO_DAC_SDAOEB | LOCOMO_DAC_SCLOEB);
+
+	return 0;
+}
+static SIMPLE_DEV_PM_OPS(locomo_i2c_pm, locomo_i2c_suspend, locomo_i2c_resume);
+#define LOCOMO_I2C_PM	(&locomo_i2c_pm)
+#else
+#define LOCOMO_I2C_PM	NULL
+#endif
+
+
+static struct platform_driver locomo_i2c_driver = {
+	.driver		= {
+		.name	= "locomo-i2c",
+		.pm	= LOCOMO_I2C_PM,
+	},
+	.probe		= locomo_i2c_probe,
+	.remove		= locomo_i2c_remove,
+};
+
+module_platform_driver(locomo_i2c_driver);
+
+MODULE_DESCRIPTION("LoCoMo i2c bus driver");
+MODULE_AUTHOR("Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:locomo-i2c");
-- 
2.1.4


^ permalink raw reply related

* [PATCH v3 11/17] ARM: sa1100: make collie use new locomo drivers
From: Dmitry Eremin-Solenikov @ 2015-05-17 16:27 UTC (permalink / raw)
  To: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Dmitry Torokhov, Bryan Wu,
	Richard Purdie, Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami
  Cc: linux-arm-kernel, linux-gpio, linux-input, linux-leds, linux-spi,
	linux-fbdev, alsa-devel
In-Reply-To: <1431880077-26321-1-git-send-email-dbaryshkov@gmail.com>

Switch collie to new mfd-based locomo driver. Update platform data and
add necessary spi, i2c and regulator devices.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
 arch/arm/mach-sa1100/Kconfig               |   1 -
 arch/arm/mach-sa1100/collie.c              | 213 ++++++++++++++++++++++-------
 arch/arm/mach-sa1100/include/mach/collie.h |  16 ++-
 3 files changed, 178 insertions(+), 52 deletions(-)

diff --git a/arch/arm/mach-sa1100/Kconfig b/arch/arm/mach-sa1100/Kconfig
index c6f6ed1..37af126 100644
--- a/arch/arm/mach-sa1100/Kconfig
+++ b/arch/arm/mach-sa1100/Kconfig
@@ -48,7 +48,6 @@ endchoice
 config SA1100_COLLIE
 	bool "Sharp Zaurus SL5500"
 	# FIXME: select ARM_SA11x0_CPUFREQ
-	select SHARP_LOCOMO
 	select SHARP_PARAM
 	select SHARP_SCOOP
 	help
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
index 3cc2b71..b6dda7a 100644
--- a/arch/arm/mach-sa1100/collie.c
+++ b/arch/arm/mach-sa1100/collie.c
@@ -24,13 +24,21 @@
 #include <linux/platform_data/sa11x0-serial.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/ucb1x00.h>
+#include <linux/mfd/locomo.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/timer.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
+#include <linux/i2c.h>
 #include <linux/gpio.h>
 #include <linux/power/gpio-charger.h>
+#include <linux/gpio/machine.h>
+#include <linux/iio/machine.h>
+#include <linux/mmc/host.h>
+#include <linux/regulator/fixed.h>
+#include <linux/regulator/machine.h>
+#include <linux/spi/mmc_spi.h>
 
 #include <video/sa1100fb.h>
 
@@ -47,7 +55,6 @@
 
 #include <asm/hardware/scoop.h>
 #include <asm/mach/sharpsl_param.h>
-#include <asm/hardware/locomo.h>
 #include <linux/platform_data/mfd-mcp-sa11x0.h>
 #include <mach/irqs.h>
 
@@ -151,36 +158,54 @@ static struct platform_device collie_power_device = {
 	.dev.platform_data	= &collie_power_data,
 };
 
-#ifdef CONFIG_SHARP_LOCOMO
 /*
  * low-level UART features.
  */
-struct platform_device collie_locomo_device;
+static struct gpio collie_uart_gpio[] = {
+	{ COLLIE_GPIO_CTS, GPIOF_IN, "CTS" },
+	{ COLLIE_GPIO_RTS, GPIOF_OUT_INIT_LOW, "RTS" },
+	{ COLLIE_GPIO_DTR, GPIOF_OUT_INIT_LOW, "DTR" },
+	{ COLLIE_GPIO_DSR, GPIOF_IN, "DSR" },
+};
+
+static bool collie_uart_gpio_ok;
 
 static void collie_uart_set_mctrl(struct uart_port *port, u_int mctrl)
 {
-	if (mctrl & TIOCM_RTS)
-		locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_RTS, 0);
-	else
-		locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_RTS, 1);
-
-	if (mctrl & TIOCM_DTR)
-		locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_DTR, 0);
-	else
-		locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_DTR, 1);
+	if (!collie_uart_gpio_ok) {
+		int rc = gpio_request_array(collie_uart_gpio,
+				ARRAY_SIZE(collie_uart_gpio));
+		if (rc)
+			pr_err("collie_uart_set_mctrl: gpio request %d\n", rc);
+		else
+			collie_uart_gpio_ok = true;
+	}
+
+	if (collie_uart_gpio_ok) {
+		gpio_set_value(COLLIE_GPIO_RTS, !(mctrl & TIOCM_RTS));
+		gpio_set_value(COLLIE_GPIO_DTR, !(mctrl & TIOCM_DTR));
+	}
 }
 
 static u_int collie_uart_get_mctrl(struct uart_port *port)
 {
 	int ret = TIOCM_CD;
-	unsigned int r;
 
-	r = locomo_gpio_read_output(&collie_locomo_device.dev, LOCOMO_GPIO_CTS & LOCOMO_GPIO_DSR);
-	if (r = -ENODEV)
+	if (!collie_uart_gpio_ok) {
+		int rc = gpio_request_array(collie_uart_gpio,
+				ARRAY_SIZE(collie_uart_gpio));
+		if (rc)
+			pr_err("collie_uart_get_mctrl: gpio request %d\n", rc);
+		else
+			collie_uart_gpio_ok = true;
+	}
+
+	if (!collie_uart_gpio_ok)
 		return ret;
-	if (r & LOCOMO_GPIO_CTS)
+
+	if (gpio_get_value(COLLIE_GPIO_CTS))
 		ret |= TIOCM_CTS;
-	if (r & LOCOMO_GPIO_DSR)
+	if (gpio_get_value(COLLIE_GPIO_DSR))
 		ret |= TIOCM_DSR;
 
 	return ret;
@@ -191,33 +216,35 @@ static struct sa1100_port_fns collie_port_fns __initdata = {
 	.get_mctrl	= collie_uart_get_mctrl,
 };
 
-static int collie_uart_probe(struct locomo_dev *dev)
-{
-	return 0;
-}
-
-static int collie_uart_remove(struct locomo_dev *dev)
-{
-	return 0;
-}
+static struct regulator_consumer_supply collie_amp_on_consumer_supplies[] = {
+	REGULATOR_SUPPLY("VCC", "1-004e"),
+};
 
-static struct locomo_driver collie_uart_driver = {
-	.drv = {
-		.name = "collie_uart",
+static struct regulator_init_data collie_amp_on_init_data = {
+	.constraints	= {
+		.name	= "AMP_ON",
+		.valid_ops_mask = REGULATOR_CHANGE_STATUS,
 	},
-	.devid	= LOCOMO_DEVID_UART,
-	.probe	= collie_uart_probe,
-	.remove	= collie_uart_remove,
+	.consumer_supplies = collie_amp_on_consumer_supplies,
+	.num_consumer_supplies = ARRAY_SIZE(collie_amp_on_consumer_supplies),
 };
 
-static int __init collie_uart_init(void)
-{
-	return locomo_driver_register(&collie_uart_driver);
-}
-device_initcall(collie_uart_init);
-
-#endif
+static struct fixed_voltage_config collie_amp_on_data = {
+	.supply_name	= "amp_on",
+	.microvolts	= 3300000,
+	.gpio		= COLLIE_GPIO_AMP2_ON,
+	.startup_delay	= 5,
+	.enable_high	= 1,
+	.init_data	= &collie_amp_on_init_data,
+};
 
+static struct platform_device collie_amp_on_device = {
+	.name		= "reg-fixed-voltage",
+	.id		= -1,
+	.dev = {
+		.platform_data	= &collie_amp_on_data,
+	},
+};
 
 static struct resource locomo_resources[] = {
 	[0] = DEFINE_RES_MEM(0x40000000, SZ_8K),
@@ -225,14 +252,15 @@ static struct resource locomo_resources[] = {
 };
 
 static struct locomo_platform_data locomo_info = {
-	.irq_base	= IRQ_BOARD_START,
+	.gpio_base = COLLIE_LOCOMO_GPIO_BASE,
+	.comadj	          = 128,
 };
 
-struct platform_device collie_locomo_device = {
+static struct platform_device collie_locomo_device = {
 	.name		= "locomo",
 	.id		= 0,
 	.dev		= {
-		.platform_data	= &locomo_info,
+		.platform_data  = &locomo_info,
 	},
 	.num_resources	= ARRAY_SIZE(locomo_resources),
 	.resource	= locomo_resources,
@@ -270,7 +298,55 @@ static struct platform_device collie_gpio_keys_device = {
 	},
 };
 
+static int collie_mmc_init(struct device *dev,
+		irqreturn_t (*isr)(int, void*), void *mmc)
+{
+	int ret;
+
+	ret = gpio_request(COLLIE_GPIO_CARD_POWER, "MMC power");
+	if (!ret)
+		ret = gpio_direction_output(COLLIE_GPIO_CARD_POWER, 0);
+	if (ret)
+		gpio_free(COLLIE_GPIO_CARD_POWER);
+	return ret;
+}
+
+static void collie_mmc_exit(struct device *dev, void *mmc)
+{
+	gpio_free(COLLIE_GPIO_CARD_POWER);
+}
+
+static void collie_mmc_setpower(struct device *dev, unsigned int mask)
+{
+	gpio_set_value(COLLIE_GPIO_CARD_POWER, !!mask);
+}
+
+static struct mmc_spi_platform_data collie_mmc_data = {
+	.init		= collie_mmc_init,
+	.exit		= collie_mmc_exit,
+	.setpower	= collie_mmc_setpower,
+	.detect_delay	= 200,
+	.powerup_msecs  = 200,
+	.ocr_mask	= MMC_VDD_32_33 | MMC_VDD_33_34,
+	.flags		= MMC_SPI_USE_CD_GPIO | MMC_SPI_USE_RO_GPIO,
+	.cd_gpio	= COLLIE_GPIO_CARD_DETECT,
+	.ro_gpio	= COLLIE_GPIO_CARD_RO,
+	.caps2		= MMC_CAP2_RO_ACTIVE_HIGH,
+};
+
+static struct spi_board_info collie_spi_board_info[] __initdata = {
+	{
+		.modalias	= "mmc_spi",
+		.platform_data	= &collie_mmc_data,
+		.max_speed_hz	= 25000000,
+		.bus_num	= 0,
+		.chip_select	= 0,
+		.mode		= SPI_MODE_0,
+	},
+};
+
 static struct platform_device *devices[] __initdata = {
+	&collie_amp_on_device,
 	&collie_locomo_device,
 	&colliescoop_device,
 	&collie_power_device,
@@ -347,10 +423,39 @@ static struct sa1100fb_mach_info collie_lcd_info = {
 
 	.lccr0		= LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
 	.lccr3		= LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+};
 
-#ifdef CONFIG_BACKLIGHT_LOCOMO
-	.lcd_power	= locomolcd_power
-#endif
+static struct iio_map locomo_iio_map[] = {
+	{
+		.consumer_dev_name = "locomo-lcd.0",
+		.consumer_channel = "comadj",
+		.adc_channel_label = "CH0",
+	},
+	{ }
+};
+
+static struct i2c_board_info locomo_i2c_devs[] __initdata = {
+	{
+		I2C_BOARD_INFO("m62332", 0x4e),
+		.platform_data = locomo_iio_map,
+	},
+};
+
+static struct gpiod_lookup_table collie_bl_gpios_table = {
+	.dev_id = "locomo-backlight.0",
+	.table = {
+		GPIO_LOOKUP("locomo-gpio", 9, "flvr", GPIO_ACTIVE_HIGH),
+		{ },
+	},
+}, collie_lcd_gpios_table = {
+	.dev_id = "locomo-lcd.0",
+	.table = {
+		GPIO_LOOKUP("locomo-gpio", 4, "VSHA", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("locomo-gpio", 5, "VSHD", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("locomo-gpio", 6, "Vee", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("locomo-gpio", 7, "MOD", GPIO_ACTIVE_HIGH),
+		{ },
+	},
 };
 
 static void __init collie_init(void)
@@ -381,11 +486,19 @@ static void __init collie_init(void)
 
 	GPSR |= _COLLIE_GPIO_UCB1x00_RESET;
 
+	sharpsl_save_param();
+
 	sa11x0_ppc_configure_mcp();
 
 
 	platform_scoop_config = &collie_pcmcia_config;
 
+	if (sharpsl_param.comadj != -1)
+		locomo_info.comadj = sharpsl_param.comadj;
+
+	gpiod_add_lookup_table(&collie_bl_gpios_table);
+	gpiod_add_lookup_table(&collie_lcd_gpios_table);
+
 	ret = platform_add_devices(devices, ARRAY_SIZE(devices));
 	if (ret) {
 		printk(KERN_WARNING "collie: Unable to register LoCoMo device\n");
@@ -397,7 +510,13 @@ static void __init collie_init(void)
 	sa11x0_register_mcp(&collie_mcp_data);
 	sa11x0_register_irda(&collie_ir_data);
 
-	sharpsl_save_param();
+	i2c_register_board_info(1,
+			locomo_i2c_devs, ARRAY_SIZE(locomo_i2c_devs));
+
+	spi_register_board_info(collie_spi_board_info,
+			ARRAY_SIZE(collie_spi_board_info));
+
+	regulator_has_full_constraints();
 }
 
 static struct map_desc collie_io_desc[] __initdata = {
@@ -419,9 +538,7 @@ static void __init collie_map_io(void)
 	sa1100_map_io();
 	iotable_init(collie_io_desc, ARRAY_SIZE(collie_io_desc));
 
-#ifdef CONFIG_SHARP_LOCOMO
 	sa1100_register_uart_fns(&collie_port_fns);
-#endif
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
 }
diff --git a/arch/arm/mach-sa1100/include/mach/collie.h b/arch/arm/mach-sa1100/include/mach/collie.h
index b478ca1..2e3bf80 100644
--- a/arch/arm/mach-sa1100/include/mach/collie.h
+++ b/arch/arm/mach-sa1100/include/mach/collie.h
@@ -24,12 +24,12 @@ extern void locomolcd_power(int on);
 #define COLLIE_SCP_MUTE_L	SCOOP_GPCR_PA14
 #define COLLIE_SCP_MUTE_R	SCOOP_GPCR_PA15
 #define COLLIE_SCP_5VON		SCOOP_GPCR_PA16
-#define COLLIE_SCP_AMP_ON	SCOOP_GPCR_PA17
+#define COLLIE_GPIO_AMP2_ON	(COLLIE_SCOOP_GPIO_BASE + 6)
 #define COLLIE_GPIO_VPEN	(COLLIE_SCOOP_GPIO_BASE + 7)
 #define COLLIE_SCP_LB_VOL_CHG	SCOOP_GPCR_PA19
 
 #define COLLIE_SCOOP_IO_DIR	(COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R | \
-				COLLIE_SCP_5VON | COLLIE_SCP_AMP_ON | \
+				COLLIE_SCP_5VON | \
 				COLLIE_SCP_LB_VOL_CHG)
 #define COLLIE_SCOOP_IO_OUT	(COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R)
 
@@ -81,7 +81,7 @@ extern void locomolcd_power(int on);
 #define COLLIE_TC35143_GPIO_TBL_CHK     UCB_IO_1
 #define COLLIE_TC35143_GPIO_VPEN_ON     UCB_IO_2
 #define COLLIE_GPIO_IR_ON		(COLLIE_TC35143_GPIO_BASE + 3)
-#define COLLIE_TC35143_GPIO_AMP_ON      UCB_IO_4
+#define COLLIE_GPIO_AMP1_ON		(COLLIE_TC35143_GPIO_BASE + 4)
 #define COLLIE_TC35143_GPIO_VERSION1    UCB_IO_5
 #define COLLIE_TC35143_GPIO_FS8KLPF     UCB_IO_5
 #define COLLIE_TC35143_GPIO_BUZZER_BIAS UCB_IO_6
@@ -92,4 +92,14 @@ extern void locomolcd_power(int on);
 #define COLLIE_TC35143_GPIO_OUT		(UCB_IO_1 | UCB_IO_3 | UCB_IO_4 \
 						| UCB_IO_6)
 
+/* GPIOs on LoCoMo GA */
+#define COLLIE_LOCOMO_GPIO_BASE		(GPIO_MAX + 13 + 10)
+#define COLLIE_GPIO_RTS			(COLLIE_LOCOMO_GPIO_BASE + 0)
+#define COLLIE_GPIO_CTS			(COLLIE_LOCOMO_GPIO_BASE + 1)
+#define COLLIE_GPIO_DSR			(COLLIE_LOCOMO_GPIO_BASE + 2)
+#define COLLIE_GPIO_DTR			(COLLIE_LOCOMO_GPIO_BASE + 3)
+#define COLLIE_GPIO_CARD_DETECT		(COLLIE_LOCOMO_GPIO_BASE + 13)
+#define COLLIE_GPIO_CARD_RO		(COLLIE_LOCOMO_GPIO_BASE + 14)
+#define COLLIE_GPIO_CARD_POWER		(COLLIE_LOCOMO_GPIO_BASE + 15)
+
 #endif
-- 
2.1.4


^ permalink raw reply related

* [PATCH v3 12/17] ARM: sa1100: don't preallocate IRQ space for locomo
From: Dmitry Eremin-Solenikov @ 2015-05-17 16:27 UTC (permalink / raw)
  To: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Dmitry Torokhov, Bryan Wu,
	Richard Purdie, Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami
  Cc: linux-arm-kernel, linux-gpio, linux-input, linux-leds, linux-spi,
	linux-fbdev, alsa-devel
In-Reply-To: <1431880077-26321-1-git-send-email-dbaryshkov@gmail.com>

As new locomo driver properly supports SPARSE_IRQ, stop playing with
NR_IRQS on sa1100 (locomo was the last chip requiring NR_IRQ tricks).

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
 arch/arm/mach-sa1100/include/mach/irqs.h | 19 ++-----------------
 1 file changed, 2 insertions(+), 17 deletions(-)

diff --git a/arch/arm/mach-sa1100/include/mach/irqs.h b/arch/arm/mach-sa1100/include/mach/irqs.h
index 734e30e..b4b9608 100644
--- a/arch/arm/mach-sa1100/include/mach/irqs.h
+++ b/arch/arm/mach-sa1100/include/mach/irqs.h
@@ -79,22 +79,7 @@
 #define IRQ_BOARD_START		61
 #define IRQ_BOARD_END		77
 
-/*
- * Figure out the MAX IRQ number.
- *
- * Neponset, SA1111 and UCB1x00 are sparse IRQ aware, so can dynamically
- * allocate their IRQs above NR_IRQS.
- *
- * LoCoMo has 4 additional IRQs, but is not sparse IRQ aware, and so has
- * to be included in the NR_IRQS calculation.
- */
-#ifdef CONFIG_SHARP_LOCOMO
-#define NR_IRQS_LOCOMO		4
-#else
-#define NR_IRQS_LOCOMO		0
-#endif
-
 #ifndef NR_IRQS
-#define NR_IRQS (IRQ_BOARD_START + NR_IRQS_LOCOMO)
+#define NR_IRQS IRQ_BOARD_START
 #endif
-#define SA1100_NR_IRQS (IRQ_BOARD_START + NR_IRQS_LOCOMO)
+#define SA1100_NR_IRQS IRQ_BOARD_START
-- 
2.1.4


^ permalink raw reply related

* [PATCH v3 13/17] ASoC: pxa: poodle: make use of new locomo GPIO interface
From: Dmitry Eremin-Solenikov @ 2015-05-17 16:27 UTC (permalink / raw)
  To: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Dmitry Torokhov, Bryan Wu,
	Richard Purdie, Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw
In-Reply-To: <1431880077-26321-1-git-send-email-dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

Since LoCoMo driver has been converted to provide proper gpiolib
interface, make poodle ASoC platform driver use gpiolib API.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Acked-by: Mark Brown <broonie@kernel.org>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
---
 sound/soc/pxa/poodle.c | 52 +++++++++++++++++++-------------------------------
 1 file changed, 20 insertions(+), 32 deletions(-)

diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index 0fce8c4..c5b7c5e 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -20,15 +20,11 @@
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/gpio/consumer.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/soc.h>
 
-#include <asm/mach-types.h>
-#include <asm/hardware/locomo.h>
-#include <mach/poodle.h>
-#include <mach/audio.h>
-
 #include "../codecs/wm8731.h"
 #include "pxa2xx-i2s.h"
 
@@ -42,22 +38,18 @@
 
 static int poodle_jack_func;
 static int poodle_spk_func;
+static struct gpio_desc *poodle_mute_l, *poodle_mute_r, *poodle_amp_on;
 
 static void poodle_ext_control(struct snd_soc_dapm_context *dapm)
 {
 	/* set up jack connection */
 	if (poodle_jack_func = POODLE_HP) {
-		/* set = unmute headphone */
-		locomo_gpio_write(&poodle_locomo_device.dev,
-			POODLE_LOCOMO_GPIO_MUTE_L, 1);
-		locomo_gpio_write(&poodle_locomo_device.dev,
-			POODLE_LOCOMO_GPIO_MUTE_R, 1);
+		gpiod_set_value(poodle_mute_l, 0);
+		gpiod_set_value(poodle_mute_r, 0);
 		snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
 	} else {
-		locomo_gpio_write(&poodle_locomo_device.dev,
-			POODLE_LOCOMO_GPIO_MUTE_L, 0);
-		locomo_gpio_write(&poodle_locomo_device.dev,
-			POODLE_LOCOMO_GPIO_MUTE_R, 0);
+		gpiod_set_value(poodle_mute_l, 1);
+		gpiod_set_value(poodle_mute_r, 1);
 		snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
 	}
 
@@ -84,11 +76,8 @@ static int poodle_startup(struct snd_pcm_substream *substream)
 /* we need to unmute the HP at shutdown as the mute burns power on poodle */
 static void poodle_shutdown(struct snd_pcm_substream *substream)
 {
-	/* set = unmute headphone */
-	locomo_gpio_write(&poodle_locomo_device.dev,
-		POODLE_LOCOMO_GPIO_MUTE_L, 1);
-	locomo_gpio_write(&poodle_locomo_device.dev,
-		POODLE_LOCOMO_GPIO_MUTE_R, 1);
+	gpiod_set_value(poodle_mute_l, 0);
+	gpiod_set_value(poodle_mute_r, 0);
 }
 
 static int poodle_hw_params(struct snd_pcm_substream *substream,
@@ -178,12 +167,7 @@ static int poodle_set_spk(struct snd_kcontrol *kcontrol,
 static int poodle_amp_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *k, int event)
 {
-	if (SND_SOC_DAPM_EVENT_ON(event))
-		locomo_gpio_write(&poodle_locomo_device.dev,
-			POODLE_LOCOMO_GPIO_AMP_ON, 0);
-	else
-		locomo_gpio_write(&poodle_locomo_device.dev,
-			POODLE_LOCOMO_GPIO_AMP_ON, 1);
+	gpiod_set_value(poodle_amp_on, (SND_SOC_DAPM_EVENT_ON(event)));
 
 	return 0;
 }
@@ -268,13 +252,17 @@ static int poodle_probe(struct platform_device *pdev)
 	struct snd_soc_card *card = &poodle;
 	int ret;
 
-	locomo_gpio_set_dir(&poodle_locomo_device.dev,
-		POODLE_LOCOMO_GPIO_AMP_ON, 0);
-	/* should we mute HP at startup - burning power ?*/
-	locomo_gpio_set_dir(&poodle_locomo_device.dev,
-		POODLE_LOCOMO_GPIO_MUTE_L, 0);
-	locomo_gpio_set_dir(&poodle_locomo_device.dev,
-		POODLE_LOCOMO_GPIO_MUTE_R, 0);
+	poodle_mute_l = devm_gpiod_get(&pdev->dev, "mute-l", GPIOD_OUT_HIGH);
+	if (IS_ERR(poodle_mute_l))
+		return PTR_ERR(poodle_mute_l);
+
+	poodle_mute_r = devm_gpiod_get(&pdev->dev, "mute-r", GPIOD_OUT_HIGH);
+	if (IS_ERR(poodle_mute_r))
+		return PTR_ERR(poodle_mute_l);
+
+	poodle_amp_on = devm_gpiod_get(&pdev->dev, "amp-on", GPIOD_OUT_LOW);
+	if (IS_ERR(poodle_amp_on))
+		return PTR_ERR(poodle_amp_on);
 
 	card->dev = &pdev->dev;
 
-- 
2.1.4


^ permalink raw reply related

* [PATCH v3 14/17] ARM: pxa: poodle: use new LoCoMo driver
From: Dmitry Eremin-Solenikov @ 2015-05-17 16:27 UTC (permalink / raw)
  To: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Dmitry Torokhov, Bryan Wu,
	Richard Purdie, Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw
In-Reply-To: <1431880077-26321-1-git-send-email-dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

Convert poodle to use new mfd-based LoCoMo driver.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
---
 arch/arm/mach-pxa/Kconfig               |  1 -
 arch/arm/mach-pxa/include/mach/poodle.h |  6 ----
 arch/arm/mach-pxa/poodle.c              | 58 ++++++++++++++++++++++++++++++---
 3 files changed, 54 insertions(+), 11 deletions(-)

diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index 8896e71..a2756b0 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -481,7 +481,6 @@ config MACH_POODLE
 	bool "Enable Sharp SL-5600 (Poodle) Support"
 	depends on PXA_SHARPSL
 	select PXA25x
-	select SHARP_LOCOMO
 
 config MACH_CORGI
 	bool "Enable Sharp SL-C700 (Corgi) Support"
diff --git a/arch/arm/mach-pxa/include/mach/poodle.h b/arch/arm/mach-pxa/include/mach/poodle.h
index b56b193..5905cf1 100644
--- a/arch/arm/mach-pxa/include/mach/poodle.h
+++ b/arch/arm/mach-pxa/include/mach/poodle.h
@@ -81,12 +81,6 @@
 #define POODLE_GPIO_L_LCLK	(POODLE_SCOOP_GPIO_BASE + 10)
 #define POODLE_GPIO_HS_OUT	(POODLE_SCOOP_GPIO_BASE + 11)
 
-#define POODLE_LOCOMO_GPIO_AMP_ON      LOCOMO_GPIO(8)
-#define POODLE_LOCOMO_GPIO_MUTE_L      LOCOMO_GPIO(10)
-#define POODLE_LOCOMO_GPIO_MUTE_R      LOCOMO_GPIO(11)
-#define POODLE_LOCOMO_GPIO_232VCC_ON   LOCOMO_GPIO(12)
-#define POODLE_LOCOMO_GPIO_JK_B        LOCOMO_GPIO(13)
-
 #define POODLE_NR_IRQS		(IRQ_BOARD_START + 4)	/* 4 for LoCoMo */
 
 extern struct platform_device poodle_locomo_device;
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index 195b112..0236ee8 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -23,6 +23,7 @@
 #include <linux/delay.h>
 #include <linux/mtd/physmap.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/i2c.h>
 #include <linux/i2c/pxa-i2c.h>
 #include <linux/regulator/machine.h>
@@ -31,6 +32,8 @@
 #include <linux/spi/pxa2xx_spi.h>
 #include <linux/mtd/sharpsl.h>
 #include <linux/memblock.h>
+#include <linux/iio/machine.h>
+#include <linux/mfd/locomo.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -49,7 +52,6 @@
 #include <linux/platform_data/video-pxafb.h>
 
 #include <asm/hardware/scoop.h>
-#include <asm/hardware/locomo.h>
 #include <asm/mach/sharpsl_param.h>
 
 #include "generic.h"
@@ -179,7 +181,8 @@ static struct resource locomo_resources[] = {
 };
 
 static struct locomo_platform_data locomo_info = {
-	.irq_base	= IRQ_BOARD_START,
+	.gpio_base	  = -1,
+	.comadj	          = 118,
 };
 
 struct platform_device poodle_locomo_device = {
@@ -192,8 +195,6 @@ struct platform_device poodle_locomo_device = {
 	},
 };
 
-EXPORT_SYMBOL(poodle_locomo_device);
-
 #if defined(CONFIG_SPI_PXA2XX) || defined(CONFIG_SPI_PXA2XX_MODULE)
 static struct pxa2xx_spi_master poodle_spi_info = {
 	.num_chipselect	= 1,
@@ -424,6 +425,47 @@ static struct i2c_board_info __initdata poodle_i2c_devices[] = {
 	{ I2C_BOARD_INFO("wm8731", 0x1b) },
 };
 
+static struct iio_map locomo_iio_map[] = {
+	{
+		.consumer_dev_name = "locomo-lcd.0",
+		.consumer_channel = "comadj",
+		.adc_channel_label = "CH0",
+	},
+	{ }
+};
+
+static struct i2c_board_info locomo_i2c_devs[] __initdata = {
+	{
+		I2C_BOARD_INFO("m62332", 0x4e),
+		.platform_data = locomo_iio_map,
+	},
+};
+
+static struct gpiod_lookup_table poodle_audio_gpios_table = {
+	.dev_id = "poodle-audio",
+	.table = {
+		GPIO_LOOKUP("locomo-gpio", 10, "mute-l", GPIO_ACTIVE_LOW),
+		GPIO_LOOKUP("locomo-gpio", 11, "mute-r", GPIO_ACTIVE_LOW),
+		GPIO_LOOKUP("locomo-gpio", 8, "amp-on", GPIO_ACTIVE_LOW),
+		{ },
+	},
+}, poodle_bl_gpios_table = {
+	.dev_id = "locomo-backlight.0",
+	.table = {
+		GPIO_LOOKUP("locomo-gpio", 9, "flvr", GPIO_ACTIVE_HIGH),
+		{ },
+	},
+}, poodle_lcd_gpios_table = {
+	.dev_id = "locomo-lcd.0",
+	.table = {
+		GPIO_LOOKUP("locomo-gpio", 4, "VSHA", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("locomo-gpio", 5, "VSHD", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("locomo-gpio", 6, "Vee", GPIO_ACTIVE_HIGH),
+		GPIO_LOOKUP("locomo-gpio", 7, "MOD", GPIO_ACTIVE_HIGH),
+		{ },
+	},
+};
+
 static void poodle_poweroff(void)
 {
 	pxa_restart(REBOOT_HARD, NULL);
@@ -445,6 +487,13 @@ static void __init poodle_init(void)
 
 	platform_scoop_config = &poodle_pcmcia_config;
 
+	if (sharpsl_param.comadj != -1)
+		locomo_info.comadj = sharpsl_param.comadj;
+
+	gpiod_add_lookup_table(&poodle_audio_gpios_table);
+	gpiod_add_lookup_table(&poodle_bl_gpios_table);
+	gpiod_add_lookup_table(&poodle_lcd_gpios_table);
+
 	ret = platform_add_devices(devices, ARRAY_SIZE(devices));
 	if (ret)
 		pr_warn("poodle: Unable to register LoCoMo device\n");
@@ -455,6 +504,7 @@ static void __init poodle_init(void)
 	pxa_set_ficp_info(&poodle_ficp_platform_data);
 	pxa_set_i2c_info(NULL);
 	i2c_register_board_info(0, ARRAY_AND_SIZE(poodle_i2c_devices));
+	i2c_register_board_info(1, ARRAY_AND_SIZE(locomo_i2c_devs));
 	poodle_init_spi();
 	regulator_has_full_constraints();
 }
-- 
2.1.4


^ permalink raw reply related

* [PATCH v3 15/17] ARM: pxa: poodle: don't preallocate IRQ space for locomo
From: Dmitry Eremin-Solenikov @ 2015-05-17 16:27 UTC (permalink / raw)
  To: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Dmitry Torokhov, Bryan Wu,
	Richard Purdie, Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami
  Cc: linux-arm-kernel, linux-gpio, linux-input, linux-leds, linux-spi,
	linux-fbdev, alsa-devel
In-Reply-To: <1431880077-26321-1-git-send-email-dbaryshkov@gmail.com>

As new locomo driver supports SPARSE_IRQ, don't preallocate NR_IRQS
space for it on poodle.

Acked-by: Robert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
 arch/arm/mach-pxa/include/mach/poodle.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/mach-pxa/include/mach/poodle.h b/arch/arm/mach-pxa/include/mach/poodle.h
index 5905cf1..71b6383 100644
--- a/arch/arm/mach-pxa/include/mach/poodle.h
+++ b/arch/arm/mach-pxa/include/mach/poodle.h
@@ -81,7 +81,7 @@
 #define POODLE_GPIO_L_LCLK	(POODLE_SCOOP_GPIO_BASE + 10)
 #define POODLE_GPIO_HS_OUT	(POODLE_SCOOP_GPIO_BASE + 11)
 
-#define POODLE_NR_IRQS		(IRQ_BOARD_START + 4)	/* 4 for LoCoMo */
+#define POODLE_NR_IRQS		IRQ_BOARD_START
 
 extern struct platform_device poodle_locomo_device;
 
-- 
2.1.4


^ permalink raw reply related

* [PATCH v3 16/17] video: backlight: drop old locomo bl/lcd driver
From: Dmitry Eremin-Solenikov @ 2015-05-17 16:27 UTC (permalink / raw)
  To: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Dmitry Torokhov, Bryan Wu,
	Richard Purdie, Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami
  Cc: linux-arm-kernel, linux-gpio, linux-input, linux-leds, linux-spi,
	linux-fbdev, alsa-devel
In-Reply-To: <1431880077-26321-1-git-send-email-dbaryshkov@gmail.com>

Old locomolcd driver is now completely obsolete by new locomo_bl and
locomo_lcd drivers, so let's drop it.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
 drivers/video/backlight/locomolcd.c | 255 ------------------------------------
 1 file changed, 255 deletions(-)
 delete mode 100644 drivers/video/backlight/locomolcd.c

diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c
deleted file mode 100644
index 6c3ec42..0000000
--- a/drivers/video/backlight/locomolcd.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Backlight control code for Sharp Zaurus SL-5500
- *
- * Copyright 2005 John Lenz <lenz@cs.wisc.edu>
- * Maintainer: Pavel Machek <pavel@ucw.cz> (unless John wants to :-)
- * GPL v2
- *
- * This driver assumes single CPU. That's okay, because collie is
- * slightly old hardware, and no one is going to retrofit second CPU to
- * old PDA.
- */
-
-/* LCD power functions */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/fb.h>
-#include <linux/backlight.h>
-
-#include <asm/hardware/locomo.h>
-#include <asm/irq.h>
-#include <asm/mach/sharpsl_param.h>
-#include <asm/mach-types.h>
-
-#include "../../../arch/arm/mach-sa1100/generic.h"
-
-static struct backlight_device *locomolcd_bl_device;
-static struct locomo_dev *locomolcd_dev;
-static unsigned long locomolcd_flags;
-#define LOCOMOLCD_SUSPENDED     0x01
-
-static void locomolcd_on(int comadj)
-{
-	locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 0);
-	locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 1);
-	mdelay(2);
-
-	locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 0);
-	locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 1);
-	mdelay(2);
-
-	locomo_m62332_senddata(locomolcd_dev, comadj, 0);
-	mdelay(5);
-
-	locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 0);
-	locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 1);
-	mdelay(10);
-
-	/* TFTCRST | CPSOUT=0 | CPSEN */
-	locomo_writel(0x01, locomolcd_dev->mapbase + LOCOMO_TC);
-
-	/* Set CPSD */
-	locomo_writel(6, locomolcd_dev->mapbase + LOCOMO_CPSD);
-
-	/* TFTCRST | CPSOUT=0 | CPSEN */
-	locomo_writel((0x04 | 0x01), locomolcd_dev->mapbase + LOCOMO_TC);
-	mdelay(10);
-
-	locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 0);
-	locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 1);
-}
-
-static void locomolcd_off(int comadj)
-{
-	/* TFTCRST=1 | CPSOUT=1 | CPSEN = 0 */
-	locomo_writel(0x06, locomolcd_dev->mapbase + LOCOMO_TC);
-	mdelay(1);
-
-	locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 0);
-	mdelay(110);
-
-	locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 0);
-	mdelay(700);
-
-	/* TFTCRST=0 | CPSOUT=0 | CPSEN = 0 */
-	locomo_writel(0, locomolcd_dev->mapbase + LOCOMO_TC);
-	locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 0);
-	locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 0);
-}
-
-void locomolcd_power(int on)
-{
-	int comadj = sharpsl_param.comadj;
-	unsigned long flags;
-
-	local_irq_save(flags);
-
-	if (!locomolcd_dev) {
-		local_irq_restore(flags);
-		return;
-	}
-
-	/* read comadj */
-	if (comadj = -1 && machine_is_collie())
-		comadj = 128;
-	if (comadj = -1 && machine_is_poodle())
-		comadj = 118;
-
-	if (on)
-		locomolcd_on(comadj);
-	else
-		locomolcd_off(comadj);
-
-	local_irq_restore(flags);
-}
-EXPORT_SYMBOL(locomolcd_power);
-
-static int current_intensity;
-
-static int locomolcd_set_intensity(struct backlight_device *bd)
-{
-	int intensity = bd->props.brightness;
-
-	if (bd->props.power != FB_BLANK_UNBLANK)
-		intensity = 0;
-	if (bd->props.fb_blank != FB_BLANK_UNBLANK)
-		intensity = 0;
-	if (locomolcd_flags & LOCOMOLCD_SUSPENDED)
-		intensity = 0;
-
-	switch (intensity) {
-	/*
-	 * AC and non-AC are handled differently,
-	 * but produce same results in sharp code?
-	 */
-	case 0:
-		locomo_frontlight_set(locomolcd_dev, 0, 0, 161);
-		break;
-	case 1:
-		locomo_frontlight_set(locomolcd_dev, 117, 0, 161);
-		break;
-	case 2:
-		locomo_frontlight_set(locomolcd_dev, 163, 0, 148);
-		break;
-	case 3:
-		locomo_frontlight_set(locomolcd_dev, 194, 0, 161);
-		break;
-	case 4:
-		locomo_frontlight_set(locomolcd_dev, 194, 1, 161);
-		break;
-	default:
-		return -ENODEV;
-	}
-	current_intensity = intensity;
-	return 0;
-}
-
-static int locomolcd_get_intensity(struct backlight_device *bd)
-{
-	return current_intensity;
-}
-
-static const struct backlight_ops locomobl_data = {
-	.get_brightness = locomolcd_get_intensity,
-	.update_status  = locomolcd_set_intensity,
-};
-
-#ifdef CONFIG_PM_SLEEP
-static int locomolcd_suspend(struct device *dev)
-{
-	locomolcd_flags |= LOCOMOLCD_SUSPENDED;
-	locomolcd_set_intensity(locomolcd_bl_device);
-	return 0;
-}
-
-static int locomolcd_resume(struct device *dev)
-{
-	locomolcd_flags &= ~LOCOMOLCD_SUSPENDED;
-	locomolcd_set_intensity(locomolcd_bl_device);
-	return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(locomolcd_pm_ops, locomolcd_suspend, locomolcd_resume);
-
-static int locomolcd_probe(struct locomo_dev *ldev)
-{
-	struct backlight_properties props;
-	unsigned long flags;
-
-	local_irq_save(flags);
-	locomolcd_dev = ldev;
-
-	locomo_gpio_set_dir(ldev->dev.parent, LOCOMO_GPIO_FL_VR, 0);
-
-	/*
-	 * the poodle_lcd_power function is called for the first time
-	 * from fs_initcall, which is before locomo is activated.
-	 * We need to recall poodle_lcd_power here
-	 */
-	if (machine_is_poodle())
-		locomolcd_power(1);
-
-	local_irq_restore(flags);
-
-	memset(&props, 0, sizeof(struct backlight_properties));
-	props.type = BACKLIGHT_RAW;
-	props.max_brightness = 4;
-	locomolcd_bl_device = backlight_device_register("locomo-bl",
-							&ldev->dev, NULL,
-							&locomobl_data, &props);
-
-	if (IS_ERR(locomolcd_bl_device))
-		return PTR_ERR(locomolcd_bl_device);
-
-	/* Set up frontlight so that screen is readable */
-	locomolcd_bl_device->props.brightness = 2;
-	locomolcd_set_intensity(locomolcd_bl_device);
-
-	return 0;
-}
-
-static int locomolcd_remove(struct locomo_dev *dev)
-{
-	unsigned long flags;
-
-	locomolcd_bl_device->props.brightness = 0;
-	locomolcd_bl_device->props.power = 0;
-	locomolcd_set_intensity(locomolcd_bl_device);
-
-	backlight_device_unregister(locomolcd_bl_device);
-	local_irq_save(flags);
-	locomolcd_dev = NULL;
-	local_irq_restore(flags);
-	return 0;
-}
-
-static struct locomo_driver poodle_lcd_driver = {
-	.drv = {
-		.name	= "locomo-backlight",
-		.pm	= &locomolcd_pm_ops,
-	},
-	.devid	= LOCOMO_DEVID_BACKLIGHT,
-	.probe	= locomolcd_probe,
-	.remove	= locomolcd_remove,
-};
-
-static int __init locomolcd_init(void)
-{
-	return locomo_driver_register(&poodle_lcd_driver);
-}
-
-static void __exit locomolcd_exit(void)
-{
-	locomo_driver_unregister(&poodle_lcd_driver);
-}
-
-module_init(locomolcd_init);
-module_exit(locomolcd_exit);
-
-MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>, Pavel Machek <pavel@ucw.cz>");
-MODULE_DESCRIPTION("Collie LCD driver");
-MODULE_LICENSE("GPL");
-- 
2.1.4


^ permalink raw reply related

* Re: [PATCH] staging: sm750fb: fix typo in fb_videomode Array
From: Sudip Mukherjee @ 2015-05-18  5:16 UTC (permalink / raw)
  To: linux-fbdev
In-Reply-To: <20150516193128.GA1534@x230-arch.Speedport_W_724V_01011602_00_001>

On Sat, May 16, 2015 at 09:31:28PM +0200, Michel von Czettritz wrote:
> It appears that 'FB_SYNC_HOR_HIGH_ACT' should be assined to 'sync'
> and 'FB_VMODE_NONINTERLACED' is a flag for 'vmode'.
> 
<snip>
> 
> diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c
> index 77310ff..8ff29c6 100644
> --- a/drivers/staging/sm750fb/sm750.c
> +++ b/drivers/staging/sm750fb/sm750.c
> @@ -94,7 +94,8 @@ static const struct fb_videomode lynx750_ext[] = {
>  	 FB_VMODE_NONINTERLACED},
>  
>  	{NULL, 60, 1360, 768, 11804, 208, 64, 23, 1, 144, 3,
> -	 FB_SYNC_HOR_HIGH_ACT|FB_VMODE_NONINTERLACED},
> +	 FB_SYNC_HOR_HIGH_ACT,
> +	 FB_VMODE_NONINTERLACED},

good catch. But, see that all the entries are having:
        FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
        FB_VMODE_NONINTERLACED

this is the only entry with a different flag settings. moreover this
entry is for 1360x768@60 , see the next entry and that is also for
1360x768@60 with the correct flags. So my opinion this entry is wrong.

Send a patch instead to delete this entry and I can check that on the
hardware.

regards
sudip

	
>  
>  	/*	1360 x 768	[1.77083:1]	*/
>  	{NULL,  60, 1360, 768, 11804, 208,  64, 23, 1, 144, 3,
> -- 
> 2.3.7
> 

^ permalink raw reply

* Re: [PATCH v3 02/17] leds: port locomo leds driver to new locomo core
From: Jacek Anaszewski @ 2015-05-18  8:37 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Dmitry Torokhov, Bryan Wu,
	Richard Purdie, Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami, linux-arm-kernel, linux-gpio, linux-input,
	linux-leds, linux-spi, linux-fbdev, alsa-devel
In-Reply-To: <1431880077-26321-3-git-send-email-dbaryshkov@gmail.com>

Hi Dmitry,

On 05/17/2015 06:27 PM, Dmitry Eremin-Solenikov wrote:
> Adapt locomo leds driver to new locomo core setup.
>
> Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
> ---
>   drivers/leds/Kconfig       |   2 +-
>   drivers/leds/leds-locomo.c | 117 +++++++++++++++++++++++----------------------
>   2 files changed, 61 insertions(+), 58 deletions(-)

Acked-by: Jacek Anaszewski <j.anaszewski@samsung.com>

-- 
Best Regards,
Jacek Anaszewski

^ permalink raw reply

* Re: [PATCH] backlight: pwm_bl: Simplify usage of devm_gpiod_get_optional
From: Lee Jones @ 2015-05-18  8:47 UTC (permalink / raw)
  To: Axel Lin
  Cc: linux-pwm, linux-fbdev, Thierry Reding, Alexandre Courbot,
	Jingoo Han
In-Reply-To: <1431785290.6638.1.camel@ingics.com>

On Sat, 16 May 2015, Axel Lin wrote:

> Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions),
> the gpiod_get* functions take an additional parameter that allows to
> specify direction and initial value for output.
> Simplify the usage of devm_gpiod_get_optional accordingly.
> 
> Signed-off-by: Axel Lin <axel.lin@ingics.com>
> ---
>  drivers/video/backlight/pwm_bl.c | 6 ++----
>  1 file changed, 2 insertions(+), 4 deletions(-)

Applied, thanks.

> diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
> index 3a145a6..57cb9ec 100644
> --- a/drivers/video/backlight/pwm_bl.c
> +++ b/drivers/video/backlight/pwm_bl.c
> @@ -241,7 +241,8 @@ static int pwm_backlight_probe(struct platform_device *pdev)
>  	pb->dev = &pdev->dev;
>  	pb->enabled = false;
>  
> -	pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable");
> +	pb->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
> +						  GPIOD_OUT_HIGH);
>  	if (IS_ERR(pb->enable_gpio)) {
>  		ret = PTR_ERR(pb->enable_gpio);
>  		goto err_alloc;
> @@ -263,9 +264,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
>  		pb->enable_gpio = gpio_to_desc(data->enable_gpio);
>  	}
>  
> -	if (pb->enable_gpio)
> -		gpiod_direction_output(pb->enable_gpio, 1);
> -
>  	pb->power_supply = devm_regulator_get(&pdev->dev, "power");
>  	if (IS_ERR(pb->power_supply)) {
>  		ret = PTR_ERR(pb->power_supply);

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply

* [PATCH] radeonfb: Deinline large functions
From: Denys Vlasenko @ 2015-05-18 14:25 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: Denys Vlasenko, Jean-Christophe Plagniol-Villard, Tomi Valkeinen,
	Richard Purdie, Chris Wilson, David Airlie, Alex Deucher,
	Ben Skeggs, Zhang Rui, Len Brown, Jesse Barnes, Krzysztof Helt,
	Dave Airlie, linux-kernel, linux-fbdev

With this .config: http://busybox.net/~vda/kernel_config,
after uninlining these functions have sizes and callsite counts
as follows:

__OUTPLLP: 61 bytes, 12 callsites
__INPLL:   79 bytes, 150 callsites
__OUTPLL:  82 bytes, 138 callsites
_OUTREGP: 101 bytes, 8 callsites
_radeon_msleep:      66 bytes, 18 callsites
_radeon_fifo_wait:   83 bytes, 24 callsites
_radeon_engine_idle: 92 bytes, 10 callsites
radeon_engine_flush: 105 bytes, 2 callsites
radeon_pll_errata_after_index_slow: 31 bytes, 11 callsites
radeon_pll_errata_after_data_slow:  91 bytes, 9 callsites

radeon_pll_errata_after_FOO functions are split into two parts:
the inlined part which checks corresponding rinfo->errata bit,
and out-of-line part which performs workaround magic per se.

Reduction in code size is about 49,500 bytes:

    text     data      bss       dec     hex filename
85789648 22294616 20627456 128711720 7abfc28 vmlinux.before
85740176 22294680 20627456 128662312 7ab3b28 vmlinux

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
Cc: Tomi Valkeinen <tomi.valkeinen@ti.com>
Cc: Richard Purdie <rpurdie@rpsys.net>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: David Airlie <airlied@linux.ie>
Cc: Alex Deucher <alexdeucher@gmail.com>
Cc: Ben Skeggs <bskeggs@redhat.com>
Cc: Zhang Rui <rui.zhang@intel.com>
Cc: Len Brown <lenb@kernel.org>
Cc: Jesse Barnes <jbarnes@virtuousgeek.org>
Cc: Krzysztof Helt <krzysztof.h1@poczta.fm>
Cc: Dave Airlie <airlied@redhat.com>
Cc: linux-kernel@vger.kernel.org
Cc: linux-fbdev@vger.kernel.org
---
 drivers/video/fbdev/aty/radeon_base.c | 133 ++++++++++++++++++++++++++++++-
 drivers/video/fbdev/aty/radeonfb.h    | 144 ++++------------------------------
 2 files changed, 146 insertions(+), 131 deletions(-)

diff --git a/drivers/video/fbdev/aty/radeon_base.c b/drivers/video/fbdev/aty/radeon_base.c
index 26d80a4..bd9b6ca 100644
--- a/drivers/video/fbdev/aty/radeon_base.c
+++ b/drivers/video/fbdev/aty/radeon_base.c
@@ -282,9 +282,138 @@ static int backlight = 1;
 static int backlight = 0;
 #endif
 
-/*
- * prototypes
+/* Note about this function: we have some rare cases where we must not schedule,
+ * this typically happen with our special "wake up early" hook which allows us to
+ * wake up the graphic chip (and thus get the console back) before everything else
+ * on some machines that support that mechanism. At this point, interrupts are off
+ * and scheduling is not permitted
  */
+void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms)
+{
+	if (rinfo->no_schedule || oops_in_progress)
+		mdelay(ms);
+	else
+		msleep(ms);
+}
+
+void radeon_pll_errata_after_index_slow(struct radeonfb_info *rinfo)
+{
+	/* Called if (rinfo->errata & CHIP_ERRATA_PLL_DUMMYREADS) is set */
+	(void)INREG(CLOCK_CNTL_DATA);
+	(void)INREG(CRTC_GEN_CNTL);
+}
+
+void radeon_pll_errata_after_data_slow(struct radeonfb_info *rinfo)
+{
+	if (rinfo->errata & CHIP_ERRATA_PLL_DELAY) {
+		/* we can't deal with posted writes here ... */
+		_radeon_msleep(rinfo, 5);
+	}
+	if (rinfo->errata & CHIP_ERRATA_R300_CG) {
+		u32 save, tmp;
+		save = INREG(CLOCK_CNTL_INDEX);
+		tmp = save & ~(0x3f | PLL_WR_EN);
+		OUTREG(CLOCK_CNTL_INDEX, tmp);
+		tmp = INREG(CLOCK_CNTL_DATA);
+		OUTREG(CLOCK_CNTL_INDEX, save);
+	}
+}
+
+void _OUTREGP(struct radeonfb_info *rinfo, u32 addr, u32 val, u32 mask)
+{
+	unsigned long flags;
+	unsigned int tmp;
+
+	spin_lock_irqsave(&rinfo->reg_lock, flags);
+	tmp = INREG(addr);
+	tmp &= (mask);
+	tmp |= (val);
+	OUTREG(addr, tmp);
+	spin_unlock_irqrestore(&rinfo->reg_lock, flags);
+}
+
+u32 __INPLL(struct radeonfb_info *rinfo, u32 addr)
+{
+	u32 data;
+
+	OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000003f);
+	radeon_pll_errata_after_index(rinfo);
+	data = INREG(CLOCK_CNTL_DATA);
+	radeon_pll_errata_after_data(rinfo);
+	return data;
+}
+
+void __OUTPLL(struct radeonfb_info *rinfo, unsigned int index, u32 val)
+{
+	OUTREG8(CLOCK_CNTL_INDEX, (index & 0x0000003f) | 0x00000080);
+	radeon_pll_errata_after_index(rinfo);
+	OUTREG(CLOCK_CNTL_DATA, val);
+	radeon_pll_errata_after_data(rinfo);
+}
+
+void __OUTPLLP(struct radeonfb_info *rinfo, unsigned int index,
+			     u32 val, u32 mask)
+{
+	unsigned int tmp;
+
+	tmp  = __INPLL(rinfo, index);
+	tmp &= (mask);
+	tmp |= (val);
+	__OUTPLL(rinfo, index, tmp);
+}
+
+void _radeon_fifo_wait(struct radeonfb_info *rinfo, int entries)
+{
+	int i;
+
+	for (i=0; i<2000000; i++) {
+		if ((INREG(RBBM_STATUS) & 0x7f) >= entries)
+			return;
+		udelay(1);
+	}
+	printk(KERN_ERR "radeonfb: FIFO Timeout !\n");
+}
+
+void radeon_engine_flush(struct radeonfb_info *rinfo)
+{
+	int i;
+
+	/* Initiate flush */
+	OUTREGP(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL,
+	        ~RB2D_DC_FLUSH_ALL);
+
+	/* Ensure FIFO is empty, ie, make sure the flush commands
+	 * has reached the cache
+	 */
+	_radeon_fifo_wait(rinfo, 64);
+
+	/* Wait for the flush to complete */
+	for (i=0; i < 2000000; i++) {
+		if (!(INREG(DSTCACHE_CTLSTAT) & RB2D_DC_BUSY))
+			return;
+		udelay(1);
+	}
+	printk(KERN_ERR "radeonfb: Flush Timeout !\n");
+}
+
+void _radeon_engine_idle(struct radeonfb_info *rinfo)
+{
+	int i;
+
+	/* ensure FIFO is empty before waiting for idle */
+	_radeon_fifo_wait(rinfo, 64);
+
+	for (i=0; i<2000000; i++) {
+		if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) = 0) {
+			radeon_engine_flush(rinfo);
+			return;
+		}
+		udelay(1);
+	}
+	printk(KERN_ERR "radeonfb: Idle Timeout !\n");
+}
+
+
 
 static void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
 {
diff --git a/drivers/video/fbdev/aty/radeonfb.h b/drivers/video/fbdev/aty/radeonfb.h
index cb84604..85b80cd 100644
--- a/drivers/video/fbdev/aty/radeonfb.h
+++ b/drivers/video/fbdev/aty/radeonfb.h
@@ -370,20 +370,7 @@ struct radeonfb_info {
  * IO macros
  */
 
-/* Note about this function: we have some rare cases where we must not schedule,
- * this typically happen with our special "wake up early" hook which allows us to
- * wake up the graphic chip (and thus get the console back) before everything else
- * on some machines that support that mechanism. At this point, interrupts are off
- * and scheduling is not permitted
- */
-static inline void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms)
-{
-	if (rinfo->no_schedule || oops_in_progress)
-		mdelay(ms);
-	else
-		msleep(ms);
-}
-
+void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms);
 
 #define INREG8(addr)		readb((rinfo->mmio_base)+addr)
 #define OUTREG8(addr,val)	writeb(val, (rinfo->mmio_base)+addr)
@@ -392,19 +379,7 @@ static inline void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms)
 #define INREG(addr)		readl((rinfo->mmio_base)+addr)
 #define OUTREG(addr,val)	writel(val, (rinfo->mmio_base)+addr)
 
-static inline void _OUTREGP(struct radeonfb_info *rinfo, u32 addr,
-		       u32 val, u32 mask)
-{
-	unsigned long flags;
-	unsigned int tmp;
-
-	spin_lock_irqsave(&rinfo->reg_lock, flags);
-	tmp = INREG(addr);
-	tmp &= (mask);
-	tmp |= (val);
-	OUTREG(addr, tmp);
-	spin_unlock_irqrestore(&rinfo->reg_lock, flags);
-}
+void _OUTREGP(struct radeonfb_info *rinfo, u32 addr, u32 val, u32 mask);
 
 #define OUTREGP(addr,val,mask)	_OUTREGP(rinfo, addr, val,mask)
 
@@ -425,64 +400,24 @@ static inline void _OUTREGP(struct radeonfb_info *rinfo, u32 addr,
  * possible exception to this rule is the call to unblank(), which may
  * be done at irq time if an oops is in progress.
  */
+void radeon_pll_errata_after_index_slow(struct radeonfb_info *rinfo);
 static inline void radeon_pll_errata_after_index(struct radeonfb_info *rinfo)
 {
-	if (!(rinfo->errata & CHIP_ERRATA_PLL_DUMMYREADS))
-		return;
-
-	(void)INREG(CLOCK_CNTL_DATA);
-	(void)INREG(CRTC_GEN_CNTL);
+	if (rinfo->errata & CHIP_ERRATA_PLL_DUMMYREADS)
+		radeon_pll_errata_after_index_slow(rinfo);
 }
 
+void radeon_pll_errata_after_data_slow(struct radeonfb_info *rinfo);
 static inline void radeon_pll_errata_after_data(struct radeonfb_info *rinfo)
 {
-	if (rinfo->errata & CHIP_ERRATA_PLL_DELAY) {
-		/* we can't deal with posted writes here ... */
-		_radeon_msleep(rinfo, 5);
-	}
-	if (rinfo->errata & CHIP_ERRATA_R300_CG) {
-		u32 save, tmp;
-		save = INREG(CLOCK_CNTL_INDEX);
-		tmp = save & ~(0x3f | PLL_WR_EN);
-		OUTREG(CLOCK_CNTL_INDEX, tmp);
-		tmp = INREG(CLOCK_CNTL_DATA);
-		OUTREG(CLOCK_CNTL_INDEX, save);
-	}
-}
-
-static inline u32 __INPLL(struct radeonfb_info *rinfo, u32 addr)
-{
-	u32 data;
-
-	OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000003f);
-	radeon_pll_errata_after_index(rinfo);
-	data = INREG(CLOCK_CNTL_DATA);
-	radeon_pll_errata_after_data(rinfo);
-	return data;
-}
-
-static inline void __OUTPLL(struct radeonfb_info *rinfo, unsigned int index,
-			    u32 val)
-{
-
-	OUTREG8(CLOCK_CNTL_INDEX, (index & 0x0000003f) | 0x00000080);
-	radeon_pll_errata_after_index(rinfo);
-	OUTREG(CLOCK_CNTL_DATA, val);
-	radeon_pll_errata_after_data(rinfo);
-}
-
-
-static inline void __OUTPLLP(struct radeonfb_info *rinfo, unsigned int index,
-			     u32 val, u32 mask)
-{
-	unsigned int tmp;
-
-	tmp  = __INPLL(rinfo, index);
-	tmp &= (mask);
-	tmp |= (val);
-	__OUTPLL(rinfo, index, tmp);
+	if (rinfo->errata & (CHIP_ERRATA_PLL_DELAY|CHIP_ERRATA_R300_CG))
+		radeon_pll_errata_after_data_slow(rinfo);
 }
 
+u32 __INPLL(struct radeonfb_info *rinfo, u32 addr);
+void __OUTPLL(struct radeonfb_info *rinfo, unsigned int index, u32 val);
+void __OUTPLLP(struct radeonfb_info *rinfo, unsigned int index,
+			     u32 val, u32 mask);
 
 #define INPLL(addr)			__INPLL(rinfo, addr)
 #define OUTPLL(index, val)		__OUTPLL(rinfo, index, val)
@@ -532,58 +467,9 @@ static inline u32 radeon_get_dstbpp(u16 depth)
  * 2D Engine helper routines
  */
 
-static inline void _radeon_fifo_wait(struct radeonfb_info *rinfo, int entries)
-{
-	int i;
-
-	for (i=0; i<2000000; i++) {
-		if ((INREG(RBBM_STATUS) & 0x7f) >= entries)
-			return;
-		udelay(1);
-	}
-	printk(KERN_ERR "radeonfb: FIFO Timeout !\n");
-}
-
-static inline void radeon_engine_flush (struct radeonfb_info *rinfo)
-{
-	int i;
-
-	/* Initiate flush */
-	OUTREGP(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL,
-	        ~RB2D_DC_FLUSH_ALL);
-
-	/* Ensure FIFO is empty, ie, make sure the flush commands
-	 * has reached the cache
-	 */
-	_radeon_fifo_wait (rinfo, 64);
-
-	/* Wait for the flush to complete */
-	for (i=0; i < 2000000; i++) {
-		if (!(INREG(DSTCACHE_CTLSTAT) & RB2D_DC_BUSY))
-			return;
-		udelay(1);
-	}
-	printk(KERN_ERR "radeonfb: Flush Timeout !\n");
-}
-
-
-static inline void _radeon_engine_idle(struct radeonfb_info *rinfo)
-{
-	int i;
-
-	/* ensure FIFO is empty before waiting for idle */
-	_radeon_fifo_wait (rinfo, 64);
-
-	for (i=0; i<2000000; i++) {
-		if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) = 0) {
-			radeon_engine_flush (rinfo);
-			return;
-		}
-		udelay(1);
-	}
-	printk(KERN_ERR "radeonfb: Idle Timeout !\n");
-}
-
+void _radeon_fifo_wait(struct radeonfb_info *rinfo, int entries);
+void radeon_engine_flush(struct radeonfb_info *rinfo);
+void _radeon_engine_idle(struct radeonfb_info *rinfo);
 
 #define radeon_engine_idle()		_radeon_engine_idle(rinfo)
 #define radeon_fifo_wait(entries)	_radeon_fifo_wait(rinfo,entries)
-- 
1.8.1.4


^ permalink raw reply related

* Re: [PATCH v3 03/17] input: convert LoCoMo keyboard driver to use new locomo core
From: Dmitry Torokhov @ 2015-05-18 16:50 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Bryan Wu, Richard Purdie,
	Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami, linux-arm-kernel, linux-gpio, linux-input,
	linux-leds, linux-spi, linux-fbdev, alsa-devel
In-Reply-To: <1431880077-26321-4-git-send-email-dbaryshkov@gmail.com>

On Sun, May 17, 2015 at 07:27:43PM +0300, Dmitry Eremin-Solenikov wrote:
> As LoCoMo is switching to new device model, adapt keyboard driver to
> support new locomo core driver.
> 
> Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
> ---
>  drivers/input/keyboard/Kconfig     |   2 +-
>  drivers/input/keyboard/locomokbd.c | 256 ++++++++++++++++++-------------------
>  2 files changed, 125 insertions(+), 133 deletions(-)
> 
> diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
> index 106fbac..9a20487 100644
> --- a/drivers/input/keyboard/Kconfig
> +++ b/drivers/input/keyboard/Kconfig
> @@ -337,7 +337,7 @@ config KEYBOARD_LM8333
>  
>  config KEYBOARD_LOCOMO
>  	tristate "LoCoMo Keyboard Support"
> -	depends on SHARP_LOCOMO
> +	depends on MFD_LOCOMO
>  	help
>  	  Say Y here if you are running Linux on a Sharp Zaurus Collie or Poodle based PDA
>  
> diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
> index c94d610..1657bc0 100644
> --- a/drivers/input/keyboard/locomokbd.c
> +++ b/drivers/input/keyboard/locomokbd.c
> @@ -23,28 +23,25 @@
>   *
>   */
>  
> -#include <linux/slab.h>
> -#include <linux/module.h>
> +#include <linux/delay.h>
>  #include <linux/init.h>
>  #include <linux/input.h>
> -#include <linux/delay.h>
> -#include <linux/device.h>
>  #include <linux/interrupt.h>
> -#include <linux/ioport.h>
> -
> -#include <asm/hardware/locomo.h>
> -#include <asm/irq.h>
> -
> -MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
> -MODULE_DESCRIPTION("LoCoMo keyboard driver");
> -MODULE_LICENSE("GPL");
> -
> -#define LOCOMOKBD_NUMKEYS	128
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +#include <linux/mfd/locomo.h>
>  
>  #define KEY_ACTIVITY		KEY_F16
>  #define KEY_CONTACT		KEY_F18
>  #define KEY_CENTER		KEY_F15
>  
> +#define KB_ROWS			16
> +#define KB_COLS			8
> +#define LOCOMOKBD_NUMKEYS	(KB_ROWS * KB_COLS)
> +#define SCANCODE(c, r)		(((c)<<4) + (r) + 1)
> +
>  static const unsigned char
>  locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
>  	0, KEY_ESC, KEY_ACTIVITY, 0, 0, 0, 0, 0, 0, 0,				/* 0 - 9 */
> @@ -53,7 +50,7 @@ locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
>  	0, 0, 0, KEY_CENTER, 0, KEY_MAIL, 0, 0, 0, 0,				/* 30 - 39 */
>  	0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RIGHT,					/* 40 - 49 */
>  	KEY_UP, KEY_LEFT, 0, 0, KEY_P, 0, KEY_O, KEY_I, KEY_Y, KEY_T,		/* 50 - 59 */
> -	KEY_E, KEY_W, 0, 0, 0, 0, KEY_DOWN, KEY_ENTER, 0, 0,			/* 60 - 69 */
> +	KEY_E, KEY_W, 0, 0, 0, 0, KEY_DOWN, KEY_KPENTER, 0, 0,			/* 60 - 69 */

Please split this into a separate patch or at least call it out in the
changelog.


>  	KEY_BACKSPACE, 0, KEY_L, KEY_U, KEY_H, KEY_R, KEY_D, KEY_Q, 0, 0,	/* 70 - 79 */
>  	0, 0, 0, 0, 0, 0, KEY_ENTER, KEY_RIGHTSHIFT, KEY_K, KEY_J,		/* 80 - 89 */
>  	KEY_G, KEY_F, KEY_X, KEY_S, 0, 0, 0, 0, 0, 0,				/* 90 - 99 */
> @@ -62,20 +59,14 @@ locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
>  	KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0		/* 120 - 128 */
>  };
>  
> -#define KB_ROWS			16
> -#define KB_COLS			8
> -#define KB_ROWMASK(r)		(1 << (r))
> -#define SCANCODE(c,r)		( ((c)<<4) + (r) + 1 )
> -
>  #define KB_DELAY		8
> -#define SCAN_INTERVAL		(HZ/10)
>  
>  struct locomokbd {
>  	unsigned char keycode[LOCOMOKBD_NUMKEYS];
>  	struct input_dev *input;
> -	char phys[32];
>  
> -	unsigned long base;
> +	struct regmap *regmap;
> +	int irq;
>  	spinlock_t lock;
>  
>  	struct timer_list timer;
> @@ -84,37 +75,33 @@ struct locomokbd {
>  };
>  
>  /* helper functions for reading the keyboard matrix */
> -static inline void locomokbd_charge_all(unsigned long membase)
> +static void locomokbd_charge_all(struct locomokbd *locomokbd)
>  {
> -	locomo_writel(0x00FF, membase + LOCOMO_KSC);
> +	regmap_write(locomokbd->regmap, LOCOMO_KSC, 0x00ff);
>  }
>  
> -static inline void locomokbd_activate_all(unsigned long membase)
> +static void locomokbd_activate_all(struct locomokbd *locomokbd)
>  {
> -	unsigned long r;
> -
> -	locomo_writel(0, membase + LOCOMO_KSC);
> -	r = locomo_readl(membase + LOCOMO_KIC);
> -	r &= 0xFEFF;
> -	locomo_writel(r, membase + LOCOMO_KIC);
> +	regmap_write(locomokbd->regmap, LOCOMO_KSC, 0);
> +	regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x100, 0);
>  }
>  
> -static inline void locomokbd_activate_col(unsigned long membase, int col)
> +static void locomokbd_activate_col(struct locomokbd *locomokbd, int col)
>  {
>  	unsigned short nset;
>  	unsigned short nbset;
>  
> -	nset = 0xFF & ~(1 << col);
> +	nset = 0xFF & ~BIT(col);
>  	nbset = (nset << 8) + nset;
> -	locomo_writel(nbset, membase + LOCOMO_KSC);
> +	regmap_write(locomokbd->regmap, LOCOMO_KSC, nbset);
>  }
>  
> -static inline void locomokbd_reset_col(unsigned long membase, int col)
> +static void locomokbd_reset_col(struct locomokbd *locomokbd, int col)
>  {
>  	unsigned short nbset;
>  
> -	nbset = ((0xFF & ~(1 << col)) << 8) + 0xFF;
> -	locomo_writel(nbset, membase + LOCOMO_KSC);
> +	nbset = ((0xFF & ~BIT(col)) << 8) + 0xFF;
> +	regmap_write(locomokbd->regmap, LOCOMO_KSC, nbset);
>  }
>  
>  /*
> @@ -129,24 +116,25 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd)
>  	unsigned int row, col, rowd;
>  	unsigned long flags;
>  	unsigned int num_pressed;
> -	unsigned long membase = locomokbd->base;
> +	bool esc_pressed = false;
>  
>  	spin_lock_irqsave(&locomokbd->lock, flags);
>  
> -	locomokbd_charge_all(membase);
> +	locomokbd_charge_all(locomokbd);
>  
>  	num_pressed = 0;
>  	for (col = 0; col < KB_COLS; col++) {
> -
> -		locomokbd_activate_col(membase, col);
> +		udelay(KB_DELAY);
> +		locomokbd_activate_col(locomokbd, col);
>  		udelay(KB_DELAY);
>  
> -		rowd = ~locomo_readl(membase + LOCOMO_KIB);
> +		regmap_read(locomokbd->regmap, LOCOMO_KIB, &rowd);
> +		rowd = ~rowd;
>  		for (row = 0; row < KB_ROWS; row++) {
>  			unsigned int scancode, pressed, key;
>  
>  			scancode = SCANCODE(col, row);
> -			pressed = rowd & KB_ROWMASK(row);
> +			pressed = rowd & BIT(row);
>  			key = locomokbd->keycode[scancode];
>  
>  			input_report_key(locomokbd->input, key, pressed);
> @@ -158,30 +146,32 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd)
>  			/* The "Cancel/ESC" key is labeled "On/Off" on
>  			 * Collie and Poodle and should suspend the device
>  			 * if it was pressed for more than a second. */
> -			if (unlikely(key = KEY_ESC)) {
> -				if (!time_after(jiffies,
> -					locomokbd->suspend_jiffies + HZ))
> -					continue;
> -				if (locomokbd->count_cancel++
> -					!= (HZ/SCAN_INTERVAL + 1))
> -					continue;
> -				input_event(locomokbd->input, EV_PWR,
> -					KEY_SUSPEND, 1);
> -				locomokbd->suspend_jiffies = jiffies;
> -			} else
> -				locomokbd->count_cancel = 0;
> +			if (unlikely(key = KEY_ESC))
> +				esc_pressed = true;
>  		}
> -		locomokbd_reset_col(membase, col);
> +		locomokbd_reset_col(locomokbd, col);
>  	}
> -	locomokbd_activate_all(membase);
> +	locomokbd_activate_all(locomokbd);
>  
>  	input_sync(locomokbd->input);
>  
>  	/* if any keys are pressed, enable the timer */
>  	if (num_pressed)
> -		mod_timer(&locomokbd->timer, jiffies + SCAN_INTERVAL);
> +		mod_timer(&locomokbd->timer, jiffies + msecs_to_jiffies(100));
>  	else
> +		regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x10, 0x10);
> +
> +
> +	if (esc_pressed && time_after(jiffies,
> +		    locomokbd->suspend_jiffies + msecs_to_jiffies(1000))) {
> +		if (locomokbd->count_cancel++ > 20) {
> +			input_event(locomokbd->input, EV_PWR,
> +					KEY_SUSPEND, 1);
> +			locomokbd->suspend_jiffies = jiffies;
> +		}
> +	} else {
>  		locomokbd->count_cancel = 0;
> +	}
>  
>  	spin_unlock_irqrestore(&locomokbd->lock, flags);
>  }
> @@ -192,18 +182,17 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd)
>  static irqreturn_t locomokbd_interrupt(int irq, void *dev_id)
>  {
>  	struct locomokbd *locomokbd = dev_id;
> -	u16 r;
> +	unsigned int r;
>  
> -	r = locomo_readl(locomokbd->base + LOCOMO_KIC);
> +	regmap_read(locomokbd->regmap, LOCOMO_KIC, &r);
>  	if ((r & 0x0001) = 0)
>  		return IRQ_HANDLED;
>  
> -	locomo_writel(r & ~0x0100, locomokbd->base + LOCOMO_KIC); /* Ack */
> +	/* Mask and Ack */
> +	regmap_write(locomokbd->regmap, LOCOMO_KIC, r & ~0x110);
>  
> -	/** wait chattering delay **/
> -	udelay(100);
> +	mod_timer(&locomokbd->timer, jiffies + msecs_to_jiffies(1));
>  
> -	locomokbd_scankeyboard(locomokbd);
>  	return IRQ_HANDLED;
>  }
>  
> @@ -220,47 +209,39 @@ static void locomokbd_timer_callback(unsigned long data)
>  static int locomokbd_open(struct input_dev *dev)
>  {
>  	struct locomokbd *locomokbd = input_get_drvdata(dev);
> -	u16 r;
> -	
> -	r = locomo_readl(locomokbd->base + LOCOMO_KIC) | 0x0010;
> -	locomo_writel(r, locomokbd->base + LOCOMO_KIC);
> -	return 0;
> +
> +	return regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x10, 0x10);
>  }
>  
>  static void locomokbd_close(struct input_dev *dev)
>  {
>  	struct locomokbd *locomokbd = input_get_drvdata(dev);
> -	u16 r;
> -	
> -	r = locomo_readl(locomokbd->base + LOCOMO_KIC) & ~0x0010;
> -	locomo_writel(r, locomokbd->base + LOCOMO_KIC);
> +
> +	regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x10, 0x0);
> +
> +	del_timer_sync(&locomokbd->timer);
>  }
>  
> -static int locomokbd_probe(struct locomo_dev *dev)
> +static int locomokbd_probe(struct platform_device *dev)
>  {
>  	struct locomokbd *locomokbd;
>  	struct input_dev *input_dev;
>  	int i, err;
>  
> -	locomokbd = kzalloc(sizeof(struct locomokbd), GFP_KERNEL);
> -	input_dev = input_allocate_device();
> -	if (!locomokbd || !input_dev) {
> -		err = -ENOMEM;
> -		goto err_free_mem;
> -	}
> +	locomokbd = devm_kzalloc(&dev->dev, sizeof(struct locomokbd),
> +			GFP_KERNEL);
> +	if (!locomokbd)
> +		return -ENOMEM;
>  
> -	/* try and claim memory region */
> -	if (!request_mem_region((unsigned long) dev->mapbase,
> -				dev->length,
> -				LOCOMO_DRIVER_NAME(dev))) {
> -		err = -EBUSY;
> -		printk(KERN_ERR "locomokbd: Can't acquire access to io memory for keyboard\n");
> -		goto err_free_mem;
> -	}
> +	locomokbd->regmap = dev_get_regmap(dev->dev.parent, NULL);
> +	if (!locomokbd->regmap)
> +		return -EINVAL;
>  
> -	locomo_set_drvdata(dev, locomokbd);
> +	locomokbd->irq = platform_get_irq(dev, 0);
> +	if (locomokbd->irq < 0)
> +		return -ENXIO;
>  
> -	locomokbd->base = (unsigned long) dev->mapbase;
> +	platform_set_drvdata(dev, locomokbd);
>  
>  	spin_lock_init(&locomokbd->lock);
>  
> @@ -270,11 +251,13 @@ static int locomokbd_probe(struct locomo_dev *dev)
>  
>  	locomokbd->suspend_jiffies = jiffies;
>  
> -	locomokbd->input = input_dev;
> -	strcpy(locomokbd->phys, "locomokbd/input0");
> +	input_dev = devm_input_allocate_device(&dev->dev);
> +	if (!input_dev)
> +		return -ENOMEM;
>  
> +	locomokbd->input = input_dev;
>  	input_dev->name = "LoCoMo keyboard";
> -	input_dev->phys = locomokbd->phys;
> +	input_dev->phys = "locomokbd/input0";
>  	input_dev->id.bustype = BUS_HOST;
>  	input_dev->id.vendor = 0x0001;
>  	input_dev->id.product = 0x0001;
> @@ -291,72 +274,81 @@ static int locomokbd_probe(struct locomo_dev *dev)
>  
>  	input_set_drvdata(input_dev, locomokbd);
>  
> -	memcpy(locomokbd->keycode, locomokbd_keycode, sizeof(locomokbd->keycode));
> +	memcpy(locomokbd->keycode,
> +			locomokbd_keycode,
> +			sizeof(locomokbd->keycode));
> +
>  	for (i = 0; i < LOCOMOKBD_NUMKEYS; i++)
> -		set_bit(locomokbd->keycode[i], input_dev->keybit);
> -	clear_bit(0, input_dev->keybit);
> +		input_set_capability(input_dev, EV_KEY, locomokbd->keycode[i]);
> +	input_set_capability(input_dev, EV_PWR, KEY_SUSPEND);
> +	__set_bit(EV_REP, input_dev->evbit);
> +
> +	regmap_write(locomokbd->regmap, LOCOMO_KCMD, 1);
> +	regmap_write(locomokbd->regmap, LOCOMO_KSC, 0x0);
> +	regmap_write(locomokbd->regmap, LOCOMO_KIC, 0x0);
>  
>  	/* attempt to get the interrupt */
> -	err = request_irq(dev->irq[0], locomokbd_interrupt, 0, "locomokbd", locomokbd);
> +	err = devm_request_irq(&dev->dev, locomokbd->irq, locomokbd_interrupt,
> +			0, "locomokbd", locomokbd);
>  	if (err) {
> -		printk(KERN_ERR "locomokbd: Can't get irq for keyboard\n");
> -		goto err_release_region;
> +		dev_err(&dev->dev, "locomokbd: Can't get irq for keyboard\n");

No need for "locomokbd: " prefix it will come from dev_err.

> +		return err;
>  	}
>  
>  	err = input_register_device(locomokbd->input);
>  	if (err)
> -		goto err_free_irq;
> +		return err;
>  
>  	return 0;
>  
> - err_free_irq:
> -	free_irq(dev->irq[0], locomokbd);
> - err_release_region:
> -	release_mem_region((unsigned long) dev->mapbase, dev->length);
> -	locomo_set_drvdata(dev, NULL);
> - err_free_mem:
> -	input_free_device(input_dev);
> -	kfree(locomokbd);
> -
>  	return err;
>  }
>  
> -static int locomokbd_remove(struct locomo_dev *dev)
> +static int locomokbd_remove(struct platform_device *dev)
> +{
> +	return 0;
> +}

No need for the empty stub.

> +
> +static int __maybe_unused locomokbd_suspend(struct device *dev)
>  {
> -	struct locomokbd *locomokbd = locomo_get_drvdata(dev);
> +	struct locomokbd *locomokbd = dev_get_drvdata(dev);
>  
> -	free_irq(dev->irq[0], locomokbd);
> +	regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x10, 0x0);
>  
>  	del_timer_sync(&locomokbd->timer);
>  
> -	input_unregister_device(locomokbd->input);
> -	locomo_set_drvdata(dev, NULL);
> +	return 0;
> +}
>  
> -	release_mem_region((unsigned long) dev->mapbase, dev->length);
> +static int __maybe_unused locomokbd_resume(struct device *dev)
> +{
> +	struct locomokbd *locomokbd = dev_get_drvdata(dev);
>  
> -	kfree(locomokbd);
> +	regmap_write(locomokbd->regmap, LOCOMO_KCMD, 1);
> +	regmap_write(locomokbd->regmap, LOCOMO_KSC, 0);
> +	regmap_write(locomokbd->regmap, LOCOMO_KIC, 0x0);
> +
> +	/* Rescan keyboard only if we are open by somebody */
> +	if (locomokbd->input->users)
> +		locomokbd_scankeyboard(locomokbd);

input->users should be accessed while holing input->mutex.

>  
>  	return 0;
>  }
>  
> -static struct locomo_driver keyboard_driver = {
> -	.drv = {
> -		.name = "locomokbd"
> +static SIMPLE_DEV_PM_OPS(locomo_kbd_pm, locomokbd_suspend, locomokbd_resume);
> +
> +static struct platform_driver locomokbd_driver = {
> +	.driver = {
> +		.name	= "locomo-kbd",
> +		.pm	= &locomo_kbd_pm,
>  	},
> -	.devid	= LOCOMO_DEVID_KEYBOARD,
>  	.probe	= locomokbd_probe,
>  	.remove	= locomokbd_remove,
>  };
>  
> -static int __init locomokbd_init(void)
> -{
> -	return locomo_driver_register(&keyboard_driver);
> -}
> -
> -static void __exit locomokbd_exit(void)
> -{
> -	locomo_driver_unregister(&keyboard_driver);
> -}
> +module_platform_driver(locomokbd_driver);
>  
> -module_init(locomokbd_init);
> -module_exit(locomokbd_exit);
> +MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
> +MODULE_DESCRIPTION("LoCoMo keyboard driver");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:locomo-kbd");
> -- 
> 2.1.4
> 

Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH v3 04/17] input: make LoCoMo keyboard driver support both poodle and collie
From: Dmitry Torokhov @ 2015-05-18 16:50 UTC (permalink / raw)
  To: Dmitry Eremin-Solenikov
  Cc: Russell King, Daniel Mack, Robert Jarzmik, Linus Walleij,
	Alexandre Courbot, Wolfram Sang, Bryan Wu, Richard Purdie,
	Samuel Ortiz, Lee Jones, Mark Brown, Jingoo Han,
	Jean-Christophe Plagniol-Villard, Tomi Valkeinen, Liam Girdwood,
	Andrea Adami, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-leds-u79uwXL29TY76Z2rM5mHXA,
	linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
	alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw
In-Reply-To: <1431880077-26321-5-git-send-email-dbaryshkov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

On Sun, May 17, 2015 at 07:27:44PM +0300, Dmitry Eremin-Solenikov wrote:
> Keyboards on collie and poodle differ only in wiring of 'Home' key.
> Instead of complicating the driver with platform data, just check for
> the machine for the time being. This will be converted to DTS property
> sometime in the future.
> 
> Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>

Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

> ---
>  drivers/input/keyboard/locomokbd.c | 10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
> index 1657bc0..b422608 100644
> --- a/drivers/input/keyboard/locomokbd.c
> +++ b/drivers/input/keyboard/locomokbd.c
> @@ -33,6 +33,9 @@
>  #include <linux/slab.h>
>  #include <linux/mfd/locomo.h>
>  
> +/* There is one minor difference between mappings on poodle and collie */
> +#include <asm/mach-types.h>
> +
>  #define KEY_ACTIVITY		KEY_F16
>  #define KEY_CONTACT		KEY_F18
>  #define KEY_CENTER		KEY_F15
> @@ -45,7 +48,7 @@
>  static const unsigned char
>  locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
>  	0, KEY_ESC, KEY_ACTIVITY, 0, 0, 0, 0, 0, 0, 0,				/* 0 - 9 */
> -	0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_HOME, KEY_CONTACT,			/* 10 - 19 */
> +	0, 0, 0, 0, 0, 0, 0, KEY_MENU, 0, KEY_CONTACT,				/* 10 - 19 */
>  	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,						/* 20 - 29 */
>  	0, 0, 0, KEY_CENTER, 0, KEY_MAIL, 0, 0, 0, 0,				/* 30 - 39 */
>  	0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RIGHT,					/* 40 - 49 */
> @@ -278,6 +281,11 @@ static int locomokbd_probe(struct platform_device *dev)
>  			locomokbd_keycode,
>  			sizeof(locomokbd->keycode));
>  
> +	if (machine_is_collie())
> +		locomokbd->keycode[18] = KEY_HOME;
> +	else
> +		locomokbd->keycode[3] = KEY_HOME;
> +
>  	for (i = 0; i < LOCOMOKBD_NUMKEYS; i++)
>  		input_set_capability(input_dev, EV_KEY, locomokbd->keycode[i]);
>  	input_set_capability(input_dev, EV_PWR, KEY_SUSPEND);
> -- 
> 2.1.4
> 

-- 
Dmitry

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox