blob: bbcba8199c781e247ecb53bf5d8a413eb56cdfb5 [file] [log] [blame]
Michael Bohan0ba63b82012-02-06 13:42:34 -08001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
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 Bohan6b901572012-05-30 13:32:24 -070034#define Q_NUM_CTL_REGS 0xD
Michael Bohane25e15f2012-04-12 17:28:26 -070035
36/* type registers base address offsets */
Michael Bohan6b901572012-05-30 13:32:24 -070037#define Q_REG_TYPE 0x4
38#define Q_REG_SUBTYPE 0x5
Michael Bohane25e15f2012-04-12 17:28:26 -070039
40/* gpio peripheral type and subtype values */
41#define Q_GPIO_TYPE 0x10
Michael Bohan6b901572012-05-30 13:32:24 -070042#define Q_GPIO_SUBTYPE_GPIO_4CH 0x0
43#define Q_GPIO_SUBTYPE_GPIOC_4CH 0x2
44#define Q_GPIO_SUBTYPE_GPIO_8CH 0x4
45#define Q_GPIO_SUBTYPE_GPIOC_8CH 0x6
46
47/* mpp peripheral type and subtype values */
48#define Q_MPP_TYPE 0x11
49#define Q_MPP_SUBTYPE_4CH_NO_ANA_OUT 0x1
50#define Q_MPP_SUBTYPE_4CH_NO_SINK 0x2
51#define Q_MPP_SUBTYPE_4CH_FULL_FUNC 0x3
52#define Q_MPP_SUBTYPE_8CH_FULL_FUNC 0x7
Michael Bohan0ba63b82012-02-06 13:42:34 -080053
54/* control register base address offsets */
Michael Bohane25e15f2012-04-12 17:28:26 -070055#define Q_REG_MODE_CTL 0x40
Michael Bohan6b901572012-05-30 13:32:24 -070056#define Q_REG_DIG_VIN_CTL 0x41
Michael Bohane25e15f2012-04-12 17:28:26 -070057#define Q_REG_DIG_PULL_CTL 0x42
58#define Q_REG_DIG_IN_CTL 0x43
Michael Bohane25e15f2012-04-12 17:28:26 -070059#define Q_REG_DIG_OUT_CTL 0x45
60#define Q_REG_EN_CTL 0x46
Michael Bohan6b901572012-05-30 13:32:24 -070061#define Q_REG_AOUT_CTL 0x48
62#define Q_REG_AIN_CTL 0x4A
63#define Q_REG_SINK_CTL 0x4C
Michael Bohan0ba63b82012-02-06 13:42:34 -080064
65/* control register regs array indices */
Michael Bohane25e15f2012-04-12 17:28:26 -070066#define Q_REG_I_MODE_CTL 0
Michael Bohan6b901572012-05-30 13:32:24 -070067#define Q_REG_I_DIG_VIN_CTL 1
Michael Bohane25e15f2012-04-12 17:28:26 -070068#define Q_REG_I_DIG_PULL_CTL 2
69#define Q_REG_I_DIG_IN_CTL 3
Michael Bohane25e15f2012-04-12 17:28:26 -070070#define Q_REG_I_DIG_OUT_CTL 5
71#define Q_REG_I_EN_CTL 6
Michael Bohan6b901572012-05-30 13:32:24 -070072#define Q_REG_I_AOUT_CTL 8
73#define Q_REG_I_AIN_CTL 10
74#define Q_REG_I_SINK_CTL 12
Michael Bohan0ba63b82012-02-06 13:42:34 -080075
Michael Bohane25e15f2012-04-12 17:28:26 -070076/* control reg: mode */
Michael Bohan0ba63b82012-02-06 13:42:34 -080077#define Q_REG_OUT_INVERT_SHIFT 0
78#define Q_REG_OUT_INVERT_MASK 0x1
79#define Q_REG_SRC_SEL_SHIFT 1
80#define Q_REG_SRC_SEL_MASK 0xE
Michael Bohane25e15f2012-04-12 17:28:26 -070081#define Q_REG_MODE_SEL_SHIFT 4
82#define Q_REG_MODE_SEL_MASK 0x70
83
84/* control reg: dig_vin */
85#define Q_REG_VIN_SHIFT 0
86#define Q_REG_VIN_MASK 0x7
87
88/* control reg: dig_pull */
89#define Q_REG_PULL_SHIFT 0
90#define Q_REG_PULL_MASK 0x7
91
92/* control reg: dig_out */
93#define Q_REG_OUT_STRENGTH_SHIFT 0
94#define Q_REG_OUT_STRENGTH_MASK 0x3
95#define Q_REG_OUT_TYPE_SHIFT 4
96#define Q_REG_OUT_TYPE_MASK 0x30
97
98/* control reg: en */
Michael Bohan0ba63b82012-02-06 13:42:34 -080099#define Q_REG_MASTER_EN_SHIFT 7
100#define Q_REG_MASTER_EN_MASK 0x80
101
Michael Bohan6b901572012-05-30 13:32:24 -0700102/* control reg: ana_out */
103#define Q_REG_AOUT_REF_SHIFT 0
104#define Q_REG_AOUT_REF_MASK 0x7
105
106/* control reg: ana_in */
107#define Q_REG_AIN_ROUTE_SHIFT 0
108#define Q_REG_AIN_ROUTE_MASK 0x7
109
110/* control reg: sink */
111#define Q_REG_CS_OUT_SHIFT 0
112#define Q_REG_CS_OUT_MASK 0x7
113
Michael Bohana05f4552012-05-24 15:58:11 -0700114enum qpnp_pin_param_type {
Michael Bohan6b901572012-05-30 13:32:24 -0700115 Q_PIN_CFG_MODE,
Michael Bohana05f4552012-05-24 15:58:11 -0700116 Q_PIN_CFG_OUTPUT_TYPE,
117 Q_PIN_CFG_INVERT,
118 Q_PIN_CFG_PULL,
119 Q_PIN_CFG_VIN_SEL,
120 Q_PIN_CFG_OUT_STRENGTH,
Michael Bohan6b901572012-05-30 13:32:24 -0700121 Q_PIN_CFG_SELECT,
Michael Bohana05f4552012-05-24 15:58:11 -0700122 Q_PIN_CFG_MASTER_EN,
Michael Bohan6b901572012-05-30 13:32:24 -0700123 Q_PIN_CFG_AOUT_REF,
124 Q_PIN_CFG_AIN_ROUTE,
125 Q_PIN_CFG_CS_OUT,
Michael Bohana05f4552012-05-24 15:58:11 -0700126 Q_PIN_CFG_INVALID,
Michael Bohana19dced2012-04-24 13:14:50 -0700127};
128
Michael Bohana05f4552012-05-24 15:58:11 -0700129#define Q_NUM_PARAMS Q_PIN_CFG_INVALID
Michael Bohana19dced2012-04-24 13:14:50 -0700130
Michael Bohane25e15f2012-04-12 17:28:26 -0700131/* param error checking */
Michael Bohan6b901572012-05-30 13:32:24 -0700132#define QPNP_PIN_MODE_INVALID 3
Michael Bohana05f4552012-05-24 15:58:11 -0700133#define QPNP_PIN_INVERT_INVALID 2
134#define QPNP_PIN_OUT_BUF_INVALID 3
Michael Bohan6b901572012-05-30 13:32:24 -0700135#define QPNP_PIN_VIN_4CH_INVALID 5
136#define QPNP_PIN_VIN_8CH_INVALID 8
137#define QPNP_PIN_GPIO_PULL_INVALID 6
138#define QPNP_PIN_MPP_PULL_INVALID 4
Michael Bohana05f4552012-05-24 15:58:11 -0700139#define QPNP_PIN_OUT_STRENGTH_INVALID 4
140#define QPNP_PIN_SRC_INVALID 8
141#define QPNP_PIN_MASTER_INVALID 2
Michael Bohan6b901572012-05-30 13:32:24 -0700142#define QPNP_PIN_AOUT_REF_INVALID 8
143#define QPNP_PIN_AIN_ROUTE_INVALID 8
144#define QPNP_PIN_CS_OUT_INVALID 8
Michael Bohan0ba63b82012-02-06 13:42:34 -0800145
Michael Bohana05f4552012-05-24 15:58:11 -0700146struct qpnp_pin_spec {
Michael Bohan0ba63b82012-02-06 13:42:34 -0800147 uint8_t slave; /* 0-15 */
148 uint16_t offset; /* 0-255 */
149 uint32_t gpio_chip_idx; /* offset from gpio_chip base */
Michael Bohana05f4552012-05-24 15:58:11 -0700150 uint32_t pmic_pin; /* PMIC pin number */
Michael Bohan0ba63b82012-02-06 13:42:34 -0800151 int irq; /* logical IRQ number */
152 u8 regs[Q_NUM_CTL_REGS]; /* Control regs */
Michael Bohan6b901572012-05-30 13:32:24 -0700153 u8 num_ctl_regs; /* usable number on this pin */
Michael Bohane25e15f2012-04-12 17:28:26 -0700154 u8 type; /* peripheral type */
155 u8 subtype; /* peripheral subtype */
Michael Bohande3942a2012-04-17 15:28:01 -0700156 struct device_node *node;
Michael Bohana05f4552012-05-24 15:58:11 -0700157 enum qpnp_pin_param_type params[Q_NUM_PARAMS];
158 struct qpnp_pin_chip *q_chip;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800159};
160
Michael Bohana05f4552012-05-24 15:58:11 -0700161struct qpnp_pin_chip {
Michael Bohan0ba63b82012-02-06 13:42:34 -0800162 struct gpio_chip gpio_chip;
163 struct spmi_device *spmi;
Michael Bohana05f4552012-05-24 15:58:11 -0700164 struct qpnp_pin_spec **pmic_pins;
165 struct qpnp_pin_spec **chip_gpios;
166 uint32_t pmic_pin_lowest;
167 uint32_t pmic_pin_highest;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800168 struct device_node *int_ctrl;
169 struct list_head chip_list;
Michael Bohana19dced2012-04-24 13:14:50 -0700170 struct dentry *dfs_dir;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800171};
172
Michael Bohana05f4552012-05-24 15:58:11 -0700173static LIST_HEAD(qpnp_pin_chips);
174static DEFINE_MUTEX(qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800175
Michael Bohana05f4552012-05-24 15:58:11 -0700176static inline void qpnp_pmic_pin_set_spec(struct qpnp_pin_chip *q_chip,
177 uint32_t pmic_pin,
178 struct qpnp_pin_spec *spec)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800179{
Michael Bohana05f4552012-05-24 15:58:11 -0700180 q_chip->pmic_pins[pmic_pin - q_chip->pmic_pin_lowest] = spec;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800181}
182
Michael Bohana05f4552012-05-24 15:58:11 -0700183static inline struct qpnp_pin_spec *qpnp_pmic_pin_get_spec(
184 struct qpnp_pin_chip *q_chip,
185 uint32_t pmic_pin)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800186{
Michael Bohana05f4552012-05-24 15:58:11 -0700187 if (pmic_pin < q_chip->pmic_pin_lowest ||
188 pmic_pin > q_chip->pmic_pin_highest)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800189 return NULL;
190
Michael Bohana05f4552012-05-24 15:58:11 -0700191 return q_chip->pmic_pins[pmic_pin - q_chip->pmic_pin_lowest];
Michael Bohan0ba63b82012-02-06 13:42:34 -0800192}
193
Michael Bohana05f4552012-05-24 15:58:11 -0700194static inline struct qpnp_pin_spec *qpnp_chip_gpio_get_spec(
195 struct qpnp_pin_chip *q_chip,
Michael Bohan0ba63b82012-02-06 13:42:34 -0800196 uint32_t chip_gpio)
197{
198 if (chip_gpio > q_chip->gpio_chip.ngpio)
199 return NULL;
200
201 return q_chip->chip_gpios[chip_gpio];
202}
203
Michael Bohana05f4552012-05-24 15:58:11 -0700204static inline void qpnp_chip_gpio_set_spec(struct qpnp_pin_chip *q_chip,
Michael Bohan0ba63b82012-02-06 13:42:34 -0800205 uint32_t chip_gpio,
Michael Bohana05f4552012-05-24 15:58:11 -0700206 struct qpnp_pin_spec *spec)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800207{
208 q_chip->chip_gpios[chip_gpio] = spec;
209}
210
Michael Bohan58d07802012-05-31 15:37:55 -0700211/*
212 * Determines whether a specified param's configuration is correct.
213 * This check is two tier. First a check is done whether the hardware
214 * supports this param and value requested. The second check validates
215 * that the configuration is correct, given the fact that the hardware
216 * supports it.
217 *
218 * Returns
Michael Bohan6b901572012-05-30 13:32:24 -0700219 * -ENXIO is the hardware does not support this param.
220 * -EINVAL if the the hardware does support this param, but the
221 * requested value is outside the supported range.
Michael Bohan58d07802012-05-31 15:37:55 -0700222 */
223static int qpnp_pin_check_config(enum qpnp_pin_param_type idx,
224 struct qpnp_pin_spec *q_spec, uint32_t val)
225{
226 switch (idx) {
Michael Bohan6b901572012-05-30 13:32:24 -0700227 case Q_PIN_CFG_MODE:
228 if (val >= QPNP_PIN_MODE_INVALID)
Michael Bohan58d07802012-05-31 15:37:55 -0700229 return -EINVAL;
230 break;
231 case Q_PIN_CFG_OUTPUT_TYPE:
Michael Bohan6b901572012-05-30 13:32:24 -0700232 if (q_spec->type != Q_GPIO_TYPE)
Michael Bohan58d07802012-05-31 15:37:55 -0700233 return -ENXIO;
Michael Bohan6b901572012-05-30 13:32:24 -0700234 if ((val == QPNP_PIN_OUT_BUF_OPEN_DRAIN_NMOS ||
235 val == QPNP_PIN_OUT_BUF_OPEN_DRAIN_PMOS) &&
236 (q_spec->subtype == Q_GPIO_SUBTYPE_GPIOC_4CH ||
237 (q_spec->subtype == Q_GPIO_SUBTYPE_GPIOC_8CH)))
238 return -EINVAL;
Michael Bohan58d07802012-05-31 15:37:55 -0700239 else if (val >= QPNP_PIN_OUT_BUF_INVALID)
240 return -EINVAL;
241 break;
242 case Q_PIN_CFG_INVERT:
243 if (val >= QPNP_PIN_INVERT_INVALID)
244 return -EINVAL;
245 break;
246 case Q_PIN_CFG_PULL:
Michael Bohan6b901572012-05-30 13:32:24 -0700247 if (q_spec->type == Q_GPIO_TYPE &&
248 val >= QPNP_PIN_GPIO_PULL_INVALID)
249 return -EINVAL;
250 if (q_spec->type == Q_MPP_TYPE &&
251 val >= QPNP_PIN_MPP_PULL_INVALID)
Michael Bohan58d07802012-05-31 15:37:55 -0700252 return -EINVAL;
253 break;
254 case Q_PIN_CFG_VIN_SEL:
Michael Bohan6b901572012-05-30 13:32:24 -0700255 if (val >= QPNP_PIN_VIN_8CH_INVALID)
Michael Bohan58d07802012-05-31 15:37:55 -0700256 return -EINVAL;
Michael Bohan6b901572012-05-30 13:32:24 -0700257 else if (val >= QPNP_PIN_VIN_4CH_INVALID) {
258 if (q_spec->type == Q_GPIO_TYPE &&
259 (q_spec->subtype == Q_GPIO_SUBTYPE_GPIO_4CH ||
260 q_spec->subtype == Q_GPIO_SUBTYPE_GPIOC_4CH))
261 return -EINVAL;
262 if (q_spec->type == Q_MPP_TYPE &&
263 (q_spec->subtype == Q_MPP_SUBTYPE_4CH_NO_ANA_OUT ||
264 q_spec->subtype == Q_MPP_SUBTYPE_4CH_NO_SINK ||
265 q_spec->subtype == Q_MPP_SUBTYPE_4CH_FULL_FUNC))
266 return -EINVAL;
267 }
Michael Bohan58d07802012-05-31 15:37:55 -0700268 break;
269 case Q_PIN_CFG_OUT_STRENGTH:
Michael Bohan6b901572012-05-30 13:32:24 -0700270 if (q_spec->type != Q_GPIO_TYPE)
271 return -ENXIO;
Michael Bohan58d07802012-05-31 15:37:55 -0700272 if (val >= QPNP_PIN_OUT_STRENGTH_INVALID ||
273 val == 0)
274 return -EINVAL;
275 break;
Michael Bohan6b901572012-05-30 13:32:24 -0700276 case Q_PIN_CFG_SELECT:
277 if (q_spec->type == Q_MPP_TYPE &&
278 (val == QPNP_PIN_SEL_FUNC_1 ||
279 val == QPNP_PIN_SEL_FUNC_2))
280 return -EINVAL;
Michael Bohan58d07802012-05-31 15:37:55 -0700281 if (val >= QPNP_PIN_SRC_INVALID)
282 return -EINVAL;
283 break;
284 case Q_PIN_CFG_MASTER_EN:
285 if (val >= QPNP_PIN_MASTER_INVALID)
286 return -EINVAL;
287 break;
Michael Bohan6b901572012-05-30 13:32:24 -0700288 case Q_PIN_CFG_AOUT_REF:
289 if (q_spec->type != Q_MPP_TYPE)
290 return -ENXIO;
291 if (q_spec->subtype == Q_MPP_SUBTYPE_4CH_NO_ANA_OUT)
292 return -ENXIO;
293 if (val >= QPNP_PIN_AOUT_REF_INVALID)
294 return -EINVAL;
295 break;
296 case Q_PIN_CFG_AIN_ROUTE:
297 if (q_spec->type != Q_MPP_TYPE)
298 return -ENXIO;
299 if (val >= QPNP_PIN_AIN_ROUTE_INVALID)
300 return -EINVAL;
301 break;
302 case Q_PIN_CFG_CS_OUT:
303 if (q_spec->type != Q_MPP_TYPE)
304 return -ENXIO;
305 if (q_spec->subtype == Q_MPP_SUBTYPE_4CH_NO_SINK)
306 return -ENXIO;
307 if (val >= QPNP_PIN_CS_OUT_INVALID)
308 return -EINVAL;
309 break;
310
Michael Bohan58d07802012-05-31 15:37:55 -0700311 default:
312 pr_err("invalid param type %u specified\n", idx);
313 return -EINVAL;
314 }
315 return 0;
316}
317
318#define Q_CHK_INVALID(idx, q_spec, val) \
319 (qpnp_pin_check_config(idx, q_spec, val) == -EINVAL)
320
321static int qpnp_pin_check_constraints(struct qpnp_pin_spec *q_spec,
322 struct qpnp_pin_cfg *param)
Michael Bohane25e15f2012-04-12 17:28:26 -0700323{
Michael Bohan6b901572012-05-30 13:32:24 -0700324 int pin = q_spec->pmic_pin;
325 const char *name;
Michael Bohane25e15f2012-04-12 17:28:26 -0700326
Michael Bohan6b901572012-05-30 13:32:24 -0700327 name = (q_spec->type == Q_GPIO_TYPE) ? "gpio" : "mpp";
328
329 if (Q_CHK_INVALID(Q_PIN_CFG_MODE, q_spec, param->mode))
330 pr_err("invalid direction for %s %d\n", name, pin);
Michael Bohan58d07802012-05-31 15:37:55 -0700331 else if (Q_CHK_INVALID(Q_PIN_CFG_INVERT, q_spec, param->invert))
Michael Bohan6b901572012-05-30 13:32:24 -0700332 pr_err("invalid invert polarity for %s %d\n", name, pin);
333 else if (Q_CHK_INVALID(Q_PIN_CFG_SELECT, q_spec, param->select))
334 pr_err("invalid source select for %s %d\n", name, pin);
Michael Bohan58d07802012-05-31 15:37:55 -0700335 else if (Q_CHK_INVALID(Q_PIN_CFG_OUT_STRENGTH,
336 q_spec, param->out_strength))
Michael Bohan6b901572012-05-30 13:32:24 -0700337 pr_err("invalid out strength for %s %d\n", name, pin);
Michael Bohan58d07802012-05-31 15:37:55 -0700338 else if (Q_CHK_INVALID(Q_PIN_CFG_OUTPUT_TYPE,
339 q_spec, param->output_type))
Michael Bohan6b901572012-05-30 13:32:24 -0700340 pr_err("invalid out type for %s %d\n", name, pin);
Michael Bohan58d07802012-05-31 15:37:55 -0700341 else if (Q_CHK_INVALID(Q_PIN_CFG_VIN_SEL, q_spec, param->vin_sel))
Michael Bohan6b901572012-05-30 13:32:24 -0700342 pr_err("invalid vin select value for %s %d\n", name, pin);
Michael Bohan58d07802012-05-31 15:37:55 -0700343 else if (Q_CHK_INVALID(Q_PIN_CFG_PULL, q_spec, param->pull))
Michael Bohan6b901572012-05-30 13:32:24 -0700344 pr_err("invalid pull value for pin %s %d\n", name, pin);
Michael Bohan58d07802012-05-31 15:37:55 -0700345 else if (Q_CHK_INVALID(Q_PIN_CFG_MASTER_EN, q_spec, param->master_en))
Michael Bohan6b901572012-05-30 13:32:24 -0700346 pr_err("invalid master_en value for %s %d\n", name, pin);
347 else if (Q_CHK_INVALID(Q_PIN_CFG_AOUT_REF, q_spec, param->aout_ref))
348 pr_err("invalid aout_reg value for %s %d\n", name, pin);
349 else if (Q_CHK_INVALID(Q_PIN_CFG_AIN_ROUTE, q_spec, param->ain_route))
350 pr_err("invalid ain_route value for %s %d\n", name, pin);
351 else if (Q_CHK_INVALID(Q_PIN_CFG_CS_OUT, q_spec, param->cs_out))
352 pr_err("invalid cs_out value for %s %d\n", name, pin);
Michael Bohane25e15f2012-04-12 17:28:26 -0700353 else
354 return 0;
355
356 return -EINVAL;
357}
358
Michael Bohande3942a2012-04-17 15:28:01 -0700359static inline u8 q_reg_get(u8 *reg, int shift, int mask)
360{
361 return (*reg & mask) >> shift;
362}
363
Michael Bohane25e15f2012-04-12 17:28:26 -0700364static inline void q_reg_set(u8 *reg, int shift, int mask, int value)
365{
366 *reg |= (value << shift) & mask;
367}
368
369static inline void q_reg_clr_set(u8 *reg, int shift, int mask, int value)
370{
371 *reg &= ~mask;
372 *reg |= (value << shift) & mask;
373}
374
Michael Bohan6b901572012-05-30 13:32:24 -0700375/*
376 * Calculate the minimum number of registers that must be read / written
377 * in order to satisfy the full feature set of the given pin.
378 */
379static int qpnp_pin_ctl_regs_init(struct qpnp_pin_spec *q_spec)
380{
381 if (q_spec->type == Q_GPIO_TYPE)
382 q_spec->num_ctl_regs = 7;
383 else if (q_spec->type == Q_MPP_TYPE)
384 switch (q_spec->subtype) {
385 case Q_MPP_SUBTYPE_4CH_NO_SINK:
386 q_spec->num_ctl_regs = 12;
387 break;
388 case Q_MPP_SUBTYPE_4CH_NO_ANA_OUT:
389 case Q_MPP_SUBTYPE_4CH_FULL_FUNC:
390 case Q_MPP_SUBTYPE_8CH_FULL_FUNC:
391 q_spec->num_ctl_regs = 13;
392 break;
393 default:
394 pr_err("Invalid MPP subtype 0x%x\n", q_spec->subtype);
395 return -EINVAL;
396 }
397 else {
398 pr_err("Invalid type 0x%x\n", q_spec->type);
399 return -EINVAL;
400 }
401 return 0;
402}
403
404static int qpnp_pin_read_regs(struct qpnp_pin_chip *q_chip,
405 struct qpnp_pin_spec *q_spec, u16 addr, u8 *buf)
406{
407 int bytes_left = q_spec->num_ctl_regs;
408 int rc;
409 char *reg_p = &q_spec->regs[0];
410
411 while (bytes_left > 0) {
412 rc = spmi_ext_register_readl(q_chip->spmi->ctrl, q_spec->slave,
413 Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
414 reg_p, bytes_left < 8 ? bytes_left : 8);
415 if (rc)
416 return rc;
417 bytes_left -= 8;
418 reg_p += 8;
419 }
420 return 0;
421}
422
423static int qpnp_pin_write_regs(struct qpnp_pin_chip *q_chip,
424 struct qpnp_pin_spec *q_spec, u16 addr, u8 *buf)
425{
426 int bytes_left = q_spec->num_ctl_regs;
427 int rc;
428 char *reg_p = &q_spec->regs[0];
429
430 while (bytes_left > 0) {
431 rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
432 Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
433 reg_p, bytes_left < 8 ? bytes_left : 8);
434 if (rc)
435 return rc;
436 bytes_left -= 8;
437 reg_p += 8;
438 }
439 return 0;
440}
441
Michael Bohana05f4552012-05-24 15:58:11 -0700442static int qpnp_pin_cache_regs(struct qpnp_pin_chip *q_chip,
Michael Bohan6b901572012-05-30 13:32:24 -0700443 struct qpnp_pin_spec *q_spec)
Michael Bohande3942a2012-04-17 15:28:01 -0700444{
445 int rc;
446 struct device *dev = &q_chip->spmi->dev;
447
Michael Bohan6b901572012-05-30 13:32:24 -0700448 rc = qpnp_pin_read_regs(q_chip, q_spec,
449 Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
450 &q_spec->regs[Q_REG_I_MODE_CTL]);
Michael Bohande3942a2012-04-17 15:28:01 -0700451 if (rc)
452 dev_err(dev, "%s: unable to read control regs\n", __func__);
453
454 return rc;
455}
456
Michael Bohan58d07802012-05-31 15:37:55 -0700457#define Q_HAVE_HW_SP(idx, q_spec, val) \
458 (qpnp_pin_check_config(idx, q_spec, val) == 0)
459
Michael Bohana05f4552012-05-24 15:58:11 -0700460static int _qpnp_pin_config(struct qpnp_pin_chip *q_chip,
Michael Bohan6b901572012-05-30 13:32:24 -0700461 struct qpnp_pin_spec *q_spec,
462 struct qpnp_pin_cfg *param)
Michael Bohane25e15f2012-04-12 17:28:26 -0700463{
464 struct device *dev = &q_chip->spmi->dev;
465 int rc;
466
Michael Bohan58d07802012-05-31 15:37:55 -0700467 rc = qpnp_pin_check_constraints(q_spec, param);
Michael Bohane25e15f2012-04-12 17:28:26 -0700468 if (rc)
469 goto gpio_cfg;
470
Michael Bohan6b901572012-05-30 13:32:24 -0700471 /* set mode */
472 if (Q_HAVE_HW_SP(Q_PIN_CFG_MODE, q_spec, param->mode))
Michael Bohan58d07802012-05-31 15:37:55 -0700473 q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700474 Q_REG_MODE_SEL_SHIFT, Q_REG_MODE_SEL_MASK,
Michael Bohan6b901572012-05-30 13:32:24 -0700475 param->mode);
Michael Bohane25e15f2012-04-12 17:28:26 -0700476
477 /* output specific configuration */
Michael Bohan58d07802012-05-31 15:37:55 -0700478 if (Q_HAVE_HW_SP(Q_PIN_CFG_INVERT, q_spec, param->invert))
479 q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700480 Q_REG_OUT_INVERT_SHIFT, Q_REG_OUT_INVERT_MASK,
481 param->invert);
Michael Bohan6b901572012-05-30 13:32:24 -0700482 if (Q_HAVE_HW_SP(Q_PIN_CFG_SELECT, q_spec, param->select))
Michael Bohan58d07802012-05-31 15:37:55 -0700483 q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700484 Q_REG_SRC_SEL_SHIFT, Q_REG_SRC_SEL_MASK,
Michael Bohan6b901572012-05-30 13:32:24 -0700485 param->select);
Michael Bohan58d07802012-05-31 15:37:55 -0700486 if (Q_HAVE_HW_SP(Q_PIN_CFG_OUT_STRENGTH, q_spec, param->out_strength))
487 q_reg_clr_set(&q_spec->regs[Q_REG_I_DIG_OUT_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700488 Q_REG_OUT_STRENGTH_SHIFT, Q_REG_OUT_STRENGTH_MASK,
489 param->out_strength);
Michael Bohan58d07802012-05-31 15:37:55 -0700490 if (Q_HAVE_HW_SP(Q_PIN_CFG_OUTPUT_TYPE, q_spec, param->output_type))
491 q_reg_clr_set(&q_spec->regs[Q_REG_I_DIG_OUT_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700492 Q_REG_OUT_TYPE_SHIFT, Q_REG_OUT_TYPE_MASK,
493 param->output_type);
494
495 /* config applicable for both input / output */
Michael Bohan58d07802012-05-31 15:37:55 -0700496 if (Q_HAVE_HW_SP(Q_PIN_CFG_VIN_SEL, q_spec, param->vin_sel))
497 q_reg_clr_set(&q_spec->regs[Q_REG_I_DIG_VIN_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700498 Q_REG_VIN_SHIFT, Q_REG_VIN_MASK,
499 param->vin_sel);
Michael Bohan58d07802012-05-31 15:37:55 -0700500 if (Q_HAVE_HW_SP(Q_PIN_CFG_PULL, q_spec, param->pull))
501 q_reg_clr_set(&q_spec->regs[Q_REG_I_DIG_PULL_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700502 Q_REG_PULL_SHIFT, Q_REG_PULL_MASK,
503 param->pull);
Michael Bohan58d07802012-05-31 15:37:55 -0700504 if (Q_HAVE_HW_SP(Q_PIN_CFG_MASTER_EN, q_spec, param->master_en))
505 q_reg_clr_set(&q_spec->regs[Q_REG_I_EN_CTL],
Michael Bohane25e15f2012-04-12 17:28:26 -0700506 Q_REG_MASTER_EN_SHIFT, Q_REG_MASTER_EN_MASK,
507 param->master_en);
508
Michael Bohan6b901572012-05-30 13:32:24 -0700509 /* mpp specific config */
510 if (Q_HAVE_HW_SP(Q_PIN_CFG_AOUT_REF, q_spec, param->aout_ref))
511 q_reg_clr_set(&q_spec->regs[Q_REG_I_AOUT_CTL],
512 Q_REG_AOUT_REF_SHIFT, Q_REG_AOUT_REF_MASK,
513 param->aout_ref);
514 if (Q_HAVE_HW_SP(Q_PIN_CFG_AIN_ROUTE, q_spec, param->ain_route))
515 q_reg_clr_set(&q_spec->regs[Q_REG_I_AIN_CTL],
516 Q_REG_AIN_ROUTE_SHIFT, Q_REG_AIN_ROUTE_MASK,
517 param->ain_route);
518 if (Q_HAVE_HW_SP(Q_PIN_CFG_CS_OUT, q_spec, param->cs_out))
519 q_reg_clr_set(&q_spec->regs[Q_REG_I_SINK_CTL],
520 Q_REG_CS_OUT_SHIFT, Q_REG_CS_OUT_MASK,
521 param->cs_out);
522
523 rc = qpnp_pin_write_regs(q_chip, q_spec,
524 Q_REG_ADDR(q_spec, Q_REG_MODE_CTL),
525 &q_spec->regs[Q_REG_I_MODE_CTL]);
Michael Bohane25e15f2012-04-12 17:28:26 -0700526 if (rc) {
Michael Bohan6ea2cd22012-05-29 15:40:18 -0700527 dev_err(&q_chip->spmi->dev, "%s: unable to write master enable\n",
528 __func__);
Michael Bohane25e15f2012-04-12 17:28:26 -0700529 goto gpio_cfg;
530 }
531
532 return 0;
533
534gpio_cfg:
Michael Bohana05f4552012-05-24 15:58:11 -0700535 dev_err(dev, "%s: unable to set default config for pmic gpio %d\n",
536 __func__, q_spec->pmic_pin);
Michael Bohane25e15f2012-04-12 17:28:26 -0700537
538 return rc;
539}
540
Michael Bohana05f4552012-05-24 15:58:11 -0700541int qpnp_pin_config(int gpio, struct qpnp_pin_cfg *param)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800542{
543 int rc, chip_offset;
Michael Bohana05f4552012-05-24 15:58:11 -0700544 struct qpnp_pin_chip *q_chip;
545 struct qpnp_pin_spec *q_spec = NULL;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800546 struct gpio_chip *gpio_chip;
547
548 if (param == NULL)
549 return -EINVAL;
550
Michael Bohana05f4552012-05-24 15:58:11 -0700551 mutex_lock(&qpnp_pin_chips_lock);
552 list_for_each_entry(q_chip, &qpnp_pin_chips, chip_list) {
Michael Bohan0ba63b82012-02-06 13:42:34 -0800553 gpio_chip = &q_chip->gpio_chip;
554 if (gpio >= gpio_chip->base
555 && gpio < gpio_chip->base + gpio_chip->ngpio) {
556 chip_offset = gpio - gpio_chip->base;
557 q_spec = qpnp_chip_gpio_get_spec(q_chip, chip_offset);
558 if (WARN_ON(!q_spec)) {
Michael Bohana05f4552012-05-24 15:58:11 -0700559 mutex_unlock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800560 return -ENODEV;
561 }
562 break;
563 }
564 }
Michael Bohana05f4552012-05-24 15:58:11 -0700565 mutex_unlock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800566
Michael Bohana05f4552012-05-24 15:58:11 -0700567 rc = _qpnp_pin_config(q_chip, q_spec, param);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800568
569 return rc;
570}
Michael Bohana05f4552012-05-24 15:58:11 -0700571EXPORT_SYMBOL(qpnp_pin_config);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800572
Michael Bohan6ea2cd22012-05-29 15:40:18 -0700573#define Q_MAX_CHIP_NAME 128
574int qpnp_pin_map(const char *name, uint32_t pmic_pin)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800575{
Michael Bohana05f4552012-05-24 15:58:11 -0700576 struct qpnp_pin_chip *q_chip;
577 struct qpnp_pin_spec *q_spec = NULL;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800578
Michael Bohana05f4552012-05-24 15:58:11 -0700579 mutex_lock(&qpnp_pin_chips_lock);
580 list_for_each_entry(q_chip, &qpnp_pin_chips, chip_list) {
Michael Bohan6ea2cd22012-05-29 15:40:18 -0700581 if (strncmp(q_chip->gpio_chip.label, name,
582 Q_MAX_CHIP_NAME) != 0)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800583 continue;
Michael Bohana05f4552012-05-24 15:58:11 -0700584 if (q_chip->pmic_pin_lowest <= pmic_pin &&
585 q_chip->pmic_pin_highest >= pmic_pin) {
586 q_spec = qpnp_pmic_pin_get_spec(q_chip, pmic_pin);
587 mutex_unlock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800588 if (WARN_ON(!q_spec))
589 return -ENODEV;
590 return q_chip->gpio_chip.base + q_spec->gpio_chip_idx;
591 }
592 }
Michael Bohana05f4552012-05-24 15:58:11 -0700593 mutex_unlock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800594 return -EINVAL;
595}
Michael Bohana05f4552012-05-24 15:58:11 -0700596EXPORT_SYMBOL(qpnp_pin_map);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800597
Michael Bohana05f4552012-05-24 15:58:11 -0700598static int qpnp_pin_to_irq(struct gpio_chip *gpio_chip, unsigned offset)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800599{
Michael Bohana05f4552012-05-24 15:58:11 -0700600 struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
601 struct qpnp_pin_spec *q_spec;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800602
603 q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
604 if (!q_spec)
605 return -EINVAL;
606
607 return q_spec->irq;
608}
609
Michael Bohana05f4552012-05-24 15:58:11 -0700610static int qpnp_pin_get(struct gpio_chip *gpio_chip, unsigned offset)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800611{
612 int rc, ret_val;
Michael Bohana05f4552012-05-24 15:58:11 -0700613 struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
614 struct qpnp_pin_spec *q_spec = NULL;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800615 u8 buf[1];
616
617 if (WARN_ON(!q_chip))
618 return -ENODEV;
619
620 q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
621 if (WARN_ON(!q_spec))
622 return -ENODEV;
623
624 /* gpio val is from RT status iff input is enabled */
Michael Bohane25e15f2012-04-12 17:28:26 -0700625 if ((q_spec->regs[Q_REG_I_MODE_CTL] & Q_REG_MODE_SEL_MASK)
Michael Bohan6b901572012-05-30 13:32:24 -0700626 == QPNP_PIN_MODE_DIG_IN) {
Michael Bohan0ba63b82012-02-06 13:42:34 -0800627 /* INT_RT_STS */
628 rc = spmi_ext_register_readl(q_chip->spmi->ctrl, q_spec->slave,
629 Q_REG_ADDR(q_spec, Q_REG_STATUS1),
630 &buf[0], 1);
631 return buf[0];
632
633 } else {
Michael Bohane25e15f2012-04-12 17:28:26 -0700634 ret_val = (q_spec->regs[Q_REG_I_MODE_CTL] &
Michael Bohan0ba63b82012-02-06 13:42:34 -0800635 Q_REG_OUT_INVERT_MASK) >> Q_REG_OUT_INVERT_SHIFT;
636 return ret_val;
637 }
638
639 return 0;
640}
641
Michael Bohana05f4552012-05-24 15:58:11 -0700642static int __qpnp_pin_set(struct qpnp_pin_chip *q_chip,
643 struct qpnp_pin_spec *q_spec, int value)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800644{
645 int rc;
646
647 if (!q_chip || !q_spec)
648 return -EINVAL;
649
Michael Bohan0ba63b82012-02-06 13:42:34 -0800650 if (value)
Michael Bohane25e15f2012-04-12 17:28:26 -0700651 q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
652 Q_REG_OUT_INVERT_SHIFT, Q_REG_OUT_INVERT_MASK, 1);
653 else
654 q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
655 Q_REG_OUT_INVERT_SHIFT, Q_REG_OUT_INVERT_MASK, 0);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800656
657 rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
Michael Bohane25e15f2012-04-12 17:28:26 -0700658 Q_REG_ADDR(q_spec, Q_REG_I_MODE_CTL),
659 &q_spec->regs[Q_REG_I_MODE_CTL], 1);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800660 if (rc)
661 dev_err(&q_chip->spmi->dev, "%s: spmi write failed\n",
662 __func__);
663 return rc;
664}
665
666
Michael Bohana05f4552012-05-24 15:58:11 -0700667static void qpnp_pin_set(struct gpio_chip *gpio_chip,
Michael Bohan0ba63b82012-02-06 13:42:34 -0800668 unsigned offset, int value)
669{
Michael Bohana05f4552012-05-24 15:58:11 -0700670 struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
671 struct qpnp_pin_spec *q_spec;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800672
673 if (WARN_ON(!q_chip))
674 return;
675
676 q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
677 if (WARN_ON(!q_spec))
678 return;
679
Michael Bohana05f4552012-05-24 15:58:11 -0700680 __qpnp_pin_set(q_chip, q_spec, value);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800681}
682
Michael Bohan6b901572012-05-30 13:32:24 -0700683static int qpnp_pin_set_mode(struct qpnp_pin_chip *q_chip,
684 struct qpnp_pin_spec *q_spec, int mode)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800685{
686 int rc;
687
688 if (!q_chip || !q_spec)
689 return -EINVAL;
690
Michael Bohan6b901572012-05-30 13:32:24 -0700691 if (mode >= QPNP_PIN_MODE_INVALID) {
692 pr_err("invalid mode specification %d\n", mode);
Michael Bohane25e15f2012-04-12 17:28:26 -0700693 return -EINVAL;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800694 }
695
Michael Bohane25e15f2012-04-12 17:28:26 -0700696 q_reg_clr_set(&q_spec->regs[Q_REG_I_MODE_CTL],
697 Q_REG_MODE_SEL_SHIFT,
698 Q_REG_MODE_SEL_MASK,
Michael Bohan6b901572012-05-30 13:32:24 -0700699 mode);
Michael Bohane25e15f2012-04-12 17:28:26 -0700700
Michael Bohan0ba63b82012-02-06 13:42:34 -0800701 rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
Michael Bohane25e15f2012-04-12 17:28:26 -0700702 Q_REG_ADDR(q_spec, Q_REG_I_MODE_CTL),
703 &q_spec->regs[Q_REG_I_MODE_CTL], 1);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800704 return rc;
705}
706
Michael Bohana05f4552012-05-24 15:58:11 -0700707static int qpnp_pin_direction_input(struct gpio_chip *gpio_chip,
Michael Bohan0ba63b82012-02-06 13:42:34 -0800708 unsigned offset)
709{
Michael Bohana05f4552012-05-24 15:58:11 -0700710 struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
711 struct qpnp_pin_spec *q_spec;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800712
713 if (WARN_ON(!q_chip))
714 return -ENODEV;
715
716 q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
717 if (WARN_ON(!q_spec))
718 return -ENODEV;
719
Michael Bohan6b901572012-05-30 13:32:24 -0700720 return qpnp_pin_set_mode(q_chip, q_spec, QPNP_PIN_MODE_DIG_IN);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800721}
722
Michael Bohana05f4552012-05-24 15:58:11 -0700723static int qpnp_pin_direction_output(struct gpio_chip *gpio_chip,
Michael Bohan0ba63b82012-02-06 13:42:34 -0800724 unsigned offset,
725 int val)
726{
727 int rc;
Michael Bohana05f4552012-05-24 15:58:11 -0700728 struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
729 struct qpnp_pin_spec *q_spec;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800730
731 if (WARN_ON(!q_chip))
732 return -ENODEV;
733
734 q_spec = qpnp_chip_gpio_get_spec(q_chip, offset);
735 if (WARN_ON(!q_spec))
736 return -ENODEV;
737
Michael Bohana05f4552012-05-24 15:58:11 -0700738 rc = __qpnp_pin_set(q_chip, q_spec, val);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800739 if (rc)
740 return rc;
741
Michael Bohan6b901572012-05-30 13:32:24 -0700742 rc = qpnp_pin_set_mode(q_chip, q_spec, QPNP_PIN_MODE_DIG_OUT);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800743
744 return rc;
745}
746
Michael Bohana05f4552012-05-24 15:58:11 -0700747static int qpnp_pin_of_gpio_xlate(struct gpio_chip *gpio_chip,
Michael Bohan0b24fb12012-06-01 10:30:12 -0700748 const struct of_phandle_args *gpio_spec,
749 u32 *flags)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800750{
Michael Bohana05f4552012-05-24 15:58:11 -0700751 struct qpnp_pin_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
752 struct qpnp_pin_spec *q_spec;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800753
754 if (WARN_ON(gpio_chip->of_gpio_n_cells < 2)) {
Michael Bohane25e15f2012-04-12 17:28:26 -0700755 pr_err("of_gpio_n_cells < 2\n");
Michael Bohan0ba63b82012-02-06 13:42:34 -0800756 return -EINVAL;
757 }
758
Michael Bohana05f4552012-05-24 15:58:11 -0700759 q_spec = qpnp_pmic_pin_get_spec(q_chip, gpio_spec->args[0]);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800760 if (!q_spec) {
Michael Bohan0b24fb12012-06-01 10:30:12 -0700761 pr_err("no such PMIC gpio %u in device topology\n",
762 gpio_spec->args[0]);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800763 return -EINVAL;
764 }
765
766 if (flags)
Michael Bohan0b24fb12012-06-01 10:30:12 -0700767 *flags = gpio_spec->args[1];
Michael Bohan0ba63b82012-02-06 13:42:34 -0800768
769 return q_spec->gpio_chip_idx;
770}
771
Michael Bohana05f4552012-05-24 15:58:11 -0700772static int qpnp_pin_apply_config(struct qpnp_pin_chip *q_chip,
773 struct qpnp_pin_spec *q_spec)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800774{
Michael Bohana05f4552012-05-24 15:58:11 -0700775 struct qpnp_pin_cfg param;
Michael Bohande3942a2012-04-17 15:28:01 -0700776 struct device_node *node = q_spec->node;
Michael Bohan0ba63b82012-02-06 13:42:34 -0800777 int rc;
778
Michael Bohan6b901572012-05-30 13:32:24 -0700779 param.mode = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
Michael Bohande3942a2012-04-17 15:28:01 -0700780 Q_REG_MODE_SEL_SHIFT,
781 Q_REG_MODE_SEL_MASK);
782 param.output_type = q_reg_get(&q_spec->regs[Q_REG_I_DIG_OUT_CTL],
783 Q_REG_OUT_TYPE_SHIFT,
784 Q_REG_OUT_TYPE_MASK);
785 param.invert = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
786 Q_REG_OUT_INVERT_MASK,
787 Q_REG_OUT_INVERT_MASK);
788 param.pull = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
789 Q_REG_PULL_SHIFT, Q_REG_PULL_MASK);
790 param.vin_sel = q_reg_get(&q_spec->regs[Q_REG_I_DIG_VIN_CTL],
791 Q_REG_VIN_SHIFT, Q_REG_VIN_MASK);
792 param.out_strength = q_reg_get(&q_spec->regs[Q_REG_I_DIG_OUT_CTL],
793 Q_REG_OUT_STRENGTH_SHIFT,
794 Q_REG_OUT_STRENGTH_MASK);
Michael Bohan6b901572012-05-30 13:32:24 -0700795 param.select = q_reg_get(&q_spec->regs[Q_REG_I_MODE_CTL],
Michael Bohande3942a2012-04-17 15:28:01 -0700796 Q_REG_SRC_SEL_SHIFT, Q_REG_SRC_SEL_MASK);
797 param.master_en = q_reg_get(&q_spec->regs[Q_REG_I_EN_CTL],
798 Q_REG_MASTER_EN_SHIFT,
799 Q_REG_MASTER_EN_MASK);
Michael Bohan6b901572012-05-30 13:32:24 -0700800 param.aout_ref = q_reg_get(&q_spec->regs[Q_REG_I_AOUT_CTL],
801 Q_REG_AOUT_REF_SHIFT,
802 Q_REG_AOUT_REF_MASK);
803 param.ain_route = q_reg_get(&q_spec->regs[Q_REG_I_AIN_CTL],
804 Q_REG_AIN_ROUTE_SHIFT,
805 Q_REG_AIN_ROUTE_MASK);
806 param.cs_out = q_reg_get(&q_spec->regs[Q_REG_I_SINK_CTL],
807 Q_REG_CS_OUT_SHIFT,
808 Q_REG_CS_OUT_MASK);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800809
Michael Bohan6b901572012-05-30 13:32:24 -0700810 of_property_read_u32(node, "qcom,mode",
811 &param.mode);
Michael Bohande3942a2012-04-17 15:28:01 -0700812 of_property_read_u32(node, "qcom,output-type",
813 &param.output_type);
814 of_property_read_u32(node, "qcom,invert",
815 &param.invert);
816 of_property_read_u32(node, "qcom,pull",
817 &param.pull);
818 of_property_read_u32(node, "qcom,vin-sel",
819 &param.vin_sel);
820 of_property_read_u32(node, "qcom,out-strength",
821 &param.out_strength);
822 of_property_read_u32(node, "qcom,src-select",
Michael Bohan6b901572012-05-30 13:32:24 -0700823 &param.select);
824 of_property_read_u32(node, "qcom,master-en",
Michael Bohande3942a2012-04-17 15:28:01 -0700825 &param.master_en);
Michael Bohan6b901572012-05-30 13:32:24 -0700826 of_property_read_u32(node, "qcom,aout-ref",
827 &param.aout_ref);
828 of_property_read_u32(node, "qcom,ain-route",
829 &param.ain_route);
830 of_property_read_u32(node, "qcom,cs-out",
831 &param.cs_out);
Michael Bohana05f4552012-05-24 15:58:11 -0700832 rc = _qpnp_pin_config(q_chip, q_spec, &param);
Michael Bohande3942a2012-04-17 15:28:01 -0700833
Michael Bohan0ba63b82012-02-06 13:42:34 -0800834 return rc;
835}
836
Michael Bohana05f4552012-05-24 15:58:11 -0700837static int qpnp_pin_free_chip(struct qpnp_pin_chip *q_chip)
Michael Bohan0ba63b82012-02-06 13:42:34 -0800838{
839 struct spmi_device *spmi = q_chip->spmi;
840 int rc, i;
841
842 if (q_chip->chip_gpios)
843 for (i = 0; i < spmi->num_dev_node; i++)
844 kfree(q_chip->chip_gpios[i]);
845
Michael Bohana05f4552012-05-24 15:58:11 -0700846 mutex_lock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800847 list_del(&q_chip->chip_list);
Michael Bohana05f4552012-05-24 15:58:11 -0700848 mutex_unlock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800849 rc = gpiochip_remove(&q_chip->gpio_chip);
850 if (rc)
851 dev_err(&q_chip->spmi->dev, "%s: unable to remove gpio\n",
852 __func__);
853 kfree(q_chip->chip_gpios);
Michael Bohana05f4552012-05-24 15:58:11 -0700854 kfree(q_chip->pmic_pins);
Michael Bohan0ba63b82012-02-06 13:42:34 -0800855 kfree(q_chip);
856 return rc;
857}
858
Michael Bohana05f4552012-05-24 15:58:11 -0700859#ifdef CONFIG_GPIO_QPNP_PIN_DEBUG
860struct qpnp_pin_reg {
Michael Bohana19dced2012-04-24 13:14:50 -0700861 uint32_t addr;
862 uint32_t idx;
863 uint32_t shift;
864 uint32_t mask;
865};
866
867static struct dentry *driver_dfs_dir;
868
Michael Bohana05f4552012-05-24 15:58:11 -0700869static int qpnp_pin_reg_attr(enum qpnp_pin_param_type type,
870 struct qpnp_pin_reg *cfg)
Michael Bohana19dced2012-04-24 13:14:50 -0700871{
872 switch (type) {
Michael Bohan6b901572012-05-30 13:32:24 -0700873 case Q_PIN_CFG_MODE:
Michael Bohana19dced2012-04-24 13:14:50 -0700874 cfg->addr = Q_REG_MODE_CTL;
875 cfg->idx = Q_REG_I_MODE_CTL;
876 cfg->shift = Q_REG_MODE_SEL_SHIFT;
877 cfg->mask = Q_REG_MODE_SEL_MASK;
878 break;
Michael Bohana05f4552012-05-24 15:58:11 -0700879 case Q_PIN_CFG_OUTPUT_TYPE:
Michael Bohana19dced2012-04-24 13:14:50 -0700880 cfg->addr = Q_REG_DIG_OUT_CTL;
881 cfg->idx = Q_REG_I_DIG_OUT_CTL;
882 cfg->shift = Q_REG_OUT_TYPE_SHIFT;
883 cfg->mask = Q_REG_OUT_TYPE_MASK;
884 break;
Michael Bohana05f4552012-05-24 15:58:11 -0700885 case Q_PIN_CFG_INVERT:
Michael Bohana19dced2012-04-24 13:14:50 -0700886 cfg->addr = Q_REG_MODE_CTL;
887 cfg->idx = Q_REG_I_MODE_CTL;
888 cfg->shift = Q_REG_OUT_INVERT_SHIFT;
889 cfg->mask = Q_REG_OUT_INVERT_MASK;
890 break;
Michael Bohana05f4552012-05-24 15:58:11 -0700891 case Q_PIN_CFG_PULL:
Michael Bohana19dced2012-04-24 13:14:50 -0700892 cfg->addr = Q_REG_DIG_PULL_CTL;
893 cfg->idx = Q_REG_I_DIG_PULL_CTL;
894 cfg->shift = Q_REG_PULL_SHIFT;
895 cfg->mask = Q_REG_PULL_MASK;
896 break;
Michael Bohana05f4552012-05-24 15:58:11 -0700897 case Q_PIN_CFG_VIN_SEL:
Michael Bohana19dced2012-04-24 13:14:50 -0700898 cfg->addr = Q_REG_DIG_VIN_CTL;
899 cfg->idx = Q_REG_I_DIG_VIN_CTL;
900 cfg->shift = Q_REG_VIN_SHIFT;
901 cfg->mask = Q_REG_VIN_MASK;
902 break;
Michael Bohana05f4552012-05-24 15:58:11 -0700903 case Q_PIN_CFG_OUT_STRENGTH:
Michael Bohana19dced2012-04-24 13:14:50 -0700904 cfg->addr = Q_REG_DIG_OUT_CTL;
905 cfg->idx = Q_REG_I_DIG_OUT_CTL;
906 cfg->shift = Q_REG_OUT_STRENGTH_SHIFT;
907 cfg->mask = Q_REG_OUT_STRENGTH_MASK;
908 break;
Michael Bohan6b901572012-05-30 13:32:24 -0700909 case Q_PIN_CFG_SELECT:
Michael Bohana19dced2012-04-24 13:14:50 -0700910 cfg->addr = Q_REG_MODE_CTL;
911 cfg->idx = Q_REG_I_MODE_CTL;
912 cfg->shift = Q_REG_SRC_SEL_SHIFT;
913 cfg->mask = Q_REG_SRC_SEL_MASK;
914 break;
Michael Bohana05f4552012-05-24 15:58:11 -0700915 case Q_PIN_CFG_MASTER_EN:
Michael Bohana19dced2012-04-24 13:14:50 -0700916 cfg->addr = Q_REG_EN_CTL;
917 cfg->idx = Q_REG_I_EN_CTL;
918 cfg->shift = Q_REG_MASTER_EN_SHIFT;
919 cfg->mask = Q_REG_MASTER_EN_MASK;
920 break;
Michael Bohan6b901572012-05-30 13:32:24 -0700921 case Q_PIN_CFG_AOUT_REF:
922 cfg->addr = Q_REG_AOUT_CTL;
923 cfg->idx = Q_REG_I_AOUT_CTL;
924 cfg->shift = Q_REG_AOUT_REF_SHIFT;
925 cfg->mask = Q_REG_AOUT_REF_MASK;
926 break;
927 case Q_PIN_CFG_AIN_ROUTE:
928 cfg->addr = Q_REG_AIN_CTL;
929 cfg->idx = Q_REG_I_AIN_CTL;
930 cfg->shift = Q_REG_AIN_ROUTE_SHIFT;
931 cfg->mask = Q_REG_AIN_ROUTE_MASK;
932 break;
933 case Q_PIN_CFG_CS_OUT:
934 cfg->addr = Q_REG_SINK_CTL;
935 cfg->idx = Q_REG_I_SINK_CTL;
936 cfg->shift = Q_REG_CS_OUT_SHIFT;
937 cfg->mask = Q_REG_CS_OUT_MASK;
938 break;
Michael Bohana19dced2012-04-24 13:14:50 -0700939 default:
940 return -EINVAL;
941 }
942
943 return 0;
944}
945
Michael Bohana05f4552012-05-24 15:58:11 -0700946static int qpnp_pin_debugfs_get(void *data, u64 *val)
Michael Bohana19dced2012-04-24 13:14:50 -0700947{
Michael Bohana05f4552012-05-24 15:58:11 -0700948 enum qpnp_pin_param_type *idx = data;
949 struct qpnp_pin_spec *q_spec;
950 struct qpnp_pin_reg cfg = {};
Michael Bohana19dced2012-04-24 13:14:50 -0700951 int rc;
952
Michael Bohana05f4552012-05-24 15:58:11 -0700953 rc = qpnp_pin_reg_attr(*idx, &cfg);
Michael Bohana19dced2012-04-24 13:14:50 -0700954 if (rc)
955 return rc;
Michael Bohana05f4552012-05-24 15:58:11 -0700956 q_spec = container_of(idx, struct qpnp_pin_spec, params[*idx]);
Michael Bohana19dced2012-04-24 13:14:50 -0700957 *val = q_reg_get(&q_spec->regs[cfg.idx], cfg.shift, cfg.mask);
958 return 0;
959}
960
Michael Bohana05f4552012-05-24 15:58:11 -0700961static int qpnp_pin_debugfs_set(void *data, u64 val)
Michael Bohana19dced2012-04-24 13:14:50 -0700962{
Michael Bohana05f4552012-05-24 15:58:11 -0700963 enum qpnp_pin_param_type *idx = data;
964 struct qpnp_pin_spec *q_spec;
965 struct qpnp_pin_chip *q_chip;
966 struct qpnp_pin_reg cfg = {};
Michael Bohana19dced2012-04-24 13:14:50 -0700967 int rc;
968
Michael Bohana05f4552012-05-24 15:58:11 -0700969 q_spec = container_of(idx, struct qpnp_pin_spec, params[*idx]);
Michael Bohana19dced2012-04-24 13:14:50 -0700970 q_chip = q_spec->q_chip;
971
Michael Bohan58d07802012-05-31 15:37:55 -0700972 rc = qpnp_pin_check_config(*idx, q_spec, val);
Michael Bohana19dced2012-04-24 13:14:50 -0700973 if (rc)
974 return rc;
975
Michael Bohana05f4552012-05-24 15:58:11 -0700976 rc = qpnp_pin_reg_attr(*idx, &cfg);
Michael Bohana19dced2012-04-24 13:14:50 -0700977 if (rc)
978 return rc;
979 q_reg_clr_set(&q_spec->regs[cfg.idx], cfg.shift, cfg.mask, val);
980 rc = spmi_ext_register_writel(q_chip->spmi->ctrl, q_spec->slave,
981 Q_REG_ADDR(q_spec, cfg.addr),
982 &q_spec->regs[cfg.idx], 1);
983
984 return rc;
985}
Michael Bohana05f4552012-05-24 15:58:11 -0700986DEFINE_SIMPLE_ATTRIBUTE(qpnp_pin_fops, qpnp_pin_debugfs_get,
987 qpnp_pin_debugfs_set, "%llu\n");
Michael Bohana19dced2012-04-24 13:14:50 -0700988
989#define DEBUGFS_BUF_SIZE 11 /* supports 2^32 in decimal */
990
Michael Bohana05f4552012-05-24 15:58:11 -0700991struct qpnp_pin_debugfs_args {
992 enum qpnp_pin_param_type type;
Michael Bohana19dced2012-04-24 13:14:50 -0700993 const char *filename;
994};
995
Michael Bohana05f4552012-05-24 15:58:11 -0700996static struct qpnp_pin_debugfs_args dfs_args[] = {
Michael Bohan6b901572012-05-30 13:32:24 -0700997 { Q_PIN_CFG_MODE, "mode" },
Michael Bohana05f4552012-05-24 15:58:11 -0700998 { Q_PIN_CFG_OUTPUT_TYPE, "output_type" },
999 { Q_PIN_CFG_INVERT, "invert" },
1000 { Q_PIN_CFG_PULL, "pull" },
1001 { Q_PIN_CFG_VIN_SEL, "vin_sel" },
1002 { Q_PIN_CFG_OUT_STRENGTH, "out_strength" },
Michael Bohan6b901572012-05-30 13:32:24 -07001003 { Q_PIN_CFG_SELECT, "select" },
1004 { Q_PIN_CFG_MASTER_EN, "master_en" },
1005 { Q_PIN_CFG_AOUT_REF, "aout_ref" },
1006 { Q_PIN_CFG_AIN_ROUTE, "ain_route" },
1007 { Q_PIN_CFG_CS_OUT, "cs_out" },
Michael Bohana19dced2012-04-24 13:14:50 -07001008};
1009
Michael Bohana05f4552012-05-24 15:58:11 -07001010static int qpnp_pin_debugfs_create(struct qpnp_pin_chip *q_chip)
Michael Bohana19dced2012-04-24 13:14:50 -07001011{
1012 struct spmi_device *spmi = q_chip->spmi;
1013 struct device *dev = &spmi->dev;
Michael Bohana05f4552012-05-24 15:58:11 -07001014 struct qpnp_pin_spec *q_spec;
1015 enum qpnp_pin_param_type *params;
1016 enum qpnp_pin_param_type type;
1017 char pmic_pin[DEBUGFS_BUF_SIZE];
Michael Bohana19dced2012-04-24 13:14:50 -07001018 const char *filename;
1019 struct dentry *dfs, *dfs_io_dir;
Michael Bohan6b901572012-05-30 13:32:24 -07001020 int i, j, rc;
Michael Bohana19dced2012-04-24 13:14:50 -07001021
1022 BUG_ON(Q_NUM_PARAMS != ARRAY_SIZE(dfs_args));
1023
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001024 q_chip->dfs_dir = debugfs_create_dir(q_chip->gpio_chip.label,
Michael Bohana19dced2012-04-24 13:14:50 -07001025 driver_dfs_dir);
1026 if (q_chip->dfs_dir == NULL) {
1027 dev_err(dev, "%s: cannot register chip debugfs directory %s\n",
1028 __func__, dev->of_node->name);
1029 return -ENODEV;
1030 }
1031
1032 for (i = 0; i < spmi->num_dev_node; i++) {
1033 q_spec = qpnp_chip_gpio_get_spec(q_chip, i);
1034 params = q_spec->params;
Michael Bohana05f4552012-05-24 15:58:11 -07001035 snprintf(pmic_pin, DEBUGFS_BUF_SIZE, "%u", q_spec->pmic_pin);
Michael Bohan6b901572012-05-30 13:32:24 -07001036 dfs_io_dir = debugfs_create_dir(pmic_pin, q_chip->dfs_dir);
Michael Bohana19dced2012-04-24 13:14:50 -07001037 if (dfs_io_dir == NULL)
1038 goto dfs_err;
1039
1040 for (j = 0; j < Q_NUM_PARAMS; j++) {
1041 type = dfs_args[j].type;
1042 filename = dfs_args[j].filename;
1043
Michael Bohan6b901572012-05-30 13:32:24 -07001044 /*
1045 * Use a value of '0' to see if the pin has even basic
1046 * support for a function. Do not create a file if
1047 * it doesn't.
1048 */
1049 rc = qpnp_pin_check_config(type, q_spec, 0);
1050 if (rc == -ENXIO)
1051 continue;
1052
Michael Bohana19dced2012-04-24 13:14:50 -07001053 params[type] = type;
1054 dfs = debugfs_create_file(
1055 filename,
1056 S_IRUGO | S_IWUSR,
1057 dfs_io_dir,
1058 &q_spec->params[type],
Michael Bohana05f4552012-05-24 15:58:11 -07001059 &qpnp_pin_fops);
Michael Bohana19dced2012-04-24 13:14:50 -07001060 if (dfs == NULL)
1061 goto dfs_err;
1062 }
1063 }
1064 return 0;
1065dfs_err:
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001066 dev_err(dev, "%s: cannot register debugfs for pmic gpio %u on chip %s\n",
1067 __func__, q_spec->pmic_pin, dev->of_node->name);
Michael Bohana19dced2012-04-24 13:14:50 -07001068 debugfs_remove_recursive(q_chip->dfs_dir);
1069 return -ENFILE;
1070}
1071#else
Michael Bohana05f4552012-05-24 15:58:11 -07001072static int qpnp_pin_debugfs_create(struct qpnp_pin_chip *q_chip)
Michael Bohana19dced2012-04-24 13:14:50 -07001073{
1074 return 0;
1075}
1076#endif
1077
Michael Bohana05f4552012-05-24 15:58:11 -07001078static int qpnp_pin_probe(struct spmi_device *spmi)
Michael Bohan0ba63b82012-02-06 13:42:34 -08001079{
Michael Bohana05f4552012-05-24 15:58:11 -07001080 struct qpnp_pin_chip *q_chip;
1081 struct qpnp_pin_spec *q_spec;
Michael Bohan0e5534d2012-05-22 17:33:45 -07001082 struct resource *res;
1083 struct spmi_resource *d_node;
Michael Bohan94e397b2012-04-25 15:21:55 -07001084 int i, rc;
1085 int lowest_gpio = UINT_MAX, highest_gpio = 0;
1086 u32 intspec[3], gpio;
Michael Bohane25e15f2012-04-12 17:28:26 -07001087 char buf[2];
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001088 const char *dev_name;
1089
1090 dev_name = spmi_get_primary_dev_name(spmi);
1091 if (!dev_name) {
1092 dev_err(&spmi->dev, "%s: label binding undefined for node %s\n",
1093 __func__, spmi->dev.of_node->full_name);
1094 return -EINVAL;
1095 }
Michael Bohan0ba63b82012-02-06 13:42:34 -08001096
1097 q_chip = kzalloc(sizeof(*q_chip), GFP_KERNEL);
1098 if (!q_chip) {
1099 dev_err(&spmi->dev, "%s: Can't allocate gpio_chip\n",
1100 __func__);
1101 return -ENOMEM;
1102 }
1103 q_chip->spmi = spmi;
1104 dev_set_drvdata(&spmi->dev, q_chip);
1105
Michael Bohana05f4552012-05-24 15:58:11 -07001106 mutex_lock(&qpnp_pin_chips_lock);
1107 list_add(&q_chip->chip_list, &qpnp_pin_chips);
1108 mutex_unlock(&qpnp_pin_chips_lock);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001109
1110 /* first scan through nodes to find the range required for allocation */
1111 for (i = 0; i < spmi->num_dev_node; i++) {
Michael Bohan94e397b2012-04-25 15:21:55 -07001112 rc = of_property_read_u32(spmi->dev_node[i].of_node,
Michael Bohana05f4552012-05-24 15:58:11 -07001113 "qcom,pin-num", &gpio);
Michael Bohan94e397b2012-04-25 15:21:55 -07001114 if (rc) {
Michael Bohana05f4552012-05-24 15:58:11 -07001115 dev_err(&spmi->dev, "%s: unable to get qcom,pin-num property\n",
1116 __func__);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001117 goto err_probe;
1118 }
1119
Michael Bohan0ba63b82012-02-06 13:42:34 -08001120 if (gpio < lowest_gpio)
1121 lowest_gpio = gpio;
1122 if (gpio > highest_gpio)
1123 highest_gpio = gpio;
1124 }
1125
1126 if (highest_gpio < lowest_gpio) {
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001127 dev_err(&spmi->dev, "%s: no device nodes specified in topology\n",
1128 __func__);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001129 rc = -EINVAL;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001130 goto err_probe;
1131 } else if (lowest_gpio == 0) {
1132 dev_err(&spmi->dev, "%s: 0 is not a valid PMIC GPIO\n",
1133 __func__);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001134 rc = -EINVAL;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001135 goto err_probe;
1136 }
1137
Michael Bohana05f4552012-05-24 15:58:11 -07001138 q_chip->pmic_pin_lowest = lowest_gpio;
1139 q_chip->pmic_pin_highest = highest_gpio;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001140
1141 /* allocate gpio lookup tables */
Michael Bohana05f4552012-05-24 15:58:11 -07001142 q_chip->pmic_pins = kzalloc(sizeof(struct qpnp_pin_spec *) *
Michael Bohan0ba63b82012-02-06 13:42:34 -08001143 highest_gpio - lowest_gpio + 1,
1144 GFP_KERNEL);
Michael Bohana05f4552012-05-24 15:58:11 -07001145 q_chip->chip_gpios = kzalloc(sizeof(struct qpnp_pin_spec *) *
Michael Bohan0ba63b82012-02-06 13:42:34 -08001146 spmi->num_dev_node, GFP_KERNEL);
Michael Bohana05f4552012-05-24 15:58:11 -07001147 if (!q_chip->pmic_pins || !q_chip->chip_gpios) {
Michael Bohan0ba63b82012-02-06 13:42:34 -08001148 dev_err(&spmi->dev, "%s: unable to allocate memory\n",
1149 __func__);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001150 rc = -ENOMEM;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001151 goto err_probe;
1152 }
1153
1154 /* get interrupt controller device_node */
1155 q_chip->int_ctrl = of_irq_find_parent(spmi->dev.of_node);
1156 if (!q_chip->int_ctrl) {
1157 dev_err(&spmi->dev, "%s: Can't find interrupt parent\n",
1158 __func__);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001159 rc = -EINVAL;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001160 goto err_probe;
1161 }
1162
1163 /* now scan through again and populate the lookup table */
1164 for (i = 0; i < spmi->num_dev_node; i++) {
Michael Bohan0e5534d2012-05-22 17:33:45 -07001165 d_node = &spmi->dev_node[i];
1166 res = spmi_get_resource(spmi, d_node, IORESOURCE_MEM, 0);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001167 if (!res) {
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001168 dev_err(&spmi->dev, "%s: node %s is missing has no base address definition\n",
Michael Bohan0e5534d2012-05-22 17:33:45 -07001169 __func__, d_node->of_node->full_name);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001170 }
1171
Michael Bohan0e5534d2012-05-22 17:33:45 -07001172 rc = of_property_read_u32(d_node->of_node,
Michael Bohana05f4552012-05-24 15:58:11 -07001173 "qcom,pin-num", &gpio);
Michael Bohan94e397b2012-04-25 15:21:55 -07001174 if (rc) {
Michael Bohana05f4552012-05-24 15:58:11 -07001175 dev_err(&spmi->dev, "%s: unable to get qcom,pin-num property\n",
1176 __func__);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001177 goto err_probe;
1178 }
Michael Bohan0ba63b82012-02-06 13:42:34 -08001179
Michael Bohana05f4552012-05-24 15:58:11 -07001180 q_spec = kzalloc(sizeof(struct qpnp_pin_spec),
Michael Bohan0ba63b82012-02-06 13:42:34 -08001181 GFP_KERNEL);
1182 if (!q_spec) {
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001183 dev_err(&spmi->dev, "%s: unable to allocate memory\n",
1184 __func__);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001185 rc = -ENOMEM;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001186 goto err_probe;
1187 }
1188
1189 q_spec->slave = spmi->sid;
1190 q_spec->offset = res->start;
1191 q_spec->gpio_chip_idx = i;
Michael Bohana05f4552012-05-24 15:58:11 -07001192 q_spec->pmic_pin = gpio;
Michael Bohan0e5534d2012-05-22 17:33:45 -07001193 q_spec->node = d_node->of_node;
Michael Bohana19dced2012-04-24 13:14:50 -07001194 q_spec->q_chip = q_chip;
Michael Bohane25e15f2012-04-12 17:28:26 -07001195
1196 rc = spmi_ext_register_readl(spmi->ctrl, q_spec->slave,
1197 Q_REG_ADDR(q_spec, Q_REG_TYPE), &buf[0], 2);
1198 if (rc) {
1199 dev_err(&spmi->dev, "%s: unable to read type regs\n",
1200 __func__);
Michael Bohane25e15f2012-04-12 17:28:26 -07001201 goto err_probe;
1202 }
1203 q_spec->type = buf[0];
1204 q_spec->subtype = buf[1];
Michael Bohan0ba63b82012-02-06 13:42:34 -08001205
Michael Bohan6b901572012-05-30 13:32:24 -07001206 rc = qpnp_pin_ctl_regs_init(q_spec);
1207 if (rc)
1208 goto err_probe;
1209
Michael Bohan0ba63b82012-02-06 13:42:34 -08001210 /* call into irq_domain to get irq mapping */
1211 intspec[0] = q_chip->spmi->sid;
1212 intspec[1] = (q_spec->offset >> 8) & 0xFF;
1213 intspec[2] = 0;
1214 q_spec->irq = irq_create_of_mapping(q_chip->int_ctrl,
1215 intspec, 3);
1216 if (!q_spec->irq) {
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001217 dev_err(&spmi->dev, "%s: invalid irq for gpio %u\n",
1218 __func__, gpio);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001219 rc = -EINVAL;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001220 goto err_probe;
1221 }
Michael Bohana19dced2012-04-24 13:14:50 -07001222 /* initialize lookup table params */
Michael Bohana05f4552012-05-24 15:58:11 -07001223 qpnp_pmic_pin_set_spec(q_chip, gpio, q_spec);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001224 qpnp_chip_gpio_set_spec(q_chip, i, q_spec);
1225 }
1226
1227 q_chip->gpio_chip.base = -1;
1228 q_chip->gpio_chip.ngpio = spmi->num_dev_node;
Michael Bohan6ea2cd22012-05-29 15:40:18 -07001229 q_chip->gpio_chip.label = dev_name;
Michael Bohana05f4552012-05-24 15:58:11 -07001230 q_chip->gpio_chip.direction_input = qpnp_pin_direction_input;
1231 q_chip->gpio_chip.direction_output = qpnp_pin_direction_output;
1232 q_chip->gpio_chip.to_irq = qpnp_pin_to_irq;
1233 q_chip->gpio_chip.get = qpnp_pin_get;
1234 q_chip->gpio_chip.set = qpnp_pin_set;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001235 q_chip->gpio_chip.dev = &spmi->dev;
Michael Bohana05f4552012-05-24 15:58:11 -07001236 q_chip->gpio_chip.of_xlate = qpnp_pin_of_gpio_xlate;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001237 q_chip->gpio_chip.of_gpio_n_cells = 2;
1238 q_chip->gpio_chip.can_sleep = 0;
1239
1240 rc = gpiochip_add(&q_chip->gpio_chip);
1241 if (rc) {
1242 dev_err(&spmi->dev, "%s: Can't add gpio chip, rc = %d\n",
1243 __func__, rc);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001244 goto err_probe;
1245 }
1246
Michael Bohande3942a2012-04-17 15:28:01 -07001247 /* now configure gpio config defaults if they exist */
Michael Bohan0ba63b82012-02-06 13:42:34 -08001248 for (i = 0; i < spmi->num_dev_node; i++) {
1249 q_spec = qpnp_chip_gpio_get_spec(q_chip, i);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001250 if (WARN_ON(!q_spec)) {
1251 rc = -ENODEV;
1252 goto err_probe;
1253 }
Michael Bohan0ba63b82012-02-06 13:42:34 -08001254
Michael Bohana05f4552012-05-24 15:58:11 -07001255 rc = qpnp_pin_cache_regs(q_chip, q_spec);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001256 if (rc)
Michael Bohan0ba63b82012-02-06 13:42:34 -08001257 goto err_probe;
Michael Bohande3942a2012-04-17 15:28:01 -07001258
Michael Bohana05f4552012-05-24 15:58:11 -07001259 rc = qpnp_pin_apply_config(q_chip, q_spec);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001260 if (rc)
Michael Bohande3942a2012-04-17 15:28:01 -07001261 goto err_probe;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001262 }
1263
1264 dev_dbg(&spmi->dev, "%s: gpio_chip registered between %d-%u\n",
1265 __func__, q_chip->gpio_chip.base,
1266 (q_chip->gpio_chip.base + q_chip->gpio_chip.ngpio) - 1);
Michael Bohana19dced2012-04-24 13:14:50 -07001267
Michael Bohana05f4552012-05-24 15:58:11 -07001268 rc = qpnp_pin_debugfs_create(q_chip);
Michael Bohana19dced2012-04-24 13:14:50 -07001269 if (rc) {
1270 dev_err(&spmi->dev, "%s: debugfs creation failed\n", __func__);
1271 goto err_probe;
1272 }
1273
Michael Bohan0ba63b82012-02-06 13:42:34 -08001274 return 0;
1275
1276err_probe:
Michael Bohana05f4552012-05-24 15:58:11 -07001277 qpnp_pin_free_chip(q_chip);
Michael Bohanfdcbed22012-04-23 17:44:27 -07001278 return rc;
Michael Bohan0ba63b82012-02-06 13:42:34 -08001279}
1280
Michael Bohana05f4552012-05-24 15:58:11 -07001281static int qpnp_pin_remove(struct spmi_device *spmi)
Michael Bohan0ba63b82012-02-06 13:42:34 -08001282{
Michael Bohana05f4552012-05-24 15:58:11 -07001283 struct qpnp_pin_chip *q_chip = dev_get_drvdata(&spmi->dev);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001284
Michael Bohana19dced2012-04-24 13:14:50 -07001285 debugfs_remove_recursive(q_chip->dfs_dir);
1286
Michael Bohana05f4552012-05-24 15:58:11 -07001287 return qpnp_pin_free_chip(q_chip);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001288}
1289
1290static struct of_device_id spmi_match_table[] = {
Michael Bohana05f4552012-05-24 15:58:11 -07001291 { .compatible = "qcom,qpnp-pin",
Michael Bohan0ba63b82012-02-06 13:42:34 -08001292 },
1293 {}
1294};
1295
Michael Bohana05f4552012-05-24 15:58:11 -07001296static const struct spmi_device_id qpnp_pin_id[] = {
1297 { "qcom,qpnp-pin", 0 },
Michael Bohan0ba63b82012-02-06 13:42:34 -08001298 { }
1299};
Michael Bohana05f4552012-05-24 15:58:11 -07001300MODULE_DEVICE_TABLE(spmi, qpnp_pin_id);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001301
Michael Bohana05f4552012-05-24 15:58:11 -07001302static struct spmi_driver qpnp_pin_driver = {
Michael Bohan0ba63b82012-02-06 13:42:34 -08001303 .driver = {
Michael Bohana05f4552012-05-24 15:58:11 -07001304 .name = "qcom,qpnp-pin",
Michael Bohan0ba63b82012-02-06 13:42:34 -08001305 .of_match_table = spmi_match_table,
1306 },
Michael Bohana05f4552012-05-24 15:58:11 -07001307 .probe = qpnp_pin_probe,
1308 .remove = qpnp_pin_remove,
1309 .id_table = qpnp_pin_id,
Michael Bohan0ba63b82012-02-06 13:42:34 -08001310};
1311
Michael Bohana05f4552012-05-24 15:58:11 -07001312static int __init qpnp_pin_init(void)
Michael Bohan0ba63b82012-02-06 13:42:34 -08001313{
Michael Bohana05f4552012-05-24 15:58:11 -07001314#ifdef CONFIG_GPIO_QPNP_PIN_DEBUG
1315 driver_dfs_dir = debugfs_create_dir("qpnp_pin", NULL);
Michael Bohana19dced2012-04-24 13:14:50 -07001316 if (driver_dfs_dir == NULL)
1317 pr_err("Cannot register top level debugfs directory\n");
1318#endif
1319
Michael Bohana05f4552012-05-24 15:58:11 -07001320 return spmi_driver_register(&qpnp_pin_driver);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001321}
1322
Michael Bohana05f4552012-05-24 15:58:11 -07001323static void __exit qpnp_pin_exit(void)
Michael Bohan0ba63b82012-02-06 13:42:34 -08001324{
Michael Bohana05f4552012-05-24 15:58:11 -07001325#ifdef CONFIG_GPIO_QPNP_PIN_DEBUG
Michael Bohana19dced2012-04-24 13:14:50 -07001326 debugfs_remove_recursive(driver_dfs_dir);
1327#endif
Michael Bohana05f4552012-05-24 15:58:11 -07001328 spmi_driver_unregister(&qpnp_pin_driver);
Michael Bohan0ba63b82012-02-06 13:42:34 -08001329}
1330
Michael Bohan0ba63b82012-02-06 13:42:34 -08001331MODULE_DESCRIPTION("QPNP PMIC gpio driver");
Michael Bohan7f0cc9d2012-04-16 17:16:09 -07001332MODULE_LICENSE("GPL v2");
Michael Bohan0ba63b82012-02-06 13:42:34 -08001333
Michael Bohana05f4552012-05-24 15:58:11 -07001334module_init(qpnp_pin_init);
1335module_exit(qpnp_pin_exit);