Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Manuel Lauss and committed by
Jean Delvare
f09f71b2 f6a71105

+81 -61
+81 -61
drivers/i2c/busses/i2c-au1550.c
··· 269 269 au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) 270 270 { 271 271 struct i2c_au1550_data *adap = i2c_adap->algo_data; 272 + volatile psc_smb_t *sp = (volatile psc_smb_t *)adap->psc_base; 272 273 struct i2c_msg *p; 273 274 int i, err = 0; 275 + 276 + sp->psc_ctrl = PSC_CTRL_ENABLE; 277 + au_sync(); 274 278 275 279 for (i = 0; !err && i < num; i++) { 276 280 p = &msgs[i]; ··· 292 288 */ 293 289 if (err == 0) 294 290 err = num; 291 + 292 + sp->psc_ctrl = PSC_CTRL_SUSPEND; 293 + au_sync(); 294 + 295 295 return err; 296 296 } 297 297 ··· 310 302 .functionality = au1550_func, 311 303 }; 312 304 313 - /* 314 - * registering functions to load algorithms at runtime 315 - * Prior to calling us, the 50MHz clock frequency and routing 316 - * must have been set up for the PSC indicated by the adapter. 317 - */ 318 - static int __devinit 319 - i2c_au1550_probe(struct platform_device *pdev) 305 + static void i2c_au1550_setup(struct i2c_au1550_data *priv) 320 306 { 321 - struct i2c_au1550_data *priv; 322 - volatile psc_smb_t *sp; 323 - struct resource *r; 307 + volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; 324 308 u32 stat; 325 - int ret; 326 309 327 - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 328 - if (!r) { 329 - ret = -ENODEV; 330 - goto out; 331 - } 332 - 333 - priv = kzalloc(sizeof(struct i2c_au1550_data), GFP_KERNEL); 334 - if (!priv) { 335 - ret = -ENOMEM; 336 - goto out; 337 - } 338 - 339 - priv->ioarea = request_mem_region(r->start, r->end - r->start + 1, 340 - pdev->name); 341 - if (!priv->ioarea) { 342 - ret = -EBUSY; 343 - goto out_mem; 344 - } 345 - 346 - priv->psc_base = CKSEG1ADDR(r->start); 347 - priv->xfer_timeout = 200; 348 - priv->ack_timeout = 200; 349 - 350 - priv->adap.id = I2C_HW_AU1550_PSC; 351 - priv->adap.nr = pdev->id; 352 - priv->adap.algo = &au1550_algo; 353 - priv->adap.algo_data = priv; 354 - priv->adap.dev.parent = &pdev->dev; 355 - strlcpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name)); 356 - 357 - /* Now, set up the PSC for SMBus PIO mode. 358 - */ 359 - sp = (volatile psc_smb_t *)priv->psc_base; 360 310 sp->psc_ctrl = PSC_CTRL_DISABLE; 361 311 au_sync(); 362 312 sp->psc_sel = PSC_SEL_PS_SMBUSMODE; ··· 350 384 do { 351 385 stat = sp->psc_smbstat; 352 386 au_sync(); 353 - } while ((stat & PSC_SMBSTAT_DR) == 0); 387 + } while ((stat & PSC_SMBSTAT_SR) == 0); 388 + 389 + sp->psc_ctrl = PSC_CTRL_SUSPEND; 390 + au_sync(); 391 + } 392 + 393 + static void i2c_au1550_disable(struct i2c_au1550_data *priv) 394 + { 395 + volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; 396 + 397 + sp->psc_smbcfg = 0; 398 + sp->psc_ctrl = PSC_CTRL_DISABLE; 399 + au_sync(); 400 + } 401 + 402 + /* 403 + * registering functions to load algorithms at runtime 404 + * Prior to calling us, the 50MHz clock frequency and routing 405 + * must have been set up for the PSC indicated by the adapter. 406 + */ 407 + static int __devinit 408 + i2c_au1550_probe(struct platform_device *pdev) 409 + { 410 + struct i2c_au1550_data *priv; 411 + struct resource *r; 412 + int ret; 413 + 414 + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 415 + if (!r) { 416 + ret = -ENODEV; 417 + goto out; 418 + } 419 + 420 + priv = kzalloc(sizeof(struct i2c_au1550_data), GFP_KERNEL); 421 + if (!priv) { 422 + ret = -ENOMEM; 423 + goto out; 424 + } 425 + 426 + priv->ioarea = request_mem_region(r->start, r->end - r->start + 1, 427 + pdev->name); 428 + if (!priv->ioarea) { 429 + ret = -EBUSY; 430 + goto out_mem; 431 + } 432 + 433 + priv->psc_base = CKSEG1ADDR(r->start); 434 + priv->xfer_timeout = 200; 435 + priv->ack_timeout = 200; 436 + 437 + priv->adap.id = I2C_HW_AU1550_PSC; 438 + priv->adap.nr = pdev->id; 439 + priv->adap.algo = &au1550_algo; 440 + priv->adap.algo_data = priv; 441 + priv->adap.dev.parent = &pdev->dev; 442 + strlcpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name)); 443 + 444 + /* Now, set up the PSC for SMBus PIO mode. 445 + */ 446 + i2c_au1550_setup(priv); 354 447 355 448 ret = i2c_add_numbered_adapter(&priv->adap); 356 449 if (ret == 0) { ··· 417 392 return 0; 418 393 } 419 394 420 - /* disable the PSC */ 421 - sp->psc_smbcfg = 0; 422 - sp->psc_ctrl = PSC_CTRL_DISABLE; 423 - au_sync(); 395 + i2c_au1550_disable(priv); 424 396 425 397 release_resource(priv->ioarea); 426 398 kfree(priv->ioarea); ··· 431 409 i2c_au1550_remove(struct platform_device *pdev) 432 410 { 433 411 struct i2c_au1550_data *priv = platform_get_drvdata(pdev); 434 - volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; 435 412 436 413 platform_set_drvdata(pdev, NULL); 437 414 i2c_del_adapter(&priv->adap); 438 - sp->psc_smbcfg = 0; 439 - sp->psc_ctrl = PSC_CTRL_DISABLE; 440 - au_sync(); 415 + i2c_au1550_disable(priv); 441 416 release_resource(priv->ioarea); 442 417 kfree(priv->ioarea); 443 418 kfree(priv); 444 419 return 0; 445 420 } 446 421 422 + #ifdef CONFIG_PM 447 423 static int 448 424 i2c_au1550_suspend(struct platform_device *pdev, pm_message_t state) 449 425 { 450 426 struct i2c_au1550_data *priv = platform_get_drvdata(pdev); 451 - volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; 452 427 453 - sp->psc_ctrl = PSC_CTRL_SUSPEND; 454 - au_sync(); 428 + i2c_au1550_disable(priv); 429 + 455 430 return 0; 456 431 } 457 432 ··· 456 437 i2c_au1550_resume(struct platform_device *pdev) 457 438 { 458 439 struct i2c_au1550_data *priv = platform_get_drvdata(pdev); 459 - volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; 460 440 461 - sp->psc_ctrl = PSC_CTRL_ENABLE; 462 - au_sync(); 463 - while (!(sp->psc_smbstat & PSC_SMBSTAT_SR)) 464 - au_sync(); 441 + i2c_au1550_setup(priv); 442 + 465 443 return 0; 466 444 } 445 + #else 446 + #define i2c_au1550_suspend NULL 447 + #define i2c_au1550_resume NULL 448 + #endif 467 449 468 450 static struct platform_driver au1xpsc_smbus_driver = { 469 451 .driver = {