Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5388d480 authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branch 'asoc/topic/pxa' into asoc-next

parents 8a8b0e87 a1ce3138
Loading
Loading
Loading
Loading
+65 −0
Original line number Original line Diff line number Diff line
Device tree bindings for Marvell PXA SSP ports

Required properties:

	- compatible:	Must be one of
				mrvl,pxa25x-ssp
				mvrl,pxa25x-nssp
				mrvl,pxa27x-ssp
				mrvl,pxa3xx-ssp
				mvrl,pxa168-ssp
				mrvl,pxa910-ssp
				mrvl,ce4100-ssp
				mrvl,lpss-ssp

	- reg:		The memory base
	- dmas:		Two dma phandles, one for rx, one for tx
	- dma-names:	Must be "rx", "tx"


Example for PXA3xx:

	ssp0: ssp@41000000 {
		compatible = "mrvl,pxa3xx-ssp";
		reg = <0x41000000 0x40>;
		ssp-id = <1>;
		interrupts = <24>;
		clock-names = "pxa27x-ssp.0";
		dmas = <&dma 13
			&dma 14>;
		dma-names = "rx", "tx";
	};

	ssp1: ssp@41700000 {
		compatible = "mrvl,pxa3xx-ssp";
		reg = <0x41700000 0x40>;
		ssp-id = <2>;
		interrupts = <16>;
		clock-names = "pxa27x-ssp.1";
		dmas = <&dma 15
			&dma 16>;
		dma-names = "rx", "tx";
	};

	ssp2: ssp@41900000 {
		compatibl3 = "mrvl,pxa3xx-ssp";
		reg = <0x41900000 0x40>;
		ssp-id = <3>;
		interrupts = <0>;
		clock-names = "pxa27x-ssp.2";
		dmas = <&dma 66
			&dma 67>;
		dma-names = "rx", "tx";
	};

	ssp3: ssp@41a00000 {
		compatible = "mrvl,pxa3xx-ssp";
		reg = <0x41a00000 0x40>;
		ssp-id = <4>;
		interrupts = <13>;
		clock-names = "pxa27x-ssp.3";
		dmas = <&dma 2
			&dma 3>;
		dma-names = "rx", "tx";
	};
+28 −0
Original line number Original line Diff line number Diff line
Marvell PXA SSP CPU DAI bindings

Required properties:

	compatible	Must be "mrvl,pxa-ssp-dai"
	port		A phandle reference to a PXA ssp upstream device

Example:

	/* upstream device */

	ssp0: ssp@41000000 {
		compatible = "mrvl,pxa3xx-ssp";
		reg = <0x41000000 0x40>;
		interrupts = <24>;
		clock-names = "pxa27x-ssp.0";
		dmas = <&dma 13
			&dma 14>;
		dma-names = "rx", "tx";
	};

	/* DAI as user */

	ssp_dai0: ssp_dai@0 {
		compatible = "mrvl,pxa-ssp-dai";
		port = <&ssp0>;
	};
+15 −0
Original line number Original line Diff line number Diff line
DT bindings for ARM PXA2xx PCM platform driver

This is just a dummy driver that registers the PXA ASoC platform driver.
It does not have any resources assigned.

Required properties:

	- compatible		'mrvl,pxa-pcm-audio'

Example:

	pxa_pcm_audio: snd_soc_pxa_audio {
		compatible = "mrvl,pxa-pcm-audio";
	};
+114 −57
Original line number Original line Diff line number Diff line
@@ -30,6 +30,8 @@
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/io.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>


#include <asm/irq.h>
#include <asm/irq.h>
#include <mach/hardware.h>
#include <mach/hardware.h>
@@ -60,6 +62,30 @@ struct ssp_device *pxa_ssp_request(int port, const char *label)
}
}
EXPORT_SYMBOL(pxa_ssp_request);
EXPORT_SYMBOL(pxa_ssp_request);


struct ssp_device *pxa_ssp_request_of(const struct device_node *of_node,
				      const char *label)
{
	struct ssp_device *ssp = NULL;

	mutex_lock(&ssp_lock);

	list_for_each_entry(ssp, &ssp_list, node) {
		if (ssp->of_node == of_node && ssp->use_count == 0) {
			ssp->use_count++;
			ssp->label = label;
			break;
		}
	}

	mutex_unlock(&ssp_lock);

	if (&ssp->node == &ssp_list)
		return NULL;

	return ssp;
}
EXPORT_SYMBOL(pxa_ssp_request_of);

void pxa_ssp_free(struct ssp_device *ssp)
void pxa_ssp_free(struct ssp_device *ssp)
{
{
	mutex_lock(&ssp_lock);
	mutex_lock(&ssp_lock);
@@ -72,96 +98,126 @@ void pxa_ssp_free(struct ssp_device *ssp)
}
}
EXPORT_SYMBOL(pxa_ssp_free);
EXPORT_SYMBOL(pxa_ssp_free);


