All of lore.kernel.org
 help / color / mirror / Atom feed
From: thierry.reding@gmail.com (Thierry Reding)
To: linux-arm-kernel@lists.infradead.org
Subject: [RFC PATCH dtc] C-based DT schema checker integrated into dtc
Date: Wed, 6 Nov 2013 13:17:54 +0100	[thread overview]
Message-ID: <20131106121752.GB6984@ulmo.nvidia.com> (raw)
In-Reply-To: <1704730.RnIqE1USnv@wuerfel>

On Mon, Nov 04, 2013 at 09:43:22PM +0100, Arnd Bergmann wrote:
> On Monday 04 November 2013 09:37:07 Stephen Warren wrote:
> > > The basic idea is to extend 'devres' to automatically register
> > > all the resources (registers, irq, dma, gpio, pinctrl, clk, regulator, ...)
> > > and simple properties before the ->probe() callback is even called,
> > > based on a per-driver data structure that describes them, and that
> > > can be easily parsed by an external tool.
> > 
> > I had suggested that while talking to someone at the kernel summit,
> > basically each driver supplies functions like:
> > 
> > 1) ACPI -> platform data or resources converter
> > 2) DT -> platform or resources data converter
> > 3) anything else -> platform or resources data converter
> > 4) probe()
> 
> FWIW, here is a very early draft of the interfaces I have in mind.
> At the moment the implementation is DT focused, but that should
> be extensible to ACPI if necessary.
> 
> At the end, you can see how a probe function could end up looking.
> I'm sure this is full of bugs at the moment, incomplete and needs
> to be moved into actual header and C files, but it should be enough
> to get across where I'm getting with this, and to see if anyone
> thinks it's a really bad idea or won't actually work.

I know that this is completely unconstructive, but the below gives me
the creeps.

Thierry

