Re: [PATCH] auxdisplay: charlcd: fix x/y command parsing

2018-12-06 Thread Robert Abel
Hi Miguel,

On 05 Dec 2018 17:47, Miguel Ojeda wrote:> Hi Mans,
>
> [CC'ing a few people involved previously on this]

Thanks for CC'ing me!

On 06 Dec 2018 11:06, Miguel Ojeda wrote [to Mans Rullgard]:
> Are you able to test this?

It's unfortunate that my original comment got ignored back when the breaking 
patch was submitted.
Nevertheless, if somebody posts a patch, I'm happy to test.

Regards,

Robert


Re: [PATCH] auxdisplay: charlcd: fix x/y command parsing

2018-12-06 Thread Robert Abel
Hi Miguel,

On 05 Dec 2018 17:47, Miguel Ojeda wrote:> Hi Mans,
>
> [CC'ing a few people involved previously on this]

Thanks for CC'ing me!

On 06 Dec 2018 11:06, Miguel Ojeda wrote [to Mans Rullgard]:
> Are you able to test this?

It's unfortunate that my original comment got ignored back when the breaking 
patch was submitted.
Nevertheless, if somebody posts a patch, I'm happy to test.

Regards,

Robert


[of] deadlock b/c of gpiochip and pinctrl dependency

2018-11-17 Thread Robert Abel
Hi!

I found a dependency issue with gpiochip and pinctrl while using the gpio-hog 
feature that was implemented by Benoit
Parrot in f625d4601759f. Relevant device-tree overlay shown below [3].

I ran into a deadlock situation, because adding a gpiochip requires a 
registered pinctrl with registered ranges, because
the function to add the gpiochip will check for hogged pins and request gpio 
pin functionality for them.
This works in situations when gpiochip and pinctrl functionality don't depend 
on each other. However, consider the
following code, which is from the bcm2835 driver for Raspberry Pi found here 
[1]:

pinctrl-bcm2835.c:
err = gpiochip_add_data(>gpio_chip, pc);
if (err) {
dev_err(dev, "could not add GPIO chipn");
return err;
}

...

pc->pctl_dev = devm_pinctrl_register(dev, _pinctrl_desc, pc);
if (IS_ERR(pc->pctl_dev)) {
gpiochip_remove(>gpio_chip);
return PTR_ERR(pc->pctl_dev);
}

...

pinctrl_add_gpio_range(pc->pctl_dev, >gpio_range);


It's not very obvious, that calling gpiochip_add_data should only be done after 
adding the required ranges to pinctrl,
because the following happens:

gpiochip_add_data(_with_key):
  of_gpiochip_add:
of_gpiochip_scan_gpios:
  for_each_available_child_of_node(chip->of_node, np) with "gpio-hog":
gpiod_hog
  gpiochip_request_own_desc:
gpiod_request_commit:
  status = chip->request(chip, gpio_chip_hwgpio(desc)):
gpiochip_generic_request(...):
  pinctrl_gpio_request:
pinctrl_get_device_gpio_range:
  /* GPIO range not found, because it wasn't registered yet 
*/
  return -EPROBE_DEFER;

This of course deadlocks my system, because everything ends up waiting on the 
gpiochip, which cannot ever be
instantiated. I couldn't find any documentation explicitly mentioning this 
dependency between gpiochip and pinctrl.
My workaround for the moment is to re-order the gpiochip_add_data call after 
the devm_pinctrl_register and
pinctrl_add_gpio_range calls. I haven't observed any ill effect, but I'm not 
sure what other components may already act
on pinctrl while gpiochip is dangling or if any of the other functions that are 
called by add require it as well.

Obviously, this approach won't work for SoCs where setting certain pinctrl 
settings need to touch gpio settings to e.g.
activate pull-ups.

In general, I sought the same functionality that Markus Pargmann was trying to 
implement in 2015 [2].
That is, to name and possibly export gpios through device tree.

It seems disadvantageous that one cannot currently specify pinctrl settings 
while hogging or export by name.
Dynamic device tree overlays also don't work. Perhaps an actual driver instead 
of the hogging mechanism would solve all
dependency issues better?

Regards,

Robert

Please CC, as I'm off-list.


  [1]: 
https://github.com/raspberrypi/linux/blob/83ea2e93/drivers/pinctrl/bcm/pinctrl-bcm2835.c#L1027
  [2]: 
http://lists.infradead.org/pipermail/linux-arm-kernel/2015-July/357418.html
  [3]: gpio-hog.dtso
   /dts-v1/;
   /plugin/;

   #include 

   / {
   compatible = "brcm,bcm2708";
   fragment@0 {
   target = <>;
   __overlay__ {
   myLed {
   gpios = <18 GPIO_ACTIVE_HIGH>;
   gpio-hog;
   output-low;
   };
   };
   };
   };


[of] deadlock b/c of gpiochip and pinctrl dependency

2018-11-17 Thread Robert Abel
Hi!

I found a dependency issue with gpiochip and pinctrl while using the gpio-hog 
feature that was implemented by Benoit
Parrot in f625d4601759f. Relevant device-tree overlay shown below [3].

I ran into a deadlock situation, because adding a gpiochip requires a 
registered pinctrl with registered ranges, because
the function to add the gpiochip will check for hogged pins and request gpio 
pin functionality for them.
This works in situations when gpiochip and pinctrl functionality don't depend 
on each other. However, consider the
following code, which is from the bcm2835 driver for Raspberry Pi found here 
[1]:

pinctrl-bcm2835.c:
err = gpiochip_add_data(>gpio_chip, pc);
if (err) {
dev_err(dev, "could not add GPIO chipn");
return err;
}

...

pc->pctl_dev = devm_pinctrl_register(dev, _pinctrl_desc, pc);
if (IS_ERR(pc->pctl_dev)) {
gpiochip_remove(>gpio_chip);
return PTR_ERR(pc->pctl_dev);
}

...

pinctrl_add_gpio_range(pc->pctl_dev, >gpio_range);


It's not very obvious, that calling gpiochip_add_data should only be done after 
adding the required ranges to pinctrl,
because the following happens:

gpiochip_add_data(_with_key):
  of_gpiochip_add:
of_gpiochip_scan_gpios:
  for_each_available_child_of_node(chip->of_node, np) with "gpio-hog":
gpiod_hog
  gpiochip_request_own_desc:
gpiod_request_commit:
  status = chip->request(chip, gpio_chip_hwgpio(desc)):
gpiochip_generic_request(...):
  pinctrl_gpio_request:
pinctrl_get_device_gpio_range:
  /* GPIO range not found, because it wasn't registered yet 
*/
  return -EPROBE_DEFER;

This of course deadlocks my system, because everything ends up waiting on the 
gpiochip, which cannot ever be
instantiated. I couldn't find any documentation explicitly mentioning this 
dependency between gpiochip and pinctrl.
My workaround for the moment is to re-order the gpiochip_add_data call after 
the devm_pinctrl_register and
pinctrl_add_gpio_range calls. I haven't observed any ill effect, but I'm not 
sure what other components may already act
on pinctrl while gpiochip is dangling or if any of the other functions that are 
called by add require it as well.

Obviously, this approach won't work for SoCs where setting certain pinctrl 
settings need to touch gpio settings to e.g.
activate pull-ups.

In general, I sought the same functionality that Markus Pargmann was trying to 
implement in 2015 [2].
That is, to name and possibly export gpios through device tree.

It seems disadvantageous that one cannot currently specify pinctrl settings 
while hogging or export by name.
Dynamic device tree overlays also don't work. Perhaps an actual driver instead 
of the hogging mechanism would solve all
dependency issues better?

Regards,

Robert

Please CC, as I'm off-list.


  [1]: 
https://github.com/raspberrypi/linux/blob/83ea2e93/drivers/pinctrl/bcm/pinctrl-bcm2835.c#L1027
  [2]: 
http://lists.infradead.org/pipermail/linux-arm-kernel/2015-July/357418.html
  [3]: gpio-hog.dtso
   /dts-v1/;
   /plugin/;

   #include 

   / {
   compatible = "brcm,bcm2708";
   fragment@0 {
   target = <>;
   __overlay__ {
   myLed {
   gpios = <18 GPIO_ACTIVE_HIGH>;
   gpio-hog;
   output-low;
   };
   };
   };
   };


[PATCH 1/2] auxdisplay: charlcd: fix x/y address commands

2018-02-27 Thread Robert Abel
The current version does not parse x/y commands at all.
Simplify the x/y command syntax to the one indicated in
the comment all along and introduce a parsing function
that handles parsing a sequence of one or two subcommands
where each subcommand must appear at most once.

Signed-off-by: Robert Abel <ra...@robertabel.eu>
---
 drivers/auxdisplay/charlcd.c | 109 +--
 1 file changed, 96 insertions(+), 13 deletions(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index e3b2fd15c5a3..ae078f414539 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -292,6 +292,96 @@ static int charlcd_init_display(struct charlcd *lcd)
return 0;
 }
 
+/**
+ * parse_xy() - Parse coordinates of a movement command.
+ * @s: Pointer to null-terminated movement command string.
+ * @x: Pointer to x position.
+ * @y: Pointer to y position.
+ *
+ * Parses a movement command of the form "([xy][0-9]+){1,2};",
+ * where each group must begin with a different subcommand.
+ *
+ * The positions will only be updated when their respective
+ * subcommand is encountered and when the whole movement
+ * command is valid.
+ *
+ * The movement command string must contain a ';' at the end.
+ *
+ * For instance:
+ *   - ";"  fails.
+ *   - "x1;"returns (1, ).
+ *   - "y2x1;"  returns (1, 2).
+ *   - "x12y34x56;" fails.
+ *   - ""   fails.
+ *   - "x"  illegal input.
+ *   - "x;" fails.
+ *   - "x1" illegal input.
+ *   - "xy12;"  fails.
+ *   - "x12yy12;"   fails.
+ *   - "xx" illegal input.
+ *
+ * Return: Returns whether the command is valid. The position arguments are
+ * only written if the parsing was successful.
+ */
+static bool parse_xy(const char *s, unsigned long *x, unsigned long *y)
+{
+
+   unsigned long new_x = *x;
+   unsigned long new_y = *y;
+
+   char xcoord[LCD_ESCAPE_LEN];
+   char ycoord[LCD_ESCAPE_LEN];
+   const char *split = strpbrk(s + 1, "xy");
+   const char *end = strchr(s, ';');
+   char *coord0 = xcoord;
+   char *coord1 = ycoord;
+   unsigned long *new0 = _x;
+   unsigned long *new1 = _y;
+
+   memset(xcoord, 0, sizeof(xcoord));
+   memset(ycoord, 0, sizeof(ycoord));
+
+   /* validate input */
+   switch (*s) {
+   case 'x':
+   if (split != NULL && *split != 'y')
+   return false;
+   break;
+   case 'y':
+   /* swap coordinates */
+   coord0 = ycoord;
+   coord1 = xcoord;
+   new0 = _y;
+   new1 = _x;
+
+   if (split != NULL && *split != 'x')
+   return false;
+   break;
+   default:
+   return false;
+   }
+
+   /* parse coordinate 0 and 1 */
+   if (split == NULL) {
+   memcpy(coord0, s + 1, end - s - 1);
+   if (kstrtoul(coord0, 10, new0) < 0)
+   return false;
+   } else {
+   memcpy(coord0, s + 1, split - s - 1);
+   memcpy(coord1, split + 1, end - split - 1);
+   if (kstrtoul(coord0, 10, new0) < 0)
+   return false;
+   if (kstrtoul(coord1, 10, new1) < 0)
+   return false;
+   }
+
+   /* update coordinates on success */
+   *x = new_x;
+   *y = new_y;
+   return true;
+
+}
+
 /*
  * These are the file operation function for user access to /dev/lcd
  * This function can also be called from inside the kernel, by
@@ -473,21 +563,14 @@ static inline int handle_lcd_special_code(struct charlcd 
*lcd)
if (!strchr(esc, ';'))
break;
 
-   while (*esc) {
-   if (*esc == 'x') {
-   esc++;
-   if (kstrtoul(esc, 10, >addr.x) < 0)
-   break;
-   } else if (*esc == 'y') {
-   esc++;
-   if (kstrtoul(esc, 10, >addr.y) < 0)
-   break;
-   } else {
-   break;
-   }
+   /* If the command is valid, move to the new address */
+   if (parse_xy(esc, >addr.x, >addr.y)) {
+   priv->addr.x = min_t(unsigned long, priv->addr.x, 
lcd->bwidth - 1);
+   priv->addr.y %= lcd->height;
+   charlcd_gotoxy(lcd);
}
 
-   charlcd_gotoxy(lcd);
+   /* Regardless of its validity, mark as processed */
processed = 1;
break;
}
-- 
2.11.0



[PATCH 1/2] auxdisplay: charlcd: fix x/y address commands

2018-02-27 Thread Robert Abel
The current version does not parse x/y commands at all.
Simplify the x/y command syntax to the one indicated in
the comment all along and introduce a parsing function
that handles parsing a sequence of one or two subcommands
where each subcommand must appear at most once.

Signed-off-by: Robert Abel 
---
 drivers/auxdisplay/charlcd.c | 109 +--
 1 file changed, 96 insertions(+), 13 deletions(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index e3b2fd15c5a3..ae078f414539 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -292,6 +292,96 @@ static int charlcd_init_display(struct charlcd *lcd)
return 0;
 }
 
+/**
+ * parse_xy() - Parse coordinates of a movement command.
+ * @s: Pointer to null-terminated movement command string.
+ * @x: Pointer to x position.
+ * @y: Pointer to y position.
+ *
+ * Parses a movement command of the form "([xy][0-9]+){1,2};",
+ * where each group must begin with a different subcommand.
+ *
+ * The positions will only be updated when their respective
+ * subcommand is encountered and when the whole movement
+ * command is valid.
+ *
+ * The movement command string must contain a ';' at the end.
+ *
+ * For instance:
+ *   - ";"  fails.
+ *   - "x1;"returns (1, ).
+ *   - "y2x1;"  returns (1, 2).
+ *   - "x12y34x56;" fails.
+ *   - ""   fails.
+ *   - "x"  illegal input.
+ *   - "x;" fails.
+ *   - "x1" illegal input.
+ *   - "xy12;"  fails.
+ *   - "x12yy12;"   fails.
+ *   - "xx" illegal input.
+ *
+ * Return: Returns whether the command is valid. The position arguments are
+ * only written if the parsing was successful.
+ */
+static bool parse_xy(const char *s, unsigned long *x, unsigned long *y)
+{
+
+   unsigned long new_x = *x;
+   unsigned long new_y = *y;
+
+   char xcoord[LCD_ESCAPE_LEN];
+   char ycoord[LCD_ESCAPE_LEN];
+   const char *split = strpbrk(s + 1, "xy");
+   const char *end = strchr(s, ';');
+   char *coord0 = xcoord;
+   char *coord1 = ycoord;
+   unsigned long *new0 = _x;
+   unsigned long *new1 = _y;
+
+   memset(xcoord, 0, sizeof(xcoord));
+   memset(ycoord, 0, sizeof(ycoord));
+
+   /* validate input */
+   switch (*s) {
+   case 'x':
+   if (split != NULL && *split != 'y')
+   return false;
+   break;
+   case 'y':
+   /* swap coordinates */
+   coord0 = ycoord;
+   coord1 = xcoord;
+   new0 = _y;
+   new1 = _x;
+
+   if (split != NULL && *split != 'x')
+   return false;
+   break;
+   default:
+   return false;
+   }
+
+   /* parse coordinate 0 and 1 */
+   if (split == NULL) {
+   memcpy(coord0, s + 1, end - s - 1);
+   if (kstrtoul(coord0, 10, new0) < 0)
+   return false;
+   } else {
+   memcpy(coord0, s + 1, split - s - 1);
+   memcpy(coord1, split + 1, end - split - 1);
+   if (kstrtoul(coord0, 10, new0) < 0)
+   return false;
+   if (kstrtoul(coord1, 10, new1) < 0)
+   return false;
+   }
+
+   /* update coordinates on success */
+   *x = new_x;
+   *y = new_y;
+   return true;
+
+}
+
 /*
  * These are the file operation function for user access to /dev/lcd
  * This function can also be called from inside the kernel, by
@@ -473,21 +563,14 @@ static inline int handle_lcd_special_code(struct charlcd 
*lcd)
if (!strchr(esc, ';'))
break;
 
-   while (*esc) {
-   if (*esc == 'x') {
-   esc++;
-   if (kstrtoul(esc, 10, >addr.x) < 0)
-   break;
-   } else if (*esc == 'y') {
-   esc++;
-   if (kstrtoul(esc, 10, >addr.y) < 0)
-   break;
-   } else {
-   break;
-   }
+   /* If the command is valid, move to the new address */
+   if (parse_xy(esc, >addr.x, >addr.y)) {
+   priv->addr.x = min_t(unsigned long, priv->addr.x, 
lcd->bwidth - 1);
+   priv->addr.y %= lcd->height;
+   charlcd_gotoxy(lcd);
}
 
-   charlcd_gotoxy(lcd);
+   /* Regardless of its validity, mark as processed */
processed = 1;
break;
}
-- 
2.11.0



[PATCH 2/2] auxdisplay: charlcd: make home command unshift display

