Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 358783
b: refs/heads/master
c: 24e9e15
h: refs/heads/master
i:
  358781: 29dfb30
  358779: b35cf64
  358775: d8d2d70
  358767: b24c169
  358751: e91ad34
  358719: a579f25
  358655: 4829203
v: v3
  • Loading branch information
Patrice Chotard authored and Wolfram Sang committed Jan 28, 2013
1 parent f53e801 commit 1f60830
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 631056c399d2bdf34ee147c99401fee093ee4bfe
refs/heads/master: 24e9e157d5197e469a414d0f52ce04e8b539a715
89 changes: 89 additions & 0 deletions trunk/drivers/i2c/busses/i2c-nomadik.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <linux/platform_data/i2c-nomadik.h>
#include <linux/of.h>
#include <linux/of_i2c.h>
#include <linux/pinctrl/consumer.h>

#define DRIVER_NAME "nmk-i2c"

Expand Down Expand Up @@ -147,6 +148,10 @@ struct i2c_nmk_client {
* @stop: stop condition.
* @xfer_complete: acknowledge completion for a I2C message.
* @result: controller propogated result.
* @pinctrl: pinctrl handle.
* @pins_default: default state for the pins.
* @pins_idle: idle state for the pins.
* @pins_sleep: sleep state for the pins.
* @busy: Busy doing transfer.
*/
struct nmk_i2c_dev {
Expand All @@ -160,6 +165,11 @@ struct nmk_i2c_dev {
int stop;
struct completion xfer_complete;
int result;
/* Three pin states - default, idle & sleep */
struct pinctrl *pinctrl;
struct pinctrl_state *pins_default;
struct pinctrl_state *pins_idle;
struct pinctrl_state *pins_sleep;
bool busy;
};

Expand Down Expand Up @@ -636,6 +646,15 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
goto out_clk;
}

/* Optionaly enable pins to be muxed in and configured */
if (!IS_ERR(dev->pins_default)) {
status = pinctrl_select_state(dev->pinctrl,
dev->pins_default);
if (status)
dev_err(&dev->adev->dev,
"could not set default pins\n");
}

status = init_hw(dev);
if (status)
goto out;
Expand Down Expand Up @@ -663,6 +682,15 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
out:
clk_disable_unprepare(dev->clk);
out_clk:
/* Optionally let pins go into idle state */
if (!IS_ERR(dev->pins_idle)) {
status = pinctrl_select_state(dev->pinctrl,
dev->pins_idle);
if (status)
dev_err(&dev->adev->dev,
"could not set pins to idle state\n");
}

pm_runtime_put_sync(&dev->adev->dev);

dev->busy = false;
Expand Down Expand Up @@ -857,15 +885,41 @@ static int nmk_i2c_suspend(struct device *dev)
{
struct amba_device *adev = to_amba_device(dev);
struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
int ret;

if (nmk_i2c->busy)
return -EBUSY;

if (!IS_ERR(nmk_i2c->pins_sleep)) {
ret = pinctrl_select_state(nmk_i2c->pinctrl,
nmk_i2c->pins_sleep);
if (ret)
dev_err(dev, "could not set pins to sleep state\n");
}

return 0;
}

static int nmk_i2c_resume(struct device *dev)
{
struct amba_device *adev = to_amba_device(dev);
struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
int ret;

/* First go to the default state */
if (!IS_ERR(nmk_i2c->pins_default)) {
ret = pinctrl_select_state(nmk_i2c->pinctrl,
nmk_i2c->pins_default);
if (ret)
dev_err(dev, "could not set pins to default state\n");
}
/* Then let's idle the pins until the next transfer happens */
if (!IS_ERR(nmk_i2c->pins_idle)) {
ret = pinctrl_select_state(nmk_i2c->pinctrl,
nmk_i2c->pins_idle);
if (ret)
dev_err(dev, "could not set pins to idle state\n");
}
return 0;
}
#else
Expand Down Expand Up @@ -953,6 +1007,40 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
dev->adev = adev;
amba_set_drvdata(adev, dev);

dev->pinctrl = devm_pinctrl_get(&adev->dev);
if (IS_ERR(dev->pinctrl)) {
ret = PTR_ERR(dev->pinctrl);
goto err_pinctrl;
}

dev->pins_default = pinctrl_lookup_state(dev->pinctrl,
PINCTRL_STATE_DEFAULT);
if (IS_ERR(dev->pins_default)) {
dev_err(&adev->dev, "could not get default pinstate\n");
} else {
ret = pinctrl_select_state(dev->pinctrl,
dev->pins_default);
if (ret)
dev_dbg(&adev->dev, "could not set default pinstate\n");
}

dev->pins_idle = pinctrl_lookup_state(dev->pinctrl,
PINCTRL_STATE_IDLE);
if (IS_ERR(dev->pins_idle)) {
dev_dbg(&adev->dev, "could not get idle pinstate\n");
} else {
/* If possible, let's go to idle until the first transfer */
ret = pinctrl_select_state(dev->pinctrl,
dev->pins_idle);
if (ret)
dev_dbg(&adev->dev, "could not set idle pinstate\n");
}

dev->pins_sleep = pinctrl_lookup_state(dev->pinctrl,
PINCTRL_STATE_SLEEP);
if (IS_ERR(dev->pins_sleep))
dev_dbg(&adev->dev, "could not get sleep pinstate\n");

dev->virtbase = ioremap(adev->res.start, resource_size(&adev->res));
if (!dev->virtbase) {
ret = -ENOMEM;
Expand Down Expand Up @@ -1022,6 +1110,7 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
err_no_ioremap:
amba_set_drvdata(adev, NULL);
kfree(dev);
err_pinctrl:
err_no_mem:

return ret;
Expand Down

0 comments on commit 1f60830

Please sign in to comment.