summaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpio-mlxbf.c
blob: 1fa9973f55b96a4b517b5864ffb92fbbf8626053 (plain)
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 __maybe_unused 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");