blob: 9dde023640baaba1ced1627295de6a662d008189 [file] [log] [blame]
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +03001/*
2 * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/gpio.h>
15#include <linux/module.h>
16#include <linux/of.h>
17#include <linux/pinctrl/pinconf-generic.h>
18#include <linux/pinctrl/pinconf.h>
19#include <linux/pinctrl/pinmux.h>
20#include <linux/platform_device.h>
21#include <linux/regmap.h>
22#include <linux/slab.h>
23#include <linux/types.h>
24
25#include <dt-bindings/pinctrl/qcom,pmic-mpp.h>
26
27#include "../core.h"
28#include "../pinctrl-utils.h"
29
30#define PMIC_MPP_ADDRESS_RANGE 0x100
31
32/*
33 * Pull Up Values - it indicates whether a pull-up should be
34 * applied for bidirectional mode only. The hardware ignores the
35 * configuration when operating in other modes.
36 */
37#define PMIC_MPP_PULL_UP_0P6KOHM 0
38#define PMIC_MPP_PULL_UP_10KOHM 1
39#define PMIC_MPP_PULL_UP_30KOHM 2
40#define PMIC_MPP_PULL_UP_OPEN 3
41
42/* type registers base address bases */
43#define PMIC_MPP_REG_TYPE 0x4
44#define PMIC_MPP_REG_SUBTYPE 0x5
45
46/* mpp peripheral type and subtype values */
47#define PMIC_MPP_TYPE 0x11
48#define PMIC_MPP_SUBTYPE_4CH_NO_ANA_OUT 0x3
49#define PMIC_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT 0x4
50#define PMIC_MPP_SUBTYPE_4CH_NO_SINK 0x5
51#define PMIC_MPP_SUBTYPE_ULT_4CH_NO_SINK 0x6
52#define PMIC_MPP_SUBTYPE_4CH_FULL_FUNC 0x7
53#define PMIC_MPP_SUBTYPE_8CH_FULL_FUNC 0xf
54
55#define PMIC_MPP_REG_RT_STS 0x10
56#define PMIC_MPP_REG_RT_STS_VAL_MASK 0x1
57
58/* control register base address bases */
59#define PMIC_MPP_REG_MODE_CTL 0x40
60#define PMIC_MPP_REG_DIG_VIN_CTL 0x41
61#define PMIC_MPP_REG_DIG_PULL_CTL 0x42
62#define PMIC_MPP_REG_DIG_IN_CTL 0x43
63#define PMIC_MPP_REG_EN_CTL 0x46
64#define PMIC_MPP_REG_AIN_CTL 0x4a
Bjorn Andersson0e948042015-06-17 23:47:28 -070065#define PMIC_MPP_REG_SINK_CTL 0x4c
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +030066
67/* PMIC_MPP_REG_MODE_CTL */
68#define PMIC_MPP_REG_MODE_VALUE_MASK 0x1
69#define PMIC_MPP_REG_MODE_FUNCTION_SHIFT 1
70#define PMIC_MPP_REG_MODE_FUNCTION_MASK 0x7
71#define PMIC_MPP_REG_MODE_DIR_SHIFT 4
72#define PMIC_MPP_REG_MODE_DIR_MASK 0x7
73
74/* PMIC_MPP_REG_DIG_VIN_CTL */
75#define PMIC_MPP_REG_VIN_SHIFT 0
76#define PMIC_MPP_REG_VIN_MASK 0x7
77
78/* PMIC_MPP_REG_DIG_PULL_CTL */
79#define PMIC_MPP_REG_PULL_SHIFT 0
80#define PMIC_MPP_REG_PULL_MASK 0x7
81
82/* PMIC_MPP_REG_EN_CTL */
83#define PMIC_MPP_REG_MASTER_EN_SHIFT 7
84
85/* PMIC_MPP_REG_AIN_CTL */
86#define PMIC_MPP_REG_AIN_ROUTE_SHIFT 0
87#define PMIC_MPP_REG_AIN_ROUTE_MASK 0x7
88
Bjorn Anderssoneaaf5dd2015-06-17 23:47:27 -070089#define PMIC_MPP_MODE_DIGITAL_INPUT 0
90#define PMIC_MPP_MODE_DIGITAL_OUTPUT 1
91#define PMIC_MPP_MODE_DIGITAL_BIDIR 2
92#define PMIC_MPP_MODE_ANALOG_BIDIR 3
93#define PMIC_MPP_MODE_ANALOG_INPUT 4
94#define PMIC_MPP_MODE_ANALOG_OUTPUT 5
95#define PMIC_MPP_MODE_CURRENT_SINK 6
96
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +030097#define PMIC_MPP_PHYSICAL_OFFSET 1
98
99/* Qualcomm specific pin configurations */
100#define PMIC_MPP_CONF_AMUX_ROUTE (PIN_CONFIG_END + 1)
101#define PMIC_MPP_CONF_ANALOG_MODE (PIN_CONFIG_END + 2)
Bjorn Andersson0e948042015-06-17 23:47:28 -0700102#define PMIC_MPP_CONF_SINK_MODE (PIN_CONFIG_END + 3)
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300103
104/**
105 * struct pmic_mpp_pad - keep current MPP settings
106 * @base: Address base in SPMI device.
107 * @irq: IRQ number which this MPP generate.
108 * @is_enabled: Set to false when MPP should be put in high Z state.
109 * @out_value: Cached pin output value.
110 * @output_enabled: Set to true if MPP output logic is enabled.
111 * @input_enabled: Set to true if MPP input buffer logic is enabled.
112 * @analog_mode: Set to true when MPP should operate in Analog Input, Analog
113 * Output or Bidirectional Analog mode.
Bjorn Andersson0e948042015-06-17 23:47:28 -0700114 * @sink_mode: Boolean indicating if ink mode is slected
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300115 * @num_sources: Number of power-sources supported by this MPP.
116 * @power_source: Current power-source used.
117 * @amux_input: Set the source for analog input.
118 * @pullup: Pullup resistor value. Valid in Bidirectional mode only.
119 * @function: See pmic_mpp_functions[].
Bjorn Andersson0e948042015-06-17 23:47:28 -0700120 * @drive_strength: Amount of current in sink mode
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300121 */
122struct pmic_mpp_pad {
123 u16 base;
124 int irq;
125 bool is_enabled;
126 bool out_value;
127 bool output_enabled;
128 bool input_enabled;
129 bool analog_mode;
Bjorn Andersson0e948042015-06-17 23:47:28 -0700130 bool sink_mode;
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300131 unsigned int num_sources;
132 unsigned int power_source;
133 unsigned int amux_input;
134 unsigned int pullup;
135 unsigned int function;
Bjorn Andersson0e948042015-06-17 23:47:28 -0700136 unsigned int drive_strength;
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300137};
138
139struct pmic_mpp_state {
140 struct device *dev;
141 struct regmap *map;
142 struct pinctrl_dev *ctrl;
143 struct gpio_chip chip;
144};
145
Bjorn Anderssonba5f94c2015-06-17 23:47:25 -0700146static const struct pinconf_generic_params pmic_mpp_bindings[] = {
147 {"qcom,amux-route", PMIC_MPP_CONF_AMUX_ROUTE, 0},
148 {"qcom,analog-mode", PMIC_MPP_CONF_ANALOG_MODE, 0},
Bjorn Andersson0e948042015-06-17 23:47:28 -0700149 {"qcom,sink-mode", PMIC_MPP_CONF_SINK_MODE, 0},
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300150};
151
Bjorn Anderssonba5f94c2015-06-17 23:47:25 -0700152#ifdef CONFIG_DEBUG_FS
153static const struct pin_config_item pmic_conf_items[] = {
154 PCONFDUMP(PMIC_MPP_CONF_AMUX_ROUTE, "analog mux", NULL, true),
155 PCONFDUMP(PMIC_MPP_CONF_ANALOG_MODE, "analog output", NULL, false),
Bjorn Andersson0e948042015-06-17 23:47:28 -0700156 PCONFDUMP(PMIC_MPP_CONF_SINK_MODE, "sink mode", NULL, false),
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300157};
Bjorn Anderssonba5f94c2015-06-17 23:47:25 -0700158#endif
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300159
160static const char *const pmic_mpp_groups[] = {
161 "mpp1", "mpp2", "mpp3", "mpp4", "mpp5", "mpp6", "mpp7", "mpp8",
162};
163
164static const char *const pmic_mpp_functions[] = {
165 PMIC_MPP_FUNC_NORMAL, PMIC_MPP_FUNC_PAIRED,
166 "reserved1", "reserved2",
167 PMIC_MPP_FUNC_DTEST1, PMIC_MPP_FUNC_DTEST2,
168 PMIC_MPP_FUNC_DTEST3, PMIC_MPP_FUNC_DTEST4,
169};
170
171static inline struct pmic_mpp_state *to_mpp_state(struct gpio_chip *chip)
172{
173 return container_of(chip, struct pmic_mpp_state, chip);
174};
175
176static int pmic_mpp_read(struct pmic_mpp_state *state,
177 struct pmic_mpp_pad *pad, unsigned int addr)
178{
179 unsigned int val;
180 int ret;
181
182 ret = regmap_read(state->map, pad->base + addr, &val);
183 if (ret < 0)
184 dev_err(state->dev, "read 0x%x failed\n", addr);
185 else
186 ret = val;
187
188 return ret;
189}
190
191static int pmic_mpp_write(struct pmic_mpp_state *state,
192 struct pmic_mpp_pad *pad, unsigned int addr,
193 unsigned int val)
194{
195 int ret;
196
197 ret = regmap_write(state->map, pad->base + addr, val);
198 if (ret < 0)
199 dev_err(state->dev, "write 0x%x failed\n", addr);
200
201 return ret;
202}
203
204static int pmic_mpp_get_groups_count(struct pinctrl_dev *pctldev)
205{
206 /* Every PIN is a group */
207 return pctldev->desc->npins;
208}
209
210static const char *pmic_mpp_get_group_name(struct pinctrl_dev *pctldev,
211 unsigned pin)
212{
213 return pctldev->desc->pins[pin].name;
214}
215
216static int pmic_mpp_get_group_pins(struct pinctrl_dev *pctldev,
217 unsigned pin,
218 const unsigned **pins, unsigned *num_pins)
219{
220 *pins = &pctldev->desc->pins[pin].number;
221 *num_pins = 1;
222 return 0;
223}
224
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300225static const struct pinctrl_ops pmic_mpp_pinctrl_ops = {
226 .get_groups_count = pmic_mpp_get_groups_count,
227 .get_group_name = pmic_mpp_get_group_name,
228 .get_group_pins = pmic_mpp_get_group_pins,
Bjorn Anderssonba5f94c2015-06-17 23:47:25 -0700229 .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300230 .dt_free_map = pinctrl_utils_dt_free_map,
231};
232
233static int pmic_mpp_get_functions_count(struct pinctrl_dev *pctldev)
234{
235 return ARRAY_SIZE(pmic_mpp_functions);
236}
237
238static const char *pmic_mpp_get_function_name(struct pinctrl_dev *pctldev,
239 unsigned function)
240{
241 return pmic_mpp_functions[function];
242}
243
244static int pmic_mpp_get_function_groups(struct pinctrl_dev *pctldev,
245 unsigned function,
246 const char *const **groups,
247 unsigned *const num_qgroups)
248{
249 *groups = pmic_mpp_groups;
250 *num_qgroups = pctldev->desc->npins;
251 return 0;
252}
253
Bjorn Andersson0e948042015-06-17 23:47:28 -0700254static int pmic_mpp_write_mode_ctl(struct pmic_mpp_state *state,
255 struct pmic_mpp_pad *pad)
256{
257 unsigned int val;
258
259 if (pad->analog_mode) {
260 val = PMIC_MPP_MODE_ANALOG_INPUT;
261 if (pad->output_enabled) {
262 if (pad->input_enabled)
263 val = PMIC_MPP_MODE_ANALOG_BIDIR;
264 else
265 val = PMIC_MPP_MODE_ANALOG_OUTPUT;
266 }
267 } else if (pad->sink_mode) {
268 val = PMIC_MPP_MODE_CURRENT_SINK;
269 } else {
270 val = PMIC_MPP_MODE_DIGITAL_INPUT;
271 if (pad->output_enabled) {
272 if (pad->input_enabled)
273 val = PMIC_MPP_MODE_DIGITAL_BIDIR;
274 else
275 val = PMIC_MPP_MODE_DIGITAL_OUTPUT;
276 }
277 }
278
279 val = val << PMIC_MPP_REG_MODE_DIR_SHIFT;
280 val |= pad->function << PMIC_MPP_REG_MODE_FUNCTION_SHIFT;
281 val |= pad->out_value & PMIC_MPP_REG_MODE_VALUE_MASK;
282
283 return pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val);
284}
285
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300286static int pmic_mpp_set_mux(struct pinctrl_dev *pctldev, unsigned function,
287 unsigned pin)
288{
289 struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev);
290 struct pmic_mpp_pad *pad;
291 unsigned int val;
292 int ret;
293
294 pad = pctldev->desc->pins[pin].drv_data;
295
296 pad->function = function;
297
Bjorn Andersson0e948042015-06-17 23:47:28 -0700298 ret = pmic_mpp_write_mode_ctl(state, pad);
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300299
300 val = pad->is_enabled << PMIC_MPP_REG_MASTER_EN_SHIFT;
301
302 return pmic_mpp_write(state, pad, PMIC_MPP_REG_EN_CTL, val);
303}
304
305static const struct pinmux_ops pmic_mpp_pinmux_ops = {
306 .get_functions_count = pmic_mpp_get_functions_count,
307 .get_function_name = pmic_mpp_get_function_name,
308 .get_function_groups = pmic_mpp_get_function_groups,
309 .set_mux = pmic_mpp_set_mux,
310};
311
312static int pmic_mpp_config_get(struct pinctrl_dev *pctldev,
313 unsigned int pin, unsigned long *config)
314{
315 unsigned param = pinconf_to_config_param(*config);
316 struct pmic_mpp_pad *pad;
317 unsigned arg = 0;
318
319 pad = pctldev->desc->pins[pin].drv_data;
320
321 switch (param) {
322 case PIN_CONFIG_BIAS_DISABLE:
323 arg = pad->pullup == PMIC_MPP_PULL_UP_OPEN;
324 break;
325 case PIN_CONFIG_BIAS_PULL_UP:
326 switch (pad->pullup) {
327 case PMIC_MPP_PULL_UP_OPEN:
328 arg = 0;
329 break;
330 case PMIC_MPP_PULL_UP_0P6KOHM:
331 arg = 600;
332 break;
333 case PMIC_MPP_PULL_UP_10KOHM:
334 arg = 10000;
335 break;
336 case PMIC_MPP_PULL_UP_30KOHM:
337 arg = 30000;
338 break;
339 default:
340 return -EINVAL;
341 }
342 break;
343 case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
344 arg = !pad->is_enabled;
345 break;
346 case PIN_CONFIG_POWER_SOURCE:
347 arg = pad->power_source;
348 break;
349 case PIN_CONFIG_INPUT_ENABLE:
350 arg = pad->input_enabled;
351 break;
352 case PIN_CONFIG_OUTPUT:
353 arg = pad->out_value;
354 break;
355 case PMIC_MPP_CONF_AMUX_ROUTE:
356 arg = pad->amux_input;
357 break;
Bjorn Andersson0e948042015-06-17 23:47:28 -0700358 case PIN_CONFIG_DRIVE_STRENGTH:
359 arg = pad->drive_strength;
360 break;
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300361 case PMIC_MPP_CONF_ANALOG_MODE:
362 arg = pad->analog_mode;
363 break;
Bjorn Andersson0e948042015-06-17 23:47:28 -0700364 case PMIC_MPP_CONF_SINK_MODE:
365 arg = pad->sink_mode;
366 break;
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300367 default:
368 return -EINVAL;
369 }
370
371 /* Convert register value to pinconf value */
372 *config = pinconf_to_config_packed(param, arg);
373 return 0;
374}
375
376static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
377 unsigned long *configs, unsigned nconfs)
378{
379 struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev);
380 struct pmic_mpp_pad *pad;
381 unsigned param, arg;
382 unsigned int val;
383 int i, ret;
384
385 pad = pctldev->desc->pins[pin].drv_data;
386
Bjorn Andersson7682b372015-06-17 23:47:26 -0700387 /* Make it possible to enable the pin, by not setting high impedance */
388 pad->is_enabled = true;
389
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300390 for (i = 0; i < nconfs; i++) {
391 param = pinconf_to_config_param(configs[i]);
392 arg = pinconf_to_config_argument(configs[i]);
393
394 switch (param) {
395 case PIN_CONFIG_BIAS_DISABLE:
396 pad->pullup = PMIC_MPP_PULL_UP_OPEN;
397 break;
398 case PIN_CONFIG_BIAS_PULL_UP:
399 switch (arg) {
400 case 600:
401 pad->pullup = PMIC_MPP_PULL_UP_0P6KOHM;
402 break;
403 case 10000:
404 pad->pullup = PMIC_MPP_PULL_UP_10KOHM;
405 break;
406 case 30000:
407 pad->pullup = PMIC_MPP_PULL_UP_30KOHM;
408 break;
409 default:
410 return -EINVAL;
411 }
412 break;
413 case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
414 pad->is_enabled = false;
415 break;
416 case PIN_CONFIG_POWER_SOURCE:
417 if (arg >= pad->num_sources)
418 return -EINVAL;
419 pad->power_source = arg;
420 break;
421 case PIN_CONFIG_INPUT_ENABLE:
422 pad->input_enabled = arg ? true : false;
423 break;
424 case PIN_CONFIG_OUTPUT:
425 pad->output_enabled = true;
426 pad->out_value = arg;
427 break;
Bjorn Andersson0e948042015-06-17 23:47:28 -0700428 case PIN_CONFIG_DRIVE_STRENGTH:
429 arg = pad->drive_strength;
430 break;
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300431 case PMIC_MPP_CONF_AMUX_ROUTE:
432 if (arg >= PMIC_MPP_AMUX_ROUTE_ABUS4)
433 return -EINVAL;
434 pad->amux_input = arg;
435 break;
436 case PMIC_MPP_CONF_ANALOG_MODE:
Bjorn Andersson0e948042015-06-17 23:47:28 -0700437 pad->analog_mode = !!arg;
438 break;
439 case PMIC_MPP_CONF_SINK_MODE:
440 pad->sink_mode = !!arg;
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300441 break;
442 default:
443 return -EINVAL;
444 }
445 }
446
447 val = pad->power_source << PMIC_MPP_REG_VIN_SHIFT;
448
449 ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_DIG_VIN_CTL, val);
450 if (ret < 0)
451 return ret;
452
453 val = pad->pullup << PMIC_MPP_REG_PULL_SHIFT;
454
455 ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_DIG_PULL_CTL, val);
456 if (ret < 0)
457 return ret;
458
459 val = pad->amux_input & PMIC_MPP_REG_AIN_ROUTE_MASK;
460
461 ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_AIN_CTL, val);
462 if (ret < 0)
463 return ret;
464
Bjorn Andersson0e948042015-06-17 23:47:28 -0700465 ret = pmic_mpp_write_mode_ctl(state, pad);
Bjorn Andersson7682b372015-06-17 23:47:26 -0700466 if (ret < 0)
467 return ret;
468
469 val = pad->is_enabled << PMIC_MPP_REG_MASTER_EN_SHIFT;
470
471 return pmic_mpp_write(state, pad, PMIC_MPP_REG_EN_CTL, val);
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300472}
473
474static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev,
475 struct seq_file *s, unsigned pin)
476{
477 struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev);
478 struct pmic_mpp_pad *pad;
Bjorn Andersson7682b372015-06-17 23:47:26 -0700479 int ret;
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300480
481 static const char *const biases[] = {
482 "0.6kOhm", "10kOhm", "30kOhm", "Disabled"
483 };
484
Bjorn Andersson0e948042015-06-17 23:47:28 -0700485 static const char *const modes[] = {
486 "digital", "analog", "sink"
487 };
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300488
489 pad = pctldev->desc->pins[pin].drv_data;
490
491 seq_printf(s, " mpp%-2d:", pin + PMIC_MPP_PHYSICAL_OFFSET);
492
Bjorn Andersson7682b372015-06-17 23:47:26 -0700493 if (!pad->is_enabled) {
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300494 seq_puts(s, " ---");
495 } else {
496
497 if (pad->input_enabled) {
498 ret = pmic_mpp_read(state, pad, PMIC_MPP_REG_RT_STS);
Ivan T. Ivanov4e637ac2015-04-09 18:18:37 +0300499 if (ret < 0)
500 return;
501
502 ret &= PMIC_MPP_REG_RT_STS_VAL_MASK;
503 pad->out_value = ret;
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300504 }
505
506 seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in");
Bjorn Andersson0e948042015-06-17 23:47:28 -0700507 seq_printf(s, " %-7s", modes[pad->analog_mode ? 1 : (pad->sink_mode ? 2 : 0)]);
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300508 seq_printf(s, " %-7s", pmic_mpp_functions[pad->function]);
509 seq_printf(s, " vin-%d", pad->power_source);
510 seq_printf(s, " %-8s", biases[pad->pullup]);
511 seq_printf(s, " %-4s", pad->out_value ? "high" : "low");
512 }
513}
514
515static const struct pinconf_ops pmic_mpp_pinconf_ops = {
Bjorn Anderssonba5f94c2015-06-17 23:47:25 -0700516 .is_generic = true,
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300517 .pin_config_group_get = pmic_mpp_config_get,
518 .pin_config_group_set = pmic_mpp_config_set,
519 .pin_config_group_dbg_show = pmic_mpp_config_dbg_show,
520};
521
522static int pmic_mpp_direction_input(struct gpio_chip *chip, unsigned pin)
523{
524 struct pmic_mpp_state *state = to_mpp_state(chip);
525 unsigned long config;
526
527 config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
528
529 return pmic_mpp_config_set(state->ctrl, pin, &config, 1);
530}
531
532static int pmic_mpp_direction_output(struct gpio_chip *chip,
533 unsigned pin, int val)
534{
535 struct pmic_mpp_state *state = to_mpp_state(chip);
536 unsigned long config;
537
538 config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val);
539
540 return pmic_mpp_config_set(state->ctrl, pin, &config, 1);
541}
542
543static int pmic_mpp_get(struct gpio_chip *chip, unsigned pin)
544{
545 struct pmic_mpp_state *state = to_mpp_state(chip);
546 struct pmic_mpp_pad *pad;
547 int ret;
548
549 pad = state->ctrl->desc->pins[pin].drv_data;
550
551 if (pad->input_enabled) {
552 ret = pmic_mpp_read(state, pad, PMIC_MPP_REG_RT_STS);
553 if (ret < 0)
554 return ret;
555
556 pad->out_value = ret & PMIC_MPP_REG_RT_STS_VAL_MASK;
557 }
558
559 return pad->out_value;
560}
561
562static void pmic_mpp_set(struct gpio_chip *chip, unsigned pin, int value)
563{
564 struct pmic_mpp_state *state = to_mpp_state(chip);
565 unsigned long config;
566
567 config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value);
568
569 pmic_mpp_config_set(state->ctrl, pin, &config, 1);
570}
571
572static int pmic_mpp_request(struct gpio_chip *chip, unsigned base)
573{
574 return pinctrl_request_gpio(chip->base + base);
575}
576
577static void pmic_mpp_free(struct gpio_chip *chip, unsigned base)
578{
579 pinctrl_free_gpio(chip->base + base);
580}
581
582static int pmic_mpp_of_xlate(struct gpio_chip *chip,
583 const struct of_phandle_args *gpio_desc,
584 u32 *flags)
585{
586 if (chip->of_gpio_n_cells < 2)
587 return -EINVAL;
588
589 if (flags)
590 *flags = gpio_desc->args[1];
591
592 return gpio_desc->args[0] - PMIC_MPP_PHYSICAL_OFFSET;
593}
594
595static int pmic_mpp_to_irq(struct gpio_chip *chip, unsigned pin)
596{
597 struct pmic_mpp_state *state = to_mpp_state(chip);
598 struct pmic_mpp_pad *pad;
599
600 pad = state->ctrl->desc->pins[pin].drv_data;
601
602 return pad->irq;
603}
604
605static void pmic_mpp_dbg_show(struct seq_file *s, struct gpio_chip *chip)
606{
607 struct pmic_mpp_state *state = to_mpp_state(chip);
608 unsigned i;
609
610 for (i = 0; i < chip->ngpio; i++) {
611 pmic_mpp_config_dbg_show(state->ctrl, s, i);
612 seq_puts(s, "\n");
613 }
614}
615
616static const struct gpio_chip pmic_mpp_gpio_template = {
617 .direction_input = pmic_mpp_direction_input,
618 .direction_output = pmic_mpp_direction_output,
619 .get = pmic_mpp_get,
620 .set = pmic_mpp_set,
621 .request = pmic_mpp_request,
622 .free = pmic_mpp_free,
623 .of_xlate = pmic_mpp_of_xlate,
624 .to_irq = pmic_mpp_to_irq,
625 .dbg_show = pmic_mpp_dbg_show,
626};
627
628static int pmic_mpp_populate(struct pmic_mpp_state *state,
629 struct pmic_mpp_pad *pad)
630{
631 int type, subtype, val, dir;
632
633 type = pmic_mpp_read(state, pad, PMIC_MPP_REG_TYPE);
634 if (type < 0)
635 return type;
636
637 if (type != PMIC_MPP_TYPE) {
638 dev_err(state->dev, "incorrect block type 0x%x at 0x%x\n",
639 type, pad->base);
640 return -ENODEV;
641 }
642
643 subtype = pmic_mpp_read(state, pad, PMIC_MPP_REG_SUBTYPE);
644 if (subtype < 0)
645 return subtype;
646
647 switch (subtype) {
648 case PMIC_MPP_SUBTYPE_4CH_NO_ANA_OUT:
649 case PMIC_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT:
650 case PMIC_MPP_SUBTYPE_4CH_NO_SINK:
651 case PMIC_MPP_SUBTYPE_ULT_4CH_NO_SINK:
652 case PMIC_MPP_SUBTYPE_4CH_FULL_FUNC:
653 pad->num_sources = 4;
654 break;
655 case PMIC_MPP_SUBTYPE_8CH_FULL_FUNC:
656 pad->num_sources = 8;
657 break;
658 default:
659 dev_err(state->dev, "unknown MPP type 0x%x at 0x%x\n",
660 subtype, pad->base);
661 return -ENODEV;
662 }
663
664 val = pmic_mpp_read(state, pad, PMIC_MPP_REG_MODE_CTL);
665 if (val < 0)
666 return val;
667
668 pad->out_value = val & PMIC_MPP_REG_MODE_VALUE_MASK;
669
670 dir = val >> PMIC_MPP_REG_MODE_DIR_SHIFT;
671 dir &= PMIC_MPP_REG_MODE_DIR_MASK;
672
673 switch (dir) {
Bjorn Anderssoneaaf5dd2015-06-17 23:47:27 -0700674 case PMIC_MPP_MODE_DIGITAL_INPUT:
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300675 pad->input_enabled = true;
676 pad->output_enabled = false;
677 pad->analog_mode = false;
Bjorn Andersson0e948042015-06-17 23:47:28 -0700678 pad->sink_mode = false;
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300679 break;
Bjorn Anderssoneaaf5dd2015-06-17 23:47:27 -0700680 case PMIC_MPP_MODE_DIGITAL_OUTPUT:
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300681 pad->input_enabled = false;
682 pad->output_enabled = true;
683 pad->analog_mode = false;
Bjorn Andersson0e948042015-06-17 23:47:28 -0700684 pad->sink_mode = false;
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300685 break;
Bjorn Anderssoneaaf5dd2015-06-17 23:47:27 -0700686 case PMIC_MPP_MODE_DIGITAL_BIDIR:
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300687 pad->input_enabled = true;
688 pad->output_enabled = true;
689 pad->analog_mode = false;
Bjorn Andersson0e948042015-06-17 23:47:28 -0700690 pad->sink_mode = false;
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300691 break;
Bjorn Anderssoneaaf5dd2015-06-17 23:47:27 -0700692 case PMIC_MPP_MODE_ANALOG_BIDIR:
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300693 pad->input_enabled = true;
694 pad->output_enabled = true;
695 pad->analog_mode = true;
Bjorn Andersson0e948042015-06-17 23:47:28 -0700696 pad->sink_mode = false;
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300697 break;
Bjorn Anderssoneaaf5dd2015-06-17 23:47:27 -0700698 case PMIC_MPP_MODE_ANALOG_INPUT:
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300699 pad->input_enabled = true;
700 pad->output_enabled = false;
701 pad->analog_mode = true;
Bjorn Andersson0e948042015-06-17 23:47:28 -0700702 pad->sink_mode = false;
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300703 break;
Bjorn Anderssoneaaf5dd2015-06-17 23:47:27 -0700704 case PMIC_MPP_MODE_ANALOG_OUTPUT:
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300705 pad->input_enabled = false;
706 pad->output_enabled = true;
707 pad->analog_mode = true;
Bjorn Andersson0e948042015-06-17 23:47:28 -0700708 pad->sink_mode = false;
709 break;
710 case PMIC_MPP_MODE_CURRENT_SINK:
711 pad->input_enabled = false;
712 pad->output_enabled = true;
713 pad->analog_mode = false;
714 pad->sink_mode = true;
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300715 break;
716 default:
717 dev_err(state->dev, "unknown MPP direction\n");
718 return -ENODEV;
719 }
720
721 pad->function = val >> PMIC_MPP_REG_MODE_FUNCTION_SHIFT;
722 pad->function &= PMIC_MPP_REG_MODE_FUNCTION_MASK;
723
724 val = pmic_mpp_read(state, pad, PMIC_MPP_REG_DIG_VIN_CTL);
725 if (val < 0)
726 return val;
727
728 pad->power_source = val >> PMIC_MPP_REG_VIN_SHIFT;
729 pad->power_source &= PMIC_MPP_REG_VIN_MASK;
730
731 val = pmic_mpp_read(state, pad, PMIC_MPP_REG_DIG_PULL_CTL);
732 if (val < 0)
733 return val;
734
735 pad->pullup = val >> PMIC_MPP_REG_PULL_SHIFT;
736 pad->pullup &= PMIC_MPP_REG_PULL_MASK;
737
738 val = pmic_mpp_read(state, pad, PMIC_MPP_REG_AIN_CTL);
739 if (val < 0)
740 return val;
741
742 pad->amux_input = val >> PMIC_MPP_REG_AIN_ROUTE_SHIFT;
743 pad->amux_input &= PMIC_MPP_REG_AIN_ROUTE_MASK;
744
Bjorn Andersson0e948042015-06-17 23:47:28 -0700745 val = pmic_mpp_read(state, pad, PMIC_MPP_REG_SINK_CTL);
746 if (val < 0)
747 return val;
748
749 pad->drive_strength = val;
750
Bjorn Andersson7682b372015-06-17 23:47:26 -0700751 val = pmic_mpp_read(state, pad, PMIC_MPP_REG_EN_CTL);
752 if (val < 0)
753 return val;
754
755 pad->is_enabled = !!val;
756
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300757 return 0;
758}
759
760static int pmic_mpp_probe(struct platform_device *pdev)
761{
762 struct device *dev = &pdev->dev;
763 struct pinctrl_pin_desc *pindesc;
764 struct pinctrl_desc *pctrldesc;
765 struct pmic_mpp_pad *pad, *pads;
766 struct pmic_mpp_state *state;
767 int ret, npins, i;
768 u32 res[2];
769
770 ret = of_property_read_u32_array(dev->of_node, "reg", res, 2);
771 if (ret < 0) {
772 dev_err(dev, "missing base address and/or range");
773 return ret;
774 }
775
776 npins = res[1] / PMIC_MPP_ADDRESS_RANGE;
777 if (!npins)
778 return -EINVAL;
779
780 BUG_ON(npins > ARRAY_SIZE(pmic_mpp_groups));
781
782 state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
783 if (!state)
784 return -ENOMEM;
785
786 platform_set_drvdata(pdev, state);
787
788 state->dev = &pdev->dev;
789 state->map = dev_get_regmap(dev->parent, NULL);
790
791 pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL);
792 if (!pindesc)
793 return -ENOMEM;
794
795 pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL);
796 if (!pads)
797 return -ENOMEM;
798
799 pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL);
800 if (!pctrldesc)
801 return -ENOMEM;
802
803 pctrldesc->pctlops = &pmic_mpp_pinctrl_ops;
804 pctrldesc->pmxops = &pmic_mpp_pinmux_ops;
805 pctrldesc->confops = &pmic_mpp_pinconf_ops;
806 pctrldesc->owner = THIS_MODULE;
807 pctrldesc->name = dev_name(dev);
808 pctrldesc->pins = pindesc;
809 pctrldesc->npins = npins;
810
Bjorn Anderssonba5f94c2015-06-17 23:47:25 -0700811 pctrldesc->num_custom_params = ARRAY_SIZE(pmic_mpp_bindings);
812 pctrldesc->custom_params = pmic_mpp_bindings;
813#ifdef CONFIG_DEBUG_FS
814 pctrldesc->custom_conf_items = pmic_conf_items;
815#endif
816
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300817 for (i = 0; i < npins; i++, pindesc++) {
818 pad = &pads[i];
819 pindesc->drv_data = pad;
820 pindesc->number = i;
821 pindesc->name = pmic_mpp_groups[i];
822
823 pad->irq = platform_get_irq(pdev, i);
824 if (pad->irq < 0)
825 return pad->irq;
826
827 pad->base = res[0] + i * PMIC_MPP_ADDRESS_RANGE;
828
829 ret = pmic_mpp_populate(state, pad);
830 if (ret < 0)
831 return ret;
832 }
833
834 state->chip = pmic_mpp_gpio_template;
835 state->chip.dev = dev;
836 state->chip.base = -1;
837 state->chip.ngpio = npins;
838 state->chip.label = dev_name(dev);
839 state->chip.of_gpio_n_cells = 2;
840 state->chip.can_sleep = false;
841
842 state->ctrl = pinctrl_register(pctrldesc, dev, state);
Masahiro Yamada323de9e2015-06-09 13:01:16 +0900843 if (IS_ERR(state->ctrl))
844 return PTR_ERR(state->ctrl);
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300845
846 ret = gpiochip_add(&state->chip);
847 if (ret) {
848 dev_err(state->dev, "can't add gpio chip\n");
849 goto err_chip;
850 }
851
852 ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0, npins);
853 if (ret) {
854 dev_err(dev, "failed to add pin range\n");
855 goto err_range;
856 }
857
858 return 0;
859
860err_range:
861 gpiochip_remove(&state->chip);
862err_chip:
863 pinctrl_unregister(state->ctrl);
864 return ret;
865}
866
867static int pmic_mpp_remove(struct platform_device *pdev)
868{
869 struct pmic_mpp_state *state = platform_get_drvdata(pdev);
870
871 gpiochip_remove(&state->chip);
872 pinctrl_unregister(state->ctrl);
873 return 0;
874}
875
876static const struct of_device_id pmic_mpp_of_match[] = {
877 { .compatible = "qcom,pm8841-mpp" }, /* 4 MPP's */
Ivan T. Ivanov7414b092015-03-31 12:37:18 +0300878 { .compatible = "qcom,pm8916-mpp" }, /* 4 MPP's */
Ivan T. Ivanovcfb24f62014-10-22 12:58:47 +0300879 { .compatible = "qcom,pm8941-mpp" }, /* 8 MPP's */
880 { .compatible = "qcom,pma8084-mpp" }, /* 8 MPP's */
881 { },
882};
883
884MODULE_DEVICE_TABLE(of, pmic_mpp_of_match);
885
886static struct platform_driver pmic_mpp_driver = {
887 .driver = {
888 .name = "qcom-spmi-mpp",
889 .of_match_table = pmic_mpp_of_match,
890 },
891 .probe = pmic_mpp_probe,
892 .remove = pmic_mpp_remove,
893};
894
895module_platform_driver(pmic_mpp_driver);
896
897MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");
898MODULE_DESCRIPTION("Qualcomm SPMI PMIC MPP pin control driver");
899MODULE_ALIAS("platform:qcom-spmi-mpp");
900MODULE_LICENSE("GPL v2");