// SPDX-License-Identifier: GPL-2.0+
/*
* OWL SoC's Pinctrl driver
*
* Copyright (c) 2014 Actions Semi Inc.
* Author: David Liu <liuwei@actions-semi.com>
*
* Copyright (c) 2018 Linaro Ltd.
* Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
*/
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include "../core.h"
#include "../pinctrl-utils.h"
#include "pinctrl-owl.h"
/**
* struct owl_pinctrl - pinctrl state of the device
* @dev: device handle
* @pctrldev: pinctrl handle
* @chip: gpio chip
* @lock: spinlock to protect registers
* @clk: clock control
* @soc: reference to soc_data
* @base: pinctrl register base address
* @irq_chip: IRQ chip information
* @num_irq: number of possible interrupts
* @irq: interrupt numbers
*/
struct owl_pinctrl {
struct device *dev;
struct pinctrl_dev *pctrldev;
struct gpio_chip chip;
raw_spinlock_t lock;
struct clk *clk;
const struct owl_pinctrl_soc_data *soc;
void __iomem *base;
struct irq_chip irq_chip;
unsigned int num_irq;
unsigned int *irq;
};
static void owl_update_bits(void __iomem *base, u32 mask, u32 val)
{
u32 reg_val;
reg_val = readl_relaxed(base);
reg_val = (reg_val & ~mask) | (val & mask);
writel_relaxed(reg_val, base);
}
static u32 owl_read_field(struct owl_pinctrl *pctrl, u32 reg,
u32 bit, u32 width)
{
u32 tmp, mask;
tmp = readl_relaxed(pctrl->base + reg);
mask = (1 << width) - 1;
return (tmp >> bit) & mask;
}
static void owl_write_field(struct owl_pinctrl *pctrl, u32 reg, u32 arg,
u32 bit, u32 width)
{
u32 mask;
mask = (1 << width) - 1;
mask = mask << bit;
owl_update_bits(pctrl->base + reg, mask, (arg << bit));
}
static int owl_get_groups_count(struct pinctrl_dev *pctrldev)
{
struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
return pctrl->soc->ngroups;
}
static const char *owl_get_group_name(struct pinctrl_dev *pctrldev,
unsigned int group)
{
struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
return pctrl->soc->groups[group].name;
}
static int owl_get_group_pins(struct pinctrl_dev *pctrldev,
unsigned int group,
const unsigned int **pins,
unsigned int *num_pins)
{
struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
*pins = pctrl->soc->groups[group].pads;
*num_pins = pctrl->soc->groups[group].npads;
return 0;
}
static void owl_pin_dbg_show(struct pinctrl_dev *pctrldev,
struct seq_file *s,
unsigned int offset)
{
struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
seq_printf(s, "%s", dev_name(pctrl->dev));
}
static const struct pinctrl_ops owl_pinctrl_ops = {
.get_groups_count = owl_get_groups_count,
.get_group_name = owl_get_group_name,
.get_group_pins = owl_get_group_pins,
.pin_dbg_show = owl_pin_dbg_show,
.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
.dt_free_map = pinctrl_utils_free_map,
};
static int owl_get_funcs_count(struct pinctrl_dev *pctrldev)
{
struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
return pctrl->soc->nfunctions;
}
static const char *owl_get_func_name(struct pinctrl_dev *pctrldev,
unsigned int function)
{
struct owl_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
return pctrl->soc->functions[function].name;
}
static int owl_get_func_groups(struct pinctrl_dev *pctrldev,
unsigned