aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/tuner-xc2028.c
diff options
context:
space:
mode:
authorChris Pascoe <c.pascoe@itee.uq.edu.au>2007-11-19 02:31:58 -0500
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-01-25 16:02:22 -0500
commit7d58d1117ec02f5fe22ddd03ca08fe2a8c777ea2 (patch)
tree1672eb110109e87ab050415d7727383e8e26f2dc /drivers/media/video/tuner-xc2028.c
parente155d908f72cc429b538c101ee8ffcd10a44b69b (diff)
V4L/DVB (6633): xc2028: make register reads atomic
Issuing register reads as a separate address write and data read transactions means that other I2C activity could occur in between and state could get out of sync. Issue both the write and read in a single transaction so that the i2c layer can prevent other users accessing the bus until we are complete. Signed-off-by: Chris Pascoe <c.pascoe@itee.uq.edu.au> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/tuner-xc2028.c')
-rw-r--r--drivers/media/video/tuner-xc2028.c55
1 files changed, 30 insertions, 25 deletions
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c
index 166fede7d0e3..a49a4e886897 100644
--- a/drivers/media/video/tuner-xc2028.c
+++ b/drivers/media/video/tuner-xc2028.c
@@ -101,6 +101,16 @@ struct xc2028_data {
101 _rc; \ 101 _rc; \
102}) 102})
103 103
104#define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({ \
105 int _rc; \
106 _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize, \
107 ibuf, isize); \
108 if (isize != _rc) \
109 tuner_err("i2c input error: rc = %d (should be %d)\n", \
110 _rc, (int)isize); \
111 _rc; \
112})
113
104#define send_seq(priv, data...) ({ \ 114#define send_seq(priv, data...) ({ \
105 static u8 _val[] = data; \ 115 static u8 _val[] = data; \
106 int _rc; \ 116 int _rc; \
@@ -113,25 +123,21 @@ struct xc2028_data {
113 _rc; \ 123 _rc; \
114}) 124})
115 125
116static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg) 126static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
117{ 127{
118 int rc;
119 unsigned char buf[2]; 128 unsigned char buf[2];
129 unsigned char ibuf[2];
120 130
121 tuner_dbg("%s called\n", __FUNCTION__); 131 tuner_dbg("%s %04x called\n", __FUNCTION__, reg);
122 132
123 buf[0] = reg>>8; 133 buf[0] = reg >> 8;
124 buf[1] = (unsigned char) reg; 134 buf[1] = (unsigned char) reg;
125 135
126 rc = i2c_send(priv, buf, 2); 136 if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2)
127 if (rc < 0) 137 return -EIO;
128 return rc;
129
130 rc = i2c_rcv(priv, buf, 2);
131 if (rc < 0)
132 return rc;
133 138
134 return (buf[1]) | (buf[0] << 8); 139 *val = (ibuf[1]) | (ibuf[0] << 8);
140 return 0;
135} 141}
136 142
137void dump_firm_type(unsigned int type) 143void dump_firm_type(unsigned int type)
@@ -567,7 +573,8 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
567 v4l2_std_id std, fe_bandwidth_t bandwidth) 573 v4l2_std_id std, fe_bandwidth_t bandwidth)
568{ 574{
569 struct xc2028_data *priv = fe->tuner_priv; 575 struct xc2028_data *priv = fe->tuner_priv;
570 int rc, version, hwmodel; 576 int rc;
577 u16 version, hwmodel;
571 v4l2_std_id std0 = 0; 578 v4l2_std_id std0 = 0;
572 unsigned int type0 = 0, type = 0; 579 unsigned int type0 = 0, type = 0;
573 int change_digital_bandwidth; 580 int change_digital_bandwidth;
@@ -692,8 +699,8 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
692 699
693 rc = load_scode(fe, type, &std, 0); 700 rc = load_scode(fe, type, &std, 0);
694 701
695 version = xc2028_get_reg(priv, 0x0004); 702 xc2028_get_reg(priv, 0x0004, &version);
696 hwmodel = xc2028_get_reg(priv, 0x0008); 703 xc2028_get_reg(priv, 0x0008, &hwmodel);
697 704
698 tuner_info("Device is Xceive %d version %d.%d, " 705 tuner_info("Device is Xceive %d version %d.%d, "
699 "firmware version %d.%d\n", 706 "firmware version %d.%d\n",
@@ -708,33 +715,31 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
708static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) 715static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
709{ 716{
710 struct xc2028_data *priv = fe->tuner_priv; 717 struct xc2028_data *priv = fe->tuner_priv;
711 int frq_lock, signal = 0; 718 u16 frq_lock, signal = 0;
719 int rc;
712 720
713 tuner_dbg("%s called\n", __FUNCTION__); 721 tuner_dbg("%s called\n", __FUNCTION__);
714 722
715 mutex_lock(&priv->lock); 723 mutex_lock(&priv->lock);
716 724
717 *strength = 0;
718
719 /* Sync Lock Indicator */ 725 /* Sync Lock Indicator */
720 frq_lock = xc2028_get_reg(priv, 0x0002); 726 rc = xc2028_get_reg(priv, 0x0002, &frq_lock);
721 if (frq_lock <= 0) 727 if (rc < 0 || frq_lock == 0)
722 goto ret; 728 goto ret;
723 729
724 /* Frequency is locked. Return signal quality */ 730 /* Frequency is locked. Return signal quality */
725 731
726 /* Get SNR of the video signal */ 732 /* Get SNR of the video signal */
727 signal = xc2028_get_reg(priv, 0x0040); 733 rc = xc2028_get_reg(priv, 0x0040, &signal);
728 734 if (rc < 0)
729 if (signal <= 0) 735 signal = -frq_lock;
730 signal = frq_lock;
731 736
732ret: 737ret:
733 mutex_unlock(&priv->lock); 738 mutex_unlock(&priv->lock);
734 739
735 *strength = signal; 740 *strength = signal;
736 741
737 return 0; 742 return rc;
738} 743}
739 744
740#define DIV 15625 745#define DIV 15625