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

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * TI OMAP I2C master mode driver
 *
 * Copyright (C) 2003 MontaVista Software, Inc.
 * Copyright (C) 2005 Nokia Corporation
 * Copyright (C) 2004 - 2007 Texas Instruments.
 *
 * Originally written by MontaVista Software, Inc.
 * Additional contributions by:
 *	Tony Lindgren <[email protected]>
 *	Imre Deak <[email protected]>
 *	Juha Yrjölä <[email protected]>
 *	Syed Khasim <[email protected]>
 *	Nishant Menon <[email protected]>
 */

#include <linux/module.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/platform_data/i2c-omap.h>
#include <linux/pm_runtime.h>
#include <linux/pinctrl/consumer.h>
#include <linux/property.h>

/* I2C controller revisions */
#define OMAP_I2C_OMAP1_REV_2

/* I2C controller revisions present on specific hardware */
#define OMAP_I2C_REV_ON_2430
#define OMAP_I2C_REV_ON_3430_3530
#define OMAP_I2C_REV_ON_3630
#define OMAP_I2C_REV_ON_4430_PLUS

/* timeout waiting for the controller to respond */
#define OMAP_I2C_TIMEOUT

/* timeout for pm runtime autosuspend */
#define OMAP_I2C_PM_TIMEOUT

/* timeout for making decision on bus free status */
#define OMAP_I2C_BUS_FREE_TIMEOUT

/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */
enum {};

/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
#define OMAP_I2C_IE_XDR
#define OMAP_I2C_IE_RDR
#define OMAP_I2C_IE_XRDY
#define OMAP_I2C_IE_RRDY
#define OMAP_I2C_IE_ARDY
#define OMAP_I2C_IE_NACK
#define OMAP_I2C_IE_AL

/* I2C Status Register (OMAP_I2C_STAT): */
#define OMAP_I2C_STAT_XDR
#define OMAP_I2C_STAT_RDR
#define OMAP_I2C_STAT_BB
#define OMAP_I2C_STAT_ROVR
#define OMAP_I2C_STAT_XUDF
#define OMAP_I2C_STAT_AAS
#define OMAP_I2C_STAT_BF
#define OMAP_I2C_STAT_XRDY
#define OMAP_I2C_STAT_RRDY
#define OMAP_I2C_STAT_ARDY
#define OMAP_I2C_STAT_NACK
#define OMAP_I2C_STAT_AL

/* I2C WE wakeup enable register */
#define OMAP_I2C_WE_XDR_WE
#define OMAP_I2C_WE_RDR_WE
#define OMAP_I2C_WE_AAS_WE
#define OMAP_I2C_WE_BF_WE
#define OMAP_I2C_WE_STC_WE
#define OMAP_I2C_WE_GC_WE
#define OMAP_I2C_WE_DRDY_WE
#define OMAP_I2C_WE_ARDY_WE
#define OMAP_I2C_WE_NACK_WE
#define OMAP_I2C_WE_AL_WE

#define OMAP_I2C_WE_ALL

/* I2C Buffer Configuration Register (OMAP_I2C_BUF): */
#define OMAP_I2C_BUF_RDMA_EN
#define OMAP_I2C_BUF_RXFIF_CLR
#define OMAP_I2C_BUF_XDMA_EN
#define OMAP_I2C_BUF_TXFIF_CLR

/* I2C Configuration Register (OMAP_I2C_CON): */
#define OMAP_I2C_CON_EN
#define OMAP_I2C_CON_BE
#define OMAP_I2C_CON_OPMODE_HS
#define OMAP_I2C_CON_STB
#define OMAP_I2C_CON_MST
#define OMAP_I2C_CON_TRX
#define OMAP_I2C_CON_XA
#define OMAP_I2C_CON_RM
#define OMAP_I2C_CON_STP
#define OMAP_I2C_CON_STT

/* I2C SCL time value when Master */
#define OMAP_I2C_SCLL_HSSCLL
#define OMAP_I2C_SCLH_HSSCLH

/* I2C System Test Register (OMAP_I2C_SYSTEST): */
#define OMAP_I2C_SYSTEST_ST_EN
#define OMAP_I2C_SYSTEST_FREE
#define OMAP_I2C_SYSTEST_TMODE_MASK
#define OMAP_I2C_SYSTEST_TMODE_SHIFT
/* Functional mode */
#define OMAP_I2C_SYSTEST_SCL_I_FUNC
#define OMAP_I2C_SYSTEST_SCL_O_FUNC
#define OMAP_I2C_SYSTEST_SDA_I_FUNC
#define OMAP_I2C_SYSTEST_SDA_O_FUNC
/* SDA/SCL IO mode */
#define OMAP_I2C_SYSTEST_SCL_I
#define OMAP_I2C_SYSTEST_SCL_O
#define OMAP_I2C_SYSTEST_SDA_I
#define OMAP_I2C_SYSTEST_SDA_O

