Re: [PATCH v3 04/14] i2c: add nexell driver

2020-07-06 Thread Stefan Bosch

Hello Heiko,

thank you for your proposals. I'll make the appropriate changes.

Regards
Stefan

Am 03.07.20 um 08:03 schrieb Heiko Schocher:

Hello Stefan,

Am 29.06.2020 um 19:46 schrieb Stefan Bosch:

Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01:
- i2c/nx_i2c.c: Some adaptions mainly because of changes in
   "struct udevice".
- several Bugfixes in nx_i2c.c.
- the driver has been for s5p6818 only. Code extended appropriately
   in order s5p4418 is also working.
- "probe_chip" added.
- pinctrl-driver/dt is used instead of configuring the i2c I/O-pins
   in the i2c-driver.
- '#ifdef CONFIG...' changed to 'if (IS_ENABLED(CONFIG...))' where
   possible (and similar).
- livetree API (dev_read_...) is used instead of fdt one (fdt...).

Signed-off-by: Stefan Bosch 


Reviewed-by: Heiko Schocher 

Nitpick only ...

[...]

diff --git a/drivers/i2c/nx_i2c.c b/drivers/i2c/nx_i2c.c
new file mode 100644
index 000..cefc774
--- /dev/null
+++ b/drivers/i2c/nx_i2c.c
@@ -0,0 +1,624 @@

[...]

