aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-04-11 15:19:26 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-04-11 15:19:26 -0700
commit9e528fe13c95cee1b4ee23690aebf8b02eebac1f (patch)
treef66470b8f1fed6353824caadbbe8fa02744dc583
parent6f9fd9359daf4a4353bc78325a77e47dd78f60e3 (diff)
downloadltsi-kernel-9e528fe13c95cee1b4ee23690aebf8b02eebac1f.tar.gz
marzen i2c patches added
-rw-r--r--patches.marzen/arm-shmobile-r8a7779-add-i2c-driver-support.patch127
-rw-r--r--patches.marzen/i2c-add-renesas-r-car-i2c-driver.patch784
-rw-r--r--patches.marzen/i2c-rcar-fix-section-mismatch.patch47
-rw-r--r--patches.marzen/i2c-rcar-used-devm_request_and_ioremap-instead-of-devm_ioremap.patch31
-rw-r--r--series4
5 files changed, 993 insertions, 0 deletions
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
index 00000000000000..cb0fa454ce8984
--- /dev/null
+++ b/patches.marzen/arm-shmobile-r8a7779-add-i2c-driver-support.patch
@@ -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
index 00000000000000..96736e4a97f8cc
--- /dev/null
+++ b/patches.marzen/i2c-add-renesas-r-car-i2c-driver.patch
@@ -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
index 00000000000000..7a68c8f200a221
--- /dev/null
+++ b/patches.marzen/i2c-rcar-fix-section-mismatch.patch
@@ -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
index 00000000000000..b4d97de24b4455
--- /dev/null
+++ b/patches.marzen/i2c-rcar-used-devm_request_and_ioremap-instead-of-devm_ioremap.patch
@@ -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 24e95ab5172d7e..20122f39c9af2f 100644
--- 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