aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/sony-laptop.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86/sony-laptop.c')
-rw-r--r--drivers/platform/x86/sony-laptop.c178
1 files changed, 178 insertions, 0 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 89e5cf9b1914..0ac186e9abdc 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -144,6 +144,10 @@ static void sony_nc_kbd_backlight_resume(void);
144static void sony_nc_kbd_backlight_setup(struct platform_device *pd); 144static void sony_nc_kbd_backlight_setup(struct platform_device *pd);
145static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd); 145static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd);
146 146
147static int sony_nc_battery_care_setup(struct platform_device *pd,
148 unsigned int handle);
149static void sony_nc_battery_care_cleanup(struct platform_device *pd);
150
147enum sony_nc_rfkill { 151enum sony_nc_rfkill {
148 SONY_WIFI, 152 SONY_WIFI,
149 SONY_BLUETOOTH, 153 SONY_BLUETOOTH,
@@ -1270,6 +1274,14 @@ static void sony_nc_function_setup(struct acpi_device *device,
1270 /* setup hotkeys */ 1274 /* setup hotkeys */
1271 sony_call_snc_handle(handle, 0x100, &result); 1275 sony_call_snc_handle(handle, 0x100, &result);
1272 break; 1276 break;
1277 case 0x0115:
1278 case 0x0136:
1279 case 0x013f:
1280 result = sony_nc_battery_care_setup(pf_device, handle);
1281 if (result)
1282 pr_err("couldn't set up battery care function (%d)\n",
1283 result);
1284 break;
1273 case 0x0124: 1285 case 0x0124:
1274 case 0x0135: 1286 case 0x0135:
1275 sony_nc_rfkill_setup(device); 1287 sony_nc_rfkill_setup(device);
@@ -1306,6 +1318,11 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
1306 continue; 1318 continue;
1307 1319
1308 switch (handle) { 1320 switch (handle) {
1321 case 0x0115:
1322 case 0x0136:
1323 case 0x013f:
1324 sony_nc_battery_care_cleanup(pd);
1325 break;
1309 case 0x0124: 1326 case 0x0124:
1310 case 0x0135: 1327 case 0x0135:
1311 sony_nc_rfkill_cleanup(); 1328 sony_nc_rfkill_cleanup();
@@ -1745,6 +1762,167 @@ static void sony_nc_kbd_backlight_resume(void)
1745 &ignore); 1762 &ignore);
1746} 1763}
1747 1764
1765struct battery_care_control {
1766 struct device_attribute attrs[2];
1767 unsigned int handle;
1768};
1769static struct battery_care_control *bcare_ctl;
1770
1771static ssize_t sony_nc_battery_care_limit_store(struct device *dev,
1772 struct device_attribute *attr,
1773 const char *buffer, size_t count)
1774{
1775 unsigned int result, cmd;
1776 unsigned long value;
1777
1778 if (count > 31)
1779 return -EINVAL;
1780
1781 if (kstrtoul(buffer, 10, &value))
1782 return -EINVAL;
1783
1784 /* limit values (2 bits):
1785 * 00 - none
1786 * 01 - 80%
1787 * 10 - 50%
1788 * 11 - 100%
1789 *
1790 * bit 0: 0 disable BCL, 1 enable BCL
1791 * bit 1: 1 tell to store the battery limit (see bits 6,7) too
1792 * bits 2,3: reserved
1793 * bits 4,5: store the limit into the EC
1794 * bits 6,7: store the limit into the battery
1795 */
1796
1797 /*
1798 * handle 0x0115 should allow storing on battery too;
1799 * handle 0x0136 same as 0x0115 + health status;
1800 * handle 0x013f, same as 0x0136 but no storing on the battery
1801 *
1802 * Store only inside the EC for now, regardless the handle number
1803 */
1804 if (value == 0)
1805 /* disable limits */
1806 cmd = 0x0;
1807
1808 else if (value <= 50)
1809 cmd = 0x21;
1810
1811 else if (value <= 80)
1812 cmd = 0x11;
1813
1814 else if (value <= 100)
1815 cmd = 0x31;
1816
1817 else
1818 return -EINVAL;
1819
1820 if (sony_call_snc_handle(bcare_ctl->handle, (cmd << 0x10) | 0x0100,
1821 &result))
1822 return -EIO;
1823
1824 return count;
1825}
1826
1827static ssize_t sony_nc_battery_care_limit_show(struct device *dev,
1828 struct device_attribute *attr, char *buffer)
1829{
1830 unsigned int result, status;
1831
1832 if (sony_call_snc_handle(bcare_ctl->handle, 0x0000, &result))
1833 return -EIO;
1834
1835 status = (result & 0x01) ? ((result & 0x30) >> 0x04) : 0;
1836 switch (status) {
1837 case 1:
1838 status = 80;
1839 break;
1840 case 2:
1841 status = 50;
1842 break;
1843 case 3:
1844 status = 100;
1845 break;
1846 default:
1847 status = 0;
1848 break;
1849 }
1850
1851 return snprintf(buffer, PAGE_SIZE, "%d\n", status);
1852}
1853
1854static ssize_t sony_nc_battery_care_health_show(struct device *dev,
1855 struct device_attribute *attr, char *buffer)
1856{
1857 ssize_t count = 0;
1858 unsigned int health;
1859
1860 if (sony_call_snc_handle(bcare_ctl->handle, 0x0200, &health))
1861 return -EIO;
1862
1863 count = snprintf(buffer, PAGE_SIZE, "%d\n", health & 0xff);
1864
1865 return count;
1866}
1867
1868static int sony_nc_battery_care_setup(struct platform_device *pd,
1869 unsigned int handle)
1870{
1871 int ret = 0;
1872
1873 bcare_ctl = kzalloc(sizeof(struct battery_care_control), GFP_KERNEL);
1874 if (!bcare_ctl)
1875 return -ENOMEM;
1876
1877 bcare_ctl->handle = handle;
1878
1879 sysfs_attr_init(&bcare_ctl->attrs[0].attr);
1880 bcare_ctl->attrs[0].attr.name = "battery_care_limiter";
1881 bcare_ctl->attrs[0].attr.mode = S_IRUGO | S_IWUSR;
1882 bcare_ctl->attrs[0].show = sony_nc_battery_care_limit_show;
1883 bcare_ctl->attrs[0].store = sony_nc_battery_care_limit_store;
1884
1885 ret = device_create_file(&pd->dev, &bcare_ctl->attrs[0]);
1886 if (ret)
1887 goto outkzalloc;
1888
1889 /* 0x0115 is for models with no health reporting capability */
1890 if (handle == 0x0115)
1891 return 0;
1892
1893 sysfs_attr_init(&bcare_ctl->attrs[1].attr);
1894 bcare_ctl->attrs[1].attr.name = "battery_care_health";
1895 bcare_ctl->attrs[1].attr.mode = S_IRUGO;
1896 bcare_ctl->attrs[1].show = sony_nc_battery_care_health_show;
1897
1898 ret = device_create_file(&pd->dev, &bcare_ctl->attrs[1]);
1899 if (ret)
1900 goto outlimiter;
1901
1902 return 0;
1903
1904outlimiter:
1905 device_remove_file(&pd->dev, &bcare_ctl->attrs[0]);
1906
1907outkzalloc:
1908 kfree(bcare_ctl);
1909 bcare_ctl = NULL;
1910
1911 return ret;
1912}
1913
1914static void sony_nc_battery_care_cleanup(struct platform_device *pd)
1915{
1916 if (bcare_ctl) {
1917 device_remove_file(&pd->dev, &bcare_ctl->attrs[0]);
1918 if (bcare_ctl->handle != 0x0115)
1919 device_remove_file(&pd->dev, &bcare_ctl->attrs[1]);
1920
1921 kfree(bcare_ctl);
1922 bcare_ctl = NULL;
1923 }
1924}
1925
1748static void sony_nc_backlight_ng_read_limits(int handle, 1926static void sony_nc_backlight_ng_read_limits(int handle,
1749 struct sony_backlight_props *props) 1927 struct sony_backlight_props *props)
1750{ 1928{