// SPDX-License-Identifier: GPL-2.0
/*
* ZynqMP pin controller
*
* Copyright (C) 2020, 2021 Xilinx, Inc.
*
* Sai Krishna Potthuri <lakshmi.sai.krishna.potthuri@xilinx.com>
* Rajan Vaja <rajan.vaja@xilinx.com>
*/
#include <dt-bindings/pinctrl/pinctrl-zynqmp.h>
#include <linux/bitfield.h>
#include <linux/bitmap.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/firmware/xlnx-zynqmp.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include "core.h"
#include "pinctrl-utils.h"
#define ZYNQMP_PIN_PREFIX "MIO"
#define PINCTRL_GET_FUNC_NAME_RESP_LEN 16
#define MAX_FUNC_NAME_LEN 16
#define MAX_GROUP_PIN 50
#define MAX_PIN_GROUPS 50
#define END_OF_FUNCTIONS "END_OF_FUNCTIONS"
#define NUM_GROUPS_PER_RESP 6
#define PINCTRL_GET_FUNC_GROUPS_RESP_LEN 12
#define PINCTRL_GET_PIN_GROUPS_RESP_LEN 12
#define NA_GROUP 0xFFFF
#define RESERVED_GROUP 0xFFFE
#define DRIVE_STRENGTH_2MA 2
#define DRIVE_STRENGTH_4MA 4
#define DRIVE_STRENGTH_8MA 8
#define DRIVE_STRENGTH_12MA 12
#define VERSAL_LPD_PIN_PREFIX "LPD_MIO"
#define VERSAL_PMC_PIN_PREFIX "PMC_MIO"
#define VERSAL_PINCTRL_ATTR_NODETYPE_MASK GENMASK(19, 14)
#define VERSAL_PINCTRL_NODETYPE_LPD_MIO BIT(0)
/**
* struct zynqmp_pmux_function - a pinmux function
* @name: Name of the pin mux function
* @groups: List of pin groups for this function
* @ngroups: Number of entries in @groups
*
* This structure holds information about pin control function
* and function group names supporting that function.
*/
struct zynqmp_pmux_function {
char name[MAX_FUNC_NAME_LEN];
const char * const *groups;
unsigned int ngroups;
};
/**
* struct zynqmp_pinctrl - driver data
* @pctrl: Pin control device
* @groups: Pin groups
* @ngroups: Number of @groups
* @funcs: Pin mux functions
* @nfuncs: Number of @funcs
*
* This struct is stored as driver data and used to retrieve
* information regarding pin control functions, groups and
* group pins.
*/
struct zynqmp_pinctrl {
struct pinctrl_dev *pctrl;
const struct zynqmp_pctrl_group *groups;
unsigned int ngroups;
const struct zynqmp_pmux_function *funcs;
unsigned int nfuncs;
};
/**
* struct zynqmp_pctrl_group - Pin control group info
* @name: Group name
* @pins: Group pin numbers
* @npins: Number of pins in the group
*/
struct zynqmp_pctrl_group {
const char *name;
unsigned int pins[MAX_GROUP_PIN];
unsigned int npins;
};
static struct pinctrl_desc zynqmp_desc;
static u32 family_code;
static int zynqmp_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
{
struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
return pctrl->ngroups + zynqmp_desc.npins;
}
static const char *zynqmp_pctrl_get_group_name(struct pinctrl_dev *pctldev,
unsigned int selector)
{
struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
if (selector < pctrl->ngroups)
return pctrl->groups[selector].name;
return zynqmp_desc.pins[selector - pctrl->ngroups].name;
}
static int zynqmp_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
unsigned int selector,
const unsigned int **pins,
unsigned int *npins)
{
struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
if (selector < pctrl->ngroups) {
*pins = pctrl->groups[selector].pins;
*npins = pctrl->groups[selector].npins;
} else {
*pins = &zynqmp_desc.pins[selector - pctrl->ngroups].number;
*npins = 1;
}
return 0;
}
static const struct pinctrl_ops zynqmp_pctrl_ops = {
.get_groups_count = zynqmp_pctrl_get_groups_count,
.get_group_name = zynqmp_pctrl_get_group_name,
.get_group_pins = zynqmp_pctrl_get_group_pins,
.dt_node_to_map = pinconf_generic_dt_node_to_map_all,
.dt_free_map = pinctrl_utils_free_map,
};
static int zynqmp_pinmux_request_pin(struct pinctrl_dev *pctldev,
unsigned int pin)
{
int ret;
ret = zynqmp_pm_pinctrl_request(pin);
if (ret) {
dev_err(pctldev->dev, "request failed for pin %u\n", pin);
return ret;
}
return 0;
}
static int zynqmp_pmux_get_functions_count(struct pinctrl_dev *pctldev)
{
struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
return pctrl->nfuncs;
}
static const char *zynqmp_pmux_get_function_name(struct pinctrl_dev *pctldev,
unsigned int selector)
{
struct zynqmp_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
return pctrl->funcs[selector].name;
}
/**
* zynqmp_pmux_get_function_groups() - Get groups for the function
* @pctldev: Pincontrol device pointer.
* @selector: Function ID
* @groups: Group names.
* @num_groups: Number of function groups.
*
* Get function's group count and group names.
*
* Return: 0
*/
static int zynqmp_pmux_get_function_groups(struct pinctrl_dev *pctldev,
unsigned int selector,
const