diff options
| -rw-r--r-- | Documentation/devicetree/bindings/power/rx51-battery.txt | 25 | ||||
| -rw-r--r-- | Documentation/power/power_supply_class.txt | 6 | ||||
| -rw-r--r-- | drivers/power/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/power/Makefile | 1 | ||||
| -rw-r--r-- | drivers/power/bq2415x_charger.c | 8 | ||||
| -rw-r--r-- | drivers/power/bq27x00_battery.c | 28 | ||||
| -rw-r--r-- | drivers/power/ipaq_micro_battery.c | 290 | ||||
| -rw-r--r-- | drivers/power/power_supply_core.c | 3 | ||||
| -rw-r--r-- | drivers/power/power_supply_sysfs.c | 4 | ||||
| -rw-r--r-- | drivers/power/reset/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/power/reset/Makefile | 1 | ||||
| -rw-r--r-- | drivers/power/reset/brcmstb-reboot.c | 120 | ||||
| -rw-r--r-- | drivers/power/reset/gpio-poweroff.c | 52 | ||||
| -rw-r--r-- | drivers/power/reset/restart-poweroff.c | 2 | ||||
| -rw-r--r-- | drivers/power/rx51_battery.c | 90 | ||||
| -rw-r--r-- | drivers/power/tps65090-charger.c | 76 | ||||
| -rw-r--r-- | drivers/power/twl4030_charger.c | 44 | ||||
| -rw-r--r-- | include/linux/power_supply.h | 4 |
18 files changed, 673 insertions, 99 deletions
diff --git a/Documentation/devicetree/bindings/power/rx51-battery.txt b/Documentation/devicetree/bindings/power/rx51-battery.txt new file mode 100644 index 000000000000..90438453db58 --- /dev/null +++ b/Documentation/devicetree/bindings/power/rx51-battery.txt | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | Binding for Nokia N900 battery | ||
| 2 | |||
| 3 | The Nokia N900 battery status can be read via the TWL4030's A/D converter. | ||
| 4 | |||
| 5 | Required properties: | ||
| 6 | - compatible: Should contain one of the following: | ||
| 7 | * "nokia,n900-battery" | ||
| 8 | - io-channels: Should contain IIO channel specifiers | ||
| 9 | for each element in io-channel-names. | ||
| 10 | - io-channel-names: Should contain the following values: | ||
| 11 | * "temp" - The ADC channel for temperature reading | ||
| 12 | * "bsi" - The ADC channel for battery size identification | ||
| 13 | * "vbat" - The ADC channel to measure the battery voltage | ||
| 14 | |||
| 15 | Example from Nokia N900: | ||
| 16 | |||
| 17 | battery: n900-battery { | ||
| 18 | compatible = "nokia,n900-battery"; | ||
| 19 | io-channels = <&twl4030_madc 0>, | ||
| 20 | <&twl4030_madc 4>, | ||
| 21 | <&twl4030_madc 12>; | ||
| 22 | io-channel-names = "temp", | ||
| 23 | "bsi", | ||
| 24 | "vbat"; | ||
| 25 | }; | ||
diff --git a/Documentation/power/power_supply_class.txt b/Documentation/power/power_supply_class.txt index 89a8816990ff..48cff881cb8a 100644 --- a/Documentation/power/power_supply_class.txt +++ b/Documentation/power/power_supply_class.txt | |||
| @@ -118,6 +118,10 @@ relative, time-based measurements. | |||
| 118 | CONSTANT_CHARGE_CURRENT - constant charge current programmed by charger. | 118 | CONSTANT_CHARGE_CURRENT - constant charge current programmed by charger. |
| 119 | CONSTANT_CHARGE_CURRENT_MAX - maximum charge current supported by the | 119 | CONSTANT_CHARGE_CURRENT_MAX - maximum charge current supported by the |
| 120 | power supply object. | 120 | power supply object. |
| 121 | INPUT_CURRENT_LIMIT - input current limit programmed by charger. Indicates | ||
| 122 | the current drawn from a charging source. | ||
| 123 | CHARGE_TERM_CURRENT - Charge termination current used to detect the end of charge | ||
| 124 | condition. | ||
| 121 | 125 | ||
| 122 | CONSTANT_CHARGE_VOLTAGE - constant charge voltage programmed by charger. | 126 | CONSTANT_CHARGE_VOLTAGE - constant charge voltage programmed by charger. |
| 123 | CONSTANT_CHARGE_VOLTAGE_MAX - maximum charge voltage supported by the | 127 | CONSTANT_CHARGE_VOLTAGE_MAX - maximum charge voltage supported by the |
| @@ -140,6 +144,8 @@ TEMP_ALERT_MAX - maximum battery temperature alert. | |||
| 140 | TEMP_AMBIENT - ambient temperature. | 144 | TEMP_AMBIENT - ambient temperature. |
| 141 | TEMP_AMBIENT_ALERT_MIN - minimum ambient temperature alert. | 145 | TEMP_AMBIENT_ALERT_MIN - minimum ambient temperature alert. |
| 142 | TEMP_AMBIENT_ALERT_MAX - maximum ambient temperature alert. | 146 | TEMP_AMBIENT_ALERT_MAX - maximum ambient temperature alert. |
| 147 | TEMP_MIN - minimum operatable temperature | ||
| 148 | TEMP_MAX - maximum operatable temperature | ||
| 143 | 149 | ||
| 144 | TIME_TO_EMPTY - seconds left for battery to be considered empty (i.e. | 150 | TIME_TO_EMPTY - seconds left for battery to be considered empty (i.e. |
| 145 | while battery powers a load) | 151 | while battery powers a load) |
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index ba6975123071..73cfcdf28a36 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig | |||
| @@ -137,6 +137,13 @@ config BATTERY_COLLIE | |||
| 137 | Say Y to enable support for the battery on the Sharp Zaurus | 137 | Say Y to enable support for the battery on the Sharp Zaurus |
| 138 | SL-5500 (collie) models. | 138 | SL-5500 (collie) models. |
| 139 | 139 | ||
| 140 | config BATTERY_IPAQ_MICRO | ||
| 141 | tristate "iPAQ Atmel Micro ASIC battery driver" | ||
| 142 | depends on MFD_IPAQ_MICRO | ||
| 143 | help | ||
| 144 | Choose this option if you want to monitor battery status on | ||
| 145 | Compaq/HP iPAQ h3100 and h3600. | ||
| 146 | |||
| 140 | config BATTERY_WM97XX | 147 | config BATTERY_WM97XX |
| 141 | bool "WM97xx generic battery driver" | 148 | bool "WM97xx generic battery driver" |
| 142 | depends on TOUCHSCREEN_WM97XX=y | 149 | depends on TOUCHSCREEN_WM97XX=y |
diff --git a/drivers/power/Makefile b/drivers/power/Makefile index ee54a3e4c90a..dfa894273926 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile | |||
| @@ -25,6 +25,7 @@ obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o | |||
| 25 | obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o | 25 | obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o |
| 26 | obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o | 26 | obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o |
| 27 | obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o | 27 | obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o |
| 28 | obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o | ||
| 28 | obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o | 29 | obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o |
| 29 | obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o | 30 | obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o |
| 30 | obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o | 31 | obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o |
diff --git a/drivers/power/bq2415x_charger.c b/drivers/power/bq2415x_charger.c index 79a37f6d3307..e384844a1ae1 100644 --- a/drivers/power/bq2415x_charger.c +++ b/drivers/power/bq2415x_charger.c | |||
| @@ -840,8 +840,7 @@ static int bq2415x_notifier_call(struct notifier_block *nb, | |||
| 840 | if (bq->automode < 1) | 840 | if (bq->automode < 1) |
| 841 | return NOTIFY_OK; | 841 | return NOTIFY_OK; |
| 842 | 842 | ||
| 843 | sysfs_notify(&bq->charger.dev->kobj, NULL, "reported_mode"); | 843 | schedule_delayed_work(&bq->work, 0); |
| 844 | bq2415x_set_mode(bq, bq->reported_mode); | ||
| 845 | 844 | ||
| 846 | return NOTIFY_OK; | 845 | return NOTIFY_OK; |
| 847 | } | 846 | } |
| @@ -892,6 +891,11 @@ static void bq2415x_timer_work(struct work_struct *work) | |||
| 892 | int error; | 891 | int error; |
| 893 | int boost; | 892 | int boost; |
| 894 | 893 | ||
| 894 | if (bq->automode > 0 && (bq->reported_mode != bq->mode)) { | ||
| 895 | sysfs_notify(&bq->charger.dev->kobj, NULL, "reported_mode"); | ||
| 896 | bq2415x_set_mode(bq, bq->reported_mode); | ||
| 897 | } | ||
| 898 | |||
| 895 | if (!bq->autotimer) | 899 | if (!bq->autotimer) |
| 896 | return; | 900 | return; |
| 897 | 901 | ||
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index b309713b63bc..e10763e3a1d5 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | * http://www.ti.com/product/bq27425-g1 | 25 | * http://www.ti.com/product/bq27425-g1 |
| 26 | */ | 26 | */ |
| 27 | 27 | ||
| 28 | #include <linux/device.h> | ||
| 28 | #include <linux/module.h> | 29 | #include <linux/module.h> |
| 29 | #include <linux/param.h> | 30 | #include <linux/param.h> |
| 30 | #include <linux/jiffies.h> | 31 | #include <linux/jiffies.h> |
| @@ -415,6 +416,9 @@ static void bq27x00_update(struct bq27x00_device_info *di) | |||
| 415 | bool is_bq27425 = di->chip == BQ27425; | 416 | bool is_bq27425 = di->chip == BQ27425; |
| 416 | 417 | ||
| 417 | cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, !is_bq27500); | 418 | cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, !is_bq27500); |
| 419 | if ((cache.flags & 0xff) == 0xff) | ||
| 420 | /* read error */ | ||
| 421 | cache.flags = -1; | ||
| 418 | if (cache.flags >= 0) { | 422 | if (cache.flags >= 0) { |
| 419 | if (!is_bq27500 && !is_bq27425 | 423 | if (!is_bq27500 && !is_bq27425 |
| 420 | && (cache.flags & BQ27000_FLAG_CI)) { | 424 | && (cache.flags & BQ27000_FLAG_CI)) { |
| @@ -804,7 +808,7 @@ static int bq27x00_battery_probe(struct i2c_client *client, | |||
| 804 | goto batt_failed_1; | 808 | goto batt_failed_1; |
| 805 | } | 809 | } |
| 806 | 810 | ||
| 807 | di = kzalloc(sizeof(*di), GFP_KERNEL); | 811 | di = devm_kzalloc(&client->dev, sizeof(*di), GFP_KERNEL); |
| 808 | if (!di) { | 812 | if (!di) { |
| 809 | dev_err(&client->dev, "failed to allocate device info data\n"); | 813 | dev_err(&client->dev, "failed to allocate device info data\n"); |
| 810 | retval = -ENOMEM; | 814 | retval = -ENOMEM; |
| @@ -819,14 +823,12 @@ static int bq27x00_battery_probe(struct i2c_client *client, | |||
| 819 | 823 | ||
| 820 | retval = bq27x00_powersupply_init(di); | 824 | retval = bq27x00_powersupply_init(di); |
| 821 | if (retval) | 825 | if (retval) |
| 822 | goto batt_failed_3; | 826 | goto batt_failed_2; |
| 823 | 827 | ||
| 824 | i2c_set_clientdata(client, di); | 828 | i2c_set_clientdata(client, di); |
| 825 | 829 | ||
| 826 | return 0; | 830 | return 0; |
| 827 | 831 | ||
| 828 | batt_failed_3: | ||
| 829 | kfree(di); | ||
| 830 | batt_failed_2: | 832 | batt_failed_2: |
| 831 | kfree(name); | 833 | kfree(name); |
| 832 | batt_failed_1: | 834 | batt_failed_1: |
| @@ -849,8 +851,6 @@ static int bq27x00_battery_remove(struct i2c_client *client) | |||
| 849 | idr_remove(&battery_id, di->id); | 851 | idr_remove(&battery_id, di->id); |
| 850 | mutex_unlock(&battery_mutex); | 852 | mutex_unlock(&battery_mutex); |
| 851 | 853 | ||
| 852 | kfree(di); | ||
| 853 | |||
| 854 | return 0; | 854 | return 0; |
| 855 | } | 855 | } |
| 856 | 856 | ||
| @@ -933,7 +933,6 @@ static int bq27000_battery_probe(struct platform_device *pdev) | |||
| 933 | { | 933 | { |
| 934 | struct bq27x00_device_info *di; | 934 | struct bq27x00_device_info *di; |
| 935 | struct bq27000_platform_data *pdata = pdev->dev.platform_data; | 935 | struct bq27000_platform_data *pdata = pdev->dev.platform_data; |
| 936 | int ret; | ||
| 937 | 936 | ||
| 938 | if (!pdata) { | 937 | if (!pdata) { |
| 939 | dev_err(&pdev->dev, "no platform_data supplied\n"); | 938 | dev_err(&pdev->dev, "no platform_data supplied\n"); |
| @@ -945,7 +944,7 @@ static int bq27000_battery_probe(struct platform_device *pdev) | |||
| 945 | return -EINVAL; | 944 | return -EINVAL; |
| 946 | } | 945 | } |
| 947 | 946 | ||
| 948 | di = kzalloc(sizeof(*di), GFP_KERNEL); | 947 | di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL); |
| 949 | if (!di) { | 948 | if (!di) { |
| 950 | dev_err(&pdev->dev, "failed to allocate device info data\n"); | 949 | dev_err(&pdev->dev, "failed to allocate device info data\n"); |
| 951 | return -ENOMEM; | 950 | return -ENOMEM; |
| @@ -959,16 +958,7 @@ static int bq27000_battery_probe(struct platform_device *pdev) | |||
| 959 | di->bat.name = pdata->name ?: dev_name(&pdev->dev); | 958 | di->bat.name = pdata->name ?: dev_name(&pdev->dev); |
| 960 | di->bus.read = &bq27000_read_platform; | 959 | di->bus.read = &bq27000_read_platform; |
| 961 | 960 | ||
| 962 | ret = bq27x00_powersupply_init(di); | 961 | return bq27x00_powersupply_init(di); |
| 963 | if (ret) | ||
| 964 | goto err_free; | ||
| 965 | |||
| 966 | return 0; | ||
| 967 | |||
| 968 | err_free: | ||
| 969 | kfree(di); | ||
| 970 | |||
| 971 | return ret; | ||
| 972 | } | 962 | } |
| 973 | 963 | ||
| 974 | static int bq27000_battery_remove(struct platform_device *pdev) | 964 | static int bq27000_battery_remove(struct platform_device *pdev) |
| @@ -977,8 +967,6 @@ static int bq27000_battery_remove(struct platform_device *pdev) | |||
| 977 | 967 | ||
| 978 | bq27x00_powersupply_unregister(di); | 968 | bq27x00_powersupply_unregister(di); |
| 979 | 969 | ||
| 980 | kfree(di); | ||
| 981 | |||
| 982 | return 0; | 970 | return 0; |
| 983 | } | 971 | } |
| 984 | 972 | ||
diff --git a/drivers/power/ipaq_micro_battery.c b/drivers/power/ipaq_micro_battery.c new file mode 100644 index 000000000000..9d694605cdb7 --- /dev/null +++ b/drivers/power/ipaq_micro_battery.c | |||
| @@ -0,0 +1,290 @@ | |||
| 1 | /* | ||
| 2 | * This program is free software; you can redistribute it and/or modify | ||
| 3 | * it under the terms of the GNU General Public License version 2 as | ||
| 4 | * published by the Free Software Foundation. | ||
| 5 | * | ||
| 6 | * h3xxx atmel micro companion support, battery subdevice | ||
| 7 | * based on previous kernel 2.4 version | ||
| 8 | * Author : Alessandro Gardich <gremlin@gremlin.it> | ||
| 9 | * Author : Linus Walleij <linus.walleij@linaro.org> | ||
| 10 | * | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/init.h> | ||
| 15 | #include <linux/platform_device.h> | ||
| 16 | #include <linux/mfd/ipaq-micro.h> | ||
| 17 | #include <linux/power_supply.h> | ||
| 18 | #include <linux/workqueue.h> | ||
| 19 | |||
| 20 | #define BATT_PERIOD 100000 /* 100 seconds in milliseconds */ | ||
| 21 | |||
| 22 | #define MICRO_BATT_CHEM_ALKALINE 0x01 | ||
| 23 | #define MICRO_BATT_CHEM_NICD 0x02 | ||
| 24 | #define MICRO_BATT_CHEM_NIMH 0x03 | ||
| 25 | #define MICRO_BATT_CHEM_LION 0x04 | ||
| 26 | #define MICRO_BATT_CHEM_LIPOLY 0x05 | ||
| 27 | #define MICRO_BATT_CHEM_NOT_INSTALLED 0x06 | ||
| 28 | #define MICRO_BATT_CHEM_UNKNOWN 0xff | ||
| 29 | |||
| 30 | #define MICRO_BATT_STATUS_HIGH 0x01 | ||
| 31 | #define MICRO_BATT_STATUS_LOW 0x02 | ||
| 32 | #define MICRO_BATT_STATUS_CRITICAL 0x04 | ||
| 33 | #define MICRO_BATT_STATUS_CHARGING 0x08 | ||
| 34 | #define MICRO_BATT_STATUS_CHARGEMAIN 0x10 | ||
| 35 | #define MICRO_BATT_STATUS_DEAD 0x20 /* Battery will not charge */ | ||
| 36 | #define MICRO_BATT_STATUS_NOTINSTALLED 0x20 /* For expansion pack batteries */ | ||
| 37 | #define MICRO_BATT_STATUS_FULL 0x40 /* Battery fully charged */ | ||
| 38 | #define MICRO_BATT_STATUS_NOBATTERY 0x80 | ||
| 39 | #define MICRO_BATT_STATUS_UNKNOWN 0xff | ||
| 40 | |||
| 41 | struct micro_battery { | ||
| 42 | struct ipaq_micro *micro; | ||
| 43 | struct workqueue_struct *wq; | ||
| 44 | struct delayed_work update; | ||
| 45 | u8 ac; | ||
| 46 | u8 chemistry; | ||
| 47 | unsigned int voltage; | ||
| 48 | u16 temperature; | ||
| 49 | u8 flag; | ||
| 50 | }; | ||
| 51 | |||
| 52 | static void micro_battery_work(struct work_struct *work) | ||
| 53 | { | ||
| 54 | struct micro_battery *mb = container_of(work, | ||
| 55 | struct micro_battery, update.work); | ||
| 56 | struct ipaq_micro_msg msg_battery = { | ||
| 57 | .id = MSG_BATTERY, | ||
| 58 | }; | ||
| 59 | struct ipaq_micro_msg msg_sensor = { | ||
| 60 | .id = MSG_THERMAL_SENSOR, | ||
| 61 | }; | ||
| 62 | |||
| 63 | /* First send battery message */ | ||
| 64 | ipaq_micro_tx_msg_sync(mb->micro, &msg_battery); | ||
| 65 | if (msg_battery.rx_len < 4) | ||
| 66 | pr_info("ERROR"); | ||
| 67 | |||
| 68 | /* | ||
| 69 | * Returned message format: | ||
| 70 | * byte 0: 0x00 = Not plugged in | ||
| 71 | * 0x01 = AC adapter plugged in | ||
| 72 | * byte 1: chemistry | ||
| 73 | * byte 2: voltage LSB | ||
| 74 | * byte 3: voltage MSB | ||
| 75 | * byte 4: flags | ||
| 76 | * byte 5-9: same for battery 2 | ||
| 77 | */ | ||
| 78 | mb->ac = msg_battery.rx_data[0]; | ||
| 79 | mb->chemistry = msg_battery.rx_data[1]; | ||
| 80 | mb->voltage = ((((unsigned short)msg_battery.rx_data[3] << 8) + | ||
| 81 | msg_battery.rx_data[2]) * 5000L) * 1000 / 1024; | ||
| 82 | mb->flag = msg_battery.rx_data[4]; | ||
| 83 | |||
| 84 | if (msg_battery.rx_len == 9) | ||
| 85 | pr_debug("second battery ignored\n"); | ||
| 86 | |||
| 87 | /* Then read the sensor */ | ||
| 88 | ipaq_micro_tx_msg_sync(mb->micro, &msg_sensor); | ||
| 89 | mb->temperature = msg_sensor.rx_data[1] << 8 | msg_sensor.rx_data[0]; | ||
| 90 | |||
| 91 | queue_delayed_work(mb->wq, &mb->update, msecs_to_jiffies(BATT_PERIOD)); | ||
| 92 | } | ||
| 93 | |||
| 94 | static int get_capacity(struct power_supply *b) | ||
| 95 | { | ||
| 96 | struct micro_battery *mb = dev_get_drvdata(b->dev->parent); | ||
| 97 | |||
| 98 | switch (mb->flag & 0x07) { | ||
| 99 | case MICRO_BATT_STATUS_HIGH: | ||
| 100 | return 100; | ||
| 101 | break; | ||
| 102 | case MICRO_BATT_STATUS_LOW: | ||
| 103 | return 50; | ||
| 104 | break; | ||
| 105 | case MICRO_BATT_STATUS_CRITICAL: | ||
| 106 | return 5; | ||
| 107 | break; | ||
| 108 | default: | ||
| 109 | break; | ||
| 110 | } | ||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | static int get_status(struct power_supply *b) | ||
| 115 | { | ||
| 116 | struct micro_battery *mb = dev_get_drvdata(b->dev->parent); | ||
| 117 | |||
| 118 | if (mb->flag == MICRO_BATT_STATUS_UNKNOWN) | ||
| 119 | return POWER_SUPPLY_STATUS_UNKNOWN; | ||
| 120 | |||
| 121 | if (mb->flag & MICRO_BATT_STATUS_FULL) | ||
| 122 | return POWER_SUPPLY_STATUS_FULL; | ||
| 123 | |||
| 124 | if ((mb->flag & MICRO_BATT_STATUS_CHARGING) || | ||
| 125 | (mb->flag & MICRO_BATT_STATUS_CHARGEMAIN)) | ||
| 126 | return POWER_SUPPLY_STATUS_CHARGING; | ||
| 127 | |||
| 128 | return POWER_SUPPLY_STATUS_DISCHARGING; | ||
| 129 | } | ||
| 130 | |||
| 131 | static int micro_batt_get_property(struct power_supply *b, | ||
| 132 | enum power_supply_property psp, | ||
| 133 | union power_supply_propval *val) | ||
| 134 | { | ||
| 135 | struct micro_battery *mb = dev_get_drvdata(b->dev->parent); | ||
| 136 | |||
| 137 | switch (psp) { | ||
| 138 | case POWER_SUPPLY_PROP_TECHNOLOGY: | ||
| 139 | switch (mb->chemistry) { | ||
| 140 | case MICRO_BATT_CHEM_NICD: | ||
| 141 | val->intval = POWER_SUPPLY_TECHNOLOGY_NiCd; | ||
| 142 | break; | ||
| 143 | case MICRO_BATT_CHEM_NIMH: | ||
| 144 | val->intval = POWER_SUPPLY_TECHNOLOGY_NiMH; | ||
| 145 | break; | ||
| 146 | case MICRO_BATT_CHEM_LION: | ||
| 147 | val->intval = POWER_SUPPLY_TECHNOLOGY_LION; | ||
| 148 | break; | ||
| 149 | case MICRO_BATT_CHEM_LIPOLY: | ||
| 150 | val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO; | ||
| 151 | break; | ||
| 152 | default: | ||
| 153 | val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; | ||
| 154 | break; | ||
| 155 | }; | ||
| 156 | break; | ||
| 157 | case POWER_SUPPLY_PROP_STATUS: | ||
| 158 | val->intval = get_status(b); | ||
| 159 | break; | ||
| 160 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: | ||
| 161 | val->intval = 4700000; | ||
| 162 | break; | ||
| 163 | case POWER_SUPPLY_PROP_CAPACITY: | ||
| 164 | val->intval = get_capacity(b); | ||
| 165 | break; | ||
| 166 | case POWER_SUPPLY_PROP_TEMP: | ||
| 167 | val->intval = mb->temperature; | ||
| 168 | break; | ||
| 169 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
| 170 | val->intval = mb->voltage; | ||
| 171 | break; | ||
| 172 | default: | ||
| 173 | return -EINVAL; | ||
| 174 | }; | ||
| 175 | |||
| 176 | return 0; | ||
| 177 | } | ||
| 178 | |||
| 179 | static int micro_ac_get_property(struct power_supply *b, | ||
| 180 | enum power_supply_property psp, | ||
| 181 | union power_supply_propval *val) | ||
| 182 | { | ||
| 183 | struct micro_battery *mb = dev_get_drvdata(b->dev->parent); | ||
| 184 | |||
| 185 | switch (psp) { | ||
| 186 | case POWER_SUPPLY_PROP_ONLINE: | ||
| 187 | val->intval = mb->ac; | ||
| 188 | break; | ||
| 189 | default: | ||
| 190 | return -EINVAL; | ||
| 191 | }; | ||
| 192 | |||
| 193 | return 0; | ||
| 194 | } | ||
| 195 | |||
| 196 | static enum power_supply_property micro_batt_power_props[] = { | ||
| 197 | POWER_SUPPLY_PROP_TECHNOLOGY, | ||
| 198 | POWER_SUPPLY_PROP_STATUS, | ||
| 199 | POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, | ||
| 200 | POWER_SUPPLY_PROP_CAPACITY, | ||
| 201 | POWER_SUPPLY_PROP_TEMP, | ||
| 202 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
| 203 | }; | ||
| 204 | |||
| 205 | static struct power_supply micro_batt_power = { | ||
| 206 | .name = "main-battery", | ||
| 207 | .type = POWER_SUPPLY_TYPE_BATTERY, | ||
| 208 | .properties = micro_batt_power_props, | ||
| 209 | .num_properties = ARRAY_SIZE(micro_batt_power_props), | ||
| 210 | .get_property = micro_batt_get_property, | ||
| 211 | .use_for_apm = 1, | ||
| 212 | }; | ||
| 213 | |||
| 214 | static enum power_supply_property micro_ac_power_props[] = { | ||
| 215 | POWER_SUPPLY_PROP_ONLINE, | ||
| 216 | }; | ||
| 217 | |||
| 218 | static struct power_supply micro_ac_power = { | ||
| 219 | .name = "ac", | ||
| 220 | .type = POWER_SUPPLY_TYPE_MAINS, | ||
| 221 | .properties = micro_ac_power_props, | ||
| 222 | .num_properties = ARRAY_SIZE(micro_ac_power_props), | ||
| 223 | .get_property = micro_ac_get_property, | ||
| 224 | }; | ||
| 225 | |||
| 226 | static int micro_batt_probe(struct platform_device *pdev) | ||
| 227 | { | ||
| 228 | struct micro_battery *mb; | ||
| 229 | |||
| 230 | mb = devm_kzalloc(&pdev->dev, sizeof(*mb), GFP_KERNEL); | ||
| 231 | if (!mb) | ||
| 232 | return -ENOMEM; | ||
| 233 | |||
| 234 | mb->micro = dev_get_drvdata(pdev->dev.parent); | ||
| 235 | mb->wq = create_singlethread_workqueue("ipaq-battery-wq"); | ||
| 236 | INIT_DELAYED_WORK(&mb->update, micro_battery_work); | ||
| 237 | platform_set_drvdata(pdev, mb); | ||
| 238 | queue_delayed_work(mb->wq, &mb->update, 1); | ||
| 239 | power_supply_register(&pdev->dev, µ_batt_power); | ||
| 240 | power_supply_register(&pdev->dev, µ_ac_power); | ||
| 241 | |||
| 242 | dev_info(&pdev->dev, "iPAQ micro battery driver\n"); | ||
| 243 | return 0; | ||
| 244 | } | ||
| 245 | |||
| 246 | static int micro_batt_remove(struct platform_device *pdev) | ||
| 247 | |||
| 248 | { | ||
| 249 | struct micro_battery *mb = platform_get_drvdata(pdev); | ||
| 250 | |||
| 251 | power_supply_unregister(µ_ac_power); | ||
| 252 | power_supply_unregister(µ_batt_power); | ||
| 253 | cancel_delayed_work_sync(&mb->update); | ||
| 254 | |||
| 255 | return 0; | ||
| 256 | } | ||
| 257 | |||
| 258 | static int micro_batt_suspend(struct device *dev) | ||
| 259 | { | ||
| 260 | struct micro_battery *mb = dev_get_drvdata(dev); | ||
| 261 | |||
| 262 | cancel_delayed_work_sync(&mb->update); | ||
| 263 | return 0; | ||
| 264 | } | ||
| 265 | |||
| 266 | static int micro_batt_resume(struct device *dev) | ||
| 267 | { | ||
| 268 | struct micro_battery *mb = dev_get_drvdata(dev); | ||
| 269 | |||
| 270 | queue_delayed_work(mb->wq, &mb->update, msecs_to_jiffies(BATT_PERIOD)); | ||
| 271 | return 0; | ||
| 272 | } | ||
| 273 | |||
| 274 | static const struct dev_pm_ops micro_batt_dev_pm_ops = { | ||
| 275 | SET_SYSTEM_SLEEP_PM_OPS(micro_batt_suspend, micro_batt_resume) | ||
| 276 | }; | ||
| 277 | |||
| 278 | static struct platform_driver micro_batt_device_driver = { | ||
| 279 | .driver = { | ||
| 280 | .name = "ipaq-micro-battery", | ||
| 281 | .pm = µ_batt_dev_pm_ops, | ||
| 282 | }, | ||
| 283 | .probe = micro_batt_probe, | ||
| 284 | .remove = micro_batt_remove, | ||
| 285 | }; | ||
| 286 | module_platform_driver(micro_batt_device_driver); | ||
| 287 | |||
| 288 | MODULE_LICENSE("GPL"); | ||
| 289 | MODULE_DESCRIPTION("driver for iPAQ Atmel micro battery"); | ||
| 290 | MODULE_ALIAS("platform:battery-ipaq-micro"); | ||
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 5a5a24e7d43c..078afd61490d 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c | |||
| @@ -537,7 +537,8 @@ static void psy_unregister_cooler(struct power_supply *psy) | |||
| 537 | } | 537 | } |
| 538 | #endif | 538 | #endif |
| 539 | 539 | ||
| 540 | int __power_supply_register(struct device *parent, struct power_supply *psy, bool ws) | 540 | static int __power_supply_register(struct device *parent, |
| 541 | struct power_supply *psy, bool ws) | ||
| 541 | { | 542 | { |
| 542 | struct device *dev; | 543 | struct device *dev; |
| 543 | int rc; | 544 | int rc; |
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c index 44420d1e9094..750a20275664 100644 --- a/drivers/power/power_supply_sysfs.c +++ b/drivers/power/power_supply_sysfs.c | |||
| @@ -167,6 +167,7 @@ static struct device_attribute power_supply_attrs[] = { | |||
| 167 | POWER_SUPPLY_ATTR(constant_charge_voltage_max), | 167 | POWER_SUPPLY_ATTR(constant_charge_voltage_max), |
| 168 | POWER_SUPPLY_ATTR(charge_control_limit), | 168 | POWER_SUPPLY_ATTR(charge_control_limit), |
| 169 | POWER_SUPPLY_ATTR(charge_control_limit_max), | 169 | POWER_SUPPLY_ATTR(charge_control_limit_max), |
| 170 | POWER_SUPPLY_ATTR(input_current_limit), | ||
| 170 | POWER_SUPPLY_ATTR(energy_full_design), | 171 | POWER_SUPPLY_ATTR(energy_full_design), |
| 171 | POWER_SUPPLY_ATTR(energy_empty_design), | 172 | POWER_SUPPLY_ATTR(energy_empty_design), |
| 172 | POWER_SUPPLY_ATTR(energy_full), | 173 | POWER_SUPPLY_ATTR(energy_full), |
| @@ -178,6 +179,8 @@ static struct device_attribute power_supply_attrs[] = { | |||
| 178 | POWER_SUPPLY_ATTR(capacity_alert_max), | 179 | POWER_SUPPLY_ATTR(capacity_alert_max), |
| 179 | POWER_SUPPLY_ATTR(capacity_level), | 180 | POWER_SUPPLY_ATTR(capacity_level), |
| 180 | POWER_SUPPLY_ATTR(temp), | 181 | POWER_SUPPLY_ATTR(temp), |
| 182 | POWER_SUPPLY_ATTR(temp_max), | ||
| 183 | POWER_SUPPLY_ATTR(temp_min), | ||
| 181 | POWER_SUPPLY_ATTR(temp_alert_min), | 184 | POWER_SUPPLY_ATTR(temp_alert_min), |
| 182 | POWER_SUPPLY_ATTR(temp_alert_max), | 185 | POWER_SUPPLY_ATTR(temp_alert_max), |
| 183 | POWER_SUPPLY_ATTR(temp_ambient), | 186 | POWER_SUPPLY_ATTR(temp_ambient), |
| @@ -189,6 +192,7 @@ static struct device_attribute power_supply_attrs[] = { | |||
| 189 | POWER_SUPPLY_ATTR(time_to_full_avg), | 192 | POWER_SUPPLY_ATTR(time_to_full_avg), |
| 190 | POWER_SUPPLY_ATTR(type), | 193 | POWER_SUPPLY_ATTR(type), |
| 191 | POWER_SUPPLY_ATTR(scope), | 194 | POWER_SUPPLY_ATTR(scope), |
| 195 | POWER_SUPPLY_ATTR(charge_term_current), | ||
| 192 | /* Properties of type `const char *' */ | 196 | /* Properties of type `const char *' */ |
| 193 | POWER_SUPPLY_ATTR(model_name), | 197 | POWER_SUPPLY_ATTR(model_name), |
| 194 | POWER_SUPPLY_ATTR(manufacturer), | 198 | POWER_SUPPLY_ATTR(manufacturer), |
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index bdcf5173e377..f2ac54df496f 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig | |||
| @@ -20,6 +20,17 @@ config POWER_RESET_AXXIA | |||
| 20 | 20 | ||
| 21 | Say Y if you have an Axxia family SoC. | 21 | Say Y if you have an Axxia family SoC. |
| 22 | 22 | ||
| 23 | config POWER_RESET_BRCMSTB | ||
| 24 | bool "Broadcom STB reset driver" if COMPILE_TEST | ||
| 25 | depends on POWER_RESET && ARM | ||
| 26 | default ARCH_BRCMSTB | ||
| 27 | help | ||
| 28 | This driver provides restart support for ARM-based Broadcom STB | ||
| 29 | boards. | ||
| 30 | |||
| 31 | Say Y here if you have an ARM-based Broadcom STB board and you wish | ||
| 32 | to have restart support. | ||
| 33 | |||
| 23 | config POWER_RESET_GPIO | 34 | config POWER_RESET_GPIO |
| 24 | bool "GPIO power-off driver" | 35 | bool "GPIO power-off driver" |
| 25 | depends on OF_GPIO && POWER_RESET | 36 | depends on OF_GPIO && POWER_RESET |
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index dde2e8bbac53..7379818ca69d 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | obj-$(CONFIG_POWER_RESET_AS3722) += as3722-poweroff.o | 1 | obj-$(CONFIG_POWER_RESET_AS3722) += as3722-poweroff.o |
| 2 | obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o | 2 | obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o |
| 3 | obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o | ||
| 3 | obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o | 4 | obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o |
| 4 | obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o | 5 | obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o |
| 5 | obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o | 6 | obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o |
diff --git a/drivers/power/reset/brcmstb-reboot.c b/drivers/power/reset/brcmstb-reboot.c new file mode 100644 index 000000000000..3f236924742a --- /dev/null +++ b/drivers/power/reset/brcmstb-reboot.c | |||
| @@ -0,0 +1,120 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2013 Broadcom Corporation | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or | ||
| 5 | * modify it under the terms of the GNU General Public License as | ||
| 6 | * published by the Free Software Foundation version 2. | ||
| 7 | * | ||
| 8 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
| 9 | * kind, whether express or implied; without even the implied warranty | ||
| 10 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/device.h> | ||
| 15 | #include <linux/errno.h> | ||
| 16 | #include <linux/init.h> | ||
| 17 | #include <linux/io.h> | ||
| 18 | #include <linux/jiffies.h> | ||
| 19 | #include <linux/of_address.h> | ||
| 20 | #include <linux/of_irq.h> | ||
| 21 | #include <linux/of_platform.h> | ||
| 22 | #include <linux/platform_device.h> | ||
| 23 | #include <linux/printk.h> | ||
| 24 | #include <linux/reboot.h> | ||
| 25 | #include <linux/regmap.h> | ||
| 26 | #include <linux/smp.h> | ||
| 27 | #include <linux/mfd/syscon.h> | ||
| 28 | |||
| 29 | #include <asm/system_misc.h> | ||
| 30 | |||
| 31 | #define RESET_SOURCE_ENABLE_REG 1 | ||
| 32 | #define SW_MASTER_RESET_REG 2 | ||
| 33 | |||
| 34 | static struct regmap *regmap; | ||
| 35 | static u32 rst_src_en; | ||
| 36 | static u32 sw_mstr_rst; | ||
| 37 | |||
| 38 | static void brcmstb_reboot(enum reboot_mode mode, const char *cmd) | ||
| 39 | { | ||
| 40 | int rc; | ||
| 41 | u32 tmp; | ||
| 42 | |||
| 43 | rc = regmap_write(regmap, rst_src_en, 1); | ||
| 44 | if (rc) { | ||
| 45 | pr_err("failed to write rst_src_en (%d)\n", rc); | ||
| 46 | return; | ||
| 47 | } | ||
| 48 | |||
| 49 | rc = regmap_read(regmap, rst_src_en, &tmp); | ||
| 50 | if (rc) { | ||
| 51 | pr_err("failed to read rst_src_en (%d)\n", rc); | ||
| 52 | return; | ||
| 53 | } | ||
| 54 | |||
| 55 | rc = regmap_write(regmap, sw_mstr_rst, 1); | ||
| 56 | if (rc) { | ||
| 57 | pr_err("failed to write sw_mstr_rst (%d)\n", rc); | ||
| 58 | return; | ||
| 59 | } | ||
| 60 | |||
| 61 | rc = regmap_read(regmap, sw_mstr_rst, &tmp); | ||
| 62 | if (rc) { | ||
| 63 | pr_err("failed to read sw_mstr_rst (%d)\n", rc); | ||
| 64 | return; | ||
| 65 | } | ||
| 66 | |||
| 67 | while (1) | ||
| 68 | ; | ||
| 69 | } | ||
| 70 | |||
| 71 | static int brcmstb_reboot_probe(struct platform_device *pdev) | ||
| 72 | { | ||
| 73 | int rc; | ||
| 74 | struct device_node *np = pdev->dev.of_node; | ||
| 75 | |||
| 76 | regmap = syscon_regmap_lookup_by_phandle(np, "syscon"); | ||
| 77 | if (IS_ERR(regmap)) { | ||
| 78 | pr_err("failed to get syscon phandle\n"); | ||
| 79 | return -EINVAL; | ||
| 80 | } | ||
| 81 | |||
| 82 | rc = of_property_read_u32_index(np, "syscon", RESET_SOURCE_ENABLE_REG, | ||
| 83 | &rst_src_en); | ||
| 84 | if (rc) { | ||
| 85 | pr_err("can't get rst_src_en offset (%d)\n", rc); | ||
| 86 | return -EINVAL; | ||
| 87 | } | ||
| 88 | |||
| 89 | rc = of_property_read_u32_index(np, "syscon", SW_MASTER_RESET_REG, | ||
| 90 | &sw_mstr_rst); | ||
| 91 | if (rc) { | ||
| 92 | pr_err("can't get sw_mstr_rst offset (%d)\n", rc); | ||
| 93 | return -EINVAL; | ||
| 94 | } | ||
| 95 | |||
| 96 | arm_pm_restart = brcmstb_reboot; | ||
| 97 | |||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | static const struct of_device_id of_match[] = { | ||
| 102 | { .compatible = "brcm,brcmstb-reboot", }, | ||
| 103 | {}, | ||
| 104 | }; | ||
| 105 | |||
| 106 | static struct platform_driver brcmstb_reboot_driver = { | ||
| 107 | .probe = brcmstb_reboot_probe, | ||
| 108 | .driver = { | ||
| 109 | .name = "brcmstb-reboot", | ||
| 110 | .owner = THIS_MODULE, | ||
| 111 | .of_match_table = of_match, | ||
| 112 | }, | ||
| 113 | }; | ||
| 114 | |||
| 115 | static int __init brcmstb_reboot_init(void) | ||
| 116 | { | ||
| 117 | return platform_driver_probe(&brcmstb_reboot_driver, | ||
| 118 | brcmstb_reboot_probe); | ||
| 119 | } | ||
| 120 | subsys_initcall(brcmstb_reboot_init); | ||
diff --git a/drivers/power/reset/gpio-poweroff.c b/drivers/power/reset/gpio-poweroff.c index e290d48ddd99..ce849bc9b269 100644 --- a/drivers/power/reset/gpio-poweroff.c +++ b/drivers/power/reset/gpio-poweroff.c | |||
| @@ -15,31 +15,29 @@ | |||
| 15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| 16 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
| 17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
| 18 | #include <linux/gpio.h> | 18 | #include <linux/gpio/consumer.h> |
| 19 | #include <linux/of_platform.h> | 19 | #include <linux/of_platform.h> |
| 20 | #include <linux/of_gpio.h> | ||
| 21 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| 22 | 21 | ||
| 23 | /* | 22 | /* |
| 24 | * Hold configuration here, cannot be more than one instance of the driver | 23 | * Hold configuration here, cannot be more than one instance of the driver |
| 25 | * since pm_power_off itself is global. | 24 | * since pm_power_off itself is global. |
| 26 | */ | 25 | */ |
| 27 | static int gpio_num = -1; | 26 | static struct gpio_desc *reset_gpio; |
| 28 | static int gpio_active_low; | ||
| 29 | 27 | ||
| 30 | static void gpio_poweroff_do_poweroff(void) | 28 | static void gpio_poweroff_do_poweroff(void) |
| 31 | { | 29 | { |
| 32 | BUG_ON(!gpio_is_valid(gpio_num)); | 30 | BUG_ON(!reset_gpio); |
| 33 | 31 | ||
| 34 | /* drive it active, also inactive->active edge */ | 32 | /* drive it active, also inactive->active edge */ |
| 35 | gpio_direction_output(gpio_num, !gpio_active_low); | 33 | gpiod_direction_output(reset_gpio, 1); |
| 36 | mdelay(100); | 34 | mdelay(100); |
| 37 | /* drive inactive, also active->inactive edge */ | 35 | /* drive inactive, also active->inactive edge */ |
| 38 | gpio_set_value(gpio_num, gpio_active_low); | 36 | gpiod_set_value(reset_gpio, 0); |
| 39 | mdelay(100); | 37 | mdelay(100); |
| 40 | 38 | ||
| 41 | /* drive it active, also inactive->active edge */ | 39 | /* drive it active, also inactive->active edge */ |
| 42 | gpio_set_value(gpio_num, !gpio_active_low); | 40 | gpiod_set_value(reset_gpio, 1); |
| 43 | 41 | ||
| 44 | /* give it some time */ | 42 | /* give it some time */ |
| 45 | mdelay(3000); | 43 | mdelay(3000); |
| @@ -49,54 +47,42 @@ static void gpio_poweroff_do_poweroff(void) | |||
| 49 | 47 | ||
| 50 | static int gpio_poweroff_probe(struct platform_device *pdev) | 48 | static int gpio_poweroff_probe(struct platform_device *pdev) |
| 51 | { | 49 | { |
| 52 | enum of_gpio_flags flags; | ||
| 53 | bool input = false; | 50 | bool input = false; |
| 54 | int ret; | ||
| 55 | 51 | ||
| 56 | /* If a pm_power_off function has already been added, leave it alone */ | 52 | /* If a pm_power_off function has already been added, leave it alone */ |
| 57 | if (pm_power_off != NULL) { | 53 | if (pm_power_off != NULL) { |
| 58 | pr_err("%s: pm_power_off function already registered", | 54 | dev_err(&pdev->dev, |
| 55 | "%s: pm_power_off function already registered", | ||
| 59 | __func__); | 56 | __func__); |
| 60 | return -EBUSY; | 57 | return -EBUSY; |
| 61 | } | 58 | } |
| 62 | 59 | ||
| 63 | gpio_num = of_get_gpio_flags(pdev->dev.of_node, 0, &flags); | 60 | reset_gpio = devm_gpiod_get(&pdev->dev, NULL); |
| 64 | if (!gpio_is_valid(gpio_num)) | 61 | if (IS_ERR(reset_gpio)) |
| 65 | return gpio_num; | 62 | return PTR_ERR(reset_gpio); |
| 66 | |||
| 67 | gpio_active_low = flags & OF_GPIO_ACTIVE_LOW; | ||
| 68 | 63 | ||
| 69 | input = of_property_read_bool(pdev->dev.of_node, "input"); | 64 | input = of_property_read_bool(pdev->dev.of_node, "input"); |
| 70 | 65 | ||
| 71 | ret = gpio_request(gpio_num, "poweroff-gpio"); | ||
| 72 | if (ret) { | ||
| 73 | pr_err("%s: Could not get GPIO %d", __func__, gpio_num); | ||
| 74 | return ret; | ||
| 75 | } | ||
| 76 | if (input) { | 66 | if (input) { |
| 77 | if (gpio_direction_input(gpio_num)) { | 67 | if (gpiod_direction_input(reset_gpio)) { |
| 78 | pr_err("Could not set direction of GPIO %d to input", | 68 | dev_err(&pdev->dev, |
| 79 | gpio_num); | 69 | "Could not set direction of reset GPIO to input\n"); |
| 80 | goto err; | 70 | return -ENODEV; |
| 81 | } | 71 | } |
| 82 | } else { | 72 | } else { |
| 83 | if (gpio_direction_output(gpio_num, gpio_active_low)) { | 73 | if (gpiod_direction_output(reset_gpio, 0)) { |
| 84 | pr_err("Could not set direction of GPIO %d", gpio_num); | 74 | dev_err(&pdev->dev, |
| 85 | goto err; | 75 | "Could not set direction of reset GPIO\n"); |
| 76 | return -ENODEV; | ||
| 86 | } | 77 | } |
| 87 | } | 78 | } |
| 88 | 79 | ||
| 89 | pm_power_off = &gpio_poweroff_do_poweroff; | 80 | pm_power_off = &gpio_poweroff_do_poweroff; |
| 90 | return 0; | 81 | return 0; |
| 91 | |||
| 92 | err: | ||
| 93 | gpio_free(gpio_num); | ||
| 94 | return -ENODEV; | ||
| 95 | } | 82 | } |
| 96 | 83 | ||
| 97 | static int gpio_poweroff_remove(struct platform_device *pdev) | 84 | static int gpio_poweroff_remove(struct platform_device *pdev) |
| 98 | { | 85 | { |
| 99 | gpio_free(gpio_num); | ||
| 100 | if (pm_power_off == &gpio_poweroff_do_poweroff) | 86 | if (pm_power_off == &gpio_poweroff_do_poweroff) |
| 101 | pm_power_off = NULL; | 87 | pm_power_off = NULL; |
| 102 | 88 | ||
diff --git a/drivers/power/reset/restart-poweroff.c b/drivers/power/reset/restart-poweroff.c index 5758033e0c16..3e51f8d29bfe 100644 --- a/drivers/power/reset/restart-poweroff.c +++ b/drivers/power/reset/restart-poweroff.c | |||
| @@ -62,5 +62,5 @@ module_platform_driver(restart_poweroff_driver); | |||
| 62 | 62 | ||
| 63 | MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch"); | 63 | MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch"); |
| 64 | MODULE_DESCRIPTION("restart poweroff driver"); | 64 | MODULE_DESCRIPTION("restart poweroff driver"); |
| 65 | MODULE_LICENSE("GPLv2"); | 65 | MODULE_LICENSE("GPL v2"); |
| 66 | MODULE_ALIAS("platform:poweroff-restart"); | 66 | MODULE_ALIAS("platform:poweroff-restart"); |
diff --git a/drivers/power/rx51_battery.c b/drivers/power/rx51_battery.c index 1bc5857b8bd5..d5a2acfb8821 100644 --- a/drivers/power/rx51_battery.c +++ b/drivers/power/rx51_battery.c | |||
| @@ -24,34 +24,27 @@ | |||
| 24 | #include <linux/power_supply.h> | 24 | #include <linux/power_supply.h> |
| 25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
| 26 | #include <linux/i2c/twl4030-madc.h> | 26 | #include <linux/i2c/twl4030-madc.h> |
| 27 | 27 | #include <linux/iio/consumer.h> | |
| 28 | /* RX51 specific channels */ | 28 | #include <linux/of.h> |
| 29 | #define TWL4030_MADC_BTEMP_RX51 TWL4030_MADC_ADCIN0 | ||
| 30 | #define TWL4030_MADC_BCI_RX51 TWL4030_MADC_ADCIN4 | ||
| 31 | 29 | ||
| 32 | struct rx51_device_info { | 30 | struct rx51_device_info { |
| 33 | struct device *dev; | 31 | struct device *dev; |
| 34 | struct power_supply bat; | 32 | struct power_supply bat; |
| 33 | struct iio_channel *channel_temp; | ||
| 34 | struct iio_channel *channel_bsi; | ||
| 35 | struct iio_channel *channel_vbat; | ||
| 35 | }; | 36 | }; |
| 36 | 37 | ||
| 37 | /* | 38 | /* |
| 38 | * Read ADCIN channel value, code copied from maemo kernel | 39 | * Read ADCIN channel value, code copied from maemo kernel |
| 39 | */ | 40 | */ |
| 40 | static int rx51_battery_read_adc(int channel) | 41 | static int rx51_battery_read_adc(struct iio_channel *channel) |
| 41 | { | 42 | { |
| 42 | struct twl4030_madc_request req; | 43 | int val, err; |
| 43 | 44 | err = iio_read_channel_average_raw(channel, &val); | |
| 44 | req.channels = channel; | 45 | if (err < 0) |
| 45 | req.do_avg = 1; | 46 | return err; |
| 46 | req.method = TWL4030_MADC_SW1; | 47 | return val; |
| 47 | req.func_cb = NULL; | ||
| 48 | req.type = TWL4030_MADC_WAIT; | ||
| 49 | req.raw = true; | ||
| 50 | |||
| 51 | if (twl4030_madc_conversion(&req) <= 0) | ||
| 52 | return -ENODATA; | ||
| 53 | |||
| 54 | return req.rbuf[ffs(channel) - 1]; | ||
| 55 | } | 48 | } |
| 56 | 49 | ||
| 57 | /* | 50 | /* |
| @@ -60,10 +53,12 @@ static int rx51_battery_read_adc(int channel) | |||
| 60 | */ | 53 | */ |
| 61 | static int rx51_battery_read_voltage(struct rx51_device_info *di) | 54 | static int rx51_battery_read_voltage(struct rx51_device_info *di) |
| 62 | { | 55 | { |
| 63 | int voltage = rx51_battery_read_adc(TWL4030_MADC_VBAT); | 56 | int voltage = rx51_battery_read_adc(di->channel_vbat); |
| 64 | 57 | ||
| 65 | if (voltage < 0) | 58 | if (voltage < 0) { |
| 59 | dev_err(di->dev, "Could not read ADC: %d\n", voltage); | ||
| 66 | return voltage; | 60 | return voltage; |
| 61 | } | ||
| 67 | 62 | ||
| 68 | return 1000 * (10000 * voltage / 1705); | 63 | return 1000 * (10000 * voltage / 1705); |
| 69 | } | 64 | } |
| @@ -112,7 +107,10 @@ static int rx51_battery_read_temperature(struct rx51_device_info *di) | |||
| 112 | { | 107 | { |
| 113 | int min = 0; | 108 | int min = 0; |
| 114 | int max = ARRAY_SIZE(rx51_temp_table2) - 1; | 109 | int max = ARRAY_SIZE(rx51_temp_table2) - 1; |
| 115 | int raw = rx51_battery_read_adc(TWL4030_MADC_BTEMP_RX51); | 110 | int raw = rx51_battery_read_adc(di->channel_temp); |
| 111 | |||
| 112 | if (raw < 0) | ||
| 113 | dev_err(di->dev, "Could not read ADC: %d\n", raw); | ||
| 116 | 114 | ||
| 117 | /* Zero and negative values are undefined */ | 115 | /* Zero and negative values are undefined */ |
| 118 | if (raw <= 0) | 116 | if (raw <= 0) |
| @@ -146,10 +144,12 @@ static int rx51_battery_read_temperature(struct rx51_device_info *di) | |||
| 146 | */ | 144 | */ |
| 147 | static int rx51_battery_read_capacity(struct rx51_device_info *di) | 145 | static int rx51_battery_read_capacity(struct rx51_device_info *di) |
| 148 | { | 146 | { |
| 149 | int capacity = rx51_battery_read_adc(TWL4030_MADC_BCI_RX51); | 147 | int capacity = rx51_battery_read_adc(di->channel_bsi); |
| 150 | 148 | ||
| 151 | if (capacity < 0) | 149 | if (capacity < 0) { |
| 150 | dev_err(di->dev, "Could not read ADC: %d\n", capacity); | ||
| 152 | return capacity; | 151 | return capacity; |
| 152 | } | ||
| 153 | 153 | ||
| 154 | return 1280 * (1200 * capacity)/(1024 - capacity); | 154 | return 1280 * (1200 * capacity)/(1024 - capacity); |
| 155 | } | 155 | } |
| @@ -213,17 +213,46 @@ static int rx51_battery_probe(struct platform_device *pdev) | |||
| 213 | 213 | ||
| 214 | platform_set_drvdata(pdev, di); | 214 | platform_set_drvdata(pdev, di); |
| 215 | 215 | ||
| 216 | di->dev = &pdev->dev; | ||
| 216 | di->bat.name = dev_name(&pdev->dev); | 217 | di->bat.name = dev_name(&pdev->dev); |
| 217 | di->bat.type = POWER_SUPPLY_TYPE_BATTERY; | 218 | di->bat.type = POWER_SUPPLY_TYPE_BATTERY; |
| 218 | di->bat.properties = rx51_battery_props; | 219 | di->bat.properties = rx51_battery_props; |
| 219 | di->bat.num_properties = ARRAY_SIZE(rx51_battery_props); | 220 | di->bat.num_properties = ARRAY_SIZE(rx51_battery_props); |
| 220 | di->bat.get_property = rx51_battery_get_property; | 221 | di->bat.get_property = rx51_battery_get_property; |
| 221 | 222 | ||
| 223 | di->channel_temp = iio_channel_get(di->dev, "temp"); | ||
| 224 | if (IS_ERR(di->channel_temp)) { | ||
| 225 | ret = PTR_ERR(di->channel_temp); | ||
| 226 | goto error; | ||
| 227 | } | ||
| 228 | |||
| 229 | di->channel_bsi = iio_channel_get(di->dev, "bsi"); | ||
| 230 | if (IS_ERR(di->channel_bsi)) { | ||
| 231 | ret = PTR_ERR(di->channel_bsi); | ||
| 232 | goto error_channel_temp; | ||
| 233 | } | ||
| 234 | |||
| 235 | di->channel_vbat = iio_channel_get(di->dev, "vbat"); | ||
| 236 | if (IS_ERR(di->channel_vbat)) { | ||
| 237 | ret = PTR_ERR(di->channel_vbat); | ||
| 238 | goto error_channel_bsi; | ||
| 239 | } | ||
| 240 | |||
| 222 | ret = power_supply_register(di->dev, &di->bat); | 241 | ret = power_supply_register(di->dev, &di->bat); |
| 223 | if (ret) | 242 | if (ret) |
| 224 | return ret; | 243 | goto error_channel_vbat; |
| 225 | 244 | ||
| 226 | return 0; | 245 | return 0; |
| 246 | |||
| 247 | error_channel_vbat: | ||
| 248 | iio_channel_release(di->channel_vbat); | ||
| 249 | error_channel_bsi: | ||
| 250 | iio_channel_release(di->channel_bsi); | ||
| 251 | error_channel_temp: | ||
| 252 | iio_channel_release(di->channel_temp); | ||
| 253 | error: | ||
| 254 | |||
| 255 | return ret; | ||
| 227 | } | 256 | } |
| 228 | 257 | ||
| 229 | static int rx51_battery_remove(struct platform_device *pdev) | 258 | static int rx51_battery_remove(struct platform_device *pdev) |
| @@ -232,15 +261,28 @@ static int rx51_battery_remove(struct platform_device *pdev) | |||
| 232 | 261 | ||
| 233 | power_supply_unregister(&di->bat); | 262 | power_supply_unregister(&di->bat); |
| 234 | 263 | ||
| 264 | iio_channel_release(di->channel_vbat); | ||
| 265 | iio_channel_release(di->channel_bsi); | ||
| 266 | iio_channel_release(di->channel_temp); | ||
| 267 | |||
| 235 | return 0; | 268 | return 0; |
| 236 | } | 269 | } |
| 237 | 270 | ||
| 271 | #ifdef CONFIG_OF | ||
| 272 | static const struct of_device_id n900_battery_of_match[] = { | ||
| 273 | {.compatible = "nokia,n900-battery", }, | ||
| 274 | { }, | ||
| 275 | }; | ||
| 276 | MODULE_DEVICE_TABLE(of, n900_battery_of_match); | ||
| 277 | #endif | ||
| 278 | |||
| 238 | static struct platform_driver rx51_battery_driver = { | 279 | static struct platform_driver rx51_battery_driver = { |
| 239 | .probe = rx51_battery_probe, | 280 | .probe = rx51_battery_probe, |
| 240 | .remove = rx51_battery_remove, | 281 | .remove = rx51_battery_remove, |
| 241 | .driver = { | 282 | .driver = { |
| 242 | .name = "rx51-battery", | 283 | .name = "rx51-battery", |
| 243 | .owner = THIS_MODULE, | 284 | .owner = THIS_MODULE, |
| 285 | .of_match_table = of_match_ptr(n900_battery_of_match), | ||
| 244 | }, | 286 | }, |
| 245 | }; | 287 | }; |
| 246 | module_platform_driver(rx51_battery_driver); | 288 | module_platform_driver(rx51_battery_driver); |
diff --git a/drivers/power/tps65090-charger.c b/drivers/power/tps65090-charger.c index 1685f63b9e5d..3e8ba97c8169 100644 --- a/drivers/power/tps65090-charger.c +++ b/drivers/power/tps65090-charger.c | |||
| @@ -17,9 +17,11 @@ | |||
| 17 | */ | 17 | */ |
| 18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
| 19 | #include <linux/err.h> | 19 | #include <linux/err.h> |
| 20 | #include <linux/freezer.h> | ||
| 20 | #include <linux/init.h> | 21 | #include <linux/init.h> |
| 21 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
| 22 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
| 24 | #include <linux/kthread.h> | ||
| 23 | #include <linux/module.h> | 25 | #include <linux/module.h> |
| 24 | #include <linux/of_device.h> | 26 | #include <linux/of_device.h> |
| 25 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
| @@ -32,11 +34,15 @@ | |||
| 32 | #define TPS65090_VACG BIT(1) | 34 | #define TPS65090_VACG BIT(1) |
| 33 | #define TPS65090_NOITERM BIT(5) | 35 | #define TPS65090_NOITERM BIT(5) |
| 34 | 36 | ||
| 37 | #define POLL_INTERVAL (HZ * 2) /* Used when no irq */ | ||
| 38 | |||
| 35 | struct tps65090_charger { | 39 | struct tps65090_charger { |
| 36 | struct device *dev; | 40 | struct device *dev; |
| 37 | int ac_online; | 41 | int ac_online; |
| 38 | int prev_ac_online; | 42 | int prev_ac_online; |
| 39 | int irq; | 43 | int irq; |
| 44 | struct task_struct *poll_task; | ||
| 45 | bool passive_mode; | ||
| 40 | struct power_supply ac; | 46 | struct power_supply ac; |
| 41 | struct tps65090_platform_data *pdata; | 47 | struct tps65090_platform_data *pdata; |
| 42 | }; | 48 | }; |
| @@ -49,6 +55,9 @@ static int tps65090_low_chrg_current(struct tps65090_charger *charger) | |||
| 49 | { | 55 | { |
| 50 | int ret; | 56 | int ret; |
| 51 | 57 | ||
| 58 | if (charger->passive_mode) | ||
| 59 | return 0; | ||
| 60 | |||
| 52 | ret = tps65090_write(charger->dev->parent, TPS65090_REG_CG_CTRL5, | 61 | ret = tps65090_write(charger->dev->parent, TPS65090_REG_CG_CTRL5, |
| 53 | TPS65090_NOITERM); | 62 | TPS65090_NOITERM); |
| 54 | if (ret < 0) { | 63 | if (ret < 0) { |
| @@ -64,6 +73,9 @@ static int tps65090_enable_charging(struct tps65090_charger *charger) | |||
| 64 | int ret; | 73 | int ret; |
| 65 | uint8_t ctrl0 = 0; | 74 | uint8_t ctrl0 = 0; |
| 66 | 75 | ||
| 76 | if (charger->passive_mode) | ||
| 77 | return 0; | ||
| 78 | |||
| 67 | ret = tps65090_read(charger->dev->parent, TPS65090_REG_CG_CTRL0, | 79 | ret = tps65090_read(charger->dev->parent, TPS65090_REG_CG_CTRL0, |
| 68 | &ctrl0); | 80 | &ctrl0); |
| 69 | if (ret < 0) { | 81 | if (ret < 0) { |
| @@ -87,6 +99,9 @@ static int tps65090_config_charger(struct tps65090_charger *charger) | |||
| 87 | uint8_t intrmask = 0; | 99 | uint8_t intrmask = 0; |
| 88 | int ret; | 100 | int ret; |
| 89 | 101 | ||
| 102 | if (charger->passive_mode) | ||
| 103 | return 0; | ||
| 104 | |||
| 90 | if (charger->pdata->enable_low_current_chrg) { | 105 | if (charger->pdata->enable_low_current_chrg) { |
| 91 | ret = tps65090_low_chrg_current(charger); | 106 | ret = tps65090_low_chrg_current(charger); |
| 92 | if (ret < 0) { | 107 | if (ret < 0) { |
| @@ -164,10 +179,14 @@ static irqreturn_t tps65090_charger_isr(int irq, void *dev_id) | |||
| 164 | } | 179 | } |
| 165 | 180 | ||
| 166 | /* Clear interrupts. */ | 181 | /* Clear interrupts. */ |
| 167 | ret = tps65090_write(charger->dev->parent, TPS65090_REG_INTR_STS, 0x00); | 182 | if (!charger->passive_mode) { |
| 168 | if (ret < 0) { | 183 | ret = tps65090_write(charger->dev->parent, |
| 169 | dev_err(charger->dev, "%s(): Error in writing reg 0x%x\n", | 184 | TPS65090_REG_INTR_STS, 0x00); |
| 185 | if (ret < 0) { | ||
| 186 | dev_err(charger->dev, | ||
| 187 | "%s(): Error in writing reg 0x%x\n", | ||
| 170 | __func__, TPS65090_REG_INTR_STS); | 188 | __func__, TPS65090_REG_INTR_STS); |
| 189 | } | ||
| 171 | } | 190 | } |
| 172 | 191 | ||
| 173 | if (charger->prev_ac_online != charger->ac_online) | 192 | if (charger->prev_ac_online != charger->ac_online) |
| @@ -198,6 +217,18 @@ static struct tps65090_platform_data * | |||
| 198 | 217 | ||
| 199 | } | 218 | } |
| 200 | 219 | ||
| 220 | static int tps65090_charger_poll_task(void *data) | ||
| 221 | { | ||
| 222 | set_freezable(); | ||
| 223 | |||
| 224 | while (!kthread_should_stop()) { | ||
| 225 | schedule_timeout_interruptible(POLL_INTERVAL); | ||
| 226 | try_to_freeze(); | ||
| 227 | tps65090_charger_isr(-1, data); | ||
| 228 | } | ||
| 229 | return 0; | ||
| 230 | } | ||
| 231 | |||
| 201 | static int tps65090_charger_probe(struct platform_device *pdev) | 232 | static int tps65090_charger_probe(struct platform_device *pdev) |
| 202 | { | 233 | { |
| 203 | struct tps65090_charger *cdata; | 234 | struct tps65090_charger *cdata; |
| @@ -244,22 +275,10 @@ static int tps65090_charger_probe(struct platform_device *pdev) | |||
| 244 | } | 275 | } |
| 245 | 276 | ||
| 246 | irq = platform_get_irq(pdev, 0); | 277 | irq = platform_get_irq(pdev, 0); |
| 247 | if (irq <= 0) { | 278 | if (irq < 0) |
| 248 | dev_warn(&pdev->dev, "Unable to get charger irq = %d\n", irq); | 279 | irq = -ENXIO; |
| 249 | ret = irq; | ||
| 250 | goto fail_unregister_supply; | ||
| 251 | } | ||
| 252 | |||
| 253 | cdata->irq = irq; | 280 | cdata->irq = irq; |
| 254 | 281 | ||
| 255 | ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, | ||
| 256 | tps65090_charger_isr, 0, "tps65090-charger", cdata); | ||
| 257 | if (ret) { | ||
| 258 | dev_err(cdata->dev, "Unable to register irq %d err %d\n", irq, | ||
| 259 | ret); | ||
| 260 | goto fail_unregister_supply; | ||
| 261 | } | ||
| 262 | |||
| 263 | ret = tps65090_config_charger(cdata); | 282 | ret = tps65090_config_charger(cdata); |
| 264 | if (ret < 0) { | 283 | if (ret < 0) { |
| 265 | dev_err(&pdev->dev, "charger config failed, err %d\n", ret); | 284 | dev_err(&pdev->dev, "charger config failed, err %d\n", ret); |
| @@ -285,6 +304,27 @@ static int tps65090_charger_probe(struct platform_device *pdev) | |||
| 285 | power_supply_changed(&cdata->ac); | 304 | power_supply_changed(&cdata->ac); |
| 286 | } | 305 | } |
| 287 | 306 | ||
| 307 | if (irq != -ENXIO) { | ||
| 308 | ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, | ||
| 309 | tps65090_charger_isr, 0, "tps65090-charger", cdata); | ||
| 310 | if (ret) { | ||
| 311 | dev_err(cdata->dev, | ||
| 312 | "Unable to register irq %d err %d\n", irq, | ||
| 313 | ret); | ||
| 314 | goto fail_unregister_supply; | ||
| 315 | } | ||
| 316 | } else { | ||
| 317 | cdata->poll_task = kthread_run(tps65090_charger_poll_task, | ||
| 318 | cdata, "ktps65090charger"); | ||
| 319 | cdata->passive_mode = true; | ||
| 320 | if (IS_ERR(cdata->poll_task)) { | ||
| 321 | ret = PTR_ERR(cdata->poll_task); | ||
| 322 | dev_err(cdata->dev, | ||
| 323 | "Unable to run kthread err %d\n", ret); | ||
| 324 | goto fail_unregister_supply; | ||
| 325 | } | ||
| 326 | } | ||
| 327 | |||
| 288 | return 0; | 328 | return 0; |
| 289 | 329 | ||
| 290 | fail_unregister_supply: | 330 | fail_unregister_supply: |
| @@ -297,6 +337,8 @@ static int tps65090_charger_remove(struct platform_device *pdev) | |||
| 297 | { | 337 | { |
| 298 | struct tps65090_charger *cdata = platform_get_drvdata(pdev); | 338 | struct tps65090_charger *cdata = platform_get_drvdata(pdev); |
| 299 | 339 | ||
| 340 | if (cdata->irq == -ENXIO) | ||
| 341 | kthread_stop(cdata->poll_task); | ||
| 300 | power_supply_unregister(&cdata->ac); | 342 | power_supply_unregister(&cdata->ac); |
| 301 | 343 | ||
| 302 | return 0; | 344 | return 0; |
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c index f14108844e1a..2598c588006e 100644 --- a/drivers/power/twl4030_charger.c +++ b/drivers/power/twl4030_charger.c | |||
| @@ -28,10 +28,13 @@ | |||
| 28 | #define TWL4030_BCIICHG 0x08 | 28 | #define TWL4030_BCIICHG 0x08 |
| 29 | #define TWL4030_BCIVAC 0x0a | 29 | #define TWL4030_BCIVAC 0x0a |
| 30 | #define TWL4030_BCIVBUS 0x0c | 30 | #define TWL4030_BCIVBUS 0x0c |
| 31 | #define TWL4030_BCIMFSTS3 0x0F | ||
| 31 | #define TWL4030_BCIMFSTS4 0x10 | 32 | #define TWL4030_BCIMFSTS4 0x10 |
| 32 | #define TWL4030_BCICTL1 0x23 | 33 | #define TWL4030_BCICTL1 0x23 |
| 33 | #define TWL4030_BB_CFG 0x12 | 34 | #define TWL4030_BB_CFG 0x12 |
| 34 | 35 | ||
| 36 | #define TWL4030_BCIMFSTS1 0x01 | ||
| 37 | |||
| 35 | #define TWL4030_BCIAUTOWEN BIT(5) | 38 | #define TWL4030_BCIAUTOWEN BIT(5) |
| 36 | #define TWL4030_CONFIG_DONE BIT(4) | 39 | #define TWL4030_CONFIG_DONE BIT(4) |
| 37 | #define TWL4030_BCIAUTOUSB BIT(1) | 40 | #define TWL4030_BCIAUTOUSB BIT(1) |
| @@ -52,6 +55,9 @@ | |||
| 52 | #define TWL4030_BBISEL_500uA 0x02 | 55 | #define TWL4030_BBISEL_500uA 0x02 |
| 53 | #define TWL4030_BBISEL_1000uA 0x03 | 56 | #define TWL4030_BBISEL_1000uA 0x03 |
| 54 | 57 | ||
| 58 | #define TWL4030_BATSTSPCHG BIT(2) | ||
| 59 | #define TWL4030_BATSTSMCHG BIT(6) | ||
| 60 | |||
| 55 | /* BCI interrupts */ | 61 | /* BCI interrupts */ |
| 56 | #define TWL4030_WOVF BIT(0) /* Watchdog overflow */ | 62 | #define TWL4030_WOVF BIT(0) /* Watchdog overflow */ |
| 57 | #define TWL4030_TMOVF BIT(1) /* Timer overflow */ | 63 | #define TWL4030_TMOVF BIT(1) /* Timer overflow */ |
| @@ -145,6 +151,35 @@ static int twl4030bci_read_adc_val(u8 reg) | |||
| 145 | } | 151 | } |
| 146 | 152 | ||
| 147 | /* | 153 | /* |
| 154 | * Check if Battery Pack was present | ||
| 155 | */ | ||
| 156 | static int twl4030_is_battery_present(struct twl4030_bci *bci) | ||
| 157 | { | ||
| 158 | int ret; | ||
| 159 | u8 val = 0; | ||
| 160 | |||
| 161 | /* Battery presence in Main charge? */ | ||
| 162 | ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val, TWL4030_BCIMFSTS3); | ||
| 163 | if (ret) | ||
| 164 | return ret; | ||
| 165 | if (val & TWL4030_BATSTSMCHG) | ||
| 166 | return 0; | ||
| 167 | |||
| 168 | /* | ||
| 169 | * OK, It could be that bootloader did not enable main charger, | ||
| 170 | * pre-charge is h/w auto. So, Battery presence in Pre-charge? | ||
| 171 | */ | ||
| 172 | ret = twl_i2c_read_u8(TWL4030_MODULE_PRECHARGE, &val, | ||
| 173 | TWL4030_BCIMFSTS1); | ||
| 174 | if (ret) | ||
| 175 | return ret; | ||
| 176 | if (val & TWL4030_BATSTSPCHG) | ||
| 177 | return 0; | ||
| 178 | |||
| 179 | return -ENODEV; | ||
| 180 | } | ||
| 181 | |||
| 182 | /* | ||
| 148 | * Check if VBUS power is present | 183 | * Check if VBUS power is present |
| 149 | */ | 184 | */ |
| 150 | static int twl4030_bci_have_vbus(struct twl4030_bci *bci) | 185 | static int twl4030_bci_have_vbus(struct twl4030_bci *bci) |
| @@ -541,8 +576,14 @@ static int __init twl4030_bci_probe(struct platform_device *pdev) | |||
| 541 | bci->irq_chg = platform_get_irq(pdev, 0); | 576 | bci->irq_chg = platform_get_irq(pdev, 0); |
| 542 | bci->irq_bci = platform_get_irq(pdev, 1); | 577 | bci->irq_bci = platform_get_irq(pdev, 1); |
| 543 | 578 | ||
| 544 | platform_set_drvdata(pdev, bci); | 579 | /* Only proceed further *IF* battery is physically present */ |
| 580 | ret = twl4030_is_battery_present(bci); | ||
| 581 | if (ret) { | ||
| 582 | dev_crit(&pdev->dev, "Battery was not detected:%d\n", ret); | ||
| 583 | goto fail_no_battery; | ||
| 584 | } | ||
| 545 | 585 | ||
| 586 | platform_set_drvdata(pdev, bci); | ||
| 546 | bci->ac.name = "twl4030_ac"; | 587 | bci->ac.name = "twl4030_ac"; |
| 547 | bci->ac.type = POWER_SUPPLY_TYPE_MAINS; | 588 | bci->ac.type = POWER_SUPPLY_TYPE_MAINS; |
| 548 | bci->ac.properties = twl4030_charger_props; | 589 | bci->ac.properties = twl4030_charger_props; |
| @@ -633,6 +674,7 @@ fail_chg_irq: | |||
| 633 | fail_register_usb: | 674 | fail_register_usb: |
| 634 | power_supply_unregister(&bci->ac); | 675 | power_supply_unregister(&bci->ac); |
| 635 | fail_register_ac: | 676 | fail_register_ac: |
| 677 | fail_no_battery: | ||
| 636 | kfree(bci); | 678 | kfree(bci); |
| 637 | 679 | ||
| 638 | return ret; | 680 | return ret; |
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index f2b76aeaf4e4..f3dea41dbcd2 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h | |||
| @@ -120,6 +120,7 @@ enum power_supply_property { | |||
| 120 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, | 120 | POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, |
| 121 | POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, | 121 | POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, |
| 122 | POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, | 122 | POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, |
| 123 | POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, | ||
| 123 | POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, | 124 | POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, |
| 124 | POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN, | 125 | POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN, |
| 125 | POWER_SUPPLY_PROP_ENERGY_FULL, | 126 | POWER_SUPPLY_PROP_ENERGY_FULL, |
| @@ -131,6 +132,8 @@ enum power_supply_property { | |||
| 131 | POWER_SUPPLY_PROP_CAPACITY_ALERT_MAX, /* in percents! */ | 132 | POWER_SUPPLY_PROP_CAPACITY_ALERT_MAX, /* in percents! */ |
| 132 | POWER_SUPPLY_PROP_CAPACITY_LEVEL, | 133 | POWER_SUPPLY_PROP_CAPACITY_LEVEL, |
| 133 | POWER_SUPPLY_PROP_TEMP, | 134 | POWER_SUPPLY_PROP_TEMP, |
| 135 | POWER_SUPPLY_PROP_TEMP_MAX, | ||
| 136 | POWER_SUPPLY_PROP_TEMP_MIN, | ||
| 134 | POWER_SUPPLY_PROP_TEMP_ALERT_MIN, | 137 | POWER_SUPPLY_PROP_TEMP_ALERT_MIN, |
| 135 | POWER_SUPPLY_PROP_TEMP_ALERT_MAX, | 138 | POWER_SUPPLY_PROP_TEMP_ALERT_MAX, |
| 136 | POWER_SUPPLY_PROP_TEMP_AMBIENT, | 139 | POWER_SUPPLY_PROP_TEMP_AMBIENT, |
| @@ -142,6 +145,7 @@ enum power_supply_property { | |||
| 142 | POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, | 145 | POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, |
| 143 | POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */ | 146 | POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */ |
| 144 | POWER_SUPPLY_PROP_SCOPE, | 147 | POWER_SUPPLY_PROP_SCOPE, |
| 148 | POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, | ||
| 145 | /* Properties of type `const char *' */ | 149 | /* Properties of type `const char *' */ |
| 146 | POWER_SUPPLY_PROP_MODEL_NAME, | 150 | POWER_SUPPLY_PROP_MODEL_NAME, |
| 147 | POWER_SUPPLY_PROP_MANUFACTURER, | 151 | POWER_SUPPLY_PROP_MANUFACTURER, |
