1c78c42d7SShravan Kumar Ramani // SPDX-License-Identifier: GPL-2.0 2c78c42d7SShravan Kumar Ramani 3c78c42d7SShravan Kumar Ramani #include <linux/acpi.h> 4c78c42d7SShravan Kumar Ramani #include <linux/bitops.h> 5c78c42d7SShravan Kumar Ramani #include <linux/device.h> 6c78c42d7SShravan Kumar Ramani #include <linux/gpio/driver.h> 7c78c42d7SShravan Kumar Ramani #include <linux/io.h> 8c78c42d7SShravan Kumar Ramani #include <linux/kernel.h> 9c78c42d7SShravan Kumar Ramani #include <linux/module.h> 10c78c42d7SShravan Kumar Ramani #include <linux/platform_device.h> 11c78c42d7SShravan Kumar Ramani #include <linux/pm.h> 12c78c42d7SShravan Kumar Ramani #include <linux/resource.h> 13c78c42d7SShravan Kumar Ramani #include <linux/types.h> 14c78c42d7SShravan Kumar Ramani 15c78c42d7SShravan Kumar Ramani /* Number of pins on BlueField */ 16c78c42d7SShravan Kumar Ramani #define MLXBF_GPIO_NR 54 17c78c42d7SShravan Kumar Ramani 18c78c42d7SShravan Kumar Ramani /* Pad Electrical Controls. */ 19c78c42d7SShravan Kumar Ramani #define MLXBF_GPIO_PAD_CONTROL_FIRST_WORD 0x0700 20c78c42d7SShravan Kumar Ramani #define MLXBF_GPIO_PAD_CONTROL_1_FIRST_WORD 0x0708 21c78c42d7SShravan Kumar Ramani #define MLXBF_GPIO_PAD_CONTROL_2_FIRST_WORD 0x0710 22c78c42d7SShravan Kumar Ramani #define MLXBF_GPIO_PAD_CONTROL_3_FIRST_WORD 0x0718 23c78c42d7SShravan Kumar Ramani 24c78c42d7SShravan Kumar Ramani #define MLXBF_GPIO_PIN_DIR_I 0x1040 25c78c42d7SShravan Kumar Ramani #define MLXBF_GPIO_PIN_DIR_O 0x1048 26c78c42d7SShravan Kumar Ramani #define MLXBF_GPIO_PIN_STATE 0x1000 27c78c42d7SShravan Kumar Ramani #define MLXBF_GPIO_SCRATCHPAD 0x20 28c78c42d7SShravan Kumar Ramani 29c78c42d7SShravan Kumar Ramani #ifdef CONFIG_PM 30c78c42d7SShravan Kumar Ramani struct mlxbf_gpio_context_save_regs { 31c78c42d7SShravan Kumar Ramani u64 scratchpad; 32c78c42d7SShravan Kumar Ramani u64 pad_control[MLXBF_GPIO_NR]; 33c78c42d7SShravan Kumar Ramani u64 pin_dir_i; 34c78c42d7SShravan Kumar Ramani u64 pin_dir_o; 35c78c42d7SShravan Kumar Ramani }; 36c78c42d7SShravan Kumar Ramani #endif 37c78c42d7SShravan Kumar Ramani 38c78c42d7SShravan Kumar Ramani /* Device state structure. */ 39c78c42d7SShravan Kumar Ramani struct mlxbf_gpio_state { 40c78c42d7SShravan Kumar Ramani struct gpio_chip gc; 41c78c42d7SShravan Kumar Ramani 42c78c42d7SShravan Kumar Ramani /* Memory Address */ 43c78c42d7SShravan Kumar Ramani void __iomem *base; 44c78c42d7SShravan Kumar Ramani 45c78c42d7SShravan Kumar Ramani #ifdef CONFIG_PM 46c78c42d7SShravan Kumar Ramani struct mlxbf_gpio_context_save_regs csave_regs; 47c78c42d7SShravan Kumar Ramani #endif 48c78c42d7SShravan Kumar Ramani }; 49c78c42d7SShravan Kumar Ramani 50c78c42d7SShravan Kumar Ramani static int mlxbf_gpio_probe(struct platform_device *pdev) 51c78c42d7SShravan Kumar Ramani { 52c78c42d7SShravan Kumar Ramani struct mlxbf_gpio_state *gs; 53c78c42d7SShravan Kumar Ramani struct device *dev = &pdev->dev; 54c78c42d7SShravan Kumar Ramani struct gpio_chip *gc; 55c78c42d7SShravan Kumar Ramani int ret; 56c78c42d7SShravan Kumar Ramani 57c78c42d7SShravan Kumar Ramani gs = devm_kzalloc(&pdev->dev, sizeof(*gs), GFP_KERNEL); 58c78c42d7SShravan Kumar Ramani if (!gs) 59c78c42d7SShravan Kumar Ramani return -ENOMEM; 60c78c42d7SShravan Kumar Ramani 61c78c42d7SShravan Kumar Ramani gs->base = devm_platform_ioremap_resource(pdev, 0); 62c78c42d7SShravan Kumar Ramani if (IS_ERR(gs->base)) 63c78c42d7SShravan Kumar Ramani return PTR_ERR(gs->base); 64c78c42d7SShravan Kumar Ramani 65c78c42d7SShravan Kumar Ramani gc = &gs->gc; 66c78c42d7SShravan Kumar Ramani ret = bgpio_init(gc, dev, 8, 67c78c42d7SShravan Kumar Ramani gs->base + MLXBF_GPIO_PIN_STATE, 68c78c42d7SShravan Kumar Ramani NULL, 69c78c42d7SShravan Kumar Ramani NULL, 70c78c42d7SShravan Kumar Ramani gs->base + MLXBF_GPIO_PIN_DIR_O, 71c78c42d7SShravan Kumar Ramani gs->base + MLXBF_GPIO_PIN_DIR_I, 72c78c42d7SShravan Kumar Ramani 0); 73c78c42d7SShravan Kumar Ramani if (ret) 74c78c42d7SShravan Kumar Ramani return -ENODEV; 75c78c42d7SShravan Kumar Ramani 76c78c42d7SShravan Kumar Ramani gc->owner = THIS_MODULE; 77c78c42d7SShravan Kumar Ramani gc->ngpio = MLXBF_GPIO_NR; 78c78c42d7SShravan Kumar Ramani 79c78c42d7SShravan Kumar Ramani ret = devm_gpiochip_add_data(dev, &gs->gc, gs); 80c78c42d7SShravan Kumar Ramani if (ret) { 81c78c42d7SShravan Kumar Ramani dev_err(&pdev->dev, "Failed adding memory mapped gpiochip\n"); 82c78c42d7SShravan Kumar Ramani return ret; 83c78c42d7SShravan Kumar Ramani } 84c78c42d7SShravan Kumar Ramani 85c78c42d7SShravan Kumar Ramani platform_set_drvdata(pdev, gs); 86c78c42d7SShravan Kumar Ramani dev_info(&pdev->dev, "registered Mellanox BlueField GPIO"); 87c78c42d7SShravan Kumar Ramani return 0; 88c78c42d7SShravan Kumar Ramani } 89c78c42d7SShravan Kumar Ramani 90c78c42d7SShravan Kumar Ramani #ifdef CONFIG_PM 91c78c42d7SShravan Kumar Ramani static int mlxbf_gpio_suspend(struct platform_device *pdev, pm_message_t state) 92c78c42d7SShravan Kumar Ramani { 93c78c42d7SShravan Kumar Ramani struct mlxbf_gpio_state *gs = platform_get_drvdata(pdev); 94c78c42d7SShravan Kumar Ramani 95c78c42d7SShravan Kumar Ramani gs->csave_regs.scratchpad = readq(gs->base + MLXBF_GPIO_SCRATCHPAD); 96c78c42d7SShravan Kumar Ramani gs->csave_regs.pad_control[0] = 97c78c42d7SShravan Kumar Ramani readq(gs->base + MLXBF_GPIO_PAD_CONTROL_FIRST_WORD); 98c78c42d7SShravan Kumar Ramani gs->csave_regs.pad_control[1] = 99c78c42d7SShravan Kumar Ramani readq(gs->base + MLXBF_GPIO_PAD_CONTROL_1_FIRST_WORD); 100c78c42d7SShravan Kumar Ramani gs->csave_regs.pad_control[2] = 101c78c42d7SShravan Kumar Ramani readq(gs->base + MLXBF_GPIO_PAD_CONTROL_2_FIRST_WORD); 102c78c42d7SShravan Kumar Ramani gs->csave_regs.pad_control[3] = 103c78c42d7SShravan Kumar Ramani readq(gs->base + MLXBF_GPIO_PAD_CONTROL_3_FIRST_WORD); 104c78c42d7SShravan Kumar Ramani gs->csave_regs.pin_dir_i = readq(gs->base + MLXBF_GPIO_PIN_DIR_I); 105c78c42d7SShravan Kumar Ramani gs->csave_regs.pin_dir_o = readq(gs->base + MLXBF_GPIO_PIN_DIR_O); 106c78c42d7SShravan Kumar Ramani 107c78c42d7SShravan Kumar Ramani return 0; 108c78c42d7SShravan Kumar Ramani } 109c78c42d7SShravan Kumar Ramani 110c78c42d7SShravan Kumar Ramani static int mlxbf_gpio_resume(struct platform_device *pdev) 111c78c42d7SShravan Kumar Ramani { 112c78c42d7SShravan Kumar Ramani struct mlxbf_gpio_state *gs = platform_get_drvdata(pdev); 113c78c42d7SShravan Kumar Ramani 114c78c42d7SShravan Kumar Ramani writeq(gs->csave_regs.scratchpad, gs->base + MLXBF_GPIO_SCRATCHPAD); 115c78c42d7SShravan Kumar Ramani writeq(gs->csave_regs.pad_control[0], 116c78c42d7SShravan Kumar Ramani gs->base + MLXBF_GPIO_PAD_CONTROL_FIRST_WORD); 117c78c42d7SShravan Kumar Ramani writeq(gs->csave_regs.pad_control[1], 118c78c42d7SShravan Kumar Ramani gs->base + MLXBF_GPIO_PAD_CONTROL_1_FIRST_WORD); 119c78c42d7SShravan Kumar Ramani writeq(gs->csave_regs.pad_control[2], 120c78c42d7SShravan Kumar Ramani gs->base + MLXBF_GPIO_PAD_CONTROL_2_FIRST_WORD); 121c78c42d7SShravan Kumar Ramani writeq(gs->csave_regs.pad_control[3], 122c78c42d7SShravan Kumar Ramani gs->base + MLXBF_GPIO_PAD_CONTROL_3_FIRST_WORD); 123c78c42d7SShravan Kumar Ramani writeq(gs->csave_regs.pin_dir_i, gs->base + MLXBF_GPIO_PIN_DIR_I); 124c78c42d7SShravan Kumar Ramani writeq(gs->csave_regs.pin_dir_o, gs->base + MLXBF_GPIO_PIN_DIR_O); 125c78c42d7SShravan Kumar Ramani 126c78c42d7SShravan Kumar Ramani return 0; 127c78c42d7SShravan Kumar Ramani } 128c78c42d7SShravan Kumar Ramani #endif 129c78c42d7SShravan Kumar Ramani 130*6ac2de95SLee Jones static const struct acpi_device_id __maybe_unused mlxbf_gpio_acpi_match[] = { 131c78c42d7SShravan Kumar Ramani { "MLNXBF02", 0 }, 132c78c42d7SShravan Kumar Ramani {} 133c78c42d7SShravan Kumar Ramani }; 134c78c42d7SShravan Kumar Ramani MODULE_DEVICE_TABLE(acpi, mlxbf_gpio_acpi_match); 135c78c42d7SShravan Kumar Ramani 136c78c42d7SShravan Kumar Ramani static struct platform_driver mlxbf_gpio_driver = { 137c78c42d7SShravan Kumar Ramani .driver = { 138c78c42d7SShravan Kumar Ramani .name = "mlxbf_gpio", 139c78c42d7SShravan Kumar Ramani .acpi_match_table = ACPI_PTR(mlxbf_gpio_acpi_match), 140c78c42d7SShravan Kumar Ramani }, 141c78c42d7SShravan Kumar Ramani .probe = mlxbf_gpio_probe, 142c78c42d7SShravan Kumar Ramani #ifdef CONFIG_PM 143c78c42d7SShravan Kumar Ramani .suspend = mlxbf_gpio_suspend, 144c78c42d7SShravan Kumar Ramani .resume = mlxbf_gpio_resume, 145c78c42d7SShravan Kumar Ramani #endif 146c78c42d7SShravan Kumar Ramani }; 147c78c42d7SShravan Kumar Ramani 148c78c42d7SShravan Kumar Ramani module_platform_driver(mlxbf_gpio_driver); 149c78c42d7SShravan Kumar Ramani 150c78c42d7SShravan Kumar Ramani MODULE_DESCRIPTION("Mellanox BlueField GPIO Driver"); 151c78c42d7SShravan Kumar Ramani MODULE_AUTHOR("Mellanox Technologies"); 152c78c42d7SShravan Kumar Ramani MODULE_LICENSE("GPL"); 153