1*3d6529b8SJonas Schwöbel // SPDX-License-Identifier: GPL-2.0+ 2*3d6529b8SJonas Schwöbel 3*3d6529b8SJonas Schwöbel #include <linux/devm-helpers.h> 4*3d6529b8SJonas Schwöbel #include <linux/delay.h> 5*3d6529b8SJonas Schwöbel #include <linux/gpio/consumer.h> 6*3d6529b8SJonas Schwöbel #include <linux/i2c.h> 7*3d6529b8SJonas Schwöbel #include <linux/interrupt.h> 8*3d6529b8SJonas Schwöbel #include <linux/module.h> 9*3d6529b8SJonas Schwöbel #include <linux/property.h> 10*3d6529b8SJonas Schwöbel #include <linux/power_supply.h> 11*3d6529b8SJonas Schwöbel #include <linux/types.h> 12*3d6529b8SJonas Schwöbel 13*3d6529b8SJonas Schwöbel /* Register Addresses (B=byte; W=word; S=string) */ 14*3d6529b8SJonas Schwöbel #define REGB_STATUS 0x02 15*3d6529b8SJonas Schwöbel #define REGW_VOLTAGE_NOW 0x20 16*3d6529b8SJonas Schwöbel #define REGW_CURRENT_NOW 0x24 17*3d6529b8SJonas Schwöbel #define REGW_CAPACITY 0x28 18*3d6529b8SJonas Schwöbel #define REGW_CHARGE_NOW 0x2a 19*3d6529b8SJonas Schwöbel #define REGW_CHARGE_FULL 0x2c 20*3d6529b8SJonas Schwöbel #define REGW_CYCLE_COUNT 0x3a 21*3d6529b8SJonas Schwöbel #define REGW_CHARGE_FULL_DESIGN 0x3c 22*3d6529b8SJonas Schwöbel #define REGW_VOLTAGE_MAX_DESIGN 0x3e 23*3d6529b8SJonas Schwöbel #define REGW_SERIAL_NUMBER 0x44 24*3d6529b8SJonas Schwöbel #define REGS_MANUFACTURER 0x46 25*3d6529b8SJonas Schwöbel #define REGS_MODEL_NAME 0x52 26*3d6529b8SJonas Schwöbel #define REGS_TECHNOLOGY 0x5a 27*3d6529b8SJonas Schwöbel #define REGB_ONLINE 0x67 28*3d6529b8SJonas Schwöbel 29*3d6529b8SJonas Schwöbel struct srt_ec_device { 30*3d6529b8SJonas Schwöbel struct i2c_client *client; 31*3d6529b8SJonas Schwöbel 32*3d6529b8SJonas Schwöbel struct power_supply *bat; 33*3d6529b8SJonas Schwöbel struct power_supply *psy; 34*3d6529b8SJonas Schwöbel 35*3d6529b8SJonas Schwöbel struct gpio_desc *enable_gpiod; 36*3d6529b8SJonas Schwöbel struct delayed_work poll_work; 37*3d6529b8SJonas Schwöbel 38*3d6529b8SJonas Schwöbel unsigned int technology; 39*3d6529b8SJonas Schwöbel unsigned int capacity; 40*3d6529b8SJonas Schwöbel 41*3d6529b8SJonas Schwöbel const char *serial; 42*3d6529b8SJonas Schwöbel char manufacturer[13]; 43*3d6529b8SJonas Schwöbel char model_name[10]; 44*3d6529b8SJonas Schwöbel }; 45*3d6529b8SJonas Schwöbel 46*3d6529b8SJonas Schwöbel static const enum power_supply_property srt_bat_power_supply_props[] = { 47*3d6529b8SJonas Schwöbel POWER_SUPPLY_PROP_CAPACITY, 48*3d6529b8SJonas Schwöbel POWER_SUPPLY_PROP_CHARGE_NOW, 49*3d6529b8SJonas Schwöbel POWER_SUPPLY_PROP_CHARGE_FULL, 50*3d6529b8SJonas Schwöbel POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 51*3d6529b8SJonas Schwöbel POWER_SUPPLY_PROP_CURRENT_NOW, 52*3d6529b8SJonas Schwöbel POWER_SUPPLY_PROP_CYCLE_COUNT, 53*3d6529b8SJonas Schwöbel POWER_SUPPLY_PROP_MANUFACTURER, 54*3d6529b8SJonas Schwöbel POWER_SUPPLY_PROP_MODEL_NAME, 55*3d6529b8SJonas Schwöbel POWER_SUPPLY_PROP_ONLINE, 56*3d6529b8SJonas Schwöbel POWER_SUPPLY_PROP_PRESENT, 57*3d6529b8SJonas Schwöbel POWER_SUPPLY_PROP_SERIAL_NUMBER, 58*3d6529b8SJonas Schwöbel POWER_SUPPLY_PROP_STATUS, 59*3d6529b8SJonas Schwöbel POWER_SUPPLY_PROP_TECHNOLOGY, 60*3d6529b8SJonas Schwöbel POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, 61*3d6529b8SJonas Schwöbel POWER_SUPPLY_PROP_VOLTAGE_NOW, 62*3d6529b8SJonas Schwöbel }; 63*3d6529b8SJonas Schwöbel 64*3d6529b8SJonas Schwöbel static const enum power_supply_property srt_psy_power_supply_props[] = { 65*3d6529b8SJonas Schwöbel POWER_SUPPLY_PROP_ONLINE, 66*3d6529b8SJonas Schwöbel POWER_SUPPLY_PROP_PRESENT, 67*3d6529b8SJonas Schwöbel }; 68*3d6529b8SJonas Schwöbel 69*3d6529b8SJonas Schwöbel static int srt_bat_get_value(struct i2c_client *client, int reg, int *val) 70*3d6529b8SJonas Schwöbel { 71*3d6529b8SJonas Schwöbel int ret; 72*3d6529b8SJonas Schwöbel 73*3d6529b8SJonas Schwöbel switch (reg) { 74*3d6529b8SJonas Schwöbel case REGW_CHARGE_NOW: 75*3d6529b8SJonas Schwöbel case REGW_CHARGE_FULL_DESIGN: 76*3d6529b8SJonas Schwöbel case REGW_CHARGE_FULL: 77*3d6529b8SJonas Schwöbel case REGW_VOLTAGE_MAX_DESIGN: 78*3d6529b8SJonas Schwöbel case REGW_VOLTAGE_NOW: 79*3d6529b8SJonas Schwöbel ret = i2c_smbus_read_word_data(client, reg); 80*3d6529b8SJonas Schwöbel if (ret < 0) 81*3d6529b8SJonas Schwöbel return ret; 82*3d6529b8SJonas Schwöbel 83*3d6529b8SJonas Schwöbel *val = ret * 1000; 84*3d6529b8SJonas Schwöbel break; 85*3d6529b8SJonas Schwöbel 86*3d6529b8SJonas Schwöbel case REGW_CURRENT_NOW: 87*3d6529b8SJonas Schwöbel ret = i2c_smbus_read_word_data(client, reg); 88*3d6529b8SJonas Schwöbel if (ret < 0) 89*3d6529b8SJonas Schwöbel return ret; 90*3d6529b8SJonas Schwöbel 91*3d6529b8SJonas Schwöbel *val = (s16)ret * 1000; 92*3d6529b8SJonas Schwöbel break; 93*3d6529b8SJonas Schwöbel 94*3d6529b8SJonas Schwöbel case REGW_CAPACITY: 95*3d6529b8SJonas Schwöbel case REGW_CYCLE_COUNT: 96*3d6529b8SJonas Schwöbel ret = i2c_smbus_read_word_data(client, reg); 97*3d6529b8SJonas Schwöbel if (ret < 0) 98*3d6529b8SJonas Schwöbel return ret; 99*3d6529b8SJonas Schwöbel 100*3d6529b8SJonas Schwöbel *val = ret; 101*3d6529b8SJonas Schwöbel break; 102*3d6529b8SJonas Schwöbel 103*3d6529b8SJonas Schwöbel case REGB_STATUS: 104*3d6529b8SJonas Schwöbel ret = i2c_smbus_read_byte_data(client, reg); 105*3d6529b8SJonas Schwöbel if (ret < 0) 106*3d6529b8SJonas Schwöbel return ret; 107*3d6529b8SJonas Schwöbel 108*3d6529b8SJonas Schwöbel if (ret & BIT(0)) 109*3d6529b8SJonas Schwöbel *val = POWER_SUPPLY_STATUS_CHARGING; 110*3d6529b8SJonas Schwöbel else 111*3d6529b8SJonas Schwöbel *val = POWER_SUPPLY_STATUS_DISCHARGING; 112*3d6529b8SJonas Schwöbel break; 113*3d6529b8SJonas Schwöbel 114*3d6529b8SJonas Schwöbel case REGB_ONLINE: 115*3d6529b8SJonas Schwöbel ret = i2c_smbus_read_byte_data(client, reg); 116*3d6529b8SJonas Schwöbel if (ret < 0) 117*3d6529b8SJonas Schwöbel return ret; 118*3d6529b8SJonas Schwöbel 119*3d6529b8SJonas Schwöbel *val = (ret & BIT(1)) >> 1; 120*3d6529b8SJonas Schwöbel break; 121*3d6529b8SJonas Schwöbel 122*3d6529b8SJonas Schwöbel default: 123*3d6529b8SJonas Schwöbel return -EINVAL; 124*3d6529b8SJonas Schwöbel } 125*3d6529b8SJonas Schwöbel 126*3d6529b8SJonas Schwöbel return 0; 127*3d6529b8SJonas Schwöbel } 128*3d6529b8SJonas Schwöbel 129*3d6529b8SJonas Schwöbel static int srt_bat_power_supply_get_property(struct power_supply *psy, 130*3d6529b8SJonas Schwöbel enum power_supply_property psp, 131*3d6529b8SJonas Schwöbel union power_supply_propval *val) 132*3d6529b8SJonas Schwöbel { 133*3d6529b8SJonas Schwöbel struct srt_ec_device *srt = power_supply_get_drvdata(psy); 134*3d6529b8SJonas Schwöbel struct i2c_client *client = srt->client; 135*3d6529b8SJonas Schwöbel int ret = 0; 136*3d6529b8SJonas Schwöbel 137*3d6529b8SJonas Schwöbel switch (psp) { 138*3d6529b8SJonas Schwöbel case POWER_SUPPLY_PROP_MANUFACTURER: 139*3d6529b8SJonas Schwöbel val->strval = srt->manufacturer; 140*3d6529b8SJonas Schwöbel break; 141*3d6529b8SJonas Schwöbel case POWER_SUPPLY_PROP_MODEL_NAME: 142*3d6529b8SJonas Schwöbel val->strval = srt->model_name; 143*3d6529b8SJonas Schwöbel break; 144*3d6529b8SJonas Schwöbel case POWER_SUPPLY_PROP_SERIAL_NUMBER: 145*3d6529b8SJonas Schwöbel val->strval = srt->serial; 146*3d6529b8SJonas Schwöbel break; 147*3d6529b8SJonas Schwöbel case POWER_SUPPLY_PROP_CAPACITY: 148*3d6529b8SJonas Schwöbel ret = srt_bat_get_value(client, REGW_CAPACITY, &val->intval); 149*3d6529b8SJonas Schwöbel break; 150*3d6529b8SJonas Schwöbel case POWER_SUPPLY_PROP_CHARGE_NOW: 151*3d6529b8SJonas Schwöbel ret = srt_bat_get_value(client, REGW_CHARGE_NOW, &val->intval); 152*3d6529b8SJonas Schwöbel break; 153*3d6529b8SJonas Schwöbel case POWER_SUPPLY_PROP_CHARGE_FULL: 154*3d6529b8SJonas Schwöbel ret = srt_bat_get_value(client, REGW_CHARGE_FULL, &val->intval); 155*3d6529b8SJonas Schwöbel break; 156*3d6529b8SJonas Schwöbel case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 157*3d6529b8SJonas Schwöbel ret = srt_bat_get_value(client, REGW_CHARGE_FULL_DESIGN, 158*3d6529b8SJonas Schwöbel &val->intval); 159*3d6529b8SJonas Schwöbel break; 160*3d6529b8SJonas Schwöbel case POWER_SUPPLY_PROP_CURRENT_NOW: 161*3d6529b8SJonas Schwöbel ret = srt_bat_get_value(client, REGW_CURRENT_NOW, &val->intval); 162*3d6529b8SJonas Schwöbel break; 163*3d6529b8SJonas Schwöbel case POWER_SUPPLY_PROP_CYCLE_COUNT: 164*3d6529b8SJonas Schwöbel ret = srt_bat_get_value(client, REGW_CYCLE_COUNT, &val->intval); 165*3d6529b8SJonas Schwöbel break; 166*3d6529b8SJonas Schwöbel case POWER_SUPPLY_PROP_PRESENT: 167*3d6529b8SJonas Schwöbel val->intval = 1; 168*3d6529b8SJonas Schwöbel break; 169*3d6529b8SJonas Schwöbel case POWER_SUPPLY_PROP_ONLINE: 170*3d6529b8SJonas Schwöbel ret = srt_bat_get_value(client, REGB_ONLINE, &val->intval); 171*3d6529b8SJonas Schwöbel break; 172*3d6529b8SJonas Schwöbel case POWER_SUPPLY_PROP_STATUS: 173*3d6529b8SJonas Schwöbel if (srt->capacity < 100) 174*3d6529b8SJonas Schwöbel ret = srt_bat_get_value(client, REGB_STATUS, &val->intval); 175*3d6529b8SJonas Schwöbel else 176*3d6529b8SJonas Schwöbel val->intval = POWER_SUPPLY_STATUS_FULL; 177*3d6529b8SJonas Schwöbel break; 178*3d6529b8SJonas Schwöbel case POWER_SUPPLY_PROP_TECHNOLOGY: 179*3d6529b8SJonas Schwöbel val->intval = srt->technology; 180*3d6529b8SJonas Schwöbel break; 181*3d6529b8SJonas Schwöbel case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: 182*3d6529b8SJonas Schwöbel ret = srt_bat_get_value(client, REGW_VOLTAGE_MAX_DESIGN, 183*3d6529b8SJonas Schwöbel &val->intval); 184*3d6529b8SJonas Schwöbel break; 185*3d6529b8SJonas Schwöbel case POWER_SUPPLY_PROP_VOLTAGE_NOW: 186*3d6529b8SJonas Schwöbel ret = srt_bat_get_value(client, REGW_VOLTAGE_NOW, &val->intval); 187*3d6529b8SJonas Schwöbel break; 188*3d6529b8SJonas Schwöbel default: 189*3d6529b8SJonas Schwöbel return -EINVAL; 190*3d6529b8SJonas Schwöbel } 191*3d6529b8SJonas Schwöbel 192*3d6529b8SJonas Schwöbel return ret; 193*3d6529b8SJonas Schwöbel } 194*3d6529b8SJonas Schwöbel 195*3d6529b8SJonas Schwöbel static int srt_psy_power_supply_get_property(struct power_supply *psy, 196*3d6529b8SJonas Schwöbel enum power_supply_property psp, 197*3d6529b8SJonas Schwöbel union power_supply_propval *val) 198*3d6529b8SJonas Schwöbel { 199*3d6529b8SJonas Schwöbel struct srt_ec_device *srt = power_supply_get_drvdata(psy); 200*3d6529b8SJonas Schwöbel struct i2c_client *client = srt->client; 201*3d6529b8SJonas Schwöbel int ret; 202*3d6529b8SJonas Schwöbel 203*3d6529b8SJonas Schwöbel switch (psp) { 204*3d6529b8SJonas Schwöbel case POWER_SUPPLY_PROP_ONLINE: 205*3d6529b8SJonas Schwöbel case POWER_SUPPLY_PROP_PRESENT: 206*3d6529b8SJonas Schwöbel ret = i2c_smbus_read_byte_data(client, REGB_ONLINE); 207*3d6529b8SJonas Schwöbel if (ret < 0) 208*3d6529b8SJonas Schwöbel return ret; 209*3d6529b8SJonas Schwöbel 210*3d6529b8SJonas Schwöbel val->intval = ret & BIT(0); 211*3d6529b8SJonas Schwöbel break; 212*3d6529b8SJonas Schwöbel default: 213*3d6529b8SJonas Schwöbel return -EINVAL; 214*3d6529b8SJonas Schwöbel } 215*3d6529b8SJonas Schwöbel 216*3d6529b8SJonas Schwöbel return 0; 217*3d6529b8SJonas Schwöbel } 218*3d6529b8SJonas Schwöbel 219*3d6529b8SJonas Schwöbel static void srt_bat_poll_work(struct work_struct *work) 220*3d6529b8SJonas Schwöbel { 221*3d6529b8SJonas Schwöbel struct srt_ec_device *srt = 222*3d6529b8SJonas Schwöbel container_of(work, struct srt_ec_device, poll_work.work); 223*3d6529b8SJonas Schwöbel int ret, capacity; 224*3d6529b8SJonas Schwöbel 225*3d6529b8SJonas Schwöbel ret = srt_bat_get_value(srt->client, REGW_CAPACITY, &capacity); 226*3d6529b8SJonas Schwöbel if (!ret && capacity != srt->capacity) { 227*3d6529b8SJonas Schwöbel srt->capacity = capacity; 228*3d6529b8SJonas Schwöbel power_supply_changed(srt->bat); 229*3d6529b8SJonas Schwöbel } 230*3d6529b8SJonas Schwöbel 231*3d6529b8SJonas Schwöbel /* continuously send uevent notification */ 232*3d6529b8SJonas Schwöbel schedule_delayed_work(&srt->poll_work, 30 * HZ); 233*3d6529b8SJonas Schwöbel } 234*3d6529b8SJonas Schwöbel 235*3d6529b8SJonas Schwöbel static irqreturn_t srt_psy_detect_irq(int irq, void *dev_id) 236*3d6529b8SJonas Schwöbel { 237*3d6529b8SJonas Schwöbel struct srt_ec_device *srt = dev_id; 238*3d6529b8SJonas Schwöbel 239*3d6529b8SJonas Schwöbel power_supply_changed(srt->psy); 240*3d6529b8SJonas Schwöbel 241*3d6529b8SJonas Schwöbel return IRQ_HANDLED; 242*3d6529b8SJonas Schwöbel } 243*3d6529b8SJonas Schwöbel 244*3d6529b8SJonas Schwöbel static const struct power_supply_desc srt_bat_power_supply_desc = { 245*3d6529b8SJonas Schwöbel .name = "surface-rt-battery", 246*3d6529b8SJonas Schwöbel .type = POWER_SUPPLY_TYPE_BATTERY, 247*3d6529b8SJonas Schwöbel .properties = srt_bat_power_supply_props, 248*3d6529b8SJonas Schwöbel .num_properties = ARRAY_SIZE(srt_bat_power_supply_props), 249*3d6529b8SJonas Schwöbel .get_property = srt_bat_power_supply_get_property, 250*3d6529b8SJonas Schwöbel .external_power_changed = power_supply_changed, 251*3d6529b8SJonas Schwöbel }; 252*3d6529b8SJonas Schwöbel 253*3d6529b8SJonas Schwöbel static const struct power_supply_desc srt_psy_power_supply_desc = { 254*3d6529b8SJonas Schwöbel .name = "surface-rt-ac-adapter", 255*3d6529b8SJonas Schwöbel .type = POWER_SUPPLY_TYPE_MAINS, 256*3d6529b8SJonas Schwöbel .properties = srt_psy_power_supply_props, 257*3d6529b8SJonas Schwöbel .num_properties = ARRAY_SIZE(srt_psy_power_supply_props), 258*3d6529b8SJonas Schwöbel .get_property = srt_psy_power_supply_get_property, 259*3d6529b8SJonas Schwöbel }; 260*3d6529b8SJonas Schwöbel 261*3d6529b8SJonas Schwöbel static char *battery_supplied_to[] = { "surface-rt-battery" }; 262*3d6529b8SJonas Schwöbel 263*3d6529b8SJonas Schwöbel static int srt_ec_probe(struct i2c_client *client) 264*3d6529b8SJonas Schwöbel { 265*3d6529b8SJonas Schwöbel struct power_supply_config bat_cfg = {}; 266*3d6529b8SJonas Schwöbel struct power_supply_config psy_cfg = {}; 267*3d6529b8SJonas Schwöbel struct device *dev = &client->dev; 268*3d6529b8SJonas Schwöbel struct srt_ec_device *srt; 269*3d6529b8SJonas Schwöbel char str_buf[4]; 270*3d6529b8SJonas Schwöbel int ret; 271*3d6529b8SJonas Schwöbel 272*3d6529b8SJonas Schwöbel srt = devm_kzalloc(dev, sizeof(*srt), GFP_KERNEL); 273*3d6529b8SJonas Schwöbel if (!srt) 274*3d6529b8SJonas Schwöbel return -ENOMEM; 275*3d6529b8SJonas Schwöbel 276*3d6529b8SJonas Schwöbel i2c_set_clientdata(client, srt); 277*3d6529b8SJonas Schwöbel srt->client = client; 278*3d6529b8SJonas Schwöbel 279*3d6529b8SJonas Schwöbel srt->enable_gpiod = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); 280*3d6529b8SJonas Schwöbel if (IS_ERR(srt->enable_gpiod)) 281*3d6529b8SJonas Schwöbel return dev_err_probe(dev, PTR_ERR(srt->enable_gpiod), 282*3d6529b8SJonas Schwöbel "failed to get enable gpio\n"); 283*3d6529b8SJonas Schwöbel 284*3d6529b8SJonas Schwöbel /* wait till EC is ready */ 285*3d6529b8SJonas Schwöbel usleep_range(1000, 1500); 286*3d6529b8SJonas Schwöbel 287*3d6529b8SJonas Schwöbel ret = i2c_smbus_read_word_data(client, REGW_SERIAL_NUMBER); 288*3d6529b8SJonas Schwöbel if (ret < 0) 289*3d6529b8SJonas Schwöbel return ret; 290*3d6529b8SJonas Schwöbel 291*3d6529b8SJonas Schwöbel srt->serial = devm_kasprintf(dev, GFP_KERNEL, "%04x", ret); 292*3d6529b8SJonas Schwöbel if (!srt->serial) 293*3d6529b8SJonas Schwöbel return -ENOMEM; 294*3d6529b8SJonas Schwöbel 295*3d6529b8SJonas Schwöbel ret = i2c_smbus_read_i2c_block_data(client, REGS_MANUFACTURER, 296*3d6529b8SJonas Schwöbel sizeof(srt->manufacturer) - 1, 297*3d6529b8SJonas Schwöbel srt->manufacturer); 298*3d6529b8SJonas Schwöbel if (ret < 0) 299*3d6529b8SJonas Schwöbel return ret; 300*3d6529b8SJonas Schwöbel 301*3d6529b8SJonas Schwöbel ret = i2c_smbus_read_i2c_block_data(client, REGS_MODEL_NAME, 302*3d6529b8SJonas Schwöbel sizeof(srt->model_name) - 1, 303*3d6529b8SJonas Schwöbel srt->model_name); 304*3d6529b8SJonas Schwöbel if (ret < 0) 305*3d6529b8SJonas Schwöbel return ret; 306*3d6529b8SJonas Schwöbel 307*3d6529b8SJonas Schwöbel ret = i2c_smbus_read_i2c_block_data(client, REGS_TECHNOLOGY, 308*3d6529b8SJonas Schwöbel sizeof(str_buf), str_buf); 309*3d6529b8SJonas Schwöbel if (ret < 0) 310*3d6529b8SJonas Schwöbel return ret; 311*3d6529b8SJonas Schwöbel 312*3d6529b8SJonas Schwöbel if (!strncmp(str_buf, "LION", 4)) 313*3d6529b8SJonas Schwöbel srt->technology = POWER_SUPPLY_TECHNOLOGY_LION; 314*3d6529b8SJonas Schwöbel else 315*3d6529b8SJonas Schwöbel srt->technology = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; 316*3d6529b8SJonas Schwöbel 317*3d6529b8SJonas Schwöbel bat_cfg.drv_data = srt; 318*3d6529b8SJonas Schwöbel bat_cfg.fwnode = dev_fwnode(dev); 319*3d6529b8SJonas Schwöbel 320*3d6529b8SJonas Schwöbel srt->bat = devm_power_supply_register(dev, &srt_bat_power_supply_desc, 321*3d6529b8SJonas Schwöbel &bat_cfg); 322*3d6529b8SJonas Schwöbel if (IS_ERR(srt->bat)) 323*3d6529b8SJonas Schwöbel return dev_err_probe(dev, PTR_ERR(srt->bat), 324*3d6529b8SJonas Schwöbel "failed to register battery power supply\n"); 325*3d6529b8SJonas Schwöbel 326*3d6529b8SJonas Schwöbel psy_cfg.drv_data = srt; 327*3d6529b8SJonas Schwöbel psy_cfg.fwnode = dev_fwnode(dev); 328*3d6529b8SJonas Schwöbel psy_cfg.supplied_to = battery_supplied_to; 329*3d6529b8SJonas Schwöbel psy_cfg.num_supplicants = ARRAY_SIZE(battery_supplied_to); 330*3d6529b8SJonas Schwöbel 331*3d6529b8SJonas Schwöbel srt->psy = devm_power_supply_register(dev, &srt_psy_power_supply_desc, 332*3d6529b8SJonas Schwöbel &psy_cfg); 333*3d6529b8SJonas Schwöbel if (IS_ERR(srt->psy)) 334*3d6529b8SJonas Schwöbel return dev_err_probe(dev, PTR_ERR(srt->psy), 335*3d6529b8SJonas Schwöbel "failed to register AC power supply\n"); 336*3d6529b8SJonas Schwöbel 337*3d6529b8SJonas Schwöbel ret = devm_request_threaded_irq(dev, client->irq, NULL, srt_psy_detect_irq, 338*3d6529b8SJonas Schwöbel IRQF_ONESHOT, client->name, srt); 339*3d6529b8SJonas Schwöbel if (ret < 0) 340*3d6529b8SJonas Schwöbel return dev_err_probe(dev, ret, "failed to request interrupt\n"); 341*3d6529b8SJonas Schwöbel 342*3d6529b8SJonas Schwöbel ret = devm_delayed_work_autocancel(dev, &srt->poll_work, srt_bat_poll_work); 343*3d6529b8SJonas Schwöbel if (ret < 0) 344*3d6529b8SJonas Schwöbel return ret; 345*3d6529b8SJonas Schwöbel 346*3d6529b8SJonas Schwöbel schedule_delayed_work(&srt->poll_work, HZ); 347*3d6529b8SJonas Schwöbel 348*3d6529b8SJonas Schwöbel return 0; 349*3d6529b8SJonas Schwöbel } 350*3d6529b8SJonas Schwöbel 351*3d6529b8SJonas Schwöbel static int srt_ec_suspend(struct device *dev) 352*3d6529b8SJonas Schwöbel { 353*3d6529b8SJonas Schwöbel struct srt_ec_device *srt = dev_get_drvdata(dev); 354*3d6529b8SJonas Schwöbel 355*3d6529b8SJonas Schwöbel cancel_delayed_work_sync(&srt->poll_work); 356*3d6529b8SJonas Schwöbel 357*3d6529b8SJonas Schwöbel return 0; 358*3d6529b8SJonas Schwöbel } 359*3d6529b8SJonas Schwöbel 360*3d6529b8SJonas Schwöbel static int srt_ec_resume(struct device *dev) 361*3d6529b8SJonas Schwöbel { 362*3d6529b8SJonas Schwöbel struct srt_ec_device *srt = dev_get_drvdata(dev); 363*3d6529b8SJonas Schwöbel 364*3d6529b8SJonas Schwöbel schedule_delayed_work(&srt->poll_work, HZ); 365*3d6529b8SJonas Schwöbel 366*3d6529b8SJonas Schwöbel return 0; 367*3d6529b8SJonas Schwöbel } 368*3d6529b8SJonas Schwöbel 369*3d6529b8SJonas Schwöbel static DEFINE_SIMPLE_DEV_PM_OPS(srt_ec_pm_ops, srt_ec_suspend, srt_ec_resume); 370*3d6529b8SJonas Schwöbel 371*3d6529b8SJonas Schwöbel static const struct of_device_id srt_ec_of_match[] = { 372*3d6529b8SJonas Schwöbel { .compatible = "microsoft,surface-rt-ec" }, 373*3d6529b8SJonas Schwöbel { } 374*3d6529b8SJonas Schwöbel }; 375*3d6529b8SJonas Schwöbel MODULE_DEVICE_TABLE(of, srt_ec_of_match); 376*3d6529b8SJonas Schwöbel 377*3d6529b8SJonas Schwöbel static struct i2c_driver srt_ec_driver = { 378*3d6529b8SJonas Schwöbel .driver = { 379*3d6529b8SJonas Schwöbel .name = "surface-rt-ec", 380*3d6529b8SJonas Schwöbel .of_match_table = srt_ec_of_match, 381*3d6529b8SJonas Schwöbel .pm = &srt_ec_pm_ops, 382*3d6529b8SJonas Schwöbel }, 383*3d6529b8SJonas Schwöbel .probe = srt_ec_probe, 384*3d6529b8SJonas Schwöbel }; 385*3d6529b8SJonas Schwöbel module_i2c_driver(srt_ec_driver); 386*3d6529b8SJonas Schwöbel 387*3d6529b8SJonas Schwöbel MODULE_AUTHOR("Jonas Schwöbel <jonasschwoebel@yahoo.de>"); 388*3d6529b8SJonas Schwöbel MODULE_DESCRIPTION("Surface RT Embedded Controller driver"); 389*3d6529b8SJonas Schwöbel MODULE_LICENSE("GPL"); 390