2018-02-27 Thread Robert Abel
A user has no way of unshifting the display programmatically once shifted.
Users cannot rely on ^[[H (home) to result in their message being seen either.
Use the actual HOME command 0x02 instead of only returning to x0/y0.
Users can still do ^[[Lx0y0; (go to x/y) if they wish to use the 'old' home
function.
Implement fast clearing of LCD by going to x0/y0 first, clearing display and
then calling home to possibly unshift display possibly avoiding artifacts by
not unshifting before clearing display.

Signed-off-by: Robert Abel <ra...@robertabel.eu>
---
 drivers/auxdisplay/charlcd.c | 28 ++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index ae078f414539..fdb3aa6423bf 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -43,6 +43,8 @@
 /* LCD commands */
 #define LCD_CMD_DISPLAY_CLEAR  0x01/* Clear entire display */
 
+#define LCD_CMD_HOME0x02/* Set DDRAM address to 0 and unshift 
display */
+
 #define LCD_CMD_ENTRY_MODE 0x04/* Set entry mode */
 #define LCD_CMD_CURSOR_INC 0x02/* Increment cursor */
 
@@ -174,13 +176,24 @@ static void charlcd_gotoxy(struct charlcd *lcd)
lcd->ops->write_cmd(lcd, LCD_CMD_SET_DDRAM_ADDR | addr);
 }
 
+/**
+ * charlcd_home() - Return to DDRAM address 0 and unshift the display.
+ * @lcd: LCD descriptor structure.
+ *
+ * Return to coordinates x0/y0 and unshift the display.
+ *
+ * Note: Use the movement command ^[[Lx0y0; instead of home
+ * in case the display should not be unshifted.
+ */
 static void charlcd_home(struct charlcd *lcd)
 {
struct charlcd_priv *priv = to_priv(lcd);
 
+   /* return to x0/y0 and unshift the display */
priv->addr.x = 0;
priv->addr.y = 0;
-   charlcd_gotoxy(lcd);
+   lcd->ops->write_cmd(lcd, LCD_CMD_HOME);
+   long_sleep(2);
 }
 
 static void charlcd_print(struct charlcd *lcd, char c)
@@ -198,11 +211,21 @@ static void charlcd_print(struct charlcd *lcd, char c)
charlcd_gotoxy(lcd);
 }
 
+/**
+ * charlcd_clear_fast() - Perform a fast clear of the display and return home.
+ * @lcd: LCD descriptor structure.
+ *
+ * The display will be unshifted and at coordinates x0/y0 after fast clear.
+ */
 static void charlcd_clear_fast(struct charlcd *lcd)
 {
+   struct charlcd_priv *priv = to_priv(lcd);
int pos;
 
-   charlcd_home(lcd);
+   /* avoid artifacts by going to x0/y0 without unshifting the display */
+   priv->addr.x = 0;
+   priv->addr.y = 0;
+   charlcd_gotoxy(lcd);
 
if (lcd->ops->clear_fast)
lcd->ops->clear_fast(lcd);
@@ -210,6 +233,7 @@ static void charlcd_clear_fast(struct charlcd *lcd)
for (pos = 0; pos < min(2, lcd->height) * lcd->hwidth; pos++)
lcd->ops->write_data(lcd, ' ');
 
+   /* return to x0/y0 and unshift the display */
charlcd_home(lcd);
 }
 
-- 
2.11.0



[PATCH 2/2] auxdisplay: charlcd: make home command unshift display

2018-02-27 Thread Robert Abel
A user has no way of unshifting the display programmatically once shifted.
Users cannot rely on ^[[H (home) to result in their message being seen either.
Use the actual HOME command 0x02 instead of only returning to x0/y0.
Users can still do ^[[Lx0y0; (go to x/y) if they wish to use the 'old' home
function.
Implement fast clearing of LCD by going to x0/y0 first, clearing display and
then calling home to possibly unshift display possibly avoiding artifacts by
not unshifting before clearing display.

Signed-off-by: Robert Abel 
---
 drivers/auxdisplay/charlcd.c | 28 ++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index ae078f414539..fdb3aa6423bf 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -43,6 +43,8 @@
 /* LCD commands */
 #define LCD_CMD_DISPLAY_CLEAR  0x01/* Clear entire display */
 
+#define LCD_CMD_HOME0x02/* Set DDRAM address to 0 and unshift 
display */
+
 #define LCD_CMD_ENTRY_MODE 0x04/* Set entry mode */
 #define LCD_CMD_CURSOR_INC 0x02/* Increment cursor */
 
@@ -174,13 +176,24 @@ static void charlcd_gotoxy(struct charlcd *lcd)
lcd->ops->write_cmd(lcd, LCD_CMD_SET_DDRAM_ADDR | addr);
 }
 
+/**
+ * charlcd_home() - Return to DDRAM address 0 and unshift the display.
+ * @lcd: LCD descriptor structure.
+ *
+ * Return to coordinates x0/y0 and unshift the display.
+ *
+ * Note: Use the movement command ^[[Lx0y0; instead of home
+ * in case the display should not be unshifted.
+ */
 static void charlcd_home(struct charlcd *lcd)
 {
struct charlcd_priv *priv = to_priv(lcd);
 
+   /* return to x0/y0 and unshift the display */
priv->addr.x = 0;
priv->addr.y = 0;
-   charlcd_gotoxy(lcd);
+   lcd->ops->write_cmd(lcd, LCD_CMD_HOME);
+   long_sleep(2);
 }
 
 static void charlcd_print(struct charlcd *lcd, char c)
@@ -198,11 +211,21 @@ static void charlcd_print(struct charlcd *lcd, char c)
charlcd_gotoxy(lcd);
 }
 
+/**
+ * charlcd_clear_fast() - Perform a fast clear of the display and return home.
+ * @lcd: LCD descriptor structure.
+ *
+ * The display will be unshifted and at coordinates x0/y0 after fast clear.
+ */
 static void charlcd_clear_fast(struct charlcd *lcd)
 {
+   struct charlcd_priv *priv = to_priv(lcd);
int pos;
 
-   charlcd_home(lcd);
+   /* avoid artifacts by going to x0/y0 without unshifting the display */
+   priv->addr.x = 0;
+   priv->addr.y = 0;
+   charlcd_gotoxy(lcd);
 
if (lcd->ops->clear_fast)
lcd->ops->clear_fast(lcd);
@@ -210,6 +233,7 @@ static void charlcd_clear_fast(struct charlcd *lcd)
for (pos = 0; pos < min(2, lcd->height) * lcd->hwidth; pos++)
lcd->ops->write_data(lcd, ' ');
 
+   /* return to x0/y0 and unshift the display */
charlcd_home(lcd);
 }
 
-- 
2.11.0



[PATCH RFC 0/2] auxdisplay: charlcd: fix movement and home commands

2018-02-27 Thread Robert Abel
I reworked the previous patches 2-4 into these two patches.
The first patch proproses a different solution to the movement command
parse code that reduces the movement command two at most two movement
subcommands (x or y standalone, x followed by y or vice-versa).

The second patch add comments in code to the home and clear_fast functions
and explains their behavior a bit more.

Robert Abel (2):
  auxdisplay: charlcd: fix x/y address commands
  auxdisplay: charlcd: make home command unshift display

 drivers/auxdisplay/charlcd.c | 137 ++-
 1 file changed, 122 insertions(+), 15 deletions(-)

-- 
2.11.0



[PATCH RFC 0/2] auxdisplay: charlcd: fix movement and home commands

2018-02-27 Thread Robert Abel
I reworked the previous patches 2-4 into these two patches.
The first patch proproses a different solution to the movement command
parse code that reduces the movement command two at most two movement
subcommands (x or y standalone, x followed by y or vice-versa).

The second patch add comments in code to the home and clear_fast functions
and explains their behavior a bit more.

Robert Abel (2):
  auxdisplay: charlcd: fix x/y address commands
  auxdisplay: charlcd: make home command unshift display

 drivers/auxdisplay/charlcd.c | 137 ++-
 1 file changed, 122 insertions(+), 15 deletions(-)

-- 
2.11.0



Re: [PATCH 3/4] auxdisplay: charlcd: fix x/y address commands

2018-02-27 Thread Robert Abel
Hi Willy,

On 27 Feb 2018 06:19, Willy Tarreau wrote:
> Well actually I don't see a problem there at all. The principle is simply
> to accept any sequence assigning x or y or both. If you write x4y2x6, it
> simply means that you changed your mind regarding x and that the last
> value (6) is the one you want. Just as if you wrote "^[[Lx4;^[[y2;^[[x6;".
> The while loop doesn't even try to do anything clever, it simply parses
> everything matching x and y followed by digits. I think the only reason
> for having both x and y processed in the same loop was to call
> charlcd_gotoxy() only once for both axes.

I didn't say it is a problem. It is however an edge case that incurs a
lot of code for little to no functionality.
I'd much prefer if we broke backwards compatibility here and actually
only parse the format that is indicated in the comment:

> case 'x':   /* gotoxy : LxXXX[yYYY]; */
> case 'y':   /* gotoxy : LyYYY[xXXX]; */
>  

Exactly one x command followed exactly by zero or one y command or
vice-versa.

If somebody changes their mind during the escape sequence, they can just
issue a new one instead of appending to the current one.

I'll post an example patch.

Regards,

Robert


Re: [PATCH 3/4] auxdisplay: charlcd: fix x/y address commands

2018-02-27 Thread Robert Abel
Hi Willy,

On 27 Feb 2018 06:19, Willy Tarreau wrote:
> Well actually I don't see a problem there at all. The principle is simply
> to accept any sequence assigning x or y or both. If you write x4y2x6, it
> simply means that you changed your mind regarding x and that the last
> value (6) is the one you want. Just as if you wrote "^[[Lx4;^[[y2;^[[x6;".
> The while loop doesn't even try to do anything clever, it simply parses
> everything matching x and y followed by digits. I think the only reason
> for having both x and y processed in the same loop was to call
> charlcd_gotoxy() only once for both axes.

I didn't say it is a problem. It is however an edge case that incurs a
lot of code for little to no functionality.
I'd much prefer if we broke backwards compatibility here and actually
only parse the format that is indicated in the comment:

> case 'x':   /* gotoxy : LxXXX[yYYY]; */
> case 'y':   /* gotoxy : LyYYY[xXXX]; */
>  

Exactly one x command followed exactly by zero or one y command or
vice-versa.

If somebody changes their mind during the escape sequence, they can just
issue a new one instead of appending to the current one.

I'll post an example patch.

Regards,

Robert


Re: [PATCH RFC v3] auxdisplay: charlcd: Fix and clean up handling of x/y commands

2018-02-27 Thread Robert Abel
On 27 Feb 2018 23:09, Miguel Ojeda wrote:> @@ -469,24 +543,11 @@ static
inline int handle_lcd_special_code(struct charlcd *lcd)
>   }
>   case 'x':   /* gotoxy : LxXXX[yYYY]; */
>   case 'y':   /* gotoxy : LyYYY[xXXX]; */
> - if (!strchr(esc, ';'))
> - break;

Might want to keep this. It's in line with all other cases and prevents
calling parse_xy with input that has no chance of being correct due to
missing final ';'.

> + /* If the command is valid, move to the new address */
> + if (parse_xy(esc, >addr.x, >addr.y))
> + charlcd_gotoxy(lcd);

While not in the original code, the inputs are now not clamped to width
and height.
That means for a two-line display ^[[Ly02; will actually end up on line
y = 1, not y = 2 % 2 = 0, because the four-line display logic bumps the
address up.
The same goes for going over lcd->width/lcd->bwidth in the x coordinate.
For four-line displays that ends up going to the line y + 2, because the
buffer is split in the middle.
The distinction between lcd->width and lcd->bwidth depends on whether it
makes sense to put the cursor outside the visible area or not.

Regards,

Robert


Re: [PATCH RFC v3] auxdisplay: charlcd: Fix and clean up handling of x/y commands

2018-02-27 Thread Robert Abel
On 27 Feb 2018 23:09, Miguel Ojeda wrote:> @@ -469,24 +543,11 @@ static
inline int handle_lcd_special_code(struct charlcd *lcd)
>   }
>   case 'x':   /* gotoxy : LxXXX[yYYY]; */
>   case 'y':   /* gotoxy : LyYYY[xXXX]; */
> - if (!strchr(esc, ';'))
> - break;

Might want to keep this. It's in line with all other cases and prevents
calling parse_xy with input that has no chance of being correct due to
missing final ';'.

> + /* If the command is valid, move to the new address */
> + if (parse_xy(esc, >addr.x, >addr.y))
> + charlcd_gotoxy(lcd);

While not in the original code, the inputs are now not clamped to width
and height.
That means for a two-line display ^[[Ly02; will actually end up on line
y = 1, not y = 2 % 2 = 0, because the four-line display logic bumps the
address up.
The same goes for going over lcd->width/lcd->bwidth in the x coordinate.
For four-line displays that ends up going to the line y + 2, because the
buffer is split in the middle.
The distinction between lcd->width and lcd->bwidth depends on whether it
makes sense to put the cursor outside the visible area or not.

Regards,

Robert


Re: [PATCH 1/3] auxdisplay: charlcd: fix hex literal ranges for graphics command

2018-02-26 Thread Robert Abel
On 26 Feb 2018 00:54, Robert Abel wrote:> Robert Abel (4):
>   auxdisplay: charlcd: fix two-line command ^[[LN not marked as
> processed
>   auxdisplay: charlcd: name x/y address struct
>   auxdisplay: charlcd: fix x/y address commands
>   auxdisplay: charlcd: make home command unshift display

So I think as it stands, only the first patch is being picked up, while
the other three will need rework, which is fine.

I think I'm going to wait a little while with the x/y fix until the
simple_strto* situation has settled.

For the home command basically only more comments in code should be
necessary.
More comments will also be good for the x/y issue once I change the
implementation.

Regards,

Robert


Re: [PATCH 1/3] auxdisplay: charlcd: fix hex literal ranges for graphics command

2018-02-26 Thread Robert Abel
On 26 Feb 2018 00:54, Robert Abel wrote:> Robert Abel (4):
>   auxdisplay: charlcd: fix two-line command ^[[LN not marked as
> processed
>   auxdisplay: charlcd: name x/y address struct
>   auxdisplay: charlcd: fix x/y address commands
>   auxdisplay: charlcd: make home command unshift display

So I think as it stands, only the first patch is being picked up, while
the other three will need rework, which is fine.

I think I'm going to wait a little while with the x/y fix until the
simple_strto* situation has settled.

For the home command basically only more comments in code should be
necessary.
More comments will also be good for the x/y issue once I change the
implementation.

Regards,

Robert


Re: [PATCH 3/4] auxdisplay: charlcd: fix x/y address commands

2018-02-26 Thread Robert Abel
Hi Miguel,

On 26 Feb 2018 17:49, Miguel Ojeda wrote:
> On Mon, Feb 26, 2018 at 12:54 AM, Robert Abel <ra...@robertabel.eu> wrote:
>> +   /* clamp new x/y coordinates */
>> +   if (tmp_addr.x >= lcd->width)
>> +   tmp_addr.x = lcd->width - 1;
> 
> tmp_addr.x = min(tmp_addr.x, lcd->width - 1);

Had throught of that, too. However, it introduces a warning about type
mismatch, because lcd->width is int while tmp_addr.x is unsigned long
int. I didn't fell like saving a line warranted much bigger changes to
the lcd struct.

Regards,

Robert


Re: [PATCH 3/4] auxdisplay: charlcd: fix x/y address commands

2018-02-26 Thread Robert Abel
Hi Miguel,

On 26 Feb 2018 17:49, Miguel Ojeda wrote:
> On Mon, Feb 26, 2018 at 12:54 AM, Robert Abel  wrote:
>> +   /* clamp new x/y coordinates */
>> +   if (tmp_addr.x >= lcd->width)
>> +   tmp_addr.x = lcd->width - 1;
> 
> tmp_addr.x = min(tmp_addr.x, lcd->width - 1);

Had throught of that, too. However, it introduces a warning about type
mismatch, because lcd->width is int while tmp_addr.x is unsigned long
int. I didn't fell like saving a line warranted much bigger changes to
the lcd struct.

Regards,

Robert


Re: [PATCH 3/4] auxdisplay: charlcd: fix x/y address commands

2018-02-26 Thread Robert Abel
Hi @ll,

this is a discussion stemming from drivers/auxdisplay about the usage
and possible deprecation of simple_strto* set of functions found in
lib/vsprintf.
I cc'ed everybody who signed off and also everybody who
signed/authored/added/removed more than 20% of lib/vsprintf.

This has come up, because some auxdisplay functionality was broken by a
well-intentioned patch to switch from simple_strtoul to kstrtoul in
129957069e6af42a6e021d90679c56662c95f7e1
(https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=129957069e6af42a6e021d90679c56662c95f7e1)
and now there is discussion about whether the simple_strto* functions
are really obsolete.

On 26 Feb 2018 18:26, Miguel Ojeda wrote:
> On Mon, Feb 26, 2018 at 6:09 PM, Andy Shevchenko wrote:
>> On Mon, Feb 26, 2018 at 6:54 PM, Miguel Ojeda wrote:
>>> On Mon, Feb 26, 2018 at 12:44 PM, Andy Shevchenko wrote:
 Perhaps instead of dancing around kstrtox() better to switch to
 simple_strtoul() ?
>>>
>>> It seems deprecated:
>>>
>>> /* Obsolete, do not use.  Use kstrto instead */
>>> extern unsigned long simple_strtoul(const char *,char **,unsigned int);
>>
>> It has been discussed several times. The comment is simple wrong.
>>
>> Because of the requirement of kstrtox() to have a \0 or \n followed by
>> \0 as "end of field".
>> simple_strto*() is suitable to be run in place.
> 
> I agree that in-place versions of these kind of string functions are
> very useful, don't get me wrong! But unless someone changes the
> "official" comment, we shouldn't add new code relying on them.

So can we get clarity in form of a patch here, or not?
I'm hesitant to move back to simple_kstroul, because to me it seems that
general consensus (at least when the comment was put there) was to
remove it:

> commit 462e471107624fe9bd8b6353ac13e06305c3f3fd
> Author: Eldad Zack <>
> Date:   Mon Dec 17 16:03:05 2012 -0800
> 
> simple_strto*: annotate function as obsolete
> 
> Update the documentation for simple_strto* to reflect that it has been
> obsoleted and advise the usage of kstrto*.
> 
> Signed-off-by: Eldad Zack <>
> Cc: J. Bruce Fields <>
> Cc: Joe Perches <>
> Cc: Randy Dunlap <>
> Cc: Alexey Dobriyan <>
> Cc: Rob Landley <>
> Signed-off-by: Andrew Morton <>
> Signed-off-by: Linus Torvalds <>

One big advantage simple_kstro* functions have over their kstrto*
cousins is that strings don't need to be null-terminated. Instead, they
will be parsed as far as they can be and a pointer to the end of the
respective number will be returned.

Regards,

Robert


Re: [PATCH 3/4] auxdisplay: charlcd: fix x/y address commands

2018-02-26 Thread Robert Abel
Hi @ll,

this is a discussion stemming from drivers/auxdisplay about the usage
and possible deprecation of simple_strto* set of functions found in
lib/vsprintf.
I cc'ed everybody who signed off and also everybody who
signed/authored/added/removed more than 20% of lib/vsprintf.

This has come up, because some auxdisplay functionality was broken by a
well-intentioned patch to switch from simple_strtoul to kstrtoul in
129957069e6af42a6e021d90679c56662c95f7e1
(https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=129957069e6af42a6e021d90679c56662c95f7e1)
and now there is discussion about whether the simple_strto* functions
are really obsolete.

On 26 Feb 2018 18:26, Miguel Ojeda wrote:
> On Mon, Feb 26, 2018 at 6:09 PM, Andy Shevchenko wrote:
>> On Mon, Feb 26, 2018 at 6:54 PM, Miguel Ojeda wrote:
>>> On Mon, Feb 26, 2018 at 12:44 PM, Andy Shevchenko wrote:
 Perhaps instead of dancing around kstrtox() better to switch to
 simple_strtoul() ?
>>>
>>> It seems deprecated:
>>>
>>> /* Obsolete, do not use.  Use kstrto instead */
>>> extern unsigned long simple_strtoul(const char *,char **,unsigned int);
>>
>> It has been discussed several times. The comment is simple wrong.
>>
>> Because of the requirement of kstrtox() to have a \0 or \n followed by
>> \0 as "end of field".
>> simple_strto*() is suitable to be run in place.
> 
> I agree that in-place versions of these kind of string functions are
> very useful, don't get me wrong! But unless someone changes the
> "official" comment, we shouldn't add new code relying on them.

So can we get clarity in form of a patch here, or not?
I'm hesitant to move back to simple_kstroul, because to me it seems that
general consensus (at least when the comment was put there) was to
remove it:

> commit 462e471107624fe9bd8b6353ac13e06305c3f3fd
> Author: Eldad Zack <>
> Date:   Mon Dec 17 16:03:05 2012 -0800
> 
> simple_strto*: annotate function as obsolete
> 
> Update the documentation for simple_strto* to reflect that it has been
> obsoleted and advise the usage of kstrto*.
> 
> Signed-off-by: Eldad Zack <>
> Cc: J. Bruce Fields <>
> Cc: Joe Perches <>
> Cc: Randy Dunlap <>
> Cc: Alexey Dobriyan <>
> Cc: Rob Landley <>
> Signed-off-by: Andrew Morton <>
> Signed-off-by: Linus Torvalds <>

One big advantage simple_kstro* functions have over their kstrto*
cousins is that strings don't need to be null-terminated. Instead, they
will be parsed as far as they can be and a pointer to the end of the
respective number will be returned.

Regards,

Robert


Re: [PATCH 3/4] auxdisplay: charlcd: fix x/y address commands

2018-02-26 Thread Robert Abel
On 26 Feb 2018 17:49, Miguel Ojeda wrote:
> On a general note, the code seems a bit convoluted for what it does,
> specially without the comment written in the commit message :-) Isn't
> it simpler to use a tiny array in the stack and put the numbers to be
> converted instead of modifying the input sequence and dancing with
> pointers?

That's what I felt at first, too. If we can drop the backwards
compatibility of repeated xy commands, the whole affair gets much
easier, but will unfortunately break existing use.

Ex. ^[[Lx004y002x006; --> x6y2, because repeats of x would just
overwrite earlier values. That's what the while loop allowed in the
first place.

I suspect the while loop to parse was just a clever way of parsing y
followed by x and x followed by y using the same code and the
overwriting behavior is actually an unaccounted-for side-effect.

Regards,

Robert


Re: [PATCH 3/4] auxdisplay: charlcd: fix x/y address commands

2018-02-26 Thread Robert Abel
On 26 Feb 2018 17:49, Miguel Ojeda wrote:
> On a general note, the code seems a bit convoluted for what it does,
> specially without the comment written in the commit message :-) Isn't
> it simpler to use a tiny array in the stack and put the numbers to be
> converted instead of modifying the input sequence and dancing with
> pointers?

That's what I felt at first, too. If we can drop the backwards
compatibility of repeated xy commands, the whole affair gets much
easier, but will unfortunately break existing use.

Ex. ^[[Lx004y002x006; --> x6y2, because repeats of x would just
overwrite earlier values. That's what the while loop allowed in the
first place.

I suspect the while loop to parse was just a clever way of parsing y
followed by x and x followed by y using the same code and the
overwriting behavior is actually an unaccounted-for side-effect.

Regards,

Robert


Re: [PATCH 3/4] auxdisplay: charlcd: fix x/y address commands

2018-02-26 Thread Robert Abel
Hi Andy, Hi Miguel,

On 26 Feb 2018 12:44, Andy Shevchenko wrote:
> Can we avoid yoda style of programming?
On 26 Feb 2018 17:49, Miguel Ojeda wrote:
> Please do not change the style of the code w.r.t to the rest of the
> file, which writes tests with the non-lvalue on the right-hand side
> and do not compare against '\0'. Same for the rest.

I am actually a fan of yoda-style programming, although its value is
diminished with modern IDEs, which we all use, right?

On 26 Feb 2018 17:54, Miguel Ojeda wrote:
> On Mon, Feb 26, 2018 at 12:44 PM, Andy Shevchenko
>> Perhaps instead of dancing around kstrtox() better to switch to
>> simple_strtoul() ?
>
> It seems deprecated:
>
> /* Obsolete, do not use.  Use kstrto instead */
> extern unsigned long simple_strtoul(const char *,char **,unsigned int);

I thought the whole point was that simple_strtoul is deprecated and on
the kill list? Isn't that kind of against the whole argument of
re-inventing the wheel?
If using simple_strtoul is an option, it might be best to bring it back
and not touch the buffer at all.

Regards,

Robert


Re: [PATCH 3/4] auxdisplay: charlcd: fix x/y address commands

2018-02-26 Thread Robert Abel
Hi Andy, Hi Miguel,

On 26 Feb 2018 12:44, Andy Shevchenko wrote:
> Can we avoid yoda style of programming?
On 26 Feb 2018 17:49, Miguel Ojeda wrote:
> Please do not change the style of the code w.r.t to the rest of the
> file, which writes tests with the non-lvalue on the right-hand side
> and do not compare against '\0'. Same for the rest.

I am actually a fan of yoda-style programming, although its value is
diminished with modern IDEs, which we all use, right?

On 26 Feb 2018 17:54, Miguel Ojeda wrote:
> On Mon, Feb 26, 2018 at 12:44 PM, Andy Shevchenko
>> Perhaps instead of dancing around kstrtox() better to switch to
>> simple_strtoul() ?
>
> It seems deprecated:
>
> /* Obsolete, do not use.  Use kstrto instead */
> extern unsigned long simple_strtoul(const char *,char **,unsigned int);

I thought the whole point was that simple_strtoul is deprecated and on
the kill list? Isn't that kind of against the whole argument of
re-inventing the wheel?
If using simple_strtoul is an option, it might be best to bring it back
and not touch the buffer at all.

Regards,

Robert


Re: [PATCH 3/4] auxdisplay: charlcd: fix x/y address commands

2018-02-26 Thread Robert Abel
Hi Geert,

On 26 Feb 2018 09:46, Geert Uytterhoeven wrote:
>> +
>> +   nxt_cmd = *esc++;
>> +   nxt_esc = esc;
>> +
>> +   while ('\0' != *esc) {
>> +
>> +   cmd = nxt_cmd;
>> +   esc = nxt_esc;
>> +   nxt_esc = strpbrk(esc, "xy;");
>> +   if (NULL != nxt_esc) {
>> +   nxt_cmd = *nxt_esc;
>> +   /* terminate current sequence with NUL */
>> +   *nxt_esc++ = '\0';
>> +   }
> 
> So if none of "x", "y", or ";" is found, nxt_cmd will still contain
> the current command?
> Shouldn't it be reset to '\0' or so?

I originally had a comment there, but it then felt kinda silly.
Since one of the conditions of the code is that a semicolon ';' is
detected at the end of the stream, the situation you describe never
occurs until the end of the command string.

nxt_esc == NULL only when cmd == ';' and *esc == NULL. Since there is
nothing to terminate and the code won't run again (due to while (*esc)),
I didn't reset nxt_cmd. Other than that, I also don't know that there is
a sensible reset value.

Regards,

Robert


Re: [PATCH 3/4] auxdisplay: charlcd: fix x/y address commands

2018-02-26 Thread Robert Abel
Hi Geert,

On 26 Feb 2018 09:46, Geert Uytterhoeven wrote:
>> +
>> +   nxt_cmd = *esc++;
>> +   nxt_esc = esc;
>> +
>> +   while ('\0' != *esc) {
>> +
>> +   cmd = nxt_cmd;
>> +   esc = nxt_esc;
>> +   nxt_esc = strpbrk(esc, "xy;");
>> +   if (NULL != nxt_esc) {
>> +   nxt_cmd = *nxt_esc;
>> +   /* terminate current sequence with NUL */
>> +   *nxt_esc++ = '\0';
>> +   }
> 
> So if none of "x", "y", or ";" is found, nxt_cmd will still contain
> the current command?
> Shouldn't it be reset to '\0' or so?

I originally had a comment there, but it then felt kinda silly.
Since one of the conditions of the code is that a semicolon ';' is
detected at the end of the stream, the situation you describe never
occurs until the end of the command string.

nxt_esc == NULL only when cmd == ';' and *esc == NULL. Since there is
nothing to terminate and the code won't run again (due to while (*esc)),
I didn't reset nxt_cmd. Other than that, I also don't know that there is
a sensible reset value.

Regards,

Robert


[PATCH 3/4] auxdisplay: charlcd: fix x/y address commands

2018-02-25 Thread Robert Abel
NUL-terminate each individual number to be parsed.
To do this, the next command character and a pointer to its argument
are found and stored. The command character is then overwritten by NUL
before kstr* functions are called on the buffer.

Signed-off-by: Robert Abel <ra...@robertabel.eu>
---
 drivers/auxdisplay/charlcd.c | 53 
 1 file changed, 44 insertions(+), 9 deletions(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index a3d364e6c666..24cabe88c7f0 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -471,28 +471,63 @@ static inline int handle_lcd_special_code(struct charlcd 
*lcd)
break;
}
case 'x':   /* gotoxy : LxXXX[yYYY]; */
-   case 'y':   /* gotoxy : LyYYY[xXXX]; */
+   case 'y': { /* gotoxy : LyYYY[xXXX]; */
+
+   char* nxt_esc;
+   char  nxt_cmd;
+   char  cmd;
+   struct charlcd_priv_addr tmp_addr;
+
if (!strchr(esc, ';'))
break;
 
-   while (*esc) {
-   if (*esc == 'x') {
-   esc++;
-   if (kstrtoul(esc, 10, >addr.x) < 0)
+   /* sequence is processed whether legal or illegal */
+   processed = 1;
+
+   /* copy current address to temporary buffer */
+   tmp_addr = priv->addr;
+
+   nxt_cmd = *esc++;
+   nxt_esc = esc;
+
+   while ('\0' != *esc) {
+
+   cmd = nxt_cmd;
+   esc = nxt_esc;
+   nxt_esc = strpbrk(esc, "xy;");
+   if (NULL != nxt_esc) {
+   nxt_cmd = *nxt_esc;
+   /* terminate current sequence with NUL */
+   *nxt_esc++ = '\0';
+   }
+
+   if ('x' == cmd) {
+   if (kstrtoul(esc, 10, _addr.x) < 0)
break;
-   } else if (*esc == 'y') {
-   esc++;
-   if (kstrtoul(esc, 10, >addr.y) < 0)
+   } else if ('y' == cmd) {
+   if (kstrtoul(esc, 10, _addr.y) < 0)
break;
} else {
+   /* break on unknown command or ';' */
break;
}
+
}
 
+   /* unknown commands in sequence will be followed by at least 
';' */
+   if ('\0' != *esc)
+   break;
+
+   /* clamp new x/y coordinates */
+   if (tmp_addr.x >= lcd->width)
+   tmp_addr.x = lcd->width - 1;
+   tmp_addr.y %= lcd->height;
+
+   priv->addr = tmp_addr;
charlcd_gotoxy(lcd);
-   processed = 1;
break;
}
+   }
 
/* TODO: This indent party here got ugly, clean it! */
/* Check whether one flag was changed */
-- 
2.11.0



[PATCH 3/4] auxdisplay: charlcd: fix x/y address commands

2018-02-25 Thread Robert Abel
NUL-terminate each individual number to be parsed.
To do this, the next command character and a pointer to its argument
are found and stored. The command character is then overwritten by NUL
before kstr* functions are called on the buffer.

Signed-off-by: Robert Abel 
---
 drivers/auxdisplay/charlcd.c | 53 
 1 file changed, 44 insertions(+), 9 deletions(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index a3d364e6c666..24cabe88c7f0 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -471,28 +471,63 @@ static inline int handle_lcd_special_code(struct charlcd 
*lcd)
break;
}
case 'x':   /* gotoxy : LxXXX[yYYY]; */
-   case 'y':   /* gotoxy : LyYYY[xXXX]; */
+   case 'y': { /* gotoxy : LyYYY[xXXX]; */
+
+   char* nxt_esc;
+   char  nxt_cmd;
+   char  cmd;
+   struct charlcd_priv_addr tmp_addr;
+
if (!strchr(esc, ';'))
break;
 
-   while (*esc) {
-   if (*esc == 'x') {
-   esc++;
-   if (kstrtoul(esc, 10, >addr.x) < 0)
+   /* sequence is processed whether legal or illegal */
+   processed = 1;
+
+   /* copy current address to temporary buffer */
+   tmp_addr = priv->addr;
+
+   nxt_cmd = *esc++;
+   nxt_esc = esc;
+
+   while ('\0' != *esc) {
+
+   cmd = nxt_cmd;
+   esc = nxt_esc;
+   nxt_esc = strpbrk(esc, "xy;");
+   if (NULL != nxt_esc) {
+   nxt_cmd = *nxt_esc;
+   /* terminate current sequence with NUL */
+   *nxt_esc++ = '\0';
+   }
+
+   if ('x' == cmd) {
+   if (kstrtoul(esc, 10, _addr.x) < 0)
break;
-   } else if (*esc == 'y') {
-   esc++;
-   if (kstrtoul(esc, 10, >addr.y) < 0)
+   } else if ('y' == cmd) {
+   if (kstrtoul(esc, 10, _addr.y) < 0)
break;
} else {
+   /* break on unknown command or ';' */
break;
}
+
}
 
+   /* unknown commands in sequence will be followed by at least 
';' */
+   if ('\0' != *esc)
+   break;
+
+   /* clamp new x/y coordinates */
+   if (tmp_addr.x >= lcd->width)
+   tmp_addr.x = lcd->width - 1;
+   tmp_addr.y %= lcd->height;
+
+   priv->addr = tmp_addr;
charlcd_gotoxy(lcd);
-   processed = 1;
break;
}
+   }
 
/* TODO: This indent party here got ugly, clean it! */
/* Check whether one flag was changed */
-- 
2.11.0



[PATCH 1/4] auxdisplay: charlcd: fix two-line command ^[[LN not marked as processed

2018-02-25 Thread Robert Abel
Signed-off-by: Robert Abel <ra...@robertabel.eu>
---
 drivers/auxdisplay/charlcd.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index a3486db03d81..e3b2fd15c5a3 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -362,6 +362,7 @@ static inline int handle_lcd_special_code(struct charlcd 
*lcd)
break;
case 'N':   /* Two Lines */
priv->flags |= LCD_FLAG_N;
+   processed = 1;
break;
case 'l':   /* Shift Cursor Left */
if (priv->addr.x > 0) {
-- 
2.11.0



[PATCH 1/4] auxdisplay: charlcd: fix two-line command ^[[LN not marked as processed

2018-02-25 Thread Robert Abel
Signed-off-by: Robert Abel 
---
 drivers/auxdisplay/charlcd.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index a3486db03d81..e3b2fd15c5a3 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -362,6 +362,7 @@ static inline int handle_lcd_special_code(struct charlcd 
*lcd)
break;
case 'N':   /* Two Lines */
priv->flags |= LCD_FLAG_N;
+   processed = 1;
break;
case 'l':   /* Shift Cursor Left */
if (priv->addr.x > 0) {
-- 
2.11.0



[PATCH 2/4] auxdisplay: charlcd: name x/y address struct

2018-02-25 Thread Robert Abel
Signed-off-by: Robert Abel <ra...@robertabel.eu>
---
 drivers/auxdisplay/charlcd.c | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index e3b2fd15c5a3..a3d364e6c666 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -67,6 +67,11 @@
 #define LCD_ESCAPE_LEN 24  /* Max chars for LCD escape command */
 #define LCD_ESCAPE_CHAR27  /* Use char 27 for escape 
command */
 
+struct charlcd_priv_addr {
+   unsigned long int x;
+   unsigned long int y;
+};
+
 struct charlcd_priv {
struct charlcd lcd;
 
@@ -80,12 +85,9 @@ struct charlcd_priv {
unsigned long int flags;
 
/* Contains the LCD X and Y offset */
-   struct {
-   unsigned long int x;
-   unsigned long int y;
-   } addr;
+   struct charlcd_priv_addr addr;
 
-   /* Current escape sequence and it's length or -1 if outside */
+   /* Current escape sequence and its length or -1 if outside */
struct {
char buf[LCD_ESCAPE_LEN + 1];
int len;
-- 
2.11.0



[PATCH 2/4] auxdisplay: charlcd: name x/y address struct

2018-02-25 Thread Robert Abel
Signed-off-by: Robert Abel 
---
 drivers/auxdisplay/charlcd.c | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index e3b2fd15c5a3..a3d364e6c666 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -67,6 +67,11 @@
 #define LCD_ESCAPE_LEN 24  /* Max chars for LCD escape command */
 #define LCD_ESCAPE_CHAR27  /* Use char 27 for escape 
command */
 
+struct charlcd_priv_addr {
+   unsigned long int x;
+   unsigned long int y;
+};
+
 struct charlcd_priv {
struct charlcd lcd;
 
@@ -80,12 +85,9 @@ struct charlcd_priv {
unsigned long int flags;
 
/* Contains the LCD X and Y offset */
-   struct {
-   unsigned long int x;
-   unsigned long int y;
-   } addr;
+   struct charlcd_priv_addr addr;
 
-   /* Current escape sequence and it's length or -1 if outside */
+   /* Current escape sequence and its length or -1 if outside */
struct {
char buf[LCD_ESCAPE_LEN + 1];
int len;
-- 
2.11.0



[PATCH 4/4] auxdisplay: charlcd: make home command unshift display

2018-02-25 Thread Robert Abel
A user has no way of unshifting the display programmatically once shifted.
Users cannot rely on ^[[H (home) to result in their message being seen either.
Use the actual HOME command 0x02 instead of only returning to x0/y0.
Users can still do ^[[Lx0y0; (go to x/y) if they wish to use the 'old' home
function.
Implement fast clearing of LCD by going to x0/y0 first, clearing display and
then calling home to possibly unshift display possibly avoiding artifacts by
not unshifting before clearing display.

Signed-off-by: Robert Abel <ra...@robertabel.eu>
---
 drivers/auxdisplay/charlcd.c | 10 --
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index 24cabe88c7f0..41f9aa4a73d4 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -43,6 +43,8 @@
 /* LCD commands */
 #define LCD_CMD_DISPLAY_CLEAR  0x01/* Clear entire display */
 
+#define LCD_CMD_HOME0x02/* Set DDRAM address to 0 and unshift 
display */
+
 #define LCD_CMD_ENTRY_MODE 0x04/* Set entry mode */
 #define LCD_CMD_CURSOR_INC 0x02/* Increment cursor */
 
@@ -182,7 +184,8 @@ static void charlcd_home(struct charlcd *lcd)
 
priv->addr.x = 0;
priv->addr.y = 0;
-   charlcd_gotoxy(lcd);
+   lcd->ops->write_cmd(lcd, LCD_CMD_HOME);
+   long_sleep(2);
 }
 
 static void charlcd_print(struct charlcd *lcd, char c)
@@ -202,9 +205,12 @@ static void charlcd_print(struct charlcd *lcd, char c)
 
 static void charlcd_clear_fast(struct charlcd *lcd)
 {
+   struct charlcd_priv *priv = to_priv(lcd);
int pos;
 
-   charlcd_home(lcd);
+   priv->addr.x = 0;
+   priv->addr.y = 0;
+   charlcd_gotoxy(lcd);
 
if (lcd->ops->clear_fast)
lcd->ops->clear_fast(lcd);
-- 
2.11.0



[PATCH 4/4] auxdisplay: charlcd: make home command unshift display

2018-02-25 Thread Robert Abel
A user has no way of unshifting the display programmatically once shifted.
Users cannot rely on ^[[H (home) to result in their message being seen either.
Use the actual HOME command 0x02 instead of only returning to x0/y0.
Users can still do ^[[Lx0y0; (go to x/y) if they wish to use the 'old' home
function.
Implement fast clearing of LCD by going to x0/y0 first, clearing display and
then calling home to possibly unshift display possibly avoiding artifacts by
not unshifting before clearing display.

Signed-off-by: Robert Abel 
---
 drivers/auxdisplay/charlcd.c | 10 --
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index 24cabe88c7f0..41f9aa4a73d4 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -43,6 +43,8 @@
 /* LCD commands */
 #define LCD_CMD_DISPLAY_CLEAR  0x01/* Clear entire display */
 
+#define LCD_CMD_HOME0x02/* Set DDRAM address to 0 and unshift 
display */
+
 #define LCD_CMD_ENTRY_MODE 0x04/* Set entry mode */
 #define LCD_CMD_CURSOR_INC 0x02/* Increment cursor */
 
@@ -182,7 +184,8 @@ static void charlcd_home(struct charlcd *lcd)
 
priv->addr.x = 0;
priv->addr.y = 0;
-   charlcd_gotoxy(lcd);
+   lcd->ops->write_cmd(lcd, LCD_CMD_HOME);
+   long_sleep(2);
 }
 
 static void charlcd_print(struct charlcd *lcd, char c)
@@ -202,9 +205,12 @@ static void charlcd_print(struct charlcd *lcd, char c)
 
 static void charlcd_clear_fast(struct charlcd *lcd)
 {
+   struct charlcd_priv *priv = to_priv(lcd);
int pos;
 
-   charlcd_home(lcd);
+   priv->addr.x = 0;
+   priv->addr.y = 0;
+   charlcd_gotoxy(lcd);
 
if (lcd->ops->clear_fast)
lcd->ops->clear_fast(lcd);
-- 
2.11.0



Re: [PATCH 1/3] auxdisplay: charlcd: fix hex literal ranges for graphics command

2018-02-25 Thread Robert Abel
The following patch set fixes the x/y coordinate addressing issue I mentioned 
earlier
as well as not marking the two-line command sequence as processed resulting in 
a confusing
state.

I implemented the logic around using kstrtoul by terminating the substrings 
that contain
numbers for each command separately and then restoring the command character 
following the
number that was overwritten.

Additionally, the code now doesn't write live to the x and y address fields and 
will
bail out if an unknown command character or an invalid number was encountered.

I did try to keep it backwards compatible, so sequences of the form 
^[[Lx0y1x2y4; will
still work (and result in x2y4).

Additionally, I noticed that the ^[[H home function was just resetting the x/y 
coordinates
but not the display shift, which results in a situation where the display 
cannot be
programmatically unshifted (except for init ^[[LI). So I implemented the HOME 
command 0x02
for charlcd_home. The old behavior can be simulated using ^[[Lx0y0; (just reset 
x/y, don't
unshift).

I tested on my Raspberry Pi Zero W with a clone 1602 display.

Robert Abel (4):
  auxdisplay: charlcd: fix two-line command ^[[LN not marked as
processed
  auxdisplay: charlcd: name x/y address struct
  auxdisplay: charlcd: fix x/y address commands
  auxdisplay: charlcd: make home command unshift display

 drivers/auxdisplay/charlcd.c | 76 ++--
 1 file changed, 60 insertions(+), 16 deletions(-)

-- 
2.11.0



Re: [PATCH 1/3] auxdisplay: charlcd: fix hex literal ranges for graphics command

2018-02-25 Thread Robert Abel
The following patch set fixes the x/y coordinate addressing issue I mentioned 
earlier
as well as not marking the two-line command sequence as processed resulting in 
a confusing
state.

I implemented the logic around using kstrtoul by terminating the substrings 
that contain
numbers for each command separately and then restoring the command character 
following the
number that was overwritten.

Additionally, the code now doesn't write live to the x and y address fields and 
will
bail out if an unknown command character or an invalid number was encountered.

I did try to keep it backwards compatible, so sequences of the form 
^[[Lx0y1x2y4; will
still work (and result in x2y4).

Additionally, I noticed that the ^[[H home function was just resetting the x/y 
coordinates
but not the display shift, which results in a situation where the display 
cannot be
programmatically unshifted (except for init ^[[LI). So I implemented the HOME 
command 0x02
for charlcd_home. The old behavior can be simulated using ^[[Lx0y0; (just reset 
x/y, don't
unshift).

I tested on my Raspberry Pi Zero W with a clone 1602 display.

Robert Abel (4):
  auxdisplay: charlcd: fix two-line command ^[[LN not marked as
processed
  auxdisplay: charlcd: name x/y address struct
  auxdisplay: charlcd: fix x/y address commands
  auxdisplay: charlcd: make home command unshift display

 drivers/auxdisplay/charlcd.c | 76 ++--
 1 file changed, 60 insertions(+), 16 deletions(-)

-- 
2.11.0



Re: [PATCH 1/3] auxdisplay: charlcd: fix hex literal ranges for graphics command

2018-02-25 Thread Robert Abel
The following patch set fixes the x/y coordinate addressing issue I mentioned 
earlier
as well as not marking the two-line command sequence as processed resulting in 
a confusing
state.

I implemented the logic around using kstrtoul by terminating the substrings 
that contain
numbers for each command separately and then restoring the command character 
following the
number that was overwritten.

Additionally, the code now doesn't write live to the x and y address fields and 
will
bail out if an unknown command character or an invalid number was encountered.

I did try to keep it backwards compatible, so sequences of the form 
^[[Lx0y1x2y4; will
still work (and result in x2y4).

Additionally, I noticed that the ^[[H home function was just resetting the x/y 
coordinates
but not the display shift, which results in a situation where the display 
cannot be
programmatically unshifted (except for init ^[[LI). So I implemented the HOME 
command 0x02
for charlcd_home. The old behavior can be simulated using ^[[Lx0y0; (just reset 
x/y, don't
unshift).

I tested on my Raspberry Pi Zero W with a clone 1602 display.

Robert Abel (4):
  auxdisplay: charlcd: fix two-line command ^[[LN not marked as
processed
  auxdisplay: charlcd: name x/y address struct
  auxdisplay: charlcd: fix x/y address commands
  auxdisplay: charlcd: make home command unshift display

 drivers/auxdisplay/charlcd.c | 76 ++--
 1 file changed, 60 insertions(+), 16 deletions(-)

-- 
2.11.0



Re: [PATCH 1/3] auxdisplay: charlcd: fix hex literal ranges for graphics command

2018-02-25 Thread Robert Abel
The following patch set fixes the x/y coordinate addressing issue I mentioned 
earlier
as well as not marking the two-line command sequence as processed resulting in 
a confusing
state.

I implemented the logic around using kstrtoul by terminating the substrings 
that contain
numbers for each command separately and then restoring the command character 
following the
number that was overwritten.

Additionally, the code now doesn't write live to the x and y address fields and 
will
bail out if an unknown command character or an invalid number was encountered.

I did try to keep it backwards compatible, so sequences of the form 
^[[Lx0y1x2y4; will
still work (and result in x2y4).

Additionally, I noticed that the ^[[H home function was just resetting the x/y 
coordinates
but not the display shift, which results in a situation where the display 
cannot be
programmatically unshifted (except for init ^[[LI). So I implemented the HOME 
command 0x02
for charlcd_home. The old behavior can be simulated using ^[[Lx0y0; (just reset 
x/y, don't
unshift).

I tested on my Raspberry Pi Zero W with a clone 1602 display.

Robert Abel (4):
  auxdisplay: charlcd: fix two-line command ^[[LN not marked as
processed
  auxdisplay: charlcd: name x/y address struct
  auxdisplay: charlcd: fix x/y address commands
  auxdisplay: charlcd: make home command unshift display

 drivers/auxdisplay/charlcd.c | 76 ++--
 1 file changed, 60 insertions(+), 16 deletions(-)

-- 
2.11.0



Re: [PATCH 1/3] auxdisplay: charlcd: fix hex literal ranges for graphics command

2018-02-25 Thread Robert Abel
Hi Andy,

On 15 Feb 2018 11:57, Andy Shevchenko wrote:
> On Thu, Feb 15, 2018 at 1:17 AM, Robert Abel <ra...@robertabel.eu> wrote:
>> hex_to_bin look fine to me, although personally I'm not a big fan of its
>> use of tolower.
> 
> Let's duplicate then over and over?

I was speaking more generally about performance here. There is a reason
for kstrtox.c:57
(https://elixir.bootlin.com/linux/v4.14.7/source/lib/kstrtox.c#L57)
> unsigned int lc = c | 0x20; /* don't tolower() this line */

> Can you point to the documentation where user can easily (w/o reading
> the code) get how it suppose to be?

Unfortunately not. I read the code myself to know how it is supposed to
work. That's definitely a gap in documentation.

> On Thu, Feb 15, 2018 at 1:17 AM, Robert Abel <ra...@robertabel.eu> wrote:
>> I noticed the only part of the code that does make use of library
>> functions, parsing x and y coordinates using kstrtoul, is broken.
>> Apparently it used to use simple_strtoul, which worked and then got
>> replaced.
> By which commit?

129957069e6af42a6e021d90679c56662c95f7e1
(https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=129957069e6af42a6e021d90679c56662c95f7e1)

I'll try to answer to this email with relevant patches for charlcd.c.

Regards,

Robert


Re: [PATCH 1/3] auxdisplay: charlcd: fix hex literal ranges for graphics command

2018-02-25 Thread Robert Abel
Hi Andy,

On 15 Feb 2018 11:57, Andy Shevchenko wrote:
> On Thu, Feb 15, 2018 at 1:17 AM, Robert Abel  wrote:
>> hex_to_bin look fine to me, although personally I'm not a big fan of its
>> use of tolower.
> 
> Let's duplicate then over and over?

I was speaking more generally about performance here. There is a reason
for kstrtox.c:57
(https://elixir.bootlin.com/linux/v4.14.7/source/lib/kstrtox.c#L57)
> unsigned int lc = c | 0x20; /* don't tolower() this line */

> Can you point to the documentation where user can easily (w/o reading
> the code) get how it suppose to be?

Unfortunately not. I read the code myself to know how it is supposed to
work. That's definitely a gap in documentation.

> On Thu, Feb 15, 2018 at 1:17 AM, Robert Abel  wrote:
>> I noticed the only part of the code that does make use of library
>> functions, parsing x and y coordinates using kstrtoul, is broken.
>> Apparently it used to use simple_strtoul, which worked and then got
>> replaced.
> By which commit?

129957069e6af42a6e021d90679c56662c95f7e1
(https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=129957069e6af42a6e021d90679c56662c95f7e1)

I'll try to answer to this email with relevant patches for charlcd.c.

Regards,

Robert


Re: [PATCH 1/3] auxdisplay: charlcd: fix hex literal ranges for graphics command

2018-02-14 Thread Robert Abel
On 13 Feb 2018 14:36, Andy Shevchenko wrote:
> I understand that we have a huge and hopefully nice library in the
> kernel, but the question still the same, what prevents a developer or
> maintainer to look at it from time to time?
> 
> For, I dare to say, ages we have hex_to_bin() and hex2bin().
> Can we use it?

hex_to_bin look fine to me, although personally I'm not a big fan of its
use of tolower.

The current parser implementation is much more lenient than hex2bin,
however. hex2bin won't parse strings containing illegal characters
(which are currently skipped) or hexadecimal strings with an odd number
of digits (which are currently allowed and the final digit will be ignored).

I noticed the only part of the code that does make use of library
functions, parsing x and y coordinates using kstrtoul, is broken.
Apparently it used to use simple_strtoul, which worked and then got
replaced. So apparently looking over the kernel lib from time to time
can also do some harm ;)
Patch incoming :)

Regards,

Robert


Re: [PATCH 1/3] auxdisplay: charlcd: fix hex literal ranges for graphics command

2018-02-14 Thread Robert Abel
On 13 Feb 2018 14:36, Andy Shevchenko wrote:
> I understand that we have a huge and hopefully nice library in the
> kernel, but the question still the same, what prevents a developer or
> maintainer to look at it from time to time?
> 
> For, I dare to say, ages we have hex_to_bin() and hex2bin().
> Can we use it?

hex_to_bin look fine to me, although personally I'm not a big fan of its
use of tolower.

The current parser implementation is much more lenient than hex2bin,
however. hex2bin won't parse strings containing illegal characters
(which are currently skipped) or hexadecimal strings with an odd number
of digits (which are currently allowed and the final digit will be ignored).

I noticed the only part of the code that does make use of library
functions, parsing x and y coordinates using kstrtoul, is broken.
Apparently it used to use simple_strtoul, which worked and then got
replaced. So apparently looking over the kernel lib from time to time
can also do some harm ;)
Patch incoming :)

Regards,

Robert


[PATCH 3/3] auxdisplay: charlcd: replace octal literal with form-feed escape sequence

2018-02-09 Thread Robert Abel
There is no need to resort to octal escape sequence for the form feed character 
when an established escape sequence exists.

Signed-off-by: Robert Abel <ra...@robertabel.eu>
---
 drivers/auxdisplay/charlcd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index 92549c8344a4..a3486db03d81 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -555,7 +555,7 @@ static void charlcd_write_char(struct charlcd *lcd, char c)
/* back one char again */
lcd->ops->write_cmd(lcd, LCD_CMD_SHIFT);
break;
-   case '\014':
+   case '\f':
/* quickly clear the display */
charlcd_clear_fast(lcd);
break;
-- 
2.11.0



[PATCH 3/3] auxdisplay: charlcd: replace octal literal with form-feed escape sequence

2018-02-09 Thread Robert Abel
There is no need to resort to octal escape sequence for the form feed character 
when an established escape sequence exists.

Signed-off-by: Robert Abel 
---
 drivers/auxdisplay/charlcd.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index 92549c8344a4..a3486db03d81 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -555,7 +555,7 @@ static void charlcd_write_char(struct charlcd *lcd, char c)
/* back one char again */
lcd->ops->write_cmd(lcd, LCD_CMD_SHIFT);
break;
-   case '\014':
+   case '\f':
/* quickly clear the display */
charlcd_clear_fast(lcd);
break;
-- 
2.11.0



[PATCH 2/3] auxdisplay: charlcd: use null character instead of zero literal to terminate strings

2018-02-09 Thread Robert Abel
Using '\0' instead of plain 0 makes the intent clearer that this is indeed a 
string and not a series of integers.

Signed-off-by: Robert Abel <ra...@robertabel.eu>
---
 drivers/auxdisplay/charlcd.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index 324d02f9f1c5..92549c8344a4 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -527,7 +527,7 @@ static void charlcd_write_char(struct charlcd *lcd, char c)
if ((c != '\n') && priv->esc_seq.len >= 0) {
/* yes, let's add this char to the buffer */
priv->esc_seq.buf[priv->esc_seq.len++] = c;
-   priv->esc_seq.buf[priv->esc_seq.len] = 0;
+   priv->esc_seq.buf[priv->esc_seq.len] = '\0';
} else {
/* aborts any previous escape sequence */
priv->esc_seq.len = -1;
@@ -536,7 +536,7 @@ static void charlcd_write_char(struct charlcd *lcd, char c)
case LCD_ESCAPE_CHAR:
/* start of an escape sequence */
priv->esc_seq.len = 0;
-   priv->esc_seq.buf[priv->esc_seq.len] = 0;
+   priv->esc_seq.buf[priv->esc_seq.len] = '\0';
break;
case '\b':
/* go back one char and clear it */
-- 
2.11.0



[PATCH 1/3] auxdisplay: charlcd: fix hex literal ranges for graphics command

2018-02-09 Thread Robert Abel
The graphics command expects 16 hexadecimal literals, but would allow 
characters in range [0-9a-zA-Z] instead of [0-9a-fA-F].

Signed-off-by: Robert Abel <ra...@robertabel.eu>
---
 drivers/auxdisplay/charlcd.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index 642afd88870b..324d02f9f1c5 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -441,9 +441,9 @@ static inline int handle_lcd_special_code(struct charlcd 
*lcd)
shift ^= 4;
if (*esc >= '0' && *esc <= '9') {
value |= (*esc - '0') << shift;
-   } else if (*esc >= 'A' && *esc <= 'Z') {
+   } else if (*esc >= 'A' && *esc <= 'F') {
value |= (*esc - 'A' + 10) << shift;
-   } else if (*esc >= 'a' && *esc <= 'z') {
+   } else if (*esc >= 'a' && *esc <= 'f') {
value |= (*esc - 'a' + 10) << shift;
} else {
esc++;
-- 
2.11.0



[PATCH 2/3] auxdisplay: charlcd: use null character instead of zero literal to terminate strings

2018-02-09 Thread Robert Abel
Using '\0' instead of plain 0 makes the intent clearer that this is indeed a 
string and not a series of integers.

Signed-off-by: Robert Abel 
---
 drivers/auxdisplay/charlcd.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index 324d02f9f1c5..92549c8344a4 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -527,7 +527,7 @@ static void charlcd_write_char(struct charlcd *lcd, char c)
if ((c != '\n') && priv->esc_seq.len >= 0) {
/* yes, let's add this char to the buffer */
priv->esc_seq.buf[priv->esc_seq.len++] = c;
-   priv->esc_seq.buf[priv->esc_seq.len] = 0;
+   priv->esc_seq.buf[priv->esc_seq.len] = '\0';
} else {
/* aborts any previous escape sequence */
priv->esc_seq.len = -1;
@@ -536,7 +536,7 @@ static void charlcd_write_char(struct charlcd *lcd, char c)
case LCD_ESCAPE_CHAR:
/* start of an escape sequence */
priv->esc_seq.len = 0;
-   priv->esc_seq.buf[priv->esc_seq.len] = 0;
+   priv->esc_seq.buf[priv->esc_seq.len] = '\0';
break;
case '\b':
/* go back one char and clear it */
-- 
2.11.0



[PATCH 1/3] auxdisplay: charlcd: fix hex literal ranges for graphics command

2018-02-09 Thread Robert Abel
The graphics command expects 16 hexadecimal literals, but would allow 
characters in range [0-9a-zA-Z] instead of [0-9a-fA-F].

Signed-off-by: Robert Abel 
---
 drivers/auxdisplay/charlcd.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/auxdisplay/charlcd.c b/drivers/auxdisplay/charlcd.c
index 642afd88870b..324d02f9f1c5 100644
--- a/drivers/auxdisplay/charlcd.c
+++ b/drivers/auxdisplay/charlcd.c
@@ -441,9 +441,9 @@ static inline int handle_lcd_special_code(struct charlcd 
*lcd)
shift ^= 4;
if (*esc >= '0' && *esc <= '9') {
value |= (*esc - '0') << shift;
-   } else if (*esc >= 'A' && *esc <= 'Z') {
+   } else if (*esc >= 'A' && *esc <= 'F') {
value |= (*esc - 'A' + 10) << shift;
-   } else if (*esc >= 'a' && *esc <= 'z') {
+   } else if (*esc >= 'a' && *esc <= 'f') {
value |= (*esc - 'a' + 10) << shift;
} else {
esc++;
-- 
2.11.0



[PATCH 0/3] auxdisplay: charlcd: miscellaneous patches

2018-02-09 Thread Robert Abel
While looking at charlcd I noticed some little bits here and there that might
be corrected or improved.

Robert Abel (3):
  auxdisplay: charlcd: fix hex literal ranges for graphics command
  auxdisplay: charlcd: use null character instead of zero literal to
terminate strings
  auxdisplay: charlcd: replace octal literal with form-feed escape
sequence

 drivers/auxdisplay/charlcd.c | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

-- 
2.11.0



[PATCH 0/3] auxdisplay: charlcd: miscellaneous patches

2018-02-09 Thread Robert Abel
While looking at charlcd I noticed some little bits here and there that might
be corrected or improved.

Robert Abel (3):
  auxdisplay: charlcd: fix hex literal ranges for graphics command
  auxdisplay: charlcd: use null character instead of zero literal to
terminate strings
  auxdisplay: charlcd: replace octal literal with form-feed escape
sequence

 drivers/auxdisplay/charlcd.c | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

-- 
2.11.0



of: dynamic: resource: add WARN in release_resource for DT overlays

2015-07-30 Thread Robert ABEL

This patch prevents a kernel OOPS when removing a DT overlay containing
nodes with reg properties. release_resources is called for these nodes.
However, the resource structs were never initialized, hence the kernel OOPS.

This is obviously a stopgap measure until a proper solution is coded, see [1].


[1]: https://lkml.org/lkml/2014/4/17/359
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] of: resource: add WARN for invalid release_resource calls

2015-07-30 Thread Robert ABEL
Signed-off-by: Robert ABEL 
---
 kernel/resource.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/kernel/resource.c b/kernel/resource.c
index 0bcebff..b4c9b27 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -236,6 +236,13 @@ static int __release_resource(struct resource *old)
 {
struct resource *tmp, **p;
 
+/* devicetree overlays:
+ * of code doesn't initialize parent, child, sibling
+ * gracefully 'do the right thing' here
+ */
+   if (WARN(!old->parent, "%s: uninitialized resource %s\n", __FUNCTION__, 
old->name))
+   return 0;
+
p = >parent->child;
for (;;) {
tmp = *p;
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


of: dynamic: resource: add WARN in release_resource for DT overlays

2015-07-30 Thread Robert ABEL

This patch prevents a kernel OOPS when removing a DT overlay containing
nodes with reg properties. release_resources is called for these nodes.
However, the resource structs were never initialized, hence the kernel OOPS.

This is obviously a stopgap measure until a proper solution is coded, see [1].


[1]: https://lkml.org/lkml/2014/4/17/359
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] of: resource: add WARN for invalid release_resource calls

2015-07-30 Thread Robert ABEL
Signed-off-by: Robert ABEL ra...@cit-ec.uni-bielefeld.de
---
 kernel/resource.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/kernel/resource.c b/kernel/resource.c
index 0bcebff..b4c9b27 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -236,6 +236,13 @@ static int __release_resource(struct resource *old)
 {
struct resource *tmp, **p;
 
+/* devicetree overlays:
+ * of code doesn't initialize parent, child, sibling
+ * gracefully 'do the right thing' here
+ */
+   if (WARN(!old-parent, %s: uninitialized resource %s\n, __FUNCTION__, 
old-name))
+   return 0;
+
p = old-parent-child;
for (;;) {
tmp = *p;
-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] net: rfkill-regulator: fix compiler warning

2015-07-28 Thread Robert ABEL
pdata char* name => const char* name

Signed-off-by: Robert ABEL 
---
 include/linux/rfkill-regulator.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/rfkill-regulator.h b/include/linux/rfkill-regulator.h
index aca36bc..594d8e7 100644
--- a/include/linux/rfkill-regulator.h
+++ b/include/linux/rfkill-regulator.h
@@ -41,7 +41,7 @@
 #include 
 
 struct rfkill_regulator_platform_data {
-   char *name; /* the name for the rfkill switch */
+   const char *name;   /* the name for the rfkill switch */
enum rfkill_type type;  /* the type as specified in rfkill.h */
 };
 
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] net: rfkill-regulator: fix compiler warning

2015-07-28 Thread Robert ABEL
pdata char* name = const char* name

Signed-off-by: Robert ABEL ra...@cit-ec.uni-bielefeld.de
---
 include/linux/rfkill-regulator.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/rfkill-regulator.h b/include/linux/rfkill-regulator.h
index aca36bc..594d8e7 100644
--- a/include/linux/rfkill-regulator.h
+++ b/include/linux/rfkill-regulator.h
@@ -41,7 +41,7 @@
 #include linux/rfkill.h
 
 struct rfkill_regulator_platform_data {
-   char *name; /* the name for the rfkill switch */
+   const char *name;   /* the name for the rfkill switch */
enum rfkill_type type;  /* the type as specified in rfkill.h */
 };
 
-- 
2.5.0

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 0/8] ARM OMAP2+ GPMC: fixes and bus children

2015-03-03 Thread Robert Abel
Hi Roger,

On Tue, Mar 3, 2015 at 1:55 PM, Roger Quadros  wrote:
> I'm OK with this version.
>
> Tony, after you ACK these I will queue them for v4.1.

Please use v4 of my patches. The DTS output has been changed and the
comments have their colon.

Regards,

Robert
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/8] ARM OMAP2+ GPMC: add bus children

2015-03-03 Thread Robert Abel
Hi Roger,

On Tue, Mar 3, 2015 at 11:09 AM, Roger Quadros  wrote:
> If that is the case then I'd rather not check for return value of 
> of_platform_populate().
> Failure in populating GPMC child's children is already out of scope of GPMC 
> driver.

Well, I'd rather leave it in for now. If something *does* break in the
future, the user will at least get a message about it.

Regards,

Robert
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 0/8] ARM OMAP2+ GPMC: fixes and bus children

2015-03-03 Thread Robert Abel
Hi Roger,

On Tue, Mar 3, 2015 at 1:55 PM, Roger Quadros rog...@ti.com wrote:
 I'm OK with this version.

 Tony, after you ACK these I will queue them for v4.1.

Please use v4 of my patches. The DTS output has been changed and the
comments have their colon.

Regards,

Robert
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/8] ARM OMAP2+ GPMC: add bus children

2015-03-03 Thread Robert Abel
Hi Roger,

On Tue, Mar 3, 2015 at 11:09 AM, Roger Quadros rog...@ti.com wrote:
 If that is the case then I'd rather not check for return value of 
 of_platform_populate().
 Failure in populating GPMC child's children is already out of scope of GPMC 
 driver.

Well, I'd rather leave it in for now. If something *does* break in the
future, the user will at least get a message about it.

Regards,

Robert
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 7/8 v4] ARM OMAP2+ GPMC: fix WAITMONITORINGTIME divider bug

2015-02-27 Thread Robert ABEL
The WAITMONITORINGTIME is expressed as a number of GPMC_CLK clock cycles,
even though the access is defined as asynchronous, and no GPMC_CLK clock
is provided to the external device. Still, GPMCFCLKDIVIDER is used as a divider
for the GPMC clock, so it must be programmed to define the
correct WAITMONITORINGTIME delay.

This patch correctly computes WAITMONITORINGTIME in GPMC_CLK cycles instead of 
GPMC_FCLK cycles,
both during programming (gpmc_cs_set_timings) and during retrieval 
(gpmc_cs_show_timings).

Signed-off-by: Robert ABEL 
---
 drivers/memory/omap-gpmc.c | 128 +++--
 1 file changed, 101 insertions(+), 27 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 8ee335d..d091065 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -170,6 +170,11 @@
  */
 #defineGPMC_NR_IRQ 2
 
+enum gpmc_clk_domain {
+   GPMC_CD_FCLK,
+   GPMC_CD_CLK
+};
+
 struct gpmc_cs_data {
const char *name;
 
@@ -268,16 +273,54 @@ static unsigned long gpmc_get_fclk_period(void)
return rate;
 }
 
-static unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
+/**
+ * gpmc_get_clk_period - get period of selected clock domain in ps
+ * @cs Chip Select Region.
+ * @cd Clock Domain.
+ *
+ * GPMC_CS_CONFIG1 GPMCFCLKDIVIDER for cs has to be setup
+ * prior to calling this function with GPMC_CD_CLK.
+ */
+static unsigned long gpmc_get_clk_period(int cs, enum gpmc_clk_domain cd)
+{
+
+   unsigned long tick_ps = gpmc_get_fclk_period();
+   u32 l;
+   int div;
+
+   switch (cd) {
+   case GPMC_CD_CLK:
+   /* get current clk divider */
+   l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+   div = (l & 0x03) + 1;
+   /* get GPMC_CLK period */
+   tick_ps *= div;
+   break;
+   case GPMC_CD_FCLK:
+   /* FALL-THROUGH */
+   default:
+   break;
+   }
+
+   return tick_ps;
+
+}
+
+static unsigned int gpmc_ns_to_clk_ticks(unsigned int time_ns, int cs, enum 
gpmc_clk_domain cd)
 {
unsigned long tick_ps;
 
/* Calculate in picosecs to yield more exact results */
-   tick_ps = gpmc_get_fclk_period();
+   tick_ps = gpmc_get_clk_period(cs, cd);
 
return (time_ns * 1000 + tick_ps - 1) / tick_ps;
 }
 
+static unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
+{
+   return gpmc_ns_to_clk_ticks(time_ns, /* any CS */ 0, GPMC_CD_FCLK);
+}
+
 static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
 {
unsigned long tick_ps;
@@ -288,9 +331,14 @@ static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
return (time_ps + tick_ps - 1) / tick_ps;
 }
 
+unsigned int gpmc_clk_ticks_to_ns(unsigned ticks, int cs, enum gpmc_clk_domain 
cd)
+{
+   return ticks * gpmc_get_clk_period(cs, cd) / 1000;
+}
+
 unsigned int gpmc_ticks_to_ns(unsigned int ticks)
 {
-   return ticks * gpmc_get_fclk_period() / 1000;
+   return gpmc_clk_ticks_to_ns(ticks, /* any CS */ 0, GPMC_CD_FCLK);
 }
 
 static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
@@ -346,18 +394,24 @@ static void gpmc_cs_bool_timings(int cs, const struct 
gpmc_bool_timings *p)
  * @st_bit:  Start Bit
  * @end_bit: End Bit. Must be >= @st_bit.
  * @name:DTS node name, w/o "gpmc,"
+ * @cd:  Clock Domain of timing parameter.
+ * @shift:   Parameter value left shifts @shift, which is then printed instead 
of value.
  * @raw: Raw Format Option.
  *   raw format:  gpmc,name = 
  *   tick format: gpmc,name =  /* x ns -- y ns; x ticks 
*/
  *   Where x ns -- y ns result in the same tick value.
  * @noval:   Parameter values equal to 0 are not printed.
- * @shift:   Parameter value left shifts @shift, which is then printed instead 
of value.
  * @return:  Specified timing parameter (after optional @shift).
  *
  */
-static int get_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
-  bool raw, bool noval, int shift,
-  const char *name)
+static int get_gpmc_timing_reg(
+   /* timing specifiers */
+   int cs, int reg, int st_bit, int end_bit,
+   const char *name, const enum gpmc_clk_domain cd,
+   /* value transform */
+   int shift,
+   /* format specifiers */
+   bool raw, bool noval)
 {
u32 l;
int nr_bits;
@@ -377,8 +431,8 @@ static int get_gpmc_timing_reg(int cs, int reg, int st_bit, 
int end_bit,
unsigned int time_ns_min = 0;
 
if (l)
-   time_ns_min = gpmc_ticks_to_ns(l - 1) + 1;
-   time_ns = gpmc_ticks_to_ns(l);
+   time_ns_min = gpmc_clk_ticks_to_ns(l - 1, cs, cd) + 1;
+   time_ns = gpmc_clk_ticks_to_ns(l, cs, cd);
pr_info("gpmc,%s = <%u> /* %u ns - %u ns; %i ticks */\n",
name,

[PATCH 6/8 v4] ARM OMAP2+ GPMC: calculate GPMCFCLKDIVIDER based on WAITMONITORINGTIME

2015-02-27 Thread Robert ABEL
The WAITMONITORINGTIME is expressed as a number of GPMC_CLK clock cycles,
even though the access is defined as asynchronous, and no GPMC_CLK clock
is provided to the external device. Still, GPMCFCLKDIVIDER is used as a divider
for the GPMC clock, so it must be programmed to define the
correct WAITMONITORINGTIME delay.

Calculate GPMCFCLKDIVIDER independent of gpmc,sync-clk-ps in DT for
pure asynchronous accesses, i.e. both read and write asynchronous.

Signed-off-by: Robert ABEL 
---
 arch/arm/mach-omap2/gpmc-nand.c| 17 
 arch/arm/mach-omap2/gpmc-onenand.c |  4 +-
 arch/arm/mach-omap2/usb-tusb6010.c |  4 +-
 drivers/memory/omap-gpmc.c | 85 ++
 include/linux/omap-gpmc.h  |  2 +-
 5 files changed, 92 insertions(+), 20 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index d5951b1..e863a59 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -96,14 +96,6 @@ int gpmc_nand_init(struct omap_nand_platform_data 
*gpmc_nand_data,
gpmc_nand_res[1].start = gpmc_get_client_irq(GPMC_IRQ_FIFOEVENTENABLE);
gpmc_nand_res[2].start = gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT);
 
-   if (gpmc_t) {
-   err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t);
-   if (err < 0) {
-   pr_err("omap2-gpmc: Unable to set gpmc timings: %d\n", 
err);
-   return err;
-   }
-   }
-
memset(, 0, sizeof(struct gpmc_settings));
if (gpmc_nand_data->of_node)
gpmc_read_settings_dt(gpmc_nand_data->of_node, );
@@ -111,6 +103,15 @@ int gpmc_nand_init(struct omap_nand_platform_data 
*gpmc_nand_data,
gpmc_set_legacy(gpmc_nand_data, );
 
s.device_nand = true;
+
+   if (gpmc_t) {
+   err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t, );
+   if (err < 0) {
+   pr_err("omap2-gpmc: Unable to set gpmc timings: %d\n", 
err);
+   return err;
+   }
+   }
+
err = gpmc_cs_program_settings(gpmc_nand_data->cs, );
if (err < 0)
goto out_free_cs;
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c 
b/arch/arm/mach-omap2/gpmc-onenand.c
index 53d197e..f899e77 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -293,7 +293,7 @@ static int omap2_onenand_setup_async(void __iomem 
*onenand_base)
if (ret < 0)
return ret;
 
-   ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, );
+   ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, , _async);
if (ret < 0)
return ret;
 
@@ -331,7 +331,7 @@ static int omap2_onenand_setup_sync(void __iomem 
*onenand_base, int *freq_ptr)
if (ret < 0)
return ret;
 
-   ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, );
+   ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, , _sync);
if (ret < 0)
return ret;
 
diff --git a/arch/arm/mach-omap2/usb-tusb6010.c 
b/arch/arm/mach-omap2/usb-tusb6010.c
index 8333400..e554d9e 100644
--- a/arch/arm/mach-omap2/usb-tusb6010.c
+++ b/arch/arm/mach-omap2/usb-tusb6010.c
@@ -71,7 +71,7 @@ static int tusb_set_async_mode(unsigned sysclk_ps)
 
gpmc_calc_timings(, _async, _t);
 
-   return gpmc_cs_set_timings(async_cs, );
+   return gpmc_cs_set_timings(async_cs, , _async);
 }
 
 static int tusb_set_sync_mode(unsigned sysclk_ps)
@@ -98,7 +98,7 @@ static int tusb_set_sync_mode(unsigned sysclk_ps)
 
gpmc_calc_timings(, _sync, _t);
 
-   return gpmc_cs_set_timings(sync_cs, );
+   return gpmc_cs_set_timings(sync_cs, , _sync);
 }
 
 /* tusb driver calls this when it changes the chip's clocking */
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 02e5228..8ee335d 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -138,7 +138,9 @@
 #define GPMC_CONFIG1_PAGE_LEN(val)  ((val & 3) << 23)
 #define GPMC_CONFIG1_WAIT_READ_MON  (1 << 22)
 #define GPMC_CONFIG1_WAIT_WRITE_MON (1 << 21)
-#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
+#define GPMC_CONFIG1_WAIT_MON_TIME(val) ((val & 3) << 18)
+/** WAITMONITORINGTIME Max Ticks */
+#define GPMC_CONFIG1_WAITMONITORINGTIME_MAX  2
 #define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
 #define GPMC_CONFIG1_DEVICESIZE(val)((val & 3) << 12)
 #define GPMC_CONFIG1_DEVICESIZE_16  GPMC_CONFIG1_DEVICESIZE(1)
@@ -516,13 +518,48 @@ static int set_gpmc_timing_reg(int cs, int reg, int 
st_bit, int end_bit,
t->field, #field) < 0)  \
return -1
 
+/**
+ * gpmc_calc_waitmonitoring_divider - calculate proper GPMCFCLKDIVIDER based 
on WAITMONIT

[PATCH 8/8 v4] ARM OMAP2+ GPMC: fix programming/showing reserved timing parameters

2015-02-27 Thread Robert ABEL
GPMC_CONFIG1_i parameters CLKACTIVATIONTIME and WAITMONITORINGTIME
have reserved values.
Raise an error if calculated timings try to program reserved values.

GPMC_CONFIG1_i ATTACHEDDEVICEPAGELENGTH and DEVICESIZE were already checked
when parsing the DT.

Explicitly comment invalid values on gpmc_cs_show_timings for
-CLKACTIVATIONTIME
-WAITMONITORINGTIME
-DEVICESIZE
-ATTACHEDDEVICEPAGELENGTH

Signed-off-by: Robert ABEL 
---
 drivers/memory/omap-gpmc.c | 68 ++
 1 file changed, 45 insertions(+), 23 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index d091065..750c655 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -135,7 +135,11 @@
 #define GPMC_CONFIG1_WRITETYPE_ASYNC(0 << 27)
 #define GPMC_CONFIG1_WRITETYPE_SYNC (1 << 27)
 #define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
+/** CLKACTIVATIONTIME Max Ticks */
+#define GPMC_CONFIG1_CLKACTIVATIONTIME_MAX 2
 #define GPMC_CONFIG1_PAGE_LEN(val)  ((val & 3) << 23)
+/** ATTACHEDDEVICEPAGELENGTH Max Value */
+#define GPMC_CONFIG1_ATTACHEDDEVICEPAGELENGTH_MAX 2
 #define GPMC_CONFIG1_WAIT_READ_MON  (1 << 22)
 #define GPMC_CONFIG1_WAIT_WRITE_MON (1 << 21)
 #define GPMC_CONFIG1_WAIT_MON_TIME(val) ((val & 3) << 18)
@@ -144,6 +148,8 @@
 #define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
 #define GPMC_CONFIG1_DEVICESIZE(val)((val & 3) << 12)
 #define GPMC_CONFIG1_DEVICESIZE_16  GPMC_CONFIG1_DEVICESIZE(1)
+/** DEVICESIZE Max Value */
+#define GPMC_CONFIG1_DEVICESIZE_MAX 1
 #define GPMC_CONFIG1_DEVICETYPE(val)((val & 3) << 10)
 #define GPMC_CONFIG1_DEVICETYPE_NOR GPMC_CONFIG1_DEVICETYPE(0)
 #define GPMC_CONFIG1_MUXTYPE(val)   ((val & 3) << 8)
@@ -393,6 +399,8 @@ static void gpmc_cs_bool_timings(int cs, const struct 
gpmc_bool_timings *p)
  * @reg: GPMC_CS_CONFIGn register offset.
  * @st_bit:  Start Bit
  * @end_bit: End Bit. Must be >= @st_bit.
+ * @ma:x Maximum parameter value (before optional @shift).
+ *   If 0, maximum is as high as @st_bit and @end_bit allow.
  * @name:DTS node name, w/o "gpmc,"
  * @cd:  Clock Domain of timing parameter.
  * @shift:   Parameter value left shifts @shift, which is then printed instead 
of value.
@@ -400,13 +408,14 @@ static void gpmc_cs_bool_timings(int cs, const struct 
gpmc_bool_timings *p)
  *   raw format:  gpmc,name = 
  *   tick format: gpmc,name =  /* x ns -- y ns; x ticks 
*/
  *   Where x ns -- y ns result in the same tick value.
+ *   When @max is exceeded, "invalid" is printed inside comment.
  * @noval:   Parameter values equal to 0 are not printed.
  * @return:  Specified timing parameter (after optional @shift).
  *
  */
 static int get_gpmc_timing_reg(
/* timing specifiers */
-   int cs, int reg, int st_bit, int end_bit,
+   int cs, int reg, int st_bit, int end_bit, int max,
const char *name, const enum gpmc_clk_domain cd,
/* value transform */
int shift,
@@ -416,11 +425,15 @@ static int get_gpmc_timing_reg(
u32 l;
int nr_bits;
int mask;
+   bool invalid;
 
l = gpmc_cs_read_reg(cs, reg);
nr_bits = end_bit - st_bit + 1;
mask = (1 << nr_bits) - 1;
l = (l >> st_bit) & mask;
+   if (!max)
+   max = mask;
+   invalid = l > max;
if (shift)
l = (shift << l);
if (noval && (l == 0))
@@ -433,11 +446,11 @@ static int get_gpmc_timing_reg(
if (l)
time_ns_min = gpmc_clk_ticks_to_ns(l - 1, cs, cd) + 1;
time_ns = gpmc_clk_ticks_to_ns(l, cs, cd);
-   pr_info("gpmc,%s = <%u> /* %u ns - %u ns; %i ticks */\n",
-   name, time_ns, time_ns_min, time_ns, l);
+   pr_info("gpmc,%s = <%u> /* %u ns - %u ns; %i ticks%s*/\n",
+   name, time_ns, time_ns_min, time_ns, l, invalid ? "; 
invalid " : " ");
} else {
/* raw format */
-   pr_info("gpmc,%s = <%u>\n", name, l);
+   pr_info("gpmc,%s = <%u>%s\n", name, l, invalid ? " /* invalid 
*/" : "");
}
 
return l;
@@ -447,15 +460,19 @@ static int get_gpmc_timing_reg(
pr_info("cs%i %s: 0x%08x\n", cs, #config, \
gpmc_cs_read_reg(cs, config))
 #define GPMC_GET_RAW(reg, st, end, field) \
-   get_gpmc_timing_reg(cs, (reg), (st), (end), field, GPMC_CD_FCLK, 0, 1, 
0)
+   get_gpmc_timing_reg(cs, (reg), (st), (end), 0, field, GPMC_CD_FCLK, 0, 
1, 0)
+#define GPMC_GET_RAW_MAX(reg, st, end, max, field) \
+   get_gpmc_timing_reg(cs, (reg), (st), (end), (max), field, 

[PATCH 1/8 v4] ARM OMAP2+ GPMC: don't undef DEBUG

2015-02-27 Thread Robert ABEL
OMAP2+ GPMC driver undefines DEBUG, which makes it unnecessarily
hard to turn DEBUG on. Remove the offending lines.

Signed-off-by: Robert ABEL 
---
 drivers/memory/omap-gpmc.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 24696f5..5cabac8 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -12,8 +12,6 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#undef DEBUG
-
 #include 
 #include 
 #include 
-- 
2.3.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 0/8 v4] ARM OMAP2+ GPMC: fixes and bus children

2015-02-27 Thread Robert ABEL
These are the changes I proposed in these patch series: [1], [2], [3], [4]
rebased to 3.19 as well as new changes for little bugs I noticed while
preparing this patch series as well as changes introduced via comments.

1. DEBUG was undefined in source code --> remove offending lines
2. add capability to have busses as children of the GPMC and multiple
   devices on a bus. See [2] for an example DTS syntax.
3. debug output was unaligned --> align it
4. output for copy-pasting to DTS had erroneous timing outputs and
   made it hard to copy-paste --> correct timing values, add comments
   as DTS comments.
5. WAITMONITORINGTIME is expressed as GPMC_CLK cycles for all accesses.
   GPMCFCLKDIVIDER is used as a divider, so it must always be programmed.
6. GPMCFCLKDIVIDER is calculated according to WAITMONITORINGTIME for
   asynchronous accesses inside the driver --> asynchronous accesses now
   completely decoupled from gpmc,sync-clk-ps.
7. WAITMONITORINGTIME was being programmed/shown in GPMC_FCLK cycles instead
   of GPMC_CLK cycles --> add clock domain information where necessary.
8. Calculated values for WAITMONITORINGTIME and CLKACTIVATIONTIME that were
   outside the defined range would not raise an error.
   DEVICESIZE, ATTACHEDDEVICEPAGELENGTH, WAITMONITORINGTIME and
   CLKACTIVATIONTIME would not be marked as incorrect on DTS output.
   --> Fix all of these.

[1]: https://lkml.org/lkml/2015/2/12/495
[2]: https://lkml.org/lkml/2015/2/16/337
[3]: https://lkml.org/lkml/2015/2/24/609
[4]: https://lkml.org/lkml/2015/2/26/387

Robert ABEL (9):
  ARM OMAP2+ GPMC: don't undef DEBUG
  ARM OMAP2+ GPMC: add bus children
  ARM OMAP2+ GPMC: fix debug output alignment
  ARM OMAP2+ GPMC: change get_gpmc_timing_reg output for DTS
  ARM OMAP2+ GPMC: always program GPMCFCLKDIVIDER
  ARM OMAP2+ GPMC: calculate GPMCFCLKDIVIDER based on WAITMONITORINGTIME
  ARM OMAP2+ GPMC: fix WAITMONITORINGTIME divider bug
  ARM OMAP2+ GPMC: fix programming/showing reserved timing parameters

 arch/arm/mach-omap2/gpmc-nand.c|  17 +-
 arch/arm/mach-omap2/gpmc-onenand.c |   4 +-
 arch/arm/mach-omap2/usb-tusb6010.c |   4 +-
 drivers/memory/Makefile|   2 +
 drivers/memory/omap-gpmc.c | 313 +
 include/linux/omap-gpmc.h  |   2 +-
 6 files changed, 265 insertions(+), 77 deletions(-)

-- 
2.3.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 5/8 v4] ARM OMAP2+ GPMC: always program GPMCFCLKDIVIDER

2015-02-27 Thread Robert ABEL
The WAITMONITORINGTIME is expressed as a number of GPMC_CLK clock cycles,
even though the access is defined as asynchronous, and no GPMC_CLK clock
is provided to the external device. Still, GPMCFCLKDIVIDER is used as a divider
for the GPMC clock, so it must be programmed to define the
correct WAITMONITORINGTIME delay.

Signed-off-by: Robert ABEL 
---
 drivers/memory/omap-gpmc.c | 17 ++---
 1 file changed, 6 insertions(+), 11 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 432e638..02e5228 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -499,7 +499,7 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, 
int end_bit,
 
l = gpmc_cs_read_reg(cs, reg);
 #ifdef DEBUG
-   printk(KERN_INFO
+   pr_info(
"GPMC CS%d: %-17s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
   cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
(l >> st_bit) & mask, time);
@@ -571,19 +571,14 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings 
*t)
if (gpmc_capability & GPMC_HAS_WR_ACCESS)
GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
 
-   /* caller is expected to have initialized CONFIG1 to cover
-* at least sync vs async
-*/
l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-   if (l & (GPMC_CONFIG1_READTYPE_SYNC | GPMC_CONFIG1_WRITETYPE_SYNC)) {
 #ifdef DEBUG
-   printk(KERN_INFO "GPMC CS%d CLK period is %lu ns (div %d)\n",
-   cs, (div * gpmc_get_fclk_period()) / 1000, div);
+   pr_info("GPMC CS%d CLK period is %lu ns (div %d)\n",
+   cs, (div * gpmc_get_fclk_period()) / 1000, div);
 #endif
-   l &= ~0x03;
-   l |= (div - 1);
-   gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
-   }
+   l &= ~0x03;
+   l |= (div - 1);
+   gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
 
gpmc_cs_bool_timings(cs, >bool_timings);
gpmc_cs_show_timings(cs, "after gpmc_cs_set_timings");
-- 
2.3.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 4/8 v4] ARM OMAP2+ GPMC: change get_gpmc_timing_reg output for DTS

2015-02-27 Thread Robert ABEL
DTS output was formatted to require additional work when copy-pasting into DTS.
Nano-second timings were replaced with interval of values that produce the same
number of clock ticks.

Signed-off-by: Robert ABEL 
---
 drivers/memory/omap-gpmc.c | 38 --
 1 file changed, 28 insertions(+), 10 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index dbb6753..432e638 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -337,32 +337,50 @@ static void gpmc_cs_bool_timings(int cs, const struct 
gpmc_bool_timings *p)
 }
 
 #ifdef DEBUG
+/**
+ * get_gpmc_timing_reg - read a timing parameter and print DTS settings for it.
+ * @cs:  Chip Select Region
+ * @reg: GPMC_CS_CONFIGn register offset.
+ * @st_bit:  Start Bit
+ * @end_bit: End Bit. Must be >= @st_bit.
+ * @name:DTS node name, w/o "gpmc,"
+ * @raw: Raw Format Option.
+ *   raw format:  gpmc,name = 
+ *   tick format: gpmc,name =  /* x ns -- y ns; x ticks 
*/
+ *   Where x ns -- y ns result in the same tick value.
+ * @noval:   Parameter values equal to 0 are not printed.
+ * @shift:   Parameter value left shifts @shift, which is then printed instead 
of value.
+ * @return:  Specified timing parameter (after optional @shift).
+ *
+ */
 static int get_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
   bool raw, bool noval, int shift,
   const char *name)
 {
u32 l;
-   int nr_bits, max_value, mask;
+   int nr_bits;
+   int mask;
 
l = gpmc_cs_read_reg(cs, reg);
nr_bits = end_bit - st_bit + 1;
-   max_value = (1 << nr_bits) - 1;
-   mask = max_value << st_bit;
-   l = (l & mask) >> st_bit;
+   mask = (1 << nr_bits) - 1;
+   l = (l >> st_bit) & mask;
if (shift)
l = (shift << l);
if (noval && (l == 0))
return 0;
if (!raw) {
-   unsigned int time_ns_min, time_ns, time_ns_max;
+   /* DTS tick format for timings in ns */
+   unsigned int time_ns;
+   unsigned int time_ns_min = 0;
 
-   time_ns_min = gpmc_ticks_to_ns(l ? l - 1 : 0);
+   if (l)
+   time_ns_min = gpmc_ticks_to_ns(l - 1) + 1;
time_ns = gpmc_ticks_to_ns(l);
-   time_ns_max = gpmc_ticks_to_ns(l + 1 > max_value ?
-  max_value : l + 1);
-   pr_info("gpmc,%s = <%u> (%u - %u ns, %i ticks)\n",
-   name, time_ns, time_ns_min, time_ns_max, l);
+   pr_info("gpmc,%s = <%u> /* %u ns - %u ns; %i ticks */\n",
+   name, time_ns, time_ns_min, time_ns, l);
} else {
+   /* raw format */
pr_info("gpmc,%s = <%u>\n", name, l);
}
 
-- 
2.3.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/8 v4] ARM OMAP2+ GPMC: add bus children

2015-02-27 Thread Robert ABEL
This patch adds support for spawning buses as children of the GPMC.

Signed-off-by: Robert ABEL 
---
 drivers/memory/omap-gpmc.c | 17 +++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 5cabac8..74a8c52 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -27,6 +27,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -1800,8 +1801,20 @@ static int gpmc_probe_generic_child(struct 
platform_device *pdev,
gpmc_cs_enable_mem(cs);
 
 no_timings:
-   if (of_platform_device_create(child, NULL, >dev))
-   return 0;
+
+   /* create platform device, NULL on error or when disabled */
+   if (!of_platform_device_create(child, NULL, >dev))
+   goto err_child_fail;
+
+   /* is child a common bus? */
+   if (of_match_node(of_default_bus_match_table, child))
+   /* create children and other common bus children */
+   if (of_platform_populate(child, of_default_bus_match_table, 
NULL, >dev))
+   goto err_child_fail;
+
+   return 0;
+
+err_child_fail:
 
dev_err(>dev, "failed to create gpmc child %s\n", child->name);
ret = -ENODEV;
-- 
2.3.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 3/8 v4] ARM OMAP2+ GPMC: fix debug output alignment

2015-02-27 Thread Robert ABEL
GPMC debug output is aligned to 10 characters for field names.
However, some fields have bigger names, screwing up the alignment.
Consequently, alignment was changed to longest field name (17 chars) for now.

Signed-off-by: Robert ABEL 
---
 drivers/memory/omap-gpmc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 74a8c52..dbb6753 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -482,7 +482,7 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, 
int end_bit,
l = gpmc_cs_read_reg(cs, reg);
 #ifdef DEBUG
printk(KERN_INFO
-   "GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
+   "GPMC CS%d: %-17s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
   cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
(l >> st_bit) & mask, time);
 #endif
-- 
2.3.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/8] ARM OMAP2+ GPMC: add bus children

2015-02-27 Thread Robert Abel
Hi Roger,

On Fri, Feb 27, 2015 at 11:24 AM, Roger Quadros  wrote:
>> + /* is child a common bus? */
>> + if (of_match_node(of_default_bus_match_table, child))
>> + /* create children and other common bus children */
>> + if (of_platform_populate(child, of_default_bus_match_table, 
>> NULL, >dev))
>> + goto err_child_fail;
>
> this would print "failed to create gpmc child" but we have already created
> the gpmc child in the first of_platform_device_create() call.
> A more appropriate message would be "failed to populate all children of 
> child->name"
>
> Also do you want to return failure?
> it will result in of_node_put() of the child and another print message
> about "probing gpmc child %s failed" in gpmc_probe_dt().
>
> IMO if the GPMC node's child was created fine then we shouldn't return error.

As of_platform_populate _always_ return 0 no matter what, the only way
to reach that message is if probing the child failed.
As I cannot see into the future when of_platform_populate might
actually be changed to return meaningful codes, we shouldn't try to
foresee what the actual problem might be today either. This is a
battle for another day.

Regards,

Robert
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 4/8] ARM OMAP2+ GPMC: change get_gpmc_timing_reg output for DTS

2015-02-27 Thread Robert Abel
On Thu, Feb 26, 2015 at 4:06 PM, Sergei Shtylyov
 wrote:
>Documentation/kernel-doc-nano-HOWTO.txt requires colons after the
> parameter names, doesn't it?

Jesus Christ, you guys are killing me...
I've already spent way more time on this patch series than I intended
to anyway...

>> +   mask = (1 << nr_bits) - 1;
>
>
>BIT(nr_bits) - 1, perhaps?

Not happening... BIT macro obscures what's actually going on.

Regards,

Robert
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 4/8] ARM OMAP2+ GPMC: change get_gpmc_timing_reg output for DTS

2015-02-27 Thread Robert Abel
Hi Roger,

On Fri, Feb 27, 2015 at 11:43 AM, Roger Quadros  wrote:
>>   time_ns_min = gpmc_ticks_to_ns(l ? l - 1 : 0);
>
> should be
> time_ns_min = l ? gpmc_ticks_to_ns(l - 1) + 1 : 0;
That's a micro-optimization.
>
> + 1ns since we don't want to fall into the previous tick 
> bracket.
> for l == 0 we have t_min as 0. no need to pass it through 
> gpmc_ticks_to_ns() or add 1 ns.
That's why the invervals are half-open. I can make them closed, no problem.

Regards,

Robert
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 4/8] ARM OMAP2+ GPMC: change get_gpmc_timing_reg output for DTS

2015-02-27 Thread Robert Abel
Hi Roger,

On Fri, Feb 27, 2015 at 11:43 AM, Roger Quadros rog...@ti.com wrote:
   time_ns_min = gpmc_ticks_to_ns(l ? l - 1 : 0);

 should be
 time_ns_min = l ? gpmc_ticks_to_ns(l - 1) + 1 : 0;
That's a micro-optimization.

 + 1ns since we don't want to fall into the previous tick 
 bracket.
 for l == 0 we have t_min as 0. no need to pass it through 
 gpmc_ticks_to_ns() or add 1 ns.
That's why the invervals are half-open. I can make them closed, no problem.

Regards,

Robert
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 4/8] ARM OMAP2+ GPMC: change get_gpmc_timing_reg output for DTS

2015-02-27 Thread Robert Abel
On Thu, Feb 26, 2015 at 4:06 PM, Sergei Shtylyov
sergei.shtyl...@cogentembedded.com wrote:
Documentation/kernel-doc-nano-HOWTO.txt requires colons after the
 parameter names, doesn't it?

Jesus Christ, you guys are killing me...
I've already spent way more time on this patch series than I intended
to anyway...

 +   mask = (1  nr_bits) - 1;


BIT(nr_bits) - 1, perhaps?

Not happening... BIT macro obscures what's actually going on.

Regards,

Robert
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/8] ARM OMAP2+ GPMC: add bus children

2015-02-27 Thread Robert Abel
Hi Roger,

On Fri, Feb 27, 2015 at 11:24 AM, Roger Quadros rog...@ti.com wrote:
 + /* is child a common bus? */
 + if (of_match_node(of_default_bus_match_table, child))
 + /* create children and other common bus children */
 + if (of_platform_populate(child, of_default_bus_match_table, 
 NULL, pdev-dev))
 + goto err_child_fail;

 this would print failed to create gpmc child but we have already created
 the gpmc child in the first of_platform_device_create() call.
 A more appropriate message would be failed to populate all children of 
 child-name

 Also do you want to return failure?
 it will result in of_node_put() of the child and another print message
 about probing gpmc child %s failed in gpmc_probe_dt().

 IMO if the GPMC node's child was created fine then we shouldn't return error.

As of_platform_populate _always_ return 0 no matter what, the only way
to reach that message is if probing the child failed.
As I cannot see into the future when of_platform_populate might
actually be changed to return meaningful codes, we shouldn't try to
foresee what the actual problem might be today either. This is a
battle for another day.

Regards,

Robert
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 7/8 v4] ARM OMAP2+ GPMC: fix WAITMONITORINGTIME divider bug

2015-02-27 Thread Robert ABEL
The WAITMONITORINGTIME is expressed as a number of GPMC_CLK clock cycles,
even though the access is defined as asynchronous, and no GPMC_CLK clock
is provided to the external device. Still, GPMCFCLKDIVIDER is used as a divider
for the GPMC clock, so it must be programmed to define the
correct WAITMONITORINGTIME delay.

This patch correctly computes WAITMONITORINGTIME in GPMC_CLK cycles instead of 
GPMC_FCLK cycles,
both during programming (gpmc_cs_set_timings) and during retrieval 
(gpmc_cs_show_timings).

Signed-off-by: Robert ABEL ra...@cit-ec.uni-bielefeld.de
---
 drivers/memory/omap-gpmc.c | 128 +++--
 1 file changed, 101 insertions(+), 27 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 8ee335d..d091065 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -170,6 +170,11 @@
  */
 #defineGPMC_NR_IRQ 2
 
+enum gpmc_clk_domain {
+   GPMC_CD_FCLK,
+   GPMC_CD_CLK
+};
+
 struct gpmc_cs_data {
const char *name;
 
@@ -268,16 +273,54 @@ static unsigned long gpmc_get_fclk_period(void)
return rate;
 }
 
-static unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
+/**
+ * gpmc_get_clk_period - get period of selected clock domain in ps
+ * @cs Chip Select Region.
+ * @cd Clock Domain.
+ *
+ * GPMC_CS_CONFIG1 GPMCFCLKDIVIDER for cs has to be setup
+ * prior to calling this function with GPMC_CD_CLK.
+ */
+static unsigned long gpmc_get_clk_period(int cs, enum gpmc_clk_domain cd)
+{
+
+   unsigned long tick_ps = gpmc_get_fclk_period();
+   u32 l;
+   int div;
+
+   switch (cd) {
+   case GPMC_CD_CLK:
+   /* get current clk divider */
+   l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+   div = (l  0x03) + 1;
+   /* get GPMC_CLK period */
+   tick_ps *= div;
+   break;
+   case GPMC_CD_FCLK:
+   /* FALL-THROUGH */
+   default:
+   break;
+   }
+
+   return tick_ps;
+
+}
+
+static unsigned int gpmc_ns_to_clk_ticks(unsigned int time_ns, int cs, enum 
gpmc_clk_domain cd)
 {
unsigned long tick_ps;
 
/* Calculate in picosecs to yield more exact results */
-   tick_ps = gpmc_get_fclk_period();
+   tick_ps = gpmc_get_clk_period(cs, cd);
 
return (time_ns * 1000 + tick_ps - 1) / tick_ps;
 }
 
+static unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
+{
+   return gpmc_ns_to_clk_ticks(time_ns, /* any CS */ 0, GPMC_CD_FCLK);
+}
+
 static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
 {
unsigned long tick_ps;
@@ -288,9 +331,14 @@ static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
return (time_ps + tick_ps - 1) / tick_ps;
 }
 
+unsigned int gpmc_clk_ticks_to_ns(unsigned ticks, int cs, enum gpmc_clk_domain 
cd)
+{
+   return ticks * gpmc_get_clk_period(cs, cd) / 1000;
+}
+
 unsigned int gpmc_ticks_to_ns(unsigned int ticks)
 {
-   return ticks * gpmc_get_fclk_period() / 1000;
+   return gpmc_clk_ticks_to_ns(ticks, /* any CS */ 0, GPMC_CD_FCLK);
 }
 
 static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
@@ -346,18 +394,24 @@ static void gpmc_cs_bool_timings(int cs, const struct 
gpmc_bool_timings *p)
  * @st_bit:  Start Bit
  * @end_bit: End Bit. Must be = @st_bit.
  * @name:DTS node name, w/o gpmc,
+ * @cd:  Clock Domain of timing parameter.
+ * @shift:   Parameter value left shifts @shift, which is then printed instead 
of value.
  * @raw: Raw Format Option.
  *   raw format:  gpmc,name = value
  *   tick format: gpmc,name = value /zwj;* x ns -- y ns; x ticks 
*zwj;/
  *   Where x ns -- y ns result in the same tick value.
  * @noval:   Parameter values equal to 0 are not printed.
- * @shift:   Parameter value left shifts @shift, which is then printed instead 
of value.
  * @return:  Specified timing parameter (after optional @shift).
  *
  */
-static int get_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
-  bool raw, bool noval, int shift,
-  const char *name)
+static int get_gpmc_timing_reg(
+   /* timing specifiers */
+   int cs, int reg, int st_bit, int end_bit,
+   const char *name, const enum gpmc_clk_domain cd,
+   /* value transform */
+   int shift,
+   /* format specifiers */
+   bool raw, bool noval)
 {
u32 l;
int nr_bits;
@@ -377,8 +431,8 @@ static int get_gpmc_timing_reg(int cs, int reg, int st_bit, 
int end_bit,
unsigned int time_ns_min = 0;
 
if (l)
-   time_ns_min = gpmc_ticks_to_ns(l - 1) + 1;
-   time_ns = gpmc_ticks_to_ns(l);
+   time_ns_min = gpmc_clk_ticks_to_ns(l - 1, cs, cd) + 1;
+   time_ns = gpmc_clk_ticks_to_ns(l, cs, cd);
pr_info(gpmc,%s = %u /* %u ns - %u ns; %i ticks */\n

[PATCH 0/8 v4] ARM OMAP2+ GPMC: fixes and bus children

2015-02-27 Thread Robert ABEL
These are the changes I proposed in these patch series: [1], [2], [3], [4]
rebased to 3.19 as well as new changes for little bugs I noticed while
preparing this patch series as well as changes introduced via comments.

1. DEBUG was undefined in source code -- remove offending lines
2. add capability to have busses as children of the GPMC and multiple
   devices on a bus. See [2] for an example DTS syntax.
3. debug output was unaligned -- align it
4. output for copy-pasting to DTS had erroneous timing outputs and
   made it hard to copy-paste -- correct timing values, add comments
   as DTS comments.
5. WAITMONITORINGTIME is expressed as GPMC_CLK cycles for all accesses.
   GPMCFCLKDIVIDER is used as a divider, so it must always be programmed.
6. GPMCFCLKDIVIDER is calculated according to WAITMONITORINGTIME for
   asynchronous accesses inside the driver -- asynchronous accesses now
   completely decoupled from gpmc,sync-clk-ps.
7. WAITMONITORINGTIME was being programmed/shown in GPMC_FCLK cycles instead
   of GPMC_CLK cycles -- add clock domain information where necessary.
8. Calculated values for WAITMONITORINGTIME and CLKACTIVATIONTIME that were
   outside the defined range would not raise an error.
   DEVICESIZE, ATTACHEDDEVICEPAGELENGTH, WAITMONITORINGTIME and
   CLKACTIVATIONTIME would not be marked as incorrect on DTS output.
   -- Fix all of these.

[1]: https://lkml.org/lkml/2015/2/12/495
[2]: https://lkml.org/lkml/2015/2/16/337
[3]: https://lkml.org/lkml/2015/2/24/609
[4]: https://lkml.org/lkml/2015/2/26/387

Robert ABEL (9):
  ARM OMAP2+ GPMC: don't undef DEBUG
  ARM OMAP2+ GPMC: add bus children
  ARM OMAP2+ GPMC: fix debug output alignment
  ARM OMAP2+ GPMC: change get_gpmc_timing_reg output for DTS
  ARM OMAP2+ GPMC: always program GPMCFCLKDIVIDER
  ARM OMAP2+ GPMC: calculate GPMCFCLKDIVIDER based on WAITMONITORINGTIME
  ARM OMAP2+ GPMC: fix WAITMONITORINGTIME divider bug
  ARM OMAP2+ GPMC: fix programming/showing reserved timing parameters

 arch/arm/mach-omap2/gpmc-nand.c|  17 +-
 arch/arm/mach-omap2/gpmc-onenand.c |   4 +-
 arch/arm/mach-omap2/usb-tusb6010.c |   4 +-
 drivers/memory/Makefile|   2 +
 drivers/memory/omap-gpmc.c | 313 +
 include/linux/omap-gpmc.h  |   2 +-
 6 files changed, 265 insertions(+), 77 deletions(-)

-- 
2.3.0

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 5/8 v4] ARM OMAP2+ GPMC: always program GPMCFCLKDIVIDER

2015-02-27 Thread Robert ABEL
The WAITMONITORINGTIME is expressed as a number of GPMC_CLK clock cycles,
even though the access is defined as asynchronous, and no GPMC_CLK clock
is provided to the external device. Still, GPMCFCLKDIVIDER is used as a divider
for the GPMC clock, so it must be programmed to define the
correct WAITMONITORINGTIME delay.

Signed-off-by: Robert ABEL ra...@cit-ec.uni-bielefeld.de
---
 drivers/memory/omap-gpmc.c | 17 ++---
 1 file changed, 6 insertions(+), 11 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 432e638..02e5228 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -499,7 +499,7 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, 
int end_bit,
 
l = gpmc_cs_read_reg(cs, reg);
 #ifdef DEBUG
-   printk(KERN_INFO
+   pr_info(
GPMC CS%d: %-17s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n,
   cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
(l  st_bit)  mask, time);
@@ -571,19 +571,14 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings 
*t)
if (gpmc_capability  GPMC_HAS_WR_ACCESS)
GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
 
-   /* caller is expected to have initialized CONFIG1 to cover
-* at least sync vs async
-*/
l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-   if (l  (GPMC_CONFIG1_READTYPE_SYNC | GPMC_CONFIG1_WRITETYPE_SYNC)) {
 #ifdef DEBUG
-   printk(KERN_INFO GPMC CS%d CLK period is %lu ns (div %d)\n,
-   cs, (div * gpmc_get_fclk_period()) / 1000, div);
+   pr_info(GPMC CS%d CLK period is %lu ns (div %d)\n,
+   cs, (div * gpmc_get_fclk_period()) / 1000, div);
 #endif
-   l = ~0x03;
-   l |= (div - 1);
-   gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
-   }
+   l = ~0x03;
+   l |= (div - 1);
+   gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
 
gpmc_cs_bool_timings(cs, t-bool_timings);
gpmc_cs_show_timings(cs, after gpmc_cs_set_timings);
-- 
2.3.0

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/8 v4] ARM OMAP2+ GPMC: don't undef DEBUG

2015-02-27 Thread Robert ABEL
OMAP2+ GPMC driver undefines DEBUG, which makes it unnecessarily
hard to turn DEBUG on. Remove the offending lines.

Signed-off-by: Robert ABEL ra...@cit-ec.uni-bielefeld.de
---
 drivers/memory/omap-gpmc.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 24696f5..5cabac8 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -12,8 +12,6 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#undef DEBUG
-
 #include linux/irq.h
 #include linux/kernel.h
 #include linux/init.h
-- 
2.3.0

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 6/8 v4] ARM OMAP2+ GPMC: calculate GPMCFCLKDIVIDER based on WAITMONITORINGTIME

2015-02-27 Thread Robert ABEL
The WAITMONITORINGTIME is expressed as a number of GPMC_CLK clock cycles,
even though the access is defined as asynchronous, and no GPMC_CLK clock
is provided to the external device. Still, GPMCFCLKDIVIDER is used as a divider
for the GPMC clock, so it must be programmed to define the
correct WAITMONITORINGTIME delay.

Calculate GPMCFCLKDIVIDER independent of gpmc,sync-clk-ps in DT for
pure asynchronous accesses, i.e. both read and write asynchronous.

Signed-off-by: Robert ABEL ra...@cit-ec.uni-bielefeld.de
---
 arch/arm/mach-omap2/gpmc-nand.c| 17 
 arch/arm/mach-omap2/gpmc-onenand.c |  4 +-
 arch/arm/mach-omap2/usb-tusb6010.c |  4 +-
 drivers/memory/omap-gpmc.c | 85 ++
 include/linux/omap-gpmc.h  |  2 +-
 5 files changed, 92 insertions(+), 20 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index d5951b1..e863a59 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -96,14 +96,6 @@ int gpmc_nand_init(struct omap_nand_platform_data 
*gpmc_nand_data,
gpmc_nand_res[1].start = gpmc_get_client_irq(GPMC_IRQ_FIFOEVENTENABLE);
gpmc_nand_res[2].start = gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT);
 
-   if (gpmc_t) {
-   err = gpmc_cs_set_timings(gpmc_nand_data-cs, gpmc_t);
-   if (err  0) {
-   pr_err(omap2-gpmc: Unable to set gpmc timings: %d\n, 
err);
-   return err;
-   }
-   }
-
memset(s, 0, sizeof(struct gpmc_settings));
if (gpmc_nand_data-of_node)
gpmc_read_settings_dt(gpmc_nand_data-of_node, s);
@@ -111,6 +103,15 @@ int gpmc_nand_init(struct omap_nand_platform_data 
*gpmc_nand_data,
gpmc_set_legacy(gpmc_nand_data, s);
 
s.device_nand = true;
+
+   if (gpmc_t) {
+   err = gpmc_cs_set_timings(gpmc_nand_data-cs, gpmc_t, s);
+   if (err  0) {
+   pr_err(omap2-gpmc: Unable to set gpmc timings: %d\n, 
err);
+   return err;
+   }
+   }
+
err = gpmc_cs_program_settings(gpmc_nand_data-cs, s);
if (err  0)
goto out_free_cs;
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c 
b/arch/arm/mach-omap2/gpmc-onenand.c
index 53d197e..f899e77 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -293,7 +293,7 @@ static int omap2_onenand_setup_async(void __iomem 
*onenand_base)
if (ret  0)
return ret;
 
-   ret = gpmc_cs_set_timings(gpmc_onenand_data-cs, t);
+   ret = gpmc_cs_set_timings(gpmc_onenand_data-cs, t, onenand_async);
if (ret  0)
return ret;
 
@@ -331,7 +331,7 @@ static int omap2_onenand_setup_sync(void __iomem 
*onenand_base, int *freq_ptr)
if (ret  0)
return ret;
 
-   ret = gpmc_cs_set_timings(gpmc_onenand_data-cs, t);
+   ret = gpmc_cs_set_timings(gpmc_onenand_data-cs, t, onenand_sync);
if (ret  0)
return ret;
 
diff --git a/arch/arm/mach-omap2/usb-tusb6010.c 
b/arch/arm/mach-omap2/usb-tusb6010.c
index 8333400..e554d9e 100644
--- a/arch/arm/mach-omap2/usb-tusb6010.c
+++ b/arch/arm/mach-omap2/usb-tusb6010.c
@@ -71,7 +71,7 @@ static int tusb_set_async_mode(unsigned sysclk_ps)
 
gpmc_calc_timings(t, tusb_async, dev_t);
 
-   return gpmc_cs_set_timings(async_cs, t);
+   return gpmc_cs_set_timings(async_cs, t, tusb_async);
 }
 
 static int tusb_set_sync_mode(unsigned sysclk_ps)
@@ -98,7 +98,7 @@ static int tusb_set_sync_mode(unsigned sysclk_ps)
 
gpmc_calc_timings(t, tusb_sync, dev_t);
 
-   return gpmc_cs_set_timings(sync_cs, t);
+   return gpmc_cs_set_timings(sync_cs, t, tusb_sync);
 }
 
 /* tusb driver calls this when it changes the chip's clocking */
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 02e5228..8ee335d 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -138,7 +138,9 @@
 #define GPMC_CONFIG1_PAGE_LEN(val)  ((val  3)  23)
 #define GPMC_CONFIG1_WAIT_READ_MON  (1  22)
 #define GPMC_CONFIG1_WAIT_WRITE_MON (1  21)
-#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val  3)  18)
+#define GPMC_CONFIG1_WAIT_MON_TIME(val) ((val  3)  18)
+/** WAITMONITORINGTIME Max Ticks */
+#define GPMC_CONFIG1_WAITMONITORINGTIME_MAX  2
 #define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val  3)  16)
 #define GPMC_CONFIG1_DEVICESIZE(val)((val  3)  12)
 #define GPMC_CONFIG1_DEVICESIZE_16  GPMC_CONFIG1_DEVICESIZE(1)
@@ -516,13 +518,48 @@ static int set_gpmc_timing_reg(int cs, int reg, int 
st_bit, int end_bit,
t-field, #field)  0)  \
return -1
 
+/**
+ * gpmc_calc_waitmonitoring_divider - calculate proper GPMCFCLKDIVIDER based 
on WAITMONITORINGTIME
+ * WAITMONITORINGTIME will be _at least_ as long as desired, i.e.
+ * read  -- don't sample bus

[PATCH 8/8 v4] ARM OMAP2+ GPMC: fix programming/showing reserved timing parameters

2015-02-27 Thread Robert ABEL
GPMC_CONFIG1_i parameters CLKACTIVATIONTIME and WAITMONITORINGTIME
have reserved values.
Raise an error if calculated timings try to program reserved values.

GPMC_CONFIG1_i ATTACHEDDEVICEPAGELENGTH and DEVICESIZE were already checked
when parsing the DT.

Explicitly comment invalid values on gpmc_cs_show_timings for
-CLKACTIVATIONTIME
-WAITMONITORINGTIME
-DEVICESIZE
-ATTACHEDDEVICEPAGELENGTH

Signed-off-by: Robert ABEL ra...@cit-ec.uni-bielefeld.de
---
 drivers/memory/omap-gpmc.c | 68 ++
 1 file changed, 45 insertions(+), 23 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index d091065..750c655 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -135,7 +135,11 @@
 #define GPMC_CONFIG1_WRITETYPE_ASYNC(0  27)
 #define GPMC_CONFIG1_WRITETYPE_SYNC (1  27)
 #define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val  3)  25)
+/** CLKACTIVATIONTIME Max Ticks */
+#define GPMC_CONFIG1_CLKACTIVATIONTIME_MAX 2
 #define GPMC_CONFIG1_PAGE_LEN(val)  ((val  3)  23)
+/** ATTACHEDDEVICEPAGELENGTH Max Value */
+#define GPMC_CONFIG1_ATTACHEDDEVICEPAGELENGTH_MAX 2
 #define GPMC_CONFIG1_WAIT_READ_MON  (1  22)
 #define GPMC_CONFIG1_WAIT_WRITE_MON (1  21)
 #define GPMC_CONFIG1_WAIT_MON_TIME(val) ((val  3)  18)
@@ -144,6 +148,8 @@
 #define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val  3)  16)
 #define GPMC_CONFIG1_DEVICESIZE(val)((val  3)  12)
 #define GPMC_CONFIG1_DEVICESIZE_16  GPMC_CONFIG1_DEVICESIZE(1)
+/** DEVICESIZE Max Value */
+#define GPMC_CONFIG1_DEVICESIZE_MAX 1
 #define GPMC_CONFIG1_DEVICETYPE(val)((val  3)  10)
 #define GPMC_CONFIG1_DEVICETYPE_NOR GPMC_CONFIG1_DEVICETYPE(0)
 #define GPMC_CONFIG1_MUXTYPE(val)   ((val  3)  8)
@@ -393,6 +399,8 @@ static void gpmc_cs_bool_timings(int cs, const struct 
gpmc_bool_timings *p)
  * @reg: GPMC_CS_CONFIGn register offset.
  * @st_bit:  Start Bit
  * @end_bit: End Bit. Must be = @st_bit.
+ * @ma:x Maximum parameter value (before optional @shift).
+ *   If 0, maximum is as high as @st_bit and @end_bit allow.
  * @name:DTS node name, w/o gpmc,
  * @cd:  Clock Domain of timing parameter.
  * @shift:   Parameter value left shifts @shift, which is then printed instead 
of value.
@@ -400,13 +408,14 @@ static void gpmc_cs_bool_timings(int cs, const struct 
gpmc_bool_timings *p)
  *   raw format:  gpmc,name = value
  *   tick format: gpmc,name = value /zwj;* x ns -- y ns; x ticks 
*zwj;/
  *   Where x ns -- y ns result in the same tick value.
+ *   When @max is exceeded, invalid is printed inside comment.
  * @noval:   Parameter values equal to 0 are not printed.
  * @return:  Specified timing parameter (after optional @shift).
  *
  */
 static int get_gpmc_timing_reg(
/* timing specifiers */
-   int cs, int reg, int st_bit, int end_bit,
+   int cs, int reg, int st_bit, int end_bit, int max,
const char *name, const enum gpmc_clk_domain cd,
/* value transform */
int shift,
@@ -416,11 +425,15 @@ static int get_gpmc_timing_reg(
u32 l;
int nr_bits;
int mask;
+   bool invalid;
 
l = gpmc_cs_read_reg(cs, reg);
nr_bits = end_bit - st_bit + 1;
mask = (1  nr_bits) - 1;
l = (l  st_bit)  mask;
+   if (!max)
+   max = mask;
+   invalid = l  max;
if (shift)
l = (shift  l);
if (noval  (l == 0))
@@ -433,11 +446,11 @@ static int get_gpmc_timing_reg(
if (l)
time_ns_min = gpmc_clk_ticks_to_ns(l - 1, cs, cd) + 1;
time_ns = gpmc_clk_ticks_to_ns(l, cs, cd);
-   pr_info(gpmc,%s = %u /* %u ns - %u ns; %i ticks */\n,
-   name, time_ns, time_ns_min, time_ns, l);
+   pr_info(gpmc,%s = %u /* %u ns - %u ns; %i ticks%s*/\n,
+   name, time_ns, time_ns_min, time_ns, l, invalid ? ; 
invalid  :  );
} else {
/* raw format */
-   pr_info(gpmc,%s = %u\n, name, l);
+   pr_info(gpmc,%s = %u%s\n, name, l, invalid ?  /* invalid 
*/ : );
}
 
return l;
@@ -447,15 +460,19 @@ static int get_gpmc_timing_reg(
pr_info(cs%i %s: 0x%08x\n, cs, #config, \
gpmc_cs_read_reg(cs, config))
 #define GPMC_GET_RAW(reg, st, end, field) \
-   get_gpmc_timing_reg(cs, (reg), (st), (end), field, GPMC_CD_FCLK, 0, 1, 
0)
+   get_gpmc_timing_reg(cs, (reg), (st), (end), 0, field, GPMC_CD_FCLK, 0, 
1, 0)
+#define GPMC_GET_RAW_MAX(reg, st, end, max, field) \
+   get_gpmc_timing_reg(cs, (reg), (st), (end), (max), field, GPMC_CD_FCLK, 
0, 1, 0)
 #define GPMC_GET_RAW_BOOL(reg, st, end, field) \
-   get_gpmc_timing_reg(cs, (reg), (st), (end), field, GPMC_CD_FCLK, 0, 1, 
1)
-#define GPMC_GET_RAW_SHIFT(reg, st, end, shift, field) \
-   get_gpmc_timing_reg(cs, (reg), (st), (end), field, GPMC_CD_FCLK

[PATCH 3/8 v4] ARM OMAP2+ GPMC: fix debug output alignment

2015-02-27 Thread Robert ABEL
GPMC debug output is aligned to 10 characters for field names.
However, some fields have bigger names, screwing up the alignment.
Consequently, alignment was changed to longest field name (17 chars) for now.

Signed-off-by: Robert ABEL ra...@cit-ec.uni-bielefeld.de
---
 drivers/memory/omap-gpmc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 74a8c52..dbb6753 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -482,7 +482,7 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, 
int end_bit,
l = gpmc_cs_read_reg(cs, reg);
 #ifdef DEBUG
printk(KERN_INFO
-   GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n,
+   GPMC CS%d: %-17s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n,
   cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
(l  st_bit)  mask, time);
 #endif
-- 
2.3.0

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/8 v4] ARM OMAP2+ GPMC: add bus children

2015-02-27 Thread Robert ABEL
This patch adds support for spawning buses as children of the GPMC.

Signed-off-by: Robert ABEL ra...@cit-ec.uni-bielefeld.de
---
 drivers/memory/omap-gpmc.c | 17 +++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 5cabac8..74a8c52 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -27,6 +27,7 @@
 #include linux/of_address.h
 #include linux/of_mtd.h
 #include linux/of_device.h
+#include linux/of_platform.h
 #include linux/omap-gpmc.h
 #include linux/mtd/nand.h
 #include linux/pm_runtime.h
@@ -1800,8 +1801,20 @@ static int gpmc_probe_generic_child(struct 
platform_device *pdev,
gpmc_cs_enable_mem(cs);
 
 no_timings:
-   if (of_platform_device_create(child, NULL, pdev-dev))
-   return 0;
+
+   /* create platform device, NULL on error or when disabled */
+   if (!of_platform_device_create(child, NULL, pdev-dev))
+   goto err_child_fail;
+
+   /* is child a common bus? */
+   if (of_match_node(of_default_bus_match_table, child))
+   /* create children and other common bus children */
+   if (of_platform_populate(child, of_default_bus_match_table, 
NULL, pdev-dev))
+   goto err_child_fail;
+
+   return 0;
+
+err_child_fail:
 
dev_err(pdev-dev, failed to create gpmc child %s\n, child-name);
ret = -ENODEV;
-- 
2.3.0

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 4/8 v4] ARM OMAP2+ GPMC: change get_gpmc_timing_reg output for DTS

2015-02-27 Thread Robert ABEL
DTS output was formatted to require additional work when copy-pasting into DTS.
Nano-second timings were replaced with interval of values that produce the same
number of clock ticks.

Signed-off-by: Robert ABEL ra...@cit-ec.uni-bielefeld.de
---
 drivers/memory/omap-gpmc.c | 38 --
 1 file changed, 28 insertions(+), 10 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index dbb6753..432e638 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -337,32 +337,50 @@ static void gpmc_cs_bool_timings(int cs, const struct 
gpmc_bool_timings *p)
 }
 
 #ifdef DEBUG
+/**
+ * get_gpmc_timing_reg - read a timing parameter and print DTS settings for it.
+ * @cs:  Chip Select Region
+ * @reg: GPMC_CS_CONFIGn register offset.
+ * @st_bit:  Start Bit
+ * @end_bit: End Bit. Must be = @st_bit.
+ * @name:DTS node name, w/o gpmc,
+ * @raw: Raw Format Option.
+ *   raw format:  gpmc,name = value
+ *   tick format: gpmc,name = value /zwj;* x ns -- y ns; x ticks 
*zwj;/
+ *   Where x ns -- y ns result in the same tick value.
+ * @noval:   Parameter values equal to 0 are not printed.
+ * @shift:   Parameter value left shifts @shift, which is then printed instead 
of value.
+ * @return:  Specified timing parameter (after optional @shift).
+ *
+ */
 static int get_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
   bool raw, bool noval, int shift,
   const char *name)
 {
u32 l;
-   int nr_bits, max_value, mask;
+   int nr_bits;
+   int mask;
 
l = gpmc_cs_read_reg(cs, reg);
nr_bits = end_bit - st_bit + 1;
-   max_value = (1  nr_bits) - 1;
-   mask = max_value  st_bit;
-   l = (l  mask)  st_bit;
+   mask = (1  nr_bits) - 1;
+   l = (l  st_bit)  mask;
if (shift)
l = (shift  l);
if (noval  (l == 0))
return 0;
if (!raw) {
-   unsigned int time_ns_min, time_ns, time_ns_max;
+   /* DTS tick format for timings in ns */
+   unsigned int time_ns;
+   unsigned int time_ns_min = 0;
 
-   time_ns_min = gpmc_ticks_to_ns(l ? l - 1 : 0);
+   if (l)
+   time_ns_min = gpmc_ticks_to_ns(l - 1) + 1;
time_ns = gpmc_ticks_to_ns(l);
-   time_ns_max = gpmc_ticks_to_ns(l + 1  max_value ?
-  max_value : l + 1);
-   pr_info(gpmc,%s = %u (%u - %u ns, %i ticks)\n,
-   name, time_ns, time_ns_min, time_ns_max, l);
+   pr_info(gpmc,%s = %u /* %u ns - %u ns; %i ticks */\n,
+   name, time_ns, time_ns_min, time_ns, l);
} else {
+   /* raw format */
pr_info(gpmc,%s = %u\n, name, l);
}
 
-- 
2.3.0

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 4/8] ARM OMAP2+ GPMC: fix debug output alignment

2015-02-26 Thread Robert ABEL
GPMC debug output is aligned to 10 characters for field names.
However, some fields have bigger names, screwing up the alignment.
Consequently, alignment was changed to longest field name (17 chars) for now.

Signed-off-by: Robert ABEL 
---
 drivers/memory/omap-gpmc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 74a8c52..dbb6753 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -482,7 +482,7 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, 
int end_bit,
l = gpmc_cs_read_reg(cs, reg);
 #ifdef DEBUG
printk(KERN_INFO
-   "GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
+   "GPMC CS%d: %-17s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
   cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
(l >> st_bit) & mask, time);
 #endif
-- 
2.3.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/8] ARM OMAP2+ GPMC: add bus children

2015-02-26 Thread Robert ABEL
This patch adds support for spawning buses as children of the GPMC.

Signed-off-by: Robert ABEL 
---
 drivers/memory/omap-gpmc.c | 17 +++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 5cabac8..74a8c52 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -27,6 +27,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -1800,8 +1801,20 @@ static int gpmc_probe_generic_child(struct 
platform_device *pdev,
gpmc_cs_enable_mem(cs);
 
 no_timings:
-   if (of_platform_device_create(child, NULL, >dev))
-   return 0;
+
+   /* create platform device, NULL on error or when disabled */
+   if (!of_platform_device_create(child, NULL, >dev))
+   goto err_child_fail;
+
+   /* is child a common bus? */
+   if (of_match_node(of_default_bus_match_table, child))
+   /* create children and other common bus children */
+   if (of_platform_populate(child, of_default_bus_match_table, 
NULL, >dev))
+   goto err_child_fail;
+
+   return 0;
+
+err_child_fail:
 
dev_err(>dev, "failed to create gpmc child %s\n", child->name);
ret = -ENODEV;
-- 
2.3.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 4/8] ARM OMAP2+ GPMC: change get_gpmc_timing_reg output for DTS

2015-02-26 Thread Robert ABEL
DTS output was formatted to require additional work when copy-pasting into DTS.
Nano-second timings were replaced with interval of values that produce the same
number of clock ticks.

Signed-off-by: Robert ABEL 
---
 drivers/memory/omap-gpmc.c | 35 ++-
 1 file changed, 26 insertions(+), 9 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index dbb6753..9340e7a 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -337,32 +337,49 @@ static void gpmc_cs_bool_timings(int cs, const struct 
gpmc_bool_timings *p)
 }
 
 #ifdef DEBUG
+/**
+ * get_gpmc_timing_reg - read a timing parameter and print DTS settings for it.
+ * @cs  Chip Select Region
+ * @reg GPMC_CS_CONFIGn register offset.
+ * @st_bit  Start Bit
+ * @end_bit End Bit. Must be >= @st_bit.
+ * @nameDTS node name, w/o "gpmc,"
+ * @raw Raw Format Option.
+ *  raw format:  gpmc,name = 
+ *  tick format: gpmc,name =  /*(x ns -- y ns]; x ticks 
*/
+ *  Where (x ns -- y ns] is the half-open interval from x ns to y ns 
that
+ *  result in the same tick value.
+ * @noval   Parameter values equal to 0 are not printed.
+ * @shift   Parameter value left shifts @shift, which is then printed instead 
of value.
+ *
+ */
 static int get_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
   bool raw, bool noval, int shift,
   const char *name)
 {
u32 l;
-   int nr_bits, max_value, mask;
+   int nr_bits;
+   int mask;
 
l = gpmc_cs_read_reg(cs, reg);
nr_bits = end_bit - st_bit + 1;
-   max_value = (1 << nr_bits) - 1;
-   mask = max_value << st_bit;
-   l = (l & mask) >> st_bit;
+   mask = (1 << nr_bits) - 1;
+   l = (l >> st_bit) & mask;
if (shift)
l = (shift << l);
if (noval && (l == 0))
return 0;
if (!raw) {
-   unsigned int time_ns_min, time_ns, time_ns_max;
+   /* DTS tick format for timings in ns */
+   unsigned int time_ns;
+   unsigned int time_ns_min;
 
time_ns_min = gpmc_ticks_to_ns(l ? l - 1 : 0);
time_ns = gpmc_ticks_to_ns(l);
-   time_ns_max = gpmc_ticks_to_ns(l + 1 > max_value ?
-  max_value : l + 1);
-   pr_info("gpmc,%s = <%u> (%u - %u ns, %i ticks)\n",
-   name, time_ns, time_ns_min, time_ns_max, l);
+   pr_info("gpmc,%s = <%u> /* (%u ns - %u ns]; %i ticks */\n",
+   name, time_ns, time_ns_min, time_ns, l);
} else {
+   /* raw format */
pr_info("gpmc,%s = <%u>\n", name, l);
}
 
-- 
2.3.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 6/8] ARM OMAP2+ GPMC: calculate GPMCFCLKDIVIDER based on WAITMONITORINGTIME

2015-02-26 Thread Robert ABEL
The WAITMONITORINGTIME is expressed as a number of GPMC_CLK clock cycles,
even though the access is defined as asynchronous, and no GPMC_CLK clock
is provided to the external device. Still, GPMCFCLKDIVIDER is used as a divider
for the GPMC clock, so it must be programmed to define the
correct WAITMONITORINGTIME delay.

Calculate GPMCFCLKDIVIDER independent of gpmc,sync-clk-ps in DT for
pure asynchronous accesses, i.e. both read and write asynchronous.

Signed-off-by: Robert ABEL 
---
 arch/arm/mach-omap2/gpmc-nand.c| 17 
 arch/arm/mach-omap2/gpmc-onenand.c |  4 +-
 arch/arm/mach-omap2/usb-tusb6010.c |  4 +-
 drivers/memory/omap-gpmc.c | 82 ++
 include/linux/omap-gpmc.h  |  2 +-
 5 files changed, 89 insertions(+), 20 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index d5951b1..e863a59 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -96,14 +96,6 @@ int gpmc_nand_init(struct omap_nand_platform_data 
*gpmc_nand_data,
gpmc_nand_res[1].start = gpmc_get_client_irq(GPMC_IRQ_FIFOEVENTENABLE);
gpmc_nand_res[2].start = gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT);
 
-   if (gpmc_t) {
-   err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t);
-   if (err < 0) {
-   pr_err("omap2-gpmc: Unable to set gpmc timings: %d\n", 
err);
-   return err;
-   }
-   }
-
memset(, 0, sizeof(struct gpmc_settings));
if (gpmc_nand_data->of_node)
gpmc_read_settings_dt(gpmc_nand_data->of_node, );
@@ -111,6 +103,15 @@ int gpmc_nand_init(struct omap_nand_platform_data 
*gpmc_nand_data,
gpmc_set_legacy(gpmc_nand_data, );
 
s.device_nand = true;
+
+   if (gpmc_t) {
+   err = gpmc_cs_set_timings(gpmc_nand_data->cs, gpmc_t, );
+   if (err < 0) {
+   pr_err("omap2-gpmc: Unable to set gpmc timings: %d\n", 
err);
+   return err;
+   }
+   }
+
err = gpmc_cs_program_settings(gpmc_nand_data->cs, );
if (err < 0)
goto out_free_cs;
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c 
b/arch/arm/mach-omap2/gpmc-onenand.c
index 53d197e..f899e77 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -293,7 +293,7 @@ static int omap2_onenand_setup_async(void __iomem 
*onenand_base)
if (ret < 0)
return ret;
 
-   ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, );
+   ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, , _async);
if (ret < 0)
return ret;
 
@@ -331,7 +331,7 @@ static int omap2_onenand_setup_sync(void __iomem 
*onenand_base, int *freq_ptr)
if (ret < 0)
return ret;
 
-   ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, );
+   ret = gpmc_cs_set_timings(gpmc_onenand_data->cs, , _sync);
if (ret < 0)
return ret;
 
diff --git a/arch/arm/mach-omap2/usb-tusb6010.c 
b/arch/arm/mach-omap2/usb-tusb6010.c
index 8333400..e554d9e 100644
--- a/arch/arm/mach-omap2/usb-tusb6010.c
+++ b/arch/arm/mach-omap2/usb-tusb6010.c
@@ -71,7 +71,7 @@ static int tusb_set_async_mode(unsigned sysclk_ps)
 
gpmc_calc_timings(, _async, _t);
 
-   return gpmc_cs_set_timings(async_cs, );
+   return gpmc_cs_set_timings(async_cs, , _async);
 }
 
 static int tusb_set_sync_mode(unsigned sysclk_ps)
@@ -98,7 +98,7 @@ static int tusb_set_sync_mode(unsigned sysclk_ps)
 
gpmc_calc_timings(, _sync, _t);
 
-   return gpmc_cs_set_timings(sync_cs, );
+   return gpmc_cs_set_timings(sync_cs, , _sync);
 }
 
 /* tusb driver calls this when it changes the chip's clocking */
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 4139f0d..d71ea05 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -138,7 +138,9 @@
 #define GPMC_CONFIG1_PAGE_LEN(val)  ((val & 3) << 23)
 #define GPMC_CONFIG1_WAIT_READ_MON  (1 << 22)
 #define GPMC_CONFIG1_WAIT_WRITE_MON (1 << 21)
-#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
+#define GPMC_CONFIG1_WAIT_MON_TIME(val) ((val & 3) << 18)
+/** WAITMONITORINGTIME Max Ticks */
+#define GPMC_CONFIG1_WAITMONITORINGTIME_MAX  2
 #define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
 #define GPMC_CONFIG1_DEVICESIZE(val)((val & 3) << 12)
 #define GPMC_CONFIG1_DEVICESIZE_16  GPMC_CONFIG1_DEVICESIZE(1)
@@ -515,13 +517,46 @@ static int set_gpmc_timing_reg(int cs, int reg, int 
st_bit, int end_bit,
t->field, #field) < 0)  \
return -1
 
+/**
+ * gpmc_calc_waitmonitoring_divider - calculate proper GPMCFCLKDIVIDER based 
on WAITMONIT

[PATCH 5/8] ARM OMAP2+ GPMC: always program GPMCFCLKDIVIDER

2015-02-26 Thread Robert ABEL
The WAITMONITORINGTIME is expressed as a number of GPMC_CLK clock cycles,
even though the access is defined as asynchronous, and no GPMC_CLK clock
is provided to the external device. Still, GPMCFCLKDIVIDER is used as a divider
for the GPMC clock, so it must be programmed to define the
correct WAITMONITORINGTIME delay.

Signed-off-by: Robert ABEL 
---
 drivers/memory/omap-gpmc.c | 17 ++---
 1 file changed, 6 insertions(+), 11 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 9340e7a..4139f0d 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -498,7 +498,7 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, 
int end_bit,
 
l = gpmc_cs_read_reg(cs, reg);
 #ifdef DEBUG
-   printk(KERN_INFO
+   pr_info(
"GPMC CS%d: %-17s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n",
   cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
(l >> st_bit) & mask, time);
@@ -570,19 +570,14 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings 
*t)
if (gpmc_capability & GPMC_HAS_WR_ACCESS)
GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
 
-   /* caller is expected to have initialized CONFIG1 to cover
-* at least sync vs async
-*/
l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-   if (l & (GPMC_CONFIG1_READTYPE_SYNC | GPMC_CONFIG1_WRITETYPE_SYNC)) {
 #ifdef DEBUG
-   printk(KERN_INFO "GPMC CS%d CLK period is %lu ns (div %d)\n",
-   cs, (div * gpmc_get_fclk_period()) / 1000, div);
+   pr_info("GPMC CS%d CLK period is %lu ns (div %d)\n",
+   cs, (div * gpmc_get_fclk_period()) / 1000, div);
 #endif
-   l &= ~0x03;
-   l |= (div - 1);
-   gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
-   }
+   l &= ~0x03;
+   l |= (div - 1);
+   gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
 
gpmc_cs_bool_timings(cs, >bool_timings);
gpmc_cs_show_timings(cs, "after gpmc_cs_set_timings");
-- 
2.3.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 0/8] ARM OMAP2+ GPMC: fixes and bus children

2015-02-26 Thread Robert ABEL
These are the changes I proposed in three separate patchsets
#([1], [2], [3]) rebased to 3.19 as well as new changes for little bugs
I noticed while preparing this patchset.

1. DEBUG was undefined in source code --> remove offending lines
2. add capability to have busses as children of the GPMC and multiple
   devices on a bus. See [2] for an example DTS syntax.
3. debug output was unaligned --> align it
4. output for copy-pasting to DTS had erroneous timing outputs and
   made it hard to copy-paste --> correct timing values, add comments
   as DTS comments.
5. WAITMONITORINGTIME is expressed as GPMC_CLK cycles for all accesses.
   GPMCFCLKDIVIDER is used as a divider, so it must always be programmed.
6. GPMCFCLKDIVIDER is calculated according to WAITMONITORINGTIME for
   asynchronous accesses inside the driver --> asynchronous accesses now
   completely decoupled from gpmc,sync-clk-ps.
7. WAITMONITORINGTIME was being programmed/shown in GPMC_FCLK cycles instead
   of GPMC_CLK cycles --> add clock domain information where necessary.
8. Calculated values for WAITMONITORINGTIME and CLKACTIVATIONTIME that were
   outside the defined range would not raise an error.
   DEVICESIZE, ATTACHEDDEVICEPAGELENGTH, WAITMONITORINGTIME and
   CLKACTIVATIONTIME would not be marked as incorrect on DTS output.
   --> Fix all of these.

[1]: https://lkml.org/lkml/2015/2/12/495
[2]: https://lkml.org/lkml/2015/2/16/337
[3]: https://lkml.org/lkml/2015/2/24/609

Robert ABEL (9):
  ARM OMAP2+ GPMC: don't undef DEBUG
  ARM OMAP2+ GPMC: add bus children
  ARM OMAP2+ GPMC: fix debug output alignment
  ARM OMAP2+ GPMC: change get_gpmc_timing_reg output for DTS
  ARM OMAP2+ GPMC: always program GPMCFCLKDIVIDER
  ARM OMAP2+ GPMC: calculate GPMCFCLKDIVIDER based on WAITMONITORINGTIME
  ARM OMAP2+ GPMC: fix WAITMONITORINGTIME divider bug
  ARM OMAP2+ GPMC: fix programming/showing reserved timing parameters

 arch/arm/mach-omap2/gpmc-nand.c|  17 +-
 arch/arm/mach-omap2/gpmc-onenand.c |   4 +-
 arch/arm/mach-omap2/usb-tusb6010.c |   4 +-
 drivers/memory/Makefile|   2 +
 drivers/memory/omap-gpmc.c | 313 +
 include/linux/omap-gpmc.h  |   2 +-
 6 files changed, 265 insertions(+), 77 deletions(-)

-- 
2.3.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 7/8] ARM OMAP2+ GPMC: fix WAITMONITORINGTIME divider bug

2015-02-26 Thread Robert ABEL
The WAITMONITORINGTIME is expressed as a number of GPMC_CLK clock cycles,
even though the access is defined as asynchronous, and no GPMC_CLK clock
is provided to the external device. Still, GPMCFCLKDIVIDER is used as a divider
for the GPMC clock, so it must be programmed to define the
correct WAITMONITORINGTIME delay.

This patch correctly computes WAITMONITORINGTIME in GPMC_CLK cycles instead of 
GPMC_FCLK cycles,
both during programming (gpmc_cs_set_timings) and during retrieval 
(gpmc_cs_show_timings).

Signed-off-by: Robert ABEL 
---
 drivers/memory/omap-gpmc.c | 126 +++--
 1 file changed, 99 insertions(+), 27 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index d71ea05..400b0a6 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -170,6 +170,11 @@
  */
 #defineGPMC_NR_IRQ 2
 
+enum gpmc_clk_domain {
+   GPMC_CD_FCLK,
+   GPMC_CD_CLK
+};
+
 struct gpmc_cs_data {
const char *name;
 
@@ -268,16 +273,54 @@ static unsigned long gpmc_get_fclk_period(void)
return rate;
 }
 
-static unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
+/**
+ * gpmc_get_clk_period - get period of selected clock domain in ps
+ * @cs Chip Select Region.
+ * @cd Clock Domain.
+ *
+ * GPMC_CS_CONFIG1 GPMCFCLKDIVIDER for cs has to be setup
+ * prior to calling this function with GPMC_CD_CLK.
+ */
+static unsigned long gpmc_get_clk_period(int cs, enum gpmc_clk_domain cd)
+{
+
+   unsigned long tick_ps = gpmc_get_fclk_period();
+   u32 l;
+   int div;
+
+   switch (cd) {
+   case GPMC_CD_CLK:
+   /* get current clk divider */
+   l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+   div = (l & 0x03) + 1;
+   /* get GPMC_CLK period */
+   tick_ps *= div;
+   break;
+   case GPMC_CD_FCLK:
+   /* FALL-THROUGH */
+   default:
+   break;
+   }
+
+   return tick_ps;
+
+}
+
+static unsigned int gpmc_ns_to_clk_ticks(unsigned int time_ns, int cs, enum 
gpmc_clk_domain cd)
 {
unsigned long tick_ps;
 
/* Calculate in picosecs to yield more exact results */
-   tick_ps = gpmc_get_fclk_period();
+   tick_ps = gpmc_get_clk_period(cs, cd);
 
return (time_ns * 1000 + tick_ps - 1) / tick_ps;
 }
 
+static unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
+{
+   return gpmc_ns_to_clk_ticks(time_ns, /* any CS */ 0, GPMC_CD_FCLK);
+}
+
 static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
 {
unsigned long tick_ps;
@@ -288,9 +331,14 @@ static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
return (time_ps + tick_ps - 1) / tick_ps;
 }
 
+unsigned int gpmc_clk_ticks_to_ns(unsigned ticks, int cs, enum gpmc_clk_domain 
cd)
+{
+   return ticks * gpmc_get_clk_period(cs, cd) / 1000;
+}
+
 unsigned int gpmc_ticks_to_ns(unsigned int ticks)
 {
-   return ticks * gpmc_get_fclk_period() / 1000;
+   return gpmc_clk_ticks_to_ns(ticks, /* any CS */ 0, GPMC_CD_FCLK);
 }
 
 static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
@@ -346,18 +394,24 @@ static void gpmc_cs_bool_timings(int cs, const struct 
gpmc_bool_timings *p)
  * @st_bit  Start Bit
  * @end_bit End Bit. Must be >= @st_bit.
  * @nameDTS node name, w/o "gpmc,"
+ * @cd  Clock Domain of timing parameter.
+ * @shift   Parameter value left shifts @shift, which is then printed instead 
of value.
  * @raw Raw Format Option.
  *  raw format:  gpmc,name = 
  *  tick format: gpmc,name =  /*(x ns -- y ns]; x ticks 
*/
  *  Where (x ns -- y ns] is the half-open interval from x ns to y ns 
that
  *  result in the same tick value.
  * @noval   Parameter values equal to 0 are not printed.
- * @shift   Parameter value left shifts @shift, which is then printed instead 
of value.
  *
  */
-static int get_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
-  bool raw, bool noval, int shift,
-  const char *name)
+static int get_gpmc_timing_reg(
+   /* timing specifiers */
+   int cs, int reg, int st_bit, int end_bit,
+   const char *name, const enum gpmc_clk_domain cd,
+   /* value transform */
+   int shift,
+   /* format specifiers */
+   bool raw, bool noval)
 {
u32 l;
int nr_bits;
@@ -376,8 +430,8 @@ static int get_gpmc_timing_reg(int cs, int reg, int st_bit, 
int end_bit,
unsigned int time_ns;
unsigned int time_ns_min;
 
-   time_ns_min = gpmc_ticks_to_ns(l ? l - 1 : 0);
-   time_ns = gpmc_ticks_to_ns(l);
+   time_ns_min = gpmc_clk_ticks_to_ns(l ? l - 1 : 0, cs, cd);
+   time_ns = gpmc_clk_ticks_to_ns(l, cs, cd);
pr_info("gpmc,%s = <%u> /* (%u ns - %u ns]; %i ticks */\n",
name,

[PATCH 1/8] ARM OMAP2+ GPMC: don't undef DEBUG

2015-02-26 Thread Robert ABEL
OMAP2+ GPMC driver undefines DEBUG, which makes it unnecessarily
hard to turn DEBUG on. Remove the offending lines.

Signed-off-by: Robert ABEL 
---
 drivers/memory/omap-gpmc.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 24696f5..5cabac8 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -12,8 +12,6 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#undef DEBUG
-
 #include 
 #include 
 #include 
-- 
2.3.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 8/8] ARM OMAP2+ GPMC: fix programming/showing reserved timing parameters

2015-02-26 Thread Robert ABEL
GPMC_CONFIG1_i parameters CLKACTIVATIONTIME and WAITMONITORINGTIME
have reserved values.
Raise an error if calculated timings try to program reserved values.

GPMC_CONFIG1_i ATTACHEDDEVICEPAGELENGTH and DEVICESIZE were already checked
when parsing the DT.

Explicitly comment invalid values on gpmc_cs_show_timings for
-CLKACTIVATIONTIME
-WAITMONITORINGTIME
-DEVICESIZE
-ATTACHEDDEVICEPAGELENGTH

Signed-off-by: Robert ABEL 
---
 drivers/memory/omap-gpmc.c | 68 ++
 1 file changed, 45 insertions(+), 23 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 400b0a6..7e5300d 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -135,7 +135,11 @@
 #define GPMC_CONFIG1_WRITETYPE_ASYNC(0 << 27)
 #define GPMC_CONFIG1_WRITETYPE_SYNC (1 << 27)
 #define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
+/** CLKACTIVATIONTIME Max Ticks */
+#define GPMC_CONFIG1_CLKACTIVATIONTIME_MAX 2
 #define GPMC_CONFIG1_PAGE_LEN(val)  ((val & 3) << 23)
+/** ATTACHEDDEVICEPAGELENGTH Max Value */
+#define GPMC_CONFIG1_ATTACHEDDEVICEPAGELENGTH_MAX 2
 #define GPMC_CONFIG1_WAIT_READ_MON  (1 << 22)
 #define GPMC_CONFIG1_WAIT_WRITE_MON (1 << 21)
 #define GPMC_CONFIG1_WAIT_MON_TIME(val) ((val & 3) << 18)
@@ -144,6 +148,8 @@
 #define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val & 3) << 16)
 #define GPMC_CONFIG1_DEVICESIZE(val)((val & 3) << 12)
 #define GPMC_CONFIG1_DEVICESIZE_16  GPMC_CONFIG1_DEVICESIZE(1)
+/** DEVICESIZE Max Value */
+#define GPMC_CONFIG1_DEVICESIZE_MAX 1
 #define GPMC_CONFIG1_DEVICETYPE(val)((val & 3) << 10)
 #define GPMC_CONFIG1_DEVICETYPE_NOR GPMC_CONFIG1_DEVICETYPE(0)
 #define GPMC_CONFIG1_MUXTYPE(val)   ((val & 3) << 8)
@@ -393,6 +399,8 @@ static void gpmc_cs_bool_timings(int cs, const struct 
gpmc_bool_timings *p)
  * @reg GPMC_CS_CONFIGn register offset.
  * @st_bit  Start Bit
  * @end_bit End Bit. Must be >= @st_bit.
+ * @max Maximum parameter value (before optional @shift).
+ *  If 0, maximum is as high as @st_bit and @end_bit allow.
  * @nameDTS node name, w/o "gpmc,"
  * @cd  Clock Domain of timing parameter.
  * @shift   Parameter value left shifts @shift, which is then printed instead 
of value.
@@ -401,12 +409,13 @@ static void gpmc_cs_bool_timings(int cs, const struct 
gpmc_bool_timings *p)
  *  tick format: gpmc,name =  /*(x ns -- y ns]; x ticks 
*/
  *  Where (x ns -- y ns] is the half-open interval from x ns to y ns 
that
  *  result in the same tick value.
+ *  When @max is exceeded, "invalid" is printed inside comment.
  * @noval   Parameter values equal to 0 are not printed.
  *
  */
 static int get_gpmc_timing_reg(
/* timing specifiers */
-   int cs, int reg, int st_bit, int end_bit,
+   int cs, int reg, int st_bit, int end_bit, int max,
const char *name, const enum gpmc_clk_domain cd,
/* value transform */
int shift,
@@ -416,11 +425,15 @@ static int get_gpmc_timing_reg(
u32 l;
int nr_bits;
int mask;
+   bool invalid;
 
l = gpmc_cs_read_reg(cs, reg);
nr_bits = end_bit - st_bit + 1;
mask = (1 << nr_bits) - 1;
l = (l >> st_bit) & mask;
+   if (!max)
+   max = mask;
+   invalid = l > max;
if (shift)
l = (shift << l);
if (noval && (l == 0))
@@ -432,11 +445,11 @@ static int get_gpmc_timing_reg(
 
time_ns_min = gpmc_clk_ticks_to_ns(l ? l - 1 : 0, cs, cd);
time_ns = gpmc_clk_ticks_to_ns(l, cs, cd);
-   pr_info("gpmc,%s = <%u> /* (%u ns - %u ns]; %i ticks */\n",
-   name, time_ns, time_ns_min, time_ns, l);
+   pr_info("gpmc,%s = <%u> /* (%u ns - %u ns]; %i ticks %s*/\n",
+   name, time_ns, time_ns_min, time_ns, l, invalid ? "; 
invalid " : "");
} else {
/* raw format */
-   pr_info("gpmc,%s = <%u>\n", name, l);
+   pr_info("gpmc,%s = <%u>%s\n", name, l, invalid ? " /* invalid 
*/" : "");
}
 
return l;
@@ -446,15 +459,19 @@ static int get_gpmc_timing_reg(
pr_info("cs%i %s: 0x%08x\n", cs, #config, \
gpmc_cs_read_reg(cs, config))
 #define GPMC_GET_RAW(reg, st, end, field) \
-   get_gpmc_timing_reg(cs, (reg), (st), (end), field, GPMC_CD_FCLK, 0, 1, 
0)
+   get_gpmc_timing_reg(cs, (reg), (st), (end), 0, field, GPMC_CD_FCLK, 0, 
1, 0)
+#define GPMC_GET_RAW_MAX(reg, st, end, max, field) \
+   get_gpmc_timing_reg(cs, (reg), (st), (end), (max), field, GPMC_CD_FCLK, 
0, 1, 0)
 #define GPMC_GET_RAW_BOOL(reg, st, end, field) \
- 

[PATCH 4/8] ARM OMAP2+ GPMC: change get_gpmc_timing_reg output for DTS

2015-02-26 Thread Robert ABEL
DTS output was formatted to require additional work when copy-pasting into DTS.
Nano-second timings were replaced with interval of values that produce the same
number of clock ticks.

Signed-off-by: Robert ABEL ra...@cit-ec.uni-bielefeld.de
---
 drivers/memory/omap-gpmc.c | 35 ++-
 1 file changed, 26 insertions(+), 9 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index dbb6753..9340e7a 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -337,32 +337,49 @@ static void gpmc_cs_bool_timings(int cs, const struct 
gpmc_bool_timings *p)
 }
 
 #ifdef DEBUG
+/**
+ * get_gpmc_timing_reg - read a timing parameter and print DTS settings for it.
+ * @cs  Chip Select Region
+ * @reg GPMC_CS_CONFIGn register offset.
+ * @st_bit  Start Bit
+ * @end_bit End Bit. Must be = @st_bit.
+ * @nameDTS node name, w/o gpmc,
+ * @raw Raw Format Option.
+ *  raw format:  gpmc,name = value
+ *  tick format: gpmc,name = value /zwj;*(x ns -- y ns]; x ticks 
*zwj;/
+ *  Where (x ns -- y ns] is the half-open interval from x ns to y ns 
that
+ *  result in the same tick value.
+ * @noval   Parameter values equal to 0 are not printed.
+ * @shift   Parameter value left shifts @shift, which is then printed instead 
of value.
+ *
+ */
 static int get_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
   bool raw, bool noval, int shift,
   const char *name)
 {
u32 l;
-   int nr_bits, max_value, mask;
+   int nr_bits;
+   int mask;
 
l = gpmc_cs_read_reg(cs, reg);
nr_bits = end_bit - st_bit + 1;
-   max_value = (1  nr_bits) - 1;
-   mask = max_value  st_bit;
-   l = (l  mask)  st_bit;
+   mask = (1  nr_bits) - 1;
+   l = (l  st_bit)  mask;
if (shift)
l = (shift  l);
if (noval  (l == 0))
return 0;
if (!raw) {
-   unsigned int time_ns_min, time_ns, time_ns_max;
+   /* DTS tick format for timings in ns */
+   unsigned int time_ns;
+   unsigned int time_ns_min;
 
time_ns_min = gpmc_ticks_to_ns(l ? l - 1 : 0);
time_ns = gpmc_ticks_to_ns(l);
-   time_ns_max = gpmc_ticks_to_ns(l + 1  max_value ?
-  max_value : l + 1);
-   pr_info(gpmc,%s = %u (%u - %u ns, %i ticks)\n,
-   name, time_ns, time_ns_min, time_ns_max, l);
+   pr_info(gpmc,%s = %u /* (%u ns - %u ns]; %i ticks */\n,
+   name, time_ns, time_ns_min, time_ns, l);
} else {
+   /* raw format */
pr_info(gpmc,%s = %u\n, name, l);
}
 
-- 
2.3.0

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/8] ARM OMAP2+ GPMC: add bus children

2015-02-26 Thread Robert ABEL
This patch adds support for spawning buses as children of the GPMC.

Signed-off-by: Robert ABEL ra...@cit-ec.uni-bielefeld.de
---
 drivers/memory/omap-gpmc.c | 17 +++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 5cabac8..74a8c52 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -27,6 +27,7 @@
 #include linux/of_address.h
 #include linux/of_mtd.h
 #include linux/of_device.h
+#include linux/of_platform.h
 #include linux/omap-gpmc.h
 #include linux/mtd/nand.h
 #include linux/pm_runtime.h
@@ -1800,8 +1801,20 @@ static int gpmc_probe_generic_child(struct 
platform_device *pdev,
gpmc_cs_enable_mem(cs);
 
 no_timings:
-   if (of_platform_device_create(child, NULL, pdev-dev))
-   return 0;
+
+   /* create platform device, NULL on error or when disabled */
+   if (!of_platform_device_create(child, NULL, pdev-dev))
+   goto err_child_fail;
+
+   /* is child a common bus? */
+   if (of_match_node(of_default_bus_match_table, child))
+   /* create children and other common bus children */
+   if (of_platform_populate(child, of_default_bus_match_table, 
NULL, pdev-dev))
+   goto err_child_fail;
+
+   return 0;
+
+err_child_fail:
 
dev_err(pdev-dev, failed to create gpmc child %s\n, child-name);
ret = -ENODEV;
-- 
2.3.0

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 4/8] ARM OMAP2+ GPMC: fix debug output alignment

2015-02-26 Thread Robert ABEL
GPMC debug output is aligned to 10 characters for field names.
However, some fields have bigger names, screwing up the alignment.
Consequently, alignment was changed to longest field name (17 chars) for now.

Signed-off-by: Robert ABEL ra...@cit-ec.uni-bielefeld.de
---
 drivers/memory/omap-gpmc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 74a8c52..dbb6753 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -482,7 +482,7 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, 
int end_bit,
l = gpmc_cs_read_reg(cs, reg);
 #ifdef DEBUG
printk(KERN_INFO
-   GPMC CS%d: %-10s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n,
+   GPMC CS%d: %-17s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n,
   cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
(l  st_bit)  mask, time);
 #endif
-- 
2.3.0

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 6/8] ARM OMAP2+ GPMC: calculate GPMCFCLKDIVIDER based on WAITMONITORINGTIME

2015-02-26 Thread Robert ABEL
The WAITMONITORINGTIME is expressed as a number of GPMC_CLK clock cycles,
even though the access is defined as asynchronous, and no GPMC_CLK clock
is provided to the external device. Still, GPMCFCLKDIVIDER is used as a divider
for the GPMC clock, so it must be programmed to define the
correct WAITMONITORINGTIME delay.

Calculate GPMCFCLKDIVIDER independent of gpmc,sync-clk-ps in DT for
pure asynchronous accesses, i.e. both read and write asynchronous.

Signed-off-by: Robert ABEL ra...@cit-ec.uni-bielefeld.de
---
 arch/arm/mach-omap2/gpmc-nand.c| 17 
 arch/arm/mach-omap2/gpmc-onenand.c |  4 +-
 arch/arm/mach-omap2/usb-tusb6010.c |  4 +-
 drivers/memory/omap-gpmc.c | 82 ++
 include/linux/omap-gpmc.h  |  2 +-
 5 files changed, 89 insertions(+), 20 deletions(-)

diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index d5951b1..e863a59 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -96,14 +96,6 @@ int gpmc_nand_init(struct omap_nand_platform_data 
*gpmc_nand_data,
gpmc_nand_res[1].start = gpmc_get_client_irq(GPMC_IRQ_FIFOEVENTENABLE);
gpmc_nand_res[2].start = gpmc_get_client_irq(GPMC_IRQ_COUNT_EVENT);
 
-   if (gpmc_t) {
-   err = gpmc_cs_set_timings(gpmc_nand_data-cs, gpmc_t);
-   if (err  0) {
-   pr_err(omap2-gpmc: Unable to set gpmc timings: %d\n, 
err);
-   return err;
-   }
-   }
-
memset(s, 0, sizeof(struct gpmc_settings));
if (gpmc_nand_data-of_node)
gpmc_read_settings_dt(gpmc_nand_data-of_node, s);
@@ -111,6 +103,15 @@ int gpmc_nand_init(struct omap_nand_platform_data 
*gpmc_nand_data,
gpmc_set_legacy(gpmc_nand_data, s);
 
s.device_nand = true;
+
+   if (gpmc_t) {
+   err = gpmc_cs_set_timings(gpmc_nand_data-cs, gpmc_t, s);
+   if (err  0) {
+   pr_err(omap2-gpmc: Unable to set gpmc timings: %d\n, 
err);
+   return err;
+   }
+   }
+
err = gpmc_cs_program_settings(gpmc_nand_data-cs, s);
if (err  0)
goto out_free_cs;
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c 
b/arch/arm/mach-omap2/gpmc-onenand.c
index 53d197e..f899e77 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -293,7 +293,7 @@ static int omap2_onenand_setup_async(void __iomem 
*onenand_base)
if (ret  0)
return ret;
 
-   ret = gpmc_cs_set_timings(gpmc_onenand_data-cs, t);
+   ret = gpmc_cs_set_timings(gpmc_onenand_data-cs, t, onenand_async);
if (ret  0)
return ret;
 
@@ -331,7 +331,7 @@ static int omap2_onenand_setup_sync(void __iomem 
*onenand_base, int *freq_ptr)
if (ret  0)
return ret;
 
-   ret = gpmc_cs_set_timings(gpmc_onenand_data-cs, t);
+   ret = gpmc_cs_set_timings(gpmc_onenand_data-cs, t, onenand_sync);
if (ret  0)
return ret;
 
diff --git a/arch/arm/mach-omap2/usb-tusb6010.c 
b/arch/arm/mach-omap2/usb-tusb6010.c
index 8333400..e554d9e 100644
--- a/arch/arm/mach-omap2/usb-tusb6010.c
+++ b/arch/arm/mach-omap2/usb-tusb6010.c
@@ -71,7 +71,7 @@ static int tusb_set_async_mode(unsigned sysclk_ps)
 
gpmc_calc_timings(t, tusb_async, dev_t);
 
-   return gpmc_cs_set_timings(async_cs, t);
+   return gpmc_cs_set_timings(async_cs, t, tusb_async);
 }
 
 static int tusb_set_sync_mode(unsigned sysclk_ps)
@@ -98,7 +98,7 @@ static int tusb_set_sync_mode(unsigned sysclk_ps)
 
gpmc_calc_timings(t, tusb_sync, dev_t);
 
-   return gpmc_cs_set_timings(sync_cs, t);
+   return gpmc_cs_set_timings(sync_cs, t, tusb_sync);
 }
 
 /* tusb driver calls this when it changes the chip's clocking */
diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 4139f0d..d71ea05 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -138,7 +138,9 @@
 #define GPMC_CONFIG1_PAGE_LEN(val)  ((val  3)  23)
 #define GPMC_CONFIG1_WAIT_READ_MON  (1  22)
 #define GPMC_CONFIG1_WAIT_WRITE_MON (1  21)
-#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val  3)  18)
+#define GPMC_CONFIG1_WAIT_MON_TIME(val) ((val  3)  18)
+/** WAITMONITORINGTIME Max Ticks */
+#define GPMC_CONFIG1_WAITMONITORINGTIME_MAX  2
 #define GPMC_CONFIG1_WAIT_PIN_SEL(val)  ((val  3)  16)
 #define GPMC_CONFIG1_DEVICESIZE(val)((val  3)  12)
 #define GPMC_CONFIG1_DEVICESIZE_16  GPMC_CONFIG1_DEVICESIZE(1)
@@ -515,13 +517,46 @@ static int set_gpmc_timing_reg(int cs, int reg, int 
st_bit, int end_bit,
t-field, #field)  0)  \
return -1
 
+/**
+ * gpmc_calc_waitmonitoring_divider - calculate proper GPMCFCLKDIVIDER based 
on WAITMONITORINGTIME
+ * @wait_monitoring WAITMONITORINGTIME in ns.
+ * @return  -1 on failure to scale, else

[PATCH 5/8] ARM OMAP2+ GPMC: always program GPMCFCLKDIVIDER

2015-02-26 Thread Robert ABEL
The WAITMONITORINGTIME is expressed as a number of GPMC_CLK clock cycles,
even though the access is defined as asynchronous, and no GPMC_CLK clock
is provided to the external device. Still, GPMCFCLKDIVIDER is used as a divider
for the GPMC clock, so it must be programmed to define the
correct WAITMONITORINGTIME delay.

Signed-off-by: Robert ABEL ra...@cit-ec.uni-bielefeld.de
---
 drivers/memory/omap-gpmc.c | 17 ++---
 1 file changed, 6 insertions(+), 11 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 9340e7a..4139f0d 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -498,7 +498,7 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, 
int end_bit,
 
l = gpmc_cs_read_reg(cs, reg);
 #ifdef DEBUG
-   printk(KERN_INFO
+   pr_info(
GPMC CS%d: %-17s: %3d ticks, %3lu ns (was %3i ticks) %3d ns\n,
   cs, name, ticks, gpmc_get_fclk_period() * ticks / 1000,
(l  st_bit)  mask, time);
@@ -570,19 +570,14 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings 
*t)
if (gpmc_capability  GPMC_HAS_WR_ACCESS)
GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access);
 
-   /* caller is expected to have initialized CONFIG1 to cover
-* at least sync vs async
-*/
l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-   if (l  (GPMC_CONFIG1_READTYPE_SYNC | GPMC_CONFIG1_WRITETYPE_SYNC)) {
 #ifdef DEBUG
-   printk(KERN_INFO GPMC CS%d CLK period is %lu ns (div %d)\n,
-   cs, (div * gpmc_get_fclk_period()) / 1000, div);
+   pr_info(GPMC CS%d CLK period is %lu ns (div %d)\n,
+   cs, (div * gpmc_get_fclk_period()) / 1000, div);
 #endif
-   l = ~0x03;
-   l |= (div - 1);
-   gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
-   }
+   l = ~0x03;
+   l |= (div - 1);
+   gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l);
 
gpmc_cs_bool_timings(cs, t-bool_timings);
gpmc_cs_show_timings(cs, after gpmc_cs_set_timings);
-- 
2.3.0

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 7/8] ARM OMAP2+ GPMC: fix WAITMONITORINGTIME divider bug

2015-02-26 Thread Robert ABEL
The WAITMONITORINGTIME is expressed as a number of GPMC_CLK clock cycles,
even though the access is defined as asynchronous, and no GPMC_CLK clock
is provided to the external device. Still, GPMCFCLKDIVIDER is used as a divider
for the GPMC clock, so it must be programmed to define the
correct WAITMONITORINGTIME delay.

This patch correctly computes WAITMONITORINGTIME in GPMC_CLK cycles instead of 
GPMC_FCLK cycles,
both during programming (gpmc_cs_set_timings) and during retrieval 
(gpmc_cs_show_timings).

Signed-off-by: Robert ABEL ra...@cit-ec.uni-bielefeld.de
---
 drivers/memory/omap-gpmc.c | 126 +++--
 1 file changed, 99 insertions(+), 27 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index d71ea05..400b0a6 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -170,6 +170,11 @@
  */
 #defineGPMC_NR_IRQ 2
 
+enum gpmc_clk_domain {
+   GPMC_CD_FCLK,
+   GPMC_CD_CLK
+};
+
 struct gpmc_cs_data {
const char *name;
 
@@ -268,16 +273,54 @@ static unsigned long gpmc_get_fclk_period(void)
return rate;
 }
 
-static unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
+/**
+ * gpmc_get_clk_period - get period of selected clock domain in ps
+ * @cs Chip Select Region.
+ * @cd Clock Domain.
+ *
+ * GPMC_CS_CONFIG1 GPMCFCLKDIVIDER for cs has to be setup
+ * prior to calling this function with GPMC_CD_CLK.
+ */
+static unsigned long gpmc_get_clk_period(int cs, enum gpmc_clk_domain cd)
+{
+
+   unsigned long tick_ps = gpmc_get_fclk_period();
+   u32 l;
+   int div;
+
+   switch (cd) {
+   case GPMC_CD_CLK:
+   /* get current clk divider */
+   l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+   div = (l  0x03) + 1;
+   /* get GPMC_CLK period */
+   tick_ps *= div;
+   break;
+   case GPMC_CD_FCLK:
+   /* FALL-THROUGH */
+   default:
+   break;
+   }
+
+   return tick_ps;
+
+}
+
+static unsigned int gpmc_ns_to_clk_ticks(unsigned int time_ns, int cs, enum 
gpmc_clk_domain cd)
 {
unsigned long tick_ps;
 
/* Calculate in picosecs to yield more exact results */
-   tick_ps = gpmc_get_fclk_period();
+   tick_ps = gpmc_get_clk_period(cs, cd);
 
return (time_ns * 1000 + tick_ps - 1) / tick_ps;
 }
 
+static unsigned int gpmc_ns_to_ticks(unsigned int time_ns)
+{
+   return gpmc_ns_to_clk_ticks(time_ns, /* any CS */ 0, GPMC_CD_FCLK);
+}
+
 static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
 {
unsigned long tick_ps;
@@ -288,9 +331,14 @@ static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
return (time_ps + tick_ps - 1) / tick_ps;
 }
 
+unsigned int gpmc_clk_ticks_to_ns(unsigned ticks, int cs, enum gpmc_clk_domain 
cd)
+{
+   return ticks * gpmc_get_clk_period(cs, cd) / 1000;
+}
+
 unsigned int gpmc_ticks_to_ns(unsigned int ticks)
 {
-   return ticks * gpmc_get_fclk_period() / 1000;
+   return gpmc_clk_ticks_to_ns(ticks, /* any CS */ 0, GPMC_CD_FCLK);
 }
 
 static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
@@ -346,18 +394,24 @@ static void gpmc_cs_bool_timings(int cs, const struct 
gpmc_bool_timings *p)
  * @st_bit  Start Bit
  * @end_bit End Bit. Must be = @st_bit.
  * @nameDTS node name, w/o gpmc,
+ * @cd  Clock Domain of timing parameter.
+ * @shift   Parameter value left shifts @shift, which is then printed instead 
of value.
  * @raw Raw Format Option.
  *  raw format:  gpmc,name = value
  *  tick format: gpmc,name = value /zwj;*(x ns -- y ns]; x ticks 
*zwj;/
  *  Where (x ns -- y ns] is the half-open interval from x ns to y ns 
that
  *  result in the same tick value.
  * @noval   Parameter values equal to 0 are not printed.
- * @shift   Parameter value left shifts @shift, which is then printed instead 
of value.
  *
  */
-static int get_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
-  bool raw, bool noval, int shift,
-  const char *name)
+static int get_gpmc_timing_reg(
+   /* timing specifiers */
+   int cs, int reg, int st_bit, int end_bit,
+   const char *name, const enum gpmc_clk_domain cd,
+   /* value transform */
+   int shift,
+   /* format specifiers */
+   bool raw, bool noval)
 {
u32 l;
int nr_bits;
@@ -376,8 +430,8 @@ static int get_gpmc_timing_reg(int cs, int reg, int st_bit, 
int end_bit,
unsigned int time_ns;
unsigned int time_ns_min;
 
-   time_ns_min = gpmc_ticks_to_ns(l ? l - 1 : 0);
-   time_ns = gpmc_ticks_to_ns(l);
+   time_ns_min = gpmc_clk_ticks_to_ns(l ? l - 1 : 0, cs, cd);
+   time_ns = gpmc_clk_ticks_to_ns(l, cs, cd);
pr_info(gpmc,%s = %u /* (%u ns - %u ns]; %i ticks */\n,
name

[PATCH 1/8] ARM OMAP2+ GPMC: don't undef DEBUG

2015-02-26 Thread Robert ABEL
OMAP2+ GPMC driver undefines DEBUG, which makes it unnecessarily
hard to turn DEBUG on. Remove the offending lines.

Signed-off-by: Robert ABEL ra...@cit-ec.uni-bielefeld.de
---
 drivers/memory/omap-gpmc.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c
index 24696f5..5cabac8 100644
--- a/drivers/memory/omap-gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -12,8 +12,6 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#undef DEBUG
-
 #include linux/irq.h
 #include linux/kernel.h
 #include linux/init.h
-- 
2.3.0

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


  1   2   >