[PATCH] i2c: nomadik: adopt pinctrl support

2013-01-06 Thread Linus Walleij
From: Patrice Chotard 

Amend the I2C nomadik pin controller to optionally take a pin control
handle and set the state of the pins to:

- "default" on boot, resume and before performing an i2c transfer
- "idle" after initial default, after resume default, and after each
   i2c xfer
- "sleep" on suspend()

This should make it possible to optimize energy usage for the pins
both for the suspend/resume cycle, and for runtime cases inbetween
I2C transfers.

Signed-off-by: Patrice Chotard 
Signed-off-by: Linus Walleij 
---
ChangeLog v3->v4:
- Rebase onto v3.8-rc2
ChangeLog v2->v3:
- Rebase on top of the patch from Philippe/Ulf.
ChangeLog v1->v2:
- We used only two states initially: default and sleep. It turns
  out you can save some energy when idling (between transfers)
  and even more when suspending on our platform, so grab all
  three states and use them as applicable.
---
 drivers/i2c/busses/i2c-nomadik.c | 92 
 1 file changed, 92 insertions(+)

diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index 8b2ffcf..8a5168a 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -26,6 +26,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define DRIVER_NAME "nmk-i2c"
 
@@ -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 {
@@ -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;
boolbusy;
 };
 
@@ -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;
@@ -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;
@@ -857,15 +885,44 @@ 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
@@ -953,6 +1010,40 @@ static int nmk_i2c_probe(struct amba_device *adev, const 
struct amba_id *id)
dev->adev = adev;
amb

question about drivers/i2c/busses/i2c-davinci.c

2013-01-06 Thread Julia Lawall
The function davinci_i2c_remove in drivers/i2c/busses/i2c-davinci.c 
contains the following code:


put_device(&pdev->dev);

clk_disable_unprepare(dev->clk);
clk_put(dev->clk);
dev->clk = NULL;

davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0);
free_irq(dev->irq, dev);

Is there any danger in putting free_irq(dev->irq, dev); after 
put_device(&pdev->dev);, because the interrupt handler i2c_davinci_isr can 
eg refer to dev->dev.


thanks,
julia
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] at24: extend driver to allow writing via i2c_smbus_write_byte_data

2013-01-06 Thread Christian Gmeiner
ping
--
Christian Gmeiner, MSc


2012/12/19 Christian Gmeiner :
> I have a at24 EEPROM connected via i2c bus provided by ISCH i2c
> bus driver. This bus driver does not support
> I2C_FUNC_SMBUS_WRITE_I2C_BLOCK and so I was looking for a way
> to be able to write the eeprom. This patch adds support for
> I2C_SMBUS_BYTE_DATA writing via i2c_smbus_write_byte_data.
> It is quite slow, but it works.
>
> Signed-off-by: Christian Gmeiner 
> ---
>  drivers/misc/eeprom/at24.c | 35 +--
>  1 file changed, 29 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
> index 2baeec5..723b411 100644
> --- a/drivers/misc/eeprom/at24.c
> +++ b/drivers/misc/eeprom/at24.c
> @@ -56,6 +56,7 @@ struct at24_data {
> struct at24_platform_data chip;
> struct memory_accessor macc;
> int use_smbus;
> +   int use_smbuse_write;
>
> /*
>  * Lock protects against activities from other Linux tasks,
> @@ -324,7 +325,7 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, 
> const char *buf,
>  {
> struct i2c_client *client;
> struct i2c_msg msg;
> -   ssize_t status;
> +   ssize_t status = 0;
> unsigned long timeout, write_time;
> unsigned next_page;
>
> @@ -365,9 +366,18 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, 
> const char *buf,
> timeout = jiffies + msecs_to_jiffies(write_timeout);
> do {
> write_time = jiffies;
> -   if (at24->use_smbus) {
> -   status = i2c_smbus_write_i2c_block_data(client,
> -   offset, count, buf);
> +   if (at24->use_smbuse_write) {
> +   switch (at24->use_smbuse_write) {
> +   case I2C_SMBUS_I2C_BLOCK_DATA:
> +   status = 
> i2c_smbus_write_i2c_block_data(client,
> +   offset, count, buf);
> +   break;
> +   case I2C_SMBUS_BYTE_DATA:
> +   status = i2c_smbus_write_byte_data(client,
> +   offset, buf[0]);
> +   break;
> +   }
> +
> if (status == 0)
> status = count;
> } else {
> @@ -484,6 +494,7 @@ static int at24_probe(struct i2c_client *client, const 
> struct i2c_device_id *id)
> struct at24_platform_data chip;
> bool writable;
> int use_smbus = 0;
> +   int use_smbus_write = 0;
> struct at24_data *at24;
> int err;
> unsigned i, num_addresses;
> @@ -547,6 +558,18 @@ static int at24_probe(struct i2c_client *client, const 
> struct i2c_device_id *id)
> }
> }
>
> +   /* Use I2C operations unless we're stuck with SMBus extensions. */
> +   if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
> +   if (!i2c_check_functionality(client->adapter,
> +   I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
> +   use_smbus_write = I2C_SMBUS_I2C_BLOCK_DATA;
> +   } else if (i2c_check_functionality(client->adapter,
> +   I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) {
> +   use_smbus_write = I2C_SMBUS_BYTE_DATA;
> +   chip.page_size = 1;
> +   }
> +   }
> +
> if (chip.flags & AT24_FLAG_TAKE8ADDR)
> num_addresses = 8;
> else
> @@ -562,6 +585,7 @@ static int at24_probe(struct i2c_client *client, const 
> struct i2c_device_id *id)
>
> mutex_init(&at24->lock);
> at24->use_smbus = use_smbus;
> +   at24->use_smbuse_write = use_smbus_write;
> at24->chip = chip;
> at24->num_addresses = num_addresses;
>
> @@ -579,8 +603,7 @@ static int at24_probe(struct i2c_client *client, const 
> struct i2c_device_id *id)
>
> writable = !(chip.flags & AT24_FLAG_READONLY);
> if (writable) {
> -   if (!use_smbus || i2c_check_functionality(client->adapter,
> -   I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
> +   if (!use_smbus || use_smbus_write) {
>
> unsigned write_max = chip.page_size;
>
> --
> 1.7.12.2.421.g261b511
>
--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html