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

i2c: uniphier: add suspend / resume support

When resuming, set up registers that have been lost in the sleep state.
Also, add clock handling in the resume / suspend hooks.

Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>

authored by

Masahiro Yamada and committed by
Wolfram Sang
9f9d6a40 8dc0f8c7

+35 -5
+35 -5
drivers/i2c/busses/i2c-uniphier.c
··· 53 53 void __iomem *membase; 54 54 struct clk *clk; 55 55 unsigned int busy_cnt; 56 + unsigned int clk_cycle; 56 57 }; 57 58 58 59 static irqreturn_t uniphier_i2c_interrupt(int irq, void *dev_id) ··· 317 316 .unprepare_recovery = uniphier_i2c_unprepare_recovery, 318 317 }; 319 318 320 - static void uniphier_i2c_hw_init(struct uniphier_i2c_priv *priv, 321 - u32 bus_speed, unsigned long clk_rate) 319 + static void uniphier_i2c_hw_init(struct uniphier_i2c_priv *priv) 322 320 { 321 + unsigned int cyc = priv->clk_cycle; 322 + 323 323 uniphier_i2c_reset(priv, true); 324 324 325 - writel((clk_rate / bus_speed / 2 << 16) | (clk_rate / bus_speed), 326 - priv->membase + UNIPHIER_I2C_CLK); 325 + writel((cyc / 2 << 16) | cyc, priv->membase + UNIPHIER_I2C_CLK); 327 326 328 327 uniphier_i2c_reset(priv, false); 329 328 } ··· 377 376 goto disable_clk; 378 377 } 379 378 379 + priv->clk_cycle = clk_rate / bus_speed; 380 380 init_completion(&priv->comp); 381 381 priv->adap.owner = THIS_MODULE; 382 382 priv->adap.algo = &uniphier_i2c_algo; ··· 388 386 i2c_set_adapdata(&priv->adap, priv); 389 387 platform_set_drvdata(pdev, priv); 390 388 391 - uniphier_i2c_hw_init(priv, bus_speed, clk_rate); 389 + uniphier_i2c_hw_init(priv); 392 390 393 391 ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name, 394 392 priv); ··· 415 413 return 0; 416 414 } 417 415 416 + static int __maybe_unused uniphier_i2c_suspend(struct device *dev) 417 + { 418 + struct uniphier_i2c_priv *priv = dev_get_drvdata(dev); 419 + 420 + clk_disable_unprepare(priv->clk); 421 + 422 + return 0; 423 + } 424 + 425 + static int __maybe_unused uniphier_i2c_resume(struct device *dev) 426 + { 427 + struct uniphier_i2c_priv *priv = dev_get_drvdata(dev); 428 + int ret; 429 + 430 + ret = clk_prepare_enable(priv->clk); 431 + if (ret) 432 + return ret; 433 + 434 + uniphier_i2c_hw_init(priv); 435 + 436 + return 0; 437 + } 438 + 439 + static const struct dev_pm_ops uniphier_i2c_pm_ops = { 440 + SET_SYSTEM_SLEEP_PM_OPS(uniphier_i2c_suspend, uniphier_i2c_resume) 441 + }; 442 + 418 443 static const struct of_device_id uniphier_i2c_match[] = { 419 444 { .compatible = "socionext,uniphier-i2c" }, 420 445 { /* sentinel */ } ··· 454 425 .driver = { 455 426 .name = "uniphier-i2c", 456 427 .of_match_table = uniphier_i2c_match, 428 + .pm = &uniphier_i2c_pm_ops, 457 429 }, 458 430 }; 459 431 module_platform_driver(uniphier_i2c_drv);