Merge branch 'i2c/next' into next

* i2c/next: (28 commits)
  LF-263-2 i2c: imx: increase PM timeout to avoid operate clk frequently
  LF-263-1 i2c: lpi2c: increase PM timeout to avoid operate clk frequently
  i2c: mux: pca954x: support property idle-state
  dt-bindings: i2c: support property idle-state
  LF-98 i2c: imx: fix the judgement of slave mode in isr
  ...
This commit is contained in:
Dong Aisheng 2019-12-02 18:02:28 +08:00
commit a44f25b882
8 changed files with 1113 additions and 96 deletions

View File

@ -25,6 +25,8 @@ Required Properties:
Optional Properties:
- reset-gpios: Reference to the GPIO connected to the reset input.
- idle-state: if present, overrides i2c-mux-idle-disconnect,
Please refer to Documentation/devicetree/bindings/mux/mux-controller.txt
- i2c-mux-idle-disconnect: Boolean; if defined, forces mux to disconnect all
children in idle state. This is necessary for example, if there are several
multiplexers on the bus and the devices behind them use same I2C addresses.

View File

@ -0,0 +1,29 @@
* Freescale Virtual I2C RPMSG bus driver for i.MX
Required properties:
- compatible :
- "fsl,i2c-rpbus" for I2C bus over RPMSG compatible on i.MX8QXP/QM soc
The i2c-rpbus node should define its bus id (which is the node communicating
with M4) in alias.
Examples:
aliases {
...
i2c1 = &i2c_rpbus_1;
...
};
&i2c_rpbus_1 {
compatible = "fsl,i2c-rpbus";
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
devs_in_this_i2c_bus__for_example: pca6416@20 {
compatible = "ti,tca6416";
reg = <0x20>;
gpio-controller;
#gpio-cells = <2>;
};
};

View File

@ -922,6 +922,12 @@ config I2C_RK3X
This driver can also be built as a module. If so, the module will
be called i2c-rk3x.
config I2C_RPBUS
tristate "I2C proxy bus over RPMSG"
depends on I2C && RPMSG
help
This driver can support virtual i2c-rpmsg function.
config HAVE_S3C2410_I2C
bool
help

View File

@ -130,6 +130,7 @@ obj-$(CONFIG_I2C_DLN2) += i2c-dln2.o
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
obj-$(CONFIG_I2C_ROBOTFUZZ_OSIF) += i2c-robotfuzz-osif.o
obj-$(CONFIG_I2C_RPBUS) += i2c-rpmsg-imx.o
obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o
obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
obj-$(CONFIG_I2C_VIPERBOARD) += i2c-viperboard.o

View File

@ -81,7 +81,7 @@
#define FAST_PLUS_MAX_BITRATE 3400000
#define HIGHSPEED_MAX_BITRATE 5000000
#define I2C_PM_TIMEOUT 10 /* ms */
#define I2C_PM_TIMEOUT 1000 /* ms */
enum lpi2c_imx_mode {
STANDARD, /* 100+Kbps */
@ -100,7 +100,9 @@ enum lpi2c_imx_pincfg {
struct lpi2c_imx_struct {
struct i2c_adapter adapter;
struct clk *clk;
int irq;
struct clk *clk_per;
struct clk *clk_ipg;
void __iomem *base;
__u8 *rx_buf;
__u8 *tx_buf;
@ -213,7 +215,12 @@ static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx)
lpi2c_imx_set_mode(lpi2c_imx);
clk_rate = clk_get_rate(lpi2c_imx->clk);
clk_rate = clk_get_rate(lpi2c_imx->clk_per);
if (!clk_rate) {
dev_dbg(&lpi2c_imx->adapter.dev, "clk_per rate is 0\n");
return -EINVAL;
}
if (lpi2c_imx->mode == HS || lpi2c_imx->mode == ULTRA_FAST)
filt = 0;
else
@ -513,15 +520,17 @@ static irqreturn_t lpi2c_imx_isr(int irq, void *dev_id)
lpi2c_imx_intctrl(lpi2c_imx, 0);
temp = readl(lpi2c_imx->base + LPI2C_MSR);
if (temp & MSR_NDF) {
complete(&lpi2c_imx->complete);
goto ret;
}
if (temp & MSR_RDF)
lpi2c_imx_read_rxfifo(lpi2c_imx);
if (temp & MSR_TDF)
else if (temp & MSR_TDF)
lpi2c_imx_write_txfifo(lpi2c_imx);
if (temp & MSR_NDF)
complete(&lpi2c_imx->complete);
ret:
return IRQ_HANDLED;
}
@ -546,7 +555,7 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
{
struct lpi2c_imx_struct *lpi2c_imx;
unsigned int temp;
int irq, ret;
int ret;
lpi2c_imx = devm_kzalloc(&pdev->dev, sizeof(*lpi2c_imx), GFP_KERNEL);
if (!lpi2c_imx)
@ -556,10 +565,10 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
if (IS_ERR(lpi2c_imx->base))
return PTR_ERR(lpi2c_imx->base);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
lpi2c_imx->irq = platform_get_irq(pdev, 0);
if (lpi2c_imx->irq < 0) {
dev_err(&pdev->dev, "can't get irq number\n");
return irq;
return lpi2c_imx->irq;
}
lpi2c_imx->adapter.owner = THIS_MODULE;
@ -569,10 +578,16 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
strlcpy(lpi2c_imx->adapter.name, pdev->name,
sizeof(lpi2c_imx->adapter.name));
lpi2c_imx->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(lpi2c_imx->clk)) {
lpi2c_imx->clk_per = devm_clk_get(&pdev->dev, "per");
if (IS_ERR(lpi2c_imx->clk_per)) {
dev_err(&pdev->dev, "can't get I2C peripheral clock\n");
return PTR_ERR(lpi2c_imx->clk);
return PTR_ERR(lpi2c_imx->clk_per);
}
lpi2c_imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(lpi2c_imx->clk_ipg)) {
dev_err(&pdev->dev, "can't get I2C ipg clock\n");
return PTR_ERR(lpi2c_imx->clk_ipg);
}
ret = of_property_read_u32(pdev->dev.of_node,
@ -580,45 +595,29 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
if (ret)
lpi2c_imx->bitrate = LPI2C_DEFAULT_RATE;
ret = devm_request_irq(&pdev->dev, irq, lpi2c_imx_isr, 0,
pdev->name, lpi2c_imx);
if (ret) {
dev_err(&pdev->dev, "can't claim irq %d\n", irq);
return ret;
}
i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx);
platform_set_drvdata(pdev, lpi2c_imx);
ret = clk_prepare_enable(lpi2c_imx->clk);
if (ret) {
dev_err(&pdev->dev, "clk enable failed %d\n", ret);
return ret;
}
pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT);
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_get_noresume(&pdev->dev);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
temp = readl(lpi2c_imx->base + LPI2C_PARAM);
lpi2c_imx->txfifosize = 1 << (temp & 0x0f);
lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f);
pm_runtime_put(&pdev->dev);
ret = i2c_add_adapter(&lpi2c_imx->adapter);
if (ret)
goto rpm_disable;
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
dev_info(&lpi2c_imx->adapter.dev, "LPI2C adapter registered\n");
return 0;
rpm_disable:
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
@ -641,8 +640,10 @@ static int __maybe_unused lpi2c_runtime_suspend(struct device *dev)
{
struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev);
clk_disable_unprepare(lpi2c_imx->clk);
pinctrl_pm_select_sleep_state(dev);
devm_free_irq(dev, lpi2c_imx->irq, lpi2c_imx);
clk_disable_unprepare(lpi2c_imx->clk_ipg);
clk_disable_unprepare(lpi2c_imx->clk_per);
pinctrl_pm_select_idle_state(dev);
return 0;
}
@ -653,18 +654,50 @@ static int __maybe_unused lpi2c_runtime_resume(struct device *dev)
int ret;
pinctrl_pm_select_default_state(dev);
ret = clk_prepare_enable(lpi2c_imx->clk);
ret = clk_prepare_enable(lpi2c_imx->clk_per);
if (ret) {
dev_err(dev, "failed to enable I2C clock, ret=%d\n", ret);
dev_err(dev, "can't enable I2C per clock, ret=%d\n", ret);
return ret;
}
ret = clk_prepare_enable(lpi2c_imx->clk_ipg);
if (ret) {
clk_disable_unprepare(lpi2c_imx->clk_per);
dev_err(dev, "can't enable I2C ipg clock, ret=%d\n", ret);
}
ret = devm_request_irq(dev, lpi2c_imx->irq, lpi2c_imx_isr,
IRQF_NO_SUSPEND,
dev_name(dev), lpi2c_imx);
if (ret) {
dev_err(dev, "can't claim irq %d\n", lpi2c_imx->irq);
return ret;
}
return ret;
}
static int lpi2c_suspend_noirq(struct device *dev)
{
int ret;
ret = pm_runtime_force_suspend(dev);
if (ret)
return ret;
pinctrl_pm_select_sleep_state(dev);
return 0;
}
static int lpi2c_resume_noirq(struct device *dev)
{
return pm_runtime_force_resume(dev);
}
static const struct dev_pm_ops lpi2c_pm_ops = {
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(lpi2c_suspend_noirq,
lpi2c_resume_noirq)
SET_RUNTIME_PM_OPS(lpi2c_runtime_suspend,
lpi2c_runtime_resume, NULL)
};
@ -679,7 +712,17 @@ static struct platform_driver lpi2c_imx_driver = {
},
};
module_platform_driver(lpi2c_imx_driver);
static int __init lpi2c_imx_init(void)
{
return platform_driver_register(&lpi2c_imx_driver);
}
subsys_initcall(lpi2c_imx_init);
static void __exit lpi2c_imx_exit(void)
{
platform_driver_unregister(&lpi2c_imx_driver);
}
module_exit(lpi2c_imx_exit);
MODULE_AUTHOR("Gao Pan <pandy.gao@nxp.com>");
MODULE_DESCRIPTION("I2C adapter driver for LPI2C bus");

