2022-06-07 17:11:13 +03:00
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2014 Broadcom Corporation
2015-06-09 22:36:20 +03:00
# include <linux/clk.h>
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/i2c.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/sched.h>
# include <linux/slab.h>
# define N_DATA_REGS 8
2015-12-16 23:49:09 +03:00
/*
* PER_I2C / BSC count register mask depends on 1 byte / 4 byte data register
* size . Cable modem and DSL SoCs with Peripheral i2c cores use 1 byte per
* data register whereas STB SoCs use 4 byte per data register transfer ,
* account for this difference in total count per transaction and mask to
* use .
*/
# define BSC_CNT_REG1_MASK(nb) (nb == 1 ? GENMASK(3, 0) : GENMASK(5, 0))
# define BSC_CNT_REG1_SHIFT 0
2015-06-09 22:36:20 +03:00
/* BSC CTL register field definitions */
# define BSC_CTL_REG_DTF_MASK 0x00000003
# define BSC_CTL_REG_SCL_SEL_MASK 0x00000030
# define BSC_CTL_REG_SCL_SEL_SHIFT 4
# define BSC_CTL_REG_INT_EN_MASK 0x00000040
# define BSC_CTL_REG_INT_EN_SHIFT 6
# define BSC_CTL_REG_DIV_CLK_MASK 0x00000080
2015-12-16 23:49:09 +03:00
/* BSC_IIC_ENABLE r/w enable and interrupt field definitions */
2015-06-09 22:36:20 +03:00
# define BSC_IIC_EN_RESTART_MASK 0x00000040
# define BSC_IIC_EN_NOSTART_MASK 0x00000020
# define BSC_IIC_EN_NOSTOP_MASK 0x00000010
# define BSC_IIC_EN_NOACK_MASK 0x00000004
# define BSC_IIC_EN_INTRP_MASK 0x00000002
# define BSC_IIC_EN_ENABLE_MASK 0x00000001
/* BSC_CTLHI control register field definitions */
# define BSC_CTLHI_REG_INPUT_SWITCHING_LEVEL_MASK 0x00000080
# define BSC_CTLHI_REG_DATAREG_SIZE_MASK 0x00000040
# define BSC_CTLHI_REG_IGNORE_ACK_MASK 0x00000002
# define BSC_CTLHI_REG_WAIT_DIS_MASK 0x00000001
# define I2C_TIMEOUT 100 /* msecs */
/* Condition mask used for non combined transfer */
# define COND_RESTART BSC_IIC_EN_RESTART_MASK
# define COND_NOSTART BSC_IIC_EN_NOSTART_MASK
# define COND_NOSTOP BSC_IIC_EN_NOSTOP_MASK
# define COND_START_STOP (COND_RESTART | COND_NOSTART | COND_NOSTOP)
/* BSC data transfer direction */
# define DTF_WR_MASK 0x00000000
# define DTF_RD_MASK 0x00000001
/* BSC data transfer direction combined format */
# define DTF_RD_WR_MASK 0x00000002
# define DTF_WR_RD_MASK 0x00000003
# define INT_ENABLE true
# define INT_DISABLE false
/* BSC block register map structure to cache fields to be written */
struct bsc_regs {
u32 chip_address ; /* slave address */
u32 data_in [ N_DATA_REGS ] ; /* tx data buffer*/
u32 cnt_reg ; /* rx/tx data length */
u32 ctl_reg ; /* control register */
u32 iic_enable ; /* xfer enable and status */
u32 data_out [ N_DATA_REGS ] ; /* rx data buffer */
u32 ctlhi_reg ; /* more control fields */
u32 scl_param ; /* reserved */
} ;
struct bsc_clk_param {
u32 hz ;
u32 scl_mask ;
u32 div_mask ;
} ;
enum bsc_xfer_cmd {
CMD_WR ,
CMD_RD ,
CMD_WR_NOACK ,
CMD_RD_NOACK ,
} ;
static char const * cmd_string [ ] = {
[ CMD_WR ] = " WR " ,
[ CMD_RD ] = " RD " ,
[ CMD_WR_NOACK ] = " WR NOACK " ,
[ CMD_RD_NOACK ] = " RD NOACK " ,
} ;
enum bus_speeds {
SPD_375K ,
SPD_390K ,
SPD_187K ,
SPD_200K ,
SPD_93K ,
SPD_97K ,
SPD_46K ,
SPD_50K
} ;
static const struct bsc_clk_param bsc_clk [ ] = {
[ SPD_375K ] = {
. hz = 375000 ,
. scl_mask = SPD_375K < < BSC_CTL_REG_SCL_SEL_SHIFT ,
. div_mask = 0
} ,
[ SPD_390K ] = {
. hz = 390000 ,
. scl_mask = SPD_390K < < BSC_CTL_REG_SCL_SEL_SHIFT ,
. div_mask = 0
} ,
[ SPD_187K ] = {
. hz = 187500 ,
. scl_mask = SPD_187K < < BSC_CTL_REG_SCL_SEL_SHIFT ,
. div_mask = 0
} ,
[ SPD_200K ] = {
. hz = 200000 ,
. scl_mask = SPD_200K < < BSC_CTL_REG_SCL_SEL_SHIFT ,
. div_mask = 0
} ,
[ SPD_93K ] = {
. hz = 93750 ,
. scl_mask = SPD_375K < < BSC_CTL_REG_SCL_SEL_SHIFT ,
. div_mask = BSC_CTL_REG_DIV_CLK_MASK
} ,
[ SPD_97K ] = {
. hz = 97500 ,
. scl_mask = SPD_390K < < BSC_CTL_REG_SCL_SEL_SHIFT ,
. div_mask = BSC_CTL_REG_DIV_CLK_MASK
} ,
[ SPD_46K ] = {
. hz = 46875 ,
. scl_mask = SPD_187K < < BSC_CTL_REG_SCL_SEL_SHIFT ,
. div_mask = BSC_CTL_REG_DIV_CLK_MASK
} ,
[ SPD_50K ] = {
. hz = 50000 ,
. scl_mask = SPD_200K < < BSC_CTL_REG_SCL_SEL_SHIFT ,
. div_mask = BSC_CTL_REG_DIV_CLK_MASK
}
} ;
struct brcmstb_i2c_dev {
struct device * device ;
void __iomem * base ;
int irq ;
struct bsc_regs * bsc_regmap ;
struct i2c_adapter adapter ;
struct completion done ;
u32 clk_freq_hz ;
2015-12-16 23:49:09 +03:00
int data_regsz ;
2023-10-06 17:41:17 +03:00
bool atomic ;
2015-06-09 22:36:20 +03:00
} ;
/* register accessors for both be and le cpu arch */
# ifdef CONFIG_CPU_BIG_ENDIAN
# define __bsc_readl(_reg) ioread32be(_reg)
# define __bsc_writel(_val, _reg) iowrite32be(_val, _reg)
# else
# define __bsc_readl(_reg) ioread32(_reg)
# define __bsc_writel(_val, _reg) iowrite32(_val, _reg)
# endif
# define bsc_readl(_dev, _reg) \
__bsc_readl ( _dev - > base + offsetof ( struct bsc_regs , _reg ) )
# define bsc_writel(_dev, _val, _reg) \
__bsc_writel ( _val , _dev - > base + offsetof ( struct bsc_regs , _reg ) )
2015-12-16 23:49:09 +03:00
static inline int brcmstb_i2c_get_xfersz ( struct brcmstb_i2c_dev * dev )
{
return ( N_DATA_REGS * dev - > data_regsz ) ;
}
static inline int brcmstb_i2c_get_data_regsz ( struct brcmstb_i2c_dev * dev )
{
return dev - > data_regsz ;
}
2015-06-09 22:36:20 +03:00
static void brcmstb_i2c_enable_disable_irq ( struct brcmstb_i2c_dev * dev ,
bool int_en )
{
if ( int_en )
/* Enable BSC CTL interrupt line */
dev - > bsc_regmap - > ctl_reg | = BSC_CTL_REG_INT_EN_MASK ;
else
/* Disable BSC CTL interrupt line */
dev - > bsc_regmap - > ctl_reg & = ~ BSC_CTL_REG_INT_EN_MASK ;
barrier ( ) ;
bsc_writel ( dev , dev - > bsc_regmap - > ctl_reg , ctl_reg ) ;
}
static irqreturn_t brcmstb_i2c_isr ( int irq , void * devid )
{
struct brcmstb_i2c_dev * dev = devid ;
u32 status_bsc_ctl = bsc_readl ( dev , ctl_reg ) ;
u32 status_iic_intrp = bsc_readl ( dev , iic_enable ) ;
dev_dbg ( dev - > device , " isr CTL_REG %x IIC_EN %x \n " ,
status_bsc_ctl , status_iic_intrp ) ;
if ( ! ( status_bsc_ctl & BSC_CTL_REG_INT_EN_MASK ) )
return IRQ_NONE ;
brcmstb_i2c_enable_disable_irq ( dev , INT_DISABLE ) ;
2016-08-03 15:03:10 +03:00
complete ( & dev - > done ) ;
2015-06-09 22:36:20 +03:00
dev_dbg ( dev - > device , " isr handled " ) ;
return IRQ_HANDLED ;
}
/* Wait for device to be ready */
static int brcmstb_i2c_wait_if_busy ( struct brcmstb_i2c_dev * dev )
{
unsigned long timeout = jiffies + msecs_to_jiffies ( I2C_TIMEOUT ) ;
while ( ( bsc_readl ( dev , iic_enable ) & BSC_IIC_EN_INTRP_MASK ) ) {
if ( time_after ( jiffies , timeout ) )
return - ETIMEDOUT ;
cpu_relax ( ) ;
}
return 0 ;
}
/* i2c xfer completion function, handles both irq and polling mode */
static int brcmstb_i2c_wait_for_completion ( struct brcmstb_i2c_dev * dev )
{
int ret = 0 ;
unsigned long timeout = msecs_to_jiffies ( I2C_TIMEOUT ) ;
2023-10-06 17:41:17 +03:00
if ( dev - > irq > = 0 & & ! dev - > atomic ) {
2015-06-09 22:36:20 +03:00
if ( ! wait_for_completion_timeout ( & dev - > done , timeout ) )
ret = - ETIMEDOUT ;
} else {
/* we are in polling mode */
u32 bsc_intrp ;
unsigned long time_left = jiffies + timeout ;
do {
bsc_intrp = bsc_readl ( dev , iic_enable ) &
BSC_IIC_EN_INTRP_MASK ;
if ( time_after ( jiffies , time_left ) ) {
ret = - ETIMEDOUT ;
break ;
}
cpu_relax ( ) ;
} while ( ! bsc_intrp ) ;
}
if ( dev - > irq < 0 | | ret = = - ETIMEDOUT )
brcmstb_i2c_enable_disable_irq ( dev , INT_DISABLE ) ;
return ret ;
}
/* Set xfer START/STOP conditions for subsequent transfer */
static void brcmstb_set_i2c_start_stop ( struct brcmstb_i2c_dev * dev ,
u32 cond_flag )
{
u32 regval = dev - > bsc_regmap - > iic_enable ;
dev - > bsc_regmap - > iic_enable = ( regval & ~ COND_START_STOP ) | cond_flag ;
}
/* Send I2C request check completion */
static int brcmstb_send_i2c_cmd ( struct brcmstb_i2c_dev * dev ,
enum bsc_xfer_cmd cmd )
{
int rc = 0 ;
struct bsc_regs * pi2creg = dev - > bsc_regmap ;
/* Make sure the hardware is ready */
rc = brcmstb_i2c_wait_if_busy ( dev ) ;
if ( rc < 0 )
return rc ;
/* only if we are in interrupt mode */
2023-10-06 17:41:17 +03:00
if ( dev - > irq > = 0 & & ! dev - > atomic )
2015-06-09 22:36:20 +03:00
reinit_completion ( & dev - > done ) ;
/* enable BSC CTL interrupt line */
brcmstb_i2c_enable_disable_irq ( dev , INT_ENABLE ) ;
/* initiate transfer by setting iic_enable */
pi2creg - > iic_enable | = BSC_IIC_EN_ENABLE_MASK ;
bsc_writel ( dev , pi2creg - > iic_enable , iic_enable ) ;
/* Wait for transaction to finish or timeout */
rc = brcmstb_i2c_wait_for_completion ( dev ) ;
if ( rc ) {
dev_dbg ( dev - > device , " intr timeout for cmd %s \n " ,
cmd_string [ cmd ] ) ;
goto cmd_out ;
}
2021-02-25 19:11:01 +03:00
if ( ( cmd = = CMD_RD | | cmd = = CMD_WR ) & &
2015-06-09 22:36:20 +03:00
bsc_readl ( dev , iic_enable ) & BSC_IIC_EN_NOACK_MASK ) {
rc = - EREMOTEIO ;
dev_dbg ( dev - > device , " controller received NOACK intr for %s \n " ,
cmd_string [ cmd ] ) ;
}
cmd_out :
bsc_writel ( dev , 0 , cnt_reg ) ;
bsc_writel ( dev , 0 , iic_enable ) ;
return rc ;
}
/* Actual data transfer through the BSC master */
static int brcmstb_i2c_xfer_bsc_data ( struct brcmstb_i2c_dev * dev ,
u8 * buf , unsigned int len ,
struct i2c_msg * pmsg )
{
2015-12-16 23:49:09 +03:00
int cnt , byte , i , rc ;
2015-06-09 22:36:20 +03:00
enum bsc_xfer_cmd cmd ;
u32 ctl_reg ;
struct bsc_regs * pi2creg = dev - > bsc_regmap ;
int no_ack = pmsg - > flags & I2C_M_IGNORE_NAK ;
2015-12-16 23:49:09 +03:00
int data_regsz = brcmstb_i2c_get_data_regsz ( dev ) ;
2015-06-09 22:36:20 +03:00
/* see if the transaction needs to check NACK conditions */
2016-07-15 06:45:09 +03:00
if ( no_ack ) {
2015-06-09 22:36:20 +03:00
cmd = ( pmsg - > flags & I2C_M_RD ) ? CMD_RD_NOACK
: CMD_WR_NOACK ;
pi2creg - > ctlhi_reg | = BSC_CTLHI_REG_IGNORE_ACK_MASK ;
} else {
cmd = ( pmsg - > flags & I2C_M_RD ) ? CMD_RD : CMD_WR ;
pi2creg - > ctlhi_reg & = ~ BSC_CTLHI_REG_IGNORE_ACK_MASK ;
}
bsc_writel ( dev , pi2creg - > ctlhi_reg , ctlhi_reg ) ;
/* set data transfer direction */
ctl_reg = pi2creg - > ctl_reg & ~ BSC_CTL_REG_DTF_MASK ;
if ( cmd = = CMD_WR | | cmd = = CMD_WR_NOACK )
pi2creg - > ctl_reg = ctl_reg | DTF_WR_MASK ;
else
pi2creg - > ctl_reg = ctl_reg | DTF_RD_MASK ;
/* set the read/write length */
2015-12-16 23:49:09 +03:00
bsc_writel ( dev , BSC_CNT_REG1_MASK ( data_regsz ) &
( len < < BSC_CNT_REG1_SHIFT ) , cnt_reg ) ;
2015-06-09 22:36:20 +03:00
/* Write data into data_in register */
2015-12-16 23:49:09 +03:00
2015-06-09 22:36:20 +03:00
if ( cmd = = CMD_WR | | cmd = = CMD_WR_NOACK ) {
2015-12-16 23:49:09 +03:00
for ( cnt = 0 , i = 0 ; cnt < len ; cnt + = data_regsz , i + + ) {
2015-06-09 22:36:20 +03:00
u32 word = 0 ;
2015-12-16 23:49:09 +03:00
for ( byte = 0 ; byte < data_regsz ; byte + + ) {
word > > = BITS_PER_BYTE ;
2015-06-09 22:36:20 +03:00
if ( ( cnt + byte ) < len )
2015-12-16 23:49:09 +03:00
word | = buf [ cnt + byte ] < <
( BITS_PER_BYTE * ( data_regsz - 1 ) ) ;
2015-06-09 22:36:20 +03:00
}
2015-12-16 23:49:09 +03:00
bsc_writel ( dev , word , data_in [ i ] ) ;
2015-06-09 22:36:20 +03:00
}
}
/* Initiate xfer, the function will return on completion */
rc = brcmstb_send_i2c_cmd ( dev , cmd ) ;
if ( rc ! = 0 ) {
dev_dbg ( dev - > device , " %s failure " , cmd_string [ cmd ] ) ;
return rc ;
}
2015-12-16 23:49:09 +03:00
/* Read data from data_out register */
2015-06-09 22:36:20 +03:00
if ( cmd = = CMD_RD | | cmd = = CMD_RD_NOACK ) {
2015-12-16 23:49:09 +03:00
for ( cnt = 0 , i = 0 ; cnt < len ; cnt + = data_regsz , i + + ) {
u32 data = bsc_readl ( dev , data_out [ i ] ) ;
2015-06-09 22:36:20 +03:00
2015-12-16 23:49:09 +03:00
for ( byte = 0 ; byte < data_regsz & &
2015-06-09 22:36:20 +03:00
( byte + cnt ) < len ; byte + + ) {
buf [ cnt + byte ] = data & 0xff ;
2015-12-16 23:49:09 +03:00
data > > = BITS_PER_BYTE ;
2015-06-09 22:36:20 +03:00
}
}
}
return 0 ;
}
/* Write a single byte of data to the i2c bus */
static int brcmstb_i2c_write_data_byte ( struct brcmstb_i2c_dev * dev ,
u8 * buf , unsigned int nak_expected )
{
enum bsc_xfer_cmd cmd = nak_expected ? CMD_WR : CMD_WR_NOACK ;
bsc_writel ( dev , 1 , cnt_reg ) ;
bsc_writel ( dev , * buf , data_in ) ;
return brcmstb_send_i2c_cmd ( dev , cmd ) ;
}
/* Send i2c address */
static int brcmstb_i2c_do_addr ( struct brcmstb_i2c_dev * dev ,
struct i2c_msg * msg )
{
unsigned char addr ;
if ( msg - > flags & I2C_M_TEN ) {
/* First byte is 11110XX0 where XX is upper 2 bits */
addr = 0xF0 | ( ( msg - > addr & 0x300 ) > > 7 ) ;
bsc_writel ( dev , addr , chip_address ) ;
/* Second byte is the remaining 8 bits */
addr = msg - > addr & 0xFF ;
if ( brcmstb_i2c_write_data_byte ( dev , & addr , 0 ) < 0 )
return - EREMOTEIO ;
if ( msg - > flags & I2C_M_RD ) {
/* For read, send restart without stop condition */
brcmstb_set_i2c_start_stop ( dev , COND_RESTART
| COND_NOSTOP ) ;
/* Then re-send the first byte with the read bit set */
addr = 0xF0 | ( ( msg - > addr & 0x300 ) > > 7 ) | 0x01 ;
if ( brcmstb_i2c_write_data_byte ( dev , & addr , 0 ) < 0 )
return - EREMOTEIO ;
}
} else {
2016-04-03 21:44:49 +03:00
addr = i2c_8bit_addr_from_msg ( msg ) ;
2015-06-09 22:36:20 +03:00
bsc_writel ( dev , addr , chip_address ) ;
}
return 0 ;
}
/* Master transfer function */
static int brcmstb_i2c_xfer ( struct i2c_adapter * adapter ,
struct i2c_msg msgs [ ] , int num )
{
struct brcmstb_i2c_dev * dev = i2c_get_adapdata ( adapter ) ;
struct i2c_msg * pmsg ;
int rc = 0 ;
int i ;
int bytes_to_xfer ;
u8 * tmp_buf ;
int len = 0 ;
2015-12-16 23:49:09 +03:00
int xfersz = brcmstb_i2c_get_xfersz ( dev ) ;
2017-03-03 04:55:03 +03:00
u32 cond , cond_per_msg ;
2015-06-09 22:36:20 +03:00
/* Loop through all messages */
for ( i = 0 ; i < num ; i + + ) {
pmsg = & msgs [ i ] ;
len = pmsg - > len ;
tmp_buf = pmsg - > buf ;
dev_dbg ( dev - > device ,
" msg# %d/%d flg %x buf %x len %d \n " , i ,
num - 1 , pmsg - > flags ,
pmsg - > buf ? pmsg - > buf [ 0 ] : ' 0 ' , pmsg - > len ) ;
if ( i < ( num - 1 ) & & ( msgs [ i + 1 ] . flags & I2C_M_NOSTART ) )
2017-03-03 04:55:03 +03:00
cond = ~ COND_START_STOP ;
2015-06-09 22:36:20 +03:00
else
2017-03-03 04:55:03 +03:00
cond = COND_RESTART | COND_NOSTOP ;
brcmstb_set_i2c_start_stop ( dev , cond ) ;
2015-06-09 22:36:20 +03:00
/* Send slave address */
if ( ! ( pmsg - > flags & I2C_M_NOSTART ) ) {
rc = brcmstb_i2c_do_addr ( dev , pmsg ) ;
if ( rc < 0 ) {
dev_dbg ( dev - > device ,
" NACK for addr %2.2x msg#%d rc = %d \n " ,
pmsg - > addr , i , rc ) ;
goto out ;
}
}
2017-03-03 04:55:03 +03:00
cond_per_msg = cond ;
2015-06-09 22:36:20 +03:00
/* Perform data transfer */
while ( len ) {
2015-12-16 23:49:09 +03:00
bytes_to_xfer = min ( len , xfersz ) ;
2015-06-09 22:36:20 +03:00
2017-03-03 04:55:03 +03:00
if ( len < = xfersz ) {
if ( i = = ( num - 1 ) )
cond_per_msg = cond_per_msg &
~ ( COND_RESTART | COND_NOSTOP ) ;
else
cond_per_msg = cond ;
} else {
cond_per_msg = ( cond_per_msg & ~ COND_RESTART ) |
COND_NOSTOP ;
}
brcmstb_set_i2c_start_stop ( dev , cond_per_msg ) ;
2015-06-09 22:36:20 +03:00
rc = brcmstb_i2c_xfer_bsc_data ( dev , tmp_buf ,
bytes_to_xfer , pmsg ) ;
if ( rc < 0 )
goto out ;
len - = bytes_to_xfer ;
tmp_buf + = bytes_to_xfer ;
2017-03-03 04:55:03 +03:00
cond_per_msg = COND_NOSTART | COND_NOSTOP ;
2015-06-09 22:36:20 +03:00
}
}
rc = num ;
out :
return rc ;
}
2023-10-06 17:41:17 +03:00
static int brcmstb_i2c_xfer_atomic ( struct i2c_adapter * adapter ,
struct i2c_msg msgs [ ] , int num )
{
struct brcmstb_i2c_dev * dev = i2c_get_adapdata ( adapter ) ;
int ret ;
if ( dev - > irq > = 0 )
disable_irq ( dev - > irq ) ;
dev - > atomic = true ;
ret = brcmstb_i2c_xfer ( adapter , msgs , num ) ;
dev - > atomic = false ;
if ( dev - > irq > = 0 )
enable_irq ( dev - > irq ) ;
return ret ;
}
2015-06-09 22:36:20 +03:00
static u32 brcmstb_i2c_functionality ( struct i2c_adapter * adap )
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR
| I2C_FUNC_NOSTART | I2C_FUNC_PROTOCOL_MANGLING ;
}
static const struct i2c_algorithm brcmstb_i2c_algo = {
. master_xfer = brcmstb_i2c_xfer ,
2023-10-06 17:41:17 +03:00
. master_xfer_atomic = brcmstb_i2c_xfer_atomic ,
2015-06-09 22:36:20 +03:00
. functionality = brcmstb_i2c_functionality ,
} ;
static void brcmstb_i2c_set_bus_speed ( struct brcmstb_i2c_dev * dev )
{
int i = 0 , num_speeds = ARRAY_SIZE ( bsc_clk ) ;
u32 clk_freq_hz = dev - > clk_freq_hz ;
for ( i = 0 ; i < num_speeds ; i + + ) {
if ( bsc_clk [ i ] . hz = = clk_freq_hz ) {
dev - > bsc_regmap - > ctl_reg & = ~ ( BSC_CTL_REG_SCL_SEL_MASK
| BSC_CTL_REG_DIV_CLK_MASK ) ;
dev - > bsc_regmap - > ctl_reg | = ( bsc_clk [ i ] . scl_mask |
bsc_clk [ i ] . div_mask ) ;
bsc_writel ( dev , dev - > bsc_regmap - > ctl_reg , ctl_reg ) ;
break ;
}
}
/* in case we did not get find a valid speed */
if ( i = = num_speeds ) {
i = ( bsc_readl ( dev , ctl_reg ) & BSC_CTL_REG_SCL_SEL_MASK ) > >
BSC_CTL_REG_SCL_SEL_SHIFT ;
dev_warn ( dev - > device , " leaving current clock-frequency @ %dHz \n " ,
bsc_clk [ i ] . hz ) ;
}
}
static void brcmstb_i2c_set_bsc_reg_defaults ( struct brcmstb_i2c_dev * dev )
{
2015-12-16 23:49:09 +03:00
if ( brcmstb_i2c_get_data_regsz ( dev ) = = sizeof ( u32 ) )
/* set 4 byte data in/out xfers */
dev - > bsc_regmap - > ctlhi_reg = BSC_CTLHI_REG_DATAREG_SIZE_MASK ;
else
dev - > bsc_regmap - > ctlhi_reg & = ~ BSC_CTLHI_REG_DATAREG_SIZE_MASK ;
2015-06-09 22:36:20 +03:00
bsc_writel ( dev , dev - > bsc_regmap - > ctlhi_reg , ctlhi_reg ) ;
/* set bus speed */
brcmstb_i2c_set_bus_speed ( dev ) ;
}
2020-02-24 12:06:05 +03:00
# define AUTOI2C_CTRL0 0x26c
# define AUTOI2C_CTRL0_RELEASE_BSC BIT(1)
static int bcm2711_release_bsc ( struct brcmstb_i2c_dev * dev )
{
struct platform_device * pdev = to_platform_device ( dev - > device ) ;
void __iomem * autoi2c ;
/* Map hardware registers */
2023-03-21 14:44:06 +03:00
autoi2c = devm_platform_ioremap_resource_byname ( pdev , " auto-i2c " ) ;
2020-02-24 12:06:05 +03:00
if ( IS_ERR ( autoi2c ) )
return PTR_ERR ( autoi2c ) ;
writel ( AUTOI2C_CTRL0_RELEASE_BSC , autoi2c + AUTOI2C_CTRL0 ) ;
devm_iounmap ( & pdev - > dev , autoi2c ) ;
/* We need to reset the controller after the release */
dev - > bsc_regmap - > iic_enable = 0 ;
bsc_writel ( dev , dev - > bsc_regmap - > iic_enable , iic_enable ) ;
return 0 ;
}
2015-06-09 22:36:20 +03:00
static int brcmstb_i2c_probe ( struct platform_device * pdev )
{
struct brcmstb_i2c_dev * dev ;
struct i2c_adapter * adap ;
const char * int_name ;
2023-07-10 09:33:42 +03:00
int rc ;
2015-06-09 22:36:20 +03:00
/* Allocate memory for private data structure */
dev = devm_kzalloc ( & pdev - > dev , sizeof ( * dev ) , GFP_KERNEL ) ;
if ( ! dev )
return - ENOMEM ;
2016-02-21 17:16:48 +03:00
dev - > bsc_regmap = devm_kzalloc ( & pdev - > dev , sizeof ( * dev - > bsc_regmap ) , GFP_KERNEL ) ;
2015-06-09 22:36:20 +03:00
if ( ! dev - > bsc_regmap )
return - ENOMEM ;
platform_set_drvdata ( pdev , dev ) ;
dev - > device = & pdev - > dev ;
init_completion ( & dev - > done ) ;
/* Map hardware registers */
2023-07-10 09:33:42 +03:00
dev - > base = devm_platform_ioremap_resource ( pdev , 0 ) ;
if ( IS_ERR ( dev - > base ) )
return PTR_ERR ( dev - > base ) ;
2015-06-09 22:36:20 +03:00
2020-02-24 12:06:05 +03:00
if ( of_device_is_compatible ( dev - > device - > of_node ,
" brcm,bcm2711-hdmi-i2c " ) ) {
rc = bcm2711_release_bsc ( dev ) ;
if ( rc )
2023-07-10 09:33:42 +03:00
return rc ;
2020-02-24 12:06:05 +03:00
}
2015-06-09 22:36:20 +03:00
rc = of_property_read_string ( dev - > device - > of_node , " interrupt-names " ,
& int_name ) ;
if ( rc < 0 )
int_name = NULL ;
/* Get the interrupt number */
2020-04-26 00:38:07 +03:00
dev - > irq = platform_get_irq_optional ( pdev , 0 ) ;
2015-06-09 22:36:20 +03:00
/* disable the bsc interrupt line */
brcmstb_i2c_enable_disable_irq ( dev , INT_DISABLE ) ;
/* register the ISR handler */
2020-04-26 00:38:07 +03:00
if ( dev - > irq > = 0 ) {
rc = devm_request_irq ( & pdev - > dev , dev - > irq , brcmstb_i2c_isr ,
IRQF_SHARED ,
int_name ? int_name : pdev - > name ,
dev ) ;
if ( rc ) {
dev_dbg ( dev - > device , " falling back to polling mode " ) ;
dev - > irq = - 1 ;
}
2015-06-09 22:36:20 +03:00
}
if ( of_property_read_u32 ( dev - > device - > of_node ,
" clock-frequency " , & dev - > clk_freq_hz ) ) {
dev_warn ( dev - > device , " setting clock-frequency@%dHz \n " ,
bsc_clk [ 0 ] . hz ) ;
dev - > clk_freq_hz = bsc_clk [ 0 ] . hz ;
}
2015-12-16 23:49:09 +03:00
/* set the data in/out register size for compatible SoCs */
if ( of_device_is_compatible ( dev - > device - > of_node ,
2022-02-15 10:27:35 +03:00
" brcm,brcmper-i2c " ) )
2015-12-16 23:49:09 +03:00
dev - > data_regsz = sizeof ( u8 ) ;
else
dev - > data_regsz = sizeof ( u32 ) ;
2015-06-09 22:36:20 +03:00
brcmstb_i2c_set_bsc_reg_defaults ( dev ) ;
/* Add the i2c adapter */
adap = & dev - > adapter ;
i2c_set_adapdata ( adap , dev ) ;
adap - > owner = THIS_MODULE ;
2022-08-11 10:10:30 +03:00
strscpy ( adap - > name , dev_name ( & pdev - > dev ) , sizeof ( adap - > name ) ) ;
2015-06-09 22:36:20 +03:00
adap - > algo = & brcmstb_i2c_algo ;
adap - > dev . parent = & pdev - > dev ;
adap - > dev . of_node = pdev - > dev . of_node ;
rc = i2c_add_adapter ( adap ) ;
2016-08-09 14:36:17 +03:00
if ( rc )
2023-07-10 09:33:42 +03:00
return rc ;
2015-06-09 22:36:20 +03:00
dev_info ( dev - > device , " %s@%dhz registered in %s mode \n " ,
int_name ? int_name : " " , dev - > clk_freq_hz ,
( dev - > irq > = 0 ) ? " interrupt " : " polling " ) ;
return 0 ;
}
2023-05-08 23:51:38 +03:00
static void brcmstb_i2c_remove ( struct platform_device * pdev )
2015-06-09 22:36:20 +03:00
{
struct brcmstb_i2c_dev * dev = platform_get_drvdata ( pdev ) ;
i2c_del_adapter ( & dev - > adapter ) ;
}
static int brcmstb_i2c_suspend ( struct device * dev )
{
struct brcmstb_i2c_dev * i2c_dev = dev_get_drvdata ( dev ) ;
2018-12-19 19:48:20 +03:00
i2c_mark_adapter_suspended ( & i2c_dev - > adapter ) ;
2015-06-09 22:36:20 +03:00
return 0 ;
}
static int brcmstb_i2c_resume ( struct device * dev )
{
struct brcmstb_i2c_dev * i2c_dev = dev_get_drvdata ( dev ) ;
brcmstb_i2c_set_bsc_reg_defaults ( i2c_dev ) ;
2018-12-19 19:48:20 +03:00
i2c_mark_adapter_resumed ( & i2c_dev - > adapter ) ;
2015-06-09 22:36:20 +03:00
return 0 ;
}
2023-07-22 14:50:27 +03:00
static DEFINE_SIMPLE_DEV_PM_OPS ( brcmstb_i2c_pm , brcmstb_i2c_suspend ,
brcmstb_i2c_resume ) ;
2015-06-09 22:36:20 +03:00
static const struct of_device_id brcmstb_i2c_of_match [ ] = {
{ . compatible = " brcm,brcmstb-i2c " } ,
2015-12-16 23:49:09 +03:00
{ . compatible = " brcm,brcmper-i2c " } ,
2020-02-24 12:06:05 +03:00
{ . compatible = " brcm,bcm2711-hdmi-i2c " } ,
2015-06-09 22:36:20 +03:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , brcmstb_i2c_of_match ) ;
static struct platform_driver brcmstb_i2c_driver = {
. driver = {
. name = " brcmstb-i2c " ,
. of_match_table = brcmstb_i2c_of_match ,
2023-07-22 14:50:27 +03:00
. pm = pm_sleep_ptr ( & brcmstb_i2c_pm ) ,
2015-06-09 22:36:20 +03:00
} ,
. probe = brcmstb_i2c_probe ,
2023-05-08 23:51:38 +03:00
. remove_new = brcmstb_i2c_remove ,
2015-06-09 22:36:20 +03:00
} ;
module_platform_driver ( brcmstb_i2c_driver ) ;
MODULE_AUTHOR ( " Kamal Dasu <kdasu@broadcom.com> " ) ;
MODULE_DESCRIPTION ( " Broadcom Settop I2C Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;