libceph: move r_reply_op_{len,result} into struct ceph_osd_req_op
[linux-2.6-block.git] / drivers / power / bq24735-charger.c
index eb2b3689de975ac1b670b2a2226b82734b7fc58e..fa454c19ce1747ff27f090766b4acf40c0481a3a 100644 (file)
@@ -48,6 +48,8 @@ struct bq24735 {
        struct power_supply_desc        charger_desc;
        struct i2c_client               *client;
        struct bq24735_platform         *pdata;
+       struct mutex                    lock;
+       bool                            charging;
 };
 
 static inline struct bq24735 *to_bq24735(struct power_supply *psy)
@@ -56,9 +58,23 @@ static inline struct bq24735 *to_bq24735(struct power_supply *psy)
 }
 
 static enum power_supply_property bq24735_charger_properties[] = {
+       POWER_SUPPLY_PROP_STATUS,
        POWER_SUPPLY_PROP_ONLINE,
 };
 
+static int bq24735_charger_property_is_writeable(struct power_supply *psy,
+                                                enum power_supply_property psp)
+{
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               return 1;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
 static inline int bq24735_write_word(struct i2c_client *client, u8 reg,
                                     u16 value)
 {
@@ -90,6 +106,9 @@ static int bq24735_update_word(struct i2c_client *client, u8 reg,
 
 static inline int bq24735_enable_charging(struct bq24735 *charger)
 {
+       if (charger->pdata->ext_control)
+               return 0;
+
        return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
                                   BQ24735_CHG_OPT_CHARGE_DISABLE,
                                   ~BQ24735_CHG_OPT_CHARGE_DISABLE);
@@ -97,6 +116,9 @@ static inline int bq24735_enable_charging(struct bq24735 *charger)
 
 static inline int bq24735_disable_charging(struct bq24735 *charger)
 {
+       if (charger->pdata->ext_control)
+               return 0;
+
        return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
                                   BQ24735_CHG_OPT_CHARGE_DISABLE,
                                   BQ24735_CHG_OPT_CHARGE_DISABLE);
@@ -108,6 +130,9 @@ static int bq24735_config_charger(struct bq24735 *charger)
        int ret;
        u16 value;
 
+       if (pdata->ext_control)
+               return 0;
+
        if (pdata->charge_current) {
                value = pdata->charge_current & BQ24735_CHARGE_CURRENT_MASK;
 
@@ -174,16 +199,30 @@ static bool bq24735_charger_is_present(struct bq24735 *charger)
        return false;
 }
 
+static int bq24735_charger_is_charging(struct bq24735 *charger)
+{
+       int ret = bq24735_read_word(charger->client, BQ24735_CHG_OPT);
+
+       if (ret < 0)
+               return ret;
+
+       return !(ret & BQ24735_CHG_OPT_CHARGE_DISABLE);
+}
+
 static irqreturn_t bq24735_charger_isr(int irq, void *devid)
 {
        struct power_supply *psy = devid;
        struct bq24735 *charger = to_bq24735(psy);
 
-       if (bq24735_charger_is_present(charger))
+       mutex_lock(&charger->lock);
+
+       if (charger->charging && bq24735_charger_is_present(charger))
                bq24735_enable_charging(charger);
        else
                bq24735_disable_charging(charger);
 
+       mutex_unlock(&charger->lock);
+
        power_supply_changed(psy);
 
        return IRQ_HANDLED;
@@ -199,6 +238,19 @@ static int bq24735_charger_get_property(struct power_supply *psy,
        case POWER_SUPPLY_PROP_ONLINE:
                val->intval = bq24735_charger_is_present(charger) ? 1 : 0;
                break;
+       case POWER_SUPPLY_PROP_STATUS:
+               switch (bq24735_charger_is_charging(charger)) {
+               case 1:
+                       val->intval = POWER_SUPPLY_STATUS_CHARGING;
+                       break;
+               case 0:
+                       val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+                       break;
+               default:
+                       val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+                       break;
+               }
+               break;
        default:
                return -EINVAL;
        }
@@ -206,6 +258,46 @@ static int bq24735_charger_get_property(struct power_supply *psy,
        return 0;
 }
 
+static int bq24735_charger_set_property(struct power_supply *psy,
+                                       enum power_supply_property psp,
+                                       const union power_supply_propval *val)
+{
+       struct bq24735 *charger = to_bq24735(psy);
+       int ret;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               switch (val->intval) {
+               case POWER_SUPPLY_STATUS_CHARGING:
+                       mutex_lock(&charger->lock);
+                       charger->charging = true;
+                       ret = bq24735_enable_charging(charger);
+                       mutex_unlock(&charger->lock);
+                       if (ret)
+                               return ret;
+                       bq24735_config_charger(charger);
+                       break;
+               case POWER_SUPPLY_STATUS_DISCHARGING:
+               case POWER_SUPPLY_STATUS_NOT_CHARGING:
+                       mutex_lock(&charger->lock);
+                       charger->charging = false;
+                       ret = bq24735_disable_charging(charger);
+                       mutex_unlock(&charger->lock);
+                       if (ret)
+                               return ret;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               power_supply_changed(psy);
+               break;
+       default:
+               return -EPERM;
+       }
+
+       return 0;
+}
+
 static struct bq24735_platform *bq24735_parse_dt_data(struct i2c_client *client)
 {
        struct bq24735_platform *pdata;
@@ -239,6 +331,8 @@ static struct bq24735_platform *bq24735_parse_dt_data(struct i2c_client *client)
        if (!ret)
                pdata->input_current = val;
 
+       pdata->ext_control = of_property_read_bool(np, "ti,external-control");
+
        return pdata;
 }
 
@@ -255,6 +349,8 @@ static int bq24735_charger_probe(struct i2c_client *client,
        if (!charger)
                return -ENOMEM;
 
+       mutex_init(&charger->lock);
+       charger->charging = true;
        charger->pdata = client->dev.platform_data;
 
        if (IS_ENABLED(CONFIG_OF) && !charger->pdata && client->dev.of_node)
@@ -285,6 +381,9 @@ static int bq24735_charger_probe(struct i2c_client *client,
        supply_desc->properties = bq24735_charger_properties;
        supply_desc->num_properties = ARRAY_SIZE(bq24735_charger_properties);
        supply_desc->get_property = bq24735_charger_get_property;
+       supply_desc->set_property = bq24735_charger_set_property;
+       supply_desc->property_is_writeable =
+                               bq24735_charger_property_is_writeable;
 
        psy_cfg.supplied_to = charger->pdata->supplied_to;
        psy_cfg.num_supplicants = charger->pdata->num_supplicants;
@@ -293,27 +392,6 @@ static int bq24735_charger_probe(struct i2c_client *client,
 
        i2c_set_clientdata(client, charger);
 
-       ret = bq24735_read_word(client, BQ24735_MANUFACTURER_ID);
-       if (ret < 0) {
-               dev_err(&client->dev, "Failed to read manufacturer id : %d\n",
-                       ret);
-               return ret;
-       } else if (ret != 0x0040) {
-               dev_err(&client->dev,
-                       "manufacturer id mismatch. 0x0040 != 0x%04x\n", ret);
-               return -ENODEV;
-       }
-
-       ret = bq24735_read_word(client, BQ24735_DEVICE_ID);
-       if (ret < 0) {
-               dev_err(&client->dev, "Failed to read device id : %d\n", ret);
-               return ret;
-       } else if (ret != 0x000B) {
-               dev_err(&client->dev,
-                       "device id mismatch. 0x000b != 0x%04x\n", ret);
-               return -ENODEV;
-       }
-
        if (gpio_is_valid(charger->pdata->status_gpio)) {
                ret = devm_gpio_request(&client->dev,
                                        charger->pdata->status_gpio,
@@ -327,6 +405,30 @@ static int bq24735_charger_probe(struct i2c_client *client,
                charger->pdata->status_gpio_valid = !ret;
        }
 
+       if (!charger->pdata->status_gpio_valid
+           || bq24735_charger_is_present(charger)) {
+               ret = bq24735_read_word(client, BQ24735_MANUFACTURER_ID);
+               if (ret < 0) {
+                       dev_err(&client->dev, "Failed to read manufacturer id : %d\n",
+                               ret);
+                       return ret;
+               } else if (ret != 0x0040) {
+                       dev_err(&client->dev,
+                               "manufacturer id mismatch. 0x0040 != 0x%04x\n", ret);
+                       return -ENODEV;
+               }
+
+               ret = bq24735_read_word(client, BQ24735_DEVICE_ID);
+               if (ret < 0) {
+                       dev_err(&client->dev, "Failed to read device id : %d\n", ret);
+                       return ret;
+               } else if (ret != 0x000B) {
+                       dev_err(&client->dev,
+                               "device id mismatch. 0x000b != 0x%04x\n", ret);
+                       return -ENODEV;
+               }
+       }
+
        ret = bq24735_config_charger(charger);
        if (ret < 0) {
                dev_err(&client->dev, "failed in configuring charger");