linux/drivers/gpio/gpio-mlxbf2.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3#include <linux/bitfield.h>
   4#include <linux/bitops.h>
   5#include <linux/device.h>
   6#include <linux/gpio/driver.h>
   7#include <linux/io.h>
   8#include <linux/ioport.h>
   9#include <linux/kernel.h>
  10#include <linux/mod_devicetable.h>
  11#include <linux/module.h>
  12#include <linux/platform_device.h>
  13#include <linux/pm.h>
  14#include <linux/resource.h>
  15#include <linux/spinlock.h>
  16#include <linux/types.h>
  17
  18/*
  19 * There are 3 YU GPIO blocks:
  20 * gpio[0]: HOST_GPIO0->HOST_GPIO31
  21 * gpio[1]: HOST_GPIO32->HOST_GPIO63
  22 * gpio[2]: HOST_GPIO64->HOST_GPIO69
  23 */
  24#define MLXBF2_GPIO_MAX_PINS_PER_BLOCK 32
  25
  26/*
  27 * arm_gpio_lock register:
  28 * bit[31]      lock status: active if set
  29 * bit[15:0]    set lock
  30 * The lock is enabled only if 0xd42f is written to this field
  31 */
  32#define YU_ARM_GPIO_LOCK_ADDR           0x2801088
  33#define YU_ARM_GPIO_LOCK_SIZE           0x8
  34#define YU_LOCK_ACTIVE_BIT(val)         (val >> 31)
  35#define YU_ARM_GPIO_LOCK_ACQUIRE        0xd42f
  36#define YU_ARM_GPIO_LOCK_RELEASE        0x0
  37
  38/*
  39 * gpio[x] block registers and their offset
  40 */
  41#define YU_GPIO_DATAIN                  0x04
  42#define YU_GPIO_MODE1                   0x08
  43#define YU_GPIO_MODE0                   0x0c
  44#define YU_GPIO_DATASET                 0x14
  45#define YU_GPIO_DATACLEAR               0x18
  46#define YU_GPIO_MODE1_CLEAR             0x50
  47#define YU_GPIO_MODE0_SET               0x54
  48#define YU_GPIO_MODE0_CLEAR             0x58
  49
  50struct mlxbf2_gpio_context_save_regs {
  51        u32 gpio_mode0;
  52        u32 gpio_mode1;
  53};
  54
  55/* BlueField-2 gpio block context structure. */
  56struct mlxbf2_gpio_context {
  57        struct gpio_chip gc;
  58
  59        /* YU GPIO blocks address */
  60        void __iomem *gpio_io;
  61
  62        struct mlxbf2_gpio_context_save_regs *csave_regs;
  63};
  64
  65/* BlueField-2 gpio shared structure. */
  66struct mlxbf2_gpio_param {
  67        void __iomem *io;
  68        struct resource *res;
  69        struct mutex *lock;
  70};
  71
  72static struct resource yu_arm_gpio_lock_res =
  73        DEFINE_RES_MEM_NAMED(YU_ARM_GPIO_LOCK_ADDR, YU_ARM_GPIO_LOCK_SIZE, "YU_ARM_GPIO_LOCK");
  74
  75static DEFINE_MUTEX(yu_arm_gpio_lock_mutex);
  76
  77static struct mlxbf2_gpio_param yu_arm_gpio_lock_param = {
  78        .res = &yu_arm_gpio_lock_res,
  79        .lock = &yu_arm_gpio_lock_mutex,
  80};
  81
  82/* Request memory region and map yu_arm_gpio_lock resource */
  83static int mlxbf2_gpio_get_lock_res(struct platform_device *pdev)
  84{
  85        struct device *dev = &pdev->dev;
  86        struct resource *res;
  87        resource_size_t size;
  88        int ret = 0;
  89
  90        mutex_lock(yu_arm_gpio_lock_param.lock);
  91
  92        /* Check if the memory map already exists */
  93        if (yu_arm_gpio_lock_param.io)
  94                goto exit;
  95
  96        res = yu_arm_gpio_lock_param.res;
  97        size = resource_size(res);
  98
  99        if (!devm_request_mem_region(dev, res->start, size, res->name)) {
 100                ret = -EFAULT;
 101                goto exit;
 102        }
 103
 104        yu_arm_gpio_lock_param.io = devm_ioremap(dev, res->start, size);
 105        if (!yu_arm_gpio_lock_param.io)
 106                ret = -ENOMEM;
 107
 108exit:
 109        mutex_unlock(yu_arm_gpio_lock_param.lock);
 110
 111        return ret;
 112}
 113
 114/*
 115 * Acquire the YU arm_gpio_lock to be able to change the direction
 116 * mode. If the lock_active bit is already set, return an error.
 117 */
 118static int mlxbf2_gpio_lock_acquire(struct mlxbf2_gpio_context *gs)
 119{
 120        u32 arm_gpio_lock_val;
 121
 122        mutex_lock(yu_arm_gpio_lock_param.lock);
 123        spin_lock(&gs->gc.bgpio_lock);
 124
 125        arm_gpio_lock_val = readl(yu_arm_gpio_lock_param.io);
 126
 127        /*
 128         * When lock active bit[31] is set, ModeX is write enabled
 129         */
 130        if (YU_LOCK_ACTIVE_BIT(arm_gpio_lock_val)) {
 131                spin_unlock(&gs->gc.bgpio_lock);
 132                mutex_unlock(yu_arm_gpio_lock_param.lock);
 133                return -EINVAL;
 134        }
 135
 136        writel(YU_ARM_GPIO_LOCK_ACQUIRE, yu_arm_gpio_lock_param.io);
 137
 138        return 0;
 139}
 140
 141/*
 142 * Release the YU arm_gpio_lock after changing the direction mode.
 143 */
 144static void mlxbf2_gpio_lock_release(struct mlxbf2_gpio_context *gs)
 145        __releases(&gs->gc.bgpio_lock)
 146        __releases(yu_arm_gpio_lock_param.lock)
 147{
 148        writel(YU_ARM_GPIO_LOCK_RELEASE, yu_arm_gpio_lock_param.io);
 149        spin_unlock(&gs->gc.bgpio_lock);
 150        mutex_unlock(yu_arm_gpio_lock_param.lock);
 151}
 152
 153/*
 154 * mode0 and mode1 are both locked by the gpio_lock field.
 155 *
 156 * Together, mode0 and mode1 define the gpio Mode dependeing also
 157 * on Reg_DataOut.
 158 *
 159 * {mode1,mode0}:{Reg_DataOut=0,Reg_DataOut=1}->{DataOut=0,DataOut=1}
 160 *
 161 * {0,0}:Reg_DataOut{0,1}->{Z,Z} Input PAD
 162 * {0,1}:Reg_DataOut{0,1}->{0,1} Full drive Output PAD
 163 * {1,0}:Reg_DataOut{0,1}->{0,Z} 0-set PAD to low, 1-float
 164 * {1,1}:Reg_DataOut{0,1}->{Z,1} 0-float, 1-set PAD to high
 165 */
 166
 167/*
 168 * Set input direction:
 169 * {mode1,mode0} = {0,0}
 170 */
 171static int mlxbf2_gpio_direction_input(struct gpio_chip *chip,
 172                                       unsigned int offset)
 173{
 174        struct mlxbf2_gpio_context *gs = gpiochip_get_data(chip);
 175        int ret;
 176
 177        /*
 178         * Although the arm_gpio_lock was set in the probe function, check again
 179         * if it is still enabled to be able to write to the ModeX registers.
 180         */
 181        ret = mlxbf2_gpio_lock_acquire(gs);
 182        if (ret < 0)
 183                return ret;
 184
 185        writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE0_CLEAR);
 186        writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE1_CLEAR);
 187
 188        mlxbf2_gpio_lock_release(gs);
 189
 190        return ret;
 191}
 192
 193/*
 194 * Set output direction:
 195 * {mode1,mode0} = {0,1}
 196 */
 197static int mlxbf2_gpio_direction_output(struct gpio_chip *chip,
 198                                        unsigned int offset,
 199                                        int value)
 200{
 201        struct mlxbf2_gpio_context *gs = gpiochip_get_data(chip);
 202        int ret = 0;
 203
 204        /*
 205         * Although the arm_gpio_lock was set in the probe function,
 206         * check again it is still enabled to be able to write to the
 207         * ModeX registers.
 208         */
 209        ret = mlxbf2_gpio_lock_acquire(gs);
 210        if (ret < 0)
 211                return ret;
 212
 213        writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE1_CLEAR);
 214        writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE0_SET);
 215
 216        mlxbf2_gpio_lock_release(gs);
 217
 218        return ret;
 219}
 220
 221/* BlueField-2 GPIO driver initialization routine. */
 222static int
 223mlxbf2_gpio_probe(struct platform_device *pdev)
 224{
 225        struct mlxbf2_gpio_context *gs;
 226        struct device *dev = &pdev->dev;
 227        struct gpio_chip *gc;
 228        unsigned int npins;
 229        int ret;
 230
 231        gs = devm_kzalloc(dev, sizeof(*gs), GFP_KERNEL);
 232        if (!gs)
 233                return -ENOMEM;
 234
 235        /* YU GPIO block address */
 236        gs->gpio_io = devm_platform_ioremap_resource(pdev, 0);
 237        if (IS_ERR(gs->gpio_io))
 238                return PTR_ERR(gs->gpio_io);
 239
 240        ret = mlxbf2_gpio_get_lock_res(pdev);
 241        if (ret) {
 242                dev_err(dev, "Failed to get yu_arm_gpio_lock resource\n");
 243                return ret;
 244        }
 245
 246        if (device_property_read_u32(dev, "npins", &npins))
 247                npins = MLXBF2_GPIO_MAX_PINS_PER_BLOCK;
 248
 249        gc = &gs->gc;
 250
 251        ret = bgpio_init(gc, dev, 4,
 252                        gs->gpio_io + YU_GPIO_DATAIN,
 253                        gs->gpio_io + YU_GPIO_DATASET,
 254                        gs->gpio_io + YU_GPIO_DATACLEAR,
 255                        NULL,
 256                        NULL,
 257                        0);
 258
 259        if (ret) {
 260                dev_err(dev, "bgpio_init failed\n");
 261                return ret;
 262        }
 263
 264        gc->direction_input = mlxbf2_gpio_direction_input;
 265        gc->direction_output = mlxbf2_gpio_direction_output;
 266        gc->ngpio = npins;
 267        gc->owner = THIS_MODULE;
 268
 269        platform_set_drvdata(pdev, gs);
 270
 271        ret = devm_gpiochip_add_data(dev, &gs->gc, gs);
 272        if (ret) {
 273                dev_err(dev, "Failed adding memory mapped gpiochip\n");
 274                return ret;
 275        }
 276
 277        return 0;
 278}
 279
 280static int __maybe_unused mlxbf2_gpio_suspend(struct device *dev)
 281{
 282        struct mlxbf2_gpio_context *gs = dev_get_drvdata(dev);
 283
 284        gs->csave_regs->gpio_mode0 = readl(gs->gpio_io +
 285                YU_GPIO_MODE0);
 286        gs->csave_regs->gpio_mode1 = readl(gs->gpio_io +
 287                YU_GPIO_MODE1);
 288
 289        return 0;
 290}
 291
 292static int __maybe_unused mlxbf2_gpio_resume(struct device *dev)
 293{
 294        struct mlxbf2_gpio_context *gs = dev_get_drvdata(dev);
 295
 296        writel(gs->csave_regs->gpio_mode0, gs->gpio_io +
 297                YU_GPIO_MODE0);
 298        writel(gs->csave_regs->gpio_mode1, gs->gpio_io +
 299                YU_GPIO_MODE1);
 300
 301        return 0;
 302}
 303static SIMPLE_DEV_PM_OPS(mlxbf2_pm_ops, mlxbf2_gpio_suspend, mlxbf2_gpio_resume);
 304
 305static const struct acpi_device_id __maybe_unused mlxbf2_gpio_acpi_match[] = {
 306        { "MLNXBF22", 0 },
 307        {},
 308};
 309MODULE_DEVICE_TABLE(acpi, mlxbf2_gpio_acpi_match);
 310
 311static struct platform_driver mlxbf2_gpio_driver = {
 312        .driver = {
 313                .name = "mlxbf2_gpio",
 314                .acpi_match_table = mlxbf2_gpio_acpi_match,
 315                .pm = &mlxbf2_pm_ops,
 316        },
 317        .probe    = mlxbf2_gpio_probe,
 318};
 319
 320module_platform_driver(mlxbf2_gpio_driver);
 321
 322MODULE_DESCRIPTION("Mellanox BlueField-2 GPIO Driver");
 323MODULE_AUTHOR("Mellanox Technologies");
 324MODULE_LICENSE("GPL v2");
 325