#ifdef CONFIG_OF
static const struct of_device_id pxa_ssp_of_ids[] = {
	{ .compatible = "mrvl,pxa25x-ssp",	.data = (void *) PXA25x_SSP },
	{ .compatible = "mvrl,pxa25x-nssp",	.data = (void *) PXA25x_NSSP },
	{ .compatible = "mrvl,pxa27x-ssp",	.data = (void *) PXA27x_SSP },
	{ .compatible = "mrvl,pxa3xx-ssp",	.data = (void *) PXA3xx_SSP },
	{ .compatible = "mvrl,pxa168-ssp",	.data = (void *) PXA168_SSP },
	{ .compatible = "mrvl,pxa910-ssp",	.data = (void *) PXA910_SSP },
	{ .compatible = "mrvl,ce4100-ssp",	.data = (void *) CE4100_SSP },
	{ .compatible = "mrvl,lpss-ssp",	.data = (void *) LPSS_SSP },
	{ },
};
MODULE_DEVICE_TABLE(of, pxa_ssp_of_ids);
#endif

static int pxa_ssp_probe(struct platform_device *pdev)
static int pxa_ssp_probe(struct platform_device *pdev)
{
{
	const struct platform_device_id *id = platform_get_device_id(pdev);
	struct resource *res;
	struct resource *res;
	struct ssp_device *ssp;
	struct ssp_device *ssp;
	int ret = 0;
	struct device *dev = &pdev->dev;


	ssp = kzalloc(sizeof(struct ssp_device), GFP_KERNEL);
	ssp = devm_kzalloc(dev, sizeof(struct ssp_device), GFP_KERNEL);
	if (ssp == NULL) {
	if (ssp == NULL)
		dev_err(&pdev->dev, "failed to allocate memory");
		return -ENOMEM;
		return -ENOMEM;
	}

	ssp->pdev = pdev;
	ssp->pdev = pdev;


	ssp->clk = clk_get(&pdev->dev, NULL);
	ssp->clk = devm_clk_get(dev, NULL);
	if (IS_ERR(ssp->clk)) {
	if (IS_ERR(ssp->clk))
		ret = PTR_ERR(ssp->clk);
		return PTR_ERR(ssp->clk);
		goto err_free;

	}
	if (dev->of_node) {
		struct of_phandle_args dma_spec;
		struct device_node *np = dev->of_node;

		/*
		 * FIXME: we should allocate the DMA channel from this
		 * context and pass the channel down to the ssp users.
		 * For now, we lookup the rx and tx indices manually
		 */


		/* rx */
		of_parse_phandle_with_args(np, "dmas", "#dma-cells",
					   0, &dma_spec);
		ssp->drcmr_rx = dma_spec.args[0];
		of_node_put(dma_spec.np);

		/* tx */
		of_parse_phandle_with_args(np, "dmas", "#dma-cells",
					   1, &dma_spec);
		ssp->drcmr_tx = dma_spec.args[0];
		of_node_put(dma_spec.np);
	} else {
		res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
		res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
		if (res == NULL) {
		if (res == NULL) {
		dev_err(&pdev->dev, "no SSP RX DRCMR defined\n");
			dev_err(dev, "no SSP RX DRCMR defined\n");
		ret = -ENODEV;
			return -ENODEV;
		goto err_free_clk;
		}
		}
		ssp->drcmr_rx = res->start;
		ssp->drcmr_rx = res->start;


		res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
		res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
		if (res == NULL) {
		if (res == NULL) {
		dev_err(&pdev->dev, "no SSP TX DRCMR defined\n");
			dev_err(dev, "no SSP TX DRCMR defined\n");
		ret = -ENODEV;
			return -ENODEV;
		goto err_free_clk;
		}
		}
		ssp->drcmr_tx = res->start;
		ssp->drcmr_tx = res->start;
	}


	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (res == NULL) {
	if (res == NULL) {
		dev_err(&pdev->dev, "no memory resource defined\n");
		dev_err(dev, "no memory resource defined\n");
		ret = -ENODEV;
		return -ENODEV;
		goto err_free_clk;
	}
	}


	res = request_mem_region(res->start, resource_size(res),
	res = devm_request_mem_region(dev, res->start, resource_size(res),
				      pdev->name);
				      pdev->name);
	if (res == NULL) {
	if (res == NULL) {
		dev_err(&pdev->dev, "failed to request memory resource\n");
		dev_err(dev, "failed to request memory resource\n");
		ret = -EBUSY;
		return -EBUSY;
		goto err_free_clk;
	}
	}


	ssp->phys_base = res->start;
	ssp->phys_base = res->start;


	ssp->mmio_base = ioremap(res->start, resource_size(res));
	ssp->mmio_base = devm_ioremap(dev, res->start, resource_size(res));
	if (ssp->mmio_base == NULL) {
	if (ssp->mmio_base == NULL) {
		dev_err(&pdev->dev, "failed to ioremap() registers\n");
		dev_err(dev, "failed to ioremap() registers\n");
		ret = -ENODEV;
		return -ENODEV;
		goto err_free_mem;
	}
	}


	ssp->irq = platform_get_irq(pdev, 0);
	ssp->irq = platform_get_irq(pdev, 0);
	if (ssp->irq < 0) {
	if (ssp->irq < 0) {
		dev_err(&pdev->dev, "no IRQ resource defined\n");
		dev_err(dev, "no IRQ resource defined\n");
		ret = -ENODEV;
		return -ENODEV;
		goto err_free_io;
	}
	}


	if (dev->of_node) {
		const struct of_device_id *id =
			of_match_device(of_match_ptr(pxa_ssp_of_ids), dev);
		ssp->type = (int) id->data;
	} else {
		const struct platform_device_id *id =
			platform_get_device_id(pdev);
		ssp->type = (int) id->driver_data;

		/* PXA2xx/3xx SSP ports starts from 1 and the internal pdev->id
		/* PXA2xx/3xx SSP ports starts from 1 and the internal pdev->id
		 * starts from 0, do a translation here
		 * starts from 0, do a translation here
		 */
		 */
		ssp->port_id = pdev->id + 1;
		ssp->port_id = pdev->id + 1;
	}

	ssp->use_count = 0;
	ssp->use_count = 0;
	ssp->type = (int)id->driver_data;
	ssp->of_node = dev->of_node;


	mutex_lock(&ssp_lock);
	mutex_lock(&ssp_lock);
	list_add(&ssp->node, &ssp_list);
	list_add(&ssp->node, &ssp_list);
	mutex_unlock(&ssp_lock);
	mutex_unlock(&ssp_lock);


	platform_set_drvdata(pdev, ssp);
	platform_set_drvdata(pdev, ssp);
	return 0;


err_free_io:
	return 0;
	iounmap(ssp->mmio_base);
err_free_mem:
	release_mem_region(res->start, resource_size(res));
err_free_clk:
	clk_put(ssp->clk);
err_free:
	kfree(ssp);
	return ret;
}
}


