Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] si2168: change the i2c gate to be mux-locked

The root i2c adapter lock is then no longer held by the i2c mux during
accesses behind the i2c gate, and such accesses need to take that lock
just like any other ordinary i2c accesses do.

So, declare the i2c gate mux-locked, and zap the code that makes the
i2c accesses unlocked. But add a mutex so that firmware commands are
still serialized.

Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Peter Rosin <peda@axentia.se>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>

authored by

Antti Palosaari and committed by
Wolfram Sang
e6d7ffcd 1ffcfaf1

+22 -64
+1 -1
Documentation/i2c/i2c-topology
··· 56 56 dvb-frontends/m88ds3103 Parent-locked 57 57 dvb-frontends/rtl2830 Parent-locked 58 58 dvb-frontends/rtl2832 Parent-locked 59 - dvb-frontends/si2168 Parent-locked 59 + dvb-frontends/si2168 Mux-locked 60 60 usb/cx231xx/ Parent-locked 61 61 62 62
+20 -63
drivers/media/dvb-frontends/si2168.c
··· 18 18 19 19 static const struct dvb_frontend_ops si2168_ops; 20 20 21 - /* Own I2C adapter locking is needed because of I2C gate logic. */ 22 - static int si2168_i2c_master_send_unlocked(const struct i2c_client *client, 23 - const char *buf, int count) 24 - { 25 - int ret; 26 - struct i2c_msg msg = { 27 - .addr = client->addr, 28 - .flags = 0, 29 - .len = count, 30 - .buf = (char *)buf, 31 - }; 32 - 33 - ret = __i2c_transfer(client->adapter, &msg, 1); 34 - return (ret == 1) ? count : ret; 35 - } 36 - 37 - static int si2168_i2c_master_recv_unlocked(const struct i2c_client *client, 38 - char *buf, int count) 39 - { 40 - int ret; 41 - struct i2c_msg msg = { 42 - .addr = client->addr, 43 - .flags = I2C_M_RD, 44 - .len = count, 45 - .buf = buf, 46 - }; 47 - 48 - ret = __i2c_transfer(client->adapter, &msg, 1); 49 - return (ret == 1) ? count : ret; 50 - } 51 - 52 21 /* execute firmware command */ 53 - static int si2168_cmd_execute_unlocked(struct i2c_client *client, 54 - struct si2168_cmd *cmd) 22 + static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) 55 23 { 24 + struct si2168_dev *dev = i2c_get_clientdata(client); 56 25 int ret; 57 26 unsigned long timeout; 58 27 28 + mutex_lock(&dev->i2c_mutex); 29 + 59 30 if (cmd->wlen) { 60 31 /* write cmd and args for firmware */ 61 - ret = si2168_i2c_master_send_unlocked(client, cmd->args, 62 - cmd->wlen); 32 + ret = i2c_master_send(client, cmd->args, cmd->wlen); 63 33 if (ret < 0) { 64 - goto err; 34 + goto err_mutex_unlock; 65 35 } else if (ret != cmd->wlen) { 66 36 ret = -EREMOTEIO; 67 - goto err; 37 + goto err_mutex_unlock; 68 38 } 69 39 } 70 40 ··· 43 73 #define TIMEOUT 70 44 74 timeout = jiffies + msecs_to_jiffies(TIMEOUT); 45 75 while (!time_after(jiffies, timeout)) { 46 - ret = si2168_i2c_master_recv_unlocked(client, cmd->args, 47 - cmd->rlen); 76 + ret = i2c_master_recv(client, cmd->args, cmd->rlen); 48 77 if (ret < 0) { 49 - goto err; 78 + goto err_mutex_unlock; 50 79 } else if (ret != cmd->rlen) { 51 80 ret = -EREMOTEIO; 52 - goto err; 81 + goto err_mutex_unlock; 53 82 } 54 83 55 84 /* firmware ready? */ ··· 63 94 /* error bit set? */ 64 95 if ((cmd->args[0] >> 6) & 0x01) { 65 96 ret = -EREMOTEIO; 66 - goto err; 97 + goto err_mutex_unlock; 67 98 } 68 99 69 100 if (!((cmd->args[0] >> 7) & 0x01)) { 70 101 ret = -ETIMEDOUT; 71 - goto err; 102 + goto err_mutex_unlock; 72 103 } 73 104 } 74 105 106 + mutex_unlock(&dev->i2c_mutex); 75 107 return 0; 76 - err: 108 + err_mutex_unlock: 109 + mutex_unlock(&dev->i2c_mutex); 77 110 dev_dbg(&client->dev, "failed=%d\n", ret); 78 - return ret; 79 - } 80 - 81 - static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd) 82 - { 83 - int ret; 84 - 85 - i2c_lock_adapter(client->adapter); 86 - ret = si2168_cmd_execute_unlocked(client, cmd); 87 - i2c_unlock_adapter(client->adapter); 88 - 89 111 return ret; 90 112 } 91 113 ··· 570 610 return 0; 571 611 } 572 612 573 - /* 574 - * I2C gate logic 575 - * We must use unlocked I2C I/O because I2C adapter lock is already taken 576 - * by the caller (usually tuner driver). 577 - */ 578 613 static int si2168_select(struct i2c_mux_core *muxc, u32 chan) 579 614 { 580 615 struct i2c_client *client = i2c_mux_priv(muxc); ··· 580 625 memcpy(cmd.args, "\xc0\x0d\x01", 3); 581 626 cmd.wlen = 3; 582 627 cmd.rlen = 0; 583 - ret = si2168_cmd_execute_unlocked(client, &cmd); 628 + ret = si2168_cmd_execute(client, &cmd); 584 629 if (ret) 585 630 goto err; 586 631 ··· 600 645 memcpy(cmd.args, "\xc0\x0d\x00", 3); 601 646 cmd.wlen = 3; 602 647 cmd.rlen = 0; 603 - ret = si2168_cmd_execute_unlocked(client, &cmd); 648 + ret = si2168_cmd_execute(client, &cmd); 604 649 if (ret) 605 650 goto err; 606 651 ··· 663 708 goto err; 664 709 } 665 710 711 + mutex_init(&dev->i2c_mutex); 712 + 666 713 /* create mux i2c adapter for tuner */ 667 714 dev->muxc = i2c_mux_alloc(client->adapter, &client->dev, 668 - 1, 0, 0, 715 + 1, 0, I2C_MUX_LOCKED, 669 716 si2168_select, si2168_deselect); 670 717 if (!dev->muxc) { 671 718 ret = -ENOMEM;
+1
drivers/media/dvb-frontends/si2168_priv.h
··· 29 29 30 30 /* state struct */ 31 31 struct si2168_dev { 32 + struct mutex i2c_mutex; 32 33 struct i2c_mux_core *muxc; 33 34 struct dvb_frontend fe; 34 35 enum fe_delivery_system delivery_system;