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

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Driver for I2C adapter in Rockchip RK3xxx SoC
 *
 * Max Schwarz <[email protected]>
 * based on the patches by Rockchip Inc.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/spinlock.h>
#include <linux/clk.h>
#include <linux/wait.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/math64.h>


/* Register Map */
#define REG_CON
#define REG_CLKDIV
#define REG_MRXADDR
#define REG_MRXRADDR
#define REG_MTXCNT
#define REG_MRXCNT
#define REG_IEN
#define REG_IPD
#define REG_FCNT

/* Data buffer offsets */
#define TXBUFFER_BASE
#define RXBUFFER_BASE

/* REG_CON bits */
#define REG_CON_EN
enum {};
#define REG_CON_MOD(mod)
#define REG_CON_MOD_MASK
#define REG_CON_START
#define REG_CON_STOP
#define REG_CON_LASTACK
#define REG_CON_ACTACK

#define REG_CON_TUNING_MASK

#define REG_CON_SDA_CFG(cfg)
#define REG_CON_STA_CFG(cfg)
#define REG_CON_STO_CFG(cfg)

/* REG_MRXADDR bits */
#define REG_MRXADDR_VALID(x)

/* REG_IEN/REG_IPD bits */
#define REG_INT_BTF
#define REG_INT_BRF
#define REG_INT_MBTF
#define REG_INT_MBRF
#define REG_INT_START
#define REG_INT_STOP
#define REG_INT_NAKRCV
#define REG_INT_ALL

/* Constants */
#define WAIT_TIMEOUT
#define DEFAULT_SCL_RATE

/**
 * struct i2c_spec_values - I2C specification values for various modes
 * @min_hold_start_ns: min hold time (repeated) START condition
 * @min_low_ns: min LOW period of the SCL clock
 * @min_high_ns: min HIGH period of the SCL cloc
 * @min_setup_start_ns: min set-up time for a repeated START conditio
 * @max_data_hold_ns: max data hold time
 * @min_data_setup_ns: min data set-up time
 * @min_setup_stop_ns: min set-up time for STOP condition
 * @min_hold_buffer_ns: min bus free time between a STOP and
 * START condition
 */
struct i2c_spec_values {};

static const struct i2c_spec_values standard_mode_spec =;

static const struct i2c_spec_values fast_mode_spec =;

static const struct i2c_spec_values fast_mode_plus_spec =;

/**
 * struct rk3x_i2c_calced_timings - calculated V1 timings
 * @div_low: Divider output for low
 * @div_high: Divider output for high
 * @tuning: Used to adjust setup/hold data time,
 * setup/hold start time and setup stop time for
 * v1's calc_timings, the tuning should all be 0
 * for old hardware anyone using v0's calc_timings.
 */
struct rk3x_i2c_calced_timings {};

enum rk3x_i2c_state {};

/**
 * struct rk3x_i2c_soc_data - SOC-specific data
 * @grf_offset: offset inside the grf regmap for setting the i2c type
 * @calc_timings: Callback function for i2c timing information calculated
 */
struct rk3x_i2c_soc_data {};

/**
 * struct rk3x_i2c - private data of the controller
 * @adap: corresponding I2C adapter
 * @dev: device for this controller
 * @soc_data: related soc data struct
 * @regs: virtual memory area
 * @clk: function clk for rk3399 or function & Bus clks for others
 * @pclk: Bus clk for rk3399
 * @clk_rate_nb: i2c clk rate change notify
 * @irq: irq number
 * @t: I2C known timing information
 * @lock: spinlock for the i2c bus
 * @wait: the waitqueue to wait for i2c transfer
 * @busy: the condition for the event to wait for
 * @msg: current i2c message
 * @addr: addr of i2c target device
 * @mode: mode of i2c transfer
 * @is_last_msg: flag determines whether it is the last msg in this transfer
 * @state: state of i2c transfer
 * @processed: byte length which has been send or received
 * @error: error code for i2c transfer
 */
struct rk3x_i2c {};

static inline void i2c_writel(struct rk3x_i2c *i2c, u32 value,
			      unsigned int offset)
{}

static inline u32 i2c_readl(struct rk3x_i2c *i2c, unsigned int offset)
{}

/* Reset all interrupt pending bits */
static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c)
{}

/**
 * rk3x_i2c_start - Generate a START condition, which triggers a REG_INT_START interrupt.
 * @i2c: target controller data
 */
static void rk3x_i2c_start(struct rk3x_i2c *i2c)
{}

/**
 * rk3x_i2c_stop - Generate a STOP condition, which triggers a REG_INT_STOP interrupt.
 * @i2c: target controller data
 * @error: Error code to return in rk3x_i2c_xfer
 */
static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error)
{}

/**
 * rk3x_i2c_prepare_read - Setup a read according to i2c->msg
 * @i2c: target controller data
 */
static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c)
{}

/**
 * rk3x_i2c_fill_transmit_buf - Fill the transmit buffer with data from i2c->msg
 * @i2c: target controller data
 */