> 
> 	Arnd
> 
> #if 0
> /* allocate drvdata */
> DEVM_ALLOC,
> 
> /* request hardware properties */
> DEVM_IRQ,
> DEVM_IOMAP,
> DEVM_GPIO,
> DEVM_DMA_SLAVE,
> DEVM_PINCTRL,
> DEVM_REGULATOR,
> DEVM_CLK,
> DEVM_PWM,
> DEVM_USBPHY,
> 
> /* auxiliary information */
> DEVM_PROP_BOOL
> DEVM_PROP_U32
> DEVM_PROP_STRING
> #endif
> 
> #error don't bother compiling this file, it's only proof-of-concept
> 
> struct device;
> 
> struct devm_probe {
> 	int (*initfunc)(struct device *dev, const struct devm_probe *probe);
> 	ptrdiff_t offset;
> 	unsigned int index;
> 	const char *name;
> 	void *arg;
> 	unsigned int flags;
> };
> 
> /* like offsetof(), but ensures that MEMBER is of type MEMBERTYPE */
> #define offsetof_t(TYPE, MEMBER, MEMBERTYPE) \
> 	((typeof(MEMBER)*)0 - typeof(MEMBERTYPE*)0 + offsetof((TYPE), (MEMBER)))
> 
> /* cast 'ptr' to void* and cause a build warning if it wasn't of 'type' before */
> #define typecheck_ptr(ptr, type) \
> 	(void *)(ptr - (type)NULL + (type)NULL)
> 
> /*
>  * This is the main entry point for drivers: 
>  *
>  * Given an zero-terminated array of 'struct devm_probe' entries,
>  * this calls all initfunc pointers in the given order. Each initfunc
>  * may manipulate a field in the driver_data, as pointed to by
>  * the 'offset' member.
>  */
> int devm_probe(struct device *dev, const struct devm_probe *probe)
> {
> 	int ret;
> 
> 	for (ret = 0; !ret && probe->initfunc, probe++)
> 		ret = probe->initfunc(dev, probe);
> 
> 	return ret;
> }
> EXPORT_SYMBOL_GPL(devm_probe);
> 
> /*
>  * this must be the called before any of the others, or not at
>  * all, if dev_set_drvdata() has already been called.
>  */
> static void devm_probe_alloc_release(struct device *dev, void *res)
> {
> 	dev_set_drvdata(dev, NULL);
> }
> int devm_probe_alloc(struct device *dev, const struct devm_probe *probe)
> {
> 	void *dr;
> 
> 	if (dev_get_drvdata)
> 		return -EBUSY;
> 
> 	dr = alloc_dr(devm_probe_alloc_release, probe->offset, GFP_KERNEL);
> 	if (unlikely(!dr))
> 		return -ENOMEM;
> 
> 	dev_set_drvdata(dev, dr);
> 	set_node_dbginfo(&dr->node, "devm_probe_alloc", size);
> 	devres_add(dev, dr->data);
> }
> EXPORT_SYMBOL_GPL(devm_probe_alloc);
> 
> 
> #define DEVM_ALLOC(_struct) \
> 	{ .initfunc = devm_probe_alloc, .offset = sizeof(struct _struct), }
> 
> int devm_probe_irq(struct device *dev, const struct devm_probe *probe)
> {
> 	int ret;
> 	int irq;
> 	int *irqp;
> 	int index;
> 	const char *name;
> 
> 	/* come up with a reasonable string for the irq name,
> 	   maybe create devm_kasprintf() to allow arbitrary length? */
> 	name = devm_kmalloc(dev, 32, GFP_KERNEL);
> 	if (!name)
> 		return -ENOMEM;
> 	if (probe->name)
> 		snprintf(name, 32 - 1, "%s:%s", dev_name(dev), probe->name);
> 	else
> 		snprintf(name, 32 - 1, "%s:%n", dev_name(dev), probe->index);
> 
> 	/* find IRQ number from resource if platform device */
> 	irq = 0;
> 	if (dev->bus_type == &platform_bus) {
> 		struct platform_device *pdev = to_platform_device(dev);
> 
> 		if (probe->name)
> 			irq = platform_get_irq_byname(pdev, probe->name);
> 		else
> 			irq = platform_get_irq(pdev, probe->index);
> 	}
> 
> 	/* try getting irq number from device tree if that failed */
> 	if (!irq && dev->of_node) {
> 		if (probe->name)
> 			index = of_property_match_string(dev->of_node,
> 							 "interrupt-names",
> 							 probe->name);
> 		else
> 			index = probe->index;
> 
> 		irq = irq_of_parse_and_map(dev->of_node, index);
> 	}
> 
> 	/* copy irq number to driver data */
> 	irqp = dev_get_drvdata(dev) + probe->offset;
> 	*irqp = irq;
> 	
> 	return devm_request_irq(dev, irq, probe->arg, probe->flags, name, probe->dev);
> }
> EXPORT_SYMBOL_GPL(devm_probe_irq);
> 
> #define DEVM_IRQ(_struct, _member, _index, _handler, _flags) {	\
> 	.initfunc = devm_probe_irq,				\
> 	.offset = offsetof_t(struct _struct, _member, int),	\
> 	.index = _index,					\
> 	.arg = typecheck_ptr((_handler), irq_handler_t),	\
> 	.flags = _flags,					\
> }	
> 
> #define DEVM_IRQ_NAMED(_struct, _member, _name, _handler, _flags) { \
> 	.initfunc = devm_probe_irq,				\
> 	.offset = offsetof_t(struct _struct, _member, int),	\
> 	.name = _name,						\
> 	.arg = typecheck_ptr((_handler), irq_handler_t),	\
> 	.flags = _flags,					\
> }	
> 
> 
> #define DEVM_IOMAP_NOREQUEST 1
> 
> int devm_probe_iomap(struct device *dev, const struct devm_probe *probe)
> {
> 	struct resource res, *resp;
> 	void __iomem *vaddr;
> 	void * __iomem *vaddrp;
> 	int ret;
> 
> 	/* find mem resource from platform device */
> 	if (dev->bus_type == &platform_bus) {
> 		struct platform_device *pdev = to_platform_device(dev);
> 
> 		if (probe->name)
> 			resp = platform_get_resource_byname(pdev,
> 					IORESOURCE_MEM, probe->name);
> 		else
> 			resp = platform_get_resource(pdev,
> 					IORESOURCE_MEM, probe->index);
> 	}
> 
> 	/* try getting resource from device tree if that failed */
> 	if (!resp && dev->of_node) {
> 		if (probe->name)
> 			index = of_property_match_string(dev->of_node,
> 							 "reg-names",
> 							 probe->name);
> 		else
> 			index = probe->index;
> 
> 		ret = of_address_to_resource(dev->of_node, index, &res);
> 		if (ret)
> 			return ret;
> 		resp = &res;
> 	}
> 
> 
> 	if (probe->flags & DEVM_IOMAP_NOREQUEST) {
> 		vaddr = devm_ioremap(dev, resp->start, resource_size(resp));
> 		if (!vaddr)
> 			return -EINVAL;
> 	} else {
> 		vaddr = devm_ioremap_resource(dev, resp);
> 		if (IS_ERR(vaddr))
> 			return PTR_ERR(vaddr);
> 	}
> 
> 	vaddrp = dev_get_drvdata(dev) + probe->offset;
> 	*vaddrp = vaddr;
> 
> 	return 0;
> }
> EXPORT_SYMBOL_GPL(devm_probe_iomap);
> 
> #define DEVM_IOMAP(_struct, _member, _index, _flags) {			\
> 	.initfunc = devm_probe_iomap,					\
> 	.offset = offsetof_t(struct _struct, _member, void __iomem *),	\
> 	.index = _index,						\
> 	.flags = _flags,						\
> }	
> 
> #define DEVM_IOMAP_NAMED(_struct, _member, _name, _flags) { 		\
> 	.initfunc = devm_probe_iomap,					\
> 	.offset = offsetof_t(struct _struct, _member, void __iomem *),	\
> 	.name = _name,							\
> 	.flags = _flags,						\
> }	
> 
> int devm_probe_gpio(struct device *dev, const struct devm_probe *probe)
> {
> 	struct gpio_desc *desc, **descp;
> 
> 	desc = devm_gpiod_get_index(dev, probe->name, probe->index);
> 	if (IS_ERR(desc)) {
> 		/* FIXME: this looks wrong */
> 		desc = of_get_named_gpiod_flags(dev->of_node, probe->name,
> 						probe->index, NULL);
> 		if (IS_ERR(desc))
> 			return PTR_ERR(desc);
> 		devm_gpio_request(dev, desc_to_gpio(desc), probe->name);
> 	}
> 
> 	descp = dev_get_drvdata(dev) + probe->offset;
> 	*descp = desc;
> 
> 	return 0;
> }
> 
> #define DEVM_GPIO(_struct, _member, _index) {				 \
> 	.initfunc = devm_probe_iomap,					 \
> 	.offset = offsetof_t(struct _struct, _member, struct gpio_desc*),\
> 	.name = "gpios",						 \
> 	.index = _index,						 \
> }	
> 
> #define DEVM_GPIO_NAMED(_struct, _member, _name) { 			 \
> 	.initfunc = devm_probe_iomap,					 \
> 	.offset = offsetof_t(struct _struct, _member, struct gpio_desc*),\
> 	.name = _name,							 \
> }	
> 
> static void devm_probe_dma_release(struct device *dev, void *chanp)
> {
> 	dma_release_channel(*(struct dma_chan**)chanp);
> }
> 
> int devm_probe_dma(struct device *dev, const struct devm_probe *probe)
> {
> 	struct dma_chan *chan, **chanp;
> 
> 	/* there is no devm_dma_request_channel yet, so build our own */
> 	chanp = devres_alloc(devm_probe_dma_release, sizeof(chanp), GFP_KERNEL);
> 	if (!chanp)
> 		return -ENOMEM;
> 
> 	chan = dma_request_slave_channel(dev, probe->name);
> 	if (!chan) {
> 		devres_free(chanp);
> 		return -EINVAL;
> 	}
> 
> 	*chanp = chan;
> 	devres_add(dev, chanp);
> 
> 	/* add pointer to the private data */
> 	chanp = dev_get_drvdata(dev) + probe->offset;
> 	*chanp = chan;
> 
> 	return 0;
> }
> 
> #define DEVM_DMA_SLAVE(_struct, _member, _name)				\
> 	.offset = offsetof_t(struct _struct, _member, struct dma_chan*),\
> 	.name = _name,							\
> }
> 
> /*
>  * simple properties: bool, u32, string
>  * no actual need for managed interfaces, just a way to abstract the
>  * access to DT or other information source
>  */
> int devm_probe_prop_bool(struct device *dev, struct devm_probe *probe)
> {
> 	bool *val;
> 
> 	val = dev_get_drvdata(dev) + probe->offset;
> 	*val = of_property_read_bool(dev->of_node, probe->name);
> 
> 	return 0;
> }
> EXPORT_SYMBOL_GPL(devm_probe_prop_bool);
> 
> #define DEVM_PROP_BOOL(_struct, _member, _name)			\
> 	.offset = offsetof_t(struct _struct, _member, bool),	\
> 	.name = _name,						\
> }
> 
> int devm_probe_prop_u32(struct device *dev, struct devm_probe *probe)
> {
> 	u32 *val;
> 	int ret;
> 
> 	val = dev_get_drvdata(dev) + probe->offset;
> 	ret = of_property_read_u32(dev->of_node, probe->name, val);
> 
> 	return ret;
> }
> EXPORT_SYMBOL_GPL(devm_probe_prop_bool);
> 
> #define DEVM_PROP_U32(_struct, _member, _name)			\
> 	.offset = offsetof_t(struct _struct, _member, u32),	\
> 	.name = _name,						\
> }
> 
> int devm_probe_prop_string(struct device *dev, struct devm_probe *probe)
> {
> 	const char **val;
> 	int ret;
> 
> 	val = dev_get_drvdata(dev) + probe->offset;
> 	ret = of_property_read_string(dev->of_node, probe->name, val);
> 
> 	return ret;
> }
> EXPORT_SYMBOL_GPL(devm_probe_prop_bool);
> 
> #define DEVM_PROP_STRING(_struct, _member, _name)			\
> 	.offset = offsetof_t(struct _struct, _member, const char *),	\
> 	.name = _name,							\
> }
> 
> /* example driver */
> struct foo_priv {
> 	spinlock_t lock;
> 	void __iomem *regs;
> 	int irq;
> 	struct gpio_desc *gpio;
> 	struct dma_chan *rxdma;
> 	struct dma_chan *txdma;
> 	bool oldstyle_dma;
> };
> 
> static irqreturn_t foo_irq_handler(int irq, void *dev);
> 
> /*
>  * this lists all properties we access from the driver. The list
>  * is interpreted by devm_probe() and can be programmatically
>  * verified to match the binding.
>  */
> static const struct devm_probe foo_probe_list[] = {
> 	DEVM_ALLOC(foo_priv),
> 	DEVM_IOMAP(foo_priv, regs, 0, 0),
> 	DEVM_PROP_BOOL(foo_priv, oldstyle_dma, "foo,oldstyle-dma"),
> 	DEVM_DMA_SLAVE(foo_priv, rxdma, "rx");
> 	DEVM_DMA_SLAVE(foo_priv, txdma, "tx");
> 	DEVM_GPIO(foo_priv, gpio, 0);
> 	DEVM_IRQ_NAMED(foo_priv, irq, foo_irq_handler, "fifo", IRQF_SHARED),
> 	{},
> };
> 
> static int foo_probe(struct platform_device *dev)
> {
> 	int ret;
> 
> 	ret = devm_probe(dev->dev, foo_probe_list);
> 	if (ret)
> 		return ret;
> 
> 	return bar_subsystem_register(&foo_bar_ops, dev);
> }
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20131106/4a78b7af/attachment-0001.sig>

