/* Copyright (C) 2016 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This file contains the Northstar2 IOMUX driver that supports group
* based PINMUX configuration. The PWM is functional only when the
* corresponding mfio pin group is selected as gpio.
*/
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "../core.h"
#include "../pinctrl-utils.h"
#define NS2_NUM_IOMUX 19
#define NS2_NUM_PWM_MUX 4
#define NS2_PIN_MUX_BASE0 0x00
#define NS2_PIN_MUX_BASE1 0x01
#define NS2_PIN_CONF_BASE 0x02
#define NS2_MUX_PAD_FUNC1_OFFSET 0x04
#define NS2_PIN_SRC_MASK 0x01
#define NS2_PIN_PULL_MASK 0x03
#define NS2_PIN_DRIVE_STRENGTH_MASK 0x07
#define NS2_PIN_PULL_UP 0x01
#define NS2_PIN_PULL_DOWN 0x02
#define NS2_PIN_INPUT_EN_MASK 0x01
/*
* Northstar2 IOMUX register description
*
* @base: base address number
* @offset: register offset for mux configuration of a group
* @shift: bit shift for mux configuration of a group
* @mask: mask bits
* @alt: alternate function to set to
*/
struct ns2_mux {
unsigned int base;
unsigned int offset;
unsigned int shift;
unsigned int mask;
unsigned int alt;
};
/*
* Keep track of Northstar2 IOMUX configuration and prevent double
* configuration
*
* @ns2_mux: Northstar2 IOMUX register description
* @is_configured: flag to indicate whether a mux setting has already
* been configured
*/
struct ns2_mux_log {
struct ns2_mux mux;
bool is_configured;
};
/*
* Group based IOMUX configuration
*
* @name: name of the group
* @pins: array of pins used by this group
* @num_pins: total number of pins used by this group
* @mux: Northstar2 group based IOMUX configuration
*/
struct ns2_pin_group {
const char *name;
const unsigned int *pins;
const unsigned int num_pins;
const struct ns2_mux mux;
};
/*
* Northstar2 mux function and supported pin groups
*
* @name: name of the function
* @groups: array of groups that can be supported by this function
* @num_groups: total number of groups that can be supported by function
*/
struct ns2_pin_function {
const char *name;
const char * const *groups;
const unsigned int num_groups;
};
/*
* Northstar2 IOMUX pinctrl core
*
* @pctl: pointer to pinctrl_dev
* @dev: pointer to device
* @base0: first IOMUX register base
* @base1: second IOMUX register base
* @pinconf_base: configuration register base
* @groups: pointer to array of groups
* @num_groups: total number of groups
* @functions: pointer to array of functions
* @num_functions: total number of functions
* @mux_log: pointer to the array of mux logs
* @lock: lock to protect register access
*/
struct ns2_pinctrl {
struct pinctrl_dev *pctl;
struct device *dev;
void __iomem *base0;
void __iomem *base1;
void __iomem *pinconf_base;
const struct ns2_pin_group *groups;
unsigned int num_groups;
const struct ns2_pin_function *functions;
unsigned int num_functions;
struct ns2_mux_log *mux_log;
spinlock_t lock;
};
/*
* Pin configuration info
*
* @base: base address number
* @offset: register offset from base
* @src_shift: slew rate control bit shift in the register
* @input_en: input enable control bit shift
* @pull_shift: pull-up/pull-down control bit shift in the register
* @drive_shift: drive strength control bit shift in the register
*/
struct ns2_pinconf {
unsigned int base;
unsigned int offset;
unsigned int src_shift;
unsigned int input_en;
unsigned int pull_shift;
unsigned int drive_shift;
};
/*
* Description of a pin in Northstar2
*
* @pin: pin number
* @name: pin name
* @pin_conf: pin configuration structure
*/
struct ns2_pin {
unsigned int pin;
char *name;
struct ns2_pinconf pin_conf;
};
#define NS2_PIN_DESC(p, n, b, o, s, i, pu, d) \
{ \
.pin = p, \
.name = n, \
.pin_conf = { \
.base = b, \
.offset = o, \
.src_shift = s, \
.input_en = i, \
.pull_shift = pu, \
.drive_shift = d, \
} \
}
/*
* List of pins in Northstar2
*/
static struct ns2_pin ns2_pins[] = {
NS2_PIN_DESC(0, "mfio_0", -1, 0, 0, 0, 0, 0),
NS2_PIN_DESC(1, "mfio_1", -1, 0, 0, 0, 0, 0),
NS2_PIN_DESC(2, "mfio_2", -1, 0, 0, 0, 0, 0),
NS2_PIN_DESC(3, "mfio_3", -1, 0, 0, 0, 0, 0),
NS2_PIN_DESC(4, "mfio_4", -1, 0, 0, 0, 0, 0),
NS2_PIN_DESC(5, "mfio_5", -1, 0, 0, 0, 0, 0),
NS2_PIN_DESC(6, "mfio_6", -1, 0, 0, 0, 0, 0),
NS2_PIN_DESC(7, "mfio_7", -1, 0, 0, 0, 0, 0),
NS2_PIN_DESC(8, "mfio_8", -1, 0, 0, 0, 0, 0),
NS2_PIN_DESC(9, "mfio_9", -1, 0, 0, 0, 0, 0),
NS2_PIN_DESC(10, "mfio_10", -1, 0, 0, 0, 0, 0),
NS2_PIN_DESC(11, &qu