Lines Matching +full:i2c +full:- +full:scl +full:- +full:hz
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Synopsys DesignWare I2C adapter driver.
5 * Based on the TI DAVINCI I2C adapter driver.
18 #include <linux/i2c.h>
29 #include "i2c-designware-core.h"
59 "incorrect slave-transmitter mode configuration",
66 *val = readl_relaxed(dev->base + reg); in dw_reg_read()
75 writel_relaxed(val, dev->base + reg); in dw_reg_write()
84 *val = swab32(readl_relaxed(dev->base + reg)); in dw_reg_read_swab()
93 writel_relaxed(swab32(val), dev->base + reg); in dw_reg_write_swab()
102 *val = readw_relaxed(dev->base + reg) | in dw_reg_read_word()
103 (readw_relaxed(dev->base + reg + 2) << 16); in dw_reg_read_word()
112 writew_relaxed(val, dev->base + reg); in dw_reg_write_word()
113 writew_relaxed(val >> 16, dev->base + reg + 2); in dw_reg_write_word()
119 * i2c_dw_init_regmap() - Initialize registers map
144 if (dev->map) in i2c_dw_init_regmap()
151 reg = readl(dev->base + DW_IC_COMP_TYPE); in i2c_dw_init_regmap()
154 if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU) in i2c_dw_init_regmap()
164 dev_err(dev->dev, in i2c_dw_init_regmap()
166 return -ENODEV; in i2c_dw_init_regmap()
172 * basically we have MMIO-based regmap so non of the read/write methods in i2c_dw_init_regmap()
175 dev->map = devm_regmap_init(dev->dev, NULL, dev, &map_cfg); in i2c_dw_init_regmap()
176 if (IS_ERR(dev->map)) { in i2c_dw_init_regmap()
177 dev_err(dev->dev, "Failed to init the registers map\n"); in i2c_dw_init_regmap()
178 return PTR_ERR(dev->map); in i2c_dw_init_regmap()
193 struct i2c_timings *t = &dev->timings; in i2c_dw_validate_speed()
201 if (t->bus_freq_hz == supported_speeds[i]) in i2c_dw_validate_speed()
205 dev_err(dev->dev, in i2c_dw_validate_speed()
206 "%d Hz is unsupported, only 100kHz, 400kHz, 1MHz and 3.4MHz are supported\n", in i2c_dw_validate_speed()
207 t->bus_freq_hz); in i2c_dw_validate_speed()
209 return -EINVAL; in i2c_dw_validate_speed()
247 if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 3) { in i2c_dw_acpi_params()
248 const union acpi_object *objs = obj->package.elements; in i2c_dw_acpi_params()
261 struct i2c_timings *t = &dev->timings; in i2c_dw_acpi_configure()
268 i2c_dw_acpi_params(device, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, &ss_ht); in i2c_dw_acpi_configure()
269 i2c_dw_acpi_params(device, "FPCN", &dev->fp_hcnt, &dev->fp_lcnt, &fp_ht); in i2c_dw_acpi_configure()
270 i2c_dw_acpi_params(device, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt, &hs_ht); in i2c_dw_acpi_configure()
271 i2c_dw_acpi_params(device, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, &fs_ht); in i2c_dw_acpi_configure()
273 switch (t->bus_freq_hz) { in i2c_dw_acpi_configure()
275 dev->sda_hold_time = ss_ht; in i2c_dw_acpi_configure()
278 dev->sda_hold_time = fp_ht; in i2c_dw_acpi_configure()
281 dev->sda_hold_time = hs_ht; in i2c_dw_acpi_configure()
285 dev->sda_hold_time = fs_ht; in i2c_dw_acpi_configure()
319 u32 acpi_speed = i2c_dw_acpi_round_bus_speed(dev->dev); in i2c_dw_adjust_bus_speed()
320 struct i2c_timings *t = &dev->timings; in i2c_dw_adjust_bus_speed()
323 * Find bus speed from the "clock-frequency" device property, ACPI in i2c_dw_adjust_bus_speed()
326 if (acpi_speed && t->bus_freq_hz) in i2c_dw_adjust_bus_speed()
327 t->bus_freq_hz = min(t->bus_freq_hz, acpi_speed); in i2c_dw_adjust_bus_speed()
328 else if (acpi_speed || t->bus_freq_hz) in i2c_dw_adjust_bus_speed()
329 t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed); in i2c_dw_adjust_bus_speed()
331 t->bus_freq_hz = I2C_MAX_FAST_MODE_FREQ; in i2c_dw_adjust_bus_speed()
338 * DesignWare I2C core doesn't seem to have solid strategy to meet in i2c_dw_scl_hcnt()
349 * configuration. The resulting I2C bus speed will be in i2c_dw_scl_hcnt()
354 return DIV_ROUND_CLOSEST(ic_clk * tSYMBOL, MICRO) - 8 + offset; in i2c_dw_scl_hcnt()
370 return DIV_ROUND_CLOSEST(ic_clk * (tSYMBOL + tf), MICRO) - 3 + offset; in i2c_dw_scl_hcnt()
380 * DW I2C core starts counting the SCL CNTs for the LOW period in i2c_dw_scl_lcnt()
381 * of the SCL clock (tLOW) as soon as it pulls the SCL line. in i2c_dw_scl_lcnt()
383 * account the fall time of SCL signal (tf). Default tf value in i2c_dw_scl_lcnt()
386 return DIV_ROUND_CLOSEST(ic_clk * (tLOW + tf), MICRO) - 1 + offset; in i2c_dw_scl_lcnt()
399 ret = regmap_read(dev->map, DW_IC_COMP_VERSION, ®); in i2c_dw_set_sda_hold()
404 if (!dev->sda_hold_time) { in i2c_dw_set_sda_hold()
406 ret = regmap_read(dev->map, DW_IC_SDA_HOLD, in i2c_dw_set_sda_hold()
407 &dev->sda_hold_time); in i2c_dw_set_sda_hold()
413 * Workaround for avoiding TX arbitration lost in case I2C in i2c_dw_set_sda_hold()
415 * SCL by enabling non-zero SDA RX hold. Specification says it in i2c_dw_set_sda_hold()
416 * extends incoming SDA low to high transition while SCL is in i2c_dw_set_sda_hold()
419 if (!(dev->sda_hold_time & DW_IC_SDA_HOLD_RX_MASK)) in i2c_dw_set_sda_hold()
420 dev->sda_hold_time |= 1 << DW_IC_SDA_HOLD_RX_SHIFT; in i2c_dw_set_sda_hold()
422 dev_dbg(dev->dev, "SDA Hold Time TX:RX = %d:%d\n", in i2c_dw_set_sda_hold()
423 dev->sda_hold_time & ~(u32)DW_IC_SDA_HOLD_RX_MASK, in i2c_dw_set_sda_hold()
424 dev->sda_hold_time >> DW_IC_SDA_HOLD_RX_SHIFT); in i2c_dw_set_sda_hold()
425 } else if (dev->set_sda_hold_time) { in i2c_dw_set_sda_hold()
426 dev->set_sda_hold_time(dev); in i2c_dw_set_sda_hold()
427 } else if (dev->sda_hold_time) { in i2c_dw_set_sda_hold()
428 dev_warn(dev->dev, in i2c_dw_set_sda_hold()
430 dev->sda_hold_time = 0; in i2c_dw_set_sda_hold()
450 regmap_read(dev->map, DW_IC_ENABLE_STATUS, &status); in __i2c_dw_disable()
455 * Wait 10 times the signaling period of the highest I2C in __i2c_dw_disable()
457 * 25us) as described in the DesignWare I2C databook. in __i2c_dw_disable()
460 } while (timeout--); in __i2c_dw_disable()
462 dev_warn(dev->dev, "timeout in disabling adapter\n"); in __i2c_dw_disable()
471 if (WARN_ON_ONCE(!dev->get_clk_rate_khz)) in i2c_dw_clk_rate()
473 return dev->get_clk_rate_khz(dev); in i2c_dw_clk_rate()
480 if (IS_ERR(dev->clk)) in i2c_dw_prepare_clk()
481 return PTR_ERR(dev->clk); in i2c_dw_prepare_clk()
485 ret = clk_prepare_enable(dev->pclk); in i2c_dw_prepare_clk()
489 ret = clk_prepare_enable(dev->clk); in i2c_dw_prepare_clk()
491 clk_disable_unprepare(dev->pclk); in i2c_dw_prepare_clk()
496 clk_disable_unprepare(dev->clk); in i2c_dw_prepare_clk()
497 clk_disable_unprepare(dev->pclk); in i2c_dw_prepare_clk()
507 if (!dev->acquire_lock) in i2c_dw_acquire_lock()
510 ret = dev->acquire_lock(); in i2c_dw_acquire_lock()
514 dev_err(dev->dev, "couldn't acquire bus ownership\n"); in i2c_dw_acquire_lock()
521 if (dev->release_lock) in i2c_dw_release_lock()
522 dev->release_lock(); in i2c_dw_release_lock()
533 ret = regmap_read_poll_timeout(dev->map, DW_IC_STATUS, status, in i2c_dw_wait_bus_not_busy()
537 dev_warn(dev->dev, "timeout waiting for bus ready\n"); in i2c_dw_wait_bus_not_busy()
539 i2c_recover_bus(&dev->adapter); in i2c_dw_wait_bus_not_busy()
541 regmap_read(dev->map, DW_IC_STATUS, &status); in i2c_dw_wait_bus_not_busy()
551 unsigned long abort_source = dev->abort_source; in i2c_dw_handle_tx_abort()
556 dev_dbg(dev->dev, in i2c_dw_handle_tx_abort()
558 return -EREMOTEIO; in i2c_dw_handle_tx_abort()
562 dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]); in i2c_dw_handle_tx_abort()
565 return -EAGAIN; in i2c_dw_handle_tx_abort()
567 return -EINVAL; /* wrong msgs[] data */ in i2c_dw_handle_tx_abort()
569 return -EIO; in i2c_dw_handle_tx_abort()
581 ret = regmap_read(dev->map, DW_IC_COMP_PARAM_1, ¶m); in i2c_dw_set_fifo_size()
587 if (!dev->tx_fifo_depth) { in i2c_dw_set_fifo_size()
588 dev->tx_fifo_depth = tx_fifo_depth; in i2c_dw_set_fifo_size()
589 dev->rx_fifo_depth = rx_fifo_depth; in i2c_dw_set_fifo_size()
591 dev->tx_fifo_depth = min_t(u32, dev->tx_fifo_depth, in i2c_dw_set_fifo_size()
593 dev->rx_fifo_depth = min_t(u32, dev->rx_fifo_depth, in i2c_dw_set_fifo_size()
604 return dev->functionality; in i2c_dw_func()
615 regmap_write(dev->map, DW_IC_INTR_MASK, 0); in i2c_dw_disable()
616 regmap_read(dev->map, DW_IC_CLR_INTR, &dummy); in i2c_dw_disable()
621 regmap_write(dev->map, DW_IC_INTR_MASK, 0); in i2c_dw_disable_int()
624 MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core");