aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_i2c.c
diff options
context:
space:
mode:
authorDaniel Kurtz <djkurtz@chromium.org>2012-03-30 07:46:39 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-04-12 15:14:07 -0400
commit72d66afd1461effb143784a0f6cde2a9f9908b70 (patch)
tree29f0f2117a8705112860a371e089070f24022041 /drivers/gpu/drm/i915/intel_i2c.c
parente646d5773572bf52017983d758bdf05777dc5600 (diff)
drm/i915/intel_i2c: use WAIT cycle, not STOP
The i915 is only able to generate a STOP cycle (i.e. finalize an i2c transaction) during a DATA or WAIT phase. In other words, the controller rejects a STOP requested as part of the first transaction in a sequence. Thus, for the first transaction we must always use a WAIT cycle, detect when the device has finished (and is in a WAIT phase), and then either start the next transaction, or, if there are no more transactions, generate a STOP cycle. Note: Theoretically, the last transaction of a multi-transaction sequence could initiate a STOP cycle. However, this slight optimization is left for another patch. We return -ETIMEDOUT if the hardware doesn't deactivate after the STOP cycle. Signed-off-by: Daniel Kurtz <djkurtz@chromium.org> [danvet: added comment to the code that gmbus can't generate STOP on the very first cycle.] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_i2c.c')
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c33
1 files changed, 18 insertions, 15 deletions
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 9707868881ec..291e51ec309b 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -204,8 +204,7 @@ intel_gpio_setup(struct intel_gmbus *bus, u32 pin)
204} 204}
205 205
206static int 206static int
207gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, 207gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
208 bool last)
209{ 208{
210 int reg_offset = dev_priv->gpio_mmio_base; 209 int reg_offset = dev_priv->gpio_mmio_base;
211 u16 len = msg->len; 210 u16 len = msg->len;
@@ -213,7 +212,6 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
213 212
214 I915_WRITE(GMBUS1 + reg_offset, 213 I915_WRITE(GMBUS1 + reg_offset,
215 GMBUS_CYCLE_WAIT | 214 GMBUS_CYCLE_WAIT |
216 (last ? GMBUS_CYCLE_STOP : 0) |
217 (len << GMBUS_BYTE_COUNT_SHIFT) | 215 (len << GMBUS_BYTE_COUNT_SHIFT) |
218 (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) | 216 (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) |
219 GMBUS_SLAVE_READ | GMBUS_SW_RDY); 217 GMBUS_SLAVE_READ | GMBUS_SW_RDY);
@@ -239,8 +237,7 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
239} 237}
240 238
241static int 239static int
242gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg, 240gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
243 bool last)
244{ 241{
245 int reg_offset = dev_priv->gpio_mmio_base; 242 int reg_offset = dev_priv->gpio_mmio_base;
246 u16 len = msg->len; 243 u16 len = msg->len;
@@ -256,7 +253,6 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
256 I915_WRITE(GMBUS3 + reg_offset, val); 253 I915_WRITE(GMBUS3 + reg_offset, val);
257 I915_WRITE(GMBUS1 + reg_offset, 254 I915_WRITE(GMBUS1 + reg_offset,
258 GMBUS_CYCLE_WAIT | 255 GMBUS_CYCLE_WAIT |
259 (last ? GMBUS_CYCLE_STOP : 0) |
260 (msg->len << GMBUS_BYTE_COUNT_SHIFT) | 256 (msg->len << GMBUS_BYTE_COUNT_SHIFT) |
261 (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) | 257 (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) |
262 GMBUS_SLAVE_WRITE | GMBUS_SW_RDY); 258 GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
@@ -289,7 +285,8 @@ gmbus_xfer(struct i2c_adapter *adapter,
289 struct intel_gmbus, 285 struct intel_gmbus,
290 adapter); 286 adapter);
291 struct drm_i915_private *dev_priv = bus->dev_priv; 287 struct drm_i915_private *dev_priv = bus->dev_priv;
292 int i, reg_offset, ret; 288 int i, reg_offset;
289 int ret = 0;
293 290
294 mutex_lock(&dev_priv->gmbus_mutex); 291 mutex_lock(&dev_priv->gmbus_mutex);
295 292
@@ -303,20 +300,17 @@ gmbus_xfer(struct i2c_adapter *adapter,
303 I915_WRITE(GMBUS0 + reg_offset, bus->reg0); 300 I915_WRITE(GMBUS0 + reg_offset, bus->reg0);
304 301
305 for (i = 0; i < num; i++) { 302 for (i = 0; i < num; i++) {
306 bool last = i + 1 == num;
307
308 if (msgs[i].flags & I2C_M_RD) 303 if (msgs[i].flags & I2C_M_RD)
309 ret = gmbus_xfer_read(dev_priv, &msgs[i], last); 304 ret = gmbus_xfer_read(dev_priv, &msgs[i]);
310 else 305 else
311 ret = gmbus_xfer_write(dev_priv, &msgs[i], last); 306 ret = gmbus_xfer_write(dev_priv, &msgs[i]);
312 307
313 if (ret == -ETIMEDOUT) 308 if (ret == -ETIMEDOUT)
314 goto timeout; 309 goto timeout;
315 if (ret == -ENXIO) 310 if (ret == -ENXIO)
316 goto clear_err; 311 goto clear_err;
317 312
318 if (!last && 313 if (wait_for(I915_READ(GMBUS2 + reg_offset) &
319 wait_for(I915_READ(GMBUS2 + reg_offset) &
320 (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 314 (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE),
321 50)) 315 50))
322 goto timeout; 316 goto timeout;
@@ -324,15 +318,24 @@ gmbus_xfer(struct i2c_adapter *adapter,
324 goto clear_err; 318 goto clear_err;
325 } 319 }
326 320
321 /* Generate a STOP condition on the bus. Note that gmbus can't generata
322 * a STOP on the very first cycle. To simplify the code we
323 * unconditionally generate the STOP condition with an additional gmbus
324 * cycle. */
325 I915_WRITE(GMBUS1 + reg_offset, GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
326
327 /* Mark the GMBUS interface as disabled after waiting for idle. 327 /* Mark the GMBUS interface as disabled after waiting for idle.
328 * We will re-enable it at the start of the next xfer, 328 * We will re-enable it at the start of the next xfer,
329 * till then let it sleep. 329 * till then let it sleep.
330 */ 330 */
331 if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, 10)) 331 if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0,
332 10)) {
332 DRM_INFO("GMBUS [%s] timed out waiting for idle\n", 333 DRM_INFO("GMBUS [%s] timed out waiting for idle\n",
333 adapter->name); 334 adapter->name);
335 ret = -ETIMEDOUT;
336 }
334 I915_WRITE(GMBUS0 + reg_offset, 0); 337 I915_WRITE(GMBUS0 + reg_offset, 0);
335 ret = i; 338 ret = ret ?: i;
336 goto out; 339 goto out;
337 340
338clear_err: 341clear_err: