diff options
author | Antti Palosaari <crope@iki.fi> | 2014-12-09 14:14:41 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2015-02-03 12:54:59 -0500 |
commit | fd4cfa8bb1bc0cdd385f33303b5058674ea8e24c (patch) | |
tree | fdd1c1a9e2dfb1a70f499e6f3e6fe1bfa16cbd72 /drivers/media | |
parent | d9bd3fa6ec9efbfb0dadc7ba86848604fbebfc4b (diff) |
[media] rtl2830: implement own I2C locking
Own I2C locking is needed due to two special reasons:
1) Chips uses multiple register pages/banks on single I2C slave.
Page is changed via I2C register access.
2) Chip offers muxed/gated I2C adapter for tuner. Gate/mux is
controlled by I2C register access.
Due to these reasons, I2C locking did not fit very well.
Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/dvb-frontends/rtl2830.c | 45 | ||||
-rw-r--r-- | drivers/media/dvb-frontends/rtl2830_priv.h | 1 |
2 files changed, 39 insertions, 7 deletions
diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c index 8abaca66e132..3a9e4e986fc2 100644 --- a/drivers/media/dvb-frontends/rtl2830.c +++ b/drivers/media/dvb-frontends/rtl2830.c | |||
@@ -43,7 +43,7 @@ static int rtl2830_wr(struct i2c_client *client, u8 reg, const u8 *val, int len) | |||
43 | buf[0] = reg; | 43 | buf[0] = reg; |
44 | memcpy(&buf[1], val, len); | 44 | memcpy(&buf[1], val, len); |
45 | 45 | ||
46 | ret = i2c_transfer(client->adapter, msg, 1); | 46 | ret = __i2c_transfer(client->adapter, msg, 1); |
47 | if (ret == 1) { | 47 | if (ret == 1) { |
48 | ret = 0; | 48 | ret = 0; |
49 | } else { | 49 | } else { |
@@ -73,7 +73,7 @@ static int rtl2830_rd(struct i2c_client *client, u8 reg, u8 *val, int len) | |||
73 | } | 73 | } |
74 | }; | 74 | }; |
75 | 75 | ||
76 | ret = i2c_transfer(client->adapter, msg, 2); | 76 | ret = __i2c_transfer(client->adapter, msg, 2); |
77 | if (ret == 2) { | 77 | if (ret == 2) { |
78 | ret = 0; | 78 | ret = 0; |
79 | } else { | 79 | } else { |
@@ -93,16 +93,23 @@ static int rtl2830_wr_regs(struct i2c_client *client, u16 reg, const u8 *val, in | |||
93 | u8 reg2 = (reg >> 0) & 0xff; | 93 | u8 reg2 = (reg >> 0) & 0xff; |
94 | u8 page = (reg >> 8) & 0xff; | 94 | u8 page = (reg >> 8) & 0xff; |
95 | 95 | ||
96 | mutex_lock(&dev->i2c_mutex); | ||
97 | |||
96 | /* switch bank if needed */ | 98 | /* switch bank if needed */ |
97 | if (page != dev->page) { | 99 | if (page != dev->page) { |
98 | ret = rtl2830_wr(client, 0x00, &page, 1); | 100 | ret = rtl2830_wr(client, 0x00, &page, 1); |
99 | if (ret) | 101 | if (ret) |
100 | return ret; | 102 | goto err_mutex_unlock; |
101 | 103 | ||
102 | dev->page = page; | 104 | dev->page = page; |
103 | } | 105 | } |
104 | 106 | ||
105 | return rtl2830_wr(client, reg2, val, len); | 107 | ret = rtl2830_wr(client, reg2, val, len); |
108 | |||
109 | err_mutex_unlock: | ||
110 | mutex_unlock(&dev->i2c_mutex); | ||
111 | |||
112 | return ret; | ||
106 | } | 113 | } |
107 | 114 | ||
108 | /* read multiple registers */ | 115 | /* read multiple registers */ |
@@ -113,16 +120,23 @@ static int rtl2830_rd_regs(struct i2c_client *client, u16 reg, u8 *val, int len) | |||
113 | u8 reg2 = (reg >> 0) & 0xff; | 120 | u8 reg2 = (reg >> 0) & 0xff; |
114 | u8 page = (reg >> 8) & 0xff; | 121 | u8 page = (reg >> 8) & 0xff; |
115 | 122 | ||
123 | mutex_lock(&dev->i2c_mutex); | ||
124 | |||
116 | /* switch bank if needed */ | 125 | /* switch bank if needed */ |
117 | if (page != dev->page) { | 126 | if (page != dev->page) { |
118 | ret = rtl2830_wr(client, 0x00, &page, 1); | 127 | ret = rtl2830_wr(client, 0x00, &page, 1); |
119 | if (ret) | 128 | if (ret) |
120 | return ret; | 129 | goto err_mutex_unlock; |
121 | 130 | ||
122 | dev->page = page; | 131 | dev->page = page; |
123 | } | 132 | } |
124 | 133 | ||
125 | return rtl2830_rd(client, reg2, val, len); | 134 | ret = rtl2830_rd(client, reg2, val, len); |
135 | |||
136 | err_mutex_unlock: | ||
137 | mutex_unlock(&dev->i2c_mutex); | ||
138 | |||
139 | return ret; | ||
126 | } | 140 | } |
127 | 141 | ||
128 | /* read single register */ | 142 | /* read single register */ |
@@ -815,6 +829,10 @@ static int rtl2830_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id) | |||
815 | }; | 829 | }; |
816 | int ret; | 830 | int ret; |
817 | 831 | ||
832 | dev_dbg(&client->dev, "\n"); | ||
833 | |||
834 | mutex_lock(&dev->i2c_mutex); | ||
835 | |||
818 | /* select register page */ | 836 | /* select register page */ |
819 | ret = __i2c_transfer(client->adapter, select_reg_page_msg, 1); | 837 | ret = __i2c_transfer(client->adapter, select_reg_page_msg, 1); |
820 | if (ret != 1) { | 838 | if (ret != 1) { |
@@ -841,6 +859,18 @@ err: | |||
841 | return ret; | 859 | return ret; |
842 | } | 860 | } |
843 | 861 | ||
862 | static int rtl2830_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan) | ||
863 | { | ||
864 | struct i2c_client *client = mux_priv; | ||
865 | struct rtl2830_dev *dev = i2c_get_clientdata(client); | ||
866 | |||
867 | dev_dbg(&client->dev, "\n"); | ||
868 | |||
869 | mutex_unlock(&dev->i2c_mutex); | ||
870 | |||
871 | return 0; | ||
872 | } | ||
873 | |||
844 | static struct dvb_frontend *rtl2830_get_dvb_frontend(struct i2c_client *client) | 874 | static struct dvb_frontend *rtl2830_get_dvb_frontend(struct i2c_client *client) |
845 | { | 875 | { |
846 | struct rtl2830_dev *dev = i2c_get_clientdata(client); | 876 | struct rtl2830_dev *dev = i2c_get_clientdata(client); |
@@ -886,6 +916,7 @@ static int rtl2830_probe(struct i2c_client *client, | |||
886 | dev->client = client; | 916 | dev->client = client; |
887 | dev->pdata = client->dev.platform_data; | 917 | dev->pdata = client->dev.platform_data; |
888 | dev->sleeping = true; | 918 | dev->sleeping = true; |
919 | mutex_init(&dev->i2c_mutex); | ||
889 | INIT_DELAYED_WORK(&dev->stat_work, rtl2830_stat_work); | 920 | INIT_DELAYED_WORK(&dev->stat_work, rtl2830_stat_work); |
890 | 921 | ||
891 | /* check if the demod is there */ | 922 | /* check if the demod is there */ |
@@ -895,7 +926,7 @@ static int rtl2830_probe(struct i2c_client *client, | |||
895 | 926 | ||
896 | /* create muxed i2c adapter for tuner */ | 927 | /* create muxed i2c adapter for tuner */ |
897 | dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev, | 928 | dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev, |
898 | client, 0, 0, 0, rtl2830_select, NULL); | 929 | client, 0, 0, 0, rtl2830_select, rtl2830_deselect); |
899 | if (dev->adapter == NULL) { | 930 | if (dev->adapter == NULL) { |
900 | ret = -ENODEV; | 931 | ret = -ENODEV; |
901 | goto err_kfree; | 932 | goto err_kfree; |
diff --git a/drivers/media/dvb-frontends/rtl2830_priv.h b/drivers/media/dvb-frontends/rtl2830_priv.h index 293188924f51..517758ab687a 100644 --- a/drivers/media/dvb-frontends/rtl2830_priv.h +++ b/drivers/media/dvb-frontends/rtl2830_priv.h | |||
@@ -30,6 +30,7 @@ struct rtl2830_dev { | |||
30 | struct i2c_adapter *adapter; | 30 | struct i2c_adapter *adapter; |
31 | struct dvb_frontend fe; | 31 | struct dvb_frontend fe; |
32 | bool sleeping; | 32 | bool sleeping; |
33 | struct mutex i2c_mutex; | ||
33 | u8 page; /* active register page */ | 34 | u8 page; /* active register page */ |
34 | unsigned long filters; | 35 | unsigned long filters; |
35 | struct delayed_work stat_work; | 36 | struct delayed_work stat_work; |