linux/arch/mips/pmcs-msp71xx/gpio.c
<<
>>
Prefs
   1/*
   2 * Generic PMC MSP71xx GPIO handling. These base gpio are controlled by two
   3 * types of registers. The data register sets the output level when in output
   4 * mode and when in input mode will contain the value at the input. The config
   5 * register sets the various modes for each gpio.
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 *
  11 * @author Patrick Glass <patrickglass@gmail.com>
  12 */
  13
  14#include <linux/kernel.h>
  15#include <linux/module.h>
  16#include <linux/init.h>
  17#include <linux/gpio.h>
  18#include <linux/spinlock.h>
  19#include <linux/io.h>
  20
  21#define MSP71XX_CFG_OFFSET(gpio)        (4 * (gpio))
  22#define CONF_MASK                       0x0F
  23#define MSP71XX_GPIO_INPUT              0x01
  24#define MSP71XX_GPIO_OUTPUT             0x08
  25
  26#define MSP71XX_GPIO_BASE               0x0B8400000L
  27
  28#define to_msp71xx_gpio_chip(c) container_of(c, struct msp71xx_gpio_chip, chip)
  29
  30static spinlock_t gpio_lock;
  31
  32/*
  33 * struct msp71xx_gpio_chip - container for gpio chip and registers
  34 * @chip: chip structure for the specified gpio bank
  35 * @data_reg: register for reading and writing the gpio pin value
  36 * @config_reg: register to set the mode for the gpio pin bank
  37 * @out_drive_reg: register to set the output drive mode for the gpio pin bank
  38 */
  39struct msp71xx_gpio_chip {
  40        struct gpio_chip chip;
  41        void __iomem *data_reg;
  42        void __iomem *config_reg;
  43        void __iomem *out_drive_reg;
  44};
  45
  46/*
  47 * msp71xx_gpio_get() - return the chip's gpio value
  48 * @chip: chip structure which controls the specified gpio
  49 * @offset: gpio whose value will be returned
  50 *
  51 * It will return 0 if gpio value is low and other if high.
  52 */
  53static int msp71xx_gpio_get(struct gpio_chip *chip, unsigned offset)
  54{
  55        struct msp71xx_gpio_chip *msp_chip = to_msp71xx_gpio_chip(chip);
  56
  57        return __raw_readl(msp_chip->data_reg) & (1 << offset);
  58}
  59
  60/*
  61 * msp71xx_gpio_set() - set the output value for the gpio
  62 * @chip: chip structure who controls the specified gpio
  63 * @offset: gpio whose value will be assigned
  64 * @value: logic level to assign to the gpio initially
  65 *
  66 * This will set the gpio bit specified to the desired value. It will set the
  67 * gpio pin low if value is 0 otherwise it will be high.
  68 */
  69static void msp71xx_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
  70{
  71        struct msp71xx_gpio_chip *msp_chip = to_msp71xx_gpio_chip(chip);
  72        unsigned long flags;
  73        u32 data;
  74
  75        spin_lock_irqsave(&gpio_lock, flags);
  76
  77        data = __raw_readl(msp_chip->data_reg);
  78        if (value)
  79                data |= (1 << offset);
  80        else
  81                data &= ~(1 << offset);
  82        __raw_writel(data, msp_chip->data_reg);
  83
  84        spin_unlock_irqrestore(&gpio_lock, flags);
  85}
  86
  87/*
  88 * msp71xx_set_gpio_mode() - declare the mode for a gpio
  89 * @chip: chip structure which controls the specified gpio
  90 * @offset: gpio whose value will be assigned
  91 * @mode: desired configuration for the gpio (see datasheet)
  92 *
  93 * It will set the gpio pin config to the @mode value passed in.
  94 */
  95static int msp71xx_set_gpio_mode(struct gpio_chip *chip,
  96                                 unsigned offset, int mode)
  97{
  98        struct msp71xx_gpio_chip *msp_chip = to_msp71xx_gpio_chip(chip);
  99        const unsigned bit_offset = MSP71XX_CFG_OFFSET(offset);
 100        unsigned long flags;
 101        u32 cfg;
 102
 103        spin_lock_irqsave(&gpio_lock, flags);
 104
 105        cfg = __raw_readl(msp_chip->config_reg);
 106        cfg &= ~(CONF_MASK << bit_offset);
 107        cfg |= (mode << bit_offset);
 108        __raw_writel(cfg, msp_chip->config_reg);
 109
 110        spin_unlock_irqrestore(&gpio_lock, flags);
 111
 112        return 0;
 113}
 114
 115/*
 116 * msp71xx_direction_output() - declare the direction mode for a gpio
 117 * @chip: chip structure which controls the specified gpio
 118 * @offset: gpio whose value will be assigned
 119 * @value: logic level to assign to the gpio initially
 120 *
 121 * This call will set the mode for the @gpio to output. It will set the
 122 * gpio pin low if value is 0 otherwise it will be high.
 123 */
 124static int msp71xx_direction_output(struct gpio_chip *chip,
 125                                    unsigned offset, int value)
 126{
 127        msp71xx_gpio_set(chip, offset, value);
 128
 129        return msp71xx_set_gpio_mode(chip, offset, MSP71XX_GPIO_OUTPUT);
 130}
 131
 132/*
 133 * msp71xx_direction_input() - declare the direction mode for a gpio
 134 * @chip: chip structure which controls the specified gpio
 135 * @offset: gpio whose to which the value will be assigned
 136 *
 137 * This call will set the mode for the @gpio to input.
 138 */
 139static int msp71xx_direction_input(struct gpio_chip *chip, unsigned offset)
 140{
 141        return msp71xx_set_gpio_mode(chip, offset, MSP71XX_GPIO_INPUT);
 142}
 143
 144/*
 145 * msp71xx_set_output_drive() - declare the output drive for the gpio line
 146 * @gpio: gpio pin whose output drive you wish to modify
 147 * @value: zero for active drain 1 for open drain drive
 148 *
 149 * This call will set the output drive mode for the @gpio to output.
 150 */
 151int msp71xx_set_output_drive(unsigned gpio, int value)
 152{
 153        unsigned long flags;
 154        u32 data;
 155
 156        if (gpio > 15 || gpio < 0)
 157                return -EINVAL;
 158
 159        spin_lock_irqsave(&gpio_lock, flags);
 160
 161        data = __raw_readl((void __iomem *)(MSP71XX_GPIO_BASE + 0x190));
 162        if (value)
 163                data |= (1 << gpio);
 164        else
 165                data &= ~(1 << gpio);
 166        __raw_writel(data, (void __iomem *)(MSP71XX_GPIO_BASE + 0x190));
 167
 168        spin_unlock_irqrestore(&gpio_lock, flags);
 169
 170        return 0;
 171}
 172EXPORT_SYMBOL(msp71xx_set_output_drive);
 173
 174#define MSP71XX_GPIO_BANK(name, dr, cr, base_gpio, num_gpio) \
 175{ \
 176        .chip = { \
 177                .label            = name, \
 178                .direction_input  = msp71xx_direction_input, \
 179                .direction_output = msp71xx_direction_output, \
 180                .get              = msp71xx_gpio_get, \
 181                .set              = msp71xx_gpio_set, \
 182                .base             = base_gpio, \
 183                .ngpio            = num_gpio \
 184        }, \
 185        .data_reg       = (void __iomem *)(MSP71XX_GPIO_BASE + dr), \
 186        .config_reg     = (void __iomem *)(MSP71XX_GPIO_BASE + cr), \
 187        .out_drive_reg  = (void __iomem *)(MSP71XX_GPIO_BASE + 0x190), \
 188}
 189
 190/*
 191 * struct msp71xx_gpio_banks[] - container array of gpio banks
 192 * @chip: chip structure for the specified gpio bank
 193 * @data_reg: register for reading and writing the gpio pin value
 194 * @config_reg: register to set the mode for the gpio pin bank
 195 *
 196 * This array structure defines the gpio banks for the PMC MIPS Processor.
 197 * We specify the bank name, the data register, the config register, base
 198 * starting gpio number, and the number of gpios exposed by the bank.
 199 */
 200static struct msp71xx_gpio_chip msp71xx_gpio_banks[] = {
 201
 202        MSP71XX_GPIO_BANK("GPIO_1_0", 0x170, 0x180, 0, 2),
 203        MSP71XX_GPIO_BANK("GPIO_5_2", 0x174, 0x184, 2, 4),
 204        MSP71XX_GPIO_BANK("GPIO_9_6", 0x178, 0x188, 6, 4),
 205        MSP71XX_GPIO_BANK("GPIO_15_10", 0x17C, 0x18C, 10, 6),
 206};
 207
 208void __init msp71xx_init_gpio(void)
 209{
 210        int i;
 211
 212        spin_lock_init(&gpio_lock);
 213
 214        for (i = 0; i < ARRAY_SIZE(msp71xx_gpio_banks); i++)
 215                gpiochip_add(&msp71xx_gpio_banks[i].chip);
 216}
 217