// SPDX-License-Identifier: GPL-2.0-only /* * Driver for I2C adapter in Rockchip RK3xxx SoC * * Max Schwarz <max.schwarz@online.de> * based on the patches by Rockchip Inc.
*/
/** * struct i2c_spec_values - I2C specification values for various modes * @min_hold_start_ns: min hold time (repeated) START condition * @min_low_ns: min LOW period of the SCL clock * @min_high_ns: min HIGH period of the SCL cloc * @min_setup_start_ns: min set-up time for a repeated START conditio * @max_data_hold_ns: max data hold time * @min_data_setup_ns: min data set-up time * @min_setup_stop_ns: min set-up time for STOP condition * @min_hold_buffer_ns: min bus free time between a STOP and * START condition
*/ struct i2c_spec_values { unsignedlong min_hold_start_ns; unsignedlong min_low_ns; unsignedlong min_high_ns; unsignedlong min_setup_start_ns; unsignedlong max_data_hold_ns; unsignedlong min_data_setup_ns; unsignedlong min_setup_stop_ns; unsignedlong min_hold_buffer_ns;
};
/** * struct rk3x_i2c_calced_timings - calculated V1 timings * @div_low: Divider output for low * @div_high: Divider output for high * @tuning: Used to adjust setup/hold data time, * setup/hold start time and setup stop time for * v1's calc_timings, the tuning should all be 0 * for old hardware anyone using v0's calc_timings.
*/ struct rk3x_i2c_calced_timings { unsignedlong div_low; unsignedlong div_high; unsignedint tuning;
};
/** * struct rk3x_i2c_soc_data - SOC-specific data * @grf_offset: offset inside the grf regmap for setting the i2c type * @calc_timings: Callback function for i2c timing information calculated
*/ struct rk3x_i2c_soc_data { int grf_offset; int (*calc_timings)(unsignedlong, struct i2c_timings *, struct rk3x_i2c_calced_timings *);
};
/** * struct rk3x_i2c - private data of the controller * @adap: corresponding I2C adapter * @dev: device for this controller * @soc_data: related soc data struct * @regs: virtual memory area * @clk: function clk for rk3399 or function & Bus clks for others * @pclk: Bus clk for rk3399 * @clk_rate_nb: i2c clk rate change notify * @irq: irq number * @t: I2C known timing information * @lock: spinlock for the i2c bus * @wait: the waitqueue to wait for i2c transfer * @busy: the condition for the event to wait for * @msg: current i2c message * @addr: addr of i2c target device * @mode: mode of i2c transfer * @is_last_msg: flag determines whether it is the last msg in this transfer * @state: state of i2c transfer * @processed: byte length which has been send or received * @error: error code for i2c transfer
*/ struct rk3x_i2c { struct i2c_adapter adap; struct device *dev; conststruct rk3x_i2c_soc_data *soc_data;
ctrl = i2c_readl(i2c, REG_CON);
ctrl |= REG_CON_STOP;
i2c_writel(i2c, ctrl, REG_CON);
} else { /* Signal rk3x_i2c_xfer to start the next message. */
i2c->busy = false;
i2c->state = STATE_IDLE;
/* * The HW is actually not capable of REPEATED START. But we can * get the intended effect by resetting its internal state * and issuing an ordinary START.
*/
ctrl = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
i2c_writel(i2c, ctrl, REG_CON);
/* signal that we are finished with the current msg */
wake_up(&i2c->wait);
}
}
/** * rk3x_i2c_prepare_read - Setup a read according to i2c->msg * @i2c: target controller data
*/ staticvoid rk3x_i2c_prepare_read(struct rk3x_i2c *i2c)
{ unsignedint len = i2c->msg->len - i2c->processed;
u32 con;
con = i2c_readl(i2c, REG_CON);
/* * The hw can read up to 32 bytes at a time. If we need more than one * chunk, send an ACK after the last byte of the current chunk.
*/ if (len > 32) {
len = 32;
con &= ~REG_CON_LASTACK;
} else {
con |= REG_CON_LASTACK;
}
/* make sure we are in plain RX mode if we read a second chunk */ if (i2c->processed != 0) {
con &= ~REG_CON_MOD_MASK;
con |= REG_CON_MOD(REG_CON_MOD_RX);
}
/** * rk3x_i2c_fill_transmit_buf - Fill the transmit buffer with data from i2c->msg * @i2c: target controller data
*/ staticvoid rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c)
{ unsignedint i, j;
u32 cnt = 0;
u32 val;
u8 byte;
for (i = 0; i < 8; ++i) {
val = 0; for (j = 0; j < 4; ++j) { if ((i2c->processed == i2c->msg->len) && (cnt != 0)) break;
dev_dbg(i2c->dev, "IRQ: state %d, ipd: %x\n", i2c->state, ipd);
/* Clean interrupt bits we don't care about */
ipd &= ~(REG_INT_BRF | REG_INT_BTF);
if (ipd & REG_INT_NAKRCV) { /* * We got a NACK in the last operation. Depending on whether * IGNORE_NAK is set, we have to stop the operation and report * an error.
*/
i2c_writel(i2c, REG_INT_NAKRCV, REG_IPD);
ipd &= ~REG_INT_NAKRCV;
if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
rk3x_i2c_stop(i2c, -ENXIO);
}
/* is there anything left to handle? */ if ((ipd & REG_INT_ALL) == 0) goto out;
switch (i2c->state) { case STATE_START:
rk3x_i2c_handle_start(i2c, ipd); break; case STATE_WRITE:
rk3x_i2c_handle_write(i2c, ipd); break; case STATE_READ:
rk3x_i2c_handle_read(i2c, ipd); break; case STATE_STOP:
rk3x_i2c_handle_stop(i2c, ipd); break; case STATE_IDLE: break;
}
/** * rk3x_i2c_v0_calc_timings - Calculate divider values for desired SCL frequency * @clk_rate: I2C input clock rate * @t: Known I2C timing information * @t_calc: Caculated rk3x private timings that would be written into regs * * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case * a best-effort divider value is returned in divs. If the target rate is * too high, we silently use the highest possible rate.
*/ staticint rk3x_i2c_v0_calc_timings(unsignedlong clk_rate, struct i2c_timings *t, struct rk3x_i2c_calced_timings *t_calc)
{ unsignedlong min_low_ns, min_high_ns; unsignedlong max_low_ns, min_total_ns;
unsignedlong data_hold_buffer_ns = 50; conststruct i2c_spec_values *spec; int ret = 0;
/* Only support standard-mode and fast-mode */ if (WARN_ON(t->bus_freq_hz > I2C_MAX_FAST_MODE_FREQ))
t->bus_freq_hz = I2C_MAX_FAST_MODE_FREQ;
/* prevent scl_rate_khz from becoming 0 */ if (WARN_ON(t->bus_freq_hz < 1000))
t->bus_freq_hz = 1000;
/* * min_low_ns: The minimum number of ns we need to hold low to * meet I2C specification, should include fall time. * min_high_ns: The minimum number of ns we need to hold high to * meet I2C specification, should include rise time. * max_low_ns: The maximum number of ns we can hold low to meet * I2C specification. * * Note: max_low_ns should be (maximum data hold time * 2 - buffer) * This is because the i2c host on Rockchip holds the data line * for half the low time.
*/
spec = rk3x_i2c_get_spec(t->bus_freq_hz);
min_high_ns = t->scl_rise_ns + spec->min_high_ns;
/* * Timings for repeated start: * - controller appears to drop SDA at .875x (7/8) programmed clk high. * - controller appears to keep SCL high for 2x programmed clk high. * * We need to account for those rules in picking our "high" time so * we meet tSU;STA and tHD;STA times.
*/
min_high_ns = max(min_high_ns, DIV_ROUND_UP(
(t->scl_rise_ns + spec->min_setup_start_ns) * 1000, 875));
min_high_ns = max(min_high_ns, DIV_ROUND_UP(
(t->scl_rise_ns + spec->min_setup_start_ns + t->sda_fall_ns +
spec->min_high_ns), 2));
/* * We need the total div to be >= this number * so we don't clock too fast.
*/
min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8);
/* These are the min dividers needed for min hold times. */
min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000);
min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000);
min_div_for_hold = (min_low_div + min_high_div);
/* * This is the maximum divider so we don't go over the maximum. * We don't round up here (we round down) since this is a maximum.
*/
max_low_div = clk_rate_khz * max_low_ns / (8 * 1000000);
if (min_div_for_hold > min_total_div) { /* * Time needed to meet hold requirements is important. * Just use that.
*/
t_calc->div_low = min_low_div;
t_calc->div_high = min_high_div;
} else { /* * We've got to distribute some time among the low and high * so we don't run too fast.
*/
extra_div = min_total_div - min_div_for_hold;
/* * We'll try to split things up perfectly evenly, * biasing slightly towards having a higher div * for low (spend more time low).
*/
ideal_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns,
scl_rate_khz * 8 * min_total_ns);
/* Don't allow it to go over the maximum */ if (ideal_low_div > max_low_div)
ideal_low_div = max_low_div;
/* * Handle when the ideal low div is going to take up * more than we have.
*/ if (ideal_low_div > min_low_div + extra_div)
ideal_low_div = min_low_div + extra_div;
/* Give low the "ideal" and give high whatever extra is left */
extra_low_div = ideal_low_div - min_low_div;
t_calc->div_low = ideal_low_div;
t_calc->div_high = min_high_div + (extra_div - extra_low_div);
}
/* * Adjust to the fact that the hardware has an implicit "+1". * NOTE: Above calculations always produce div_low > 0 and div_high > 0.
*/
t_calc->div_low--;
t_calc->div_high--;
/* Give the tuning value 0, that would not update con register */
t_calc->tuning = 0; /* Maximum divider supported by hw is 0xffff */ if (t_calc->div_low > 0xffff) {
t_calc->div_low = 0xffff;
ret = -EINVAL;
}
if (t_calc->div_high > 0xffff) {
t_calc->div_high = 0xffff;
ret = -EINVAL;
}
return ret;
}
/** * rk3x_i2c_v1_calc_timings - Calculate timing values for desired SCL frequency * @clk_rate: I2C input clock rate * @t: Known I2C timing information * @t_calc: Caculated rk3x private timings that would be written into regs * * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case * a best-effort divider value is returned in divs. If the target rate is * too high, we silently use the highest possible rate. * The following formulas are v1's method to calculate timings. * * l = divl + 1; * h = divh + 1; * s = sda_update_config + 1; * u = start_setup_config + 1; * p = stop_setup_config + 1; * T = Tclk_i2c; * * tHigh = 8 * h * T; * tLow = 8 * l * T; * * tHD;sda = (l * s + 1) * T; * tSU;sda = [(8 - s) * l + 1] * T; * tI2C = 8 * (l + h) * T; * * tSU;sta = (8h * u + 1) * T; * tHD;sta = [8h * (u + 1) - 1] * T; * tSU;sto = (8h * p + 1) * T;
*/ staticint rk3x_i2c_v1_calc_timings(unsignedlong clk_rate, struct i2c_timings *t, struct rk3x_i2c_calced_timings *t_calc)
{ unsignedlong min_low_ns, min_high_ns; unsignedlong min_setup_start_ns, min_setup_data_ns; unsignedlong min_setup_stop_ns, max_hold_data_ns;
/* Support standard-mode, fast-mode and fast-mode plus */ if (WARN_ON(t->bus_freq_hz > I2C_MAX_FAST_MODE_PLUS_FREQ))
t->bus_freq_hz = I2C_MAX_FAST_MODE_PLUS_FREQ;
/* prevent scl_rate_khz from becoming 0 */ if (WARN_ON(t->bus_freq_hz < 1000))
t->bus_freq_hz = 1000;
/* * min_low_ns: The minimum number of ns we need to hold low to * meet I2C specification, should include fall time. * min_high_ns: The minimum number of ns we need to hold high to * meet I2C specification, should include rise time.
*/
spec = rk3x_i2c_get_spec(t->bus_freq_hz);
/* * Final divh and divl must be greater than 0, otherwise the * hardware would not output the i2c clk.
*/
min_high_div = (min_high_div < 1) ? 2 : min_high_div;
min_low_div = (min_low_div < 1) ? 2 : min_low_div;
/* These are the min dividers needed for min hold times. */
min_div_for_hold = (min_low_div + min_high_div);
/* * This is the maximum divider so we don't go over the maximum. * We don't round up here (we round down) since this is a maximum.
*/ if (min_div_for_hold >= min_total_div) { /* * Time needed to meet hold requirements is important. * Just use that.
*/
t_calc->div_low = min_low_div;
t_calc->div_high = min_high_div;
} else { /* * We've got to distribute some time among the low and high * so we don't run too fast. * We'll try to split things up by the scale of min_low_div and * min_high_div, biasing slightly towards having a higher div * for low (spend more time low).
*/
extra_div = min_total_div - min_div_for_hold;
extra_low_div = DIV_ROUND_UP(min_low_div * extra_div,
min_div_for_hold);
/** * rk3x_i2c_clk_notifier_cb - Clock rate change callback * @nb: Pointer to notifier block * @event: Notification reason * @data: Pointer to notification data object * * The callback checks whether a valid bus frequency can be generated after the * change. If so, the change is acknowledged, otherwise the change is aborted. * New dividers are written to the HW in the pre- or post change notification * depending on the scaling direction. * * Code adapted from i2c-cadence.c. * * Return: NOTIFY_STOP if the rate change should be aborted, NOTIFY_OK * to acknowledge the change, NOTIFY_DONE if the notification is * considered irrelevant.
*/ staticint rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsignedlong
event, void *data)
{ struct clk_notifier_data *ndata = data; struct rk3x_i2c *i2c = container_of(nb, struct rk3x_i2c, clk_rate_nb); struct rk3x_i2c_calced_timings calc;
switch (event) { case PRE_RATE_CHANGE: /* * Try the calculation (but don't store the result) ahead of * time to see if we need to block the clock change. Timings * shouldn't actually take effect until rk3x_i2c_adapt_div().
*/ if (i2c->soc_data->calc_timings(ndata->new_rate, &i2c->t,
&calc) != 0) return NOTIFY_STOP;
/* scale up */ if (ndata->new_rate > ndata->old_rate)
rk3x_i2c_adapt_div(i2c, ndata->new_rate);
return NOTIFY_OK; case POST_RATE_CHANGE: /* scale down */ if (ndata->new_rate < ndata->old_rate)
rk3x_i2c_adapt_div(i2c, ndata->new_rate); return NOTIFY_OK; case ABORT_RATE_CHANGE: /* scale up */ if (ndata->new_rate > ndata->old_rate)
rk3x_i2c_adapt_div(i2c, ndata->old_rate); return NOTIFY_OK; default: return NOTIFY_DONE;
}
}
/** * rk3x_i2c_setup - Setup I2C registers for an I2C operation specified by msgs, num. * @i2c: target controller data * @msgs: I2C msgs to process * @num: Number of msgs * * Must be called with i2c->lock held. * * Return: Number of I2C msgs processed or negative in case of error
*/ staticint rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num)
{
u32 addr = (msgs[0].addr & 0x7f) << 1; int ret = 0;
/* * The I2C adapter can issue a small (len < 4) write packet before * reading. This speeds up SMBus-style register reads. * The MRXADDR/MRXRADDR hold the target address and the target register * address in this case.
*/
dev_dbg(i2c->dev, "Combined write/read from addr 0x%x\n",
addr >> 1);
/* Fill MRXRADDR with the register address(es) */ for (i = 0; i < msgs[0].len; ++i) {
reg_addr |= msgs[0].buf[i] << (i * 8);
reg_addr |= REG_MRXADDR_VALID(i);
}
/* msgs[0] is handled by hw. */
i2c->msg = &msgs[1];
ret = 2;
} else { /* * We'll have to do it the boring way and process the msgs * one-by-one.
*/
if (msgs[0].flags & I2C_M_RD) {
addr |= 1; /* set read bit */
/* * We have to transmit the target addr first. Use * MOD_REGISTER_TX for that purpose.
*/
i2c->mode = REG_CON_MOD_REGISTER_TX;
i2c_writel(i2c, addr | REG_MRXADDR_VALID(0),
REG_MRXADDR);
i2c_writel(i2c, 0, REG_MRXRADDR);
} else {
i2c->mode = REG_CON_MOD_TX;
}
staticint rk3x_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg *msgs, int num, bool polling)
{ struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data; unsignedlong flags; long time_left;
u32 val; int ret = 0; int i;
spin_lock_irqsave(&i2c->lock, flags);
clk_enable(i2c->clk);
clk_enable(i2c->pclk);
i2c->is_last_msg = false;
/* * Process msgs. We can handle more than one message at once (see * rk3x_i2c_setup()).
*/ for (i = 0; i < num; i += ret) {
ret = rk3x_i2c_setup(i2c, msgs + i, num - i);
if (ret < 0) {
dev_err(i2c->dev, "rk3x_i2c_setup() failed\n"); break;
}
if (time_left == 0) { /* Force a STOP condition without interrupt */
i2c_writel(i2c, 0, REG_IEN);
val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
val |= REG_CON_EN | REG_CON_STOP;
i2c_writel(i2c, val, REG_CON);
i2c->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(i2c->regs)) return PTR_ERR(i2c->regs);
/* Try to set the I2C adapter number from dt */
bus_nr = of_alias_get_id(np, "i2c");
/* * Switch to new interface if the SoC also offers the old one. * The control bit is located in the GRF register space.
*/ if (i2c->soc_data->grf_offset >= 0) { struct regmap *grf;
ret = devm_request_irq(&pdev->dev, irq, rk3x_i2c_irq,
0, dev_name(&pdev->dev), i2c); if (ret < 0) {
dev_err(&pdev->dev, "cannot request IRQ\n"); return ret;
}
i2c->irq = irq;
platform_set_drvdata(pdev, i2c);
if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) { /* Only one clock to use for bus clock and peripheral clock */
i2c->clk = devm_clk_get(&pdev->dev, NULL);
i2c->pclk = i2c->clk;
} else {
i2c->clk = devm_clk_get(&pdev->dev, "i2c");
i2c->pclk = devm_clk_get(&pdev->dev, "pclk");
}
if (IS_ERR(i2c->clk)) return dev_err_probe(&pdev->dev, PTR_ERR(i2c->clk), "Can't get bus clk\n");
if (IS_ERR(i2c->pclk)) return dev_err_probe(&pdev->dev, PTR_ERR(i2c->pclk), "Can't get periph clk\n");
ret = clk_prepare(i2c->clk); if (ret < 0) {
dev_err(&pdev->dev, "Can't prepare bus clk: %d\n", ret); return ret;
}
ret = clk_prepare(i2c->pclk); if (ret < 0) {
dev_err(&pdev->dev, "Can't prepare periph clock: %d\n", ret); goto err_clk;
}
i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb;
ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb); if (ret != 0) {
dev_err(&pdev->dev, "Unable to register clock notifier\n"); goto err_pclk;
}
ret = clk_enable(i2c->clk); if (ret < 0) {
dev_err(&pdev->dev, "Can't enable bus clk: %d\n", ret); goto err_clk_notifier;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.