+static uint i2c_set_clk(struct nx_i2c_bus *bus, uint enb)
+{
+    struct clk *clk;
+    char name[50];
+
+    sprintf(name, "%s.%d", DEV_NAME_I2C, bus->bus_num);
+    clk = clk_get((const char *)name);
+    if (!clk) {
+    debug("%s(): clk_get(%s) error!\n",
+  __func__, (const char *)name);
+    return -EINVAL;
+    }
+
+    if (enb) {
+    clk_disable(clk);
+    clk_enable(clk);
+    } else {
+    clk_disable(clk);
+    }


You can do here:

 clk_disable(clk);
 if (enb)
     clk_enable(clk);


+
+    return 0;
+}
+
+#ifdef CONFIG_ARCH_S5P6818
+/* Set SDA line delay, not available at S5P4418 */
+static int nx_i2c_set_sda_delay(struct nx_i2c_bus *bus)
+{
+    struct nx_i2c_regs *i2c = bus->regs;
+    uint pclk = 0;
+    uint t_pclk = 0;
+    uint delay = 0;
+
+    /* get input clock of the I2C-controller */
+    pclk = i2c_get_clkrate(bus);
+
+    if (bus->sda_delay) {
+    /* t_pclk = period time of one pclk [ns] */
+    t_pclk = DIV_ROUND_UP(1000, pclk / 100);
+    /* delay = number of pclks required for sda_delay [ns] */
+    delay = DIV_ROUND_UP(bus->sda_delay, t_pclk);
+    /* delay = register value (step of 5 clocks) */
+    delay = DIV_ROUND_UP(delay, 5);
+    /* max. possible register value = 3 */
+    if (delay > 3) {


May you use defines here?


+    delay = 3;
+    debug("%s(): sda-delay des.: %dns, sat. to max.: %dns 
(granularity: %dns)\n",

+  __func__, bus->sda_delay, t_pclk * delay * 5,
+  t_pclk * 5);
+    } else {
+    debug("%s(): sda-delay des.: %dns, act.: %dns 
(granularity: %dns)\n",

+  __func__, bus->sda_delay, t_pclk * delay * 5,
+  t_pclk * 5);
+    }
+
+    delay |= I2CLC_FILTER;
+    } else {
+    delay = 0;
+    debug("%s(): sda-delay = 0\n", __func__);
+    }
+
+    delay &= 0x7;
+    writel(delay, &i2c->iiclc);
+
+    return 0;
+}
+#endif
+
+static int nx_i2c_set_bus_speed(struct udevice *dev, uint speed)
+{
+    struct nx_i2c_bus *bus = dev_get_priv(dev);
+    struct nx_i2c_regs *i2c = bus->regs;
+    unsigned long pclk, pres = 16, div;
+
+    if (i2c_set_clk(bus, 1))
+    return -EINVAL;
+
+    /* get input clock of the I2C-controller */
+    pclk = i2c_get_clkrate(bus);
+
+    /* calculate prescaler and divisor values */
+    if ((pclk / pres / (16 + 1)) > speed)
+    /* set prescaler to 256 */
+    pres = 256;
+
+    div = 0;
+    /* actual divider = div + 1 */
+    while ((pclk / pres / (div + 1)) > speed)
+    div++;
+
+    if (div > 0xF) {
+    debug("%s(): pres==%ld, div==0x%lx is saturated to 0xF !)\n",
+  __func__, pres, div);
+    div = 0xF;
+    } else {
+    debug("%s(): pres==%ld, div==0x%lx)\n", __func__, pres, div);
+    }
+
+    /* set prescaler, divisor according to pclk, also set ACKGEN, IRQ */
+    writel((div & 0x0F) | ((pres == 256) ? 0x40 : 0), &i2c->iiccon);


Ok, I am really nitpicking now ... can you use defines here instead
this magic values?

[...]

Thanks!

bye,
Heiko


Re: [PATCH v3 04/14] i2c: add nexell driver

2020-07-02 Thread Heiko Schocher

Hello Stefan,

Am 29.06.2020 um 19:46 schrieb Stefan Bosch:

Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01:
- i2c/nx_i2c.c: Some adaptions mainly because of changes in
   "struct udevice".
- several Bugfixes in nx_i2c.c.
- the driver has been for s5p6818 only. Code extended appropriately
   in order s5p4418 is also working.
- "probe_chip" added.
- pinctrl-driver/dt is used instead of configuring the i2c I/O-pins
   in the i2c-driver.
- '#ifdef CONFIG...' changed to 'if (IS_ENABLED(CONFIG...))' where
   possible (and similar).
- livetree API (dev_read_...) is used instead of fdt one (fdt...).

Signed-off-by: Stefan Bosch 


Reviewed-by: Heiko Schocher 

Nitpick only ...

[...]

diff --git a/drivers/i2c/nx_i2c.c b/drivers/i2c/nx_i2c.c
new file mode 100644
index 000..cefc774
--- /dev/null
+++ b/drivers/i2c/nx_i2c.c
@@ -0,0 +1,624 @@

[...]

+static uint i2c_set_clk(struct nx_i2c_bus *bus, uint enb)
+{
+   struct clk *clk;
+   char name[50];
+
+   sprintf(name, "%s.%d", DEV_NAME_I2C, bus->bus_num);
+   clk = clk_get((const char *)name);
+   if (!clk) {
+   debug("%s(): clk_get(%s) error!\n",
+ __func__, (const char *)name);
+   return -EINVAL;
+   }
+
+   if (enb) {
+   clk_disable(clk);
+   clk_enable(clk);
+   } else {
+   clk_disable(clk);
+   }


You can do here:

clk_disable(clk);
if (enb)
clk_enable(clk);


+
+   return 0;
+}
+
+#ifdef CONFIG_ARCH_S5P6818
+/* Set SDA line delay, not available at S5P4418 */
+static int nx_i2c_set_sda_delay(struct nx_i2c_bus *bus)
+{
+   struct nx_i2c_regs *i2c = bus->regs;
+   uint pclk = 0;
+   uint t_pclk = 0;
+   uint delay = 0;
+
+   /* get input clock of the I2C-controller */
+   pclk = i2c_get_clkrate(bus);
+
+   if (bus->sda_delay) {
+   /* t_pclk = period time of one pclk [ns] */
+   t_pclk = DIV_ROUND_UP(1000, pclk / 100);
+   /* delay = number of pclks required for sda_delay [ns] */
+   delay = DIV_ROUND_UP(bus->sda_delay, t_pclk);
+   /* delay = register value (step of 5 clocks) */
+   delay = DIV_ROUND_UP(delay, 5);
+   /* max. possible register value = 3 */
+   if (delay > 3) {


May you use defines here?


+   delay = 3;
+   debug("%s(): sda-delay des.: %dns, sat. to max.: %dns 
(granularity: %dns)\n",
+ __func__, bus->sda_delay, t_pclk * delay * 5,
+ t_pclk * 5);
+   } else {
+   debug("%s(): sda-delay des.: %dns, act.: %dns (granularity: 
%dns)\n",
+ __func__, bus->sda_delay, t_pclk * delay * 5,
+ t_pclk * 5);
+   }
+
+   delay |= I2CLC_FILTER;
+   } else {
+   delay = 0;
+   debug("%s(): sda-delay = 0\n", __func__);
+   }
+
+   delay &= 0x7;
+   writel(delay, &i2c->iiclc);
+
+   return 0;
+}
+#endif
+
+static int nx_i2c_set_bus_speed(struct udevice *dev, uint speed)
+{
+   struct nx_i2c_bus *bus = dev_get_priv(dev);
+   struct nx_i2c_regs *i2c = bus->regs;
+   unsigned long pclk, pres = 16, div;
+
+   if (i2c_set_clk(bus, 1))
+   return -EINVAL;
+
+   /* get input clock of the I2C-controller */
+   pclk = i2c_get_clkrate(bus);
+
+   /* calculate prescaler and divisor values */
+   if ((pclk / pres / (16 + 1)) > speed)
+   /* set prescaler to 256 */
+   pres = 256;
+
+   div = 0;
+   /* actual divider = div + 1 */
+   while ((pclk / pres / (div + 1)) > speed)
+   div++;
+
+   if (div > 0xF) {
+   debug("%s(): pres==%ld, div==0x%lx is saturated to 0xF !)\n",
+ __func__, pres, div);
+   div = 0xF;
+   } else {
+   debug("%s(): pres==%ld, div==0x%lx)\n", __func__, pres, div);
+   }
+
+   /* set prescaler, divisor according to pclk, also set ACKGEN, IRQ */
+   writel((div & 0x0F) | ((pres == 256) ? 0x40 : 0), &i2c->iiccon);


Ok, I am really nitpicking now ... can you use defines here instead
this magic values?

[...]

Thanks!

bye,
Heiko
--
DENX Software Engineering GmbH,  Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-52   Fax: +49-8142-66989-80   Email: h...@denx.de


[PATCH v3 04/14] i2c: add nexell driver

2020-06-29 Thread Stefan Bosch
Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01:
- i2c/nx_i2c.c: Some adaptions mainly because of changes in
  "struct udevice".
- several Bugfixes in nx_i2c.c.
- the driver has been for s5p6818 only. Code extended appropriately
  in order s5p4418 is also working.
- "probe_chip" added.
- pinctrl-driver/dt is used instead of configuring the i2c I/O-pins
  in the i2c-driver.
- '#ifdef CONFIG...' changed to 'if (IS_ENABLED(CONFIG...))' where
  possible (and similar).
- livetree API (dev_read_...) is used instead of fdt one (fdt...).

Signed-off-by: Stefan Bosch 
---

Changes in v3:
- pinctrl-driver/dt is used now instead of configuring the i2c I/O-pins
  in the i2c-driver.
- drivers/i2c/nx_i2c.c: '#include ' inserted because it has been
  removed from common.h.
- '#ifdef...' changed to 'if (IS_ENABLED(CONFIG...))' where possible
  because of appropriate warnings of patman.
- Changed to livetree API as proposed by patman:
  fdtdec_get_int() --> dev_read_s32_default()

Changes in v2:
- commit "i2c: mmc: add nexell driver (gpio, i2c, mmc, pwm)" splitted
  into separate commits for gpio, i2c, mmc, pwm.
- several Bugfixes in nx_i2c.c.
- the i2c-driver has been for s5p6818 only. Code extended approriately
  in order s5p4418 is also working.
- "probe_chip" added to the i2c-driver.
- doc/device-tree-bindings/i2c/nx_i2c.txt added.

 doc/device-tree-bindings/i2c/nx_i2c.txt |  28 ++
 drivers/i2c/Kconfig |   9 +
 drivers/i2c/Makefile|   1 +
 drivers/i2c/nx_i2c.c| 624 
 4 files changed, 662 insertions(+)
 create mode 100644 doc/device-tree-bindings/i2c/nx_i2c.txt
 create mode 100644 drivers/i2c/nx_i2c.c

diff --git a/doc/device-tree-bindings/i2c/nx_i2c.txt 
b/doc/device-tree-bindings/i2c/nx_i2c.txt
new file mode 100644
index 000..9f3abe7
--- /dev/null
+++ b/doc/device-tree-bindings/i2c/nx_i2c.txt
@@ -0,0 +1,28 @@
+I2C controller embedded in Nexell's/Samsung's SoC S5P4418 and S5P6818
+
+Driver:
+- drivers/i2c/nx_i2c.c
+
+Required properties:
+- #address-cells = <1>;
+- #size-cells = <0>;
+- compatible = "nexell,s5pxx18-i2c";
+- reg = ;
+Where i2c_base has to be the base address of the i2c-register set.
+I2C0: 0xc00a4000
+I2C1: 0xc00a5000
+I2C2: 0xc00a6000
+
+Optional properties:
+- clock-frequency: Desired I2C bus frequency in Hz, default value is 10.
+- i2c-sda-delay-ns (S5P6818 only): SDA delay in ns, default value is 0.
+- Child nodes conforming to i2c bus binding.
+
+Example:
+   i2c0:i2c@c00a4000 {
+   #address-cells = <1>;
+   #size-cells = <0>;
+   compatible = "nexell,s5pxx18-i2c";
+   reg = <0xc00a4000 0x100>;
+   clock-frequency = <40>;
+   };
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index f8b18de..b276f0b 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -325,6 +325,15 @@ config SYS_MXC_I2C8_SLAVE
 MXC I2C8 Slave
 endif
 
+config SYS_I2C_NEXELL
+   bool "Nexell I2C driver"
+   depends on DM_I2C
+   help
+ Add support for the Nexell I2C driver. This is used with various
+ Nexell parts such as S5Pxx18 series SoCs. All chips
+ have several I2C ports and all are provided, controlled by the
+ device tree.
+
 config SYS_I2C_OMAP24XX
bool "TI OMAP2+ I2C driver"
depends on ARCH_OMAP2PLUS || ARCH_K3
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 62935b7..6ebc1aa 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_SYS_I2C_LPC32XX) += lpc32xx_i2c.o
 obj-$(CONFIG_SYS_I2C_MESON) += meson_i2c.o
 obj-$(CONFIG_SYS_I2C_MVTWSI) += mvtwsi.o
 obj-$(CONFIG_SYS_I2C_MXC) += mxc_i2c.o
