linux/drivers/i2c/busses/i2c-img-scb.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * I2C adapter for the IMG Serial Control Bus (SCB) IP block.
 *
 * Copyright (C) 2009, 2010, 2012, 2014 Imagination Technologies Ltd.
 *
 * There are three ways that this I2C controller can be driven:
 *
 * - Raw control of the SDA and SCK signals.
 *
 *   This corresponds to MODE_RAW, which takes control of the signals
 *   directly for a certain number of clock cycles (the INT_TIMING
 *   interrupt can be used for timing).
 *
 * - Atomic commands. A low level I2C symbol (such as generate
 *   start/stop/ack/nack bit, generate byte, receive byte, and receive
 *   ACK) is given to the hardware, with detection of completion by bits
 *   in the LINESTAT register.
 *
 *   This mode of operation is used by MODE_ATOMIC, which uses an I2C
 *   state machine in the interrupt handler to compose/react to I2C
 *   transactions using atomic mode commands, and also by MODE_SEQUENCE,
 *   which emits a simple fixed sequence of atomic mode commands.
 *
 *   Due to software control, the use of atomic commands usually results
 *   in suboptimal use of the bus, with gaps between the I2C symbols while
 *   the driver decides what to do next.
 *
 * - Automatic mode. A bus address, and whether to read/write is
 *   specified, and the hardware takes care of the I2C state machine,
 *   using a FIFO to send/receive bytes of data to an I2C slave. The
 *   driver just has to keep the FIFO drained or filled in response to the
 *   appropriate FIFO interrupts.
 *
 *   This corresponds to MODE_AUTOMATIC, which manages the FIFOs and deals
 *   with control of repeated start bits between I2C messages.
 *
 *   Use of automatic mode and the FIFO can make much more efficient use
 *   of the bus compared to individual atomic commands, with potentially
 *   no wasted time between I2C symbols or I2C messages.
 *
 * In most cases MODE_AUTOMATIC is used, however if any of the messages in
 * a transaction are zero byte writes (e.g. used by i2cdetect for probing
 * the bus), MODE_ATOMIC must be used since automatic mode is normally
 * started by the writing of data into the FIFO.
 *
 * The other modes are used in specific circumstances where MODE_ATOMIC and
 * MODE_AUTOMATIC aren't appropriate. MODE_RAW is used to implement a bus
 * recovery routine. MODE_SEQUENCE is used to reset the bus and make sure
 * it is in a sane state.
 *
 * Notice that the driver implements a timer-based timeout mechanism.
 * The reason for this mechanism is to reduce the number of interrupts
 * received in automatic mode.
 *
 * The driver would get a slave event and transaction done interrupts for
 * each atomic mode command that gets completed. However, these events are
 * not needed in automatic mode, becase those atomic mode commands are
 * managed automatically by the hardware.
 *
 * In practice, normal I2C transactions will be complete well before you
 * get the timer interrupt, as the timer is re-scheduled during FIFO
 * maintenance and disabled after the transaction is complete.
 *
 * In this way normal automatic mode operation isn't impacted by
 * unnecessary interrupts, but the exceptional abort condition can still be
 * detected (with a slight delay).
 */

#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/timer.h>

/* Register offsets */

#define SCB_STATUS_REG
#define SCB_OVERRIDE_REG
#define SCB_READ_ADDR_REG
#define SCB_READ_COUNT_REG
#define SCB_WRITE_ADDR_REG
#define SCB_READ_DATA_REG
#define SCB_WRITE_DATA_REG
#define SCB_FIFO_STATUS_REG
#define SCB_CONTROL_SOFT_RESET
#define SCB_CLK_SET_REG
#define SCB_INT_STATUS_REG
#define SCB_INT_CLEAR_REG
#define SCB_INT_MASK_REG
#define SCB_CONTROL_REG
#define SCB_TIME_TPL_REG
#define SCB_TIME_TPH_REG
#define SCB_TIME_TP2S_REG
#define SCB_TIME_TBI_REG
#define SCB_TIME_TSL_REG
#define SCB_TIME_TDL_REG
#define SCB_TIME_TSDL_REG
#define SCB_TIME_TSDH_REG
#define SCB_READ_XADDR_REG
#define SCB_WRITE_XADDR_REG
#define SCB_WRITE_COUNT_REG
#define SCB_CORE_REV_REG
#define SCB_TIME_TCKH_REG
#define SCB_TIME_TCKL_REG
#define SCB_FIFO_FLUSH_REG
#define SCB_READ_FIFO_REG
#define SCB_CLEAR_REG

/* SCB_CONTROL_REG bits */

#define SCB_CONTROL_CLK_ENABLE
#define SCB_CONTROL_TRANSACTION_HALT

#define FIFO_READ_FULL
#define FIFO_READ_EMPTY
#define FIFO_WRITE_FULL
#define FIFO_WRITE_EMPTY

