2022-07-08 13:03:50 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for the Renesas RZ / V2M I2C unit
*
* Copyright ( C ) 2016 - 2022 Renesas Electronics Corporation
*/
# include <linux/bits.h>
# include <linux/clk.h>
# include <linux/device.h>
# include <linux/err.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/iopoll.h>
# include <linux/i2c.h>
# include <linux/jiffies.h>
# include <linux/kernel.h>
# include <linux/math64.h>
# include <linux/module.h>
# include <linux/mod_devicetable.h>
# include <linux/platform_device.h>
# include <linux/pm_runtime.h>
# include <linux/reset.h>
/* Register offsets */
# define IICB0DAT 0x00 /* Data Register */
# define IICB0CTL0 0x08 /* Control Register 0 */
# define IICB0TRG 0x0C /* Trigger Register */
# define IICB0STR0 0x10 /* Status Register 0 */
# define IICB0CTL1 0x20 /* Control Register 1 */
# define IICB0WL 0x24 /* Low Level Width Setting Reg */
# define IICB0WH 0x28 /* How Level Width Setting Reg */
/* IICB0CTL0 */
# define IICB0IICE BIT(7) /* I2C Enable */
# define IICB0SLWT BIT(1) /* Interrupt Request Timing */
# define IICB0SLAC BIT(0) /* Acknowledge */
/* IICB0TRG */
# define IICB0WRET BIT(2) /* Quit Wait Trigger */
# define IICB0STT BIT(1) /* Create Start Condition Trigger */
# define IICB0SPT BIT(0) /* Create Stop Condition Trigger */
/* IICB0STR0 */
# define IICB0SSAC BIT(8) /* Ack Flag */
# define IICB0SSBS BIT(6) /* Bus Flag */
# define IICB0SSSP BIT(4) /* Stop Condition Flag */
/* IICB0CTL1 */
# define IICB0MDSC BIT(7) /* Bus Mode */
# define IICB0SLSE BIT(1) /* Start condition output */
struct rzv2m_i2c_priv {
void __iomem * base ;
struct i2c_adapter adap ;
struct clk * clk ;
int bus_mode ;
struct completion msg_tia_done ;
u32 iicb0wl ;
u32 iicb0wh ;
} ;
enum bcr_index {
RZV2M_I2C_100K = 0 ,
RZV2M_I2C_400K ,
} ;
struct bitrate_config {
unsigned int percent_low ;
unsigned int min_hold_time_ns ;
} ;
static const struct bitrate_config bitrate_configs [ ] = {
[ RZV2M_I2C_100K ] = { 47 , 3450 } ,
[ RZV2M_I2C_400K ] = { 52 , 900 } ,
} ;
2023-05-26 16:57:37 +03:00
static inline void bit_setl ( void __iomem * addr , u32 val )
{
writel ( readl ( addr ) | val , addr ) ;
}
static inline void bit_clrl ( void __iomem * addr , u32 val )
{
writel ( readl ( addr ) & ~ val , addr ) ;
}
2022-07-08 13:03:50 +03:00
static irqreturn_t rzv2m_i2c_tia_irq_handler ( int this_irq , void * dev_id )
{
struct rzv2m_i2c_priv * priv = dev_id ;
complete ( & priv - > msg_tia_done ) ;
return IRQ_HANDLED ;
}
/* Calculate IICB0WL and IICB0WH */
static int rzv2m_i2c_clock_calculate ( struct device * dev ,
struct rzv2m_i2c_priv * priv )
{
const struct bitrate_config * config ;
unsigned int hold_time_ns ;
unsigned int total_pclks ;
unsigned int trf_pclks ;
unsigned long pclk_hz ;
struct i2c_timings t ;
u32 trf_ns ;
i2c_parse_fw_timings ( dev , & t , true ) ;
pclk_hz = clk_get_rate ( priv - > clk ) ;
total_pclks = pclk_hz / t . bus_freq_hz ;
trf_ns = t . scl_rise_ns + t . scl_fall_ns ;
trf_pclks = mul_u64_u32_div ( pclk_hz , trf_ns , NSEC_PER_SEC ) ;
/* Config setting */
switch ( t . bus_freq_hz ) {
case I2C_MAX_FAST_MODE_FREQ :
priv - > bus_mode = RZV2M_I2C_400K ;
break ;
case I2C_MAX_STANDARD_MODE_FREQ :
priv - > bus_mode = RZV2M_I2C_100K ;
break ;
default :
dev_err ( dev , " transfer speed is invalid \n " ) ;
return - EINVAL ;
}
config = & bitrate_configs [ priv - > bus_mode ] ;
/* IICB0WL = (percent_low / Transfer clock) x PCLK */
priv - > iicb0wl = total_pclks * config - > percent_low / 100 ;
if ( priv - > iicb0wl > ( BIT ( 10 ) - 1 ) )
return - EINVAL ;
/* IICB0WH = ((percent_high / Transfer clock) x PCLK) - (tR + tF) */
priv - > iicb0wh = total_pclks - priv - > iicb0wl - trf_pclks ;
if ( priv - > iicb0wh > ( BIT ( 10 ) - 1 ) )
return - EINVAL ;
/*
* Data hold time must be less than 0.9 us in fast mode and
* 3.45 us in standard mode .
* Data hold time = IICB0WL [ 9 : 2 ] / PCLK
*/
hold_time_ns = div64_ul ( ( u64 ) ( priv - > iicb0wl > > 2 ) * NSEC_PER_SEC , pclk_hz ) ;
if ( hold_time_ns > config - > min_hold_time_ns ) {
dev_err ( dev , " data hold time %dns is over %dns \n " ,
hold_time_ns , config - > min_hold_time_ns ) ;
return - EINVAL ;
}
return 0 ;
}
static void rzv2m_i2c_init ( struct rzv2m_i2c_priv * priv )
{
u32 i2c_ctl0 ;
u32 i2c_ctl1 ;
/* i2c disable */
writel ( 0 , priv - > base + IICB0CTL0 ) ;
/* IICB0CTL1 setting */
i2c_ctl1 = IICB0SLSE ;
if ( priv - > bus_mode = = RZV2M_I2C_400K )
i2c_ctl1 | = IICB0MDSC ;
writel ( i2c_ctl1 , priv - > base + IICB0CTL1 ) ;
/* IICB0WL IICB0WH setting */
writel ( priv - > iicb0wl , priv - > base + IICB0WL ) ;
writel ( priv - > iicb0wh , priv - > base + IICB0WH ) ;
/* i2c enable after setting */
i2c_ctl0 = IICB0SLWT | IICB0SLAC | IICB0IICE ;
writel ( i2c_ctl0 , priv - > base + IICB0CTL0 ) ;
}
static int rzv2m_i2c_write_with_ack ( struct rzv2m_i2c_priv * priv , u32 data )
{
unsigned long time_left ;
reinit_completion ( & priv - > msg_tia_done ) ;
writel ( data , priv - > base + IICB0DAT ) ;
time_left = wait_for_completion_timeout ( & priv - > msg_tia_done ,
priv - > adap . timeout ) ;
if ( ! time_left )
return - ETIMEDOUT ;
/* Confirm ACK */
if ( ( readl ( priv - > base + IICB0STR0 ) & IICB0SSAC ) ! = IICB0SSAC )
return - ENXIO ;
return 0 ;
}
static int rzv2m_i2c_read_with_ack ( struct rzv2m_i2c_priv * priv , u8 * data ,
bool last )
{
unsigned long time_left ;
u32 data_tmp ;
reinit_completion ( & priv - > msg_tia_done ) ;
/* Interrupt request timing : 8th clock */
bit_clrl ( priv - > base + IICB0CTL0 , IICB0SLWT ) ;
/* Exit the wait state */
writel ( IICB0WRET , priv - > base + IICB0TRG ) ;
/* Wait for transaction */
time_left = wait_for_completion_timeout ( & priv - > msg_tia_done ,
priv - > adap . timeout ) ;
if ( ! time_left )
return - ETIMEDOUT ;
if ( last ) {
/* Disable ACK */
bit_clrl ( priv - > base + IICB0CTL0 , IICB0SLAC ) ;
/* Read data*/
data_tmp = readl ( priv - > base + IICB0DAT ) ;
/* Interrupt request timing : 9th clock */
bit_setl ( priv - > base + IICB0CTL0 , IICB0SLWT ) ;
/* Exit the wait state */
writel ( IICB0WRET , priv - > base + IICB0TRG ) ;
/* Wait for transaction */
time_left = wait_for_completion_timeout ( & priv - > msg_tia_done ,
priv - > adap . timeout ) ;
if ( ! time_left )
return - ETIMEDOUT ;
/* Enable ACK */
bit_setl ( priv - > base + IICB0CTL0 , IICB0SLAC ) ;
} else {
/* Read data */
data_tmp = readl ( priv - > base + IICB0DAT ) ;
}
* data = data_tmp ;
return 0 ;
}
static int rzv2m_i2c_send ( struct rzv2m_i2c_priv * priv , struct i2c_msg * msg ,
unsigned int * count )
{
unsigned int i ;
int ret ;
for ( i = 0 ; i < msg - > len ; i + + ) {
ret = rzv2m_i2c_write_with_ack ( priv , msg - > buf [ i ] ) ;
if ( ret < 0 )
return ret ;
}
* count = i ;
return 0 ;
}
static int rzv2m_i2c_receive ( struct rzv2m_i2c_priv * priv , struct i2c_msg * msg ,
unsigned int * count )
{
unsigned int i ;
int ret ;
for ( i = 0 ; i < msg - > len ; i + + ) {
ret = rzv2m_i2c_read_with_ack ( priv , & msg - > buf [ i ] ,
( msg - > len - 1 ) = = i ) ;
if ( ret < 0 )
return ret ;
}
* count = i ;
return 0 ;
}
static int rzv2m_i2c_send_address ( struct rzv2m_i2c_priv * priv ,
struct i2c_msg * msg )
{
u32 addr ;
int ret ;
if ( msg - > flags & I2C_M_TEN ) {
/*
* 10 - bit address
* addr_1 : 5 ' b11110 | addr [ 9 : 8 ] | ( R / nW )
* addr_2 : addr [ 7 : 0 ]
*/
addr = 0xf0 | ( ( msg - > addr & GENMASK ( 9 , 8 ) ) > > 7 ) ;
addr | = ! ! ( msg - > flags & I2C_M_RD ) ;
/* Send 1st address(extend code) */
ret = rzv2m_i2c_write_with_ack ( priv , addr ) ;
if ( ret )
return ret ;
/* Send 2nd address */
ret = rzv2m_i2c_write_with_ack ( priv , msg - > addr & 0xff ) ;
} else {
/* 7-bit address */
addr = i2c_8bit_addr_from_msg ( msg ) ;
ret = rzv2m_i2c_write_with_ack ( priv , addr ) ;
}
return ret ;
}
static int rzv2m_i2c_stop_condition ( struct rzv2m_i2c_priv * priv )
{
u32 value ;
/* Send stop condition */
writel ( IICB0SPT , priv - > base + IICB0TRG ) ;
return readl_poll_timeout ( priv - > base + IICB0STR0 ,
value , value & IICB0SSSP ,
100 , jiffies_to_usecs ( priv - > adap . timeout ) ) ;
}
static int rzv2m_i2c_master_xfer_msg ( struct rzv2m_i2c_priv * priv ,
struct i2c_msg * msg , int stop )
{
unsigned int count = 0 ;
int ret , read = ! ! ( msg - > flags & I2C_M_RD ) ;
/* Send start condition */
writel ( IICB0STT , priv - > base + IICB0TRG ) ;
ret = rzv2m_i2c_send_address ( priv , msg ) ;
if ( ! ret ) {
if ( read )
ret = rzv2m_i2c_receive ( priv , msg , & count ) ;
else
ret = rzv2m_i2c_send ( priv , msg , & count ) ;
if ( ! ret & & stop )
ret = rzv2m_i2c_stop_condition ( priv ) ;
}
if ( ret = = - ENXIO )
rzv2m_i2c_stop_condition ( priv ) ;
else if ( ret < 0 )
rzv2m_i2c_init ( priv ) ;
else
ret = count ;
return ret ;
}
static int rzv2m_i2c_master_xfer ( struct i2c_adapter * adap ,
struct i2c_msg * msgs , int num )
{
struct rzv2m_i2c_priv * priv = i2c_get_adapdata ( adap ) ;
struct device * dev = priv - > adap . dev . parent ;
unsigned int i ;
int ret ;
ret = pm_runtime_resume_and_get ( dev ) ;
if ( ret < 0 )
return ret ;
if ( readl ( priv - > base + IICB0STR0 ) & IICB0SSBS ) {
ret = - EAGAIN ;
goto out ;
}
/* I2C main transfer */
for ( i = 0 ; i < num ; i + + ) {
ret = rzv2m_i2c_master_xfer_msg ( priv , & msgs [ i ] , i = = ( num - 1 ) ) ;
if ( ret < 0 )
goto out ;
}
ret = num ;
out :
pm_runtime_mark_last_busy ( dev ) ;
pm_runtime_put_autosuspend ( dev ) ;
return ret ;
}
static u32 rzv2m_i2c_func ( struct i2c_adapter * adap )
{
return I2C_FUNC_I2C | ( I2C_FUNC_SMBUS_EMUL & ~ I2C_FUNC_SMBUS_QUICK ) |
I2C_FUNC_10BIT_ADDR ;
}
2023-05-26 16:57:38 +03:00
static int rzv2m_i2c_disable ( struct device * dev , struct rzv2m_i2c_priv * priv )
{
int ret ;
ret = pm_runtime_resume_and_get ( dev ) ;
if ( ret < 0 )
return ret ;
bit_clrl ( priv - > base + IICB0CTL0 , IICB0IICE ) ;
pm_runtime_put ( dev ) ;
return 0 ;
}
2022-07-08 13:03:50 +03:00
static const struct i2c_adapter_quirks rzv2m_i2c_quirks = {
. flags = I2C_AQ_NO_ZERO_LEN ,
} ;
static struct i2c_algorithm rzv2m_i2c_algo = {
. master_xfer = rzv2m_i2c_master_xfer ,
. functionality = rzv2m_i2c_func ,
} ;
static int rzv2m_i2c_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct rzv2m_i2c_priv * priv ;
struct reset_control * rstc ;
struct i2c_adapter * adap ;
struct resource * res ;
int irq , ret ;
priv = devm_kzalloc ( dev , sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
priv - > base = devm_platform_get_and_ioremap_resource ( pdev , 0 , & res ) ;
if ( IS_ERR ( priv - > base ) )
return PTR_ERR ( priv - > base ) ;
priv - > clk = devm_clk_get ( dev , NULL ) ;
if ( IS_ERR ( priv - > clk ) )
return dev_err_probe ( dev , PTR_ERR ( priv - > clk ) , " Can't get clock \n " ) ;
rstc = devm_reset_control_get_shared ( dev , NULL ) ;
if ( IS_ERR ( rstc ) )
return dev_err_probe ( dev , PTR_ERR ( rstc ) , " Missing reset ctrl \n " ) ;
/*
* The reset also affects other HW that is not under the control
* of Linux . Therefore , all we can do is deassert the reset .
*/
reset_control_deassert ( rstc ) ;
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 )
return irq ;
ret = devm_request_irq ( dev , irq , rzv2m_i2c_tia_irq_handler , 0 ,
dev_name ( dev ) , priv ) ;
if ( ret < 0 )
return dev_err_probe ( dev , ret , " Unable to request irq %d \n " , irq ) ;
adap = & priv - > adap ;
adap - > nr = pdev - > id ;
adap - > algo = & rzv2m_i2c_algo ;
adap - > quirks = & rzv2m_i2c_quirks ;
adap - > dev . parent = dev ;
adap - > owner = THIS_MODULE ;
device_set_node ( & adap - > dev , dev_fwnode ( dev ) ) ;
i2c_set_adapdata ( adap , priv ) ;
strscpy ( adap - > name , pdev - > name , sizeof ( adap - > name ) ) ;
init_completion ( & priv - > msg_tia_done ) ;
ret = rzv2m_i2c_clock_calculate ( dev , priv ) ;
if ( ret < 0 )
return ret ;
pm_runtime_enable ( dev ) ;
pm_runtime_get_sync ( dev ) ;
rzv2m_i2c_init ( priv ) ;
pm_runtime_put ( dev ) ;
platform_set_drvdata ( pdev , priv ) ;
ret = i2c_add_numbered_adapter ( adap ) ;
2023-05-26 16:57:38 +03:00
if ( ret < 0 ) {
rzv2m_i2c_disable ( dev , priv ) ;
2022-07-08 13:03:50 +03:00
pm_runtime_disable ( dev ) ;
2023-05-26 16:57:38 +03:00
}
2022-07-08 13:03:50 +03:00
return ret ;
}
2023-05-08 23:51:38 +03:00
static void rzv2m_i2c_remove ( struct platform_device * pdev )
2022-07-08 13:03:50 +03:00
{
struct rzv2m_i2c_priv * priv = platform_get_drvdata ( pdev ) ;
struct device * dev = priv - > adap . dev . parent ;
i2c_del_adapter ( & priv - > adap ) ;
2023-05-26 16:57:38 +03:00
rzv2m_i2c_disable ( dev , priv ) ;
2022-07-08 13:03:50 +03:00
pm_runtime_disable ( dev ) ;
}
static int rzv2m_i2c_suspend ( struct device * dev )
{
struct rzv2m_i2c_priv * priv = dev_get_drvdata ( dev ) ;
2023-05-26 16:57:38 +03:00
return rzv2m_i2c_disable ( dev , priv ) ;
2022-07-08 13:03:50 +03:00
}
static int rzv2m_i2c_resume ( struct device * dev )
{
struct rzv2m_i2c_priv * priv = dev_get_drvdata ( dev ) ;
int ret ;
ret = rzv2m_i2c_clock_calculate ( dev , priv ) ;
if ( ret < 0 )
return ret ;
ret = pm_runtime_resume_and_get ( dev ) ;
if ( ret < 0 )
return ret ;
rzv2m_i2c_init ( priv ) ;
pm_runtime_put ( dev ) ;
return 0 ;
}
static const struct of_device_id rzv2m_i2c_ids [ ] = {
{ . compatible = " renesas,rzv2m-i2c " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , rzv2m_i2c_ids ) ;
static const struct dev_pm_ops rzv2m_i2c_pm_ops = {
SYSTEM_SLEEP_PM_OPS ( rzv2m_i2c_suspend , rzv2m_i2c_resume )
} ;
static struct platform_driver rzv2m_i2c_driver = {
. driver = {
. name = " rzv2m-i2c " ,
. of_match_table = rzv2m_i2c_ids ,
. pm = pm_sleep_ptr ( & rzv2m_i2c_pm_ops ) ,
} ,
. probe = rzv2m_i2c_probe ,
2023-05-08 23:51:38 +03:00
. remove_new = rzv2m_i2c_remove ,
2022-07-08 13:03:50 +03:00
} ;
module_platform_driver ( rzv2m_i2c_driver ) ;
MODULE_DESCRIPTION ( " RZ/V2M I2C bus driver " ) ;
MODULE_AUTHOR ( " Renesas Electronics Corporation " ) ;
MODULE_LICENSE ( " GPL " ) ;