Unverified Commit 03e31603 authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'imx-drivers-5.20' of...

Merge tag 'imx-drivers-5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux into arm/drivers

i.MX drivers change for 5.20:

- Update imx8m-blk-ctrl driver to print the name of the power domain,
  so that the error message becomes more useful.
- Update the error messages in gpcv2 driver by printing the reason why
  a regulator fails to be enabled or disabled.
- A series from Michael Walle to convert the guts driver from a platform
  driver to an core_initcall for getting rid of all those global static
  variables.
- A couple of follow-up fixes on guts driver series.

* tag 'imx-drivers-5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux:
  soc: fsl: guts: check return value after calling of_iomap() in fsl_guts_get_soc_uid()
  soc: fsl: guts: fix return value check in fsl_guts_init()
  soc: imx: imx8m-blk-ctrl: Make error prints useful
  soc: fsl: guts: add serial_number support
  soc: fsl: guts: drop platform driver
  soc: fsl: guts: use of_root instead of own reference
  soc: fsl: guts: allocate soc_dev_attr on the heap
  soc: fsl: guts: embed fsl_guts_get_svr() in probe()
  soc: fsl: guts: remove module_exit() and fsl_guts_remove()
  soc: fsl: guts: machine variable might be unset
  soc: imx: gpcv2: print errno for regulator errors

Link: https://lore.kernel.org/r/20220709082951.15123-1-shawnguo@kernel.org


Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents 62fcbc5c 63f98153
Loading
Loading
Loading
Loading
+121 −100
Original line number Diff line number Diff line
@@ -14,21 +14,16 @@
#include <linux/platform_device.h>
#include <linux/fsl/guts.h>

struct guts {
	struct ccsr_guts __iomem *regs;
	bool little_endian;
};

struct fsl_soc_die_attr {
	char	*die;
	u32	svr;
	u32	mask;
};

static struct guts *guts;
static struct soc_device_attribute soc_dev_attr;
static struct soc_device *soc_dev;

struct fsl_soc_data {
	const char *sfp_compat;
	u32 uid_offset;
};

/* SoC die attribute definition for QorIQ platform */
static const struct fsl_soc_die_attr fsl_soc_die[] = {
@@ -120,88 +115,36 @@ static const struct fsl_soc_die_attr *fsl_soc_die_match(
	return NULL;
}

static u32 fsl_guts_get_svr(void)
{
	u32 svr = 0;

	if (!guts || !guts->regs)
		return svr;

	if (guts->little_endian)
		svr = ioread32(&guts->regs->svr);
	else
		svr = ioread32be(&guts->regs->svr);

	return svr;
}

static int fsl_guts_probe(struct platform_device *pdev)
static u64 fsl_guts_get_soc_uid(const char *compat, unsigned int offset)
{
	struct device_node *root, *np = pdev->dev.of_node;
	struct device *dev = &pdev->dev;
	const struct fsl_soc_die_attr *soc_die;
	const char *machine;
	u32 svr;

	/* Initialize guts */
	guts = devm_kzalloc(dev, sizeof(*guts), GFP_KERNEL);
	if (!guts)
		return -ENOMEM;
	struct device_node *np;
	void __iomem *sfp_base;
	u64 uid;

	guts->little_endian = of_property_read_bool(np, "little-endian");

	guts->regs = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(guts->regs))
		return PTR_ERR(guts->regs);
	np = of_find_compatible_node(NULL, NULL, compat);
	if (!np)
		return 0;

	/* Register soc device */
	root = of_find_node_by_path("/");
	if (of_property_read_string(root, "model", &machine))
		of_property_read_string_index(root, "compatible", 0, &machine);
	if (machine) {
		soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL);
		if (!soc_dev_attr.machine) {
			of_node_put(root);
			return -ENOMEM;
		}
	sfp_base = of_iomap(np, 0);
	if (!sfp_base) {
		of_node_put(np);
		return 0;
	}
	of_node_put(root);

	svr = fsl_guts_get_svr();
	soc_die = fsl_soc_die_match(svr, fsl_soc_die);
	if (soc_die) {
		soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL,
						     "QorIQ %s", soc_die->die);
	} else {
		soc_dev_attr.family = devm_kasprintf(dev, GFP_KERNEL, "QorIQ");
	}
	if (!soc_dev_attr.family)
		return -ENOMEM;
	soc_dev_attr.soc_id = devm_kasprintf(dev, GFP_KERNEL,
					     "svr:0x%08x", svr);
	if (!soc_dev_attr.soc_id)
		return -ENOMEM;
	soc_dev_attr.revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d",
					       (svr >>  4) & 0xf, svr & 0xf);
	if (!soc_dev_attr.revision)
		return -ENOMEM;
	uid = ioread32(sfp_base + offset);
	uid <<= 32;
	uid |= ioread32(sfp_base + offset + 4);

	soc_dev = soc_device_register(&soc_dev_attr);
	if (IS_ERR(soc_dev))
		return PTR_ERR(soc_dev);
	iounmap(sfp_base);
	of_node_put(np);

	pr_info("Machine: %s\n", soc_dev_attr.machine);
	pr_info("SoC family: %s\n", soc_dev_attr.family);
	pr_info("SoC ID: %s, Revision: %s\n",
		soc_dev_attr.soc_id, soc_dev_attr.revision);
	return 0;
	return uid;
}

