/* * HSI2C controller from Samsung supports 2 modes of operation * 1. Auto mode: Where in master automatically controls the whole transaction * 2. Manual mode: Software controls the transaction by issuing commands * START, READ, WRITE, STOP, RESTART in I2C_MANUAL_CMD register. * * Operation mode can be selected by setting AUTO_MODE bit in I2C_CONF register * * Special bits are available for both modes of operation to set commands * and for checking transfer status
*/
/* * Since the TRANS_DONE bit is cleared on read, and we may read it * either during an IRQ or after a transaction, keep track of its * state here.
*/ int trans_done;
/* * Called from atomic context, don't use interrupts.
*/ unsignedint atomic;
/* Controller operating frequency */ unsignedint op_clock;
/* Version of HS-I2C Hardware */ conststruct exynos_hsi2c_variant *variant;
};
/** * struct exynos_hsi2c_variant - platform specific HSI2C driver data * @fifo_depth: the fifo depth supported by the HSI2C module * @hw: the hardware variant of Exynos I2C controller * * Specifies platform specific configuration of HSI2C module. * Note: A structure for driver specific platform data is used for future * expansion of its usage.
*/ struct exynos_hsi2c_variant { unsignedint fifo_depth; enum i2c_type_exynos hw;
};
/* * exynos5_i2c_set_timing: updates the registers with appropriate * timing values calculated * * Timing values for operation are calculated against 100kHz, 400kHz * or 1MHz controller operating frequency. * * Returns 0 on success, -EINVAL if the cycle length cannot * be calculated.
*/ staticint exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings)
{
u32 i2c_timing_s1;
u32 i2c_timing_s2;
u32 i2c_timing_s3;
u32 i2c_timing_sla; unsignedint t_start_su, t_start_hd; unsignedint t_stop_su; unsignedint t_data_su, t_data_hd; unsignedint t_scl_l, t_scl_h; unsignedint t_sr_release; unsignedint t_ftl_cycle; unsignedint clkin = clk_get_rate(i2c->clk); unsignedint op_clk = hs_timings ? i2c->op_clock :
(i2c->op_clock >= I2C_MAX_FAST_MODE_PLUS_FREQ) ? I2C_MAX_STANDARD_MODE_FREQ :
i2c->op_clock; int div, clk_cycle, temp;
/* * In case of HSI2C controllers in ExynosAutoV9: * * FSCL = IPCLK / ((CLK_DIV + 1) * 16) * T_SCL_LOW = IPCLK * (CLK_DIV + 1) * (N + M) * [N : number of 0's in the TSCL_H_HS] * [M : number of 0's in the TSCL_L_HS] * T_SCL_HIGH = IPCLK * (CLK_DIV + 1) * (N + M) * [N : number of 1's in the TSCL_H_HS] * [M : number of 1's in the TSCL_L_HS] * * Result of (N + M) is always 8. * In general case, we don't need to control timing_s1 and timing_s2.
*/ if (i2c->variant->hw == I2C_TYPE_EXYNOSAUTOV9) {
div = ((clkin / (16 * i2c->op_clock)) - 1);
i2c_timing_s3 = div << 16; if (hs_timings)
writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_HS3); else
writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_FS3);
return 0;
}
/* * In case of HSI2C controller in Exynos5 series * FPCLK / FI2C = * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE * * In case of HSI2C controllers in Exynos7 series * FPCLK / FI2C = * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + FLT_CYCLE * * clk_cycle := TSCLK_L + TSCLK_H * temp := (CLK_DIV + 1) * (clk_cycle + 2) * * In case of HSI2C controllers in Exynos8895 * FPCLK / FI2C = * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + * 2 * ((FLT_CYCLE + 3) - (FLT_CYCLE + 3) % (CLK_DIV + 1)) * * clk_cycle := TSCLK_L + TSCLK_H * temp := (FPCLK / FI2C) - (FLT_CYCLE + 3) * 2 * * Constraints: 4 <= temp, 0 <= CLK_DIV < 256, 2 <= clk_cycle <= 510 * * To split SCL clock into low, high periods appropriately, one * proportion factor for each I2C mode is used, which is calculated * using this formula. * ``` * ((t_low_min + (scl_clock - t_low_min - t_high_min) / 2) / scl_clock) * ``` * where: * t_low_min is the minimal value of low period of the SCL clock in us; * t_high_min is the minimal value of high period of the SCL clock in us; * scl_clock is converted from SCL clock frequency into us. * * Below are the proportion factors for these I2C modes: * t_low_min, t_high_min, scl_clock, proportion * Standard Mode: 4.7us, 4.0us, 10us, 0.535 * Fast Mode: 1.3us, 0.6us, 2.5us, 0.64 * Fast-Plus Mode: 0.5us, 0.26us, 1us, 0.62 *
*/
t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7; if (i2c->variant->hw == I2C_TYPE_EXYNOS8895)
temp = clkin / op_clk - (t_ftl_cycle + 3) * 2; elseif (i2c->variant->hw == I2C_TYPE_EXYNOS7)
temp = clkin / op_clk - 8 - t_ftl_cycle; else
temp = clkin / op_clk - 8 - (t_ftl_cycle * 2);
div = temp / 512;
/* We don't expect calculations to fail during the run */
exynos5_hsi2c_clock_setup(i2c); /* Initialize the configure registers */
exynos5_i2c_init(i2c);
}
/* * exynos5_i2c_irq: top level IRQ servicing routine * * INT_STATUS registers gives the interrupt details. Further, * FIFO_STATUS or TRANS_STATUS registers are to be check for detailed * state of the bus.
*/ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id)
{ struct exynos5_i2c *i2c = dev_id;
u32 fifo_level, int_status, fifo_status, trans_status; unsignedchar byte; int len = 0;
/* * exynos5_i2c_wait_bus_idle * * Wait for the bus to go idle, indicated by the MASTER_BUSY bit being * cleared. * * Returns -EBUSY if the bus cannot be bought to idle
*/ staticint exynos5_i2c_wait_bus_idle(struct exynos5_i2c *i2c)
{ unsignedlong stop_time;
u32 trans_status;
/* wait for 100 milli seconds for the bus to be idle */
stop_time = jiffies + msecs_to_jiffies(100) + 1; do {
trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS); if (!(trans_status & HSI2C_MASTER_BUSY)) return 0;
usleep_range(50, 200);
} while (time_before(jiffies, stop_time));
/* * Specification says master should send nine clock pulses. It can be * emulated by sending manual read command (nine pulses for read eight * bits + one pulse for NACK).
*/
writel(HSI2C_CMD_READ_DATA, i2c->regs + HSI2C_MANUAL_CMD);
exynos5_i2c_wait_bus_idle(i2c);
writel(HSI2C_CMD_SEND_STOP, i2c->regs + HSI2C_MANUAL_CMD);
exynos5_i2c_wait_bus_idle(i2c);
/* * HSI2C_MASTER_ST_LOSE state (in Exynos7 and ExynosAutoV9 variants) * before transaction indicates that bus is stuck (SDA is low). * In such case bus recovery can be performed.
*/
timeout = jiffies + msecs_to_jiffies(100); for (;;) {
u32 st = readl(i2c->regs + HSI2C_TRANS_STATUS);
if ((st & HSI2C_MASTER_ST_MASK) != HSI2C_MASTER_ST_LOSE) return;
if (time_is_before_jiffies(timeout)) return;
exynos5_i2c_bus_recover(i2c);
}
}
/* * exynos5_i2c_message_start: Configures the bus and starts the xfer * i2c: struct exynos5_i2c pointer for the current bus * stop: Enables stop after transfer if set. Set for last transfer of * in the list of messages. * * Configures the bus for read/write function * Sets chip address to talk to, message length to be sent. * Enables appropriate interrupts and sends start xfer command.
*/ staticvoid exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop)
{
u32 i2c_ctl;
u32 int_en = 0;
u32 i2c_auto_conf = 0;
u32 i2c_addr = 0;
u32 fifo_ctl; unsignedlong flags; unsignedshort trig_lvl;
/* * Enable interrupts before starting the transfer so that we don't * miss any INT_I2C interrupts.
*/
spin_lock_irqsave(&i2c->lock, flags);
writel(int_en, i2c->regs + HSI2C_INT_ENABLE);
if (time_left == 0)
ret = -ETIMEDOUT; else
ret = i2c->state;
/* * If this is the last message to be transferred (stop == 1) * Then check if the bus can be brought back to idle.
*/ if (ret == 0 && stop)
ret = exynos5_i2c_wait_bus_idle(i2c);
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.