162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci// Copyright (C) 2014 Broadcom Corporation 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/clk.h> 562306a36Sopenharmony_ci#include <linux/delay.h> 662306a36Sopenharmony_ci#include <linux/device.h> 762306a36Sopenharmony_ci#include <linux/i2c.h> 862306a36Sopenharmony_ci#include <linux/interrupt.h> 962306a36Sopenharmony_ci#include <linux/io.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/platform_device.h> 1362306a36Sopenharmony_ci#include <linux/sched.h> 1462306a36Sopenharmony_ci#include <linux/slab.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define N_DATA_REGS 8 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* 1962306a36Sopenharmony_ci * PER_I2C/BSC count register mask depends on 1 byte/4 byte data register 2062306a36Sopenharmony_ci * size. Cable modem and DSL SoCs with Peripheral i2c cores use 1 byte per 2162306a36Sopenharmony_ci * data register whereas STB SoCs use 4 byte per data register transfer, 2262306a36Sopenharmony_ci * account for this difference in total count per transaction and mask to 2362306a36Sopenharmony_ci * use. 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ci#define BSC_CNT_REG1_MASK(nb) (nb == 1 ? GENMASK(3, 0) : GENMASK(5, 0)) 2662306a36Sopenharmony_ci#define BSC_CNT_REG1_SHIFT 0 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* BSC CTL register field definitions */ 2962306a36Sopenharmony_ci#define BSC_CTL_REG_DTF_MASK 0x00000003 3062306a36Sopenharmony_ci#define BSC_CTL_REG_SCL_SEL_MASK 0x00000030 3162306a36Sopenharmony_ci#define BSC_CTL_REG_SCL_SEL_SHIFT 4 3262306a36Sopenharmony_ci#define BSC_CTL_REG_INT_EN_MASK 0x00000040 3362306a36Sopenharmony_ci#define BSC_CTL_REG_INT_EN_SHIFT 6 3462306a36Sopenharmony_ci#define BSC_CTL_REG_DIV_CLK_MASK 0x00000080 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* BSC_IIC_ENABLE r/w enable and interrupt field definitions */ 3762306a36Sopenharmony_ci#define BSC_IIC_EN_RESTART_MASK 0x00000040 3862306a36Sopenharmony_ci#define BSC_IIC_EN_NOSTART_MASK 0x00000020 3962306a36Sopenharmony_ci#define BSC_IIC_EN_NOSTOP_MASK 0x00000010 4062306a36Sopenharmony_ci#define BSC_IIC_EN_NOACK_MASK 0x00000004 4162306a36Sopenharmony_ci#define BSC_IIC_EN_INTRP_MASK 0x00000002 4262306a36Sopenharmony_ci#define BSC_IIC_EN_ENABLE_MASK 0x00000001 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* BSC_CTLHI control register field definitions */ 4562306a36Sopenharmony_ci#define BSC_CTLHI_REG_INPUT_SWITCHING_LEVEL_MASK 0x00000080 4662306a36Sopenharmony_ci#define BSC_CTLHI_REG_DATAREG_SIZE_MASK 0x00000040 4762306a36Sopenharmony_ci#define BSC_CTLHI_REG_IGNORE_ACK_MASK 0x00000002 4862306a36Sopenharmony_ci#define BSC_CTLHI_REG_WAIT_DIS_MASK 0x00000001 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define I2C_TIMEOUT 100 /* msecs */ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* Condition mask used for non combined transfer */ 5362306a36Sopenharmony_ci#define COND_RESTART BSC_IIC_EN_RESTART_MASK 5462306a36Sopenharmony_ci#define COND_NOSTART BSC_IIC_EN_NOSTART_MASK 5562306a36Sopenharmony_ci#define COND_NOSTOP BSC_IIC_EN_NOSTOP_MASK 5662306a36Sopenharmony_ci#define COND_START_STOP (COND_RESTART | COND_NOSTART | COND_NOSTOP) 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* BSC data transfer direction */ 5962306a36Sopenharmony_ci#define DTF_WR_MASK 0x00000000 6062306a36Sopenharmony_ci#define DTF_RD_MASK 0x00000001 6162306a36Sopenharmony_ci/* BSC data transfer direction combined format */ 6262306a36Sopenharmony_ci#define DTF_RD_WR_MASK 0x00000002 6362306a36Sopenharmony_ci#define DTF_WR_RD_MASK 0x00000003 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define INT_ENABLE true 6662306a36Sopenharmony_ci#define INT_DISABLE false 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* BSC block register map structure to cache fields to be written */ 6962306a36Sopenharmony_cistruct bsc_regs { 7062306a36Sopenharmony_ci u32 chip_address; /* slave address */ 7162306a36Sopenharmony_ci u32 data_in[N_DATA_REGS]; /* tx data buffer*/ 7262306a36Sopenharmony_ci u32 cnt_reg; /* rx/tx data length */ 7362306a36Sopenharmony_ci u32 ctl_reg; /* control register */ 7462306a36Sopenharmony_ci u32 iic_enable; /* xfer enable and status */ 7562306a36Sopenharmony_ci u32 data_out[N_DATA_REGS]; /* rx data buffer */ 7662306a36Sopenharmony_ci u32 ctlhi_reg; /* more control fields */ 7762306a36Sopenharmony_ci u32 scl_param; /* reserved */ 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistruct bsc_clk_param { 8162306a36Sopenharmony_ci u32 hz; 8262306a36Sopenharmony_ci u32 scl_mask; 8362306a36Sopenharmony_ci u32 div_mask; 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cienum bsc_xfer_cmd { 8762306a36Sopenharmony_ci CMD_WR, 8862306a36Sopenharmony_ci CMD_RD, 8962306a36Sopenharmony_ci CMD_WR_NOACK, 9062306a36Sopenharmony_ci CMD_RD_NOACK, 9162306a36Sopenharmony_ci}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic char const *cmd_string[] = { 9462306a36Sopenharmony_ci [CMD_WR] = "WR", 9562306a36Sopenharmony_ci [CMD_RD] = "RD", 9662306a36Sopenharmony_ci [CMD_WR_NOACK] = "WR NOACK", 9762306a36Sopenharmony_ci [CMD_RD_NOACK] = "RD NOACK", 9862306a36Sopenharmony_ci}; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cienum bus_speeds { 10162306a36Sopenharmony_ci SPD_375K, 10262306a36Sopenharmony_ci SPD_390K, 10362306a36Sopenharmony_ci SPD_187K, 10462306a36Sopenharmony_ci SPD_200K, 10562306a36Sopenharmony_ci SPD_93K, 10662306a36Sopenharmony_ci SPD_97K, 10762306a36Sopenharmony_ci SPD_46K, 10862306a36Sopenharmony_ci SPD_50K 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic const struct bsc_clk_param bsc_clk[] = { 11262306a36Sopenharmony_ci [SPD_375K] = { 11362306a36Sopenharmony_ci .hz = 375000, 11462306a36Sopenharmony_ci .scl_mask = SPD_375K << BSC_CTL_REG_SCL_SEL_SHIFT, 11562306a36Sopenharmony_ci .div_mask = 0 11662306a36Sopenharmony_ci }, 11762306a36Sopenharmony_ci [SPD_390K] = { 11862306a36Sopenharmony_ci .hz = 390000, 11962306a36Sopenharmony_ci .scl_mask = SPD_390K << BSC_CTL_REG_SCL_SEL_SHIFT, 12062306a36Sopenharmony_ci .div_mask = 0 12162306a36Sopenharmony_ci }, 12262306a36Sopenharmony_ci [SPD_187K] = { 12362306a36Sopenharmony_ci .hz = 187500, 12462306a36Sopenharmony_ci .scl_mask = SPD_187K << BSC_CTL_REG_SCL_SEL_SHIFT, 12562306a36Sopenharmony_ci .div_mask = 0 12662306a36Sopenharmony_ci }, 12762306a36Sopenharmony_ci [SPD_200K] = { 12862306a36Sopenharmony_ci .hz = 200000, 12962306a36Sopenharmony_ci .scl_mask = SPD_200K << BSC_CTL_REG_SCL_SEL_SHIFT, 13062306a36Sopenharmony_ci .div_mask = 0 13162306a36Sopenharmony_ci }, 13262306a36Sopenharmony_ci [SPD_93K] = { 13362306a36Sopenharmony_ci .hz = 93750, 13462306a36Sopenharmony_ci .scl_mask = SPD_375K << BSC_CTL_REG_SCL_SEL_SHIFT, 13562306a36Sopenharmony_ci .div_mask = BSC_CTL_REG_DIV_CLK_MASK 13662306a36Sopenharmony_ci }, 13762306a36Sopenharmony_ci [SPD_97K] = { 13862306a36Sopenharmony_ci .hz = 97500, 13962306a36Sopenharmony_ci .scl_mask = SPD_390K << BSC_CTL_REG_SCL_SEL_SHIFT, 14062306a36Sopenharmony_ci .div_mask = BSC_CTL_REG_DIV_CLK_MASK 14162306a36Sopenharmony_ci }, 14262306a36Sopenharmony_ci [SPD_46K] = { 14362306a36Sopenharmony_ci .hz = 46875, 14462306a36Sopenharmony_ci .scl_mask = SPD_187K << BSC_CTL_REG_SCL_SEL_SHIFT, 14562306a36Sopenharmony_ci .div_mask = BSC_CTL_REG_DIV_CLK_MASK 14662306a36Sopenharmony_ci }, 14762306a36Sopenharmony_ci [SPD_50K] = { 14862306a36Sopenharmony_ci .hz = 50000, 14962306a36Sopenharmony_ci .scl_mask = SPD_200K << BSC_CTL_REG_SCL_SEL_SHIFT, 15062306a36Sopenharmony_ci .div_mask = BSC_CTL_REG_DIV_CLK_MASK 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci}; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistruct brcmstb_i2c_dev { 15562306a36Sopenharmony_ci struct device *device; 15662306a36Sopenharmony_ci void __iomem *base; 15762306a36Sopenharmony_ci int irq; 15862306a36Sopenharmony_ci struct bsc_regs *bsc_regmap; 15962306a36Sopenharmony_ci struct i2c_adapter adapter; 16062306a36Sopenharmony_ci struct completion done; 16162306a36Sopenharmony_ci u32 clk_freq_hz; 16262306a36Sopenharmony_ci int data_regsz; 16362306a36Sopenharmony_ci}; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/* register accessors for both be and le cpu arch */ 16662306a36Sopenharmony_ci#ifdef CONFIG_CPU_BIG_ENDIAN 16762306a36Sopenharmony_ci#define __bsc_readl(_reg) ioread32be(_reg) 16862306a36Sopenharmony_ci#define __bsc_writel(_val, _reg) iowrite32be(_val, _reg) 16962306a36Sopenharmony_ci#else 17062306a36Sopenharmony_ci#define __bsc_readl(_reg) ioread32(_reg) 17162306a36Sopenharmony_ci#define __bsc_writel(_val, _reg) iowrite32(_val, _reg) 17262306a36Sopenharmony_ci#endif 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci#define bsc_readl(_dev, _reg) \ 17562306a36Sopenharmony_ci __bsc_readl(_dev->base + offsetof(struct bsc_regs, _reg)) 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci#define bsc_writel(_dev, _val, _reg) \ 17862306a36Sopenharmony_ci __bsc_writel(_val, _dev->base + offsetof(struct bsc_regs, _reg)) 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic inline int brcmstb_i2c_get_xfersz(struct brcmstb_i2c_dev *dev) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci return (N_DATA_REGS * dev->data_regsz); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic inline int brcmstb_i2c_get_data_regsz(struct brcmstb_i2c_dev *dev) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci return dev->data_regsz; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic void brcmstb_i2c_enable_disable_irq(struct brcmstb_i2c_dev *dev, 19162306a36Sopenharmony_ci bool int_en) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (int_en) 19562306a36Sopenharmony_ci /* Enable BSC CTL interrupt line */ 19662306a36Sopenharmony_ci dev->bsc_regmap->ctl_reg |= BSC_CTL_REG_INT_EN_MASK; 19762306a36Sopenharmony_ci else 19862306a36Sopenharmony_ci /* Disable BSC CTL interrupt line */ 19962306a36Sopenharmony_ci dev->bsc_regmap->ctl_reg &= ~BSC_CTL_REG_INT_EN_MASK; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci barrier(); 20262306a36Sopenharmony_ci bsc_writel(dev, dev->bsc_regmap->ctl_reg, ctl_reg); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic irqreturn_t brcmstb_i2c_isr(int irq, void *devid) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci struct brcmstb_i2c_dev *dev = devid; 20862306a36Sopenharmony_ci u32 status_bsc_ctl = bsc_readl(dev, ctl_reg); 20962306a36Sopenharmony_ci u32 status_iic_intrp = bsc_readl(dev, iic_enable); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci dev_dbg(dev->device, "isr CTL_REG %x IIC_EN %x\n", 21262306a36Sopenharmony_ci status_bsc_ctl, status_iic_intrp); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (!(status_bsc_ctl & BSC_CTL_REG_INT_EN_MASK)) 21562306a36Sopenharmony_ci return IRQ_NONE; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci brcmstb_i2c_enable_disable_irq(dev, INT_DISABLE); 21862306a36Sopenharmony_ci complete(&dev->done); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci dev_dbg(dev->device, "isr handled"); 22162306a36Sopenharmony_ci return IRQ_HANDLED; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci/* Wait for device to be ready */ 22562306a36Sopenharmony_cistatic int brcmstb_i2c_wait_if_busy(struct brcmstb_i2c_dev *dev) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(I2C_TIMEOUT); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci while ((bsc_readl(dev, iic_enable) & BSC_IIC_EN_INTRP_MASK)) { 23062306a36Sopenharmony_ci if (time_after(jiffies, timeout)) 23162306a36Sopenharmony_ci return -ETIMEDOUT; 23262306a36Sopenharmony_ci cpu_relax(); 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci return 0; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci/* i2c xfer completion function, handles both irq and polling mode */ 23862306a36Sopenharmony_cistatic int brcmstb_i2c_wait_for_completion(struct brcmstb_i2c_dev *dev) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci int ret = 0; 24162306a36Sopenharmony_ci unsigned long timeout = msecs_to_jiffies(I2C_TIMEOUT); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (dev->irq >= 0) { 24462306a36Sopenharmony_ci if (!wait_for_completion_timeout(&dev->done, timeout)) 24562306a36Sopenharmony_ci ret = -ETIMEDOUT; 24662306a36Sopenharmony_ci } else { 24762306a36Sopenharmony_ci /* we are in polling mode */ 24862306a36Sopenharmony_ci u32 bsc_intrp; 24962306a36Sopenharmony_ci unsigned long time_left = jiffies + timeout; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci do { 25262306a36Sopenharmony_ci bsc_intrp = bsc_readl(dev, iic_enable) & 25362306a36Sopenharmony_ci BSC_IIC_EN_INTRP_MASK; 25462306a36Sopenharmony_ci if (time_after(jiffies, time_left)) { 25562306a36Sopenharmony_ci ret = -ETIMEDOUT; 25662306a36Sopenharmony_ci break; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci cpu_relax(); 25962306a36Sopenharmony_ci } while (!bsc_intrp); 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (dev->irq < 0 || ret == -ETIMEDOUT) 26362306a36Sopenharmony_ci brcmstb_i2c_enable_disable_irq(dev, INT_DISABLE); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return ret; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci/* Set xfer START/STOP conditions for subsequent transfer */ 26962306a36Sopenharmony_cistatic void brcmstb_set_i2c_start_stop(struct brcmstb_i2c_dev *dev, 27062306a36Sopenharmony_ci u32 cond_flag) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci u32 regval = dev->bsc_regmap->iic_enable; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci dev->bsc_regmap->iic_enable = (regval & ~COND_START_STOP) | cond_flag; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci/* Send I2C request check completion */ 27862306a36Sopenharmony_cistatic int brcmstb_send_i2c_cmd(struct brcmstb_i2c_dev *dev, 27962306a36Sopenharmony_ci enum bsc_xfer_cmd cmd) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci int rc = 0; 28262306a36Sopenharmony_ci struct bsc_regs *pi2creg = dev->bsc_regmap; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Make sure the hardware is ready */ 28562306a36Sopenharmony_ci rc = brcmstb_i2c_wait_if_busy(dev); 28662306a36Sopenharmony_ci if (rc < 0) 28762306a36Sopenharmony_ci return rc; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* only if we are in interrupt mode */ 29062306a36Sopenharmony_ci if (dev->irq >= 0) 29162306a36Sopenharmony_ci reinit_completion(&dev->done); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* enable BSC CTL interrupt line */ 29462306a36Sopenharmony_ci brcmstb_i2c_enable_disable_irq(dev, INT_ENABLE); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci /* initiate transfer by setting iic_enable */ 29762306a36Sopenharmony_ci pi2creg->iic_enable |= BSC_IIC_EN_ENABLE_MASK; 29862306a36Sopenharmony_ci bsc_writel(dev, pi2creg->iic_enable, iic_enable); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* Wait for transaction to finish or timeout */ 30162306a36Sopenharmony_ci rc = brcmstb_i2c_wait_for_completion(dev); 30262306a36Sopenharmony_ci if (rc) { 30362306a36Sopenharmony_ci dev_dbg(dev->device, "intr timeout for cmd %s\n", 30462306a36Sopenharmony_ci cmd_string[cmd]); 30562306a36Sopenharmony_ci goto cmd_out; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if ((cmd == CMD_RD || cmd == CMD_WR) && 30962306a36Sopenharmony_ci bsc_readl(dev, iic_enable) & BSC_IIC_EN_NOACK_MASK) { 31062306a36Sopenharmony_ci rc = -EREMOTEIO; 31162306a36Sopenharmony_ci dev_dbg(dev->device, "controller received NOACK intr for %s\n", 31262306a36Sopenharmony_ci cmd_string[cmd]); 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cicmd_out: 31662306a36Sopenharmony_ci bsc_writel(dev, 0, cnt_reg); 31762306a36Sopenharmony_ci bsc_writel(dev, 0, iic_enable); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci return rc; 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci/* Actual data transfer through the BSC master */ 32362306a36Sopenharmony_cistatic int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev, 32462306a36Sopenharmony_ci u8 *buf, unsigned int len, 32562306a36Sopenharmony_ci struct i2c_msg *pmsg) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci int cnt, byte, i, rc; 32862306a36Sopenharmony_ci enum bsc_xfer_cmd cmd; 32962306a36Sopenharmony_ci u32 ctl_reg; 33062306a36Sopenharmony_ci struct bsc_regs *pi2creg = dev->bsc_regmap; 33162306a36Sopenharmony_ci int no_ack = pmsg->flags & I2C_M_IGNORE_NAK; 33262306a36Sopenharmony_ci int data_regsz = brcmstb_i2c_get_data_regsz(dev); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci /* see if the transaction needs to check NACK conditions */ 33562306a36Sopenharmony_ci if (no_ack) { 33662306a36Sopenharmony_ci cmd = (pmsg->flags & I2C_M_RD) ? CMD_RD_NOACK 33762306a36Sopenharmony_ci : CMD_WR_NOACK; 33862306a36Sopenharmony_ci pi2creg->ctlhi_reg |= BSC_CTLHI_REG_IGNORE_ACK_MASK; 33962306a36Sopenharmony_ci } else { 34062306a36Sopenharmony_ci cmd = (pmsg->flags & I2C_M_RD) ? CMD_RD : CMD_WR; 34162306a36Sopenharmony_ci pi2creg->ctlhi_reg &= ~BSC_CTLHI_REG_IGNORE_ACK_MASK; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci bsc_writel(dev, pi2creg->ctlhi_reg, ctlhi_reg); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* set data transfer direction */ 34662306a36Sopenharmony_ci ctl_reg = pi2creg->ctl_reg & ~BSC_CTL_REG_DTF_MASK; 34762306a36Sopenharmony_ci if (cmd == CMD_WR || cmd == CMD_WR_NOACK) 34862306a36Sopenharmony_ci pi2creg->ctl_reg = ctl_reg | DTF_WR_MASK; 34962306a36Sopenharmony_ci else 35062306a36Sopenharmony_ci pi2creg->ctl_reg = ctl_reg | DTF_RD_MASK; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* set the read/write length */ 35362306a36Sopenharmony_ci bsc_writel(dev, BSC_CNT_REG1_MASK(data_regsz) & 35462306a36Sopenharmony_ci (len << BSC_CNT_REG1_SHIFT), cnt_reg); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* Write data into data_in register */ 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (cmd == CMD_WR || cmd == CMD_WR_NOACK) { 35962306a36Sopenharmony_ci for (cnt = 0, i = 0; cnt < len; cnt += data_regsz, i++) { 36062306a36Sopenharmony_ci u32 word = 0; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci for (byte = 0; byte < data_regsz; byte++) { 36362306a36Sopenharmony_ci word >>= BITS_PER_BYTE; 36462306a36Sopenharmony_ci if ((cnt + byte) < len) 36562306a36Sopenharmony_ci word |= buf[cnt + byte] << 36662306a36Sopenharmony_ci (BITS_PER_BYTE * (data_regsz - 1)); 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci bsc_writel(dev, word, data_in[i]); 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* Initiate xfer, the function will return on completion */ 37362306a36Sopenharmony_ci rc = brcmstb_send_i2c_cmd(dev, cmd); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (rc != 0) { 37662306a36Sopenharmony_ci dev_dbg(dev->device, "%s failure", cmd_string[cmd]); 37762306a36Sopenharmony_ci return rc; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* Read data from data_out register */ 38162306a36Sopenharmony_ci if (cmd == CMD_RD || cmd == CMD_RD_NOACK) { 38262306a36Sopenharmony_ci for (cnt = 0, i = 0; cnt < len; cnt += data_regsz, i++) { 38362306a36Sopenharmony_ci u32 data = bsc_readl(dev, data_out[i]); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci for (byte = 0; byte < data_regsz && 38662306a36Sopenharmony_ci (byte + cnt) < len; byte++) { 38762306a36Sopenharmony_ci buf[cnt + byte] = data & 0xff; 38862306a36Sopenharmony_ci data >>= BITS_PER_BYTE; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return 0; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci/* Write a single byte of data to the i2c bus */ 39762306a36Sopenharmony_cistatic int brcmstb_i2c_write_data_byte(struct brcmstb_i2c_dev *dev, 39862306a36Sopenharmony_ci u8 *buf, unsigned int nak_expected) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci enum bsc_xfer_cmd cmd = nak_expected ? CMD_WR : CMD_WR_NOACK; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci bsc_writel(dev, 1, cnt_reg); 40362306a36Sopenharmony_ci bsc_writel(dev, *buf, data_in); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci return brcmstb_send_i2c_cmd(dev, cmd); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci/* Send i2c address */ 40962306a36Sopenharmony_cistatic int brcmstb_i2c_do_addr(struct brcmstb_i2c_dev *dev, 41062306a36Sopenharmony_ci struct i2c_msg *msg) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci unsigned char addr; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (msg->flags & I2C_M_TEN) { 41562306a36Sopenharmony_ci /* First byte is 11110XX0 where XX is upper 2 bits */ 41662306a36Sopenharmony_ci addr = 0xF0 | ((msg->addr & 0x300) >> 7); 41762306a36Sopenharmony_ci bsc_writel(dev, addr, chip_address); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* Second byte is the remaining 8 bits */ 42062306a36Sopenharmony_ci addr = msg->addr & 0xFF; 42162306a36Sopenharmony_ci if (brcmstb_i2c_write_data_byte(dev, &addr, 0) < 0) 42262306a36Sopenharmony_ci return -EREMOTEIO; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci if (msg->flags & I2C_M_RD) { 42562306a36Sopenharmony_ci /* For read, send restart without stop condition */ 42662306a36Sopenharmony_ci brcmstb_set_i2c_start_stop(dev, COND_RESTART 42762306a36Sopenharmony_ci | COND_NOSTOP); 42862306a36Sopenharmony_ci /* Then re-send the first byte with the read bit set */ 42962306a36Sopenharmony_ci addr = 0xF0 | ((msg->addr & 0x300) >> 7) | 0x01; 43062306a36Sopenharmony_ci if (brcmstb_i2c_write_data_byte(dev, &addr, 0) < 0) 43162306a36Sopenharmony_ci return -EREMOTEIO; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci } else { 43562306a36Sopenharmony_ci addr = i2c_8bit_addr_from_msg(msg); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci bsc_writel(dev, addr, chip_address); 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci return 0; 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci/* Master transfer function */ 44462306a36Sopenharmony_cistatic int brcmstb_i2c_xfer(struct i2c_adapter *adapter, 44562306a36Sopenharmony_ci struct i2c_msg msgs[], int num) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci struct brcmstb_i2c_dev *dev = i2c_get_adapdata(adapter); 44862306a36Sopenharmony_ci struct i2c_msg *pmsg; 44962306a36Sopenharmony_ci int rc = 0; 45062306a36Sopenharmony_ci int i; 45162306a36Sopenharmony_ci int bytes_to_xfer; 45262306a36Sopenharmony_ci u8 *tmp_buf; 45362306a36Sopenharmony_ci int len = 0; 45462306a36Sopenharmony_ci int xfersz = brcmstb_i2c_get_xfersz(dev); 45562306a36Sopenharmony_ci u32 cond, cond_per_msg; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* Loop through all messages */ 45862306a36Sopenharmony_ci for (i = 0; i < num; i++) { 45962306a36Sopenharmony_ci pmsg = &msgs[i]; 46062306a36Sopenharmony_ci len = pmsg->len; 46162306a36Sopenharmony_ci tmp_buf = pmsg->buf; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci dev_dbg(dev->device, 46462306a36Sopenharmony_ci "msg# %d/%d flg %x buf %x len %d\n", i, 46562306a36Sopenharmony_ci num - 1, pmsg->flags, 46662306a36Sopenharmony_ci pmsg->buf ? pmsg->buf[0] : '0', pmsg->len); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (i < (num - 1) && (msgs[i + 1].flags & I2C_M_NOSTART)) 46962306a36Sopenharmony_ci cond = ~COND_START_STOP; 47062306a36Sopenharmony_ci else 47162306a36Sopenharmony_ci cond = COND_RESTART | COND_NOSTOP; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci brcmstb_set_i2c_start_stop(dev, cond); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* Send slave address */ 47662306a36Sopenharmony_ci if (!(pmsg->flags & I2C_M_NOSTART)) { 47762306a36Sopenharmony_ci rc = brcmstb_i2c_do_addr(dev, pmsg); 47862306a36Sopenharmony_ci if (rc < 0) { 47962306a36Sopenharmony_ci dev_dbg(dev->device, 48062306a36Sopenharmony_ci "NACK for addr %2.2x msg#%d rc = %d\n", 48162306a36Sopenharmony_ci pmsg->addr, i, rc); 48262306a36Sopenharmony_ci goto out; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci cond_per_msg = cond; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* Perform data transfer */ 48962306a36Sopenharmony_ci while (len) { 49062306a36Sopenharmony_ci bytes_to_xfer = min(len, xfersz); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (len <= xfersz) { 49362306a36Sopenharmony_ci if (i == (num - 1)) 49462306a36Sopenharmony_ci cond_per_msg = cond_per_msg & 49562306a36Sopenharmony_ci ~(COND_RESTART | COND_NOSTOP); 49662306a36Sopenharmony_ci else 49762306a36Sopenharmony_ci cond_per_msg = cond; 49862306a36Sopenharmony_ci } else { 49962306a36Sopenharmony_ci cond_per_msg = (cond_per_msg & ~COND_RESTART) | 50062306a36Sopenharmony_ci COND_NOSTOP; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci brcmstb_set_i2c_start_stop(dev, cond_per_msg); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci rc = brcmstb_i2c_xfer_bsc_data(dev, tmp_buf, 50662306a36Sopenharmony_ci bytes_to_xfer, pmsg); 50762306a36Sopenharmony_ci if (rc < 0) 50862306a36Sopenharmony_ci goto out; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci len -= bytes_to_xfer; 51162306a36Sopenharmony_ci tmp_buf += bytes_to_xfer; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci cond_per_msg = COND_NOSTART | COND_NOSTOP; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci rc = num; 51862306a36Sopenharmony_ciout: 51962306a36Sopenharmony_ci return rc; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic u32 brcmstb_i2c_functionality(struct i2c_adapter *adap) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR 52662306a36Sopenharmony_ci | I2C_FUNC_NOSTART | I2C_FUNC_PROTOCOL_MANGLING; 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic const struct i2c_algorithm brcmstb_i2c_algo = { 53062306a36Sopenharmony_ci .master_xfer = brcmstb_i2c_xfer, 53162306a36Sopenharmony_ci .functionality = brcmstb_i2c_functionality, 53262306a36Sopenharmony_ci}; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_cistatic void brcmstb_i2c_set_bus_speed(struct brcmstb_i2c_dev *dev) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci int i = 0, num_speeds = ARRAY_SIZE(bsc_clk); 53762306a36Sopenharmony_ci u32 clk_freq_hz = dev->clk_freq_hz; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci for (i = 0; i < num_speeds; i++) { 54062306a36Sopenharmony_ci if (bsc_clk[i].hz == clk_freq_hz) { 54162306a36Sopenharmony_ci dev->bsc_regmap->ctl_reg &= ~(BSC_CTL_REG_SCL_SEL_MASK 54262306a36Sopenharmony_ci | BSC_CTL_REG_DIV_CLK_MASK); 54362306a36Sopenharmony_ci dev->bsc_regmap->ctl_reg |= (bsc_clk[i].scl_mask | 54462306a36Sopenharmony_ci bsc_clk[i].div_mask); 54562306a36Sopenharmony_ci bsc_writel(dev, dev->bsc_regmap->ctl_reg, ctl_reg); 54662306a36Sopenharmony_ci break; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci /* in case we did not get find a valid speed */ 55162306a36Sopenharmony_ci if (i == num_speeds) { 55262306a36Sopenharmony_ci i = (bsc_readl(dev, ctl_reg) & BSC_CTL_REG_SCL_SEL_MASK) >> 55362306a36Sopenharmony_ci BSC_CTL_REG_SCL_SEL_SHIFT; 55462306a36Sopenharmony_ci dev_warn(dev->device, "leaving current clock-frequency @ %dHz\n", 55562306a36Sopenharmony_ci bsc_clk[i].hz); 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_cistatic void brcmstb_i2c_set_bsc_reg_defaults(struct brcmstb_i2c_dev *dev) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci if (brcmstb_i2c_get_data_regsz(dev) == sizeof(u32)) 56262306a36Sopenharmony_ci /* set 4 byte data in/out xfers */ 56362306a36Sopenharmony_ci dev->bsc_regmap->ctlhi_reg = BSC_CTLHI_REG_DATAREG_SIZE_MASK; 56462306a36Sopenharmony_ci else 56562306a36Sopenharmony_ci dev->bsc_regmap->ctlhi_reg &= ~BSC_CTLHI_REG_DATAREG_SIZE_MASK; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci bsc_writel(dev, dev->bsc_regmap->ctlhi_reg, ctlhi_reg); 56862306a36Sopenharmony_ci /* set bus speed */ 56962306a36Sopenharmony_ci brcmstb_i2c_set_bus_speed(dev); 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci#define AUTOI2C_CTRL0 0x26c 57362306a36Sopenharmony_ci#define AUTOI2C_CTRL0_RELEASE_BSC BIT(1) 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_cistatic int bcm2711_release_bsc(struct brcmstb_i2c_dev *dev) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev->device); 57862306a36Sopenharmony_ci void __iomem *autoi2c; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci /* Map hardware registers */ 58162306a36Sopenharmony_ci autoi2c = devm_platform_ioremap_resource_byname(pdev, "auto-i2c"); 58262306a36Sopenharmony_ci if (IS_ERR(autoi2c)) 58362306a36Sopenharmony_ci return PTR_ERR(autoi2c); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci writel(AUTOI2C_CTRL0_RELEASE_BSC, autoi2c + AUTOI2C_CTRL0); 58662306a36Sopenharmony_ci devm_iounmap(&pdev->dev, autoi2c); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* We need to reset the controller after the release */ 58962306a36Sopenharmony_ci dev->bsc_regmap->iic_enable = 0; 59062306a36Sopenharmony_ci bsc_writel(dev, dev->bsc_regmap->iic_enable, iic_enable); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci return 0; 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cistatic int brcmstb_i2c_probe(struct platform_device *pdev) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci struct brcmstb_i2c_dev *dev; 59862306a36Sopenharmony_ci struct i2c_adapter *adap; 59962306a36Sopenharmony_ci const char *int_name; 60062306a36Sopenharmony_ci int rc; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci /* Allocate memory for private data structure */ 60362306a36Sopenharmony_ci dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); 60462306a36Sopenharmony_ci if (!dev) 60562306a36Sopenharmony_ci return -ENOMEM; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci dev->bsc_regmap = devm_kzalloc(&pdev->dev, sizeof(*dev->bsc_regmap), GFP_KERNEL); 60862306a36Sopenharmony_ci if (!dev->bsc_regmap) 60962306a36Sopenharmony_ci return -ENOMEM; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci platform_set_drvdata(pdev, dev); 61262306a36Sopenharmony_ci dev->device = &pdev->dev; 61362306a36Sopenharmony_ci init_completion(&dev->done); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci /* Map hardware registers */ 61662306a36Sopenharmony_ci dev->base = devm_platform_ioremap_resource(pdev, 0); 61762306a36Sopenharmony_ci if (IS_ERR(dev->base)) 61862306a36Sopenharmony_ci return PTR_ERR(dev->base); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (of_device_is_compatible(dev->device->of_node, 62162306a36Sopenharmony_ci "brcm,bcm2711-hdmi-i2c")) { 62262306a36Sopenharmony_ci rc = bcm2711_release_bsc(dev); 62362306a36Sopenharmony_ci if (rc) 62462306a36Sopenharmony_ci return rc; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci rc = of_property_read_string(dev->device->of_node, "interrupt-names", 62862306a36Sopenharmony_ci &int_name); 62962306a36Sopenharmony_ci if (rc < 0) 63062306a36Sopenharmony_ci int_name = NULL; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci /* Get the interrupt number */ 63362306a36Sopenharmony_ci dev->irq = platform_get_irq_optional(pdev, 0); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci /* disable the bsc interrupt line */ 63662306a36Sopenharmony_ci brcmstb_i2c_enable_disable_irq(dev, INT_DISABLE); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* register the ISR handler */ 63962306a36Sopenharmony_ci if (dev->irq >= 0) { 64062306a36Sopenharmony_ci rc = devm_request_irq(&pdev->dev, dev->irq, brcmstb_i2c_isr, 64162306a36Sopenharmony_ci IRQF_SHARED, 64262306a36Sopenharmony_ci int_name ? int_name : pdev->name, 64362306a36Sopenharmony_ci dev); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci if (rc) { 64662306a36Sopenharmony_ci dev_dbg(dev->device, "falling back to polling mode"); 64762306a36Sopenharmony_ci dev->irq = -1; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci if (of_property_read_u32(dev->device->of_node, 65262306a36Sopenharmony_ci "clock-frequency", &dev->clk_freq_hz)) { 65362306a36Sopenharmony_ci dev_warn(dev->device, "setting clock-frequency@%dHz\n", 65462306a36Sopenharmony_ci bsc_clk[0].hz); 65562306a36Sopenharmony_ci dev->clk_freq_hz = bsc_clk[0].hz; 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci /* set the data in/out register size for compatible SoCs */ 65962306a36Sopenharmony_ci if (of_device_is_compatible(dev->device->of_node, 66062306a36Sopenharmony_ci "brcm,brcmper-i2c")) 66162306a36Sopenharmony_ci dev->data_regsz = sizeof(u8); 66262306a36Sopenharmony_ci else 66362306a36Sopenharmony_ci dev->data_regsz = sizeof(u32); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci brcmstb_i2c_set_bsc_reg_defaults(dev); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* Add the i2c adapter */ 66862306a36Sopenharmony_ci adap = &dev->adapter; 66962306a36Sopenharmony_ci i2c_set_adapdata(adap, dev); 67062306a36Sopenharmony_ci adap->owner = THIS_MODULE; 67162306a36Sopenharmony_ci strscpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name)); 67262306a36Sopenharmony_ci adap->algo = &brcmstb_i2c_algo; 67362306a36Sopenharmony_ci adap->dev.parent = &pdev->dev; 67462306a36Sopenharmony_ci adap->dev.of_node = pdev->dev.of_node; 67562306a36Sopenharmony_ci rc = i2c_add_adapter(adap); 67662306a36Sopenharmony_ci if (rc) 67762306a36Sopenharmony_ci return rc; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci dev_info(dev->device, "%s@%dhz registered in %s mode\n", 68062306a36Sopenharmony_ci int_name ? int_name : " ", dev->clk_freq_hz, 68162306a36Sopenharmony_ci (dev->irq >= 0) ? "interrupt" : "polling"); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci return 0; 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic void brcmstb_i2c_remove(struct platform_device *pdev) 68762306a36Sopenharmony_ci{ 68862306a36Sopenharmony_ci struct brcmstb_i2c_dev *dev = platform_get_drvdata(pdev); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci i2c_del_adapter(&dev->adapter); 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cistatic int brcmstb_i2c_suspend(struct device *dev) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci i2c_mark_adapter_suspended(&i2c_dev->adapter); 69862306a36Sopenharmony_ci return 0; 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_cistatic int brcmstb_i2c_resume(struct device *dev) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci brcmstb_i2c_set_bsc_reg_defaults(i2c_dev); 70662306a36Sopenharmony_ci i2c_mark_adapter_resumed(&i2c_dev->adapter); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci return 0; 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(brcmstb_i2c_pm, brcmstb_i2c_suspend, 71262306a36Sopenharmony_ci brcmstb_i2c_resume); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_cistatic const struct of_device_id brcmstb_i2c_of_match[] = { 71562306a36Sopenharmony_ci {.compatible = "brcm,brcmstb-i2c"}, 71662306a36Sopenharmony_ci {.compatible = "brcm,brcmper-i2c"}, 71762306a36Sopenharmony_ci {.compatible = "brcm,bcm2711-hdmi-i2c"}, 71862306a36Sopenharmony_ci {}, 71962306a36Sopenharmony_ci}; 72062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, brcmstb_i2c_of_match); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_cistatic struct platform_driver brcmstb_i2c_driver = { 72362306a36Sopenharmony_ci .driver = { 72462306a36Sopenharmony_ci .name = "brcmstb-i2c", 72562306a36Sopenharmony_ci .of_match_table = brcmstb_i2c_of_match, 72662306a36Sopenharmony_ci .pm = pm_sleep_ptr(&brcmstb_i2c_pm), 72762306a36Sopenharmony_ci }, 72862306a36Sopenharmony_ci .probe = brcmstb_i2c_probe, 72962306a36Sopenharmony_ci .remove_new = brcmstb_i2c_remove, 73062306a36Sopenharmony_ci}; 73162306a36Sopenharmony_cimodule_platform_driver(brcmstb_i2c_driver); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ciMODULE_AUTHOR("Kamal Dasu <kdasu@broadcom.com>"); 73462306a36Sopenharmony_ciMODULE_DESCRIPTION("Broadcom Settop I2C Driver"); 73562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 736