static int cdns_i2c_set_bus_speed(struct udevice *dev, unsigned int speed) { struct i2c_cdns_bus *bus = dev_get_priv(dev); u32 div_a = 0, div_b = 0; unsigned long speed_p = speed; int ret = 0; if (speed > 400000) { debug("%s, failed to set clock speed to %u\n", __func__, speed); return -EINVAL; } ret = cdns_i2c_calc_divs(&speed_p, bus->input_freq, &div_a, &div_b); if (ret) return ret; debug("%s: div_a: %d, div_b: %d, input freq: %d, speed: %d/%ld\n", __func__, div_a, div_b, bus->input_freq, speed, speed_p); writel((div_b << CDNS_I2C_CONTROL_DIV_B_SHIFT) | (div_a << CDNS_I2C_CONTROL_DIV_A_SHIFT), &bus->regs->control); /* Enable master mode, ack, and 7-bit addressing */ setbits_le32(&bus->regs->control, CDNS_I2C_CONTROL_MS | CDNS_I2C_CONTROL_ACKEN | CDNS_I2C_CONTROL_NEA); return 0; }
/** * cdns_i2c_clk_notifier_cb - Clock rate change callback * @nb: Pointer to notifier block * @event: Notification reason * @data: Pointer to notification data object * * This function is called when the cdns_i2c input clock frequency changes. * 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. * * Return: NOTIFY_STOP if the rate change should be aborted, NOTIFY_OK * to acknowedge the change, NOTIFY_DONE if the notification is * considered irrelevant. */ static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long event, void *data) { struct clk_notifier_data *ndata = data; struct cdns_i2c *id = to_cdns_i2c(nb); if (pm_runtime_suspended(id->dev)) return NOTIFY_OK; switch (event) { case PRE_RATE_CHANGE: { unsigned long input_clk = ndata->new_rate; unsigned long fscl = id->i2c_clk; unsigned int div_a, div_b; int ret; ret = cdns_i2c_calc_divs(&fscl, input_clk, &div_a, &div_b); if (ret) { dev_warn(id->adap.dev.parent, "clock rate change rejected\n"); return NOTIFY_STOP; } /* scale up */ if (ndata->new_rate > ndata->old_rate) cdns_i2c_setclk(ndata->new_rate, id); return NOTIFY_OK; } case POST_RATE_CHANGE: id->input_clk = ndata->new_rate; /* scale down */ if (ndata->new_rate < ndata->old_rate) cdns_i2c_setclk(ndata->new_rate, id); return NOTIFY_OK; case ABORT_RATE_CHANGE: /* scale up */ if (ndata->new_rate > ndata->old_rate) cdns_i2c_setclk(ndata->old_rate, id); return NOTIFY_OK; default: return NOTIFY_DONE; } }
/** * cdns_i2c_setclk - This function sets the serial clock rate for the I2C device * @clk_in: I2C clock input frequency in Hz * @id: Pointer to the I2C device structure * * The device must be idle rather than busy transferring data before setting * these device options. * The data rate is set by values in the control register. * The formula for determining the correct register values is * Fscl = Fpclk/(22 x (divisor_a+1) x (divisor_b+1)) * See the hardware data sheet for a full explanation of setting the serial * clock rate. The clock can not be faster than the input clock divide by 22. * The two most common clock rates are 100KHz and 400KHz. * * Return: 0 on success, negative error otherwise */ static int cdns_i2c_setclk(unsigned long clk_in, struct cdns_i2c *id) { unsigned int div_a, div_b; unsigned int ctrl_reg; int ret = 0; unsigned long fscl = id->i2c_clk; ret = cdns_i2c_calc_divs(&fscl, clk_in, &div_a, &div_b); if (ret) return ret; ctrl_reg = id->ctrl_reg; ctrl_reg &= ~(CDNS_I2C_CR_DIVA_MASK | CDNS_I2C_CR_DIVB_MASK); ctrl_reg |= ((div_a << CDNS_I2C_CR_DIVA_SHIFT) | (div_b << CDNS_I2C_CR_DIVB_SHIFT)); id->ctrl_reg = ctrl_reg; return 0; }