/*
* Spreadtrum pin controller driver
* Copyright (C) 2017 Spreadtrum - http://www.spreadtrum.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include <linux/debugfs.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/slab.h>
#include "../core.h"
#include "../pinmux.h"
#include "../pinconf.h"
#include "../pinctrl-utils.h"
#include "pinctrl-sprd.h"
#define PINCTRL_BIT_MASK(width) (~(~0UL << (width)))
#define PINCTRL_REG_OFFSET 0x20
#define PINCTRL_REG_MISC_OFFSET 0x4020
#define PINCTRL_REG_LEN 0x4
#define PIN_FUNC_MASK (BIT(4) | BIT(5))
#define PIN_FUNC_SEL_1 ~PIN_FUNC_MASK
#define PIN_FUNC_SEL_2 BIT(4)
#define PIN_FUNC_SEL_3 BIT(5)
#define PIN_FUNC_SEL_4 PIN_FUNC_MASK
#define AP_SLEEP_MODE BIT(13)
#define PUBCP_SLEEP_MODE BIT(14)
#define TGLDSP_SLEEP_MODE BIT(15)
#define AGDSP_SLEEP_MODE BIT(16)
#define SLEEP_MODE_MASK GENMASK(3, 0)
#define SLEEP_MODE_SHIFT 13
#define SLEEP_INPUT BIT(1)
#define SLEEP_INPUT_MASK 0x1
#define SLEEP_INPUT_SHIFT 1
#define SLEEP_OUTPUT BIT(0)
#define SLEEP_OUTPUT_MASK 0x1
#define SLEEP_OUTPUT_SHIFT 0
#define DRIVE_STRENGTH_MASK GENMASK(3, 0)
#define DRIVE_STRENGTH_SHIFT 19
#define SLEEP_PULL_DOWN BIT(2)
#define SLEEP_PULL_DOWN_MASK 0x1
#define SLEEP_PULL_DOWN_SHIFT 2
#define PULL_DOWN BIT(6)
#define PULL_DOWN_MASK 0x1
#define PULL_DOWN_SHIFT 6
#define SLEEP_PULL_UP BIT(3)
#define SLEEP_PULL_UP_MASK 0x1
#define SLEEP_PULL_UP_SHIFT 3
#define PULL_UP_20K (BIT(12) | BIT(7))
#define PULL_UP_4_7K BIT(12)
#define PULL_UP_MASK 0x21
#define PULL_UP_SHIFT 7
#define INPUT_SCHMITT BIT(11)
#define INPUT_SCHMITT_MASK 0x1
#define INPUT_SCHMITT_SHIFT 11
enum pin_sleep_mode {
AP_SLEEP = BIT(0),
PUBCP_SLEEP = BIT(1),
TGLDSP_SLEEP = BIT(2),
AGDSP_SLEEP = BIT(3),
};
enum pin_func_sel {
PIN_FUNC_1,
PIN_FUNC_2,
PIN_FUNC_3,
PIN_FUNC_4,
PIN_FUNC_MAX,
};
/**
* struct sprd_pin: represent one pin's description
* @name: pin name
* @number: pin number
* @type: pin type, can be GLOBAL_CTRL_PIN/COMMON_PIN/MISC_PIN
* @reg: pin register address
* @bit_offset: bit offset in pin register
* @bit_width: bit width in pin register
*/
struct sprd_pin {
const char *name;
unsigned int number;
enum pin_type type;
unsigned long reg;
unsigned long bit_offset;
unsigned long bit_width;
};
/**
* struct sprd_pin_group: represent one group's description
* @name: group name
* @npins: pin numbers of this group
* @pins: pointer to pins array
*/
struct sprd_pin_group {
const char *name;
unsigned int npins;
unsigned int *pins;
};
/**
* struct sprd_pinctrl_soc_info: represent the SoC's pins description
* @groups: pointer to groups of pins
* @ngroups: group numbers of the whole SoC
* @pins: pointer to pins description
* @npins: pin numbers of the whole SoC
* @grp_names: pointer to group names array
*/
struct sprd_pinctrl_soc_info {
struct sprd_pin_group *groups;
unsigned int ngroups;
struct sprd_pin *pins;
unsigned int npins;
const char **grp_names;
};
/**
* struct sprd_pinctrl: represent the pin controller device
* @dev: pointer to the device structure
* @pctl: pointer to the pinctrl handle
* @base: base address of the controller
* @info: pointer to SoC's pins description information
*/
struct sprd_pinctrl {
struct device *dev;
struct pinctrl_dev *pctl;
void __iomem *base;
struct sprd_pinctrl_soc_info *info;
};
enum sprd_pinconf_params {
SPRD_PIN_CONFIG_CONTROL = PIN_CONFIG_END + 1,
SPRD_PIN_CONFIG_SLEEP_MODE = PIN_CONFIG_END + 2,
};
static int sprd_pinctrl_get_id_by_name(struct sprd_pinctrl *sprd_pctl,
const char *name)
{
struct sprd_pinctrl_soc_info *info = sprd_pctl->info;
int i;
for (i = 0; i < info->npins; i++) {
if (!strcmp(info->pins[i].name, name))
return info->pins[i].number;
}
return -ENODEV;
}
static struct sprd_pin *
sprd_pinctrl_get_pin_by_id(struct sprd_pinctrl *sprd_pctl, unsigned int id)
{
struct sprd_pinctrl_soc_info *info = sprd_pctl->info;
struct sprd_pin *pin = NULL;
int i;
for (i = 0; i < info->npins; i++) {
if