File Index
Files and directories
Sign in
FILE

mlxreg-dpu.c

File preview with syntax highlighting.

linux-6.19.14/drivers/platform/mellanox/mlxreg-dpu.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Nvidia Data Processor Unit platform driver
  4 *
  5 * Copyright (C) 2025 Nvidia Technologies Ltd.
  6 */
  7
  8#include <linux/device.h>
  9#include <linux/dev_printk.h>
 10#include <linux/i2c.h>
 11#include <linux/module.h>
 12#include <linux/platform_data/mlxcpld.h>
 13#include <linux/platform_data/mlxreg.h>
 14#include <linux/platform_device.h>
 15#include <linux/regmap.h>
 16
 17/* I2C bus IO offsets */
 18#define MLXREG_DPU_REG_FPGA1_VER_OFFSET			0x2400
 19#define MLXREG_DPU_REG_FPGA1_PN_OFFSET			0x2404
 20#define MLXREG_DPU_REG_FPGA1_PN1_OFFSET			0x2405
 21#define MLXREG_DPU_REG_PG_OFFSET			0x2414
 22#define MLXREG_DPU_REG_PG_EVENT_OFFSET			0x2415
 23#define MLXREG_DPU_REG_PG_MASK_OFFSET			0x2416
 24#define MLXREG_DPU_REG_RESET_GP1_OFFSET			0x2417
 25#define MLXREG_DPU_REG_RST_CAUSE1_OFFSET		0x241e
 26#define MLXREG_DPU_REG_GP0_RO_OFFSET			0x242b
 27#define MLXREG_DPU_REG_GP0_OFFSET			0x242e
 28#define MLXREG_DPU_REG_GP1_OFFSET			0x242c
 29#define MLXREG_DPU_REG_GP4_OFFSET			0x2438
 30#define MLXREG_DPU_REG_AGGRCO_OFFSET			0x2442
 31#define MLXREG_DPU_REG_AGGRCO_MASK_OFFSET		0x2443
 32#define MLXREG_DPU_REG_HEALTH_OFFSET			0x244d
 33#define MLXREG_DPU_REG_HEALTH_EVENT_OFFSET		0x244e
 34#define MLXREG_DPU_REG_HEALTH_MASK_OFFSET		0x244f
 35#define MLXREG_DPU_REG_FPGA1_MVER_OFFSET		0x24de
 36#define MLXREG_DPU_REG_CONFIG3_OFFSET			0x24fd
 37#define MLXREG_DPU_REG_MAX				0x3fff
 38
 39/* Power Good event masks. */
 40#define MLXREG_DPU_PG_VDDIO_MASK			BIT(0)
 41#define MLXREG_DPU_PG_VDD_CPU_MASK			BIT(1)
 42#define MLXREG_DPU_PG_VDD_MASK				BIT(2)
 43#define MLXREG_DPU_PG_1V8_MASK				BIT(3)
 44#define MLXREG_DPU_PG_COMPARATOR_MASK			BIT(4)
 45#define MLXREG_DPU_PG_VDDQ_MASK				BIT(5)
 46#define MLXREG_DPU_PG_HVDD_MASK				BIT(6)
 47#define MLXREG_DPU_PG_DVDD_MASK				BIT(7)
 48#define MLXREG_DPU_PG_MASK				(MLXREG_DPU_PG_DVDD_MASK | \
 49							 MLXREG_DPU_PG_HVDD_MASK | \
 50							 MLXREG_DPU_PG_VDDQ_MASK | \
 51							 MLXREG_DPU_PG_COMPARATOR_MASK | \
 52							 MLXREG_DPU_PG_1V8_MASK | \
 53							 MLXREG_DPU_PG_VDD_CPU_MASK | \
 54							 MLXREG_DPU_PG_VDD_MASK | \
 55							 MLXREG_DPU_PG_VDDIO_MASK)
 56
 57/* Health event masks. */
 58#define MLXREG_DPU_HLTH_THERMAL_TRIP_MASK		BIT(0)
 59#define MLXREG_DPU_HLTH_UFM_UPGRADE_DONE_MASK		BIT(1)
 60#define MLXREG_DPU_HLTH_VDDQ_HOT_ALERT_MASK		BIT(2)
 61#define MLXREG_DPU_HLTH_VDD_CPU_HOT_ALERT_MASK		BIT(3)
 62#define MLXREG_DPU_HLTH_VDDQ_ALERT_MASK			BIT(4)
 63#define MLXREG_DPU_HLTH_VDD_CPU_ALERT_MASK		BIT(5)
 64#define MLXREG_DPU_HEALTH_MASK				(MLXREG_DPU_HLTH_UFM_UPGRADE_DONE_MASK | \
 65							 MLXREG_DPU_HLTH_VDDQ_HOT_ALERT_MASK | \
 66							 MLXREG_DPU_HLTH_VDD_CPU_HOT_ALERT_MASK | \
 67							 MLXREG_DPU_HLTH_VDDQ_ALERT_MASK | \
 68							 MLXREG_DPU_HLTH_VDD_CPU_ALERT_MASK | \
 69							 MLXREG_DPU_HLTH_THERMAL_TRIP_MASK)
 70
 71/* Hotplug aggregation masks. */
 72#define MLXREG_DPU_HEALTH_AGGR_MASK			BIT(0)
 73#define MLXREG_DPU_PG_AGGR_MASK				BIT(1)
 74#define MLXREG_DPU_AGGR_MASK				(MLXREG_DPU_HEALTH_AGGR_MASK | \
 75							 MLXREG_DPU_PG_AGGR_MASK)
 76
 77/* Voltage regulator firmware update status mask. */
 78#define MLXREG_DPU_VOLTREG_UPD_MASK			GENMASK(5, 4)
 79
 80#define MLXREG_DPU_NR_NONE				(-1)
 81
 82/*
 83 * enum mlxreg_dpu_type - Data Processor Unit types
 84 *
 85 * @MLXREG_DPU_BF3: DPU equipped with BF3 SoC;
 86 */
 87enum mlxreg_dpu_type {
 88	MLXREG_DPU_BF3 = 0x0050,
 89};
 90
 91/* Default register access data. */
 92static struct mlxreg_core_data mlxreg_dpu_io_data[] = {
 93	{
 94		.label = "fpga1_version",
 95		.reg = MLXREG_DPU_REG_FPGA1_VER_OFFSET,
 96		.bit = GENMASK(7, 0),
 97		.mode = 0444,
 98	},
 99	{
100		.label = "fpga1_pn",
101		.reg = MLXREG_DPU_REG_FPGA1_PN_OFFSET,
102		.bit = GENMASK(15, 0),
103		.mode = 0444,
104		.regnum = 2,
105	},
106	{
107		.label = "fpga1_version_min",
108		.reg = MLXREG_DPU_REG_FPGA1_MVER_OFFSET,
109		.bit = GENMASK(7, 0),
110		.mode = 0444,
111	},
112	{
113		.label = "perst_rst",
114		.reg = MLXREG_DPU_REG_RESET_GP1_OFFSET,
115		.mask = GENMASK(7, 0) & ~BIT(0),
116		.mode = 0644,
117	},
118	{
119		.label = "usbphy_rst",
120		.reg = MLXREG_DPU_REG_RESET_GP1_OFFSET,
121		.mask = GENMASK(7, 0) & ~BIT(1),
122		.mode = 0644,
123	},
124	{
125		.label = "phy_rst",
126		.reg = MLXREG_DPU_REG_RESET_GP1_OFFSET,
127		.mask = GENMASK(7, 0) & ~BIT(2),
128		.mode = 0644,
129	},
130	{
131		.label = "tpm_rst",
132		.reg = MLXREG_DPU_REG_RESET_GP1_OFFSET,
133		.mask = GENMASK(7, 0) & ~BIT(6),
134		.mode = 0644,
135	},
136	{
137		.label = "reset_from_main_board",
138		.reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET,
139		.mask = GENMASK(7, 0) & ~BIT(1),
140		.mode = 0444,
141	},
142	{
143		.label = "reset_aux_pwr_or_reload",
144		.reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET,
145		.mask = GENMASK(7, 0) & ~BIT(2),
146		.mode = 0444,
147	},
148	{
149		.label = "reset_comex_pwr_fail",
150		.reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET,
151		.mask = GENMASK(7, 0) & ~BIT(3),
152		.mode = 0444,
153	},
154	{
155		.label = "reset_dpu_thermal",
156		.reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET,
157		.mask = GENMASK(7, 0) & ~BIT(6),
158		.mode = 0444,
159	},
160	{
161		.label = "reset_pwr_off",
162		.reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET,
163		.mask = GENMASK(7, 0) & ~BIT(7),
164		.mode = 0444,
165	},
166	{
167		.label = "dpu_id",
168		.reg = MLXREG_DPU_REG_GP0_RO_OFFSET,
169		.bit = GENMASK(3, 0),
170		.mode = 0444,
171	},
172	{
173		.label = "voltreg_update_status",
174		.reg = MLXREG_DPU_REG_GP0_RO_OFFSET,
175		.mask = MLXREG_DPU_VOLTREG_UPD_MASK,
176		.bit = 5,
177		.mode = 0444,
178	},
179	{
180		.label = "boot_progress",
181		.reg = MLXREG_DPU_REG_GP1_OFFSET,
182		.mask = GENMASK(3, 0),
183		.mode = 0444,
184	},
185	{
186		.label = "ufm_upgrade",
187		.reg = MLXREG_DPU_REG_GP4_OFFSET,
188		.mask = GENMASK(7, 0) & ~BIT(1),
189		.mode = 0644,
190	},
191};
192
193static struct mlxreg_core_platform_data mlxreg_dpu_default_regs_io_data = {
194		.data = mlxreg_dpu_io_data,
195		.counter = ARRAY_SIZE(mlxreg_dpu_io_data),
196};
197
198/* Default hotplug data. */
199static struct mlxreg_core_data mlxreg_dpu_power_events_items_data[] = {
200	{
201		.label = "pg_vddio",
202		.reg = MLXREG_DPU_REG_PG_OFFSET,
203		.mask = MLXREG_DPU_PG_VDDIO_MASK,
204		.hpdev.nr = MLXREG_DPU_NR_NONE,
205	},
206	{
207		.label = "pg_vdd_cpu",
208		.reg = MLXREG_DPU_REG_PG_OFFSET,
209		.mask = MLXREG_DPU_PG_VDD_CPU_MASK,
210		.hpdev.nr = MLXREG_DPU_NR_NONE,
211	},
212	{
213		.label = "pg_vdd",
214		.reg = MLXREG_DPU_REG_PG_OFFSET,
215		.mask = MLXREG_DPU_PG_VDD_MASK,
216		.hpdev.nr = MLXREG_DPU_NR_NONE,
217	},
218	{
219		.label = "pg_1v8",
220		.reg = MLXREG_DPU_REG_PG_OFFSET,
221		.mask = MLXREG_DPU_PG_1V8_MASK,
222		.hpdev.nr = MLXREG_DPU_NR_NONE,
223	},
224	{
225		.label = "pg_comparator",
226		.reg = MLXREG_DPU_REG_PG_OFFSET,
227		.mask = MLXREG_DPU_PG_COMPARATOR_MASK,
228		.hpdev.nr = MLXREG_DPU_NR_NONE,
229	},
230	{
231		.label = "pg_vddq",
232		.reg = MLXREG_DPU_REG_PG_OFFSET,
233		.mask = MLXREG_DPU_PG_VDDQ_MASK,
234		.hpdev.nr = MLXREG_DPU_NR_NONE,
235	},
236	{
237		.label = "pg_hvdd",
238		.reg = MLXREG_DPU_REG_PG_OFFSET,
239		.mask = MLXREG_DPU_PG_HVDD_MASK,
240		.hpdev.nr = MLXREG_DPU_NR_NONE,
241	},
242	{
243		.label = "pg_dvdd",
244		.reg = MLXREG_DPU_REG_PG_OFFSET,
245		.mask = MLXREG_DPU_PG_DVDD_MASK,
246		.hpdev.nr = MLXREG_DPU_NR_NONE,
247	},
248};
249
250static struct mlxreg_core_data mlxreg_dpu_health_events_items_data[] = {
251	{
252		.label = "thermal_trip",
253		.reg = MLXREG_DPU_REG_HEALTH_OFFSET,
254		.mask = MLXREG_DPU_HLTH_THERMAL_TRIP_MASK,
255		.hpdev.nr = MLXREG_DPU_NR_NONE,
256	},
257	{
258		.label = "ufm_upgrade_done",
259		.reg = MLXREG_DPU_REG_HEALTH_OFFSET,
260		.mask = MLXREG_DPU_HLTH_UFM_UPGRADE_DONE_MASK,
261		.hpdev.nr = MLXREG_DPU_NR_NONE,
262	},
263	{
264		.label = "vddq_hot_alert",
265		.reg = MLXREG_DPU_REG_HEALTH_OFFSET,
266		.mask = MLXREG_DPU_HLTH_VDDQ_HOT_ALERT_MASK,
267		.hpdev.nr = MLXREG_DPU_NR_NONE,
268	},
269	{
270		.label = "vdd_cpu_hot_alert",
271		.reg = MLXREG_DPU_REG_HEALTH_OFFSET,
272		.mask = MLXREG_DPU_HLTH_VDD_CPU_HOT_ALERT_MASK,
273		.hpdev.nr = MLXREG_DPU_NR_NONE,
274	},
275	{
276		.label = "vddq_alert",
277		.reg = MLXREG_DPU_REG_HEALTH_OFFSET,
278		.mask = MLXREG_DPU_HLTH_VDDQ_ALERT_MASK,
279		.hpdev.nr = MLXREG_DPU_NR_NONE,
280	},
281	{
282		.label = "vdd_cpu_alert",
283		.reg = MLXREG_DPU_REG_HEALTH_OFFSET,
284		.mask = MLXREG_DPU_HLTH_VDD_CPU_ALERT_MASK,
285		.hpdev.nr = MLXREG_DPU_NR_NONE,
286	},
287};
288
289static struct mlxreg_core_item mlxreg_dpu_hotplug_items[] = {
290	{
291		.data = mlxreg_dpu_power_events_items_data,
292		.aggr_mask = MLXREG_DPU_PG_AGGR_MASK,
293		.reg = MLXREG_DPU_REG_PG_OFFSET,
294		.mask = MLXREG_DPU_PG_MASK,
295		.count = ARRAY_SIZE(mlxreg_dpu_power_events_items_data),
296		.health = false,
297		.inversed = 0,
298	},
299	{
300		.data = mlxreg_dpu_health_events_items_data,
301		.aggr_mask = MLXREG_DPU_HEALTH_AGGR_MASK,
302		.reg = MLXREG_DPU_REG_HEALTH_OFFSET,
303		.mask = MLXREG_DPU_HEALTH_MASK,
304		.count = ARRAY_SIZE(mlxreg_dpu_health_events_items_data),
305		.health = false,
306		.inversed = 0,
307	},
308};
309
310static
311struct mlxreg_core_hotplug_platform_data mlxreg_dpu_default_hotplug_data = {
312	.items = mlxreg_dpu_hotplug_items,
313	.count = ARRAY_SIZE(mlxreg_dpu_hotplug_items),
314	.cell = MLXREG_DPU_REG_AGGRCO_OFFSET,
315	.mask = MLXREG_DPU_AGGR_MASK,
316};
317
318/**
319 * struct mlxreg_dpu - device private data
320 * @dev: platform device
321 * @data: platform core data
322 * @io_data: register access platform data
323 * @io_regs: register access device
324 * @hotplug_data: hotplug platform data
325 * @hotplug: hotplug device
326 */
327struct mlxreg_dpu {
328	struct device *dev;
329	struct mlxreg_core_data *data;
330	struct mlxreg_core_platform_data *io_data;
331	struct platform_device *io_regs;
332	struct mlxreg_core_hotplug_platform_data *hotplug_data;
333	struct platform_device *hotplug;
334};
335
336static bool mlxreg_dpu_writeable_reg(struct device *dev, unsigned int reg)
337{
338	switch (reg) {
339	case MLXREG_DPU_REG_PG_EVENT_OFFSET:
340	case MLXREG_DPU_REG_PG_MASK_OFFSET:
341	case MLXREG_DPU_REG_RESET_GP1_OFFSET:
342	case MLXREG_DPU_REG_GP0_OFFSET:
343	case MLXREG_DPU_REG_GP1_OFFSET:
344	case MLXREG_DPU_REG_GP4_OFFSET:
345	case MLXREG_DPU_REG_AGGRCO_OFFSET:
346	case MLXREG_DPU_REG_AGGRCO_MASK_OFFSET:
347	case MLXREG_DPU_REG_HEALTH_EVENT_OFFSET:
348	case MLXREG_DPU_REG_HEALTH_MASK_OFFSET:
349		return true;
350	}
351	return false;
352}
353
354static bool mlxreg_dpu_readable_reg(struct device *dev, unsigned int reg)
355{
356	switch (reg) {
357	case MLXREG_DPU_REG_FPGA1_VER_OFFSET:
358	case MLXREG_DPU_REG_FPGA1_PN_OFFSET:
359	case MLXREG_DPU_REG_FPGA1_PN1_OFFSET:
360	case MLXREG_DPU_REG_PG_OFFSET:
361	case MLXREG_DPU_REG_PG_EVENT_OFFSET:
362	case MLXREG_DPU_REG_PG_MASK_OFFSET:
363	case MLXREG_DPU_REG_RESET_GP1_OFFSET:
364	case MLXREG_DPU_REG_RST_CAUSE1_OFFSET:
365	case MLXREG_DPU_REG_GP0_RO_OFFSET:
366	case MLXREG_DPU_REG_GP0_OFFSET:
367	case MLXREG_DPU_REG_GP1_OFFSET:
368	case MLXREG_DPU_REG_GP4_OFFSET:
369	case MLXREG_DPU_REG_AGGRCO_OFFSET:
370	case MLXREG_DPU_REG_AGGRCO_MASK_OFFSET:
371	case MLXREG_DPU_REG_HEALTH_OFFSET:
372	case MLXREG_DPU_REG_HEALTH_EVENT_OFFSET:
373	case MLXREG_DPU_REG_HEALTH_MASK_OFFSET:
374	case MLXREG_DPU_REG_FPGA1_MVER_OFFSET:
375	case MLXREG_DPU_REG_CONFIG3_OFFSET:
376		return true;
377	}
378	return false;
379}
380
381static bool mlxreg_dpu_volatile_reg(struct device *dev, unsigned int reg)
382{
383	switch (reg) {
384	case MLXREG_DPU_REG_FPGA1_VER_OFFSET:
385	case MLXREG_DPU_REG_FPGA1_PN_OFFSET:
386	case MLXREG_DPU_REG_FPGA1_PN1_OFFSET:
387	case MLXREG_DPU_REG_PG_OFFSET:
388	case MLXREG_DPU_REG_PG_EVENT_OFFSET:
389	case MLXREG_DPU_REG_PG_MASK_OFFSET:
390	case MLXREG_DPU_REG_RESET_GP1_OFFSET:
391	case MLXREG_DPU_REG_RST_CAUSE1_OFFSET:
392	case MLXREG_DPU_REG_GP0_RO_OFFSET:
393	case MLXREG_DPU_REG_GP0_OFFSET:
394	case MLXREG_DPU_REG_GP1_OFFSET:
395	case MLXREG_DPU_REG_GP4_OFFSET:
396	case MLXREG_DPU_REG_AGGRCO_OFFSET:
397	case MLXREG_DPU_REG_AGGRCO_MASK_OFFSET:
398	case MLXREG_DPU_REG_HEALTH_OFFSET:
399	case MLXREG_DPU_REG_HEALTH_EVENT_OFFSET:
400	case MLXREG_DPU_REG_HEALTH_MASK_OFFSET:
401	case MLXREG_DPU_REG_FPGA1_MVER_OFFSET:
402	case MLXREG_DPU_REG_CONFIG3_OFFSET:
403		return true;
404	}
405	return false;
406}
407
408/* Configuration for the register map of a device with 2 bytes address space. */
409static const struct regmap_config mlxreg_dpu_regmap_conf = {
410	.reg_bits = 16,
411	.val_bits = 8,
412	.max_register = MLXREG_DPU_REG_MAX,
413	.cache_type = REGCACHE_FLAT,
414	.writeable_reg = mlxreg_dpu_writeable_reg,
415	.readable_reg = mlxreg_dpu_readable_reg,
416	.volatile_reg = mlxreg_dpu_volatile_reg,
417};
418
419static int
420mlxreg_dpu_copy_hotplug_data(struct device *dev, struct mlxreg_dpu *mlxreg_dpu,
421			     const struct mlxreg_core_hotplug_platform_data *hotplug_data)
422{
423	struct mlxreg_core_item *item;
424	int i;
425
426	mlxreg_dpu->hotplug_data = devm_kmemdup(dev, hotplug_data,
427						sizeof(*mlxreg_dpu->hotplug_data), GFP_KERNEL);
428	if (!mlxreg_dpu->hotplug_data)
429		return -ENOMEM;
430
431	mlxreg_dpu->hotplug_data->items = devm_kmemdup(dev, hotplug_data->items,
432						       mlxreg_dpu->hotplug_data->count *
433						       sizeof(*mlxreg_dpu->hotplug_data->items),
434						       GFP_KERNEL);
435	if (!mlxreg_dpu->hotplug_data->items)
436		return -ENOMEM;
437
438	item = mlxreg_dpu->hotplug_data->items;
439	for (i = 0; i < hotplug_data->count; i++, item++) {
440		item->data = devm_kmemdup(dev, hotplug_data->items[i].data,
441					  hotplug_data->items[i].count * sizeof(*item->data),
442					  GFP_KERNEL);
443		if (!item->data)
444			return -ENOMEM;
445	}
446
447	return 0;
448}
449
450static int mlxreg_dpu_config_init(struct mlxreg_dpu *mlxreg_dpu, void *regmap,
451				  struct mlxreg_core_data *data, int irq)
452{
453	struct device *dev = &data->hpdev.client->dev;
454	u32 regval;
455	int err;
456
457	/* Validate DPU type. */
458	err = regmap_read(regmap, MLXREG_DPU_REG_CONFIG3_OFFSET, &regval);
459	if (err)
460		return err;
461
462	switch (regval) {
463	case MLXREG_DPU_BF3:
464		/* Copy platform specific hotplug data. */
465		err = mlxreg_dpu_copy_hotplug_data(dev, mlxreg_dpu,
466						   &mlxreg_dpu_default_hotplug_data);
467		if (err)
468			return err;
469
470		mlxreg_dpu->io_data = &mlxreg_dpu_default_regs_io_data;
471
472		break;
473	default:
474		return -ENODEV;
475	}
476
477	/* Register IO access driver. */
478	if (mlxreg_dpu->io_data) {
479		mlxreg_dpu->io_data->regmap = regmap;
480		mlxreg_dpu->io_regs =
481			platform_device_register_resndata(dev, "mlxreg-io",
482							  data->slot, NULL, 0,
483							  mlxreg_dpu->io_data,
484							  sizeof(*mlxreg_dpu->io_data));
485		if (IS_ERR(mlxreg_dpu->io_regs)) {
486			dev_err(dev, "Failed to create region for client %s at bus %d at addr 0x%02x\n",
487				data->hpdev.brdinfo->type, data->hpdev.nr,
488				data->hpdev.brdinfo->addr);
489			return PTR_ERR(mlxreg_dpu->io_regs);
490		}
491	}
492
493	/* Register hotplug driver. */
494	if (mlxreg_dpu->hotplug_data && irq) {
495		mlxreg_dpu->hotplug_data->regmap = regmap;
496		mlxreg_dpu->hotplug_data->irq = irq;
497		mlxreg_dpu->hotplug =
498			platform_device_register_resndata(dev, "mlxreg-hotplug",
499							  data->slot, NULL, 0,
500							  mlxreg_dpu->hotplug_data,
501							  sizeof(*mlxreg_dpu->hotplug_data));
502		if (IS_ERR(mlxreg_dpu->hotplug)) {
503			err = PTR_ERR(mlxreg_dpu->hotplug);
504			goto fail_register_hotplug;
505		}
506	}
507
508	return 0;
509
510fail_register_hotplug:
511	platform_device_unregister(mlxreg_dpu->io_regs);
512
513	return err;
514}
515
516static void mlxreg_dpu_config_exit(struct mlxreg_dpu *mlxreg_dpu)
517{
518	platform_device_unregister(mlxreg_dpu->hotplug);
519	platform_device_unregister(mlxreg_dpu->io_regs);
520}
521
522static int mlxreg_dpu_probe(struct platform_device *pdev)
523{
524	struct mlxreg_core_data *data;
525	struct mlxreg_dpu *mlxreg_dpu;
526	void *regmap;
527	int err;
528
529	data = dev_get_platdata(&pdev->dev);
530	if (!data || !data->hpdev.brdinfo)
531		return -EINVAL;
532
533	data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr);
534	if (!data->hpdev.adapter)
535		return -EPROBE_DEFER;
536
537	mlxreg_dpu = devm_kzalloc(&pdev->dev, sizeof(*mlxreg_dpu), GFP_KERNEL);
538	if (!mlxreg_dpu) {
539		err = -ENOMEM;
540		goto alloc_fail;
541	}
542
543	/* Create device at the top of DPU I2C tree. */
544	data->hpdev.client = i2c_new_client_device(data->hpdev.adapter,
545						   data->hpdev.brdinfo);
546	if (IS_ERR(data->hpdev.client)) {
547		dev_err(&pdev->dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
548			data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr);
549		err = PTR_ERR(data->hpdev.client);
550		goto i2c_new_device_fail;
551	}
552
553	regmap = devm_regmap_init_i2c(data->hpdev.client, &mlxreg_dpu_regmap_conf);
554	if (IS_ERR(regmap)) {
555		dev_err(&pdev->dev, "Failed to create regmap for client %s at bus %d at addr 0x%02x\n",
556			data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr);
557		err = PTR_ERR(regmap);
558		goto devm_regmap_init_i2c_fail;
559	}
560
561	/* Sync registers with hardware. */
562	regcache_mark_dirty(regmap);
563	err = regcache_sync(regmap);
564	if (err) {
565		dev_err(&pdev->dev, "Failed to sync regmap for client %s at bus %d at addr 0x%02x\n",
566			data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr);
567		goto regcache_sync_fail;
568	}
569
570	mlxreg_dpu->data = data;
571	mlxreg_dpu->dev = &pdev->dev;
572	platform_set_drvdata(pdev, mlxreg_dpu);
573
574	err = mlxreg_dpu_config_init(mlxreg_dpu, regmap, data, data->hpdev.brdinfo->irq);
575	if (err)
576		goto mlxreg_dpu_config_init_fail;
577
578	return err;
579
580mlxreg_dpu_config_init_fail:
581regcache_sync_fail:
582devm_regmap_init_i2c_fail:
583	i2c_unregister_device(data->hpdev.client);
584i2c_new_device_fail:
585alloc_fail:
586	i2c_put_adapter(data->hpdev.adapter);
587	return err;
588}
589
590static void mlxreg_dpu_remove(struct platform_device *pdev)
591{
592	struct mlxreg_core_data *data = dev_get_platdata(&pdev->dev);
593	struct mlxreg_dpu *mlxreg_dpu = platform_get_drvdata(pdev);
594
595	mlxreg_dpu_config_exit(mlxreg_dpu);
596	i2c_unregister_device(data->hpdev.client);
597	i2c_put_adapter(data->hpdev.adapter);
598}
599
600static struct platform_driver mlxreg_dpu_driver = {
601	.probe = mlxreg_dpu_probe,
602	.remove = mlxreg_dpu_remove,
603	.driver = {
604		.name = "mlxreg-dpu",
605	},
606};
607
608module_platform_driver(mlxreg_dpu_driver);
609
610MODULE_AUTHOR("Vadim Pasternak <vadimp@nvidia.com>");
611MODULE_DESCRIPTION("Nvidia Data Processor Unit platform driver");
612MODULE_LICENSE("Dual BSD/GPL");
613MODULE_ALIAS("platform:mlxreg-dpu");
~/ Read-only file preview.