Commit 91962feb authored by Wolfram Sang's avatar Wolfram Sang

Merge tag 'i2c-host-6.9' of...

Merge tag 'i2c-host-6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux into i2c/for-mergewindow

The i801 and designware drivers received most of the changes,
including refactorings and some additions.

Recovery changes for the iMX and iMX-LPI2C are now utilizing the
generic i2c support.

The Cadence driver now supports system suspend and resume.

The hisi, mpc, sh_mobile, and npcm drivers have undergone some
cleanups and improvements. Meanwhile, Uwe continues his work on
converting the "remove" callback to become a void function.

The pca954x mux driver now supports additional configurations,
such as isolating faulty channels and flushing stuck buses, among
others.

Support has been added for Renesas r8a779h0, i.MX95 LPI2C, and
Microchip sam9x7. Meanwhile, Geert lays the groundwork for the
upcoming R-Car Gen4.
parents 68a04aee 06d0cb6c
......@@ -25,7 +25,9 @@ properties:
- atmel,sama5d2-i2c
- microchip,sam9x60-i2c
- items:
- const: microchip,sama7g5-i2c
- enum:
- microchip,sama7g5-i2c
- microchip,sam9x7-i2c
- const: microchip,sam9x60-i2c
reg:
......
......@@ -24,6 +24,7 @@ properties:
- fsl,imx8qm-lpi2c
- fsl,imx8ulp-lpi2c
- fsl,imx93-lpi2c
- fsl,imx95-lpi2c
- const: fsl,imx7ulp-lpi2c
reg:
......
......@@ -96,6 +96,6 @@ examples:
interrupts = <43 2>;
interrupt-parent = <&mpic>;
clock-frequency = <400000>;
i2c-scl-clk-low-timeout-us = <10000>;
i2c-transfer-timeout-us = <10000>;
};
...
......@@ -71,6 +71,23 @@ properties:
description: A voltage regulator supplying power to the chip. On PCA9846
the regulator supplies power to VDD2 (core logic) and optionally to VDD1.
maxim,isolate-stuck-channel:
type: boolean
description: Allows to use non faulty channels while a stuck channel is
isolated from the upstream bus. If not set all channels are isolated from
the upstream bus until the fault is cleared.
maxim,send-flush-out-sequence:
type: boolean
description: Send a flush-out sequence to stuck auxiliary buses
automatically after a stuck channel is being detected.
maxim,preconnection-wiggle-test-enable:
type: boolean
description: Send a STOP condition to the auxiliary buses when the switch
register activates a channel to detect a stuck high fault. On fault the
channel is isolated from the upstream bus.
required:
- compatible
- reg
......@@ -95,6 +112,19 @@ allOf:
"#interrupt-cells": false
interrupt-controller: false
- if:
not:
properties:
compatible:
contains:
enum:
- maxim,max7357
then:
properties:
maxim,isolate-stuck-channel: false
maxim,send-flush-out-sequence: false
maxim,preconnection-wiggle-test-enable: false
unevaluatedProperties: false
examples:
......
......@@ -53,6 +53,7 @@ properties:
- renesas,i2c-r8a779a0 # R-Car V3U
- renesas,i2c-r8a779f0 # R-Car S4-8
- renesas,i2c-r8a779g0 # R-Car V4H
- renesas,i2c-r8a779h0 # R-Car V4M
- const: renesas,rcar-gen4-i2c # R-Car Gen4
reg:
......
......@@ -1235,7 +1235,7 @@ config I2C_RCAR
depends on ARCH_RENESAS || COMPILE_TEST
select I2C_SLAVE
select I2C_SMBUS
select RESET_CONTROLLER if ARCH_RCAR_GEN3
select RESET_CONTROLLER if ARCH_RCAR_GEN3 || ARCH_RCAR_GEN4
help
If you say yes to this option, support will be included for the
R-Car I2C controller.
......
......@@ -1176,6 +1176,18 @@ static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev)
return 0;
}
static int __maybe_unused cdns_i2c_suspend(struct device *dev)
{
struct cdns_i2c *xi2c = dev_get_drvdata(dev);
i2c_mark_adapter_suspended(&xi2c->adap);
if (!pm_runtime_status_suspended(dev))
return cdns_i2c_runtime_suspend(dev);
return 0;
}
/**
* cdns_i2c_init - Controller initialisation
* @id: Device private data structure
......@@ -1219,7 +1231,28 @@ static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev)
return 0;
}
static int __maybe_unused cdns_i2c_resume(struct device *dev)
{
struct cdns_i2c *xi2c = dev_get_drvdata(dev);
int err;
err = cdns_i2c_runtime_resume(dev);
if (err)
return err;
if (pm_runtime_status_suspended(dev)) {
err = cdns_i2c_runtime_suspend(dev);
if (err)
return err;
}
i2c_mark_adapter_resumed(&xi2c->adap);
return 0;
}
static const struct dev_pm_ops cdns_i2c_dev_pm_ops = {
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cdns_i2c_suspend, cdns_i2c_resume)
SET_RUNTIME_PM_OPS(cdns_i2c_runtime_suspend,
cdns_i2c_runtime_resume, NULL)
};
......
......@@ -648,7 +648,7 @@ void i2c_dw_disable(struct dw_i2c_dev *dev)
__i2c_dw_disable(dev);
/* Disable all interrupts */
regmap_write(dev->map, DW_IC_INTR_MASK, 0);
__i2c_dw_write_intr_mask(dev, 0);
regmap_read(dev->map, DW_IC_CLR_INTR, &dummy);
i2c_dw_release_lock(dev);
......
......@@ -212,6 +212,7 @@ struct reset_control;
* @msg_err: error status of the current transfer
* @status: i2c master status, one of STATUS_*
* @abort_source: copy of the TX_ABRT_SOURCE register
* @sw_mask: SW mask of DW_IC_INTR_MASK used in polling mode
* @irq: interrupt number for the i2c master
* @flags: platform specific flags like type of IO accessors or model
* @adapter: i2c subsystem adapter node
......@@ -270,6 +271,7 @@ struct dw_i2c_dev {
int msg_err;
unsigned int status;
unsigned int abort_source;
unsigned int sw_mask;
int irq;
u32 flags;
struct i2c_adapter adapter;
......@@ -303,6 +305,7 @@ struct dw_i2c_dev {
#define ACCESS_INTR_MASK BIT(0)
#define ACCESS_NO_IRQ_SUSPEND BIT(1)
#define ARBITRATION_SEMAPHORE BIT(2)
#define ACCESS_POLLING BIT(3)
#define MODEL_MSCC_OCELOT BIT(8)
#define MODEL_BAIKAL_BT1 BIT(9)
......@@ -318,7 +321,7 @@ struct dw_i2c_dev {
#define AMD_UCSI_INTR_EN 0xd
#define TXGBE_TX_FIFO_DEPTH 4
#define TXGBE_RX_FIFO_DEPTH 0
#define TXGBE_RX_FIFO_DEPTH 1
struct i2c_dw_semaphore_callbacks {
int (*probe)(struct dw_i2c_dev *dev);
......@@ -351,6 +354,24 @@ static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev)
dev->status &= ~STATUS_ACTIVE;
}
static inline void __i2c_dw_write_intr_mask(struct dw_i2c_dev *dev,
unsigned int intr_mask)
{
unsigned int val = dev->flags & ACCESS_POLLING ? 0 : intr_mask;
regmap_write(dev->map, DW_IC_INTR_MASK, val);
dev->sw_mask = intr_mask;
}
static inline void __i2c_dw_read_intr_mask(struct dw_i2c_dev *dev,
unsigned int *intr_mask)
{
if (!(dev->flags & ACCESS_POLLING))
regmap_read(dev->map, DW_IC_INTR_MASK, intr_mask);
else
*intr_mask = dev->sw_mask;
}
void __i2c_dw_disable(struct dw_i2c_dev *dev);
extern void i2c_dw_configure_master(struct dw_i2c_dev *dev);
......
This diff is collapsed.
......@@ -154,7 +154,7 @@ static int navi_amd_setup(struct pci_dev *pdev, struct dw_pci_controller *c)
{
struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev);
dev->flags |= MODEL_AMD_NAVI_GPU;
dev->flags |= MODEL_AMD_NAVI_GPU | ACCESS_POLLING;
dev->timings.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ;
return 0;
}
......
......@@ -290,7 +290,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
dev->flags = (uintptr_t)device_get_match_data(&pdev->dev);
if (device_property_present(&pdev->dev, "wx,i2c-snps-model"))
dev->flags = MODEL_WANGXUN_SP;
dev->flags = MODEL_WANGXUN_SP | ACCESS_POLLING;
dev->dev = &pdev->dev;
dev->irq = irq;
......
......@@ -57,6 +57,8 @@
#define HISI_I2C_FS_SPK_LEN_CNT GENMASK(7, 0)
#define HISI_I2C_HS_SPK_LEN 0x003c
#define HISI_I2C_HS_SPK_LEN_CNT GENMASK(7, 0)
#define HISI_I2C_TX_INT_CLR 0x0040
#define HISI_I2C_TX_AEMPTY_INT BIT(0)
#define HISI_I2C_INT_MSTAT 0x0044
#define HISI_I2C_INT_CLR 0x0048
#define HISI_I2C_INT_MASK 0x004C
......@@ -124,6 +126,11 @@ static void hisi_i2c_clear_int(struct hisi_i2c_controller *ctlr, u32 mask)
writel_relaxed(mask, ctlr->iobase + HISI_I2C_INT_CLR);
}
static void hisi_i2c_clear_tx_int(struct hisi_i2c_controller *ctlr, u32 mask)
{
writel_relaxed(mask, ctlr->iobase + HISI_I2C_TX_INT_CLR);
}
static void hisi_i2c_handle_errors(struct hisi_i2c_controller *ctlr)
{
u32 int_err = ctlr->xfer_err, reg;
......@@ -168,6 +175,7 @@ static int hisi_i2c_start_xfer(struct hisi_i2c_controller *ctlr)
writel(reg, ctlr->iobase + HISI_I2C_FIFO_CTRL);
hisi_i2c_clear_int(ctlr, HISI_I2C_INT_ALL);
hisi_i2c_clear_tx_int(ctlr, HISI_I2C_TX_AEMPTY_INT);
hisi_i2c_enable_int(ctlr, HISI_I2C_INT_ALL);
return 0;
......@@ -266,7 +274,7 @@ static int hisi_i2c_read_rx_fifo(struct hisi_i2c_controller *ctlr)
static void hisi_i2c_xfer_msg(struct hisi_i2c_controller *ctlr)
{
int max_write = HISI_I2C_TX_FIFO_DEPTH;
int max_write = HISI_I2C_TX_FIFO_DEPTH - HISI_I2C_TX_F_AE_THRESH;
bool need_restart = false, last_msg;
struct i2c_msg *cur_msg;
u32 cmd, fifo_state;
......@@ -323,6 +331,8 @@ static void hisi_i2c_xfer_msg(struct hisi_i2c_controller *ctlr)
*/
if (ctlr->msg_tx_idx == ctlr->msg_num)
hisi_i2c_disable_int(ctlr, HISI_I2C_INT_TX_EMPTY);
hisi_i2c_clear_tx_int(ctlr, HISI_I2C_TX_AEMPTY_INT);
}
static irqreturn_t hisi_i2c_irq(int irq, void *context)
......@@ -363,6 +373,7 @@ static irqreturn_t hisi_i2c_irq(int irq, void *context)
if (int_stat & HISI_I2C_INT_TRANS_CPLT) {
hisi_i2c_disable_int(ctlr, HISI_I2C_INT_ALL);
hisi_i2c_clear_int(ctlr, HISI_I2C_INT_ALL);
hisi_i2c_clear_tx_int(ctlr, HISI_I2C_TX_AEMPTY_INT);
complete(ctlr->completion);
}
......
This diff is collapsed.
......@@ -106,6 +106,7 @@ struct lpi2c_imx_struct {
unsigned int txfifosize;
unsigned int rxfifosize;
enum lpi2c_imx_mode mode;
struct i2c_bus_recovery_info rinfo;
};
static void lpi2c_imx_intctrl(struct lpi2c_imx_struct *lpi2c_imx,
......@@ -133,6 +134,8 @@ static int lpi2c_imx_bus_busy(struct lpi2c_imx_struct *lpi2c_imx)
if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
dev_dbg(&lpi2c_imx->adapter.dev, "bus not work\n");
if (lpi2c_imx->adapter.bus_recovery_info)
i2c_recover_bus(&lpi2c_imx->adapter);
return -ETIMEDOUT;
}
schedule();
......@@ -190,6 +193,8 @@ static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx)
if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
dev_dbg(&lpi2c_imx->adapter.dev, "stop timeout\n");
if (lpi2c_imx->adapter.bus_recovery_info)
i2c_recover_bus(&lpi2c_imx->adapter);
break;
}
schedule();
......@@ -325,6 +330,8 @@ static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx)
if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) {
dev_dbg(&lpi2c_imx->adapter.dev, "txfifo empty timeout\n");
if (lpi2c_imx->adapter.bus_recovery_info)
i2c_recover_bus(&lpi2c_imx->adapter);
return -ETIMEDOUT;
}
schedule();
......@@ -526,6 +533,20 @@ static irqreturn_t lpi2c_imx_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int lpi2c_imx_init_recovery_info(struct lpi2c_imx_struct *lpi2c_imx,
struct platform_device *pdev)
{
struct i2c_bus_recovery_info *bri = &lpi2c_imx->rinfo;
bri->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(bri->pinctrl))
return PTR_ERR(bri->pinctrl);
lpi2c_imx->adapter.bus_recovery_info = bri;
return 0;
}
static u32 lpi2c_imx_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
......@@ -600,6 +621,12 @@ static int lpi2c_imx_probe(struct platform_device *pdev)
lpi2c_imx->txfifosize = 1 << (temp & 0x0f);
lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f);
/* Init optional bus recovery function */
ret = lpi2c_imx_init_recovery_info(lpi2c_imx, pdev);
/* Give it another chance if pinctrl used is not ready yet */
if (ret == -EPROBE_DEFER)
goto rpm_disable;
ret = i2c_add_adapter(&lpi2c_imx->adapter);
if (ret)
goto rpm_disable;
......
......@@ -212,10 +212,6 @@ struct imx_i2c_struct {
const struct imx_i2c_hwdata *hwdata;
struct i2c_bus_recovery_info rinfo;
struct pinctrl *pinctrl;
struct pinctrl_state *pinctrl_pins_default;
struct pinctrl_state *pinctrl_pins_gpio;
struct imx_i2c_dma *dma;
struct i2c_client *slave;
enum i2c_slave_event last_slave_event;
......@@ -1357,24 +1353,6 @@ static int i2c_imx_xfer_atomic(struct i2c_adapter *adapter,
return result;
}
static void i2c_imx_prepare_recovery(struct i2c_adapter *adap)
{
struct imx_i2c_struct *i2c_imx;
i2c_imx = container_of(adap, struct imx_i2c_struct, adapter);
pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_gpio);
}
static void i2c_imx_unprepare_recovery(struct i2c_adapter *adap)
{
struct imx_i2c_struct *i2c_imx;
i2c_imx = container_of(adap, struct imx_i2c_struct, adapter);
pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_default);
}
/*
* We switch SCL and SDA to their GPIO function and do some bitbanging
* for bus recovery. These alternative pinmux settings can be
......@@ -1385,43 +1363,13 @@ static void i2c_imx_unprepare_recovery(struct i2c_adapter *adap)
static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
struct platform_device *pdev)
{
struct i2c_bus_recovery_info *rinfo = &i2c_imx->rinfo;
i2c_imx->pinctrl = devm_pinctrl_get(&pdev->dev);
if (!i2c_imx->pinctrl) {
dev_info(&pdev->dev, "pinctrl unavailable, bus recovery not supported\n");
return 0;
}
if (IS_ERR(i2c_imx->pinctrl)) {
dev_info(&pdev->dev, "can't get pinctrl, bus recovery not supported\n");
return PTR_ERR(i2c_imx->pinctrl);
}
i2c_imx->pinctrl_pins_default = pinctrl_lookup_state(i2c_imx->pinctrl,
PINCTRL_STATE_DEFAULT);
i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl,
"gpio");
rinfo->sda_gpiod = devm_gpiod_get_optional(&pdev->dev, "sda", GPIOD_IN);
rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", GPIOD_OUT_HIGH_OPEN_DRAIN);
if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER ||
PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER) {
return -EPROBE_DEFER;
} else if (IS_ERR(rinfo->sda_gpiod) ||
IS_ERR(rinfo->scl_gpiod) ||
IS_ERR(i2c_imx->pinctrl_pins_default) ||
IS_ERR(i2c_imx->pinctrl_pins_gpio)) {
dev_dbg(&pdev->dev, "recovery information incomplete\n");
return 0;
}
struct i2c_bus_recovery_info *bri = &i2c_imx->rinfo;
dev_dbg(&pdev->dev, "using scl%s for recovery\n",
rinfo->sda_gpiod ? ",sda" : "");
bri->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(bri->pinctrl))
return PTR_ERR(bri->pinctrl);
rinfo->prepare_recovery = i2c_imx_prepare_recovery;
rinfo->unprepare_recovery = i2c_imx_unprepare_recovery;
rinfo->recover_bus = i2c_generic_scl_recovery;
i2c_imx->adapter.bus_recovery_info = rinfo;
i2c_imx->adapter.bus_recovery_info = bri;
return 0;
}
......
......@@ -30,8 +30,6 @@
#include <asm/mpc85xx.h>
#include <sysdev/fsl_soc.h>
#define DRV_NAME "mpc-i2c"
#define MPC_I2C_CLOCK_LEGACY 0
#define MPC_I2C_CLOCK_PRESERVE (~0U)
......@@ -844,14 +842,14 @@ static int fsl_i2c_probe(struct platform_device *op)
mpc_i2c_setup_8xxx(op->dev.of_node, i2c, clock);
}
/*
* "fsl,timeout" has been marked as deprecated and, to maintain
* backward compatibility, we will only look for it if
* "i2c-scl-clk-low-timeout-us" is not present.
*/
/* Sadly, we have to support two deprecated bindings here */
result = of_property_read_u32(op->dev.of_node,
"i2c-scl-clk-low-timeout-us",
"i2c-transfer-timeout-us",
&mpc_ops.timeout);
if (result == -EINVAL)
result = of_property_read_u32(op->dev.of_node,
"i2c-scl-clk-low-timeout-us",
&mpc_ops.timeout);
if (result == -EINVAL)
result = of_property_read_u32(op->dev.of_node,
"fsl,timeout", &mpc_ops.timeout);
......@@ -960,7 +958,7 @@ static struct platform_driver mpc_i2c_driver = {
.probe = fsl_i2c_probe,
.remove_new = fsl_i2c_remove,
.driver = {
.name = DRV_NAME,
.name = "mpc-i2c",
.of_match_table = mpc_i2c_of_match,
.pm = &mpc_i2c_pm_ops,
},
......
......@@ -1264,9 +1264,6 @@ static int npcm_i2c_reg_slave(struct i2c_client *client)
bus->slave = client;
if (!bus->slave)
return -EINVAL;
if (client->flags & I2C_CLIENT_TEN)
return -EAFNOSUPPORT;
......
......@@ -773,7 +773,7 @@ static int sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd)
iic_wr(pd, ICCR, ICCR_TRS);
udelay(10);
return sh_mobile_i2c_init(pd);
return sh_mobile_i2c_v2_init(pd);
}
static const struct sh_mobile_dt_config default_dt_config = {
......@@ -782,11 +782,6 @@ static const struct sh_mobile_dt_config default_dt_config = {
};
static const struct sh_mobile_dt_config fast_clock_dt_config = {
.clks_per_count = 2,
.setup = sh_mobile_i2c_init,
};
static const struct sh_mobile_dt_config v2_freq_calc_dt_config = {
.clks_per_count = 2,
.setup = sh_mobile_i2c_v2_init,
};
......@@ -799,17 +794,17 @@ static const struct sh_mobile_dt_config r8a7740_dt_config = {
static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
{ .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7740", .data = &r8a7740_dt_config },
{ .compatible = "renesas,iic-r8a774c0", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,iic-r8a7790", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,iic-r8a7791", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,iic-r8a7792", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,iic-r8a7793", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,iic-r8a7794", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,iic-r8a7795", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,iic-r8a77990", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,iic-r8a774c0", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7790", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7791", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7792", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7793", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7794", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7795", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a77990", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-sh73a0", .data = &fast_clock_dt_config },
{ .compatible = "renesas,rcar-gen2-iic", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,rcar-gen3-iic", .data = &v2_freq_calc_dt_config },
{ .compatible = "renesas,rcar-gen2-iic", .data = &fast_clock_dt_config },
{ .compatible = "renesas,rcar-gen3-iic", .data = &fast_clock_dt_config },
{ .compatible = "renesas,rmobile-iic", .data = &default_dt_config },
{},
};
......
......@@ -570,7 +570,7 @@ static int sprd_i2c_probe(struct platform_device *pdev)
return ret;
}
static int sprd_i2c_remove(struct platform_device *pdev)
static void sprd_i2c_remove(struct platform_device *pdev)
{
struct sprd_i2c *i2c_dev = platform_get_drvdata(pdev);
int ret;
......@@ -586,8 +586,6 @@ static int sprd_i2c_remove(struct platform_device *pdev)
pm_runtime_put_noidle(i2c_dev->dev);
pm_runtime_disable(i2c_dev->dev);
return 0;
}
static int __maybe_unused sprd_i2c_suspend_noirq(struct device *dev)
......@@ -645,7 +643,7 @@ MODULE_DEVICE_TABLE(of, sprd_i2c_of_match);
static struct platform_driver sprd_i2c_driver = {
.probe = sprd_i2c_probe,
.remove = sprd_i2c_remove,
.remove_new = sprd_i2c_remove,
.driver = {
.name = "sprd-i2c",
.of_match_table = sprd_i2c_of_match,
......
......@@ -57,6 +57,20 @@
#define PCA954X_IRQ_OFFSET 4
/*
* MAX7357's configuration register is writeable after POR, but
* can be locked by setting the basic mode bit. MAX7358 configuration
* register is locked by default and needs to be unlocked first.
* The configuration register holds the following settings:
*/
#define MAX7357_CONF_INT_ENABLE BIT(0)
#define MAX7357_CONF_FLUSH_OUT BIT(1)
#define MAX7357_CONF_RELEASE_INT BIT(2)
#define MAX7357_CONF_DISCON_SINGLE_CHAN BIT(4)
#define MAX7357_CONF_PRECONNECT_TEST BIT(7)
#define MAX7357_POR_DEFAULT_CONF MAX7357_CONF_INT_ENABLE
enum pca_type {
max_7356,
max_7357,
......@@ -470,7 +484,34 @@ static int pca954x_init(struct i2c_client *client, struct pca954x *data)
else
data->last_chan = 0; /* Disconnect multiplexer */
ret = i2c_smbus_write_byte(client, data->last_chan);
if (device_is_compatible(&client->dev, "maxim,max7357")) {
if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
u8 conf = MAX7357_POR_DEFAULT_CONF;
/*
* The interrupt signal is shared with the reset pin. Release the
* interrupt after 1.6 seconds to allow using the pin as reset.
*/
conf |= MAX7357_CONF_RELEASE_INT;
if (device_property_read_bool(&client->dev, "maxim,isolate-stuck-channel"))
conf |= MAX7357_CONF_DISCON_SINGLE_CHAN;
if (device_property_read_bool(&client->dev,
"maxim,send-flush-out-sequence"))
conf |= MAX7357_CONF_FLUSH_OUT;
if (device_property_read_bool(&client->dev,
"maxim,preconnection-wiggle-test-enable"))
conf |= MAX7357_CONF_PRECONNECT_TEST;
ret = i2c_smbus_write_byte_data(client, data->last_chan, conf);
} else {
dev_warn(&client->dev, "Write byte data not supported."
"Cannot enable enhanced mode features\n");
ret = i2c_smbus_write_byte(client, data->last_chan);
}
} else {
ret = i2c_smbus_write_byte(client, data->last_chan);
}
if (ret < 0)
data->last_chan = 0;
......
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