WARNING: multiple messages have this Message-ID (diff)
From: Thierry Reding <thierry.reding-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
To: Arnd Bergmann <arnd-r2nGTMty4D4@public.gmane.org>
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	mark.rutland-5wv7dgnIgG8@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Jon Loeliger <jdl-CYoMK+44s/E@public.gmane.org>,
	khilman-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
	Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>,
	Benoit Cousson <bcousson-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>,
	pawel.moll-5wv7dgnIgG8@public.gmane.org,
	Stephen Warren <swarren-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>,
	Tomasz Figa <t.figa-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>,
	fparent-rdvid1DuHRBWk0Htik3J/w@public.gmane.org,
	Tomasz Figa <tomasz.figa-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
	rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org,
	Grant Likely
	<grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org>,
	a.hajda-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org,
	s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org,
	galak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org,
	olof-nZhT3qVonbNeoWH0uzbU5w@public.gmane.org,
	Alison_Chaiken-nmGgyN9QBj3QT0dZR+AlfA@public.gmane.org,
	David Gibson
	<david-xT8FGy+AXnRB3Ne2BGzF6laj5H9X9Tb+@public.gmane.org>
Subject: Re: [RFC PATCH dtc] C-based DT schema checker integrated into dtc
Date: Wed, 6 Nov 2013 13:17:54 +0100	[thread overview]
Message-ID: <20131106121752.GB6984@ulmo.nvidia.com> (raw)
In-Reply-To: <1704730.RnIqE1USnv@wuerfel>

