Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * NVMEM layout bus handling
  4 *
  5 * Copyright (C) 2023 Bootlin
  6 * Author: Miquel Raynal <miquel.raynal@bootlin.com
  7 */
  8
  9#include <linux/device.h>
 10#include <linux/dma-mapping.h>
 11#include <linux/nvmem-consumer.h>
 12#include <linux/nvmem-provider.h>
 13#include <linux/of.h>
 14#include <linux/of_device.h>
 15#include <linux/of_irq.h>
 16
 17#include "internals.h"
 18
 19#define to_nvmem_layout_driver(drv) \
 20	(container_of_const((drv), struct nvmem_layout_driver, driver))
 21#define to_nvmem_layout_device(_dev) \
 22	container_of((_dev), struct nvmem_layout, dev)
 23
 24static int nvmem_layout_bus_match(struct device *dev, const struct device_driver *drv)
 25{
 26	return of_driver_match_device(dev, drv);
 27}
 28
 29static int nvmem_layout_bus_probe(struct device *dev)
 30{
 31	struct nvmem_layout_driver *drv = to_nvmem_layout_driver(dev->driver);
 32	struct nvmem_layout *layout = to_nvmem_layout_device(dev);
 33
 34	if (!drv->probe || !drv->remove)
 35		return -EINVAL;
 36
 37	return drv->probe(layout);
 38}
 39
 40static void nvmem_layout_bus_remove(struct device *dev)
 41{
 42	struct nvmem_layout_driver *drv = to_nvmem_layout_driver(dev->driver);
 43	struct nvmem_layout *layout = to_nvmem_layout_device(dev);
 44
 45	return drv->remove(layout);
 46}
 47
 48static const struct bus_type nvmem_layout_bus_type = {
 49	.name		= "nvmem-layout",
 50	.match		= nvmem_layout_bus_match,
 51	.probe		= nvmem_layout_bus_probe,
 52	.remove		= nvmem_layout_bus_remove,
 53};
 54
 55int __nvmem_layout_driver_register(struct nvmem_layout_driver *drv,
 56				   struct module *owner)
 57{
 58	drv->driver.bus = &nvmem_layout_bus_type;
 59	drv->driver.owner = owner;
 60
 61	return driver_register(&drv->driver);
 62}
 63EXPORT_SYMBOL_GPL(__nvmem_layout_driver_register);
 64
 65void nvmem_layout_driver_unregister(struct nvmem_layout_driver *drv)
 66{
 67	driver_unregister(&drv->driver);
 68}
 69EXPORT_SYMBOL_GPL(nvmem_layout_driver_unregister);
 70
 71static void nvmem_layout_release_device(struct device *dev)
 72{
 73	struct nvmem_layout *layout = to_nvmem_layout_device(dev);
 74
 75	of_node_put(layout->dev.of_node);
 76	kfree(layout);
 77}
 78
 79static int nvmem_layout_create_device(struct nvmem_device *nvmem,
 80				      struct device_node *np)
 81{
 82	struct nvmem_layout *layout;
 83	struct device *dev;
 84	int ret;
 85
 86	layout = kzalloc(sizeof(*layout), GFP_KERNEL);
 87	if (!layout)
 88		return -ENOMEM;
 89
 90	/* Create a bidirectional link */
 91	layout->nvmem = nvmem;
 92	nvmem->layout = layout;
 93
 94	/* Device model registration */
 95	dev = &layout->dev;
 96	device_initialize(dev);
 97	dev->parent = &nvmem->dev;
 98	dev->bus = &nvmem_layout_bus_type;
 99	dev->release = nvmem_layout_release_device;
100	dev->coherent_dma_mask = DMA_BIT_MASK(32);
101	dev->dma_mask = &dev->coherent_dma_mask;
102	device_set_node(dev, of_fwnode_handle(of_node_get(np)));
103	of_device_make_bus_id(dev);
104	of_msi_configure(dev, dev->of_node);
105
106	ret = device_add(dev);
107	if (ret) {
108		put_device(dev);
109		return ret;
110	}
111
112	return 0;
113}
114
115static const struct of_device_id of_nvmem_layout_skip_table[] = {
116	{ .compatible = "fixed-layout", },
117	{}
118};
119
120static int nvmem_layout_bus_populate(struct nvmem_device *nvmem,
121				     struct device_node *layout_dn)
122{
123	int ret;
124
125	/* Make sure it has a compatible property */
126	if (!of_property_present(layout_dn, "compatible")) {
127		pr_debug("%s() - skipping %pOF, no compatible prop\n",
128			 __func__, layout_dn);
129		return 0;
130	}
131
132	/* Fixed layouts are parsed manually somewhere else for now */
133	if (of_match_node(of_nvmem_layout_skip_table, layout_dn)) {
134		pr_debug("%s() - skipping %pOF node\n", __func__, layout_dn);
135		return 0;
136	}
137
138	if (of_node_check_flag(layout_dn, OF_POPULATED_BUS)) {
139		pr_debug("%s() - skipping %pOF, already populated\n",
140			 __func__, layout_dn);
141
142		return 0;
143	}
144
145	/* NVMEM layout buses expect only a single device representing the layout */
146	ret = nvmem_layout_create_device(nvmem, layout_dn);
147	if (ret)
148		return ret;
149
150	of_node_set_flag(layout_dn, OF_POPULATED_BUS);
151
152	return 0;
153}
154
155struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
156{
157	return of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
158}
159EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container);
160
161/*
162 * Returns the number of devices populated, 0 if the operation was not relevant
163 * for this nvmem device, an error code otherwise.
164 */
165int nvmem_populate_layout(struct nvmem_device *nvmem)
166{
167	struct device_node *layout_dn;
168	int ret;
169
170	layout_dn = of_nvmem_layout_get_container(nvmem);
171	if (!layout_dn)
172		return 0;
173
174	/* Populate the layout device */
175	device_links_supplier_sync_state_pause();
176	ret = nvmem_layout_bus_populate(nvmem, layout_dn);
177	device_links_supplier_sync_state_resume();
178
179	of_node_put(layout_dn);
180	return ret;
181}
182
183void nvmem_destroy_layout(struct nvmem_device *nvmem)
184{
185	struct device *dev;
186
187	if (!nvmem->layout)
188		return;
189
190	dev = &nvmem->layout->dev;
191	of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
192	device_unregister(dev);
193}
194
195int nvmem_layout_bus_register(void)
196{
197	return bus_register(&nvmem_layout_bus_type);
198}
199
200void nvmem_layout_bus_unregister(void)
201{
202	bus_unregister(&nvmem_layout_bus_type);
203}
v6.8
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * NVMEM layout bus handling
  4 *
  5 * Copyright (C) 2023 Bootlin
  6 * Author: Miquel Raynal <miquel.raynal@bootlin.com
  7 */
  8
  9#include <linux/device.h>
 10#include <linux/dma-mapping.h>
 11#include <linux/nvmem-consumer.h>
 12#include <linux/nvmem-provider.h>
 13#include <linux/of.h>
 14#include <linux/of_device.h>
 15#include <linux/of_irq.h>
 16
 17#include "internals.h"
 18
 19#define to_nvmem_layout_driver(drv) \
 20	(container_of((drv), struct nvmem_layout_driver, driver))
 21#define to_nvmem_layout_device(_dev) \
 22	container_of((_dev), struct nvmem_layout, dev)
 23
 24static int nvmem_layout_bus_match(struct device *dev, struct device_driver *drv)
 25{
 26	return of_driver_match_device(dev, drv);
 27}
 28
 29static int nvmem_layout_bus_probe(struct device *dev)
 30{
 31	struct nvmem_layout_driver *drv = to_nvmem_layout_driver(dev->driver);
 32	struct nvmem_layout *layout = to_nvmem_layout_device(dev);
 33
 34	if (!drv->probe || !drv->remove)
 35		return -EINVAL;
 36
 37	return drv->probe(layout);
 38}
 39
 40static void nvmem_layout_bus_remove(struct device *dev)
 41{
 42	struct nvmem_layout_driver *drv = to_nvmem_layout_driver(dev->driver);
 43	struct nvmem_layout *layout = to_nvmem_layout_device(dev);
 44
 45	return drv->remove(layout);
 46}
 47
 48static struct bus_type nvmem_layout_bus_type = {
 49	.name		= "nvmem-layout",
 50	.match		= nvmem_layout_bus_match,
 51	.probe		= nvmem_layout_bus_probe,
 52	.remove		= nvmem_layout_bus_remove,
 53};
 54
 55int nvmem_layout_driver_register(struct nvmem_layout_driver *drv)
 
 56{
 57	drv->driver.bus = &nvmem_layout_bus_type;
 
 58
 59	return driver_register(&drv->driver);
 60}
 61EXPORT_SYMBOL_GPL(nvmem_layout_driver_register);
 62
 63void nvmem_layout_driver_unregister(struct nvmem_layout_driver *drv)
 64{
 65	driver_unregister(&drv->driver);
 66}
 67EXPORT_SYMBOL_GPL(nvmem_layout_driver_unregister);
 68
 69static void nvmem_layout_release_device(struct device *dev)
 70{
 71	struct nvmem_layout *layout = to_nvmem_layout_device(dev);
 72
 73	of_node_put(layout->dev.of_node);
 74	kfree(layout);
 75}
 76
 77static int nvmem_layout_create_device(struct nvmem_device *nvmem,
 78				      struct device_node *np)
 79{
 80	struct nvmem_layout *layout;
 81	struct device *dev;
 82	int ret;
 83
 84	layout = kzalloc(sizeof(*layout), GFP_KERNEL);
 85	if (!layout)
 86		return -ENOMEM;
 87
 88	/* Create a bidirectional link */
 89	layout->nvmem = nvmem;
 90	nvmem->layout = layout;
 91
 92	/* Device model registration */
 93	dev = &layout->dev;
 94	device_initialize(dev);
 95	dev->parent = &nvmem->dev;
 96	dev->bus = &nvmem_layout_bus_type;
 97	dev->release = nvmem_layout_release_device;
 98	dev->coherent_dma_mask = DMA_BIT_MASK(32);
 99	dev->dma_mask = &dev->coherent_dma_mask;
100	device_set_node(dev, of_fwnode_handle(of_node_get(np)));
101	of_device_make_bus_id(dev);
102	of_msi_configure(dev, dev->of_node);
103
104	ret = device_add(dev);
105	if (ret) {
106		put_device(dev);
107		return ret;
108	}
109
110	return 0;
111}
112
113static const struct of_device_id of_nvmem_layout_skip_table[] = {
114	{ .compatible = "fixed-layout", },
115	{}
116};
117
118static int nvmem_layout_bus_populate(struct nvmem_device *nvmem,
119				     struct device_node *layout_dn)
120{
121	int ret;
122
123	/* Make sure it has a compatible property */
124	if (!of_get_property(layout_dn, "compatible", NULL)) {
125		pr_debug("%s() - skipping %pOF, no compatible prop\n",
126			 __func__, layout_dn);
127		return 0;
128	}
129
130	/* Fixed layouts are parsed manually somewhere else for now */
131	if (of_match_node(of_nvmem_layout_skip_table, layout_dn)) {
132		pr_debug("%s() - skipping %pOF node\n", __func__, layout_dn);
133		return 0;
134	}
135
136	if (of_node_check_flag(layout_dn, OF_POPULATED_BUS)) {
137		pr_debug("%s() - skipping %pOF, already populated\n",
138			 __func__, layout_dn);
139
140		return 0;
141	}
142
143	/* NVMEM layout buses expect only a single device representing the layout */
144	ret = nvmem_layout_create_device(nvmem, layout_dn);
145	if (ret)
146		return ret;
147
148	of_node_set_flag(layout_dn, OF_POPULATED_BUS);
149
150	return 0;
151}
152
153struct device_node *of_nvmem_layout_get_container(struct nvmem_device *nvmem)
154{
155	return of_get_child_by_name(nvmem->dev.of_node, "nvmem-layout");
156}
157EXPORT_SYMBOL_GPL(of_nvmem_layout_get_container);
158
159/*
160 * Returns the number of devices populated, 0 if the operation was not relevant
161 * for this nvmem device, an error code otherwise.
162 */
163int nvmem_populate_layout(struct nvmem_device *nvmem)
164{
165	struct device_node *layout_dn;
166	int ret;
167
168	layout_dn = of_nvmem_layout_get_container(nvmem);
169	if (!layout_dn)
170		return 0;
171
172	/* Populate the layout device */
173	device_links_supplier_sync_state_pause();
174	ret = nvmem_layout_bus_populate(nvmem, layout_dn);
175	device_links_supplier_sync_state_resume();
176
177	of_node_put(layout_dn);
178	return ret;
179}
180
181void nvmem_destroy_layout(struct nvmem_device *nvmem)
182{
183	struct device *dev;
184
185	if (!nvmem->layout)
186		return;
187
188	dev = &nvmem->layout->dev;
189	of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
190	device_unregister(dev);
191}
192
193int nvmem_layout_bus_register(void)
194{
195	return bus_register(&nvmem_layout_bus_type);
196}
197
198void nvmem_layout_bus_unregister(void)
199{
200	bus_unregister(&nvmem_layout_bus_type);
201}