static void rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c)
{}


/* IRQ handlers for individual states */

static void rk3x_i2c_handle_start(struct rk3x_i2c *i2c, unsigned int ipd)
{}

static void rk3x_i2c_handle_write(struct rk3x_i2c *i2c, unsigned int ipd)
{}

static void rk3x_i2c_handle_read(struct rk3x_i2c *i2c, unsigned int ipd)
{}

static void rk3x_i2c_handle_stop(struct rk3x_i2c *i2c, unsigned int ipd)
{}

static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id)
{}

/**
 * rk3x_i2c_get_spec - Get timing values of I2C specification
 * @speed: Desired SCL frequency
 *
 * Return: Matched i2c_spec_values.
 */
static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
{}

/**
 * rk3x_i2c_v0_calc_timings - Calculate divider values for desired SCL frequency
 * @clk_rate: I2C input clock rate
 * @t: Known I2C timing information
 * @t_calc: Caculated rk3x private timings that would be written into regs
 *
 * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case
 * a best-effort divider value is returned in divs. If the target rate is
 * too high, we silently use the highest possible rate.
 */
static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
				    struct i2c_timings *t,
				    struct rk3x_i2c_calced_timings *t_calc)
{}

/**
 * rk3x_i2c_v1_calc_timings - Calculate timing values for desired SCL frequency
 * @clk_rate: I2C input clock rate
 * @t: Known I2C timing information
 * @t_calc: Caculated rk3x private timings that would be written into regs
 *
 * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case
 * a best-effort divider value is returned in divs. If the target rate is
 * too high, we silently use the highest possible rate.
 * The following formulas are v1's method to calculate timings.
 *
 * l = divl + 1;
 * h = divh + 1;
 * s = sda_update_config + 1;
 * u = start_setup_config + 1;
 * p = stop_setup_config + 1;
 * T = Tclk_i2c;
 *
 * tHigh = 8 * h * T;
 * tLow = 8 * l * T;
 *
 * tHD;sda = (l * s + 1) * T;
 * tSU;sda = [(8 - s) * l + 1] * T;
 * tI2C = 8 * (l + h) * T;
 *
 * tSU;sta = (8h * u + 1) * T;
 * tHD;sta = [8h * (u + 1) - 1] * T;
 * tSU;sto = (8h * p + 1) * T;
 */
static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
				    struct i2c_timings *t,
				    struct rk3x_i2c_calced_timings *t_calc)
{}

static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
{}

/**
 * rk3x_i2c_clk_notifier_cb - Clock rate change callback
 * @nb:		Pointer to notifier block
 * @event:	Notification reason
 * @data:	Pointer to notification data object
 *
 * The callback checks whether a valid bus frequency can be generated after the
 * change. If so, the change is acknowledged, otherwise the change is aborted.
 * New dividers are written to the HW in the pre- or post change notification
 * depending on the scaling direction.
 *
 * Code adapted from i2c-cadence.c.
 *
 * Return:	NOTIFY_STOP if the rate change should be aborted, NOTIFY_OK
 *		to acknowledge the change, NOTIFY_DONE if the notification is
 *		considered irrelevant.
 */
static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
				    event, void *data)
{}

/**
 * rk3x_i2c_setup - Setup I2C registers for an I2C operation specified by msgs, num.
 * @i2c: target controller data
 * @msgs: I2C msgs to process
 * @num: Number of msgs
 *
 * Must be called with i2c->lock held.
 *
 * Return: Number of I2C msgs processed or negative in case of error
 */
static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num)
{}

static int rk3x_i2c_wait_xfer_poll(struct rk3x_i2c *i2c)
{}

static int rk3x_i2c_xfer_common(struct i2c_adapter *adap,
				struct i2c_msg *msgs, int num, bool polling)
{}

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

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

static __maybe_unused int rk3x_i2c_resume(struct device *dev)
{}

static u32 rk3x_i2c_func(struct i2c_adapter *adap)
{}

static const struct i2c_algorithm rk3x_i2c_algorithm =;

static const struct rk3x_i2c_soc_data rv1108_soc_data =;

static const struct rk3x_i2c_soc_data rv1126_soc_data =;

static const struct rk3x_i2c_soc_data rk3066_soc_data =;

static const struct rk3x_i2c_soc_data rk3188_soc_data =;

static const struct rk3x_i2c_soc_data rk3228_soc_data =;

static const struct rk3x_i2c_soc_data rk3288_soc_data =;

static const struct rk3x_i2c_soc_data rk3399_soc_data =;

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

static int rk3x_i2c_probe(struct platform_device *pdev)
{}

static void rk3x_i2c_remove(struct platform_device *pdev)
{}

static SIMPLE_DEV_PM_OPS(rk3x_i2c_pm_ops, NULL, rk3x_i2c_resume);

static struct platform_driver rk3x_i2c_driver =;

module_platform_driver();

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