18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * SuperH Mobile I2C Controller
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2014-19 Wolfram Sang <wsa@sang-engineering.com>
68c2ecf20Sopenharmony_ci * Copyright (C) 2008 Magnus Damm
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Portions of the code based on out-of-tree driver i2c-sh7343.c
98c2ecf20Sopenharmony_ci * Copyright (c) 2006 Carlos Munoz <carlos@kenati.com>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/clk.h>
138c2ecf20Sopenharmony_ci#include <linux/delay.h>
148c2ecf20Sopenharmony_ci#include <linux/dmaengine.h>
158c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
168c2ecf20Sopenharmony_ci#include <linux/err.h>
178c2ecf20Sopenharmony_ci#include <linux/i2c.h>
188c2ecf20Sopenharmony_ci#include <linux/init.h>
198c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
208c2ecf20Sopenharmony_ci#include <linux/io.h>
218c2ecf20Sopenharmony_ci#include <linux/kernel.h>
228c2ecf20Sopenharmony_ci#include <linux/module.h>
238c2ecf20Sopenharmony_ci#include <linux/of_device.h>
248c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
258c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
268c2ecf20Sopenharmony_ci#include <linux/slab.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* Transmit operation:                                                      */
298c2ecf20Sopenharmony_ci/*                                                                          */
308c2ecf20Sopenharmony_ci/* 0 byte transmit                                                          */
318c2ecf20Sopenharmony_ci/* BUS:     S     A8     ACK   P(*)                                         */
328c2ecf20Sopenharmony_ci/* IRQ:       DTE   WAIT                                                    */
338c2ecf20Sopenharmony_ci/* ICIC:                                                                    */
348c2ecf20Sopenharmony_ci/* ICCR: 0x94       0x90                                                    */
358c2ecf20Sopenharmony_ci/* ICDR:      A8                                                            */
368c2ecf20Sopenharmony_ci/*                                                                          */
378c2ecf20Sopenharmony_ci/* 1 byte transmit                                                          */
388c2ecf20Sopenharmony_ci/* BUS:     S     A8     ACK   D8(1)   ACK   P(*)                           */
398c2ecf20Sopenharmony_ci/* IRQ:       DTE   WAIT         WAIT                                       */
408c2ecf20Sopenharmony_ci/* ICIC:      -DTE                                                          */
418c2ecf20Sopenharmony_ci/* ICCR: 0x94                    0x90                                       */
428c2ecf20Sopenharmony_ci/* ICDR:      A8    D8(1)                                                   */
438c2ecf20Sopenharmony_ci/*                                                                          */
448c2ecf20Sopenharmony_ci/* 2 byte transmit                                                          */
458c2ecf20Sopenharmony_ci/* BUS:     S     A8     ACK   D8(1)   ACK   D8(2)   ACK   P(*)             */
468c2ecf20Sopenharmony_ci/* IRQ:       DTE   WAIT         WAIT          WAIT                         */
478c2ecf20Sopenharmony_ci/* ICIC:      -DTE                                                          */
488c2ecf20Sopenharmony_ci/* ICCR: 0x94                                  0x90                         */
498c2ecf20Sopenharmony_ci/* ICDR:      A8    D8(1)        D8(2)                                      */
508c2ecf20Sopenharmony_ci/*                                                                          */
518c2ecf20Sopenharmony_ci/* 3 bytes or more, +---------+ gets repeated                               */
528c2ecf20Sopenharmony_ci/*                                                                          */
538c2ecf20Sopenharmony_ci/*                                                                          */
548c2ecf20Sopenharmony_ci/* Receive operation:                                                       */
558c2ecf20Sopenharmony_ci/*                                                                          */
568c2ecf20Sopenharmony_ci/* 0 byte receive - not supported since slave may hold SDA low              */
578c2ecf20Sopenharmony_ci/*                                                                          */
588c2ecf20Sopenharmony_ci/* 1 byte receive       [TX] | [RX]                                         */
598c2ecf20Sopenharmony_ci/* BUS:     S     A8     ACK | D8(1)   ACK   P(*)                           */
608c2ecf20Sopenharmony_ci/* IRQ:       DTE   WAIT     |   WAIT     DTE                               */
618c2ecf20Sopenharmony_ci/* ICIC:      -DTE           |   +DTE                                       */
628c2ecf20Sopenharmony_ci/* ICCR: 0x94       0x81     |   0xc0                                       */
638c2ecf20Sopenharmony_ci/* ICDR:      A8             |            D8(1)                             */
648c2ecf20Sopenharmony_ci/*                                                                          */
658c2ecf20Sopenharmony_ci/* 2 byte receive        [TX]| [RX]                                         */
668c2ecf20Sopenharmony_ci/* BUS:     S     A8     ACK | D8(1)   ACK   D8(2)   ACK   P(*)             */
678c2ecf20Sopenharmony_ci/* IRQ:       DTE   WAIT     |   WAIT          WAIT     DTE                 */
688c2ecf20Sopenharmony_ci/* ICIC:      -DTE           |                 +DTE                         */
698c2ecf20Sopenharmony_ci/* ICCR: 0x94       0x81     |                 0xc0                         */
708c2ecf20Sopenharmony_ci/* ICDR:      A8             |                 D8(1)    D8(2)               */
718c2ecf20Sopenharmony_ci/*                                                                          */
728c2ecf20Sopenharmony_ci/* 3 byte receive       [TX] | [RX]                                     (*) */
738c2ecf20Sopenharmony_ci/* BUS:     S     A8     ACK | D8(1)   ACK   D8(2)   ACK   D8(3)   ACK    P */
748c2ecf20Sopenharmony_ci/* IRQ:       DTE   WAIT     |   WAIT          WAIT         WAIT      DTE   */
758c2ecf20Sopenharmony_ci/* ICIC:      -DTE           |                              +DTE            */
768c2ecf20Sopenharmony_ci/* ICCR: 0x94       0x81     |                              0xc0            */
778c2ecf20Sopenharmony_ci/* ICDR:      A8             |                 D8(1)        D8(2)     D8(3) */
788c2ecf20Sopenharmony_ci/*                                                                          */
798c2ecf20Sopenharmony_ci/* 4 bytes or more, this part is repeated    +---------+                    */
808c2ecf20Sopenharmony_ci/*                                                                          */
818c2ecf20Sopenharmony_ci/*                                                                          */
828c2ecf20Sopenharmony_ci/* Interrupt order and BUSY flag                                            */
838c2ecf20Sopenharmony_ci/*     ___                                                 _                */
848c2ecf20Sopenharmony_ci/* SDA ___\___XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAAAAAAA___/                 */
858c2ecf20Sopenharmony_ci/* SCL      \_/1\_/2\_/3\_/4\_/5\_/6\_/7\_/8\___/9\_____/                   */
868c2ecf20Sopenharmony_ci/*                                                                          */
878c2ecf20Sopenharmony_ci/*        S   D7  D6  D5  D4  D3  D2  D1  D0              P(*)              */
888c2ecf20Sopenharmony_ci/*                                           ___                            */
898c2ecf20Sopenharmony_ci/* WAIT IRQ ________________________________/   \___________                */
908c2ecf20Sopenharmony_ci/* TACK IRQ ____________________________________/   \_______                */
918c2ecf20Sopenharmony_ci/* DTE  IRQ __________________________________________/   \_                */
928c2ecf20Sopenharmony_ci/* AL   IRQ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX                */
938c2ecf20Sopenharmony_ci/*         _______________________________________________                  */
948c2ecf20Sopenharmony_ci/* BUSY __/                                               \_                */
958c2ecf20Sopenharmony_ci/*                                                                          */
968c2ecf20Sopenharmony_ci/* (*) The STOP condition is only sent by the master at the end of the last */
978c2ecf20Sopenharmony_ci/* I2C message or if the I2C_M_STOP flag is set. Similarly, the BUSY bit is */
988c2ecf20Sopenharmony_ci/* only cleared after the STOP condition, so, between messages we have to   */
998c2ecf20Sopenharmony_ci/* poll for the DTE bit.                                                    */
1008c2ecf20Sopenharmony_ci/*                                                                          */
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cienum sh_mobile_i2c_op {
1038c2ecf20Sopenharmony_ci	OP_START = 0,
1048c2ecf20Sopenharmony_ci	OP_TX_FIRST,
1058c2ecf20Sopenharmony_ci	OP_TX,
1068c2ecf20Sopenharmony_ci	OP_TX_STOP,
1078c2ecf20Sopenharmony_ci	OP_TX_TO_RX,
1088c2ecf20Sopenharmony_ci	OP_RX,
1098c2ecf20Sopenharmony_ci	OP_RX_STOP,
1108c2ecf20Sopenharmony_ci	OP_RX_STOP_DATA,
1118c2ecf20Sopenharmony_ci};
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistruct sh_mobile_i2c_data {
1148c2ecf20Sopenharmony_ci	struct device *dev;
1158c2ecf20Sopenharmony_ci	void __iomem *reg;
1168c2ecf20Sopenharmony_ci	struct i2c_adapter adap;
1178c2ecf20Sopenharmony_ci	unsigned long bus_speed;
1188c2ecf20Sopenharmony_ci	unsigned int clks_per_count;
1198c2ecf20Sopenharmony_ci	struct clk *clk;
1208c2ecf20Sopenharmony_ci	u_int8_t icic;
1218c2ecf20Sopenharmony_ci	u_int8_t flags;
1228c2ecf20Sopenharmony_ci	u_int16_t iccl;
1238c2ecf20Sopenharmony_ci	u_int16_t icch;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	spinlock_t lock;
1268c2ecf20Sopenharmony_ci	wait_queue_head_t wait;
1278c2ecf20Sopenharmony_ci	struct i2c_msg *msg;
1288c2ecf20Sopenharmony_ci	int pos;
1298c2ecf20Sopenharmony_ci	int sr;
1308c2ecf20Sopenharmony_ci	bool send_stop;
1318c2ecf20Sopenharmony_ci	bool stop_after_dma;
1328c2ecf20Sopenharmony_ci	bool atomic_xfer;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	struct resource *res;
1358c2ecf20Sopenharmony_ci	struct dma_chan *dma_tx;
1368c2ecf20Sopenharmony_ci	struct dma_chan *dma_rx;
1378c2ecf20Sopenharmony_ci	struct scatterlist sg;
1388c2ecf20Sopenharmony_ci	enum dma_data_direction dma_direction;
1398c2ecf20Sopenharmony_ci	u8 *dma_buf;
1408c2ecf20Sopenharmony_ci};
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistruct sh_mobile_dt_config {
1438c2ecf20Sopenharmony_ci	int clks_per_count;
1448c2ecf20Sopenharmony_ci	int (*setup)(struct sh_mobile_i2c_data *pd);
1458c2ecf20Sopenharmony_ci};
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci#define IIC_FLAG_HAS_ICIC67	(1 << 0)
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci/* Register offsets */
1508c2ecf20Sopenharmony_ci#define ICDR			0x00
1518c2ecf20Sopenharmony_ci#define ICCR			0x04
1528c2ecf20Sopenharmony_ci#define ICSR			0x08
1538c2ecf20Sopenharmony_ci#define ICIC			0x0c
1548c2ecf20Sopenharmony_ci#define ICCL			0x10
1558c2ecf20Sopenharmony_ci#define ICCH			0x14
1568c2ecf20Sopenharmony_ci#define ICSTART			0x70
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci/* Register bits */
1598c2ecf20Sopenharmony_ci#define ICCR_ICE		0x80
1608c2ecf20Sopenharmony_ci#define ICCR_RACK		0x40
1618c2ecf20Sopenharmony_ci#define ICCR_TRS		0x10
1628c2ecf20Sopenharmony_ci#define ICCR_BBSY		0x04
1638c2ecf20Sopenharmony_ci#define ICCR_SCP		0x01
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci#define ICSR_SCLM		0x80
1668c2ecf20Sopenharmony_ci#define ICSR_SDAM		0x40
1678c2ecf20Sopenharmony_ci#define SW_DONE			0x20
1688c2ecf20Sopenharmony_ci#define ICSR_BUSY		0x10
1698c2ecf20Sopenharmony_ci#define ICSR_AL			0x08
1708c2ecf20Sopenharmony_ci#define ICSR_TACK		0x04
1718c2ecf20Sopenharmony_ci#define ICSR_WAIT		0x02
1728c2ecf20Sopenharmony_ci#define ICSR_DTE		0x01
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci#define ICIC_ICCLB8		0x80
1758c2ecf20Sopenharmony_ci#define ICIC_ICCHB8		0x40
1768c2ecf20Sopenharmony_ci#define ICIC_TDMAE		0x20
1778c2ecf20Sopenharmony_ci#define ICIC_RDMAE		0x10
1788c2ecf20Sopenharmony_ci#define ICIC_ALE		0x08
1798c2ecf20Sopenharmony_ci#define ICIC_TACKE		0x04
1808c2ecf20Sopenharmony_ci#define ICIC_WAITE		0x02
1818c2ecf20Sopenharmony_ci#define ICIC_DTEE		0x01
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci#define ICSTART_ICSTART		0x10
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic void iic_wr(struct sh_mobile_i2c_data *pd, int offs, unsigned char data)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	if (offs == ICIC)
1888c2ecf20Sopenharmony_ci		data |= pd->icic;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	iowrite8(data, pd->reg + offs);
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_cistatic unsigned char iic_rd(struct sh_mobile_i2c_data *pd, int offs)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	return ioread8(pd->reg + offs);
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic void iic_set_clr(struct sh_mobile_i2c_data *pd, int offs,
1998c2ecf20Sopenharmony_ci			unsigned char set, unsigned char clr)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	iic_wr(pd, offs, (iic_rd(pd, offs) | set) & ~clr);
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic u32 sh_mobile_i2c_iccl(unsigned long count_khz, u32 tLOW, u32 tf)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	/*
2078c2ecf20Sopenharmony_ci	 * Conditional expression:
2088c2ecf20Sopenharmony_ci	 *   ICCL >= COUNT_CLK * (tLOW + tf)
2098c2ecf20Sopenharmony_ci	 *
2108c2ecf20Sopenharmony_ci	 * SH-Mobile IIC hardware starts counting the LOW period of
2118c2ecf20Sopenharmony_ci	 * the SCL signal (tLOW) as soon as it pulls the SCL line.
2128c2ecf20Sopenharmony_ci	 * In order to meet the tLOW timing spec, we need to take into
2138c2ecf20Sopenharmony_ci	 * account the fall time of SCL signal (tf).  Default tf value
2148c2ecf20Sopenharmony_ci	 * should be 0.3 us, for safety.
2158c2ecf20Sopenharmony_ci	 */
2168c2ecf20Sopenharmony_ci	return (((count_khz * (tLOW + tf)) + 5000) / 10000);
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic u32 sh_mobile_i2c_icch(unsigned long count_khz, u32 tHIGH, u32 tf)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	/*
2228c2ecf20Sopenharmony_ci	 * Conditional expression:
2238c2ecf20Sopenharmony_ci	 *   ICCH >= COUNT_CLK * (tHIGH + tf)
2248c2ecf20Sopenharmony_ci	 *
2258c2ecf20Sopenharmony_ci	 * SH-Mobile IIC hardware is aware of SCL transition period 'tr',
2268c2ecf20Sopenharmony_ci	 * and can ignore it.  SH-Mobile IIC controller starts counting
2278c2ecf20Sopenharmony_ci	 * the HIGH period of the SCL signal (tHIGH) after the SCL input
2288c2ecf20Sopenharmony_ci	 * voltage increases at VIH.
2298c2ecf20Sopenharmony_ci	 *
2308c2ecf20Sopenharmony_ci	 * Afterward it turned out calculating ICCH using only tHIGH spec
2318c2ecf20Sopenharmony_ci	 * will result in violation of the tHD;STA timing spec.  We need
2328c2ecf20Sopenharmony_ci	 * to take into account the fall time of SDA signal (tf) at START
2338c2ecf20Sopenharmony_ci	 * condition, in order to meet both tHIGH and tHD;STA specs.
2348c2ecf20Sopenharmony_ci	 */
2358c2ecf20Sopenharmony_ci	return (((count_khz * (tHIGH + tf)) + 5000) / 10000);
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic int sh_mobile_i2c_check_timing(struct sh_mobile_i2c_data *pd)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	u16 max_val = pd->flags & IIC_FLAG_HAS_ICIC67 ? 0x1ff : 0xff;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	if (pd->iccl > max_val || pd->icch > max_val) {
2438c2ecf20Sopenharmony_ci		dev_err(pd->dev, "timing values out of range: L/H=0x%x/0x%x\n",
2448c2ecf20Sopenharmony_ci			pd->iccl, pd->icch);
2458c2ecf20Sopenharmony_ci		return -EINVAL;
2468c2ecf20Sopenharmony_ci	}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	/* one more bit of ICCL in ICIC */
2498c2ecf20Sopenharmony_ci	if (pd->iccl & 0x100)
2508c2ecf20Sopenharmony_ci		pd->icic |= ICIC_ICCLB8;
2518c2ecf20Sopenharmony_ci	else
2528c2ecf20Sopenharmony_ci		pd->icic &= ~ICIC_ICCLB8;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	/* one more bit of ICCH in ICIC */
2558c2ecf20Sopenharmony_ci	if (pd->icch & 0x100)
2568c2ecf20Sopenharmony_ci		pd->icic |= ICIC_ICCHB8;
2578c2ecf20Sopenharmony_ci	else
2588c2ecf20Sopenharmony_ci		pd->icic &= ~ICIC_ICCHB8;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	dev_dbg(pd->dev, "timing values: L/H=0x%x/0x%x\n", pd->iccl, pd->icch);
2618c2ecf20Sopenharmony_ci	return 0;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cistatic int sh_mobile_i2c_init(struct sh_mobile_i2c_data *pd)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	unsigned long i2c_clk_khz;
2678c2ecf20Sopenharmony_ci	u32 tHIGH, tLOW, tf;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	i2c_clk_khz = clk_get_rate(pd->clk) / 1000 / pd->clks_per_count;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	if (pd->bus_speed == I2C_MAX_STANDARD_MODE_FREQ) {
2728c2ecf20Sopenharmony_ci		tLOW	= 47;	/* tLOW = 4.7 us */
2738c2ecf20Sopenharmony_ci		tHIGH	= 40;	/* tHD;STA = tHIGH = 4.0 us */
2748c2ecf20Sopenharmony_ci		tf	= 3;	/* tf = 0.3 us */
2758c2ecf20Sopenharmony_ci	} else if (pd->bus_speed == I2C_MAX_FAST_MODE_FREQ) {
2768c2ecf20Sopenharmony_ci		tLOW	= 13;	/* tLOW = 1.3 us */
2778c2ecf20Sopenharmony_ci		tHIGH	= 6;	/* tHD;STA = tHIGH = 0.6 us */
2788c2ecf20Sopenharmony_ci		tf	= 3;	/* tf = 0.3 us */
2798c2ecf20Sopenharmony_ci	} else {
2808c2ecf20Sopenharmony_ci		dev_err(pd->dev, "unrecognized bus speed %lu Hz\n",
2818c2ecf20Sopenharmony_ci			pd->bus_speed);
2828c2ecf20Sopenharmony_ci		return -EINVAL;
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	pd->iccl = sh_mobile_i2c_iccl(i2c_clk_khz, tLOW, tf);
2868c2ecf20Sopenharmony_ci	pd->icch = sh_mobile_i2c_icch(i2c_clk_khz, tHIGH, tf);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	return sh_mobile_i2c_check_timing(pd);
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic int sh_mobile_i2c_v2_init(struct sh_mobile_i2c_data *pd)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	unsigned long clks_per_cycle;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	/* L = 5, H = 4, L + H = 9 */
2968c2ecf20Sopenharmony_ci	clks_per_cycle = clk_get_rate(pd->clk) / pd->bus_speed;
2978c2ecf20Sopenharmony_ci	pd->iccl = DIV_ROUND_UP(clks_per_cycle * 5 / 9 - 1, pd->clks_per_count);
2988c2ecf20Sopenharmony_ci	pd->icch = DIV_ROUND_UP(clks_per_cycle * 4 / 9 - 5, pd->clks_per_count);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	return sh_mobile_i2c_check_timing(pd);
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic unsigned char i2c_op(struct sh_mobile_i2c_data *pd, enum sh_mobile_i2c_op op)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	unsigned char ret = 0;
3068c2ecf20Sopenharmony_ci	unsigned long flags;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	dev_dbg(pd->dev, "op %d\n", op);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	spin_lock_irqsave(&pd->lock, flags);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	switch (op) {
3138c2ecf20Sopenharmony_ci	case OP_START: /* issue start and trigger DTE interrupt */
3148c2ecf20Sopenharmony_ci		iic_wr(pd, ICCR, ICCR_ICE | ICCR_TRS | ICCR_BBSY);
3158c2ecf20Sopenharmony_ci		break;
3168c2ecf20Sopenharmony_ci	case OP_TX_FIRST: /* disable DTE interrupt and write client address */
3178c2ecf20Sopenharmony_ci		iic_wr(pd, ICIC, ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
3188c2ecf20Sopenharmony_ci		iic_wr(pd, ICDR, i2c_8bit_addr_from_msg(pd->msg));
3198c2ecf20Sopenharmony_ci		break;
3208c2ecf20Sopenharmony_ci	case OP_TX: /* write data */
3218c2ecf20Sopenharmony_ci		iic_wr(pd, ICDR, pd->msg->buf[pd->pos]);
3228c2ecf20Sopenharmony_ci		break;
3238c2ecf20Sopenharmony_ci	case OP_TX_STOP: /* issue a stop (or rep_start) */
3248c2ecf20Sopenharmony_ci		iic_wr(pd, ICCR, pd->send_stop ? ICCR_ICE | ICCR_TRS
3258c2ecf20Sopenharmony_ci					       : ICCR_ICE | ICCR_TRS | ICCR_BBSY);
3268c2ecf20Sopenharmony_ci		break;
3278c2ecf20Sopenharmony_ci	case OP_TX_TO_RX: /* select read mode */
3288c2ecf20Sopenharmony_ci		iic_wr(pd, ICCR, ICCR_ICE | ICCR_SCP);
3298c2ecf20Sopenharmony_ci		break;
3308c2ecf20Sopenharmony_ci	case OP_RX: /* just read data */
3318c2ecf20Sopenharmony_ci		ret = iic_rd(pd, ICDR);
3328c2ecf20Sopenharmony_ci		break;
3338c2ecf20Sopenharmony_ci	case OP_RX_STOP: /* enable DTE interrupt, issue stop */
3348c2ecf20Sopenharmony_ci		if (!pd->atomic_xfer)
3358c2ecf20Sopenharmony_ci			iic_wr(pd, ICIC,
3368c2ecf20Sopenharmony_ci			       ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
3378c2ecf20Sopenharmony_ci		iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK);
3388c2ecf20Sopenharmony_ci		break;
3398c2ecf20Sopenharmony_ci	case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */
3408c2ecf20Sopenharmony_ci		if (!pd->atomic_xfer)
3418c2ecf20Sopenharmony_ci			iic_wr(pd, ICIC,
3428c2ecf20Sopenharmony_ci			       ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
3438c2ecf20Sopenharmony_ci		ret = iic_rd(pd, ICDR);
3448c2ecf20Sopenharmony_ci		iic_wr(pd, ICCR, ICCR_ICE | ICCR_RACK);
3458c2ecf20Sopenharmony_ci		break;
3468c2ecf20Sopenharmony_ci	}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&pd->lock, flags);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	dev_dbg(pd->dev, "op %d, data out 0x%02x\n", op, ret);
3518c2ecf20Sopenharmony_ci	return ret;
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	if (pd->pos == pd->msg->len) {
3578c2ecf20Sopenharmony_ci		i2c_op(pd, OP_TX_STOP);
3588c2ecf20Sopenharmony_ci		return 1;
3598c2ecf20Sopenharmony_ci	}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	if (pd->pos == -1)
3628c2ecf20Sopenharmony_ci		i2c_op(pd, OP_TX_FIRST);
3638c2ecf20Sopenharmony_ci	else
3648c2ecf20Sopenharmony_ci		i2c_op(pd, OP_TX);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	pd->pos++;
3678c2ecf20Sopenharmony_ci	return 0;
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_cistatic int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	int real_pos;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	/* switch from TX (address) to RX (data) adds two interrupts */
3758c2ecf20Sopenharmony_ci	real_pos = pd->pos - 2;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	if (pd->pos == -1) {
3788c2ecf20Sopenharmony_ci		i2c_op(pd, OP_TX_FIRST);
3798c2ecf20Sopenharmony_ci	} else if (pd->pos == 0) {
3808c2ecf20Sopenharmony_ci		i2c_op(pd, OP_TX_TO_RX);
3818c2ecf20Sopenharmony_ci	} else if (pd->pos == pd->msg->len) {
3828c2ecf20Sopenharmony_ci		if (pd->stop_after_dma) {
3838c2ecf20Sopenharmony_ci			/* Simulate PIO end condition after DMA transfer */
3848c2ecf20Sopenharmony_ci			i2c_op(pd, OP_RX_STOP);
3858c2ecf20Sopenharmony_ci			pd->pos++;
3868c2ecf20Sopenharmony_ci			goto done;
3878c2ecf20Sopenharmony_ci		}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci		if (real_pos < 0)
3908c2ecf20Sopenharmony_ci			i2c_op(pd, OP_RX_STOP);
3918c2ecf20Sopenharmony_ci		else
3928c2ecf20Sopenharmony_ci			pd->msg->buf[real_pos] = i2c_op(pd, OP_RX_STOP_DATA);
3938c2ecf20Sopenharmony_ci	} else if (real_pos >= 0) {
3948c2ecf20Sopenharmony_ci		pd->msg->buf[real_pos] = i2c_op(pd, OP_RX);
3958c2ecf20Sopenharmony_ci	}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci done:
3988c2ecf20Sopenharmony_ci	pd->pos++;
3998c2ecf20Sopenharmony_ci	return pd->pos == (pd->msg->len + 2);
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
4038c2ecf20Sopenharmony_ci{
4048c2ecf20Sopenharmony_ci	struct sh_mobile_i2c_data *pd = dev_id;
4058c2ecf20Sopenharmony_ci	unsigned char sr;
4068c2ecf20Sopenharmony_ci	int wakeup = 0;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	sr = iic_rd(pd, ICSR);
4098c2ecf20Sopenharmony_ci	pd->sr |= sr; /* remember state */
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr,
4128c2ecf20Sopenharmony_ci	       (pd->msg->flags & I2C_M_RD) ? "read" : "write",
4138c2ecf20Sopenharmony_ci	       pd->pos, pd->msg->len);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	/* Kick off TxDMA after preface was done */
4168c2ecf20Sopenharmony_ci	if (pd->dma_direction == DMA_TO_DEVICE && pd->pos == 0)
4178c2ecf20Sopenharmony_ci		iic_set_clr(pd, ICIC, ICIC_TDMAE, 0);
4188c2ecf20Sopenharmony_ci	else if (sr & (ICSR_AL | ICSR_TACK))
4198c2ecf20Sopenharmony_ci		/* don't interrupt transaction - continue to issue stop */
4208c2ecf20Sopenharmony_ci		iic_wr(pd, ICSR, sr & ~(ICSR_AL | ICSR_TACK));
4218c2ecf20Sopenharmony_ci	else if (pd->msg->flags & I2C_M_RD)
4228c2ecf20Sopenharmony_ci		wakeup = sh_mobile_i2c_isr_rx(pd);
4238c2ecf20Sopenharmony_ci	else
4248c2ecf20Sopenharmony_ci		wakeup = sh_mobile_i2c_isr_tx(pd);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	/* Kick off RxDMA after preface was done */
4278c2ecf20Sopenharmony_ci	if (pd->dma_direction == DMA_FROM_DEVICE && pd->pos == 1)
4288c2ecf20Sopenharmony_ci		iic_set_clr(pd, ICIC, ICIC_RDMAE, 0);
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */
4318c2ecf20Sopenharmony_ci		iic_wr(pd, ICSR, sr & ~ICSR_WAIT);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	if (wakeup) {
4348c2ecf20Sopenharmony_ci		pd->sr |= SW_DONE;
4358c2ecf20Sopenharmony_ci		if (!pd->atomic_xfer)
4368c2ecf20Sopenharmony_ci			wake_up(&pd->wait);
4378c2ecf20Sopenharmony_ci	}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	/* defeat write posting to avoid spurious WAIT interrupts */
4408c2ecf20Sopenharmony_ci	iic_rd(pd, ICSR);
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
4438c2ecf20Sopenharmony_ci}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_cistatic void sh_mobile_i2c_dma_unmap(struct sh_mobile_i2c_data *pd)
4468c2ecf20Sopenharmony_ci{
4478c2ecf20Sopenharmony_ci	struct dma_chan *chan = pd->dma_direction == DMA_FROM_DEVICE
4488c2ecf20Sopenharmony_ci				? pd->dma_rx : pd->dma_tx;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	dma_unmap_single(chan->device->dev, sg_dma_address(&pd->sg),
4518c2ecf20Sopenharmony_ci			 pd->msg->len, pd->dma_direction);
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	pd->dma_direction = DMA_NONE;
4548c2ecf20Sopenharmony_ci}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_cistatic void sh_mobile_i2c_cleanup_dma(struct sh_mobile_i2c_data *pd)
4578c2ecf20Sopenharmony_ci{
4588c2ecf20Sopenharmony_ci	if (pd->dma_direction == DMA_NONE)
4598c2ecf20Sopenharmony_ci		return;
4608c2ecf20Sopenharmony_ci	else if (pd->dma_direction == DMA_FROM_DEVICE)
4618c2ecf20Sopenharmony_ci		dmaengine_terminate_all(pd->dma_rx);
4628c2ecf20Sopenharmony_ci	else if (pd->dma_direction == DMA_TO_DEVICE)
4638c2ecf20Sopenharmony_ci		dmaengine_terminate_all(pd->dma_tx);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	sh_mobile_i2c_dma_unmap(pd);
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_cistatic void sh_mobile_i2c_dma_callback(void *data)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	struct sh_mobile_i2c_data *pd = data;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	sh_mobile_i2c_dma_unmap(pd);
4738c2ecf20Sopenharmony_ci	pd->pos = pd->msg->len;
4748c2ecf20Sopenharmony_ci	pd->stop_after_dma = true;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE);
4778c2ecf20Sopenharmony_ci}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_cistatic struct dma_chan *sh_mobile_i2c_request_dma_chan(struct device *dev,
4808c2ecf20Sopenharmony_ci				enum dma_transfer_direction dir, dma_addr_t port_addr)
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	struct dma_chan *chan;
4838c2ecf20Sopenharmony_ci	struct dma_slave_config cfg;
4848c2ecf20Sopenharmony_ci	char *chan_name = dir == DMA_MEM_TO_DEV ? "tx" : "rx";
4858c2ecf20Sopenharmony_ci	int ret;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	chan = dma_request_chan(dev, chan_name);
4888c2ecf20Sopenharmony_ci	if (IS_ERR(chan)) {
4898c2ecf20Sopenharmony_ci		dev_dbg(dev, "request_channel failed for %s (%ld)\n", chan_name,
4908c2ecf20Sopenharmony_ci			PTR_ERR(chan));
4918c2ecf20Sopenharmony_ci		return chan;
4928c2ecf20Sopenharmony_ci	}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	memset(&cfg, 0, sizeof(cfg));
4958c2ecf20Sopenharmony_ci	cfg.direction = dir;
4968c2ecf20Sopenharmony_ci	if (dir == DMA_MEM_TO_DEV) {
4978c2ecf20Sopenharmony_ci		cfg.dst_addr = port_addr;
4988c2ecf20Sopenharmony_ci		cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
4998c2ecf20Sopenharmony_ci	} else {
5008c2ecf20Sopenharmony_ci		cfg.src_addr = port_addr;
5018c2ecf20Sopenharmony_ci		cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
5028c2ecf20Sopenharmony_ci	}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	ret = dmaengine_slave_config(chan, &cfg);
5058c2ecf20Sopenharmony_ci	if (ret) {
5068c2ecf20Sopenharmony_ci		dev_dbg(dev, "slave_config failed for %s (%d)\n", chan_name, ret);
5078c2ecf20Sopenharmony_ci		dma_release_channel(chan);
5088c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
5098c2ecf20Sopenharmony_ci	}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	dev_dbg(dev, "got DMA channel for %s\n", chan_name);
5128c2ecf20Sopenharmony_ci	return chan;
5138c2ecf20Sopenharmony_ci}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_cistatic void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd)
5168c2ecf20Sopenharmony_ci{
5178c2ecf20Sopenharmony_ci	bool read = pd->msg->flags & I2C_M_RD;
5188c2ecf20Sopenharmony_ci	enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
5198c2ecf20Sopenharmony_ci	struct dma_chan *chan = read ? pd->dma_rx : pd->dma_tx;
5208c2ecf20Sopenharmony_ci	struct dma_async_tx_descriptor *txdesc;
5218c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
5228c2ecf20Sopenharmony_ci	dma_cookie_t cookie;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	if (PTR_ERR(chan) == -EPROBE_DEFER) {
5258c2ecf20Sopenharmony_ci		if (read)
5268c2ecf20Sopenharmony_ci			chan = pd->dma_rx = sh_mobile_i2c_request_dma_chan(pd->dev, DMA_DEV_TO_MEM,
5278c2ecf20Sopenharmony_ci									   pd->res->start + ICDR);
5288c2ecf20Sopenharmony_ci		else
5298c2ecf20Sopenharmony_ci			chan = pd->dma_tx = sh_mobile_i2c_request_dma_chan(pd->dev, DMA_MEM_TO_DEV,
5308c2ecf20Sopenharmony_ci									   pd->res->start + ICDR);
5318c2ecf20Sopenharmony_ci	}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	if (IS_ERR(chan))
5348c2ecf20Sopenharmony_ci		return;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	dma_addr = dma_map_single(chan->device->dev, pd->dma_buf, pd->msg->len, dir);
5378c2ecf20Sopenharmony_ci	if (dma_mapping_error(chan->device->dev, dma_addr)) {
5388c2ecf20Sopenharmony_ci		dev_dbg(pd->dev, "dma map failed, using PIO\n");
5398c2ecf20Sopenharmony_ci		return;
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	sg_dma_len(&pd->sg) = pd->msg->len;
5438c2ecf20Sopenharmony_ci	sg_dma_address(&pd->sg) = dma_addr;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	pd->dma_direction = dir;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	txdesc = dmaengine_prep_slave_sg(chan, &pd->sg, 1,
5488c2ecf20Sopenharmony_ci					 read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV,
5498c2ecf20Sopenharmony_ci					 DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
5508c2ecf20Sopenharmony_ci	if (!txdesc) {
5518c2ecf20Sopenharmony_ci		dev_dbg(pd->dev, "dma prep slave sg failed, using PIO\n");
5528c2ecf20Sopenharmony_ci		sh_mobile_i2c_cleanup_dma(pd);
5538c2ecf20Sopenharmony_ci		return;
5548c2ecf20Sopenharmony_ci	}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	txdesc->callback = sh_mobile_i2c_dma_callback;
5578c2ecf20Sopenharmony_ci	txdesc->callback_param = pd;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	cookie = dmaengine_submit(txdesc);
5608c2ecf20Sopenharmony_ci	if (dma_submit_error(cookie)) {
5618c2ecf20Sopenharmony_ci		dev_dbg(pd->dev, "submitting dma failed, using PIO\n");
5628c2ecf20Sopenharmony_ci		sh_mobile_i2c_cleanup_dma(pd);
5638c2ecf20Sopenharmony_ci		return;
5648c2ecf20Sopenharmony_ci	}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	dma_async_issue_pending(chan);
5678c2ecf20Sopenharmony_ci}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_cistatic void start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg,
5708c2ecf20Sopenharmony_ci		     bool do_init)
5718c2ecf20Sopenharmony_ci{
5728c2ecf20Sopenharmony_ci	if (do_init) {
5738c2ecf20Sopenharmony_ci		/* Initialize channel registers */
5748c2ecf20Sopenharmony_ci		iic_wr(pd, ICCR, ICCR_SCP);
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci		/* Enable channel and configure rx ack */
5778c2ecf20Sopenharmony_ci		iic_wr(pd, ICCR, ICCR_ICE | ICCR_SCP);
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci		/* Set the clock */
5808c2ecf20Sopenharmony_ci		iic_wr(pd, ICCL, pd->iccl & 0xff);
5818c2ecf20Sopenharmony_ci		iic_wr(pd, ICCH, pd->icch & 0xff);
5828c2ecf20Sopenharmony_ci	}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	pd->msg = usr_msg;
5858c2ecf20Sopenharmony_ci	pd->pos = -1;
5868c2ecf20Sopenharmony_ci	pd->sr = 0;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	if (pd->atomic_xfer)
5898c2ecf20Sopenharmony_ci		return;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	pd->dma_buf = i2c_get_dma_safe_msg_buf(pd->msg, 8);
5928c2ecf20Sopenharmony_ci	if (pd->dma_buf)
5938c2ecf20Sopenharmony_ci		sh_mobile_i2c_xfer_dma(pd);
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	/* Enable all interrupts to begin with */
5968c2ecf20Sopenharmony_ci	iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
5978c2ecf20Sopenharmony_ci}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_cistatic int poll_dte(struct sh_mobile_i2c_data *pd)
6008c2ecf20Sopenharmony_ci{
6018c2ecf20Sopenharmony_ci	int i;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	for (i = 1000; i; i--) {
6048c2ecf20Sopenharmony_ci		u_int8_t val = iic_rd(pd, ICSR);
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci		if (val & ICSR_DTE)
6078c2ecf20Sopenharmony_ci			break;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci		if (val & ICSR_TACK)
6108c2ecf20Sopenharmony_ci			return -ENXIO;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci		udelay(10);
6138c2ecf20Sopenharmony_ci	}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	return i ? 0 : -ETIMEDOUT;
6168c2ecf20Sopenharmony_ci}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_cistatic int poll_busy(struct sh_mobile_i2c_data *pd)
6198c2ecf20Sopenharmony_ci{
6208c2ecf20Sopenharmony_ci	int i;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	for (i = 1000; i; i--) {
6238c2ecf20Sopenharmony_ci		u_int8_t val = iic_rd(pd, ICSR);
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci		dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr);
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci		/* the interrupt handler may wake us up before the
6288c2ecf20Sopenharmony_ci		 * transfer is finished, so poll the hardware
6298c2ecf20Sopenharmony_ci		 * until we're done.
6308c2ecf20Sopenharmony_ci		 */
6318c2ecf20Sopenharmony_ci		if (!(val & ICSR_BUSY)) {
6328c2ecf20Sopenharmony_ci			/* handle missing acknowledge and arbitration lost */
6338c2ecf20Sopenharmony_ci			val |= pd->sr;
6348c2ecf20Sopenharmony_ci			if (val & ICSR_TACK)
6358c2ecf20Sopenharmony_ci				return -ENXIO;
6368c2ecf20Sopenharmony_ci			if (val & ICSR_AL)
6378c2ecf20Sopenharmony_ci				return -EAGAIN;
6388c2ecf20Sopenharmony_ci			break;
6398c2ecf20Sopenharmony_ci		}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci		udelay(10);
6428c2ecf20Sopenharmony_ci	}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	return i ? 0 : -ETIMEDOUT;
6458c2ecf20Sopenharmony_ci}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_cistatic int sh_mobile_xfer(struct sh_mobile_i2c_data *pd,
6488c2ecf20Sopenharmony_ci			 struct i2c_msg *msgs, int num)
6498c2ecf20Sopenharmony_ci{
6508c2ecf20Sopenharmony_ci	struct i2c_msg	*msg;
6518c2ecf20Sopenharmony_ci	int err = 0;
6528c2ecf20Sopenharmony_ci	int i;
6538c2ecf20Sopenharmony_ci	long time_left;
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	/* Wake up device and enable clock */
6568c2ecf20Sopenharmony_ci	pm_runtime_get_sync(pd->dev);
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	/* Process all messages */
6598c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++) {
6608c2ecf20Sopenharmony_ci		bool do_start = pd->send_stop || !i;
6618c2ecf20Sopenharmony_ci		msg = &msgs[i];
6628c2ecf20Sopenharmony_ci		pd->send_stop = i == num - 1 || msg->flags & I2C_M_STOP;
6638c2ecf20Sopenharmony_ci		pd->stop_after_dma = false;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci		start_ch(pd, msg, do_start);
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci		if (do_start)
6688c2ecf20Sopenharmony_ci			i2c_op(pd, OP_START);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci		if (pd->atomic_xfer) {
6718c2ecf20Sopenharmony_ci			unsigned long j = jiffies + pd->adap.timeout;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci			time_left = time_before_eq(jiffies, j);
6748c2ecf20Sopenharmony_ci			while (time_left &&
6758c2ecf20Sopenharmony_ci			       !(pd->sr & (ICSR_TACK | SW_DONE))) {
6768c2ecf20Sopenharmony_ci				unsigned char sr = iic_rd(pd, ICSR);
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci				if (sr & (ICSR_AL   | ICSR_TACK |
6798c2ecf20Sopenharmony_ci					  ICSR_WAIT | ICSR_DTE)) {
6808c2ecf20Sopenharmony_ci					sh_mobile_i2c_isr(0, pd);
6818c2ecf20Sopenharmony_ci					udelay(150);
6828c2ecf20Sopenharmony_ci				} else {
6838c2ecf20Sopenharmony_ci					cpu_relax();
6848c2ecf20Sopenharmony_ci				}
6858c2ecf20Sopenharmony_ci				time_left = time_before_eq(jiffies, j);
6868c2ecf20Sopenharmony_ci			}
6878c2ecf20Sopenharmony_ci		} else {
6888c2ecf20Sopenharmony_ci			/* The interrupt handler takes care of the rest... */
6898c2ecf20Sopenharmony_ci			time_left = wait_event_timeout(pd->wait,
6908c2ecf20Sopenharmony_ci					pd->sr & (ICSR_TACK | SW_DONE),
6918c2ecf20Sopenharmony_ci					pd->adap.timeout);
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci			/* 'stop_after_dma' tells if DMA xfer was complete */
6948c2ecf20Sopenharmony_ci			i2c_put_dma_safe_msg_buf(pd->dma_buf, pd->msg,
6958c2ecf20Sopenharmony_ci						 pd->stop_after_dma);
6968c2ecf20Sopenharmony_ci		}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci		if (!time_left) {
6998c2ecf20Sopenharmony_ci			dev_err(pd->dev, "Transfer request timed out\n");
7008c2ecf20Sopenharmony_ci			if (pd->dma_direction != DMA_NONE)
7018c2ecf20Sopenharmony_ci				sh_mobile_i2c_cleanup_dma(pd);
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci			err = -ETIMEDOUT;
7048c2ecf20Sopenharmony_ci			break;
7058c2ecf20Sopenharmony_ci		}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci		if (pd->send_stop)
7088c2ecf20Sopenharmony_ci			err = poll_busy(pd);
7098c2ecf20Sopenharmony_ci		else
7108c2ecf20Sopenharmony_ci			err = poll_dte(pd);
7118c2ecf20Sopenharmony_ci		if (err < 0)
7128c2ecf20Sopenharmony_ci			break;
7138c2ecf20Sopenharmony_ci	}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	/* Disable channel */
7168c2ecf20Sopenharmony_ci	iic_wr(pd, ICCR, ICCR_SCP);
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	/* Disable clock and mark device as idle */
7198c2ecf20Sopenharmony_ci	pm_runtime_put_sync(pd->dev);
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	return err ?: num;
7228c2ecf20Sopenharmony_ci}
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_cistatic int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
7258c2ecf20Sopenharmony_ci			      struct i2c_msg *msgs,
7268c2ecf20Sopenharmony_ci			      int num)
7278c2ecf20Sopenharmony_ci{
7288c2ecf20Sopenharmony_ci	struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	pd->atomic_xfer = false;
7318c2ecf20Sopenharmony_ci	return sh_mobile_xfer(pd, msgs, num);
7328c2ecf20Sopenharmony_ci}
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_cistatic int sh_mobile_i2c_xfer_atomic(struct i2c_adapter *adapter,
7358c2ecf20Sopenharmony_ci				     struct i2c_msg *msgs,
7368c2ecf20Sopenharmony_ci				     int num)
7378c2ecf20Sopenharmony_ci{
7388c2ecf20Sopenharmony_ci	struct sh_mobile_i2c_data *pd = i2c_get_adapdata(adapter);
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	pd->atomic_xfer = true;
7418c2ecf20Sopenharmony_ci	return sh_mobile_xfer(pd, msgs, num);
7428c2ecf20Sopenharmony_ci}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_cistatic u32 sh_mobile_i2c_func(struct i2c_adapter *adapter)
7458c2ecf20Sopenharmony_ci{
7468c2ecf20Sopenharmony_ci	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
7478c2ecf20Sopenharmony_ci}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_cistatic const struct i2c_algorithm sh_mobile_i2c_algorithm = {
7508c2ecf20Sopenharmony_ci	.functionality = sh_mobile_i2c_func,
7518c2ecf20Sopenharmony_ci	.master_xfer = sh_mobile_i2c_xfer,
7528c2ecf20Sopenharmony_ci	.master_xfer_atomic = sh_mobile_i2c_xfer_atomic,
7538c2ecf20Sopenharmony_ci};
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_cistatic const struct i2c_adapter_quirks sh_mobile_i2c_quirks = {
7568c2ecf20Sopenharmony_ci	.flags = I2C_AQ_NO_ZERO_LEN_READ,
7578c2ecf20Sopenharmony_ci};
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci/*
7608c2ecf20Sopenharmony_ci * r8a7740 has an errata regarding I2C I/O pad reset needing this workaround.
7618c2ecf20Sopenharmony_ci */
7628c2ecf20Sopenharmony_cistatic int sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd)
7638c2ecf20Sopenharmony_ci{
7648c2ecf20Sopenharmony_ci	iic_set_clr(pd, ICCR, ICCR_ICE, 0);
7658c2ecf20Sopenharmony_ci	iic_rd(pd, ICCR); /* dummy read */
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	iic_set_clr(pd, ICSTART, ICSTART_ICSTART, 0);
7688c2ecf20Sopenharmony_ci	iic_rd(pd, ICSTART); /* dummy read */
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	udelay(10);
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	iic_wr(pd, ICCR, ICCR_SCP);
7738c2ecf20Sopenharmony_ci	iic_wr(pd, ICSTART, 0);
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	udelay(10);
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	iic_wr(pd, ICCR, ICCR_TRS);
7788c2ecf20Sopenharmony_ci	udelay(10);
7798c2ecf20Sopenharmony_ci	iic_wr(pd, ICCR, 0);
7808c2ecf20Sopenharmony_ci	udelay(10);
7818c2ecf20Sopenharmony_ci	iic_wr(pd, ICCR, ICCR_TRS);
7828c2ecf20Sopenharmony_ci	udelay(10);
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	return sh_mobile_i2c_init(pd);
7858c2ecf20Sopenharmony_ci}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_cistatic const struct sh_mobile_dt_config default_dt_config = {
7888c2ecf20Sopenharmony_ci	.clks_per_count = 1,
7898c2ecf20Sopenharmony_ci	.setup = sh_mobile_i2c_init,
7908c2ecf20Sopenharmony_ci};
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_cistatic const struct sh_mobile_dt_config fast_clock_dt_config = {
7938c2ecf20Sopenharmony_ci	.clks_per_count = 2,
7948c2ecf20Sopenharmony_ci	.setup = sh_mobile_i2c_init,
7958c2ecf20Sopenharmony_ci};
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_cistatic const struct sh_mobile_dt_config v2_freq_calc_dt_config = {
7988c2ecf20Sopenharmony_ci	.clks_per_count = 2,
7998c2ecf20Sopenharmony_ci	.setup = sh_mobile_i2c_v2_init,
8008c2ecf20Sopenharmony_ci};
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_cistatic const struct sh_mobile_dt_config r8a7740_dt_config = {
8038c2ecf20Sopenharmony_ci	.clks_per_count = 1,
8048c2ecf20Sopenharmony_ci	.setup = sh_mobile_i2c_r8a7740_workaround,
8058c2ecf20Sopenharmony_ci};
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_cistatic const struct of_device_id sh_mobile_i2c_dt_ids[] = {
8088c2ecf20Sopenharmony_ci	{ .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_dt_config },
8098c2ecf20Sopenharmony_ci	{ .compatible = "renesas,iic-r8a7740", .data = &r8a7740_dt_config },
8108c2ecf20Sopenharmony_ci	{ .compatible = "renesas,iic-r8a774c0", .data = &v2_freq_calc_dt_config },
8118c2ecf20Sopenharmony_ci	{ .compatible = "renesas,iic-r8a7790", .data = &v2_freq_calc_dt_config },
8128c2ecf20Sopenharmony_ci	{ .compatible = "renesas,iic-r8a7791", .data = &v2_freq_calc_dt_config },
8138c2ecf20Sopenharmony_ci	{ .compatible = "renesas,iic-r8a7792", .data = &v2_freq_calc_dt_config },
8148c2ecf20Sopenharmony_ci	{ .compatible = "renesas,iic-r8a7793", .data = &v2_freq_calc_dt_config },
8158c2ecf20Sopenharmony_ci	{ .compatible = "renesas,iic-r8a7794", .data = &v2_freq_calc_dt_config },
8168c2ecf20Sopenharmony_ci	{ .compatible = "renesas,iic-r8a7795", .data = &v2_freq_calc_dt_config },
8178c2ecf20Sopenharmony_ci	{ .compatible = "renesas,iic-r8a77990", .data = &v2_freq_calc_dt_config },
8188c2ecf20Sopenharmony_ci	{ .compatible = "renesas,iic-sh73a0", .data = &fast_clock_dt_config },
8198c2ecf20Sopenharmony_ci	{ .compatible = "renesas,rcar-gen2-iic", .data = &v2_freq_calc_dt_config },
8208c2ecf20Sopenharmony_ci	{ .compatible = "renesas,rcar-gen3-iic", .data = &v2_freq_calc_dt_config },
8218c2ecf20Sopenharmony_ci	{ .compatible = "renesas,rmobile-iic", .data = &default_dt_config },
8228c2ecf20Sopenharmony_ci	{},
8238c2ecf20Sopenharmony_ci};
8248c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sh_mobile_i2c_dt_ids);
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_cistatic void sh_mobile_i2c_release_dma(struct sh_mobile_i2c_data *pd)
8278c2ecf20Sopenharmony_ci{
8288c2ecf20Sopenharmony_ci	if (!IS_ERR(pd->dma_tx)) {
8298c2ecf20Sopenharmony_ci		dma_release_channel(pd->dma_tx);
8308c2ecf20Sopenharmony_ci		pd->dma_tx = ERR_PTR(-EPROBE_DEFER);
8318c2ecf20Sopenharmony_ci	}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	if (!IS_ERR(pd->dma_rx)) {
8348c2ecf20Sopenharmony_ci		dma_release_channel(pd->dma_rx);
8358c2ecf20Sopenharmony_ci		pd->dma_rx = ERR_PTR(-EPROBE_DEFER);
8368c2ecf20Sopenharmony_ci	}
8378c2ecf20Sopenharmony_ci}
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_cistatic int sh_mobile_i2c_hook_irqs(struct platform_device *dev, struct sh_mobile_i2c_data *pd)
8408c2ecf20Sopenharmony_ci{
8418c2ecf20Sopenharmony_ci	struct resource *res;
8428c2ecf20Sopenharmony_ci	resource_size_t n;
8438c2ecf20Sopenharmony_ci	int k = 0, ret;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) {
8468c2ecf20Sopenharmony_ci		for (n = res->start; n <= res->end; n++) {
8478c2ecf20Sopenharmony_ci			ret = devm_request_irq(&dev->dev, n, sh_mobile_i2c_isr,
8488c2ecf20Sopenharmony_ci					  0, dev_name(&dev->dev), pd);
8498c2ecf20Sopenharmony_ci			if (ret) {
8508c2ecf20Sopenharmony_ci				dev_err(&dev->dev, "cannot request IRQ %pa\n", &n);
8518c2ecf20Sopenharmony_ci				return ret;
8528c2ecf20Sopenharmony_ci			}
8538c2ecf20Sopenharmony_ci		}
8548c2ecf20Sopenharmony_ci		k++;
8558c2ecf20Sopenharmony_ci	}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	return k > 0 ? 0 : -ENOENT;
8588c2ecf20Sopenharmony_ci}
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_cistatic int sh_mobile_i2c_probe(struct platform_device *dev)
8618c2ecf20Sopenharmony_ci{
8628c2ecf20Sopenharmony_ci	struct sh_mobile_i2c_data *pd;
8638c2ecf20Sopenharmony_ci	struct i2c_adapter *adap;
8648c2ecf20Sopenharmony_ci	struct resource *res;
8658c2ecf20Sopenharmony_ci	const struct sh_mobile_dt_config *config;
8668c2ecf20Sopenharmony_ci	int ret;
8678c2ecf20Sopenharmony_ci	u32 bus_speed;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	pd = devm_kzalloc(&dev->dev, sizeof(struct sh_mobile_i2c_data), GFP_KERNEL);
8708c2ecf20Sopenharmony_ci	if (!pd)
8718c2ecf20Sopenharmony_ci		return -ENOMEM;
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	pd->clk = devm_clk_get(&dev->dev, NULL);
8748c2ecf20Sopenharmony_ci	if (IS_ERR(pd->clk)) {
8758c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "cannot get clock\n");
8768c2ecf20Sopenharmony_ci		return PTR_ERR(pd->clk);
8778c2ecf20Sopenharmony_ci	}
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	ret = sh_mobile_i2c_hook_irqs(dev, pd);
8808c2ecf20Sopenharmony_ci	if (ret)
8818c2ecf20Sopenharmony_ci		return ret;
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	pd->dev = &dev->dev;
8848c2ecf20Sopenharmony_ci	platform_set_drvdata(dev, pd);
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	pd->res = res;
8898c2ecf20Sopenharmony_ci	pd->reg = devm_ioremap_resource(&dev->dev, res);
8908c2ecf20Sopenharmony_ci	if (IS_ERR(pd->reg))
8918c2ecf20Sopenharmony_ci		return PTR_ERR(pd->reg);
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	ret = of_property_read_u32(dev->dev.of_node, "clock-frequency", &bus_speed);
8948c2ecf20Sopenharmony_ci	pd->bus_speed = (ret || !bus_speed) ? I2C_MAX_STANDARD_MODE_FREQ : bus_speed;
8958c2ecf20Sopenharmony_ci	pd->clks_per_count = 1;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	/* Newer variants come with two new bits in ICIC */
8988c2ecf20Sopenharmony_ci	if (resource_size(res) > 0x17)
8998c2ecf20Sopenharmony_ci		pd->flags |= IIC_FLAG_HAS_ICIC67;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	pm_runtime_enable(&dev->dev);
9028c2ecf20Sopenharmony_ci	pm_runtime_get_sync(&dev->dev);
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	config = of_device_get_match_data(&dev->dev);
9058c2ecf20Sopenharmony_ci	if (config) {
9068c2ecf20Sopenharmony_ci		pd->clks_per_count = config->clks_per_count;
9078c2ecf20Sopenharmony_ci		ret = config->setup(pd);
9088c2ecf20Sopenharmony_ci	} else {
9098c2ecf20Sopenharmony_ci		ret = sh_mobile_i2c_init(pd);
9108c2ecf20Sopenharmony_ci	}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	pm_runtime_put_sync(&dev->dev);
9138c2ecf20Sopenharmony_ci	if (ret)
9148c2ecf20Sopenharmony_ci		return ret;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	/* Init DMA */
9178c2ecf20Sopenharmony_ci	sg_init_table(&pd->sg, 1);
9188c2ecf20Sopenharmony_ci	pd->dma_direction = DMA_NONE;
9198c2ecf20Sopenharmony_ci	pd->dma_rx = pd->dma_tx = ERR_PTR(-EPROBE_DEFER);
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	/* setup the private data */
9228c2ecf20Sopenharmony_ci	adap = &pd->adap;
9238c2ecf20Sopenharmony_ci	i2c_set_adapdata(adap, pd);
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	adap->owner = THIS_MODULE;
9268c2ecf20Sopenharmony_ci	adap->algo = &sh_mobile_i2c_algorithm;
9278c2ecf20Sopenharmony_ci	adap->quirks = &sh_mobile_i2c_quirks;
9288c2ecf20Sopenharmony_ci	adap->dev.parent = &dev->dev;
9298c2ecf20Sopenharmony_ci	adap->retries = 5;
9308c2ecf20Sopenharmony_ci	adap->nr = dev->id;
9318c2ecf20Sopenharmony_ci	adap->dev.of_node = dev->dev.of_node;
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	strlcpy(adap->name, dev->name, sizeof(adap->name));
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	spin_lock_init(&pd->lock);
9368c2ecf20Sopenharmony_ci	init_waitqueue_head(&pd->wait);
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	ret = i2c_add_numbered_adapter(adap);
9398c2ecf20Sopenharmony_ci	if (ret < 0) {
9408c2ecf20Sopenharmony_ci		sh_mobile_i2c_release_dma(pd);
9418c2ecf20Sopenharmony_ci		return ret;
9428c2ecf20Sopenharmony_ci	}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	dev_info(&dev->dev, "I2C adapter %d, bus speed %lu Hz\n", adap->nr, pd->bus_speed);
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	return 0;
9478c2ecf20Sopenharmony_ci}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_cistatic int sh_mobile_i2c_remove(struct platform_device *dev)
9508c2ecf20Sopenharmony_ci{
9518c2ecf20Sopenharmony_ci	struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev);
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	i2c_del_adapter(&pd->adap);
9548c2ecf20Sopenharmony_ci	sh_mobile_i2c_release_dma(pd);
9558c2ecf20Sopenharmony_ci	pm_runtime_disable(&dev->dev);
9568c2ecf20Sopenharmony_ci	return 0;
9578c2ecf20Sopenharmony_ci}
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_cistatic struct platform_driver sh_mobile_i2c_driver = {
9608c2ecf20Sopenharmony_ci	.driver		= {
9618c2ecf20Sopenharmony_ci		.name		= "i2c-sh_mobile",
9628c2ecf20Sopenharmony_ci		.of_match_table = sh_mobile_i2c_dt_ids,
9638c2ecf20Sopenharmony_ci	},
9648c2ecf20Sopenharmony_ci	.probe		= sh_mobile_i2c_probe,
9658c2ecf20Sopenharmony_ci	.remove		= sh_mobile_i2c_remove,
9668c2ecf20Sopenharmony_ci};
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_cistatic int __init sh_mobile_i2c_adap_init(void)
9698c2ecf20Sopenharmony_ci{
9708c2ecf20Sopenharmony_ci	return platform_driver_register(&sh_mobile_i2c_driver);
9718c2ecf20Sopenharmony_ci}
9728c2ecf20Sopenharmony_cisubsys_initcall(sh_mobile_i2c_adap_init);
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_cistatic void __exit sh_mobile_i2c_adap_exit(void)
9758c2ecf20Sopenharmony_ci{
9768c2ecf20Sopenharmony_ci	platform_driver_unregister(&sh_mobile_i2c_driver);
9778c2ecf20Sopenharmony_ci}
9788c2ecf20Sopenharmony_cimodule_exit(sh_mobile_i2c_adap_exit);
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SuperH Mobile I2C Bus Controller driver");
9818c2ecf20Sopenharmony_ciMODULE_AUTHOR("Magnus Damm");
9828c2ecf20Sopenharmony_ciMODULE_AUTHOR("Wolfram Sang");
9838c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
9848c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:i2c-sh_mobile");
985