From f1bdb261ca5e2af8bdcacb4bd1a884865b280c7d Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 9 Sep 2019 11:15:39 +0200 Subject: i2c: port Linux i2c_parse_fw_timings Linux has a generic function for extracting i2c timings parameters from device-associated firmware nodes. Port this function to barebox, but have it only work on device tree nodes for now. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- drivers/i2c/i2c.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'drivers/i2c') diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c index 25e0fe7add..9df5ee70c7 100644 --- a/drivers/i2c/i2c.c +++ b/drivers/i2c/i2c.c @@ -556,6 +556,66 @@ struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) return NULL; } +/** + * i2c_parse_fw_timings - get I2C related timing parameters from firmware + * @dev: The device to scan for I2C timing properties + * @t: the i2c_timings struct to be filled with values + * @use_defaults: bool to use sane defaults derived from the I2C specification + * when properties are not found, otherwise use 0 + * + * Scan the device for the generic I2C properties describing timing parameters + * for the signal and fill the given struct with the results. If a property was + * not found and use_defaults was true, then maximum timings are assumed which + * are derived from the I2C specification. If use_defaults is not used, the + * results will be 0, so drivers can apply their own defaults later. The latter + * is mainly intended for avoiding regressions of existing drivers which want + * to switch to this function. New drivers almost always should use the defaults. + */ + +void i2c_parse_fw_timings(struct device_d *dev, struct i2c_timings *t, bool use_defaults) +{ + int ret; + + memset(t, 0, sizeof(*t)); + + ret = of_property_read_u32(dev->device_node, "clock-frequency", + &t->bus_freq_hz); + if (ret && use_defaults) + t->bus_freq_hz = 100000; + + ret = of_property_read_u32(dev->device_node, "i2c-scl-rising-time-ns", + &t->scl_rise_ns); + if (ret && use_defaults) { + if (t->bus_freq_hz <= 100000) + t->scl_rise_ns = 1000; + else if (t->bus_freq_hz <= 400000) + t->scl_rise_ns = 300; + else + t->scl_rise_ns = 120; + } + + ret = of_property_read_u32(dev->device_node, "i2c-scl-falling-time-ns", + &t->scl_fall_ns); + if (ret && use_defaults) { + if (t->bus_freq_hz <= 400000) + t->scl_fall_ns = 300; + else + t->scl_fall_ns = 120; + } + + of_property_read_u32(dev->device_node, "i2c-scl-internal-delay-ns", + &t->scl_int_delay_ns); + + ret = of_property_read_u32(dev->device_node, "i2c-sda-falling-time-ns", + &t->sda_fall_ns); + if (ret && use_defaults) + t->sda_fall_ns = t->scl_fall_ns; + + of_property_read_u32(dev->device_node, "i2c-sda-hold-time-ns", + &t->sda_hold_ns); +} +EXPORT_SYMBOL_GPL(i2c_parse_fw_timings); + /** * i2c_add_numbered_adapter - declare i2c adapter, use static bus number * @adapter: the adapter to register (with adap->nr initialized) -- cgit v1.2.3