Skip to content

Commit

Permalink
Merge tag 'i2c-for-5.19' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/wsa/linux

Pull i2c updates from Wolfram Sang:
 "Only driver updates for 5.19.

  Bigger changes are for Meson, NPCM, and R-Car, but there are also
  changes all over the place"

* tag 'i2c-for-5.19' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (34 commits)
  i2c: meson: fix typo in comment
  i2c: rcar: use flags instead of atomic_xfer
  i2c: rcar: REP_AFTER_RD is not a persistent flag
  i2c: rcar: use BIT macro consistently
  i2c: qcom-geni: remove unnecessary conditions
  i2c: mt7621: Use devm_platform_get_and_ioremap_resource()
  i2c: rcar: refactor handling of first message
  i2c: rcar: avoid race condition with SMIs
  i2c: xiic: Correct the datatype for rx_watermark
  i2c: rcar: fix PM ref counts in probe error paths
  i2c: npcm: Handle spurious interrupts
  i2c: npcm: Correct register access width
  i2c: npcm: Add tx complete counter
  i2c: npcm: Fix timeout calculation
  i2c: npcm: Remove unused variable clk_regmap
  i2c: npcm: Change the way of getting GCR regmap
  i2c: xiic: Fix Tx Interrupt path for grouped messages
  i2c: xiic: Fix coding style issues
  i2c: xiic: return value of xiic_reinit
  i2c: cadence: Increase timeout per message if necessary
  ...
  • Loading branch information
torvalds committed May 31, 2022
2 parents 35b51af + 3cd4030 commit f8a52af
Show file tree
Hide file tree
Showing 15 changed files with 380 additions and 238 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ properties:
- renesas,i2c-r8a77980 # R-Car V3H
- renesas,i2c-r8a77990 # R-Car E3
- renesas,i2c-r8a77995 # R-Car D3
- renesas,i2c-r8a779a0 # R-Car V3U
- const: renesas,rcar-gen3-i2c # R-Car Gen3 and RZ/G2

- items:
- enum:
- renesas,i2c-r8a779a0 # R-Car V3U
- renesas,i2c-r8a779f0 # R-Car S4-8
- const: renesas,rcar-gen4-i2c # R-Car Gen4

Expand Down
13 changes: 8 additions & 5 deletions Documentation/i2c/writing-clients.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ driver model device node, and its I2C address.
},

.id_table = foo_idtable,
.probe = foo_probe,
.probe_new = foo_probe,
.remove = foo_remove,
/* if device autodetection is needed: */
.class = I2C_CLASS_SOMETHING,
Expand Down Expand Up @@ -155,8 +155,7 @@ those devices, and a remove() method to unbind.

::

static int foo_probe(struct i2c_client *client,
const struct i2c_device_id *id);
static int foo_probe(struct i2c_client *client);
static int foo_remove(struct i2c_client *client);

Remember that the i2c_driver does not create those client handles. The
Expand All @@ -165,8 +164,12 @@ handle may be used during foo_probe(). If foo_probe() reports success
foo_remove() returns. That binding model is used by most Linux drivers.

The probe function is called when an entry in the id_table name field
matches the device's name. It is passed the entry that was matched so
the driver knows which one in the table matched.
matches the device's name. If the probe function needs that entry, it
can retrieve it using

::

const struct i2c_device_id *id = i2c_match_id(foo_idtable, client);


Device Creation
Expand Down
11 changes: 11 additions & 0 deletions drivers/i2c/busses/i2c-at91-master.c
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
unsigned int_addr_flag = 0;
struct i2c_msg *m_start = msg;
bool is_read;
u8 *dma_buf = NULL;

dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);

Expand Down Expand Up @@ -703,7 +704,17 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
dev->msg = m_start;
dev->recv_len_abort = false;

if (dev->use_dma) {
dma_buf = i2c_get_dma_safe_msg_buf(m_start, 1);
if (!dma_buf) {
ret = -ENOMEM;
goto out;
}
dev->buf = dma_buf;
}

ret = at91_do_twi_transfer(dev);
i2c_put_dma_safe_msg_buf(dma_buf, m_start, !ret);