[-- Attachment #1: Type: text/plain, Size: 12405 bytes --]

On Mon, Nov 04, 2013 at 09:43:22PM +0100, Arnd Bergmann wrote:
> On Monday 04 November 2013 09:37:07 Stephen Warren wrote:
> > > The basic idea is to extend 'devres' to automatically register
> > > all the resources (registers, irq, dma, gpio, pinctrl, clk, regulator, ...)
> > > and simple properties before the ->probe() callback is even called,
> > > based on a per-driver data structure that describes them, and that
> > > can be easily parsed by an external tool.
> > 
> > I had suggested that while talking to someone at the kernel summit,
> > basically each driver supplies functions like:
> > 
> > 1) ACPI -> platform data or resources converter
> > 2) DT -> platform or resources data converter
> > 3) anything else -> platform or resources data converter
> > 4) probe()
> 
> FWIW, here is a very early draft of the interfaces I have in mind.
> At the moment the implementation is DT focused, but that should
> be extensible to ACPI if necessary.
> 
> At the end, you can see how a probe function could end up looking.
> I'm sure this is full of bugs at the moment, incomplete and needs
> to be moved into actual header and C files, but it should be enough
> to get across where I'm getting with this, and to see if anyone
> thinks it's a really bad idea or won't actually work.

I know that this is completely unconstructive, but the below gives me
the creeps.

