2019-05-27 09:55:21 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2015-05-21 11:53:28 +03:00
/*
* Copyright ( c ) 2014 MediaTek Inc .
* Author : Xudong Chen < xudong . chen @ mediatek . com >
*/
# include <linux/clk.h>
# include <linux/completion.h>
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/dma-mapping.h>
# include <linux/err.h>
# include <linux/errno.h>
# include <linux/i2c.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/kernel.h>
# include <linux/mm.h>
# include <linux/module.h>
# include <linux/of_address.h>
2018-04-16 05:32:52 +03:00
# include <linux/of_device.h>
2015-05-21 11:53:28 +03:00
# include <linux/of_irq.h>
# include <linux/platform_device.h>
# include <linux/scatterlist.h>
# include <linux/sched.h>
# include <linux/slab.h>
2015-05-21 11:53:30 +03:00
# define I2C_RS_TRANSFER (1 << 4)
2019-04-02 15:35:57 +03:00
# define I2C_ARB_LOST (1 << 3)
2015-05-21 11:53:28 +03:00
# define I2C_HS_NACKERR (1 << 2)
# define I2C_ACKERR (1 << 1)
# define I2C_TRANSAC_COMP (1 << 0)
# define I2C_TRANSAC_START (1 << 0)
2015-05-21 11:53:30 +03:00
# define I2C_RS_MUL_CNFG (1 << 15)
# define I2C_RS_MUL_TRIG (1 << 14)
2015-05-21 11:53:28 +03:00
# define I2C_DCM_DISABLE 0x0000
# define I2C_IO_CONFIG_OPEN_DRAIN 0x0003
# define I2C_IO_CONFIG_PUSH_PULL 0x0000
# define I2C_SOFT_RST 0x0001
# define I2C_FIFO_ADDR_CLR 0x0001
# define I2C_DELAY_LEN 0x0002
# define I2C_ST_START_CON 0x8001
# define I2C_FS_START_CON 0x1800
# define I2C_TIME_CLR_VALUE 0x0000
# define I2C_TIME_DEFAULT_VALUE 0x0003
# define I2C_WRRD_TRANAC_VALUE 0x0002
# define I2C_RD_TRANAC_VALUE 0x0001
# define I2C_DMA_CON_TX 0x0000
# define I2C_DMA_CON_RX 0x0001
# define I2C_DMA_START_EN 0x0001
# define I2C_DMA_INT_FLAG_NONE 0x0000
# define I2C_DMA_CLR_FLAG 0x0000
2015-08-06 10:22:10 +03:00
# define I2C_DMA_HARD_RST 0x0002
2016-02-01 20:19:03 +03:00
# define I2C_DMA_4G_MODE 0x0001
2015-05-21 11:53:28 +03:00
2017-12-19 09:51:02 +03:00
# define I2C_DEFAULT_CLK_DIV 5
2015-05-21 11:53:28 +03:00
# define I2C_DEFAULT_SPEED 100000 /* hz */
# define MAX_FS_MODE_SPEED 400000
# define MAX_HS_MODE_SPEED 3400000
# define MAX_SAMPLE_CNT_DIV 8
# define MAX_STEP_CNT_DIV 64
# define MAX_HS_STEP_CNT_DIV 8
# define I2C_CONTROL_RS (0x1 << 1)
# define I2C_CONTROL_DMA_EN (0x1 << 2)
# define I2C_CONTROL_CLK_EXT_EN (0x1 << 3)
# define I2C_CONTROL_DIR_CHANGE (0x1 << 4)
# define I2C_CONTROL_ACKERR_DET_EN (0x1 << 5)
# define I2C_CONTROL_TRANSFER_LEN_CHANGE (0x1 << 6)
2019-04-02 15:35:58 +03:00
# define I2C_CONTROL_DMAACK_EN (0x1 << 8)
# define I2C_CONTROL_ASYNC_MODE (0x1 << 9)
2015-05-21 11:53:28 +03:00
# define I2C_CONTROL_WRAPPER (0x1 << 0)
# define I2C_DRV_NAME "i2c-mt65xx"
enum DMA_REGS_OFFSET {
OFFSET_INT_FLAG = 0x0 ,
OFFSET_INT_EN = 0x04 ,
OFFSET_EN = 0x08 ,
2015-08-06 10:22:10 +03:00
OFFSET_RST = 0x0c ,
2015-05-21 11:53:28 +03:00
OFFSET_CON = 0x18 ,
OFFSET_TX_MEM_ADDR = 0x1c ,
OFFSET_RX_MEM_ADDR = 0x20 ,
OFFSET_TX_LEN = 0x24 ,
OFFSET_RX_LEN = 0x28 ,
2016-02-01 20:19:03 +03:00
OFFSET_TX_4G_MODE = 0x54 ,
OFFSET_RX_4G_MODE = 0x58 ,
2015-05-21 11:53:28 +03:00
} ;
enum i2c_trans_st_rs {
I2C_TRANS_STOP = 0 ,
I2C_TRANS_REPEATED_START ,
} ;
enum mtk_trans_op {
I2C_MASTER_WR = 1 ,
I2C_MASTER_RD ,
I2C_MASTER_WRRD ,
} ;
enum I2C_REGS_OFFSET {
2019-04-02 15:35:55 +03:00
OFFSET_DATA_PORT ,
OFFSET_SLAVE_ADDR ,
OFFSET_INTR_MASK ,
OFFSET_INTR_STAT ,
OFFSET_CONTROL ,
OFFSET_TRANSFER_LEN ,
OFFSET_TRANSAC_LEN ,
OFFSET_DELAY_LEN ,
OFFSET_TIMING ,
OFFSET_START ,
OFFSET_EXT_CONF ,
OFFSET_FIFO_STAT ,
OFFSET_FIFO_THRESH ,
OFFSET_FIFO_ADDR_CLR ,
OFFSET_IO_CONFIG ,
OFFSET_RSV_DEBUG ,
OFFSET_HS ,
OFFSET_SOFTRESET ,
OFFSET_DCM_EN ,
OFFSET_PATH_DIR ,
OFFSET_DEBUGSTAT ,
OFFSET_DEBUGCTRL ,
OFFSET_TRANSFER_LEN_AUX ,
OFFSET_CLOCK_DIV ,
2019-04-02 15:35:59 +03:00
OFFSET_LTIMING ,
2019-04-02 15:35:55 +03:00
} ;
static const u16 mt_i2c_regs_v1 [ ] = {
[ OFFSET_DATA_PORT ] = 0x0 ,
[ OFFSET_SLAVE_ADDR ] = 0x4 ,
[ OFFSET_INTR_MASK ] = 0x8 ,
[ OFFSET_INTR_STAT ] = 0xc ,
[ OFFSET_CONTROL ] = 0x10 ,
[ OFFSET_TRANSFER_LEN ] = 0x14 ,
[ OFFSET_TRANSAC_LEN ] = 0x18 ,
[ OFFSET_DELAY_LEN ] = 0x1c ,
[ OFFSET_TIMING ] = 0x20 ,
[ OFFSET_START ] = 0x24 ,
[ OFFSET_EXT_CONF ] = 0x28 ,
[ OFFSET_FIFO_STAT ] = 0x30 ,
[ OFFSET_FIFO_THRESH ] = 0x34 ,
[ OFFSET_FIFO_ADDR_CLR ] = 0x38 ,
[ OFFSET_IO_CONFIG ] = 0x40 ,
[ OFFSET_RSV_DEBUG ] = 0x44 ,
[ OFFSET_HS ] = 0x48 ,
[ OFFSET_SOFTRESET ] = 0x50 ,
[ OFFSET_DCM_EN ] = 0x54 ,
[ OFFSET_PATH_DIR ] = 0x60 ,
[ OFFSET_DEBUGSTAT ] = 0x64 ,
[ OFFSET_DEBUGCTRL ] = 0x68 ,
[ OFFSET_TRANSFER_LEN_AUX ] = 0x6c ,
[ OFFSET_CLOCK_DIV ] = 0x70 ,
2015-05-21 11:53:28 +03:00
} ;
2019-04-02 15:35:59 +03:00
static const u16 mt_i2c_regs_v2 [ ] = {
[ OFFSET_DATA_PORT ] = 0x0 ,
[ OFFSET_SLAVE_ADDR ] = 0x4 ,
[ OFFSET_INTR_MASK ] = 0x8 ,
[ OFFSET_INTR_STAT ] = 0xc ,
[ OFFSET_CONTROL ] = 0x10 ,
[ OFFSET_TRANSFER_LEN ] = 0x14 ,
[ OFFSET_TRANSAC_LEN ] = 0x18 ,
[ OFFSET_DELAY_LEN ] = 0x1c ,
[ OFFSET_TIMING ] = 0x20 ,
[ OFFSET_START ] = 0x24 ,
[ OFFSET_EXT_CONF ] = 0x28 ,
[ OFFSET_LTIMING ] = 0x2c ,
[ OFFSET_HS ] = 0x30 ,
[ OFFSET_IO_CONFIG ] = 0x34 ,
[ OFFSET_FIFO_ADDR_CLR ] = 0x38 ,
[ OFFSET_TRANSFER_LEN_AUX ] = 0x44 ,
[ OFFSET_CLOCK_DIV ] = 0x48 ,
[ OFFSET_SOFTRESET ] = 0x50 ,
[ OFFSET_DEBUGSTAT ] = 0xe0 ,
[ OFFSET_DEBUGCTRL ] = 0xe8 ,
[ OFFSET_FIFO_STAT ] = 0xf4 ,
[ OFFSET_FIFO_THRESH ] = 0xf8 ,
[ OFFSET_DCM_EN ] = 0xf88 ,
} ;
2015-05-21 11:53:28 +03:00
struct mtk_i2c_compatible {
const struct i2c_adapter_quirks * quirks ;
2019-04-02 15:35:55 +03:00
const u16 * regs ;
2015-05-21 11:53:28 +03:00
unsigned char pmic_i2c : 1 ;
unsigned char dcm : 1 ;
2015-05-21 11:53:30 +03:00
unsigned char auto_restart : 1 ;
2015-11-09 08:43:58 +03:00
unsigned char aux_len_reg : 1 ;
2016-02-01 20:19:03 +03:00
unsigned char support_33bits : 1 ;
2017-12-19 09:51:02 +03:00
unsigned char timing_adjust : 1 ;
2019-04-02 15:35:58 +03:00
unsigned char dma_sync : 1 ;
2019-04-02 15:35:59 +03:00
unsigned char ltiming_adjust : 1 ;
2015-05-21 11:53:28 +03:00
} ;
struct mtk_i2c {
struct i2c_adapter adap ; /* i2c host adapter */
struct device * dev ;
struct completion msg_complete ;
/* set in i2c probe */
void __iomem * base ; /* i2c base addr */
void __iomem * pdmabase ; /* dma base address*/
struct clk * clk_main ; /* main clock for i2c bus */
struct clk * clk_dma ; /* DMA clock for i2c via DMA */
struct clk * clk_pmic ; /* PMIC clock for i2c from PMIC */
2019-04-02 15:35:57 +03:00
struct clk * clk_arb ; /* Arbitrator clock for i2c */
2015-05-21 11:53:28 +03:00
bool have_pmic ; /* can use i2c pins from PMIC */
bool use_push_pull ; /* IO config push-pull mode */
u16 irq_stat ; /* interrupt status */
2017-07-17 14:02:10 +03:00
unsigned int clk_src_div ;
2015-05-21 11:53:28 +03:00
unsigned int speed_hz ; /* The speed in transfer */
enum mtk_trans_op op ;
u16 timing_reg ;
u16 high_speed_reg ;
2019-04-02 15:35:59 +03:00
u16 ltiming_reg ;
2015-11-09 08:43:58 +03:00
unsigned char auto_restart ;
2015-12-15 10:22:26 +03:00
bool ignore_restart_irq ;
2015-05-21 11:53:28 +03:00
const struct mtk_i2c_compatible * dev_comp ;
} ;
static const struct i2c_adapter_quirks mt6577_i2c_quirks = {
. flags = I2C_AQ_COMB_WRITE_THEN_READ ,
. max_num_msgs = 1 ,
. max_write_len = 255 ,
. max_read_len = 255 ,
. max_comb_1st_msg_len = 255 ,
. max_comb_2nd_msg_len = 31 ,
} ;
2017-08-21 06:36:54 +03:00
static const struct i2c_adapter_quirks mt7622_i2c_quirks = {
. max_num_msgs = 255 ,
} ;
2017-12-19 09:51:02 +03:00
static const struct mtk_i2c_compatible mt2712_compat = {
2019-04-02 15:35:55 +03:00
. regs = mt_i2c_regs_v1 ,
2017-12-19 09:51:02 +03:00
. pmic_i2c = 0 ,
. dcm = 1 ,
. auto_restart = 1 ,
. aux_len_reg = 1 ,
. support_33bits = 1 ,
. timing_adjust = 1 ,
2019-04-02 15:35:58 +03:00
. dma_sync = 0 ,
2019-04-02 15:35:59 +03:00
. ltiming_adjust = 0 ,
2017-12-19 09:51:02 +03:00
} ;
2015-05-21 11:53:28 +03:00
static const struct mtk_i2c_compatible mt6577_compat = {
. quirks = & mt6577_i2c_quirks ,
2019-04-02 15:35:55 +03:00
. regs = mt_i2c_regs_v1 ,
2015-05-21 11:53:28 +03:00
. pmic_i2c = 0 ,
. dcm = 1 ,
2015-05-21 11:53:30 +03:00
. auto_restart = 0 ,
2015-11-09 08:43:58 +03:00
. aux_len_reg = 0 ,
2016-02-01 20:19:03 +03:00
. support_33bits = 0 ,
2017-12-19 09:51:02 +03:00
. timing_adjust = 0 ,
2019-04-02 15:35:58 +03:00
. dma_sync = 0 ,
2019-04-02 15:35:59 +03:00
. ltiming_adjust = 0 ,
2015-05-21 11:53:28 +03:00
} ;
static const struct mtk_i2c_compatible mt6589_compat = {
. quirks = & mt6577_i2c_quirks ,
2019-04-02 15:35:55 +03:00
. regs = mt_i2c_regs_v1 ,
2015-05-21 11:53:28 +03:00
. pmic_i2c = 1 ,
. dcm = 0 ,
2015-05-21 11:53:30 +03:00
. auto_restart = 0 ,
2015-11-09 08:43:58 +03:00
. aux_len_reg = 0 ,
2016-02-01 20:19:03 +03:00
. support_33bits = 0 ,
2017-12-19 09:51:02 +03:00
. timing_adjust = 0 ,
2019-04-02 15:35:58 +03:00
. dma_sync = 0 ,
2019-04-02 15:35:59 +03:00
. ltiming_adjust = 0 ,
2015-05-21 11:53:30 +03:00
} ;
2017-08-21 06:36:54 +03:00
static const struct mtk_i2c_compatible mt7622_compat = {
. quirks = & mt7622_i2c_quirks ,
2019-04-02 15:35:55 +03:00
. regs = mt_i2c_regs_v1 ,
2017-08-21 06:36:54 +03:00
. pmic_i2c = 0 ,
. dcm = 1 ,
. auto_restart = 1 ,
. aux_len_reg = 1 ,
. support_33bits = 0 ,
2017-12-19 09:51:02 +03:00
. timing_adjust = 0 ,
2019-04-02 15:35:58 +03:00
. dma_sync = 0 ,
2019-04-02 15:35:59 +03:00
. ltiming_adjust = 0 ,
2017-08-21 06:36:54 +03:00
} ;
2015-05-21 11:53:30 +03:00
static const struct mtk_i2c_compatible mt8173_compat = {
2019-04-02 15:35:55 +03:00
. regs = mt_i2c_regs_v1 ,
2015-05-21 11:53:30 +03:00
. pmic_i2c = 0 ,
. dcm = 1 ,
. auto_restart = 1 ,
2015-11-09 08:43:58 +03:00
. aux_len_reg = 1 ,
2016-02-01 20:19:03 +03:00
. support_33bits = 1 ,
2017-12-19 09:51:02 +03:00
. timing_adjust = 0 ,
2019-04-02 15:35:58 +03:00
. dma_sync = 0 ,
2019-04-02 15:35:59 +03:00
. ltiming_adjust = 0 ,
} ;
static const struct mtk_i2c_compatible mt8183_compat = {
. regs = mt_i2c_regs_v2 ,
. pmic_i2c = 0 ,
. dcm = 0 ,
. auto_restart = 1 ,
. aux_len_reg = 1 ,
. support_33bits = 1 ,
. timing_adjust = 1 ,
. dma_sync = 1 ,
. ltiming_adjust = 1 ,
2015-05-21 11:53:28 +03:00
} ;
static const struct of_device_id mtk_i2c_of_match [ ] = {
2017-12-19 09:51:02 +03:00
{ . compatible = " mediatek,mt2712-i2c " , . data = & mt2712_compat } ,
2015-05-21 11:53:28 +03:00
{ . compatible = " mediatek,mt6577-i2c " , . data = & mt6577_compat } ,
{ . compatible = " mediatek,mt6589-i2c " , . data = & mt6589_compat } ,
2017-08-21 06:36:54 +03:00
{ . compatible = " mediatek,mt7622-i2c " , . data = & mt7622_compat } ,
2015-05-21 11:53:30 +03:00
{ . compatible = " mediatek,mt8173-i2c " , . data = & mt8173_compat } ,
2019-04-02 15:35:59 +03:00
{ . compatible = " mediatek,mt8183-i2c " , . data = & mt8183_compat } ,
2015-05-21 11:53:28 +03:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , mtk_i2c_of_match ) ;
2019-04-02 15:35:55 +03:00
static u16 mtk_i2c_readw ( struct mtk_i2c * i2c , enum I2C_REGS_OFFSET reg )
{
return readw ( i2c - > base + i2c - > dev_comp - > regs [ reg ] ) ;
}
static void mtk_i2c_writew ( struct mtk_i2c * i2c , u16 val ,
enum I2C_REGS_OFFSET reg )
{
writew ( val , i2c - > base + i2c - > dev_comp - > regs [ reg ] ) ;
}
2015-05-21 11:53:28 +03:00
static int mtk_i2c_clock_enable ( struct mtk_i2c * i2c )
{
int ret ;
ret = clk_prepare_enable ( i2c - > clk_dma ) ;
if ( ret )
return ret ;
ret = clk_prepare_enable ( i2c - > clk_main ) ;
if ( ret )
goto err_main ;
if ( i2c - > have_pmic ) {
ret = clk_prepare_enable ( i2c - > clk_pmic ) ;
if ( ret )
goto err_pmic ;
}
2019-04-02 15:35:57 +03:00
if ( i2c - > clk_arb ) {
ret = clk_prepare_enable ( i2c - > clk_arb ) ;
if ( ret )
goto err_arb ;
}
2015-05-21 11:53:28 +03:00
return 0 ;
2019-04-02 15:35:57 +03:00
err_arb :
if ( i2c - > have_pmic )
clk_disable_unprepare ( i2c - > clk_pmic ) ;
2015-05-21 11:53:28 +03:00
err_pmic :
clk_disable_unprepare ( i2c - > clk_main ) ;
err_main :
clk_disable_unprepare ( i2c - > clk_dma ) ;
return ret ;
}
static void mtk_i2c_clock_disable ( struct mtk_i2c * i2c )
{
2019-04-02 15:35:57 +03:00
if ( i2c - > clk_arb )
clk_disable_unprepare ( i2c - > clk_arb ) ;
2015-05-21 11:53:28 +03:00
if ( i2c - > have_pmic )
clk_disable_unprepare ( i2c - > clk_pmic ) ;
clk_disable_unprepare ( i2c - > clk_main ) ;
clk_disable_unprepare ( i2c - > clk_dma ) ;
}
static void mtk_i2c_init_hw ( struct mtk_i2c * i2c )
{
u16 control_reg ;
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , I2C_SOFT_RST , OFFSET_SOFTRESET ) ;
2015-05-21 11:53:28 +03:00
/* Set ioconfig */
if ( i2c - > use_push_pull )
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , I2C_IO_CONFIG_PUSH_PULL , OFFSET_IO_CONFIG ) ;
2015-05-21 11:53:28 +03:00
else
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , I2C_IO_CONFIG_OPEN_DRAIN , OFFSET_IO_CONFIG ) ;
2015-05-21 11:53:28 +03:00
if ( i2c - > dev_comp - > dcm )
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , I2C_DCM_DISABLE , OFFSET_DCM_EN ) ;
2015-05-21 11:53:28 +03:00
2017-12-19 09:51:02 +03:00
if ( i2c - > dev_comp - > timing_adjust )
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , I2C_DEFAULT_CLK_DIV - 1 , OFFSET_CLOCK_DIV ) ;
2017-12-19 09:51:02 +03:00
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , i2c - > timing_reg , OFFSET_TIMING ) ;
mtk_i2c_writew ( i2c , i2c - > high_speed_reg , OFFSET_HS ) ;
2019-04-02 15:35:59 +03:00
if ( i2c - > dev_comp - > ltiming_adjust )
mtk_i2c_writew ( i2c , i2c - > ltiming_reg , OFFSET_LTIMING ) ;
2015-05-21 11:53:28 +03:00
/* If use i2c pin from PMIC mt6397 side, need set PATH_DIR first */
if ( i2c - > have_pmic )
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , I2C_CONTROL_WRAPPER , OFFSET_PATH_DIR ) ;
2015-05-21 11:53:28 +03:00
control_reg = I2C_CONTROL_ACKERR_DET_EN |
I2C_CONTROL_CLK_EXT_EN | I2C_CONTROL_DMA_EN ;
2019-04-02 15:35:58 +03:00
if ( i2c - > dev_comp - > dma_sync )
control_reg | = I2C_CONTROL_DMAACK_EN | I2C_CONTROL_ASYNC_MODE ;
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , control_reg , OFFSET_CONTROL ) ;
mtk_i2c_writew ( i2c , I2C_DELAY_LEN , OFFSET_DELAY_LEN ) ;
2015-08-06 10:22:10 +03:00
writel ( I2C_DMA_HARD_RST , i2c - > pdmabase + OFFSET_RST ) ;
udelay ( 50 ) ;
writel ( I2C_DMA_CLR_FLAG , i2c - > pdmabase + OFFSET_RST ) ;
2015-05-21 11:53:28 +03:00
}
/*
* Calculate i2c port speed
*
* Hardware design :
* i2c_bus_freq = parent_clk / ( clock_div * 2 * sample_cnt * step_cnt )
* clock_div : fixed in hardware , but may be various in different SoCs
*
* The calculation want to pick the highest bus frequency that is still
* less than or equal to i2c - > speed_hz . The calculation try to get
* sample_cnt and step_cn
*/
2017-07-17 14:02:10 +03:00
static int mtk_i2c_calculate_speed ( struct mtk_i2c * i2c , unsigned int clk_src ,
unsigned int target_speed ,
unsigned int * timing_step_cnt ,
unsigned int * timing_sample_cnt )
2015-05-21 11:53:28 +03:00
{
unsigned int step_cnt ;
unsigned int sample_cnt ;
unsigned int max_step_cnt ;
unsigned int base_sample_cnt = MAX_SAMPLE_CNT_DIV ;
unsigned int base_step_cnt ;
unsigned int opt_div ;
unsigned int best_mul ;
unsigned int cnt_mul ;
if ( target_speed > MAX_HS_MODE_SPEED )
target_speed = MAX_HS_MODE_SPEED ;
if ( target_speed > MAX_FS_MODE_SPEED )
max_step_cnt = MAX_HS_STEP_CNT_DIV ;
else
max_step_cnt = MAX_STEP_CNT_DIV ;
base_step_cnt = max_step_cnt ;
/* Find the best combination */
opt_div = DIV_ROUND_UP ( clk_src > > 1 , target_speed ) ;
best_mul = MAX_SAMPLE_CNT_DIV * max_step_cnt ;
/* Search for the best pair (sample_cnt, step_cnt) with
* 0 < sample_cnt < MAX_SAMPLE_CNT_DIV
* 0 < step_cnt < max_step_cnt
* sample_cnt * step_cnt > = opt_div
* optimizing for sample_cnt * step_cnt being minimal
*/
for ( sample_cnt = 1 ; sample_cnt < = MAX_SAMPLE_CNT_DIV ; sample_cnt + + ) {
step_cnt = DIV_ROUND_UP ( opt_div , sample_cnt ) ;
cnt_mul = step_cnt * sample_cnt ;
if ( step_cnt > max_step_cnt )
continue ;
if ( cnt_mul < best_mul ) {
best_mul = cnt_mul ;
base_sample_cnt = sample_cnt ;
base_step_cnt = step_cnt ;
if ( best_mul = = opt_div )
break ;
}
}
sample_cnt = base_sample_cnt ;
step_cnt = base_step_cnt ;
if ( ( clk_src / ( 2 * sample_cnt * step_cnt ) ) > target_speed ) {
/* In this case, hardware can't support such
* low i2c_bus_freq
*/
dev_dbg ( i2c - > dev , " Unsupported speed (%uhz) \n " , target_speed ) ;
return - EINVAL ;
}
2017-07-17 14:02:10 +03:00
* timing_step_cnt = step_cnt - 1 ;
* timing_sample_cnt = sample_cnt - 1 ;
return 0 ;
}
static int mtk_i2c_set_speed ( struct mtk_i2c * i2c , unsigned int parent_clk )
{
unsigned int clk_src ;
unsigned int step_cnt ;
unsigned int sample_cnt ;
2019-04-02 15:35:59 +03:00
unsigned int l_step_cnt ;
unsigned int l_sample_cnt ;
2017-07-17 14:02:10 +03:00
unsigned int target_speed ;
int ret ;
clk_src = parent_clk / i2c - > clk_src_div ;
target_speed = i2c - > speed_hz ;
2015-05-21 11:53:28 +03:00
if ( target_speed > MAX_FS_MODE_SPEED ) {
2017-07-17 14:02:10 +03:00
/* Set master code speed register */
ret = mtk_i2c_calculate_speed ( i2c , clk_src , MAX_FS_MODE_SPEED ,
2019-04-02 15:35:59 +03:00
& l_step_cnt , & l_sample_cnt ) ;
2017-07-17 14:02:10 +03:00
if ( ret < 0 )
return ret ;
2019-04-02 15:35:59 +03:00
i2c - > timing_reg = ( l_sample_cnt < < 8 ) | l_step_cnt ;
2017-07-17 14:02:10 +03:00
2015-05-21 11:53:28 +03:00
/* Set the high speed mode register */
2017-07-17 14:02:10 +03:00
ret = mtk_i2c_calculate_speed ( i2c , clk_src , target_speed ,
& step_cnt , & sample_cnt ) ;
if ( ret < 0 )
return ret ;
2015-05-21 11:53:28 +03:00
i2c - > high_speed_reg = I2C_TIME_DEFAULT_VALUE |
( sample_cnt < < 12 ) | ( step_cnt < < 8 ) ;
2019-04-02 15:35:59 +03:00
if ( i2c - > dev_comp - > ltiming_adjust )
i2c - > ltiming_reg = ( l_sample_cnt < < 6 ) | l_step_cnt |
( sample_cnt < < 12 ) | ( step_cnt < < 9 ) ;
2015-05-21 11:53:28 +03:00
} else {
2017-07-17 14:02:10 +03:00
ret = mtk_i2c_calculate_speed ( i2c , clk_src , target_speed ,
& step_cnt , & sample_cnt ) ;
if ( ret < 0 )
return ret ;
i2c - > timing_reg = ( sample_cnt < < 8 ) | step_cnt ;
2015-05-21 11:53:28 +03:00
/* Disable the high speed transaction */
i2c - > high_speed_reg = I2C_TIME_CLR_VALUE ;
2019-04-02 15:35:59 +03:00
if ( i2c - > dev_comp - > ltiming_adjust )
i2c - > ltiming_reg = ( sample_cnt < < 6 ) | step_cnt ;
2015-05-21 11:53:28 +03:00
}
return 0 ;
}
2016-02-01 20:19:03 +03:00
static inline u32 mtk_i2c_set_4g_mode ( dma_addr_t addr )
{
return ( addr & BIT_ULL ( 32 ) ) ? I2C_DMA_4G_MODE : I2C_DMA_CLR_FLAG ;
}
2015-05-21 11:53:30 +03:00
static int mtk_i2c_do_transfer ( struct mtk_i2c * i2c , struct i2c_msg * msgs ,
int num , int left_num )
2015-05-21 11:53:28 +03:00
{
u16 addr_reg ;
2015-05-21 11:53:30 +03:00
u16 start_reg ;
2015-05-21 11:53:28 +03:00
u16 control_reg ;
2015-05-21 11:53:30 +03:00
u16 restart_flag = 0 ;
2016-02-01 20:19:03 +03:00
u32 reg_4g_mode ;
2018-09-06 16:15:29 +03:00
u8 * dma_rd_buf = NULL ;
u8 * dma_wr_buf = NULL ;
2015-05-21 11:53:28 +03:00
dma_addr_t rpaddr = 0 ;
dma_addr_t wpaddr = 0 ;
int ret ;
i2c - > irq_stat = 0 ;
2015-11-09 08:43:58 +03:00
if ( i2c - > auto_restart )
2015-05-21 11:53:30 +03:00
restart_flag = I2C_RS_TRANSFER ;
2015-05-21 11:53:28 +03:00
reinit_completion ( & i2c - > msg_complete ) ;
2019-04-02 15:35:55 +03:00
control_reg = mtk_i2c_readw ( i2c , OFFSET_CONTROL ) &
2015-05-21 11:53:28 +03:00
~ ( I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS ) ;
2019-01-21 10:59:30 +03:00
if ( ( i2c - > speed_hz > MAX_FS_MODE_SPEED ) | | ( left_num > = 1 ) )
2015-05-21 11:53:28 +03:00
control_reg | = I2C_CONTROL_RS ;
if ( i2c - > op = = I2C_MASTER_WRRD )
control_reg | = I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS ;
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , control_reg , OFFSET_CONTROL ) ;
2015-05-21 11:53:28 +03:00
/* set start condition */
2019-01-21 10:59:30 +03:00
if ( i2c - > speed_hz < = I2C_DEFAULT_SPEED )
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , I2C_ST_START_CON , OFFSET_EXT_CONF ) ;
2015-05-21 11:53:28 +03:00
else
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , I2C_FS_START_CON , OFFSET_EXT_CONF ) ;
2015-05-21 11:53:28 +03:00
2016-04-03 21:44:55 +03:00
addr_reg = i2c_8bit_addr_from_msg ( msgs ) ;
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , addr_reg , OFFSET_SLAVE_ADDR ) ;
2015-05-21 11:53:28 +03:00
/* Clear interrupt status */
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , restart_flag | I2C_HS_NACKERR | I2C_ACKERR |
2019-04-02 15:35:57 +03:00
I2C_ARB_LOST | I2C_TRANSAC_COMP , OFFSET_INTR_STAT ) ;
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , I2C_FIFO_ADDR_CLR , OFFSET_FIFO_ADDR_CLR ) ;
2015-05-21 11:53:28 +03:00
/* Enable interrupt */
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , restart_flag | I2C_HS_NACKERR | I2C_ACKERR |
2019-04-02 15:35:57 +03:00
I2C_ARB_LOST | I2C_TRANSAC_COMP , OFFSET_INTR_MASK ) ;
2015-05-21 11:53:28 +03:00
/* Set transfer and transaction len */
if ( i2c - > op = = I2C_MASTER_WRRD ) {
2015-11-09 08:43:58 +03:00
if ( i2c - > dev_comp - > aux_len_reg ) {
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , msgs - > len , OFFSET_TRANSFER_LEN ) ;
mtk_i2c_writew ( i2c , ( msgs + 1 ) - > len ,
OFFSET_TRANSFER_LEN_AUX ) ;
2015-11-09 08:43:58 +03:00
} else {
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , msgs - > len | ( ( msgs + 1 ) - > len ) < < 8 ,
OFFSET_TRANSFER_LEN ) ;
2015-11-09 08:43:58 +03:00
}
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , I2C_WRRD_TRANAC_VALUE , OFFSET_TRANSAC_LEN ) ;
2015-05-21 11:53:28 +03:00
} else {
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , msgs - > len , OFFSET_TRANSFER_LEN ) ;
mtk_i2c_writew ( i2c , num , OFFSET_TRANSAC_LEN ) ;
2015-05-21 11:53:28 +03:00
}
/* Prepare buffer data to start transfer */
if ( i2c - > op = = I2C_MASTER_RD ) {
writel ( I2C_DMA_INT_FLAG_NONE , i2c - > pdmabase + OFFSET_INT_FLAG ) ;
writel ( I2C_DMA_CON_RX , i2c - > pdmabase + OFFSET_CON ) ;
2018-09-06 16:15:29 +03:00
2019-02-15 12:02:02 +03:00
dma_rd_buf = i2c_get_dma_safe_msg_buf ( msgs , 1 ) ;
2018-09-06 16:15:29 +03:00
if ( ! dma_rd_buf )
return - ENOMEM ;
rpaddr = dma_map_single ( i2c - > dev , dma_rd_buf ,
2015-05-21 11:53:28 +03:00
msgs - > len , DMA_FROM_DEVICE ) ;
2018-09-06 16:15:29 +03:00
if ( dma_mapping_error ( i2c - > dev , rpaddr ) ) {
i2c_put_dma_safe_msg_buf ( dma_rd_buf , msgs , false ) ;
2015-05-21 11:53:28 +03:00
return - ENOMEM ;
2018-09-06 16:15:29 +03:00
}
2016-02-01 20:19:03 +03:00
if ( i2c - > dev_comp - > support_33bits ) {
reg_4g_mode = mtk_i2c_set_4g_mode ( rpaddr ) ;
writel ( reg_4g_mode , i2c - > pdmabase + OFFSET_RX_4G_MODE ) ;
}
2015-05-21 11:53:28 +03:00
writel ( ( u32 ) rpaddr , i2c - > pdmabase + OFFSET_RX_MEM_ADDR ) ;
writel ( msgs - > len , i2c - > pdmabase + OFFSET_RX_LEN ) ;
} else if ( i2c - > op = = I2C_MASTER_WR ) {
writel ( I2C_DMA_INT_FLAG_NONE , i2c - > pdmabase + OFFSET_INT_FLAG ) ;
writel ( I2C_DMA_CON_TX , i2c - > pdmabase + OFFSET_CON ) ;
2018-09-06 16:15:29 +03:00
2019-02-15 12:02:02 +03:00
dma_wr_buf = i2c_get_dma_safe_msg_buf ( msgs , 1 ) ;
2018-09-06 16:15:29 +03:00
if ( ! dma_wr_buf )
return - ENOMEM ;
wpaddr = dma_map_single ( i2c - > dev , dma_wr_buf ,
2015-05-21 11:53:28 +03:00
msgs - > len , DMA_TO_DEVICE ) ;
2018-09-06 16:15:29 +03:00
if ( dma_mapping_error ( i2c - > dev , wpaddr ) ) {
i2c_put_dma_safe_msg_buf ( dma_wr_buf , msgs , false ) ;
2015-05-21 11:53:28 +03:00
return - ENOMEM ;
2018-09-06 16:15:29 +03:00
}
2016-02-01 20:19:03 +03:00
if ( i2c - > dev_comp - > support_33bits ) {
reg_4g_mode = mtk_i2c_set_4g_mode ( wpaddr ) ;
writel ( reg_4g_mode , i2c - > pdmabase + OFFSET_TX_4G_MODE ) ;
}
2015-05-21 11:53:28 +03:00
writel ( ( u32 ) wpaddr , i2c - > pdmabase + OFFSET_TX_MEM_ADDR ) ;
writel ( msgs - > len , i2c - > pdmabase + OFFSET_TX_LEN ) ;
} else {
writel ( I2C_DMA_CLR_FLAG , i2c - > pdmabase + OFFSET_INT_FLAG ) ;
writel ( I2C_DMA_CLR_FLAG , i2c - > pdmabase + OFFSET_CON ) ;
2018-09-06 16:15:29 +03:00
2019-02-15 12:02:02 +03:00
dma_wr_buf = i2c_get_dma_safe_msg_buf ( msgs , 1 ) ;
2018-09-06 16:15:29 +03:00
if ( ! dma_wr_buf )
return - ENOMEM ;
wpaddr = dma_map_single ( i2c - > dev , dma_wr_buf ,
2015-05-21 11:53:28 +03:00
msgs - > len , DMA_TO_DEVICE ) ;
2018-09-06 16:15:29 +03:00
if ( dma_mapping_error ( i2c - > dev , wpaddr ) ) {
i2c_put_dma_safe_msg_buf ( dma_wr_buf , msgs , false ) ;
2015-05-21 11:53:28 +03:00
return - ENOMEM ;
2018-09-06 16:15:29 +03:00
}
2019-02-15 12:02:02 +03:00
dma_rd_buf = i2c_get_dma_safe_msg_buf ( ( msgs + 1 ) , 1 ) ;
2018-09-06 16:15:29 +03:00
if ( ! dma_rd_buf ) {
dma_unmap_single ( i2c - > dev , wpaddr ,
msgs - > len , DMA_TO_DEVICE ) ;
i2c_put_dma_safe_msg_buf ( dma_wr_buf , msgs , false ) ;
return - ENOMEM ;
}
rpaddr = dma_map_single ( i2c - > dev , dma_rd_buf ,
2015-05-21 11:53:28 +03:00
( msgs + 1 ) - > len ,
DMA_FROM_DEVICE ) ;
if ( dma_mapping_error ( i2c - > dev , rpaddr ) ) {
dma_unmap_single ( i2c - > dev , wpaddr ,
msgs - > len , DMA_TO_DEVICE ) ;
2018-09-06 16:15:29 +03:00
i2c_put_dma_safe_msg_buf ( dma_wr_buf , msgs , false ) ;
i2c_put_dma_safe_msg_buf ( dma_rd_buf , ( msgs + 1 ) , false ) ;
2015-05-21 11:53:28 +03:00
return - ENOMEM ;
}
2016-02-01 20:19:03 +03:00
if ( i2c - > dev_comp - > support_33bits ) {
reg_4g_mode = mtk_i2c_set_4g_mode ( wpaddr ) ;
writel ( reg_4g_mode , i2c - > pdmabase + OFFSET_TX_4G_MODE ) ;
reg_4g_mode = mtk_i2c_set_4g_mode ( rpaddr ) ;
writel ( reg_4g_mode , i2c - > pdmabase + OFFSET_RX_4G_MODE ) ;
}
2015-05-21 11:53:28 +03:00
writel ( ( u32 ) wpaddr , i2c - > pdmabase + OFFSET_TX_MEM_ADDR ) ;
writel ( ( u32 ) rpaddr , i2c - > pdmabase + OFFSET_RX_MEM_ADDR ) ;
writel ( msgs - > len , i2c - > pdmabase + OFFSET_TX_LEN ) ;
writel ( ( msgs + 1 ) - > len , i2c - > pdmabase + OFFSET_RX_LEN ) ;
}
writel ( I2C_DMA_START_EN , i2c - > pdmabase + OFFSET_EN ) ;
2015-05-21 11:53:30 +03:00
2015-11-09 08:43:58 +03:00
if ( ! i2c - > auto_restart ) {
2015-05-21 11:53:30 +03:00
start_reg = I2C_TRANSAC_START ;
} else {
start_reg = I2C_TRANSAC_START | I2C_RS_MUL_TRIG ;
if ( left_num > = 1 )
start_reg | = I2C_RS_MUL_CNFG ;
}
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , start_reg , OFFSET_START ) ;
2015-05-21 11:53:28 +03:00
ret = wait_for_completion_timeout ( & i2c - > msg_complete ,
i2c - > adap . timeout ) ;
/* Clear interrupt mask */
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , ~ ( restart_flag | I2C_HS_NACKERR | I2C_ACKERR |
2019-04-02 15:35:57 +03:00
I2C_ARB_LOST | I2C_TRANSAC_COMP ) , OFFSET_INTR_MASK ) ;
2015-05-21 11:53:28 +03:00
if ( i2c - > op = = I2C_MASTER_WR ) {
dma_unmap_single ( i2c - > dev , wpaddr ,
msgs - > len , DMA_TO_DEVICE ) ;
2018-09-06 16:15:29 +03:00
i2c_put_dma_safe_msg_buf ( dma_wr_buf , msgs , true ) ;
2015-05-21 11:53:28 +03:00
} else if ( i2c - > op = = I2C_MASTER_RD ) {
dma_unmap_single ( i2c - > dev , rpaddr ,
msgs - > len , DMA_FROM_DEVICE ) ;
2018-09-06 16:15:29 +03:00
i2c_put_dma_safe_msg_buf ( dma_rd_buf , msgs , true ) ;
2015-05-21 11:53:28 +03:00
} else {
dma_unmap_single ( i2c - > dev , wpaddr , msgs - > len ,
DMA_TO_DEVICE ) ;
dma_unmap_single ( i2c - > dev , rpaddr , ( msgs + 1 ) - > len ,
DMA_FROM_DEVICE ) ;
2018-09-06 16:15:29 +03:00
i2c_put_dma_safe_msg_buf ( dma_wr_buf , msgs , true ) ;
i2c_put_dma_safe_msg_buf ( dma_rd_buf , ( msgs + 1 ) , true ) ;
2015-05-21 11:53:28 +03:00
}
if ( ret = = 0 ) {
dev_dbg ( i2c - > dev , " addr: %x, transfer timeout \n " , msgs - > addr ) ;
mtk_i2c_init_hw ( i2c ) ;
return - ETIMEDOUT ;
}
if ( i2c - > irq_stat & ( I2C_HS_NACKERR | I2C_ACKERR ) ) {
dev_dbg ( i2c - > dev , " addr: %x, transfer ACK error \n " , msgs - > addr ) ;
mtk_i2c_init_hw ( i2c ) ;
return - ENXIO ;
}
return 0 ;
}
static int mtk_i2c_transfer ( struct i2c_adapter * adap ,
struct i2c_msg msgs [ ] , int num )
{
int ret ;
int left_num = num ;
struct mtk_i2c * i2c = i2c_get_adapdata ( adap ) ;
ret = mtk_i2c_clock_enable ( i2c ) ;
if ( ret )
return ret ;
2015-11-09 08:43:58 +03:00
i2c - > auto_restart = i2c - > dev_comp - > auto_restart ;
/* checking if we can skip restart and optimize using WRRD mode */
if ( i2c - > auto_restart & & num = = 2 ) {
if ( ! ( msgs [ 0 ] . flags & I2C_M_RD ) & & ( msgs [ 1 ] . flags & I2C_M_RD ) & &
msgs [ 0 ] . addr = = msgs [ 1 ] . addr ) {
i2c - > auto_restart = 0 ;
}
}
2015-12-15 10:22:26 +03:00
if ( i2c - > auto_restart & & num > = 2 & & i2c - > speed_hz > MAX_FS_MODE_SPEED )
/* ignore the first restart irq after the master code,
* otherwise the first transfer will be discarded .
*/
i2c - > ignore_restart_irq = true ;
else
i2c - > ignore_restart_irq = false ;
2015-05-21 11:53:30 +03:00
while ( left_num - - ) {
if ( ! msgs - > buf ) {
dev_dbg ( i2c - > dev , " data buffer is NULL. \n " ) ;
ret = - EINVAL ;
goto err_exit ;
}
2015-05-21 11:53:28 +03:00
2015-05-21 11:53:30 +03:00
if ( msgs - > flags & I2C_M_RD )
i2c - > op = I2C_MASTER_RD ;
else
i2c - > op = I2C_MASTER_WR ;
2015-11-09 08:43:58 +03:00
if ( ! i2c - > auto_restart ) {
2015-05-21 11:53:30 +03:00
if ( num > 1 ) {
/* combined two messages into one transaction */
i2c - > op = I2C_MASTER_WRRD ;
left_num - - ;
}
}
2015-05-21 11:53:28 +03:00
2015-05-21 11:53:30 +03:00
/* always use DMA mode. */
ret = mtk_i2c_do_transfer ( i2c , msgs , num , left_num ) ;
if ( ret < 0 )
goto err_exit ;
2015-05-21 11:53:28 +03:00
2015-05-21 11:53:30 +03:00
msgs + + ;
}
2015-05-21 11:53:28 +03:00
/* the return value is number of executed messages */
ret = num ;
err_exit :
mtk_i2c_clock_disable ( i2c ) ;
return ret ;
}
static irqreturn_t mtk_i2c_irq ( int irqno , void * dev_id )
{
struct mtk_i2c * i2c = dev_id ;
2015-05-21 11:53:30 +03:00
u16 restart_flag = 0 ;
2015-08-06 10:22:11 +03:00
u16 intr_stat ;
2015-05-21 11:53:30 +03:00
2015-11-09 08:43:58 +03:00
if ( i2c - > auto_restart )
2015-05-21 11:53:30 +03:00
restart_flag = I2C_RS_TRANSFER ;
2015-05-21 11:53:28 +03:00
2019-04-02 15:35:55 +03:00
intr_stat = mtk_i2c_readw ( i2c , OFFSET_INTR_STAT ) ;
mtk_i2c_writew ( i2c , intr_stat , OFFSET_INTR_STAT ) ;
2015-05-21 11:53:28 +03:00
2015-08-06 10:22:11 +03:00
/*
* when occurs ack error , i2c controller generate two interrupts
* first is the ack error interrupt , then the complete interrupt
* i2c - > irq_stat need keep the two interrupt value .
*/
i2c - > irq_stat | = intr_stat ;
2015-12-15 10:22:26 +03:00
if ( i2c - > ignore_restart_irq & & ( i2c - > irq_stat & restart_flag ) ) {
i2c - > ignore_restart_irq = false ;
i2c - > irq_stat = 0 ;
2019-04-02 15:35:55 +03:00
mtk_i2c_writew ( i2c , I2C_RS_MUL_CNFG | I2C_RS_MUL_TRIG |
I2C_TRANSAC_START , OFFSET_START ) ;
2015-12-15 10:22:26 +03:00
} else {
if ( i2c - > irq_stat & ( I2C_TRANSAC_COMP | restart_flag ) )
complete ( & i2c - > msg_complete ) ;
}
2015-05-21 11:53:28 +03:00
return IRQ_HANDLED ;
}
static u32 mtk_i2c_functionality ( struct i2c_adapter * adap )
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL ;
}
static const struct i2c_algorithm mtk_i2c_algorithm = {
. master_xfer = mtk_i2c_transfer ,
. functionality = mtk_i2c_functionality ,
} ;
2017-07-17 14:02:10 +03:00
static int mtk_i2c_parse_dt ( struct device_node * np , struct mtk_i2c * i2c )
2015-05-21 11:53:28 +03:00
{
int ret ;
ret = of_property_read_u32 ( np , " clock-frequency " , & i2c - > speed_hz ) ;
if ( ret < 0 )
i2c - > speed_hz = I2C_DEFAULT_SPEED ;
2017-07-17 14:02:10 +03:00
ret = of_property_read_u32 ( np , " clock-div " , & i2c - > clk_src_div ) ;
2015-05-21 11:53:28 +03:00
if ( ret < 0 )
return ret ;
2017-07-17 14:02:10 +03:00
if ( i2c - > clk_src_div = = 0 )
2015-05-21 11:53:28 +03:00
return - EINVAL ;
i2c - > have_pmic = of_property_read_bool ( np , " mediatek,have-pmic " ) ;
i2c - > use_push_pull =
of_property_read_bool ( np , " mediatek,use-push-pull " ) ;
return 0 ;
}
static int mtk_i2c_probe ( struct platform_device * pdev )
{
int ret = 0 ;
struct mtk_i2c * i2c ;
struct clk * clk ;
struct resource * res ;
int irq ;
i2c = devm_kzalloc ( & pdev - > dev , sizeof ( * i2c ) , GFP_KERNEL ) ;
if ( ! i2c )
return - ENOMEM ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
i2c - > base = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( i2c - > base ) )
return PTR_ERR ( i2c - > base ) ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 1 ) ;
i2c - > pdmabase = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( i2c - > pdmabase ) )
return PTR_ERR ( i2c - > pdmabase ) ;
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < = 0 )
return irq ;
init_completion ( & i2c - > msg_complete ) ;
2018-04-16 05:32:52 +03:00
i2c - > dev_comp = of_device_get_match_data ( & pdev - > dev ) ;
2015-05-21 11:53:28 +03:00
i2c - > adap . dev . of_node = pdev - > dev . of_node ;
i2c - > dev = & pdev - > dev ;
i2c - > adap . dev . parent = & pdev - > dev ;
i2c - > adap . owner = THIS_MODULE ;
i2c - > adap . algo = & mtk_i2c_algorithm ;
i2c - > adap . quirks = i2c - > dev_comp - > quirks ;
i2c - > adap . timeout = 2 * HZ ;
i2c - > adap . retries = 1 ;
2017-12-19 09:51:02 +03:00
ret = mtk_i2c_parse_dt ( pdev - > dev . of_node , i2c ) ;
if ( ret )
return - EINVAL ;
if ( i2c - > dev_comp - > timing_adjust )
i2c - > clk_src_div * = I2C_DEFAULT_CLK_DIV ;
2015-05-21 11:53:28 +03:00
if ( i2c - > have_pmic & & ! i2c - > dev_comp - > pmic_i2c )
return - EINVAL ;
i2c - > clk_main = devm_clk_get ( & pdev - > dev , " main " ) ;
if ( IS_ERR ( i2c - > clk_main ) ) {
dev_err ( & pdev - > dev , " cannot get main clock \n " ) ;
return PTR_ERR ( i2c - > clk_main ) ;
}
i2c - > clk_dma = devm_clk_get ( & pdev - > dev , " dma " ) ;
if ( IS_ERR ( i2c - > clk_dma ) ) {
dev_err ( & pdev - > dev , " cannot get dma clock \n " ) ;
return PTR_ERR ( i2c - > clk_dma ) ;
}
2019-04-02 15:35:57 +03:00
i2c - > clk_arb = devm_clk_get ( & pdev - > dev , " arb " ) ;
if ( IS_ERR ( i2c - > clk_arb ) )
i2c - > clk_arb = NULL ;
2015-05-21 11:53:28 +03:00
clk = i2c - > clk_main ;
if ( i2c - > have_pmic ) {
i2c - > clk_pmic = devm_clk_get ( & pdev - > dev , " pmic " ) ;
if ( IS_ERR ( i2c - > clk_pmic ) ) {
dev_err ( & pdev - > dev , " cannot get pmic clock \n " ) ;
return PTR_ERR ( i2c - > clk_pmic ) ;
}
clk = i2c - > clk_pmic ;
}
strlcpy ( i2c - > adap . name , I2C_DRV_NAME , sizeof ( i2c - > adap . name ) ) ;
2017-07-17 14:02:10 +03:00
ret = mtk_i2c_set_speed ( i2c , clk_get_rate ( clk ) ) ;
2015-05-21 11:53:28 +03:00
if ( ret ) {
dev_err ( & pdev - > dev , " Failed to set the speed. \n " ) ;
return - EINVAL ;
}
2016-02-01 20:19:03 +03:00
if ( i2c - > dev_comp - > support_33bits ) {
ret = dma_set_mask ( & pdev - > dev , DMA_BIT_MASK ( 33 ) ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " dma_set_mask return error. \n " ) ;
return ret ;
}
}
2015-05-21 11:53:28 +03:00
ret = mtk_i2c_clock_enable ( i2c ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " clock enable failed! \n " ) ;
return ret ;
}
mtk_i2c_init_hw ( i2c ) ;
mtk_i2c_clock_disable ( i2c ) ;
ret = devm_request_irq ( & pdev - > dev , irq , mtk_i2c_irq ,
IRQF_TRIGGER_NONE , I2C_DRV_NAME , i2c ) ;
if ( ret < 0 ) {
dev_err ( & pdev - > dev ,
" Request I2C IRQ %d fail \n " , irq ) ;
return ret ;
}
i2c_set_adapdata ( & i2c - > adap , i2c ) ;
ret = i2c_add_adapter ( & i2c - > adap ) ;
2016-08-09 14:36:17 +03:00
if ( ret )
2015-05-21 11:53:28 +03:00
return ret ;
platform_set_drvdata ( pdev , i2c ) ;
return 0 ;
}
static int mtk_i2c_remove ( struct platform_device * pdev )
{
struct mtk_i2c * i2c = platform_get_drvdata ( pdev ) ;
i2c_del_adapter ( & i2c - > adap ) ;
return 0 ;
}
2015-10-06 12:22:56 +03:00
# ifdef CONFIG_PM_SLEEP
static int mtk_i2c_resume ( struct device * dev )
{
2017-12-19 09:51:03 +03:00
int ret ;
2015-10-06 12:22:56 +03:00
struct mtk_i2c * i2c = dev_get_drvdata ( dev ) ;
2017-12-19 09:51:03 +03:00
ret = mtk_i2c_clock_enable ( i2c ) ;
if ( ret ) {
dev_err ( dev , " clock enable failed! \n " ) ;
return ret ;
}
2015-10-06 12:22:56 +03:00
mtk_i2c_init_hw ( i2c ) ;
2017-12-19 09:51:03 +03:00
mtk_i2c_clock_disable ( i2c ) ;
2015-10-06 12:22:56 +03:00
return 0 ;
}
# endif
static const struct dev_pm_ops mtk_i2c_pm = {
SET_SYSTEM_SLEEP_PM_OPS ( NULL , mtk_i2c_resume )
} ;
2015-05-21 11:53:28 +03:00
static struct platform_driver mtk_i2c_driver = {
. probe = mtk_i2c_probe ,
. remove = mtk_i2c_remove ,
. driver = {
. name = I2C_DRV_NAME ,
2015-10-06 12:22:56 +03:00
. pm = & mtk_i2c_pm ,
2015-05-21 11:53:28 +03:00
. of_match_table = of_match_ptr ( mtk_i2c_of_match ) ,
} ,
} ;
module_platform_driver ( mtk_i2c_driver ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " MediaTek I2C Bus Driver " ) ;
MODULE_AUTHOR ( " Xudong Chen <xudong.chen@mediatek.com> " ) ;