gpio-mlxbf.c 3.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
// SPDX-License-Identifier: GPL-2.0

#include <linux/acpi.h>
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/gpio/driver.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/resource.h>
#include <linux/types.h>

/* Number of pins on BlueField */
#define MLXBF_GPIO_NR 54

/* Pad Electrical Controls. */
#define MLXBF_GPIO_PAD_CONTROL_FIRST_WORD 0x0700
#define MLXBF_GPIO_PAD_CONTROL_1_FIRST_WORD 0x0708
#define MLXBF_GPIO_PAD_CONTROL_2_FIRST_WORD 0x0710
#define MLXBF_GPIO_PAD_CONTROL_3_FIRST_WORD 0x0718

#define MLXBF_GPIO_PIN_DIR_I 0x1040
#define MLXBF_GPIO_PIN_DIR_O 0x1048
#define MLXBF_GPIO_PIN_STATE 0x1000
#define MLXBF_GPIO_SCRATCHPAD 0x20

#ifdef CONFIG_PM
struct mlxbf_gpio_context_save_regs {
	u64 scratchpad;
	u64 pad_control[MLXBF_GPIO_NR];
	u64 pin_dir_i;
	u64 pin_dir_o;
};
#endif

/* Device state structure. */
struct mlxbf_gpio_state {
	struct gpio_chip gc;

	/* Memory Address */
	void __iomem *base;

#ifdef CONFIG_PM
	struct mlxbf_gpio_context_save_regs csave_regs;
#endif
};

static int mlxbf_gpio_probe(struct platform_device *pdev)
{
	struct mlxbf_gpio_state *gs;
	struct device *dev = &pdev->dev;
	struct gpio_chip *gc;
	int ret;

	gs = devm_kzalloc(&pdev->dev, sizeof(*gs), GFP_KERNEL);
	if (!gs)
		return -ENOMEM;

	gs->base = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(gs->base))
		return PTR_ERR(gs->base);

	gc = &gs->gc;
	ret = bgpio_init(gc, dev, 8,
			 gs->base + MLXBF_GPIO_PIN_STATE,
			 NULL,
			 NULL,
			 gs->base + MLXBF_GPIO_PIN_DIR_O,
			 gs->base + MLXBF_GPIO_PIN_DIR_I,
			 0);
	if (ret)
		return -ENODEV;

	gc->owner = THIS_MODULE;
	gc->ngpio = MLXBF_GPIO_NR;

	ret = devm_gpiochip_add_data(dev, &gs->gc, gs);
	if (ret) {
		dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n");
		return ret;
	}

	platform_set_drvdata(pdev, gs);
	dev_info(&pdev->dev, "registered Mellanox BlueField GPIO");
	return 0;
}

#ifdef CONFIG_PM
static int mlxbf_gpio_suspend(struct platform_device *pdev, pm_message_t state)
{
	struct mlxbf_gpio_state *gs = platform_get_drvdata(pdev);

	gs->csave_regs.scratchpad = readq(gs->base + MLXBF_GPIO_SCRATCHPAD);
	gs->csave_regs.pad_control[0] =
		readq(gs->base + MLXBF_GPIO_PAD_CONTROL_FIRST_WORD);
	gs->csave_regs.pad_control[1] =
		readq(gs->base + MLXBF_GPIO_PAD_CONTROL_1_FIRST_WORD);
	gs->csave_regs.pad_control[2] =
		readq(gs->base + MLXBF_GPIO_PAD_CONTROL_2_FIRST_WORD);
	gs->csave_regs.pad_control[3] =
		readq(gs->base + MLXBF_GPIO_PAD_CONTROL_3_FIRST_WORD);
	gs->csave_regs.pin_dir_i = readq(gs->base + MLXBF_GPIO_PIN_DIR_I);
	gs->csave_regs.pin_dir_o = readq(gs->base + MLXBF_GPIO_PIN_DIR_O);

	return 0;
}

static int mlxbf_gpio_resume(struct platform_device *pdev)
{
	struct mlxbf_gpio_state *gs = platform_get_drvdata(pdev);

	writeq(gs->csave_regs.scratchpad, gs->base + MLXBF_GPIO_SCRATCHPAD);
	writeq(gs->csave_regs.pad_control[0],
	       gs->base + MLXBF_GPIO_PAD_CONTROL_FIRST_WORD);
	writeq(gs->csave_regs.pad_control[1],
	       gs->base + MLXBF_GPIO_PAD_CONTROL_1_FIRST_WORD);
	writeq(gs->csave_regs.pad_control[2],
	       gs->base + MLXBF_GPIO_PAD_CONTROL_2_FIRST_WORD);
	writeq(gs->csave_regs.pad_control[3],
	       gs->base + MLXBF_GPIO_PAD_CONTROL_3_FIRST_WORD);
	writeq(gs->csave_regs.pin_dir_i, gs->base + MLXBF_GPIO_PIN_DIR_I);
	writeq(gs->csave_regs.pin_dir_o, gs->base + MLXBF_GPIO_PIN_DIR_O);

	return 0;
}
#endif

static const struct acpi_device_id mlxbf_gpio_acpi_match[] = {
	{ "MLNXBF02", 0 },
	{}
};
MODULE_DEVICE_TABLE(acpi, mlxbf_gpio_acpi_match);

static struct platform_driver mlxbf_gpio_driver = {
	.driver = {
		.name = "mlxbf_gpio",
		.acpi_match_table = ACPI_PTR(mlxbf_gpio_acpi_match),
	},
	.probe    = mlxbf_gpio_probe,
#ifdef CONFIG_PM
	.suspend  = mlxbf_gpio_suspend,
	.resume   = mlxbf_gpio_resume,
#endif
};

module_platform_driver(mlxbf_gpio_driver);

MODULE_DESCRIPTION("Mellanox BlueField GPIO Driver");
MODULE_AUTHOR("Mellanox Technologies");
MODULE_LICENSE("GPL");