From ad115623449a3e80d89b725f833b885a9ad29c33 Mon Sep 17 00:00:00 2001 From: Federico Vaga <federico.vaga@cern.ch> Date: Tue, 17 Mar 2020 11:13:35 +0100 Subject: [PATCH] sw:i2c: add support for kernel greater than 4.7 Instead of check for version here and there, the main code always uses the latest API, and in a preprocessor ``if`` statement I implemented the compatibility layer. Like this it will be easier to apply patches from the kernel to our local driver Signed-off-by: Federico Vaga <federico.vaga@cern.ch> --- CHANGELOG.rst | 1 + .../drivers/i2c/busses/i2c-ocores.c | 167 +++++++++++++----- 2 files changed, 128 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8b26d4eb..2af56bfc 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,7 @@ Versioning: `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_ Added ----- - [hdl] VHDL functions to convert characters and strings to upper/lower case. +- [sw][i2c] support for kernel greater than 4.7 Changed ------- - [hdl] Rewritten the WB master interface used in simulations. diff --git a/software/i2c-ocores/drivers/i2c/busses/i2c-ocores.c b/software/i2c-ocores/drivers/i2c/busses/i2c-ocores.c index b7a458d6..12465de3 100644 --- a/software/i2c-ocores/drivers/i2c/busses/i2c-ocores.c +++ b/software/i2c-ocores/drivers/i2c/busses/i2c-ocores.c @@ -28,6 +28,91 @@ #include <linux/spinlock.h> #include <linux/jiffies.h> +struct ocores_i2c; +static int ohwr_i2c_mux_select(struct ocores_i2c *i2c, u32 num); +static int ohwr_i2c_mux_deselect(struct ocores_i2c *i2c, u32 num); + +#if KERNEL_VERSION(4, 7, 0) > LINUX_VERSION_CODE +struct i2c_mux_core { + struct i2c_adapter *parent; + struct device *dev; + void *priv; + + unsigned int max_adapters; + struct i2c_adapter *adapter[0]; +}; + +/** + * It selects the I2C bus to use and lock it + */ +static int ocores_i2c_mux_select_old_api(struct i2c_adapter *adap, + void *priv, u32 num) +{ + struct ocores_i2c *i2c = priv; + + return ohwr_i2c_mux_select(i2c, num); +} + +/** + * It unlocks the bus so that it can be changed. + */ +static int ocores_i2c_mux_deselect_old_api(struct i2c_adapter *adap, + void *priv, u32 num) +{ + struct ocores_i2c *i2c = priv; + + return ohwr_i2c_mux_deselect(i2c, num); +} + +struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent, + struct device *dev, int max_adapters, + int sizeof_priv, u32 flags, + int (*select)(struct i2c_mux_core *, u32), + int (*deselect)(struct i2c_mux_core *, u32)) +{ + struct i2c_mux_core *muxc; + + muxc = devm_kzalloc(dev, sizeof(*muxc) + + sizeof(*muxc->adapter) * max_adapters + + sizeof_priv, GFP_KERNEL); + if (!muxc) + return NULL; + if (sizeof_priv) + muxc->priv = &muxc->adapter[max_adapters]; + muxc->parent = parent; + muxc->dev = dev; + muxc->max_adapters = max_adapters; + + return muxc; +} + +int i2c_mux_add_adapter(struct i2c_mux_core *muxc, + u32 force_nr, u32 chan_id, + unsigned int class) +{ + muxc->adapter[chan_id] = i2c_add_mux_adapter(muxc->parent, + muxc->dev, + muxc->priv, + force_nr, + chan_id, +#if KERNEL_VERSION(3, 7, 0) <= LINUX_VERSION_CODE + class, /* class */ +#endif + ocores_i2c_mux_select_old_api, + ocores_i2c_mux_deselect_old_api); + return muxc->adapter[chan_id] ? 0 : -EINVAL; +} + +void i2c_mux_del_adapters(struct i2c_mux_core *muxc) +{ + int i; + + for (i = 0; i < muxc->max_adapters; ++i) + i2c_del_mux_adapter(muxc->adapter[i]); +} +#endif + + #define OCORES_FLAG_POLL BIT(0) /** @@ -41,8 +126,7 @@ struct ocores_i2c { unsigned long flags; wait_queue_head_t wait; struct i2c_adapter adap; - struct i2c_adapter **adap_mux; - unsigned int n_adap_mux; + struct i2c_mux_core *adap_mux; struct i2c_msg *msg; int pos; int nmsgs; @@ -578,14 +662,8 @@ static const struct platform_device_id ocores_id_table[] = { }; MODULE_DEVICE_TABLE(id_table, ocores_id_table); - -/** - * It selects the I2C bus to use and lock it - */ -static int ocores_i2c_mux_select(struct i2c_adapter *adap, - void *priv, u32 num) +static int ohwr_i2c_mux_select(struct ocores_i2c *i2c, u32 num) { - struct ocores_i2c *i2c = priv; u8 mux; mux = oc_getreg(i2c, OCI2C_OHWR_MUX); @@ -601,57 +679,69 @@ static int ocores_i2c_mux_select(struct i2c_adapter *adap, return 0; } - -/** - * It unlocks the bus so that it can be changed. - */ -static int ocores_i2c_mux_deselect(struct i2c_adapter *adap, - void *priv, u32 num) +static int ohwr_i2c_mux_deselect(struct ocores_i2c *i2c, u32 num) { - struct ocores_i2c *i2c = priv; u8 mux; /* Unlock bus selection */ mux = oc_getreg(i2c, OCI2C_OHWR_MUX); if (unlikely(!(mux & OCI2C_OHWR_MUX_BUSY))) - dev_err(&adap->dev, "deselect a bus that was not selected\n"); + dev_err(i2c->adap_mux->dev, + "deselect a bus that was not selected\n"); mux &= ~OCI2C_OHWR_MUX_BUSY; oc_setreg(i2c, OCI2C_OHWR_MUX, mux); return 0; } +/** + * It selects the I2C bus to use and lock it + */ +static int ocores_i2c_mux_select(struct i2c_mux_core *muxc, u32 num) +{ + struct ocores_i2c *i2c = muxc->priv; + + return ohwr_i2c_mux_select(i2c, num); +} + +/** + * It unlocks the bus so that it can be changed. + */ +static int ocores_i2c_mux_deselect(struct i2c_mux_core *muxc, u32 num) +{ + struct ocores_i2c *i2c = muxc->priv; + + return ohwr_i2c_mux_deselect(i2c, num); +} /** * Add OHWR multiplexer */ static int ocores_i2c_probe_ohwr(struct ocores_i2c *i2c) { - int err, i; - - i2c->n_adap_mux = 2; - i2c->adap_mux = devm_kzalloc(&i2c->adap.dev, - sizeof(void *) * i2c->n_adap_mux, - GFP_KERNEL); - for (i = 0; i < i2c->n_adap_mux; ++i) { - i2c->adap_mux[i] = i2c_add_mux_adapter(&i2c->adap, - i2c->adap.dev.parent, - i2c, - 0, i, -#if KERNEL_VERSION(3, 7, 0) <= LINUX_VERSION_CODE - 0, /* class */ -#endif - ocores_i2c_mux_select, - ocores_i2c_mux_deselect); - if (!i2c->adap_mux[i]) + int i, err = 0; + + i2c->adap_mux = i2c_mux_alloc(&i2c->adap, i2c->adap.dev.parent, + 2, sizeof(i2c), 0, + ocores_i2c_mux_select, + ocores_i2c_mux_deselect); + if (!i2c->adap_mux) { + err = -ENOMEM; + goto err_exit; + } + i2c->adap_mux->priv = i2c; + for (i = 0; i < i2c->adap_mux->max_adapters; ++i) { + err = i2c_mux_add_adapter(i2c->adap_mux, + 0, i, 0); + if (err) goto err_add; } return 0; err_add: - while (--i >= 0) - i2c_del_mux_adapter(i2c->adap_mux[i]); + i2c_mux_del_adapters(i2c->adap_mux); +err_exit: return err; } @@ -660,10 +750,7 @@ err_add: */ static void ocores_i2c_remove_ohwr(struct ocores_i2c *i2c) { - int i; - - for (i = 0; i < i2c->n_adap_mux; ++i) - i2c_del_mux_adapter(i2c->adap_mux[i]); + i2c_mux_del_adapters(i2c->adap_mux); } #ifdef CONFIG_OF -- GitLab