// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) ST-Ericsson SA 2013
*
* Author: Patrice Chotard <patrice.chotard@st.com>
*
* Driver allows to use AxB5xx unused pins to be used as GPIO
*/
#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/machine.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 "../pinconf.h"
#include "../pinctrl-utils.h"
#include "pinctrl-abx500.h"
/*
* GPIO registers offset
* Bank: 0x10
*/
#define AB8500_GPIO_SEL1_REG 0x00
#define AB8500_GPIO_SEL2_REG 0x01
#define AB8500_GPIO_SEL3_REG 0x02
#define AB8500_GPIO_SEL4_REG 0x03
#define AB8500_GPIO_SEL5_REG 0x04
#define AB8500_GPIO_SEL6_REG 0x05
#define AB8500_GPIO_DIR1_REG 0x10
#define AB8500_GPIO_DIR2_REG 0x11
#define AB8500_GPIO_DIR3_REG 0x12
#define AB8500_GPIO_DIR4_REG 0x13
#define AB8500_GPIO_DIR5_REG 0x14
#define AB8500_GPIO_DIR6_REG 0x15
#define AB8500_GPIO_OUT1_REG 0x20
#define AB8500_GPIO_OUT2_REG 0x21
#define AB8500_GPIO_OUT3_REG 0x22
#define AB8500_GPIO_OUT4_REG 0x23
#define AB8500_GPIO_OUT5_REG 0x24
#define AB8500_GPIO_OUT6_REG 0x25
#define AB8500_GPIO_PUD1_REG 0x30
#define AB8500_GPIO_PUD2_REG 0x31
#define AB8500_GPIO_PUD3_REG 0x32
#define AB8500_GPIO_PUD4_REG 0x33
#define AB8500_GPIO_PUD5_REG 0x34
#define AB8500_GPIO_PUD6_REG 0x35
#define AB8500_GPIO_IN1_REG 0x40
#define AB8500_GPIO_IN2_REG 0x41
#define AB8500_GPIO_IN3_REG 0x42
#define AB8500_GPIO_IN4_REG 0x43
#define AB8500_GPIO_IN5_REG 0x44
#define AB8500_GPIO_IN6_REG 0x45
#define AB8500_GPIO_ALTFUN_REG 0x50
#define ABX500_GPIO_INPUT 0
#define ABX500_GPIO_OUTPUT 1
struct abx500_pinctrl {
struct device *dev;
struct pinctrl_dev *pctldev;
struct abx500_pinctrl_soc_data *soc;
struct gpio_chip chip;
struct ab8500 *parent;
struct abx500_gpio_irq_cluster *irq_cluster;
int irq_cluster_size;
};
static int abx500_gpio_get_bit(struct gpio_chip *chip, u8 reg,
unsigned offset, bool *bit)
{
struct abx500_pinctrl *pct = gpiochip_get_data(chip);
u8 pos = offset % 8;
u8 val;
int ret;
reg += offset / 8;
ret = abx500_get_register_interruptible(pct->dev,
AB8500_MISC, reg, &val);
if (ret < 0) {
dev_err(pct->dev,
"%s read reg =%x, offset=%x failed (%d)\n",
__func__, reg, offset, ret);
return ret;
}
*bit = !!(val & BIT(pos));
return 0;
}
static int abx500_gpio_set_bits(struct gpio_chip *chip, u8 reg,
unsigned offset, int val)
{
struct abx500_pinctrl *pct = gpiochip_get_data(chip);
u8 pos = offset % 8;
int ret;
reg += offset / 8;
ret = abx500_mask_and_set_register_interruptible(pct->dev,
AB8500_MISC, reg, BIT(pos), val << pos);
if (ret < 0)
dev_err(pct->dev, "%s write reg, %x offset %x failed (%d)\n",
__func__, reg, offset, ret);
return ret;
}
/**
* abx500_gpio_get() - Get the particular GPIO value
* @chip: Gpio device
* @offset: GPIO number to read
*/
static int abx500_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct abx500_pinctrl *pct = gpiochip_get_data(chip);
bool bit;
bool is_out;
u8 gpio_offset = offset - 1;
int ret;
ret = abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG,
gpio_offset, &is_out);
if (ret < 0)
goto out;
if (is_out)
ret = abx500_gpio_get_bit(chip, AB8500_GPIO_OUT1_REG,
gpio_offset, &bit);
else
ret = abx500_gpio_get_bit(chip, AB8500_GPIO_IN1_REG,
gpio_offset, &bit);
out:
if (ret < 0) {
dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
return ret;
}
return bit;
}
static void abx500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
{
struct abx500_pinctrl *pct = gpiochip_get_data(chip);
int ret;
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val);
if (ret < 0)
dev_err(pct->dev, "%s write failed (%d)\n", __func__, ret);
}
static int abx500_gpio_direction_output(struct gpio_chip *chip,
unsigned offset,
int val)
{
struct abx500_pinctrl *pct = gpiochip_get_data(chip);
int ret;
/* set direction as output */
ret = abx500_gpio_set_bits(chip,
AB8500_GPIO_DIR1_REG,
offset