blob: 9d17b4bd01004bdfab0c1db048782ab2bc69e3a9 [file] [log] [blame]
Ken Tsou8acade12020-07-09 03:17:35 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2020, Google Inc
4 *
5 * MAX20339 OVP and LS driver
6 */
7
8#define pr_fmt(fmt) KBUILD_MODNAME ": %s " fmt, __func__
9
10#include <linux/gpio.h>
11#include <linux/gpio/driver.h>
12#include <linux/i2c.h>
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/mutex.h>
16#include <linux/of_device.h>
AleX Pelosif2d03562021-04-25 16:44:02 -070017#include <linux/of_gpio.h>
18#include <linux/of_irq.h>
19#include <linux/interrupt.h>
Ken Tsou8acade12020-07-09 03:17:35 +080020#include <linux/regmap.h>
21
Badhri Jagan Sridharanefc68ab2020-11-09 23:59:03 -080022#define MAX20339_STATUS1 0x1
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -080023#define MAX20339_STATUS1_VINVALID BIT(5)
Badhri Jagan Sridharanefc68ab2020-11-09 23:59:03 -080024#define MAX20339_STATUS2 0x2
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -080025#define MAX20339_STATUS_SWITCH_CLOSED BIT(0)
AleX Pelosi70a9a592021-02-09 23:57:18 -080026#define MAX20339_STATUS2_SWITCH_CLOSED_SHIFT 0
27#define MAX20339_STATUS2_SWITCH_CLOSED_MASK 0x1
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -080028
Badhri Jagan Sridharanefc68ab2020-11-09 23:59:03 -080029#define MAX20339_STATUS3 0x3
30#define MAX20339_INT1 0x4
31#define MAX20339_INT2 0x5
32#define MAX20339_INT3 0x6
33#define MAX20339_INTMASK1 0x7
Ken Tsou8acade12020-07-09 03:17:35 +080034#define MAX20339_OVLOSEL 0x11
AleX Pelosid4c570e2021-05-18 17:02:46 -070035#define MAX20339_OVLOSEL_INOVLOSEL_5_85 0x0
Ken Tsou8acade12020-07-09 03:17:35 +080036#define MAX20339_OVLOSEL_INOVLOSEL_14_5 0x2
AleX Pelosid4c570e2021-05-18 17:02:46 -070037#define MAX20339_OVLOSEL_INOVLOSEL_MASK 0x3
Badhri Jagan Sridharanc1ab7ba2021-02-06 00:03:59 -080038#define MAX20339_IN_CTR_REG 0x10
39#define MAX20339_IN_CTR_SWEN_SHIFT 0
40#define MAX20339_IN_CTR_SWEN_MASK GENMASK(1, 0)
41#define MAX20339_IN_CTR_SWEN_FORCE_ON 0x3
42#define MAX20339_IN_CTR_SWEN_FORCE_OFF 0x0
Ken Tsou8acade12020-07-09 03:17:35 +080043
44#define MAX20339_POLL_ATTEMPTS 10
45#define MAX20339_INT2_REG 0x5
46#define MAX20339_INT2_LSW1CLOSEDI (1 << 0)
47#define MAX20339_INT3_REG 0x6
48#define MAX20339_INT3_LSW2CLOSEDI (1 << 0)
49
50#define MAX20339_SW_CNTL_REG 0xA
51#define MAX20339_SW_CNTL_LSW1_EN_SHIFT 0
52#define MAX20339_SW_CNTL_LSW1_EN_MASK 0x1
53#define MAX20339_SW_CNTL_LSW1_OV_SHIFT 1
54#define MAX20338_SW_CNTL_LSW1_OV_EN_MASK 0x2
55#define MAX20339_SW_CNTL_LSW2_EN_SHIFT 4
56#define MAX20339_SW_CNTL_LSW2_EN_MASK 0x10
57#define MAX20338_SW_CNTL_LSW2_OV_EN_SHIFT 5
58#define MAX20338_SW_CNTL_LSW2_OV_EN_MASK 0x20
59
AleX Pelosid4c570e2021-05-18 17:02:46 -070060
Ken Tsou8acade12020-07-09 03:17:35 +080061#define MAX20339_MIN_GPIO 0
AleX Pelosid4c570e2021-05-18 17:02:46 -070062#define MAX20339_MAX_GPIO 8
63#define MAX20339_NUM_GPIOS 8
Ken Tsou8acade12020-07-09 03:17:35 +080064#define MAX20339_LSW1_OFF 0
65#define MAX20339_LSW2_OFF 1
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -080066#define MAX20339_LSW1_STATUS_OFF 2
67#define MAX20339_VIN_VALID_OFF 3
Badhri Jagan Sridharanc1ab7ba2021-02-06 00:03:59 -080068#define MAX20339_IN_CTR_SWEN_OFF 4
AleX Pelosi70a9a592021-02-09 23:57:18 -080069#define MAX20339_LSW1_IS_OPEN_OFF 5
70#define MAX20339_LSW1_IS_CLOSED_OFF 6
AleX Pelosid4c570e2021-05-18 17:02:46 -070071#define MAX20339_OTG_ENA_OFF 7
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -080072
AleX Pelosi0b34cda2021-07-28 15:59:41 -070073#define MAX20339_LSW1_TIMEOUT_MS 100
74#define MAX20339_VIN_VALID_TIMEOUT_MS 100
Ken Tsou8acade12020-07-09 03:17:35 +080075
76struct max20339_ovp {
77 struct i2c_client *client;
78 struct regmap *regmap;
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -080079 wait_queue_head_t gpio_get_wq;
AleX Pelosi6852a072020-09-08 19:05:56 -070080#if IS_ENABLED(CONFIG_GPIOLIB)
Ken Tsou8acade12020-07-09 03:17:35 +080081 struct gpio_chip gpio;
82#endif
AleX Pelosif2d03562021-04-25 16:44:02 -070083 int irq_gpio;
Ken Tsou8acade12020-07-09 03:17:35 +080084};
85
86static const struct regmap_range max20339_ovp_range[] = {
87 regmap_reg_range(0x0, 0x2f)
88};
89
90const struct regmap_access_table max20339_ovp_write_table = {
91 .yes_ranges = max20339_ovp_range,
92 .n_yes_ranges = ARRAY_SIZE(max20339_ovp_range),
93};
94
95static const struct regmap_config max20339_regmap_config = {
96 .reg_bits = 8,
97 .val_bits = 8,
98 .max_register = 0x2f,
99 .wr_table = &max20339_ovp_write_table,
100};
101
AleX Pelosif2d03562021-04-25 16:44:02 -0700102static irqreturn_t max20339_irq(int irqno, void *data)
Badhri Jagan Sridharanefc68ab2020-11-09 23:59:03 -0800103{
104 struct max20339_ovp *ovp = data;
105 struct device *dev;
106 u8 buf[6];
107 int ret;
108
AleX Pelosif2d03562021-04-25 16:44:02 -0700109 /* not really possible now */
Badhri Jagan Sridharanefc68ab2020-11-09 23:59:03 -0800110 if (!ovp)
AleX Pelosif2d03562021-04-25 16:44:02 -0700111 return IRQ_NONE;
Badhri Jagan Sridharanefc68ab2020-11-09 23:59:03 -0800112
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -0800113 wake_up_all(&ovp->gpio_get_wq);
114
AleX Pelosif2d03562021-04-25 16:44:02 -0700115 /* TODO: check the actual status and return IRQ_NONE if none is set */
116
Badhri Jagan Sridharanefc68ab2020-11-09 23:59:03 -0800117 dev = &ovp->client->dev;
118 ret = regmap_bulk_read(ovp->regmap, MAX20339_STATUS1, buf, ARRAY_SIZE(buf));
119 if (!ret)
120 dev_info(dev,
121 "OVP TRIGGERED: STATUS1:%#x STATUS2:%#x STATUS3:%#x INT1:%#x INT2:%#x INT3:%#x\n",
122 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
123 else
124 dev_err(dev, "OVP TRIGGERED: Failed on reading status:%d\n", ret);
AleX Pelosif2d03562021-04-25 16:44:02 -0700125
126 return IRQ_HANDLED;
Badhri Jagan Sridharanefc68ab2020-11-09 23:59:03 -0800127}
Badhri Jagan Sridharanefc68ab2020-11-09 23:59:03 -0800128
Ken Tsou8acade12020-07-09 03:17:35 +0800129static int max20339_init_regs(struct regmap *regmap, struct device *dev)
130{
131 int ret;
132 unsigned int val;
Badhri Jagan Sridharanefc68ab2020-11-09 23:59:03 -0800133 const u8 irq_mask[] = {0xff, 0xff, 0xff};
Ken Tsou8acade12020-07-09 03:17:35 +0800134
135 ret = regmap_read(regmap, MAX20339_OVLOSEL, &val);
136 if (ret < 0) {
137 dev_err(dev, "OVLSEL read error: ret %d\n", ret);
138 return ret;
139 }
140
141 dev_info(dev, "OVLOSEL default: %#x\n", val);
142
143 ret = regmap_write(regmap, MAX20339_OVLOSEL,
144 MAX20339_OVLOSEL_INOVLOSEL_14_5);
145 if (ret < 0) {
146 dev_err(dev, "OVLSEL write error: ret %d\n", ret);
147 return ret;
148 }
149
Badhri Jagan Sridharanc1ab7ba2021-02-06 00:03:59 -0800150 ret = regmap_read(regmap, MAX20339_IN_CTR_REG, &val);
Ken Tsou8acade12020-07-09 03:17:35 +0800151 if (ret < 0) {
152 dev_err(dev, "IN_CTR read error: ret %d\n", ret);
153 return ret;
154 }
155
156 dev_info(dev, "IN_CTR default: %#x\n", val);
157
158 /* Disable & enable to make OVLOSEL reflect */
Badhri Jagan Sridharanc1ab7ba2021-02-06 00:03:59 -0800159 ret = regmap_write(regmap, MAX20339_IN_CTR_REG, 0);
Ken Tsou8acade12020-07-09 03:17:35 +0800160 if (ret < 0) {
161 dev_err(dev, "IN_CTR write error: ret %d\n", ret);
162 return ret;
163 }
164
Badhri Jagan Sridharanfb4784f2020-11-13 12:24:35 -0800165 /* Enable Force on while re-enabling the switch */
Badhri Jagan Sridharanc1ab7ba2021-02-06 00:03:59 -0800166 ret = regmap_write(regmap, MAX20339_IN_CTR_REG, val | MAX20339_IN_CTR_SWEN_FORCE_ON);
Ken Tsou8acade12020-07-09 03:17:35 +0800167 if (ret < 0) {
168 dev_err(dev, "IN_CTR write error: ret %d\n", ret);
169 return ret;
170 }
171
Badhri Jagan Sridharanefc68ab2020-11-09 23:59:03 -0800172 ret = regmap_bulk_write(regmap, MAX20339_INTMASK1, irq_mask, ARRAY_SIZE(irq_mask));
173 if (ret < 0) {
Ken Tsoue23e7572020-11-13 10:23:15 +0800174 dev_err(dev, "INTMASK1-3 enable failed: ret %d\n", ret);
Badhri Jagan Sridharanefc68ab2020-11-09 23:59:03 -0800175 return ret;
176 }
177
Ken Tsou8acade12020-07-09 03:17:35 +0800178 return ret;
179}
180
AleX Pelosi6852a072020-09-08 19:05:56 -0700181#if IS_ENABLED(CONFIG_GPIOLIB)
Ken Tsou8acade12020-07-09 03:17:35 +0800182static int max20339_gpio_get_direction(struct gpio_chip *chip,
183 unsigned int offset)
184{
185 return GPIOF_DIR_OUT;
186}
187
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -0800188static bool max20339_is_lsw_closed(struct max20339_ovp *ovp, int offset)
189{
190 int ret;
AleX Pelosi0b34cda2021-07-28 15:59:41 -0700191 unsigned int val = 0;
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -0800192
AleX Pelosi70a9a592021-02-09 23:57:18 -0800193 ret = regmap_read(ovp->regmap, offset == MAX20339_LSW1_OFF ?
194 MAX20339_STATUS2 : MAX20339_STATUS3, &val);
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -0800195 if (ret < 0)
196 return false;
AleX Pelosi70a9a592021-02-09 23:57:18 -0800197
198 return (val & MAX20339_STATUS_SWITCH_CLOSED) != 0;
199}
200
201/* 1 same as state, 0 not same */
202static int max20339_test_lsw1_state(struct max20339_ovp *ovp, int state)
203{
AleX Pelosi0b34cda2021-07-28 15:59:41 -0700204 const int poll_interval_ms = 20;
205 int ret = -ETIMEDOUT;
AleX Pelosi70a9a592021-02-09 23:57:18 -0800206 unsigned int val;
207 bool closed;
AleX Pelosi0b34cda2021-07-28 15:59:41 -0700208 int i;
AleX Pelosi70a9a592021-02-09 23:57:18 -0800209
210 ret = regmap_read(ovp->regmap, MAX20339_STATUS2, &val);
211 if (ret < 0)
212 return ret;
213
214 closed = (val & MAX20339_STATUS_SWITCH_CLOSED) != 0;
215 if (closed == state)
216 return 1;
217
AleX Pelosi0b34cda2021-07-28 15:59:41 -0700218 /* wait_event_timeout() timeout is not reliable */
219 for (i = 0; i <= MAX20339_LSW1_TIMEOUT_MS; i += poll_interval_ms) {
220 if (max20339_is_lsw_closed(ovp, MAX20339_LSW1_OFF) == state) {
221 ret = 0;
222 break;
223 }
224
225 mdelay(poll_interval_ms);
226 }
227
AleX Pelosi70a9a592021-02-09 23:57:18 -0800228 if (!ret)
229 dev_warn(&ovp->client->dev, "Timeout for lsw1==%d\n", state);
230
231 return max20339_is_lsw_closed(ovp, MAX20339_LSW1_OFF) == state;
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -0800232}
233
234static bool max20339_is_vin_valid(struct max20339_ovp *ovp)
235{
236 int ret;
237 unsigned int val;
238
239 ret = regmap_read(ovp->regmap, MAX20339_STATUS1, &val);
240 if (ret < 0)
241 return false;
242
243 return (val & MAX20339_STATUS_SWITCH_CLOSED) != 0;
244}
245
Ken Tsou8acade12020-07-09 03:17:35 +0800246static int max20339_gpio_get(struct gpio_chip *chip, unsigned int offset)
247{
Ken Tsou8acade12020-07-09 03:17:35 +0800248 struct max20339_ovp *ovp = gpiochip_get_data(chip);
AleX Pelosi70a9a592021-02-09 23:57:18 -0800249 unsigned int val;
250 u8 mask, shift;
251 int ret, reg;
Ken Tsou8acade12020-07-09 03:17:35 +0800252
253 switch (offset) {
254 case MAX20339_LSW1_OFF:
255 mask = MAX20339_SW_CNTL_LSW1_EN_MASK;
256 shift = MAX20339_SW_CNTL_LSW1_EN_SHIFT;
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -0800257 reg = MAX20339_SW_CNTL_REG;
Ken Tsou8acade12020-07-09 03:17:35 +0800258 break;
259 case MAX20339_LSW2_OFF:
260 mask = MAX20339_SW_CNTL_LSW2_EN_MASK;
261 shift = MAX20339_SW_CNTL_LSW2_EN_SHIFT;
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -0800262 reg = MAX20339_SW_CNTL_REG;
263 break;
264 case MAX20339_LSW1_STATUS_OFF:
AleX Pelosi70a9a592021-02-09 23:57:18 -0800265 mask = MAX20339_STATUS2_SWITCH_CLOSED_MASK;
266 shift = MAX20339_STATUS2_SWITCH_CLOSED_SHIFT;
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -0800267 reg = MAX20339_STATUS2;
268 break;
269 case MAX20339_VIN_VALID_OFF:
270 reg = MAX20339_STATUS1;
Ken Tsou8acade12020-07-09 03:17:35 +0800271 break;
AleX Pelosi70a9a592021-02-09 23:57:18 -0800272 case MAX20339_LSW1_IS_OPEN_OFF:
273 return max20339_test_lsw1_state(ovp, 0);
274 case MAX20339_LSW1_IS_CLOSED_OFF:
275 return max20339_test_lsw1_state(ovp, 1);
Ken Tsou8acade12020-07-09 03:17:35 +0800276 default:
277 return -EINVAL;
278 }
279
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -0800280 ret = regmap_read(ovp->regmap, reg, &val);
Ken Tsou8acade12020-07-09 03:17:35 +0800281 if (ret < 0) {
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -0800282 dev_err(&ovp->client->dev, "%x read error: ret %d\n", reg, ret);
Ken Tsou8acade12020-07-09 03:17:35 +0800283 return ret;
284 }
285
AleX Pelosi70a9a592021-02-09 23:57:18 -0800286 /* only checked for valid */
287 if (offset == MAX20339_VIN_VALID_OFF) {
288
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -0800289 if (val & MAX20339_STATUS1_VINVALID)
290 return 1;
AleX Pelosi70a9a592021-02-09 23:57:18 -0800291
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -0800292 wait_event_timeout(ovp->gpio_get_wq, max20339_is_vin_valid(ovp),
AleX Pelosi0b34cda2021-07-28 15:59:41 -0700293 msecs_to_jiffies(MAX20339_VIN_VALID_TIMEOUT_MS));
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -0800294 return max20339_is_vin_valid(ovp) ? 1 : 0;
295 }
AleX Pelosi70a9a592021-02-09 23:57:18 -0800296
Ken Tsou8acade12020-07-09 03:17:35 +0800297 return (val & mask) >> shift;
298}
299
300static void max20339_gpio_set(struct gpio_chip *chip,
301 unsigned int offset, int value)
302{
303 int ret;
304 unsigned int tmp;
305 bool change;
306 u8 mask;
Badhri Jagan Sridharana76b3592021-02-05 19:48:58 -0800307 u8 status_reg; /* status register to poll for update */
Badhri Jagan Sridharana76b3592021-02-05 19:48:58 -0800308 u8 sw_cntl_reg;
Ken Tsou8acade12020-07-09 03:17:35 +0800309 int i;
310 struct max20339_ovp *ovp = gpiochip_get_data(chip);
311
AleX Pelosi0b34cda2021-07-28 15:59:41 -0700312 dev_dbg(&ovp->client->dev, "%s off=%u val=%d", __func__, offset, value);
Ken Tsou8acade12020-07-09 03:17:35 +0800313 switch (offset) {
314 case MAX20339_LSW1_OFF:
Badhri Jagan Sridharana76b3592021-02-05 19:48:58 -0800315 sw_cntl_reg = MAX20339_SW_CNTL_REG;
Ken Tsou8acade12020-07-09 03:17:35 +0800316 mask = MAX20339_SW_CNTL_LSW1_EN_MASK;
Badhri Jagan Sridharana76b3592021-02-05 19:48:58 -0800317 status_reg = MAX20339_STATUS2;
Badhri Jagan Sridharanc1ab7ba2021-02-06 00:03:59 -0800318 tmp = (!!value << MAX20339_SW_CNTL_LSW1_EN_SHIFT);
Ken Tsou8acade12020-07-09 03:17:35 +0800319 break;
320 case MAX20339_LSW2_OFF:
Badhri Jagan Sridharana76b3592021-02-05 19:48:58 -0800321 sw_cntl_reg = MAX20339_SW_CNTL_REG;
Ken Tsou8acade12020-07-09 03:17:35 +0800322 mask = MAX20339_SW_CNTL_LSW2_EN_MASK;
Badhri Jagan Sridharana76b3592021-02-05 19:48:58 -0800323 status_reg = MAX20339_STATUS3;
Badhri Jagan Sridharanc1ab7ba2021-02-06 00:03:59 -0800324 tmp = (!!value << MAX20339_SW_CNTL_LSW2_EN_SHIFT);
325 break;
326 case MAX20339_IN_CTR_SWEN_OFF:
327 sw_cntl_reg = MAX20339_IN_CTR_REG;
328 mask = MAX20339_IN_CTR_SWEN_MASK;
329 status_reg = MAX20339_STATUS1;
330 tmp = value ? MAX20339_IN_CTR_SWEN_FORCE_ON : MAX20339_IN_CTR_SWEN_FORCE_OFF;
Ken Tsou8acade12020-07-09 03:17:35 +0800331 break;
AleX Pelosid4c570e2021-05-18 17:02:46 -0700332
333 /* b/178458456 clear/reset INOVLO on enter/exit from OTG cases */
334 case MAX20339_OTG_ENA_OFF:
335 tmp = value ? MAX20339_OVLOSEL_INOVLOSEL_5_85 :
336 MAX20339_OVLOSEL_INOVLOSEL_14_5;
337 ret = regmap_update_bits(ovp->regmap, MAX20339_OVLOSEL,
338 MAX20339_OVLOSEL_INOVLOSEL_MASK,
339 tmp);
340 if (ret < 0)
341 dev_err(&ovp->client->dev, "OVLOSEL update error: ret %d\n", ret);
342 return;
Ken Tsou8acade12020-07-09 03:17:35 +0800343 default:
344 return;
345 }
346
Badhri Jagan Sridharana76b3592021-02-05 19:48:58 -0800347 ret = regmap_update_bits_base(ovp->regmap, sw_cntl_reg, mask, tmp,
Ken Tsou8acade12020-07-09 03:17:35 +0800348 &change, false, false);
349 if (ret < 0)
350 dev_err(&ovp->client->dev, "SW_CNTL update error: ret %d\n", ret);
351
352 /* poll until update seen */
353 for (i = 0; i < MAX20339_POLL_ATTEMPTS; i++) {
Badhri Jagan Sridharana76b3592021-02-05 19:48:58 -0800354 ret = regmap_read(ovp->regmap, status_reg, &tmp);
Badhri Jagan Sridharanc1ab7ba2021-02-06 00:03:59 -0800355 if ((tmp & MAX20339_STATUS_SWITCH_CLOSED) == value)
Ken Tsou8acade12020-07-09 03:17:35 +0800356 break;
357 mdelay(20);
358 }
359
360}
361#endif
362
AleX Pelosif2d03562021-04-25 16:44:02 -0700363/* HACK: will make max77729_pmic an interrupt controller and use the irq */
364static int max20339_setup_irq(struct max20339_ovp *ovp)
365{
366 struct device *dev = &ovp->client->dev;
367 int ret = -EINVAL;
368
369 ovp->irq_gpio = of_get_named_gpio(dev->of_node, "max20339,irq-gpio", 0);
370 if (ovp->irq_gpio < 0) {
371 dev_err(dev, "failed to get irq-gpio (%d)\n", ovp->irq_gpio);
372 } else {
373 const int irq = gpio_to_irq(ovp->irq_gpio);
374
375 ret = devm_request_threaded_irq(dev, irq, NULL,
376 max20339_irq,
377 IRQF_TRIGGER_FALLING |
378 IRQF_SHARED |
379 IRQF_ONESHOT,
380 "max2339_ovp",
381 ovp);
382
383 dev_err(dev, "ovp->irq_gpio=%d found irq=%d registered %d\n",
384 ovp->irq_gpio, irq, ret);
385 }
386
387 /* Read to clear interrupts */
388 max20339_irq(-1, ovp);
389
390 return ret;
391}
392
Ken Tsou8acade12020-07-09 03:17:35 +0800393static int max20339_probe(struct i2c_client *client,
394 const struct i2c_device_id *i2c_id)
395{
396 struct max20339_ovp *ovp;
AleX Pelosif2d03562021-04-25 16:44:02 -0700397 int rc, ret = 0;
Ken Tsou8acade12020-07-09 03:17:35 +0800398
399 ovp = devm_kzalloc(&client->dev, sizeof(*ovp), GFP_KERNEL);
400 if (!ovp)
401 return -ENOMEM;
402
403 ovp->client = client;
AleX Pelosif2d03562021-04-25 16:44:02 -0700404 ovp->regmap = devm_regmap_init_i2c(client, &max20339_regmap_config);
Ken Tsou8acade12020-07-09 03:17:35 +0800405 if (IS_ERR(ovp->regmap)) {
406 dev_err(&client->dev, "Regmap init failed\n");
407 return PTR_ERR(ovp->regmap);
408 }
409
410 max20339_init_regs(ovp->regmap, &client->dev);
Badhri Jagan Sridharanefc68ab2020-11-09 23:59:03 -0800411 i2c_set_clientdata(client, ovp);
Badhri Jagan Sridharan38c847e2021-02-01 00:18:07 -0800412 init_waitqueue_head(&ovp->gpio_get_wq);
Badhri Jagan Sridharanefc68ab2020-11-09 23:59:03 -0800413
AleX Pelosi6852a072020-09-08 19:05:56 -0700414#if IS_ENABLED(CONFIG_GPIOLIB)
415 /* Setup GPIO controller */
Ken Tsou8acade12020-07-09 03:17:35 +0800416 ovp->gpio.owner = THIS_MODULE;
417 ovp->gpio.parent = &client->dev;
418 ovp->gpio.label = "max20339_gpio";
419 ovp->gpio.get_direction = max20339_gpio_get_direction;
420 ovp->gpio.get = max20339_gpio_get;
421 ovp->gpio.set = max20339_gpio_set;
422 ovp->gpio.base = -1;
423 ovp->gpio.ngpio = MAX20339_NUM_GPIOS;
424 ovp->gpio.can_sleep = true;
425 ovp->gpio.of_node = of_find_node_by_name(client->dev.of_node,
426 ovp->gpio.label);
427 if (!ovp->gpio.of_node)
428 dev_err(&client->dev, "Failed to find %s DT node\n",
429 ovp->gpio.label);
430
431 ret = devm_gpiochip_add_data(&client->dev, &ovp->gpio, ovp);
432 if (ret)
433 dev_err(&client->dev, "Failed to initialize gpio chip\n");
434#endif
435
AleX Pelosif2d03562021-04-25 16:44:02 -0700436 rc = max20339_setup_irq(ovp);
437 if (rc < 0)
438 dev_err(&client->dev, "Init IRQ failed (%d)\n", rc);
439
Ken Tsou8acade12020-07-09 03:17:35 +0800440 return ret;
441}
442
443static int max20339_remove(struct i2c_client *client)
444{
445 return 0;
446}
447
448static const struct i2c_device_id max20339_id[] = {
449 { "max20339ovp", 0 },
450 { }
451};
452MODULE_DEVICE_TABLE(i2c, max20339_id);
453
454#ifdef CONFIG_OF
455static const struct of_device_id max20339_of_match[] = {
456 { .compatible = "max20339ovp", },
457 {},
458};
459MODULE_DEVICE_TABLE(of, max20339_of_match);
460#endif
461
462static struct i2c_driver max20339_i2c_driver = {
463 .driver = {
464 .name = "max20339ovp",
465 .of_match_table = of_match_ptr(max20339_of_match),
466 },
467 .probe = max20339_probe,
468 .remove = max20339_remove,
469 .id_table = max20339_id,
470};
471module_i2c_driver(max20339_i2c_driver);
472
473MODULE_AUTHOR("Badhri Jagan Sridharan <badhri@google.com>");
Ken Tsou98b71642020-07-09 16:17:29 +0800474MODULE_LICENSE("GPL");