static int pxa_ssp_remove(struct platform_device *pdev)
static int pxa_ssp_remove(struct platform_device *pdev)
@@ -203,6 +259,7 @@ static struct platform_driver pxa_ssp_driver = {
	.driver		= {
	.driver		= {
		.owner		= THIS_MODULE,
		.owner		= THIS_MODULE,
		.name		= "pxa2xx-ssp",
		.name		= "pxa2xx-ssp",
		.of_match_table	= of_match_ptr(pxa_ssp_of_ids),
	},
	},
	.id_table	= ssp_id_table,
	.id_table	= ssp_id_table,
};
};
+11 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,8 @@


#include <linux/list.h>
#include <linux/list.h>
#include <linux/io.h>
#include <linux/io.h>
#include <linux/of.h>



/*
/*
 * SSP Serial Port Registers
 * SSP Serial Port Registers
@@ -190,6 +192,8 @@ struct ssp_device {
	int		irq;
	int		irq;
	int		drcmr_rx;
	int		drcmr_rx;
	int		drcmr_tx;
	int		drcmr_tx;

	struct device_node	*of_node;
};
};


/**
/**
@@ -218,11 +222,18 @@ static inline u32 pxa_ssp_read_reg(struct ssp_device *dev, u32 reg)
#ifdef CONFIG_ARCH_PXA
#ifdef CONFIG_ARCH_PXA
struct ssp_device *pxa_ssp_request(int port, const char *label);
struct ssp_device *pxa_ssp_request(int port, const char *label);
void pxa_ssp_free(struct ssp_device *);
void pxa_ssp_free(struct ssp_device *);
struct ssp_device *pxa_ssp_request_of(const struct device_node *of_node,
				      const char *label);
#else
#else
static inline struct ssp_device *pxa_ssp_request(int port, const char *label)
static inline struct ssp_device *pxa_ssp_request(int port, const char *label)
{
{
	return NULL;
	return NULL;
}
}
static inline struct ssp_device *pxa_ssp_request_of(const struct device_node *n,
						    const char *name)
{
	return NULL;
}
static inline void pxa_ssp_free(struct ssp_device *ssp) {}
static inline void pxa_ssp_free(struct ssp_device *ssp) {}
#endif
#endif


Loading