/* OCP_SYSSTATUS bit definitions */
#define SYSS_RESETDONE_MASK

/* OCP_SYSCONFIG bit definitions */
#define SYSC_CLOCKACTIVITY_MASK
#define SYSC_SIDLEMODE_MASK
#define SYSC_ENAWAKEUP_MASK
#define SYSC_SOFTRESET_MASK
#define SYSC_AUTOIDLE_MASK

#define SYSC_IDLEMODE_SMART
#define SYSC_CLOCKACTIVITY_FCLK

/* Errata definitions */
#define I2C_OMAP_ERRATA_I207
#define I2C_OMAP_ERRATA_I462

#define OMAP_I2C_IP_V2_INTERRUPTS_MASK

struct omap_i2c_dev {};

static const u8 reg_map_ip_v1[] =;

static const u8 reg_map_ip_v2[] =;

static int omap_i2c_xfer_data(struct omap_i2c_dev *omap);

static inline void omap_i2c_write_reg(struct omap_i2c_dev *omap,
				      int reg, u16 val)
{}

static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *omap, int reg)
{}

static void __omap_i2c_init(struct omap_i2c_dev *omap)
{}

static int omap_i2c_reset(struct omap_i2c_dev *omap)
{}

static int omap_i2c_init(struct omap_i2c_dev *omap)
{}

/*
 * Try bus recovery, but only if SDA is actually low.
 */
static int omap_i2c_recover_bus(struct omap_i2c_dev *omap)
{}

/*
 * Waiting on Bus Busy
 */
static int omap_i2c_wait_for_bb(struct omap_i2c_dev *omap)
{}

/*
 * Wait while BB-bit doesn't reflect the I2C bus state
 *
 * In a multimaster environment, after IP software reset, BB-bit value doesn't
 * correspond to the current bus state. It may happen what BB-bit will be 0,
 * while the bus is busy due to another I2C master activity.
 * Here are BB-bit values after reset:
 *     SDA   SCL   BB   NOTES
 *       0     0    0   1, 2
 *       1     0    0   1, 2
 *       0     1    1
 *       1     1    0   3
 * Later, if IP detect SDA=0 and SCL=1 (ACK) or SDA 1->0 while SCL=1 (START)
 * combinations on the bus, it set BB-bit to 1.
 * If IP detect SDA 0->1 while SCL=1 (STOP) combination on the bus,
 * it set BB-bit to 0 and BF to 1.
 * BB and BF bits correctly tracks the bus state while IP is suspended
 * BB bit became valid on the next FCLK clock after CON_EN bit set
 *
 * NOTES:
 * 1. Any transfer started when BB=0 and bus is busy wouldn't be
 *    completed by IP and results in controller timeout.
 * 2. Any transfer started when BB=0 and SCL=0 results in IP
 *    starting to drive SDA low. In that case IP corrupt data
 *    on the bus.
 * 3. Any transfer started in the middle of another master's transfer
 *    results in unpredictable results and data corruption
 */
static int omap_i2c_wait_for_bb_valid(struct omap_i2c_dev *omap)
{}

static void omap_i2c_resize_fifo(struct omap_i2c_dev *omap, u8 size, bool is_rx)
{}

static void omap_i2c_wait(struct omap_i2c_dev *omap)
{}

/*
 * Low level master read/write transaction.
 */
static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
			     struct i2c_msg *msg, int stop, bool polling)
{}


/*
 * Prepare controller for a transaction and call omap_i2c_xfer_msg
 * to do the work during IRQ processing.
 */
static int
omap_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg msgs[], int num,
		     bool polling)
{}

