mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
Merge tag 'i2c-for-5.19' of git://git.kernel.org/pub/scm/linux/kernel/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 ...
This commit is contained in:
@@ -46,11 +46,11 @@ properties:
|
|||||||
- renesas,i2c-r8a77980 # R-Car V3H
|
- renesas,i2c-r8a77980 # R-Car V3H
|
||||||
- renesas,i2c-r8a77990 # R-Car E3
|
- renesas,i2c-r8a77990 # R-Car E3
|
||||||
- renesas,i2c-r8a77995 # R-Car D3
|
- renesas,i2c-r8a77995 # R-Car D3
|
||||||
- renesas,i2c-r8a779a0 # R-Car V3U
|
|
||||||
- const: renesas,rcar-gen3-i2c # R-Car Gen3 and RZ/G2
|
- const: renesas,rcar-gen3-i2c # R-Car Gen3 and RZ/G2
|
||||||
|
|
||||||
- items:
|
- items:
|
||||||
- enum:
|
- enum:
|
||||||
|
- renesas,i2c-r8a779a0 # R-Car V3U
|
||||||
- renesas,i2c-r8a779f0 # R-Car S4-8
|
- renesas,i2c-r8a779f0 # R-Car S4-8
|
||||||
- const: renesas,rcar-gen4-i2c # R-Car Gen4
|
- const: renesas,rcar-gen4-i2c # R-Car Gen4
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ driver model device node, and its I2C address.
|
|||||||
},
|
},
|
||||||
|
|
||||||
.id_table = foo_idtable,
|
.id_table = foo_idtable,
|
||||||
.probe = foo_probe,
|
.probe_new = foo_probe,
|
||||||
.remove = foo_remove,
|
.remove = foo_remove,
|
||||||
/* if device autodetection is needed: */
|
/* if device autodetection is needed: */
|
||||||
.class = I2C_CLASS_SOMETHING,
|
.class = I2C_CLASS_SOMETHING,
|
||||||
@@ -155,8 +155,7 @@ those devices, and a remove() method to unbind.
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
static int foo_probe(struct i2c_client *client,
|
static int foo_probe(struct i2c_client *client);
|
||||||
const struct i2c_device_id *id);
|
|
||||||
static int foo_remove(struct i2c_client *client);
|
static int foo_remove(struct i2c_client *client);
|
||||||
|
|
||||||
Remember that the i2c_driver does not create those client handles. The
|
Remember that the i2c_driver does not create those client handles. The
|
||||||
@@ -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.
|
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
|
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
|
matches the device's name. If the probe function needs that entry, it
|
||||||
the driver knows which one in the table matched.
|
can retrieve it using
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
const struct i2c_device_id *id = i2c_match_id(foo_idtable, client);
|
||||||
|
|
||||||
|
|
||||||
Device Creation
|
Device Creation
|
||||||
|
|||||||
@@ -656,6 +656,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
|
|||||||
unsigned int_addr_flag = 0;
|
unsigned int_addr_flag = 0;
|
||||||
struct i2c_msg *m_start = msg;
|
struct i2c_msg *m_start = msg;
|
||||||
bool is_read;
|
bool is_read;
|
||||||
|
u8 *dma_buf = NULL;
|
||||||
|
|
||||||
dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
|
dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num);
|
||||||
|
|
||||||
@@ -703,7 +704,17 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
|
|||||||
dev->msg = m_start;
|
dev->msg = m_start;
|
||||||
dev->recv_len_abort = false;
|
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);
|
ret = at91_do_twi_transfer(dev);
|
||||||
|
i2c_put_dma_safe_msg_buf(dma_buf, m_start, !ret);
|
||||||
|
|
||||||
ret = (ret < 0) ? ret : num;
|
ret = (ret < 0) ? ret : num;
|
||||||
out:
|
out:
|
||||||
|
|||||||
@@ -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,
|
static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
|
||||||
struct i2c_adapter *adap)
|
struct i2c_adapter *adap)
|
||||||
{
|
{
|
||||||
unsigned long time_left;
|
unsigned long time_left, msg_timeout;
|
||||||
u32 reg;
|
u32 reg;
|
||||||
|
|
||||||
id->p_msg = msg;
|
id->p_msg = msg;
|
||||||
@@ -785,8 +785,16 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
|
|||||||
else
|
else
|
||||||
cdns_i2c_msend(id);
|
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 */
|
/* 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) {
|
if (time_left == 0) {
|
||||||
cdns_i2c_master_reset(adap);
|
cdns_i2c_master_reset(adap);
|
||||||
dev_err(id->adap.dev.parent,
|
dev_err(id->adap.dev.parent,
|
||||||
|
|||||||
@@ -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);
|
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) {
|
if (ret < 0) {
|
||||||
dev_err(dev->dev, "Failed to runtime_get device: %d\n", ret);
|
dev_err(dev->dev, "Failed to runtime_get device: %d\n", ret);
|
||||||
pm_runtime_put_noidle(dev->dev);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -821,10 +820,9 @@ static int davinci_i2c_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
pm_runtime_enable(dev->dev);
|
pm_runtime_enable(dev->dev);
|
||||||
|
|
||||||
r = pm_runtime_get_sync(dev->dev);
|
r = pm_runtime_resume_and_get(dev->dev);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
dev_err(dev->dev, "failed to runtime_get device: %d\n", r);
|
dev_err(dev->dev, "failed to runtime_get device: %d\n", r);
|
||||||
pm_runtime_put_noidle(dev->dev);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -898,11 +896,9 @@ static int davinci_i2c_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
i2c_del_adapter(&dev->adapter);
|
i2c_del_adapter(&dev->adapter);
|
||||||
|
|
||||||
ret = pm_runtime_get_sync(&pdev->dev);
|
ret = pm_runtime_resume_and_get(&pdev->dev);
|
||||||
if (ret < 0) {
|
if (ret < 0)
|
||||||
pm_runtime_put_noidle(&pdev->dev);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0);
|
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0);
|
||||||
|
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
#define PSP_CMD_TIMEOUT_US (500 * USEC_PER_MSEC)
|
#define PSP_CMD_TIMEOUT_US (500 * USEC_PER_MSEC)
|
||||||
|
|
||||||
#define PSP_I2C_REQ_BUS_CMD 0x64
|
#define PSP_I2C_REQ_BUS_CMD 0x64
|
||||||
#define PSP_I2C_REQ_RETRY_CNT 10
|
#define PSP_I2C_REQ_RETRY_CNT 400
|
||||||
#define PSP_I2C_REQ_RETRY_DELAY_US (50 * USEC_PER_MSEC)
|
#define PSP_I2C_REQ_RETRY_DELAY_US (25 * USEC_PER_MSEC)
|
||||||
#define PSP_I2C_REQ_STS_OK 0x0
|
#define PSP_I2C_REQ_STS_OK 0x0
|
||||||
#define PSP_I2C_REQ_STS_BUS_BUSY 0x1
|
#define PSP_I2C_REQ_STS_BUS_BUSY 0x1
|
||||||
#define PSP_I2C_REQ_STS_INV_PARAM 0x3
|
#define PSP_I2C_REQ_STS_INV_PARAM 0x3
|
||||||
|
|||||||
@@ -266,9 +266,9 @@ int i2c_dw_acpi_configure(struct device *device)
|
|||||||
* selected speed modes.
|
* selected speed modes.
|
||||||
*/
|
*/
|
||||||
i2c_dw_acpi_params(device, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, &ss_ht);
|
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, "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, "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) {
|
switch (t->bus_freq_hz) {
|
||||||
case I2C_MAX_STANDARD_MODE_FREQ:
|
case I2C_MAX_STANDARD_MODE_FREQ:
|
||||||
|
|||||||
@@ -30,18 +30,21 @@
|
|||||||
#define REG_TOK_RDATA1 0x1c
|
#define REG_TOK_RDATA1 0x1c
|
||||||
|
|
||||||
/* Control register fields */
|
/* Control register fields */
|
||||||
#define REG_CTRL_START BIT(0)
|
#define REG_CTRL_START BIT(0)
|
||||||
#define REG_CTRL_ACK_IGNORE BIT(1)
|
#define REG_CTRL_ACK_IGNORE BIT(1)
|
||||||
#define REG_CTRL_STATUS BIT(2)
|
#define REG_CTRL_STATUS BIT(2)
|
||||||
#define REG_CTRL_ERROR BIT(3)
|
#define REG_CTRL_ERROR BIT(3)
|
||||||
#define REG_CTRL_CLKDIV GENMASK(21, 12)
|
#define REG_CTRL_CLKDIV_SHIFT 12
|
||||||
#define REG_CTRL_CLKDIVEXT GENMASK(29, 28)
|
#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 GENMASK(7, 0)
|
#define REG_SLV_ADDR_MASK GENMASK(7, 0)
|
||||||
#define REG_SLV_SDA_FILTER GENMASK(10, 8)
|
#define REG_SLV_SDA_FILTER_MASK GENMASK(10, 8)
|
||||||
#define REG_SLV_SCL_FILTER GENMASK(13, 11)
|
#define REG_SLV_SCL_FILTER_MASK GENMASK(13, 11)
|
||||||
#define REG_SLV_SCL_LOW GENMASK(27, 16)
|
#define REG_SLV_SCL_LOW_SHIFT 16
|
||||||
#define REG_SLV_SCL_LOW_EN BIT(28)
|
#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 I2C_TIMEOUT_MS 500
|
||||||
#define FILTER_DELAY 15
|
#define FILTER_DELAY 15
|
||||||
@@ -62,10 +65,6 @@ enum {
|
|||||||
STATE_WRITE,
|
STATE_WRITE,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct meson_i2c_data {
|
|
||||||
unsigned char div_factor;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct meson_i2c - Meson I2C device private data
|
* struct meson_i2c - Meson I2C device private data
|
||||||
*
|
*
|
||||||
@@ -83,7 +82,7 @@ struct meson_i2c_data {
|
|||||||
* @done: Completion used to wait for transfer termination
|
* @done: Completion used to wait for transfer termination
|
||||||
* @tokens: Sequence of tokens to be written to the device
|
* @tokens: Sequence of tokens to be written to the device
|
||||||
* @num_tokens: Number of tokens
|
* @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 meson_i2c {
|
||||||
struct i2c_adapter adap;
|
struct i2c_adapter adap;
|
||||||
@@ -106,6 +105,10 @@ struct meson_i2c {
|
|||||||
const struct meson_i2c_data *data;
|
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,
|
static void meson_i2c_set_mask(struct meson_i2c *i2c, int reg, u32 mask,
|
||||||
u32 val)
|
u32 val)
|
||||||
{
|
{
|
||||||
@@ -134,14 +137,62 @@ static void meson_i2c_add_token(struct meson_i2c *i2c, int token)
|
|||||||
i2c->num_tokens++;
|
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 long clk_rate = clk_get_rate(i2c->clk);
|
||||||
unsigned int div;
|
unsigned int div;
|
||||||
|
|
||||||
div = DIV_ROUND_UP(clk_rate, freq);
|
div = DIV_ROUND_UP(clk_rate, freq);
|
||||||
div -= FILTER_DELAY;
|
div -= FILTER_DELAY;
|
||||||
div = DIV_ROUND_UP(div, i2c->data->div_factor);
|
div = DIV_ROUND_UP(div, 4);
|
||||||
|
|
||||||
/* clock divider has 12 bits */
|
/* clock divider has 12 bits */
|
||||||
if (div > GENMASK(11, 0)) {
|
if (div > GENMASK(11, 0)) {
|
||||||
@@ -149,11 +200,11 @@ static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq)
|
|||||||
div = GENMASK(11, 0);
|
div = GENMASK(11, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV,
|
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV_MASK,
|
||||||
FIELD_PREP(REG_CTRL_CLKDIV, div & GENMASK(9, 0)));
|
FIELD_PREP(REG_CTRL_CLKDIV_MASK, div & GENMASK(9, 0)));
|
||||||
|
|
||||||
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT,
|
meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT_MASK,
|
||||||
FIELD_PREP(REG_CTRL_CLKDIVEXT, div >> 10));
|
FIELD_PREP(REG_CTRL_CLKDIVEXT_MASK, div >> 10));
|
||||||
|
|
||||||
/* Disable HIGH/LOW mode */
|
/* Disable HIGH/LOW mode */
|
||||||
meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_SCL_LOW_EN, 0);
|
meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_SCL_LOW_EN, 0);
|
||||||
@@ -292,8 +343,8 @@ static void meson_i2c_do_start(struct meson_i2c *i2c, struct i2c_msg *msg)
|
|||||||
TOKEN_SLAVE_ADDR_WRITE;
|
TOKEN_SLAVE_ADDR_WRITE;
|
||||||
|
|
||||||
|
|
||||||
meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_ADDR,
|
meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_ADDR_MASK,
|
||||||
FIELD_PREP(REG_SLV_ADDR, msg->addr << 1));
|
FIELD_PREP(REG_SLV_ADDR_MASK, msg->addr << 1));
|
||||||
|
|
||||||
meson_i2c_add_token(i2c, TOKEN_START);
|
meson_i2c_add_token(i2c, TOKEN_START);
|
||||||
meson_i2c_add_token(i2c, token);
|
meson_i2c_add_token(i2c, token);
|
||||||
@@ -467,9 +518,13 @@ static int meson_i2c_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
/* Disable filtering */
|
/* Disable filtering */
|
||||||
meson_i2c_set_mask(i2c, REG_SLAVE_ADDR,
|
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);
|
ret = i2c_add_adapter(&i2c->adap);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@@ -491,15 +546,15 @@ static int meson_i2c_remove(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct meson_i2c_data i2c_meson6_data = {
|
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 = {
|
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 = {
|
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[] = {
|
static const struct of_device_id meson_i2c_match[] = {
|
||||||
|
|||||||
@@ -1177,7 +1177,7 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
|
|||||||
int left_num = num;
|
int left_num = num;
|
||||||
struct mtk_i2c *i2c = i2c_get_adapdata(adap);
|
struct mtk_i2c *i2c = i2c_get_adapdata(adap);
|
||||||
|
|
||||||
ret = clk_bulk_prepare_enable(I2C_MT65XX_CLK_MAX, i2c->clocks);
|
ret = clk_bulk_enable(I2C_MT65XX_CLK_MAX, i2c->clocks);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -1231,7 +1231,7 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap,
|
|||||||
ret = num;
|
ret = num;
|
||||||
|
|
||||||
err_exit:
|
err_exit:
|
||||||
clk_bulk_disable_unprepare(I2C_MT65XX_CLK_MAX, i2c->clocks);
|
clk_bulk_disable(I2C_MT65XX_CLK_MAX, i2c->clocks);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1412,7 +1412,7 @@ static int mtk_i2c_probe(struct platform_device *pdev)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
mtk_i2c_init_hw(i2c);
|
mtk_i2c_init_hw(i2c);
|
||||||
clk_bulk_disable_unprepare(I2C_MT65XX_CLK_MAX, i2c->clocks);
|
clk_bulk_disable(I2C_MT65XX_CLK_MAX, i2c->clocks);
|
||||||
|
|
||||||
ret = devm_request_irq(&pdev->dev, irq, mtk_i2c_irq,
|
ret = devm_request_irq(&pdev->dev, irq, mtk_i2c_irq,
|
||||||
IRQF_NO_SUSPEND | IRQF_TRIGGER_NONE,
|
IRQF_NO_SUSPEND | IRQF_TRIGGER_NONE,
|
||||||
@@ -1439,6 +1439,8 @@ static int mtk_i2c_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
i2c_del_adapter(&i2c->adap);
|
i2c_del_adapter(&i2c->adap);
|
||||||
|
|
||||||
|
clk_bulk_unprepare(I2C_MT65XX_CLK_MAX, i2c->clocks);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1448,6 +1450,7 @@ static int mtk_i2c_suspend_noirq(struct device *dev)
|
|||||||
struct mtk_i2c *i2c = dev_get_drvdata(dev);
|
struct mtk_i2c *i2c = dev_get_drvdata(dev);
|
||||||
|
|
||||||
i2c_mark_adapter_suspended(&i2c->adap);
|
i2c_mark_adapter_suspended(&i2c->adap);
|
||||||
|
clk_bulk_unprepare(I2C_MT65XX_CLK_MAX, i2c->clocks);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1465,7 +1468,7 @@ static int mtk_i2c_resume_noirq(struct device *dev)
|
|||||||
|
|
||||||
mtk_i2c_init_hw(i2c);
|
mtk_i2c_init_hw(i2c);
|
||||||
|
|
||||||
clk_bulk_disable_unprepare(I2C_MT65XX_CLK_MAX, i2c->clocks);
|
clk_bulk_disable(I2C_MT65XX_CLK_MAX, i2c->clocks);
|
||||||
|
|
||||||
i2c_mark_adapter_resumed(&i2c->adap);
|
i2c_mark_adapter_resumed(&i2c->adap);
|
||||||
|
|
||||||
|
|||||||
@@ -270,18 +270,15 @@ static void mtk_i2c_init(struct mtk_i2c *i2c)
|
|||||||
|
|
||||||
static int mtk_i2c_probe(struct platform_device *pdev)
|
static int mtk_i2c_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct resource *res;
|
|
||||||
struct mtk_i2c *i2c;
|
struct mtk_i2c *i2c;
|
||||||
struct i2c_adapter *adap;
|
struct i2c_adapter *adap;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
||||||
|
|
||||||
i2c = devm_kzalloc(&pdev->dev, sizeof(struct mtk_i2c), GFP_KERNEL);
|
i2c = devm_kzalloc(&pdev->dev, sizeof(struct mtk_i2c), GFP_KERNEL);
|
||||||
if (!i2c)
|
if (!i2c)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
i2c->base = devm_ioremap_resource(&pdev->dev, res);
|
i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
|
||||||
if (IS_ERR(i2c->base))
|
if (IS_ERR(i2c->base))
|
||||||
return PTR_ERR(i2c->base);
|
return PTR_ERR(i2c->base);
|
||||||
|
|
||||||
|
|||||||
@@ -314,6 +314,7 @@ struct npcm_i2c {
|
|||||||
u64 rec_fail_cnt;
|
u64 rec_fail_cnt;
|
||||||
u64 nack_cnt;
|
u64 nack_cnt;
|
||||||
u64 timeout_cnt;
|
u64 timeout_cnt;
|
||||||
|
u64 tx_complete_cnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void npcm_i2c_select_bank(struct npcm_i2c *bus,
|
static inline void npcm_i2c_select_bank(struct npcm_i2c *bus,
|
||||||
@@ -359,14 +360,14 @@ static int npcm_i2c_get_SCL(struct i2c_adapter *_adap)
|
|||||||
{
|
{
|
||||||
struct npcm_i2c *bus = container_of(_adap, struct npcm_i2c, adap);
|
struct npcm_i2c *bus = container_of(_adap, struct npcm_i2c, adap);
|
||||||
|
|
||||||
return !!(I2CCTL3_SCL_LVL & ioread32(bus->reg + NPCM_I2CCTL3));
|
return !!(I2CCTL3_SCL_LVL & ioread8(bus->reg + NPCM_I2CCTL3));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int npcm_i2c_get_SDA(struct i2c_adapter *_adap)
|
static int npcm_i2c_get_SDA(struct i2c_adapter *_adap)
|
||||||
{
|
{
|
||||||
struct npcm_i2c *bus = container_of(_adap, struct npcm_i2c, adap);
|
struct npcm_i2c *bus = container_of(_adap, struct npcm_i2c, adap);
|
||||||
|
|
||||||
return !!(I2CCTL3_SDA_LVL & ioread32(bus->reg + NPCM_I2CCTL3));
|
return !!(I2CCTL3_SDA_LVL & ioread8(bus->reg + NPCM_I2CCTL3));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u16 npcm_i2c_get_index(struct npcm_i2c *bus)
|
static inline u16 npcm_i2c_get_index(struct npcm_i2c *bus)
|
||||||
@@ -563,6 +564,15 @@ static inline void npcm_i2c_nack(struct npcm_i2c *bus)
|
|||||||
iowrite8(val, bus->reg + NPCM_I2CCTL1);
|
iowrite8(val, bus->reg + NPCM_I2CCTL1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void npcm_i2c_clear_master_status(struct npcm_i2c *bus)
|
||||||
|
{
|
||||||
|
u8 val;
|
||||||
|
|
||||||
|
/* Clear NEGACK, STASTR and BER bits */
|
||||||
|
val = NPCM_I2CST_BER | NPCM_I2CST_NEGACK | NPCM_I2CST_STASTR;
|
||||||
|
iowrite8(val, bus->reg + NPCM_I2CST);
|
||||||
|
}
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||||
static void npcm_i2c_slave_int_enable(struct npcm_i2c *bus, bool enable)
|
static void npcm_i2c_slave_int_enable(struct npcm_i2c *bus, bool enable)
|
||||||
{
|
{
|
||||||
@@ -642,8 +652,8 @@ static void npcm_i2c_reset(struct npcm_i2c *bus)
|
|||||||
iowrite8(NPCM_I2CCST_BB, bus->reg + NPCM_I2CCST);
|
iowrite8(NPCM_I2CCST_BB, bus->reg + NPCM_I2CCST);
|
||||||
iowrite8(0xFF, bus->reg + NPCM_I2CST);
|
iowrite8(0xFF, bus->reg + NPCM_I2CST);
|
||||||
|
|
||||||
/* Clear EOB bit */
|
/* Clear and disable EOB */
|
||||||
iowrite8(NPCM_I2CCST3_EO_BUSY, bus->reg + NPCM_I2CCST3);
|
npcm_i2c_eob_int(bus, false);
|
||||||
|
|
||||||
/* Clear all fifo bits: */
|
/* Clear all fifo bits: */
|
||||||
iowrite8(NPCM_I2CFIF_CTS_CLR_FIFO, bus->reg + NPCM_I2CFIF_CTS);
|
iowrite8(NPCM_I2CFIF_CTS_CLR_FIFO, bus->reg + NPCM_I2CFIF_CTS);
|
||||||
@@ -655,6 +665,9 @@ static void npcm_i2c_reset(struct npcm_i2c *bus)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* clear status bits for spurious interrupts */
|
||||||
|
npcm_i2c_clear_master_status(bus);
|
||||||
|
|
||||||
bus->state = I2C_IDLE;
|
bus->state = I2C_IDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -684,6 +697,8 @@ static void npcm_i2c_callback(struct npcm_i2c *bus,
|
|||||||
switch (op_status) {
|
switch (op_status) {
|
||||||
case I2C_MASTER_DONE_IND:
|
case I2C_MASTER_DONE_IND:
|
||||||
bus->cmd_err = bus->msgs_num;
|
bus->cmd_err = bus->msgs_num;
|
||||||
|
if (bus->tx_complete_cnt < ULLONG_MAX)
|
||||||
|
bus->tx_complete_cnt++;
|
||||||
fallthrough;
|
fallthrough;
|
||||||
case I2C_BLOCK_BYTES_ERR_IND:
|
case I2C_BLOCK_BYTES_ERR_IND:
|
||||||
/* Master tx finished and all transmit bytes were sent */
|
/* Master tx finished and all transmit bytes were sent */
|
||||||
@@ -815,15 +830,6 @@ static void npcm_i2c_read_fifo(struct npcm_i2c *bus, u8 bytes_in_fifo)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void npcm_i2c_clear_master_status(struct npcm_i2c *bus)
|
|
||||||
{
|
|
||||||
u8 val;
|
|
||||||
|
|
||||||
/* Clear NEGACK, STASTR and BER bits */
|
|
||||||
val = NPCM_I2CST_BER | NPCM_I2CST_NEGACK | NPCM_I2CST_STASTR;
|
|
||||||
iowrite8(val, bus->reg + NPCM_I2CST);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void npcm_i2c_master_abort(struct npcm_i2c *bus)
|
static void npcm_i2c_master_abort(struct npcm_i2c *bus)
|
||||||
{
|
{
|
||||||
/* Only current master is allowed to issue a stop condition */
|
/* Only current master is allowed to issue a stop condition */
|
||||||
@@ -1231,7 +1237,16 @@ static irqreturn_t npcm_i2c_int_slave_handler(struct npcm_i2c *bus)
|
|||||||
ret = IRQ_HANDLED;
|
ret = IRQ_HANDLED;
|
||||||
} /* SDAST */
|
} /* SDAST */
|
||||||
|
|
||||||
return ret;
|
/*
|
||||||
|
* if irq is not one of the above, make sure EOB is disabled and all
|
||||||
|
* status bits are cleared.
|
||||||
|
*/
|
||||||
|
if (ret == IRQ_NONE) {
|
||||||
|
npcm_i2c_eob_int(bus, false);
|
||||||
|
npcm_i2c_clear_master_status(bus);
|
||||||
|
}
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int npcm_i2c_reg_slave(struct i2c_client *client)
|
static int npcm_i2c_reg_slave(struct i2c_client *client)
|
||||||
@@ -1467,6 +1482,9 @@ static void npcm_i2c_irq_handle_nack(struct npcm_i2c *bus)
|
|||||||
npcm_i2c_eob_int(bus, false);
|
npcm_i2c_eob_int(bus, false);
|
||||||
npcm_i2c_master_stop(bus);
|
npcm_i2c_master_stop(bus);
|
||||||
|
|
||||||
|
/* Clear SDA Status bit (by reading dummy byte) */
|
||||||
|
npcm_i2c_rd_byte(bus);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The bus is released from stall only after the SW clears
|
* The bus is released from stall only after the SW clears
|
||||||
* NEGACK bit. Then a Stop condition is sent.
|
* NEGACK bit. Then a Stop condition is sent.
|
||||||
@@ -1474,6 +1492,8 @@ static void npcm_i2c_irq_handle_nack(struct npcm_i2c *bus)
|
|||||||
npcm_i2c_clear_master_status(bus);
|
npcm_i2c_clear_master_status(bus);
|
||||||
readx_poll_timeout_atomic(ioread8, bus->reg + NPCM_I2CCST, val,
|
readx_poll_timeout_atomic(ioread8, bus->reg + NPCM_I2CCST, val,
|
||||||
!(val & NPCM_I2CCST_BUSY), 10, 200);
|
!(val & NPCM_I2CCST_BUSY), 10, 200);
|
||||||
|
/* verify no status bits are still set after bus is released */
|
||||||
|
npcm_i2c_clear_master_status(bus);
|
||||||
}
|
}
|
||||||
bus->state = I2C_IDLE;
|
bus->state = I2C_IDLE;
|
||||||
|
|
||||||
@@ -1672,10 +1692,10 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap)
|
|||||||
int iter = 27;
|
int iter = 27;
|
||||||
|
|
||||||
if ((npcm_i2c_get_SDA(_adap) == 1) && (npcm_i2c_get_SCL(_adap) == 1)) {
|
if ((npcm_i2c_get_SDA(_adap) == 1) && (npcm_i2c_get_SCL(_adap) == 1)) {
|
||||||
dev_dbg(bus->dev, "bus%d recovery skipped, bus not stuck",
|
dev_dbg(bus->dev, "bus%d-0x%x recovery skipped, bus not stuck",
|
||||||
bus->num);
|
bus->num, bus->dest_addr);
|
||||||
npcm_i2c_reset(bus);
|
npcm_i2c_reset(bus);
|
||||||
return status;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
npcm_i2c_int_enable(bus, false);
|
npcm_i2c_int_enable(bus, false);
|
||||||
@@ -1909,6 +1929,7 @@ static int npcm_i2c_init_module(struct npcm_i2c *bus, enum i2c_mode mode,
|
|||||||
bus_freq_hz < I2C_FREQ_MIN_HZ || bus_freq_hz > I2C_FREQ_MAX_HZ)
|
bus_freq_hz < I2C_FREQ_MIN_HZ || bus_freq_hz > I2C_FREQ_MAX_HZ)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
npcm_i2c_int_enable(bus, false);
|
||||||
npcm_i2c_disable(bus);
|
npcm_i2c_disable(bus);
|
||||||
|
|
||||||
/* Configure FIFO mode : */
|
/* Configure FIFO mode : */
|
||||||
@@ -1937,10 +1958,17 @@ static int npcm_i2c_init_module(struct npcm_i2c *bus, enum i2c_mode mode,
|
|||||||
val = (val | NPCM_I2CCTL1_NMINTE) & ~NPCM_I2CCTL1_RWS;
|
val = (val | NPCM_I2CCTL1_NMINTE) & ~NPCM_I2CCTL1_RWS;
|
||||||
iowrite8(val, bus->reg + NPCM_I2CCTL1);
|
iowrite8(val, bus->reg + NPCM_I2CCTL1);
|
||||||
|
|
||||||
npcm_i2c_int_enable(bus, true);
|
|
||||||
|
|
||||||
npcm_i2c_reset(bus);
|
npcm_i2c_reset(bus);
|
||||||
|
|
||||||
|
/* check HW is OK: SDA and SCL should be high at this point. */
|
||||||
|
if ((npcm_i2c_get_SDA(&bus->adap) == 0) || (npcm_i2c_get_SCL(&bus->adap) == 0)) {
|
||||||
|
dev_err(bus->dev, "I2C%d init fail: lines are low\n", bus->num);
|
||||||
|
dev_err(bus->dev, "SDA=%d SCL=%d\n", npcm_i2c_get_SDA(&bus->adap),
|
||||||
|
npcm_i2c_get_SCL(&bus->adap));
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
npcm_i2c_int_enable(bus, true);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1988,10 +2016,14 @@ static irqreturn_t npcm_i2c_bus_irq(int irq, void *dev_id)
|
|||||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||||
if (bus->slave) {
|
if (bus->slave) {
|
||||||
bus->master_or_slave = I2C_SLAVE;
|
bus->master_or_slave = I2C_SLAVE;
|
||||||
return npcm_i2c_int_slave_handler(bus);
|
if (npcm_i2c_int_slave_handler(bus))
|
||||||
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return IRQ_NONE;
|
/* clear status bits for spurious interrupts */
|
||||||
|
npcm_i2c_clear_master_status(bus);
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool npcm_i2c_master_start_xmit(struct npcm_i2c *bus,
|
static bool npcm_i2c_master_start_xmit(struct npcm_i2c *bus,
|
||||||
@@ -2047,8 +2079,7 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
|||||||
u16 nwrite, nread;
|
u16 nwrite, nread;
|
||||||
u8 *write_data, *read_data;
|
u8 *write_data, *read_data;
|
||||||
u8 slave_addr;
|
u8 slave_addr;
|
||||||
int timeout;
|
unsigned long timeout;
|
||||||
int ret = 0;
|
|
||||||
bool read_block = false;
|
bool read_block = false;
|
||||||
bool read_PEC = false;
|
bool read_PEC = false;
|
||||||
u8 bus_busy;
|
u8 bus_busy;
|
||||||
@@ -2099,13 +2130,13 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
|||||||
* 9: bits per transaction (including the ack/nack)
|
* 9: bits per transaction (including the ack/nack)
|
||||||
*/
|
*/
|
||||||
timeout_usec = (2 * 9 * USEC_PER_SEC / bus->bus_freq) * (2 + nread + nwrite);
|
timeout_usec = (2 * 9 * USEC_PER_SEC / bus->bus_freq) * (2 + nread + nwrite);
|
||||||
timeout = max(msecs_to_jiffies(35), usecs_to_jiffies(timeout_usec));
|
timeout = max_t(unsigned long, bus->adap.timeout, usecs_to_jiffies(timeout_usec));
|
||||||
if (nwrite >= 32 * 1024 || nread >= 32 * 1024) {
|
if (nwrite >= 32 * 1024 || nread >= 32 * 1024) {
|
||||||
dev_err(bus->dev, "i2c%d buffer too big\n", bus->num);
|
dev_err(bus->dev, "i2c%d buffer too big\n", bus->num);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
time_left = jiffies + msecs_to_jiffies(DEFAULT_STALL_COUNT) + 1;
|
time_left = jiffies + timeout + 1;
|
||||||
do {
|
do {
|
||||||
/*
|
/*
|
||||||
* we must clear slave address immediately when the bus is not
|
* we must clear slave address immediately when the bus is not
|
||||||
@@ -2138,12 +2169,12 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
|||||||
bus->read_block_use = read_block;
|
bus->read_block_use = read_block;
|
||||||
|
|
||||||
reinit_completion(&bus->cmd_complete);
|
reinit_completion(&bus->cmd_complete);
|
||||||
if (!npcm_i2c_master_start_xmit(bus, slave_addr, nwrite, nread,
|
|
||||||
write_data, read_data, read_PEC,
|
|
||||||
read_block))
|
|
||||||
ret = -EBUSY;
|
|
||||||
|
|
||||||
if (ret != -EBUSY) {
|
npcm_i2c_int_enable(bus, true);
|
||||||
|
|
||||||
|
if (npcm_i2c_master_start_xmit(bus, slave_addr, nwrite, nread,
|
||||||
|
write_data, read_data, read_PEC,
|
||||||
|
read_block)) {
|
||||||
time_left = wait_for_completion_timeout(&bus->cmd_complete,
|
time_left = wait_for_completion_timeout(&bus->cmd_complete,
|
||||||
timeout);
|
timeout);
|
||||||
|
|
||||||
@@ -2157,26 +2188,31 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret = bus->cmd_err;
|
|
||||||
|
|
||||||
/* if there was BER, check if need to recover the bus: */
|
/* if there was BER, check if need to recover the bus: */
|
||||||
if (bus->cmd_err == -EAGAIN)
|
if (bus->cmd_err == -EAGAIN)
|
||||||
ret = i2c_recover_bus(adap);
|
bus->cmd_err = i2c_recover_bus(adap);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* After any type of error, check if LAST bit is still set,
|
* After any type of error, check if LAST bit is still set,
|
||||||
* due to a HW issue.
|
* due to a HW issue.
|
||||||
* It cannot be cleared without resetting the module.
|
* It cannot be cleared without resetting the module.
|
||||||
*/
|
*/
|
||||||
if (bus->cmd_err &&
|
else if (bus->cmd_err &&
|
||||||
(NPCM_I2CRXF_CTL_LAST_PEC & ioread8(bus->reg + NPCM_I2CRXF_CTL)))
|
(NPCM_I2CRXF_CTL_LAST_PEC & ioread8(bus->reg + NPCM_I2CRXF_CTL)))
|
||||||
npcm_i2c_reset(bus);
|
npcm_i2c_reset(bus);
|
||||||
|
|
||||||
|
/* after any xfer, successful or not, stall and EOB must be disabled */
|
||||||
|
npcm_i2c_stall_after_start(bus, false);
|
||||||
|
npcm_i2c_eob_int(bus, false);
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
#if IS_ENABLED(CONFIG_I2C_SLAVE)
|
||||||
/* reenable slave if it was enabled */
|
/* reenable slave if it was enabled */
|
||||||
if (bus->slave)
|
if (bus->slave)
|
||||||
iowrite8((bus->slave->addr & 0x7F) | NPCM_I2CADDR_SAEN,
|
iowrite8((bus->slave->addr & 0x7F) | NPCM_I2CADDR_SAEN,
|
||||||
bus->reg + NPCM_I2CADDR1);
|
bus->reg + NPCM_I2CADDR1);
|
||||||
|
#else
|
||||||
|
npcm_i2c_int_enable(bus, false);
|
||||||
#endif
|
#endif
|
||||||
return bus->cmd_err;
|
return bus->cmd_err;
|
||||||
}
|
}
|
||||||
@@ -2223,17 +2259,18 @@ static void npcm_i2c_init_debugfs(struct platform_device *pdev,
|
|||||||
debugfs_create_u64("rec_succ_cnt", 0444, d, &bus->rec_succ_cnt);
|
debugfs_create_u64("rec_succ_cnt", 0444, d, &bus->rec_succ_cnt);
|
||||||
debugfs_create_u64("rec_fail_cnt", 0444, d, &bus->rec_fail_cnt);
|
debugfs_create_u64("rec_fail_cnt", 0444, d, &bus->rec_fail_cnt);
|
||||||
debugfs_create_u64("timeout_cnt", 0444, d, &bus->timeout_cnt);
|
debugfs_create_u64("timeout_cnt", 0444, d, &bus->timeout_cnt);
|
||||||
|
debugfs_create_u64("tx_complete_cnt", 0444, d, &bus->tx_complete_cnt);
|
||||||
|
|
||||||
bus->debugfs = d;
|
bus->debugfs = d;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int npcm_i2c_probe_bus(struct platform_device *pdev)
|
static int npcm_i2c_probe_bus(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct npcm_i2c *bus;
|
struct device_node *np = pdev->dev.of_node;
|
||||||
struct i2c_adapter *adap;
|
|
||||||
struct clk *i2c_clk;
|
|
||||||
static struct regmap *gcr_regmap;
|
static struct regmap *gcr_regmap;
|
||||||
static struct regmap *clk_regmap;
|
struct i2c_adapter *adap;
|
||||||
|
struct npcm_i2c *bus;
|
||||||
|
struct clk *i2c_clk;
|
||||||
int irq;
|
int irq;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -2250,15 +2287,14 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev)
|
|||||||
return PTR_ERR(i2c_clk);
|
return PTR_ERR(i2c_clk);
|
||||||
bus->apb_clk = clk_get_rate(i2c_clk);
|
bus->apb_clk = clk_get_rate(i2c_clk);
|
||||||
|
|
||||||
gcr_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr");
|
gcr_regmap = syscon_regmap_lookup_by_phandle(np, "nuvoton,sys-mgr");
|
||||||
|
if (IS_ERR(gcr_regmap))
|
||||||
|
gcr_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr");
|
||||||
|
|
||||||
if (IS_ERR(gcr_regmap))
|
if (IS_ERR(gcr_regmap))
|
||||||
return PTR_ERR(gcr_regmap);
|
return PTR_ERR(gcr_regmap);
|
||||||
regmap_write(gcr_regmap, NPCM_I2CSEGCTL, NPCM_I2CSEGCTL_INIT_VAL);
|
regmap_write(gcr_regmap, NPCM_I2CSEGCTL, NPCM_I2CSEGCTL_INIT_VAL);
|
||||||
|
|
||||||
clk_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-clk");
|
|
||||||
if (IS_ERR(clk_regmap))
|
|
||||||
return PTR_ERR(clk_regmap);
|
|
||||||
|
|
||||||
bus->reg = devm_platform_ioremap_resource(pdev, 0);
|
bus->reg = devm_platform_ioremap_resource(pdev, 0);
|
||||||
if (IS_ERR(bus->reg))
|
if (IS_ERR(bus->reg))
|
||||||
return PTR_ERR(bus->reg);
|
return PTR_ERR(bus->reg);
|
||||||
@@ -2269,7 +2305,7 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev)
|
|||||||
adap = &bus->adap;
|
adap = &bus->adap;
|
||||||
adap->owner = THIS_MODULE;
|
adap->owner = THIS_MODULE;
|
||||||
adap->retries = 3;
|
adap->retries = 3;
|
||||||
adap->timeout = HZ;
|
adap->timeout = msecs_to_jiffies(35);
|
||||||
adap->algo = &npcm_i2c_algo;
|
adap->algo = &npcm_i2c_algo;
|
||||||
adap->quirks = &npcm_i2c_quirks;
|
adap->quirks = &npcm_i2c_quirks;
|
||||||
adap->algo_data = bus;
|
adap->algo_data = bus;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/of_irq.h>
|
#include <linux/of_irq.h>
|
||||||
#include <asm/prom.h>
|
|
||||||
#include <asm/pmac_low_i2c.h>
|
#include <asm/pmac_low_i2c.h>
|
||||||
|
|
||||||
MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
|
MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
|
||||||
|
|||||||
@@ -727,16 +727,14 @@ static int setup_gpi_dma(struct geni_i2c_dev *gi2c)
|
|||||||
if (IS_ERR(gi2c->tx_c)) {
|
if (IS_ERR(gi2c->tx_c)) {
|
||||||
ret = dev_err_probe(gi2c->se.dev, PTR_ERR(gi2c->tx_c),
|
ret = dev_err_probe(gi2c->se.dev, PTR_ERR(gi2c->tx_c),
|
||||||
"Failed to get tx DMA ch\n");
|
"Failed to get tx DMA ch\n");
|
||||||
if (ret < 0)
|
goto err_tx;
|
||||||
goto err_tx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gi2c->rx_c = dma_request_chan(gi2c->se.dev, "rx");
|
gi2c->rx_c = dma_request_chan(gi2c->se.dev, "rx");
|
||||||
if (IS_ERR(gi2c->rx_c)) {
|
if (IS_ERR(gi2c->rx_c)) {
|
||||||
ret = dev_err_probe(gi2c->se.dev, PTR_ERR(gi2c->rx_c),
|
ret = dev_err_probe(gi2c->se.dev, PTR_ERR(gi2c->rx_c),
|
||||||
"Failed to get rx DMA ch\n");
|
"Failed to get rx DMA ch\n");
|
||||||
if (ret < 0)
|
goto err_rx;
|
||||||
goto err_rx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(gi2c->se.dev, "Grabbed GPI dma channels\n");
|
dev_dbg(gi2c->se.dev, "Grabbed GPI dma channels\n");
|
||||||
|
|||||||
@@ -45,44 +45,44 @@
|
|||||||
#define ICDMAER 0x3c /* DMA enable (Gen3) */
|
#define ICDMAER 0x3c /* DMA enable (Gen3) */
|
||||||
|
|
||||||
/* ICSCR */
|
/* ICSCR */
|
||||||
#define SDBS (1 << 3) /* slave data buffer select */
|
#define SDBS BIT(3) /* slave data buffer select */
|
||||||
#define SIE (1 << 2) /* slave interface enable */
|
#define SIE BIT(2) /* slave interface enable */
|
||||||
#define GCAE (1 << 1) /* general call address enable */
|
#define GCAE BIT(1) /* general call address enable */
|
||||||
#define FNA (1 << 0) /* forced non acknowledgment */
|
#define FNA BIT(0) /* forced non acknowledgment */
|
||||||
|
|
||||||
/* ICMCR */
|
/* ICMCR */
|
||||||
#define MDBS (1 << 7) /* non-fifo mode switch */
|
#define MDBS BIT(7) /* non-fifo mode switch */
|
||||||
#define FSCL (1 << 6) /* override SCL pin */
|
#define FSCL BIT(6) /* override SCL pin */
|
||||||
#define FSDA (1 << 5) /* override SDA pin */
|
#define FSDA BIT(5) /* override SDA pin */
|
||||||
#define OBPC (1 << 4) /* override pins */
|
#define OBPC BIT(4) /* override pins */
|
||||||
#define MIE (1 << 3) /* master if enable */
|
#define MIE BIT(3) /* master if enable */
|
||||||
#define TSBE (1 << 2)
|
#define TSBE BIT(2)
|
||||||
#define FSB (1 << 1) /* force stop bit */
|
#define FSB BIT(1) /* force stop bit */
|
||||||
#define ESG (1 << 0) /* enable start bit gen */
|
#define ESG BIT(0) /* enable start bit gen */
|
||||||
|
|
||||||
/* ICSSR (also for ICSIER) */
|
/* ICSSR (also for ICSIER) */
|
||||||
#define GCAR (1 << 6) /* general call received */
|
#define GCAR BIT(6) /* general call received */
|
||||||
#define STM (1 << 5) /* slave transmit mode */
|
#define STM BIT(5) /* slave transmit mode */
|
||||||
#define SSR (1 << 4) /* stop received */
|
#define SSR BIT(4) /* stop received */
|
||||||
#define SDE (1 << 3) /* slave data empty */
|
#define SDE BIT(3) /* slave data empty */
|
||||||
#define SDT (1 << 2) /* slave data transmitted */
|
#define SDT BIT(2) /* slave data transmitted */
|
||||||
#define SDR (1 << 1) /* slave data received */
|
#define SDR BIT(1) /* slave data received */
|
||||||
#define SAR (1 << 0) /* slave addr received */
|
#define SAR BIT(0) /* slave addr received */
|
||||||
|
|
||||||
/* ICMSR (also for ICMIE) */
|
/* ICMSR (also for ICMIE) */
|
||||||
#define MNR (1 << 6) /* nack received */
|
#define MNR BIT(6) /* nack received */
|
||||||
#define MAL (1 << 5) /* arbitration lost */
|
#define MAL BIT(5) /* arbitration lost */
|
||||||
#define MST (1 << 4) /* sent a stop */
|
#define MST BIT(4) /* sent a stop */
|
||||||
#define MDE (1 << 3)
|
#define MDE BIT(3)
|
||||||
#define MDT (1 << 2)
|
#define MDT BIT(2)
|
||||||
#define MDR (1 << 1)
|
#define MDR BIT(1)
|
||||||
#define MAT (1 << 0) /* slave addr xfer done */
|
#define MAT BIT(0) /* slave addr xfer done */
|
||||||
|
|
||||||
/* ICDMAER */
|
/* ICDMAER */
|
||||||
#define RSDMAE (1 << 3) /* DMA Slave Received Enable */
|
#define RSDMAE BIT(3) /* DMA Slave Received Enable */
|
||||||
#define TSDMAE (1 << 2) /* DMA Slave Transmitted Enable */
|
#define TSDMAE BIT(2) /* DMA Slave Transmitted Enable */
|
||||||
#define RMDMAE (1 << 1) /* DMA Master Received Enable */
|
#define RMDMAE BIT(1) /* DMA Master Received Enable */
|
||||||
#define TMDMAE (1 << 0) /* DMA Master Transmitted Enable */
|
#define TMDMAE BIT(0) /* DMA Master Transmitted Enable */
|
||||||
|
|
||||||
/* ICFBSCR */
|
/* ICFBSCR */
|
||||||
#define TCYC17 0x0f /* 17*Tcyc delay 1st bit between SDA and SCL */
|
#define TCYC17 0x0f /* 17*Tcyc delay 1st bit between SDA and SCL */
|
||||||
@@ -97,17 +97,15 @@
|
|||||||
#define RCAR_IRQ_RECV (MNR | MAL | MST | MAT | MDR)
|
#define RCAR_IRQ_RECV (MNR | MAL | MST | MAT | MDR)
|
||||||
#define RCAR_IRQ_STOP (MST)
|
#define RCAR_IRQ_STOP (MST)
|
||||||
|
|
||||||
#define RCAR_IRQ_ACK_SEND (~(MAT | MDE) & 0x7F)
|
#define ID_LAST_MSG BIT(0)
|
||||||
#define RCAR_IRQ_ACK_RECV (~(MAT | MDR) & 0x7F)
|
#define ID_REP_AFTER_RD BIT(1)
|
||||||
|
#define ID_DONE BIT(2)
|
||||||
#define ID_LAST_MSG (1 << 0)
|
#define ID_ARBLOST BIT(3)
|
||||||
#define ID_FIRST_MSG (1 << 1)
|
#define ID_NACK BIT(4)
|
||||||
#define ID_DONE (1 << 2)
|
#define ID_EPROTO BIT(5)
|
||||||
#define ID_ARBLOST (1 << 3)
|
|
||||||
#define ID_NACK (1 << 4)
|
|
||||||
/* persistent flags */
|
/* persistent flags */
|
||||||
#define ID_P_HOST_NOTIFY BIT(28)
|
#define ID_P_NOT_ATOMIC BIT(28)
|
||||||
#define ID_P_REP_AFTER_RD BIT(29)
|
#define ID_P_HOST_NOTIFY BIT(29)
|
||||||
#define ID_P_NO_RXDMA BIT(30) /* HW forbids RXDMA sometimes */
|
#define ID_P_NO_RXDMA BIT(30) /* HW forbids RXDMA sometimes */
|
||||||
#define ID_P_PM_BLOCKED BIT(31)
|
#define ID_P_PM_BLOCKED BIT(31)
|
||||||
#define ID_P_MASK GENMASK(31, 28)
|
#define ID_P_MASK GENMASK(31, 28)
|
||||||
@@ -141,7 +139,6 @@ struct rcar_i2c_priv {
|
|||||||
enum dma_data_direction dma_direction;
|
enum dma_data_direction dma_direction;
|
||||||
|
|
||||||
struct reset_control *rstc;
|
struct reset_control *rstc;
|
||||||
bool atomic_xfer;
|
|
||||||
int irq;
|
int irq;
|
||||||
|
|
||||||
struct i2c_client *host_notify_client;
|
struct i2c_client *host_notify_client;
|
||||||
@@ -160,6 +157,11 @@ static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg)
|
|||||||
return readl(priv->io + reg);
|
return readl(priv->io + reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rcar_i2c_clear_irq(struct rcar_i2c_priv *priv, u32 val)
|
||||||
|
{
|
||||||
|
writel(~val & 0x7f, priv->io + ICMSR);
|
||||||
|
}
|
||||||
|
|
||||||
static int rcar_i2c_get_scl(struct i2c_adapter *adap)
|
static int rcar_i2c_get_scl(struct i2c_adapter *adap)
|
||||||
{
|
{
|
||||||
struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
|
struct rcar_i2c_priv *priv = i2c_get_adapdata(adap);
|
||||||
@@ -330,41 +332,46 @@ scgd_find:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't have a test case but the HW engineers say that the write order of
|
||||||
|
* ICMSR and ICMCR depends on whether we issue START or REP_START. So, ICMSR
|
||||||
|
* handling is outside of this function. First messages clear ICMSR before this
|
||||||
|
* function, interrupt handlers clear the relevant bits after this function.
|
||||||
|
*/
|
||||||
static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv)
|
static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv)
|
||||||
{
|
{
|
||||||
int read = !!rcar_i2c_is_recv(priv);
|
int read = !!rcar_i2c_is_recv(priv);
|
||||||
|
bool rep_start = !(priv->flags & ID_REP_AFTER_RD);
|
||||||
|
|
||||||
priv->pos = 0;
|
priv->pos = 0;
|
||||||
|
priv->flags &= ID_P_MASK;
|
||||||
|
|
||||||
if (priv->msgs_left == 1)
|
if (priv->msgs_left == 1)
|
||||||
priv->flags |= ID_LAST_MSG;
|
priv->flags |= ID_LAST_MSG;
|
||||||
|
|
||||||
rcar_i2c_write(priv, ICMAR, i2c_8bit_addr_from_msg(priv->msg));
|
rcar_i2c_write(priv, ICMAR, i2c_8bit_addr_from_msg(priv->msg));
|
||||||
if (!priv->atomic_xfer)
|
if (priv->flags & ID_P_NOT_ATOMIC)
|
||||||
rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND);
|
rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND);
|
||||||
|
|
||||||
/*
|
if (rep_start)
|
||||||
* We don't have a test case but the HW engineers say that the write order
|
|
||||||
* of ICMSR and ICMCR depends on whether we issue START or REP_START. Since
|
|
||||||
* it didn't cause a drawback for me, let's rather be safe than sorry.
|
|
||||||
*/
|
|
||||||
if (priv->flags & ID_FIRST_MSG) {
|
|
||||||
rcar_i2c_write(priv, ICMSR, 0);
|
|
||||||
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
|
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
|
||||||
} else {
|
}
|
||||||
if (priv->flags & ID_P_REP_AFTER_RD)
|
|
||||||
priv->flags &= ~ID_P_REP_AFTER_RD;
|
static void rcar_i2c_first_msg(struct rcar_i2c_priv *priv,
|
||||||
else
|
struct i2c_msg *msgs, int num)
|
||||||
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
|
{
|
||||||
rcar_i2c_write(priv, ICMSR, 0);
|
priv->msg = msgs;
|
||||||
}
|
priv->msgs_left = num;
|
||||||
|
rcar_i2c_write(priv, ICMSR, 0); /* must be before preparing msg */
|
||||||
|
rcar_i2c_prepare_msg(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv)
|
static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv)
|
||||||
{
|
{
|
||||||
priv->msg++;
|
priv->msg++;
|
||||||
priv->msgs_left--;
|
priv->msgs_left--;
|
||||||
priv->flags &= ID_P_MASK;
|
|
||||||
rcar_i2c_prepare_msg(priv);
|
rcar_i2c_prepare_msg(priv);
|
||||||
|
/* ICMSR handling must come afterwards in the irq handler */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rcar_i2c_cleanup_dma(struct rcar_i2c_priv *priv, bool terminate)
|
static void rcar_i2c_cleanup_dma(struct rcar_i2c_priv *priv, bool terminate)
|
||||||
@@ -413,7 +420,7 @@ static bool rcar_i2c_dma(struct rcar_i2c_priv *priv)
|
|||||||
int len;
|
int len;
|
||||||
|
|
||||||
/* Do various checks to see if DMA is feasible at all */
|
/* Do various checks to see if DMA is feasible at all */
|
||||||
if (priv->atomic_xfer || IS_ERR(chan) || msg->len < RCAR_MIN_DMA_LEN ||
|
if (!(priv->flags & ID_P_NOT_ATOMIC) || IS_ERR(chan) || msg->len < RCAR_MIN_DMA_LEN ||
|
||||||
!(msg->flags & I2C_M_DMA_SAFE) || (read && priv->flags & ID_P_NO_RXDMA))
|
!(msg->flags & I2C_M_DMA_SAFE) || (read && priv->flags & ID_P_NO_RXDMA))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -475,11 +482,15 @@ static bool rcar_i2c_dma(struct rcar_i2c_priv *priv)
|
|||||||
static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
|
static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
|
||||||
{
|
{
|
||||||
struct i2c_msg *msg = priv->msg;
|
struct i2c_msg *msg = priv->msg;
|
||||||
|
u32 irqs_to_clear = MDE;
|
||||||
|
|
||||||
/* FIXME: sometimes, unknown interrupt happened. Do nothing */
|
/* FIXME: sometimes, unknown interrupt happened. Do nothing */
|
||||||
if (!(msr & MDE))
|
if (!(msr & MDE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (msr & MAT)
|
||||||
|
irqs_to_clear |= MAT;
|
||||||
|
|
||||||
/* Check if DMA can be enabled and take over */
|
/* Check if DMA can be enabled and take over */
|
||||||
if (priv->pos == 1 && rcar_i2c_dma(priv))
|
if (priv->pos == 1 && rcar_i2c_dma(priv))
|
||||||
return;
|
return;
|
||||||
@@ -503,31 +514,32 @@ static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr)
|
|||||||
* [ICRXTX] -> [SHIFT] -> [I2C bus]
|
* [ICRXTX] -> [SHIFT] -> [I2C bus]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (priv->flags & ID_LAST_MSG) {
|
if (priv->flags & ID_LAST_MSG)
|
||||||
/*
|
/*
|
||||||
* If current msg is the _LAST_ msg,
|
* If current msg is the _LAST_ msg,
|
||||||
* prepare stop condition here.
|
* prepare stop condition here.
|
||||||
* ID_DONE will be set on STOP irq.
|
* ID_DONE will be set on STOP irq.
|
||||||
*/
|
*/
|
||||||
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
|
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
|
||||||
} else {
|
else
|
||||||
rcar_i2c_next_msg(priv);
|
rcar_i2c_next_msg(priv);
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_SEND);
|
rcar_i2c_clear_irq(priv, irqs_to_clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
|
static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
|
||||||
{
|
{
|
||||||
struct i2c_msg *msg = priv->msg;
|
struct i2c_msg *msg = priv->msg;
|
||||||
|
bool recv_len_init = priv->pos == 0 && msg->flags & I2C_M_RECV_LEN;
|
||||||
|
u32 irqs_to_clear = MDR;
|
||||||
|
|
||||||
/* FIXME: sometimes, unknown interrupt happened. Do nothing */
|
/* FIXME: sometimes, unknown interrupt happened. Do nothing */
|
||||||
if (!(msr & MDR))
|
if (!(msr & MDR))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (msr & MAT) {
|
if (msr & MAT) {
|
||||||
|
irqs_to_clear |= MAT;
|
||||||
/*
|
/*
|
||||||
* Address transfer phase finished, but no data at this point.
|
* Address transfer phase finished, but no data at this point.
|
||||||
* Try to use DMA to receive data.
|
* Try to use DMA to receive data.
|
||||||
@@ -535,24 +547,41 @@ static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr)
|
|||||||
rcar_i2c_dma(priv);
|
rcar_i2c_dma(priv);
|
||||||
} else if (priv->pos < msg->len) {
|
} else if (priv->pos < msg->len) {
|
||||||
/* get received data */
|
/* get received data */
|
||||||
msg->buf[priv->pos] = rcar_i2c_read(priv, ICRXTX);
|
u8 data = rcar_i2c_read(priv, ICRXTX);
|
||||||
|
|
||||||
|
msg->buf[priv->pos] = data;
|
||||||
|
if (recv_len_init) {
|
||||||
|
if (data == 0 || data > I2C_SMBUS_BLOCK_MAX) {
|
||||||
|
priv->flags |= ID_DONE | ID_EPROTO;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
msg->len += msg->buf[0];
|
||||||
|
/* Enough data for DMA? */
|
||||||
|
if (rcar_i2c_dma(priv))
|
||||||
|
return;
|
||||||
|
/* new length after RECV_LEN now properly initialized */
|
||||||
|
recv_len_init = false;
|
||||||
|
}
|
||||||
priv->pos++;
|
priv->pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If next received data is the _LAST_, go to new phase. */
|
/*
|
||||||
if (priv->pos + 1 == msg->len) {
|
* If next received data is the _LAST_ and we are not waiting for a new
|
||||||
|
* length because of RECV_LEN, then go to a new phase.
|
||||||
|
*/
|
||||||
|
if (priv->pos + 1 == msg->len && !recv_len_init) {
|
||||||
if (priv->flags & ID_LAST_MSG) {
|
if (priv->flags & ID_LAST_MSG) {
|
||||||
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
|
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
|
||||||
} else {
|
} else {
|
||||||
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
|
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
|
||||||
priv->flags |= ID_P_REP_AFTER_RD;
|
priv->flags |= ID_REP_AFTER_RD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->pos == msg->len && !(priv->flags & ID_LAST_MSG))
|
if (priv->pos == msg->len && !(priv->flags & ID_LAST_MSG))
|
||||||
rcar_i2c_next_msg(priv);
|
rcar_i2c_next_msg(priv);
|
||||||
else
|
|
||||||
rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_RECV);
|
rcar_i2c_clear_irq(priv, irqs_to_clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
|
static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
|
||||||
@@ -641,7 +670,7 @@ static irqreturn_t rcar_i2c_irq(int irq, struct rcar_i2c_priv *priv, u32 msr)
|
|||||||
/* Nack */
|
/* Nack */
|
||||||
if (msr & MNR) {
|
if (msr & MNR) {
|
||||||
/* HW automatically sends STOP after received NACK */
|
/* HW automatically sends STOP after received NACK */
|
||||||
if (!priv->atomic_xfer)
|
if (priv->flags & ID_P_NOT_ATOMIC)
|
||||||
rcar_i2c_write(priv, ICMIER, RCAR_IRQ_STOP);
|
rcar_i2c_write(priv, ICMIER, RCAR_IRQ_STOP);
|
||||||
priv->flags |= ID_NACK;
|
priv->flags |= ID_NACK;
|
||||||
goto out;
|
goto out;
|
||||||
@@ -663,7 +692,7 @@ out:
|
|||||||
if (priv->flags & ID_DONE) {
|
if (priv->flags & ID_DONE) {
|
||||||
rcar_i2c_write(priv, ICMIER, 0);
|
rcar_i2c_write(priv, ICMIER, 0);
|
||||||
rcar_i2c_write(priv, ICMSR, 0);
|
rcar_i2c_write(priv, ICMSR, 0);
|
||||||
if (!priv->atomic_xfer)
|
if (priv->flags & ID_P_NOT_ATOMIC)
|
||||||
wake_up(&priv->wait);
|
wake_up(&priv->wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,12 +705,12 @@ static irqreturn_t rcar_i2c_gen2_irq(int irq, void *ptr)
|
|||||||
u32 msr;
|
u32 msr;
|
||||||
|
|
||||||
/* Clear START or STOP immediately, except for REPSTART after read */
|
/* Clear START or STOP immediately, except for REPSTART after read */
|
||||||
if (likely(!(priv->flags & ID_P_REP_AFTER_RD)))
|
if (likely(!(priv->flags & ID_REP_AFTER_RD)))
|
||||||
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
|
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
|
||||||
|
|
||||||
/* Only handle interrupts that are currently enabled */
|
/* Only handle interrupts that are currently enabled */
|
||||||
msr = rcar_i2c_read(priv, ICMSR);
|
msr = rcar_i2c_read(priv, ICMSR);
|
||||||
if (!priv->atomic_xfer)
|
if (priv->flags & ID_P_NOT_ATOMIC)
|
||||||
msr &= rcar_i2c_read(priv, ICMIER);
|
msr &= rcar_i2c_read(priv, ICMIER);
|
||||||
|
|
||||||
return rcar_i2c_irq(irq, priv, msr);
|
return rcar_i2c_irq(irq, priv, msr);
|
||||||
@@ -694,14 +723,14 @@ static irqreturn_t rcar_i2c_gen3_irq(int irq, void *ptr)
|
|||||||
|
|
||||||
/* Only handle interrupts that are currently enabled */
|
/* Only handle interrupts that are currently enabled */
|
||||||
msr = rcar_i2c_read(priv, ICMSR);
|
msr = rcar_i2c_read(priv, ICMSR);
|
||||||
if (!priv->atomic_xfer)
|
if (priv->flags & ID_P_NOT_ATOMIC)
|
||||||
msr &= rcar_i2c_read(priv, ICMIER);
|
msr &= rcar_i2c_read(priv, ICMIER);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear START or STOP immediately, except for REPSTART after read or
|
* Clear START or STOP immediately, except for REPSTART after read or
|
||||||
* if a spurious interrupt was detected.
|
* if a spurious interrupt was detected.
|
||||||
*/
|
*/
|
||||||
if (likely(!(priv->flags & ID_P_REP_AFTER_RD) && msr))
|
if (likely(!(priv->flags & ID_REP_AFTER_RD) && msr))
|
||||||
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
|
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
|
||||||
|
|
||||||
return rcar_i2c_irq(irq, priv, msr);
|
return rcar_i2c_irq(irq, priv, msr);
|
||||||
@@ -803,7 +832,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
|
|||||||
int i, ret;
|
int i, ret;
|
||||||
long time_left;
|
long time_left;
|
||||||
|
|
||||||
priv->atomic_xfer = false;
|
priv->flags |= ID_P_NOT_ATOMIC;
|
||||||
|
|
||||||
pm_runtime_get_sync(dev);
|
pm_runtime_get_sync(dev);
|
||||||
|
|
||||||
@@ -827,11 +856,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
|
|||||||
for (i = 0; i < num; i++)
|
for (i = 0; i < num; i++)
|
||||||
rcar_i2c_request_dma(priv, msgs + i);
|
rcar_i2c_request_dma(priv, msgs + i);
|
||||||
|
|
||||||
/* init first message */
|
rcar_i2c_first_msg(priv, msgs, num);
|
||||||
priv->msg = msgs;
|
|
||||||
priv->msgs_left = num;
|
|
||||||
priv->flags = (priv->flags & ID_P_MASK) | ID_FIRST_MSG;
|
|
||||||
rcar_i2c_prepare_msg(priv);
|
|
||||||
|
|
||||||
time_left = wait_event_timeout(priv->wait, priv->flags & ID_DONE,
|
time_left = wait_event_timeout(priv->wait, priv->flags & ID_DONE,
|
||||||
num * adap->timeout);
|
num * adap->timeout);
|
||||||
@@ -847,6 +872,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
|
|||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
} else if (priv->flags & ID_ARBLOST) {
|
} else if (priv->flags & ID_ARBLOST) {
|
||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
|
} else if (priv->flags & ID_EPROTO) {
|
||||||
|
ret = -EPROTO;
|
||||||
} else {
|
} else {
|
||||||
ret = num - priv->msgs_left; /* The number of transfer */
|
ret = num - priv->msgs_left; /* The number of transfer */
|
||||||
}
|
}
|
||||||
@@ -869,7 +896,7 @@ static int rcar_i2c_master_xfer_atomic(struct i2c_adapter *adap,
|
|||||||
bool time_left;
|
bool time_left;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
priv->atomic_xfer = true;
|
priv->flags &= ~ID_P_NOT_ATOMIC;
|
||||||
|
|
||||||
pm_runtime_get_sync(dev);
|
pm_runtime_get_sync(dev);
|
||||||
|
|
||||||
@@ -879,12 +906,7 @@ static int rcar_i2c_master_xfer_atomic(struct i2c_adapter *adap,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
rcar_i2c_init(priv);
|
rcar_i2c_init(priv);
|
||||||
|
rcar_i2c_first_msg(priv, msgs, num);
|
||||||
/* init first message */
|
|
||||||
priv->msg = msgs;
|
|
||||||
priv->msgs_left = num;
|
|
||||||
priv->flags = (priv->flags & ID_P_MASK) | ID_FIRST_MSG;
|
|
||||||
rcar_i2c_prepare_msg(priv);
|
|
||||||
|
|
||||||
j = jiffies + num * adap->timeout;
|
j = jiffies + num * adap->timeout;
|
||||||
do {
|
do {
|
||||||
@@ -909,6 +931,8 @@ static int rcar_i2c_master_xfer_atomic(struct i2c_adapter *adap,
|
|||||||
ret = -ENXIO;
|
ret = -ENXIO;
|
||||||
} else if (priv->flags & ID_ARBLOST) {
|
} else if (priv->flags & ID_ARBLOST) {
|
||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
|
} else if (priv->flags & ID_EPROTO) {
|
||||||
|
ret = -EPROTO;
|
||||||
} else {
|
} else {
|
||||||
ret = num - priv->msgs_left; /* The number of transfer */
|
ret = num - priv->msgs_left; /* The number of transfer */
|
||||||
}
|
}
|
||||||
@@ -975,7 +999,7 @@ static u32 rcar_i2c_func(struct i2c_adapter *adap)
|
|||||||
* I2C_M_IGNORE_NAK (automatically sends STOP after NAK)
|
* I2C_M_IGNORE_NAK (automatically sends STOP after NAK)
|
||||||
*/
|
*/
|
||||||
u32 func = I2C_FUNC_I2C | I2C_FUNC_SLAVE |
|
u32 func = I2C_FUNC_I2C | I2C_FUNC_SLAVE |
|
||||||
(I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
|
(I2C_FUNC_SMBUS_EMUL_ALL & ~I2C_FUNC_SMBUS_QUICK);
|
||||||
|
|
||||||
if (priv->flags & ID_P_HOST_NOTIFY)
|
if (priv->flags & ID_P_HOST_NOTIFY)
|
||||||
func |= I2C_FUNC_SMBUS_HOST_NOTIFY;
|
func |= I2C_FUNC_SMBUS_HOST_NOTIFY;
|
||||||
@@ -1063,8 +1087,10 @@ static int rcar_i2c_probe(struct platform_device *pdev)
|
|||||||
pm_runtime_enable(dev);
|
pm_runtime_enable(dev);
|
||||||
pm_runtime_get_sync(dev);
|
pm_runtime_get_sync(dev);
|
||||||
ret = rcar_i2c_clock_calculate(priv);
|
ret = rcar_i2c_clock_calculate(priv);
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
goto out_pm_put;
|
pm_runtime_put(dev);
|
||||||
|
goto out_pm_disable;
|
||||||
|
}
|
||||||
|
|
||||||
rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */
|
rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */
|
||||||
|
|
||||||
@@ -1093,19 +1119,19 @@ static int rcar_i2c_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
ret = platform_get_irq(pdev, 0);
|
ret = platform_get_irq(pdev, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_pm_disable;
|
goto out_pm_put;
|
||||||
priv->irq = ret;
|
priv->irq = ret;
|
||||||
ret = devm_request_irq(dev, priv->irq, irqhandler, irqflags, dev_name(dev), priv);
|
ret = devm_request_irq(dev, priv->irq, irqhandler, irqflags, dev_name(dev), priv);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(dev, "cannot get irq %d\n", priv->irq);
|
dev_err(dev, "cannot get irq %d\n", priv->irq);
|
||||||
goto out_pm_disable;
|
goto out_pm_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
platform_set_drvdata(pdev, priv);
|
platform_set_drvdata(pdev, priv);
|
||||||
|
|
||||||
ret = i2c_add_numbered_adapter(adap);
|
ret = i2c_add_numbered_adapter(adap);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_pm_disable;
|
goto out_pm_put;
|
||||||
|
|
||||||
if (priv->flags & ID_P_HOST_NOTIFY) {
|
if (priv->flags & ID_P_HOST_NOTIFY) {
|
||||||
priv->host_notify_client = i2c_new_slave_host_notify_device(adap);
|
priv->host_notify_client = i2c_new_slave_host_notify_device(adap);
|
||||||
@@ -1122,7 +1148,8 @@ static int rcar_i2c_probe(struct platform_device *pdev)
|
|||||||
out_del_device:
|
out_del_device:
|
||||||
i2c_del_adapter(&priv->adap);
|
i2c_del_adapter(&priv->adap);
|
||||||
out_pm_put:
|
out_pm_put:
|
||||||
pm_runtime_put(dev);
|
if (priv->flags & ID_P_PM_BLOCKED)
|
||||||
|
pm_runtime_put(dev);
|
||||||
out_pm_disable:
|
out_pm_disable:
|
||||||
pm_runtime_disable(dev);
|
pm_runtime_disable(dev);
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -78,24 +78,23 @@ struct xiic_i2c {
|
|||||||
bool singlemaster;
|
bool singlemaster;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define XIIC_MSB_OFFSET 0
|
#define XIIC_MSB_OFFSET 0
|
||||||
#define XIIC_REG_OFFSET (0x100+XIIC_MSB_OFFSET)
|
#define XIIC_REG_OFFSET (0x100 + XIIC_MSB_OFFSET)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register offsets in bytes from RegisterBase. Three is added to the
|
* Register offsets in bytes from RegisterBase. Three is added to the
|
||||||
* base offset to access LSB (IBM style) of the word
|
* base offset to access LSB (IBM style) of the word
|
||||||
*/
|
*/
|
||||||
#define XIIC_CR_REG_OFFSET (0x00+XIIC_REG_OFFSET) /* Control Register */
|
#define XIIC_CR_REG_OFFSET (0x00 + XIIC_REG_OFFSET) /* Control Register */
|
||||||
#define XIIC_SR_REG_OFFSET (0x04+XIIC_REG_OFFSET) /* Status Register */
|
#define XIIC_SR_REG_OFFSET (0x04 + XIIC_REG_OFFSET) /* Status Register */
|
||||||
#define XIIC_DTR_REG_OFFSET (0x08+XIIC_REG_OFFSET) /* Data Tx Register */
|
#define XIIC_DTR_REG_OFFSET (0x08 + XIIC_REG_OFFSET) /* Data Tx Register */
|
||||||
#define XIIC_DRR_REG_OFFSET (0x0C+XIIC_REG_OFFSET) /* Data Rx Register */
|
#define XIIC_DRR_REG_OFFSET (0x0C + XIIC_REG_OFFSET) /* Data Rx Register */
|
||||||
#define XIIC_ADR_REG_OFFSET (0x10+XIIC_REG_OFFSET) /* Address Register */
|
#define XIIC_ADR_REG_OFFSET (0x10 + XIIC_REG_OFFSET) /* Address Register */
|
||||||
#define XIIC_TFO_REG_OFFSET (0x14+XIIC_REG_OFFSET) /* Tx FIFO Occupancy */
|
#define XIIC_TFO_REG_OFFSET (0x14 + XIIC_REG_OFFSET) /* Tx FIFO Occupancy */
|
||||||
#define XIIC_RFO_REG_OFFSET (0x18+XIIC_REG_OFFSET) /* Rx FIFO Occupancy */
|
#define XIIC_RFO_REG_OFFSET (0x18 + XIIC_REG_OFFSET) /* Rx FIFO Occupancy */
|
||||||
#define XIIC_TBA_REG_OFFSET (0x1C+XIIC_REG_OFFSET) /* 10 Bit Address reg */
|
#define XIIC_TBA_REG_OFFSET (0x1C + XIIC_REG_OFFSET) /* 10 Bit Address reg */
|
||||||
#define XIIC_RFD_REG_OFFSET (0x20+XIIC_REG_OFFSET) /* Rx FIFO Depth reg */
|
#define XIIC_RFD_REG_OFFSET (0x20 + XIIC_REG_OFFSET) /* Rx FIFO Depth reg */
|
||||||
#define XIIC_GPO_REG_OFFSET (0x24+XIIC_REG_OFFSET) /* Output Register */
|
#define XIIC_GPO_REG_OFFSET (0x24 + XIIC_REG_OFFSET) /* Output Register */
|
||||||
|
|
||||||
/* Control Register masks */
|
/* Control Register masks */
|
||||||
#define XIIC_CR_ENABLE_DEVICE_MASK 0x01 /* Device enable = 1 */
|
#define XIIC_CR_ENABLE_DEVICE_MASK 0x01 /* Device enable = 1 */
|
||||||
@@ -233,18 +232,21 @@ static inline int xiic_getreg32(struct xiic_i2c *i2c, int reg)
|
|||||||
static inline void xiic_irq_dis(struct xiic_i2c *i2c, u32 mask)
|
static inline void xiic_irq_dis(struct xiic_i2c *i2c, u32 mask)
|
||||||
{
|
{
|
||||||
u32 ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
|
u32 ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
|
||||||
|
|
||||||
xiic_setreg32(i2c, XIIC_IIER_OFFSET, ier & ~mask);
|
xiic_setreg32(i2c, XIIC_IIER_OFFSET, ier & ~mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void xiic_irq_en(struct xiic_i2c *i2c, u32 mask)
|
static inline void xiic_irq_en(struct xiic_i2c *i2c, u32 mask)
|
||||||
{
|
{
|
||||||
u32 ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
|
u32 ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET);
|
||||||
|
|
||||||
xiic_setreg32(i2c, XIIC_IIER_OFFSET, ier | mask);
|
xiic_setreg32(i2c, XIIC_IIER_OFFSET, ier | mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void xiic_irq_clr(struct xiic_i2c *i2c, u32 mask)
|
static inline void xiic_irq_clr(struct xiic_i2c *i2c, u32 mask)
|
||||||
{
|
{
|
||||||
u32 isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET);
|
u32 isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET);
|
||||||
|
|
||||||
xiic_setreg32(i2c, XIIC_IISR_OFFSET, isr & mask);
|
xiic_setreg32(i2c, XIIC_IISR_OFFSET, isr & mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,7 +357,8 @@ static void xiic_fill_tx_fifo(struct xiic_i2c *i2c)
|
|||||||
|
|
||||||
while (len--) {
|
while (len--) {
|
||||||
u16 data = i2c->tx_msg->buf[i2c->tx_pos++];
|
u16 data = i2c->tx_msg->buf[i2c->tx_pos++];
|
||||||
if ((xiic_tx_space(i2c) == 0) && (i2c->nmsgs == 1)) {
|
|
||||||
|
if (!xiic_tx_space(i2c) && i2c->nmsgs == 1) {
|
||||||
/* last message in transfer -> STOP */
|
/* last message in transfer -> STOP */
|
||||||
data |= XIIC_TX_DYN_STOP_MASK;
|
data |= XIIC_TX_DYN_STOP_MASK;
|
||||||
dev_dbg(i2c->adap.dev.parent, "%s TX STOP\n", __func__);
|
dev_dbg(i2c->adap.dev.parent, "%s TX STOP\n", __func__);
|
||||||
@@ -381,6 +384,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
|
|||||||
int xfer_more = 0;
|
int xfer_more = 0;
|
||||||
int wakeup_req = 0;
|
int wakeup_req = 0;
|
||||||
int wakeup_code = 0;
|
int wakeup_code = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* Get the interrupt Status from the IPIF. There is no clearing of
|
/* Get the interrupt Status from the IPIF. There is no clearing of
|
||||||
* interrupts in the IPIF. Interrupts must be cleared at the source.
|
* interrupts in the IPIF. Interrupts must be cleared at the source.
|
||||||
@@ -401,8 +405,8 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
|
|||||||
|
|
||||||
/* Service requesting interrupt */
|
/* Service requesting interrupt */
|
||||||
if ((pend & XIIC_INTR_ARB_LOST_MASK) ||
|
if ((pend & XIIC_INTR_ARB_LOST_MASK) ||
|
||||||
((pend & XIIC_INTR_TX_ERROR_MASK) &&
|
((pend & XIIC_INTR_TX_ERROR_MASK) &&
|
||||||
!(pend & XIIC_INTR_RX_FULL_MASK))) {
|
!(pend & XIIC_INTR_RX_FULL_MASK))) {
|
||||||
/* bus arbritration lost, or...
|
/* bus arbritration lost, or...
|
||||||
* Transmit error _OR_ RX completed
|
* Transmit error _OR_ RX completed
|
||||||
* if this happens when RX_FULL is not set
|
* if this happens when RX_FULL is not set
|
||||||
@@ -415,7 +419,9 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
|
|||||||
* fifos and the next message is a TX with len 0 (only addr)
|
* fifos and the next message is a TX with len 0 (only addr)
|
||||||
* reset the IP instead of just flush fifos
|
* reset the IP instead of just flush fifos
|
||||||
*/
|
*/
|
||||||
xiic_reinit(i2c);
|
ret = xiic_reinit(i2c);
|
||||||
|
if (!ret)
|
||||||
|
dev_dbg(i2c->adap.dev.parent, "reinit failed\n");
|
||||||
|
|
||||||
if (i2c->rx_msg) {
|
if (i2c->rx_msg) {
|
||||||
wakeup_req = 1;
|
wakeup_req = 1;
|
||||||
@@ -462,24 +468,6 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pend & XIIC_INTR_BNB_MASK) {
|
|
||||||
/* IIC bus has transitioned to not busy */
|
|
||||||
clr |= XIIC_INTR_BNB_MASK;
|
|
||||||
|
|
||||||
/* The bus is not busy, disable BusNotBusy interrupt */
|
|
||||||
xiic_irq_dis(i2c, XIIC_INTR_BNB_MASK);
|
|
||||||
|
|
||||||
if (!i2c->tx_msg)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
wakeup_req = 1;
|
|
||||||
|
|
||||||
if (i2c->nmsgs == 1 && !i2c->rx_msg &&
|
|
||||||
xiic_tx_space(i2c) == 0)
|
|
||||||
wakeup_code = STATE_DONE;
|
|
||||||
else
|
|
||||||
wakeup_code = STATE_ERROR;
|
|
||||||
}
|
|
||||||
if (pend & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)) {
|
if (pend & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)) {
|
||||||
/* Transmit register/FIFO is empty or ½ empty */
|
/* Transmit register/FIFO is empty or ½ empty */
|
||||||
|
|
||||||
@@ -516,6 +504,26 @@ static irqreturn_t xiic_process(int irq, void *dev_id)
|
|||||||
*/
|
*/
|
||||||
xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK);
|
xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pend & XIIC_INTR_BNB_MASK) {
|
||||||
|
/* IIC bus has transitioned to not busy */
|
||||||
|
clr |= XIIC_INTR_BNB_MASK;
|
||||||
|
|
||||||
|
/* The bus is not busy, disable BusNotBusy interrupt */
|
||||||
|
xiic_irq_dis(i2c, XIIC_INTR_BNB_MASK);
|
||||||
|
|
||||||
|
if (!i2c->tx_msg)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
wakeup_req = 1;
|
||||||
|
|
||||||
|
if (i2c->nmsgs == 1 && !i2c->rx_msg &&
|
||||||
|
xiic_tx_space(i2c) == 0)
|
||||||
|
wakeup_code = STATE_DONE;
|
||||||
|
else
|
||||||
|
wakeup_code = STATE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
dev_dbg(i2c->adap.dev.parent, "%s clr: 0x%x\n", __func__, clr);
|
dev_dbg(i2c->adap.dev.parent, "%s clr: 0x%x\n", __func__, clr);
|
||||||
|
|
||||||
@@ -570,7 +578,7 @@ static int xiic_busy(struct xiic_i2c *i2c)
|
|||||||
|
|
||||||
static void xiic_start_recv(struct xiic_i2c *i2c)
|
static void xiic_start_recv(struct xiic_i2c *i2c)
|
||||||
{
|
{
|
||||||
u8 rx_watermark;
|
u16 rx_watermark;
|
||||||
struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg;
|
struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg;
|
||||||
|
|
||||||
/* Clear and enable Rx full interrupt. */
|
/* Clear and enable Rx full interrupt. */
|
||||||
@@ -585,7 +593,7 @@ static void xiic_start_recv(struct xiic_i2c *i2c)
|
|||||||
rx_watermark = msg->len;
|
rx_watermark = msg->len;
|
||||||
if (rx_watermark > IIC_RX_FIFO_DEPTH)
|
if (rx_watermark > IIC_RX_FIFO_DEPTH)
|
||||||
rx_watermark = IIC_RX_FIFO_DEPTH;
|
rx_watermark = IIC_RX_FIFO_DEPTH;
|
||||||
xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rx_watermark - 1);
|
xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, (u8)(rx_watermark - 1));
|
||||||
|
|
||||||
if (!(msg->flags & I2C_M_NOSTART))
|
if (!(msg->flags & I2C_M_NOSTART))
|
||||||
/* write the address */
|
/* write the address */
|
||||||
@@ -638,6 +646,7 @@ static void xiic_start_send(struct xiic_i2c *i2c)
|
|||||||
static void __xiic_start_xfer(struct xiic_i2c *i2c)
|
static void __xiic_start_xfer(struct xiic_i2c *i2c)
|
||||||
{
|
{
|
||||||
int fifo_space = xiic_tx_fifo_space(i2c);
|
int fifo_space = xiic_tx_fifo_space(i2c);
|
||||||
|
|
||||||
dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, fifos space: %d\n",
|
dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, fifos space: %d\n",
|
||||||
__func__, i2c->tx_msg, fifo_space);
|
__func__, i2c->tx_msg, fifo_space);
|
||||||
|
|
||||||
@@ -739,7 +748,6 @@ static const struct i2c_adapter xiic_adapter = {
|
|||||||
.quirks = &xiic_quirks,
|
.quirks = &xiic_quirks,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static int xiic_i2c_probe(struct platform_device *pdev)
|
static int xiic_i2c_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct xiic_i2c *i2c;
|
struct xiic_i2c *i2c;
|
||||||
@@ -899,6 +907,7 @@ static const struct dev_pm_ops xiic_dev_pm_ops = {
|
|||||||
SET_RUNTIME_PM_OPS(xiic_i2c_runtime_suspend,
|
SET_RUNTIME_PM_OPS(xiic_i2c_runtime_suspend,
|
||||||
xiic_i2c_runtime_resume, NULL)
|
xiic_i2c_runtime_resume, NULL)
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct platform_driver xiic_i2c_driver = {
|
static struct platform_driver xiic_i2c_driver = {
|
||||||
.probe = xiic_i2c_probe,
|
.probe = xiic_i2c_probe,
|
||||||
.remove = xiic_i2c_remove,
|
.remove = xiic_i2c_remove,
|
||||||
@@ -914,4 +923,3 @@ module_platform_driver(xiic_i2c_driver);
|
|||||||
MODULE_AUTHOR("info@mocean-labs.com");
|
MODULE_AUTHOR("info@mocean-labs.com");
|
||||||
MODULE_DESCRIPTION("Xilinx I2C bus driver");
|
MODULE_DESCRIPTION("Xilinx I2C bus driver");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
MODULE_ALIAS("platform:"DRIVER_NAME);
|
|
||||||
|
|||||||
Reference in New Issue
Block a user