162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * This driver implements I2C master functionality using the LSI API2C 462306a36Sopenharmony_ci * controller. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * NOTE: The controller has a limitation in that it can only do transfers of 762306a36Sopenharmony_ci * maximum 255 bytes at a time. If a larger transfer is attempted, error code 862306a36Sopenharmony_ci * (-EINVAL) is returned. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/clkdev.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/err.h> 1462306a36Sopenharmony_ci#include <linux/i2c.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/io.h> 1962306a36Sopenharmony_ci#include <linux/kernel.h> 2062306a36Sopenharmony_ci#include <linux/platform_device.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define SCL_WAIT_TIMEOUT_NS 25000000 2362306a36Sopenharmony_ci#define I2C_XFER_TIMEOUT (msecs_to_jiffies(250)) 2462306a36Sopenharmony_ci#define I2C_STOP_TIMEOUT (msecs_to_jiffies(100)) 2562306a36Sopenharmony_ci#define FIFO_SIZE 8 2662306a36Sopenharmony_ci#define SEQ_LEN 2 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define GLOBAL_CONTROL 0x00 2962306a36Sopenharmony_ci#define GLOBAL_MST_EN BIT(0) 3062306a36Sopenharmony_ci#define GLOBAL_SLV_EN BIT(1) 3162306a36Sopenharmony_ci#define GLOBAL_IBML_EN BIT(2) 3262306a36Sopenharmony_ci#define INTERRUPT_STATUS 0x04 3362306a36Sopenharmony_ci#define INTERRUPT_ENABLE 0x08 3462306a36Sopenharmony_ci#define INT_SLV BIT(1) 3562306a36Sopenharmony_ci#define INT_MST BIT(0) 3662306a36Sopenharmony_ci#define WAIT_TIMER_CONTROL 0x0c 3762306a36Sopenharmony_ci#define WT_EN BIT(15) 3862306a36Sopenharmony_ci#define WT_VALUE(_x) ((_x) & 0x7fff) 3962306a36Sopenharmony_ci#define IBML_TIMEOUT 0x10 4062306a36Sopenharmony_ci#define IBML_LOW_MEXT 0x14 4162306a36Sopenharmony_ci#define IBML_LOW_SEXT 0x18 4262306a36Sopenharmony_ci#define TIMER_CLOCK_DIV 0x1c 4362306a36Sopenharmony_ci#define I2C_BUS_MONITOR 0x20 4462306a36Sopenharmony_ci#define BM_SDAC BIT(3) 4562306a36Sopenharmony_ci#define BM_SCLC BIT(2) 4662306a36Sopenharmony_ci#define BM_SDAS BIT(1) 4762306a36Sopenharmony_ci#define BM_SCLS BIT(0) 4862306a36Sopenharmony_ci#define SOFT_RESET 0x24 4962306a36Sopenharmony_ci#define MST_COMMAND 0x28 5062306a36Sopenharmony_ci#define CMD_BUSY (1<<3) 5162306a36Sopenharmony_ci#define CMD_MANUAL (0x00 | CMD_BUSY) 5262306a36Sopenharmony_ci#define CMD_AUTO (0x01 | CMD_BUSY) 5362306a36Sopenharmony_ci#define CMD_SEQUENCE (0x02 | CMD_BUSY) 5462306a36Sopenharmony_ci#define MST_RX_XFER 0x2c 5562306a36Sopenharmony_ci#define MST_TX_XFER 0x30 5662306a36Sopenharmony_ci#define MST_ADDR_1 0x34 5762306a36Sopenharmony_ci#define MST_ADDR_2 0x38 5862306a36Sopenharmony_ci#define MST_DATA 0x3c 5962306a36Sopenharmony_ci#define MST_TX_FIFO 0x40 6062306a36Sopenharmony_ci#define MST_RX_FIFO 0x44 6162306a36Sopenharmony_ci#define MST_INT_ENABLE 0x48 6262306a36Sopenharmony_ci#define MST_INT_STATUS 0x4c 6362306a36Sopenharmony_ci#define MST_STATUS_RFL (1 << 13) /* RX FIFO serivce */ 6462306a36Sopenharmony_ci#define MST_STATUS_TFL (1 << 12) /* TX FIFO service */ 6562306a36Sopenharmony_ci#define MST_STATUS_SNS (1 << 11) /* Manual mode done */ 6662306a36Sopenharmony_ci#define MST_STATUS_SS (1 << 10) /* Automatic mode done */ 6762306a36Sopenharmony_ci#define MST_STATUS_SCC (1 << 9) /* Stop complete */ 6862306a36Sopenharmony_ci#define MST_STATUS_IP (1 << 8) /* Invalid parameter */ 6962306a36Sopenharmony_ci#define MST_STATUS_TSS (1 << 7) /* Timeout */ 7062306a36Sopenharmony_ci#define MST_STATUS_AL (1 << 6) /* Arbitration lost */ 7162306a36Sopenharmony_ci#define MST_STATUS_ND (1 << 5) /* NAK on data phase */ 7262306a36Sopenharmony_ci#define MST_STATUS_NA (1 << 4) /* NAK on address phase */ 7362306a36Sopenharmony_ci#define MST_STATUS_NAK (MST_STATUS_NA | \ 7462306a36Sopenharmony_ci MST_STATUS_ND) 7562306a36Sopenharmony_ci#define MST_STATUS_ERR (MST_STATUS_NAK | \ 7662306a36Sopenharmony_ci MST_STATUS_AL | \ 7762306a36Sopenharmony_ci MST_STATUS_IP) 7862306a36Sopenharmony_ci#define MST_TX_BYTES_XFRD 0x50 7962306a36Sopenharmony_ci#define MST_RX_BYTES_XFRD 0x54 8062306a36Sopenharmony_ci#define SLV_ADDR_DEC_CTL 0x58 8162306a36Sopenharmony_ci#define SLV_ADDR_DEC_GCE BIT(0) /* ACK to General Call Address from own master (loopback) */ 8262306a36Sopenharmony_ci#define SLV_ADDR_DEC_OGCE BIT(1) /* ACK to General Call Address from external masters */ 8362306a36Sopenharmony_ci#define SLV_ADDR_DEC_SA1E BIT(2) /* ACK to addr_1 enabled */ 8462306a36Sopenharmony_ci#define SLV_ADDR_DEC_SA1M BIT(3) /* 10-bit addressing for addr_1 enabled */ 8562306a36Sopenharmony_ci#define SLV_ADDR_DEC_SA2E BIT(4) /* ACK to addr_2 enabled */ 8662306a36Sopenharmony_ci#define SLV_ADDR_DEC_SA2M BIT(5) /* 10-bit addressing for addr_2 enabled */ 8762306a36Sopenharmony_ci#define SLV_ADDR_1 0x5c 8862306a36Sopenharmony_ci#define SLV_ADDR_2 0x60 8962306a36Sopenharmony_ci#define SLV_RX_CTL 0x64 9062306a36Sopenharmony_ci#define SLV_RX_ACSA1 BIT(0) /* Generate ACK for writes to addr_1 */ 9162306a36Sopenharmony_ci#define SLV_RX_ACSA2 BIT(1) /* Generate ACK for writes to addr_2 */ 9262306a36Sopenharmony_ci#define SLV_RX_ACGCA BIT(2) /* ACK data phase transfers to General Call Address */ 9362306a36Sopenharmony_ci#define SLV_DATA 0x68 9462306a36Sopenharmony_ci#define SLV_RX_FIFO 0x6c 9562306a36Sopenharmony_ci#define SLV_FIFO_DV1 BIT(0) /* Data Valid for addr_1 */ 9662306a36Sopenharmony_ci#define SLV_FIFO_DV2 BIT(1) /* Data Valid for addr_2 */ 9762306a36Sopenharmony_ci#define SLV_FIFO_AS BIT(2) /* (N)ACK Sent */ 9862306a36Sopenharmony_ci#define SLV_FIFO_TNAK BIT(3) /* Timeout NACK */ 9962306a36Sopenharmony_ci#define SLV_FIFO_STRC BIT(4) /* First byte after start condition received */ 10062306a36Sopenharmony_ci#define SLV_FIFO_RSC BIT(5) /* Repeated Start Condition */ 10162306a36Sopenharmony_ci#define SLV_FIFO_STPC BIT(6) /* Stop Condition */ 10262306a36Sopenharmony_ci#define SLV_FIFO_DV (SLV_FIFO_DV1 | SLV_FIFO_DV2) 10362306a36Sopenharmony_ci#define SLV_INT_ENABLE 0x70 10462306a36Sopenharmony_ci#define SLV_INT_STATUS 0x74 10562306a36Sopenharmony_ci#define SLV_STATUS_RFH BIT(0) /* FIFO service */ 10662306a36Sopenharmony_ci#define SLV_STATUS_WTC BIT(1) /* Write transfer complete */ 10762306a36Sopenharmony_ci#define SLV_STATUS_SRS1 BIT(2) /* Slave read from addr 1 */ 10862306a36Sopenharmony_ci#define SLV_STATUS_SRRS1 BIT(3) /* Repeated start from addr 1 */ 10962306a36Sopenharmony_ci#define SLV_STATUS_SRND1 BIT(4) /* Read request not following start condition */ 11062306a36Sopenharmony_ci#define SLV_STATUS_SRC1 BIT(5) /* Read canceled */ 11162306a36Sopenharmony_ci#define SLV_STATUS_SRAT1 BIT(6) /* Slave Read timed out */ 11262306a36Sopenharmony_ci#define SLV_STATUS_SRDRE1 BIT(7) /* Data written after timed out */ 11362306a36Sopenharmony_ci#define SLV_READ_DUMMY 0x78 11462306a36Sopenharmony_ci#define SCL_HIGH_PERIOD 0x80 11562306a36Sopenharmony_ci#define SCL_LOW_PERIOD 0x84 11662306a36Sopenharmony_ci#define SPIKE_FLTR_LEN 0x88 11762306a36Sopenharmony_ci#define SDA_SETUP_TIME 0x8c 11862306a36Sopenharmony_ci#define SDA_HOLD_TIME 0x90 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/** 12162306a36Sopenharmony_ci * struct axxia_i2c_dev - I2C device context 12262306a36Sopenharmony_ci * @base: pointer to register struct 12362306a36Sopenharmony_ci * @msg: pointer to current message 12462306a36Sopenharmony_ci * @msg_r: pointer to current read message (sequence transfer) 12562306a36Sopenharmony_ci * @msg_xfrd: number of bytes transferred in tx_fifo 12662306a36Sopenharmony_ci * @msg_xfrd_r: number of bytes transferred in rx_fifo 12762306a36Sopenharmony_ci * @msg_err: error code for completed message 12862306a36Sopenharmony_ci * @msg_complete: xfer completion object 12962306a36Sopenharmony_ci * @dev: device reference 13062306a36Sopenharmony_ci * @adapter: core i2c abstraction 13162306a36Sopenharmony_ci * @i2c_clk: clock reference for i2c input clock 13262306a36Sopenharmony_ci * @bus_clk_rate: current i2c bus clock rate 13362306a36Sopenharmony_ci * @last: a flag indicating is this is last message in transfer 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_cistruct axxia_i2c_dev { 13662306a36Sopenharmony_ci void __iomem *base; 13762306a36Sopenharmony_ci struct i2c_msg *msg; 13862306a36Sopenharmony_ci struct i2c_msg *msg_r; 13962306a36Sopenharmony_ci size_t msg_xfrd; 14062306a36Sopenharmony_ci size_t msg_xfrd_r; 14162306a36Sopenharmony_ci int msg_err; 14262306a36Sopenharmony_ci struct completion msg_complete; 14362306a36Sopenharmony_ci struct device *dev; 14462306a36Sopenharmony_ci struct i2c_adapter adapter; 14562306a36Sopenharmony_ci struct clk *i2c_clk; 14662306a36Sopenharmony_ci u32 bus_clk_rate; 14762306a36Sopenharmony_ci bool last; 14862306a36Sopenharmony_ci struct i2c_client *slave; 14962306a36Sopenharmony_ci int irq; 15062306a36Sopenharmony_ci}; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic void i2c_int_disable(struct axxia_i2c_dev *idev, u32 mask) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci u32 int_en; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci int_en = readl(idev->base + MST_INT_ENABLE); 15762306a36Sopenharmony_ci writel(int_en & ~mask, idev->base + MST_INT_ENABLE); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic void i2c_int_enable(struct axxia_i2c_dev *idev, u32 mask) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci u32 int_en; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci int_en = readl(idev->base + MST_INT_ENABLE); 16562306a36Sopenharmony_ci writel(int_en | mask, idev->base + MST_INT_ENABLE); 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci/** 16962306a36Sopenharmony_ci * ns_to_clk - Convert time (ns) to clock cycles for the given clock frequency. 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_cistatic u32 ns_to_clk(u64 ns, u32 clk_mhz) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci return div_u64(ns * clk_mhz, 1000); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic int axxia_i2c_init(struct axxia_i2c_dev *idev) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci u32 divisor = clk_get_rate(idev->i2c_clk) / idev->bus_clk_rate; 17962306a36Sopenharmony_ci u32 clk_mhz = clk_get_rate(idev->i2c_clk) / 1000000; 18062306a36Sopenharmony_ci u32 t_setup; 18162306a36Sopenharmony_ci u32 t_high, t_low; 18262306a36Sopenharmony_ci u32 tmo_clk; 18362306a36Sopenharmony_ci u32 prescale; 18462306a36Sopenharmony_ci unsigned long timeout; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci dev_dbg(idev->dev, "rate=%uHz per_clk=%uMHz -> ratio=1:%u\n", 18762306a36Sopenharmony_ci idev->bus_clk_rate, clk_mhz, divisor); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* Reset controller */ 19062306a36Sopenharmony_ci writel(0x01, idev->base + SOFT_RESET); 19162306a36Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(100); 19262306a36Sopenharmony_ci while (readl(idev->base + SOFT_RESET) & 1) { 19362306a36Sopenharmony_ci if (time_after(jiffies, timeout)) { 19462306a36Sopenharmony_ci dev_warn(idev->dev, "Soft reset failed\n"); 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* Enable Master Mode */ 20062306a36Sopenharmony_ci writel(0x1, idev->base + GLOBAL_CONTROL); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (idev->bus_clk_rate <= I2C_MAX_STANDARD_MODE_FREQ) { 20362306a36Sopenharmony_ci /* Standard mode SCL 50/50, tSU:DAT = 250 ns */ 20462306a36Sopenharmony_ci t_high = divisor * 1 / 2; 20562306a36Sopenharmony_ci t_low = divisor * 1 / 2; 20662306a36Sopenharmony_ci t_setup = ns_to_clk(250, clk_mhz); 20762306a36Sopenharmony_ci } else { 20862306a36Sopenharmony_ci /* Fast mode SCL 33/66, tSU:DAT = 100 ns */ 20962306a36Sopenharmony_ci t_high = divisor * 1 / 3; 21062306a36Sopenharmony_ci t_low = divisor * 2 / 3; 21162306a36Sopenharmony_ci t_setup = ns_to_clk(100, clk_mhz); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* SCL High Time */ 21562306a36Sopenharmony_ci writel(t_high, idev->base + SCL_HIGH_PERIOD); 21662306a36Sopenharmony_ci /* SCL Low Time */ 21762306a36Sopenharmony_ci writel(t_low, idev->base + SCL_LOW_PERIOD); 21862306a36Sopenharmony_ci /* SDA Setup Time */ 21962306a36Sopenharmony_ci writel(t_setup, idev->base + SDA_SETUP_TIME); 22062306a36Sopenharmony_ci /* SDA Hold Time, 300ns */ 22162306a36Sopenharmony_ci writel(ns_to_clk(300, clk_mhz), idev->base + SDA_HOLD_TIME); 22262306a36Sopenharmony_ci /* Filter <50ns spikes */ 22362306a36Sopenharmony_ci writel(ns_to_clk(50, clk_mhz), idev->base + SPIKE_FLTR_LEN); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* Configure Time-Out Registers */ 22662306a36Sopenharmony_ci tmo_clk = ns_to_clk(SCL_WAIT_TIMEOUT_NS, clk_mhz); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* Find prescaler value that makes tmo_clk fit in 15-bits counter. */ 22962306a36Sopenharmony_ci for (prescale = 0; prescale < 15; ++prescale) { 23062306a36Sopenharmony_ci if (tmo_clk <= 0x7fff) 23162306a36Sopenharmony_ci break; 23262306a36Sopenharmony_ci tmo_clk >>= 1; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci if (tmo_clk > 0x7fff) 23562306a36Sopenharmony_ci tmo_clk = 0x7fff; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* Prescale divider (log2) */ 23862306a36Sopenharmony_ci writel(prescale, idev->base + TIMER_CLOCK_DIV); 23962306a36Sopenharmony_ci /* Timeout in divided clocks */ 24062306a36Sopenharmony_ci writel(WT_EN | WT_VALUE(tmo_clk), idev->base + WAIT_TIMER_CONTROL); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci /* Mask all master interrupt bits */ 24362306a36Sopenharmony_ci i2c_int_disable(idev, ~0); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci /* Interrupt enable */ 24662306a36Sopenharmony_ci writel(0x01, idev->base + INTERRUPT_ENABLE); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci return 0; 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic int i2c_m_rd(const struct i2c_msg *msg) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci return (msg->flags & I2C_M_RD) != 0; 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic int i2c_m_ten(const struct i2c_msg *msg) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci return (msg->flags & I2C_M_TEN) != 0; 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic int i2c_m_recv_len(const struct i2c_msg *msg) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci return (msg->flags & I2C_M_RECV_LEN) != 0; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci/** 26762306a36Sopenharmony_ci * axxia_i2c_empty_rx_fifo - Fetch data from RX FIFO and update SMBus block 26862306a36Sopenharmony_ci * transfer length if this is the first byte of such a transfer. 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_cistatic int axxia_i2c_empty_rx_fifo(struct axxia_i2c_dev *idev) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci struct i2c_msg *msg = idev->msg_r; 27362306a36Sopenharmony_ci size_t rx_fifo_avail = readl(idev->base + MST_RX_FIFO); 27462306a36Sopenharmony_ci int bytes_to_transfer = min(rx_fifo_avail, msg->len - idev->msg_xfrd_r); 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci while (bytes_to_transfer-- > 0) { 27762306a36Sopenharmony_ci int c = readl(idev->base + MST_DATA); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (idev->msg_xfrd_r == 0 && i2c_m_recv_len(msg)) { 28062306a36Sopenharmony_ci /* 28162306a36Sopenharmony_ci * Check length byte for SMBus block read 28262306a36Sopenharmony_ci */ 28362306a36Sopenharmony_ci if (c <= 0 || c > I2C_SMBUS_BLOCK_MAX) { 28462306a36Sopenharmony_ci idev->msg_err = -EPROTO; 28562306a36Sopenharmony_ci i2c_int_disable(idev, ~MST_STATUS_TSS); 28662306a36Sopenharmony_ci complete(&idev->msg_complete); 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci msg->len = 1 + c; 29062306a36Sopenharmony_ci writel(msg->len, idev->base + MST_RX_XFER); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci msg->buf[idev->msg_xfrd_r++] = c; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci return 0; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci/** 29962306a36Sopenharmony_ci * axxia_i2c_fill_tx_fifo - Fill TX FIFO from current message buffer. 30062306a36Sopenharmony_ci * @return: Number of bytes left to transfer. 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_cistatic int axxia_i2c_fill_tx_fifo(struct axxia_i2c_dev *idev) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct i2c_msg *msg = idev->msg; 30562306a36Sopenharmony_ci size_t tx_fifo_avail = FIFO_SIZE - readl(idev->base + MST_TX_FIFO); 30662306a36Sopenharmony_ci int bytes_to_transfer = min(tx_fifo_avail, msg->len - idev->msg_xfrd); 30762306a36Sopenharmony_ci int ret = msg->len - idev->msg_xfrd - bytes_to_transfer; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci while (bytes_to_transfer-- > 0) 31062306a36Sopenharmony_ci writel(msg->buf[idev->msg_xfrd++], idev->base + MST_DATA); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return ret; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic void axxia_i2c_slv_fifo_event(struct axxia_i2c_dev *idev) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci u32 fifo_status = readl(idev->base + SLV_RX_FIFO); 31862306a36Sopenharmony_ci u8 val; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci dev_dbg(idev->dev, "slave irq fifo_status=0x%x\n", fifo_status); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (fifo_status & SLV_FIFO_DV1) { 32362306a36Sopenharmony_ci if (fifo_status & SLV_FIFO_STRC) 32462306a36Sopenharmony_ci i2c_slave_event(idev->slave, 32562306a36Sopenharmony_ci I2C_SLAVE_WRITE_REQUESTED, &val); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci val = readl(idev->base + SLV_DATA); 32862306a36Sopenharmony_ci i2c_slave_event(idev->slave, I2C_SLAVE_WRITE_RECEIVED, &val); 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci if (fifo_status & SLV_FIFO_STPC) { 33162306a36Sopenharmony_ci readl(idev->base + SLV_DATA); /* dummy read */ 33262306a36Sopenharmony_ci i2c_slave_event(idev->slave, I2C_SLAVE_STOP, &val); 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci if (fifo_status & SLV_FIFO_RSC) 33562306a36Sopenharmony_ci readl(idev->base + SLV_DATA); /* dummy read */ 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic irqreturn_t axxia_i2c_slv_isr(struct axxia_i2c_dev *idev) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci u32 status = readl(idev->base + SLV_INT_STATUS); 34162306a36Sopenharmony_ci u8 val; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci dev_dbg(idev->dev, "slave irq status=0x%x\n", status); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (status & SLV_STATUS_RFH) 34662306a36Sopenharmony_ci axxia_i2c_slv_fifo_event(idev); 34762306a36Sopenharmony_ci if (status & SLV_STATUS_SRS1) { 34862306a36Sopenharmony_ci i2c_slave_event(idev->slave, I2C_SLAVE_READ_REQUESTED, &val); 34962306a36Sopenharmony_ci writel(val, idev->base + SLV_DATA); 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci if (status & SLV_STATUS_SRND1) { 35262306a36Sopenharmony_ci i2c_slave_event(idev->slave, I2C_SLAVE_READ_PROCESSED, &val); 35362306a36Sopenharmony_ci writel(val, idev->base + SLV_DATA); 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci if (status & SLV_STATUS_SRC1) 35662306a36Sopenharmony_ci i2c_slave_event(idev->slave, I2C_SLAVE_STOP, &val); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci writel(INT_SLV, idev->base + INTERRUPT_STATUS); 35962306a36Sopenharmony_ci return IRQ_HANDLED; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic irqreturn_t axxia_i2c_isr(int irq, void *_dev) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci struct axxia_i2c_dev *idev = _dev; 36562306a36Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 36662306a36Sopenharmony_ci u32 status; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci status = readl(idev->base + INTERRUPT_STATUS); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (status & INT_SLV) 37162306a36Sopenharmony_ci ret = axxia_i2c_slv_isr(idev); 37262306a36Sopenharmony_ci if (!(status & INT_MST)) 37362306a36Sopenharmony_ci return ret; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* Read interrupt status bits */ 37662306a36Sopenharmony_ci status = readl(idev->base + MST_INT_STATUS); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (!idev->msg) { 37962306a36Sopenharmony_ci dev_warn(idev->dev, "unexpected interrupt\n"); 38062306a36Sopenharmony_ci goto out; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* RX FIFO needs service? */ 38462306a36Sopenharmony_ci if (i2c_m_rd(idev->msg_r) && (status & MST_STATUS_RFL)) 38562306a36Sopenharmony_ci axxia_i2c_empty_rx_fifo(idev); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* TX FIFO needs service? */ 38862306a36Sopenharmony_ci if (!i2c_m_rd(idev->msg) && (status & MST_STATUS_TFL)) { 38962306a36Sopenharmony_ci if (axxia_i2c_fill_tx_fifo(idev) == 0) 39062306a36Sopenharmony_ci i2c_int_disable(idev, MST_STATUS_TFL); 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (unlikely(status & MST_STATUS_ERR)) { 39462306a36Sopenharmony_ci /* Transfer error */ 39562306a36Sopenharmony_ci i2c_int_disable(idev, ~0); 39662306a36Sopenharmony_ci if (status & MST_STATUS_AL) 39762306a36Sopenharmony_ci idev->msg_err = -EAGAIN; 39862306a36Sopenharmony_ci else if (status & MST_STATUS_NAK) 39962306a36Sopenharmony_ci idev->msg_err = -ENXIO; 40062306a36Sopenharmony_ci else 40162306a36Sopenharmony_ci idev->msg_err = -EIO; 40262306a36Sopenharmony_ci dev_dbg(idev->dev, "error %#x, addr=%#x rx=%u/%u tx=%u/%u\n", 40362306a36Sopenharmony_ci status, 40462306a36Sopenharmony_ci idev->msg->addr, 40562306a36Sopenharmony_ci readl(idev->base + MST_RX_BYTES_XFRD), 40662306a36Sopenharmony_ci readl(idev->base + MST_RX_XFER), 40762306a36Sopenharmony_ci readl(idev->base + MST_TX_BYTES_XFRD), 40862306a36Sopenharmony_ci readl(idev->base + MST_TX_XFER)); 40962306a36Sopenharmony_ci complete(&idev->msg_complete); 41062306a36Sopenharmony_ci } else if (status & MST_STATUS_SCC) { 41162306a36Sopenharmony_ci /* Stop completed */ 41262306a36Sopenharmony_ci i2c_int_disable(idev, ~MST_STATUS_TSS); 41362306a36Sopenharmony_ci complete(&idev->msg_complete); 41462306a36Sopenharmony_ci } else if (status & (MST_STATUS_SNS | MST_STATUS_SS)) { 41562306a36Sopenharmony_ci /* Transfer done */ 41662306a36Sopenharmony_ci int mask = idev->last ? ~0 : ~MST_STATUS_TSS; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci i2c_int_disable(idev, mask); 41962306a36Sopenharmony_ci if (i2c_m_rd(idev->msg_r) && idev->msg_xfrd_r < idev->msg_r->len) 42062306a36Sopenharmony_ci axxia_i2c_empty_rx_fifo(idev); 42162306a36Sopenharmony_ci complete(&idev->msg_complete); 42262306a36Sopenharmony_ci } else if (status & MST_STATUS_TSS) { 42362306a36Sopenharmony_ci /* Transfer timeout */ 42462306a36Sopenharmony_ci idev->msg_err = -ETIMEDOUT; 42562306a36Sopenharmony_ci i2c_int_disable(idev, ~MST_STATUS_TSS); 42662306a36Sopenharmony_ci complete(&idev->msg_complete); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ciout: 43062306a36Sopenharmony_ci /* Clear interrupt */ 43162306a36Sopenharmony_ci writel(INT_MST, idev->base + INTERRUPT_STATUS); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci return IRQ_HANDLED; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic void axxia_i2c_set_addr(struct axxia_i2c_dev *idev, struct i2c_msg *msg) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci u32 addr_1, addr_2; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (i2c_m_ten(msg)) { 44162306a36Sopenharmony_ci /* 10-bit address 44262306a36Sopenharmony_ci * addr_1: 5'b11110 | addr[9:8] | (R/nW) 44362306a36Sopenharmony_ci * addr_2: addr[7:0] 44462306a36Sopenharmony_ci */ 44562306a36Sopenharmony_ci addr_1 = 0xF0 | ((msg->addr >> 7) & 0x06); 44662306a36Sopenharmony_ci if (i2c_m_rd(msg)) 44762306a36Sopenharmony_ci addr_1 |= 1; /* Set the R/nW bit of the address */ 44862306a36Sopenharmony_ci addr_2 = msg->addr & 0xFF; 44962306a36Sopenharmony_ci } else { 45062306a36Sopenharmony_ci /* 7-bit address 45162306a36Sopenharmony_ci * addr_1: addr[6:0] | (R/nW) 45262306a36Sopenharmony_ci * addr_2: dont care 45362306a36Sopenharmony_ci */ 45462306a36Sopenharmony_ci addr_1 = i2c_8bit_addr_from_msg(msg); 45562306a36Sopenharmony_ci addr_2 = 0; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci writel(addr_1, idev->base + MST_ADDR_1); 45962306a36Sopenharmony_ci writel(addr_2, idev->base + MST_ADDR_2); 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci/* The NAK interrupt will be sent _before_ issuing STOP command 46362306a36Sopenharmony_ci * so the controller might still be busy processing it. No 46462306a36Sopenharmony_ci * interrupt will be sent at the end so we have to poll for it 46562306a36Sopenharmony_ci */ 46662306a36Sopenharmony_cistatic int axxia_i2c_handle_seq_nak(struct axxia_i2c_dev *idev) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci unsigned long timeout = jiffies + I2C_XFER_TIMEOUT; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci do { 47162306a36Sopenharmony_ci if ((readl(idev->base + MST_COMMAND) & CMD_BUSY) == 0) 47262306a36Sopenharmony_ci return 0; 47362306a36Sopenharmony_ci usleep_range(1, 100); 47462306a36Sopenharmony_ci } while (time_before(jiffies, timeout)); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci return -ETIMEDOUT; 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic int axxia_i2c_xfer_seq(struct axxia_i2c_dev *idev, struct i2c_msg msgs[]) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci u32 int_mask = MST_STATUS_ERR | MST_STATUS_SS | MST_STATUS_RFL; 48262306a36Sopenharmony_ci u32 rlen = i2c_m_recv_len(&msgs[1]) ? I2C_SMBUS_BLOCK_MAX : msgs[1].len; 48362306a36Sopenharmony_ci unsigned long time_left; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci axxia_i2c_set_addr(idev, &msgs[0]); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci writel(msgs[0].len, idev->base + MST_TX_XFER); 48862306a36Sopenharmony_ci writel(rlen, idev->base + MST_RX_XFER); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci idev->msg = &msgs[0]; 49162306a36Sopenharmony_ci idev->msg_r = &msgs[1]; 49262306a36Sopenharmony_ci idev->msg_xfrd = 0; 49362306a36Sopenharmony_ci idev->msg_xfrd_r = 0; 49462306a36Sopenharmony_ci idev->last = true; 49562306a36Sopenharmony_ci axxia_i2c_fill_tx_fifo(idev); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci writel(CMD_SEQUENCE, idev->base + MST_COMMAND); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci reinit_completion(&idev->msg_complete); 50062306a36Sopenharmony_ci i2c_int_enable(idev, int_mask); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&idev->msg_complete, 50362306a36Sopenharmony_ci I2C_XFER_TIMEOUT); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if (idev->msg_err == -ENXIO) { 50662306a36Sopenharmony_ci if (axxia_i2c_handle_seq_nak(idev)) 50762306a36Sopenharmony_ci axxia_i2c_init(idev); 50862306a36Sopenharmony_ci } else if (readl(idev->base + MST_COMMAND) & CMD_BUSY) { 50962306a36Sopenharmony_ci dev_warn(idev->dev, "busy after xfer\n"); 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (time_left == 0) { 51362306a36Sopenharmony_ci idev->msg_err = -ETIMEDOUT; 51462306a36Sopenharmony_ci i2c_recover_bus(&idev->adapter); 51562306a36Sopenharmony_ci axxia_i2c_init(idev); 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (unlikely(idev->msg_err) && idev->msg_err != -ENXIO) 51962306a36Sopenharmony_ci axxia_i2c_init(idev); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci return idev->msg_err; 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_cistatic int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg, 52562306a36Sopenharmony_ci bool last) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci u32 int_mask = MST_STATUS_ERR; 52862306a36Sopenharmony_ci u32 rx_xfer, tx_xfer; 52962306a36Sopenharmony_ci unsigned long time_left; 53062306a36Sopenharmony_ci unsigned int wt_value; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci idev->msg = msg; 53362306a36Sopenharmony_ci idev->msg_r = msg; 53462306a36Sopenharmony_ci idev->msg_xfrd = 0; 53562306a36Sopenharmony_ci idev->msg_xfrd_r = 0; 53662306a36Sopenharmony_ci idev->last = last; 53762306a36Sopenharmony_ci reinit_completion(&idev->msg_complete); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci axxia_i2c_set_addr(idev, msg); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (i2c_m_rd(msg)) { 54262306a36Sopenharmony_ci /* I2C read transfer */ 54362306a36Sopenharmony_ci rx_xfer = i2c_m_recv_len(msg) ? I2C_SMBUS_BLOCK_MAX : msg->len; 54462306a36Sopenharmony_ci tx_xfer = 0; 54562306a36Sopenharmony_ci } else { 54662306a36Sopenharmony_ci /* I2C write transfer */ 54762306a36Sopenharmony_ci rx_xfer = 0; 54862306a36Sopenharmony_ci tx_xfer = msg->len; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci writel(rx_xfer, idev->base + MST_RX_XFER); 55262306a36Sopenharmony_ci writel(tx_xfer, idev->base + MST_TX_XFER); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (i2c_m_rd(msg)) 55562306a36Sopenharmony_ci int_mask |= MST_STATUS_RFL; 55662306a36Sopenharmony_ci else if (axxia_i2c_fill_tx_fifo(idev) != 0) 55762306a36Sopenharmony_ci int_mask |= MST_STATUS_TFL; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci wt_value = WT_VALUE(readl(idev->base + WAIT_TIMER_CONTROL)); 56062306a36Sopenharmony_ci /* Disable wait timer temporarly */ 56162306a36Sopenharmony_ci writel(wt_value, idev->base + WAIT_TIMER_CONTROL); 56262306a36Sopenharmony_ci /* Check if timeout error happened */ 56362306a36Sopenharmony_ci if (idev->msg_err) 56462306a36Sopenharmony_ci goto out; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (!last) { 56762306a36Sopenharmony_ci writel(CMD_MANUAL, idev->base + MST_COMMAND); 56862306a36Sopenharmony_ci int_mask |= MST_STATUS_SNS; 56962306a36Sopenharmony_ci } else { 57062306a36Sopenharmony_ci writel(CMD_AUTO, idev->base + MST_COMMAND); 57162306a36Sopenharmony_ci int_mask |= MST_STATUS_SS; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci writel(WT_EN | wt_value, idev->base + WAIT_TIMER_CONTROL); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci i2c_int_enable(idev, int_mask); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci time_left = wait_for_completion_timeout(&idev->msg_complete, 57962306a36Sopenharmony_ci I2C_XFER_TIMEOUT); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci i2c_int_disable(idev, int_mask); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci if (readl(idev->base + MST_COMMAND) & CMD_BUSY) 58462306a36Sopenharmony_ci dev_warn(idev->dev, "busy after xfer\n"); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci if (time_left == 0) { 58762306a36Sopenharmony_ci idev->msg_err = -ETIMEDOUT; 58862306a36Sopenharmony_ci i2c_recover_bus(&idev->adapter); 58962306a36Sopenharmony_ci axxia_i2c_init(idev); 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ciout: 59362306a36Sopenharmony_ci if (unlikely(idev->msg_err) && idev->msg_err != -ENXIO && 59462306a36Sopenharmony_ci idev->msg_err != -ETIMEDOUT) 59562306a36Sopenharmony_ci axxia_i2c_init(idev); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci return idev->msg_err; 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci/* This function checks if the msgs[] array contains messages compatible with 60162306a36Sopenharmony_ci * Sequence mode of operation. This mode assumes there will be exactly one 60262306a36Sopenharmony_ci * write of non-zero length followed by exactly one read of non-zero length, 60362306a36Sopenharmony_ci * both targeted at the same client device. 60462306a36Sopenharmony_ci */ 60562306a36Sopenharmony_cistatic bool axxia_i2c_sequence_ok(struct i2c_msg msgs[], int num) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci return num == SEQ_LEN && !i2c_m_rd(&msgs[0]) && i2c_m_rd(&msgs[1]) && 60862306a36Sopenharmony_ci msgs[0].len > 0 && msgs[0].len <= FIFO_SIZE && 60962306a36Sopenharmony_ci msgs[1].len > 0 && msgs[0].addr == msgs[1].addr; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_cistatic int 61362306a36Sopenharmony_ciaxxia_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci struct axxia_i2c_dev *idev = i2c_get_adapdata(adap); 61662306a36Sopenharmony_ci int i; 61762306a36Sopenharmony_ci int ret = 0; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci idev->msg_err = 0; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci if (axxia_i2c_sequence_ok(msgs, num)) { 62262306a36Sopenharmony_ci ret = axxia_i2c_xfer_seq(idev, msgs); 62362306a36Sopenharmony_ci return ret ? : SEQ_LEN; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci i2c_int_enable(idev, MST_STATUS_TSS); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci for (i = 0; ret == 0 && i < num; ++i) 62962306a36Sopenharmony_ci ret = axxia_i2c_xfer_msg(idev, &msgs[i], i == (num - 1)); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci return ret ? : i; 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic int axxia_i2c_get_scl(struct i2c_adapter *adap) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci struct axxia_i2c_dev *idev = i2c_get_adapdata(adap); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci return !!(readl(idev->base + I2C_BUS_MONITOR) & BM_SCLS); 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic void axxia_i2c_set_scl(struct i2c_adapter *adap, int val) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci struct axxia_i2c_dev *idev = i2c_get_adapdata(adap); 64462306a36Sopenharmony_ci u32 tmp; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci /* Preserve SDA Control */ 64762306a36Sopenharmony_ci tmp = readl(idev->base + I2C_BUS_MONITOR) & BM_SDAC; 64862306a36Sopenharmony_ci if (!val) 64962306a36Sopenharmony_ci tmp |= BM_SCLC; 65062306a36Sopenharmony_ci writel(tmp, idev->base + I2C_BUS_MONITOR); 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic int axxia_i2c_get_sda(struct i2c_adapter *adap) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci struct axxia_i2c_dev *idev = i2c_get_adapdata(adap); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci return !!(readl(idev->base + I2C_BUS_MONITOR) & BM_SDAS); 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic struct i2c_bus_recovery_info axxia_i2c_recovery_info = { 66162306a36Sopenharmony_ci .recover_bus = i2c_generic_scl_recovery, 66262306a36Sopenharmony_ci .get_scl = axxia_i2c_get_scl, 66362306a36Sopenharmony_ci .set_scl = axxia_i2c_set_scl, 66462306a36Sopenharmony_ci .get_sda = axxia_i2c_get_sda, 66562306a36Sopenharmony_ci}; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_cistatic u32 axxia_i2c_func(struct i2c_adapter *adap) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci u32 caps = (I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | 67062306a36Sopenharmony_ci I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA); 67162306a36Sopenharmony_ci return caps; 67262306a36Sopenharmony_ci} 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cistatic int axxia_i2c_reg_slave(struct i2c_client *slave) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci struct axxia_i2c_dev *idev = i2c_get_adapdata(slave->adapter); 67762306a36Sopenharmony_ci u32 slv_int_mask = SLV_STATUS_RFH; 67862306a36Sopenharmony_ci u32 dec_ctl; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (idev->slave) 68162306a36Sopenharmony_ci return -EBUSY; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci idev->slave = slave; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci /* Enable slave mode as well */ 68662306a36Sopenharmony_ci writel(GLOBAL_MST_EN | GLOBAL_SLV_EN, idev->base + GLOBAL_CONTROL); 68762306a36Sopenharmony_ci writel(INT_MST | INT_SLV, idev->base + INTERRUPT_ENABLE); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci /* Set slave address */ 69062306a36Sopenharmony_ci dec_ctl = SLV_ADDR_DEC_SA1E; 69162306a36Sopenharmony_ci if (slave->flags & I2C_CLIENT_TEN) 69262306a36Sopenharmony_ci dec_ctl |= SLV_ADDR_DEC_SA1M; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci writel(SLV_RX_ACSA1, idev->base + SLV_RX_CTL); 69562306a36Sopenharmony_ci writel(dec_ctl, idev->base + SLV_ADDR_DEC_CTL); 69662306a36Sopenharmony_ci writel(slave->addr, idev->base + SLV_ADDR_1); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci /* Enable interrupts */ 69962306a36Sopenharmony_ci slv_int_mask |= SLV_STATUS_SRS1 | SLV_STATUS_SRRS1 | SLV_STATUS_SRND1; 70062306a36Sopenharmony_ci slv_int_mask |= SLV_STATUS_SRC1; 70162306a36Sopenharmony_ci writel(slv_int_mask, idev->base + SLV_INT_ENABLE); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci return 0; 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic int axxia_i2c_unreg_slave(struct i2c_client *slave) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci struct axxia_i2c_dev *idev = i2c_get_adapdata(slave->adapter); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* Disable slave mode */ 71162306a36Sopenharmony_ci writel(GLOBAL_MST_EN, idev->base + GLOBAL_CONTROL); 71262306a36Sopenharmony_ci writel(INT_MST, idev->base + INTERRUPT_ENABLE); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci synchronize_irq(idev->irq); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci idev->slave = NULL; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci return 0; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic const struct i2c_algorithm axxia_i2c_algo = { 72262306a36Sopenharmony_ci .master_xfer = axxia_i2c_xfer, 72362306a36Sopenharmony_ci .functionality = axxia_i2c_func, 72462306a36Sopenharmony_ci .reg_slave = axxia_i2c_reg_slave, 72562306a36Sopenharmony_ci .unreg_slave = axxia_i2c_unreg_slave, 72662306a36Sopenharmony_ci}; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic const struct i2c_adapter_quirks axxia_i2c_quirks = { 72962306a36Sopenharmony_ci .max_read_len = 255, 73062306a36Sopenharmony_ci .max_write_len = 255, 73162306a36Sopenharmony_ci}; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic int axxia_i2c_probe(struct platform_device *pdev) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 73662306a36Sopenharmony_ci struct axxia_i2c_dev *idev = NULL; 73762306a36Sopenharmony_ci void __iomem *base; 73862306a36Sopenharmony_ci int ret = 0; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL); 74162306a36Sopenharmony_ci if (!idev) 74262306a36Sopenharmony_ci return -ENOMEM; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci base = devm_platform_ioremap_resource(pdev, 0); 74562306a36Sopenharmony_ci if (IS_ERR(base)) 74662306a36Sopenharmony_ci return PTR_ERR(base); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci idev->irq = platform_get_irq(pdev, 0); 74962306a36Sopenharmony_ci if (idev->irq < 0) 75062306a36Sopenharmony_ci return idev->irq; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci idev->i2c_clk = devm_clk_get(&pdev->dev, "i2c"); 75362306a36Sopenharmony_ci if (IS_ERR(idev->i2c_clk)) { 75462306a36Sopenharmony_ci dev_err(&pdev->dev, "missing clock\n"); 75562306a36Sopenharmony_ci return PTR_ERR(idev->i2c_clk); 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci idev->base = base; 75962306a36Sopenharmony_ci idev->dev = &pdev->dev; 76062306a36Sopenharmony_ci init_completion(&idev->msg_complete); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci of_property_read_u32(np, "clock-frequency", &idev->bus_clk_rate); 76362306a36Sopenharmony_ci if (idev->bus_clk_rate == 0) 76462306a36Sopenharmony_ci idev->bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ; /* default clock rate */ 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci ret = clk_prepare_enable(idev->i2c_clk); 76762306a36Sopenharmony_ci if (ret) { 76862306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to enable clock\n"); 76962306a36Sopenharmony_ci return ret; 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci ret = axxia_i2c_init(idev); 77362306a36Sopenharmony_ci if (ret) { 77462306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to initialize\n"); 77562306a36Sopenharmony_ci goto error_disable_clk; 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, idev->irq, axxia_i2c_isr, 0, 77962306a36Sopenharmony_ci pdev->name, idev); 78062306a36Sopenharmony_ci if (ret) { 78162306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to claim IRQ%d\n", idev->irq); 78262306a36Sopenharmony_ci goto error_disable_clk; 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci i2c_set_adapdata(&idev->adapter, idev); 78662306a36Sopenharmony_ci strscpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name)); 78762306a36Sopenharmony_ci idev->adapter.owner = THIS_MODULE; 78862306a36Sopenharmony_ci idev->adapter.algo = &axxia_i2c_algo; 78962306a36Sopenharmony_ci idev->adapter.bus_recovery_info = &axxia_i2c_recovery_info; 79062306a36Sopenharmony_ci idev->adapter.quirks = &axxia_i2c_quirks; 79162306a36Sopenharmony_ci idev->adapter.dev.parent = &pdev->dev; 79262306a36Sopenharmony_ci idev->adapter.dev.of_node = pdev->dev.of_node; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci platform_set_drvdata(pdev, idev); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci ret = i2c_add_adapter(&idev->adapter); 79762306a36Sopenharmony_ci if (ret) 79862306a36Sopenharmony_ci goto error_disable_clk; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci return 0; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cierror_disable_clk: 80362306a36Sopenharmony_ci clk_disable_unprepare(idev->i2c_clk); 80462306a36Sopenharmony_ci return ret; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cistatic void axxia_i2c_remove(struct platform_device *pdev) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci struct axxia_i2c_dev *idev = platform_get_drvdata(pdev); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci clk_disable_unprepare(idev->i2c_clk); 81262306a36Sopenharmony_ci i2c_del_adapter(&idev->adapter); 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci/* Match table for of_platform binding */ 81662306a36Sopenharmony_cistatic const struct of_device_id axxia_i2c_of_match[] = { 81762306a36Sopenharmony_ci { .compatible = "lsi,api2c", }, 81862306a36Sopenharmony_ci {}, 81962306a36Sopenharmony_ci}; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, axxia_i2c_of_match); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_cistatic struct platform_driver axxia_i2c_driver = { 82462306a36Sopenharmony_ci .probe = axxia_i2c_probe, 82562306a36Sopenharmony_ci .remove_new = axxia_i2c_remove, 82662306a36Sopenharmony_ci .driver = { 82762306a36Sopenharmony_ci .name = "axxia-i2c", 82862306a36Sopenharmony_ci .of_match_table = axxia_i2c_of_match, 82962306a36Sopenharmony_ci }, 83062306a36Sopenharmony_ci}; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cimodule_platform_driver(axxia_i2c_driver); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ciMODULE_DESCRIPTION("Axxia I2C Bus driver"); 83562306a36Sopenharmony_ciMODULE_AUTHOR("Anders Berg <anders.berg@lsi.com>"); 83662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 837