// SPDX-License-Identifier: GPL-2.0
/*
* Lochnagar pin and GPIO control
*
* Copyright (c) 2017-2018 Cirrus Logic, Inc. and
* Cirrus Logic International Semiconductor Ltd.
*
* Author: Charles Keepax <ckeepax@opensource.cirrus.com>
*/
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/mfd/lochnagar.h>
#include <linux/mfd/lochnagar1_regs.h>
#include <linux/mfd/lochnagar2_regs.h>
#include <dt-bindings/pinctrl/lochnagar.h>
#include "../pinctrl-utils.h"
#define LN2_NUM_GPIO_CHANNELS 16
#define LN_CDC_AIF1_STR "codec-aif1"
#define LN_CDC_AIF2_STR "codec-aif2"
#define LN_CDC_AIF3_STR "codec-aif3"
#define LN_DSP_AIF1_STR "dsp-aif1"
#define LN_DSP_AIF2_STR "dsp-aif2"
#define LN_PSIA1_STR "psia1"
#define LN_PSIA2_STR "psia2"
#define LN_GF_AIF1_STR "gf-aif1"
#define LN_GF_AIF2_STR "gf-aif2"
#define LN_GF_AIF3_STR "gf-aif3"
#define LN_GF_AIF4_STR "gf-aif4"
#define LN_SPDIF_AIF_STR "spdif-aif"
#define LN_USB_AIF1_STR "usb-aif1"
#define LN_USB_AIF2_STR "usb-aif2"
#define LN_ADAT_AIF_STR "adat-aif"
#define LN_SOUNDCARD_AIF_STR "soundcard-aif"
#define LN_PIN_GPIO(REV, ID, NAME, REG, SHIFT, INVERT) \
static const struct lochnagar_pin lochnagar##REV##_##ID##_pin = { \
.name = NAME, .type = LN_PTYPE_GPIO, .reg = LOCHNAGAR##REV##_##REG, \
.shift = LOCHNAGAR##REV##_##SHIFT##_SHIFT, .invert = INVERT, \
}
#define LN_PIN_SAIF(REV, ID, NAME) \
static const struct lochnagar_pin lochnagar##REV##_##ID##_pin = \
{ .name = NAME, .type = LN_PTYPE_AIF, }
#define LN_PIN_AIF(REV, ID) \
LN_PIN_SAIF(REV, ID##_BCLK, LN_##ID##_STR"-bclk"); \
LN_PIN_SAIF(REV, ID##_LRCLK, LN_##ID##_STR"-lrclk"); \
LN_PIN_SAIF(REV, ID##_RXDAT, LN_##ID##_STR"-rxdat"); \
LN_PIN_SAIF(REV, ID##_TXDAT, LN_##ID##_STR"-txdat")
#define LN1_PIN_GPIO(ID, NAME, REG, SHIFT, INVERT) \
LN_PIN_GPIO(1, ID, NAME, REG, SHIFT, INVERT)
#define LN1_PIN_MUX(ID, NAME) \
static const struct lochnagar_pin lochnagar1_##ID##_pin = \
{ .name = NAME, .type = LN_PTYPE_MUX, .reg = LOCHNAGAR1_##ID, }
#define LN1_PIN_AIF(ID) LN_PIN_AIF(1, ID)
#define LN2_PIN_GPIO(ID, NAME, REG, SHIFT, INVERT) \
LN_PIN_GPIO(2, ID, NAME, REG, SHIFT, INVERT)
#define LN2_PIN_MUX(ID, NAME) \
static const struct lochnagar_pin lochnagar2_##ID##_pin = \
{ .name = NAME, .type = LN_PTYPE_MUX, .reg = LOCHNAGAR2_GPIO_##ID, }
#define LN2_PIN_AIF(ID) LN_PIN_AIF(2, ID)
#define LN2_PIN_GAI(ID) \
LN2_PIN_MUX(ID##_BCLK, LN_##ID##_STR"-bclk"); \
LN2_PIN_MUX(ID##_LRCLK, LN_##ID##_STR"-lrclk"); \
LN2_PIN_MUX(ID##_RXDAT, LN_##ID##_STR"-rxdat"); \
LN2_PIN_MUX(ID##_TXDAT, LN_##ID##_STR"-txdat")
#define LN_PIN(REV, ID) [LOCHNAGAR##REV##_PIN_##ID] = { \
.number = LOCHNAGAR##REV##_PIN_##ID, \
.name = lochnagar##REV##_##ID##_pin.name, \
.drv_data = (void *)&lochnagar##REV##_##ID##_pin, \
}
#define LN1_PIN(ID) LN_PIN(1, ID)
#define LN2_PIN(ID) LN_PIN(2, ID)
#define LN_PINS(REV, ID) \
LN_PIN(REV, ID##_BCLK), LN_PIN(REV, ID##_LRCLK), \
LN_PIN(REV, ID##_RXDAT), LN_PIN(REV, ID##_TXDAT)
#define LN1_PINS(ID) LN_PINS(1, ID)
#define LN2_PINS(ID) LN_PINS(2, ID)
enum {
LOCHNAGAR1_PIN_GF_GPIO2 = LOCHNAGAR1_PIN_NUM_GPIOS,
LOCHNAGAR1_PIN_GF_GPIO3,
LOCHNAGAR1_PIN_GF_GPIO7,
LOCHNAGAR1_PIN_LED1,
LOCHNAGAR1_PIN_LED2,
LOCHNAGAR1_PIN_CDC_AIF1_BCLK,
LOCHNAGAR1_PIN_CDC_AIF1_LRCLK,
LOCHNAGAR1_PIN_CDC_AIF1_RXDAT,
LOCHNAGAR1_PIN_CDC_AIF1_TXDAT,
LOCHNAGAR1_PIN_CDC_AIF2_BCLK,
LOCHNAGAR1_PIN_CDC_AIF2_LRCLK,
LOCHNAGAR1_PIN_CDC_AIF2_RXDAT,
LOCHNAGAR1_PIN_CDC_AIF2_TXDAT,
LOCHNAGAR1_PIN_CDC_AIF3_BCLK,
LOCHNAGAR1_PIN_CDC_AIF3_LRCLK,
LOCHNAGAR1_PIN_CDC_AIF3_RXDAT,
LOCHNAGAR1_PIN_CDC_AIF3_TXDAT,
LOCHNAGAR1_PIN_DSP_AIF1_BCLK,
LOCHNAGAR1_PIN_DSP_AIF1_LRCLK,
LOCHNAGAR1_PIN_DSP_AIF1_RXDAT,
LOCHNAGAR1_PIN_DSP_AIF1_TXDAT,
LOCHNAGAR1_PIN_DSP_AIF2_BCLK,
LOCHNAGAR1_PIN_DSP_AIF2_LRCLK,
LOCHNAGAR1_PIN_DSP_AIF2_RXDAT,
LOCHNAGAR1_PIN_DSP_AIF2_TXDAT,
LOCHNAGAR1_PIN_PSIA1_BCLK,
LOCHNAGAR1_PIN_PSIA1_LRCLK,
LOCHNAGAR1_PIN_PSIA1_RXDAT,
LOCHNAGAR1_PIN_PSIA1_TXDAT,
LOCHNAGAR1_PIN_PSIA2_BCLK,
LOCHNAGAR1_PIN_PSIA2_LRCLK,
LOCHNAGAR1_PIN_PSIA2_RXDAT,
LOCHNAGAR1_PIN_PSIA2_TXDAT,
LOCHNAGAR1_PIN_SPDIF_AIF_BCLK,
LOCHNAGAR1_PIN_SPDIF_AIF_LRCLK,
LOCHNAGAR1_PIN_SPDIF_AIF_RXDAT,
LOCHNAGAR1_PIN_SPDIF_AIF_TXDAT,
LOCHNAGAR1_PIN_GF_AIF3_BCLK,
LOCHNAGAR1_PIN_GF_AIF3_RXDAT,
LOCHNAGAR1_PIN_GF_AIF3_LRCLK,
LOCHNAGAR1_PIN_GF_AIF3_TXDAT,
LOCHNAGAR1_PIN_GF_AIF4_BCLK,
LOCHNAGAR1_PIN_GF_AIF4_RXDAT,
LOCHNAGAR1_PIN_GF_AIF4_LRCLK,
LOCHNAGAR1_PIN_GF_AIF4_TXDAT,
LOCHNAGAR1_PIN_GF_AIF1_BCLK,
LOCHNAGAR1_PIN_GF_AIF1_RXDAT,
LOCHNAGAR1_PIN_GF_AIF1_LRCLK,
LOCHNAGAR1_PIN_GF_AIF1_TXDAT,
LOCHNAGAR1_PIN_GF_AIF2_BCLK,
LOCHNAGAR1_PIN_GF_AIF2_RXDAT,
LOCHNAGAR1_PIN_GF_AIF2_LRCLK,
LOCHNAGAR1_PIN_GF_AIF2_TXDAT,
LOCHNAGAR2_PIN_SPDIF_AIF_BCLK = LOCHNAGAR2_PIN_NUM_GPIOS,
LOCHNAGAR2_PIN_SPDIF_AIF_LRCLK,
LOCHNAGAR2_PIN_SPDIF_AIF_RXDAT,
LOCHNAGAR2_PIN_SPDIF_AIF_TXDAT,
LOCHNAGAR2_PIN_USB_AIF1_BCLK,
LOCHNAGAR2_PIN_USB_AIF1_LRCLK,
LOCHNAGAR2_PIN_USB_AIF1_RXDAT,
LOCHNAGAR2_PIN_USB_AIF1_TXDAT,
LOCHNAGAR2_PIN_USB_AIF2_BCLK,
LOCHNAGAR2_PIN_USB_AIF2_LRCLK,
LOCHNAGAR2_PIN_USB_AIF2_RXDAT,
LOCHNAGAR2_PIN_USB_AIF2_TXDAT,
LOCHNAGAR2_PIN_ADAT_AIF_BCLK,
LOCHNAGAR2_PIN_ADAT_AIF_LRCLK,
LOCHNAGAR2_PIN_ADAT_AIF_RXDAT,
LOCHNAGAR2_PIN_ADAT_AIF_TXDAT,
LOCHNAGAR2_PIN_SOUNDCARD_AIF_BCLK,
LOCHNAGAR2_PIN_SOUNDCARD_AIF_LRCLK,
LOCHNAGAR2_PIN_SOUNDCARD_AIF_RXDAT,
LOCHNAGAR2_PIN_SOUNDCARD_AIF_TXDAT,
};
enum lochnagar_pin_type {
LN_PTYPE_GPIO,
LN_PTYPE_MUX,
LN_PTYPE_AIF,
LN_PTYPE_COUNT,
};
struct lochnagar_pin {
const char name[20];
enum lochnagar_pin_type type;
unsigned int reg;
int shift;
bool invert;
};
LN1_PIN_GPIO(CDC_RESET, "codec-reset", RST, CDC_RESET, 1);
LN1_PIN_GPIO(DSP_RESET, "dsp-reset", RS