diff options
Diffstat (limited to 'drivers/media/i2c/ds90ub960.c')
-rw-r--r-- | drivers/media/i2c/ds90ub960.c | 54 |
1 files changed, 32 insertions, 22 deletions
diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c index ed9ace1a5476..082fc62b0f5b 100644 --- a/drivers/media/i2c/ds90ub960.c +++ b/drivers/media/i2c/ds90ub960.c @@ -27,6 +27,7 @@ */ #include <linux/bitops.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/fwnode.h> @@ -521,7 +522,9 @@ struct ub960_rxport { }; } eq; - const struct i2c_client *aliased_clients[UB960_MAX_PORT_ALIASES]; + /* lock for aliased_addrs and associated registers */ + struct mutex aliased_addrs_lock; + u16 aliased_addrs[UB960_MAX_PORT_ALIASES]; }; struct ub960_asd { @@ -1264,8 +1267,8 @@ static int ub960_reset(struct ub960_data *priv, bool reset_regs) * I2C-ATR (address translator) */ -static int ub960_atr_attach_client(struct i2c_atr *atr, u32 chan_id, - const struct i2c_client *client, u16 alias) +static int ub960_atr_attach_addr(struct i2c_atr *atr, u32 chan_id, + u16 addr, u16 alias) { struct ub960_data *priv = i2c_atr_get_driver_data(atr); struct ub960_rxport *rxport = priv->rxports[chan_id]; @@ -1273,20 +1276,22 @@ static int ub960_atr_attach_client(struct i2c_atr *atr, u32 chan_id, unsigned int reg_idx; int ret = 0; - for (reg_idx = 0; reg_idx < ARRAY_SIZE(rxport->aliased_clients); reg_idx++) { - if (!rxport->aliased_clients[reg_idx]) + guard(mutex)(&rxport->aliased_addrs_lock); + + for (reg_idx = 0; reg_idx < ARRAY_SIZE(rxport->aliased_addrs); reg_idx++) { + if (!rxport->aliased_addrs[reg_idx]) break; } - if (reg_idx == ARRAY_SIZE(rxport->aliased_clients)) { + if (reg_idx == ARRAY_SIZE(rxport->aliased_addrs)) { dev_err(dev, "rx%u: alias pool exhausted\n", rxport->nport); return -EADDRNOTAVAIL; } - rxport->aliased_clients[reg_idx] = client; + rxport->aliased_addrs[reg_idx] = addr; ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ID(reg_idx), - client->addr << 1, &ret); + addr << 1, &ret); ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ALIAS(reg_idx), alias << 1, &ret); @@ -1294,13 +1299,13 @@ static int ub960_atr_attach_client(struct i2c_atr *atr, u32 chan_id, return ret; dev_dbg(dev, "rx%u: client 0x%02x assigned alias 0x%02x at slot %u\n", - rxport->nport, client->addr, alias, reg_idx); + rxport->nport, addr, alias, reg_idx); return 0; } -static void ub960_atr_detach_client(struct i2c_atr *atr, u32 chan_id, - const struct i2c_client *client) +static void ub960_atr_detach_addr(struct i2c_atr *atr, u32 chan_id, + u16 addr) { struct ub960_data *priv = i2c_atr_get_driver_data(atr); struct ub960_rxport *rxport = priv->rxports[chan_id]; @@ -1308,34 +1313,36 @@ static void ub960_atr_detach_client(struct i2c_atr *atr, u32 chan_id, unsigned int reg_idx; int ret; - for (reg_idx = 0; reg_idx < ARRAY_SIZE(rxport->aliased_clients); reg_idx++) { - if (rxport->aliased_clients[reg_idx] == client) + guard(mutex)(&rxport->aliased_addrs_lock); + + for (reg_idx = 0; reg_idx < ARRAY_SIZE(rxport->aliased_addrs); reg_idx++) { + if (rxport->aliased_addrs[reg_idx] == addr) break; } - if (reg_idx == ARRAY_SIZE(rxport->aliased_clients)) { + if (reg_idx == ARRAY_SIZE(rxport->aliased_addrs)) { dev_err(dev, "rx%u: client 0x%02x is not mapped!\n", - rxport->nport, client->addr); + rxport->nport, addr); return; } - rxport->aliased_clients[reg_idx] = NULL; + rxport->aliased_addrs[reg_idx] = 0; ret = ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ALIAS(reg_idx), 0, NULL); if (ret) { dev_err(dev, "rx%u: unable to fully unmap client 0x%02x: %d\n", - rxport->nport, client->addr, ret); + rxport->nport, addr, ret); return; } dev_dbg(dev, "rx%u: client 0x%02x released at slot %u\n", rxport->nport, - client->addr, reg_idx); + addr, reg_idx); } static const struct i2c_atr_ops ub960_atr_ops = { - .attach_client = ub960_atr_attach_client, - .detach_client = ub960_atr_detach_client, + .attach_addr = ub960_atr_attach_addr, + .detach_addr = ub960_atr_detach_addr, }; static int ub960_init_atr(struct ub960_data *priv) @@ -1344,7 +1351,7 @@ static int ub960_init_atr(struct ub960_data *priv) struct i2c_adapter *parent_adap = priv->client->adapter; priv->atr = i2c_atr_new(parent_adap, dev, &ub960_atr_ops, - priv->hw_data->num_rxports); + priv->hw_data->num_rxports, 0); if (IS_ERR(priv->atr)) return PTR_ERR(priv->atr); @@ -2173,7 +2180,6 @@ static int ub960_rxport_add_serializer(struct ub960_data *priv, u8 nport) struct device *dev = &priv->client->dev; struct ds90ub9xx_platform_data *ser_pdata = &rxport->ser.pdata; struct i2c_board_info ser_info = { - .of_node = to_of_node(rxport->ser.fwnode), .fwnode = rxport->ser.fwnode, .platform_data = ser_pdata, }; @@ -4374,6 +4380,8 @@ static void ub960_rxport_free_ports(struct ub960_data *priv) fwnode_handle_put(it.rxport->source.ep_fwnode); fwnode_handle_put(it.rxport->ser.fwnode); + mutex_destroy(&it.rxport->aliased_addrs_lock); + kfree(it.rxport); priv->rxports[it.nport] = NULL; } @@ -4602,6 +4610,8 @@ static int ub960_parse_dt_rxport(struct ub960_data *priv, unsigned int nport, if (ret) goto err_put_remote_fwnode; + mutex_init(&rxport->aliased_addrs_lock); + return 0; err_put_remote_fwnode: |