Thierry

> 
> 	Arnd
> 
> #if 0
> /* allocate drvdata */
> DEVM_ALLOC,
> 
> /* request hardware properties */
> DEVM_IRQ,
> DEVM_IOMAP,
> DEVM_GPIO,
> DEVM_DMA_SLAVE,
> DEVM_PINCTRL,
> DEVM_REGULATOR,
> DEVM_CLK,
> DEVM_PWM,
> DEVM_USBPHY,
> 
> /* auxiliary information */
> DEVM_PROP_BOOL
> DEVM_PROP_U32
> DEVM_PROP_STRING
> #endif
> 
> #error don't bother compiling this file, it's only proof-of-concept
> 
> struct device;
> 
> struct devm_probe {
> 	int (*initfunc)(struct device *dev, const struct devm_probe *probe);
> 	ptrdiff_t offset;
> 	unsigned int index;
> 	const char *name;
> 	void *arg;
> 	unsigned int flags;
> };
> 
> /* like offsetof(), but ensures that MEMBER is of type MEMBERTYPE */
> #define offsetof_t(TYPE, MEMBER, MEMBERTYPE) \
> 	((typeof(MEMBER)*)0 - typeof(MEMBERTYPE*)0 + offsetof((TYPE), (MEMBER)))
> 
> /* cast 'ptr' to void* and cause a build warning if it wasn't of 'type' before */
> #define typecheck_ptr(ptr, type) \
> 	(void *)(ptr - (type)NULL + (type)NULL)
> 
> /*
>  * This is the main entry point for drivers: 
>  *
>  * Given an zero-terminated array of 'struct devm_probe' entries,
>  * this calls all initfunc pointers in the given order. Each initfunc
>  * may manipulate a field in the driver_data, as pointed to by
>  * the 'offset' member.
>  */
> int devm_probe(struct device *dev, const struct devm_probe *probe)
> {
> 	int ret;
> 
> 	for (ret = 0; !ret && probe->initfunc, probe++)
> 		ret = probe->initfunc(dev, probe);
> 
> 	return ret;
> }
> EXPORT_SYMBOL_GPL(devm_probe);
> 
> /*
>  * this must be the called before any of the others, or not at
>  * all, if dev_set_drvdata() has already been called.
>  */
> static void devm_probe_alloc_release(struct device *dev, void *res)
> {
> 	dev_set_drvdata(dev, NULL);
> }
> int devm_probe_alloc(struct device *dev, const struct devm_probe *probe)
> {
> 	void *dr;
> 
> 	if (dev_get_drvdata)
> 		return -EBUSY;
> 
> 	dr = alloc_dr(devm_probe_alloc_release, probe->offset, GFP_KERNEL);
> 	if (unlikely(!dr))
> 		return -ENOMEM;
> 
> 	dev_set_drvdata(dev, dr);
> 	set_node_dbginfo(&dr->node, "devm_probe_alloc", size);
> 	devres_add(dev, dr->data);
> }
> EXPORT_SYMBOL_GPL(devm_probe_alloc);
> 
> 
> #define DEVM_ALLOC(_struct) \
> 	{ .initfunc = devm_probe_alloc, .offset = sizeof(struct _struct), }
> 
> int devm_probe_irq(struct device *dev, const struct devm_probe *probe)
> {
> 	int ret;
> 	int irq;
> 	int *irqp;
> 	int index;
> 	const char *name;
> 
> 	/* come up with a reasonable string for the irq name,
> 	   maybe create devm_kasprintf() to allow arbitrary length? */
> 	name = devm_kmalloc(dev, 32, GFP_KERNEL);
> 	if (!name)
> 		return -ENOMEM;
> 	if (probe->name)
> 		snprintf(name, 32 - 1, "%s:%s", dev_name(dev), probe->name);
> 	else
> 		snprintf(name, 32 - 1, "%s:%n", dev_name(dev), probe->index);
> 
> 	/* find IRQ number from resource if platform device */
> 	irq = 0;
> 	if (dev->bus_type == &platform_bus) {
> 		struct platform_device *pdev = to_platform_device(dev);
> 
> 		if (probe->name)
> 			irq = platform_get_irq_byname(pdev, probe->name);
> 		else
> 			irq = platform_get_irq(pdev, probe->index);
> 	}
> 
> 	/* try getting irq number from device tree if that failed */
> 	if (!irq && dev->of_node) {
> 		if (probe->name)
> 			index = of_property_match_string(dev->of_node,
> 							 "interrupt-names",
> 							 probe->name);
> 		else
> 			index = probe->index;
> 
> 		irq = irq_of_parse_and_map(dev->of_node, index);
> 	}
> 
> 	/* copy irq number to driver data */
> 	irqp = dev_get_drvdata(dev) + probe->offset;
> 	*irqp = irq;
> 	
> 	return devm_request_irq(dev, irq, probe->arg, probe->flags, name, probe->dev);
> }
> EXPORT_SYMBOL_GPL(devm_probe_irq);
> 
> #define DEVM_IRQ(_struct, _member, _index, _handler, _flags) {	\
> 	.initfunc = devm_probe_irq,				\
> 	.offset = offsetof_t(struct _struct, _member, int),	\
> 	.index = _index,					\
> 	.arg = typecheck_ptr((_handler), irq_handler_t),	\
> 	.flags = _flags,					\
> }	
> 
> #define DEVM_IRQ_NAMED(_struct, _member, _name, _handler, _flags) { \
> 	.initfunc = devm_probe_irq,				\
> 	.offset = offsetof_t(struct _struct, _member, int),	\
> 	.name = _name,						\
> 	.arg = typecheck_ptr((_handler), irq_handler_t),	\
> 	.flags = _flags,					\
> }	
> 
> 
> #define DEVM_IOMAP_NOREQUEST 1
> 
> int devm_probe_iomap(struct device *dev, const struct devm_probe *probe)
> {
> 	struct resource res, *resp;
> 	void __iomem *vaddr;
> 	void * __iomem *vaddrp;
> 	int ret;
> 
> 	/* find mem resource from platform device */
> 	if (dev->bus_type == &platform_bus) {
> 		struct platform_device *pdev = to_platform_device(dev);
> 
> 		if (probe->name)
> 			resp = platform_get_resource_byname(pdev,
> 					IORESOURCE_MEM, probe->name);
> 		else
> 			resp = platform_get_resource(pdev,
> 					IORESOURCE_MEM, probe->index);
> 	}
> 
> 	/* try getting resource from device tree if that failed */
> 	if (!resp && dev->of_node) {
> 		if (probe->name)
> 			index = of_property_match_string(dev->of_node,
> 							 "reg-names",
> 							 probe->name);
> 		else
> 			index = probe->index;
> 
> 		ret = of_address_to_resource(dev->of_node, index, &res);
> 		if (ret)
> 			return ret;
> 		resp = &res;
> 	}
> 
> 
> 	if (probe->flags & DEVM_IOMAP_NOREQUEST) {
> 		vaddr = devm_ioremap(dev, resp->start, resource_size(resp));
> 		if (!vaddr)
> 			return -EINVAL;
> 	} else {
> 		vaddr = devm_ioremap_resource(dev, resp);
> 		if (IS_ERR(vaddr))
> 			return PTR_ERR(vaddr);
> 	}
> 
> 	vaddrp = dev_get_drvdata(dev) + probe->offset;
> 	*vaddrp = vaddr;
> 
> 	return 0;
> }
> EXPORT_SYMBOL_GPL(devm_probe_iomap);
> 
> #define DEVM_IOMAP(_struct, _member, _index, _flags) {			\
> 	.initfunc = devm_probe_iomap,					\
> 	.offset = offsetof_t(struct _struct, _member, void __iomem *),	\
> 	.index = _index,						\
> 	.flags = _flags,						\
> }	
> 
> #define DEVM_IOMAP_NAMED(_struct, _member, _name, _flags) { 		\
> 	.initfunc = devm_probe_iomap,					\
> 	.offset = offsetof_t(struct _struct, _member, void __iomem *),	\
> 	.name = _name,							\
> 	.flags = _flags,						\
> }	
> 
> int devm_probe_gpio(struct device *dev, const struct devm_probe *probe)
> {
> 	struct gpio_desc *desc, **descp;
> 
> 	desc = devm_gpiod_get_index(dev, probe->name, probe->index);
> 	if (IS_ERR(desc)) {
> 		/* FIXME: this looks wrong */
> 		desc = of_get_named_gpiod_flags(dev->of_node, probe->name,
> 						probe->index, NULL);
> 		if (IS_ERR(desc))
> 			return PTR_ERR(desc);
> 		devm_gpio_request(dev, desc_to_gpio(desc), probe->name);
> 	}
> 
> 	descp = dev_get_drvdata(dev) + probe->offset;
> 	*descp = desc;
> 
> 	return 0;
> }
> 
> #define DEVM_GPIO(_struct, _member, _index) {				 \
> 	.initfunc = devm_probe_iomap,					 \
> 	.offset = offsetof_t(struct _struct, _member, struct gpio_desc*),\
> 	.name = "gpios",						 \
> 	.index = _index,						 \
> }	
> 
> #define DEVM_GPIO_NAMED(_struct, _member, _name) { 			 \
> 	.initfunc = devm_probe_iomap,					 \
> 	.offset = offsetof_t(struct _struct, _member, struct gpio_desc*),\
> 	.name = _name,							 \
> }	
> 
> static void devm_probe_dma_release(struct device *dev, void *chanp)
> {
> 	dma_release_channel(*(struct dma_chan**)chanp);
> }
> 
> int devm_probe_dma(struct device *dev, const struct devm_probe *probe)
> {
> 	struct dma_chan *chan, **chanp;
> 
> 	/* there is no devm_dma_request_channel yet, so build our own */
> 	chanp = devres_alloc(devm_probe_dma_release, sizeof(chanp), GFP_KERNEL);
> 	if (!chanp)
> 		return -ENOMEM;
> 
> 	chan = dma_request_slave_channel(dev, probe->name);
> 	if (!chan) {
> 		devres_free(chanp);
> 		return -EINVAL;
> 	}
> 
> 	*chanp = chan;
> 	devres_add(dev, chanp);
> 
> 	/* add pointer to the private data */
> 	chanp = dev_get_drvdata(dev) + probe->offset;
> 	*chanp = chan;
> 
> 	return 0;
> }
> 
> #define DEVM_DMA_SLAVE(_struct, _member, _name)				\
> 	.offset = offsetof_t(struct _struct, _member, struct dma_chan*),\
> 	.name = _name,							\
> }
> 
> /*
>  * simple properties: bool, u32, string
>  * no actual need for managed interfaces, just a way to abstract the
>  * access to DT or other information source
>  */
> int devm_probe_prop_bool(struct device *dev, struct devm_probe *probe)
> {
> 	bool *val;
> 
> 	val = dev_get_drvdata(dev) + probe->offset;
> 	*val = of_property_read_bool(dev->of_node, probe->name);
> 
> 	return 0;
> }
> EXPORT_SYMBOL_GPL(devm_probe_prop_bool);
> 
> #define DEVM_PROP_BOOL(_struct, _member, _name)			\
> 	.offset = offsetof_t(struct _struct, _member, bool),	\
> 	.name = _name,						\
> }
> 
> int devm_probe_prop_u32(struct device *dev, struct devm_probe *probe)
> {
> 	u32 *val;
> 	int ret;
> 
> 	val = dev_get_drvdata(dev) + probe->offset;
> 	ret = of_property_read_u32(dev->of_node, probe->name, val);
> 
> 	return ret;
> }
> EXPORT_SYMBOL_GPL(devm_probe_prop_bool);
> 
> #define DEVM_PROP_U32(_struct, _member, _name)			\
> 	.offset = offsetof_t(struct _struct, _member, u32),	\
> 	.name = _name,						\
> }
> 
> int devm_probe_prop_string(struct device *dev, struct devm_probe *probe)
> {
> 	const char **val;
> 	int ret;
> 
> 	val = dev_get_drvdata(dev) + probe->offset;
> 	ret = of_property_read_string(dev->of_node, probe->name, val);
> 
> 	return ret;
> }
> EXPORT_SYMBOL_GPL(devm_probe_prop_bool);
> 
> #define DEVM_PROP_STRING(_struct, _member, _name)			\
> 	.offset = offsetof_t(struct _struct, _member, const char *),	\
> 	.name = _name,							\
> }
> 
> /* example driver */
> struct foo_priv {
> 	spinlock_t lock;
> 	void __iomem *regs;
> 	int irq;
> 	struct gpio_desc *gpio;
> 	struct dma_chan *rxdma;
> 	struct dma_chan *txdma;
> 	bool oldstyle_dma;
> };
> 
> static irqreturn_t foo_irq_handler(int irq, void *dev);
> 
> /*
>  * this lists all properties we access from the driver. The list
>  * is interpreted by devm_probe() and can be programmatically
>  * verified to match the binding.
>  */
> static const struct devm_probe foo_probe_list[] = {
> 	DEVM_ALLOC(foo_priv),
> 	DEVM_IOMAP(foo_priv, regs, 0, 0),
> 	DEVM_PROP_BOOL(foo_priv, oldstyle_dma, "foo,oldstyle-dma"),
> 	DEVM_DMA_SLAVE(foo_priv, rxdma, "rx");
> 	DEVM_DMA_SLAVE(foo_priv, txdma, "tx");
> 	DEVM_GPIO(foo_priv, gpio, 0);
> 	DEVM_IRQ_NAMED(foo_priv, irq, foo_irq_handler, "fifo", IRQF_SHARED),
> 	{},
> };
> 
> static int foo_probe(struct platform_device *dev)
> {
> 	int ret;
> 
> 	ret = devm_probe(dev->dev, foo_probe_list);
> 	if (ret)
> 		return ret;
> 
> 	return bar_subsystem_register(&foo_bar_ops, dev);
> }
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

  parent reply	other threads:[~2013-11-06 12:17 UTC|newest]

