xref: /linux/drivers/power/supply/surface-rt-ec.c (revision 3d5e48944e824bddc20d7b874e784f7b279636fe)
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