static int
omap_i2c_xfer_irq(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{}

static int
omap_i2c_xfer_polling(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{}

static u32
omap_i2c_func(struct i2c_adapter *adap)
{}

static inline void
omap_i2c_complete_cmd(struct omap_i2c_dev *omap, u16 err)
{}

static inline void
omap_i2c_ack_stat(struct omap_i2c_dev *omap, u16 stat)
{}

static inline void i2c_omap_errata_i207(struct omap_i2c_dev *omap, u16 stat)
{}

/* rev1 devices are apparently only on some 15xx */
#ifdef CONFIG_ARCH_OMAP15XX

static irqreturn_t
omap_i2c_omap1_isr(int this_irq, void *dev_id)
{
	struct omap_i2c_dev *omap = dev_id;
	u16 iv, w;

	if (pm_runtime_suspended(omap->dev))
		return IRQ_NONE;

	iv = omap_i2c_read_reg(omap, OMAP_I2C_IV_REG);
	switch (iv) {
	case 0x00:	/* None */
		break;
	case 0x01:	/* Arbitration lost */
		dev_err(omap->dev, "Arbitration lost\n");
		omap_i2c_complete_cmd(omap, OMAP_I2C_STAT_AL);
		break;
	case 0x02:	/* No acknowledgement */
		omap_i2c_complete_cmd(omap, OMAP_I2C_STAT_NACK);
		omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP);
		break;
	case 0x03:	/* Register access ready */
		omap_i2c_complete_cmd(omap, 0);
		break;
	case 0x04:	/* Receive data ready */
		if (omap->buf_len) {
			w = omap_i2c_read_reg(omap, OMAP_I2C_DATA_REG);
			*omap->buf++ = w;
			omap->buf_len--;
			if (omap->buf_len) {
				*omap->buf++ = w >> 8;
				omap->buf_len--;
			}
		} else
			dev_err(omap->dev, "RRDY IRQ while no data requested\n");
		break;
	case 0x05:	/* Transmit data ready */
		if (omap->buf_len) {
			w = *omap->buf++;
			omap->buf_len--;
			if (omap->buf_len) {
				w |= *omap->buf++ << 8;
				omap->buf_len--;
			}
			omap_i2c_write_reg(omap, OMAP_I2C_DATA_REG, w);
		} else
			dev_err(omap->dev, "XRDY IRQ while no data to send\n");
		break;
	default:
		return IRQ_NONE;
	}

	return IRQ_HANDLED;
}
#else
#define omap_i2c_omap1_isr
#endif

/*
 * OMAP3430 Errata i462: When an XRDY/XDR is hit, wait for XUDF before writing
 * data to DATA_REG. Otherwise some data bytes can be lost while transferring
 * them from the memory to the I2C interface.
 */
static int errata_omap3_i462(struct omap_i2c_dev *omap)
{}

static void omap_i2c_receive_data(struct omap_i2c_dev *omap, u8 num_bytes,
		bool is_rdr)
{}

static int omap_i2c_transmit_data(struct omap_i2c_dev *omap, u8 num_bytes,
		bool is_xdr)
{}

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

static int omap_i2c_xfer_data(struct omap_i2c_dev *omap)
{}

static irqreturn_t
omap_i2c_isr_thread(int this_irq, void *dev_id)
{}

static const struct i2c_algorithm omap_i2c_algo =;

static const struct i2c_adapter_quirks omap_i2c_quirks =;

#ifdef CONFIG_OF
static struct omap_i2c_bus_platform_data omap2420_pdata =;

static struct omap_i2c_bus_platform_data omap2430_pdata =;

static struct omap_i2c_bus_platform_data omap3_pdata =;

static struct omap_i2c_bus_platform_data omap4_pdata =;

static const struct of_device_id omap_i2c_of_match[] =;
MODULE_DEVICE_TABLE(of, omap_i2c_of_match);
#endif

#define OMAP_I2C_SCHEME(rev)

#define OMAP_I2C_REV_SCHEME_0_MAJOR(rev)
#define OMAP_I2C_REV_SCHEME_0_MINOR(rev)

#define OMAP_I2C_REV_SCHEME_1_MAJOR(rev)
#define OMAP_I2C_REV_SCHEME_1_MINOR(rev)
#define OMAP_I2C_SCHEME_0
#define OMAP_I2C_SCHEME_1

static int omap_i2c_get_scl(struct i2c_adapter *adap)
{}

static int omap_i2c_get_sda(struct i2c_adapter *adap)
{}

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

static void omap_i2c_prepare_recovery(struct i2c_adapter *adap)
{}

static void omap_i2c_unprepare_recovery(struct i2c_adapter *adap)
{}

static struct i2c_bus_recovery_info omap_i2c_bus_recovery_info =;

static int
omap_i2c_probe(struct platform_device *pdev)
{}

static void omap_i2c_remove(struct platform_device *pdev)
{}

static int omap_i2c_runtime_suspend(struct device *dev)
{}

static int omap_i2c_runtime_resume(struct device *dev)
{}

static int omap_i2c_suspend(struct device *dev)
{}

static int omap_i2c_resume(struct device *dev)
{}

static const struct dev_pm_ops omap_i2c_pm_ops =;

static struct platform_driver omap_i2c_driver =;

/* I2C may be needed to bring up other drivers */
static int __init
omap_i2c_init_driver(void)
{}
subsys_initcall(omap_i2c_init_driver);

static void __exit omap_i2c_exit_driver(void)
{}
module_exit(omap_i2c_exit_driver);

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