blob: ed001f0ee38a5a8f47ba02b8628be8e92ca7b163 [file] [log] [blame]
Michael Bohan26324a22013-03-20 10:15:33 -07001/* Copyright (c) 2012-2013, 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 */
58#define Q_MPP_TYPE 0x11
Michael Bohanab7aafa2012-08-11 12:34:46 -070059#define Q_MPP_SUBTYPE_4CH_NO_ANA_OUT 0x3
60#define Q_MPP_SUBTYPE_4CH_NO_SINK 0x5
Michael Bohane824a6e2012-08-14 14:35:37 -070061#define Q_MPP_SUBTYPE_4CH_FULL_FUNC 0x7
62#define Q_MPP_SUBTYPE_8CH_FULL_FUNC 0xF
Michael Bohan0ba63b82012-02-06 13:42:34 -080063
64/* control register base address offsets */
Michael Bohane25e15f2012-04-12 17:28:26 -070065#define Q_REG_MODE_CTL 0x40
Michael Bohan6b901572012-05-30 13:32:24 -070066#define Q_REG_DIG_VIN_CTL 0x41
Michael Bohane25e15f2012-04-12 17:28:26 -070067#define Q_REG_DIG_PULL_CTL 0x42
68#define Q_REG_DIG_IN_CTL 0x43
Michael Bohane25e15f2012-04-12 17:28:26 -070069#define Q_REG_DIG_OUT_CTL 0x45
70#define Q_REG_EN_CTL 0x46
Michael Bohan6b901572012-05-30 13:32:24 -070071#define Q_REG_AOUT_CTL 0x48
72#define Q_REG_AIN_CTL 0x4A
73#define Q_REG_SINK_CTL 0x4C
Michael Bohan0ba63b82012-02-06 13:42:34 -080074
75/* control register regs array indices */
Michael Bohane25e15f2012-04-12 17:28:26 -070076#define Q_REG_I_MODE_CTL 0
Michael Bohan6b901572012-05-30 13:32:24 -070077#define Q_REG_I_DIG_VIN_CTL 1
Michael Bohane25e15f2012-04-12 17:28:26 -070078#define Q_REG_I_DIG_PULL_CTL 2
79#define Q_REG_I_DIG_IN_CTL 3
Michael Bohane25e15f2012-04-12 17:28:26 -070080#define Q_REG_I_DIG_OUT_CTL 5
81#define Q_REG_I_EN_CTL 6
Michael Bohan6b901572012-05-30 13:32:24 -070082#define Q_REG_I_AOUT_CTL 8
83#define Q_REG_I_AIN_CTL 10
84#define Q_REG_I_SINK_CTL 12
Michael Bohan0ba63b82012-02-06 13:42:34 -080085
Michael Bohane25e15f2012-04-12 17:28:26 -070086/* control reg: mode */
Michael Bohan0ba63b82012-02-06 13:42:34 -080087#define Q_REG_OUT_INVERT_SHIFT 0
88#define Q_REG_OUT_INVERT_MASK 0x1
89#define Q_REG_SRC_SEL_SHIFT 1
90#define Q_REG_SRC_SEL_MASK 0xE
Michael Bohane25e15f2012-04-12 17:28:26 -070091#define Q_REG_MODE_SEL_SHIFT 4
92#define Q_REG_MODE_SEL_MASK 0x70
93
94/* control reg: dig_vin */
95#define Q_REG_VIN_SHIFT 0
96#define Q_REG_VIN_MASK 0x7
97
98/* control reg: dig_pull */
99#define Q_REG_PULL_SHIFT 0
100#define Q_REG_PULL_MASK 0x7
101
102/* control reg: dig_out */
103#define Q_REG_OUT_STRENGTH_SHIFT 0
104#define Q_REG_OUT_STRENGTH_MASK 0x3
105#define Q_REG_OUT_TYPE_SHIFT 4
106#define Q_REG_OUT_TYPE_MASK 0x30
107
108/* control reg: en */
Michael Bohan0ba63b82012-02-06 13:42:34 -0800109#define Q_REG_MASTER_EN_SHIFT 7
110#define Q_REG_MASTER_EN_MASK 0x80
111
Michael Bohan6b901572012-05-30 13:32:24 -0700112/* control reg: ana_out */
113#define Q_REG_AOUT_REF_SHIFT 0
114#define Q_REG_AOUT_REF_MASK 0x7
115
116/* control reg: ana_in */
117#define Q_REG_AIN_ROUTE_SHIFT 0
118#define Q_REG_AIN_ROUTE_MASK 0x7
119
120/* control reg: sink */
121#define Q_REG_CS_OUT_SHIFT 0
122#define Q_REG_CS_OUT_MASK 0x7
123
Michael Bohana05f4552012-05-24 15:58:11 -0700124enum qpnp_pin_param_type {
Michael Bohan6b901572012-05-30 13:32:24 -0700125 Q_PIN_CFG_MODE,
Michael Bohana05f4552012-05-24 15:58:11 -0700126 Q_PIN_CFG_OUTPUT_TYPE,
127 Q_PIN_CFG_INVERT,
128 Q_PIN_CFG_PULL,
129 Q_PIN_CFG_VIN_SEL,
130 Q_PIN_CFG_OUT_STRENGTH,
Michael Bohand734fb22012-10-30 14:19:22 -0700131 Q_PIN_CFG_SRC_SEL,
Michael Bohana05f4552012-05-24 15:58:11 -0700132 Q_PIN_CFG_MASTER_EN,
Michael Bohan6b901572012-05-30 13:32:24 -0700133 Q_PIN_CFG_AOUT_REF,
134 Q_PIN_CFG_AIN_ROUTE,
135 Q_PIN_CFG_CS_OUT,
Michael Bohana05f4552012-05-24 15:58:11 -0700136 Q_PIN_CFG_INVALID,
Michael Bohana19dced2012-04-24 13:14:50 -0700137};
138
Michael Bohana05f4552012-05-24 15:58:11 -0700139#define Q_NUM_PARAMS Q_PIN_CFG_INVALID
Michael Bohana19dced2012-04-24 13:14:50 -0700140
Michael Bohane25e15f2012-04-12 17:28:26 -0700141/* param error checking */
Michael Bohan1c3d94f2012-08-11 14:33:03 -0700142#define QPNP_PIN_GPIO_MODE_INVALID 3
143#define QPNP_PIN_MPP_MODE_INVALID 7
Michael Bohana05f4552012-05-24 15:58:11 -0700144#define QPNP_PIN_INVERT_INVALID 2
145#define QPNP_PIN_OUT_BUF_INVALID 3
Michael Bohan6b901572012-05-30 13:32:24 -0700146#define QPNP_PIN_VIN_4CH_INVALID 5
147#define QPNP_PIN_VIN_8CH_INVALID 8
148#define QPNP_PIN_GPIO_PULL_INVALID 6
149#define QPNP_PIN_MPP_PULL_INVALID 4
Michael Bohana05f4552012-05-24 15:58:11 -0700150#define QPNP_PIN_OUT_STRENGTH_INVALID 4
151#define QPNP_PIN_SRC_INVALID 8
152#define QPNP_PIN_MASTER_INVALID 2
Michael Bohan6b901572012-05-30 13:32:24 -0700153#define QPNP_PIN_AOUT_REF_INVALID 8
154#define QPNP_PIN_AIN_ROUTE_INVALID 8
155#define QPNP_PIN_CS_OUT_INVALID 8
Michael Bohan0ba63b82012-02-06 13:42:34 -0800156
Michael Bohana05f4552012-05-24 15:58:11 -0700157struct qpnp_pin_spec {
Michael Bohan0ba63b82012-02-06 13:42:34 -0800158 uint8_t slave; /* 0-15 */
159 uint16_t offset; /* 0-255 */
160 uint32_t gpio_chip_idx; /* offset from gpio_chip base */
Michael Bohana05f4552012-05-24 15:58:11 -0700161 uint32_t pmic_pin; /* PMIC pin number */
Michael Bohan0ba63b82012-02-06 13:42:34 -0800162 int irq; /* logical IRQ number */
163 u8 regs[Q_NUM_CTL_REGS]; /* Control regs */
Michael Bohan6b901572012-05-30 13:32:24 -0700164 u8 num_ctl_regs; /* usable number on this pin */
Michael Bohane25e15f2012-04-12 17:28:26 -0700165 u8 type; /* peripheral type */
166 u8 subtype; /* peripheral subtype */
Michael Bohanbfe64c72012-08-24 16:57:26 -0700167 u8 dig_major_rev;
Michael Bohande3942a2012-04-17 15:28:01 -0700168 struct device_node *node;
Michael Bohana05f4552012-05-24 15:58:11 -0700169 enum qpnp_pin_param_type params[Q_NUM_PARAMS];
170 struct qpnp_pin_chip *q_chip;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800171};
172
Michael Bohana05f4552012-05-24 15:58:11 -0700173struct qpnp_pin_chip {
Michael Bohan0ba63b82012-02-06 13:42:34 -0800174 struct gpio_chip gpio_chip;
175 struct spmi_device *spmi;
Michael Bohana05f4552012-05-24 15:58:11 -0700176 struct qpnp_pin_spec **pmic_pins;
177 struct qpnp_pin_spec **chip_gpios;
178 uint32_t pmic_pin_lowest;
179 uint32_t pmic_pin_highest;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800180 struct device_node *int_ctrl;
181 struct list_head chip_list;
Michael Bohana19dced2012-04-24 13:14:50 -0700182 struct dentry *dfs_dir;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800183};
184
Michael Bohana05f4552012-05-24 15:58:11 -0700185static LIST_HEAD(qpnp_pin_chips);
186static DEFINE_MUTEX(qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800187
Michael Bohana05f4552012-05-24 15:58:11 -0700188static inline void qpnp_pmic_pin_set_spec(struct qpnp_pin_chip *q_chip,
189 uint32_t pmic_pin,
190 struct qpnp_pin_spec *spec)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800191{
Michael Bohana05f4552012-05-24 15:58:11 -0700192 q_chip->pmic_pins[pmic_pin - q_chip->pmic_pin_lowest] = spec;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800193}
194
Michael Bohana05f4552012-05-24 15:58:11 -0700195static inline struct qpnp_pin_spec *qpnp_pmic_pin_get_spec(
196 struct qpnp_pin_chip *q_chip,
197 uint32_t pmic_pin)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800198{
Michael Bohana05f4552012-05-24 15:58:11 -0700199 if (pmic_pin < q_chip->pmic_pin_lowest ||
200 pmic_pin > q_chip->pmic_pin_highest)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800201 return NULL;
202
Michael Bohana05f4552012-05-24 15:58:11 -0700203 return q_chip->pmic_pins[pmic_pin - q_chip->pmic_pin_lowest];
Michael Bohan0ba63b82012-02-06 13:42:34 -0800204}
205
Michael Bohana05f4552012-05-24 15:58:11 -0700206static inline struct qpnp_pin_spec *qpnp_chip_gpio_get_spec(
207 struct qpnp_pin_chip *q_chip,
Michael Bohan0ba63b82012-02-06 13:42:34 -0800208 uint32_t chip_gpio)
209{
210 if (chip_gpio > q_chip->gpio_chip.ngpio)
211 return NULL;
212
213 return q_chip->chip_gpios[chip_gpio];
214}
215
Michael Bohana05f4552012-05-24 15:58:11 -0700216static inline void qpnp_chip_gpio_set_spec(struct qpnp_pin_chip *q_chip,
Michael Bohan0ba63b82012-02-06 13:42:34 -0800217 uint32_t chip_gpio,
Michael Bohana05f4552012-05-24 15:58:11 -0700218 struct qpnp_pin_spec *spec)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800219{
220 q_chip->chip_gpios[chip_gpio] = spec;
221}
222
Michael Bohan58d07802012-05-31 15:37:55 -0700223/*
224 * Determines whether a specified param's configuration is correct.
225 * This check is two tier. First a check is done whether the hardware
226 * supports this param and value requested. The second check validates
227 * that the configuration is correct, given the fact that the hardware
228 * supports it.
229 *
230 * Returns
Michael Bohan6b901572012-05-30 13:32:24 -0700231 * -ENXIO is the hardware does not support this param.
232 * -EINVAL if the the hardware does support this param, but the
233 * requested value is outside the supported range.
Michael Bohan58d07802012-05-31 15:37:55 -0700234 */
235static int qpnp_pin_check_config(enum qpnp_pin_param_type idx,
236 struct qpnp_pin_spec *q_spec, uint32_t val)
237{
238 switch (idx) {
Michael Bohan6b901572012-05-30 13:32:24 -0700239 case Q_PIN_CFG_MODE:
Michael Bohan1c3d94f2012-08-11 14:33:03 -0700240 if (q_spec->type == Q_GPIO_TYPE &&
241 val >= QPNP_PIN_GPIO_MODE_INVALID)
242 return -EINVAL;
243 else if (q_spec->type == Q_MPP_TYPE &&
244 val >= QPNP_PIN_MPP_MODE_INVALID)
245 return -EINVAL;
Michael Bohan58d07802012-05-31 15:37:55 -0700246 break;
247 case Q_PIN_CFG_OUTPUT_TYPE:
Michael Bohan6b901572012-05-30 13:32:24 -0700248 if (q_spec->type != Q_GPIO_TYPE)
Michael Bohan58d07802012-05-31 15:37:55 -0700249 return -ENXIO;
Michael Bohan6b901572012-05-30 13:32:24 -0700250 if ((val == QPNP_PIN_OUT_BUF_OPEN_DRAIN_NMOS ||
251 val == QPNP_PIN_OUT_BUF_OPEN_DRAIN_PMOS) &&
252 (q_spec->subtype == Q_GPIO_SUBTYPE_GPIOC_4CH ||
253 (q_spec->subtype == Q_GPIO_SUBTYPE_GPIOC_8CH)))
254 return -EINVAL;
Michael Bohan58d07802012-05-31 15:37:55 -0700255 else if (val >= QPNP_PIN_OUT_BUF_INVALID)
256 return -EINVAL;
257 break;
258 case Q_PIN_CFG_INVERT:
259 if (val >= QPNP_PIN_INVERT_INVALID)
260 return -EINVAL;
261 break;
262 case Q_PIN_CFG_PULL:
Michael Bohan6b901572012-05-30 13:32:24 -0700263 if (q_spec->type == Q_GPIO_TYPE &&
264 val >= QPNP_PIN_GPIO_PULL_INVALID)
265 return -EINVAL;
266 if (q_spec->type == Q_MPP_TYPE &&
267 val >= QPNP_PIN_MPP_PULL_INVALID)
Michael Bohan58d07802012-05-31 15:37:55 -0700268 return -EINVAL;
269 break;
270 case Q_PIN_CFG_VIN_SEL:
Michael Bohan6b901572012-05-30 13:32:24 -0700271 if (val >= QPNP_PIN_VIN_8CH_INVALID)
Michael Bohan58d07802012-05-31 15:37:55 -0700272 return -EINVAL;
Michael Bohan6b901572012-05-30 13:32:24 -0700273 else if (val >= QPNP_PIN_VIN_4CH_INVALID) {
274 if (q_spec->type == Q_GPIO_TYPE &&
275 (q_spec->subtype == Q_GPIO_SUBTYPE_GPIO_4CH ||
276 q_spec->subtype == Q_GPIO_SUBTYPE_GPIOC_4CH))
277 return -EINVAL;
278 if (q_spec->type == Q_MPP_TYPE &&
279 (q_spec->subtype == Q_MPP_SUBTYPE_4CH_NO_ANA_OUT ||
280 q_spec->subtype == Q_MPP_SUBTYPE_4CH_NO_SINK ||
281 q_spec->subtype == Q_MPP_SUBTYPE_4CH_FULL_FUNC))
282 return -EINVAL;
283 }
Michael Bohan58d07802012-05-31 15:37:55 -0700284 break;
285 case Q_PIN_CFG_OUT_STRENGTH:
Michael Bohan6b901572012-05-30 13:32:24 -0700286 if (q_spec->type != Q_GPIO_TYPE)
287 return -ENXIO;
Michael Bohan58d07802012-05-31 15:37:55 -0700288 if (val >= QPNP_PIN_OUT_STRENGTH_INVALID ||
289 val == 0)
290 return -EINVAL;
291 break;
Michael Bohand734fb22012-10-30 14:19:22 -0700292 case Q_PIN_CFG_SRC_SEL:
Michael Bohan6b901572012-05-30 13:32:24 -0700293 if (q_spec->type == Q_MPP_TYPE &&
294 (val == QPNP_PIN_SEL_FUNC_1 ||
295 val == QPNP_PIN_SEL_FUNC_2))
296 return -EINVAL;
Michael Bohan58d07802012-05-31 15:37:55 -0700297 if (val >= QPNP_PIN_SRC_INVALID)
298 return -EINVAL;
299 break;
300 case Q_PIN_CFG_MASTER_EN:
301 if (val >= QPNP_PIN_MASTER_INVALID)
302 return -EINVAL;
303 break;
Michael Bohan6b901572012-05-30 13:32:24 -0700304 case Q_PIN_CFG_AOUT_REF:
305 if (q_spec->type != Q_MPP_TYPE)
306 return -ENXIO;
307 if (q_spec->subtype == Q_MPP_SUBTYPE_4CH_NO_ANA_OUT)
308 return -ENXIO;
309 if (val >= QPNP_PIN_AOUT_REF_INVALID)
310 return -EINVAL;
311 break;
312 case Q_PIN_CFG_AIN_ROUTE:
313 if (q_spec->type != Q_MPP_TYPE)
314 return -ENXIO;
315 if (val >= QPNP_PIN_AIN_ROUTE_INVALID)
316 return -EINVAL;
317 break;
318 case Q_PIN_CFG_CS_OUT:
319 if (q_spec->type != Q_MPP_TYPE)
320 return -ENXIO;
321 if (q_spec->subtype == Q_MPP_SUBTYPE_4CH_NO_SINK)
322 return -ENXIO;
323 if (val >= QPNP_PIN_CS_OUT_INVALID)
324 return -EINVAL;
325 break;
326
Michael Bohan58d07802012-05-31 15:37:55 -0700327 default:
328 pr_err("invalid param type %u specified\n", idx);
329 return -EINVAL;
330 }
331 return 0;
332}
333
334#define Q_CHK_INVALID(idx, q_spec, val) \
335 (qpnp_pin_check_config(idx, q_spec, val) == -EINVAL)
336
337static int qpnp_pin_check_constraints(struct qpnp_pin_spec *q_spec,
338 struct qpnp_pin_cfg *param)
Michael Bohane25e15f2012-04-12 17:28:26 -0700339{
Michael Bohan6b901572012-05-30 13:32:24 -0700340 int pin = q_spec->pmic_pin;
341 const char *name;
Michael Bohane25e15f2012-04-12 17:28:26 -0700342
Michael Bohan6b901572012-05-30 13:32:24 -0700343 name = (q_spec->type == Q_GPIO_TYPE) ? "gpio" : "mpp";
344
345 if (Q_CHK_INVALID(Q_PIN_CFG_MODE, q_spec, param->mode))
Michael Bohan91c5a042012-08-11 13:29:42 -0700346 pr_err("invalid direction value %d for %s %d\n",
347 param->mode, name, pin);
Michael Bohan58d07802012-05-31 15:37:55 -0700348 else if (Q_CHK_INVALID(Q_PIN_CFG_INVERT, q_spec, param->invert))
Michael Bohan91c5a042012-08-11 13:29:42 -0700349 pr_err("invalid invert polarity value %d for %s %d\n",
350 param->invert, name, pin);
Michael Bohand734fb22012-10-30 14:19:22 -0700351 else if (Q_CHK_INVALID(Q_PIN_CFG_SRC_SEL, q_spec, param->src_sel))
Michael Bohan91c5a042012-08-11 13:29:42 -0700352 pr_err("invalid source select value %d for %s %d\n",
Michael Bohand734fb22012-10-30 14:19:22 -0700353 param->src_sel, name, pin);
Michael Bohan58d07802012-05-31 15:37:55 -0700354 else if (Q_CHK_INVALID(Q_PIN_CFG_OUT_STRENGTH,
355 q_spec, param->out_strength))
Michael Bohan91c5a042012-08-11 13:29:42 -0700356 pr_err("invalid out strength value %d for %s %d\n",
357 param->out_strength, name, pin);
Michael Bohan58d07802012-05-31 15:37:55 -0700358 else if (Q_CHK_INVALID(Q_PIN_CFG_OUTPUT_TYPE,
359 q_spec, param->output_type))
Michael Bohan91c5a042012-08-11 13:29:42 -0700360 pr_err("invalid out type value %d for %s %d\n",
361 param->output_type, name, pin);
Michael Bohan58d07802012-05-31 15:37:55 -0700362 else if (Q_CHK_INVALID(Q_PIN_CFG_VIN_SEL, q_spec, param->vin_sel))
Michael Bohan91c5a042012-08-11 13:29:42 -0700363 pr_err("invalid vin select %d value for %s %d\n",
364 param->vin_sel, name, pin);
Michael Bohan58d07802012-05-31 15:37:55 -0700365 else if (Q_CHK_INVALID(Q_PIN_CFG_PULL, q_spec, param->pull))
Michael Bohan91c5a042012-08-11 13:29:42 -0700366 pr_err("invalid pull value %d for pin %s %d\n",
367 param->pull, name, pin);
Michael Bohan58d07802012-05-31 15:37:55 -0700368 else if (Q_CHK_INVALID(Q_PIN_CFG_MASTER_EN, q_spec, param->master_en))
Michael Bohan91c5a042012-08-11 13:29:42 -0700369 pr_err("invalid master_en value %d for %s %d\n",
370 param->master_en, name, pin);
Michael Bohan6b901572012-05-30 13:32:24 -0700371 else if (Q_CHK_INVALID(Q_PIN_CFG_AOUT_REF, q_spec, param->aout_ref))
Michael Bohan91c5a042012-08-11 13:29:42 -0700372 pr_err("invalid aout_reg value %d for %s %d\n",
373 param->aout_ref, name, pin);
Michael Bohan6b901572012-05-30 13:32:24 -0700374 else if (Q_CHK_INVALID(Q_PIN_CFG_AIN_ROUTE, q_spec, param->ain_route))
Michael Bohan91c5a042012-08-11 13:29:42 -0700375 pr_err("invalid ain_route value %d for %s %d\n",
376 param->ain_route, name, pin);
Michael Bohan6b901572012-05-30 13:32:24 -0700377 else if (Q_CHK_INVALID(Q_PIN_CFG_CS_OUT, q_spec, param->cs_out))
Michael Bohan91c5a042012-08-11 13:29:42 -0700378 pr_err("invalid cs_out value %d for %s %d\n",
379 param->cs_out, name, pin);
Michael Bohane25e15f2012-04-12 17:28:26 -0700380 else
381 return 0;
382
383 return -EINVAL;
384}
385
Michael Bohande3942a2012-04-17 15:28:01 -0700386static inline u8 q_reg_get(u8 *reg, int shift, int mask)
387{
388 return (*reg & mask) >> shift;
389}
390
Michael Bohane25e15f2012-04-12 17:28:26 -0700391static inline void q_reg_set(u8 *reg, int shift, int mask, int value)
392{
393 *reg |= (value << shift) & mask;
394}
395
396static inline void q_reg_clr_set(u8 *reg, int shift, int mask, int value)
397{
398 *reg &= ~mask;
399 *reg |= (value << shift) & mask;
400}
401
Michael Bohan6b901572012-05-30 13:32:24 -0700402/*
403 * Calculate the minimum number of registers that must be read / written
404 * in order to satisfy the full feature set of the given pin.
405 */
406static int qpnp_pin_ctl_regs_init(struct qpnp_pin_spec *q_spec)
407{
408 if (q_spec->type == Q_GPIO_TYPE)
409 q_spec->num_ctl_regs = 7;
410 else if (q_spec->type == Q_MPP_TYPE)
411 switch (q_spec->subtype) {
412 case Q_MPP_SUBTYPE_4CH_NO_SINK:
413 q_spec->num_ctl_regs = 12;
414 break;
415 case Q_MPP_SUBTYPE_4CH_NO_ANA_OUT:
416 case Q_MPP_SUBTYPE_4CH_FULL_FUNC:
417 case Q_MPP_SUBTYPE_8CH_FULL_FUNC:
418 q_spec->num_ctl_regs = 13;
419 break;
420 default:
421 pr_err("Invalid MPP subtype 0x%x\n", q_spec->subtype);
422 return -EINVAL;
423 }
424 else {
425 pr_err("Invalid type 0x%x\n", q_spec->type);
426 return -EINVAL;
427 }
428 return 0;
429}
430
431static int qpnp_pin_read_regs(struct qpnp_pin_chip *q_chip,
Michael Bohand3cf9b02012-08-15 23:23:52 -0700432 struct qpnp_pin_spec *q_spec)
Michael Bohan6b901572012-05-30 13:32:24 -0700433{
434 int bytes_left = q_spec->num_ctl_regs;
435 int rc;
Michael Bohand3cf9b02012-08-15 23:23:52 -0700436 char *buf_p = &q_spec->regs[0];
437 u16 reg_addr = Q_REG_ADDR(q_spec, Q_REG_MODE_CTL);
Michael Bohan6b901572012-05-30 13:32:24 -0700438
439 while (bytes_left > 0) {
440 rc = spmi_ext_register_readl(q_chip->spmi->ctrl, q_spec->slave,
Michael Bohand3cf9b02012-08-15 23:23:52 -0700441 reg_addr, buf_p, bytes_left < 8 ? bytes_left : 8);
Michael Bohan6b901572012-05-30 13:32:24 -0700442 if (rc)
443 return rc;
444 bytes_left -= 8;
Michael Bohand3cf9b02012-08-15 23:23:52 -0700445 buf_p += 8;
446 reg_addr += 8;
Michael Bohan6b901572012-05-30 13:32:24 -0700447 }
448 return 0;
449}
450
451static int qpnp_pin_write_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_writel(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
Michael Bohana05f4552012-05-24 15:58:11 -0700471static int qpnp_pin_cache_regs(struct qpnp_pin_chip *q_chip,
Michael Bohan6b901572012-05-30 13:32:24 -0700472 struct qpnp_pin_spec *q_spec)
Michael Bohande3942a2012-04-17 15:28:01 -0700473{
474 int rc;
475 struct device *dev = &q_chip->spmi->dev;
476
Michael Bohand3cf9b02012-08-15 23:23:52 -0700477 rc = qpnp_pin_read_regs(q_chip, q_spec);
Michael Bohande3942a2012-04-17 15:28:01 -0700478 if (rc)
479 dev_err(dev, "%s: unable to read control regs\n", __func__);
480
481 return rc;
482}
483
Michael Bohan58d07802012-05-31 15:37:55 -0700484#define Q_HAVE_HW_SP(idx, q_spec, val) \
485 (qpnp_pin_check_config(idx, q_spec, val) == 0)
486
Michael Bohana05f4552012-05-24 15:58:11 -0700487static int _qpnp_pin_config(struct qpnp_pin_chip *q_chip,
Michael Bohan6b901572012-05-30 13:32:24 -0700488 struct qpnp_pin_spec *q_spec,
489 struct qpnp_pin_cfg *param)
Michael Bohane25e15f2012-04-12 17:28:26 -0700490{
491 struct device *dev = &q_chip->spmi->dev;
492 int rc;
493
Michael Bohan58d07802012-05-31 15:37:55 -0700494 rc = qpnp_pin_check_constraints(q_spec, param);
Michael Bohane25e15f2012-04-12 17:28:26 -0700495 if (rc)
496 goto gpio_cfg;
497
Michael Bohan6b901572012-05-30 13:32:24 -0700498 /* set mode */
499 if (Q_HAVE_HW_SP(Q_PIN_CFG_MODE, q_spec, param->mode))
Michael Bohan58d07802012-05-31 15:37:55 -0700500 q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700501 Q_REG_MODE_SEL_SHIFT, Q_REG_MODE_SEL_MASK,
Michael Bohan6b901572012-05-30 13:32:24 -0700502 param->mode);
Michael Bohane25e15f2012-04-12 17:28:26 -0700503
504 /* output specific configuration */
Michael Bohan58d07802012-05-31 15:37:55 -0700505 if (Q_HAVE_HW_SP(Q_PIN_CFG_INVERT, q_spec, param->invert))
506 q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700507 Q_REG_OUT_INVERT_SHIFT, Q_REG_OUT_INVERT_MASK,
508 param->invert);
Michael Bohand734fb22012-10-30 14:19:22 -0700509 if (Q_HAVE_HW_SP(Q_PIN_CFG_SRC_SEL, q_spec, param->src_sel))
Michael Bohan58d07802012-05-31 15:37:55 -0700510 q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700511 Q_REG_SRC_SEL_SHIFT, Q_REG_SRC_SEL_MASK,
Michael Bohand734fb22012-10-30 14:19:22 -0700512 param->src_sel);
Michael Bohan58d07802012-05-31 15:37:55 -0700513 if (Q_HAVE_HW_SP(Q_PIN_CFG_OUT_STRENGTH, q_spec, param->out_strength))
514 q_reg_clr_set(&q_spec->regs[Q_REG_I_DIG_OUT_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700515 Q_REG_OUT_STRENGTH_SHIFT, Q_REG_OUT_STRENGTH_MASK,
516 param->out_strength);
Michael Bohan58d07802012-05-31 15:37:55 -0700517 if (Q_HAVE_HW_SP(Q_PIN_CFG_OUTPUT_TYPE, q_spec, param->output_type))
518 q_reg_clr_set(&q_spec->regs[Q_REG_I_DIG_OUT_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700519 Q_REG_OUT_TYPE_SHIFT, Q_REG_OUT_TYPE_MASK,
520 param->output_type);
521
522 /* config applicable for both input / output */
Michael Bohan58d07802012-05-31 15:37:55 -0700523 if (Q_HAVE_HW_SP(Q_PIN_CFG_VIN_SEL, q_spec, param->vin_sel))
524 q_reg_clr_set(&q_spec->regs[Q_REG_I_DIG_VIN_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700525 Q_REG_VIN_SHIFT, Q_REG_VIN_MASK,
526 param->vin_sel);
Michael Bohan58d07802012-05-31 15:37:55 -0700527 if (Q_HAVE_HW_SP(Q_PIN_CFG_PULL, q_spec, param->pull))
528 q_reg_clr_set(&q_spec->regs[Q_REG_I_DIG_PULL_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700529 Q_REG_PULL_SHIFT, Q_REG_PULL_MASK,
530 param->pull);
Michael Bohan58d07802012-05-31 15:37:55 -0700531 if (Q_HAVE_HW_SP(Q_PIN_CFG_MASTER_EN, q_spec, param->master_en))
532 q_reg_clr_set(&q_spec->regs[Q_REG_I_EN_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700533 Q_REG_MASTER_EN_SHIFT, Q_REG_MASTER_EN_MASK,
534 param->master_en);
535
Michael Bohan6b901572012-05-30 13:32:24 -0700536 /* mpp specific config */
537 if (Q_HAVE_HW_SP(Q_PIN_CFG_AOUT_REF, q_spec, param->aout_ref))
538 q_reg_clr_set(&q_spec->regs[Q_REG_I_AOUT_CTL],
539 Q_REG_AOUT_REF_SHIFT, Q_REG_AOUT_REF_MASK,
540 param->aout_ref);
541 if (Q_HAVE_HW_SP(Q_PIN_CFG_AIN_ROUTE, q_spec, param->ain_route))
542 q_reg_clr_set(&q_spec->regs[Q_REG_I_AIN_CTL],
543 Q_REG_AIN_ROUTE_SHIFT, Q_REG_AIN_ROUTE_MASK,
544 param->ain_route);
545 if (Q_HAVE_HW_SP(Q_PIN_CFG_CS_OUT, q_spec, param->cs_out))
546 q_reg_clr_set(&q_spec->regs[Q_REG_I_SINK_CTL],
547 Q_REG_CS_OUT_SHIFT, Q_REG_CS_OUT_MASK,
548 param->cs_out);
549
Michael Bohand3cf9b02012-08-15 23:23:52 -0700550 rc = qpnp_pin_write_regs(q_chip, q_spec);
Michael Bohane25e15f2012-04-12 17:28:26 -0700551 if (rc) {
Michael Bohan6ea2cd22012-05-29 15:40:18 -0700552 dev_err(&q_chip->spmi->dev, "%s: unable to write master enable\n",
553 __func__);
Michael Bohane25e15f2012-04-12 17:28:26 -0700554 goto gpio_cfg;
555 }
556
557 return 0;
558
559gpio_cfg:
Michael Bohan91c5a042012-08-11 13:29:42 -0700560 dev_err(dev, "%s: unable to set default config for pmic pin %d\n",
Michael Bohana05f4552012-05-24 15:58:11 -0700561 __func__, q_spec->pmic_pin);
Michael Bohane25e15f2012-04-12 17:28:26 -0700562
563 return rc;
564}
565
Michael Bohana05f4552012-05-24 15:58:11 -0700566int qpnp_pin_config(int gpio, struct qpnp_pin_cfg *param)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800567{
568 int rc, chip_offset;
Michael Bohana05f4552012-05-24 15:58:11 -0700569 struct qpnp_pin_chip *q_chip;
570 struct qpnp_pin_spec *q_spec = NULL;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800571 struct gpio_chip *gpio_chip;
572
573 if (param == NULL)
574 return -EINVAL;
575
Michael Bohana05f4552012-05-24 15:58:11 -0700576 mutex_lock(&qpnp_pin_chips_lock);
577 list_for_each_entry(q_chip, &qpnp_pin_chips, chip_list) {
Michael Bohan0ba63b82012-02-06 13:42:34 -0800578 gpio_chip = &q_chip->gpio_chip;
579 if (gpio >= gpio_chip->base
580 && gpio < gpio_chip->base + gpio_chip->ngpio) {
581 chip_offset = gpio - gpio_chip->base;
582 q_spec = qpnp_chip_gpio_get_spec(q_chip, chip_offset);
583 if (WARN_ON(!q_spec)) {
Michael Bohana05f4552012-05-24 15:58:11 -0700584 mutex_unlock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800585 return -ENODEV;
586 }
587 break;
588 }
589 }
Michael Bohana05f4552012-05-24 15:58:11 -0700590 mutex_unlock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800591
Zhenhua Huang30acf242013-07-11 01:52:36 +0800592 if (!q_spec)
593 return -ENODEV;
594
Michael Bohana05f4552012-05-24 15:58:11 -0700595 rc = _qpnp_pin_config(q_chip, q_spec, param);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800596
597 return rc;
598}
Michael Bohana05f4552012-05-24 15:58:11 -0700599EXPORT_SYMBOL(qpnp_pin_config);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800600
Michael Bohan6ea2cd22012-05-29 15:40:18 -0700601#define Q_MAX_CHIP_NAME 128
602int qpnp_pin_map(const char *name, uint32_t pmic_pin)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800603{
Michael Bohana05f4552012-05-24 15:58:11 -0700604 struct qpnp_pin_chip *q_chip;
605 struct qpnp_pin_spec *q_spec = NULL;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800606
Michael Bohana05f4552012-05-24 15:58:11 -0700607 mutex_lock(&qpnp_pin_chips_lock);
608 list_for_each_entry(q_chip, &qpnp_pin_chips, chip_list) {
Michael Bohan6ea2cd22012-05-29 15:40:18 -0700609 if (strncmp(q_chip->gpio_chip.label, name,
610 Q_MAX_CHIP_NAME) != 0)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800611 continue;
Michael Bohana05f4552012-05-24 15:58:11 -0700612 if (q_chip->pmic_pin_lowest <= pmic_pin &&
613 q_chip->pmic_pin_highest >= pmic_pin) {
614 q_spec = qpnp_pmic_pin_get_spec(q_chip, pmic_pin);
615 mutex_unlock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800616 if (WARN_ON(!q_spec))
617 return -ENODEV;
618 return q_chip->gpio_chip.base + q_spec->gpio_chip_idx;
619 }
620 }
Michael Bohana05f4552012-05-24 15:58:11 -0700621 mutex_unlock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800622 return -EINVAL;
623}
Michael Bohana05f4552012-05-24 15:58:11 -0700624EXPORT_SYMBOL(qpnp_pin_map);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800625
Michael Bohana05f4552012-05-24 15:58:11 -0700626static int qpnp_pin_to_irq(struct gpio_chip *gpio_chip, unsigned offset)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800627{
Michael Bohana05f4552012-05-24 15:58:11 -0700628 struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
629 struct qpnp_pin_spec *q_spec;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800630
631 q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
632 if (!q_spec)
633 return -EINVAL;
634
635 return q_spec->irq;
636}
637
Michael Bohana05f4552012-05-24 15:58:11 -0700638static int qpnp_pin_get(struct gpio_chip *gpio_chip, unsigned offset)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800639{
640 int rc, ret_val;
Michael Bohana05f4552012-05-24 15:58:11 -0700641 struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
642 struct qpnp_pin_spec *q_spec = NULL;
Michael Bohanffa16812012-08-15 18:11:49 -0700643 u8 buf[1], en_mask;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800644
645 if (WARN_ON(!q_chip))
646 return -ENODEV;
647
648 q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
649 if (WARN_ON(!q_spec))
650 return -ENODEV;
651
652 /* gpio val is from RT status iff input is enabled */
Michael Bohane25e15f2012-04-12 17:28:26 -0700653 if ((q_spec->regs[Q_REG_I_MODE_CTL] & Q_REG_MODE_SEL_MASK)
Michael Bohan6b901572012-05-30 13:32:24 -0700654 == QPNP_PIN_MODE_DIG_IN) {
Michael Bohan0ba63b82012-02-06 13:42:34 -0800655 rc = spmi_ext_register_readl(q_chip->spmi->ctrl, q_spec->slave,
656 Q_REG_ADDR(q_spec, Q_REG_STATUS1),
657 &buf[0], 1);
Michael Bohanffa16812012-08-15 18:11:49 -0700658
Michael Bohanbfe64c72012-08-24 16:57:26 -0700659 if (q_spec->type == Q_GPIO_TYPE && q_spec->dig_major_rev == 0)
660 en_mask = Q_REG_STATUS1_GPIO_EN_REV0_MASK;
661 else if (q_spec->type == Q_GPIO_TYPE &&
662 q_spec->dig_major_rev > 0)
663 en_mask = Q_REG_STATUS1_GPIO_EN_MASK;
664 else /* MPP */
665 en_mask = Q_REG_STATUS1_MPP_EN_MASK;
666
Michael Bohanffa16812012-08-15 18:11:49 -0700667 if (!(buf[0] & en_mask))
668 return -EPERM;
669
670 return buf[0] & Q_REG_STATUS1_VAL_MASK;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800671
672 } else {
Michael Bohane25e15f2012-04-12 17:28:26 -0700673 ret_val = (q_spec->regs[Q_REG_I_MODE_CTL] &
Michael Bohan0ba63b82012-02-06 13:42:34 -0800674 Q_REG_OUT_INVERT_MASK) >> Q_REG_OUT_INVERT_SHIFT;
675 return ret_val;
676 }
677
678 return 0;
679}
680
Michael Bohana05f4552012-05-24 15:58:11 -0700681static int __qpnp_pin_set(struct qpnp_pin_chip *q_chip,
682 struct qpnp_pin_spec *q_spec, int value)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800683{
684 int rc;
685
686 if (!q_chip || !q_spec)
687 return -EINVAL;
688
Michael Bohan0ba63b82012-02-06 13:42:34 -0800689 if (value)
Michael Bohane25e15f2012-04-12 17:28:26 -0700690 q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
691 Q_REG_OUT_INVERT_SHIFT, Q_REG_OUT_INVERT_MASK, 1);
692 else
693 q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
694 Q_REG_OUT_INVERT_SHIFT, Q_REG_OUT_INVERT_MASK, 0);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800695
696 rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
Michael Bohand3cf9b02012-08-15 23:23:52 -0700697 Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
Michael Bohane25e15f2012-04-12 17:28:26 -0700698 &q_spec->regs[Q_REG_I_MODE_CTL], 1);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800699 if (rc)
700 dev_err(&q_chip->spmi->dev, "%s: spmi write failed\n",
701 __func__);
702 return rc;
703}
704
705
Michael Bohana05f4552012-05-24 15:58:11 -0700706static void qpnp_pin_set(struct gpio_chip *gpio_chip,
Michael Bohan0ba63b82012-02-06 13:42:34 -0800707 unsigned offset, int value)
708{
Michael Bohana05f4552012-05-24 15:58:11 -0700709 struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
710 struct qpnp_pin_spec *q_spec;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800711
712 if (WARN_ON(!q_chip))
713 return;
714
715 q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
716 if (WARN_ON(!q_spec))
717 return;
718
Michael Bohana05f4552012-05-24 15:58:11 -0700719 __qpnp_pin_set(q_chip, q_spec, value);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800720}
721
Michael Bohan6b901572012-05-30 13:32:24 -0700722static int qpnp_pin_set_mode(struct qpnp_pin_chip *q_chip,
723 struct qpnp_pin_spec *q_spec, int mode)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800724{
725 int rc;
726
727 if (!q_chip || !q_spec)
728 return -EINVAL;
729
Michael Bohan1c3d94f2012-08-11 14:33:03 -0700730 if (qpnp_pin_check_config(Q_PIN_CFG_MODE, q_spec, mode)) {
Michael Bohan6b901572012-05-30 13:32:24 -0700731 pr_err("invalid mode specification %d\n", mode);
Michael Bohane25e15f2012-04-12 17:28:26 -0700732 return -EINVAL;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800733 }
734
Michael Bohane25e15f2012-04-12 17:28:26 -0700735 q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
736 Q_REG_MODE_SEL_SHIFT,
737 Q_REG_MODE_SEL_MASK,
Michael Bohan6b901572012-05-30 13:32:24 -0700738 mode);
Michael Bohane25e15f2012-04-12 17:28:26 -0700739
Michael Bohan0ba63b82012-02-06 13:42:34 -0800740 rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
Michael Bohand3cf9b02012-08-15 23:23:52 -0700741 Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
Michael Bohane25e15f2012-04-12 17:28:26 -0700742 &q_spec->regs[Q_REG_I_MODE_CTL], 1);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800743 return rc;
744}
745
Michael Bohana05f4552012-05-24 15:58:11 -0700746static int qpnp_pin_direction_input(struct gpio_chip *gpio_chip,
Michael Bohan0ba63b82012-02-06 13:42:34 -0800747 unsigned offset)
748{
Michael Bohana05f4552012-05-24 15:58:11 -0700749 struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
750 struct qpnp_pin_spec *q_spec;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800751
752 if (WARN_ON(!q_chip))
753 return -ENODEV;
754
755 q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
756 if (WARN_ON(!q_spec))
757 return -ENODEV;
758
Michael Bohan6b901572012-05-30 13:32:24 -0700759 return qpnp_pin_set_mode(q_chip, q_spec, QPNP_PIN_MODE_DIG_IN);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800760}
761
Michael Bohana05f4552012-05-24 15:58:11 -0700762static int qpnp_pin_direction_output(struct gpio_chip *gpio_chip,
Michael Bohan0ba63b82012-02-06 13:42:34 -0800763 unsigned offset,
764 int val)
765{
766 int rc;
Michael Bohana05f4552012-05-24 15:58:11 -0700767 struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
768 struct qpnp_pin_spec *q_spec;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800769
770 if (WARN_ON(!q_chip))
771 return -ENODEV;
772
773 q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
774 if (WARN_ON(!q_spec))
775 return -ENODEV;
776
Michael Bohana05f4552012-05-24 15:58:11 -0700777 rc = __qpnp_pin_set(q_chip, q_spec, val);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800778 if (rc)
779 return rc;
780
Michael Bohan6b901572012-05-30 13:32:24 -0700781 rc = qpnp_pin_set_mode(q_chip, q_spec, QPNP_PIN_MODE_DIG_OUT);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800782
783 return rc;
784}
785
Michael Bohana05f4552012-05-24 15:58:11 -0700786static int qpnp_pin_of_gpio_xlate(struct gpio_chip *gpio_chip,
Michael Bohan0b24fb12012-06-01 10:30:12 -0700787 const struct of_phandle_args *gpio_spec,
788 u32 *flags)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800789{
Michael Bohana05f4552012-05-24 15:58:11 -0700790 struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
791 struct qpnp_pin_spec *q_spec;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800792
793 if (WARN_ON(gpio_chip->of_gpio_n_cells < 2)) {
Michael Bohane25e15f2012-04-12 17:28:26 -0700794 pr_err("of_gpio_n_cells < 2\n");
Michael Bohan0ba63b82012-02-06 13:42:34 -0800795 return -EINVAL;
796 }
797
Michael Bohana05f4552012-05-24 15:58:11 -0700798 q_spec = qpnp_pmic_pin_get_spec(q_chip, gpio_spec->args[0]);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800799 if (!q_spec) {
Michael Bohan0b24fb12012-06-01 10:30:12 -0700800 pr_err("no such PMIC gpio %u in device topology\n",
801 gpio_spec->args[0]);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800802 return -EINVAL;
803 }
804
805 if (flags)
Michael Bohan0b24fb12012-06-01 10:30:12 -0700806 *flags = gpio_spec->args[1];
Michael Bohan0ba63b82012-02-06 13:42:34 -0800807
808 return q_spec->gpio_chip_idx;
809}
810
Michael Bohana05f4552012-05-24 15:58:11 -0700811static int qpnp_pin_apply_config(struct qpnp_pin_chip *q_chip,
812 struct qpnp_pin_spec *q_spec)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800813{
Michael Bohana05f4552012-05-24 15:58:11 -0700814 struct qpnp_pin_cfg param;
Michael Bohande3942a2012-04-17 15:28:01 -0700815 struct device_node *node = q_spec->node;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800816 int rc;
817
Michael Bohan6b901572012-05-30 13:32:24 -0700818 param.mode = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
Michael Bohande3942a2012-04-17 15:28:01 -0700819 Q_REG_MODE_SEL_SHIFT,
820 Q_REG_MODE_SEL_MASK);
821 param.output_type = q_reg_get(&q_spec->regs[Q_REG_I_DIG_OUT_CTL],
822 Q_REG_OUT_TYPE_SHIFT,
823 Q_REG_OUT_TYPE_MASK);
824 param.invert = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
Michael Bohand3cf9b02012-08-15 23:23:52 -0700825 Q_REG_OUT_INVERT_SHIFT,
Michael Bohande3942a2012-04-17 15:28:01 -0700826 Q_REG_OUT_INVERT_MASK);
Michael Bohan26324a22013-03-20 10:15:33 -0700827 param.pull = q_reg_get(&q_spec->regs[Q_REG_I_DIG_PULL_CTL],
Michael Bohande3942a2012-04-17 15:28:01 -0700828 Q_REG_PULL_SHIFT, Q_REG_PULL_MASK);
829 param.vin_sel = q_reg_get(&q_spec->regs[Q_REG_I_DIG_VIN_CTL],
830 Q_REG_VIN_SHIFT, Q_REG_VIN_MASK);
831 param.out_strength = q_reg_get(&q_spec->regs[Q_REG_I_DIG_OUT_CTL],
832 Q_REG_OUT_STRENGTH_SHIFT,
833 Q_REG_OUT_STRENGTH_MASK);
Michael Bohand734fb22012-10-30 14:19:22 -0700834 param.src_sel = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
Michael Bohande3942a2012-04-17 15:28:01 -0700835 Q_REG_SRC_SEL_SHIFT, Q_REG_SRC_SEL_MASK);
836 param.master_en = q_reg_get(&q_spec->regs[Q_REG_I_EN_CTL],
837 Q_REG_MASTER_EN_SHIFT,
838 Q_REG_MASTER_EN_MASK);
Michael Bohan6b901572012-05-30 13:32:24 -0700839 param.aout_ref = q_reg_get(&q_spec->regs[Q_REG_I_AOUT_CTL],
840 Q_REG_AOUT_REF_SHIFT,
841 Q_REG_AOUT_REF_MASK);
842 param.ain_route = q_reg_get(&q_spec->regs[Q_REG_I_AIN_CTL],
843 Q_REG_AIN_ROUTE_SHIFT,
844 Q_REG_AIN_ROUTE_MASK);
845 param.cs_out = q_reg_get(&q_spec->regs[Q_REG_I_SINK_CTL],
846 Q_REG_CS_OUT_SHIFT,
847 Q_REG_CS_OUT_MASK);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800848
Michael Bohan6b901572012-05-30 13:32:24 -0700849 of_property_read_u32(node, "qcom,mode",
850 &param.mode);
Michael Bohande3942a2012-04-17 15:28:01 -0700851 of_property_read_u32(node, "qcom,output-type",
852 &param.output_type);
853 of_property_read_u32(node, "qcom,invert",
854 &param.invert);
855 of_property_read_u32(node, "qcom,pull",
856 &param.pull);
857 of_property_read_u32(node, "qcom,vin-sel",
858 &param.vin_sel);
859 of_property_read_u32(node, "qcom,out-strength",
860 &param.out_strength);
Michael Bohand734fb22012-10-30 14:19:22 -0700861 of_property_read_u32(node, "qcom,src-sel",
862 &param.src_sel);
Michael Bohan6b901572012-05-30 13:32:24 -0700863 of_property_read_u32(node, "qcom,master-en",
Michael Bohande3942a2012-04-17 15:28:01 -0700864 &param.master_en);
Michael Bohan6b901572012-05-30 13:32:24 -0700865 of_property_read_u32(node, "qcom,aout-ref",
866 &param.aout_ref);
867 of_property_read_u32(node, "qcom,ain-route",
868 &param.ain_route);
869 of_property_read_u32(node, "qcom,cs-out",
870 &param.cs_out);
Michael Bohana05f4552012-05-24 15:58:11 -0700871 rc = _qpnp_pin_config(q_chip, q_spec, &param);
Michael Bohande3942a2012-04-17 15:28:01 -0700872
Michael Bohan0ba63b82012-02-06 13:42:34 -0800873 return rc;
874}
875
Michael Bohana05f4552012-05-24 15:58:11 -0700876static int qpnp_pin_free_chip(struct qpnp_pin_chip *q_chip)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800877{
878 struct spmi_device *spmi = q_chip->spmi;
879 int rc, i;
880
881 if (q_chip->chip_gpios)
882 for (i = 0; i < spmi->num_dev_node; i++)
883 kfree(q_chip->chip_gpios[i]);
884
Michael Bohana05f4552012-05-24 15:58:11 -0700885 mutex_lock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800886 list_del(&q_chip->chip_list);
Michael Bohana05f4552012-05-24 15:58:11 -0700887 mutex_unlock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800888 rc = gpiochip_remove(&q_chip->gpio_chip);
889 if (rc)
890 dev_err(&q_chip->spmi->dev, "%s: unable to remove gpio\n",
891 __func__);
892 kfree(q_chip->chip_gpios);
Michael Bohana05f4552012-05-24 15:58:11 -0700893 kfree(q_chip->pmic_pins);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800894 kfree(q_chip);
895 return rc;
896}
897
Michael Bohana05f4552012-05-24 15:58:11 -0700898#ifdef CONFIG_GPIO_QPNP_PIN_DEBUG
899struct qpnp_pin_reg {
Michael Bohana19dced2012-04-24 13:14:50 -0700900 uint32_t addr;
901 uint32_t idx;
902 uint32_t shift;
903 uint32_t mask;
904};
905
906static struct dentry *driver_dfs_dir;
907
Michael Bohana05f4552012-05-24 15:58:11 -0700908static int qpnp_pin_reg_attr(enum qpnp_pin_param_type type,
909 struct qpnp_pin_reg *cfg)
Michael Bohana19dced2012-04-24 13:14:50 -0700910{
911 switch (type) {
Michael Bohan6b901572012-05-30 13:32:24 -0700912 case Q_PIN_CFG_MODE:
Michael Bohana19dced2012-04-24 13:14:50 -0700913 cfg->addr = Q_REG_MODE_CTL;
914 cfg->idx = Q_REG_I_MODE_CTL;
915 cfg->shift = Q_REG_MODE_SEL_SHIFT;
916 cfg->mask = Q_REG_MODE_SEL_MASK;
917 break;
Michael Bohana05f4552012-05-24 15:58:11 -0700918 case Q_PIN_CFG_OUTPUT_TYPE:
Michael Bohana19dced2012-04-24 13:14:50 -0700919 cfg->addr = Q_REG_DIG_OUT_CTL;
920 cfg->idx = Q_REG_I_DIG_OUT_CTL;
921 cfg->shift = Q_REG_OUT_TYPE_SHIFT;
922 cfg->mask = Q_REG_OUT_TYPE_MASK;
923 break;
Michael Bohana05f4552012-05-24 15:58:11 -0700924 case Q_PIN_CFG_INVERT:
Michael Bohana19dced2012-04-24 13:14:50 -0700925 cfg->addr = Q_REG_MODE_CTL;
926 cfg->idx = Q_REG_I_MODE_CTL;
927 cfg->shift = Q_REG_OUT_INVERT_SHIFT;
928 cfg->mask = Q_REG_OUT_INVERT_MASK;
929 break;
Michael Bohana05f4552012-05-24 15:58:11 -0700930 case Q_PIN_CFG_PULL:
Michael Bohana19dced2012-04-24 13:14:50 -0700931 cfg->addr = Q_REG_DIG_PULL_CTL;
932 cfg->idx = Q_REG_I_DIG_PULL_CTL;
933 cfg->shift = Q_REG_PULL_SHIFT;
934 cfg->mask = Q_REG_PULL_MASK;
935 break;
Michael Bohana05f4552012-05-24 15:58:11 -0700936 case Q_PIN_CFG_VIN_SEL:
Michael Bohana19dced2012-04-24 13:14:50 -0700937 cfg->addr = Q_REG_DIG_VIN_CTL;
938 cfg->idx = Q_REG_I_DIG_VIN_CTL;
939 cfg->shift = Q_REG_VIN_SHIFT;
940 cfg->mask = Q_REG_VIN_MASK;
941 break;
Michael Bohana05f4552012-05-24 15:58:11 -0700942 case Q_PIN_CFG_OUT_STRENGTH:
Michael Bohana19dced2012-04-24 13:14:50 -0700943 cfg->addr = Q_REG_DIG_OUT_CTL;
944 cfg->idx = Q_REG_I_DIG_OUT_CTL;
945 cfg->shift = Q_REG_OUT_STRENGTH_SHIFT;
946 cfg->mask = Q_REG_OUT_STRENGTH_MASK;
947 break;
Michael Bohand734fb22012-10-30 14:19:22 -0700948 case Q_PIN_CFG_SRC_SEL:
Michael Bohana19dced2012-04-24 13:14:50 -0700949 cfg->addr = Q_REG_MODE_CTL;
950 cfg->idx = Q_REG_I_MODE_CTL;
951 cfg->shift = Q_REG_SRC_SEL_SHIFT;
952 cfg->mask = Q_REG_SRC_SEL_MASK;
953 break;
Michael Bohana05f4552012-05-24 15:58:11 -0700954 case Q_PIN_CFG_MASTER_EN:
Michael Bohana19dced2012-04-24 13:14:50 -0700955 cfg->addr = Q_REG_EN_CTL;
956 cfg->idx = Q_REG_I_EN_CTL;
957 cfg->shift = Q_REG_MASTER_EN_SHIFT;
958 cfg->mask = Q_REG_MASTER_EN_MASK;
959 break;
Michael Bohan6b901572012-05-30 13:32:24 -0700960 case Q_PIN_CFG_AOUT_REF:
961 cfg->addr = Q_REG_AOUT_CTL;
962 cfg->idx = Q_REG_I_AOUT_CTL;
963 cfg->shift = Q_REG_AOUT_REF_SHIFT;
964 cfg->mask = Q_REG_AOUT_REF_MASK;
965 break;
966 case Q_PIN_CFG_AIN_ROUTE:
967 cfg->addr = Q_REG_AIN_CTL;
968 cfg->idx = Q_REG_I_AIN_CTL;
969 cfg->shift = Q_REG_AIN_ROUTE_SHIFT;
970 cfg->mask = Q_REG_AIN_ROUTE_MASK;
971 break;
972 case Q_PIN_CFG_CS_OUT:
973 cfg->addr = Q_REG_SINK_CTL;
974 cfg->idx = Q_REG_I_SINK_CTL;
975 cfg->shift = Q_REG_CS_OUT_SHIFT;
976 cfg->mask = Q_REG_CS_OUT_MASK;
977 break;
Michael Bohana19dced2012-04-24 13:14:50 -0700978 default:
979 return -EINVAL;
980 }
981
982 return 0;
983}
984
Michael Bohana05f4552012-05-24 15:58:11 -0700985static int qpnp_pin_debugfs_get(void *data, u64 *val)
Michael Bohana19dced2012-04-24 13:14:50 -0700986{
Michael Bohana05f4552012-05-24 15:58:11 -0700987 enum qpnp_pin_param_type *idx = data;
988 struct qpnp_pin_spec *q_spec;
989 struct qpnp_pin_reg cfg = {};
Michael Bohana19dced2012-04-24 13:14:50 -0700990 int rc;
991
Michael Bohana05f4552012-05-24 15:58:11 -0700992 rc = qpnp_pin_reg_attr(*idx, &cfg);
Michael Bohana19dced2012-04-24 13:14:50 -0700993 if (rc)
994 return rc;
Michael Bohana05f4552012-05-24 15:58:11 -0700995 q_spec = container_of(idx, struct qpnp_pin_spec, params[*idx]);
Michael Bohana19dced2012-04-24 13:14:50 -0700996 *val = q_reg_get(&q_spec->regs[cfg.idx], cfg.shift, cfg.mask);
997 return 0;
998}
999
Michael Bohana05f4552012-05-24 15:58:11 -07001000static int qpnp_pin_debugfs_set(void *data, u64 val)
Michael Bohana19dced2012-04-24 13:14:50 -07001001{
Michael Bohana05f4552012-05-24 15:58:11 -07001002 enum qpnp_pin_param_type *idx = data;
1003 struct qpnp_pin_spec *q_spec;
1004 struct qpnp_pin_chip *q_chip;
1005 struct qpnp_pin_reg cfg = {};
Michael Bohana19dced2012-04-24 13:14:50 -07001006 int rc;
1007
Michael Bohana05f4552012-05-24 15:58:11 -07001008 q_spec = container_of(idx, struct qpnp_pin_spec, params[*idx]);
Michael Bohana19dced2012-04-24 13:14:50 -07001009 q_chip = q_spec->q_chip;
1010
Michael Bohan58d07802012-05-31 15:37:55 -07001011 rc = qpnp_pin_check_config(*idx, q_spec, val);
Michael Bohana19dced2012-04-24 13:14:50 -07001012 if (rc)
1013 return rc;
1014
Michael Bohana05f4552012-05-24 15:58:11 -07001015 rc = qpnp_pin_reg_attr(*idx, &cfg);
Michael Bohana19dced2012-04-24 13:14:50 -07001016 if (rc)
1017 return rc;
1018 q_reg_clr_set(&q_spec->regs[cfg.idx], cfg.shift, cfg.mask, val);
1019 rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
1020 Q_REG_ADDR(q_spec, cfg.addr),
1021 &q_spec->regs[cfg.idx], 1);
1022
1023 return rc;
1024}
Michael Bohana05f4552012-05-24 15:58:11 -07001025DEFINE_SIMPLE_ATTRIBUTE(qpnp_pin_fops, qpnp_pin_debugfs_get,
1026 qpnp_pin_debugfs_set, "%llu\n");
Michael Bohana19dced2012-04-24 13:14:50 -07001027
1028#define DEBUGFS_BUF_SIZE 11 /* supports 2^32 in decimal */
1029
Michael Bohana05f4552012-05-24 15:58:11 -07001030struct qpnp_pin_debugfs_args {
1031 enum qpnp_pin_param_type type;
Michael Bohana19dced2012-04-24 13:14:50 -07001032 const char *filename;
1033};
1034
Michael Bohana05f4552012-05-24 15:58:11 -07001035static struct qpnp_pin_debugfs_args dfs_args[] = {
Michael Bohan6b901572012-05-30 13:32:24 -07001036 { Q_PIN_CFG_MODE, "mode" },
Michael Bohana05f4552012-05-24 15:58:11 -07001037 { Q_PIN_CFG_OUTPUT_TYPE, "output_type" },
1038 { Q_PIN_CFG_INVERT, "invert" },
1039 { Q_PIN_CFG_PULL, "pull" },
1040 { Q_PIN_CFG_VIN_SEL, "vin_sel" },
1041 { Q_PIN_CFG_OUT_STRENGTH, "out_strength" },
Michael Bohand734fb22012-10-30 14:19:22 -07001042 { Q_PIN_CFG_SRC_SEL, "src_sel" },
Michael Bohan6b901572012-05-30 13:32:24 -07001043 { Q_PIN_CFG_MASTER_EN, "master_en" },
1044 { Q_PIN_CFG_AOUT_REF, "aout_ref" },
1045 { Q_PIN_CFG_AIN_ROUTE, "ain_route" },
1046 { Q_PIN_CFG_CS_OUT, "cs_out" },
Michael Bohana19dced2012-04-24 13:14:50 -07001047};
1048
Michael Bohana05f4552012-05-24 15:58:11 -07001049static int qpnp_pin_debugfs_create(struct qpnp_pin_chip *q_chip)
Michael Bohana19dced2012-04-24 13:14:50 -07001050{
1051 struct spmi_device *spmi = q_chip->spmi;
1052 struct device *dev = &spmi->dev;
Michael Bohana05f4552012-05-24 15:58:11 -07001053 struct qpnp_pin_spec *q_spec;
1054 enum qpnp_pin_param_type *params;
1055 enum qpnp_pin_param_type type;
1056 char pmic_pin[DEBUGFS_BUF_SIZE];
Michael Bohana19dced2012-04-24 13:14:50 -07001057 const char *filename;
1058 struct dentry *dfs, *dfs_io_dir;
Michael Bohan6b901572012-05-30 13:32:24 -07001059 int i, j, rc;
Michael Bohana19dced2012-04-24 13:14:50 -07001060
1061 BUG_ON(Q_NUM_PARAMS != ARRAY_SIZE(dfs_args));
1062
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001063 q_chip->dfs_dir = debugfs_create_dir(q_chip->gpio_chip.label,
Michael Bohana19dced2012-04-24 13:14:50 -07001064 driver_dfs_dir);
1065 if (q_chip->dfs_dir == NULL) {
1066 dev_err(dev, "%s: cannot register chip debugfs directory %s\n",
1067 __func__, dev->of_node->name);
1068 return -ENODEV;
1069 }
1070
1071 for (i = 0; i < spmi->num_dev_node; i++) {
1072 q_spec = qpnp_chip_gpio_get_spec(q_chip, i);
1073 params = q_spec->params;
Michael Bohana05f4552012-05-24 15:58:11 -07001074 snprintf(pmic_pin, DEBUGFS_BUF_SIZE, "%u", q_spec->pmic_pin);
Michael Bohan6b901572012-05-30 13:32:24 -07001075 dfs_io_dir = debugfs_create_dir(pmic_pin, q_chip->dfs_dir);
Michael Bohana19dced2012-04-24 13:14:50 -07001076 if (dfs_io_dir == NULL)
1077 goto dfs_err;
1078
1079 for (j = 0; j < Q_NUM_PARAMS; j++) {
1080 type = dfs_args[j].type;
1081 filename = dfs_args[j].filename;
1082
Michael Bohan6b901572012-05-30 13:32:24 -07001083 /*
1084 * Use a value of '0' to see if the pin has even basic
1085 * support for a function. Do not create a file if
1086 * it doesn't.
1087 */
1088 rc = qpnp_pin_check_config(type, q_spec, 0);
1089 if (rc == -ENXIO)
1090 continue;
1091
Michael Bohana19dced2012-04-24 13:14:50 -07001092 params[type] = type;
1093 dfs = debugfs_create_file(
1094 filename,
1095 S_IRUGO | S_IWUSR,
1096 dfs_io_dir,
1097 &q_spec->params[type],
Michael Bohana05f4552012-05-24 15:58:11 -07001098 &qpnp_pin_fops);
Michael Bohana19dced2012-04-24 13:14:50 -07001099 if (dfs == NULL)
1100 goto dfs_err;
1101 }
1102 }
1103 return 0;
1104dfs_err:
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001105 dev_err(dev, "%s: cannot register debugfs for pmic gpio %u on chip %s\n",
1106 __func__, q_spec->pmic_pin, dev->of_node->name);
Michael Bohana19dced2012-04-24 13:14:50 -07001107 debugfs_remove_recursive(q_chip->dfs_dir);
1108 return -ENFILE;
1109}
1110#else
Michael Bohana05f4552012-05-24 15:58:11 -07001111static int qpnp_pin_debugfs_create(struct qpnp_pin_chip *q_chip)
Michael Bohana19dced2012-04-24 13:14:50 -07001112{
1113 return 0;
1114}
1115#endif
1116
Michael Bohanbfe64c72012-08-24 16:57:26 -07001117static int qpnp_pin_is_valid_pin(struct qpnp_pin_spec *q_spec)
1118{
1119 if (q_spec->type == Q_GPIO_TYPE)
1120 switch (q_spec->subtype) {
1121 case Q_GPIO_SUBTYPE_GPIO_4CH:
1122 case Q_GPIO_SUBTYPE_GPIOC_4CH:
1123 case Q_GPIO_SUBTYPE_GPIO_8CH:
1124 case Q_GPIO_SUBTYPE_GPIOC_8CH:
1125 return 1;
1126 }
1127 else if (q_spec->type == Q_MPP_TYPE)
1128 switch (q_spec->subtype) {
1129 case Q_MPP_SUBTYPE_4CH_NO_ANA_OUT:
1130 case Q_MPP_SUBTYPE_4CH_NO_SINK:
1131 case Q_MPP_SUBTYPE_4CH_FULL_FUNC:
1132 case Q_MPP_SUBTYPE_8CH_FULL_FUNC:
1133 return 1;
1134 }
1135
1136 return 0;
1137}
1138
Michael Bohana05f4552012-05-24 15:58:11 -07001139static int qpnp_pin_probe(struct spmi_device *spmi)
Michael Bohan0ba63b82012-02-06 13:42:34 -08001140{
Michael Bohana05f4552012-05-24 15:58:11 -07001141 struct qpnp_pin_chip *q_chip;
1142 struct qpnp_pin_spec *q_spec;
Michael Bohan0e5534d2012-05-22 17:33:45 -07001143 struct resource *res;
1144 struct spmi_resource *d_node;
Michael Bohan94e397b2012-04-25 15:21:55 -07001145 int i, rc;
1146 int lowest_gpio = UINT_MAX, highest_gpio = 0;
1147 u32 intspec[3], gpio;
Michael Bohanbfe64c72012-08-24 16:57:26 -07001148 char version[Q_REG_SUBTYPE - Q_REG_DIG_MAJOR_REV + 1];
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001149 const char *dev_name;
1150
1151 dev_name = spmi_get_primary_dev_name(spmi);
1152 if (!dev_name) {
1153 dev_err(&spmi->dev, "%s: label binding undefined for node %s\n",
1154 __func__, spmi->dev.of_node->full_name);
1155 return -EINVAL;
1156 }
Michael Bohan0ba63b82012-02-06 13:42:34 -08001157
1158 q_chip = kzalloc(sizeof(*q_chip), GFP_KERNEL);
1159 if (!q_chip) {
1160 dev_err(&spmi->dev, "%s: Can't allocate gpio_chip\n",
1161 __func__);
1162 return -ENOMEM;
1163 }
1164 q_chip->spmi = spmi;
1165 dev_set_drvdata(&spmi->dev, q_chip);
1166
Michael Bohana05f4552012-05-24 15:58:11 -07001167 mutex_lock(&qpnp_pin_chips_lock);
1168 list_add(&q_chip->chip_list, &qpnp_pin_chips);
1169 mutex_unlock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001170
1171 /* first scan through nodes to find the range required for allocation */
1172 for (i = 0; i < spmi->num_dev_node; i++) {
Michael Bohan94e397b2012-04-25 15:21:55 -07001173 rc = of_property_read_u32(spmi->dev_node[i].of_node,
Michael Bohana05f4552012-05-24 15:58:11 -07001174 "qcom,pin-num", &gpio);
Michael Bohan94e397b2012-04-25 15:21:55 -07001175 if (rc) {
Michael Bohana05f4552012-05-24 15:58:11 -07001176 dev_err(&spmi->dev, "%s: unable to get qcom,pin-num property\n",
1177 __func__);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001178 goto err_probe;
1179 }
1180
Michael Bohan0ba63b82012-02-06 13:42:34 -08001181 if (gpio < lowest_gpio)
1182 lowest_gpio = gpio;
1183 if (gpio > highest_gpio)
1184 highest_gpio = gpio;
1185 }
1186
1187 if (highest_gpio < lowest_gpio) {
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001188 dev_err(&spmi->dev, "%s: no device nodes specified in topology\n",
1189 __func__);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001190 rc = -EINVAL;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001191 goto err_probe;
1192 } else if (lowest_gpio == 0) {
1193 dev_err(&spmi->dev, "%s: 0 is not a valid PMIC GPIO\n",
1194 __func__);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001195 rc = -EINVAL;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001196 goto err_probe;
1197 }
1198
Michael Bohana05f4552012-05-24 15:58:11 -07001199 q_chip->pmic_pin_lowest = lowest_gpio;
1200 q_chip->pmic_pin_highest = highest_gpio;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001201
1202 /* allocate gpio lookup tables */
Michael Bohana05f4552012-05-24 15:58:11 -07001203 q_chip->pmic_pins = kzalloc(sizeof(struct qpnp_pin_spec *) *
Michael Bohan0ba63b82012-02-06 13:42:34 -08001204 highest_gpio - lowest_gpio + 1,
1205 GFP_KERNEL);
Michael Bohana05f4552012-05-24 15:58:11 -07001206 q_chip->chip_gpios = kzalloc(sizeof(struct qpnp_pin_spec *) *
Michael Bohan0ba63b82012-02-06 13:42:34 -08001207 spmi->num_dev_node, GFP_KERNEL);
Michael Bohana05f4552012-05-24 15:58:11 -07001208 if (!q_chip->pmic_pins || !q_chip->chip_gpios) {
Michael Bohan0ba63b82012-02-06 13:42:34 -08001209 dev_err(&spmi->dev, "%s: unable to allocate memory\n",
1210 __func__);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001211 rc = -ENOMEM;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001212 goto err_probe;
1213 }
1214
1215 /* get interrupt controller device_node */
1216 q_chip->int_ctrl = of_irq_find_parent(spmi->dev.of_node);
1217 if (!q_chip->int_ctrl) {
1218 dev_err(&spmi->dev, "%s: Can't find interrupt parent\n",
1219 __func__);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001220 rc = -EINVAL;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001221 goto err_probe;
1222 }
1223
1224 /* now scan through again and populate the lookup table */
1225 for (i = 0; i < spmi->num_dev_node; i++) {
Michael Bohan0e5534d2012-05-22 17:33:45 -07001226 d_node = &spmi->dev_node[i];
1227 res = spmi_get_resource(spmi, d_node, IORESOURCE_MEM, 0);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001228 if (!res) {
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001229 dev_err(&spmi->dev, "%s: node %s is missing has no base address definition\n",
Michael Bohan0e5534d2012-05-22 17:33:45 -07001230 __func__, d_node->of_node->full_name);
Zhenhua Huang30acf242013-07-11 01:52:36 +08001231 rc = -EINVAL;
1232 goto err_probe;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001233 }
1234
Michael Bohan0e5534d2012-05-22 17:33:45 -07001235 rc = of_property_read_u32(d_node->of_node,
Michael Bohana05f4552012-05-24 15:58:11 -07001236 "qcom,pin-num", &gpio);
Michael Bohan94e397b2012-04-25 15:21:55 -07001237 if (rc) {
Michael Bohana05f4552012-05-24 15:58:11 -07001238 dev_err(&spmi->dev, "%s: unable to get qcom,pin-num property\n",
1239 __func__);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001240 goto err_probe;
1241 }
Michael Bohan0ba63b82012-02-06 13:42:34 -08001242
Michael Bohana05f4552012-05-24 15:58:11 -07001243 q_spec = kzalloc(sizeof(struct qpnp_pin_spec),
Michael Bohan0ba63b82012-02-06 13:42:34 -08001244 GFP_KERNEL);
1245 if (!q_spec) {
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001246 dev_err(&spmi->dev, "%s: unable to allocate memory\n",
1247 __func__);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001248 rc = -ENOMEM;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001249 goto err_probe;
1250 }
1251
1252 q_spec->slave = spmi->sid;
1253 q_spec->offset = res->start;
1254 q_spec->gpio_chip_idx = i;
Michael Bohana05f4552012-05-24 15:58:11 -07001255 q_spec->pmic_pin = gpio;
Michael Bohan0e5534d2012-05-22 17:33:45 -07001256 q_spec->node = d_node->of_node;
Michael Bohana19dced2012-04-24 13:14:50 -07001257 q_spec->q_chip = q_chip;
Michael Bohane25e15f2012-04-12 17:28:26 -07001258
1259 rc = spmi_ext_register_readl(spmi->ctrl, q_spec->slave,
Michael Bohanbfe64c72012-08-24 16:57:26 -07001260 Q_REG_ADDR(q_spec, Q_REG_DIG_MAJOR_REV),
1261 &version[0], ARRAY_SIZE(version));
Michael Bohane25e15f2012-04-12 17:28:26 -07001262 if (rc) {
1263 dev_err(&spmi->dev, "%s: unable to read type regs\n",
1264 __func__);
Michael Bohane25e15f2012-04-12 17:28:26 -07001265 goto err_probe;
1266 }
Michael Bohanbfe64c72012-08-24 16:57:26 -07001267 q_spec->dig_major_rev = version[Q_REG_DIG_MAJOR_REV -
1268 Q_REG_DIG_MAJOR_REV];
1269 q_spec->type = version[Q_REG_TYPE - Q_REG_DIG_MAJOR_REV];
1270 q_spec->subtype = version[Q_REG_SUBTYPE - Q_REG_DIG_MAJOR_REV];
1271
1272 if (!qpnp_pin_is_valid_pin(q_spec)) {
1273 dev_err(&spmi->dev, "%s: invalid pin type (type=0x%x subtype=0x%x)\n",
1274 __func__, q_spec->type, q_spec->subtype);
1275 goto err_probe;
1276 }
Michael Bohan0ba63b82012-02-06 13:42:34 -08001277
Michael Bohan6b901572012-05-30 13:32:24 -07001278 rc = qpnp_pin_ctl_regs_init(q_spec);
1279 if (rc)
1280 goto err_probe;
1281
Michael Bohan0ba63b82012-02-06 13:42:34 -08001282 /* call into irq_domain to get irq mapping */
1283 intspec[0] = q_chip->spmi->sid;
1284 intspec[1] = (q_spec->offset >> 8) & 0xFF;
1285 intspec[2] = 0;
1286 q_spec->irq = irq_create_of_mapping(q_chip->int_ctrl,
1287 intspec, 3);
1288 if (!q_spec->irq) {
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001289 dev_err(&spmi->dev, "%s: invalid irq for gpio %u\n",
1290 __func__, gpio);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001291 rc = -EINVAL;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001292 goto err_probe;
1293 }
Michael Bohana19dced2012-04-24 13:14:50 -07001294 /* initialize lookup table params */
Michael Bohana05f4552012-05-24 15:58:11 -07001295 qpnp_pmic_pin_set_spec(q_chip, gpio, q_spec);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001296 qpnp_chip_gpio_set_spec(q_chip, i, q_spec);
1297 }
1298
1299 q_chip->gpio_chip.base = -1;
1300 q_chip->gpio_chip.ngpio = spmi->num_dev_node;
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001301 q_chip->gpio_chip.label = dev_name;
Michael Bohana05f4552012-05-24 15:58:11 -07001302 q_chip->gpio_chip.direction_input = qpnp_pin_direction_input;
1303 q_chip->gpio_chip.direction_output = qpnp_pin_direction_output;
1304 q_chip->gpio_chip.to_irq = qpnp_pin_to_irq;
1305 q_chip->gpio_chip.get = qpnp_pin_get;
1306 q_chip->gpio_chip.set = qpnp_pin_set;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001307 q_chip->gpio_chip.dev = &spmi->dev;
Michael Bohana05f4552012-05-24 15:58:11 -07001308 q_chip->gpio_chip.of_xlate = qpnp_pin_of_gpio_xlate;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001309 q_chip->gpio_chip.of_gpio_n_cells = 2;
1310 q_chip->gpio_chip.can_sleep = 0;
1311
1312 rc = gpiochip_add(&q_chip->gpio_chip);
1313 if (rc) {
1314 dev_err(&spmi->dev, "%s: Can't add gpio chip, rc = %d\n",
1315 __func__, rc);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001316 goto err_probe;
1317 }
1318
Michael Bohande3942a2012-04-17 15:28:01 -07001319 /* now configure gpio config defaults if they exist */
Michael Bohan0ba63b82012-02-06 13:42:34 -08001320 for (i = 0; i < spmi->num_dev_node; i++) {
1321 q_spec = qpnp_chip_gpio_get_spec(q_chip, i);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001322 if (WARN_ON(!q_spec)) {
1323 rc = -ENODEV;
1324 goto err_probe;
1325 }
Michael Bohan0ba63b82012-02-06 13:42:34 -08001326
Michael Bohana05f4552012-05-24 15:58:11 -07001327 rc = qpnp_pin_cache_regs(q_chip, q_spec);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001328 if (rc)
Michael Bohan0ba63b82012-02-06 13:42:34 -08001329 goto err_probe;
Michael Bohande3942a2012-04-17 15:28:01 -07001330
Michael Bohana05f4552012-05-24 15:58:11 -07001331 rc = qpnp_pin_apply_config(q_chip, q_spec);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001332 if (rc)
Michael Bohande3942a2012-04-17 15:28:01 -07001333 goto err_probe;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001334 }
1335
1336 dev_dbg(&spmi->dev, "%s: gpio_chip registered between %d-%u\n",
1337 __func__, q_chip->gpio_chip.base,
1338 (q_chip->gpio_chip.base + q_chip->gpio_chip.ngpio) - 1);
Michael Bohana19dced2012-04-24 13:14:50 -07001339
Michael Bohana05f4552012-05-24 15:58:11 -07001340 rc = qpnp_pin_debugfs_create(q_chip);
Michael Bohana19dced2012-04-24 13:14:50 -07001341 if (rc) {
1342 dev_err(&spmi->dev, "%s: debugfs creation failed\n", __func__);
1343 goto err_probe;
1344 }
1345
Michael Bohan0ba63b82012-02-06 13:42:34 -08001346 return 0;
1347
1348err_probe:
Michael Bohana05f4552012-05-24 15:58:11 -07001349 qpnp_pin_free_chip(q_chip);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001350 return rc;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001351}
1352
Michael Bohana05f4552012-05-24 15:58:11 -07001353static int qpnp_pin_remove(struct spmi_device *spmi)
Michael Bohan0ba63b82012-02-06 13:42:34 -08001354{
Michael Bohana05f4552012-05-24 15:58:11 -07001355 struct qpnp_pin_chip *q_chip = dev_get_drvdata(&spmi->dev);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001356
Michael Bohana19dced2012-04-24 13:14:50 -07001357 debugfs_remove_recursive(q_chip->dfs_dir);
1358
Michael Bohana05f4552012-05-24 15:58:11 -07001359 return qpnp_pin_free_chip(q_chip);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001360}
1361
1362static struct of_device_id spmi_match_table[] = {
Michael Bohana05f4552012-05-24 15:58:11 -07001363 { .compatible = "qcom,qpnp-pin",
Michael Bohan0ba63b82012-02-06 13:42:34 -08001364 },
1365 {}
1366};
1367
Michael Bohana05f4552012-05-24 15:58:11 -07001368static const struct spmi_device_id qpnp_pin_id[] = {
1369 { "qcom,qpnp-pin", 0 },
Michael Bohan0ba63b82012-02-06 13:42:34 -08001370 { }
1371};
Michael Bohana05f4552012-05-24 15:58:11 -07001372MODULE_DEVICE_TABLE(spmi, qpnp_pin_id);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001373
Michael Bohana05f4552012-05-24 15:58:11 -07001374static struct spmi_driver qpnp_pin_driver = {
Michael Bohan0ba63b82012-02-06 13:42:34 -08001375 .driver = {
Michael Bohana05f4552012-05-24 15:58:11 -07001376 .name = "qcom,qpnp-pin",
Michael Bohan0ba63b82012-02-06 13:42:34 -08001377 .of_match_table = spmi_match_table,
1378 },
Michael Bohana05f4552012-05-24 15:58:11 -07001379 .probe = qpnp_pin_probe,
1380 .remove = qpnp_pin_remove,
1381 .id_table = qpnp_pin_id,
Michael Bohan0ba63b82012-02-06 13:42:34 -08001382};
1383
Michael Bohana05f4552012-05-24 15:58:11 -07001384static int __init qpnp_pin_init(void)
Michael Bohan0ba63b82012-02-06 13:42:34 -08001385{
Michael Bohana05f4552012-05-24 15:58:11 -07001386#ifdef CONFIG_GPIO_QPNP_PIN_DEBUG
1387 driver_dfs_dir = debugfs_create_dir("qpnp_pin", NULL);
Michael Bohana19dced2012-04-24 13:14:50 -07001388 if (driver_dfs_dir == NULL)
1389 pr_err("Cannot register top level debugfs directory\n");
1390#endif
1391
Michael Bohana05f4552012-05-24 15:58:11 -07001392 return spmi_driver_register(&qpnp_pin_driver);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001393}
1394
Michael Bohana05f4552012-05-24 15:58:11 -07001395static void __exit qpnp_pin_exit(void)
Michael Bohan0ba63b82012-02-06 13:42:34 -08001396{
Michael Bohana05f4552012-05-24 15:58:11 -07001397#ifdef CONFIG_GPIO_QPNP_PIN_DEBUG
Michael Bohana19dced2012-04-24 13:14:50 -07001398 debugfs_remove_recursive(driver_dfs_dir);
1399#endif
Michael Bohana05f4552012-05-24 15:58:11 -07001400 spmi_driver_unregister(&qpnp_pin_driver);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001401}
1402
Michael Bohan0ba63b82012-02-06 13:42:34 -08001403MODULE_DESCRIPTION("QPNP PMIC gpio driver");
Michael Bohan7f0cc9d2012-04-16 17:16:09 -07001404MODULE_LICENSE("GPL v2");
Michael Bohan0ba63b82012-02-06 13:42:34 -08001405
Michael Bohana05f4552012-05-24 15:58:11 -07001406module_init(qpnp_pin_init);
1407module_exit(qpnp_pin_exit);