Linux Audio

Check our new training course

Loading...
  1// SPDX-License-Identifier: GPL-2.0+
  2
  3/*
  4 * Add an IPMI platform device.
  5 */
  6
  7#include <linux/platform_device.h>
  8#include "ipmi_plat_data.h"
  9#include "ipmi_si.h"
 10
 11struct platform_device *ipmi_platform_add(const char *name, unsigned int inst,
 12					  struct ipmi_plat_data *p)
 13{
 14	struct platform_device *pdev;
 15	unsigned int num_r = 1, size = 0, pidx = 0;
 16	struct resource r[4];
 17	struct property_entry pr[6];
 18	u32 flags;
 19	int rv;
 20
 21	memset(pr, 0, sizeof(pr));
 22	memset(r, 0, sizeof(r));
 23
 24	if (p->iftype == IPMI_PLAT_IF_SI) {
 25		if (p->type == SI_BT)
 26			size = 3;
 27		else if (p->type != SI_TYPE_INVALID)
 28			size = 2;
 29
 30		if (p->regsize == 0)
 31			p->regsize = DEFAULT_REGSIZE;
 32		if (p->regspacing == 0)
 33			p->regspacing = p->regsize;
 34
 35		pr[pidx++] = PROPERTY_ENTRY_U8("ipmi-type", p->type);
 36	} else if (p->iftype == IPMI_PLAT_IF_SSIF) {
 37		pr[pidx++] = PROPERTY_ENTRY_U16("i2c-addr", p->addr);
 38	}
 39
 40	if (p->slave_addr)
 41		pr[pidx++] = PROPERTY_ENTRY_U8("slave-addr", p->slave_addr);
 42	pr[pidx++] = PROPERTY_ENTRY_U8("addr-source", p->addr_source);
 43	if (p->regshift)
 44		pr[pidx++] = PROPERTY_ENTRY_U8("reg-shift", p->regshift);
 45	pr[pidx++] = PROPERTY_ENTRY_U8("reg-size", p->regsize);
 46	/* Last entry must be left NULL to terminate it. */
 47
 48	pdev = platform_device_alloc(name, inst);
 49	if (!pdev) {
 50		pr_err("Error allocating IPMI platform device %s.%d\n",
 51		       name, inst);
 52		return NULL;
 53	}
 54
 55	if (size == 0)
 56		/* An invalid or SSIF interface, no resources. */
 57		goto add_properties;
 58
 59	/*
 60	 * Register spacing is derived from the resources in
 61	 * the IPMI platform code.
 62	 */
 63
 64	if (p->space == IPMI_IO_ADDR_SPACE)
 65		flags = IORESOURCE_IO;
 66	else
 67		flags = IORESOURCE_MEM;
 68
 69	r[0].start = p->addr;
 70	r[0].end = r[0].start + p->regsize - 1;
 71	r[0].name = "IPMI Address 1";
 72	r[0].flags = flags;
 73
 74	if (size > 1) {
 75		r[1].start = r[0].start + p->regspacing;
 76		r[1].end = r[1].start + p->regsize - 1;
 77		r[1].name = "IPMI Address 2";
 78		r[1].flags = flags;
 79		num_r++;
 80	}
 81
 82	if (size > 2) {
 83		r[2].start = r[1].start + p->regspacing;
 84		r[2].end = r[2].start + p->regsize - 1;
 85		r[2].name = "IPMI Address 3";
 86		r[2].flags = flags;
 87		num_r++;
 88	}
 89
 90	if (p->irq) {
 91		r[num_r].start = p->irq;
 92		r[num_r].end = p->irq;
 93		r[num_r].name = "IPMI IRQ";
 94		r[num_r].flags = IORESOURCE_IRQ;
 95		num_r++;
 96	}
 97
 98	rv = platform_device_add_resources(pdev, r, num_r);
 99	if (rv) {
100		dev_err(&pdev->dev,
101			"Unable to add hard-code resources: %d\n", rv);
102		goto err;
103	}
104 add_properties:
105	rv = device_create_managed_software_node(&pdev->dev, pr, NULL);
106	if (rv) {
107		dev_err(&pdev->dev,
108			"Unable to add hard-code properties: %d\n", rv);
109		goto err;
110	}
111
112	rv = platform_device_add(pdev);
113	if (rv) {
114		dev_err(&pdev->dev,
115			"Unable to add hard-code device: %d\n", rv);
116		goto err;
117	}
118	return pdev;
119
120err:
121	platform_device_put(pdev);
122	return NULL;
123}
124EXPORT_SYMBOL(ipmi_platform_add);