/* SCB_CLK_SET_REG bits */
#define SCB_FILT_DISABLE
#define SCB_FILT_BYPASS
#define SCB_FILT_INC_MASK
#define SCB_FILT_INC_SHIFT
#define SCB_INC_MASK
#define SCB_INC_SHIFT

/* SCB_INT_*_REG bits */

#define INT_BUS_INACTIVE
#define INT_UNEXPECTED_START
#define INT_SCLK_LOW_TIMEOUT
#define INT_SDAT_LOW_TIMEOUT
#define INT_WRITE_ACK_ERR
#define INT_ADDR_ACK_ERR
#define INT_FIFO_FULL
#define INT_FIFO_FILLING
#define INT_FIFO_EMPTY
#define INT_FIFO_EMPTYING
#define INT_TRANSACTION_DONE
#define INT_SLAVE_EVENT
#define INT_MASTER_HALTED
#define INT_TIMING
#define INT_STOP_DETECTED

#define INT_FIFO_FULL_FILLING

/* Level interrupts need clearing after handling instead of before */
#define INT_LEVEL

/* Don't allow any interrupts while the clock may be off */
#define INT_ENABLE_MASK_INACTIVE

/* Interrupt masks for the different driver modes */

#define INT_ENABLE_MASK_RAW

#define INT_ENABLE_MASK_ATOMIC

#define INT_ENABLE_MASK_AUTOMATIC

#define INT_ENABLE_MASK_WAITSTOP

/* SCB_STATUS_REG fields */

#define LINESTAT_SCLK_LINE_STATUS
#define LINESTAT_SCLK_EN
#define LINESTAT_SDAT_LINE_STATUS
#define LINESTAT_SDAT_EN
#define LINESTAT_DET_START_STATUS
#define LINESTAT_DET_STOP_STATUS
#define LINESTAT_DET_ACK_STATUS
#define LINESTAT_DET_NACK_STATUS
#define LINESTAT_BUS_IDLE
#define LINESTAT_T_DONE_STATUS
#define LINESTAT_SCLK_OUT_STATUS
#define LINESTAT_SDAT_OUT_STATUS
#define LINESTAT_GEN_LINE_MASK_STATUS
#define LINESTAT_START_BIT_DET
#define LINESTAT_STOP_BIT_DET
#define LINESTAT_ACK_DET
#define LINESTAT_NACK_DET
#define LINESTAT_INPUT_HELD_V
#define LINESTAT_ABORT_DET
#define LINESTAT_ACK_OR_NACK_DET
#define LINESTAT_INPUT_DATA
#define LINESTAT_INPUT_DATA_SHIFT

#define LINESTAT_CLEAR_SHIFT
#define LINESTAT_LATCHED

/* SCB_OVERRIDE_REG fields */

#define OVERRIDE_SCLK_OVR
#define OVERRIDE_SCLKEN_OVR
#define OVERRIDE_SDAT_OVR
#define OVERRIDE_SDATEN_OVR
#define OVERRIDE_MASTER
#define OVERRIDE_LINE_OVR_EN
#define OVERRIDE_DIRECT
#define OVERRIDE_CMD_SHIFT
#define OVERRIDE_CMD_MASK
#define OVERRIDE_DATA_SHIFT

#define OVERRIDE_SCLK_DOWN
#define OVERRIDE_SCLK_UP
#define OVERRIDE_SDAT_DOWN
#define OVERRIDE_SDAT_UP

/* OVERRIDE_CMD values */

#define CMD_PAUSE
#define CMD_GEN_DATA
#define CMD_GEN_START
#define CMD_GEN_STOP
#define CMD_GEN_ACK
#define CMD_GEN_NACK
#define CMD_RET_DATA
#define CMD_RET_ACK

/* Fixed timing values */

#define TIMEOUT_TBI
#define TIMEOUT_TSL
#define TIMEOUT_TDL

/* Transaction timeout */

#define IMG_I2C_TIMEOUT

/*
 * Worst incs are 1 (inaccurate) and 16*256 (irregular).
 * So a sensible inc is the logarithmic mean: 64 (2^6), which is
 * in the middle of the valid range (0-127).
 */
#define SCB_OPT_INC

/* Setup the clock enable filtering for 25 ns */
#define SCB_FILT_GLITCH

/*
 * Bits to return from interrupt handler functions for different modes.
 * This delays completion until we've finished with the registers, so that the
 * function waiting for completion can safely disable the clock to save power.
 */
#define ISR_COMPLETE_M
#define ISR_FATAL_M
#define ISR_WAITSTOP
#define ISR_STATUS_M
#define ISR_COMPLETE(err)
#define ISR_FATAL(err)

#define IMG_I2C_PM_TIMEOUT

enum img_i2c_mode {};

/* Timing parameters for i2c modes (in ns) */
struct img_i2c_timings {};

/* The timings array must be ordered from slower to faster */
static struct img_i2c_timings timings[] =;

/* Reset dance */
static u8 img_i2c_reset_seq[] =;
/* Just issue a stop (after an abort condition) */
static u8 img_i2c_stop_seq[] =;

