linux/drivers/i2c/busses/i2c-rcar.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Driver for the Renesas R-Car I2C unit
 *
 * Copyright (C) 2014-19 Wolfram Sang <[email protected]>
 * Copyright (C) 2011-2019 Renesas Electronics Corporation
 *
 * Copyright (C) 2012-14 Renesas Solutions Corp.
 * Kuninori Morimoto <[email protected]>
 *
 * This file is based on the drivers/i2c/busses/i2c-sh7760.c
 * (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <[email protected]>
 */
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/i2c.h>
#include <linux/i2c-smbus.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/slab.h>

/* register offsets */
#define ICSCR
#define ICMCR
#define ICSSR
#define ICMSR
#define ICSIER
#define ICMIER
#define ICCCR
#define ICSAR
#define ICMAR
#define ICRXTX
#define ICCCR2
#define ICMPR
#define ICHPR
#define ICLPR
#define ICFBSCR
#define ICDMAER

/* ICSCR */
#define SDBS
#define SIE
#define GCAE
#define FNA

/* ICMCR */
#define MDBS
#define FSCL
#define FSDA
#define OBPC
#define MIE
#define TSBE
#define FSB
#define ESG

/* ICSSR (also for ICSIER) */
#define GCAR
#define STM
#define SSR
#define SDE
#define SDT
#define SDR
#define SAR

/* ICMSR (also for ICMIE) */
#define MNR
#define MAL
#define MST
#define MDE
#define MDT
#define MDR
#define MAT

/* ICDMAER */
#define RSDMAE
#define TSDMAE
#define RMDMAE
#define TMDMAE

/* ICCCR2 */
#define FMPE
#define CDFD
#define HLSE
#define SME

/* ICFBSCR */
#define TCYC17

#define RCAR_MIN_DMA_LEN

/* SCL low/high ratio 5:4 to meet all I2C timing specs (incl safety margin) */
#define RCAR_SCLD_RATIO
#define RCAR_SCHD_RATIO
/*
 * SMD should be smaller than SCLD/SCHD and is always around 20 in the docs.
 * Thus, we simply use 20 which works for low and high speeds.
 */
#define RCAR_DEFAULT_SMD

#define RCAR_BUS_PHASE_START
#define RCAR_BUS_PHASE_DATA
#define RCAR_BUS_PHASE_STOP

#define RCAR_IRQ_SEND
#define RCAR_IRQ_RECV
#define RCAR_IRQ_STOP

#define ID_LAST_MSG
#define ID_REP_AFTER_RD
#define ID_DONE
#define ID_ARBLOST
#define ID_NACK
#define ID_EPROTO
/* persistent flags */
#define ID_P_FMPLUS
#define ID_P_NOT_ATOMIC
#define ID_P_HOST_NOTIFY
#define ID_P_NO_RXDMA
#define ID_P_PM_BLOCKED
#define ID_P_MASK

enum rcar_i2c_type {};

struct rcar_i2c_priv {};

#define rcar_i2c_priv_to_dev(p)
#define rcar_i2c_is_recv(p)

static void rcar_i2c_write(struct rcar_i2c_priv *priv, int reg, u32 val)
{}

static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg)
{}

static void rcar_i2c_clear_irq(struct rcar_i2c_priv *priv, u32 val)
{}

static int rcar_i2c_get_scl(struct i2c_adapter *adap)
{}

static void rcar_i2c_set_scl(struct i2c_adapter *adap, int val)
{}

static void rcar_i2c_set_sda(struct i2c_adapter *adap, int val)
{}

static int rcar_i2c_get_bus_free(struct i2c_adapter *adap)
{}

static struct i2c_bus_recovery_info rcar_i2c_bri =;

static void rcar_i2c_init(struct rcar_i2c_priv *priv)
{}

static void rcar_i2c_reset_slave(struct rcar_i2c_priv *priv)
{}

static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv)
{}

static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv)
{}

/*
 * We don't have a test case but the HW engineers say that the write order of
 * ICMSR and ICMCR depends on whether we issue START or REP_START. So, ICMSR
 * handling is outside of this function. First messages clear ICMSR before this
 * function, interrupt handlers clear the relevant bits after this function.
 */
static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv)
{}

static void rcar_i2c_first_msg(struct rcar_i2c_priv *priv,
			       struct i2c_msg *msgs, int num)
{}

static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv)
{}

static void rcar_i2c_cleanup_dma(struct rcar_i2c_priv *priv, bool terminate)
{}

static void rcar_i2c_dma_callback(void *data)
{}

static bool rcar_i2c_dma(struct rcar_i2c_priv *priv)
{}

static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
{}

static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
{}

static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
{}

/*
 * This driver has a lock-free design because there are IP cores (at least
 * R-Car Gen2) which have an inherent race condition in their hardware design.
 * There, we need to switch to RCAR_BUS_PHASE_DATA as soon as possible after
 * the interrupt was generated, otherwise an unwanted repeated message gets
 * generated. It turned out that taking a spinlock at the beginning of the ISR
 * was already causing repeated messages. Thus, this driver was converted to
 * the now lockless behaviour. Please keep this in mind when hacking the driver.
 * R-Car Gen3 seems to have this fixed but earlier versions than R-Car Gen2 are
 * likely affected. Therefore, we have different interrupt handler entries.
 */
static irqreturn_t rcar_i2c_irq(int irq, struct rcar_i2c_priv *priv, u32 msr)
{}

static irqreturn_t rcar_i2c_gen2_irq(int irq, void *ptr)
{}

static irqreturn_t rcar_i2c_gen3_irq(int irq, void *ptr)
{}

static struct dma_chan *rcar_i2c_request_dma_chan(struct device *dev,
					enum dma_transfer_direction dir,
					dma_addr_t port_addr)
{}

static void rcar_i2c_request_dma(struct rcar_i2c_priv *priv,
				 struct i2c_msg *msg)
{}

static void rcar_i2c_release_dma(struct rcar_i2c_priv *priv)
{}

/* I2C is a special case, we need to poll the status of a reset */
static int rcar_i2c_do_reset(struct rcar_i2c_priv *priv)
{}

static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
				struct i2c_msg *msgs,
				int num)
{}

static int rcar_i2c_master_xfer_atomic(struct i2c_adapter *adap,
				struct i2c_msg *msgs,
				int num)
{}

static int rcar_reg_slave(struct i2c_client *slave)
{}

static int rcar_unreg_slave(struct i2c_client *slave)
{}

static u32 rcar_i2c_func(struct i2c_adapter *adap)
{}

static const struct i2c_algorithm rcar_i2c_algo =;

static const struct i2c_adapter_quirks rcar_i2c_quirks =;

static const struct of_device_id rcar_i2c_dt_ids[] =;
MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids);

static int rcar_i2c_probe(struct platform_device *pdev)
{}

static void rcar_i2c_remove(struct platform_device *pdev)
{}

static int rcar_i2c_suspend(struct device *dev)
{}

static int rcar_i2c_resume(struct device *dev)
{}

static const struct dev_pm_ops rcar_i2c_pm_ops =;

static struct platform_driver rcar_i2c_driver =;

module_platform_driver();

MODULE_LICENSE();
MODULE_DESCRIPTION();
MODULE_AUTHOR();