18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * OWL SoC's Pinctrl driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2014 Actions Semi Inc.
68c2ecf20Sopenharmony_ci * Author: David Liu <liuwei@actions-semi.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright (c) 2018 Linaro Ltd.
98c2ecf20Sopenharmony_ci * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/clk.h>
138c2ecf20Sopenharmony_ci#include <linux/err.h>
148c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h>
158c2ecf20Sopenharmony_ci#include <linux/io.h>
168c2ecf20Sopenharmony_ci#include <linux/irq.h>
178c2ecf20Sopenharmony_ci#include <linux/module.h>
188c2ecf20Sopenharmony_ci#include <linux/of.h>
198c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
208c2ecf20Sopenharmony_ci#include <linux/pinctrl/machine.h>
218c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinctrl.h>
228c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinmux.h>
238c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf.h>
248c2ecf20Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h>
258c2ecf20Sopenharmony_ci#include <linux/slab.h>
268c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include "../core.h"
298c2ecf20Sopenharmony_ci#include "../pinctrl-utils.h"
308c2ecf20Sopenharmony_ci#include "pinctrl-owl.h"
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/**
338c2ecf20Sopenharmony_ci * struct owl_pinctrl - pinctrl state of the device
348c2ecf20Sopenharmony_ci * @dev: device handle
358c2ecf20Sopenharmony_ci * @pctrldev: pinctrl handle
368c2ecf20Sopenharmony_ci * @chip: gpio chip
378c2ecf20Sopenharmony_ci * @lock: spinlock to protect registers
388c2ecf20Sopenharmony_ci * @clk: clock control
398c2ecf20Sopenharmony_ci * @soc: reference to soc_data
408c2ecf20Sopenharmony_ci * @base: pinctrl register base address
418c2ecf20Sopenharmony_ci * @irq_chip: IRQ chip information
428c2ecf20Sopenharmony_ci * @num_irq: number of possible interrupts
438c2ecf20Sopenharmony_ci * @irq: interrupt numbers
448c2ecf20Sopenharmony_ci */
458c2ecf20Sopenharmony_cistruct owl_pinctrl {
468c2ecf20Sopenharmony_ci	struct device *dev;
478c2ecf20Sopenharmony_ci	struct pinctrl_dev *pctrldev;
488c2ecf20Sopenharmony_ci	struct gpio_chip chip;
498c2ecf20Sopenharmony_ci	raw_spinlock_t lock;
508c2ecf20Sopenharmony_ci	struct clk *clk;
518c2ecf20Sopenharmony_ci	const struct owl_pinctrl_soc_data *soc;
528c2ecf20Sopenharmony_ci	void __iomem *base;
538c2ecf20Sopenharmony_ci	struct irq_chip irq_chip;
548c2ecf20Sopenharmony_ci	unsigned int num_irq;
558c2ecf20Sopenharmony_ci	unsigned int *irq;
568c2ecf20Sopenharmony_ci};
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic void owl_update_bits(void __iomem *base, u32 mask, u32 val)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	u32 reg_val;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	reg_val = readl_relaxed(base);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	reg_val = (reg_val & ~mask) | (val & mask);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	writel_relaxed(reg_val, base);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic u32 owl_read_field(struct owl_pinctrl *pctrl, u32 reg,
708c2ecf20Sopenharmony_ci				u32 bit, u32 width)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	u32 tmp, mask;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	tmp = readl_relaxed(pctrl->base + reg);
758c2ecf20Sopenharmony_ci	mask = (1 << width) - 1;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return (tmp >> bit) & mask;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic void owl_write_field(struct owl_pinctrl *pctrl, u32 reg, u32 arg,
818c2ecf20Sopenharmony_ci				u32 bit, u32 width)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	u32 mask;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	mask = (1 << width) - 1;
868c2ecf20Sopenharmony_ci	mask = mask << bit;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	owl_update_bits(pctrl->base + reg, mask, (arg << bit));
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic int owl_get_groups_count(struct pinctrl_dev *pctrldev)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	return pctrl->soc->ngroups;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic const char *owl_get_group_name(struct pinctrl_dev *pctrldev,
998c2ecf20Sopenharmony_ci				unsigned int group)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	return pctrl->soc->groups[group].name;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic int owl_get_group_pins(struct pinctrl_dev *pctrldev,
1078c2ecf20Sopenharmony_ci				unsigned int group,
1088c2ecf20Sopenharmony_ci				const unsigned int **pins,
1098c2ecf20Sopenharmony_ci				unsigned int *num_pins)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	*pins = pctrl->soc->groups[group].pads;
1148c2ecf20Sopenharmony_ci	*num_pins = pctrl->soc->groups[group].npads;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	return 0;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic void owl_pin_dbg_show(struct pinctrl_dev *pctrldev,
1208c2ecf20Sopenharmony_ci				struct seq_file *s,
1218c2ecf20Sopenharmony_ci				unsigned int offset)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	seq_printf(s, "%s", dev_name(pctrl->dev));
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic const struct pinctrl_ops owl_pinctrl_ops = {
1298c2ecf20Sopenharmony_ci	.get_groups_count = owl_get_groups_count,
1308c2ecf20Sopenharmony_ci	.get_group_name = owl_get_group_name,
1318c2ecf20Sopenharmony_ci	.get_group_pins = owl_get_group_pins,
1328c2ecf20Sopenharmony_ci	.pin_dbg_show = owl_pin_dbg_show,
1338c2ecf20Sopenharmony_ci	.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
1348c2ecf20Sopenharmony_ci	.dt_free_map = pinctrl_utils_free_map,
1358c2ecf20Sopenharmony_ci};
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic int owl_get_funcs_count(struct pinctrl_dev *pctrldev)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	return pctrl->soc->nfunctions;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic const char *owl_get_func_name(struct pinctrl_dev *pctrldev,
1458c2ecf20Sopenharmony_ci				unsigned int function)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	return pctrl->soc->functions[function].name;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic int owl_get_func_groups(struct pinctrl_dev *pctrldev,
1538c2ecf20Sopenharmony_ci				unsigned int function,
1548c2ecf20Sopenharmony_ci				const char * const **groups,
1558c2ecf20Sopenharmony_ci				unsigned int * const num_groups)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	*groups = pctrl->soc->functions[function].groups;
1608c2ecf20Sopenharmony_ci	*num_groups = pctrl->soc->functions[function].ngroups;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	return 0;
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic inline int get_group_mfp_mask_val(const struct owl_pingroup *g,
1668c2ecf20Sopenharmony_ci				int function,
1678c2ecf20Sopenharmony_ci				u32 *mask,
1688c2ecf20Sopenharmony_ci				u32 *val)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	int id;
1718c2ecf20Sopenharmony_ci	u32 option_num;
1728c2ecf20Sopenharmony_ci	u32 option_mask;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	for (id = 0; id < g->nfuncs; id++) {
1758c2ecf20Sopenharmony_ci		if (g->funcs[id] == function)
1768c2ecf20Sopenharmony_ci			break;
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci	if (WARN_ON(id == g->nfuncs))
1798c2ecf20Sopenharmony_ci		return -EINVAL;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	option_num = (1 << g->mfpctl_width);
1828c2ecf20Sopenharmony_ci	if (id > option_num)
1838c2ecf20Sopenharmony_ci		id -= option_num;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	option_mask = option_num - 1;
1868c2ecf20Sopenharmony_ci	*mask = (option_mask  << g->mfpctl_shift);
1878c2ecf20Sopenharmony_ci	*val = (id << g->mfpctl_shift);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	return 0;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistatic int owl_set_mux(struct pinctrl_dev *pctrldev,
1938c2ecf20Sopenharmony_ci				unsigned int function,
1948c2ecf20Sopenharmony_ci				unsigned int group)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
1978c2ecf20Sopenharmony_ci	const struct owl_pingroup *g;
1988c2ecf20Sopenharmony_ci	unsigned long flags;
1998c2ecf20Sopenharmony_ci	u32 val, mask;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	g = &pctrl->soc->groups[group];
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	if (get_group_mfp_mask_val(g, function, &mask, &val))
2048c2ecf20Sopenharmony_ci		return -EINVAL;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	owl_update_bits(pctrl->base + g->mfpctl_reg, mask, val);
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	return 0;
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic const struct pinmux_ops owl_pinmux_ops = {
2168c2ecf20Sopenharmony_ci	.get_functions_count = owl_get_funcs_count,
2178c2ecf20Sopenharmony_ci	.get_function_name = owl_get_func_name,
2188c2ecf20Sopenharmony_ci	.get_function_groups = owl_get_func_groups,
2198c2ecf20Sopenharmony_ci	.set_mux = owl_set_mux,
2208c2ecf20Sopenharmony_ci};
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_cistatic int owl_pad_pinconf_reg(const struct owl_padinfo *info,
2238c2ecf20Sopenharmony_ci				unsigned int param,
2248c2ecf20Sopenharmony_ci				u32 *reg,
2258c2ecf20Sopenharmony_ci				u32 *bit,
2268c2ecf20Sopenharmony_ci				u32 *width)
2278c2ecf20Sopenharmony_ci{
2288c2ecf20Sopenharmony_ci	switch (param) {
2298c2ecf20Sopenharmony_ci	case PIN_CONFIG_BIAS_BUS_HOLD:
2308c2ecf20Sopenharmony_ci	case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
2318c2ecf20Sopenharmony_ci	case PIN_CONFIG_BIAS_PULL_DOWN:
2328c2ecf20Sopenharmony_ci	case PIN_CONFIG_BIAS_PULL_UP:
2338c2ecf20Sopenharmony_ci		if (!info->pullctl)
2348c2ecf20Sopenharmony_ci			return -EINVAL;
2358c2ecf20Sopenharmony_ci		*reg = info->pullctl->reg;
2368c2ecf20Sopenharmony_ci		*bit = info->pullctl->shift;
2378c2ecf20Sopenharmony_ci		*width = info->pullctl->width;
2388c2ecf20Sopenharmony_ci		break;
2398c2ecf20Sopenharmony_ci	case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
2408c2ecf20Sopenharmony_ci		if (!info->st)
2418c2ecf20Sopenharmony_ci			return -EINVAL;
2428c2ecf20Sopenharmony_ci		*reg = info->st->reg;
2438c2ecf20Sopenharmony_ci		*bit = info->st->shift;
2448c2ecf20Sopenharmony_ci		*width = info->st->width;
2458c2ecf20Sopenharmony_ci		break;
2468c2ecf20Sopenharmony_ci	default:
2478c2ecf20Sopenharmony_ci		return -ENOTSUPP;
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	return 0;
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic int owl_pin_config_get(struct pinctrl_dev *pctrldev,
2548c2ecf20Sopenharmony_ci				unsigned int pin,
2558c2ecf20Sopenharmony_ci				unsigned long *config)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	int ret = 0;
2588c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
2598c2ecf20Sopenharmony_ci	const struct owl_padinfo *info;
2608c2ecf20Sopenharmony_ci	unsigned int param = pinconf_to_config_param(*config);
2618c2ecf20Sopenharmony_ci	u32 reg, bit, width, arg;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	info = &pctrl->soc->padinfo[pin];
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	ret = owl_pad_pinconf_reg(info, param, &reg, &bit, &width);
2668c2ecf20Sopenharmony_ci	if (ret)
2678c2ecf20Sopenharmony_ci		return ret;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	arg = owl_read_field(pctrl, reg, bit, width);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	if (!pctrl->soc->padctl_val2arg)
2728c2ecf20Sopenharmony_ci		return -ENOTSUPP;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	ret = pctrl->soc->padctl_val2arg(info, param, &arg);
2758c2ecf20Sopenharmony_ci	if (ret)
2768c2ecf20Sopenharmony_ci		return ret;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	*config = pinconf_to_config_packed(param, arg);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	return ret;
2818c2ecf20Sopenharmony_ci}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic int owl_pin_config_set(struct pinctrl_dev *pctrldev,
2848c2ecf20Sopenharmony_ci				unsigned int pin,
2858c2ecf20Sopenharmony_ci				unsigned long *configs,
2868c2ecf20Sopenharmony_ci				unsigned int num_configs)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
2898c2ecf20Sopenharmony_ci	const struct owl_padinfo *info;
2908c2ecf20Sopenharmony_ci	unsigned long flags;
2918c2ecf20Sopenharmony_ci	unsigned int param;
2928c2ecf20Sopenharmony_ci	u32 reg, bit, width, arg;
2938c2ecf20Sopenharmony_ci	int ret = 0, i;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	info = &pctrl->soc->padinfo[pin];
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	for (i = 0; i < num_configs; i++) {
2988c2ecf20Sopenharmony_ci		param = pinconf_to_config_param(configs[i]);
2998c2ecf20Sopenharmony_ci		arg = pinconf_to_config_argument(configs[i]);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci		ret = owl_pad_pinconf_reg(info, param, &reg, &bit, &width);
3028c2ecf20Sopenharmony_ci		if (ret)
3038c2ecf20Sopenharmony_ci			return ret;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci		if (!pctrl->soc->padctl_arg2val)
3068c2ecf20Sopenharmony_ci			return -ENOTSUPP;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci		ret = pctrl->soc->padctl_arg2val(info, param, &arg);
3098c2ecf20Sopenharmony_ci		if (ret)
3108c2ecf20Sopenharmony_ci			return ret;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci		raw_spin_lock_irqsave(&pctrl->lock, flags);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci		owl_write_field(pctrl, reg, arg, bit, width);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci		raw_spin_unlock_irqrestore(&pctrl->lock, flags);
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	return ret;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic int owl_group_pinconf_reg(const struct owl_pingroup *g,
3238c2ecf20Sopenharmony_ci				unsigned int param,
3248c2ecf20Sopenharmony_ci				u32 *reg,
3258c2ecf20Sopenharmony_ci				u32 *bit,
3268c2ecf20Sopenharmony_ci				u32 *width)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	switch (param) {
3298c2ecf20Sopenharmony_ci	case PIN_CONFIG_DRIVE_STRENGTH:
3308c2ecf20Sopenharmony_ci		if (g->drv_reg < 0)
3318c2ecf20Sopenharmony_ci			return -EINVAL;
3328c2ecf20Sopenharmony_ci		*reg = g->drv_reg;
3338c2ecf20Sopenharmony_ci		*bit = g->drv_shift;
3348c2ecf20Sopenharmony_ci		*width = g->drv_width;
3358c2ecf20Sopenharmony_ci		break;
3368c2ecf20Sopenharmony_ci	case PIN_CONFIG_SLEW_RATE:
3378c2ecf20Sopenharmony_ci		if (g->sr_reg < 0)
3388c2ecf20Sopenharmony_ci			return -EINVAL;
3398c2ecf20Sopenharmony_ci		*reg = g->sr_reg;
3408c2ecf20Sopenharmony_ci		*bit = g->sr_shift;
3418c2ecf20Sopenharmony_ci		*width = g->sr_width;
3428c2ecf20Sopenharmony_ci		break;
3438c2ecf20Sopenharmony_ci	default:
3448c2ecf20Sopenharmony_ci		return -ENOTSUPP;
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	return 0;
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_cistatic int owl_group_pinconf_arg2val(const struct owl_pingroup *g,
3518c2ecf20Sopenharmony_ci				unsigned int param,
3528c2ecf20Sopenharmony_ci				u32 *arg)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	switch (param) {
3558c2ecf20Sopenharmony_ci	case PIN_CONFIG_DRIVE_STRENGTH:
3568c2ecf20Sopenharmony_ci		switch (*arg) {
3578c2ecf20Sopenharmony_ci		case 2:
3588c2ecf20Sopenharmony_ci			*arg = OWL_PINCONF_DRV_2MA;
3598c2ecf20Sopenharmony_ci			break;
3608c2ecf20Sopenharmony_ci		case 4:
3618c2ecf20Sopenharmony_ci			*arg = OWL_PINCONF_DRV_4MA;
3628c2ecf20Sopenharmony_ci			break;
3638c2ecf20Sopenharmony_ci		case 8:
3648c2ecf20Sopenharmony_ci			*arg = OWL_PINCONF_DRV_8MA;
3658c2ecf20Sopenharmony_ci			break;
3668c2ecf20Sopenharmony_ci		case 12:
3678c2ecf20Sopenharmony_ci			*arg = OWL_PINCONF_DRV_12MA;
3688c2ecf20Sopenharmony_ci			break;
3698c2ecf20Sopenharmony_ci		default:
3708c2ecf20Sopenharmony_ci			return -EINVAL;
3718c2ecf20Sopenharmony_ci		}
3728c2ecf20Sopenharmony_ci		break;
3738c2ecf20Sopenharmony_ci	case PIN_CONFIG_SLEW_RATE:
3748c2ecf20Sopenharmony_ci		if (*arg)
3758c2ecf20Sopenharmony_ci			*arg = OWL_PINCONF_SLEW_FAST;
3768c2ecf20Sopenharmony_ci		else
3778c2ecf20Sopenharmony_ci			*arg = OWL_PINCONF_SLEW_SLOW;
3788c2ecf20Sopenharmony_ci		break;
3798c2ecf20Sopenharmony_ci	default:
3808c2ecf20Sopenharmony_ci		return -ENOTSUPP;
3818c2ecf20Sopenharmony_ci	}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	return 0;
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_cistatic int owl_group_pinconf_val2arg(const struct owl_pingroup *g,
3878c2ecf20Sopenharmony_ci				unsigned int param,
3888c2ecf20Sopenharmony_ci				u32 *arg)
3898c2ecf20Sopenharmony_ci{
3908c2ecf20Sopenharmony_ci	switch (param) {
3918c2ecf20Sopenharmony_ci	case PIN_CONFIG_DRIVE_STRENGTH:
3928c2ecf20Sopenharmony_ci		switch (*arg) {
3938c2ecf20Sopenharmony_ci		case OWL_PINCONF_DRV_2MA:
3948c2ecf20Sopenharmony_ci			*arg = 2;
3958c2ecf20Sopenharmony_ci			break;
3968c2ecf20Sopenharmony_ci		case OWL_PINCONF_DRV_4MA:
3978c2ecf20Sopenharmony_ci			*arg = 4;
3988c2ecf20Sopenharmony_ci			break;
3998c2ecf20Sopenharmony_ci		case OWL_PINCONF_DRV_8MA:
4008c2ecf20Sopenharmony_ci			*arg = 8;
4018c2ecf20Sopenharmony_ci			break;
4028c2ecf20Sopenharmony_ci		case OWL_PINCONF_DRV_12MA:
4038c2ecf20Sopenharmony_ci			*arg = 12;
4048c2ecf20Sopenharmony_ci			break;
4058c2ecf20Sopenharmony_ci		default:
4068c2ecf20Sopenharmony_ci			return -EINVAL;
4078c2ecf20Sopenharmony_ci		}
4088c2ecf20Sopenharmony_ci		break;
4098c2ecf20Sopenharmony_ci	case PIN_CONFIG_SLEW_RATE:
4108c2ecf20Sopenharmony_ci		if (*arg)
4118c2ecf20Sopenharmony_ci			*arg = 1;
4128c2ecf20Sopenharmony_ci		else
4138c2ecf20Sopenharmony_ci			*arg = 0;
4148c2ecf20Sopenharmony_ci		break;
4158c2ecf20Sopenharmony_ci	default:
4168c2ecf20Sopenharmony_ci		return -ENOTSUPP;
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	return 0;
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic int owl_group_config_get(struct pinctrl_dev *pctrldev,
4238c2ecf20Sopenharmony_ci				unsigned int group,
4248c2ecf20Sopenharmony_ci				unsigned long *config)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	const struct owl_pingroup *g;
4278c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
4288c2ecf20Sopenharmony_ci	unsigned int param = pinconf_to_config_param(*config);
4298c2ecf20Sopenharmony_ci	u32 reg, bit, width, arg;
4308c2ecf20Sopenharmony_ci	int ret;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	g = &pctrl->soc->groups[group];
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	ret = owl_group_pinconf_reg(g, param, &reg, &bit, &width);
4358c2ecf20Sopenharmony_ci	if (ret)
4368c2ecf20Sopenharmony_ci		return ret;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	arg = owl_read_field(pctrl, reg, bit, width);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	ret = owl_group_pinconf_val2arg(g, param, &arg);
4418c2ecf20Sopenharmony_ci	if (ret)
4428c2ecf20Sopenharmony_ci		return ret;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	*config = pinconf_to_config_packed(param, arg);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	return ret;
4478c2ecf20Sopenharmony_ci}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_cistatic int owl_group_config_set(struct pinctrl_dev *pctrldev,
4508c2ecf20Sopenharmony_ci				unsigned int group,
4518c2ecf20Sopenharmony_ci				unsigned long *configs,
4528c2ecf20Sopenharmony_ci				unsigned int num_configs)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	const struct owl_pingroup *g;
4558c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
4568c2ecf20Sopenharmony_ci	unsigned long flags;
4578c2ecf20Sopenharmony_ci	unsigned int param;
4588c2ecf20Sopenharmony_ci	u32 reg, bit, width, arg;
4598c2ecf20Sopenharmony_ci	int ret, i;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	g = &pctrl->soc->groups[group];
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	for (i = 0; i < num_configs; i++) {
4648c2ecf20Sopenharmony_ci		param = pinconf_to_config_param(configs[i]);
4658c2ecf20Sopenharmony_ci		arg = pinconf_to_config_argument(configs[i]);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci		ret = owl_group_pinconf_reg(g, param, &reg, &bit, &width);
4688c2ecf20Sopenharmony_ci		if (ret)
4698c2ecf20Sopenharmony_ci			return ret;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci		ret = owl_group_pinconf_arg2val(g, param, &arg);
4728c2ecf20Sopenharmony_ci		if (ret)
4738c2ecf20Sopenharmony_ci			return ret;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci		/* Update register */
4768c2ecf20Sopenharmony_ci		raw_spin_lock_irqsave(&pctrl->lock, flags);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci		owl_write_field(pctrl, reg, arg, bit, width);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci		raw_spin_unlock_irqrestore(&pctrl->lock, flags);
4818c2ecf20Sopenharmony_ci	}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	return 0;
4848c2ecf20Sopenharmony_ci}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_cistatic const struct pinconf_ops owl_pinconf_ops = {
4878c2ecf20Sopenharmony_ci	.is_generic = true,
4888c2ecf20Sopenharmony_ci	.pin_config_get = owl_pin_config_get,
4898c2ecf20Sopenharmony_ci	.pin_config_set = owl_pin_config_set,
4908c2ecf20Sopenharmony_ci	.pin_config_group_get = owl_group_config_get,
4918c2ecf20Sopenharmony_ci	.pin_config_group_set = owl_group_config_set,
4928c2ecf20Sopenharmony_ci};
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_cistatic struct pinctrl_desc owl_pinctrl_desc = {
4958c2ecf20Sopenharmony_ci	.pctlops = &owl_pinctrl_ops,
4968c2ecf20Sopenharmony_ci	.pmxops = &owl_pinmux_ops,
4978c2ecf20Sopenharmony_ci	.confops = &owl_pinconf_ops,
4988c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
4998c2ecf20Sopenharmony_ci};
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_cistatic const struct owl_gpio_port *
5028c2ecf20Sopenharmony_ciowl_gpio_get_port(struct owl_pinctrl *pctrl, unsigned int *pin)
5038c2ecf20Sopenharmony_ci{
5048c2ecf20Sopenharmony_ci	unsigned int start = 0, i;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	for (i = 0; i < pctrl->soc->nports; i++) {
5078c2ecf20Sopenharmony_ci		const struct owl_gpio_port *port = &pctrl->soc->ports[i];
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci		if (*pin >= start && *pin < start + port->pins) {
5108c2ecf20Sopenharmony_ci			*pin -= start;
5118c2ecf20Sopenharmony_ci			return port;
5128c2ecf20Sopenharmony_ci		}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci		start += port->pins;
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	return NULL;
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cistatic void owl_gpio_update_reg(void __iomem *base, unsigned int pin, int flag)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	u32 val;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	val = readl_relaxed(base);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	if (flag)
5278c2ecf20Sopenharmony_ci		val |= BIT(pin);
5288c2ecf20Sopenharmony_ci	else
5298c2ecf20Sopenharmony_ci		val &= ~BIT(pin);
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	writel_relaxed(val, base);
5328c2ecf20Sopenharmony_ci}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_cistatic int owl_gpio_request(struct gpio_chip *chip, unsigned int offset)
5358c2ecf20Sopenharmony_ci{
5368c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = gpiochip_get_data(chip);
5378c2ecf20Sopenharmony_ci	const struct owl_gpio_port *port;
5388c2ecf20Sopenharmony_ci	void __iomem *gpio_base;
5398c2ecf20Sopenharmony_ci	unsigned long flags;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	port = owl_gpio_get_port(pctrl, &offset);
5428c2ecf20Sopenharmony_ci	if (WARN_ON(port == NULL))
5438c2ecf20Sopenharmony_ci		return -ENODEV;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	gpio_base = pctrl->base + port->offset;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	/*
5488c2ecf20Sopenharmony_ci	 * GPIOs have higher priority over other modules, so either setting
5498c2ecf20Sopenharmony_ci	 * them as OUT or IN is sufficient
5508c2ecf20Sopenharmony_ci	 */
5518c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
5528c2ecf20Sopenharmony_ci	owl_gpio_update_reg(gpio_base + port->outen, offset, true);
5538c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	return 0;
5568c2ecf20Sopenharmony_ci}
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_cistatic void owl_gpio_free(struct gpio_chip *chip, unsigned int offset)
5598c2ecf20Sopenharmony_ci{
5608c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = gpiochip_get_data(chip);
5618c2ecf20Sopenharmony_ci	const struct owl_gpio_port *port;
5628c2ecf20Sopenharmony_ci	void __iomem *gpio_base;
5638c2ecf20Sopenharmony_ci	unsigned long flags;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	port = owl_gpio_get_port(pctrl, &offset);
5668c2ecf20Sopenharmony_ci	if (WARN_ON(port == NULL))
5678c2ecf20Sopenharmony_ci		return;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	gpio_base = pctrl->base + port->offset;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
5728c2ecf20Sopenharmony_ci	/* disable gpio output */
5738c2ecf20Sopenharmony_ci	owl_gpio_update_reg(gpio_base + port->outen, offset, false);
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	/* disable gpio input */
5768c2ecf20Sopenharmony_ci	owl_gpio_update_reg(gpio_base + port->inen, offset, false);
5778c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
5788c2ecf20Sopenharmony_ci}
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_cistatic int owl_gpio_get(struct gpio_chip *chip, unsigned int offset)
5818c2ecf20Sopenharmony_ci{
5828c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = gpiochip_get_data(chip);
5838c2ecf20Sopenharmony_ci	const struct owl_gpio_port *port;
5848c2ecf20Sopenharmony_ci	void __iomem *gpio_base;
5858c2ecf20Sopenharmony_ci	unsigned long flags;
5868c2ecf20Sopenharmony_ci	u32 val;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	port = owl_gpio_get_port(pctrl, &offset);
5898c2ecf20Sopenharmony_ci	if (WARN_ON(port == NULL))
5908c2ecf20Sopenharmony_ci		return -ENODEV;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	gpio_base = pctrl->base + port->offset;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
5958c2ecf20Sopenharmony_ci	val = readl_relaxed(gpio_base + port->dat);
5968c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	return !!(val & BIT(offset));
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cistatic void owl_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
6028c2ecf20Sopenharmony_ci{
6038c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = gpiochip_get_data(chip);
6048c2ecf20Sopenharmony_ci	const struct owl_gpio_port *port;
6058c2ecf20Sopenharmony_ci	void __iomem *gpio_base;
6068c2ecf20Sopenharmony_ci	unsigned long flags;
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	port = owl_gpio_get_port(pctrl, &offset);
6098c2ecf20Sopenharmony_ci	if (WARN_ON(port == NULL))
6108c2ecf20Sopenharmony_ci		return;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	gpio_base = pctrl->base + port->offset;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
6158c2ecf20Sopenharmony_ci	owl_gpio_update_reg(gpio_base + port->dat, offset, value);
6168c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
6178c2ecf20Sopenharmony_ci}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_cistatic int owl_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = gpiochip_get_data(chip);
6228c2ecf20Sopenharmony_ci	const struct owl_gpio_port *port;
6238c2ecf20Sopenharmony_ci	void __iomem *gpio_base;
6248c2ecf20Sopenharmony_ci	unsigned long flags;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	port = owl_gpio_get_port(pctrl, &offset);
6278c2ecf20Sopenharmony_ci	if (WARN_ON(port == NULL))
6288c2ecf20Sopenharmony_ci		return -ENODEV;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	gpio_base = pctrl->base + port->offset;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
6338c2ecf20Sopenharmony_ci	owl_gpio_update_reg(gpio_base + port->outen, offset, false);
6348c2ecf20Sopenharmony_ci	owl_gpio_update_reg(gpio_base + port->inen, offset, true);
6358c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	return 0;
6388c2ecf20Sopenharmony_ci}
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_cistatic int owl_gpio_direction_output(struct gpio_chip *chip,
6418c2ecf20Sopenharmony_ci				unsigned int offset, int value)
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = gpiochip_get_data(chip);
6448c2ecf20Sopenharmony_ci	const struct owl_gpio_port *port;
6458c2ecf20Sopenharmony_ci	void __iomem *gpio_base;
6468c2ecf20Sopenharmony_ci	unsigned long flags;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	port = owl_gpio_get_port(pctrl, &offset);
6498c2ecf20Sopenharmony_ci	if (WARN_ON(port == NULL))
6508c2ecf20Sopenharmony_ci		return -ENODEV;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	gpio_base = pctrl->base + port->offset;
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
6558c2ecf20Sopenharmony_ci	owl_gpio_update_reg(gpio_base + port->inen, offset, false);
6568c2ecf20Sopenharmony_ci	owl_gpio_update_reg(gpio_base + port->outen, offset, true);
6578c2ecf20Sopenharmony_ci	owl_gpio_update_reg(gpio_base + port->dat, offset, value);
6588c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	return 0;
6618c2ecf20Sopenharmony_ci}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_cistatic void irq_set_type(struct owl_pinctrl *pctrl, int gpio, unsigned int type)
6648c2ecf20Sopenharmony_ci{
6658c2ecf20Sopenharmony_ci	const struct owl_gpio_port *port;
6668c2ecf20Sopenharmony_ci	void __iomem *gpio_base;
6678c2ecf20Sopenharmony_ci	unsigned long flags;
6688c2ecf20Sopenharmony_ci	unsigned int offset, value, irq_type = 0;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	switch (type) {
6718c2ecf20Sopenharmony_ci	case IRQ_TYPE_EDGE_BOTH:
6728c2ecf20Sopenharmony_ci		/*
6738c2ecf20Sopenharmony_ci		 * Since the hardware doesn't support interrupts on both edges,
6748c2ecf20Sopenharmony_ci		 * emulate it in the software by setting the single edge
6758c2ecf20Sopenharmony_ci		 * interrupt and switching to the opposite edge while ACKing
6768c2ecf20Sopenharmony_ci		 * the interrupt
6778c2ecf20Sopenharmony_ci		 */
6788c2ecf20Sopenharmony_ci		if (owl_gpio_get(&pctrl->chip, gpio))
6798c2ecf20Sopenharmony_ci			irq_type = OWL_GPIO_INT_EDGE_FALLING;
6808c2ecf20Sopenharmony_ci		else
6818c2ecf20Sopenharmony_ci			irq_type = OWL_GPIO_INT_EDGE_RISING;
6828c2ecf20Sopenharmony_ci		break;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	case IRQ_TYPE_EDGE_RISING:
6858c2ecf20Sopenharmony_ci		irq_type = OWL_GPIO_INT_EDGE_RISING;
6868c2ecf20Sopenharmony_ci		break;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	case IRQ_TYPE_EDGE_FALLING:
6898c2ecf20Sopenharmony_ci		irq_type = OWL_GPIO_INT_EDGE_FALLING;
6908c2ecf20Sopenharmony_ci		break;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	case IRQ_TYPE_LEVEL_HIGH:
6938c2ecf20Sopenharmony_ci		irq_type = OWL_GPIO_INT_LEVEL_HIGH;
6948c2ecf20Sopenharmony_ci		break;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	case IRQ_TYPE_LEVEL_LOW:
6978c2ecf20Sopenharmony_ci		irq_type = OWL_GPIO_INT_LEVEL_LOW;
6988c2ecf20Sopenharmony_ci		break;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	default:
7018c2ecf20Sopenharmony_ci		break;
7028c2ecf20Sopenharmony_ci	}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	port = owl_gpio_get_port(pctrl, &gpio);
7058c2ecf20Sopenharmony_ci	if (WARN_ON(port == NULL))
7068c2ecf20Sopenharmony_ci		return;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	gpio_base = pctrl->base + port->offset;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	offset = (gpio < 16) ? 4 : 0;
7138c2ecf20Sopenharmony_ci	value = readl_relaxed(gpio_base + port->intc_type + offset);
7148c2ecf20Sopenharmony_ci	value &= ~(OWL_GPIO_INT_MASK << ((gpio % 16) * 2));
7158c2ecf20Sopenharmony_ci	value |= irq_type << ((gpio % 16) * 2);
7168c2ecf20Sopenharmony_ci	writel_relaxed(value, gpio_base + port->intc_type + offset);
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
7198c2ecf20Sopenharmony_ci}
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_cistatic void owl_gpio_irq_mask(struct irq_data *data)
7228c2ecf20Sopenharmony_ci{
7238c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
7248c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = gpiochip_get_data(gc);
7258c2ecf20Sopenharmony_ci	const struct owl_gpio_port *port;
7268c2ecf20Sopenharmony_ci	void __iomem *gpio_base;
7278c2ecf20Sopenharmony_ci	unsigned long flags;
7288c2ecf20Sopenharmony_ci	unsigned int gpio = data->hwirq;
7298c2ecf20Sopenharmony_ci	u32 val;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	port = owl_gpio_get_port(pctrl, &gpio);
7328c2ecf20Sopenharmony_ci	if (WARN_ON(port == NULL))
7338c2ecf20Sopenharmony_ci		return;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	gpio_base = pctrl->base + port->offset;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	owl_gpio_update_reg(gpio_base + port->intc_msk, gpio, false);
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	/* disable port interrupt if no interrupt pending bit is active */
7428c2ecf20Sopenharmony_ci	val = readl_relaxed(gpio_base + port->intc_msk);
7438c2ecf20Sopenharmony_ci	if (val == 0)
7448c2ecf20Sopenharmony_ci		owl_gpio_update_reg(gpio_base + port->intc_ctl,
7458c2ecf20Sopenharmony_ci					OWL_GPIO_CTLR_ENABLE + port->shared_ctl_offset * 5, false);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
7488c2ecf20Sopenharmony_ci}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_cistatic void owl_gpio_irq_unmask(struct irq_data *data)
7518c2ecf20Sopenharmony_ci{
7528c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
7538c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = gpiochip_get_data(gc);
7548c2ecf20Sopenharmony_ci	const struct owl_gpio_port *port;
7558c2ecf20Sopenharmony_ci	void __iomem *gpio_base;
7568c2ecf20Sopenharmony_ci	unsigned long flags;
7578c2ecf20Sopenharmony_ci	unsigned int gpio = data->hwirq;
7588c2ecf20Sopenharmony_ci	u32 value;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	port = owl_gpio_get_port(pctrl, &gpio);
7618c2ecf20Sopenharmony_ci	if (WARN_ON(port == NULL))
7628c2ecf20Sopenharmony_ci		return;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	gpio_base = pctrl->base + port->offset;
7658c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	/* enable port interrupt */
7688c2ecf20Sopenharmony_ci	value = readl_relaxed(gpio_base + port->intc_ctl);
7698c2ecf20Sopenharmony_ci	value |= ((BIT(OWL_GPIO_CTLR_ENABLE) | BIT(OWL_GPIO_CTLR_SAMPLE_CLK_24M))
7708c2ecf20Sopenharmony_ci			<< port->shared_ctl_offset * 5);
7718c2ecf20Sopenharmony_ci	writel_relaxed(value, gpio_base + port->intc_ctl);
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	/* enable GPIO interrupt */
7748c2ecf20Sopenharmony_ci	owl_gpio_update_reg(gpio_base + port->intc_msk, gpio, true);
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
7778c2ecf20Sopenharmony_ci}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_cistatic void owl_gpio_irq_ack(struct irq_data *data)
7808c2ecf20Sopenharmony_ci{
7818c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
7828c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = gpiochip_get_data(gc);
7838c2ecf20Sopenharmony_ci	const struct owl_gpio_port *port;
7848c2ecf20Sopenharmony_ci	void __iomem *gpio_base;
7858c2ecf20Sopenharmony_ci	unsigned long flags;
7868c2ecf20Sopenharmony_ci	unsigned int gpio = data->hwirq;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	/*
7898c2ecf20Sopenharmony_ci	 * Switch the interrupt edge to the opposite edge of the interrupt
7908c2ecf20Sopenharmony_ci	 * which got triggered for the case of emulating both edges
7918c2ecf20Sopenharmony_ci	 */
7928c2ecf20Sopenharmony_ci	if (irqd_get_trigger_type(data) == IRQ_TYPE_EDGE_BOTH) {
7938c2ecf20Sopenharmony_ci		if (owl_gpio_get(gc, gpio))
7948c2ecf20Sopenharmony_ci			irq_set_type(pctrl, gpio, IRQ_TYPE_EDGE_FALLING);
7958c2ecf20Sopenharmony_ci		else
7968c2ecf20Sopenharmony_ci			irq_set_type(pctrl, gpio, IRQ_TYPE_EDGE_RISING);
7978c2ecf20Sopenharmony_ci	}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	port = owl_gpio_get_port(pctrl, &gpio);
8008c2ecf20Sopenharmony_ci	if (WARN_ON(port == NULL))
8018c2ecf20Sopenharmony_ci		return;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	gpio_base = pctrl->base + port->offset;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	owl_gpio_update_reg(gpio_base + port->intc_ctl,
8088c2ecf20Sopenharmony_ci				OWL_GPIO_CTLR_PENDING + port->shared_ctl_offset * 5, true);
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
8118c2ecf20Sopenharmony_ci}
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_cistatic int owl_gpio_irq_set_type(struct irq_data *data, unsigned int type)
8148c2ecf20Sopenharmony_ci{
8158c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
8168c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = gpiochip_get_data(gc);
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
8198c2ecf20Sopenharmony_ci		irq_set_handler_locked(data, handle_level_irq);
8208c2ecf20Sopenharmony_ci	else
8218c2ecf20Sopenharmony_ci		irq_set_handler_locked(data, handle_edge_irq);
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	irq_set_type(pctrl, data->hwirq, type);
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	return 0;
8268c2ecf20Sopenharmony_ci}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_cistatic void owl_gpio_irq_handler(struct irq_desc *desc)
8298c2ecf20Sopenharmony_ci{
8308c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl = irq_desc_get_handler_data(desc);
8318c2ecf20Sopenharmony_ci	struct irq_chip *chip = irq_desc_get_chip(desc);
8328c2ecf20Sopenharmony_ci	struct irq_domain *domain = pctrl->chip.irq.domain;
8338c2ecf20Sopenharmony_ci	unsigned int parent = irq_desc_get_irq(desc);
8348c2ecf20Sopenharmony_ci	const struct owl_gpio_port *port;
8358c2ecf20Sopenharmony_ci	void __iomem *base;
8368c2ecf20Sopenharmony_ci	unsigned int pin, irq, offset = 0, i;
8378c2ecf20Sopenharmony_ci	unsigned long pending_irq;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	chained_irq_enter(chip, desc);
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	for (i = 0; i < pctrl->soc->nports; i++) {
8428c2ecf20Sopenharmony_ci		port = &pctrl->soc->ports[i];
8438c2ecf20Sopenharmony_ci		base = pctrl->base + port->offset;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci		/* skip ports that are not associated with this irq */
8468c2ecf20Sopenharmony_ci		if (parent != pctrl->irq[i])
8478c2ecf20Sopenharmony_ci			goto skip;
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci		pending_irq = readl_relaxed(base + port->intc_pd);
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci		for_each_set_bit(pin, &pending_irq, port->pins) {
8528c2ecf20Sopenharmony_ci			irq = irq_find_mapping(domain, offset + pin);
8538c2ecf20Sopenharmony_ci			generic_handle_irq(irq);
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci			/* clear pending interrupt */
8568c2ecf20Sopenharmony_ci			owl_gpio_update_reg(base + port->intc_pd, pin, true);
8578c2ecf20Sopenharmony_ci		}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ciskip:
8608c2ecf20Sopenharmony_ci		offset += port->pins;
8618c2ecf20Sopenharmony_ci	}
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	chained_irq_exit(chip, desc);
8648c2ecf20Sopenharmony_ci}
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_cistatic int owl_gpio_init(struct owl_pinctrl *pctrl)
8678c2ecf20Sopenharmony_ci{
8688c2ecf20Sopenharmony_ci	struct gpio_chip *chip;
8698c2ecf20Sopenharmony_ci	struct gpio_irq_chip *gpio_irq;
8708c2ecf20Sopenharmony_ci	int ret, i, j, offset;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	chip = &pctrl->chip;
8738c2ecf20Sopenharmony_ci	chip->base = -1;
8748c2ecf20Sopenharmony_ci	chip->ngpio = pctrl->soc->ngpios;
8758c2ecf20Sopenharmony_ci	chip->label = dev_name(pctrl->dev);
8768c2ecf20Sopenharmony_ci	chip->parent = pctrl->dev;
8778c2ecf20Sopenharmony_ci	chip->owner = THIS_MODULE;
8788c2ecf20Sopenharmony_ci	chip->of_node = pctrl->dev->of_node;
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	pctrl->irq_chip.name = chip->of_node->name;
8818c2ecf20Sopenharmony_ci	pctrl->irq_chip.irq_ack = owl_gpio_irq_ack;
8828c2ecf20Sopenharmony_ci	pctrl->irq_chip.irq_mask = owl_gpio_irq_mask;
8838c2ecf20Sopenharmony_ci	pctrl->irq_chip.irq_unmask = owl_gpio_irq_unmask;
8848c2ecf20Sopenharmony_ci	pctrl->irq_chip.irq_set_type = owl_gpio_irq_set_type;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	gpio_irq = &chip->irq;
8878c2ecf20Sopenharmony_ci	gpio_irq->chip = &pctrl->irq_chip;
8888c2ecf20Sopenharmony_ci	gpio_irq->handler = handle_simple_irq;
8898c2ecf20Sopenharmony_ci	gpio_irq->default_type = IRQ_TYPE_NONE;
8908c2ecf20Sopenharmony_ci	gpio_irq->parent_handler = owl_gpio_irq_handler;
8918c2ecf20Sopenharmony_ci	gpio_irq->parent_handler_data = pctrl;
8928c2ecf20Sopenharmony_ci	gpio_irq->num_parents = pctrl->num_irq;
8938c2ecf20Sopenharmony_ci	gpio_irq->parents = pctrl->irq;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	gpio_irq->map = devm_kcalloc(pctrl->dev, chip->ngpio,
8968c2ecf20Sopenharmony_ci				sizeof(*gpio_irq->map), GFP_KERNEL);
8978c2ecf20Sopenharmony_ci	if (!gpio_irq->map)
8988c2ecf20Sopenharmony_ci		return -ENOMEM;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	for (i = 0, offset = 0; i < pctrl->soc->nports; i++) {
9018c2ecf20Sopenharmony_ci		const struct owl_gpio_port *port = &pctrl->soc->ports[i];
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci		for (j = 0; j < port->pins; j++)
9048c2ecf20Sopenharmony_ci			gpio_irq->map[offset + j] = gpio_irq->parents[i];
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci		offset += port->pins;
9078c2ecf20Sopenharmony_ci	}
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	ret = gpiochip_add_data(&pctrl->chip, pctrl);
9108c2ecf20Sopenharmony_ci	if (ret) {
9118c2ecf20Sopenharmony_ci		dev_err(pctrl->dev, "failed to register gpiochip\n");
9128c2ecf20Sopenharmony_ci		return ret;
9138c2ecf20Sopenharmony_ci	}
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	return 0;
9168c2ecf20Sopenharmony_ci}
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ciint owl_pinctrl_probe(struct platform_device *pdev,
9198c2ecf20Sopenharmony_ci				struct owl_pinctrl_soc_data *soc_data)
9208c2ecf20Sopenharmony_ci{
9218c2ecf20Sopenharmony_ci	struct owl_pinctrl *pctrl;
9228c2ecf20Sopenharmony_ci	int ret, i;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
9258c2ecf20Sopenharmony_ci	if (!pctrl)
9268c2ecf20Sopenharmony_ci		return -ENOMEM;
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	pctrl->base = devm_platform_ioremap_resource(pdev, 0);
9298c2ecf20Sopenharmony_ci	if (IS_ERR(pctrl->base))
9308c2ecf20Sopenharmony_ci		return PTR_ERR(pctrl->base);
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	/* enable GPIO/MFP clock */
9338c2ecf20Sopenharmony_ci	pctrl->clk = devm_clk_get(&pdev->dev, NULL);
9348c2ecf20Sopenharmony_ci	if (IS_ERR(pctrl->clk)) {
9358c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "no clock defined\n");
9368c2ecf20Sopenharmony_ci		return PTR_ERR(pctrl->clk);
9378c2ecf20Sopenharmony_ci	}
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(pctrl->clk);
9408c2ecf20Sopenharmony_ci	if (ret) {
9418c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "clk enable failed\n");
9428c2ecf20Sopenharmony_ci		return ret;
9438c2ecf20Sopenharmony_ci	}
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	raw_spin_lock_init(&pctrl->lock);
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	owl_pinctrl_desc.name = dev_name(&pdev->dev);
9488c2ecf20Sopenharmony_ci	owl_pinctrl_desc.pins = soc_data->pins;
9498c2ecf20Sopenharmony_ci	owl_pinctrl_desc.npins = soc_data->npins;
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	pctrl->chip.direction_input  = owl_gpio_direction_input;
9528c2ecf20Sopenharmony_ci	pctrl->chip.direction_output = owl_gpio_direction_output;
9538c2ecf20Sopenharmony_ci	pctrl->chip.get = owl_gpio_get;
9548c2ecf20Sopenharmony_ci	pctrl->chip.set = owl_gpio_set;
9558c2ecf20Sopenharmony_ci	pctrl->chip.request = owl_gpio_request;
9568c2ecf20Sopenharmony_ci	pctrl->chip.free = owl_gpio_free;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	pctrl->soc = soc_data;
9598c2ecf20Sopenharmony_ci	pctrl->dev = &pdev->dev;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	pctrl->pctrldev = devm_pinctrl_register(&pdev->dev,
9628c2ecf20Sopenharmony_ci					&owl_pinctrl_desc, pctrl);
9638c2ecf20Sopenharmony_ci	if (IS_ERR(pctrl->pctrldev)) {
9648c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "could not register Actions OWL pinmux driver\n");
9658c2ecf20Sopenharmony_ci		ret = PTR_ERR(pctrl->pctrldev);
9668c2ecf20Sopenharmony_ci		goto err_exit;
9678c2ecf20Sopenharmony_ci	}
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	ret = platform_irq_count(pdev);
9708c2ecf20Sopenharmony_ci	if (ret < 0)
9718c2ecf20Sopenharmony_ci		goto err_exit;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	pctrl->num_irq = ret;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	pctrl->irq = devm_kcalloc(&pdev->dev, pctrl->num_irq,
9768c2ecf20Sopenharmony_ci					sizeof(*pctrl->irq), GFP_KERNEL);
9778c2ecf20Sopenharmony_ci	if (!pctrl->irq) {
9788c2ecf20Sopenharmony_ci		ret = -ENOMEM;
9798c2ecf20Sopenharmony_ci		goto err_exit;
9808c2ecf20Sopenharmony_ci	}
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	for (i = 0; i < pctrl->num_irq ; i++) {
9838c2ecf20Sopenharmony_ci		ret = platform_get_irq(pdev, i);
9848c2ecf20Sopenharmony_ci		if (ret < 0)
9858c2ecf20Sopenharmony_ci			goto err_exit;
9868c2ecf20Sopenharmony_ci		pctrl->irq[i] = ret;
9878c2ecf20Sopenharmony_ci	}
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	ret = owl_gpio_init(pctrl);
9908c2ecf20Sopenharmony_ci	if (ret)
9918c2ecf20Sopenharmony_ci		goto err_exit;
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, pctrl);
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	return 0;
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_cierr_exit:
9988c2ecf20Sopenharmony_ci	clk_disable_unprepare(pctrl->clk);
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	return ret;
10018c2ecf20Sopenharmony_ci}
1002