+obj-$(CONFIG_SYS_I2C_NEXELL) += nx_i2c.o
 obj-$(CONFIG_SYS_I2C_OMAP24XX) += omap24xx_i2c.o
 obj-$(CONFIG_SYS_I2C_RCAR_I2C) += rcar_i2c.o
 obj-$(CONFIG_SYS_I2C_RCAR_IIC) += rcar_iic.o
diff --git a/drivers/i2c/nx_i2c.c b/drivers/i2c/nx_i2c.c
new file mode 100644
index 000..cefc774
--- /dev/null
+++ b/drivers/i2c/nx_i2c.c
@@ -0,0 +1,624 @@
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define I2C_WRITE   0
+#define I2C_READ1
+
+#define I2CSTAT_MTM 0xC0/* Master Transmit Mode */
+#define I2CSTAT_MRM 0x80/* Master Receive Mode */
+#define I2CSTAT_BSY 0x20/* Read: Bus Busy */
+#define I2CSTAT_SS  0x20/* Write: START (1) / STOP (0) */
+#define I2CSTAT_RXTXEN  0x10/* Rx/Tx enable */
+#define I2CSTAT_ABT0x08/* Arbitration bit */
+#define I2CSTAT_NACK0x01/* Nack bit */
+#define I2CCON_IRCLR0x100   /* Interrupt Clear bit  */
+#define I2CCON_ACKGEN   0x80/* Acknowledge generation */
+#define I2CCON_IRENB   0x20/* Interrupt Enable bit  */
+#define I2CCON_IRPND0x10/* Interrupt pending bit */
+
+#ifdef CONFIG_ARCH_S5P6818
+#define I2CLC_FILTER   0x04/*