blob: 6176df97fd30363d0efcf7dec5fa9aaba608988b [file] [log] [blame]
Abhijeet Dharmapurikarea799552014-01-08 20:16:37 -08001/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
Michael Bohan0ba63b82012-02-06 13:42:34 -08002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
Michael Bohane25e15f2012-04-12 17:28:26 -070013#define pr_fmt(fmt) "%s: " fmt, __func__
14
Michael Bohan0ba63b82012-02-06 13:42:34 -080015#include <linux/interrupt.h>
16#include <linux/types.h>
17#include <linux/spmi.h>
18#include <linux/platform_device.h>
Michael Bohana19dced2012-04-24 13:14:50 -070019#include <linux/debugfs.h>
Michael Bohan0ba63b82012-02-06 13:42:34 -080020#include <linux/gpio.h>
21#include <linux/slab.h>
22#include <linux/of.h>
23#include <linux/of_gpio.h>
24#include <linux/of_irq.h>
Michael Bohan0b24fb12012-06-01 10:30:12 -070025#include <linux/export.h>
26#include <linux/module.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070027#include <linux/export.h>
Michael Bohana05f4552012-05-24 15:58:11 -070028#include <linux/qpnp/pin.h>
Michael Bohan0ba63b82012-02-06 13:42:34 -080029
Michael Bohan0ba63b82012-02-06 13:42:34 -080030#define Q_REG_ADDR(q_spec, reg_index) \
31 ((q_spec)->offset + reg_index)
32
33#define Q_REG_STATUS1 0x8
Michael Bohanffa16812012-08-15 18:11:49 -070034#define Q_REG_STATUS1_VAL_MASK 0x1
Michael Bohanbfe64c72012-08-24 16:57:26 -070035#define Q_REG_STATUS1_GPIO_EN_REV0_MASK 0x2
36#define Q_REG_STATUS1_GPIO_EN_MASK 0x80
Michael Bohanffa16812012-08-15 18:11:49 -070037#define Q_REG_STATUS1_MPP_EN_MASK 0x80
38
Michael Bohan6b901572012-05-30 13:32:24 -070039#define Q_NUM_CTL_REGS 0xD
Michael Bohane25e15f2012-04-12 17:28:26 -070040
Michael Bohanbfe64c72012-08-24 16:57:26 -070041/* revision registers base address offsets */
42#define Q_REG_DIG_MINOR_REV 0x0
43#define Q_REG_DIG_MAJOR_REV 0x1
44#define Q_REG_ANA_MINOR_REV 0x2
45
Michael Bohane25e15f2012-04-12 17:28:26 -070046/* type registers base address offsets */
Michael Bohan6b901572012-05-30 13:32:24 -070047#define Q_REG_TYPE 0x4
48#define Q_REG_SUBTYPE 0x5
Michael Bohane25e15f2012-04-12 17:28:26 -070049
50/* gpio peripheral type and subtype values */
51#define Q_GPIO_TYPE 0x10
Michael Bohane824a6e2012-08-14 14:35:37 -070052#define Q_GPIO_SUBTYPE_GPIO_4CH 0x1
53#define Q_GPIO_SUBTYPE_GPIOC_4CH 0x5
54#define Q_GPIO_SUBTYPE_GPIO_8CH 0x9
55#define Q_GPIO_SUBTYPE_GPIOC_8CH 0xD
Michael Bohan6b901572012-05-30 13:32:24 -070056
57/* mpp peripheral type and subtype values */
Ashay Jaiswal1c61bd62014-01-22 10:29:11 +053058#define Q_MPP_TYPE 0x11
59#define Q_MPP_SUBTYPE_4CH_NO_ANA_OUT 0x3
60#define Q_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT 0x4
61#define Q_MPP_SUBTYPE_4CH_NO_SINK 0x5
62#define Q_MPP_SUBTYPE_ULT_4CH_NO_SINK 0x6
63#define Q_MPP_SUBTYPE_4CH_FULL_FUNC 0x7
64#define Q_MPP_SUBTYPE_8CH_FULL_FUNC 0xF
Michael Bohan0ba63b82012-02-06 13:42:34 -080065
66/* control register base address offsets */
Michael Bohane25e15f2012-04-12 17:28:26 -070067#define Q_REG_MODE_CTL 0x40
Michael Bohan6b901572012-05-30 13:32:24 -070068#define Q_REG_DIG_VIN_CTL 0x41
Michael Bohane25e15f2012-04-12 17:28:26 -070069#define Q_REG_DIG_PULL_CTL 0x42
70#define Q_REG_DIG_IN_CTL 0x43
Michael Bohane25e15f2012-04-12 17:28:26 -070071#define Q_REG_DIG_OUT_CTL 0x45
72#define Q_REG_EN_CTL 0x46
Michael Bohan6b901572012-05-30 13:32:24 -070073#define Q_REG_AOUT_CTL 0x48
74#define Q_REG_AIN_CTL 0x4A
75#define Q_REG_SINK_CTL 0x4C
Michael Bohan0ba63b82012-02-06 13:42:34 -080076
77/* control register regs array indices */
Michael Bohane25e15f2012-04-12 17:28:26 -070078#define Q_REG_I_MODE_CTL 0
Michael Bohan6b901572012-05-30 13:32:24 -070079#define Q_REG_I_DIG_VIN_CTL 1
Michael Bohane25e15f2012-04-12 17:28:26 -070080#define Q_REG_I_DIG_PULL_CTL 2
81#define Q_REG_I_DIG_IN_CTL 3
Michael Bohane25e15f2012-04-12 17:28:26 -070082#define Q_REG_I_DIG_OUT_CTL 5
83#define Q_REG_I_EN_CTL 6
Michael Bohan6b901572012-05-30 13:32:24 -070084#define Q_REG_I_AOUT_CTL 8
85#define Q_REG_I_AIN_CTL 10
86#define Q_REG_I_SINK_CTL 12
Michael Bohan0ba63b82012-02-06 13:42:34 -080087
Michael Bohane25e15f2012-04-12 17:28:26 -070088/* control reg: mode */
Michael Bohan0ba63b82012-02-06 13:42:34 -080089#define Q_REG_OUT_INVERT_SHIFT 0
90#define Q_REG_OUT_INVERT_MASK 0x1
91#define Q_REG_SRC_SEL_SHIFT 1
92#define Q_REG_SRC_SEL_MASK 0xE
Michael Bohane25e15f2012-04-12 17:28:26 -070093#define Q_REG_MODE_SEL_SHIFT 4
94#define Q_REG_MODE_SEL_MASK 0x70
95
96/* control reg: dig_vin */
97#define Q_REG_VIN_SHIFT 0
98#define Q_REG_VIN_MASK 0x7
99
100/* control reg: dig_pull */
101#define Q_REG_PULL_SHIFT 0
102#define Q_REG_PULL_MASK 0x7
103
104/* control reg: dig_out */
105#define Q_REG_OUT_STRENGTH_SHIFT 0
106#define Q_REG_OUT_STRENGTH_MASK 0x3
107#define Q_REG_OUT_TYPE_SHIFT 4
108#define Q_REG_OUT_TYPE_MASK 0x30
109
110/* control reg: en */
Michael Bohan0ba63b82012-02-06 13:42:34 -0800111#define Q_REG_MASTER_EN_SHIFT 7
112#define Q_REG_MASTER_EN_MASK 0x80
113
Michael Bohan6b901572012-05-30 13:32:24 -0700114/* control reg: ana_out */
115#define Q_REG_AOUT_REF_SHIFT 0
116#define Q_REG_AOUT_REF_MASK 0x7
117
118/* control reg: ana_in */
119#define Q_REG_AIN_ROUTE_SHIFT 0
120#define Q_REG_AIN_ROUTE_MASK 0x7
121
122/* control reg: sink */
123#define Q_REG_CS_OUT_SHIFT 0
124#define Q_REG_CS_OUT_MASK 0x7
125
Michael Bohana05f4552012-05-24 15:58:11 -0700126enum qpnp_pin_param_type {
Michael Bohan6b901572012-05-30 13:32:24 -0700127 Q_PIN_CFG_MODE,
Michael Bohana05f4552012-05-24 15:58:11 -0700128 Q_PIN_CFG_OUTPUT_TYPE,
129 Q_PIN_CFG_INVERT,
130 Q_PIN_CFG_PULL,
131 Q_PIN_CFG_VIN_SEL,
132 Q_PIN_CFG_OUT_STRENGTH,
Michael Bohand734fb22012-10-30 14:19:22 -0700133 Q_PIN_CFG_SRC_SEL,
Michael Bohana05f4552012-05-24 15:58:11 -0700134 Q_PIN_CFG_MASTER_EN,
Michael Bohan6b901572012-05-30 13:32:24 -0700135 Q_PIN_CFG_AOUT_REF,
136 Q_PIN_CFG_AIN_ROUTE,
137 Q_PIN_CFG_CS_OUT,
Michael Bohana05f4552012-05-24 15:58:11 -0700138 Q_PIN_CFG_INVALID,
Michael Bohana19dced2012-04-24 13:14:50 -0700139};
140
Michael Bohana05f4552012-05-24 15:58:11 -0700141#define Q_NUM_PARAMS Q_PIN_CFG_INVALID
Michael Bohana19dced2012-04-24 13:14:50 -0700142
Michael Bohane25e15f2012-04-12 17:28:26 -0700143/* param error checking */
Michael Bohan1c3d94f2012-08-11 14:33:03 -0700144#define QPNP_PIN_GPIO_MODE_INVALID 3
145#define QPNP_PIN_MPP_MODE_INVALID 7
Michael Bohana05f4552012-05-24 15:58:11 -0700146#define QPNP_PIN_INVERT_INVALID 2
147#define QPNP_PIN_OUT_BUF_INVALID 3
Michael Bohan6b901572012-05-30 13:32:24 -0700148#define QPNP_PIN_VIN_4CH_INVALID 5
149#define QPNP_PIN_VIN_8CH_INVALID 8
150#define QPNP_PIN_GPIO_PULL_INVALID 6
151#define QPNP_PIN_MPP_PULL_INVALID 4
Michael Bohana05f4552012-05-24 15:58:11 -0700152#define QPNP_PIN_OUT_STRENGTH_INVALID 4
153#define QPNP_PIN_SRC_INVALID 8
154#define QPNP_PIN_MASTER_INVALID 2
Michael Bohan6b901572012-05-30 13:32:24 -0700155#define QPNP_PIN_AOUT_REF_INVALID 8
156#define QPNP_PIN_AIN_ROUTE_INVALID 8
157#define QPNP_PIN_CS_OUT_INVALID 8
Michael Bohan0ba63b82012-02-06 13:42:34 -0800158
Michael Bohana05f4552012-05-24 15:58:11 -0700159struct qpnp_pin_spec {
Michael Bohan0ba63b82012-02-06 13:42:34 -0800160 uint8_t slave; /* 0-15 */
161 uint16_t offset; /* 0-255 */
162 uint32_t gpio_chip_idx; /* offset from gpio_chip base */
Michael Bohana05f4552012-05-24 15:58:11 -0700163 uint32_t pmic_pin; /* PMIC pin number */
Michael Bohan0ba63b82012-02-06 13:42:34 -0800164 int irq; /* logical IRQ number */
165 u8 regs[Q_NUM_CTL_REGS]; /* Control regs */
Michael Bohan6b901572012-05-30 13:32:24 -0700166 u8 num_ctl_regs; /* usable number on this pin */
Michael Bohane25e15f2012-04-12 17:28:26 -0700167 u8 type; /* peripheral type */
168 u8 subtype; /* peripheral subtype */
Michael Bohanbfe64c72012-08-24 16:57:26 -0700169 u8 dig_major_rev;
Michael Bohande3942a2012-04-17 15:28:01 -0700170 struct device_node *node;
Michael Bohana05f4552012-05-24 15:58:11 -0700171 enum qpnp_pin_param_type params[Q_NUM_PARAMS];
172 struct qpnp_pin_chip *q_chip;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800173};
174
Michael Bohana05f4552012-05-24 15:58:11 -0700175struct qpnp_pin_chip {
Michael Bohan0ba63b82012-02-06 13:42:34 -0800176 struct gpio_chip gpio_chip;
177 struct spmi_device *spmi;
Michael Bohana05f4552012-05-24 15:58:11 -0700178 struct qpnp_pin_spec **pmic_pins;
179 struct qpnp_pin_spec **chip_gpios;
180 uint32_t pmic_pin_lowest;
181 uint32_t pmic_pin_highest;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800182 struct device_node *int_ctrl;
183 struct list_head chip_list;
Michael Bohana19dced2012-04-24 13:14:50 -0700184 struct dentry *dfs_dir;
Ashay Jaiswala21fdd42014-02-25 13:53:19 +0530185 bool chip_registered;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800186};
187
Michael Bohana05f4552012-05-24 15:58:11 -0700188static LIST_HEAD(qpnp_pin_chips);
189static DEFINE_MUTEX(qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800190
Michael Bohana05f4552012-05-24 15:58:11 -0700191static inline void qpnp_pmic_pin_set_spec(struct qpnp_pin_chip *q_chip,
192 uint32_t pmic_pin,
193 struct qpnp_pin_spec *spec)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800194{
Michael Bohana05f4552012-05-24 15:58:11 -0700195 q_chip->pmic_pins[pmic_pin - q_chip->pmic_pin_lowest] = spec;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800196}
197
Michael Bohana05f4552012-05-24 15:58:11 -0700198static inline struct qpnp_pin_spec *qpnp_pmic_pin_get_spec(
199 struct qpnp_pin_chip *q_chip,
200 uint32_t pmic_pin)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800201{
Michael Bohana05f4552012-05-24 15:58:11 -0700202 if (pmic_pin < q_chip->pmic_pin_lowest ||
203 pmic_pin > q_chip->pmic_pin_highest)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800204 return NULL;
205
Michael Bohana05f4552012-05-24 15:58:11 -0700206 return q_chip->pmic_pins[pmic_pin - q_chip->pmic_pin_lowest];
Michael Bohan0ba63b82012-02-06 13:42:34 -0800207}
208
Michael Bohana05f4552012-05-24 15:58:11 -0700209static inline struct qpnp_pin_spec *qpnp_chip_gpio_get_spec(
210 struct qpnp_pin_chip *q_chip,
Michael Bohan0ba63b82012-02-06 13:42:34 -0800211 uint32_t chip_gpio)
212{
213 if (chip_gpio > q_chip->gpio_chip.ngpio)
214 return NULL;
215
216 return q_chip->chip_gpios[chip_gpio];
217}
218
Michael Bohana05f4552012-05-24 15:58:11 -0700219static inline void qpnp_chip_gpio_set_spec(struct qpnp_pin_chip *q_chip,
Michael Bohan0ba63b82012-02-06 13:42:34 -0800220 uint32_t chip_gpio,
Michael Bohana05f4552012-05-24 15:58:11 -0700221 struct qpnp_pin_spec *spec)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800222{
223 q_chip->chip_gpios[chip_gpio] = spec;
224}
225
Michael Bohan58d07802012-05-31 15:37:55 -0700226/*
227 * Determines whether a specified param's configuration is correct.
228 * This check is two tier. First a check is done whether the hardware
229 * supports this param and value requested. The second check validates
230 * that the configuration is correct, given the fact that the hardware
231 * supports it.
232 *
233 * Returns
Michael Bohan6b901572012-05-30 13:32:24 -0700234 * -ENXIO is the hardware does not support this param.
235 * -EINVAL if the the hardware does support this param, but the
236 * requested value is outside the supported range.
Michael Bohan58d07802012-05-31 15:37:55 -0700237 */
238static int qpnp_pin_check_config(enum qpnp_pin_param_type idx,
239 struct qpnp_pin_spec *q_spec, uint32_t val)
240{
Ashay Jaiswal1c61bd62014-01-22 10:29:11 +0530241 u8 subtype = q_spec->subtype;
242
Michael Bohan58d07802012-05-31 15:37:55 -0700243 switch (idx) {
Michael Bohan6b901572012-05-30 13:32:24 -0700244 case Q_PIN_CFG_MODE:
Michael Bohan1c3d94f2012-08-11 14:33:03 -0700245 if (q_spec->type == Q_GPIO_TYPE &&
246 val >= QPNP_PIN_GPIO_MODE_INVALID)
247 return -EINVAL;
Ashay Jaiswal1c61bd62014-01-22 10:29:11 +0530248 else if (q_spec->type == Q_MPP_TYPE) {
249 if (val >= QPNP_PIN_MPP_MODE_INVALID)
Michael Bohan1c3d94f2012-08-11 14:33:03 -0700250 return -EINVAL;
Ashay Jaiswal1c61bd62014-01-22 10:29:11 +0530251 if ((subtype == Q_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT ||
252 subtype == Q_MPP_SUBTYPE_ULT_4CH_NO_SINK) &&
253 (val == QPNP_PIN_MODE_BIDIR))
254 return -ENXIO;
255 }
Michael Bohan58d07802012-05-31 15:37:55 -0700256 break;
257 case Q_PIN_CFG_OUTPUT_TYPE:
Michael Bohan6b901572012-05-30 13:32:24 -0700258 if (q_spec->type != Q_GPIO_TYPE)
Michael Bohan58d07802012-05-31 15:37:55 -0700259 return -ENXIO;
Michael Bohan6b901572012-05-30 13:32:24 -0700260 if ((val == QPNP_PIN_OUT_BUF_OPEN_DRAIN_NMOS ||
261 val == QPNP_PIN_OUT_BUF_OPEN_DRAIN_PMOS) &&
Ashay Jaiswal1c61bd62014-01-22 10:29:11 +0530262 (subtype == Q_GPIO_SUBTYPE_GPIOC_4CH ||
263 (subtype == Q_GPIO_SUBTYPE_GPIOC_8CH)))
Michael Bohan6b901572012-05-30 13:32:24 -0700264 return -EINVAL;
Michael Bohan58d07802012-05-31 15:37:55 -0700265 else if (val >= QPNP_PIN_OUT_BUF_INVALID)
266 return -EINVAL;
267 break;
268 case Q_PIN_CFG_INVERT:
269 if (val >= QPNP_PIN_INVERT_INVALID)
270 return -EINVAL;
271 break;
272 case Q_PIN_CFG_PULL:
Michael Bohan6b901572012-05-30 13:32:24 -0700273 if (q_spec->type == Q_GPIO_TYPE &&
274 val >= QPNP_PIN_GPIO_PULL_INVALID)
275 return -EINVAL;
Ashay Jaiswal1c61bd62014-01-22 10:29:11 +0530276 if (q_spec->type == Q_MPP_TYPE) {
277 if (val >= QPNP_PIN_MPP_PULL_INVALID)
278 return -EINVAL;
279 if (subtype == Q_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT ||
280 subtype == Q_MPP_SUBTYPE_ULT_4CH_NO_SINK)
281 return -ENXIO;
282 }
Michael Bohan58d07802012-05-31 15:37:55 -0700283 break;
284 case Q_PIN_CFG_VIN_SEL:
Michael Bohan6b901572012-05-30 13:32:24 -0700285 if (val >= QPNP_PIN_VIN_8CH_INVALID)
Michael Bohan58d07802012-05-31 15:37:55 -0700286 return -EINVAL;
Michael Bohan6b901572012-05-30 13:32:24 -0700287 else if (val >= QPNP_PIN_VIN_4CH_INVALID) {
288 if (q_spec->type == Q_GPIO_TYPE &&
Ashay Jaiswal1c61bd62014-01-22 10:29:11 +0530289 (subtype == Q_GPIO_SUBTYPE_GPIO_4CH ||
290 subtype == Q_GPIO_SUBTYPE_GPIOC_4CH))
Michael Bohan6b901572012-05-30 13:32:24 -0700291 return -EINVAL;
292 if (q_spec->type == Q_MPP_TYPE &&
Ashay Jaiswal1c61bd62014-01-22 10:29:11 +0530293 (subtype == Q_MPP_SUBTYPE_4CH_NO_ANA_OUT ||
294 subtype == Q_MPP_SUBTYPE_4CH_NO_SINK ||
295 subtype == Q_MPP_SUBTYPE_4CH_FULL_FUNC ||
296 subtype == Q_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT ||
297 subtype == Q_MPP_SUBTYPE_ULT_4CH_NO_SINK))
Michael Bohan6b901572012-05-30 13:32:24 -0700298 return -EINVAL;
299 }
Michael Bohan58d07802012-05-31 15:37:55 -0700300 break;
301 case Q_PIN_CFG_OUT_STRENGTH:
Michael Bohan6b901572012-05-30 13:32:24 -0700302 if (q_spec->type != Q_GPIO_TYPE)
303 return -ENXIO;
Michael Bohan58d07802012-05-31 15:37:55 -0700304 if (val >= QPNP_PIN_OUT_STRENGTH_INVALID ||
305 val == 0)
306 return -EINVAL;
307 break;
Michael Bohand734fb22012-10-30 14:19:22 -0700308 case Q_PIN_CFG_SRC_SEL:
Michael Bohan6b901572012-05-30 13:32:24 -0700309 if (q_spec->type == Q_MPP_TYPE &&
310 (val == QPNP_PIN_SEL_FUNC_1 ||
311 val == QPNP_PIN_SEL_FUNC_2))
312 return -EINVAL;
Michael Bohan58d07802012-05-31 15:37:55 -0700313 if (val >= QPNP_PIN_SRC_INVALID)
314 return -EINVAL;
315 break;
316 case Q_PIN_CFG_MASTER_EN:
317 if (val >= QPNP_PIN_MASTER_INVALID)
318 return -EINVAL;
319 break;
Michael Bohan6b901572012-05-30 13:32:24 -0700320 case Q_PIN_CFG_AOUT_REF:
321 if (q_spec->type != Q_MPP_TYPE)
322 return -ENXIO;
Ashay Jaiswal1c61bd62014-01-22 10:29:11 +0530323 if (subtype == Q_MPP_SUBTYPE_4CH_NO_ANA_OUT ||
324 subtype == Q_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT)
Michael Bohan6b901572012-05-30 13:32:24 -0700325 return -ENXIO;
326 if (val >= QPNP_PIN_AOUT_REF_INVALID)
327 return -EINVAL;
328 break;
329 case Q_PIN_CFG_AIN_ROUTE:
330 if (q_spec->type != Q_MPP_TYPE)
331 return -ENXIO;
332 if (val >= QPNP_PIN_AIN_ROUTE_INVALID)
333 return -EINVAL;
334 break;
335 case Q_PIN_CFG_CS_OUT:
336 if (q_spec->type != Q_MPP_TYPE)
337 return -ENXIO;
Ashay Jaiswal1c61bd62014-01-22 10:29:11 +0530338 if (subtype == Q_MPP_SUBTYPE_4CH_NO_SINK ||
339 subtype == Q_MPP_SUBTYPE_ULT_4CH_NO_SINK)
Michael Bohan6b901572012-05-30 13:32:24 -0700340 return -ENXIO;
341 if (val >= QPNP_PIN_CS_OUT_INVALID)
342 return -EINVAL;
343 break;
344
Michael Bohan58d07802012-05-31 15:37:55 -0700345 default:
346 pr_err("invalid param type %u specified\n", idx);
347 return -EINVAL;
348 }
349 return 0;
350}
351
352#define Q_CHK_INVALID(idx, q_spec, val) \
353 (qpnp_pin_check_config(idx, q_spec, val) == -EINVAL)
354
355static int qpnp_pin_check_constraints(struct qpnp_pin_spec *q_spec,
356 struct qpnp_pin_cfg *param)
Michael Bohane25e15f2012-04-12 17:28:26 -0700357{
Michael Bohan6b901572012-05-30 13:32:24 -0700358 int pin = q_spec->pmic_pin;
359 const char *name;
Michael Bohane25e15f2012-04-12 17:28:26 -0700360
Michael Bohan6b901572012-05-30 13:32:24 -0700361 name = (q_spec->type == Q_GPIO_TYPE) ? "gpio" : "mpp";
362
363 if (Q_CHK_INVALID(Q_PIN_CFG_MODE, q_spec, param->mode))
Michael Bohan91c5a042012-08-11 13:29:42 -0700364 pr_err("invalid direction value %d for %s %d\n",
365 param->mode, name, pin);
Michael Bohan58d07802012-05-31 15:37:55 -0700366 else if (Q_CHK_INVALID(Q_PIN_CFG_INVERT, q_spec, param->invert))
Michael Bohan91c5a042012-08-11 13:29:42 -0700367 pr_err("invalid invert polarity value %d for %s %d\n",
368 param->invert, name, pin);
Michael Bohand734fb22012-10-30 14:19:22 -0700369 else if (Q_CHK_INVALID(Q_PIN_CFG_SRC_SEL, q_spec, param->src_sel))
Michael Bohan91c5a042012-08-11 13:29:42 -0700370 pr_err("invalid source select value %d for %s %d\n",
Michael Bohand734fb22012-10-30 14:19:22 -0700371 param->src_sel, name, pin);
Michael Bohan58d07802012-05-31 15:37:55 -0700372 else if (Q_CHK_INVALID(Q_PIN_CFG_OUT_STRENGTH,
373 q_spec, param->out_strength))
Michael Bohan91c5a042012-08-11 13:29:42 -0700374 pr_err("invalid out strength value %d for %s %d\n",
375 param->out_strength, name, pin);
Michael Bohan58d07802012-05-31 15:37:55 -0700376 else if (Q_CHK_INVALID(Q_PIN_CFG_OUTPUT_TYPE,
377 q_spec, param->output_type))
Michael Bohan91c5a042012-08-11 13:29:42 -0700378 pr_err("invalid out type value %d for %s %d\n",
379 param->output_type, name, pin);
Michael Bohan58d07802012-05-31 15:37:55 -0700380 else if (Q_CHK_INVALID(Q_PIN_CFG_VIN_SEL, q_spec, param->vin_sel))
Michael Bohan91c5a042012-08-11 13:29:42 -0700381 pr_err("invalid vin select %d value for %s %d\n",
382 param->vin_sel, name, pin);
Michael Bohan58d07802012-05-31 15:37:55 -0700383 else if (Q_CHK_INVALID(Q_PIN_CFG_PULL, q_spec, param->pull))
Michael Bohan91c5a042012-08-11 13:29:42 -0700384 pr_err("invalid pull value %d for pin %s %d\n",
385 param->pull, name, pin);
Michael Bohan58d07802012-05-31 15:37:55 -0700386 else if (Q_CHK_INVALID(Q_PIN_CFG_MASTER_EN, q_spec, param->master_en))
Michael Bohan91c5a042012-08-11 13:29:42 -0700387 pr_err("invalid master_en value %d for %s %d\n",
388 param->master_en, name, pin);
Michael Bohan6b901572012-05-30 13:32:24 -0700389 else if (Q_CHK_INVALID(Q_PIN_CFG_AOUT_REF, q_spec, param->aout_ref))
Michael Bohan91c5a042012-08-11 13:29:42 -0700390 pr_err("invalid aout_reg value %d for %s %d\n",
391 param->aout_ref, name, pin);
Michael Bohan6b901572012-05-30 13:32:24 -0700392 else if (Q_CHK_INVALID(Q_PIN_CFG_AIN_ROUTE, q_spec, param->ain_route))
Michael Bohan91c5a042012-08-11 13:29:42 -0700393 pr_err("invalid ain_route value %d for %s %d\n",
394 param->ain_route, name, pin);
Michael Bohan6b901572012-05-30 13:32:24 -0700395 else if (Q_CHK_INVALID(Q_PIN_CFG_CS_OUT, q_spec, param->cs_out))
Michael Bohan91c5a042012-08-11 13:29:42 -0700396 pr_err("invalid cs_out value %d for %s %d\n",
397 param->cs_out, name, pin);
Michael Bohane25e15f2012-04-12 17:28:26 -0700398 else
399 return 0;
400
401 return -EINVAL;
402}
403
Michael Bohande3942a2012-04-17 15:28:01 -0700404static inline u8 q_reg_get(u8 *reg, int shift, int mask)
405{
406 return (*reg & mask) >> shift;
407}
408
Michael Bohane25e15f2012-04-12 17:28:26 -0700409static inline void q_reg_set(u8 *reg, int shift, int mask, int value)
410{
411 *reg |= (value << shift) & mask;
412}
413
414static inline void q_reg_clr_set(u8 *reg, int shift, int mask, int value)
415{
416 *reg &= ~mask;
417 *reg |= (value << shift) & mask;
418}
419
Michael Bohan6b901572012-05-30 13:32:24 -0700420/*
421 * Calculate the minimum number of registers that must be read / written
422 * in order to satisfy the full feature set of the given pin.
423 */
424static int qpnp_pin_ctl_regs_init(struct qpnp_pin_spec *q_spec)
425{
426 if (q_spec->type == Q_GPIO_TYPE)
427 q_spec->num_ctl_regs = 7;
428 else if (q_spec->type == Q_MPP_TYPE)
429 switch (q_spec->subtype) {
430 case Q_MPP_SUBTYPE_4CH_NO_SINK:
Ashay Jaiswal1c61bd62014-01-22 10:29:11 +0530431 case Q_MPP_SUBTYPE_ULT_4CH_NO_SINK:
Michael Bohan6b901572012-05-30 13:32:24 -0700432 q_spec->num_ctl_regs = 12;
433 break;
434 case Q_MPP_SUBTYPE_4CH_NO_ANA_OUT:
Ashay Jaiswal1c61bd62014-01-22 10:29:11 +0530435 case Q_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT:
Michael Bohan6b901572012-05-30 13:32:24 -0700436 case Q_MPP_SUBTYPE_4CH_FULL_FUNC:
437 case Q_MPP_SUBTYPE_8CH_FULL_FUNC:
438 q_spec->num_ctl_regs = 13;
439 break;
440 default:
441 pr_err("Invalid MPP subtype 0x%x\n", q_spec->subtype);
442 return -EINVAL;
443 }
444 else {
445 pr_err("Invalid type 0x%x\n", q_spec->type);
446 return -EINVAL;
447 }
448 return 0;
449}
450
451static int qpnp_pin_read_regs(struct qpnp_pin_chip *q_chip,
Michael Bohand3cf9b02012-08-15 23:23:52 -0700452 struct qpnp_pin_spec *q_spec)
Michael Bohan6b901572012-05-30 13:32:24 -0700453{
454 int bytes_left = q_spec->num_ctl_regs;
455 int rc;
Michael Bohand3cf9b02012-08-15 23:23:52 -0700456 char *buf_p = &q_spec->regs[0];
457 u16 reg_addr = Q_REG_ADDR(q_spec, Q_REG_MODE_CTL);
Michael Bohan6b901572012-05-30 13:32:24 -0700458
459 while (bytes_left > 0) {
460 rc = spmi_ext_register_readl(q_chip->spmi->ctrl, q_spec->slave,
Michael Bohand3cf9b02012-08-15 23:23:52 -0700461 reg_addr, buf_p, bytes_left < 8 ? bytes_left : 8);
Michael Bohan6b901572012-05-30 13:32:24 -0700462 if (rc)
463 return rc;
464 bytes_left -= 8;
Michael Bohand3cf9b02012-08-15 23:23:52 -0700465 buf_p += 8;
466 reg_addr += 8;
Michael Bohan6b901572012-05-30 13:32:24 -0700467 }
468 return 0;
469}
470
471static int qpnp_pin_write_regs(struct qpnp_pin_chip *q_chip,
Michael Bohand3cf9b02012-08-15 23:23:52 -0700472 struct qpnp_pin_spec *q_spec)
Michael Bohan6b901572012-05-30 13:32:24 -0700473{
474 int bytes_left = q_spec->num_ctl_regs;
475 int rc;
Michael Bohand3cf9b02012-08-15 23:23:52 -0700476 char *buf_p = &q_spec->regs[0];
477 u16 reg_addr = Q_REG_ADDR(q_spec, Q_REG_MODE_CTL);
Michael Bohan6b901572012-05-30 13:32:24 -0700478
479 while (bytes_left > 0) {
480 rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
Michael Bohand3cf9b02012-08-15 23:23:52 -0700481 reg_addr, buf_p, bytes_left < 8 ? bytes_left : 8);
Michael Bohan6b901572012-05-30 13:32:24 -0700482 if (rc)
483 return rc;
484 bytes_left -= 8;
Michael Bohand3cf9b02012-08-15 23:23:52 -0700485 buf_p += 8;
486 reg_addr += 8;
Michael Bohan6b901572012-05-30 13:32:24 -0700487 }
488 return 0;
489}
490
Michael Bohana05f4552012-05-24 15:58:11 -0700491static int qpnp_pin_cache_regs(struct qpnp_pin_chip *q_chip,
Michael Bohan6b901572012-05-30 13:32:24 -0700492 struct qpnp_pin_spec *q_spec)
Michael Bohande3942a2012-04-17 15:28:01 -0700493{
494 int rc;
495 struct device *dev = &q_chip->spmi->dev;
496
Michael Bohand3cf9b02012-08-15 23:23:52 -0700497 rc = qpnp_pin_read_regs(q_chip, q_spec);
Michael Bohande3942a2012-04-17 15:28:01 -0700498 if (rc)
499 dev_err(dev, "%s: unable to read control regs\n", __func__);
500
501 return rc;
502}
503
Michael Bohan58d07802012-05-31 15:37:55 -0700504#define Q_HAVE_HW_SP(idx, q_spec, val) \
505 (qpnp_pin_check_config(idx, q_spec, val) == 0)
506
Michael Bohana05f4552012-05-24 15:58:11 -0700507static int _qpnp_pin_config(struct qpnp_pin_chip *q_chip,
Michael Bohan6b901572012-05-30 13:32:24 -0700508 struct qpnp_pin_spec *q_spec,
509 struct qpnp_pin_cfg *param)
Michael Bohane25e15f2012-04-12 17:28:26 -0700510{
511 struct device *dev = &q_chip->spmi->dev;
512 int rc;
513
Michael Bohan58d07802012-05-31 15:37:55 -0700514 rc = qpnp_pin_check_constraints(q_spec, param);
Michael Bohane25e15f2012-04-12 17:28:26 -0700515 if (rc)
516 goto gpio_cfg;
517
Michael Bohan6b901572012-05-30 13:32:24 -0700518 /* set mode */
519 if (Q_HAVE_HW_SP(Q_PIN_CFG_MODE, q_spec, param->mode))
Michael Bohan58d07802012-05-31 15:37:55 -0700520 q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700521 Q_REG_MODE_SEL_SHIFT, Q_REG_MODE_SEL_MASK,
Michael Bohan6b901572012-05-30 13:32:24 -0700522 param->mode);
Michael Bohane25e15f2012-04-12 17:28:26 -0700523
524 /* output specific configuration */
Michael Bohan58d07802012-05-31 15:37:55 -0700525 if (Q_HAVE_HW_SP(Q_PIN_CFG_INVERT, q_spec, param->invert))
526 q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700527 Q_REG_OUT_INVERT_SHIFT, Q_REG_OUT_INVERT_MASK,
528 param->invert);
Michael Bohand734fb22012-10-30 14:19:22 -0700529 if (Q_HAVE_HW_SP(Q_PIN_CFG_SRC_SEL, q_spec, param->src_sel))
Michael Bohan58d07802012-05-31 15:37:55 -0700530 q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700531 Q_REG_SRC_SEL_SHIFT, Q_REG_SRC_SEL_MASK,
Michael Bohand734fb22012-10-30 14:19:22 -0700532 param->src_sel);
Michael Bohan58d07802012-05-31 15:37:55 -0700533 if (Q_HAVE_HW_SP(Q_PIN_CFG_OUT_STRENGTH, q_spec, param->out_strength))
534 q_reg_clr_set(&q_spec->regs[Q_REG_I_DIG_OUT_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700535 Q_REG_OUT_STRENGTH_SHIFT, Q_REG_OUT_STRENGTH_MASK,
536 param->out_strength);
Michael Bohan58d07802012-05-31 15:37:55 -0700537 if (Q_HAVE_HW_SP(Q_PIN_CFG_OUTPUT_TYPE, q_spec, param->output_type))
538 q_reg_clr_set(&q_spec->regs[Q_REG_I_DIG_OUT_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700539 Q_REG_OUT_TYPE_SHIFT, Q_REG_OUT_TYPE_MASK,
540 param->output_type);
541
542 /* config applicable for both input / output */
Michael Bohan58d07802012-05-31 15:37:55 -0700543 if (Q_HAVE_HW_SP(Q_PIN_CFG_VIN_SEL, q_spec, param->vin_sel))
544 q_reg_clr_set(&q_spec->regs[Q_REG_I_DIG_VIN_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700545 Q_REG_VIN_SHIFT, Q_REG_VIN_MASK,
546 param->vin_sel);
Michael Bohan58d07802012-05-31 15:37:55 -0700547 if (Q_HAVE_HW_SP(Q_PIN_CFG_PULL, q_spec, param->pull))
548 q_reg_clr_set(&q_spec->regs[Q_REG_I_DIG_PULL_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700549 Q_REG_PULL_SHIFT, Q_REG_PULL_MASK,
550 param->pull);
Michael Bohan58d07802012-05-31 15:37:55 -0700551 if (Q_HAVE_HW_SP(Q_PIN_CFG_MASTER_EN, q_spec, param->master_en))
552 q_reg_clr_set(&q_spec->regs[Q_REG_I_EN_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700553 Q_REG_MASTER_EN_SHIFT, Q_REG_MASTER_EN_MASK,
554 param->master_en);
555
Michael Bohan6b901572012-05-30 13:32:24 -0700556 /* mpp specific config */
557 if (Q_HAVE_HW_SP(Q_PIN_CFG_AOUT_REF, q_spec, param->aout_ref))
558 q_reg_clr_set(&q_spec->regs[Q_REG_I_AOUT_CTL],
559 Q_REG_AOUT_REF_SHIFT, Q_REG_AOUT_REF_MASK,
560 param->aout_ref);
561 if (Q_HAVE_HW_SP(Q_PIN_CFG_AIN_ROUTE, q_spec, param->ain_route))
562 q_reg_clr_set(&q_spec->regs[Q_REG_I_AIN_CTL],
563 Q_REG_AIN_ROUTE_SHIFT, Q_REG_AIN_ROUTE_MASK,
564 param->ain_route);
565 if (Q_HAVE_HW_SP(Q_PIN_CFG_CS_OUT, q_spec, param->cs_out))
566 q_reg_clr_set(&q_spec->regs[Q_REG_I_SINK_CTL],
567 Q_REG_CS_OUT_SHIFT, Q_REG_CS_OUT_MASK,
568 param->cs_out);
569
Michael Bohand3cf9b02012-08-15 23:23:52 -0700570 rc = qpnp_pin_write_regs(q_chip, q_spec);
Michael Bohane25e15f2012-04-12 17:28:26 -0700571 if (rc) {
Michael Bohan6ea2cd22012-05-29 15:40:18 -0700572 dev_err(&q_chip->spmi->dev, "%s: unable to write master enable\n",
573 __func__);
Michael Bohane25e15f2012-04-12 17:28:26 -0700574 goto gpio_cfg;
575 }
576
577 return 0;
578
579gpio_cfg:
Michael Bohan91c5a042012-08-11 13:29:42 -0700580 dev_err(dev, "%s: unable to set default config for pmic pin %d\n",
Michael Bohana05f4552012-05-24 15:58:11 -0700581 __func__, q_spec->pmic_pin);
Michael Bohane25e15f2012-04-12 17:28:26 -0700582
583 return rc;
584}
585
Michael Bohana05f4552012-05-24 15:58:11 -0700586int qpnp_pin_config(int gpio, struct qpnp_pin_cfg *param)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800587{
588 int rc, chip_offset;
Michael Bohana05f4552012-05-24 15:58:11 -0700589 struct qpnp_pin_chip *q_chip;
590 struct qpnp_pin_spec *q_spec = NULL;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800591 struct gpio_chip *gpio_chip;
592
593 if (param == NULL)
594 return -EINVAL;
595
Michael Bohana05f4552012-05-24 15:58:11 -0700596 mutex_lock(&qpnp_pin_chips_lock);
597 list_for_each_entry(q_chip, &qpnp_pin_chips, chip_list) {
Michael Bohan0ba63b82012-02-06 13:42:34 -0800598 gpio_chip = &q_chip->gpio_chip;
599 if (gpio >= gpio_chip->base
600 && gpio < gpio_chip->base + gpio_chip->ngpio) {
601 chip_offset = gpio - gpio_chip->base;
602 q_spec = qpnp_chip_gpio_get_spec(q_chip, chip_offset);
603 if (WARN_ON(!q_spec)) {
Michael Bohana05f4552012-05-24 15:58:11 -0700604 mutex_unlock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800605 return -ENODEV;
606 }
607 break;
608 }
609 }
Michael Bohana05f4552012-05-24 15:58:11 -0700610 mutex_unlock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800611
Zhenhua Huang30acf242013-07-11 01:52:36 +0800612 if (!q_spec)
613 return -ENODEV;
614
Michael Bohana05f4552012-05-24 15:58:11 -0700615 rc = _qpnp_pin_config(q_chip, q_spec, param);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800616
617 return rc;
618}
Michael Bohana05f4552012-05-24 15:58:11 -0700619EXPORT_SYMBOL(qpnp_pin_config);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800620
Michael Bohan6ea2cd22012-05-29 15:40:18 -0700621#define Q_MAX_CHIP_NAME 128
622int qpnp_pin_map(const char *name, uint32_t pmic_pin)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800623{
Michael Bohana05f4552012-05-24 15:58:11 -0700624 struct qpnp_pin_chip *q_chip;
625 struct qpnp_pin_spec *q_spec = NULL;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800626
Michael Bohana05f4552012-05-24 15:58:11 -0700627 mutex_lock(&qpnp_pin_chips_lock);
628 list_for_each_entry(q_chip, &qpnp_pin_chips, chip_list) {
Michael Bohan6ea2cd22012-05-29 15:40:18 -0700629 if (strncmp(q_chip->gpio_chip.label, name,
630 Q_MAX_CHIP_NAME) != 0)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800631 continue;
Michael Bohana05f4552012-05-24 15:58:11 -0700632 if (q_chip->pmic_pin_lowest <= pmic_pin &&
633 q_chip->pmic_pin_highest >= pmic_pin) {
634 q_spec = qpnp_pmic_pin_get_spec(q_chip, pmic_pin);
635 mutex_unlock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800636 if (WARN_ON(!q_spec))
637 return -ENODEV;
638 return q_chip->gpio_chip.base + q_spec->gpio_chip_idx;
639 }
640 }
Michael Bohana05f4552012-05-24 15:58:11 -0700641 mutex_unlock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800642 return -EINVAL;
643}
Michael Bohana05f4552012-05-24 15:58:11 -0700644EXPORT_SYMBOL(qpnp_pin_map);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800645
Michael Bohana05f4552012-05-24 15:58:11 -0700646static int qpnp_pin_to_irq(struct gpio_chip *gpio_chip, unsigned offset)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800647{
Michael Bohana05f4552012-05-24 15:58:11 -0700648 struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
649 struct qpnp_pin_spec *q_spec;
Abhijeet Dharmapurikarea799552014-01-08 20:16:37 -0800650 u32 intspec[3];
Michael Bohan0ba63b82012-02-06 13:42:34 -0800651
652 q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
653 if (!q_spec)
654 return -EINVAL;
655
Abhijeet Dharmapurikarea799552014-01-08 20:16:37 -0800656 /* if we have mapped this pin previously return the virq */
657 if (q_spec->irq)
658 return q_spec->irq;
659
660 /* call into irq_domain to get irq mapping */
661 intspec[0] = q_chip->spmi->sid;
662 intspec[1] = (q_spec->offset >> 8) & 0xFF;
663 intspec[2] = 0;
664 q_spec->irq = irq_create_of_mapping(q_chip->int_ctrl, intspec, 3);
665 if (!q_spec->irq) {
666 dev_err(&q_chip->spmi->dev, "%s: invalid irq for gpio %u\n",
667 __func__, q_spec->pmic_pin);
668 WARN_ON(1);
669 return -EINVAL;
670 }
671
Michael Bohan0ba63b82012-02-06 13:42:34 -0800672 return q_spec->irq;
673}
674
Michael Bohana05f4552012-05-24 15:58:11 -0700675static int qpnp_pin_get(struct gpio_chip *gpio_chip, unsigned offset)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800676{
677 int rc, ret_val;
Michael Bohana05f4552012-05-24 15:58:11 -0700678 struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
679 struct qpnp_pin_spec *q_spec = NULL;
Michael Bohanffa16812012-08-15 18:11:49 -0700680 u8 buf[1], en_mask;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800681
682 if (WARN_ON(!q_chip))
683 return -ENODEV;
684
685 q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
686 if (WARN_ON(!q_spec))
687 return -ENODEV;
688
689 /* gpio val is from RT status iff input is enabled */
Michael Bohane25e15f2012-04-12 17:28:26 -0700690 if ((q_spec->regs[Q_REG_I_MODE_CTL] & Q_REG_MODE_SEL_MASK)
Michael Bohan6b901572012-05-30 13:32:24 -0700691 == QPNP_PIN_MODE_DIG_IN) {
Michael Bohan0ba63b82012-02-06 13:42:34 -0800692 rc = spmi_ext_register_readl(q_chip->spmi->ctrl, q_spec->slave,
693 Q_REG_ADDR(q_spec, Q_REG_STATUS1),
694 &buf[0], 1);
Michael Bohanffa16812012-08-15 18:11:49 -0700695
Michael Bohanbfe64c72012-08-24 16:57:26 -0700696 if (q_spec->type == Q_GPIO_TYPE && q_spec->dig_major_rev == 0)
697 en_mask = Q_REG_STATUS1_GPIO_EN_REV0_MASK;
698 else if (q_spec->type == Q_GPIO_TYPE &&
699 q_spec->dig_major_rev > 0)
700 en_mask = Q_REG_STATUS1_GPIO_EN_MASK;
701 else /* MPP */
702 en_mask = Q_REG_STATUS1_MPP_EN_MASK;
703
Michael Bohanffa16812012-08-15 18:11:49 -0700704 if (!(buf[0] & en_mask))
705 return -EPERM;
706
707 return buf[0] & Q_REG_STATUS1_VAL_MASK;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800708
709 } else {
Michael Bohane25e15f2012-04-12 17:28:26 -0700710 ret_val = (q_spec->regs[Q_REG_I_MODE_CTL] &
Michael Bohan0ba63b82012-02-06 13:42:34 -0800711 Q_REG_OUT_INVERT_MASK) >> Q_REG_OUT_INVERT_SHIFT;
712 return ret_val;
713 }
714
715 return 0;
716}
717
Michael Bohana05f4552012-05-24 15:58:11 -0700718static int __qpnp_pin_set(struct qpnp_pin_chip *q_chip,
719 struct qpnp_pin_spec *q_spec, int value)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800720{
721 int rc;
722
723 if (!q_chip || !q_spec)
724 return -EINVAL;
725
Michael Bohan0ba63b82012-02-06 13:42:34 -0800726 if (value)
Michael Bohane25e15f2012-04-12 17:28:26 -0700727 q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
728 Q_REG_OUT_INVERT_SHIFT, Q_REG_OUT_INVERT_MASK, 1);
729 else
730 q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
731 Q_REG_OUT_INVERT_SHIFT, Q_REG_OUT_INVERT_MASK, 0);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800732
733 rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
Michael Bohand3cf9b02012-08-15 23:23:52 -0700734 Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
Michael Bohane25e15f2012-04-12 17:28:26 -0700735 &q_spec->regs[Q_REG_I_MODE_CTL], 1);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800736 if (rc)
737 dev_err(&q_chip->spmi->dev, "%s: spmi write failed\n",
738 __func__);
739 return rc;
740}
741
742
Michael Bohana05f4552012-05-24 15:58:11 -0700743static void qpnp_pin_set(struct gpio_chip *gpio_chip,
Michael Bohan0ba63b82012-02-06 13:42:34 -0800744 unsigned offset, int value)
745{
Michael Bohana05f4552012-05-24 15:58:11 -0700746 struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
747 struct qpnp_pin_spec *q_spec;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800748
749 if (WARN_ON(!q_chip))
750 return;
751
752 q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
753 if (WARN_ON(!q_spec))
754 return;
755
Michael Bohana05f4552012-05-24 15:58:11 -0700756 __qpnp_pin_set(q_chip, q_spec, value);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800757}
758
Michael Bohan6b901572012-05-30 13:32:24 -0700759static int qpnp_pin_set_mode(struct qpnp_pin_chip *q_chip,
760 struct qpnp_pin_spec *q_spec, int mode)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800761{
762 int rc;
763
764 if (!q_chip || !q_spec)
765 return -EINVAL;
766
Michael Bohan1c3d94f2012-08-11 14:33:03 -0700767 if (qpnp_pin_check_config(Q_PIN_CFG_MODE, q_spec, mode)) {
Michael Bohan6b901572012-05-30 13:32:24 -0700768 pr_err("invalid mode specification %d\n", mode);
Michael Bohane25e15f2012-04-12 17:28:26 -0700769 return -EINVAL;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800770 }
771
Michael Bohane25e15f2012-04-12 17:28:26 -0700772 q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
773 Q_REG_MODE_SEL_SHIFT,
774 Q_REG_MODE_SEL_MASK,
Michael Bohan6b901572012-05-30 13:32:24 -0700775 mode);
Michael Bohane25e15f2012-04-12 17:28:26 -0700776
Michael Bohan0ba63b82012-02-06 13:42:34 -0800777 rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
Michael Bohand3cf9b02012-08-15 23:23:52 -0700778 Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
Michael Bohane25e15f2012-04-12 17:28:26 -0700779 &q_spec->regs[Q_REG_I_MODE_CTL], 1);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800780 return rc;
781}
782
Michael Bohana05f4552012-05-24 15:58:11 -0700783static int qpnp_pin_direction_input(struct gpio_chip *gpio_chip,
Michael Bohan0ba63b82012-02-06 13:42:34 -0800784 unsigned offset)
785{
Michael Bohana05f4552012-05-24 15:58:11 -0700786 struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
787 struct qpnp_pin_spec *q_spec;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800788
789 if (WARN_ON(!q_chip))
790 return -ENODEV;
791
792 q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
793 if (WARN_ON(!q_spec))
794 return -ENODEV;
795
Michael Bohan6b901572012-05-30 13:32:24 -0700796 return qpnp_pin_set_mode(q_chip, q_spec, QPNP_PIN_MODE_DIG_IN);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800797}
798
Michael Bohana05f4552012-05-24 15:58:11 -0700799static int qpnp_pin_direction_output(struct gpio_chip *gpio_chip,
Michael Bohan0ba63b82012-02-06 13:42:34 -0800800 unsigned offset,
801 int val)
802{
803 int rc;
Michael Bohana05f4552012-05-24 15:58:11 -0700804 struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
805 struct qpnp_pin_spec *q_spec;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800806
807 if (WARN_ON(!q_chip))
808 return -ENODEV;
809
810 q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
811 if (WARN_ON(!q_spec))
812 return -ENODEV;
813
Michael Bohana05f4552012-05-24 15:58:11 -0700814 rc = __qpnp_pin_set(q_chip, q_spec, val);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800815 if (rc)
816 return rc;
817
Michael Bohan6b901572012-05-30 13:32:24 -0700818 rc = qpnp_pin_set_mode(q_chip, q_spec, QPNP_PIN_MODE_DIG_OUT);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800819
820 return rc;
821}
822
Michael Bohana05f4552012-05-24 15:58:11 -0700823static int qpnp_pin_of_gpio_xlate(struct gpio_chip *gpio_chip,
Michael Bohan0b24fb12012-06-01 10:30:12 -0700824 const struct of_phandle_args *gpio_spec,
825 u32 *flags)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800826{
Michael Bohana05f4552012-05-24 15:58:11 -0700827 struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
828 struct qpnp_pin_spec *q_spec;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800829
830 if (WARN_ON(gpio_chip->of_gpio_n_cells < 2)) {
Michael Bohane25e15f2012-04-12 17:28:26 -0700831 pr_err("of_gpio_n_cells < 2\n");
Michael Bohan0ba63b82012-02-06 13:42:34 -0800832 return -EINVAL;
833 }
834
Michael Bohana05f4552012-05-24 15:58:11 -0700835 q_spec = qpnp_pmic_pin_get_spec(q_chip, gpio_spec->args[0]);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800836 if (!q_spec) {
Michael Bohan0b24fb12012-06-01 10:30:12 -0700837 pr_err("no such PMIC gpio %u in device topology\n",
838 gpio_spec->args[0]);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800839 return -EINVAL;
840 }
841
842 if (flags)
Michael Bohan0b24fb12012-06-01 10:30:12 -0700843 *flags = gpio_spec->args[1];
Michael Bohan0ba63b82012-02-06 13:42:34 -0800844
845 return q_spec->gpio_chip_idx;
846}
847
Michael Bohana05f4552012-05-24 15:58:11 -0700848static int qpnp_pin_apply_config(struct qpnp_pin_chip *q_chip,
849 struct qpnp_pin_spec *q_spec)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800850{
Michael Bohana05f4552012-05-24 15:58:11 -0700851 struct qpnp_pin_cfg param;
Michael Bohande3942a2012-04-17 15:28:01 -0700852 struct device_node *node = q_spec->node;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800853 int rc;
854
Michael Bohan6b901572012-05-30 13:32:24 -0700855 param.mode = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
Michael Bohande3942a2012-04-17 15:28:01 -0700856 Q_REG_MODE_SEL_SHIFT,
857 Q_REG_MODE_SEL_MASK);
858 param.output_type = q_reg_get(&q_spec->regs[Q_REG_I_DIG_OUT_CTL],
859 Q_REG_OUT_TYPE_SHIFT,
860 Q_REG_OUT_TYPE_MASK);
861 param.invert = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
Michael Bohand3cf9b02012-08-15 23:23:52 -0700862 Q_REG_OUT_INVERT_SHIFT,
Michael Bohande3942a2012-04-17 15:28:01 -0700863 Q_REG_OUT_INVERT_MASK);
Michael Bohan26324a22013-03-20 10:15:33 -0700864 param.pull = q_reg_get(&q_spec->regs[Q_REG_I_DIG_PULL_CTL],
Michael Bohande3942a2012-04-17 15:28:01 -0700865 Q_REG_PULL_SHIFT, Q_REG_PULL_MASK);
866 param.vin_sel = q_reg_get(&q_spec->regs[Q_REG_I_DIG_VIN_CTL],
867 Q_REG_VIN_SHIFT, Q_REG_VIN_MASK);
868 param.out_strength = q_reg_get(&q_spec->regs[Q_REG_I_DIG_OUT_CTL],
869 Q_REG_OUT_STRENGTH_SHIFT,
870 Q_REG_OUT_STRENGTH_MASK);
Michael Bohand734fb22012-10-30 14:19:22 -0700871 param.src_sel = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
Michael Bohande3942a2012-04-17 15:28:01 -0700872 Q_REG_SRC_SEL_SHIFT, Q_REG_SRC_SEL_MASK);
873 param.master_en = q_reg_get(&q_spec->regs[Q_REG_I_EN_CTL],
874 Q_REG_MASTER_EN_SHIFT,
875 Q_REG_MASTER_EN_MASK);
Michael Bohan6b901572012-05-30 13:32:24 -0700876 param.aout_ref = q_reg_get(&q_spec->regs[Q_REG_I_AOUT_CTL],
877 Q_REG_AOUT_REF_SHIFT,
878 Q_REG_AOUT_REF_MASK);
879 param.ain_route = q_reg_get(&q_spec->regs[Q_REG_I_AIN_CTL],
880 Q_REG_AIN_ROUTE_SHIFT,
881 Q_REG_AIN_ROUTE_MASK);
882 param.cs_out = q_reg_get(&q_spec->regs[Q_REG_I_SINK_CTL],
883 Q_REG_CS_OUT_SHIFT,
884 Q_REG_CS_OUT_MASK);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800885
Michael Bohan6b901572012-05-30 13:32:24 -0700886 of_property_read_u32(node, "qcom,mode",
887 &param.mode);
Michael Bohande3942a2012-04-17 15:28:01 -0700888 of_property_read_u32(node, "qcom,output-type",
889 &param.output_type);
890 of_property_read_u32(node, "qcom,invert",
891 &param.invert);
892 of_property_read_u32(node, "qcom,pull",
893 &param.pull);
894 of_property_read_u32(node, "qcom,vin-sel",
895 &param.vin_sel);
896 of_property_read_u32(node, "qcom,out-strength",
897 &param.out_strength);
Michael Bohand734fb22012-10-30 14:19:22 -0700898 of_property_read_u32(node, "qcom,src-sel",
899 &param.src_sel);
Michael Bohan6b901572012-05-30 13:32:24 -0700900 of_property_read_u32(node, "qcom,master-en",
Michael Bohande3942a2012-04-17 15:28:01 -0700901 &param.master_en);
Michael Bohan6b901572012-05-30 13:32:24 -0700902 of_property_read_u32(node, "qcom,aout-ref",
903 &param.aout_ref);
904 of_property_read_u32(node, "qcom,ain-route",
905 &param.ain_route);
906 of_property_read_u32(node, "qcom,cs-out",
907 &param.cs_out);
Michael Bohana05f4552012-05-24 15:58:11 -0700908 rc = _qpnp_pin_config(q_chip, q_spec, &param);
Michael Bohande3942a2012-04-17 15:28:01 -0700909
Michael Bohan0ba63b82012-02-06 13:42:34 -0800910 return rc;
911}
912
Michael Bohana05f4552012-05-24 15:58:11 -0700913static int qpnp_pin_free_chip(struct qpnp_pin_chip *q_chip)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800914{
915 struct spmi_device *spmi = q_chip->spmi;
Ashay Jaiswala21fdd42014-02-25 13:53:19 +0530916 int i, rc = 0;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800917
918 if (q_chip->chip_gpios)
919 for (i = 0; i < spmi->num_dev_node; i++)
920 kfree(q_chip->chip_gpios[i]);
921
Michael Bohana05f4552012-05-24 15:58:11 -0700922 mutex_lock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800923 list_del(&q_chip->chip_list);
Michael Bohana05f4552012-05-24 15:58:11 -0700924 mutex_unlock(&qpnp_pin_chips_lock);
Ashay Jaiswala21fdd42014-02-25 13:53:19 +0530925 if (q_chip->chip_registered) {
926 rc = gpiochip_remove(&q_chip->gpio_chip);
927 if (rc)
928 dev_err(&q_chip->spmi->dev, "%s: unable to remove gpio\n",
929 __func__);
930 }
Michael Bohan0ba63b82012-02-06 13:42:34 -0800931 kfree(q_chip->chip_gpios);
Michael Bohana05f4552012-05-24 15:58:11 -0700932 kfree(q_chip->pmic_pins);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800933 kfree(q_chip);
934 return rc;
935}
936
Michael Bohana05f4552012-05-24 15:58:11 -0700937#ifdef CONFIG_GPIO_QPNP_PIN_DEBUG
938struct qpnp_pin_reg {
Michael Bohana19dced2012-04-24 13:14:50 -0700939 uint32_t addr;
940 uint32_t idx;
941 uint32_t shift;
942 uint32_t mask;
943};
944
945static struct dentry *driver_dfs_dir;
946
Michael Bohana05f4552012-05-24 15:58:11 -0700947static int qpnp_pin_reg_attr(enum qpnp_pin_param_type type,
948 struct qpnp_pin_reg *cfg)
Michael Bohana19dced2012-04-24 13:14:50 -0700949{
950 switch (type) {
Michael Bohan6b901572012-05-30 13:32:24 -0700951 case Q_PIN_CFG_MODE:
Michael Bohana19dced2012-04-24 13:14:50 -0700952 cfg->addr = Q_REG_MODE_CTL;
953 cfg->idx = Q_REG_I_MODE_CTL;
954 cfg->shift = Q_REG_MODE_SEL_SHIFT;
955 cfg->mask = Q_REG_MODE_SEL_MASK;
956 break;
Michael Bohana05f4552012-05-24 15:58:11 -0700957 case Q_PIN_CFG_OUTPUT_TYPE:
Michael Bohana19dced2012-04-24 13:14:50 -0700958 cfg->addr = Q_REG_DIG_OUT_CTL;
959 cfg->idx = Q_REG_I_DIG_OUT_CTL;
960 cfg->shift = Q_REG_OUT_TYPE_SHIFT;
961 cfg->mask = Q_REG_OUT_TYPE_MASK;
962 break;
Michael Bohana05f4552012-05-24 15:58:11 -0700963 case Q_PIN_CFG_INVERT:
Michael Bohana19dced2012-04-24 13:14:50 -0700964 cfg->addr = Q_REG_MODE_CTL;
965 cfg->idx = Q_REG_I_MODE_CTL;
966 cfg->shift = Q_REG_OUT_INVERT_SHIFT;
967 cfg->mask = Q_REG_OUT_INVERT_MASK;
968 break;
Michael Bohana05f4552012-05-24 15:58:11 -0700969 case Q_PIN_CFG_PULL:
Michael Bohana19dced2012-04-24 13:14:50 -0700970 cfg->addr = Q_REG_DIG_PULL_CTL;
971 cfg->idx = Q_REG_I_DIG_PULL_CTL;
972 cfg->shift = Q_REG_PULL_SHIFT;
973 cfg->mask = Q_REG_PULL_MASK;
974 break;
Michael Bohana05f4552012-05-24 15:58:11 -0700975 case Q_PIN_CFG_VIN_SEL:
Michael Bohana19dced2012-04-24 13:14:50 -0700976 cfg->addr = Q_REG_DIG_VIN_CTL;
977 cfg->idx = Q_REG_I_DIG_VIN_CTL;
978 cfg->shift = Q_REG_VIN_SHIFT;
979 cfg->mask = Q_REG_VIN_MASK;
980 break;
Michael Bohana05f4552012-05-24 15:58:11 -0700981 case Q_PIN_CFG_OUT_STRENGTH:
Michael Bohana19dced2012-04-24 13:14:50 -0700982 cfg->addr = Q_REG_DIG_OUT_CTL;
983 cfg->idx = Q_REG_I_DIG_OUT_CTL;
984 cfg->shift = Q_REG_OUT_STRENGTH_SHIFT;
985 cfg->mask = Q_REG_OUT_STRENGTH_MASK;
986 break;
Michael Bohand734fb22012-10-30 14:19:22 -0700987 case Q_PIN_CFG_SRC_SEL:
Michael Bohana19dced2012-04-24 13:14:50 -0700988 cfg->addr = Q_REG_MODE_CTL;
989 cfg->idx = Q_REG_I_MODE_CTL;
990 cfg->shift = Q_REG_SRC_SEL_SHIFT;
991 cfg->mask = Q_REG_SRC_SEL_MASK;
992 break;
Michael Bohana05f4552012-05-24 15:58:11 -0700993 case Q_PIN_CFG_MASTER_EN:
Michael Bohana19dced2012-04-24 13:14:50 -0700994 cfg->addr = Q_REG_EN_CTL;
995 cfg->idx = Q_REG_I_EN_CTL;
996 cfg->shift = Q_REG_MASTER_EN_SHIFT;
997 cfg->mask = Q_REG_MASTER_EN_MASK;
998 break;
Michael Bohan6b901572012-05-30 13:32:24 -0700999 case Q_PIN_CFG_AOUT_REF:
1000 cfg->addr = Q_REG_AOUT_CTL;
1001 cfg->idx = Q_REG_I_AOUT_CTL;
1002 cfg->shift = Q_REG_AOUT_REF_SHIFT;
1003 cfg->mask = Q_REG_AOUT_REF_MASK;
1004 break;
1005 case Q_PIN_CFG_AIN_ROUTE:
1006 cfg->addr = Q_REG_AIN_CTL;
1007 cfg->idx = Q_REG_I_AIN_CTL;
1008 cfg->shift = Q_REG_AIN_ROUTE_SHIFT;
1009 cfg->mask = Q_REG_AIN_ROUTE_MASK;
1010 break;
1011 case Q_PIN_CFG_CS_OUT:
1012 cfg->addr = Q_REG_SINK_CTL;
1013 cfg->idx = Q_REG_I_SINK_CTL;
1014 cfg->shift = Q_REG_CS_OUT_SHIFT;
1015 cfg->mask = Q_REG_CS_OUT_MASK;
1016 break;
Michael Bohana19dced2012-04-24 13:14:50 -07001017 default:
1018 return -EINVAL;
1019 }
1020
1021 return 0;
1022}
1023
Michael Bohana05f4552012-05-24 15:58:11 -07001024static int qpnp_pin_debugfs_get(void *data, u64 *val)
Michael Bohana19dced2012-04-24 13:14:50 -07001025{
Michael Bohana05f4552012-05-24 15:58:11 -07001026 enum qpnp_pin_param_type *idx = data;
1027 struct qpnp_pin_spec *q_spec;
1028 struct qpnp_pin_reg cfg = {};
Michael Bohana19dced2012-04-24 13:14:50 -07001029 int rc;
1030
Michael Bohana05f4552012-05-24 15:58:11 -07001031 rc = qpnp_pin_reg_attr(*idx, &cfg);
Michael Bohana19dced2012-04-24 13:14:50 -07001032 if (rc)
1033 return rc;
Michael Bohana05f4552012-05-24 15:58:11 -07001034 q_spec = container_of(idx, struct qpnp_pin_spec, params[*idx]);
Michael Bohana19dced2012-04-24 13:14:50 -07001035 *val = q_reg_get(&q_spec->regs[cfg.idx], cfg.shift, cfg.mask);
1036 return 0;
1037}
1038
Michael Bohana05f4552012-05-24 15:58:11 -07001039static int qpnp_pin_debugfs_set(void *data, u64 val)
Michael Bohana19dced2012-04-24 13:14:50 -07001040{
Michael Bohana05f4552012-05-24 15:58:11 -07001041 enum qpnp_pin_param_type *idx = data;
1042 struct qpnp_pin_spec *q_spec;
1043 struct qpnp_pin_chip *q_chip;
1044 struct qpnp_pin_reg cfg = {};
Michael Bohana19dced2012-04-24 13:14:50 -07001045 int rc;
1046
Michael Bohana05f4552012-05-24 15:58:11 -07001047 q_spec = container_of(idx, struct qpnp_pin_spec, params[*idx]);
Michael Bohana19dced2012-04-24 13:14:50 -07001048 q_chip = q_spec->q_chip;
1049
Michael Bohan58d07802012-05-31 15:37:55 -07001050 rc = qpnp_pin_check_config(*idx, q_spec, val);
Michael Bohana19dced2012-04-24 13:14:50 -07001051 if (rc)
1052 return rc;
1053
Michael Bohana05f4552012-05-24 15:58:11 -07001054 rc = qpnp_pin_reg_attr(*idx, &cfg);
Michael Bohana19dced2012-04-24 13:14:50 -07001055 if (rc)
1056 return rc;
1057 q_reg_clr_set(&q_spec->regs[cfg.idx], cfg.shift, cfg.mask, val);
1058 rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
1059 Q_REG_ADDR(q_spec, cfg.addr),
1060 &q_spec->regs[cfg.idx], 1);
1061
1062 return rc;
1063}
Michael Bohana05f4552012-05-24 15:58:11 -07001064DEFINE_SIMPLE_ATTRIBUTE(qpnp_pin_fops, qpnp_pin_debugfs_get,
1065 qpnp_pin_debugfs_set, "%llu\n");
Michael Bohana19dced2012-04-24 13:14:50 -07001066
1067#define DEBUGFS_BUF_SIZE 11 /* supports 2^32 in decimal */
1068
Michael Bohana05f4552012-05-24 15:58:11 -07001069struct qpnp_pin_debugfs_args {
1070 enum qpnp_pin_param_type type;
Michael Bohana19dced2012-04-24 13:14:50 -07001071 const char *filename;
1072};
1073
Michael Bohana05f4552012-05-24 15:58:11 -07001074static struct qpnp_pin_debugfs_args dfs_args[] = {
Michael Bohan6b901572012-05-30 13:32:24 -07001075 { Q_PIN_CFG_MODE, "mode" },
Michael Bohana05f4552012-05-24 15:58:11 -07001076 { Q_PIN_CFG_OUTPUT_TYPE, "output_type" },
1077 { Q_PIN_CFG_INVERT, "invert" },
1078 { Q_PIN_CFG_PULL, "pull" },
1079 { Q_PIN_CFG_VIN_SEL, "vin_sel" },
1080 { Q_PIN_CFG_OUT_STRENGTH, "out_strength" },
Michael Bohand734fb22012-10-30 14:19:22 -07001081 { Q_PIN_CFG_SRC_SEL, "src_sel" },
Michael Bohan6b901572012-05-30 13:32:24 -07001082 { Q_PIN_CFG_MASTER_EN, "master_en" },
1083 { Q_PIN_CFG_AOUT_REF, "aout_ref" },
1084 { Q_PIN_CFG_AIN_ROUTE, "ain_route" },
1085 { Q_PIN_CFG_CS_OUT, "cs_out" },
Michael Bohana19dced2012-04-24 13:14:50 -07001086};
1087
Michael Bohana05f4552012-05-24 15:58:11 -07001088static int qpnp_pin_debugfs_create(struct qpnp_pin_chip *q_chip)
Michael Bohana19dced2012-04-24 13:14:50 -07001089{
1090 struct spmi_device *spmi = q_chip->spmi;
1091 struct device *dev = &spmi->dev;
Michael Bohana05f4552012-05-24 15:58:11 -07001092 struct qpnp_pin_spec *q_spec;
1093 enum qpnp_pin_param_type *params;
1094 enum qpnp_pin_param_type type;
1095 char pmic_pin[DEBUGFS_BUF_SIZE];
Michael Bohana19dced2012-04-24 13:14:50 -07001096 const char *filename;
1097 struct dentry *dfs, *dfs_io_dir;
Michael Bohan6b901572012-05-30 13:32:24 -07001098 int i, j, rc;
Michael Bohana19dced2012-04-24 13:14:50 -07001099
1100 BUG_ON(Q_NUM_PARAMS != ARRAY_SIZE(dfs_args));
1101
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001102 q_chip->dfs_dir = debugfs_create_dir(q_chip->gpio_chip.label,
Michael Bohana19dced2012-04-24 13:14:50 -07001103 driver_dfs_dir);
1104 if (q_chip->dfs_dir == NULL) {
1105 dev_err(dev, "%s: cannot register chip debugfs directory %s\n",
1106 __func__, dev->of_node->name);
1107 return -ENODEV;
1108 }
1109
1110 for (i = 0; i < spmi->num_dev_node; i++) {
1111 q_spec = qpnp_chip_gpio_get_spec(q_chip, i);
1112 params = q_spec->params;
Michael Bohana05f4552012-05-24 15:58:11 -07001113 snprintf(pmic_pin, DEBUGFS_BUF_SIZE, "%u", q_spec->pmic_pin);
Michael Bohan6b901572012-05-30 13:32:24 -07001114 dfs_io_dir = debugfs_create_dir(pmic_pin, q_chip->dfs_dir);
Michael Bohana19dced2012-04-24 13:14:50 -07001115 if (dfs_io_dir == NULL)
1116 goto dfs_err;
1117
1118 for (j = 0; j < Q_NUM_PARAMS; j++) {
1119 type = dfs_args[j].type;
1120 filename = dfs_args[j].filename;
1121
Michael Bohan6b901572012-05-30 13:32:24 -07001122 /*
1123 * Use a value of '0' to see if the pin has even basic
1124 * support for a function. Do not create a file if
1125 * it doesn't.
1126 */
1127 rc = qpnp_pin_check_config(type, q_spec, 0);
1128 if (rc == -ENXIO)
1129 continue;
1130
Michael Bohana19dced2012-04-24 13:14:50 -07001131 params[type] = type;
1132 dfs = debugfs_create_file(
1133 filename,
1134 S_IRUGO | S_IWUSR,
1135 dfs_io_dir,
1136 &q_spec->params[type],
Michael Bohana05f4552012-05-24 15:58:11 -07001137 &qpnp_pin_fops);
Michael Bohana19dced2012-04-24 13:14:50 -07001138 if (dfs == NULL)
1139 goto dfs_err;
1140 }
1141 }
1142 return 0;
1143dfs_err:
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001144 dev_err(dev, "%s: cannot register debugfs for pmic gpio %u on chip %s\n",
1145 __func__, q_spec->pmic_pin, dev->of_node->name);
Michael Bohana19dced2012-04-24 13:14:50 -07001146 debugfs_remove_recursive(q_chip->dfs_dir);
1147 return -ENFILE;
1148}
1149#else
Michael Bohana05f4552012-05-24 15:58:11 -07001150static int qpnp_pin_debugfs_create(struct qpnp_pin_chip *q_chip)
Michael Bohana19dced2012-04-24 13:14:50 -07001151{
1152 return 0;
1153}
1154#endif
1155
Michael Bohanbfe64c72012-08-24 16:57:26 -07001156static int qpnp_pin_is_valid_pin(struct qpnp_pin_spec *q_spec)
1157{
1158 if (q_spec->type == Q_GPIO_TYPE)
1159 switch (q_spec->subtype) {
1160 case Q_GPIO_SUBTYPE_GPIO_4CH:
1161 case Q_GPIO_SUBTYPE_GPIOC_4CH:
1162 case Q_GPIO_SUBTYPE_GPIO_8CH:
1163 case Q_GPIO_SUBTYPE_GPIOC_8CH:
1164 return 1;
1165 }
1166 else if (q_spec->type == Q_MPP_TYPE)
1167 switch (q_spec->subtype) {
1168 case Q_MPP_SUBTYPE_4CH_NO_ANA_OUT:
Ashay Jaiswal1c61bd62014-01-22 10:29:11 +05301169 case Q_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT:
Michael Bohanbfe64c72012-08-24 16:57:26 -07001170 case Q_MPP_SUBTYPE_4CH_NO_SINK:
Ashay Jaiswal1c61bd62014-01-22 10:29:11 +05301171 case Q_MPP_SUBTYPE_ULT_4CH_NO_SINK:
Michael Bohanbfe64c72012-08-24 16:57:26 -07001172 case Q_MPP_SUBTYPE_4CH_FULL_FUNC:
1173 case Q_MPP_SUBTYPE_8CH_FULL_FUNC:
1174 return 1;
1175 }
1176
1177 return 0;
1178}
1179
Michael Bohana05f4552012-05-24 15:58:11 -07001180static int qpnp_pin_probe(struct spmi_device *spmi)
Michael Bohan0ba63b82012-02-06 13:42:34 -08001181{
Michael Bohana05f4552012-05-24 15:58:11 -07001182 struct qpnp_pin_chip *q_chip;
1183 struct qpnp_pin_spec *q_spec;
Michael Bohan0e5534d2012-05-22 17:33:45 -07001184 struct resource *res;
1185 struct spmi_resource *d_node;
Michael Bohan94e397b2012-04-25 15:21:55 -07001186 int i, rc;
1187 int lowest_gpio = UINT_MAX, highest_gpio = 0;
Abhijeet Dharmapurikarea799552014-01-08 20:16:37 -08001188 u32 gpio;
Michael Bohanbfe64c72012-08-24 16:57:26 -07001189 char version[Q_REG_SUBTYPE - Q_REG_DIG_MAJOR_REV + 1];
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001190 const char *dev_name;
1191
1192 dev_name = spmi_get_primary_dev_name(spmi);
1193 if (!dev_name) {
1194 dev_err(&spmi->dev, "%s: label binding undefined for node %s\n",
1195 __func__, spmi->dev.of_node->full_name);
1196 return -EINVAL;
1197 }
Michael Bohan0ba63b82012-02-06 13:42:34 -08001198
1199 q_chip = kzalloc(sizeof(*q_chip), GFP_KERNEL);
1200 if (!q_chip) {
1201 dev_err(&spmi->dev, "%s: Can't allocate gpio_chip\n",
1202 __func__);
1203 return -ENOMEM;
1204 }
1205 q_chip->spmi = spmi;
1206 dev_set_drvdata(&spmi->dev, q_chip);
1207
Michael Bohana05f4552012-05-24 15:58:11 -07001208 mutex_lock(&qpnp_pin_chips_lock);
1209 list_add(&q_chip->chip_list, &qpnp_pin_chips);
1210 mutex_unlock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001211
1212 /* first scan through nodes to find the range required for allocation */
1213 for (i = 0; i < spmi->num_dev_node; i++) {
Michael Bohan94e397b2012-04-25 15:21:55 -07001214 rc = of_property_read_u32(spmi->dev_node[i].of_node,
Michael Bohana05f4552012-05-24 15:58:11 -07001215 "qcom,pin-num", &gpio);
Michael Bohan94e397b2012-04-25 15:21:55 -07001216 if (rc) {
Michael Bohana05f4552012-05-24 15:58:11 -07001217 dev_err(&spmi->dev, "%s: unable to get qcom,pin-num property\n",
1218 __func__);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001219 goto err_probe;
1220 }
1221
Michael Bohan0ba63b82012-02-06 13:42:34 -08001222 if (gpio < lowest_gpio)
1223 lowest_gpio = gpio;
1224 if (gpio > highest_gpio)
1225 highest_gpio = gpio;
1226 }
1227
1228 if (highest_gpio < lowest_gpio) {
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001229 dev_err(&spmi->dev, "%s: no device nodes specified in topology\n",
1230 __func__);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001231 rc = -EINVAL;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001232 goto err_probe;
1233 } else if (lowest_gpio == 0) {
1234 dev_err(&spmi->dev, "%s: 0 is not a valid PMIC GPIO\n",
1235 __func__);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001236 rc = -EINVAL;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001237 goto err_probe;
1238 }
1239
Michael Bohana05f4552012-05-24 15:58:11 -07001240 q_chip->pmic_pin_lowest = lowest_gpio;
1241 q_chip->pmic_pin_highest = highest_gpio;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001242
1243 /* allocate gpio lookup tables */
Michael Bohana05f4552012-05-24 15:58:11 -07001244 q_chip->pmic_pins = kzalloc(sizeof(struct qpnp_pin_spec *) *
Michael Bohan0ba63b82012-02-06 13:42:34 -08001245 highest_gpio - lowest_gpio + 1,
1246 GFP_KERNEL);
Michael Bohana05f4552012-05-24 15:58:11 -07001247 q_chip->chip_gpios = kzalloc(sizeof(struct qpnp_pin_spec *) *
Michael Bohan0ba63b82012-02-06 13:42:34 -08001248 spmi->num_dev_node, GFP_KERNEL);
Michael Bohana05f4552012-05-24 15:58:11 -07001249 if (!q_chip->pmic_pins || !q_chip->chip_gpios) {
Michael Bohan0ba63b82012-02-06 13:42:34 -08001250 dev_err(&spmi->dev, "%s: unable to allocate memory\n",
1251 __func__);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001252 rc = -ENOMEM;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001253 goto err_probe;
1254 }
1255
1256 /* get interrupt controller device_node */
1257 q_chip->int_ctrl = of_irq_find_parent(spmi->dev.of_node);
1258 if (!q_chip->int_ctrl) {
1259 dev_err(&spmi->dev, "%s: Can't find interrupt parent\n",
1260 __func__);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001261 rc = -EINVAL;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001262 goto err_probe;
1263 }
1264
1265 /* now scan through again and populate the lookup table */
1266 for (i = 0; i < spmi->num_dev_node; i++) {
Michael Bohan0e5534d2012-05-22 17:33:45 -07001267 d_node = &spmi->dev_node[i];
1268 res = spmi_get_resource(spmi, d_node, IORESOURCE_MEM, 0);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001269 if (!res) {
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001270 dev_err(&spmi->dev, "%s: node %s is missing has no base address definition\n",
Michael Bohan0e5534d2012-05-22 17:33:45 -07001271 __func__, d_node->of_node->full_name);
Zhenhua Huang30acf242013-07-11 01:52:36 +08001272 rc = -EINVAL;
1273 goto err_probe;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001274 }
1275
Michael Bohan0e5534d2012-05-22 17:33:45 -07001276 rc = of_property_read_u32(d_node->of_node,
Michael Bohana05f4552012-05-24 15:58:11 -07001277 "qcom,pin-num", &gpio);
Michael Bohan94e397b2012-04-25 15:21:55 -07001278 if (rc) {
Michael Bohana05f4552012-05-24 15:58:11 -07001279 dev_err(&spmi->dev, "%s: unable to get qcom,pin-num property\n",
1280 __func__);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001281 goto err_probe;
1282 }
Michael Bohan0ba63b82012-02-06 13:42:34 -08001283
Michael Bohana05f4552012-05-24 15:58:11 -07001284 q_spec = kzalloc(sizeof(struct qpnp_pin_spec),
Michael Bohan0ba63b82012-02-06 13:42:34 -08001285 GFP_KERNEL);
1286 if (!q_spec) {
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001287 dev_err(&spmi->dev, "%s: unable to allocate memory\n",
1288 __func__);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001289 rc = -ENOMEM;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001290 goto err_probe;
1291 }
1292
1293 q_spec->slave = spmi->sid;
1294 q_spec->offset = res->start;
1295 q_spec->gpio_chip_idx = i;
Michael Bohana05f4552012-05-24 15:58:11 -07001296 q_spec->pmic_pin = gpio;
Michael Bohan0e5534d2012-05-22 17:33:45 -07001297 q_spec->node = d_node->of_node;
Michael Bohana19dced2012-04-24 13:14:50 -07001298 q_spec->q_chip = q_chip;
Michael Bohane25e15f2012-04-12 17:28:26 -07001299
1300 rc = spmi_ext_register_readl(spmi->ctrl, q_spec->slave,
Michael Bohanbfe64c72012-08-24 16:57:26 -07001301 Q_REG_ADDR(q_spec, Q_REG_DIG_MAJOR_REV),
1302 &version[0], ARRAY_SIZE(version));
Michael Bohane25e15f2012-04-12 17:28:26 -07001303 if (rc) {
1304 dev_err(&spmi->dev, "%s: unable to read type regs\n",
1305 __func__);
Michael Bohane25e15f2012-04-12 17:28:26 -07001306 goto err_probe;
1307 }
Michael Bohanbfe64c72012-08-24 16:57:26 -07001308 q_spec->dig_major_rev = version[Q_REG_DIG_MAJOR_REV -
1309 Q_REG_DIG_MAJOR_REV];
1310 q_spec->type = version[Q_REG_TYPE - Q_REG_DIG_MAJOR_REV];
1311 q_spec->subtype = version[Q_REG_SUBTYPE - Q_REG_DIG_MAJOR_REV];
1312
1313 if (!qpnp_pin_is_valid_pin(q_spec)) {
1314 dev_err(&spmi->dev, "%s: invalid pin type (type=0x%x subtype=0x%x)\n",
1315 __func__, q_spec->type, q_spec->subtype);
1316 goto err_probe;
1317 }
Michael Bohan0ba63b82012-02-06 13:42:34 -08001318
Michael Bohan6b901572012-05-30 13:32:24 -07001319 rc = qpnp_pin_ctl_regs_init(q_spec);
1320 if (rc)
1321 goto err_probe;
1322
Michael Bohana19dced2012-04-24 13:14:50 -07001323 /* initialize lookup table params */
Michael Bohana05f4552012-05-24 15:58:11 -07001324 qpnp_pmic_pin_set_spec(q_chip, gpio, q_spec);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001325 qpnp_chip_gpio_set_spec(q_chip, i, q_spec);
1326 }
1327
1328 q_chip->gpio_chip.base = -1;
1329 q_chip->gpio_chip.ngpio = spmi->num_dev_node;
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001330 q_chip->gpio_chip.label = dev_name;
Michael Bohana05f4552012-05-24 15:58:11 -07001331 q_chip->gpio_chip.direction_input = qpnp_pin_direction_input;
1332 q_chip->gpio_chip.direction_output = qpnp_pin_direction_output;
1333 q_chip->gpio_chip.to_irq = qpnp_pin_to_irq;
1334 q_chip->gpio_chip.get = qpnp_pin_get;
1335 q_chip->gpio_chip.set = qpnp_pin_set;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001336 q_chip->gpio_chip.dev = &spmi->dev;
Michael Bohana05f4552012-05-24 15:58:11 -07001337 q_chip->gpio_chip.of_xlate = qpnp_pin_of_gpio_xlate;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001338 q_chip->gpio_chip.of_gpio_n_cells = 2;
1339 q_chip->gpio_chip.can_sleep = 0;
1340
1341 rc = gpiochip_add(&q_chip->gpio_chip);
1342 if (rc) {
1343 dev_err(&spmi->dev, "%s: Can't add gpio chip, rc = %d\n",
1344 __func__, rc);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001345 goto err_probe;
1346 }
1347
Ashay Jaiswala21fdd42014-02-25 13:53:19 +05301348 q_chip->chip_registered = true;
Michael Bohande3942a2012-04-17 15:28:01 -07001349 /* now configure gpio config defaults if they exist */
Michael Bohan0ba63b82012-02-06 13:42:34 -08001350 for (i = 0; i < spmi->num_dev_node; i++) {
1351 q_spec = qpnp_chip_gpio_get_spec(q_chip, i);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001352 if (WARN_ON(!q_spec)) {
1353 rc = -ENODEV;
1354 goto err_probe;
1355 }
Michael Bohan0ba63b82012-02-06 13:42:34 -08001356
Michael Bohana05f4552012-05-24 15:58:11 -07001357 rc = qpnp_pin_cache_regs(q_chip, q_spec);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001358 if (rc)
Michael Bohan0ba63b82012-02-06 13:42:34 -08001359 goto err_probe;
Michael Bohande3942a2012-04-17 15:28:01 -07001360
Michael Bohana05f4552012-05-24 15:58:11 -07001361 rc = qpnp_pin_apply_config(q_chip, q_spec);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001362 if (rc)
Michael Bohande3942a2012-04-17 15:28:01 -07001363 goto err_probe;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001364 }
1365
1366 dev_dbg(&spmi->dev, "%s: gpio_chip registered between %d-%u\n",
1367 __func__, q_chip->gpio_chip.base,
1368 (q_chip->gpio_chip.base + q_chip->gpio_chip.ngpio) - 1);
Michael Bohana19dced2012-04-24 13:14:50 -07001369
Michael Bohana05f4552012-05-24 15:58:11 -07001370 rc = qpnp_pin_debugfs_create(q_chip);
Michael Bohana19dced2012-04-24 13:14:50 -07001371 if (rc) {
1372 dev_err(&spmi->dev, "%s: debugfs creation failed\n", __func__);
1373 goto err_probe;
1374 }
1375
Michael Bohan0ba63b82012-02-06 13:42:34 -08001376 return 0;
1377
1378err_probe:
Michael Bohana05f4552012-05-24 15:58:11 -07001379 qpnp_pin_free_chip(q_chip);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001380 return rc;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001381}
1382
Michael Bohana05f4552012-05-24 15:58:11 -07001383static int qpnp_pin_remove(struct spmi_device *spmi)
Michael Bohan0ba63b82012-02-06 13:42:34 -08001384{
Michael Bohana05f4552012-05-24 15:58:11 -07001385 struct qpnp_pin_chip *q_chip = dev_get_drvdata(&spmi->dev);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001386
Michael Bohana19dced2012-04-24 13:14:50 -07001387 debugfs_remove_recursive(q_chip->dfs_dir);
1388
Michael Bohana05f4552012-05-24 15:58:11 -07001389 return qpnp_pin_free_chip(q_chip);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001390}
1391
1392static struct of_device_id spmi_match_table[] = {
Michael Bohana05f4552012-05-24 15:58:11 -07001393 { .compatible = "qcom,qpnp-pin",
Michael Bohan0ba63b82012-02-06 13:42:34 -08001394 },
1395 {}
1396};
1397
Michael Bohana05f4552012-05-24 15:58:11 -07001398static const struct spmi_device_id qpnp_pin_id[] = {
1399 { "qcom,qpnp-pin", 0 },
Michael Bohan0ba63b82012-02-06 13:42:34 -08001400 { }
1401};
Michael Bohana05f4552012-05-24 15:58:11 -07001402MODULE_DEVICE_TABLE(spmi, qpnp_pin_id);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001403
Michael Bohana05f4552012-05-24 15:58:11 -07001404static struct spmi_driver qpnp_pin_driver = {
Michael Bohan0ba63b82012-02-06 13:42:34 -08001405 .driver = {
Michael Bohana05f4552012-05-24 15:58:11 -07001406 .name = "qcom,qpnp-pin",
Michael Bohan0ba63b82012-02-06 13:42:34 -08001407 .of_match_table = spmi_match_table,
1408 },
Michael Bohana05f4552012-05-24 15:58:11 -07001409 .probe = qpnp_pin_probe,
1410 .remove = qpnp_pin_remove,
1411 .id_table = qpnp_pin_id,
Michael Bohan0ba63b82012-02-06 13:42:34 -08001412};
1413
Michael Bohana05f4552012-05-24 15:58:11 -07001414static int __init qpnp_pin_init(void)
Michael Bohan0ba63b82012-02-06 13:42:34 -08001415{
Michael Bohana05f4552012-05-24 15:58:11 -07001416#ifdef CONFIG_GPIO_QPNP_PIN_DEBUG
1417 driver_dfs_dir = debugfs_create_dir("qpnp_pin", NULL);
Michael Bohana19dced2012-04-24 13:14:50 -07001418 if (driver_dfs_dir == NULL)
1419 pr_err("Cannot register top level debugfs directory\n");
1420#endif
1421
Michael Bohana05f4552012-05-24 15:58:11 -07001422 return spmi_driver_register(&qpnp_pin_driver);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001423}
1424
Michael Bohana05f4552012-05-24 15:58:11 -07001425static void __exit qpnp_pin_exit(void)
Michael Bohan0ba63b82012-02-06 13:42:34 -08001426{
Michael Bohana05f4552012-05-24 15:58:11 -07001427#ifdef CONFIG_GPIO_QPNP_PIN_DEBUG
Michael Bohana19dced2012-04-24 13:14:50 -07001428 debugfs_remove_recursive(driver_dfs_dir);
1429#endif
Michael Bohana05f4552012-05-24 15:58:11 -07001430 spmi_driver_unregister(&qpnp_pin_driver);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001431}
1432
Michael Bohan0ba63b82012-02-06 13:42:34 -08001433MODULE_DESCRIPTION("QPNP PMIC gpio driver");
Michael Bohan7f0cc9d2012-04-16 17:16:09 -07001434MODULE_LICENSE("GPL v2");
Michael Bohan0ba63b82012-02-06 13:42:34 -08001435
Michael Bohana05f4552012-05-24 15:58:11 -07001436module_init(qpnp_pin_init);
1437module_exit(qpnp_pin_exit);