static int fsl_guts_remove(struct platform_device *dev)
{
	soc_device_unregister(soc_dev);
	return 0;
}
static const struct fsl_soc_data ls1028a_data = {
	.sfp_compat = "fsl,ls1028a-sfp",
	.uid_offset = 0x21c,
};

/*
 * Table for matching compatible strings, for device tree
@@ -231,28 +174,106 @@ static const struct of_device_id fsl_guts_of_match[] = {
	{ .compatible = "fsl,ls1012a-dcfg", },
	{ .compatible = "fsl,ls1046a-dcfg", },
	{ .compatible = "fsl,lx2160a-dcfg", },
	{ .compatible = "fsl,ls1028a-dcfg", },
	{ .compatible = "fsl,ls1028a-dcfg", .data = &ls1028a_data},
	{}
};
MODULE_DEVICE_TABLE(of, fsl_guts_of_match);

static struct platform_driver fsl_guts_driver = {
	.driver = {
		.name = "fsl-guts",
		.of_match_table = fsl_guts_of_match,
	},
	.probe = fsl_guts_probe,
	.remove = fsl_guts_remove,
};

static int __init fsl_guts_init(void)
{
	return platform_driver_register(&fsl_guts_driver);
	struct soc_device_attribute *soc_dev_attr;
	static struct soc_device *soc_dev;
	const struct fsl_soc_die_attr *soc_die;
	const struct fsl_soc_data *soc_data;
	const struct of_device_id *match;
	struct ccsr_guts __iomem *regs;
	const char *machine = NULL;
	struct device_node *np;
	bool little_endian;
	u64 soc_uid = 0;
	u32 svr;
	int ret;

	np = of_find_matching_node_and_match(NULL, fsl_guts_of_match, &match);
	if (!np)
		return 0;
	soc_data = match->data;

	regs = of_iomap(np, 0);
	if (!regs) {
		of_node_put(np);
		return -ENOMEM;
	}
core_initcall(fsl_guts_init);

static void __exit fsl_guts_exit(void)
{
	platform_driver_unregister(&fsl_guts_driver);
	little_endian = of_property_read_bool(np, "little-endian");
	if (little_endian)
		svr = ioread32(&regs->svr);
	else
		svr = ioread32be(&regs->svr);
	iounmap(regs);
	of_node_put(np);

	/* Register soc device */
	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
	if (!soc_dev_attr)
		return -ENOMEM;

	if (of_property_read_string(of_root, "model", &machine))
		of_property_read_string_index(of_root, "compatible", 0, &machine);
	if (machine) {
		soc_dev_attr->machine = kstrdup(machine, GFP_KERNEL);
		if (!soc_dev_attr->machine)
			goto err_nomem;
	}
