marzen i2c patches added
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 11 Apr 2013 22:19:26 +0000 (15:19 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 11 Apr 2013 22:19:26 +0000 (15:19 -0700)
patches.marzen/arm-shmobile-r8a7779-add-i2c-driver-support.patch [new file with mode: 0644]
patches.marzen/i2c-add-renesas-r-car-i2c-driver.patch [new file with mode: 0644]
patches.marzen/i2c-rcar-fix-section-mismatch.patch [new file with mode: 0644]
patches.marzen/i2c-rcar-used-devm_request_and_ioremap-instead-of-devm_ioremap.patch [new file with mode: 0644]
series

diff --git a/patches.marzen/arm-shmobile-r8a7779-add-i2c-driver-support.patch b/patches.marzen/arm-shmobile-r8a7779-add-i2c-driver-support.patch
new file mode 100644 (file)
index 0000000..cb0fa45
--- /dev/null
@@ -0,0 +1,127 @@
+From ltsi-dev-bounces@lists.linuxfoundation.org Wed Feb 27 20:03:20 2013
+From: Simon Horman <horms+renesas@verge.net.au>
+Date: Thu, 28 Feb 2013 13:03:04 +0900
+Subject: [PATCH 4/4] ARM: shmobile: r8a7779: add I2C driver support
+To: ltsi-dev@lists.linuxfoundation.org
+Cc: Magnus Damm <magnus.damm@gmail.com>, Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+Message-ID: <1362024184-27864-5-git-send-email-horms+renesas@verge.net.au>
+
+
+From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+This patch enable R-Car I2C driver
+
+Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+Signed-off-by: Simon Horman <horms@verge.net.au>
+(cherry picked from commit ccc2a27b15c978334927cea9f1156f019a01b833)
+
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ arch/arm/configs/marzen_defconfig      |    2 
+ arch/arm/mach-shmobile/setup-r8a7779.c |   77 +++++++++++++++++++++++++++++++++
+ 2 files changed, 79 insertions(+)
+
+--- a/arch/arm/configs/marzen_defconfig
++++ b/arch/arm/configs/marzen_defconfig
+@@ -69,6 +69,8 @@ CONFIG_SERIAL_SH_SCI=y
+ CONFIG_SERIAL_SH_SCI_NR_UARTS=6
+ CONFIG_SERIAL_SH_SCI_CONSOLE=y
+ # CONFIG_HW_RANDOM is not set
++CONFIG_I2C=y
++CONFIG_I2C_RCAR=y
+ CONFIG_GPIO_SYSFS=y
+ # CONFIG_HWMON is not set
+ CONFIG_SSB=y
+--- a/arch/arm/mach-shmobile/setup-r8a7779.c
++++ b/arch/arm/mach-shmobile/setup-r8a7779.c
+@@ -229,6 +229,79 @@ static struct platform_device tmu01_devi
+       .num_resources  = ARRAY_SIZE(tmu01_resources),
+ };
++/* I2C */
++static struct resource rcar_i2c0_res[] = {
++      {
++              .start  = 0xffc70000,
++              .end    = 0xffc70fff,
++              .flags  = IORESOURCE_MEM,
++      }, {
++              .start  = gic_spi(79),
++              .flags  = IORESOURCE_IRQ,
++      },
++};
++
++static struct platform_device i2c0_device = {
++      .name           = "i2c-rcar",
++      .id             = 0,
++      .resource       = rcar_i2c0_res,
++      .num_resources  = ARRAY_SIZE(rcar_i2c0_res),
++};
++
++static struct resource rcar_i2c1_res[] = {
++      {
++              .start  = 0xffc71000,
++              .end    = 0xffc71fff,
++              .flags  = IORESOURCE_MEM,
++      }, {
++              .start  = gic_spi(82),
++              .flags  = IORESOURCE_IRQ,
++      },
++};
++
++static struct platform_device i2c1_device = {
++      .name           = "i2c-rcar",
++      .id             = 1,
++      .resource       = rcar_i2c1_res,
++      .num_resources  = ARRAY_SIZE(rcar_i2c1_res),
++};
++
++static struct resource rcar_i2c2_res[] = {
++      {
++              .start  = 0xffc72000,
++              .end    = 0xffc72fff,
++              .flags  = IORESOURCE_MEM,
++      }, {
++              .start  = gic_spi(80),
++              .flags  = IORESOURCE_IRQ,
++      },
++};
++
++static struct platform_device i2c2_device = {
++      .name           = "i2c-rcar",
++      .id             = 2,
++      .resource       = rcar_i2c2_res,
++      .num_resources  = ARRAY_SIZE(rcar_i2c2_res),
++};
++
++static struct resource rcar_i2c3_res[] = {
++      {
++              .start  = 0xffc73000,
++              .end    = 0xffc73fff,
++              .flags  = IORESOURCE_MEM,
++      }, {
++              .start  = gic_spi(81),
++              .flags  = IORESOURCE_IRQ,
++      },
++};
++
++static struct platform_device i2c3_device = {
++      .name           = "i2c-rcar",
++      .id             = 3,
++      .resource       = rcar_i2c3_res,
++      .num_resources  = ARRAY_SIZE(rcar_i2c3_res),
++};
++
+ static struct platform_device *r8a7779_early_devices[] __initdata = {
+       &scif0_device,
+       &scif1_device,
+@@ -238,6 +311,10 @@ static struct platform_device *r8a7779_e
+       &scif5_device,
+       &tmu00_device,
+       &tmu01_device,
++      &i2c0_device,
++      &i2c1_device,
++      &i2c2_device,
++      &i2c3_device,
+ };
+ static struct platform_device *r8a7779_late_devices[] __initdata = {
diff --git a/patches.marzen/i2c-add-renesas-r-car-i2c-driver.patch b/patches.marzen/i2c-add-renesas-r-car-i2c-driver.patch
new file mode 100644 (file)
index 0000000..96736e4
--- /dev/null
@@ -0,0 +1,784 @@
+From ltsi-dev-bounces@lists.linuxfoundation.org Wed Feb 27 20:03:27 2013
+From: Simon Horman <horms+renesas@verge.net.au>
+Date: Thu, 28 Feb 2013 13:03:01 +0900
+Subject: [PATCH 1/4] i2c: add Renesas R-Car I2C driver
+To: ltsi-dev@lists.linuxfoundation.org
+Cc: Magnus Damm <magnus.damm@gmail.com>, Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+Message-ID: <1362024184-27864-2-git-send-email-horms+renesas@verge.net.au>
+
+
+From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+R-Car I2C is similar with SH7760 I2C.
+But the SH7760 I2C driver had many workaround operations, since H/W had bugs.
+Thus, it was pointless to keep compatible between SH7760 and R-Car I2C drivers.
+This patch creates new Renesas R-Car I2C driver.
+
+Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+(cherry picked from commit 6ccbe607132bd823abbad8d32b13af89161707da)
+
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ drivers/i2c/busses/Kconfig    |   10 
+ drivers/i2c/busses/Makefile   |    1 
+ drivers/i2c/busses/i2c-rcar.c |  709 ++++++++++++++++++++++++++++++++++++++++++
+ include/linux/i2c/i2c-rcar.h  |   10 
+ 4 files changed, 730 insertions(+)
+ create mode 100644 drivers/i2c/busses/i2c-rcar.c
+ create mode 100644 include/linux/i2c/i2c-rcar.h
+
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -723,6 +723,16 @@ config I2C_XLR
+         This driver can also be built as a module.  If so, the module
+         will be called i2c-xlr.
++config I2C_RCAR
++      tristate "Renesas R-Car I2C Controller"
++      depends on ARCH_SHMOBILE && I2C
++      help
++        If you say yes to this option, support will be included for the
++        R-Car I2C controller.
++
++        This driver can also be built as a module.  If so, the module
++        will be called i2c-rcar.
++
+ comment "External I2C/SMBus adapter drivers"
+ config I2C_DIOLAN_U2C
+--- a/drivers/i2c/busses/Makefile
++++ b/drivers/i2c/busses/Makefile
+@@ -72,6 +72,7 @@ obj-$(CONFIG_I2C_VERSATILE)  += i2c-versa
+ obj-$(CONFIG_I2C_OCTEON)      += i2c-octeon.o
+ obj-$(CONFIG_I2C_XILINX)      += i2c-xiic.o
+ obj-$(CONFIG_I2C_XLR)         += i2c-xlr.o
++obj-$(CONFIG_I2C_RCAR)                += i2c-rcar.o
+ # External I2C/SMBus adapter drivers
+ obj-$(CONFIG_I2C_DIOLAN_U2C)  += i2c-diolan-u2c.o
+--- /dev/null
++++ b/drivers/i2c/busses/i2c-rcar.c
+@@ -0,0 +1,709 @@
++/*
++ *  drivers/i2c/busses/i2c-rcar.c
++ *
++ * Copyright (C) 2012 Renesas Solutions Corp.
++ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
++ *
++ * This file is based on the drivers/i2c/busses/i2c-sh7760.c
++ * (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com>
++ *
++ * This file used out-of-tree driver i2c-rcar.c
++ * Copyright (C) 2011-2012 Renesas Electronics Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/i2c.h>
++#include <linux/i2c/i2c-rcar.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/pm_runtime.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++
++/* register offsets */
++#define ICSCR 0x00    /* slave ctrl */
++#define ICMCR 0x04    /* master ctrl */
++#define ICSSR 0x08    /* slave status */
++#define ICMSR 0x0C    /* master status */
++#define ICSIER        0x10    /* slave irq enable */
++#define ICMIER        0x14    /* master irq enable */
++#define ICCCR 0x18    /* clock dividers */
++#define ICSAR 0x1C    /* slave address */
++#define ICMAR 0x20    /* master address */
++#define ICRXTX        0x24    /* data port */
++
++/* ICMCR */
++#define MDBS  (1 << 7)        /* non-fifo mode switch */
++#define FSCL  (1 << 6)        /* override SCL pin */
++#define FSDA  (1 << 5)        /* override SDA pin */
++#define OBPC  (1 << 4)        /* override pins */
++#define MIE   (1 << 3)        /* master if enable */
++#define TSBE  (1 << 2)
++#define FSB   (1 << 1)        /* force stop bit */
++#define ESG   (1 << 0)        /* en startbit gen */
++
++/* ICMSR */
++#define MNR   (1 << 6)        /* nack received */
++#define MAL   (1 << 5)        /* arbitration lost */
++#define MST   (1 << 4)        /* sent a stop */
++#define MDE   (1 << 3)
++#define MDT   (1 << 2)
++#define MDR   (1 << 1)
++#define MAT   (1 << 0)        /* slave addr xfer done */
++
++/* ICMIE */
++#define MNRE  (1 << 6)        /* nack irq en */
++#define MALE  (1 << 5)        /* arblos irq en */
++#define MSTE  (1 << 4)        /* stop irq en */
++#define MDEE  (1 << 3)
++#define MDTE  (1 << 2)
++#define MDRE  (1 << 1)
++#define MATE  (1 << 0)        /* address sent irq en */
++
++
++enum {
++      RCAR_BUS_PHASE_ADDR,
++      RCAR_BUS_PHASE_DATA,
++      RCAR_BUS_PHASE_STOP,
++};
++
++enum {
++      RCAR_IRQ_CLOSE,
++      RCAR_IRQ_OPEN_FOR_SEND,
++      RCAR_IRQ_OPEN_FOR_RECV,
++      RCAR_IRQ_OPEN_FOR_STOP,
++};
++
++/*
++ * flags
++ */
++#define ID_LAST_MSG   (1 << 0)
++#define ID_IOERROR    (1 << 1)
++#define ID_DONE               (1 << 2)
++#define ID_ARBLOST    (1 << 3)
++#define ID_NACK               (1 << 4)
++
++struct rcar_i2c_priv {
++      void __iomem *io;
++      struct i2c_adapter adap;
++      struct i2c_msg  *msg;
++
++      spinlock_t lock;
++      wait_queue_head_t wait;
++
++      int pos;
++      int irq;
++      u32 icccr;
++      u32 flags;
++};
++
++#define rcar_i2c_priv_to_dev(p)               ((p)->adap.dev.parent)
++#define rcar_i2c_is_recv(p)           ((p)->msg->flags & I2C_M_RD)
++
++#define rcar_i2c_flags_set(p, f)      ((p)->flags |= (f))
++#define rcar_i2c_flags_has(p, f)      ((p)->flags & (f))
++
++#define LOOP_TIMEOUT  1024
++
++/*
++ *            basic functions
++ */
++static void rcar_i2c_write(struct rcar_i2c_priv *priv, int reg, u32 val)
++{
++      writel(val, priv->io + reg);
++}
++
++static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg)
++{
++      return readl(priv->io + reg);
++}
++
++static void rcar_i2c_init(struct rcar_i2c_priv *priv)
++{
++      /*
++       * reset slave mode.
++       * slave mode is not used on this driver
++       */
++      rcar_i2c_write(priv, ICSIER, 0);
++      rcar_i2c_write(priv, ICSAR, 0);
++      rcar_i2c_write(priv, ICSCR, 0);
++      rcar_i2c_write(priv, ICSSR, 0);
++
++      /* reset master mode */
++      rcar_i2c_write(priv, ICMIER, 0);
++      rcar_i2c_write(priv, ICMCR, 0);
++      rcar_i2c_write(priv, ICMSR, 0);
++      rcar_i2c_write(priv, ICMAR, 0);
++}
++
++static void rcar_i2c_irq_mask(struct rcar_i2c_priv *priv, int open)
++{
++      u32 val = MNRE | MALE | MSTE | MATE; /* default */
++
++      switch (open) {
++      case RCAR_IRQ_OPEN_FOR_SEND:
++              val |= MDEE; /* default + send */
++              break;
++      case RCAR_IRQ_OPEN_FOR_RECV:
++              val |= MDRE; /* default + read */
++              break;
++      case RCAR_IRQ_OPEN_FOR_STOP:
++              val = MSTE; /* stop irq only */
++              break;
++      case RCAR_IRQ_CLOSE:
++      default:
++              val = 0; /* all close */
++              break;
++      }
++      rcar_i2c_write(priv, ICMIER, val);
++}
++
++static void rcar_i2c_set_addr(struct rcar_i2c_priv *priv, u32 recv)
++{
++      rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | recv);
++}
++
++/*
++ *            bus control functions
++ */
++static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
++{
++      int i;
++
++      for (i = 0; i < LOOP_TIMEOUT; i++) {
++              /* make sure that bus is not busy */
++              if (!(rcar_i2c_read(priv, ICMCR) & FSDA))
++                      return 0;
++              udelay(1);
++      }
++
++      return -EBUSY;
++}
++
++static void rcar_i2c_bus_phase(struct rcar_i2c_priv *priv, int phase)
++{
++      switch (phase) {
++      case RCAR_BUS_PHASE_ADDR:
++              rcar_i2c_write(priv, ICMCR, MDBS | MIE | ESG);
++              break;
++      case RCAR_BUS_PHASE_DATA:
++              rcar_i2c_write(priv, ICMCR, MDBS | MIE);
++              break;
++      case RCAR_BUS_PHASE_STOP:
++              rcar_i2c_write(priv, ICMCR, MDBS | MIE | FSB);
++              break;
++      }
++}
++
++/*
++ *            clock function
++ */
++static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
++                                  u32 bus_speed,
++                                  struct device *dev)
++{
++      struct clk *clkp = clk_get(NULL, "peripheral_clk");
++      u32 scgd, cdf;
++      u32 round, ick;
++      u32 scl;
++
++      if (!clkp) {
++              dev_err(dev, "there is no peripheral_clk\n");
++              return -EIO;
++      }
++
++      /*
++       * calculate SCL clock
++       * see
++       *      ICCCR
++       *
++       * ick  = clkp / (1 + CDF)
++       * SCL  = ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick])
++       *
++       * ick  : I2C internal clock < 20 MHz
++       * ticf : I2C SCL falling time  =  35 ns here
++       * tr   : I2C SCL rising  time  = 200 ns here
++       * intd : LSI internal delay    =  50 ns here
++       * clkp : peripheral_clk
++       * F[]  : integer up-valuation
++       */
++      for (cdf = 0; cdf < 4; cdf++) {
++              ick = clk_get_rate(clkp) / (1 + cdf);
++              if (ick < 20000000)
++                      goto ick_find;
++      }
++      dev_err(dev, "there is no best CDF\n");
++      return -EIO;
++
++ick_find:
++      /*
++       * it is impossible to calculate large scale
++       * number on u32. separate it
++       *
++       * F[(ticf + tr + intd) * ick]
++       *  = F[(35 + 200 + 50)ns * ick]
++       *  = F[285 * ick / 1000000000]
++       *  = F[(ick / 1000000) * 285 / 1000]
++       */
++      round = (ick + 500000) / 1000000 * 285;
++      round = (round + 500) / 1000;
++
++      /*
++       * SCL  = ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick])
++       *
++       * Calculation result (= SCL) should be less than
++       * bus_speed for hardware safety
++       */
++      for (scgd = 0; scgd < 0x40; scgd++) {
++              scl = ick / (20 + (scgd * 8) + round);
++              if (scl <= bus_speed)
++                      goto scgd_find;
++      }
++      dev_err(dev, "it is impossible to calculate best SCL\n");
++      return -EIO;
++
++scgd_find:
++      dev_dbg(dev, "clk %d/%d(%lu), round %u, CDF:0x%x, SCGD: 0x%x\n",
++              scl, bus_speed, clk_get_rate(clkp), round, cdf, scgd);
++
++      /*
++       * keep icccr value
++       */
++      priv->icccr = (scgd << 2 | cdf);
++
++      return 0;
++}
++
++static void rcar_i2c_clock_start(struct rcar_i2c_priv *priv)
++{
++      rcar_i2c_write(priv, ICCCR, priv->icccr);
++}
++
++/*
++ *            status functions
++ */
++static u32 rcar_i2c_status_get(struct rcar_i2c_priv *priv)
++{
++      return rcar_i2c_read(priv, ICMSR);
++}
++
++#define rcar_i2c_status_clear(priv) rcar_i2c_status_bit_clear(priv, 0xffffffff)
++static void rcar_i2c_status_bit_clear(struct rcar_i2c_priv *priv, u32 bit)
++{
++      rcar_i2c_write(priv, ICMSR, ~bit);
++}
++
++/*
++ *            recv/send functions
++ */
++static int rcar_i2c_recv(struct rcar_i2c_priv *priv)
++{
++      rcar_i2c_set_addr(priv, 1);
++      rcar_i2c_status_clear(priv);
++      rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_ADDR);
++      rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_RECV);
++
++      return 0;
++}
++
++static int rcar_i2c_send(struct rcar_i2c_priv *priv)
++{
++      int ret;
++
++      /*
++       * It should check bus status when send case
++       */
++      ret = rcar_i2c_bus_barrier(priv);
++      if (ret < 0)
++              return ret;
++
++      rcar_i2c_set_addr(priv, 0);
++      rcar_i2c_status_clear(priv);
++      rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_ADDR);
++      rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_SEND);
++
++      return 0;
++}
++
++#define rcar_i2c_send_restart(priv) rcar_i2c_status_bit_clear(priv, (MAT | MDE))
++#define rcar_i2c_recv_restart(priv) rcar_i2c_status_bit_clear(priv, (MAT | MDR))
++
++/*
++ *            interrupt functions
++ */
++static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
++{
++      struct i2c_msg *msg = priv->msg;
++
++      /*
++       * FIXME
++       * sometimes, unknown interrupt happened.
++       * Do nothing
++       */
++      if (!(msr & MDE))
++              return 0;
++
++      /*
++       * If address transfer phase finished,
++       * goto data phase.
++       */
++      if (msr & MAT)
++              rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_DATA);
++
++      if (priv->pos < msg->len) {
++              /*
++               * Prepare next data to ICRXTX register.
++               * This data will go to _SHIFT_ register.
++               *
++               *    *
++               * [ICRXTX] -> [SHIFT] -> [I2C bus]
++               */
++              rcar_i2c_write(priv, ICRXTX, msg->buf[priv->pos]);
++              priv->pos++;
++
++      } else {
++              /*
++               * The last data was pushed to ICRXTX on _PREV_ empty irq.
++               * It is on _SHIFT_ register, and will sent to I2C bus.
++               *
++               *                *
++               * [ICRXTX] -> [SHIFT] -> [I2C bus]
++               */
++
++              if (priv->flags & ID_LAST_MSG)
++                      /*
++                       * If current msg is the _LAST_ msg,
++                       * prepare stop condition here.
++                       * ID_DONE will be set on STOP irq.
++                       */
++                      rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP);
++              else
++                      /*
++                       * If current msg is _NOT_ last msg,
++                       * it doesn't call stop phase.
++                       * thus, there is no STOP irq.
++                       * return ID_DONE here.
++                       */
++                      return ID_DONE;
++      }
++
++      rcar_i2c_send_restart(priv);
++
++      return 0;
++}
++
++static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
++{
++      struct i2c_msg *msg = priv->msg;
++
++      /*
++       * FIXME
++       * sometimes, unknown interrupt happened.
++       * Do nothing
++       */
++      if (!(msr & MDR))
++              return 0;
++
++      if (msr & MAT) {
++              /*
++               * Address transfer phase finished,
++               * but, there is no data at this point.
++               * Do nothing.
++               */
++      } else if (priv->pos < msg->len) {
++              /*
++               * get received data
++               */
++              msg->buf[priv->pos] = rcar_i2c_read(priv, ICRXTX);
++              priv->pos++;
++      }
++
++      /*
++       * If next received data is the _LAST_,
++       * go to STOP phase,
++       * otherwise, go to DATA phase.
++       */
++      if (priv->pos + 1 >= msg->len)
++              rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP);
++      else
++              rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_DATA);
++
++      rcar_i2c_recv_restart(priv);
++
++      return 0;
++}
++
++static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
++{
++      struct rcar_i2c_priv *priv = ptr;
++      struct device *dev = rcar_i2c_priv_to_dev(priv);
++      u32 msr;
++
++      /*-------------- spin lock -----------------*/
++      spin_lock(&priv->lock);
++
++      msr = rcar_i2c_status_get(priv);
++
++      /*
++       * Arbitration lost
++       */
++      if (msr & MAL) {
++              /*
++               * CAUTION
++               *
++               * When arbitration lost, device become _slave_ mode.
++               */
++              dev_dbg(dev, "Arbitration Lost\n");
++              rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST));
++              goto out;
++      }
++
++      /*
++       * Stop
++       */
++      if (msr & MST) {
++              dev_dbg(dev, "Stop\n");
++              rcar_i2c_flags_set(priv, ID_DONE);
++              goto out;
++      }
++
++      /*
++       * Nack
++       */
++      if (msr & MNR) {
++              dev_dbg(dev, "Nack\n");
++
++              /* go to stop phase */
++              rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP);
++              rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_STOP);
++              rcar_i2c_flags_set(priv, ID_NACK);
++              goto out;
++      }
++
++      /*
++       * recv/send
++       */
++      if (rcar_i2c_is_recv(priv))
++              rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr));
++      else
++              rcar_i2c_flags_set(priv, rcar_i2c_irq_send(priv, msr));
++
++out:
++      if (rcar_i2c_flags_has(priv, ID_DONE)) {
++              rcar_i2c_irq_mask(priv, RCAR_IRQ_CLOSE);
++              rcar_i2c_status_clear(priv);
++              wake_up(&priv->wait);
++      }
++
++      spin_unlock(&priv->lock);
++      /*-------------- spin unlock -----------------*/
++
++      return IRQ_HANDLED;
++}
++
++static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
++                              struct i2c_msg *msgs,
++                              int num)
++{
++      struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
++      struct device *dev = rcar_i2c_priv_to_dev(priv);
++      unsigned long flags;
++      int i, ret, timeout;
++
++      pm_runtime_get_sync(dev);
++
++      /*-------------- spin lock -----------------*/
++      spin_lock_irqsave(&priv->lock, flags);
++
++      rcar_i2c_init(priv);
++      rcar_i2c_clock_start(priv);
++
++      spin_unlock_irqrestore(&priv->lock, flags);
++      /*-------------- spin unlock -----------------*/
++
++      ret = -EINVAL;
++      for (i = 0; i < num; i++) {
++              /*-------------- spin lock -----------------*/
++              spin_lock_irqsave(&priv->lock, flags);
++
++              /* init each data */
++              priv->msg       = &msgs[i];
++              priv->pos       = 0;
++              priv->flags     = 0;
++              if (priv->msg == &msgs[num - 1])
++                      rcar_i2c_flags_set(priv, ID_LAST_MSG);
++
++              /* start send/recv */
++              if (rcar_i2c_is_recv(priv))
++                      ret = rcar_i2c_recv(priv);
++              else
++                      ret = rcar_i2c_send(priv);
++
++              spin_unlock_irqrestore(&priv->lock, flags);
++              /*-------------- spin unlock -----------------*/
++
++              if (ret < 0)
++                      break;
++
++              /*
++               * wait result
++               */
++              timeout = wait_event_timeout(priv->wait,
++                                           rcar_i2c_flags_has(priv, ID_DONE),
++                                           5 * HZ);
++              if (!timeout) {
++                      ret = -ETIMEDOUT;
++                      break;
++              }
++
++              /*
++               * error handling
++               */
++              if (rcar_i2c_flags_has(priv, ID_NACK)) {
++                      ret = -EREMOTEIO;
++                      break;
++              }
++
++              if (rcar_i2c_flags_has(priv, ID_ARBLOST)) {
++                      ret = -EAGAIN;
++                      break;
++              }
++
++              if (rcar_i2c_flags_has(priv, ID_IOERROR)) {
++                      ret = -EIO;
++                      break;
++              }
++
++              ret = i + 1; /* The number of transfer */
++      }
++
++      pm_runtime_put(dev);
++
++      if (ret < 0)
++              dev_err(dev, "error %d : %x\n", ret, priv->flags);
++
++      return ret;
++}
++
++static u32 rcar_i2c_func(struct i2c_adapter *adap)
++{
++      return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
++}
++
++static const struct i2c_algorithm rcar_i2c_algo = {
++      .master_xfer    = rcar_i2c_master_xfer,
++      .functionality  = rcar_i2c_func,
++};
++
++static int __devinit rcar_i2c_probe(struct platform_device *pdev)
++{
++      struct i2c_rcar_platform_data *pdata = pdev->dev.platform_data;
++      struct rcar_i2c_priv *priv;
++      struct i2c_adapter *adap;
++      struct resource *res;
++      struct device *dev = &pdev->dev;
++      u32 bus_speed;
++      int ret;
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (!res) {
++              dev_err(dev, "no mmio resources\n");
++              return -ENODEV;
++      }
++
++      priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL);
++      if (!priv) {
++              dev_err(dev, "no mem for private data\n");
++              return -ENOMEM;
++      }
++
++      bus_speed = 100000; /* default 100 kHz */
++      if (pdata && pdata->bus_speed)
++              bus_speed = pdata->bus_speed;
++      ret = rcar_i2c_clock_calculate(priv, bus_speed, dev);
++      if (ret < 0)
++              return ret;
++
++      priv->io = devm_ioremap(dev, res->start, resource_size(res));
++      if (!priv->io) {
++              dev_err(dev, "cannot ioremap\n");
++              return -ENODEV;
++      }
++
++      priv->irq = platform_get_irq(pdev, 0);
++      init_waitqueue_head(&priv->wait);
++      spin_lock_init(&priv->lock);
++
++      adap                    = &priv->adap;
++      adap->nr                = pdev->id;
++      adap->algo              = &rcar_i2c_algo;
++      adap->class             = I2C_CLASS_HWMON | I2C_CLASS_SPD;
++      adap->retries           = 3;
++      adap->dev.parent        = dev;
++      i2c_set_adapdata(adap, priv);
++      strlcpy(adap->name, pdev->name, sizeof(adap->name));
++
++      ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, 0,
++                             dev_name(dev), priv);
++      if (ret < 0) {
++              dev_err(dev, "cannot get irq %d\n", priv->irq);
++              return ret;
++      }
++
++      ret = i2c_add_numbered_adapter(adap);
++      if (ret < 0) {
++              dev_err(dev, "reg adap failed: %d\n", ret);
++              return ret;
++      }
++
++      pm_runtime_enable(dev);
++      platform_set_drvdata(pdev, priv);
++
++      dev_info(dev, "probed\n");
++
++      return 0;
++}
++
++static int __devexit rcar_i2c_remove(struct platform_device *pdev)
++{
++      struct rcar_i2c_priv *priv = platform_get_drvdata(pdev);
++      struct device *dev = &pdev->dev;
++
++      i2c_del_adapter(&priv->adap);
++      pm_runtime_disable(dev);
++
++      return 0;
++}
++
++static struct platform_driver rcar_i2c_drv = {
++      .driver = {
++              .name   = "i2c-rcar",
++              .owner  = THIS_MODULE,
++      },
++      .probe          = rcar_i2c_probe,
++      .remove         = __devexit_p(rcar_i2c_remove),
++};
++
++module_platform_driver(rcar_i2c_drv);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Renesas R-Car I2C bus driver");
++MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+--- /dev/null
++++ b/include/linux/i2c/i2c-rcar.h
+@@ -0,0 +1,10 @@
++#ifndef __I2C_R_CAR_H__
++#define __I2C_R_CAR_H__
++
++#include <linux/platform_device.h>
++
++struct i2c_rcar_platform_data {
++      u32 bus_speed;
++};
++
++#endif /* __I2C_R_CAR_H__ */
diff --git a/patches.marzen/i2c-rcar-fix-section-mismatch.patch b/patches.marzen/i2c-rcar-fix-section-mismatch.patch
new file mode 100644 (file)
index 0000000..7a68c8f
--- /dev/null
@@ -0,0 +1,47 @@
+From ltsi-dev-bounces@lists.linuxfoundation.org Wed Feb 27 20:03:23 2013
+From: Simon Horman <horms+renesas@verge.net.au>
+Date: Thu, 28 Feb 2013 13:03:03 +0900
+Subject: [PATCH 3/4] i2c: rcar: fix section mismatch
+To: ltsi-dev@lists.linuxfoundation.org
+Cc: Magnus Damm <magnus.damm@gmail.com>, Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+Message-ID: <1362024184-27864-4-git-send-email-horms+renesas@verge.net.au>
+
+
+From: Wolfram Sang <w.sang@pengutronix.de>
+
+Give the driver struct a name according to the 'standard' to fix:
+
+WARNING: vmlinux.o(.data+0x11798): Section mismatch in reference from the variable rcar_i2c_drv to the function .devinit.text:rcar_i2c_probe()
+...
+WARNING: vmlinux.o(.data+0x1179c): Section mismatch in reference from the variable rcar_i2c_drv to the function .devexit.text:rcar_i2c_remove()
+
+Reported-by: Simon Horman <horms@verge.net.au>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+Cc: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+(cherry picked from commit 45fd5e4ad2052101b4ceda5fdf4b003c428ebdfc)
+
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ drivers/i2c/busses/i2c-rcar.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/i2c/busses/i2c-rcar.c
++++ b/drivers/i2c/busses/i2c-rcar.c
+@@ -693,7 +693,7 @@ static int __devexit rcar_i2c_remove(str
+       return 0;
+ }
+-static struct platform_driver rcar_i2c_drv = {
++static struct platform_driver rcar_i2c_driver = {
+       .driver = {
+               .name   = "i2c-rcar",
+               .owner  = THIS_MODULE,
+@@ -702,7 +702,7 @@ static struct platform_driver rcar_i2c_d
+       .remove         = __devexit_p(rcar_i2c_remove),
+ };
+-module_platform_driver(rcar_i2c_drv);
++module_platform_driver(rcar_i2c_driver);
+ MODULE_LICENSE("GPL");
+ MODULE_DESCRIPTION("Renesas R-Car I2C bus driver");
diff --git a/patches.marzen/i2c-rcar-used-devm_request_and_ioremap-instead-of-devm_ioremap.patch b/patches.marzen/i2c-rcar-used-devm_request_and_ioremap-instead-of-devm_ioremap.patch
new file mode 100644 (file)
index 0000000..b4d97de
--- /dev/null
@@ -0,0 +1,31 @@
+From ltsi-dev-bounces@lists.linuxfoundation.org Wed Feb 27 20:03:30 2013
+From: Simon Horman <horms+renesas@verge.net.au>
+Date: Thu, 28 Feb 2013 13:03:02 +0900
+Subject: [PATCH 2/4] i2c: rcar: used devm_request_and_ioremap() instead of devm_ioremap()
+To: ltsi-dev@lists.linuxfoundation.org
+Cc: Magnus Damm <magnus.damm@gmail.com>, Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+Message-ID: <1362024184-27864-3-git-send-email-horms+renesas@verge.net.au>
+
+
+From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
+(cherry picked from commit b53f4baf8b26303fc75ef3b00cf5e7398b58efd4)
+
+Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
+---
+ drivers/i2c/busses/i2c-rcar.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/i2c/busses/i2c-rcar.c
++++ b/drivers/i2c/busses/i2c-rcar.c
+@@ -642,7 +642,7 @@ static int __devinit rcar_i2c_probe(stru
+       if (ret < 0)
+               return ret;
+-      priv->io = devm_ioremap(dev, res->start, resource_size(res));
++      priv->io = devm_request_and_ioremap(dev, res);
+       if (!priv->io) {
+               dev_err(dev, "cannot ioremap\n");
+               return -ENODEV;
diff --git a/series b/series
index 24e95ab5172d7e81c78a8f1fdb6391c579a2134b..20122f39c9af2f703f7a0a2ed4fbc44c5e3f9268 100644 (file)
--- a/series
+++ b/series
@@ -307,6 +307,10 @@ patches.marzen/0099-mmc-sh_mmcif-support-generic-card-detection.patch
 patches.marzen/arm-mach-shmobile-marzen-defconfig-update.patch
 patches.marzen/arm-shmobile-r8a7779-correct-tmu-clock-support.patch
 patches.marzen/libata-add-r-car-sata-driver.patch
+patches.marzen/i2c-add-renesas-r-car-i2c-driver.patch
+patches.marzen/i2c-rcar-used-devm_request_and_ioremap-instead-of-devm_ioremap.patch
+patches.marzen/i2c-rcar-fix-section-mismatch.patch
+patches.marzen/arm-shmobile-r8a7779-add-i2c-driver-support.patch
 
 #############################################################################
 # Armadillo 800 board support