aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorAntti Palosaari <crope@iki.fi>2014-12-09 14:14:41 -0500
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>2015-02-03 12:54:59 -0500
commitfd4cfa8bb1bc0cdd385f33303b5058674ea8e24c (patch)
treefdd1c1a9e2dfb1a70f499e6f3e6fe1bfa16cbd72 /drivers/media
parentd9bd3fa6ec9efbfb0dadc7ba86848604fbebfc4b (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.c45
-rw-r--r--drivers/media/dvb-frontends/rtl2830_priv.h1
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
109err_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
136err_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
862static 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
844static struct dvb_frontend *rtl2830_get_dvb_frontend(struct i2c_client *client) 874static 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;