diff options
author | Manuel Lauss <mano@roarinelk.homelinux.net> | 2008-07-14 16:38:34 -0400 |
---|---|---|
committer | Jean Delvare <khali@mahadeva.delvare> | 2008-07-14 16:38:34 -0400 |
commit | f09f71b24e77a2f2b4e5c98311c8804fc61ad8bc (patch) | |
tree | 6213e3f5ddf6d929dc294bec952903b3691ae505 /drivers | |
parent | f6a7110520037ba786f17b53790c6eb8a3d4ef55 (diff) |
i2c-au1550: Fix PM support
Fix driver power management:
- suspend the PSC while driver is idle.
- move PSC init/deinit to separate functions, as PSC must be
initialized/shutdown on resume/suspend.
Signed-off-by: Manuel Lauss <mano@roarinelk.homelinux.net>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/busses/i2c-au1550.c | 130 |
1 files changed, 75 insertions, 55 deletions
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index cae9dc89d88c..66a04c2c660f 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c | |||
@@ -269,9 +269,13 @@ static int | |||
269 | au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) | 269 | au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) |
270 | { | 270 | { |
271 | struct i2c_au1550_data *adap = i2c_adap->algo_data; | 271 | struct i2c_au1550_data *adap = i2c_adap->algo_data; |
272 | volatile psc_smb_t *sp = (volatile psc_smb_t *)adap->psc_base; | ||
272 | struct i2c_msg *p; | 273 | struct i2c_msg *p; |
273 | int i, err = 0; | 274 | int i, err = 0; |
274 | 275 | ||
276 | sp->psc_ctrl = PSC_CTRL_ENABLE; | ||
277 | au_sync(); | ||
278 | |||
275 | for (i = 0; !err && i < num; i++) { | 279 | for (i = 0; !err && i < num; i++) { |
276 | p = &msgs[i]; | 280 | p = &msgs[i]; |
277 | err = do_address(adap, p->addr, p->flags & I2C_M_RD, | 281 | err = do_address(adap, p->addr, p->flags & I2C_M_RD, |
@@ -288,6 +292,10 @@ au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) | |||
288 | */ | 292 | */ |
289 | if (err == 0) | 293 | if (err == 0) |
290 | err = num; | 294 | err = num; |
295 | |||
296 | sp->psc_ctrl = PSC_CTRL_SUSPEND; | ||
297 | au_sync(); | ||
298 | |||
291 | return err; | 299 | return err; |
292 | } | 300 | } |
293 | 301 | ||
@@ -302,6 +310,61 @@ static const struct i2c_algorithm au1550_algo = { | |||
302 | .functionality = au1550_func, | 310 | .functionality = au1550_func, |
303 | }; | 311 | }; |
304 | 312 | ||
313 | static void i2c_au1550_setup(struct i2c_au1550_data *priv) | ||
314 | { | ||
315 | volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; | ||
316 | u32 stat; | ||
317 | |||
318 | sp->psc_ctrl = PSC_CTRL_DISABLE; | ||
319 | au_sync(); | ||
320 | sp->psc_sel = PSC_SEL_PS_SMBUSMODE; | ||
321 | sp->psc_smbcfg = 0; | ||
322 | au_sync(); | ||
323 | sp->psc_ctrl = PSC_CTRL_ENABLE; | ||
324 | au_sync(); | ||
325 | do { | ||
326 | stat = sp->psc_smbstat; | ||
327 | au_sync(); | ||
328 | } while ((stat & PSC_SMBSTAT_SR) == 0); | ||
329 | |||
330 | sp->psc_smbcfg = (PSC_SMBCFG_RT_FIFO8 | PSC_SMBCFG_TT_FIFO8 | | ||
331 | PSC_SMBCFG_DD_DISABLE); | ||
332 | |||
333 | /* Divide by 8 to get a 6.25 MHz clock. The later protocol | ||
334 | * timings are based on this clock. | ||
335 | */ | ||
336 | sp->psc_smbcfg |= PSC_SMBCFG_SET_DIV(PSC_SMBCFG_DIV8); | ||
337 | sp->psc_smbmsk = PSC_SMBMSK_ALLMASK; | ||
338 | au_sync(); | ||
339 | |||
340 | /* Set the protocol timer values. See Table 71 in the | ||
341 | * Au1550 Data Book for standard timing values. | ||
342 | */ | ||
343 | sp->psc_smbtmr = PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(15) | \ | ||
344 | PSC_SMBTMR_SET_PU(15) | PSC_SMBTMR_SET_SH(15) | \ | ||
345 | PSC_SMBTMR_SET_SU(15) | PSC_SMBTMR_SET_CL(15) | \ | ||
346 | PSC_SMBTMR_SET_CH(15); | ||
347 | au_sync(); | ||
348 | |||
349 | sp->psc_smbcfg |= PSC_SMBCFG_DE_ENABLE; | ||
350 | do { | ||
351 | stat = sp->psc_smbstat; | ||
352 | au_sync(); | ||
353 | } while ((stat & PSC_SMBSTAT_SR) == 0); | ||
354 | |||
355 | sp->psc_ctrl = PSC_CTRL_SUSPEND; | ||
356 | au_sync(); | ||
357 | } | ||
358 | |||
359 | static void i2c_au1550_disable(struct i2c_au1550_data *priv) | ||
360 | { | ||
361 | volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; | ||
362 | |||
363 | sp->psc_smbcfg = 0; | ||
364 | sp->psc_ctrl = PSC_CTRL_DISABLE; | ||
365 | au_sync(); | ||
366 | } | ||
367 | |||
305 | /* | 368 | /* |
306 | * registering functions to load algorithms at runtime | 369 | * registering functions to load algorithms at runtime |
307 | * Prior to calling us, the 50MHz clock frequency and routing | 370 | * Prior to calling us, the 50MHz clock frequency and routing |
@@ -311,9 +374,7 @@ static int __devinit | |||
311 | i2c_au1550_probe(struct platform_device *pdev) | 374 | i2c_au1550_probe(struct platform_device *pdev) |
312 | { | 375 | { |
313 | struct i2c_au1550_data *priv; | 376 | struct i2c_au1550_data *priv; |
314 | volatile psc_smb_t *sp; | ||
315 | struct resource *r; | 377 | struct resource *r; |
316 | u32 stat; | ||
317 | int ret; | 378 | int ret; |
318 | 379 | ||
319 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 380 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
@@ -348,43 +409,7 @@ i2c_au1550_probe(struct platform_device *pdev) | |||
348 | 409 | ||
349 | /* Now, set up the PSC for SMBus PIO mode. | 410 | /* Now, set up the PSC for SMBus PIO mode. |
350 | */ | 411 | */ |
351 | sp = (volatile psc_smb_t *)priv->psc_base; | 412 | i2c_au1550_setup(priv); |
352 | sp->psc_ctrl = PSC_CTRL_DISABLE; | ||
353 | au_sync(); | ||
354 | sp->psc_sel = PSC_SEL_PS_SMBUSMODE; | ||
355 | sp->psc_smbcfg = 0; | ||
356 | au_sync(); | ||
357 | sp->psc_ctrl = PSC_CTRL_ENABLE; | ||
358 | au_sync(); | ||
359 | do { | ||
360 | stat = sp->psc_smbstat; | ||
361 | au_sync(); | ||
362 | } while ((stat & PSC_SMBSTAT_SR) == 0); | ||
363 | |||
364 | sp->psc_smbcfg = (PSC_SMBCFG_RT_FIFO8 | PSC_SMBCFG_TT_FIFO8 | | ||
365 | PSC_SMBCFG_DD_DISABLE); | ||
366 | |||
367 | /* Divide by 8 to get a 6.25 MHz clock. The later protocol | ||
368 | * timings are based on this clock. | ||
369 | */ | ||
370 | sp->psc_smbcfg |= PSC_SMBCFG_SET_DIV(PSC_SMBCFG_DIV8); | ||
371 | sp->psc_smbmsk = PSC_SMBMSK_ALLMASK; | ||
372 | au_sync(); | ||
373 | |||
374 | /* Set the protocol timer values. See Table 71 in the | ||
375 | * Au1550 Data Book for standard timing values. | ||
376 | */ | ||
377 | sp->psc_smbtmr = PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(15) | \ | ||
378 | PSC_SMBTMR_SET_PU(15) | PSC_SMBTMR_SET_SH(15) | \ | ||
379 | PSC_SMBTMR_SET_SU(15) | PSC_SMBTMR_SET_CL(15) | \ | ||
380 | PSC_SMBTMR_SET_CH(15); | ||
381 | au_sync(); | ||
382 | |||
383 | sp->psc_smbcfg |= PSC_SMBCFG_DE_ENABLE; | ||
384 | do { | ||
385 | stat = sp->psc_smbstat; | ||
386 | au_sync(); | ||
387 | } while ((stat & PSC_SMBSTAT_DR) == 0); | ||
388 | 413 | ||
389 | ret = i2c_add_numbered_adapter(&priv->adap); | 414 | ret = i2c_add_numbered_adapter(&priv->adap); |
390 | if (ret == 0) { | 415 | if (ret == 0) { |
@@ -392,10 +417,7 @@ i2c_au1550_probe(struct platform_device *pdev) | |||
392 | return 0; | 417 | return 0; |
393 | } | 418 | } |
394 | 419 | ||
395 | /* disable the PSC */ | 420 | i2c_au1550_disable(priv); |
396 | sp->psc_smbcfg = 0; | ||
397 | sp->psc_ctrl = PSC_CTRL_DISABLE; | ||
398 | au_sync(); | ||
399 | 421 | ||
400 | release_resource(priv->ioarea); | 422 | release_resource(priv->ioarea); |
401 | kfree(priv->ioarea); | 423 | kfree(priv->ioarea); |
@@ -409,27 +431,24 @@ static int __devexit | |||
409 | i2c_au1550_remove(struct platform_device *pdev) | 431 | i2c_au1550_remove(struct platform_device *pdev) |
410 | { | 432 | { |
411 | struct i2c_au1550_data *priv = platform_get_drvdata(pdev); | 433 | struct i2c_au1550_data *priv = platform_get_drvdata(pdev); |
412 | volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; | ||
413 | 434 | ||
414 | platform_set_drvdata(pdev, NULL); | 435 | platform_set_drvdata(pdev, NULL); |
415 | i2c_del_adapter(&priv->adap); | 436 | i2c_del_adapter(&priv->adap); |
416 | sp->psc_smbcfg = 0; | 437 | i2c_au1550_disable(priv); |
417 | sp->psc_ctrl = PSC_CTRL_DISABLE; | ||
418 | au_sync(); | ||
419 | release_resource(priv->ioarea); | 438 | release_resource(priv->ioarea); |
420 | kfree(priv->ioarea); | 439 | kfree(priv->ioarea); |
421 | kfree(priv); | 440 | kfree(priv); |
422 | return 0; | 441 | return 0; |
423 | } | 442 | } |
424 | 443 | ||
444 | #ifdef CONFIG_PM | ||
425 | static int | 445 | static int |
426 | i2c_au1550_suspend(struct platform_device *pdev, pm_message_t state) | 446 | i2c_au1550_suspend(struct platform_device *pdev, pm_message_t state) |
427 | { | 447 | { |
428 | struct i2c_au1550_data *priv = platform_get_drvdata(pdev); | 448 | struct i2c_au1550_data *priv = platform_get_drvdata(pdev); |
429 | volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; | ||
430 | 449 | ||
431 | sp->psc_ctrl = PSC_CTRL_SUSPEND; | 450 | i2c_au1550_disable(priv); |
432 | au_sync(); | 451 | |
433 | return 0; | 452 | return 0; |
434 | } | 453 | } |
435 | 454 | ||
@@ -437,14 +456,15 @@ static int | |||
437 | i2c_au1550_resume(struct platform_device *pdev) | 456 | i2c_au1550_resume(struct platform_device *pdev) |
438 | { | 457 | { |
439 | struct i2c_au1550_data *priv = platform_get_drvdata(pdev); | 458 | struct i2c_au1550_data *priv = platform_get_drvdata(pdev); |
440 | volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; | ||
441 | 459 | ||
442 | sp->psc_ctrl = PSC_CTRL_ENABLE; | 460 | i2c_au1550_setup(priv); |
443 | au_sync(); | 461 | |
444 | while (!(sp->psc_smbstat & PSC_SMBSTAT_SR)) | ||
445 | au_sync(); | ||
446 | return 0; | 462 | return 0; |
447 | } | 463 | } |
464 | #else | ||
465 | #define i2c_au1550_suspend NULL | ||
466 | #define i2c_au1550_resume NULL | ||
467 | #endif | ||
448 | 468 | ||
449 | static struct platform_driver au1xpsc_smbus_driver = { | 469 | static struct platform_driver au1xpsc_smbus_driver = { |
450 | .driver = { | 470 | .driver = { |