ret = (ret < 0) ? ret : num;
out:
Expand Down
12 changes: 10 additions & 2 deletions drivers/i2c/busses/i2c-cadence.c
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,7 @@ static void cdns_i2c_master_reset(struct i2c_adapter *adap)
static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
struct i2c_adapter *adap)
{
unsigned long time_left;
unsigned long time_left, msg_timeout;
u32 reg;

id->p_msg = msg;
Expand All @@ -785,8 +785,16 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
else
cdns_i2c_msend(id);

/* Minimal time to execute this message */
msg_timeout = msecs_to_jiffies((1000 * msg->len * BITS_PER_BYTE) / id->i2c_clk);
/* Plus some wiggle room */
msg_timeout += msecs_to_jiffies(500);

if (msg_timeout < adap->timeout)
msg_timeout = adap->timeout;

/* Wait for the signal of completion */
time_left = wait_for_completion_timeout(&id->xfer_done, adap->timeout);
time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout);
if (time_left == 0) {
cdns_i2c_master_reset(adap);
dev_err(id->adap.dev.parent,
Expand Down
12 changes: 4 additions & 8 deletions drivers/i2c/busses/i2c-davinci.c
Original file line number Diff line number Diff line change
Expand Up @@ -539,10 +539,9 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)

dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);

ret = pm_runtime_get_sync(dev->dev);
ret = pm_runtime_resume_and_get(dev->dev);
if (ret < 0) {
dev_err(dev->dev, "Failed to runtime_get device: %d\n", ret);
pm_runtime_put_noidle(dev->dev);
return ret;
}

Expand Down Expand Up @@ -821,10 +820,9 @@ static int davinci_i2c_probe(struct platform_device *pdev)

pm_runtime_enable(dev->dev);

r = pm_runtime_get_sync(dev->dev);
r = pm_runtime_resume_and_get(dev->dev);
if (r < 0) {
dev_err(dev->dev, "failed to runtime_get device: %d\n", r);
pm_runtime_put_noidle(dev->dev);
return r;
}

Expand Down Expand Up @@ -898,11 +896,9 @@ static int davinci_i2c_remove(struct platform_device *pdev)

i2c_del_adapter(&dev->adapter);

ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0) {
pm_runtime_put_noidle(&pdev->dev);
ret = pm_runtime_resume_and_get(&pdev->dev);
if (ret < 0)
return ret;
}

davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0);

Expand Down
4 changes: 2 additions & 2 deletions drivers/i2c/busses/i2c-designware-amdpsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
#define PSP_CMD_TIMEOUT_US (500 * USEC_PER_MSEC)

#define PSP_I2C_REQ_BUS_CMD 0x64
#define PSP_I2C_REQ_RETRY_CNT 10
#define PSP_I2C_REQ_RETRY_DELAY_US (50 * USEC_PER_MSEC)
#define PSP_I2C_REQ_RETRY_CNT 400
#define PSP_I2C_REQ_RETRY_DELAY_US (25 * USEC_PER_MSEC)
#define PSP_I2C_REQ_STS_OK 0x0
#define PSP_I2C_REQ_STS_BUS_BUSY 0x1
#define PSP_I2C_REQ_STS_INV_PARAM 0x3
Expand Down
2 changes: 1 addition & 1 deletion drivers/i2c/busses/i2c-designware-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,9 +266,9 @@ int i2c_dw_acpi_configure(struct device *device)
* selected speed modes.
*/
i2c_dw_acpi_params(device, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, &ss_ht);
i2c_dw_acpi_params(device, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, &fs_ht);
i2c_dw_acpi_params(device, "FPCN", &dev->fp_hcnt, &dev->fp_lcnt, &fp_ht);
i2c_dw_acpi_params(device, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt, &hs_ht);
i2c_dw_acpi_params(device, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, &fs_ht);

