diff options
author | Jarod Wilson <jarod@redhat.com> | 2011-03-02 11:23:52 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-03-22 18:23:48 -0400 |
commit | b443ac5a2836532af2315a4acb95c7a2cf721cbd (patch) | |
tree | 1313a4d282f79b8fe4f1eaeda25aa3653cd0e57a /drivers/media | |
parent | 53a5fd4dede974ba9727cda430e6714293be5e71 (diff) |
[media] hdpvr: i2c master enhancements
Make the hdpvr's i2c master implementation more closely mirror that of
the pvrusb2 driver. Currently makes no significant difference in IR
reception behavior with ir-kbd-i2c (i.e., it still sucks).
Signed-off-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/hdpvr/hdpvr-i2c.c | 67 |
1 files changed, 50 insertions, 17 deletions
diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c index e53fa55d56a1..3e0658768135 100644 --- a/drivers/media/video/hdpvr/hdpvr-i2c.c +++ b/drivers/media/video/hdpvr/hdpvr-i2c.c | |||
@@ -62,15 +62,25 @@ struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev) | |||
62 | } | 62 | } |
63 | 63 | ||
64 | static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus, | 64 | static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus, |
65 | unsigned char addr, char *data, int len) | 65 | unsigned char addr, char *wdata, int wlen, |
66 | char *data, int len) | ||
66 | { | 67 | { |
67 | int ret; | 68 | int ret; |
68 | 69 | ||
69 | if (len > sizeof(dev->i2c_buf)) | 70 | if ((len > sizeof(dev->i2c_buf)) || (wlen > sizeof(dev->i2c_buf))) |
70 | return -EINVAL; | 71 | return -EINVAL; |
71 | 72 | ||
72 | ret = usb_control_msg(dev->udev, | 73 | if (wlen) { |
73 | usb_rcvctrlpipe(dev->udev, 0), | 74 | memcpy(&dev->i2c_buf, wdata, wlen); |
75 | ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), | ||
76 | REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST, | ||
77 | (bus << 8) | addr, 0, &dev->i2c_buf, | ||
78 | wlen, 1000); | ||
79 | if (ret < 0) | ||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), | ||
74 | REQTYPE_I2C_READ, CTRL_READ_REQUEST, | 84 | REQTYPE_I2C_READ, CTRL_READ_REQUEST, |
75 | (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000); | 85 | (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000); |
76 | 86 | ||
@@ -92,16 +102,14 @@ static int hdpvr_i2c_write(struct hdpvr_device *dev, int bus, | |||
92 | return -EINVAL; | 102 | return -EINVAL; |
93 | 103 | ||
94 | memcpy(&dev->i2c_buf, data, len); | 104 | memcpy(&dev->i2c_buf, data, len); |
95 | ret = usb_control_msg(dev->udev, | 105 | ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), |
96 | usb_sndctrlpipe(dev->udev, 0), | ||
97 | REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST, | 106 | REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST, |
98 | (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000); | 107 | (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000); |
99 | 108 | ||
100 | if (ret < 0) | 109 | if (ret < 0) |
101 | return ret; | 110 | return ret; |
102 | 111 | ||
103 | ret = usb_control_msg(dev->udev, | 112 | ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), |
104 | usb_rcvctrlpipe(dev->udev, 0), | ||
105 | REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST, | 113 | REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST, |
106 | 0, 0, &dev->i2c_buf, 2, 1000); | 114 | 0, 0, &dev->i2c_buf, 2, 1000); |
107 | 115 | ||
@@ -117,24 +125,49 @@ static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs, | |||
117 | int num) | 125 | int num) |
118 | { | 126 | { |
119 | struct hdpvr_device *dev = i2c_get_adapdata(i2c_adapter); | 127 | struct hdpvr_device *dev = i2c_get_adapdata(i2c_adapter); |
120 | int retval = 0, i, addr; | 128 | int retval = 0, addr; |
121 | 129 | ||
122 | if (num <= 0) | 130 | if (num <= 0) |
123 | return 0; | 131 | return 0; |
124 | 132 | ||
125 | mutex_lock(&dev->i2c_mutex); | 133 | mutex_lock(&dev->i2c_mutex); |
126 | 134 | ||
127 | for (i = 0; i < num && !retval; i++) { | 135 | addr = msgs[0].addr << 1; |
128 | addr = msgs[i].addr << 1; | ||
129 | 136 | ||
130 | if (msgs[i].flags & I2C_M_RD) | 137 | if (num == 1) { |
131 | retval = hdpvr_i2c_read(dev, 1, addr, msgs[i].buf, | 138 | if (msgs[0].flags & I2C_M_RD) |
132 | msgs[i].len); | 139 | retval = hdpvr_i2c_read(dev, 1, addr, NULL, 0, |
140 | msgs[0].buf, msgs[0].len); | ||
133 | else | 141 | else |
134 | retval = hdpvr_i2c_write(dev, 1, addr, msgs[i].buf, | 142 | retval = hdpvr_i2c_write(dev, 1, addr, msgs[0].buf, |
135 | msgs[i].len); | 143 | msgs[0].len); |
144 | } else if (num == 2) { | ||
145 | if (msgs[0].addr != msgs[1].addr) { | ||
146 | v4l2_warn(&dev->v4l2_dev, "refusing 2-phase i2c xfer " | ||
147 | "with conflicting target addresses\n"); | ||
148 | retval = -EINVAL; | ||
149 | goto out; | ||
150 | } | ||
151 | |||
152 | if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD)) { | ||
153 | v4l2_warn(&dev->v4l2_dev, "refusing complex xfer with " | ||
154 | "r0=%d, r1=%d\n", msgs[0].flags & I2C_M_RD, | ||
155 | msgs[1].flags & I2C_M_RD); | ||
156 | retval = -EINVAL; | ||
157 | goto out; | ||
158 | } | ||
159 | |||
160 | /* | ||
161 | * Write followed by atomic read is the only complex xfer that | ||
162 | * we actually support here. | ||
163 | */ | ||
164 | retval = hdpvr_i2c_read(dev, 1, addr, msgs[0].buf, msgs[0].len, | ||
165 | msgs[1].buf, msgs[1].len); | ||
166 | } else { | ||
167 | v4l2_warn(&dev->v4l2_dev, "refusing %d-phase i2c xfer\n", num); | ||
136 | } | 168 | } |
137 | 169 | ||
170 | out: | ||
138 | mutex_unlock(&dev->i2c_mutex); | 171 | mutex_unlock(&dev->i2c_mutex); |
139 | 172 | ||
140 | return retval ? retval : num; | 173 | return retval ? retval : num; |
@@ -162,7 +195,7 @@ static int hdpvr_activate_ir(struct hdpvr_device *dev) | |||
162 | 195 | ||
163 | mutex_lock(&dev->i2c_mutex); | 196 | mutex_lock(&dev->i2c_mutex); |
164 | 197 | ||
165 | hdpvr_i2c_read(dev, 0, 0x54, buffer, 1); | 198 | hdpvr_i2c_read(dev, 0, 0x54, NULL, 0, buffer, 1); |
166 | 199 | ||
167 | buffer[0] = 0; | 200 | buffer[0] = 0; |
168 | buffer[1] = 0x8; | 201 | buffer[1] = 0x8; |