|
@@ -58,10 +58,27 @@ static int gpio_banks;
|
|
#define DEGLITCH (1 << 2)
|
|
#define DEGLITCH (1 << 2)
|
|
#define PULL_DOWN (1 << 3)
|
|
#define PULL_DOWN (1 << 3)
|
|
#define DIS_SCHMIT (1 << 4)
|
|
#define DIS_SCHMIT (1 << 4)
|
|
|
|
+#define DRIVE_STRENGTH_SHIFT 5
|
|
|
|
+#define DRIVE_STRENGTH_MASK 0x3
|
|
|
|
+#define DRIVE_STRENGTH (DRIVE_STRENGTH_MASK << DRIVE_STRENGTH_SHIFT)
|
|
#define DEBOUNCE (1 << 16)
|
|
#define DEBOUNCE (1 << 16)
|
|
#define DEBOUNCE_VAL_SHIFT 17
|
|
#define DEBOUNCE_VAL_SHIFT 17
|
|
#define DEBOUNCE_VAL (0x3fff << DEBOUNCE_VAL_SHIFT)
|
|
#define DEBOUNCE_VAL (0x3fff << DEBOUNCE_VAL_SHIFT)
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * These defines will translated the dt binding settings to our internal
|
|
|
|
+ * settings. They are not necessarily the same value as the register setting.
|
|
|
|
+ * The actual drive strength current of low, medium and high must be looked up
|
|
|
|
+ * from the corresponding device datasheet. This value is different for pins
|
|
|
|
+ * that are even in the same banks. It is also dependent on VCC.
|
|
|
|
+ * DRIVE_STRENGTH_DEFAULT is just a placeholder to avoid changing the drive
|
|
|
|
+ * strength when there is no dt config for it.
|
|
|
|
+ */
|
|
|
|
+#define DRIVE_STRENGTH_DEFAULT (0 << DRIVE_STRENGTH_SHIFT)
|
|
|
|
+#define DRIVE_STRENGTH_LOW (1 << DRIVE_STRENGTH_SHIFT)
|
|
|
|
+#define DRIVE_STRENGTH_MED (2 << DRIVE_STRENGTH_SHIFT)
|
|
|
|
+#define DRIVE_STRENGTH_HI (3 << DRIVE_STRENGTH_SHIFT)
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* struct at91_pmx_func - describes AT91 pinmux functions
|
|
* struct at91_pmx_func - describes AT91 pinmux functions
|
|
* @name: the name of this specific function
|
|
* @name: the name of this specific function
|
|
@@ -148,6 +165,9 @@ struct at91_pinctrl_mux_ops {
|
|
void (*set_pulldown)(void __iomem *pio, unsigned mask, bool is_on);
|
|
void (*set_pulldown)(void __iomem *pio, unsigned mask, bool is_on);
|
|
bool (*get_schmitt_trig)(void __iomem *pio, unsigned pin);
|
|
bool (*get_schmitt_trig)(void __iomem *pio, unsigned pin);
|
|
void (*disable_schmitt_trig)(void __iomem *pio, unsigned mask);
|
|
void (*disable_schmitt_trig)(void __iomem *pio, unsigned mask);
|
|
|
|
+ unsigned (*get_drivestrength)(void __iomem *pio, unsigned pin);
|
|
|
|
+ void (*set_drivestrength)(void __iomem *pio, unsigned pin,
|
|
|
|
+ u32 strength);
|
|
/* irq */
|
|
/* irq */
|
|
int (*irq_type)(struct irq_data *d, unsigned type);
|
|
int (*irq_type)(struct irq_data *d, unsigned type);
|
|
};
|
|
};
|
|
@@ -315,6 +335,30 @@ static unsigned pin_to_mask(unsigned int pin)
|
|
return 1 << pin;
|
|
return 1 << pin;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static unsigned two_bit_pin_value_shift_amount(unsigned int pin)
|
|
|
|
+{
|
|
|
|
+ /* return the shift value for a pin for "two bit" per pin registers,
|
|
|
|
+ * i.e. drive strength */
|
|
|
|
+ return 2*((pin >= MAX_NB_GPIO_PER_BANK/2)
|
|
|
|
+ ? pin - MAX_NB_GPIO_PER_BANK/2 : pin);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static unsigned sama5d3_get_drive_register(unsigned int pin)
|
|
|
|
+{
|
|
|
|
+ /* drive strength is split between two registers
|
|
|
|
+ * with two bits per pin */
|
|
|
|
+ return (pin >= MAX_NB_GPIO_PER_BANK/2)
|
|
|
|
+ ? SAMA5D3_PIO_DRIVER2 : SAMA5D3_PIO_DRIVER1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static unsigned at91sam9x5_get_drive_register(unsigned int pin)
|
|
|
|
+{
|
|
|
|
+ /* drive strength is split between two registers
|
|
|
|
+ * with two bits per pin */
|
|
|
|
+ return (pin >= MAX_NB_GPIO_PER_BANK/2)
|
|
|
|
+ ? AT91SAM9X5_PIO_DRIVER2 : AT91SAM9X5_PIO_DRIVER1;
|
|
|
|
+}
|
|
|
|
+
|
|
static void at91_mux_disable_interrupt(void __iomem *pio, unsigned mask)
|
|
static void at91_mux_disable_interrupt(void __iomem *pio, unsigned mask)
|
|
{
|
|
{
|
|
writel_relaxed(mask, pio + PIO_IDR);
|
|
writel_relaxed(mask, pio + PIO_IDR);
|
|
@@ -468,6 +512,79 @@ static bool at91_mux_pio3_get_schmitt_trig(void __iomem *pio, unsigned pin)
|
|
return (__raw_readl(pio + PIO_SCHMITT) >> pin) & 0x1;
|
|
return (__raw_readl(pio + PIO_SCHMITT) >> pin) & 0x1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static inline u32 read_drive_strength(void __iomem *reg, unsigned pin)
|
|
|
|
+{
|
|
|
|
+ unsigned tmp = __raw_readl(reg);
|
|
|
|
+
|
|
|
|
+ tmp = tmp >> two_bit_pin_value_shift_amount(pin);
|
|
|
|
+
|
|
|
|
+ return tmp & DRIVE_STRENGTH_MASK;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static unsigned at91_mux_sama5d3_get_drivestrength(void __iomem *pio,
|
|
|
|
+ unsigned pin)
|
|
|
|
+{
|
|
|
|
+ unsigned tmp = read_drive_strength(pio +
|
|
|
|
+ sama5d3_get_drive_register(pin), pin);
|
|
|
|
+
|
|
|
|
+ /* SAMA5 strength is 1:1 with our defines,
|
|
|
|
+ * except 0 is equivalent to low per datasheet */
|
|
|
|
+ if (!tmp)
|
|
|
|
+ tmp = DRIVE_STRENGTH_LOW;
|
|
|
|
+
|
|
|
|
+ return tmp;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static unsigned at91_mux_sam9x5_get_drivestrength(void __iomem *pio,
|
|
|
|
+ unsigned pin)
|
|
|
|
+{
|
|
|
|
+ unsigned tmp = read_drive_strength(pio +
|
|
|
|
+ at91sam9x5_get_drive_register(pin), pin);
|
|
|
|
+
|
|
|
|
+ /* strength is inverse in SAM9x5s hardware with the pinctrl defines
|
|
|
|
+ * hardware: 0 = hi, 1 = med, 2 = low, 3 = rsvd */
|
|
|
|
+ tmp = DRIVE_STRENGTH_HI - tmp;
|
|
|
|
+
|
|
|
|
+ return tmp;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void set_drive_strength(void __iomem *reg, unsigned pin, u32 strength)
|
|
|
|
+{
|
|
|
|
+ unsigned tmp = __raw_readl(reg);
|
|
|
|
+ unsigned shift = two_bit_pin_value_shift_amount(pin);
|
|
|
|
+
|
|
|
|
+ tmp &= ~(DRIVE_STRENGTH_MASK << shift);
|
|
|
|
+ tmp |= strength << shift;
|
|
|
|
+
|
|
|
|
+ __raw_writel(tmp, reg);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void at91_mux_sama5d3_set_drivestrength(void __iomem *pio, unsigned pin,
|
|
|
|
+ u32 setting)
|
|
|
|
+{
|
|
|
|
+ /* do nothing if setting is zero */
|
|
|
|
+ if (!setting)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ /* strength is 1 to 1 with setting for SAMA5 */
|
|
|
|
+ set_drive_strength(pio + sama5d3_get_drive_register(pin), pin, setting);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void at91_mux_sam9x5_set_drivestrength(void __iomem *pio, unsigned pin,
|
|
|
|
+ u32 setting)
|
|
|
|
+{
|
|
|
|
+ /* do nothing if setting is zero */
|
|
|
|
+ if (!setting)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ /* strength is inverse on SAM9x5s with our defines
|
|
|
|
+ * 0 = hi, 1 = med, 2 = low, 3 = rsvd */
|
|
|
|
+ setting = DRIVE_STRENGTH_HI - setting;
|
|
|
|
+
|
|
|
|
+ set_drive_strength(pio + at91sam9x5_get_drive_register(pin), pin,
|
|
|
|
+ setting);
|
|
|
|
+}
|
|
|
|
+
|
|
static struct at91_pinctrl_mux_ops at91rm9200_ops = {
|
|
static struct at91_pinctrl_mux_ops at91rm9200_ops = {
|
|
.get_periph = at91_mux_get_periph,
|
|
.get_periph = at91_mux_get_periph,
|
|
.mux_A_periph = at91_mux_set_A_periph,
|
|
.mux_A_periph = at91_mux_set_A_periph,
|
|
@@ -491,6 +608,27 @@ static struct at91_pinctrl_mux_ops at91sam9x5_ops = {
|
|
.set_pulldown = at91_mux_pio3_set_pulldown,
|
|
.set_pulldown = at91_mux_pio3_set_pulldown,
|
|
.get_schmitt_trig = at91_mux_pio3_get_schmitt_trig,
|
|
.get_schmitt_trig = at91_mux_pio3_get_schmitt_trig,
|
|
.disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig,
|
|
.disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig,
|
|
|
|
+ .get_drivestrength = at91_mux_sam9x5_get_drivestrength,
|
|
|
|
+ .set_drivestrength = at91_mux_sam9x5_set_drivestrength,
|
|
|
|
+ .irq_type = alt_gpio_irq_type,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct at91_pinctrl_mux_ops sama5d3_ops = {
|
|
|
|
+ .get_periph = at91_mux_pio3_get_periph,
|
|
|
|
+ .mux_A_periph = at91_mux_pio3_set_A_periph,
|
|
|
|
+ .mux_B_periph = at91_mux_pio3_set_B_periph,
|
|
|
|
+ .mux_C_periph = at91_mux_pio3_set_C_periph,
|
|
|
|
+ .mux_D_periph = at91_mux_pio3_set_D_periph,
|
|
|
|
+ .get_deglitch = at91_mux_pio3_get_deglitch,
|
|
|
|
+ .set_deglitch = at91_mux_pio3_set_deglitch,
|
|
|
|
+ .get_debounce = at91_mux_pio3_get_debounce,
|
|
|
|
+ .set_debounce = at91_mux_pio3_set_debounce,
|
|
|
|
+ .get_pulldown = at91_mux_pio3_get_pulldown,
|
|
|
|
+ .set_pulldown = at91_mux_pio3_set_pulldown,
|
|
|
|
+ .get_schmitt_trig = at91_mux_pio3_get_schmitt_trig,
|
|
|
|
+ .disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig,
|
|
|
|
+ .get_drivestrength = at91_mux_sama5d3_get_drivestrength,
|
|
|
|
+ .set_drivestrength = at91_mux_sama5d3_set_drivestrength,
|
|
.irq_type = alt_gpio_irq_type,
|
|
.irq_type = alt_gpio_irq_type,
|
|
};
|
|
};
|
|
|
|
|
|
@@ -716,6 +854,9 @@ static int at91_pinconf_get(struct pinctrl_dev *pctldev,
|
|
*config |= PULL_DOWN;
|
|
*config |= PULL_DOWN;
|
|
if (info->ops->get_schmitt_trig && info->ops->get_schmitt_trig(pio, pin))
|
|
if (info->ops->get_schmitt_trig && info->ops->get_schmitt_trig(pio, pin))
|
|
*config |= DIS_SCHMIT;
|
|
*config |= DIS_SCHMIT;
|
|
|
|
+ if (info->ops->get_drivestrength)
|
|
|
|
+ *config |= (info->ops->get_drivestrength(pio, pin)
|
|
|
|
+ << DRIVE_STRENGTH_SHIFT);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -729,6 +870,7 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev,
|
|
void __iomem *pio;
|
|
void __iomem *pio;
|
|
int i;
|
|
int i;
|
|
unsigned long config;
|
|
unsigned long config;
|
|
|
|
+ unsigned pin;
|
|
|
|
|
|
for (i = 0; i < num_configs; i++) {
|
|
for (i = 0; i < num_configs; i++) {
|
|
config = configs[i];
|
|
config = configs[i];
|
|
@@ -737,7 +879,8 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev,
|
|
"%s:%d, pin_id=%d, config=0x%lx",
|
|
"%s:%d, pin_id=%d, config=0x%lx",
|
|
__func__, __LINE__, pin_id, config);
|
|
__func__, __LINE__, pin_id, config);
|
|
pio = pin_to_controller(info, pin_to_bank(pin_id));
|
|
pio = pin_to_controller(info, pin_to_bank(pin_id));
|
|
- mask = pin_to_mask(pin_id % MAX_NB_GPIO_PER_BANK);
|
|
|
|
|
|
+ pin = pin_id % MAX_NB_GPIO_PER_BANK;
|
|
|
|
+ mask = pin_to_mask(pin);
|
|
|
|
|
|
if (config & PULL_UP && config & PULL_DOWN)
|
|
if (config & PULL_UP && config & PULL_DOWN)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
@@ -753,6 +896,10 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev,
|
|
info->ops->set_pulldown(pio, mask, config & PULL_DOWN);
|
|
info->ops->set_pulldown(pio, mask, config & PULL_DOWN);
|
|
if (info->ops->disable_schmitt_trig && config & DIS_SCHMIT)
|
|
if (info->ops->disable_schmitt_trig && config & DIS_SCHMIT)
|
|
info->ops->disable_schmitt_trig(pio, mask);
|
|
info->ops->disable_schmitt_trig(pio, mask);
|
|
|
|
+ if (info->ops->set_drivestrength)
|
|
|
|
+ info->ops->set_drivestrength(pio, pin,
|
|
|
|
+ (config & DRIVE_STRENGTH)
|
|
|
|
+ >> DRIVE_STRENGTH_SHIFT);
|
|
|
|
|
|
} /* for each config */
|
|
} /* for each config */
|
|
|
|
|
|
@@ -768,6 +915,15 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev,
|
|
} \
|
|
} \
|
|
} while (0)
|
|
} while (0)
|
|
|
|
|
|
|
|
+#define DBG_SHOW_FLAG_MASKED(mask,flag) do { \
|
|
|
|
+ if ((config & mask) == flag) { \
|
|
|
|
+ if (num_conf) \
|
|
|
|
+ seq_puts(s, "|"); \
|
|
|
|
+ seq_puts(s, #flag); \
|
|
|
|
+ num_conf++; \
|
|
|
|
+ } \
|
|
|
|
+} while (0)
|
|
|
|
+
|
|
static void at91_pinconf_dbg_show(struct pinctrl_dev *pctldev,
|
|
static void at91_pinconf_dbg_show(struct pinctrl_dev *pctldev,
|
|
struct seq_file *s, unsigned pin_id)
|
|
struct seq_file *s, unsigned pin_id)
|
|
{
|
|
{
|
|
@@ -781,6 +937,9 @@ static void at91_pinconf_dbg_show(struct pinctrl_dev *pctldev,
|
|
DBG_SHOW_FLAG(PULL_DOWN);
|
|
DBG_SHOW_FLAG(PULL_DOWN);
|
|
DBG_SHOW_FLAG(DIS_SCHMIT);
|
|
DBG_SHOW_FLAG(DIS_SCHMIT);
|
|
DBG_SHOW_FLAG(DEGLITCH);
|
|
DBG_SHOW_FLAG(DEGLITCH);
|
|
|
|
+ DBG_SHOW_FLAG_MASKED(DRIVE_STRENGTH, DRIVE_STRENGTH_LOW);
|
|
|
|
+ DBG_SHOW_FLAG_MASKED(DRIVE_STRENGTH, DRIVE_STRENGTH_MED);
|
|
|
|
+ DBG_SHOW_FLAG_MASKED(DRIVE_STRENGTH, DRIVE_STRENGTH_HI);
|
|
DBG_SHOW_FLAG(DEBOUNCE);
|
|
DBG_SHOW_FLAG(DEBOUNCE);
|
|
if (config & DEBOUNCE) {
|
|
if (config & DEBOUNCE) {
|
|
val = config >> DEBOUNCE_VAL_SHIFT;
|
|
val = config >> DEBOUNCE_VAL_SHIFT;
|
|
@@ -945,6 +1104,7 @@ static int at91_pinctrl_parse_functions(struct device_node *np,
|
|
}
|
|
}
|
|
|
|
|
|
static struct of_device_id at91_pinctrl_of_match[] = {
|
|
static struct of_device_id at91_pinctrl_of_match[] = {
|
|
|
|
+ { .compatible = "atmel,sama5d3-pinctrl", .data = &sama5d3_ops },
|
|
{ .compatible = "atmel,at91sam9x5-pinctrl", .data = &at91sam9x5_ops },
|
|
{ .compatible = "atmel,at91sam9x5-pinctrl", .data = &at91sam9x5_ops },
|
|
{ .compatible = "atmel,at91rm9200-pinctrl", .data = &at91rm9200_ops },
|
|
{ .compatible = "atmel,at91rm9200-pinctrl", .data = &at91rm9200_ops },
|
|
{ /* sentinel */ }
|
|
{ /* sentinel */ }
|