module_exit(fsl_guts_exit);

	soc_die = fsl_soc_die_match(svr, fsl_soc_die);
	if (soc_die) {
		soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ %s",
						 soc_die->die);
	} else {
		soc_dev_attr->family = kasprintf(GFP_KERNEL, "QorIQ");
	}
	if (!soc_dev_attr->family)
		goto err_nomem;

	soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "svr:0x%08x", svr);
	if (!soc_dev_attr->soc_id)
		goto err_nomem;

	soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%d.%d",
					   (svr >>  4) & 0xf, svr & 0xf);
	if (!soc_dev_attr->revision)
		goto err_nomem;

	if (soc_data)
		soc_uid = fsl_guts_get_soc_uid(soc_data->sfp_compat,
					       soc_data->uid_offset);
	if (soc_uid)
		soc_dev_attr->serial_number = kasprintf(GFP_KERNEL, "%016llX",
							soc_uid);

	soc_dev = soc_device_register(soc_dev_attr);
	if (IS_ERR(soc_dev)) {
		ret = PTR_ERR(soc_dev);
		goto err;
	}

	pr_info("Machine: %s\n", soc_dev_attr->machine);
	pr_info("SoC family: %s\n", soc_dev_attr->family);
	pr_info("SoC ID: %s, Revision: %s\n",
		soc_dev_attr->soc_id, soc_dev_attr->revision);

	return 0;

err_nomem:
	ret = -ENOMEM;
err:
	kfree(soc_dev_attr->machine);
	kfree(soc_dev_attr->family);
	kfree(soc_dev_attr->soc_id);
	kfree(soc_dev_attr->revision);
	kfree(soc_dev_attr->serial_number);
	kfree(soc_dev_attr);

	return ret;
}
core_initcall(fsl_guts_init);
+6 −2
Original line number Diff line number Diff line
@@ -328,7 +328,9 @@ static int imx_pgc_power_up(struct generic_pm_domain *genpd)
	if (!IS_ERR(domain->regulator)) {
		ret = regulator_enable(domain->regulator);
		if (ret) {
			dev_err(domain->dev, "failed to enable regulator\n");
			dev_err(domain->dev,
				"failed to enable regulator: %pe\n",
				ERR_PTR(ret));
			goto out_put_pm;
		}
	}
@@ -467,7 +469,9 @@ static int imx_pgc_power_down(struct generic_pm_domain *genpd)
	if (!IS_ERR(domain->regulator)) {
		ret = regulator_disable(domain->regulator);
		if (ret) {
			dev_err(domain->dev, "failed to disable regulator\n");
			dev_err(domain->dev,
				"failed to disable regulator: %pe\n",
				ERR_PTR(ret));
			return ret;
		}
	}
+6 −3
Original line number Diff line number Diff line
@@ -216,7 +216,7 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
	bc->bus_power_dev = genpd_dev_pm_attach_by_name(dev, "bus");
	if (IS_ERR(bc->bus_power_dev))
		return dev_err_probe(dev, PTR_ERR(bc->bus_power_dev),
				     "failed to attach power domain\n");
				     "failed to attach power domain \"bus\"\n");

	for (i = 0; i < bc_data->num_domains; i++) {
		const struct imx8m_blk_ctrl_domain_data *data = &bc_data->domains[i];
@@ -238,7 +238,8 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
			dev_pm_domain_attach_by_name(dev, data->gpc_name);
		if (IS_ERR(domain->power_dev)) {
			dev_err_probe(dev, PTR_ERR(domain->power_dev),
				      "failed to attach power domain\n");
				      "failed to attach power domain \"%s\"\n",
				      data->gpc_name);
			ret = PTR_ERR(domain->power_dev);
			goto cleanup_pds;
		}
@@ -251,7 +252,9 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)

		ret = pm_genpd_init(&domain->genpd, NULL, true);
		if (ret) {
			dev_err_probe(dev, ret, "failed to init power domain\n");
			dev_err_probe(dev, ret,
				      "failed to init power domain \"%s\"\n",
				      data->gpc_name);
			dev_pm_domain_detach(domain->power_dev, true);
			goto cleanup_pds;
		}