/* We're interested in different interrupts depending on the mode */
static unsigned int img_i2c_int_enable_by_mode[] =;

/* Atomic command names */
static const char * const img_i2c_atomic_cmd_names[] =;

struct img_i2c {};

static int img_i2c_runtime_suspend(struct device *dev);
static int img_i2c_runtime_resume(struct device *dev);

static void img_i2c_writel(struct img_i2c *i2c, u32 offset, u32 value)
{}

static u32 img_i2c_readl(struct img_i2c *i2c, u32 offset)
{}

/*
 * The code to read from the master read fifo, and write to the master
 * write fifo, checks a bit in an SCB register before every byte to
 * ensure that the fifo is not full (write fifo) or empty (read fifo).
 * Due to clock domain crossing inside the SCB block the updated value
 * of this bit is only visible after 2 cycles.
 *
 * The scb_wr_rd_fence() function does 2 dummy writes (to the read-only
 * revision register), and it's called after reading from or writing to the
 * fifos to ensure that subsequent reads of the fifo status bits do not read
 * stale values.
 */
static void img_i2c_wr_rd_fence(struct img_i2c *i2c)
{}

static void img_i2c_switch_mode(struct img_i2c *i2c, enum img_i2c_mode mode)
{}

static void img_i2c_raw_op(struct img_i2c *i2c)
{}

static const char *img_i2c_atomic_op_name(unsigned int cmd)
{}

/* Send a single atomic mode command to the hardware */
static void img_i2c_atomic_op(struct img_i2c *i2c, int cmd, u8 data)
{}

/* Start a transaction in atomic mode */
static void img_i2c_atomic_start(struct img_i2c *i2c)
{}

static void img_i2c_soft_reset(struct img_i2c *i2c)
{}

/*
 * Enable or release transaction halt for control of repeated starts.
 * In version 3.3 of the IP when transaction halt is set, an interrupt
 * will be generated after each byte of a transfer instead of after
 * every transfer but before the stop bit.
 * Due to this behaviour we have to be careful that every time we
 * release the transaction halt we have to re-enable it straight away
 * so that we only process a single byte, not doing so will result in
 * all remaining bytes been processed and a stop bit being issued,
 * which will prevent us having a repeated start.
 */
static void img_i2c_transaction_halt(struct img_i2c *i2c, bool t_halt)
{}

/* Drain data from the FIFO into the buffer (automatic mode) */
static void img_i2c_read_fifo(struct img_i2c *i2c)
{}

/* Fill the FIFO with data from the buffer (automatic mode) */
static void img_i2c_write_fifo(struct img_i2c *i2c)
{}

/* Start a read transaction in automatic mode */
static void img_i2c_read(struct img_i2c *i2c)
{}

/* Start a write transaction in automatic mode */
static void img_i2c_write(struct img_i2c *i2c)
{}

/*
 * Indicate that the transaction is complete. This is called from the
 * ISR to wake up the waiting thread, after which the ISR must not
 * access any more SCB registers.
 */
static void img_i2c_complete_transaction(struct img_i2c *i2c, int status)
{}

static unsigned int img_i2c_raw_atomic_delay_handler(struct img_i2c *i2c,
					u32 int_status, u32 line_status)
{}

static unsigned int img_i2c_raw(struct img_i2c *i2c, u32 int_status,
				u32 line_status)
{}

static unsigned int img_i2c_sequence(struct img_i2c *i2c, u32 int_status)
{}

static void img_i2c_reset_start(struct img_i2c *i2c)
{}

static void img_i2c_stop_start(struct img_i2c *i2c)
{}

static unsigned int img_i2c_atomic(struct img_i2c *i2c,
				   u32 int_status,
				   u32 line_status)
{}

/*
 * Timer function to check if something has gone wrong in automatic mode (so we
 * don't have to handle so many interrupts just to catch an exception).
 */
static void img_i2c_check_timer(struct timer_list *t)
{}

static unsigned int img_i2c_auto(struct img_i2c *i2c,
				 unsigned int int_status,
				 unsigned int line_status)
{}

static irqreturn_t img_i2c_isr(int irq, void *dev_id)
{}

/* Force a bus reset sequence and wait for it to complete */
static int img_i2c_reset_bus(struct img_i2c *i2c)
{}

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

static u32 img_i2c_func(struct i2c_adapter *adap)
{}

static const struct i2c_algorithm img_i2c_algo =;

static int img_i2c_init(struct img_i2c *i2c)
{}

static int img_i2c_probe(struct platform_device *pdev)
{}

static void img_i2c_remove(struct platform_device *dev)
{}

static int img_i2c_runtime_suspend(struct device *dev)
{}

static int img_i2c_runtime_resume(struct device *dev)
{}

static int img_i2c_suspend(struct device *dev)
{}

static int img_i2c_resume(struct device *dev)
{}

static const struct dev_pm_ops img_i2c_pm =;

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

static struct platform_driver img_scb_i2c_driver =;
module_platform_driver();

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