blob: 73aefc40d4e88583d4f44364bfcd2aae15964eea [file] [log] [blame]
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001/*
2 * Copyright (c) 2013, Sony Mobile Communications AB.
Archana Sathyakumar892c01c2017-10-31 13:47:20 -06003 * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
Naresh Kumar Lingagallaff508b42023-05-23 12:23:33 +05304 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
Bjorn Anderssonf365be02013-12-05 18:10:03 -08005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 and
8 * only version 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
Pramod Gurav32745582014-08-29 20:00:59 +053016#include <linux/delay.h>
Bjorn Anderssonf365be02013-12-05 18:10:03 -080017#include <linux/err.h>
Bjorn Anderssonf365be02013-12-05 18:10:03 -080018#include <linux/io.h>
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -060019#include <linux/irq.h>
Bjorn Anderssonf365be02013-12-05 18:10:03 -080020#include <linux/module.h>
21#include <linux/of.h>
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -060022#include <linux/of_irq.h>
Bjorn Anderssonf365be02013-12-05 18:10:03 -080023#include <linux/platform_device.h>
24#include <linux/pinctrl/machine.h>
25#include <linux/pinctrl/pinctrl.h>
26#include <linux/pinctrl/pinmux.h>
27#include <linux/pinctrl/pinconf.h>
28#include <linux/pinctrl/pinconf-generic.h>
Raju P.L.S.S.S.Ncdcd7692017-11-30 19:06:30 +053029#include <linux/of_irq.h>
Bjorn Anderssonf365be02013-12-05 18:10:03 -080030#include <linux/slab.h>
31#include <linux/gpio.h>
32#include <linux/interrupt.h>
Bjorn Anderssonf365be02013-12-05 18:10:03 -080033#include <linux/spinlock.h>
Maria Yu2af63b22018-03-29 17:34:28 +080034#include <linux/syscore_ops.h>
Josh Cartwrightcf1fc182014-09-23 15:59:53 -050035#include <linux/reboot.h>
Stephen Boydad644982015-07-06 18:09:30 -070036#include <linux/pm.h>
Stephen Boyd47a01ee2016-06-25 22:21:31 -070037#include <linux/log2.h>
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -060038#include <linux/irq.h>
Srinivas Rao Ld6302982018-07-31 12:36:56 +053039#include <soc/qcom/scm.h>
Linus Walleij69b78b82014-07-09 13:55:12 +020040#include "../core.h"
41#include "../pinconf.h"
Bjorn Anderssonf365be02013-12-05 18:10:03 -080042#include "pinctrl-msm.h"
Linus Walleij69b78b82014-07-09 13:55:12 +020043#include "../pinctrl-utils.h"
Bjorn Anderssonf365be02013-12-05 18:10:03 -080044
Bjorn Andersson408e3c62013-12-14 23:01:53 -080045#define MAX_NR_GPIO 300
Pramod Gurav32745582014-08-29 20:00:59 +053046#define PS_HOLD_OFFSET 0x820
Bjorn Andersson408e3c62013-12-14 23:01:53 -080047
Bjorn Anderssonf365be02013-12-05 18:10:03 -080048/**
49 * struct msm_pinctrl - state for a pinctrl-msm device
50 * @dev: device handle.
51 * @pctrl: pinctrl handle.
Bjorn Anderssonf365be02013-12-05 18:10:03 -080052 * @chip: gpiochip handle.
Josh Cartwrightcf1fc182014-09-23 15:59:53 -050053 * @restart_nb: restart notifier block.
Bjorn Anderssonf365be02013-12-05 18:10:03 -080054 * @irq: parent irq for the TLMM irq_chip.
55 * @lock: Spinlock to protect register resources as well
56 * as msm_pinctrl data structures.
57 * @enabled_irqs: Bitmap of currently enabled irqs.
58 * @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge
59 * detection.
Bjorn Anderssonf365be02013-12-05 18:10:03 -080060 * @soc; Reference to soc_data of platform specific data.
61 * @regs: Base address for the TLMM register map.
62 */
63struct msm_pinctrl {
64 struct device *dev;
65 struct pinctrl_dev *pctrl;
Bjorn Anderssonf365be02013-12-05 18:10:03 -080066 struct gpio_chip chip;
Josh Cartwrightcf1fc182014-09-23 15:59:53 -050067 struct notifier_block restart_nb;
Bjorn Anderssonf393e482013-12-14 23:01:52 -080068 int irq;
Bjorn Anderssonf365be02013-12-05 18:10:03 -080069
70 spinlock_t lock;
71
Bjorn Andersson408e3c62013-12-14 23:01:53 -080072 DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO);
73 DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO);
Bjorn Anderssonf365be02013-12-05 18:10:03 -080074
75 const struct msm_pinctrl_soc_data *soc;
76 void __iomem *regs;
Archana Sathyakumar892c01c2017-10-31 13:47:20 -060077 void __iomem *pdc_regs;
Naresh Kumar Lingagallaff508b42023-05-23 12:23:33 +053078 void __iomem *spi_base;
Srinivas Rao Ld6302982018-07-31 12:36:56 +053079 phys_addr_t spi_cfg_regs;
80 phys_addr_t spi_cfg_end;
Bjorn Anderssonf365be02013-12-05 18:10:03 -080081};
82
Maria Yu2af63b22018-03-29 17:34:28 +080083static struct msm_pinctrl *msm_pinctrl_data;
84
Bjorn Anderssonf365be02013-12-05 18:10:03 -080085static int msm_get_groups_count(struct pinctrl_dev *pctldev)
86{
87 struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
88
89 return pctrl->soc->ngroups;
90}
91
92static const char *msm_get_group_name(struct pinctrl_dev *pctldev,
93 unsigned group)
94{
95 struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
96
97 return pctrl->soc->groups[group].name;
98}
99
100static int msm_get_group_pins(struct pinctrl_dev *pctldev,
101 unsigned group,
102 const unsigned **pins,
103 unsigned *num_pins)
104{
105 struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
106
107 *pins = pctrl->soc->groups[group].pins;
108 *num_pins = pctrl->soc->groups[group].npins;
109 return 0;
110}
111
Bjorn Andersson1f2b2392013-12-14 23:01:51 -0800112static const struct pinctrl_ops msm_pinctrl_ops = {
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800113 .get_groups_count = msm_get_groups_count,
114 .get_group_name = msm_get_group_name,
115 .get_group_pins = msm_get_group_pins,
116 .dt_node_to_map = pinconf_generic_dt_node_to_map_group,
Irina Tirdead32f7fd2016-03-31 14:44:42 +0300117 .dt_free_map = pinctrl_utils_free_map,
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800118};
119
120static int msm_get_functions_count(struct pinctrl_dev *pctldev)
121{
122 struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
123
124 return pctrl->soc->nfunctions;
125}
126
127static const char *msm_get_function_name(struct pinctrl_dev *pctldev,
128 unsigned function)
129{
130 struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
131
132 return pctrl->soc->functions[function].name;
133}
134
135static int msm_get_function_groups(struct pinctrl_dev *pctldev,
136 unsigned function,
137 const char * const **groups,
138 unsigned * const num_groups)
139{
140 struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
141
142 *groups = pctrl->soc->functions[function].groups;
143 *num_groups = pctrl->soc->functions[function].ngroups;
144 return 0;
145}
146
Linus Walleij03e9f0c2014-09-03 13:02:56 +0200147static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev,
148 unsigned function,
149 unsigned group)
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800150{
151 struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
152 const struct msm_pingroup *g;
153 unsigned long flags;
Kyle Yan6c2752f2017-09-27 16:29:45 -0700154 u32 val, mask;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800155 int i;
156
157 g = &pctrl->soc->groups[group];
Stephen Boyd47a01ee2016-06-25 22:21:31 -0700158 mask = GENMASK(g->mux_bit + order_base_2(g->nfuncs) - 1, g->mux_bit);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800159
Bjorn Andersson3c253812014-03-31 14:49:55 -0700160 for (i = 0; i < g->nfuncs; i++) {
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800161 if (g->funcs[i] == function)
162 break;
163 }
164
Bjorn Andersson3c253812014-03-31 14:49:55 -0700165 if (WARN_ON(i == g->nfuncs))
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800166 return -EINVAL;
167
168 spin_lock_irqsave(&pctrl->lock, flags);
169
Kyle Yan6c2752f2017-09-27 16:29:45 -0700170 val = readl(pctrl->regs + g->ctl_reg);
John Crispin6bcf3f62016-09-12 11:36:55 +0200171 val &= ~mask;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800172 val |= i << g->mux_bit;
Kyle Yan6c2752f2017-09-27 16:29:45 -0700173 writel(val, pctrl->regs + g->ctl_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800174
175 spin_unlock_irqrestore(&pctrl->lock, flags);
176
177 return 0;
178}
179
Bjorn Andersson1f2b2392013-12-14 23:01:51 -0800180static const struct pinmux_ops msm_pinmux_ops = {
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800181 .get_functions_count = msm_get_functions_count,
182 .get_function_name = msm_get_function_name,
183 .get_function_groups = msm_get_function_groups,
Linus Walleij03e9f0c2014-09-03 13:02:56 +0200184 .set_mux = msm_pinmux_set_mux,
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800185};
186
187static int msm_config_reg(struct msm_pinctrl *pctrl,
188 const struct msm_pingroup *g,
189 unsigned param,
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800190 unsigned *mask,
191 unsigned *bit)
192{
193 switch (param) {
194 case PIN_CONFIG_BIAS_DISABLE:
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800195 case PIN_CONFIG_BIAS_PULL_DOWN:
Andy Grossb831a152014-06-17 23:49:11 -0500196 case PIN_CONFIG_BIAS_BUS_HOLD:
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800197 case PIN_CONFIG_BIAS_PULL_UP:
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800198 *bit = g->pull_bit;
199 *mask = 3;
200 break;
201 case PIN_CONFIG_DRIVE_STRENGTH:
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800202 *bit = g->drv_bit;
203 *mask = 7;
204 break;
Bjorn Anderssoned118a52014-02-04 19:55:31 -0800205 case PIN_CONFIG_OUTPUT:
Stanimir Varbanov407f5e32015-03-04 12:41:57 +0200206 case PIN_CONFIG_INPUT_ENABLE:
Bjorn Anderssoned118a52014-02-04 19:55:31 -0800207 *bit = g->oe_bit;
208 *mask = 1;
209 break;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800210 default:
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800211 return -ENOTSUPP;
212 }
213
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800214 return 0;
215}
216
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800217#define MSM_NO_PULL 0
218#define MSM_PULL_DOWN 1
Andy Grossb831a152014-06-17 23:49:11 -0500219#define MSM_KEEPER 2
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800220#define MSM_PULL_UP 3
221
Stephen Boyd7cc34e22014-03-06 22:44:44 -0800222static unsigned msm_regval_to_drive(u32 val)
223{
224 return (val + 1) * 2;
225}
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800226
227static int msm_config_group_get(struct pinctrl_dev *pctldev,
228 unsigned int group,
229 unsigned long *config)
230{
231 const struct msm_pingroup *g;
232 struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
233 unsigned param = pinconf_to_config_param(*config);
234 unsigned mask;
235 unsigned arg;
236 unsigned bit;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800237 int ret;
Kyle Yan6c2752f2017-09-27 16:29:45 -0700238 u32 val;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800239
240 g = &pctrl->soc->groups[group];
241
Stephen Boyd051a58b2014-03-06 22:44:46 -0800242 ret = msm_config_reg(pctrl, g, param, &mask, &bit);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800243 if (ret < 0)
244 return ret;
245
Kyle Yan6c2752f2017-09-27 16:29:45 -0700246 val = readl(pctrl->regs + g->ctl_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800247 arg = (val >> bit) & mask;
248
249 /* Convert register value to pinconf value */
250 switch (param) {
251 case PIN_CONFIG_BIAS_DISABLE:
252 arg = arg == MSM_NO_PULL;
253 break;
254 case PIN_CONFIG_BIAS_PULL_DOWN:
255 arg = arg == MSM_PULL_DOWN;
256 break;
Andy Grossb831a152014-06-17 23:49:11 -0500257 case PIN_CONFIG_BIAS_BUS_HOLD:
258 arg = arg == MSM_KEEPER;
259 break;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800260 case PIN_CONFIG_BIAS_PULL_UP:
261 arg = arg == MSM_PULL_UP;
262 break;
263 case PIN_CONFIG_DRIVE_STRENGTH:
Stephen Boyd7cc34e22014-03-06 22:44:44 -0800264 arg = msm_regval_to_drive(arg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800265 break;
Bjorn Anderssoned118a52014-02-04 19:55:31 -0800266 case PIN_CONFIG_OUTPUT:
267 /* Pin is not output */
268 if (!arg)
269 return -EINVAL;
270
Kyle Yan6c2752f2017-09-27 16:29:45 -0700271 val = readl(pctrl->regs + g->io_reg);
Bjorn Anderssoned118a52014-02-04 19:55:31 -0800272 arg = !!(val & BIT(g->in_bit));
273 break;
Stanimir Varbanov407f5e32015-03-04 12:41:57 +0200274 case PIN_CONFIG_INPUT_ENABLE:
275 /* Pin is output */
276 if (arg)
277 return -EINVAL;
278 arg = 1;
279 break;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800280 default:
Stanimir Varbanov38d756a2015-03-04 12:41:56 +0200281 return -ENOTSUPP;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800282 }
283
284 *config = pinconf_to_config_packed(param, arg);
285
286 return 0;
287}
288
289static int msm_config_group_set(struct pinctrl_dev *pctldev,
290 unsigned group,
291 unsigned long *configs,
292 unsigned num_configs)
293{
294 const struct msm_pingroup *g;
295 struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
296 unsigned long flags;
297 unsigned param;
298 unsigned mask;
299 unsigned arg;
300 unsigned bit;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800301 int ret;
Kyle Yan6c2752f2017-09-27 16:29:45 -0700302 u32 val;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800303 int i;
304
305 g = &pctrl->soc->groups[group];
306
307 for (i = 0; i < num_configs; i++) {
308 param = pinconf_to_config_param(configs[i]);
309 arg = pinconf_to_config_argument(configs[i]);
310
Stephen Boyd051a58b2014-03-06 22:44:46 -0800311 ret = msm_config_reg(pctrl, g, param, &mask, &bit);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800312 if (ret < 0)
313 return ret;
314
315 /* Convert pinconf values to register values */
316 switch (param) {
317 case PIN_CONFIG_BIAS_DISABLE:
318 arg = MSM_NO_PULL;
319 break;
320 case PIN_CONFIG_BIAS_PULL_DOWN:
321 arg = MSM_PULL_DOWN;
322 break;
Andy Grossb831a152014-06-17 23:49:11 -0500323 case PIN_CONFIG_BIAS_BUS_HOLD:
324 arg = MSM_KEEPER;
325 break;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800326 case PIN_CONFIG_BIAS_PULL_UP:
327 arg = MSM_PULL_UP;
328 break;
329 case PIN_CONFIG_DRIVE_STRENGTH:
330 /* Check for invalid values */
Stephen Boyd7cc34e22014-03-06 22:44:44 -0800331 if (arg > 16 || arg < 2 || (arg % 2) != 0)
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800332 arg = -1;
333 else
Stephen Boyd7cc34e22014-03-06 22:44:44 -0800334 arg = (arg / 2) - 1;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800335 break;
Bjorn Anderssoned118a52014-02-04 19:55:31 -0800336 case PIN_CONFIG_OUTPUT:
337 /* set output value */
338 spin_lock_irqsave(&pctrl->lock, flags);
Kyle Yan6c2752f2017-09-27 16:29:45 -0700339 val = readl(pctrl->regs + g->io_reg);
Bjorn Anderssoned118a52014-02-04 19:55:31 -0800340 if (arg)
341 val |= BIT(g->out_bit);
342 else
343 val &= ~BIT(g->out_bit);
Kyle Yan6c2752f2017-09-27 16:29:45 -0700344 writel(val, pctrl->regs + g->io_reg);
Bjorn Anderssoned118a52014-02-04 19:55:31 -0800345 spin_unlock_irqrestore(&pctrl->lock, flags);
346
347 /* enable output */
348 arg = 1;
349 break;
Stanimir Varbanov407f5e32015-03-04 12:41:57 +0200350 case PIN_CONFIG_INPUT_ENABLE:
351 /* disable output */
352 arg = 0;
353 break;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800354 default:
355 dev_err(pctrl->dev, "Unsupported config parameter: %x\n",
356 param);
357 return -EINVAL;
358 }
359
360 /* Range-check user-supplied value */
361 if (arg & ~mask) {
362 dev_err(pctrl->dev, "config %x: %x is invalid\n", param, arg);
363 return -EINVAL;
364 }
365
366 spin_lock_irqsave(&pctrl->lock, flags);
Kyle Yan6c2752f2017-09-27 16:29:45 -0700367 val = readl(pctrl->regs + g->ctl_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800368 val &= ~(mask << bit);
369 val |= arg << bit;
Kyle Yan6c2752f2017-09-27 16:29:45 -0700370 writel(val, pctrl->regs + g->ctl_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800371 spin_unlock_irqrestore(&pctrl->lock, flags);
372 }
373
374 return 0;
375}
376
Bjorn Andersson1f2b2392013-12-14 23:01:51 -0800377static const struct pinconf_ops msm_pinconf_ops = {
Stanimir Varbanov38d756a2015-03-04 12:41:56 +0200378 .is_generic = true,
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800379 .pin_config_group_get = msm_config_group_get,
380 .pin_config_group_set = msm_config_group_set,
381};
382
383static struct pinctrl_desc msm_pinctrl_desc = {
384 .pctlops = &msm_pinctrl_ops,
385 .pmxops = &msm_pinmux_ops,
386 .confops = &msm_pinconf_ops,
387 .owner = THIS_MODULE,
388};
389
390static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
391{
392 const struct msm_pingroup *g;
Linus Walleijfded3f42015-12-08 09:49:18 +0100393 struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800394 unsigned long flags;
Kyle Yan6c2752f2017-09-27 16:29:45 -0700395 u32 val;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800396
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800397 g = &pctrl->soc->groups[offset];
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800398
399 spin_lock_irqsave(&pctrl->lock, flags);
400
Kyle Yan6c2752f2017-09-27 16:29:45 -0700401 val = readl(pctrl->regs + g->ctl_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800402 val &= ~BIT(g->oe_bit);
Kyle Yan6c2752f2017-09-27 16:29:45 -0700403 writel(val, pctrl->regs + g->ctl_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800404
405 spin_unlock_irqrestore(&pctrl->lock, flags);
406
407 return 0;
408}
409
410static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
411{
412 const struct msm_pingroup *g;
Linus Walleijfded3f42015-12-08 09:49:18 +0100413 struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800414 unsigned long flags;
Kyle Yan6c2752f2017-09-27 16:29:45 -0700415 u32 val;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800416
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800417 g = &pctrl->soc->groups[offset];
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800418
419 spin_lock_irqsave(&pctrl->lock, flags);
420
Kyle Yan6c2752f2017-09-27 16:29:45 -0700421 val = readl(pctrl->regs + g->io_reg);
Axel Line476e772013-12-13 21:35:55 +0800422 if (value)
423 val |= BIT(g->out_bit);
424 else
425 val &= ~BIT(g->out_bit);
Kyle Yan6c2752f2017-09-27 16:29:45 -0700426 writel(val, pctrl->regs + g->io_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800427
Kyle Yan6c2752f2017-09-27 16:29:45 -0700428 val = readl(pctrl->regs + g->ctl_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800429 val |= BIT(g->oe_bit);
Kyle Yan6c2752f2017-09-27 16:29:45 -0700430 writel(val, pctrl->regs + g->ctl_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800431
432 spin_unlock_irqrestore(&pctrl->lock, flags);
433
434 return 0;
435}
436
437static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
438{
439 const struct msm_pingroup *g;
Linus Walleijfded3f42015-12-08 09:49:18 +0100440 struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
Kyle Yan6c2752f2017-09-27 16:29:45 -0700441 u32 val;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800442
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800443 g = &pctrl->soc->groups[offset];
444
Kyle Yan6c2752f2017-09-27 16:29:45 -0700445 val = readl(pctrl->regs + g->io_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800446 return !!(val & BIT(g->in_bit));
447}
448
449static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
450{
451 const struct msm_pingroup *g;
Linus Walleijfded3f42015-12-08 09:49:18 +0100452 struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800453 unsigned long flags;
Kyle Yan6c2752f2017-09-27 16:29:45 -0700454 u32 val;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800455
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800456 g = &pctrl->soc->groups[offset];
457
458 spin_lock_irqsave(&pctrl->lock, flags);
459
Kyle Yan6c2752f2017-09-27 16:29:45 -0700460 val = readl(pctrl->regs + g->io_reg);
Axel Line476e772013-12-13 21:35:55 +0800461 if (value)
462 val |= BIT(g->out_bit);
463 else
464 val &= ~BIT(g->out_bit);
Kyle Yan6c2752f2017-09-27 16:29:45 -0700465 writel(val, pctrl->regs + g->io_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800466
467 spin_unlock_irqrestore(&pctrl->lock, flags);
468}
469
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800470#ifdef CONFIG_DEBUG_FS
471#include <linux/seq_file.h>
472
473static void msm_gpio_dbg_show_one(struct seq_file *s,
474 struct pinctrl_dev *pctldev,
475 struct gpio_chip *chip,
476 unsigned offset,
477 unsigned gpio)
478{
479 const struct msm_pingroup *g;
Linus Walleijfded3f42015-12-08 09:49:18 +0100480 struct msm_pinctrl *pctrl = gpiochip_get_data(chip);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800481 unsigned func;
482 int is_out;
483 int drive;
484 int pull;
Kyle Yan6c2752f2017-09-27 16:29:45 -0700485 u32 ctl_reg;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800486
Bjorn Andersson1f2b2392013-12-14 23:01:51 -0800487 static const char * const pulls[] = {
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800488 "no pull",
489 "pull down",
490 "keeper",
491 "pull up"
492 };
493
494 g = &pctrl->soc->groups[offset];
Kyle Yan6c2752f2017-09-27 16:29:45 -0700495 ctl_reg = readl(pctrl->regs + g->ctl_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800496
497 is_out = !!(ctl_reg & BIT(g->oe_bit));
498 func = (ctl_reg >> g->mux_bit) & 7;
499 drive = (ctl_reg >> g->drv_bit) & 7;
500 pull = (ctl_reg >> g->pull_bit) & 3;
501
502 seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func);
Stephen Boyd7cc34e22014-03-06 22:44:44 -0800503 seq_printf(s, " %dmA", msm_regval_to_drive(drive));
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800504 seq_printf(s, " %s", pulls[pull]);
505}
506
507static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
508{
509 unsigned gpio = chip->base;
510 unsigned i;
511
512 for (i = 0; i < chip->ngpio; i++, gpio++) {
513 msm_gpio_dbg_show_one(s, NULL, chip, i, gpio);
Bjorn Andersson1f2b2392013-12-14 23:01:51 -0800514 seq_puts(s, "\n");
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800515 }
516}
517
518#else
519#define msm_gpio_dbg_show NULL
520#endif
521
522static struct gpio_chip msm_gpio_template = {
523 .direction_input = msm_gpio_direction_input,
524 .direction_output = msm_gpio_direction_output,
525 .get = msm_gpio_get,
526 .set = msm_gpio_set,
Jonas Gorski98c85d52015-10-11 17:34:19 +0200527 .request = gpiochip_generic_request,
528 .free = gpiochip_generic_free,
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800529 .dbg_show = msm_gpio_dbg_show,
530};
531
532/* For dual-edge interrupts in software, since some hardware has no
533 * such support:
534 *
535 * At appropriate moments, this function may be called to flip the polarity
536 * settings of both-edge irq lines to try and catch the next edge.
537 *
538 * The attempt is considered successful if:
539 * - the status bit goes high, indicating that an edge was caught, or
540 * - the input value of the gpio doesn't change during the attempt.
541 * If the value changes twice during the process, that would cause the first
542 * test to fail but would force the second, as two opposite
543 * transitions would cause a detection no matter the polarity setting.
544 *
545 * The do-loop tries to sledge-hammer closed the timing hole between
546 * the initial value-read and the polarity-write - if the line value changes
547 * during that window, an interrupt is lost, the new polarity setting is
548 * incorrect, and the first success test will fail, causing a retry.
549 *
550 * Algorithm comes from Google's msmgpio driver.
551 */
552static void msm_gpio_update_dual_edge_pos(struct msm_pinctrl *pctrl,
553 const struct msm_pingroup *g,
Kyle Yan6c2752f2017-09-27 16:29:45 -0700554 struct irq_data *d)
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800555{
556 int loop_limit = 100;
557 unsigned val, val2, intstat;
558 unsigned pol;
559
560 do {
Kyle Yan6c2752f2017-09-27 16:29:45 -0700561 val = readl(pctrl->regs + g->io_reg) & BIT(g->in_bit);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800562
Kyle Yan6c2752f2017-09-27 16:29:45 -0700563 pol = readl(pctrl->regs + g->intr_cfg_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800564 pol ^= BIT(g->intr_polarity_bit);
Kyle Yan6c2752f2017-09-27 16:29:45 -0700565 writel(pol, pctrl->regs + g->intr_cfg_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800566
Kyle Yan6c2752f2017-09-27 16:29:45 -0700567 val2 = readl(pctrl->regs + g->io_reg) & BIT(g->in_bit);
568 intstat = readl(pctrl->regs + g->intr_status_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800569 if (intstat || (val == val2))
570 return;
571 } while (loop_limit-- > 0);
572 dev_err(pctrl->dev, "dual-edge irq failed to stabilize, %#08x != %#08x\n",
573 val, val2);
574}
575
576static void msm_gpio_irq_mask(struct irq_data *d)
577{
Linus Walleijcdcb0ab2014-04-29 11:00:40 -0700578 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
Linus Walleijfded3f42015-12-08 09:49:18 +0100579 struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800580 const struct msm_pingroup *g;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800581 unsigned long flags;
Kyle Yan6c2752f2017-09-27 16:29:45 -0700582 u32 val;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800583
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800584 g = &pctrl->soc->groups[d->hwirq];
585
586 spin_lock_irqsave(&pctrl->lock, flags);
587
Kyle Yan6c2752f2017-09-27 16:29:45 -0700588 val = readl(pctrl->regs + g->intr_cfg_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800589 val &= ~BIT(g->intr_enable_bit);
Kyle Yan6c2752f2017-09-27 16:29:45 -0700590 writel(val, pctrl->regs + g->intr_cfg_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800591
592 clear_bit(d->hwirq, pctrl->enabled_irqs);
593
594 spin_unlock_irqrestore(&pctrl->lock, flags);
Raghavendra Kakarla0e77a9e2018-03-07 21:30:45 +0530595
596 if (d->parent_data)
597 irq_chip_mask_parent(d);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800598}
599
Srinivas Ramana69521392017-11-14 11:36:23 +0530600static void msm_gpio_irq_enable(struct irq_data *d)
601{
602 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
603 struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
604 const struct msm_pingroup *g;
605 unsigned long flags;
606 u32 val;
607
608 g = &pctrl->soc->groups[d->hwirq];
609
610 spin_lock_irqsave(&pctrl->lock, flags);
611 /* clear the interrupt status bit before unmask to avoid
612 * any erraneous interrupts that would have got latched
613 * when the intterupt is not in use.
614 */
615 val = readl(pctrl->regs + g->intr_status_reg);
616 val &= ~BIT(g->intr_status_bit);
617 writel(val, pctrl->regs + g->intr_status_reg);
618
619 val = readl(pctrl->regs + g->intr_cfg_reg);
620 val |= BIT(g->intr_enable_bit);
621 writel(val, pctrl->regs + g->intr_cfg_reg);
622
623 set_bit(d->hwirq, pctrl->enabled_irqs);
624
625 spin_unlock_irqrestore(&pctrl->lock, flags);
Raghavendra Kakarla0e77a9e2018-03-07 21:30:45 +0530626
627 if (d->parent_data)
628 irq_chip_enable_parent(d);
Srinivas Ramana69521392017-11-14 11:36:23 +0530629}
630
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800631static void msm_gpio_irq_unmask(struct irq_data *d)
632{
Linus Walleijcdcb0ab2014-04-29 11:00:40 -0700633 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
Tengfei Fand36f7452018-11-19 13:45:29 +0800634 uint32_t irqtype = irqd_get_trigger_type(d);
Linus Walleijfded3f42015-12-08 09:49:18 +0100635 struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800636 const struct msm_pingroup *g;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800637 unsigned long flags;
Kyle Yan6c2752f2017-09-27 16:29:45 -0700638 u32 val;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800639
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800640 g = &pctrl->soc->groups[d->hwirq];
641
642 spin_lock_irqsave(&pctrl->lock, flags);
643
Tengfei Fand36f7452018-11-19 13:45:29 +0800644 if (irqtype & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) {
645 val = readl_relaxed(pctrl->regs + g->intr_status_reg);
646 val &= ~BIT(g->intr_status_bit);
647 writel_relaxed(val, pctrl->regs + g->intr_status_reg);
648 }
649
Kyle Yan6c2752f2017-09-27 16:29:45 -0700650 val = readl(pctrl->regs + g->intr_cfg_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800651 val |= BIT(g->intr_enable_bit);
Kyle Yan6c2752f2017-09-27 16:29:45 -0700652 writel(val, pctrl->regs + g->intr_cfg_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800653
654 set_bit(d->hwirq, pctrl->enabled_irqs);
655
656 spin_unlock_irqrestore(&pctrl->lock, flags);
Raghavendra Kakarla0e77a9e2018-03-07 21:30:45 +0530657
658 if (d->parent_data)
659 irq_chip_unmask_parent(d);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800660}
661
662static void msm_gpio_irq_ack(struct irq_data *d)
663{
Linus Walleijcdcb0ab2014-04-29 11:00:40 -0700664 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
Linus Walleijfded3f42015-12-08 09:49:18 +0100665 struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800666 const struct msm_pingroup *g;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800667 unsigned long flags;
Kyle Yan6c2752f2017-09-27 16:29:45 -0700668 u32 val;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800669
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800670 g = &pctrl->soc->groups[d->hwirq];
671
672 spin_lock_irqsave(&pctrl->lock, flags);
673
Kyle Yan6c2752f2017-09-27 16:29:45 -0700674 val = readl(pctrl->regs + g->intr_status_reg);
Bjorn Andersson48f15e92014-03-31 14:49:54 -0700675 if (g->intr_ack_high)
676 val |= BIT(g->intr_status_bit);
677 else
678 val &= ~BIT(g->intr_status_bit);
Kyle Yan6c2752f2017-09-27 16:29:45 -0700679 writel(val, pctrl->regs + g->intr_status_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800680
681 if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
Kyle Yan6c2752f2017-09-27 16:29:45 -0700682 msm_gpio_update_dual_edge_pos(pctrl, g, d);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800683
684 spin_unlock_irqrestore(&pctrl->lock, flags);
685}
686
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800687static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
688{
Linus Walleijcdcb0ab2014-04-29 11:00:40 -0700689 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
Linus Walleijfded3f42015-12-08 09:49:18 +0100690 struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800691 const struct msm_pingroup *g;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800692 unsigned long flags;
Kyle Yan6c2752f2017-09-27 16:29:45 -0700693 u32 val;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800694
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800695 g = &pctrl->soc->groups[d->hwirq];
Kyle Yan6c2752f2017-09-27 16:29:45 -0700696
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800697 spin_lock_irqsave(&pctrl->lock, flags);
698
699 /*
700 * For hw without possibility of detecting both edges
701 */
702 if (g->intr_detection_width == 1 && type == IRQ_TYPE_EDGE_BOTH)
703 set_bit(d->hwirq, pctrl->dual_edge_irqs);
704 else
705 clear_bit(d->hwirq, pctrl->dual_edge_irqs);
706
707 /* Route interrupts to application cpu */
Kyle Yan6c2752f2017-09-27 16:29:45 -0700708 val = readl(pctrl->regs + g->intr_target_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800709 val &= ~(7 << g->intr_target_bit);
Georgi Djakovf712c552014-09-03 19:28:16 +0300710 val |= g->intr_target_kpss_val << g->intr_target_bit;
Kyle Yan6c2752f2017-09-27 16:29:45 -0700711 writel(val, pctrl->regs + g->intr_target_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800712
713 /* Update configuration for gpio.
714 * RAW_STATUS_EN is left on for all gpio irqs. Due to the
715 * internal circuitry of TLMM, toggling the RAW_STATUS
716 * could cause the INTR_STATUS to be set for EDGE interrupts.
717 */
Kyle Yan6c2752f2017-09-27 16:29:45 -0700718 val = readl(pctrl->regs + g->intr_cfg_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800719 val |= BIT(g->intr_raw_status_bit);
720 if (g->intr_detection_width == 2) {
721 val &= ~(3 << g->intr_detection_bit);
722 val &= ~(1 << g->intr_polarity_bit);
723 switch (type) {
724 case IRQ_TYPE_EDGE_RISING:
725 val |= 1 << g->intr_detection_bit;
726 val |= BIT(g->intr_polarity_bit);
727 break;
728 case IRQ_TYPE_EDGE_FALLING:
729 val |= 2 << g->intr_detection_bit;
730 val |= BIT(g->intr_polarity_bit);
731 break;
732 case IRQ_TYPE_EDGE_BOTH:
733 val |= 3 << g->intr_detection_bit;
734 val |= BIT(g->intr_polarity_bit);
735 break;
736 case IRQ_TYPE_LEVEL_LOW:
737 break;
738 case IRQ_TYPE_LEVEL_HIGH:
739 val |= BIT(g->intr_polarity_bit);
740 break;
741 }
742 } else if (g->intr_detection_width == 1) {
743 val &= ~(1 << g->intr_detection_bit);
744 val &= ~(1 << g->intr_polarity_bit);
745 switch (type) {
746 case IRQ_TYPE_EDGE_RISING:
747 val |= BIT(g->intr_detection_bit);
748 val |= BIT(g->intr_polarity_bit);
749 break;
750 case IRQ_TYPE_EDGE_FALLING:
751 val |= BIT(g->intr_detection_bit);
752 break;
753 case IRQ_TYPE_EDGE_BOTH:
754 val |= BIT(g->intr_detection_bit);
Bjorn Andersson48f15e92014-03-31 14:49:54 -0700755 val |= BIT(g->intr_polarity_bit);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800756 break;
757 case IRQ_TYPE_LEVEL_LOW:
758 break;
759 case IRQ_TYPE_LEVEL_HIGH:
760 val |= BIT(g->intr_polarity_bit);
761 break;
762 }
763 } else {
764 BUG();
765 }
Kyle Yan6c2752f2017-09-27 16:29:45 -0700766 writel(val, pctrl->regs + g->intr_cfg_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800767
768 if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
Kyle Yan6c2752f2017-09-27 16:29:45 -0700769 msm_gpio_update_dual_edge_pos(pctrl, g, d);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800770
771 spin_unlock_irqrestore(&pctrl->lock, flags);
772
Raghavendra Kakarla0e77a9e2018-03-07 21:30:45 +0530773 if (d->parent_data)
774 irq_chip_set_type_parent(d, type);
775
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800776 if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
Thomas Gleixner34c0ad82015-06-23 15:52:51 +0200777 irq_set_handler_locked(d, handle_level_irq);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800778 else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
Thomas Gleixner34c0ad82015-06-23 15:52:51 +0200779 irq_set_handler_locked(d, handle_edge_irq);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800780
781 return 0;
782}
783
784static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
785{
Linus Walleijcdcb0ab2014-04-29 11:00:40 -0700786 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
Linus Walleijfded3f42015-12-08 09:49:18 +0100787 struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800788 unsigned long flags;
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800789
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800790 spin_lock_irqsave(&pctrl->lock, flags);
791
Josh Cartwright6aced332014-03-05 13:33:08 -0600792 irq_set_irq_wake(pctrl->irq, on);
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800793
794 spin_unlock_irqrestore(&pctrl->lock, flags);
795
Raghavendra Kakarla0e77a9e2018-03-07 21:30:45 +0530796 if (d->parent_data)
797 irq_chip_set_wake_parent(d, on);
798
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800799 return 0;
800}
801
Raju P.L.S.S.S.Ncdcd7692017-11-30 19:06:30 +0530802static int msm_gpiochip_irq_reqres(struct irq_data *d)
803{
804 struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
805
806 if (!try_module_get(chip->owner))
807 return -ENODEV;
808
809 if (gpiochip_lock_as_irq(chip, d->hwirq)) {
810 pr_err("unable to lock HW IRQ %lu for IRQ\n", d->hwirq);
811 module_put(chip->owner);
812 return -EINVAL;
813 }
814 return 0;
815}
816
817static void msm_gpiochip_irq_relres(struct irq_data *d)
818{
819 struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
820
821 gpiochip_unlock_as_irq(chip, d->hwirq);
822 module_put(chip->owner);
823}
824
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800825static struct irq_chip msm_gpio_irq_chip = {
826 .name = "msmgpio",
Srinivas Ramana69521392017-11-14 11:36:23 +0530827 .irq_enable = msm_gpio_irq_enable,
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800828 .irq_mask = msm_gpio_irq_mask,
829 .irq_unmask = msm_gpio_irq_unmask,
830 .irq_ack = msm_gpio_irq_ack,
831 .irq_set_type = msm_gpio_irq_set_type,
832 .irq_set_wake = msm_gpio_irq_set_wake,
Raju P.L.S.S.S.Ncdcd7692017-11-30 19:06:30 +0530833 .irq_request_resources = msm_gpiochip_irq_reqres,
834 .irq_release_resources = msm_gpiochip_irq_relres,
835 .flags = IRQCHIP_MASK_ON_SUSPEND |
836 IRQCHIP_SKIP_SET_WAKE,
837};
838
839static void msm_gpio_domain_set_info(struct irq_domain *d, unsigned int irq,
840 irq_hw_number_t hwirq)
841{
842 struct gpio_chip *gc = d->host_data;
843
844 irq_domain_set_info(d, irq, hwirq, gc->irqchip, d->host_data,
845 gc->irq_handler, NULL, NULL);
846
847 if (gc->can_sleep && !gc->irq_not_threaded)
848 irq_set_nested_thread(irq, 1);
849
850 irq_set_noprobe(irq);
851}
852
853static int msm_gpio_domain_translate(struct irq_domain *d,
854 struct irq_fwspec *fwspec, unsigned long *hwirq, unsigned int *type)
855{
856 if (is_of_node(fwspec->fwnode)) {
857 if (fwspec->param_count < 2)
858 return -EINVAL;
859 if (hwirq)
860 *hwirq = fwspec->param[0];
861 if (type)
862 *type = fwspec->param[1] & IRQ_TYPE_SENSE_MASK;
863 return 0;
864 }
865
866 return -EINVAL;
867}
868
869static int msm_gpio_domain_alloc(struct irq_domain *domain, unsigned int virq,
870 unsigned int nr_irqs, void *arg)
871{
Raghavendra Kakarla0e77a9e2018-03-07 21:30:45 +0530872 int ret = 0;
Raju P.L.S.S.S.Ncdcd7692017-11-30 19:06:30 +0530873 irq_hw_number_t hwirq;
Raghavendra Kakarla0e77a9e2018-03-07 21:30:45 +0530874 struct irq_fwspec *fwspec = arg, parent_fwspec;
Raju P.L.S.S.S.Ncdcd7692017-11-30 19:06:30 +0530875
876 ret = msm_gpio_domain_translate(domain, fwspec, &hwirq, NULL);
877 if (ret)
878 return ret;
879
880 msm_gpio_domain_set_info(domain, virq, hwirq);
Raghavendra Kakarla0e77a9e2018-03-07 21:30:45 +0530881
882 parent_fwspec = *fwspec;
883 parent_fwspec.fwnode = domain->parent->fwnode;
884 return irq_domain_alloc_irqs_parent(domain, virq, nr_irqs,
885 &parent_fwspec);
Raju P.L.S.S.S.Ncdcd7692017-11-30 19:06:30 +0530886}
887
888static const struct irq_domain_ops msm_gpio_domain_ops = {
889 .translate = msm_gpio_domain_translate,
890 .alloc = msm_gpio_domain_alloc,
891 .free = irq_domain_free_irqs_top,
Bjorn Anderssonf365be02013-12-05 18:10:03 -0800892};
893
Archana Sathyakumar892c01c2017-10-31 13:47:20 -0600894static struct irq_chip msm_dirconn_irq_chip;
895
896static void msm_gpio_dirconn_handler(struct irq_desc *desc)
897{
898 struct irq_data *irqd = irq_desc_get_handler_data(desc);
899 struct irq_chip *chip = irq_desc_get_chip(desc);
900
901 chained_irq_enter(chip, desc);
902 generic_handle_irq(irqd->irq);
903 chained_irq_exit(chip, desc);
904}
905
906static void setup_pdc_gpio(struct irq_domain *domain,
907 unsigned int parent_irq, unsigned int gpio)
908{
909 int irq;
910
911 if (gpio != 0) {
Raghavendra Kakarla0e77a9e2018-03-07 21:30:45 +0530912 irq = irq_find_mapping(domain, gpio);
Archana Sathyakumar892c01c2017-10-31 13:47:20 -0600913 irq_set_parent(irq, parent_irq);
914 irq_set_chip(irq, &msm_dirconn_irq_chip);
915 irq_set_handler_data(parent_irq, irq_get_irq_data(irq));
916 }
917
918 __irq_set_handler(parent_irq, msm_gpio_dirconn_handler, false, NULL);
919}
920
921static void request_dc_interrupt(struct irq_domain *domain,
922 struct irq_domain *parent, irq_hw_number_t hwirq,
923 unsigned int gpio)
924{
925 struct irq_fwspec fwspec;
926 unsigned int parent_irq;
927
928 fwspec.fwnode = parent->fwnode;
929 fwspec.param[0] = 0; /* SPI */
930 fwspec.param[1] = hwirq;
931 fwspec.param[2] = IRQ_TYPE_NONE;
932 fwspec.param_count = 3;
933
934 parent_irq = irq_create_fwspec_mapping(&fwspec);
935
936 setup_pdc_gpio(domain, parent_irq, gpio);
937}
938
939/**
940 * gpio_muxed_to_pdc: Mux the GPIO to a PDC IRQ
941 *
942 * @pdc_domain: the PDC's domain
943 * @d: the GPIO's IRQ data
944 *
945 * Find a free PDC port for the GPIO and map the GPIO's mux information to the
946 * PDC registers; so the GPIO can be used a wakeup source.
947 */
948static void gpio_muxed_to_pdc(struct irq_domain *pdc_domain, struct irq_data *d)
949{
950 int i, j;
951 unsigned int mux;
952 struct irq_desc *desc = irq_data_to_desc(d);
953 struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
954 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
955 unsigned int gpio = d->hwirq;
956 struct msm_pinctrl *pctrl;
957 unsigned int irq;
958
959 if (!gc || !parent_data)
960 return;
961
962 pctrl = gpiochip_get_data(gc);
963
964 for (i = 0; i < pctrl->soc->n_gpio_mux_in; i++) {
965 if (gpio != pctrl->soc->gpio_mux_in[i].gpio)
966 continue;
967 mux = pctrl->soc->gpio_mux_in[i].mux;
968 for (j = 0; j < pctrl->soc->n_pdc_mux_out; j++) {
969 struct msm_pdc_mux_output *pdc_out =
970 &pctrl->soc->pdc_mux_out[j];
971
972 if (pdc_out->mux == mux)
973 break;
974 if (pdc_out->mux)
975 continue;
976 pdc_out->mux = gpio;
977 irq = irq_find_mapping(pdc_domain, pdc_out->hwirq + 32);
978 /* setup the IRQ parent for the GPIO */
979 setup_pdc_gpio(pctrl->chip.irqdomain, irq, gpio);
980 /* program pdc select grp register */
981 writel_relaxed((mux & 0x3F), pctrl->pdc_regs +
982 (0x14 * j));
983 break;
984 }
985 /* We have no more PDC port available */
986 WARN_ON(j == pctrl->soc->n_pdc_mux_out);
987 }
988}
989
Archana Sathyakumar5630a2e2017-11-02 15:24:20 -0600990static bool is_gpio_tlmm_dc(struct irq_data *d, u32 type)
991{
992 const struct msm_pingroup *g;
993 unsigned long flags;
994 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
995 struct msm_pinctrl *pctrl;
996 bool ret = false;
997 unsigned int polarity = 0, offset, val;
998 int i;
999
1000 if (!gc)
1001 return false;
1002
1003 pctrl = gpiochip_get_data(gc);
1004
1005 for (i = 0; i < pctrl->soc->n_dir_conns; i++) {
1006 struct msm_dir_conn *dir_conn = (struct msm_dir_conn *)
1007 &pctrl->soc->dir_conn[i];
1008
1009 if (dir_conn->gpio == d->hwirq && dir_conn->tlmm_dc) {
1010 ret = true;
1011 offset = pctrl->soc->dir_conn_irq_base -
1012 dir_conn->hwirq;
1013 break;
1014 }
1015 }
1016
1017 if (!ret)
1018 return ret;
1019
1020 if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW))
1021 return ret;
1022
1023 /*
1024 * Since the default polarity is set to 0, change it to 1 for
1025 * Rising edge and active high interrupt type such that the line
1026 * is not inverted.
1027 */
1028 polarity = 1;
1029
1030 spin_lock_irqsave(&pctrl->lock, flags);
1031 g = &pctrl->soc->groups[d->hwirq];
1032
1033 val = readl_relaxed(pctrl->regs + g->dir_conn_reg + (offset * 4));
1034 val |= polarity << 8;
1035
1036 writel_relaxed(val, pctrl->regs + g->dir_conn_reg + (offset * 4));
1037
1038 spin_unlock_irqrestore(&pctrl->lock, flags);
1039
1040 return ret;
1041}
1042
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001043static bool is_gpio_dual_edge(struct irq_data *d, irq_hw_number_t *dir_conn_irq)
1044{
1045 struct irq_desc *desc = irq_data_to_desc(d);
1046 struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
1047 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
1048 struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
1049 int i;
1050
1051 if (!parent_data)
1052 return false;
1053
1054 for (i = 0; i < pctrl->soc->n_dir_conns; i++) {
1055 const struct msm_dir_conn *dir_conn = &pctrl->soc->dir_conn[i];
1056
1057 if (dir_conn->gpio == d->hwirq && (dir_conn->hwirq + 32)
1058 != parent_data->hwirq) {
1059 *dir_conn_irq = dir_conn->hwirq + 32;
1060 return true;
1061 }
1062 }
Archana Sathyakumar892c01c2017-10-31 13:47:20 -06001063
1064 for (i = 0; i < pctrl->soc->n_pdc_mux_out; i++) {
1065 struct msm_pdc_mux_output *dir_conn =
1066 &pctrl->soc->pdc_mux_out[i];
1067
1068 if (dir_conn->mux == d->hwirq && (dir_conn->hwirq + 32)
1069 != parent_data->hwirq) {
1070 *dir_conn_irq = dir_conn->hwirq + 32;
1071 return true;
1072 }
1073 }
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001074 return false;
1075}
1076
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001077static void msm_dirconn_irq_mask(struct irq_data *d)
1078{
1079 struct irq_desc *desc = irq_data_to_desc(d);
1080 struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001081 irq_hw_number_t dir_conn_irq = 0;
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001082
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001083 if (!parent_data)
1084 return;
1085
1086 if (is_gpio_dual_edge(d, &dir_conn_irq)) {
1087 struct irq_data *dir_conn_data =
1088 irq_get_irq_data(irq_find_mapping(parent_data->domain,
1089 dir_conn_irq));
1090
Archana Sathyakumar892c01c2017-10-31 13:47:20 -06001091 if (!dir_conn_data)
1092 return;
1093 if (dir_conn_data->chip->irq_mask)
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001094 dir_conn_data->chip->irq_mask(dir_conn_data);
1095 }
Archana Sathyakumar892c01c2017-10-31 13:47:20 -06001096
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001097 if (parent_data->chip->irq_mask)
1098 parent_data->chip->irq_mask(parent_data);
1099}
1100
Maulik Shahe0a55832018-01-23 14:24:18 +05301101static void msm_dirconn_irq_enable(struct irq_data *d)
1102{
1103 struct irq_desc *desc = irq_data_to_desc(d);
1104 struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
1105 irq_hw_number_t dir_conn_irq = 0;
1106
1107 if (!parent_data)
1108 return;
1109
1110 if (is_gpio_dual_edge(d, &dir_conn_irq)) {
1111 struct irq_data *dir_conn_data =
1112 irq_get_irq_data(irq_find_mapping(parent_data->domain,
1113 dir_conn_irq));
1114
1115 if (dir_conn_data &&
1116 dir_conn_data->chip->irq_set_irqchip_state)
1117 dir_conn_data->chip->irq_set_irqchip_state(
1118 dir_conn_data,
1119 IRQCHIP_STATE_PENDING, 0);
1120
1121 if (dir_conn_data && dir_conn_data->chip->irq_unmask)
1122 dir_conn_data->chip->irq_unmask(dir_conn_data);
1123 }
1124
1125 if (parent_data->chip->irq_set_irqchip_state)
1126 parent_data->chip->irq_set_irqchip_state(parent_data,
1127 IRQCHIP_STATE_PENDING, 0);
1128
1129 if (parent_data->chip->irq_unmask)
1130 parent_data->chip->irq_unmask(parent_data);
1131}
1132
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001133static void msm_dirconn_irq_unmask(struct irq_data *d)
1134{
1135 struct irq_desc *desc = irq_data_to_desc(d);
1136 struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001137 irq_hw_number_t dir_conn_irq = 0;
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001138
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001139 if (!parent_data)
1140 return;
1141
1142 if (is_gpio_dual_edge(d, &dir_conn_irq)) {
1143 struct irq_data *dir_conn_data =
1144 irq_get_irq_data(irq_find_mapping(parent_data->domain,
1145 dir_conn_irq));
1146
Archana Sathyakumar892c01c2017-10-31 13:47:20 -06001147 if (!dir_conn_data)
1148 return;
1149 if (dir_conn_data->chip->irq_unmask)
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001150 dir_conn_data->chip->irq_unmask(dir_conn_data);
1151 }
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001152 if (parent_data->chip->irq_unmask)
1153 parent_data->chip->irq_unmask(parent_data);
1154}
1155
1156static void msm_dirconn_irq_ack(struct irq_data *d)
1157{
1158 struct irq_desc *desc = irq_data_to_desc(d);
1159 struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
1160
Maulik Shah9180da22017-10-31 15:23:17 +05301161 if (!parent_data)
1162 return;
1163
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001164 if (parent_data->chip->irq_ack)
1165 parent_data->chip->irq_ack(parent_data);
1166}
1167
1168static void msm_dirconn_irq_eoi(struct irq_data *d)
1169{
1170 struct irq_desc *desc = irq_data_to_desc(d);
1171 struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
1172
Maulik Shah9180da22017-10-31 15:23:17 +05301173 if (!parent_data)
1174 return;
1175
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001176 if (parent_data->chip->irq_eoi)
1177 parent_data->chip->irq_eoi(parent_data);
1178}
1179
1180static int msm_dirconn_irq_set_affinity(struct irq_data *d,
1181 const struct cpumask *maskval, bool force)
1182{
1183 struct irq_desc *desc = irq_data_to_desc(d);
1184 struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
1185
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001186 if (!parent_data)
1187 return 0;
1188
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001189 if (parent_data->chip->irq_set_affinity)
1190 return parent_data->chip->irq_set_affinity(parent_data,
1191 maskval, force);
1192 return 0;
1193}
1194
1195static int msm_dirconn_irq_set_vcpu_affinity(struct irq_data *d,
1196 void *vcpu_info)
1197{
1198 struct irq_desc *desc = irq_data_to_desc(d);
1199 struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
1200
Maulik Shah9180da22017-10-31 15:23:17 +05301201 if (!parent_data)
1202 return 0;
1203
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001204 if (parent_data->chip->irq_set_vcpu_affinity)
1205 return parent_data->chip->irq_set_vcpu_affinity(parent_data,
1206 vcpu_info);
1207 return 0;
1208}
1209
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001210static void msm_dirconn_cfg_reg(struct irq_data *d, u32 offset)
1211{
1212 u32 val = 0;
1213 const struct msm_pingroup *g;
1214 unsigned long flags;
1215 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
1216 struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
1217
1218 spin_lock_irqsave(&pctrl->lock, flags);
1219 g = &pctrl->soc->groups[d->hwirq];
1220
1221 val = readl_relaxed(pctrl->regs + g->dir_conn_reg + (offset * 4));
1222 val = (d->hwirq) & 0xFF;
1223
1224 writel_relaxed(val, pctrl->regs + g->dir_conn_reg + (offset * 4));
1225
1226 //write the dir_conn_en bit
1227 val = readl_relaxed(pctrl->regs + g->intr_cfg_reg);
1228 val |= BIT(g->dir_conn_en_bit);
1229 writel_relaxed(val, pctrl->regs + g->intr_cfg_reg);
1230 spin_unlock_irqrestore(&pctrl->lock, flags);
1231}
1232
1233static void msm_dirconn_uncfg_reg(struct irq_data *d, u32 offset)
1234{
1235 const struct msm_pingroup *g;
1236 unsigned long flags;
1237 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
1238 struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
1239
1240 spin_lock_irqsave(&pctrl->lock, flags);
1241 g = &pctrl->soc->groups[d->hwirq];
1242
1243 writel_relaxed(BIT(8), pctrl->regs + g->dir_conn_reg + (offset * 4));
1244 spin_unlock_irqrestore(&pctrl->lock, flags);
1245}
1246
1247static int select_dir_conn_mux(struct irq_data *d, irq_hw_number_t *irq)
1248{
1249 struct msm_dir_conn *dc = NULL;
1250 struct irq_desc *desc = irq_data_to_desc(d);
1251 struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
1252 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
1253 struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
1254 int i;
1255
1256 if (!parent_data)
1257 return -EINVAL;
1258
1259 for (i = 0; i < pctrl->soc->n_dir_conns; i++) {
1260 struct msm_dir_conn *dir_conn =
1261 (struct msm_dir_conn *)&pctrl->soc->dir_conn[i];
1262
1263 /* Check if there is already mux assigned for this gpio */
1264 if (dir_conn->gpio == d->hwirq && (dir_conn->hwirq + 32) !=
1265 parent_data->hwirq) {
1266 *irq = dir_conn->hwirq + 32;
1267 return pctrl->soc->dir_conn_irq_base - dir_conn->hwirq;
1268 }
1269
1270 if (dir_conn->gpio)
1271 continue;
1272
1273 /* Use the first unused direct connect available */
1274 dc = dir_conn;
1275 break;
1276 }
1277
1278 if (dc) {
1279 *irq = dc->hwirq + 32;
1280 dc->gpio = (u32)d->hwirq;
1281 return pctrl->soc->dir_conn_irq_base - (u32)dc->hwirq;
1282 }
1283
1284 pr_err("%s: No direct connects available for interrupt %lu\n",
1285 __func__, d->hwirq);
1286 return -EINVAL;
1287}
1288
1289static void add_dirconn_tlmm(struct irq_data *d, irq_hw_number_t irq)
1290{
1291 struct irq_desc *desc = irq_data_to_desc(d);
1292 struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
1293 struct irq_data *dir_conn_data = NULL;
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301294 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001295 int offset = 0;
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301296 unsigned int virt = 0, val = 0;
1297 struct msm_pinctrl *pctrl;
1298 phys_addr_t spi_cfg_reg = 0;
1299 unsigned long flags;
Naresh Kumar Lingagallaff508b42023-05-23 12:23:33 +05301300 u32 offset_local;
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001301
1302 offset = select_dir_conn_mux(d, &irq);
1303 if (offset < 0 || !parent_data)
1304 return;
1305
1306 virt = irq_find_mapping(parent_data->domain, irq);
1307 msm_dirconn_cfg_reg(d, offset);
1308 irq_set_handler_data(virt, d);
1309 desc = irq_to_desc(virt);
1310 if (!desc)
1311 return;
1312
1313 dir_conn_data = &(desc->irq_data);
1314
1315 if (dir_conn_data) {
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301316
1317 pctrl = gpiochip_get_data(gc);
1318 if (pctrl->spi_cfg_regs) {
1319 spi_cfg_reg = pctrl->spi_cfg_regs +
Raghavendra Kakarlacd625c32018-10-10 11:47:43 +05301320 ((dir_conn_data->hwirq - 32) / 32) * 4;
Naresh Kumar Lingagallaff508b42023-05-23 12:23:33 +05301321 offset_local = ((dir_conn_data->hwirq - 32) / 32) * 4;
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301322 if (spi_cfg_reg < pctrl->spi_cfg_end) {
1323 spin_lock_irqsave(&pctrl->lock, flags);
Naresh Kumar Lingagallaff508b42023-05-23 12:23:33 +05301324 val = readl_relaxed(pctrl->spi_base +
1325 offset_local);
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301326 /*
1327 * Clear the respective bit for edge type
1328 * interrupt
1329 */
Raghavendra Kakarlacd625c32018-10-10 11:47:43 +05301330 val &= ~(1 << ((dir_conn_data->hwirq - 32)
1331 % 32));
Naresh Kumar Lingagallaff508b42023-05-23 12:23:33 +05301332 writel_relaxed(val, pctrl->spi_base +
1333 offset_local);
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301334 spin_unlock_irqrestore(&pctrl->lock, flags);
1335 } else
1336 pr_err("%s: type config failed for SPI: %lu\n",
1337 __func__, irq);
1338 } else
1339 pr_debug("%s: type config for SPI is not supported\n",
1340 __func__);
1341
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001342 if (dir_conn_data->chip && dir_conn_data->chip->irq_set_type)
1343 dir_conn_data->chip->irq_set_type(dir_conn_data,
1344 IRQ_TYPE_EDGE_RISING);
1345 if (dir_conn_data->chip && dir_conn_data->chip->irq_unmask)
1346 dir_conn_data->chip->irq_unmask(dir_conn_data);
1347 }
1348}
1349
1350static void remove_dirconn_tlmm(struct irq_data *d, irq_hw_number_t irq)
1351{
1352 struct irq_desc *desc = irq_data_to_desc(d);
1353 struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
1354 struct irq_data *dir_conn_data = NULL;
1355 int offset = 0;
1356 unsigned int virt = 0;
1357
1358 virt = irq_find_mapping(parent_data->domain, irq);
1359 msm_dirconn_uncfg_reg(d, offset);
1360 irq_set_handler_data(virt, NULL);
1361 desc = irq_to_desc(virt);
1362 if (!desc)
1363 return;
1364
1365 dir_conn_data = &(desc->irq_data);
1366
1367 if (dir_conn_data) {
1368 if (dir_conn_data->chip && dir_conn_data->chip->irq_mask)
1369 dir_conn_data->chip->irq_mask(dir_conn_data);
1370 }
1371}
1372
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001373static int msm_dirconn_irq_set_type(struct irq_data *d, unsigned int type)
1374{
1375 struct irq_desc *desc = irq_data_to_desc(d);
1376 struct irq_data *parent_data = irq_get_irq_data(desc->parent_irq);
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301377 struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001378 irq_hw_number_t irq = 0;
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301379 struct msm_pinctrl *pctrl;
1380 phys_addr_t spi_cfg_reg = 0;
1381 unsigned int config_val = 0;
1382 unsigned int val = 0;
1383 unsigned long flags;
Naresh Kumar Lingagallaff508b42023-05-23 12:23:33 +05301384 u32 offset_local;
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001385
1386 if (!parent_data)
1387 return 0;
1388
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301389 pctrl = gpiochip_get_data(gc);
1390
Archana Sathyakumar5630a2e2017-11-02 15:24:20 -06001391 if (type == IRQ_TYPE_EDGE_BOTH)
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001392 add_dirconn_tlmm(d, irq);
Archana Sathyakumar5630a2e2017-11-02 15:24:20 -06001393 else if (is_gpio_dual_edge(d, &irq))
1394 remove_dirconn_tlmm(d, irq);
1395 else if (is_gpio_tlmm_dc(d, type))
1396 type = IRQ_TYPE_EDGE_RISING;
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001397
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301398 /*
1399 * Shared SPI config for Edge is 0 and
1400 * for Level interrupt is 1
1401 */
1402 if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) {
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001403 irq_set_handler_locked(d, handle_level_irq);
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301404 config_val = 1;
1405 } else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
Archana Sathyakumar8ff3ba62017-10-06 11:58:46 -06001406 irq_set_handler_locked(d, handle_edge_irq);
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001407
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301408 if (pctrl->spi_cfg_regs && type != IRQ_TYPE_NONE) {
1409 spi_cfg_reg = pctrl->spi_cfg_regs +
Raghavendra Kakarlacd625c32018-10-10 11:47:43 +05301410 ((parent_data->hwirq - 32) / 32) * 4;
Naresh Kumar Lingagallaff508b42023-05-23 12:23:33 +05301411 offset_local = ((parent_data->hwirq - 32) / 32) * 4;
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301412 if (spi_cfg_reg < pctrl->spi_cfg_end) {
1413 spin_lock_irqsave(&pctrl->lock, flags);
Naresh Kumar Lingagallaff508b42023-05-23 12:23:33 +05301414 val = readl_relaxed(pctrl->spi_base + offset_local);
Raghavendra Kakarlacd625c32018-10-10 11:47:43 +05301415 val &= ~(1 << ((parent_data->hwirq - 32) % 32));
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301416 if (config_val)
Raghavendra Kakarlacd625c32018-10-10 11:47:43 +05301417 val |= (1 << ((parent_data->hwirq - 32) % 32));
Naresh Kumar Lingagallaff508b42023-05-23 12:23:33 +05301418 writel_relaxed(val, pctrl->spi_base + offset_local);
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301419 spin_unlock_irqrestore(&pctrl->lock, flags);
1420 } else
1421 pr_err("%s: type config failed for SPI: %lu\n",
1422 __func__, irq);
1423 } else
1424 pr_debug("%s: SPI type config is not supported\n", __func__);
1425
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001426 if (parent_data->chip->irq_set_type)
1427 return parent_data->chip->irq_set_type(parent_data, type);
1428
1429 return 0;
1430}
1431
1432static struct irq_chip msm_dirconn_irq_chip = {
1433 .name = "msmgpio-dc",
1434 .irq_mask = msm_dirconn_irq_mask,
Maulik Shahe0a55832018-01-23 14:24:18 +05301435 .irq_enable = msm_dirconn_irq_enable,
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001436 .irq_unmask = msm_dirconn_irq_unmask,
1437 .irq_eoi = msm_dirconn_irq_eoi,
1438 .irq_ack = msm_dirconn_irq_ack,
1439 .irq_set_type = msm_dirconn_irq_set_type,
1440 .irq_set_affinity = msm_dirconn_irq_set_affinity,
1441 .irq_set_vcpu_affinity = msm_dirconn_irq_set_vcpu_affinity,
1442 .flags = IRQCHIP_SKIP_SET_WAKE
1443 | IRQCHIP_MASK_ON_SUSPEND
1444 | IRQCHIP_SET_TYPE_MASKED,
1445};
1446
Thomas Gleixnerbd0b9ac2015-09-14 10:42:37 +02001447static void msm_gpio_irq_handler(struct irq_desc *desc)
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001448{
Linus Walleijcdcb0ab2014-04-29 11:00:40 -07001449 struct gpio_chip *gc = irq_desc_get_handler_data(desc);
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001450 const struct msm_pingroup *g;
Linus Walleijfded3f42015-12-08 09:49:18 +01001451 struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
Jiang Liu5663bb22015-06-04 12:13:16 +08001452 struct irq_chip *chip = irq_desc_get_chip(desc);
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001453 int irq_pin;
1454 int handled = 0;
Kyle Yan6c2752f2017-09-27 16:29:45 -07001455 u32 val;
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001456 int i;
1457
1458 chained_irq_enter(chip, desc);
1459
1460 /*
Bjorn Andersson1f2b2392013-12-14 23:01:51 -08001461 * Each pin has it's own IRQ status register, so use
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001462 * enabled_irq bitmap to limit the number of reads.
1463 */
1464 for_each_set_bit(i, pctrl->enabled_irqs, pctrl->chip.ngpio) {
1465 g = &pctrl->soc->groups[i];
Kyle Yan6c2752f2017-09-27 16:29:45 -07001466 val = readl(pctrl->regs + g->intr_status_reg);
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001467 if (val & BIT(g->intr_status_bit)) {
Linus Walleijcdcb0ab2014-04-29 11:00:40 -07001468 irq_pin = irq_find_mapping(gc->irqdomain, i);
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001469 generic_handle_irq(irq_pin);
1470 handled++;
1471 }
1472 }
1473
Bjorn Andersson1f2b2392013-12-14 23:01:51 -08001474 /* No interrupts were flagged */
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001475 if (handled == 0)
Thomas Gleixnerbd0b9ac2015-09-14 10:42:37 +02001476 handle_bad_irq(desc);
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001477
1478 chained_irq_exit(chip, desc);
1479}
1480
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001481static void msm_gpio_setup_dir_connects(struct msm_pinctrl *pctrl)
1482{
1483 struct device_node *parent_node;
Archana Sathyakumar892c01c2017-10-31 13:47:20 -06001484 struct irq_domain *pdc_domain;
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001485 unsigned int i;
1486
1487 parent_node = of_irq_find_parent(pctrl->dev->of_node);
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001488 if (!parent_node)
1489 return;
1490
Archana Sathyakumar892c01c2017-10-31 13:47:20 -06001491 pdc_domain = irq_find_host(parent_node);
1492 if (!pdc_domain)
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001493 return;
1494
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001495 for (i = 0; i < pctrl->soc->n_dir_conns; i++) {
1496 const struct msm_dir_conn *dirconn = &pctrl->soc->dir_conn[i];
Archana Sathyakumar5630a2e2017-11-02 15:24:20 -06001497 struct irq_data *d;
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001498
Archana Sathyakumar892c01c2017-10-31 13:47:20 -06001499 request_dc_interrupt(pctrl->chip.irqdomain, pdc_domain,
1500 dirconn->hwirq, dirconn->gpio);
Archana Sathyakumar5630a2e2017-11-02 15:24:20 -06001501
1502 if (!dirconn->gpio)
1503 continue;
1504
1505 if (!dirconn->tlmm_dc)
1506 continue;
1507
1508 /*
1509 * If the gpio is routed through TLMM direct connect interrupts,
1510 * program the TLMM registers for this setup.
1511 */
1512 d = irq_get_irq_data(irq_find_mapping(pctrl->chip.irqdomain,
1513 dirconn->gpio));
1514 if (!d)
1515 continue;
1516
1517 msm_dirconn_cfg_reg(d, pctrl->soc->dir_conn_irq_base
1518 - (u32)dirconn->hwirq);
Archana Sathyakumar892c01c2017-10-31 13:47:20 -06001519 }
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001520
Archana Sathyakumar892c01c2017-10-31 13:47:20 -06001521 for (i = 0; i < pctrl->soc->n_pdc_mux_out; i++) {
1522 struct msm_pdc_mux_output *pdc_out =
1523 &pctrl->soc->pdc_mux_out[i];
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001524
Archana Sathyakumar892c01c2017-10-31 13:47:20 -06001525 request_dc_interrupt(pctrl->chip.irqdomain, pdc_domain,
1526 pdc_out->hwirq, 0);
1527 }
1528
1529 /*
1530 * Statically choose the GPIOs for mapping to PDC. Dynamic mux mapping
1531 * is very difficult.
1532 */
Maulik Shahf166e3f2018-08-06 17:27:12 +05301533 for (i = 0; i < pctrl->soc->n_gpio_mux_in; i++) {
Archana Sathyakumar892c01c2017-10-31 13:47:20 -06001534 unsigned int irq;
1535 struct irq_data *d;
1536 struct msm_gpio_mux_input *gpio_in =
1537 &pctrl->soc->gpio_mux_in[i];
1538 if (!gpio_in->init)
1539 continue;
1540
1541 irq = irq_find_mapping(pctrl->chip.irqdomain, gpio_in->gpio);
1542 d = irq_get_irq_data(irq);
1543 if (!d)
1544 continue;
1545
1546 gpio_muxed_to_pdc(pdc_domain, d);
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001547 }
1548}
1549
Raju P.L.S.S.S.Ncdcd7692017-11-30 19:06:30 +05301550static int msm_gpiochip_to_irq(struct gpio_chip *chip, unsigned int offset)
1551{
Raghavendra Kakarla0e77a9e2018-03-07 21:30:45 +05301552 struct irq_fwspec fwspec;
Raghavendra Kakarla882117f2018-08-21 16:24:01 +05301553 struct irq_domain *domain = chip->irqdomain;
1554 int virq;
1555
1556 virq = irq_find_mapping(domain, offset);
1557 if (virq)
1558 return virq;
Raghavendra Kakarla0e77a9e2018-03-07 21:30:45 +05301559
1560 fwspec.fwnode = of_node_to_fwnode(chip->of_node);
1561 fwspec.param[0] = offset;
1562 fwspec.param[1] = IRQ_TYPE_NONE;
1563 fwspec.param_count = 2;
1564
1565 return irq_create_fwspec_mapping(&fwspec);
Raju P.L.S.S.S.Ncdcd7692017-11-30 19:06:30 +05301566}
1567
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001568static int msm_gpio_init(struct msm_pinctrl *pctrl)
1569{
1570 struct gpio_chip *chip;
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001571 int ret;
Stephen Boyddcd278b2014-03-06 22:44:41 -08001572 unsigned ngpio = pctrl->soc->ngpios;
Raghavendra Kakarla0e77a9e2018-03-07 21:30:45 +05301573 struct device_node *irq_parent = NULL;
Raju P.L.S.S.S.Ncdcd7692017-11-30 19:06:30 +05301574 struct irq_domain *domain_parent;
Stephen Boyddcd278b2014-03-06 22:44:41 -08001575
1576 if (WARN_ON(ngpio > MAX_NR_GPIO))
1577 return -EINVAL;
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001578
1579 chip = &pctrl->chip;
1580 chip->base = 0;
Stephen Boyddcd278b2014-03-06 22:44:41 -08001581 chip->ngpio = ngpio;
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001582 chip->label = dev_name(pctrl->dev);
Linus Walleij58383c72015-11-04 09:56:26 +01001583 chip->parent = pctrl->dev;
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001584 chip->owner = THIS_MODULE;
1585 chip->of_node = pctrl->dev->of_node;
1586
Linus Walleijfded3f42015-12-08 09:49:18 +01001587 ret = gpiochip_add_data(&pctrl->chip, pctrl);
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001588 if (ret) {
1589 dev_err(pctrl->dev, "Failed register gpiochip\n");
1590 return ret;
1591 }
1592
Christian Lamparter43b08612018-05-21 22:57:37 +02001593 /*
1594 * For DeviceTree-supported systems, the gpio core checks the
1595 * pinctrl's device node for the "gpio-ranges" property.
1596 * If it is present, it takes care of adding the pin ranges
1597 * for the driver. In this case the driver can skip ahead.
1598 *
1599 * In order to remain compatible with older, existing DeviceTree
1600 * files which don't set the "gpio-ranges" property or systems that
1601 * utilize ACPI the driver has to call gpiochip_add_pin_range().
1602 */
1603 if (!of_property_read_bool(pctrl->dev->of_node, "gpio-ranges")) {
1604 ret = gpiochip_add_pin_range(&pctrl->chip,
1605 dev_name(pctrl->dev), 0, 0, chip->ngpio);
1606 if (ret) {
1607 dev_err(pctrl->dev, "Failed to add pin range\n");
1608 gpiochip_remove(&pctrl->chip);
1609 return ret;
1610 }
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001611 }
1612
Raghavendra Kakarla0e77a9e2018-03-07 21:30:45 +05301613 irq_parent = of_irq_find_parent(chip->of_node);
1614 if (of_device_is_compatible(irq_parent, "qcom,mpm-gpio")) {
1615 chip->irqchip = &msm_gpio_irq_chip;
1616 chip->irq_handler = handle_fasteoi_irq;
1617 chip->irq_default_type = IRQ_TYPE_NONE;
1618 chip->to_irq = msm_gpiochip_to_irq;
1619 chip->lock_key = NULL;
1620 domain_parent = irq_find_host(irq_parent);
1621 if (!domain_parent) {
1622 pr_err("unable to find parent domain\n");
1623 gpiochip_remove(&pctrl->chip);
1624 return -ENXIO;
1625 }
Raju P.L.S.S.S.Ncdcd7692017-11-30 19:06:30 +05301626
Raghavendra Kakarla0e77a9e2018-03-07 21:30:45 +05301627 chip->irqdomain = irq_domain_add_hierarchy(domain_parent, 0,
Raju P.L.S.S.S.Ncdcd7692017-11-30 19:06:30 +05301628 chip->ngpio,
1629 chip->of_node,
1630 &msm_gpio_domain_ops,
1631 chip);
Raghavendra Kakarla0e77a9e2018-03-07 21:30:45 +05301632 if (!chip->irqdomain) {
1633 dev_err(pctrl->dev, "Failed to add irqchip to gpiochip\n");
1634 chip->irqchip = NULL;
1635 gpiochip_remove(&pctrl->chip);
1636 return -ENXIO;
1637 }
1638 } else {
1639 ret = gpiochip_irqchip_add(chip,
1640 &msm_gpio_irq_chip,
1641 0,
1642 handle_fasteoi_irq,
1643 IRQ_TYPE_NONE);
1644 if (ret) {
1645 dev_err(pctrl->dev, "Failed to add irqchip to gpiochip\n");
1646 gpiochip_remove(&pctrl->chip);
1647 return ret;
1648 }
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001649 }
Raju P.L.S.S.S.Ncdcd7692017-11-30 19:06:30 +05301650 gpiochip_set_chained_irqchip(chip, &msm_gpio_irq_chip,
1651 pctrl->irq, msm_gpio_irq_handler);
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001652
Mahesh Sivasubramanianfcc313e2017-04-10 09:05:59 -06001653 msm_gpio_setup_dir_connects(pctrl);
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001654 return 0;
1655}
1656
Josh Cartwrightcf1fc182014-09-23 15:59:53 -05001657static int msm_ps_hold_restart(struct notifier_block *nb, unsigned long action,
1658 void *data)
Pramod Gurav32745582014-08-29 20:00:59 +05301659{
Josh Cartwrightcf1fc182014-09-23 15:59:53 -05001660 struct msm_pinctrl *pctrl = container_of(nb, struct msm_pinctrl, restart_nb);
1661
1662 writel(0, pctrl->regs + PS_HOLD_OFFSET);
1663 mdelay(1000);
1664 return NOTIFY_DONE;
Pramod Gurav32745582014-08-29 20:00:59 +05301665}
1666
Stephen Boydad644982015-07-06 18:09:30 -07001667static struct msm_pinctrl *poweroff_pctrl;
1668
1669static void msm_ps_hold_poweroff(void)
1670{
1671 msm_ps_hold_restart(&poweroff_pctrl->restart_nb, 0, NULL);
1672}
1673
Pramod Gurav32745582014-08-29 20:00:59 +05301674static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl)
1675{
Stephen Boydbcd53f82015-01-19 11:17:45 +01001676 int i;
Pramod Gurav32745582014-08-29 20:00:59 +05301677 const struct msm_function *func = pctrl->soc->functions;
1678
Stephen Boydbcd53f82015-01-19 11:17:45 +01001679 for (i = 0; i < pctrl->soc->nfunctions; i++)
Pramod Gurav32745582014-08-29 20:00:59 +05301680 if (!strcmp(func[i].name, "ps_hold")) {
Josh Cartwrightcf1fc182014-09-23 15:59:53 -05001681 pctrl->restart_nb.notifier_call = msm_ps_hold_restart;
1682 pctrl->restart_nb.priority = 128;
1683 if (register_restart_handler(&pctrl->restart_nb))
1684 dev_err(pctrl->dev,
1685 "failed to setup restart handler.\n");
Stephen Boydad644982015-07-06 18:09:30 -07001686 poweroff_pctrl = pctrl;
1687 pm_power_off = msm_ps_hold_poweroff;
Josh Cartwrightcf1fc182014-09-23 15:59:53 -05001688 break;
Pramod Gurav32745582014-08-29 20:00:59 +05301689 }
1690}
Pramod Gurav32745582014-08-29 20:00:59 +05301691
Maria Yu2af63b22018-03-29 17:34:28 +08001692#ifdef CONFIG_PM
1693static int msm_pinctrl_suspend(void)
1694{
1695 return 0;
1696}
1697
1698static void msm_pinctrl_resume(void)
1699{
1700 int i, irq;
1701 u32 val;
1702 unsigned long flags;
1703 struct irq_desc *desc;
1704 const struct msm_pingroup *g;
1705 const char *name = "null";
1706 struct msm_pinctrl *pctrl = msm_pinctrl_data;
1707
1708 if (!msm_show_resume_irq_mask)
1709 return;
1710
1711 spin_lock_irqsave(&pctrl->lock, flags);
1712 for_each_set_bit(i, pctrl->enabled_irqs, pctrl->chip.ngpio) {
1713 g = &pctrl->soc->groups[i];
1714 val = readl_relaxed(pctrl->regs + g->intr_status_reg);
1715 if (val & BIT(g->intr_status_bit)) {
1716 irq = irq_find_mapping(pctrl->chip.irqdomain, i);
1717 desc = irq_to_desc(irq);
1718 if (desc == NULL)
1719 name = "stray irq";
1720 else if (desc->action && desc->action->name)
1721 name = desc->action->name;
1722
1723 pr_warn("%s: %d triggered %s\n", __func__, irq, name);
1724 }
1725 }
1726 spin_unlock_irqrestore(&pctrl->lock, flags);
1727}
1728#else
1729#define msm_pinctrl_suspend NULL
1730#define msm_pinctrl_resume NULL
1731#endif
1732
1733static struct syscore_ops msm_pinctrl_pm_ops = {
1734 .suspend = msm_pinctrl_suspend,
1735 .resume = msm_pinctrl_resume,
1736};
1737
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001738int msm_pinctrl_probe(struct platform_device *pdev,
1739 const struct msm_pinctrl_soc_data *soc_data)
1740{
1741 struct msm_pinctrl *pctrl;
1742 struct resource *res;
1743 int ret;
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301744 char *key;
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001745
Maria Yu2af63b22018-03-29 17:34:28 +08001746 msm_pinctrl_data = pctrl = devm_kzalloc(&pdev->dev,
1747 sizeof(*pctrl), GFP_KERNEL);
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001748 if (!pctrl) {
1749 dev_err(&pdev->dev, "Can't allocate msm_pinctrl\n");
1750 return -ENOMEM;
1751 }
1752 pctrl->dev = &pdev->dev;
1753 pctrl->soc = soc_data;
1754 pctrl->chip = msm_gpio_template;
1755
1756 spin_lock_init(&pctrl->lock);
1757
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301758 key = "pinctrl_regs";
1759 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001760 pctrl->regs = devm_ioremap_resource(&pdev->dev, res);
1761 if (IS_ERR(pctrl->regs))
1762 return PTR_ERR(pctrl->regs);
1763
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301764 key = "pdc_regs";
1765 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
Archana Sathyakumar892c01c2017-10-31 13:47:20 -06001766 pctrl->pdc_regs = devm_ioremap_resource(&pdev->dev, res);
1767
Srinivas Rao Ld6302982018-07-31 12:36:56 +05301768 key = "spi_cfg_regs";
1769 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, key);
1770 if (res) {
1771 pctrl->spi_cfg_regs = res->start;
1772 pctrl->spi_cfg_end = res->end;
1773 }
1774
Pramod Gurav32745582014-08-29 20:00:59 +05301775 msm_pinctrl_setup_pm_reset(pctrl);
1776
Bjorn Anderssonf393e482013-12-14 23:01:52 -08001777 pctrl->irq = platform_get_irq(pdev, 0);
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001778 if (pctrl->irq < 0) {
1779 dev_err(&pdev->dev, "No interrupt defined for msmgpio\n");
1780 return pctrl->irq;
1781 }
1782
1783 msm_pinctrl_desc.name = dev_name(&pdev->dev);
1784 msm_pinctrl_desc.pins = pctrl->soc->pins;
1785 msm_pinctrl_desc.npins = pctrl->soc->npins;
Laxman Dewanganfe0267f2016-02-24 14:44:07 +05301786 pctrl->pctrl = devm_pinctrl_register(&pdev->dev, &msm_pinctrl_desc,
1787 pctrl);
Masahiro Yamada323de9e2015-06-09 13:01:16 +09001788 if (IS_ERR(pctrl->pctrl)) {
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001789 dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
Masahiro Yamada323de9e2015-06-09 13:01:16 +09001790 return PTR_ERR(pctrl->pctrl);
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001791 }
1792
1793 ret = msm_gpio_init(pctrl);
Laxman Dewanganfe0267f2016-02-24 14:44:07 +05301794 if (ret)
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001795 return ret;
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001796
1797 platform_set_drvdata(pdev, pctrl);
1798
Maria Yu2af63b22018-03-29 17:34:28 +08001799 register_syscore_ops(&msm_pinctrl_pm_ops);
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001800 dev_dbg(&pdev->dev, "Probed Qualcomm pinctrl driver\n");
1801
1802 return 0;
1803}
1804EXPORT_SYMBOL(msm_pinctrl_probe);
1805
1806int msm_pinctrl_remove(struct platform_device *pdev)
1807{
1808 struct msm_pinctrl *pctrl = platform_get_drvdata(pdev);
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001809
Linus Walleij2fcea6c2014-09-16 15:05:41 -07001810 gpiochip_remove(&pctrl->chip);
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001811
Josh Cartwrightcf1fc182014-09-23 15:59:53 -05001812 unregister_restart_handler(&pctrl->restart_nb);
Maria Yu2af63b22018-03-29 17:34:28 +08001813 unregister_syscore_ops(&msm_pinctrl_pm_ops);
Josh Cartwrightcf1fc182014-09-23 15:59:53 -05001814
Bjorn Anderssonf365be02013-12-05 18:10:03 -08001815 return 0;
1816}
1817EXPORT_SYMBOL(msm_pinctrl_remove);
1818