switch (t->bus_freq_hz) {
case I2C_MAX_STANDARD_MODE_FREQ:
Expand Down
115 changes: 85 additions & 30 deletions drivers/i2c/busses/i2c-meson.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,21 @@
#define REG_TOK_RDATA1 0x1c

/* Control register fields */
#define REG_CTRL_START BIT(0)
#define REG_CTRL_ACK_IGNORE BIT(1)
#define REG_CTRL_STATUS BIT(2)
#define REG_CTRL_ERROR BIT(3)
#define REG_CTRL_CLKDIV GENMASK(21, 12)
#define REG_CTRL_CLKDIVEXT GENMASK(29, 28)

#define REG_SLV_ADDR GENMASK(7, 0)
#define REG_SLV_SDA_FILTER GENMASK(10, 8)
#define REG_SLV_SCL_FILTER GENMASK(13, 11)
#define REG_SLV_SCL_LOW GENMASK(27, 16)
#define REG_SLV_SCL_LOW_EN BIT(28)
#define REG_CTRL_START BIT(0)
#define REG_CTRL_ACK_IGNORE BIT(1)
#define REG_CTRL_STATUS BIT(2)
#define REG_CTRL_ERROR BIT(3)
#define REG_CTRL_CLKDIV_SHIFT 12
#define REG_CTRL_CLKDIV_MASK GENMASK(21, REG_CTRL_CLKDIV_SHIFT)
#define REG_CTRL_CLKDIVEXT_SHIFT 28
#define REG_CTRL_CLKDIVEXT_MASK GENMASK(29, REG_CTRL_CLKDIVEXT_SHIFT)

#define REG_SLV_ADDR_MASK GENMASK(7, 0)
#define REG_SLV_SDA_FILTER_MASK GENMASK(10, 8)
#define REG_SLV_SCL_FILTER_MASK GENMASK(13, 11)
#define REG_SLV_SCL_LOW_SHIFT 16
#define REG_SLV_SCL_LOW_MASK GENMASK(27, REG_SLV_SCL_LOW_SHIFT)
#define REG_SLV_SCL_LOW_EN BIT(28)

#define I2C_TIMEOUT_MS 500
#define FILTER_DELAY 15
Expand All @@ -62,10 +65,6 @@ enum {
STATE_WRITE,
};

struct meson_i2c_data {
unsigned char div_factor;
};

/**
* struct meson_i2c - Meson I2C device private data
*
Expand All @@ -83,7 +82,7 @@ struct meson_i2c_data {
* @done: Completion used to wait for transfer termination
* @tokens: Sequence of tokens to be written to the device
* @num_tokens: Number of tokens
* @data: Pointer to the controlller's platform data
* @data: Pointer to the controller's platform data
*/
struct meson_i2c {
struct i2c_adapter adap;
Expand All @@ -106,6 +105,10 @@ struct meson_i2c {
const struct meson_i2c_data *data;
};

struct meson_i2c_data {
void (*set_clk_div)(struct meson_i2c *i2c, unsigned int freq);
};

static void meson_i2c_set_mask(struct meson_i2c *i2c, int reg, u32 mask,
u32 val)
{
Expand Down Expand Up @@ -134,26 +137,74 @@ static void meson_i2c_add_token(struct meson_i2c *i2c, int token)
i2c->num_tokens++;
}

static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq)
static void meson_gxbb_axg_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq)
{
unsigned long clk_rate = clk_get_rate(i2c->clk);
unsigned int div_h, div_l;

/* According to I2C-BUS Spec 2.1, in FAST-MODE, the minimum LOW period is 1.3uS, and
* minimum HIGH is least 0.6us.
* For 400000 freq, the period is 2.5us. To keep within the specs, give 40% of period to
* HIGH and 60% to LOW. This means HIGH at 1.0us and LOW 1.5us.
* The same applies for Fast-mode plus, where LOW is 0.5us and HIGH is 0.26us.
* Duty = H/(H + L) = 2/5
*/
if (freq <= I2C_MAX_STANDARD_MODE_FREQ) {
div_h = DIV_ROUND_UP(clk_rate, freq);
div_l = DIV_ROUND_UP(div_h, 4);
div_h = DIV_ROUND_UP(div_h, 2) - FILTER_DELAY;
} else {
div_h = DIV_ROUND_UP(clk_rate * 2, freq * 5) - FILTER_DELAY;
div_l = DIV_ROUND_UP(clk_rate * 3, freq * 5 * 2);
}

/* clock divider has 12 bits */
if (div_h > GENMASK(11, 0)) {
dev_err(i2c->dev, "requested bus frequency too low\n");
div_h = GENMASK(11, 0);
}
if (div_l > GENMASK(11, 0)) {
dev_err(i2c->dev, "requested bus frequency too low\n");
div_l = GENMASK(11, 0);
}

meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV_MASK,
FIELD_PREP(REG_CTRL_CLKDIV_MASK, div_h & GENMASK(9, 0)));

meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT_MASK,
FIELD_PREP(REG_CTRL_CLKDIVEXT_MASK, div_h >> 10));

/* set SCL low delay */
meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_SCL_LOW_MASK,
FIELD_PREP(REG_SLV_SCL_LOW_MASK, div_l));

/* Enable HIGH/LOW mode */
meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_SCL_LOW_EN, REG_SLV_SCL_LOW_EN);

dev_dbg(i2c->dev, "%s: clk %lu, freq %u, divh %u, divl %u\n", __func__,
clk_rate, freq, div_h, div_l);
}

static void meson6_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq)
{
unsigned long clk_rate = clk_get_rate(i2c->clk);
unsigned int div;

div = DIV_ROUND_UP(clk_rate, freq);
div -= FILTER_DELAY;
div = DIV_ROUND_UP(div, i2c->data->div_factor);
div = DIV_ROUND_UP(div, 4);

/* clock divider has 12 bits */
if (div > GENMASK(11, 0)) {
dev_err(i2c->dev, "requested bus frequency too low\n");
div = GENMASK(11, 0);
}

meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV,
FIELD_PREP(REG_CTRL_CLKDIV, div & GENMASK(9, 0)));
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV_MASK,
FIELD_PREP(REG_CTRL_CLKDIV_MASK, div & GENMASK(9, 0)));

meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT,
FIELD_PREP(REG_CTRL_CLKDIVEXT, div >> 10));
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT_MASK,
FIELD_PREP(REG_CTRL_CLKDIVEXT_MASK, div >> 10));

/* Disable HIGH/LOW mode */
meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_SCL_LOW_EN, 0);
Expand Down Expand Up @@ -292,8 +343,8 @@ static void meson_i2c_do_start(struct meson_i2c *i2c, struct i2c_msg *msg)
TOKEN_SLAVE_ADDR_WRITE;


meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_ADDR,
FIELD_PREP(REG_SLV_ADDR, msg->addr << 1));
meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_ADDR_MASK,
FIELD_PREP(REG_SLV_ADDR_MASK, msg->addr << 1));

meson_i2c_add_token(i2c, TOKEN_START);
meson_i2c_add_token(i2c, token);
Expand Down Expand Up @@ -467,9 +518,13 @@ static int meson_i2c_probe(struct platform_device *pdev)

/* Disable filtering */
meson_i2c_set_mask(i2c, REG_SLAVE_ADDR,
REG_SLV_SDA_FILTER | REG_SLV_SCL_FILTER, 0);
REG_SLV_SDA_FILTER_MASK | REG_SLV_SCL_FILTER_MASK, 0);

meson_i2c_set_clk_div(i2c, timings.bus_freq_hz);
if (!i2c->data->set_clk_div) {
clk_disable_unprepare(i2c->clk);
return -EINVAL;
}
i2c->data->set_clk_div(i2c, timings.bus_freq_hz);

ret = i2c_add_adapter(&i2c->adap);
if (ret < 0) {
Expand All @@ -491,15 +546,15 @@ static int meson_i2c_remove(struct platform_device *pdev)
}

static const struct meson_i2c_data i2c_meson6_data = {
.div_factor = 4,
.set_clk_div = meson6_i2c_set_clk_div,
};

static const struct meson_i2c_data i2c_gxbb_data = {
.div_factor = 4,
.set_clk_div = meson_gxbb_axg_i2c_set_clk_div,
};

static const struct meson_i2c_data i2c_axg_data = {
.div_factor = 3,
.set_clk_div = meson_gxbb_axg_i2c_set_clk_div,
};

static const struct of_device_id meson_i2c_match[] = {
Expand Down
Loading

0 comments on commit f8a52af

Please sign in to comment.