1
0
This repository has been archived on 2025-07-31. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
orange_kernel/drivers/i2c/busses/i2c-x1.c
2025-03-18 10:29:27 +08:00

2187 lines
53 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2023 Ky
*
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/reset.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/timer.h>
#include <linux/time.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/i2c.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/scatterlist.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/reboot.h>
#include <linux/of_device.h>
#include <linux/rpmsg.h>
#include "i2c-x1.h"
#ifdef CONFIG_SOC_KY_X1
#define STARTUP_MSG "startup"
#define IRQUP_MSG "irqon"
struct instance_data {
struct rpmsg_device *rpdev;
struct ky_i2c_dev *ky_i2c;
};
static unsigned long long private_data[2];
static const struct of_device_id r_ky_i2c_dt_match[];
#endif
static inline u32 ky_i2c_read_reg(struct ky_i2c_dev *ky_i2c, int reg)
{
return readl(ky_i2c->mapbase + reg);
}
static inline void
ky_i2c_write_reg(struct ky_i2c_dev *ky_i2c, int reg, u32 val)
{
writel(val, ky_i2c->mapbase + reg);
}
static void ky_i2c_enable(struct ky_i2c_dev *ky_i2c)
{
ky_i2c_write_reg(ky_i2c, REG_CR,
ky_i2c_read_reg(ky_i2c, REG_CR) | CR_IUE);
}
static void ky_i2c_disable(struct ky_i2c_dev *ky_i2c)
{
ky_i2c->i2c_ctrl_reg_value = ky_i2c_read_reg(ky_i2c, REG_CR) & ~CR_IUE;
ky_i2c_write_reg(ky_i2c, REG_CR, ky_i2c->i2c_ctrl_reg_value);
}
static void ky_i2c_flush_fifo_buffer(struct ky_i2c_dev *ky_i2c)
{
/* flush REG_WFIFO_WPTR and REG_WFIFO_RPTR */
ky_i2c_write_reg(ky_i2c, REG_WFIFO_WPTR, 0);
ky_i2c_write_reg(ky_i2c, REG_WFIFO_RPTR, 0);
/* flush REG_RFIFO_WPTR and REG_RFIFO_RPTR */
ky_i2c_write_reg(ky_i2c, REG_RFIFO_WPTR, 0);
ky_i2c_write_reg(ky_i2c, REG_RFIFO_RPTR, 0);
}
static void ky_i2c_controller_reset(struct ky_i2c_dev *ky_i2c)
{
/* i2c controller reset */
ky_i2c_write_reg(ky_i2c, REG_CR, CR_UR);
udelay(5);
ky_i2c_write_reg(ky_i2c, REG_CR, 0);
/* set load counter register */
if (ky_i2c->i2c_lcr)
ky_i2c_write_reg(ky_i2c, REG_LCR, ky_i2c->i2c_lcr);
/* set wait counter register */
if (ky_i2c->i2c_wcr)
ky_i2c_write_reg(ky_i2c, REG_WCR, ky_i2c->i2c_wcr);
}
static void ky_i2c_bus_reset(struct ky_i2c_dev *ky_i2c)
{
int clk_cnt = 0;
u32 bus_status;
/* if bus is locked, reset unit. 0: locked */
bus_status = ky_i2c_read_reg(ky_i2c, REG_BMR);
if (!(bus_status & BMR_SDA) || !(bus_status & BMR_SCL)) {
ky_i2c_controller_reset(ky_i2c);
usleep_range(10, 20);
/* check scl status again */
bus_status = ky_i2c_read_reg(ky_i2c, REG_BMR);
if (!(bus_status & BMR_SCL))
dev_alert(ky_i2c->dev, "unit reset failed\n");
}
while (clk_cnt < 9) {
/* check whether the SDA is still locked by slave */
bus_status = ky_i2c_read_reg(ky_i2c, REG_BMR);
if (bus_status & BMR_SDA)
break;
/* if still locked, send one clk to slave to request release */
ky_i2c_write_reg(ky_i2c, REG_RST_CYC, 0x1);
ky_i2c_write_reg(ky_i2c, REG_CR, CR_RSTREQ);
usleep_range(20, 30);
clk_cnt++;
}
bus_status = ky_i2c_read_reg(ky_i2c, REG_BMR);
if (clk_cnt >= 9 && !(bus_status & BMR_SDA))
dev_alert(ky_i2c->dev, "bus reset clk reaches the max 9-clocks\n");
else
dev_alert(ky_i2c->dev, "bus reset, send clk: %d\n", clk_cnt);
}
static void ky_i2c_reset(struct ky_i2c_dev *ky_i2c)
{
ky_i2c_controller_reset(ky_i2c);
}
static int ky_i2c_recover_bus_busy(struct ky_i2c_dev *ky_i2c)
{
int timeout;
int cnt, ret = 0;
if (ky_i2c->high_mode)
timeout = 1000; /* 1000us */
else
timeout = 1500; /* 1500us */
cnt = KY_I2C_BUS_RECOVER_TIMEOUT / timeout;
if (likely(!(ky_i2c_read_reg(ky_i2c, REG_SR) & (SR_UB | SR_IBB))))
return 0;
/* wait unit and bus to recover idle */
while (unlikely(ky_i2c_read_reg(ky_i2c, REG_SR) & (SR_UB | SR_IBB))) {
if (cnt-- <= 0)
break;
usleep_range(timeout / 2, timeout);
}
if (unlikely(cnt <= 0)) {
/* reset controller */
ky_i2c_reset(ky_i2c);
ret = -EAGAIN;
}
return ret;
}
static void ky_i2c_check_bus_release(struct ky_i2c_dev *ky_i2c)
{
/* in case bus is not released after transfer completes */
if (unlikely(ky_i2c_read_reg(ky_i2c, REG_SR) & SR_EBB)) {
ky_i2c_bus_reset(ky_i2c);
usleep_range(90, 150);
}
}
static void ky_i2c_unit_init(struct ky_i2c_dev *ky_i2c)
{
u32 cr_val = 0;
/*
* Unmask interrupt bits for all xfer mode:
* bus error, arbitration loss detected.
* For transaction complete signal, we use master stop
* interrupt, so we don't need to unmask CR_TXDONEIE.
*/
cr_val |= CR_BEIE | CR_ALDIE;
if (likely(ky_i2c->xfer_mode == KY_I2C_MODE_INTERRUPT))
/*
* Unmask interrupt bits for interrupt xfer mode:
* DBR rx full.
* For tx empty interrupt CR_DTEIE, we only
* need to enable when trigger byte transfer to start
* data sending.
*/
cr_val |= CR_DRFIE;
else if (likely(ky_i2c->xfer_mode == KY_I2C_MODE_FIFO))
/* enable i2c FIFO mode*/
cr_val |= CR_FIFOEN;
else if (ky_i2c->xfer_mode == KY_I2C_MODE_DMA)
/* enable i2c DMA mode*/
cr_val |= CR_DMAEN | CR_FIFOEN;
/* set speed bits */
if (ky_i2c->fast_mode)
cr_val |= CR_MODE_FAST;
if (ky_i2c->high_mode)
cr_val |= CR_MODE_HIGH | CR_GPIOEN;
/* disable response to general call */
cr_val |= CR_GCD;
/* enable SCL clock output */
cr_val |= CR_SCLE;
/* enable master stop detected */
cr_val |= CR_MSDE | CR_MSDIE;
/* disable int to use pio xfer mode*/
if (unlikely(ky_i2c->xfer_mode == KY_I2C_MODE_PIO))
cr_val &= ~(CR_ALDIE | CR_BEIE | CR_MSDIE | CR_DTEIE);
ky_i2c_write_reg(ky_i2c, REG_CR, cr_val);
}
static void ky_i2c_trigger_byte_xfer(struct ky_i2c_dev *ky_i2c)
{
u32 cr_val = ky_i2c_read_reg(ky_i2c, REG_CR);
/* send start pulse */
cr_val &= ~CR_STOP;
if (ky_i2c->xfer_mode == KY_I2C_MODE_PIO)
cr_val |= CR_START | CR_TB;
else
cr_val |= CR_START | CR_TB | CR_DTEIE;
ky_i2c_write_reg(ky_i2c, REG_CR, cr_val);
}
static inline void
ky_i2c_clear_int_status(struct ky_i2c_dev *ky_i2c, u32 mask)
{
ky_i2c_write_reg(ky_i2c, REG_SR, mask & KY_I2C_INT_STATUS_MASK);
}
static bool ky_i2c_is_last_byte_to_send(struct ky_i2c_dev *ky_i2c)
{
return (ky_i2c->tx_cnt == ky_i2c->cur_msg->len &&
ky_i2c->msg_idx == ky_i2c->num - 1) ? true : false;
}
static bool ky_i2c_is_last_byte_to_receive(struct ky_i2c_dev *ky_i2c)
{
/*
* if the message length is received from slave device,
* should at least to read out the length byte from slave.
*/
if (unlikely((ky_i2c->cur_msg->flags & I2C_M_RECV_LEN) &&
!ky_i2c->smbus_rcv_len)) {
return false;
} else {
return (ky_i2c->rx_cnt == ky_i2c->cur_msg->len - 1 &&
ky_i2c->msg_idx == ky_i2c->num - 1) ? true : false;
}
}
static void ky_i2c_mark_rw_flag(struct ky_i2c_dev *ky_i2c)
{
if (ky_i2c->cur_msg->flags & I2C_M_RD) {
ky_i2c->is_rx = true;
ky_i2c->slave_addr_rw =
((ky_i2c->cur_msg->addr & 0x7f) << 1) | 1;
} else {
ky_i2c->is_rx = false;
ky_i2c->slave_addr_rw = (ky_i2c->cur_msg->addr & 0x7f) << 1;
}
}
static void ky_i2c_byte_xfer_send_master_code(struct ky_i2c_dev *ky_i2c)
{
u32 cr_val = ky_i2c_read_reg(ky_i2c, REG_CR);
ky_i2c->phase = KY_I2C_XFER_MASTER_CODE;
ky_i2c_write_reg(ky_i2c, REG_DBR, ky_i2c->master_code);
cr_val &= ~(CR_STOP | CR_ALDIE);
/* high mode: enable gpio to let I2C core generates SCL clock */
cr_val |= CR_GPIOEN | CR_START | CR_TB | CR_DTEIE;
ky_i2c_write_reg(ky_i2c, REG_CR, cr_val);
}
static void ky_i2c_byte_xfer_send_slave_addr(struct ky_i2c_dev *ky_i2c)
{
ky_i2c->phase = KY_I2C_XFER_SLAVE_ADDR;
/* write slave address to DBR for interrupt mode */
ky_i2c_write_reg(ky_i2c, REG_DBR, ky_i2c->slave_addr_rw);
ky_i2c_trigger_byte_xfer(ky_i2c);
}
static int ky_i2c_byte_xfer(struct ky_i2c_dev *ky_i2c);
static int ky_i2c_byte_xfer_next_msg(struct ky_i2c_dev *ky_i2c);
static int ky_i2c_byte_xfer_body(struct ky_i2c_dev *ky_i2c)
{
int ret = 0;
u8 msglen = 0;
u32 cr_val = ky_i2c_read_reg(ky_i2c, REG_CR);
cr_val &= ~(CR_TB | CR_ACKNAK | CR_STOP | CR_START);
ky_i2c->phase = KY_I2C_XFER_BODY;
if (ky_i2c->i2c_status & SR_IRF) { /* i2c receive full */
/* if current is transmit mode, ignore this signal */
if (!ky_i2c->is_rx)
return 0;
/*
* if the message length is received from slave device,
* according to i2c spec, we should restrict the length size.
*/
if (unlikely((ky_i2c->cur_msg->flags & I2C_M_RECV_LEN) &&
!ky_i2c->smbus_rcv_len)) {
ky_i2c->smbus_rcv_len = true;
msglen = (u8)ky_i2c_read_reg(ky_i2c, REG_DBR);
if ((msglen == 0) ||
(msglen > I2C_SMBUS_BLOCK_MAX)) {
dev_err(ky_i2c->dev,
"SMbus len out of range\n");
*ky_i2c->msg_buf++ = 0;
ky_i2c->rx_cnt = ky_i2c->cur_msg->len;
cr_val |= CR_STOP | CR_ACKNAK;
cr_val |= CR_ALDIE | CR_TB;
ky_i2c_write_reg(ky_i2c, REG_CR, cr_val);
return 0;
} else {
*ky_i2c->msg_buf++ = msglen;
ky_i2c->cur_msg->len = msglen + 1;
ky_i2c->rx_cnt++;
}
} else {
if (ky_i2c->rx_cnt < ky_i2c->cur_msg->len) {
*ky_i2c->msg_buf++ =
ky_i2c_read_reg(ky_i2c, REG_DBR);
ky_i2c->rx_cnt++;
}
}
/* if transfer completes, ISR will handle it */
if (ky_i2c->i2c_status & (SR_MSD | SR_ACKNAK))
return 0;
/* trigger next byte receive */
if (ky_i2c->rx_cnt < ky_i2c->cur_msg->len) {
/* send stop pulse for last byte of last msg */
if (ky_i2c_is_last_byte_to_receive(ky_i2c))
cr_val |= CR_STOP | CR_ACKNAK;
cr_val |= CR_ALDIE | CR_TB;
ky_i2c_write_reg(ky_i2c, REG_CR, cr_val);
} else if (ky_i2c->msg_idx < ky_i2c->num - 1) {
ret = ky_i2c_byte_xfer_next_msg(ky_i2c);
} else {
/*
* For this branch, we do nothing, here the receive
* transfer is already done, the master stop interrupt
* should be generated to complete this transaction.
*/
}
} else if (ky_i2c->i2c_status & SR_ITE) { /* i2c transmit empty */
/* MSD comes with ITE */
if (ky_i2c->i2c_status & SR_MSD)
return ret;
if (ky_i2c->i2c_status & SR_RWM) { /* receive mode */
/* if current is transmit mode, ignore this signal */
if (!ky_i2c->is_rx)
return 0;
if (ky_i2c_is_last_byte_to_receive(ky_i2c))
cr_val |= CR_STOP | CR_ACKNAK;
/* trigger next byte receive */
cr_val |= CR_ALDIE | CR_TB;
/*
* Mask transmit empty interrupt to avoid useless tx
* interrupt signal after switch to receive mode, the
* next expected is receive full interrupt signal.
*/
cr_val &= ~CR_DTEIE;
ky_i2c_write_reg(ky_i2c, REG_CR, cr_val);
} else { /* transmit mode */
/* if current is receive mode, ignore this signal */
if (ky_i2c->is_rx)
return 0;
if (ky_i2c->tx_cnt < ky_i2c->cur_msg->len) {
ky_i2c_write_reg(ky_i2c, REG_DBR,
*ky_i2c->msg_buf++);
ky_i2c->tx_cnt++;
/* send stop pulse for last byte of last msg */
if (ky_i2c_is_last_byte_to_send(ky_i2c))
cr_val |= CR_STOP;
cr_val |= CR_ALDIE | CR_TB;
ky_i2c_write_reg(ky_i2c, REG_CR, cr_val);
} else if (ky_i2c->msg_idx < ky_i2c->num - 1) {
ret = ky_i2c_byte_xfer_next_msg(ky_i2c);
} else {
/*
* For this branch, we do nothing, here the
* sending transfer is already done, the master
* stop interrupt should be generated to
* complete this transaction.
*/
}
}
}
return ret;
}
static int ky_i2c_byte_xfer_next_msg(struct ky_i2c_dev *ky_i2c)
{
if (ky_i2c->msg_idx == ky_i2c->num - 1)
return 0;
ky_i2c->msg_idx++;
ky_i2c->cur_msg = ky_i2c->msgs + ky_i2c->msg_idx;
ky_i2c->msg_buf = ky_i2c->cur_msg->buf;
ky_i2c->rx_cnt = 0;
ky_i2c->tx_cnt = 0;
ky_i2c->i2c_err = 0;
ky_i2c->i2c_status = 0;
ky_i2c->smbus_rcv_len = false;
ky_i2c->phase = KY_I2C_XFER_IDLE;
ky_i2c_mark_rw_flag(ky_i2c);
return ky_i2c_byte_xfer(ky_i2c);
}
static void ky_i2c_fifo_xfer_fill_buffer(struct ky_i2c_dev *ky_i2c)
{
int finish, count = 0, fill = 0;
u32 data = 0;
u32 data_buf[KY_I2C_TX_FIFO_DEPTH * 2];
int data_cnt = 0, i;
unsigned long flags;
while (ky_i2c->msg_idx < ky_i2c->num) {
ky_i2c_mark_rw_flag(ky_i2c);
if (ky_i2c->is_rx)
finish = ky_i2c->rx_cnt;
else
finish = ky_i2c->tx_cnt;
/* write master code to fifo buffer */
if (ky_i2c->high_mode && ky_i2c->is_xfer_start) {
data = ky_i2c->master_code;
data |= WFIFO_CTRL_TB | WFIFO_CTRL_START;
data_buf[data_cnt++] = data;
fill += 2;
count = min_t(size_t, ky_i2c->cur_msg->len - finish,
KY_I2C_TX_FIFO_DEPTH - fill);
} else {
fill += 1;
count = min_t(size_t, ky_i2c->cur_msg->len - finish,
KY_I2C_TX_FIFO_DEPTH - fill);
}
ky_i2c->is_xfer_start = false;
fill += count;
data = ky_i2c->slave_addr_rw;
data |= WFIFO_CTRL_TB | WFIFO_CTRL_START;
/* write slave address to fifo buffer */
data_buf[data_cnt++] = data;
if (ky_i2c->is_rx) {
ky_i2c->rx_cnt += count;
if (ky_i2c->rx_cnt == ky_i2c->cur_msg->len &&
ky_i2c->msg_idx == ky_i2c->num - 1)
count -= 1;
while (count > 0) {
data = *ky_i2c->msg_buf | WFIFO_CTRL_TB;
data_buf[data_cnt++] = data;
ky_i2c->msg_buf++;
count--;
}
if (ky_i2c->rx_cnt == ky_i2c->cur_msg->len &&
ky_i2c->msg_idx == ky_i2c->num - 1) {
data = *ky_i2c->msg_buf++;
data = ky_i2c->slave_addr_rw | WFIFO_CTRL_TB |
WFIFO_CTRL_STOP | WFIFO_CTRL_ACKNAK;
data_buf[data_cnt++] = data;
}
} else {
ky_i2c->tx_cnt += count;
if (ky_i2c_is_last_byte_to_send(ky_i2c))
count -= 1;
while (count > 0) {
data = *ky_i2c->msg_buf | WFIFO_CTRL_TB;
data_buf[data_cnt++] = data;
ky_i2c->msg_buf++;
count--;
}
if (ky_i2c_is_last_byte_to_send(ky_i2c)) {
data = *ky_i2c->msg_buf | WFIFO_CTRL_TB |
WFIFO_CTRL_STOP;
data_buf[data_cnt++] = data;
}
}
if (ky_i2c->tx_cnt == ky_i2c->cur_msg->len ||
ky_i2c->rx_cnt == ky_i2c->cur_msg->len) {
ky_i2c->msg_idx++;
if (ky_i2c->msg_idx == ky_i2c->num)
break;
ky_i2c->cur_msg = ky_i2c->msgs + ky_i2c->msg_idx;
ky_i2c->msg_buf = ky_i2c->cur_msg->buf;
ky_i2c->rx_cnt = 0;
ky_i2c->tx_cnt = 0;
}
if (fill == KY_I2C_TX_FIFO_DEPTH)
break;
}
spin_lock_irqsave(&ky_i2c->fifo_lock, flags);
for (i = 0; i < data_cnt; i++)
ky_i2c_write_reg(ky_i2c, REG_WFIFO, data_buf[i]);
spin_unlock_irqrestore(&ky_i2c->fifo_lock, flags);
}
static void ky_i2c_fifo_xfer_copy_buffer(struct ky_i2c_dev *ky_i2c)
{
int idx = 0, cnt = 0;
struct i2c_msg *msg;
/* copy the rx FIFO buffer to msg */
while (idx < ky_i2c->num) {
msg = ky_i2c->msgs + idx;
if (msg->flags & I2C_M_RD) {
cnt = msg->len;
while (cnt > 0) {
*(msg->buf + msg->len - cnt)
= ky_i2c_read_reg(ky_i2c, REG_RFIFO);
cnt--;
}
}
idx++;
}
}
static int ky_i2c_fifo_xfer(struct ky_i2c_dev *ky_i2c)
{
int ret = 0;
unsigned long time_left;
ky_i2c_fifo_xfer_fill_buffer(ky_i2c);
time_left = wait_for_completion_timeout(&ky_i2c->complete,
ky_i2c->timeout);
if (unlikely(time_left == 0)) {
dev_alert(ky_i2c->dev, "fifo transfer timeout\n");
ky_i2c_bus_reset(ky_i2c);
ret = -ETIMEDOUT;
goto err_out;
}
if (unlikely(ky_i2c->i2c_err)) {
ret = -1;
ky_i2c_flush_fifo_buffer(ky_i2c);
goto err_out;
}
ky_i2c_fifo_xfer_copy_buffer(ky_i2c);
err_out:
return ret;
}
static void ky_i2c_dma_copy_buffer(struct ky_i2c_dev *ky_i2c)
{
int idx = 0, total = 0, i, cnt = 0;
struct i2c_msg *cur_msg;
/* calculate total rx bytes */
while (idx < ky_i2c->num) {
if ((ky_i2c->msgs + idx)->flags & I2C_M_RD)
total += (ky_i2c->msgs + idx)->len;
idx++;
}
idx = 0;
total -= total % KY_I2C_RX_FIFO_DEPTH;
while (idx < ky_i2c->num) {
cur_msg = ky_i2c->msgs + idx;
if (cur_msg->flags & I2C_M_RD) {
for (i = 0; i < cur_msg->len; i++) {
if (cnt < total) {
*(cur_msg->buf + i) = ky_i2c->rx_dma_buf[cnt];
} else {
/* copy the rest bytes from FIFO */
*(cur_msg->buf + i) =
ky_i2c_read_reg(ky_i2c, REG_RFIFO) &
0xff;
}
cnt++;
}
}
idx++;
}
}
static void ky_i2c_dma_callback(void *data)
{
return;
}
static int
ky_i2c_map_rx_sg(struct ky_i2c_dev *ky_i2c, int rx_nents, int *rx_total)
{
int len;
int rx_buf_start = *rx_total;
*rx_total += ky_i2c->cur_msg->len;
if (*rx_total < ky_i2c->rx_total) {
len = ky_i2c->cur_msg->len;
} else {
len = ky_i2c->cur_msg->len - *rx_total + ky_i2c->rx_total;
ky_i2c->rx_total = 0;
}
sg_set_buf(ky_i2c->rx_sg + rx_nents, &(ky_i2c->rx_dma_buf[rx_buf_start]), len);
return dma_map_sg(ky_i2c->dev, ky_i2c->rx_sg + rx_nents,
1, DMA_FROM_DEVICE);
}
static int ky_i2c_dma_xfer(struct ky_i2c_dev *ky_i2c)
{
struct dma_async_tx_descriptor *tx_des = NULL, *rx_des = NULL;
dma_cookie_t rx_ck = 0, tx_ck;
u32 rx_nents = 0, tx_nents = 0, data;
int ret = 0, idx = 0, count = 0, start = 0, i;
unsigned long time_left;
int rx_total = 0;
int comp_timeout = 1000000; /* (us) */
ky_i2c->rx_total -= ky_i2c->rx_total % KY_I2C_RX_FIFO_DEPTH;
while (idx < ky_i2c->num) {
ky_i2c->msg_idx = idx;
ky_i2c->cur_msg = ky_i2c->msgs + idx;
ky_i2c_mark_rw_flag(ky_i2c);
if (idx == 0 && ky_i2c->high_mode) {
/* fill master code */
data = (ky_i2c->master_code & 0xff) |
WFIFO_CTRL_TB | WFIFO_CTRL_START;
*(ky_i2c->tx_dma_buf + count) = data;
count++;
}
/* fill slave address */
data = ky_i2c->slave_addr_rw |
WFIFO_CTRL_TB | WFIFO_CTRL_START;
*(ky_i2c->tx_dma_buf + count) = data;
count++;
if (ky_i2c->is_rx) {
if (ky_i2c->rx_total) {
ret = ky_i2c_map_rx_sg(ky_i2c,
rx_nents, &rx_total);
if (!ret) {
dev_err(ky_i2c->dev,
"failed to map scatterlist\n");
ret = -EINVAL;
goto err_map;
}
rx_nents++;
}
for (i = 0; i < ky_i2c->cur_msg->len - 1; i++) {
data = ky_i2c->slave_addr_rw | WFIFO_CTRL_TB;
*(ky_i2c->tx_dma_buf + count) = data;
count++;
}
data = ky_i2c->slave_addr_rw | WFIFO_CTRL_TB;
/* send nak and stop pulse for last msg */
if (idx == ky_i2c->num - 1)
data |= WFIFO_CTRL_ACKNAK | WFIFO_CTRL_STOP;
*(ky_i2c->tx_dma_buf + count++) = data;
start += ky_i2c->cur_msg->len;
} else {
for (i = 0; i < ky_i2c->cur_msg->len - 1; i++) {
data = *(ky_i2c->cur_msg->buf + i) |
WFIFO_CTRL_TB;
*(ky_i2c->tx_dma_buf + count) = data;
count++;
}
data = *(ky_i2c->cur_msg->buf + i) | WFIFO_CTRL_TB;
/* send stop pulse for last msg */
if (idx == ky_i2c->num - 1)
data |= WFIFO_CTRL_STOP;
*(ky_i2c->tx_dma_buf + count++) = data;
}
idx++;
}
sg_set_buf(ky_i2c->tx_sg, ky_i2c->tx_dma_buf,
count * sizeof(ky_i2c->tx_dma_buf[0]));
ret = dma_map_sg(ky_i2c->dev, ky_i2c->tx_sg, 1, DMA_TO_DEVICE);
if (unlikely(!ret)) {
dev_err(ky_i2c->dev, "failed to map scatterlist\n");
ret = -EINVAL;
goto err_map;
}
tx_nents++;
tx_des = dmaengine_prep_slave_sg(ky_i2c->tx_dma, ky_i2c->tx_sg, 1,
DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_PREP_FENCE);
if (unlikely(!tx_des)) {
dev_err(ky_i2c->dev, "failed to get dma tx descriptor\n");
ret = -EINVAL;
goto err_desc;
}
tx_des->callback = ky_i2c_dma_callback;
tx_des->callback_param = ky_i2c;
tx_ck = dmaengine_submit(tx_des);
if (unlikely(dma_submit_error(tx_ck))) {
ret = -EINVAL;
goto err_desc;
}
if (likely(rx_nents)) {
rx_des = dmaengine_prep_slave_sg(ky_i2c->rx_dma,
ky_i2c->rx_sg,
rx_nents, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT);
if (unlikely(!rx_des)) {
dev_err(ky_i2c->dev,
"failed to get dma rx descriptor\n");
ret = -EINVAL;
goto err_desc;
}
rx_des->callback = ky_i2c_dma_callback;
rx_des->callback_param = ky_i2c;
rx_ck = dmaengine_submit(rx_des);
if (unlikely(dma_submit_error(rx_ck))) {
dev_err(ky_i2c->dev,
"failed to submit rx channel\n");
ret = -EINVAL;
goto err_desc;
}
dma_async_issue_pending(ky_i2c->rx_dma);
}
dma_async_issue_pending(ky_i2c->tx_dma);
time_left = wait_for_completion_timeout(&ky_i2c->complete,
ky_i2c->timeout);
if (unlikely(time_left == 0)) {
dev_alert(ky_i2c->dev, "dma transfer timeout\n");
ky_i2c_bus_reset(ky_i2c);
ky_i2c_reset(ky_i2c);
ret = -ETIMEDOUT;
comp_timeout = 0;
goto finish;
}
if (unlikely(ky_i2c->i2c_err)) {
ret = -1;
ky_i2c_flush_fifo_buffer(ky_i2c);
comp_timeout = 0;
}
finish:
/*
* wait for the rx DMA to complete, for tx, we use the i2c
* TXDONE/STOP interrupt, here we already receive the
* TXDONE/STOP signal.
*/
if (unlikely(rx_nents && dma_async_is_tx_complete(ky_i2c->rx_dma,
rx_ck, NULL, NULL) != DMA_COMPLETE)) {
int timeout = comp_timeout;
while (timeout > 0) {
if (dma_async_is_tx_complete(ky_i2c->rx_dma,
rx_ck, NULL, NULL) != DMA_COMPLETE) {
usleep_range(2, 4);
timeout -= 4;
} else
break;
}
if (timeout <= 0) {
dmaengine_pause(ky_i2c->rx_dma);
if (ret >= 0) {
ret = -1;
dev_err(ky_i2c->dev,
"dma rx channel timeout\n");
}
}
}
if (likely(ret >= 0))
ky_i2c_dma_copy_buffer(ky_i2c);
err_desc:
dma_unmap_sg(ky_i2c->dev, ky_i2c->tx_sg, tx_nents, DMA_TO_DEVICE);
err_map:
if (likely(rx_nents))
dma_unmap_sg(ky_i2c->dev, ky_i2c->rx_sg,
rx_nents, DMA_FROM_DEVICE);
/* make sure terminate transfers and free descriptors */
if (tx_des)
dmaengine_terminate_all(ky_i2c->tx_dma);
if (rx_des)
dmaengine_terminate_all(ky_i2c->rx_dma);
return ret < 0 ? ret : 0;
}
static int ky_i2c_byte_xfer(struct ky_i2c_dev *ky_i2c)
{
int ret = 0;
/* i2c error occurs */
if (unlikely(ky_i2c->i2c_err))
return -1;
if (ky_i2c->phase == KY_I2C_XFER_IDLE) {
if (ky_i2c->high_mode && ky_i2c->is_xfer_start)
ky_i2c_byte_xfer_send_master_code(ky_i2c);
else
ky_i2c_byte_xfer_send_slave_addr(ky_i2c);
ky_i2c->is_xfer_start = false;
} else if (ky_i2c->phase == KY_I2C_XFER_MASTER_CODE) {
ky_i2c_byte_xfer_send_slave_addr(ky_i2c);
} else {
ret = ky_i2c_byte_xfer_body(ky_i2c);
}
return ret;
}
static void ky_i2c_print_msg_info(struct ky_i2c_dev *ky_i2c)
{
int i, j, idx;
char printbuf[512];
idx = sprintf(printbuf, "msgs: %d, mode: %d", ky_i2c->num,
ky_i2c->xfer_mode);
for (i = 0; i < ky_i2c->num && i < sizeof(printbuf) / 128; i++) {
u16 len = ky_i2c->msgs[i].len & 0xffff;
idx += sprintf(printbuf + idx, ", addr: %02x",
ky_i2c->msgs[i].addr);
idx += sprintf(printbuf + idx, ", flag: %c, len: %d",
ky_i2c->msgs[i].flags & I2C_M_RD ? 'R' : 'W', len);
if (!(ky_i2c->msgs[i].flags & I2C_M_RD)) {
idx += sprintf(printbuf + idx, ", data:");
/* print at most ten bytes of data */
for (j = 0; j < len && j < 10; j++)
idx += sprintf(printbuf + idx, " %02x",
ky_i2c->msgs[i].buf[j]);
}
}
}
static int ky_i2c_handle_err(struct ky_i2c_dev *ky_i2c)
{
if (unlikely(ky_i2c->i2c_err)) {
dev_dbg(ky_i2c->dev, "i2c error status: 0x%08x\n",
ky_i2c->i2c_status);
if (ky_i2c->i2c_err & (SR_BED | SR_ALD))
ky_i2c_reset(ky_i2c);
/* try transfer again */
if (ky_i2c->i2c_err & (SR_RXOV | SR_ALD)) {
ky_i2c_flush_fifo_buffer(ky_i2c);
return -EAGAIN;
}
return (ky_i2c->i2c_status & SR_ACKNAK) ? -ENXIO : -EIO;
}
return 0;
}
#ifdef CONFIG_I2C_SLAVE
static void ky_i2c_slave_handler(struct ky_i2c_dev *ky_i2c)
{
u32 status = ky_i2c->i2c_status;
u8 value;
/* clear interrupt status bits[31:18]*/
ky_i2c_clear_int_status(ky_i2c, status);
if (unlikely(status & (SR_EBB | SR_BED))) {
dev_err(ky_i2c->dev,"i2c slave bus error status = 0x%x, reset controller\n", status);
/* controller reset */
ky_i2c_controller_reset(ky_i2c);
/* reinit ky i2c slave */
ky_i2c_write_reg(ky_i2c, REG_CR, KY_I2C_SLAVE_CRINIT);
return;
}
/* slave address detected */
if (status & SR_SAD) {
/* read or write request */
if (status & SR_RWM) {
i2c_slave_event(ky_i2c->slave, I2C_SLAVE_READ_REQUESTED, &value);
ky_i2c_write_reg(ky_i2c, REG_DBR, value & 0xff);
} else {
i2c_slave_event(ky_i2c->slave, I2C_SLAVE_WRITE_REQUESTED, &value);
}
ky_i2c_write_reg(ky_i2c, REG_CR, CR_TB | ky_i2c_read_reg(ky_i2c, REG_CR));
} else if (status & SR_SSD) { /* stop detect */
i2c_slave_event(ky_i2c->slave, I2C_SLAVE_STOP, &value);
ky_i2c_write_reg(ky_i2c, REG_SR, SR_SSD);
} else if (status & SR_IRF) { /* master write to us */
ky_i2c_write_reg(ky_i2c, REG_SR, SR_IRF);
value = ky_i2c_read_reg(ky_i2c, REG_DBR);
ky_i2c_write_reg(ky_i2c, REG_CR, CR_TB | ky_i2c_read_reg(ky_i2c, REG_CR));
i2c_slave_event(ky_i2c->slave, I2C_SLAVE_WRITE_RECEIVED, &value);
} else if (status & SR_ITE) { /* ITE tx empty */
ky_i2c_write_reg(ky_i2c, REG_SR, SR_ITE);
i2c_slave_event(ky_i2c->slave, I2C_SLAVE_READ_PROCESSED, &value);
ky_i2c_write_reg(ky_i2c, REG_DBR, value & 0xff);
ky_i2c_write_reg(ky_i2c, REG_CR, CR_TB | ky_i2c_read_reg(ky_i2c, REG_CR));
} else
dev_err(ky_i2c->dev,"unknown slave status 0x%x\n", status);
return;
}
#endif
static irqreturn_t ky_i2c_int_handler(int irq, void *devid)
{
struct ky_i2c_dev *ky_i2c = devid;
u32 status, ctrl;
int ret = 0;
/* record i2c status */
status = ky_i2c_read_reg(ky_i2c, REG_SR);
ky_i2c->i2c_status = status;
/* check if a valid interrupt status */
if(!status) {
/* nothing need be done */
return IRQ_HANDLED;
}
#ifdef CONFIG_I2C_SLAVE
if (ky_i2c->slave) {
ky_i2c_slave_handler(ky_i2c);
return IRQ_HANDLED;
}
#endif
/* bus error, rx overrun, arbitration lost */
ky_i2c->i2c_err = status & (SR_BED | SR_RXOV | SR_ALD);
/* clear interrupt status bits[31:18]*/
ky_i2c_clear_int_status(ky_i2c, status);
/* i2c error happens */
if (unlikely(ky_i2c->i2c_err))
goto err_out;
/* process interrupt mode */
if (likely(ky_i2c->xfer_mode == KY_I2C_MODE_INTERRUPT))
ret = ky_i2c_byte_xfer(ky_i2c);
err_out:
/*
* send transaction complete signal:
* error happens, detect master stop
*/
if (likely(ky_i2c->i2c_err || (ret < 0) || (status & SR_MSD))) {
/*
* Here the transaction is already done, we don't need any
* other interrupt signals from now, in case any interrupt
* happens before ky_i2c_xfer to disable irq and i2c unit,
* we mask all the interrupt signals and clear the interrupt
* status.
*/
ctrl = ky_i2c_read_reg(ky_i2c, REG_CR);
ctrl &= ~KY_I2C_INT_CTRL_MASK;
ky_i2c_write_reg(ky_i2c, REG_CR, ctrl);
ky_i2c_clear_int_status(ky_i2c, KY_I2C_INT_STATUS_MASK);
complete(&ky_i2c->complete);
}
return IRQ_HANDLED;
}
static void ky_i2c_choose_xfer_mode(struct ky_i2c_dev *ky_i2c)
{
unsigned long timeout;
int idx = 0, cnt = 0, freq;
bool block = false;
/* scan msgs */
if (ky_i2c->high_mode)
cnt++;
ky_i2c->rx_total = 0;
while (idx < ky_i2c->num) {
cnt += (ky_i2c->msgs + idx)->len + 1;
if ((ky_i2c->msgs + idx)->flags & I2C_M_RD)
ky_i2c->rx_total += (ky_i2c->msgs + idx)->len;
/*
* Some SMBus transactions require that
* we receive the transacttion length as the first read byte.
* force to use I2C_MODE_INTERRUPT
*/
if ((ky_i2c->msgs + idx)->flags & I2C_M_RECV_LEN) {
block = true;
cnt += I2C_SMBUS_BLOCK_MAX + 2;
}
idx++;
}
if (likely(ky_i2c->dma_disable) || block) {
ky_i2c->xfer_mode = KY_I2C_MODE_INTERRUPT;
#ifdef CONFIG_DEBUG_FS
} else if (unlikely(ky_i2c->dbgfs_mode != KY_I2C_MODE_INVALID)) {
ky_i2c->xfer_mode = ky_i2c->dbgfs_mode;
if (cnt > KY_I2C_TX_FIFO_DEPTH &&
ky_i2c->xfer_mode == KY_I2C_MODE_FIFO)
ky_i2c->xfer_mode = KY_I2C_MODE_DMA;
/* flush fifo buffer */
ky_i2c_flush_fifo_buffer(ky_i2c);
#endif
} else {
if (likely(cnt <= KY_I2C_TX_FIFO_DEPTH))
ky_i2c->xfer_mode = KY_I2C_MODE_FIFO;
else
ky_i2c->xfer_mode = KY_I2C_MODE_DMA;
/* flush fifo buffer */
ky_i2c_flush_fifo_buffer(ky_i2c);
}
/*
* if total message length is too large to over the allocated MDA
* total buf length, use interrupt mode. This may happens in the
* syzkaller test.
*/
if (unlikely(cnt > (KY_I2C_MAX_MSG_LEN * KY_I2C_SCATTERLIST_SIZE) ||
ky_i2c->rx_total > KY_I2C_DMA_RX_BUF_LEN))
ky_i2c->xfer_mode = KY_I2C_MODE_INTERRUPT;
/* calculate timeout */
if (likely(ky_i2c->high_mode))
freq = 1500000;
else if (likely(ky_i2c->fast_mode))
freq = 400000;
else
freq = 100000;
timeout = cnt * 9 * USEC_PER_SEC / freq;
if (likely(ky_i2c->xfer_mode == KY_I2C_MODE_INTERRUPT ||
ky_i2c->xfer_mode == KY_I2C_MODE_PIO))
timeout += (cnt - 1) * 220;
if (ky_i2c->xfer_mode == KY_I2C_MODE_INTERRUPT)
ky_i2c->timeout = usecs_to_jiffies(timeout + 500000);
else
ky_i2c->timeout = usecs_to_jiffies(timeout + 100000);
}
static void ky_i2c_init_xfer_params(struct ky_i2c_dev *ky_i2c)
{
/* initialize transfer parameters */
ky_i2c->msg_idx = 0;
ky_i2c->cur_msg = ky_i2c->msgs;
ky_i2c->msg_buf = ky_i2c->cur_msg->buf;
ky_i2c->rx_cnt = 0;
ky_i2c->tx_cnt = 0;
ky_i2c->i2c_err = 0;
ky_i2c->i2c_status = 0;
ky_i2c->phase = KY_I2C_XFER_IDLE;
/* only send master code once for high speed mode */
ky_i2c->is_xfer_start = true;
}
static int ky_i2c_pio_xfer(struct ky_i2c_dev *ky_i2c)
{
int ret = 0, xfer_try = 0;
u32 status;
signed long timeout;
xfer_retry:
/* calculate timeout */
ky_i2c_choose_xfer_mode(ky_i2c);
ky_i2c->xfer_mode = KY_I2C_MODE_PIO;
timeout = jiffies_to_usecs(ky_i2c->timeout);
if (!ky_i2c->clk_always_on)
clk_enable(ky_i2c->clk);
ky_i2c_controller_reset(ky_i2c);
udelay(2);
ky_i2c_unit_init(ky_i2c);
ky_i2c_clear_int_status(ky_i2c, KY_I2C_INT_STATUS_MASK);
ky_i2c_init_xfer_params(ky_i2c);
ky_i2c_mark_rw_flag(ky_i2c);
ky_i2c_enable(ky_i2c);
ret = ky_i2c_byte_xfer(ky_i2c);
if (unlikely(ret < 0)) {
ret = -EINVAL;
goto out;
}
while (ky_i2c->num > 0 && timeout > 0) {
status = ky_i2c_read_reg(ky_i2c, REG_SR);
ky_i2c_clear_int_status(ky_i2c, status);
ky_i2c->i2c_status = status;
/* bus error, arbitration lost */
ky_i2c->i2c_err = status & (SR_BED | SR_ALD);
if (unlikely(ky_i2c->i2c_err)) {
ret = -1;
break;
}
/* receive full */
if (likely(status & SR_IRF)) {
ret = ky_i2c_byte_xfer(ky_i2c);
if (unlikely(ret < 0))
break;
}
/* transmit empty */
if (likely(status & SR_ITE)) {
ret = ky_i2c_byte_xfer(ky_i2c);
if (unlikely(ret < 0))
break;
}
/* transaction done */
if (likely(status & SR_MSD))
break;
udelay(10);
timeout -= 10;
}
ky_i2c_disable(ky_i2c);
if (!ky_i2c->clk_always_on)
clk_disable(ky_i2c->clk);
if (unlikely(timeout <= 0)) {
dev_alert(ky_i2c->dev, "i2c pio transfer timeout\n");
ky_i2c_print_msg_info(ky_i2c);
ky_i2c_bus_reset(ky_i2c);
udelay(100);
ret = -ETIMEDOUT;
goto out;
}
/* process i2c error */
if (unlikely(ky_i2c->i2c_err)) {
dev_dbg(ky_i2c->dev, "i2c pio error status: 0x%08x\n",
ky_i2c->i2c_status);
ky_i2c_print_msg_info(ky_i2c);
/* try transfer again */
if (ky_i2c->i2c_err & SR_ALD)
ret = -EAGAIN;
else
ret = (ky_i2c->i2c_status & SR_ACKNAK) ? -ENXIO : -EIO;
}
out:
xfer_try++;
/* retry i2c transfer 3 times for timeout and bus busy */
if (unlikely((ret == -ETIMEDOUT || ret == -EAGAIN) &&
xfer_try <= ky_i2c->drv_retries)) {
dev_alert(ky_i2c->dev, "i2c pio retry %d, ret %d err 0x%x\n",
xfer_try, ret, ky_i2c->i2c_err);
udelay(150);
ret = 0;
goto xfer_retry;
}
return ret < 0 ? ret : ky_i2c->num;
}
static bool ky_i2c_restart_notify = false;
static bool ky_i2c_poweroff_notify = false;
struct sys_off_handler *i2c_poweroff_handler;
static int
ky_i2c_notifier_reboot_call(struct notifier_block *nb, unsigned long action, void *data)
{
ky_i2c_restart_notify = true;
return 0;
}
static int ky_i2c_notifier_poweroff_call(struct sys_off_data *data)
{
ky_i2c_poweroff_notify = true;
return NOTIFY_DONE;
}
static struct notifier_block ky_i2c_sys_nb = {
.notifier_call = ky_i2c_notifier_reboot_call,
.priority = 0,
};
static int
ky_i2c_xfer(struct i2c_adapter *adapt, struct i2c_msg msgs[], int num)
{
struct ky_i2c_dev *ky_i2c = i2c_get_adapdata(adapt);
int ret = 0, xfer_try = 0;
unsigned long time_left;
bool clk_directly = false;
#ifdef CONFIG_I2C_SLAVE
if (ky_i2c->slave) {
dev_err(ky_i2c->dev, "working as slave mode here\n");
return -EBUSY;
}
#endif
/*
* at the end of system power off sequence, system will send
* software power down command to pmic via i2c interface
* with local irq disabled, so just enter PIO mode at once
*/
if (unlikely(ky_i2c_restart_notify == true ||
ky_i2c_poweroff_notify == true
#ifdef CONFIG_DEBUG_FS
|| ky_i2c->dbgfs_mode == KY_I2C_MODE_PIO
#endif
)) {
ky_i2c->msgs = msgs;
ky_i2c->num = num;
return ky_i2c_pio_xfer(ky_i2c);
}
mutex_lock(&ky_i2c->mtx);
ky_i2c->msgs = msgs;
ky_i2c->num = num;
if (ky_i2c->shutdown) {
mutex_unlock(&ky_i2c->mtx);
return -ENXIO;
}
if (!ky_i2c->clk_always_on) {
ret = pm_runtime_get_sync(ky_i2c->dev);
if (unlikely(ret < 0)) {
/*
* during system suspend_late to system resume_early stage,
* if PM runtime is suspended, we will get -EACCES return
* value, so we need to enable clock directly, and disable after
* i2c transfer is finished, if PM runtime is active, it will
* work normally. During this stage, pmic onkey ISR that
* invoked in an irq thread may use i2c interface if we have
* onkey press action
*/
if (likely(ret == -EACCES)) {
clk_directly = true;
clk_enable(ky_i2c->clk);
} else {
dev_err(ky_i2c->dev, "pm runtime sync error: %d\n",
ret);
goto err_runtime;
}
}
}
xfer_retry:
/* if unit keeps the last control status, don't need to do reset */
if (unlikely(ky_i2c_read_reg(ky_i2c, REG_CR) != ky_i2c->i2c_ctrl_reg_value))
/* i2c controller & bus reset */
ky_i2c_reset(ky_i2c);
/* choose transfer mode */
ky_i2c_choose_xfer_mode(ky_i2c);
/* i2c unit init */
ky_i2c_unit_init(ky_i2c);
/* clear all interrupt status */
ky_i2c_clear_int_status(ky_i2c, KY_I2C_INT_STATUS_MASK);
ky_i2c_init_xfer_params(ky_i2c);
ky_i2c_mark_rw_flag(ky_i2c);
reinit_completion(&ky_i2c->complete);
ky_i2c_enable(ky_i2c);
/* i2c wait for bus busy */
ret = ky_i2c_recover_bus_busy(ky_i2c);
if (unlikely(ret))
goto timeout_xfex;
/* i2c msg transmit */
if (likely(ky_i2c->xfer_mode == KY_I2C_MODE_INTERRUPT))
ret = ky_i2c_byte_xfer(ky_i2c);
else if (likely(ky_i2c->xfer_mode == KY_I2C_MODE_FIFO))
ret = ky_i2c_fifo_xfer(ky_i2c);
else
ret = ky_i2c_dma_xfer(ky_i2c);
if (unlikely(ret < 0)) {
dev_dbg(ky_i2c->dev, "i2c transfer error\n");
/* timeout error should not be overrided, and the transfer
* error will be confirmed by err handle function latter,
* the reset should be invalid argument error. */
if (ret != -ETIMEDOUT)
ret = -EINVAL;
goto err_xfer;
}
if (likely(ky_i2c->xfer_mode == KY_I2C_MODE_INTERRUPT)) {
time_left = wait_for_completion_timeout(&ky_i2c->complete,
ky_i2c->timeout);
if (unlikely(time_left == 0)) {
dev_alert(ky_i2c->dev, "msg completion timeout\n");
ky_i2c_bus_reset(ky_i2c);
ky_i2c_reset(ky_i2c);
ret = -ETIMEDOUT;
goto timeout_xfex;
}
}
err_xfer:
if (likely(!ret))
ky_i2c_check_bus_release(ky_i2c);
timeout_xfex:
/* disable ky i2c */
ky_i2c_disable(ky_i2c);
/* print more message info when error or timeout happens */
if (unlikely(ret < 0 || ky_i2c->i2c_err))
ky_i2c_print_msg_info(ky_i2c);
/* process i2c error */
if (unlikely(ky_i2c->i2c_err))
ret = ky_i2c_handle_err(ky_i2c);
xfer_try++;
/* retry i2c transfer 3 times for timeout and bus busy */
if (unlikely((ret == -ETIMEDOUT || ret == -EAGAIN) &&
xfer_try <= ky_i2c->drv_retries)) {
dev_alert(ky_i2c->dev, "i2c transfer retry %d, ret %d mode %d err 0x%x\n",
xfer_try, ret, ky_i2c->xfer_mode, ky_i2c->i2c_err);
usleep_range(150, 200);
ret = 0;
goto xfer_retry;
}
err_runtime:
if (unlikely(clk_directly)) {
/* if clock is enabled directly, here disable it */
clk_disable(ky_i2c->clk);
}
if (!ky_i2c->clk_always_on) {
pm_runtime_mark_last_busy(ky_i2c->dev);
pm_runtime_put_autosuspend(ky_i2c->dev);
}
mutex_unlock(&ky_i2c->mtx);
return ret < 0 ? ret : num;
}
static int ky_i2c_prepare_dma(struct ky_i2c_dev *ky_i2c)
{
int ret = 0;
struct dma_slave_config *rx_cfg = &ky_i2c->rx_dma_cfg;
struct dma_slave_config *tx_cfg = &ky_i2c->tx_dma_cfg;
if (ky_i2c->dma_disable)
return 0;
/* request dma channels */
ky_i2c->rx_dma = dma_request_slave_channel(ky_i2c->dev, "rx");
if (IS_ERR_OR_NULL(ky_i2c->rx_dma)) {
ret = -1;
dev_err(ky_i2c->dev, "failed to request rx dma channel\n");
return ret;
}
ky_i2c->tx_dma = dma_request_slave_channel(ky_i2c->dev, "tx");
if (IS_ERR_OR_NULL(ky_i2c->tx_dma)) {
ret = -1;
dev_err(ky_i2c->dev, "failed to request tx dma channel\n");
goto err_rxch;
}
rx_cfg->direction = DMA_DEV_TO_MEM;
rx_cfg->src_addr = ky_i2c->resrc.start + REG_RFIFO;
rx_cfg->device_fc = true;
rx_cfg->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
rx_cfg->src_maxburst = KY_I2C_RX_FIFO_DEPTH * 1;
ret = dmaengine_slave_config(ky_i2c->rx_dma, rx_cfg);
if (ret) {
dev_err(ky_i2c->dev, "failed to config rx channel\n");
goto err_txch;
}
tx_cfg->direction = DMA_MEM_TO_DEV;
tx_cfg->dst_addr = ky_i2c->resrc.start + REG_WFIFO;
tx_cfg->device_fc = true;
tx_cfg->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
tx_cfg->dst_maxburst = KY_I2C_TX_FIFO_DEPTH * 1;
ret = dmaengine_slave_config(ky_i2c->tx_dma, tx_cfg);
if (ret) {
dev_err(ky_i2c->dev, "failed to config tx channel\n");
goto err_txch;
}
/* allocate scatter lists */
ky_i2c->rx_sg = devm_kmalloc(ky_i2c->dev,
sizeof(*ky_i2c->rx_sg) * KY_I2C_SCATTERLIST_SIZE,
GFP_KERNEL);
if (!ky_i2c->rx_sg) {
ret = -ENOMEM;
dev_err(ky_i2c->dev,
"failed to allocate memory for rx scatterlist\n");
goto err_txch;
}
sg_init_table(ky_i2c->rx_sg, KY_I2C_SCATTERLIST_SIZE);
ky_i2c->tx_sg = devm_kmalloc(ky_i2c->dev,
sizeof(*ky_i2c->tx_sg),
GFP_KERNEL);
if (!ky_i2c->tx_sg) {
ret = -ENOMEM;
dev_err(ky_i2c->dev,
"failed to allocate memory for tx scatterlist\n");
goto err_txch;
}
sg_init_table(ky_i2c->tx_sg, 1);
/* allocate memory for tx */
ky_i2c->tx_dma_buf = devm_kzalloc(ky_i2c->dev,
sizeof(ky_i2c->tx_dma_buf[0]) * KY_I2C_DMA_TX_BUF_LEN,
GFP_KERNEL);
if (!ky_i2c->tx_dma_buf) {
ret = -ENOMEM;
dev_err(ky_i2c->dev,
"failed to allocate memory for tx dma buffer\n");
goto err_txch;
}
/* allocate memory for rx */
ky_i2c->rx_dma_buf = devm_kzalloc(ky_i2c->dev,
sizeof(ky_i2c->rx_dma_buf[0]) * KY_I2C_DMA_RX_BUF_LEN,
GFP_KERNEL);
if (!ky_i2c->rx_dma_buf) {
ret = -ENOMEM;
dev_err(ky_i2c->dev,
"failed to allocate memory for rx dma buffer\n");
goto err_txch;
}
/*
* DMA controller can access all 4G or higher 4G address space, set
* dma mask will avoid to use swiotlb, that will improve performance
* and also avoid panic if swiotlb is not initialized.
* Besides, device's coherent_dma_mask is set as DMA_BIT_MASK(32)
* in initialization, see of_dma_configure().
*/
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
dma_set_mask(ky_i2c->dev, DMA_BIT_MASK(64));
#else
dma_set_mask(ky_i2c->dev, ky_i2c->dev->coherent_dma_mask);
#endif
return 0;
err_txch:
dma_release_channel(ky_i2c->tx_dma);
err_rxch:
dma_release_channel(ky_i2c->rx_dma);
return ret;
}
static int ky_i2c_release_dma(struct ky_i2c_dev *ky_i2c)
{
if (ky_i2c->dma_disable)
return 0;
if (!IS_ERR_OR_NULL(ky_i2c->rx_dma))
dma_release_channel(ky_i2c->rx_dma);
if (!IS_ERR_OR_NULL(ky_i2c->tx_dma))
dma_release_channel(ky_i2c->tx_dma);
return 0;
}
#ifdef CONFIG_DEBUG_FS
static ssize_t
ky_i2c_dbgfs_read(struct file *filp, char __user *user_buf,
size_t size, loff_t *ppos)
{
struct ky_i2c_dev *ky_i2c = filp->private_data;
char buf[64];
int ret, n, copy;
n = min(sizeof(buf) - 1, size);
switch (ky_i2c->xfer_mode) {
case KY_I2C_MODE_INTERRUPT:
copy = sprintf(buf, "%s: interrupt mode\n",
ky_i2c->dbgfs_name);
break;
case KY_I2C_MODE_FIFO:
copy = sprintf(buf, "%s: fifo mode\n", ky_i2c->dbgfs_name);
break;
case KY_I2C_MODE_DMA:
copy = sprintf(buf, "%s: dma mode\n", ky_i2c->dbgfs_name);
break;
case KY_I2C_MODE_PIO:
copy = sprintf(buf, "%s: pio mode\n", ky_i2c->dbgfs_name);
break;
default:
copy = sprintf(buf, "%s: mode is invalid\n",
ky_i2c->dbgfs_name);
break;
}
copy = min(n, copy);
ret = simple_read_from_buffer(user_buf, size, ppos, buf, copy);
return ret;
}
static ssize_t
ky_i2c_dbgfs_write(struct file *filp, const char __user *user_buf,
size_t size, loff_t *ppos)
{
struct ky_i2c_dev *ky_i2c = filp->private_data;
char buf[32];
int buf_size, i = 0;
buf_size = min(size, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT;
*(buf + buf_size) = '\0';
while (*(buf + i) != '\n' && *(buf + i) != '\0')
i++;
*(buf + i) = '\0';
i = 0;
while (*(buf + i) == ' ')
i++;
if (!strncmp(buf + i, "pio", 3)) {
ky_i2c->dbgfs_mode = KY_I2C_MODE_PIO;
} else if (!strncmp(buf + i, "interrupt", 9)) {
ky_i2c->dbgfs_mode = KY_I2C_MODE_INTERRUPT;
} else if (!strncmp(buf + i, "fifo", 4)) {
if (!ky_i2c->dma_disable)
ky_i2c->dbgfs_mode = KY_I2C_MODE_FIFO;
else
goto err_out;
} else if (!strncmp(buf + i, "dma", 3)) {
if (!ky_i2c->dma_disable)
ky_i2c->dbgfs_mode = KY_I2C_MODE_DMA;
else
goto err_out;
} else {
if (!ky_i2c->dma_disable)
dev_err(ky_i2c->dev,
"only accept: interrupt, fifo, dma, pio\n");
else
goto err_out;
}
return size;
err_out:
ky_i2c->dbgfs_mode = KY_I2C_MODE_INTERRUPT;
dev_err(ky_i2c->dev,
"dma is disabled, only accept: interrupt, pio\n");
return size;
}
static const struct file_operations ky_i2c_dbgfs_ops = {
.open = simple_open,
.read = ky_i2c_dbgfs_read,
.write = ky_i2c_dbgfs_write,
};
#endif /* CONFIG_DEBUG_FS */
#ifdef CONFIG_PM_SLEEP
/** static int ky_i2c_suspend(struct device *dev)
* {
* struct ky_i2c_dev *ky_i2c = dev_get_drvdata(dev);
*
* dev_dbg(ky_i2c->dev, "system suspend\n");
*
* if (ky_i2c->clk_always_on)
* return 0;
*
* // grab mutex to make sure the i2c transaction is over
* mutex_lock(&ky_i2c->mtx);
* if (!pm_runtime_status_suspended(dev)) {
* // sync runtime pm and system pm states:
* // prevent runtime pm suspend callback from being re-invoked
* pm_runtime_disable(dev);
* pm_runtime_set_suspended(dev);
* pm_runtime_enable(dev);
* }
* mutex_unlock(&ky_i2c->mtx);
*
* return 0;
* }
*
* static int ky_i2c_resume(struct device *dev)
* {
* struct ky_i2c_dev *ky_i2c = dev_get_drvdata(dev);
*
* dev_dbg(ky_i2c->dev, "system resume\n");
*
* return 0;
*}
*/
#endif /* CONFIG_PM_SLEEP */
/**
* static const struct dev_pm_ops ky_i2c_pm_ops = {
* SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(ky_i2c_suspend,
* ky_i2c_resume)
*};
*/
static u32 ky_i2c_func(struct i2c_adapter *adap)
{
#ifdef CONFIG_I2C_SLAVE
return I2C_FUNC_I2C | I2C_FUNC_SLAVE |
(I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
#else
return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
#endif
}
#ifdef CONFIG_I2C_SLAVE
static int ky_i2c_reg_slave(struct i2c_client *slave)
{
struct ky_i2c_dev *ky_i2c = i2c_get_adapdata(slave->adapter);
int ret = 0;
if (ky_i2c->slave)
return -EBUSY;
if (slave->flags & I2C_CLIENT_TEN)
return -EAFNOSUPPORT;
if(!slave->addr) {
dev_err(ky_i2c->dev, "have no slave address\n");
return -EAFNOSUPPORT;
}
/* Keep device active for slave address detection logic */
if (!ky_i2c->clk_always_on) {
ret = pm_runtime_get_sync(ky_i2c->dev);
if(unlikely(ret < 0)) {
return ret;
}
}
ky_i2c->slave = slave;
ky_i2c_write_reg(ky_i2c, REG_SAR, slave->addr);
ky_i2c_write_reg(ky_i2c, REG_CR, KY_I2C_SLAVE_CRINIT);
return 0;
}
static int ky_i2c_unreg_slave(struct i2c_client *slave)
{
struct ky_i2c_dev *ky_i2c = i2c_get_adapdata(slave->adapter);
WARN_ON(!ky_i2c->slave);
ky_i2c_write_reg(ky_i2c, REG_CR, 0);
/* clear slave address */
ky_i2c_write_reg(ky_i2c, REG_SAR, 0);
if (!ky_i2c->clk_always_on)
pm_runtime_put(ky_i2c->dev);
ky_i2c->slave = NULL;
return 0;
}
#endif
static const struct i2c_algorithm ky_i2c_algrtm = {
.master_xfer = ky_i2c_xfer,
.functionality = ky_i2c_func,
#ifdef CONFIG_I2C_SLAVE
.reg_slave = ky_i2c_reg_slave,
.unreg_slave = ky_i2c_unreg_slave,
#endif
};
/* i2c message limitation for DMA mode */
static struct i2c_adapter_quirks ky_i2c_quirks = {
.max_num_msgs = KY_I2C_SCATTERLIST_SIZE,
.max_write_len = KY_I2C_MAX_MSG_LEN,
.max_read_len = KY_I2C_MAX_MSG_LEN,
};
static int
ky_i2c_parse_dt(struct platform_device *pdev, struct ky_i2c_dev *ky_i2c)
{
struct device_node *dnode = pdev->dev.of_node;
int ret;
/* enable fast speed mode */
ky_i2c->fast_mode = of_property_read_bool(dnode, "ky,i2c-fast-mode");
/* enable high speed mode */
ky_i2c->high_mode = of_property_read_bool(dnode, "ky,i2c-high-mode");
if (ky_i2c->high_mode) {
/* get master code for high speed mode */
ret = of_property_read_u8(dnode, "ky,i2c-master-code",
&ky_i2c->master_code);
if (ret) {
ky_i2c->master_code = 0x0e;
dev_warn(ky_i2c->dev,
"failed to get i2c master code, use default: 0x0e\n");
}
}
ret = of_property_read_u32(dnode, "ky,i2c-clk-rate",
&ky_i2c->clk_rate);
if (ret) {
dev_err(ky_i2c->dev,
"failed to get i2c clock rate\n");
return ret;
}
ret = of_property_read_u32(dnode, "ky,i2c-lcr", &ky_i2c->i2c_lcr);
if (ret) {
dev_err(ky_i2c->dev, "failed to get i2c lcr\n");
return ret;
}
ret = of_property_read_u32(dnode, "ky,i2c-wcr", &ky_i2c->i2c_wcr);
if (ret) {
dev_err(ky_i2c->dev, "failed to get i2c wcr\n");
return ret;
}
/*
* adapter device id:
* assigned in dt node or alias name, or automatically allocated
* in i2c_add_numbered_adapter()
*/
ret = of_property_read_u32(dnode, "ky,adapter-id", &pdev->id);
if (ret)
pdev->id = -1;
/* disable DMA transfer mode */
ky_i2c->dma_disable = of_property_read_bool(dnode, "ky,dma-disable");
/* default: interrupt mode */
if (ky_i2c->dma_disable)
ky_i2c->xfer_mode = KY_I2C_MODE_INTERRUPT;
else
ky_i2c->xfer_mode = KY_I2C_MODE_DMA;
/* true: the clock will always on and not use runtime mechanism */
ky_i2c->clk_always_on = of_property_read_bool(dnode, "ky,clk-always-on");
/* apb clock: 26MHz or 52MHz */
ret = of_property_read_u32(dnode, "ky,apb_clock", &ky_i2c->apb_clock);
if (ret) {
dev_err(ky_i2c->dev, "failed to get apb clock\n");
return ret;
} else if ((ky_i2c->apb_clock != KY_I2C_APB_CLOCK_26M) &&
(ky_i2c->apb_clock != KY_I2C_APB_CLOCK_52M)) {
dev_err(ky_i2c->dev, "the apb clock should be 26M or 52M\n");
return -EINVAL;
}
return 0;
}
static int ky_i2c_probe(struct platform_device *pdev)
{
struct ky_i2c_dev *ky_i2c;
struct device_node *dnode = pdev->dev.of_node;
#ifdef CONFIG_SOC_KY_X1
struct rpmsg_device *rpdev;
struct instance_data *idata;
const struct of_device_id *of_id;
bool rcpu_i2c = false;
#endif
int ret = 0;
/* allocate memory */
ky_i2c = devm_kzalloc(&pdev->dev,
sizeof(struct ky_i2c_dev),
GFP_KERNEL);
if (!ky_i2c) {
ret = -ENOMEM;
goto err_out;
}
ky_i2c->dev = &pdev->dev;
platform_set_drvdata(pdev, ky_i2c);
mutex_init(&ky_i2c->mtx);
ky_i2c->resets = devm_reset_control_get_optional(&pdev->dev, NULL);
if(IS_ERR(ky_i2c->resets)) {
dev_err(&pdev->dev, "failed to get resets\n");
goto err_out;
}
/* reset the i2c controller */
reset_control_assert(ky_i2c->resets);
udelay(200);
reset_control_deassert(ky_i2c->resets);
ret = ky_i2c_parse_dt(pdev, ky_i2c);
if (ret)
goto err_out;
ret = of_address_to_resource(dnode, 0, &ky_i2c->resrc);
if (ret) {
dev_err(&pdev->dev, "failed to get resource\n");
ret = -ENODEV;
goto err_out;
}
ky_i2c->mapbase = devm_ioremap_resource(ky_i2c->dev, &ky_i2c->resrc);
if (IS_ERR(ky_i2c->mapbase)) {
dev_err(&pdev->dev, "failed to do ioremap\n");
ret = PTR_ERR(ky_i2c->mapbase);
goto err_out;
}
#ifdef CONFIG_SOC_KY_X1
if (of_get_property(pdev->dev.of_node, "rcpu-i2c", NULL)) {
rcpu_i2c = true;
of_id = of_match_device(r_ky_i2c_dt_match, &pdev->dev);
if (!of_id) {
pr_err("Unable to match OF ID\n");
return -ENODEV;
}
idata = (struct instance_data *)((unsigned long long *)(of_id->data))[0];
rpdev = idata->rpdev;
idata->ky_i2c = ky_i2c;
ret = rpmsg_send(rpdev->ept, STARTUP_MSG, strlen(STARTUP_MSG));
if (ret) {
dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
return ret;
}
} else
#endif
{
ky_i2c->irq = platform_get_irq(pdev, 0);
if (ky_i2c->irq < 0) {
dev_err(ky_i2c->dev, "failed to get irq resource\n");
ret = ky_i2c->irq;
goto err_out;
}
ret = devm_request_irq(ky_i2c->dev, ky_i2c->irq, ky_i2c_int_handler,
IRQF_NO_SUSPEND,
dev_name(ky_i2c->dev), ky_i2c);
if (ret) {
dev_err(ky_i2c->dev, "failed to request irq\n");
goto err_out;
}
}
ret = ky_i2c_prepare_dma(ky_i2c);
if (ret) {
dev_err(&pdev->dev, "failed to request dma channels\n");
goto err_out;
}
ky_i2c->clk = devm_clk_get(ky_i2c->dev, NULL);
if (IS_ERR(ky_i2c->clk)) {
dev_err(ky_i2c->dev, "failed to get clock\n");
ret = PTR_ERR(ky_i2c->clk);
goto err_dma;
}
#ifdef CONFIG_SOC_KY_X1
if (rcpu_i2c) {
clk_set_rate(ky_i2c->clk, ky_i2c->clk_rate);
}
#endif
clk_prepare_enable(ky_i2c->clk);
i2c_set_adapdata(&ky_i2c->adapt, ky_i2c);
ky_i2c->adapt.owner = THIS_MODULE;
ky_i2c->adapt.algo = &ky_i2c_algrtm;
ky_i2c->adapt.dev.parent = ky_i2c->dev;
ky_i2c->adapt.nr = pdev->id;
/* retries used by i2c framework: 3 times */
ky_i2c->adapt.retries = 3;
/*
* retries used by i2c driver: 3 times
* this is for the very low occasionally PMIC i2c access failure.
*/
ky_i2c->drv_retries = 3;
ky_i2c->adapt.dev.of_node = dnode;
ky_i2c->adapt.algo_data = ky_i2c;
strlcpy(ky_i2c->adapt.name, "ky-i2c-adapter",
sizeof(ky_i2c->adapt.name));
if (!ky_i2c->dma_disable)
ky_i2c->adapt.quirks = &ky_i2c_quirks;
init_completion(&ky_i2c->complete);
spin_lock_init(&ky_i2c->fifo_lock);
if (!ky_i2c->clk_always_on) {
pm_runtime_set_autosuspend_delay(ky_i2c->dev, MSEC_PER_SEC);
pm_runtime_use_autosuspend(ky_i2c->dev);
pm_runtime_set_active(ky_i2c->dev);
pm_suspend_ignore_children(&pdev->dev, 1);
pm_runtime_enable(ky_i2c->dev);
} else
dev_dbg(ky_i2c->dev, "clock keeps always on\n");
ky_i2c->dbgfs_mode = KY_I2C_MODE_INVALID;
ky_i2c->shutdown = false;
ret = i2c_add_numbered_adapter(&ky_i2c->adapt);
if (ret) {
dev_err(ky_i2c->dev, "failed to add i2c adapter\n");
goto err_clk;
}
#ifdef CONFIG_DEBUG_FS
snprintf(ky_i2c->dbgfs_name, sizeof(ky_i2c->dbgfs_name),
"ky-i2c-%d", ky_i2c->adapt.nr);
ky_i2c->dbgfs = debugfs_create_file(ky_i2c->dbgfs_name, 0644,
NULL, ky_i2c, &ky_i2c_dbgfs_ops);
if (!ky_i2c->dbgfs) {
dev_err(ky_i2c->dev, "failed to create debugfs\n");
ret = -ENOMEM;
goto err_adapt;
}
#endif
dev_dbg(ky_i2c->dev, "driver probe success with dma %s\n",
ky_i2c->dma_disable ? "disabled" : "enabled");
return 0;
#ifdef CONFIG_DEBUG_FS
err_adapt:
i2c_del_adapter(&ky_i2c->adapt);
#endif
err_clk:
if (!ky_i2c->clk_always_on) {
pm_runtime_disable(ky_i2c->dev);
pm_runtime_set_suspended(ky_i2c->dev);
}
clk_disable_unprepare(ky_i2c->clk);
err_dma:
ky_i2c_release_dma(ky_i2c);
err_out:
return ret;
}
static int ky_i2c_remove(struct platform_device *pdev)
{
struct ky_i2c_dev *ky_i2c = platform_get_drvdata(pdev);
if (!ky_i2c->clk_always_on) {
pm_runtime_disable(ky_i2c->dev);
pm_runtime_set_suspended(ky_i2c->dev);
}
debugfs_remove_recursive(ky_i2c->dbgfs);
i2c_del_adapter(&ky_i2c->adapt);
mutex_destroy(&ky_i2c->mtx);
reset_control_assert(ky_i2c->resets);
ky_i2c_release_dma(ky_i2c);
clk_disable_unprepare(ky_i2c->clk);
dev_dbg(ky_i2c->dev, "driver removed\n");
return 0;
}
static void ky_i2c_shutdown(struct platform_device *pdev)
{
/**
* we should using i2c to communicate with pmic to shutdown the system
* so we should not shutdown i2c
*/
/**
* struct ky_i2c_dev *ky_i2c = platform_get_drvdata(pdev);
*
* mutex_lock(&ky_i2c->mtx);
* ky_i2c->shutdown = true;
* mutex_unlock(&ky_i2c->mtx);
*/
}
static const struct of_device_id ky_i2c_dt_match[] = {
{
.compatible = "ky,x1-i2c",
},
{}
};
MODULE_DEVICE_TABLE(of, ky_i2c_dt_match);
static struct platform_driver ky_i2c_driver = {
.probe = ky_i2c_probe,
.remove = ky_i2c_remove,
.shutdown = ky_i2c_shutdown,
.driver = {
.name = "i2c-ky-x1",
/* .pm = &ky_i2c_pm_ops, */
.of_match_table = ky_i2c_dt_match,
},
};
static int __init ky_i2c_init(void)
{
register_restart_handler(&ky_i2c_sys_nb);
i2c_poweroff_handler = register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
SYS_OFF_PRIO_HIGH,
ky_i2c_notifier_poweroff_call,
NULL);
return platform_driver_register(&ky_i2c_driver);
}
static void __exit ky_i2c_exit(void)
{
platform_driver_unregister(&ky_i2c_driver);
unregister_restart_handler(&ky_i2c_sys_nb);
unregister_sys_off_handler(i2c_poweroff_handler);
}
subsys_initcall(ky_i2c_init);
module_exit(ky_i2c_exit);
#ifdef CONFIG_SOC_KY_X1
static const struct of_device_id r_ky_i2c_dt_match[] = {
{ .compatible = "ky,x1-i2c-rcpu", .data =(void *)&private_data[0] },
{}
};
MODULE_DEVICE_TABLE(of, r_ky_i2c_dt_match);
static struct platform_driver r_ky_i2c_driver = {
.probe = ky_i2c_probe,
.remove = ky_i2c_remove,
.shutdown = ky_i2c_shutdown,
.driver = {
.name = "ri2c-ky-x1",
/* .pm = &ky_i2c_pm_ops, */
.of_match_table = r_ky_i2c_dt_match,
},
};
static struct rpmsg_device_id rpmsg_driver_i2c_id_table[] = {
{ .name = "i2c-service", .driver_data = 0 },
{ },
};
MODULE_DEVICE_TABLE(rpmsg, rpmsg_driver_i2c_id_table);
static int rpmsg_i2c_client_probe(struct rpmsg_device *rpdev)
{
struct instance_data *idata;
dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
rpdev->src, rpdev->dst);
idata = devm_kzalloc(&rpdev->dev, sizeof(*idata), GFP_KERNEL);
if (!idata)
return -ENOMEM;
dev_set_drvdata(&rpdev->dev, idata);
idata->rpdev = rpdev;
((unsigned long long *)(r_ky_i2c_dt_match[0].data))[0] = (unsigned long long)idata;
return platform_driver_register(&r_ky_i2c_driver);
}
static int rpmsg_i2c_client_cb(struct rpmsg_device *rpdev, void *data,
int len, void *priv, u32 src)
{
int ret;
struct instance_data *idata = dev_get_drvdata(&rpdev->dev);
struct ky_i2c_dev *ky_i2c = idata->ky_i2c;
ky_i2c_int_handler(0, (void *)ky_i2c);
ret = rpmsg_send(rpdev->ept, IRQUP_MSG, strlen(IRQUP_MSG));
if (ret) {
dev_err(&rpdev->dev, "rpmsg_send failed: %d\n", ret);
return ret;
}
return 0;
}
static void rpmsg_i2c_client_remove(struct rpmsg_device *rpdev)
{
dev_info(&rpdev->dev, "rpmsg i2c client driver is removed\n");
platform_driver_unregister(&r_ky_i2c_driver);
}
static struct rpmsg_driver rpmsg_i2c_client = {
.drv.name = KBUILD_MODNAME,
.id_table = rpmsg_driver_i2c_id_table,
.probe = rpmsg_i2c_client_probe,
.callback = rpmsg_i2c_client_cb,
.remove = rpmsg_i2c_client_remove,
};
module_rpmsg_driver(rpmsg_i2c_client);
#endif
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:i2c-ky-x1");