Commit e2e5a2c6 authored by Kamal Dasu's avatar Kamal Dasu Committed by Wolfram Sang

i2c: brcmstb: Adding support for CM and DSL SoCs

Broadcoms DSL, CM (cable modem)and STB I2C core implementation have
8 data in/out registers that can transfer 8 bytes or 32 bytes max.
Cable and DSL "Peripheral" i2c cores use single byte per data
register and the STB can use 4 byte per data register transfer.
Adding support to take care of this difference. Accordingly added
the compatible string for SoCs using the "Peripheral" I2C block.
Signed-off-by: default avatarKamal Dasu <kdasu.kdev@gmail.com>
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarWolfram Sang <wsa@the-dreams.de>
parent 8378d01f
...@@ -2,7 +2,7 @@ Broadcom stb bsc iic master controller ...@@ -2,7 +2,7 @@ Broadcom stb bsc iic master controller
Required properties: Required properties:
- compatible: should be "brcm,brcmstb-i2c" - compatible: should be "brcm,brcmstb-i2c" or "brcm,brcmper-i2c"
- clock-frequency: 32-bit decimal value of iic master clock freqency in Hz - clock-frequency: 32-bit decimal value of iic master clock freqency in Hz
valid values are 375000, 390000, 187500, 200000 valid values are 375000, 390000, 187500, 200000
93750, 97500, 46875 and 50000 93750, 97500, 46875 and 50000
......
...@@ -25,13 +25,16 @@ ...@@ -25,13 +25,16 @@
#include <linux/version.h> #include <linux/version.h>
#define N_DATA_REGS 8 #define N_DATA_REGS 8
#define N_DATA_BYTES (N_DATA_REGS * 4)
/* BSC count register field definitions */ /*
#define BSC_CNT_REG1_MASK 0x0000003f * PER_I2C/BSC count register mask depends on 1 byte/4 byte data register
#define BSC_CNT_REG1_SHIFT 0 * size. Cable modem and DSL SoCs with Peripheral i2c cores use 1 byte per
#define BSC_CNT_REG2_MASK 0x00000fc0 * data register whereas STB SoCs use 4 byte per data register transfer,
#define BSC_CNT_REG2_SHIFT 6 * 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
/* BSC CTL register field definitions */ /* BSC CTL register field definitions */
#define BSC_CTL_REG_DTF_MASK 0x00000003 #define BSC_CTL_REG_DTF_MASK 0x00000003
...@@ -41,7 +44,7 @@ ...@@ -41,7 +44,7 @@
#define BSC_CTL_REG_INT_EN_SHIFT 6 #define BSC_CTL_REG_INT_EN_SHIFT 6
#define BSC_CTL_REG_DIV_CLK_MASK 0x00000080 #define BSC_CTL_REG_DIV_CLK_MASK 0x00000080
/* BSC_IIC_ENABLE r/w enable and interrupt field defintions */ /* BSC_IIC_ENABLE r/w enable and interrupt field definitions */
#define BSC_IIC_EN_RESTART_MASK 0x00000040 #define BSC_IIC_EN_RESTART_MASK 0x00000040
#define BSC_IIC_EN_NOSTART_MASK 0x00000020 #define BSC_IIC_EN_NOSTART_MASK 0x00000020
#define BSC_IIC_EN_NOSTOP_MASK 0x00000010 #define BSC_IIC_EN_NOSTOP_MASK 0x00000010
...@@ -169,6 +172,7 @@ struct brcmstb_i2c_dev { ...@@ -169,6 +172,7 @@ struct brcmstb_i2c_dev {
struct completion done; struct completion done;
bool is_suspended; bool is_suspended;
u32 clk_freq_hz; u32 clk_freq_hz;
int data_regsz;
}; };
/* register accessors for both be and le cpu arch */ /* register accessors for both be and le cpu arch */
...@@ -186,6 +190,16 @@ struct brcmstb_i2c_dev { ...@@ -186,6 +190,16 @@ struct brcmstb_i2c_dev {
#define bsc_writel(_dev, _val, _reg) \ #define bsc_writel(_dev, _val, _reg) \
__bsc_writel(_val, _dev->base + offsetof(struct bsc_regs, _reg)) __bsc_writel(_val, _dev->base + offsetof(struct bsc_regs, _reg))
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;
}
static void brcmstb_i2c_enable_disable_irq(struct brcmstb_i2c_dev *dev, static void brcmstb_i2c_enable_disable_irq(struct brcmstb_i2c_dev *dev,
bool int_en) bool int_en)
{ {
...@@ -323,14 +337,16 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev, ...@@ -323,14 +337,16 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev,
u8 *buf, unsigned int len, u8 *buf, unsigned int len,
struct i2c_msg *pmsg) struct i2c_msg *pmsg)
{ {
int cnt, byte, rc; int cnt, byte, i, rc;
enum bsc_xfer_cmd cmd; enum bsc_xfer_cmd cmd;
u32 ctl_reg; u32 ctl_reg;
struct bsc_regs *pi2creg = dev->bsc_regmap; struct bsc_regs *pi2creg = dev->bsc_regmap;
int no_ack = pmsg->flags & I2C_M_IGNORE_NAK; int no_ack = pmsg->flags & I2C_M_IGNORE_NAK;
int data_regsz = brcmstb_i2c_get_data_regsz(dev);
int xfersz = brcmstb_i2c_get_xfersz(dev);
/* see if the transaction needs to check NACK conditions */ /* see if the transaction needs to check NACK conditions */
if (no_ack || len <= N_DATA_BYTES) { if (no_ack || len <= xfersz) {
cmd = (pmsg->flags & I2C_M_RD) ? CMD_RD_NOACK cmd = (pmsg->flags & I2C_M_RD) ? CMD_RD_NOACK
: CMD_WR_NOACK; : CMD_WR_NOACK;
pi2creg->ctlhi_reg |= BSC_CTLHI_REG_IGNORE_ACK_MASK; pi2creg->ctlhi_reg |= BSC_CTLHI_REG_IGNORE_ACK_MASK;
...@@ -348,20 +364,22 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev, ...@@ -348,20 +364,22 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev,
pi2creg->ctl_reg = ctl_reg | DTF_RD_MASK; pi2creg->ctl_reg = ctl_reg | DTF_RD_MASK;
/* set the read/write length */ /* set the read/write length */
bsc_writel(dev, BSC_CNT_REG1_MASK & (len << BSC_CNT_REG1_SHIFT), bsc_writel(dev, BSC_CNT_REG1_MASK(data_regsz) &
cnt_reg); (len << BSC_CNT_REG1_SHIFT), cnt_reg);
/* Write data into data_in register */ /* Write data into data_in register */
if (cmd == CMD_WR || cmd == CMD_WR_NOACK) { if (cmd == CMD_WR || cmd == CMD_WR_NOACK) {
for (cnt = 0; cnt < len; cnt += 4) { for (cnt = 0, i = 0; cnt < len; cnt += data_regsz, i++) {
u32 word = 0; u32 word = 0;
for (byte = 0; byte < 4; byte++) { for (byte = 0; byte < data_regsz; byte++) {
word >>= 8; word >>= BITS_PER_BYTE;
if ((cnt + byte) < len) if ((cnt + byte) < len)
word |= buf[cnt + byte] << 24; word |= buf[cnt + byte] <<
(BITS_PER_BYTE * (data_regsz - 1));
} }
bsc_writel(dev, word, data_in[cnt >> 2]); bsc_writel(dev, word, data_in[i]);
} }
} }
...@@ -373,14 +391,15 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev, ...@@ -373,14 +391,15 @@ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev,
return rc; return rc;
} }
/* Read data from data_out register */
if (cmd == CMD_RD || cmd == CMD_RD_NOACK) { if (cmd == CMD_RD || cmd == CMD_RD_NOACK) {
for (cnt = 0; cnt < len; cnt += 4) { for (cnt = 0, i = 0; cnt < len; cnt += data_regsz, i++) {
u32 data = bsc_readl(dev, data_out[cnt >> 2]); u32 data = bsc_readl(dev, data_out[i]);
for (byte = 0; byte < 4 && for (byte = 0; byte < data_regsz &&
(byte + cnt) < len; byte++) { (byte + cnt) < len; byte++) {
buf[cnt + byte] = data & 0xff; buf[cnt + byte] = data & 0xff;
data >>= 8; data >>= BITS_PER_BYTE;
} }
} }
} }
...@@ -448,6 +467,7 @@ static int brcmstb_i2c_xfer(struct i2c_adapter *adapter, ...@@ -448,6 +467,7 @@ static int brcmstb_i2c_xfer(struct i2c_adapter *adapter,
int bytes_to_xfer; int bytes_to_xfer;
u8 *tmp_buf; u8 *tmp_buf;
int len = 0; int len = 0;
int xfersz = brcmstb_i2c_get_xfersz(dev);
if (dev->is_suspended) if (dev->is_suspended)
return -EBUSY; return -EBUSY;
...@@ -482,9 +502,9 @@ static int brcmstb_i2c_xfer(struct i2c_adapter *adapter, ...@@ -482,9 +502,9 @@ static int brcmstb_i2c_xfer(struct i2c_adapter *adapter,
/* Perform data transfer */ /* Perform data transfer */
while (len) { while (len) {
bytes_to_xfer = min(len, N_DATA_BYTES); bytes_to_xfer = min(len, xfersz);
if (len <= N_DATA_BYTES && i == (num - 1)) if (len <= xfersz && i == (num - 1))
brcmstb_set_i2c_start_stop(dev, brcmstb_set_i2c_start_stop(dev,
~(COND_START_STOP)); ~(COND_START_STOP));
...@@ -542,8 +562,12 @@ static void brcmstb_i2c_set_bus_speed(struct brcmstb_i2c_dev *dev) ...@@ -542,8 +562,12 @@ static void brcmstb_i2c_set_bus_speed(struct brcmstb_i2c_dev *dev)
static void brcmstb_i2c_set_bsc_reg_defaults(struct brcmstb_i2c_dev *dev) static void brcmstb_i2c_set_bsc_reg_defaults(struct brcmstb_i2c_dev *dev)
{ {
/* 4 byte data register */ if (brcmstb_i2c_get_data_regsz(dev) == sizeof(u32))
dev->bsc_regmap->ctlhi_reg = BSC_CTLHI_REG_DATAREG_SIZE_MASK; /* 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;
bsc_writel(dev, dev->bsc_regmap->ctlhi_reg, ctlhi_reg); bsc_writel(dev, dev->bsc_regmap->ctlhi_reg, ctlhi_reg);
/* set bus speed */ /* set bus speed */
brcmstb_i2c_set_bus_speed(dev); brcmstb_i2c_set_bus_speed(dev);
...@@ -608,6 +632,13 @@ static int brcmstb_i2c_probe(struct platform_device *pdev) ...@@ -608,6 +632,13 @@ static int brcmstb_i2c_probe(struct platform_device *pdev)
dev->clk_freq_hz = bsc_clk[0].hz; dev->clk_freq_hz = bsc_clk[0].hz;
} }
/* set the data in/out register size for compatible SoCs */
if (of_device_is_compatible(dev->device->of_node,
"brcmstb,brcmper-i2c"))
dev->data_regsz = sizeof(u8);
else
dev->data_regsz = sizeof(u32);
brcmstb_i2c_set_bsc_reg_defaults(dev); brcmstb_i2c_set_bsc_reg_defaults(dev);
/* Add the i2c adapter */ /* Add the i2c adapter */
...@@ -674,6 +705,7 @@ static SIMPLE_DEV_PM_OPS(brcmstb_i2c_pm, brcmstb_i2c_suspend, ...@@ -674,6 +705,7 @@ static SIMPLE_DEV_PM_OPS(brcmstb_i2c_pm, brcmstb_i2c_suspend,
static const struct of_device_id brcmstb_i2c_of_match[] = { static const struct of_device_id brcmstb_i2c_of_match[] = {
{.compatible = "brcm,brcmstb-i2c"}, {.compatible = "brcm,brcmstb-i2c"},
{.compatible = "brcm,brcmper-i2c"},
{}, {},
}; };
MODULE_DEVICE_TABLE(of, brcmstb_i2c_of_match); MODULE_DEVICE_TABLE(of, brcmstb_i2c_of_match);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment