diff options
author | Daniel Kurtz <djkurtz@chromium.org> | 2012-03-30 07:46:39 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2012-04-12 15:14:07 -0400 |
commit | 72d66afd1461effb143784a0f6cde2a9f9908b70 (patch) | |
tree | 29f0f2117a8705112860a371e089070f24022041 /drivers/gpu/drm/i915/intel_i2c.c | |
parent | e646d5773572bf52017983d758bdf05777dc5600 (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.c | 33 |
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 | ||
206 | static int | 206 | static int |
207 | gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, | 207 | gmbus_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 | ||
241 | static int | 239 | static int |
242 | gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg, | 240 | gmbus_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 | ||
338 | clear_err: | 341 | clear_err: |