View File

@ -39,18 +39,25 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_dma.h>
#include <linux/of_gpio.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_data/i2c-imx.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_address.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/libata.h>
/* This will be the driver name the kernel reports */
#define DRIVER_NAME "imx-i2c"
/* Default value */
#define IMX_I2C_BIT_RATE 100000 /* 100kHz */
#define IMX_I2C_MAX_E_BIT_RATE 384000 /* 384kHz from e7805 errata*/
/*
* Enable DMA if transfer byte size is bigger than this threshold.
@ -107,8 +114,56 @@
#define I2CR_IEN_OPCODE_0 0x0
#define I2CR_IEN_OPCODE_1 I2CR_IEN
#define I2C_PM_TIMEOUT 10 /* ms */
#define I2C_PM_TIMEOUT 1000 /* ms */
enum pinmux_endian_type {
BIG_ENDIAN,
LITTLE_ENDIAN,
};
struct pinmux_cfg {
enum pinmux_endian_type endian; /* endian of RCWPMUXCR0 */
u32 pmuxcr_offset;
u32 pmuxcr_set_bit; /* pin mux of RCWPMUXCR0 */
};
static struct pinmux_cfg ls1012a_pinmux_cfg = {
.endian = BIG_ENDIAN,
.pmuxcr_offset = 0x430,
.pmuxcr_set_bit = 0x10,
};
static struct pinmux_cfg ls1043a_pinmux_cfg = {
.endian = BIG_ENDIAN,
.pmuxcr_offset = 0x40C,
.pmuxcr_set_bit = 0x10,
};
static struct pinmux_cfg ls1046a_pinmux_cfg = {
.endian = BIG_ENDIAN,
.pmuxcr_offset = 0x40C,
.pmuxcr_set_bit = 0x80000000,
};
static const struct of_device_id pinmux_of_match[] = {
{ .compatible = "fsl,ls1012a-vf610-i2c", .data = &ls1012a_pinmux_cfg},
{ .compatible = "fsl,ls1043a-vf610-i2c", .data = &ls1043a_pinmux_cfg},
{ .compatible = "fsl,ls1046a-vf610-i2c", .data = &ls1046a_pinmux_cfg},
{},
};
MODULE_DEVICE_TABLE(of, pinmux_of_match);
/* The SCFG, Supplemental Configuration Unit, provides SoC specific
* configuration and status registers for the device. There is a
* SDHC IO VSEL control register on SCFG for some platforms. It's
* used to support SDHC IO voltage switching.
*/
static const struct of_device_id scfg_device_ids[] = {
{ .compatible = "fsl,ls1012a-scfg", },
{ .compatible = "fsl,ls1043a-scfg", },
{ .compatible = "fsl,ls1046a-scfg", },
{}
};
/*
* sorted list of clock divider, register value pairs
* taken from table 26-5, p.26-9, Freescale i.MX
@ -161,6 +216,7 @@ enum imx_i2c_type {
IMX1_I2C,
IMX21_I2C,
VF610_I2C,
IMX7D_I2C,
};
struct imx_i2c_hwdata {
@ -203,6 +259,15 @@ struct imx_i2c_struct {
struct pinctrl_state *pinctrl_pins_gpio;
struct imx_i2c_dma *dma;
int layerscape_bus_recover;
int gpio;
int need_set_pmuxcr;
int pmuxcr_set;
int pmuxcr_endian;
void __iomem *pmuxcr_addr;
#if IS_ENABLED(CONFIG_I2C_SLAVE)
struct i2c_client *slave;
#endif
};
static const struct imx_i2c_hwdata imx1_i2c_hwdata = {
@ -235,6 +300,16 @@ static struct imx_i2c_hwdata vf610_i2c_hwdata = {
};
static const struct imx_i2c_hwdata imx7d_i2c_hwdata = {
.devtype = IMX7D_I2C,
.regshift = IMX_I2C_REGSHIFT,
.clk_div = imx_i2c_clk_div,
.ndivs = ARRAY_SIZE(imx_i2c_clk_div),
.i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C,
.i2cr_ien_opcode = I2CR_IEN_OPCODE_1,
};
static const struct platform_device_id imx_i2c_devtype[] = {
{
.name = "imx1-i2c",
@ -252,6 +327,7 @@ static const struct of_device_id i2c_imx_dt_ids[] = {
{ .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, },
{ .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, },
{ .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, },
{ .compatible = "fsl,imx7d-i2c", .data = &imx7d_i2c_hwdata, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids);
@ -267,6 +343,11 @@ static inline int is_imx1_i2c(struct imx_i2c_struct *i2c_imx)
return i2c_imx->hwdata->devtype == IMX1_I2C;
}
static inline int is_imx7d_i2c(struct imx_i2c_struct *i2c_imx)
{
return i2c_imx->hwdata->devtype == IMX7D_I2C;
}
static inline void imx_i2c_write_reg(unsigned int val,
struct imx_i2c_struct *i2c_imx, unsigned int reg)
{
@ -279,6 +360,14 @@ static inline unsigned char imx_i2c_read_reg(struct imx_i2c_struct *i2c_imx,
return readb(i2c_imx->base + (reg << i2c_imx->hwdata->regshift));
}
/* Set up i2c controller register and i2c status register to default value. */
static void i2c_imx_reset_regs(struct imx_i2c_struct *i2c_imx)
{
imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
i2c_imx, IMX_I2C_I2CR);
imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
}
/* Functions for DMA support */
static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
dma_addr_t phy_addr)
@ -414,6 +503,14 @@ static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx)
dma->chan_using = NULL;
}
/* Clear arbitration lost bit */
static void i2c_imx_clr_al_bit(unsigned int status, struct imx_i2c_struct *i2c_imx)
{
status &= ~I2SR_IAL;
status |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IAL);
imx_i2c_write_reg(status, i2c_imx, IMX_I2C_I2SR);
}
static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
{
unsigned long orig_jiffies = jiffies;
@ -426,8 +523,7 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
/* check for arbitration lost */
if (temp & I2SR_IAL) {
temp &= ~I2SR_IAL;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
i2c_imx_clr_al_bit(temp, i2c_imx);
return -EAGAIN;
}
@ -474,16 +570,24 @@ static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx)
return 0;
}
static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
static int i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
unsigned int i2c_clk_rate)
{
struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div;
unsigned int div;
int i;
/* Divider value calculation */
if (i2c_imx->cur_clk == i2c_clk_rate)
return;
return 0;
/*
* Keep the denominator of the following program
* always NOT equal to 0.
*/
/* Divider value calculation */
if (!(i2c_clk_rate / 2))
return -EINVAL;
i2c_imx->cur_clk = i2c_clk_rate;
@ -514,20 +618,23 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,
dev_dbg(&i2c_imx->adapter.dev, "IFDR[IC]=0x%x, REAL DIV=%d\n",
i2c_clk_div[i].val, i2c_clk_div[i].div);
#endif
return 0;
}
static int i2c_imx_clk_notifier_call(struct notifier_block *nb,
unsigned long action, void *data)
{
int ret = 0;
struct clk_notifier_data *ndata = data;
struct imx_i2c_struct *i2c_imx = container_of(nb,
struct imx_i2c_struct,
clk_change_nb);
if (action & POST_RATE_CHANGE)
i2c_imx_set_clk(i2c_imx, ndata->new_rate);
ret = i2c_imx_set_clk(i2c_imx, ndata->new_rate);
return NOTIFY_OK;
return notifier_from_errno(ret);
}
static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
@ -537,6 +644,10 @@ static int i2c_imx_start(struct imx_i2c_struct *i2c_imx)
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
result = i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk));
if (result)
return result;
imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR);
/* Enable I2C controller */
imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
@ -588,23 +699,25 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx)
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
}
static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
/* Clear interrupt flag bit */
static void i2c_imx_clr_if_bit(unsigned int status, struct imx_i2c_struct *i2c_imx)
{
struct imx_i2c_struct *i2c_imx = dev_id;
unsigned int temp;
status &= ~I2SR_IIF;
status |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IIF);
imx_i2c_write_reg(status, i2c_imx, IMX_I2C_I2SR);
}
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
if (temp & I2SR_IIF) {
/* save status register */
i2c_imx->i2csr = temp;
temp &= ~I2SR_IIF;
temp |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IIF);
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
wake_up(&i2c_imx->queue);
return IRQ_HANDLED;
}
static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx)
{
unsigned int status;
return IRQ_NONE;
/* Save status register */
status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
i2c_imx->i2csr = status | I2SR_IIF;
wake_up(&i2c_imx->queue);
return IRQ_HANDLED;
}
static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
@ -890,20 +1003,119 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo
return 0;
}
/*
* Based on the I2C specification, if the data line (SDA) is
* stuck low, the master should send nine * clock pulses.
* The I2C slave device that held the bus low should release it
* sometime within * those nine clocks. Due to this erratum,
* the I2C controller cannot generate nine clock pulses.
*/
static int i2c_imx_recovery_for_layerscape(struct imx_i2c_struct *i2c_imx)
{
u32 pmuxcr = 0;
int ret;
unsigned int i, temp;
/* configure IICx_SCL/GPIO pin as a GPIO */
if (i2c_imx->need_set_pmuxcr == 1) {
pmuxcr = ioread32be(i2c_imx->pmuxcr_addr);
if (i2c_imx->pmuxcr_endian == BIG_ENDIAN)
iowrite32be(i2c_imx->pmuxcr_set|pmuxcr,
i2c_imx->pmuxcr_addr);
else
iowrite32(i2c_imx->pmuxcr_set|pmuxcr,
i2c_imx->pmuxcr_addr);
}
ret = gpio_request(i2c_imx->gpio, i2c_imx->adapter.name);
if (ret) {
dev_err(&i2c_imx->adapter.dev,
"can't get gpio: %d\n", ret);
return ret;
}
/* Configure GPIO pin as an output and open drain. */
gpio_direction_output(i2c_imx->gpio, 1);
udelay(10);
/* Write data to generate 9 pulses */
for (i = 0; i < 9; i++) {
gpio_set_value(i2c_imx->gpio, 1);
udelay(10);
gpio_set_value(i2c_imx->gpio, 0);
udelay(10);
}
/* ensure that the last level sent is always high */
gpio_set_value(i2c_imx->gpio, 1);
/*
* Set I2Cx_IBCR = 0h00 to generate a STOP
*/
imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx, IMX_I2C_I2CR);
/*
* Set I2Cx_IBCR = 0h80 to reset the I2Cx controller
*/
imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode | I2CR_IEN, i2c_imx, IMX_I2C_I2CR);
/* Restore the saved value of the register SCFG_RCWPMUXCR0 */
if (i2c_imx->need_set_pmuxcr == 1) {
if (i2c_imx->pmuxcr_endian == BIG_ENDIAN)
iowrite32be(pmuxcr, i2c_imx->pmuxcr_addr);
else
iowrite32(pmuxcr, i2c_imx->pmuxcr_addr);
}
/*
* Set I2C_IBSR[IBAL] to clear the IBAL bit if-
* I2C_IBSR[IBAL] = 1
*/
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
if (temp & I2SR_IAL)
i2c_imx_clr_al_bit(temp, i2c_imx);
return 0;
}
static int i2c_imx_xfer(struct i2c_adapter *adapter,
struct i2c_msg *msgs, int num)
{
unsigned int i, temp;
int result;
bool is_lastmsg = false;
bool enable_runtime_pm = false;
struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter);
dev_dbg(&i2c_imx->adapter.dev, "<%s>\n", __func__);
#if IS_ENABLED(CONFIG_I2C_SLAVE)
if (i2c_imx->slave) {
dev_err(&i2c_imx->adapter.dev, "Please not do operations of master mode in slave mode");
return -EBUSY;
}
#endif
if (!pm_runtime_enabled(i2c_imx->adapter.dev.parent)) {
pm_runtime_enable(i2c_imx->adapter.dev.parent);
enable_runtime_pm = true;
}
result = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
if (result < 0)
goto out;
/*
* workround for ERR010027: ensure that the I2C BUS is idle
* before switching to master mode and attempting a Start cycle
*/
result = i2c_imx_bus_busy(i2c_imx, 0);
if (result) {
/* timeout */
if ((result == -ETIMEDOUT) && (i2c_imx->layerscape_bus_recover == 1))
i2c_imx_recovery_for_layerscape(i2c_imx);
else
goto out;
}
/* Start I2C transfer */
result = i2c_imx_start(i2c_imx);
if (result) {
@ -971,6 +1183,9 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
pm_runtime_put_autosuspend(i2c_imx->adapter.dev.parent);
out:
if (enable_runtime_pm)
pm_runtime_disable(i2c_imx->adapter.dev.parent);
dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__,
(result < 0) ? "error" : "success msg",
(result < 0) ? result : num);
@ -1042,17 +1257,216 @@ static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
return 0;
}
/*
* switch SCL and SDA to their GPIO function and do some bitbanging
* for bus recovery.
* There are platforms such as Layerscape that don't support pinctrl, so add
* workaround for layerscape, it has no effect for other platforms.
*/
static int i2c_imx_init_recovery_for_layerscape(
struct imx_i2c_struct *i2c_imx,
struct platform_device *pdev)
{
const struct of_device_id *of_id;
struct device_node *np = pdev->dev.of_node;
struct pinmux_cfg *pinmux_cfg;
struct device_node *scfg_node;
void __iomem *scfg_base = NULL;
i2c_imx->gpio = of_get_named_gpio(np, "scl-gpios", 0);
if (!gpio_is_valid(i2c_imx->gpio)) {
dev_info(&pdev->dev, "scl-gpios not found\n");
return 0;
}
pinmux_cfg = devm_kzalloc(&pdev->dev, sizeof(*pinmux_cfg), GFP_KERNEL);
if (!pinmux_cfg)
return -ENOMEM;
i2c_imx->need_set_pmuxcr = 0;
of_id = of_match_node(pinmux_of_match, np);
if (of_id) {
pinmux_cfg = (struct pinmux_cfg *)of_id->data;
i2c_imx->pmuxcr_endian = pinmux_cfg->endian;
i2c_imx->pmuxcr_set = pinmux_cfg->pmuxcr_set_bit;
scfg_node = of_find_matching_node(NULL, scfg_device_ids);
if (scfg_node) {
scfg_base = of_iomap(scfg_node, 0);
if (scfg_base) {
i2c_imx->pmuxcr_addr = scfg_base + pinmux_cfg->pmuxcr_offset;
i2c_imx->need_set_pmuxcr = 1;
}
}
}
i2c_imx->layerscape_bus_recover = 1;
return 0;
}
static u32 i2c_imx_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
| I2C_FUNC_SMBUS_READ_BLOCK_DATA;
}
#if IS_ENABLED(CONFIG_I2C_SLAVE)
static int i2c_imx_slave_init(struct imx_i2c_struct *i2c_imx)
{
int temp;
/* Resume */
temp = pm_runtime_get_sync(i2c_imx->adapter.dev.parent);
if (temp < 0) {
dev_err(&i2c_imx->adapter.dev, "failed to resume i2c controller");
return temp;
}
/* Set slave addr. */
imx_i2c_write_reg((i2c_imx->slave->addr << 1), i2c_imx, IMX_I2C_IADR);
i2c_imx_reset_regs(i2c_imx);
/* Enable module */
temp = i2c_imx->hwdata->i2cr_ien_opcode;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
/* Enable interrupt from i2c module */
temp |= I2CR_IIEN;
imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
/* Wait controller to be stable */
usleep_range(50, 150);
return 0;
}
static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx)
{
unsigned int status, ctl;
u8 value;
if (!i2c_imx->slave) {
dev_err(&i2c_imx->adapter.dev, "cannot deal with slave irq,i2c_imx->slave is null");
return IRQ_NONE;
}
status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
if (status & I2SR_IAL) { /* Arbitration lost */
i2c_imx_clr_al_bit(status, i2c_imx);
} else if (status & I2SR_IAAS) { /* Addressed as a slave */
if (status & I2SR_SRW) { /* Master wants to read from us*/
dev_dbg(&i2c_imx->adapter.dev, "read requested");
i2c_slave_event(i2c_imx->slave, I2C_SLAVE_READ_REQUESTED, &value);
/* Slave transmit */
ctl |= I2CR_MTX;
imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
/* Send data */
imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR);
} else { /* Master wants to write to us */
dev_dbg(&i2c_imx->adapter.dev, "write requested");
i2c_slave_event(i2c_imx->slave, I2C_SLAVE_WRITE_REQUESTED, &value);
/* Slave receive */
ctl &= ~I2CR_MTX;
imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
/* Dummy read */
imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
}
} else if (!(ctl & I2CR_MTX)) { /* Receive mode */
if (status & I2SR_IBB) { /* No STOP signal detected */
ctl &= ~I2CR_MTX;
imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
value = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
i2c_slave_event(i2c_imx->slave, I2C_SLAVE_WRITE_RECEIVED, &value);
} else { /* STOP signal is detected */
dev_dbg(&i2c_imx->adapter.dev,
"STOP signal detected");
i2c_slave_event(i2c_imx->slave, I2C_SLAVE_STOP, &value);
}
} else if (!(status & I2SR_RXAK)) { /* Transmit mode received ACK */
ctl |= I2CR_MTX;
imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
i2c_slave_event(i2c_imx->slave, I2C_SLAVE_READ_PROCESSED, &value);
imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR);
} else { /* Transmit mode received NAK */
ctl &= ~I2CR_MTX;
imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR);
imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
}
return IRQ_HANDLED;
}
static int i2c_imx_reg_slave(struct i2c_client *client)
{
struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(client->adapter);
int ret;
if (i2c_imx->slave)
return -EBUSY;
i2c_imx->slave = client;
ret = i2c_imx_slave_init(i2c_imx);
if (ret < 0)
dev_err(&i2c_imx->adapter.dev, "failed to switch to slave mode");
return ret;
}
static int i2c_imx_unreg_slave(struct i2c_client *client)
{
struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(client->adapter);
int ret;
if (!i2c_imx->slave)
return -EINVAL;
/* Reset slave address. */
imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
i2c_imx_reset_regs(i2c_imx);
i2c_imx->slave = NULL;
/* Suspend */
ret = pm_runtime_put_sync(i2c_imx->adapter.dev.parent);
if (ret < 0)
dev_err(&i2c_imx->adapter.dev, "failed to suspend i2c controller");
return ret;
}
#endif
static const struct i2c_algorithm i2c_imx_algo = {
.master_xfer = i2c_imx_xfer,
.functionality = i2c_imx_func,
#if IS_ENABLED(CONFIG_I2C_SLAVE)
.reg_slave = i2c_imx_reg_slave,
.unreg_slave = i2c_imx_unreg_slave,
#endif
};
static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
{
struct imx_i2c_struct *i2c_imx = dev_id;
unsigned int status;
status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
if (status & I2SR_IIF) {
i2c_imx_clr_if_bit(status, i2c_imx);
#if IS_ENABLED(CONFIG_I2C_SLAVE)
if (i2c_imx->slave)
return i2c_imx_slave_isr(i2c_imx);
#endif
return i2c_imx_master_isr(i2c_imx);
}
return IRQ_NONE;
}
static int i2c_imx_probe(struct platform_device *pdev)
{
struct imx_i2c_struct *i2c_imx;
@ -1113,7 +1527,8 @@ static int i2c_imx_probe(struct platform_device *pdev)
}
/* Request IRQ */
ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, IRQF_SHARED,
ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr,
IRQF_SHARED | IRQF_NO_SUSPEND,
pdev->name, i2c_imx);
if (ret) {
dev_err(&pdev->dev, "can't claim irq %d\n", irq);
@ -1146,15 +1561,28 @@ static int i2c_imx_probe(struct platform_device *pdev)
i2c_imx->bitrate = pdata->bitrate;
i2c_imx->clk_change_nb.notifier_call = i2c_imx_clk_notifier_call;
clk_notifier_register(i2c_imx->clk, &i2c_imx->clk_change_nb);
i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk));
ret = i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk));
if (ret < 0) {
dev_err(&pdev->dev, "can't get I2C clock\n");
goto clk_notifier_unregister;
}
/* Set up chip registers to defaults */
imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN,
i2c_imx, IMX_I2C_I2CR);
imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
/*
* This limit caused by an i.MX7D hardware issue(e7805 in Errata).
* If there is no limit, when the bitrate set up to 400KHz, it will
* cause the SCK low level period less than 1.3us.
*/
if (is_imx7d_i2c(i2c_imx) && i2c_imx->bitrate > IMX_I2C_MAX_E_BIT_RATE)
i2c_imx->bitrate = IMX_I2C_MAX_E_BIT_RATE;
i2c_imx_reset_regs(i2c_imx);
/* Init optional bus recovery */
if (of_match_node(pinmux_of_match, pdev->dev.of_node))
ret = i2c_imx_init_recovery_for_layerscape(i2c_imx, pdev);
else
ret = i2c_imx_init_recovery_info(i2c_imx, pdev);
/* Init optional bus recovery function */
ret = i2c_imx_init_recovery_info(i2c_imx, pdev);
/* Give it another chance if pinctrl used is not ready yet */
if (ret == -EPROBE_DEFER)
goto clk_notifier_unregister;
@ -1226,7 +1654,8 @@ static int __maybe_unused i2c_imx_runtime_suspend(struct device *dev)
{
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
clk_disable(i2c_imx->clk);
clk_disable_unprepare(i2c_imx->clk);
pinctrl_pm_select_sleep_state(dev);
return 0;
}
@ -1236,14 +1665,28 @@ static int __maybe_unused i2c_imx_runtime_resume(struct device *dev)
struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev);
int ret;
ret = clk_enable(i2c_imx->clk);
pinctrl_pm_select_default_state(dev);
ret = clk_prepare_enable(i2c_imx->clk);
if (ret)
dev_err(dev, "can't enable I2C clock, ret=%d\n", ret);
return ret;
}
static int i2c_imx_suspend(struct device *dev)
{
pinctrl_pm_select_sleep_state(dev);
return 0;
}
static int i2c_imx_resume(struct device *dev)
{
pinctrl_pm_select_default_state(dev);
return 0;
}
static const struct dev_pm_ops i2c_imx_pm_ops = {
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend, i2c_imx_resume)
SET_RUNTIME_PM_OPS(i2c_imx_runtime_suspend,
i2c_imx_runtime_resume, NULL)
};

View File

@ -0,0 +1,462 @@
/*
* Copyright 2019 NXP
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/* The i2c-rpmsg transfer protocol:
*
* +---------------+-------------------------------+
* | Byte Offset | Content |
* +---------------+---+---+---+---+---+---+---+---+
* | 0 | Category |
* +---------------+---+---+---+---+---+---+---+---+
* | 1 ~ 2 | Version |
* +---------------+---+---+---+---+---+---+---+---+
* | 3 | Type |
* +---------------+---+---+---+---+---+---+---+---+
* | 4 | Command |
* +---------------+---+---+---+---+---+---+---+---+
* | 5 | Priority |
* +---------------+---+---+---+---+---+---+---+---+
* | 6 | Reserved1 |
* +---------------+---+---+---+---+---+---+---+---+
* | 7 | Reserved2 |
* +---------------+---+---+---+---+---+---+---+---+
* | 8 | Reserved3 |
* +---------------+---+---+---+---+---+---+---+---+
* | 9 | Reserved4 |
* +---------------+---+---+---+---+---+---+---+---+
* | 10 | BUS ID |
* +---------------+---+---+---+---+---+---+---+---+
* | 11 | Return Value |
* +---------------+---+---+---+---+---+---+---+---+
* | 12 ~ 13 | BUS ID |
* +---------------+---+---+---+---+---+---+---+---+
* | 14 ~ 15 | Address |
* +---------------+---+---+---+---+---+---+---+---+
* | 16 ~ 17 | Data Len |
* +---------------+---+---+---+---+---+---+---+---+
* | 18 ~ 33 | 16 Bytes Data |
* +---------------+---+---+---+---+---+---+---+---+
*
* The definition of Return Value:
* 0x00 = Success
* 0x01 = Failed
* 0x02 = Invalid parameter
* 0x03 = Invalid message
* 0x04 = Operate in invalid state
* 0x05 = Memory allocation failed
* 0x06 = Timeout when waiting for an event
* 0x07 = Cannot add to list as node already in another list
* 0x08 = Cannot remove from list as node not in list
* 0x09 = Transfer timeout
* 0x0A = Transfer failed due to peer core not ready
* 0x0B = Transfer failed due to communication failure
* 0x0C = Cannot find service for a request/notification
* 0x0D = Service version cannot support the request/notification
*
*/
#include <linux/init.h>
#include <linux/io.h>
#include <linux/imx_rpmsg.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/rpmsg.h>
#define I2C_RPMSG_MAX_BUF_SIZE 16
#define I2C_RPMSG_TIMEOUT 500 /* unit: ms */
#define I2C_RPMSG_CATEGORY 0x09
#define I2C_RPMSG_VERSION 0x0001
#define I2C_RPMSG_TYPE_REQUEST 0x00
#define I2C_RPMSG_TYPE_RESPONSE 0x01
#define I2C_RPMSG_COMMAND_READ 0x00
#define I2C_RPMSG_COMMAND_WRITE 0x01
#define I2C_RPMSG_PRIORITY 0x01
#define I2C_RPMSG_M_STOP 0x0200
struct i2c_rpmsg_msg {
struct imx_rpmsg_head header;
/* Payload Start*/
u8 bus_id;
u8 ret_val;
u16 addr;
u16 flags;
u16 len;
u8 buf[I2C_RPMSG_MAX_BUF_SIZE];
} __packed __aligned(1);
struct i2c_rpmsg_info {
struct rpmsg_device *rpdev;
struct device *dev;
struct i2c_rpmsg_msg *msg;
struct completion cmd_complete;
struct mutex lock;
u8 bus_id;
u16 addr;
};
static struct i2c_rpmsg_info i2c_rpmsg;
struct imx_rpmsg_i2c_data {
struct i2c_adapter adapter;
};
static int i2c_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
void *priv, u32 src)
{
struct i2c_rpmsg_msg *msg = (struct i2c_rpmsg_msg *)data;
if (msg->header.type != I2C_RPMSG_TYPE_RESPONSE)
return -EINVAL;
if (msg->bus_id != i2c_rpmsg.bus_id || msg->addr != i2c_rpmsg.addr) {
dev_err(&rpdev->dev,
"expected bus_id:%d, addr:%2x, received bus_id:%d, addr:%2x\n",
i2c_rpmsg.bus_id, i2c_rpmsg.addr, msg->bus_id, msg->addr);
return -EINVAL;
}
if (msg->len > I2C_RPMSG_MAX_BUF_SIZE) {
dev_err(&rpdev->dev,
"%s failed: data length greater than %d, len=%d\n",
__func__, I2C_RPMSG_MAX_BUF_SIZE, msg->len);
return -EINVAL;
}
/* Receive Success */
i2c_rpmsg.msg = msg;
complete(&i2c_rpmsg.cmd_complete);
return 0;
}
static int rpmsg_xfer(struct i2c_rpmsg_msg *rmsg, struct i2c_rpmsg_info *info)
{
int ret = 0;
ret = rpmsg_send(info->rpdev->ept, (void *)rmsg,
sizeof(struct i2c_rpmsg_msg));
if (ret < 0) {
dev_err(&info->rpdev->dev, "rpmsg_send failed: %d\n", ret);
return ret;
}
ret = wait_for_completion_timeout(&info->cmd_complete,
msecs_to_jiffies(I2C_RPMSG_TIMEOUT));
if (!ret) {
dev_err(&info->rpdev->dev, "%s failed: timeout\n", __func__);
return -ETIMEDOUT;
}
if (info->msg->ret_val) {
dev_dbg(&info->rpdev->dev,
"%s failed: %d\n", __func__, info->msg->ret_val);
return -(info->msg->ret_val);
}
return 0;
}
static int i2c_rpmsg_read(struct i2c_msg *msg, struct i2c_rpmsg_info *info,
int bus_id, bool is_last)
{
int ret;
struct i2c_rpmsg_msg rmsg;
if (!info->rpdev)
return -EINVAL;
if (msg->len > I2C_RPMSG_MAX_BUF_SIZE) {
dev_err(&info->rpdev->dev,
"%s failed: data length greater than %d, len=%d\n",
__func__, I2C_RPMSG_MAX_BUF_SIZE, msg->len);
return -EINVAL;
}
memset(&rmsg, 0, sizeof(struct i2c_rpmsg_msg));
rmsg.header.cate = I2C_RPMSG_CATEGORY;
rmsg.header.major = I2C_RPMSG_VERSION;
rmsg.header.minor = I2C_RPMSG_VERSION >> 8;
rmsg.header.type = I2C_RPMSG_TYPE_REQUEST;
rmsg.header.cmd = I2C_RPMSG_COMMAND_READ;
rmsg.header.reserved[0] = I2C_RPMSG_PRIORITY;
rmsg.bus_id = bus_id;
rmsg.ret_val = 0;
rmsg.addr = msg->addr;
if (is_last)
rmsg.flags = msg->flags | I2C_RPMSG_M_STOP;
else
rmsg.flags = msg->flags;
rmsg.len = (msg->len);
reinit_completion(&info->cmd_complete);
ret = rpmsg_xfer(&rmsg, info);
if (ret)
return ret;
if (!info->msg ||
(info->msg->len != msg->len)) {
dev_err(&info->rpdev->dev,
"%s failed: %d\n", __func__, -EPROTO);
return -EPROTO;
}
memcpy(msg->buf, info->msg->buf, info->msg->len);
return msg->len;
}
int i2c_rpmsg_write(struct i2c_msg *msg, struct i2c_rpmsg_info *info,
int bus_id, bool is_last)
{
int i, ret;
struct i2c_rpmsg_msg rmsg;
if (!info || !info->rpdev)
return -EINVAL;
if (msg->len > I2C_RPMSG_MAX_BUF_SIZE) {
dev_err(&info->rpdev->dev,
"%s failed: data length greater than %d, len=%d\n",
__func__, I2C_RPMSG_MAX_BUF_SIZE, msg->len);
return -EINVAL;
}
memset(&rmsg, 0, sizeof(struct i2c_rpmsg_msg));
rmsg.header.cate = I2C_RPMSG_CATEGORY;
rmsg.header.major = I2C_RPMSG_VERSION;
rmsg.header.minor = I2C_RPMSG_VERSION >> 8;
rmsg.header.type = I2C_RPMSG_TYPE_REQUEST;
rmsg.header.cmd = I2C_RPMSG_COMMAND_WRITE;
rmsg.header.reserved[0] = I2C_RPMSG_PRIORITY;
rmsg.bus_id = bus_id;
rmsg.ret_val = 0;
rmsg.addr = msg->addr;
if (is_last)
rmsg.flags = msg->flags | I2C_RPMSG_M_STOP;
else
rmsg.flags = msg->flags;
rmsg.len = msg->len;
for (i = 0; i < rmsg.len; i++)
rmsg.buf[i] = msg->buf[i];
reinit_completion(&info->cmd_complete);
ret = rpmsg_xfer(&rmsg, info);
if (ret)
return ret;
return ret;
}
static int i2c_rpmsg_probe(struct rpmsg_device *rpdev)
{
int ret = 0;
if (!rpdev) {
dev_info(&rpdev->dev, "%s failed, rpdev=NULL\n", __func__);
return -EINVAL;
}
i2c_rpmsg.rpdev = rpdev;
mutex_init(&i2c_rpmsg.lock);
init_completion(&i2c_rpmsg.cmd_complete);
dev_info(&rpdev->dev, "new channel: 0x%x -> 0x%x!\n",
rpdev->src, rpdev->dst);
return ret;
}
static void i2c_rpmsg_remove(struct rpmsg_device *rpdev)
{
i2c_rpmsg.rpdev = NULL;
dev_info(&rpdev->dev, "i2c rpmsg driver is removed\n");
}
static struct rpmsg_device_id i2c_rpmsg_id_table[] = {
{ .name = "rpmsg-i2c-channel" },
{ },
};
static struct rpmsg_driver i2c_rpmsg_driver = {
.drv.name = "i2c-rpmsg",
.drv.owner = THIS_MODULE,
.id_table = i2c_rpmsg_id_table,
.probe = i2c_rpmsg_probe,
.remove = i2c_rpmsg_remove,
.callback = i2c_rpmsg_cb,
};
static int i2c_rpbus_xfer(struct i2c_adapter *adapter,
struct i2c_msg *msgs, int num)
{
struct imx_rpmsg_i2c_data *rdata =
container_of(adapter, struct imx_rpmsg_i2c_data, adapter);
struct i2c_msg *pmsg;
int i, ret;
bool is_last = false;
mutex_lock(&i2c_rpmsg.lock);
for (i = 0; i < num; i++) {
if (i == num - 1)
is_last = true;
pmsg = &msgs[i];
i2c_rpmsg.bus_id = rdata->adapter.nr;
i2c_rpmsg.addr = pmsg->addr;
if (pmsg->flags & I2C_M_RD) {
ret = i2c_rpmsg_read(pmsg, &i2c_rpmsg,
rdata->adapter.nr, is_last);
if (ret < 0) {
mutex_unlock(&i2c_rpmsg.lock);
return ret;
}
pmsg->len = ret;
} else {
ret = i2c_rpmsg_write(pmsg, &i2c_rpmsg,
rdata->adapter.nr, is_last);
if (ret < 0) {
mutex_unlock(&i2c_rpmsg.lock);
return ret;
}
}
}
mutex_unlock(&i2c_rpmsg.lock);
return num;
}
static u32 i2c_rpbus_func(struct i2c_adapter *a)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
| I2C_FUNC_SMBUS_READ_BLOCK_DATA;
}
static const struct i2c_algorithm i2c_rpbus_algorithm = {
.master_xfer = i2c_rpbus_xfer,
.functionality = i2c_rpbus_func,
};
static const struct i2c_adapter_quirks i2c_rpbus_quirks = {
.max_write_len = I2C_RPMSG_MAX_BUF_SIZE,
.max_read_len = I2C_RPMSG_MAX_BUF_SIZE,
};
static int i2c_rpbus_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct imx_rpmsg_i2c_data *rdata;
struct i2c_adapter *adapter;
int ret;
if (!i2c_rpmsg.rpdev)
return -EPROBE_DEFER;
rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata), GFP_KERNEL);
if (!rdata)
return -ENOMEM;
adapter = &rdata->adapter;
/* setup i2c adapter description */
adapter->owner = THIS_MODULE;
adapter->class = I2C_CLASS_HWMON;
adapter->algo = &i2c_rpbus_algorithm;
adapter->dev.parent = dev;
adapter->dev.of_node = np;
adapter->nr = of_alias_get_id(np, "i2c");
/*
* The driver will send the adapter->nr as BUS ID to the other
* side, and the other side will check the BUS ID to see whether
* the BUS has been registered. If there is alias id for this
* virtual adapter, linux kernel will automatically allocate one
* id which might be not the same number used in the other side,
* cause i2c slave probe failure under this virtual I2C bus.
* So let's add a BUG_ON to catch this issue earlier.
*/
BUG_ON(adapter->nr < 0);
adapter->quirks = &i2c_rpbus_quirks;
snprintf(rdata->adapter.name, sizeof(rdata->adapter.name), "%s",
"i2c-rpmsg-adapter");
platform_set_drvdata(pdev, rdata);
ret = i2c_add_adapter(&rdata->adapter);
if (ret < 0) {
dev_err(dev, "failed to add I2C adapter: %d\n", ret);
return ret;
}
dev_info(dev, "add I2C adapter %s successfully\n", rdata->adapter.name);
return 0;
}
static int i2c_rpbus_remove(struct platform_device *pdev)
{
struct imx_rpmsg_i2c_data *rdata = platform_get_drvdata(pdev);
i2c_del_adapter(&rdata->adapter);
return 0;
}
static const struct of_device_id imx_rpmsg_i2c_dt_ids[] = {
{ .compatible = "fsl,i2c-rpbus", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_rpmsg_i2c_dt_ids);
static struct platform_driver imx_rpmsg_i2c_driver = {
.driver = {
.name = "imx_rpmsg_i2c",
.of_match_table = imx_rpmsg_i2c_dt_ids,
},
.probe = i2c_rpbus_probe,
.remove = i2c_rpbus_remove
};
static int __init imx_rpmsg_i2c_driver_init(void)
{
int ret = 0;
ret = register_rpmsg_driver(&i2c_rpmsg_driver);
if (ret < 0)
return ret;
return platform_driver_register(&(imx_rpmsg_i2c_driver));
}
subsys_initcall(imx_rpmsg_i2c_driver_init);
MODULE_AUTHOR("Clark Wang<xiaoning.wang@nxp.com>");
MODULE_DESCRIPTION("Driver for i2c over rpmsg");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:i2c-rpbus");

View File

@ -64,6 +64,7 @@ enum pca_type {
pca_9546,
pca_9547,
pca_9548,
pca_9646,
pca_9846,
pca_9847,
pca_9848,
@ -86,7 +87,7 @@ struct pca954x {
u8 last_chan; /* last register value */
/* MUX_IDLE_AS_IS, MUX_IDLE_DISCONNECT or >= 0 for channel */
s8 idle_state;
s32 idle_state;
struct i2c_client *client;
@ -145,6 +146,11 @@ static const struct chip_desc chips[] = {
.muxtype = pca954x_isswi,
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
},
[pca_9646] = {
.nchans = 4,
.muxtype = pca954x_isswi,
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
},
[pca_9846] = {
.nchans = 4,
.muxtype = pca954x_isswi,
@ -190,6 +196,7 @@ static const struct i2c_device_id pca954x_id[] = {
{ "pca9546", pca_9546 },
{ "pca9547", pca_9547 },
{ "pca9548", pca_9548 },
{ "pca9646", pca_9646 },
{ "pca9846", pca_9846 },
{ "pca9847", pca_9847 },
{ "pca9848", pca_9848 },
@ -208,6 +215,7 @@ static const struct of_device_id pca954x_of_match[] = {
{ .compatible = "nxp,pca9546", .data = &chips[pca_9546] },
{ .compatible = "nxp,pca9547", .data = &chips[pca_9547] },
{ .compatible = "nxp,pca9548", .data = &chips[pca_9548] },
{ .compatible = "nxp,pca9646", .data = &chips[pca_9646] },
{ .compatible = "nxp,pca9846", .data = &chips[pca_9846] },
{ .compatible = "nxp,pca9847", .data = &chips[pca_9847] },
{ .compatible = "nxp,pca9848", .data = &chips[pca_9848] },
@ -229,20 +237,23 @@ static int pca954x_reg_write(struct i2c_adapter *adap,
I2C_SMBUS_BYTE, &dummy);
}
static u8 pca954x_regval(struct pca954x *data, u8 chan)
{
/* We make switches look like muxes, not sure how to be smarter. */
if (data->chip->muxtype == pca954x_ismux)
return chan | data->chip->enable;
else
return 1 << chan;
}
static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
{
struct pca954x *data = i2c_mux_priv(muxc);
struct i2c_client *client = data->client;
const struct chip_desc *chip = data->chip;
u8 regval;
int ret = 0;
/* we make switches look like muxes, not sure how to be smarter */
if (chip->muxtype == pca954x_ismux)
regval = chan | chip->enable;
else
regval = 1 << chan;
regval = pca954x_regval(data, chan);
/* Only select the channel if its different from the last channel */
if (data->last_chan != regval) {
ret = pca954x_reg_write(muxc->parent, client, regval);
@ -256,7 +267,7 @@ static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
{
struct pca954x *data = i2c_mux_priv(muxc);
struct i2c_client *client = data->client;
s8 idle_state;
s32 idle_state;
idle_state = READ_ONCE(data->idle_state);
if (idle_state >= 0)
@ -402,6 +413,22 @@ static void pca954x_cleanup(struct i2c_mux_core *muxc)
i2c_mux_del_adapters(muxc);
}
static int pca954x_init(struct i2c_client *client, struct pca954x *data)
{
int ret;
if (data->idle_state >= 0) {
data->last_chan = pca954x_regval(data, data->idle_state);
} else {
/* Disconnect multiplexer */
data->last_chan = 0;
}
ret = i2c_smbus_write_byte(client, data->last_chan);
if (ret < 0)
data->last_chan = 0;
return ret;
}
/*
* I2C init/probing/exit functions
*/
@ -411,7 +438,6 @@ static int pca954x_probe(struct i2c_client *client,
struct i2c_adapter *adap = client->adapter;
struct device *dev = &client->dev;
struct device_node *np = dev->of_node;
bool idle_disconnect_dt;
struct gpio_desc *gpio;
struct i2c_mux_core *muxc;
struct pca954x *data;
@ -462,23 +488,24 @@ static int pca954x_probe(struct i2c_client *client,
}
}
/* Write the mux register at addr to verify
data->idle_state = MUX_IDLE_AS_IS;
if (of_property_read_u32(np, "idle-state", &data->idle_state)) {
if (np && of_property_read_bool(np, "i2c-mux-idle-disconnect"))
data->idle_state = MUX_IDLE_DISCONNECT;
}
/*
* Write the mux register at addr to verify
* that the mux is in fact present. This also
* initializes the mux to disconnected state.
* initializes the mux to a channel
* or disconnected state.
*/
if (i2c_smbus_write_byte(client, 0) < 0) {
ret = pca954x_init(client, data);
if (ret < 0) {
dev_warn(dev, "probe failed\n");
return -ENODEV;
}
data->last_chan = 0; /* force the first selection */
data->idle_state = MUX_IDLE_AS_IS;
idle_disconnect_dt = np &&
of_property_read_bool(np, "i2c-mux-idle-disconnect");
if (idle_disconnect_dt)
data->idle_state = MUX_IDLE_DISCONNECT;
ret = pca954x_irq_setup(muxc);
if (ret)
goto fail_cleanup;
@ -530,9 +557,13 @@ static int pca954x_resume(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
struct pca954x *data = i2c_mux_priv(muxc);
int ret;
data->last_chan = 0;
return i2c_smbus_write_byte(client, 0);
ret = pca954x_init(client, data);
if (ret < 0)
dev_err(&client->dev, "failed to verify the mux, the mux maybe not present in fact\n");
return ret;
}
#endif