Thread overview: 78+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-10-24 21:51 [RFC PATCH dtc] C-based DT schema checker integrated into dtc Stephen Warren
2013-10-24 21:51 ` Stephen Warren
2013-10-24 23:43 ` Grant Likely
2013-10-24 23:43   ` Grant Likely
2013-10-25  4:00   ` Kumar Gala
2013-10-25  4:00     ` Kumar Gala
2013-10-25 14:44   ` Stephen Warren
2013-10-25 14:44     ` Stephen Warren
2013-10-25 15:21     ` Jon Loeliger
2013-10-25 15:21       ` Jon Loeliger
2013-10-25 17:38       ` Rob Herring
2013-10-25 17:38         ` Rob Herring
2013-10-25 23:11       ` David Gibson
2013-10-25 23:11         ` David Gibson
2013-11-03 23:15         ` Tomasz Figa
2013-11-03 23:15           ` Tomasz Figa
2013-11-03 23:26           ` Tomasz Figa
2013-11-03 23:26             ` Tomasz Figa
2013-11-04  9:28             ` Arnd Bergmann
2013-11-04  9:28               ` Arnd Bergmann
2013-11-04 12:31               ` Tomasz Figa
2013-11-04 12:31                 ` Tomasz Figa
2013-11-04 16:37               ` Stephen Warren
2013-11-04 16:37                 ` Stephen Warren
2013-11-04 18:57                 ` Olof Johansson
2013-11-04 18:57                   ` Olof Johansson
2013-11-04 20:43                 ` Arnd Bergmann
2013-11-04 20:43                   ` Arnd Bergmann
2013-11-04 21:29                   ` Jason Gunthorpe
2013-11-04 21:29                     ` Jason Gunthorpe
2013-11-04 21:43                     ` Stephen Warren
2013-11-04 21:43                       ` Stephen Warren
2013-11-04 22:21                       ` Jason Gunthorpe
2013-11-04 22:21                         ` Jason Gunthorpe
2013-11-05 12:14                         ` Arnd Bergmann
2013-11-05 12:14                           ` Arnd Bergmann
2013-11-05  8:39                     ` Arnd Bergmann
2013-11-05  8:39                       ` Arnd Bergmann
2013-11-05 18:03                       ` Jason Gunthorpe
2013-11-05 18:03                         ` Jason Gunthorpe
2013-11-05 18:48                         ` Arnd Bergmann
2013-11-05 18:48                           ` Arnd Bergmann
2013-11-05 19:12                           ` Jason Gunthorpe
2013-11-05 19:12                             ` Jason Gunthorpe
2013-11-05 19:34                             ` Arnd Bergmann
2013-11-05 19:34                               ` Arnd Bergmann
2013-11-05 19:58                               ` Jason Gunthorpe
2013-11-05 19:58                                 ` Jason Gunthorpe
2013-11-05 20:17                                 ` Arnd Bergmann
2013-11-05 20:17                                   ` Arnd Bergmann
2013-11-05 20:36                                   ` Jason Gunthorpe
2013-11-05 20:36                                     ` Jason Gunthorpe
2013-11-04 21:50                   ` Stephen Warren
2013-11-04 21:50                     ` Stephen Warren
2013-11-05  8:22                     ` Arnd Bergmann
2013-11-05  8:22                       ` Arnd Bergmann
2013-11-06 12:17                   ` Thierry Reding [this message]
2013-11-06 12:17                     ` Thierry Reding
2013-11-04 14:28           ` David Gibson
2013-11-04 14:28             ` David Gibson
2013-11-04 16:42           ` Stephen Warren
2013-11-04 16:42             ` Stephen Warren
2013-10-28 10:17     ` David Gibson
2013-10-28 10:17       ` David Gibson
2013-10-31 21:13       ` Stephen Warren
2013-10-31 21:13         ` Stephen Warren
2013-11-01 13:24         ` David Gibson
2013-11-01 13:24           ` David Gibson
2013-10-25 23:29 ` David Gibson
2013-10-25 23:29   ` David Gibson
2013-10-31 21:11   ` Stephen Warren
2013-10-31 21:11     ` Stephen Warren
2013-11-10 11:00     ` David Gibson
2013-11-10 11:00       ` David Gibson
2013-11-12 22:06       ` Stephen Warren
2013-11-12 22:06         ` Stephen Warren
2013-11-13  0:33         ` David Gibson
2013-11-13  0:33           ` David Gibson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20131106121752.GB6984@ulmo.nvidia.com \
    --to=thierry.reding@gmail.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.