* [PATCH v2 5/7] dmaengine: cppi41: Move some constants to glue layer
From: Alexandre Bailon @ 2017-01-17 13:45 UTC (permalink / raw)
To: vinod.koul-ral2JQCrhuEAvxtiuMwx3w, b-liu-l0cyMroinI0,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A
Cc: dmaengine-u79uwXL29TY76Z2rM5mHXA, nsekhar-l0cyMroinI0,
khilman-rdvid1DuHRBWk0Htik3J/w, ptitiano-rdvid1DuHRBWk0Htik3J/w,
tony-4v6yS6AI5VpBDgjK7y7TUQ, linux-omap-u79uwXL29TY76Z2rM5mHXA,
sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
devicetree-u79uwXL29TY76Z2rM5mHXA, Alexandre Bailon
In-Reply-To: <20170117134540.9988-1-abailon-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
Some constants are defined and use by the driver whereas they are
specifics to AM335x.
Add new variables to the glue layer, initialize them with the constants,
and use them in the driver.
Signed-off-by: Alexandre Bailon <abailon-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
---
drivers/dma/cppi41.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c
index 5527376..3b2f57f 100644
--- a/drivers/dma/cppi41.c
+++ b/drivers/dma/cppi41.c
@@ -68,7 +68,6 @@
#define QMGR_MEMCTRL_IDX_SH 16
#define QMGR_MEMCTRL_DESC_SH 8
-#define QMGR_NUM_PEND 5
#define QMGR_PEND(x) (0x90 + (x) * 4)
#define QMGR_PENDING_SLOT_Q(x) (x / 32)
@@ -138,6 +137,8 @@ struct cppi41_dd {
const struct chan_queues *queues_rx;
const struct chan_queues *queues_tx;
struct chan_queues td_queue;
+ u16 first_completion_queue;
+ u16 qmgr_num_pend;
struct list_head pending; /* Pending queued transfers */
spinlock_t lock; /* Lock for pending list */
@@ -146,7 +147,6 @@ struct cppi41_dd {
unsigned int dma_tdfdq;
};
-#define FIST_COMPLETION_QUEUE 93
static struct chan_queues am335x_usb_queues_tx[] = {
/* USB0 ENDP 1 */
[ 0] = { .submit = 32, .complete = 93},
@@ -224,6 +224,8 @@ struct cppi_glue_infos {
const struct chan_queues *queues_rx;
const struct chan_queues *queues_tx;
struct chan_queues td_queue;
+ u16 first_completion_queue;
+ u16 qmgr_num_pend;
};
static struct cppi41_channel *to_cpp41_chan(struct dma_chan *c)
@@ -278,19 +280,21 @@ static u32 cppi41_pop_desc(struct cppi41_dd *cdd, unsigned queue_num)
static irqreturn_t cppi41_irq(int irq, void *data)
{
struct cppi41_dd *cdd = data;
+ u16 first_completion_queue = cdd->first_completion_queue;
+ u16 qmgr_num_pend = cdd->qmgr_num_pend;
struct cppi41_channel *c;
int i;
- for (i = QMGR_PENDING_SLOT_Q(FIST_COMPLETION_QUEUE); i < QMGR_NUM_PEND;
+ for (i = QMGR_PENDING_SLOT_Q(first_completion_queue); i < qmgr_num_pend;
i++) {
u32 val;
u32 q_num;
val = cppi_readl(cdd->qmgr_mem + QMGR_PEND(i));
- if (i == QMGR_PENDING_SLOT_Q(FIST_COMPLETION_QUEUE) && val) {
+ if (i == QMGR_PENDING_SLOT_Q(first_completion_queue) && val) {
u32 mask;
/* set corresponding bit for completetion Q 93 */
- mask = 1 << QMGR_PENDING_BIT_Q(FIST_COMPLETION_QUEUE);
+ mask = 1 << QMGR_PENDING_BIT_Q(first_completion_queue);
/* not set all bits for queues less than Q 93 */
mask--;
/* now invert and keep only Q 93+ set */
@@ -862,7 +866,7 @@ static int init_cppi41(struct device *dev, struct cppi41_dd *cdd)
return -ENOMEM;
cppi_writel(cdd->scratch_phys, cdd->qmgr_mem + QMGR_LRAM0_BASE);
- cppi_writel(QMGR_SCRATCH_SIZE, cdd->qmgr_mem + QMGR_LRAM_SIZE);
+ cppi_writel(TOTAL_DESCS_NUM, cdd->qmgr_mem + QMGR_LRAM_SIZE);
cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM1_BASE);
ret = init_descs(dev, cdd);
@@ -945,6 +949,8 @@ static const struct cppi_glue_infos am335x_usb_infos = {
.queues_rx = am335x_usb_queues_rx,
.queues_tx = am335x_usb_queues_tx,
.td_queue = { .submit = 31, .complete = 0 },
+ .first_completion_queue = 93,
+ .qmgr_num_pend = 5,
};
static const struct of_device_id cppi41_dma_ids[] = {
@@ -1021,6 +1027,8 @@ static int cppi41_dma_probe(struct platform_device *pdev)
cdd->queues_rx = glue_info->queues_rx;
cdd->queues_tx = glue_info->queues_tx;
cdd->td_queue = glue_info->td_queue;
+ cdd->qmgr_num_pend = glue_info->qmgr_num_pend;
+ cdd->first_completion_queue = glue_info->first_completion_queue;
ret = init_cppi41(dev, cdd);
if (ret)
--
2.10.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 6/7] dmaengine: cppi41: init_sched(): Get number of channels from DT
From: Alexandre Bailon @ 2017-01-17 13:45 UTC (permalink / raw)
To: vinod.koul-ral2JQCrhuEAvxtiuMwx3w, b-liu-l0cyMroinI0,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A
Cc: dmaengine-u79uwXL29TY76Z2rM5mHXA, nsekhar-l0cyMroinI0,
khilman-rdvid1DuHRBWk0Htik3J/w, ptitiano-rdvid1DuHRBWk0Htik3J/w,
tony-4v6yS6AI5VpBDgjK7y7TUQ, linux-omap-u79uwXL29TY76Z2rM5mHXA,
sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
devicetree-u79uwXL29TY76Z2rM5mHXA, Alexandre Bailon
In-Reply-To: <20170117134540.9988-1-abailon-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
Despite the driver is already using DT to get the number of channels,
init_sched() is using an hardcoded value to get it.
Use DT to get the number of channels.
Signed-off-by: Alexandre Bailon <abailon-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
---
drivers/dma/cppi41.c | 33 ++++++++++++++++++++-------------
1 file changed, 20 insertions(+), 13 deletions(-)
diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c
index 3b2f57f..303ccee 100644
--- a/drivers/dma/cppi41.c
+++ b/drivers/dma/cppi41.c
@@ -139,6 +139,8 @@ struct cppi41_dd {
struct chan_queues td_queue;
u16 first_completion_queue;
u16 qmgr_num_pend;
+ u32 n_chans;
+ u8 platform;
struct list_head pending; /* Pending queued transfers */
spinlock_t lock; /* Lock for pending list */
@@ -720,13 +722,8 @@ static int cppi41_add_chans(struct device *dev, struct cppi41_dd *cdd)
{
struct cppi41_channel *cchan;
int i;
- int ret;
- u32 n_chans;
+ u32 n_chans = cdd->n_chans;
- ret = of_property_read_u32(dev->of_node, "#dma-channels",
- &n_chans);
- if (ret)
- return ret;
/*
* The channels can only be used as TX or as RX. So we add twice
* that much dma channels because USB can only do RX or TX.
@@ -832,7 +829,7 @@ static int init_descs(struct device *dev, struct cppi41_dd *cdd)
return 0;
}
-static void init_sched(struct cppi41_dd *cdd)
+static int init_sched(struct device *dev, struct cppi41_dd *cdd)
{
unsigned ch;
unsigned word;
@@ -840,7 +837,7 @@ static void init_sched(struct cppi41_dd *cdd)
word = 0;
cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL);
- for (ch = 0; ch < 15 * 2; ch += 2) {
+ for (ch = 0; ch < cdd->n_chans; ch += 2) {
reg = SCHED_ENTRY0_CHAN(ch);
reg |= SCHED_ENTRY1_CHAN(ch) | SCHED_ENTRY1_IS_RX;
@@ -850,9 +847,11 @@ static void init_sched(struct cppi41_dd *cdd)
cppi_writel(reg, cdd->sched_mem + DMA_SCHED_WORD(word));
word++;
}
- reg = 15 * 2 * 2 - 1;
+ reg = cdd->n_chans * 2 - 1;
reg |= DMA_SCHED_CTRL_EN;
cppi_writel(reg, cdd->sched_mem + DMA_SCHED_CTRL);
+
+ return 0;
}
static int init_cppi41(struct device *dev, struct cppi41_dd *cdd)
@@ -871,12 +870,14 @@ static int init_cppi41(struct device *dev, struct cppi41_dd *cdd)
ret = init_descs(dev, cdd);
if (ret)
- goto err_td;
+ goto deinit;
cppi_writel(cdd->td_queue.submit, cdd->ctrl_mem + DMA_TDFDQ);
- init_sched(cdd);
+ ret = init_sched(dev, cdd);
+ if (ret)
+ goto deinit;
return 0;
-err_td:
+deinit:
deinit_cppi41(dev, cdd);
return ret;
}
@@ -1030,6 +1031,11 @@ static int cppi41_dma_probe(struct platform_device *pdev)
cdd->qmgr_num_pend = glue_info->qmgr_num_pend;
cdd->first_completion_queue = glue_info->first_completion_queue;
+ ret = of_property_read_u32(dev->of_node,
+ "#dma-channels", &cdd->n_chans);
+ if (ret)
+ goto err_get_n_chans;
+
ret = init_cppi41(dev, cdd);
if (ret)
goto err_init_cppi;
@@ -1072,6 +1078,7 @@ static int cppi41_dma_probe(struct platform_device *pdev)
deinit_cppi41(dev, cdd);
err_init_cppi:
pm_runtime_dont_use_autosuspend(dev);
+err_get_n_chans:
err_get_sync:
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
@@ -1128,7 +1135,7 @@ static int __maybe_unused cppi41_resume(struct device *dev)
if (!c->is_tx)
cppi_writel(c->q_num, c->gcr_reg + RXHPCRA0);
- init_sched(cdd);
+ init_sched(dev, cdd);
cppi_writel(cdd->dma_tdfdq, cdd->ctrl_mem + DMA_TDFDQ);
cppi_writel(cdd->scratch_phys, cdd->qmgr_mem + QMGR_LRAM0_BASE);
--
2.10.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v2 7/7] dmaengine: cppi41: Fix a race between PM runtime and channel abort
From: Alexandre Bailon @ 2017-01-17 13:45 UTC (permalink / raw)
To: vinod.koul-ral2JQCrhuEAvxtiuMwx3w, b-liu-l0cyMroinI0,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A
Cc: dmaengine-u79uwXL29TY76Z2rM5mHXA, nsekhar-l0cyMroinI0,
khilman-rdvid1DuHRBWk0Htik3J/w, ptitiano-rdvid1DuHRBWk0Htik3J/w,
tony-4v6yS6AI5VpBDgjK7y7TUQ, linux-omap-u79uwXL29TY76Z2rM5mHXA,
sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
devicetree-u79uwXL29TY76Z2rM5mHXA, Alexandre Bailon
In-Reply-To: <20170117134540.9988-1-abailon-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
cppi41_dma_issue_pending() may be called while the device is runtime
suspended. In that case, the descriptor will be pushed to the pending
list and then be queued to hardware queue.
But if cppi41_stop_chan() is called before the device got time to
resume, then the descriptor will remain in the pending list and be
queued to hardware queue after the teardown.
During the channel stop, check if there is a pending descriptor
and if so, remove it.
Signed-off-by: Alexandre Bailon <abailon-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
---
drivers/dma/cppi41.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c
index 303ccee..0bc4f1a 100644
--- a/drivers/dma/cppi41.c
+++ b/drivers/dma/cppi41.c
@@ -687,10 +687,17 @@ static int cppi41_stop_chan(struct dma_chan *chan)
{
struct cppi41_channel *c = to_cpp41_chan(chan);
struct cppi41_dd *cdd = c->cdd;
+ unsigned long flags;
u32 desc_num;
u32 desc_phys;
int ret;
+ /* Remove pending descriptor that haven't been pushed to queue */
+ spin_lock_irqsave(&cdd->lock, flags);
+ if (!list_empty(&c->node))
+ list_del_init(&c->node);
+ spin_unlock_irqrestore(&cdd->lock, flags);
+
desc_phys = lower_32_bits(c->desc_phys);
desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
if (!cdd->chan_busy[desc_num])
@@ -748,6 +755,7 @@ static int cppi41_add_chans(struct device *dev, struct cppi41_dd *cdd)
cchan->desc_phys = cdd->descs_phys;
cchan->desc_phys += i * sizeof(struct cppi41_desc);
cchan->chan.device = &cdd->ddev;
+ INIT_LIST_HEAD(&cchan->node);
list_add_tail(&cchan->chan.device_node, &cdd->ddev.channels);
}
cdd->first_td_desc = n_chans;
@@ -1163,7 +1171,7 @@ static int __maybe_unused cppi41_runtime_resume(struct device *dev)
spin_lock_irqsave(&cdd->lock, flags);
list_for_each_entry_safe(c, _c, &cdd->pending, node) {
push_desc_queue(c);
- list_del(&c->node);
+ list_del_init(&c->node);
}
spin_unlock_irqrestore(&cdd->lock, flags);
--
2.10.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH 1/5] ARM: OMAP2+: omap_hwmod: Add support for earlycon
From: Lokesh Vutla @ 2017-01-17 13:47 UTC (permalink / raw)
To: Mark Rutland
Cc: Tony Lindgren, Linux OMAP Mailing List, Device Tree Mailing List,
Rob Herring, Tero Kristo, Sekhar Nori, Vignesh R, Nishanth Menon
In-Reply-To: <20170117104703.GA11939@leverpostej>
On Tuesday 17 January 2017 04:17 PM, Mark Rutland wrote:
> On Tue, Jan 17, 2017 at 09:33:32AM +0530, Lokesh Vutla wrote:
>> Hwmod core tries to reset and idles each IP that is registered with hwmod.
>> In case of earlycon, that specific uart IP cannot be reset or keep it in
>> idle state else earlycon hangs once hwmod resets that uart IP. So add support
>> to not reset uart that is being used as earlycon only if CONFIG_SERIAL_EARLYCON
>> is enabled.
>
>> + np = of_find_node_by_path("/chosen");
>> + if (!np)
>> + np = of_find_node_by_path("/chosen@0");
>
> I think you can drop the second case here. There shouldn't be an "@0" on
> a chosen node; core code handles that only to cater for some legacy
> (PPC?) DTBs, and I don't beleive it's necessary for OMAP.
Right. Ill repost this series by dropping this case.
Thanks and regards,
Lokesh
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 2/2] arm64: dts: exynos: Add regulators for Vbus and Vbus-Boost
From: Javier Martinez Canillas @ 2017-01-17 13:47 UTC (permalink / raw)
To: Pankaj Dubey, linux-samsung-soc, linux-arm-kernel, devicetree
Cc: krzk, kgene, robh+dt, sanath, gautamvivek1987
In-Reply-To: <1484649143-19423-3-git-send-email-pankaj.dubey@samsung.com>
Hello Pankaj,
On 01/17/2017 07:32 AM, Pankaj Dubey wrote:
> Adding fixed voltage regulators for Vbus and Vbus-boost required
> by USB 3.0 DRD controller on Exynos7-espresso board.
>
> Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
> Signed-off-by: Vivek Gautam <gautamvivek1987@gmail.com>
Same comment than 1/2 here.
> ---
> arch/arm64/boot/dts/exynos/exynos7-espresso.dts | 44 +++++++++++++++++++++++++
> 1 file changed, 44 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/exynos/exynos7-espresso.dts b/arch/arm64/boot/dts/exynos/exynos7-espresso.dts
> index 9cf73cf..68f3a51 100644
> --- a/arch/arm64/boot/dts/exynos/exynos7-espresso.dts
> +++ b/arch/arm64/boot/dts/exynos/exynos7-espresso.dts
> @@ -33,6 +33,29 @@
> device_type = "memory";
> reg = <0x0 0x40000000 0x0 0xC0000000>;
> };
> +
> + usb30_vbus_reg: regulator-usb30 {
> + compatible = "regulator-fixed";
> + regulator-name = "VBUS_5V";
> + regulator-min-microvolt = <5000000>;
> + regulator-max-microvolt = <5000000>;
> + gpio = <&gph1 1 0>;
Please use the GPIO_ACTIVE_HIGH instead for the GPIO polarity.
> + pinctrl-names = "default";
> + pinctrl-0 = <&usb30_vbus_en>;
> + enable-active-high;
> + };
> +
> + usb3drd_boost_5v: regulator-usb3drd-boost {
> + compatible = "regulator-fixed";
> + regulator-name = "VUSB_VBUS_5V";
> + regulator-min-microvolt = <5000000>;
> + regulator-max-microvolt = <5000000>;
> + gpio = <&gpf4 1 0>;
Same here.
> + pinctrl-names = "default";
> + pinctrl-0 = <&usb3drd_boost_en>;
> + enable-active-high;
> + };
> +
> };
>
> &fin_pll {
> @@ -366,3 +389,24 @@
> vqmmc-supply = <&ldo2_reg>;
> disable-wp;
> };
> +
> +&usbdrd_phy {
> + vbus-supply = <&usb30_vbus_reg>;
> + vbus-boost-supply = <&usb3drd_boost_5v>;
> +};
> +
> +&pinctrl_bus1 {
> + usb30_vbus_en: usb30-vbus-en {
> + samsung,pins = "gph1-1";
> + samsung,pin-function = <1>;
EXYNOS_PIN_FUNC_OUTPUT
> + samsung,pin-pud = <0>;
EXYNOS_PIN_PULL_NONE
> + samsung,pin-drv = <0>;
I see that there are no Exynos7 drive strengths values for
Exynos7 in include/dt-bindings/pinctrl/samsung.h. It would
be good to add those (on a different series of course).
The patch looks good to me, so after the minor nits:
Reviewed-by: Javier Martinez Canillas <javier@osg.samsung.com>
Best regards,
--
Javier Martinez Canillas
Open Source Group
Samsung Research America
^ permalink raw reply
* [PATCH v3 0/3] iio: distance: srf08: add IIO driver for us ranger
From: Andreas Klinger @ 2017-01-17 13:48 UTC (permalink / raw)
To: jic23, knaack.h, lars, pmeerw, linux-iio, linux-kernel, ktsai,
wsa, robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak,
trivial, mranostay, linux-i2c, devicetree
Cc: ak
This patch series adds IIO driver support for srf08 ultrasonic ranger
devices.
The first patch add a trivial device tree binding for the device together
with a new vendor devantech.
The second patch is the IIO driver which in turn is using I2C to talk to
the device.
The third patch documents the added userspace ABI
Documentation about the sensor can be found here:
http://www.robot-electronics.co.uk/htm/srf08tech.html
Changes in v3:
Thanks to the reviews of Jonathan, Rob and Lars.
Some changes to the driver were made:
* Patch 2: "iio: distance: srf08: add IIO driver for us ranger"
- defaults values for sensitivity (gain) and max. range are set in
probe()
- while waiting for ultrasonic echo first wait as long as the physically
measurement need as a function of the max. range and then wait in
smaller steps until the response can be read.
- attributes are now called sensor_sensitivity instead of gain and
sensor_max_range instead of range_mm
- device-name is now "srf08"
- config menu is now calles "Proximity and distance sensors" instead of a
separate menu
* Patch 3: "iio: distance: srf08: add driver ABI documentation"
- newly created to document the driver specific interfaces
Changes in v2:
Lots of updates thanks to Peters really fast review within 30 minutes
after first submission of the driver.
* Patch 2: "iio: distance: srf08: add IIO driver for us ranger"
- alphabetic order in Makefile
- use of u8 while accessing registers
- avoid endianness problems with 16 bit values
- missing return value checks
- some explaining documentation added
Andreas Klinger (3):
iio: distance: srf08: add trivial DT binding
iio: distance: srf08: add IIO driver for us ranger
iio: distance: srf08: add driver ABI documentation
.../ABI/testing/sysfs-bus-iio-distance-srf08 | 27 ++
.../devicetree/bindings/i2c/trivial-devices.txt | 1 +
.../devicetree/bindings/vendor-prefixes.txt | 1 +
drivers/iio/proximity/Kconfig | 13 +-
drivers/iio/proximity/Makefile | 1 +
drivers/iio/proximity/srf08.c | 405 +++++++++++++++++++++
6 files changed, 447 insertions(+), 1 deletion(-)
create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-distance-srf08
create mode 100644 drivers/iio/proximity/srf08.c
--
2.1.4
--
^ permalink raw reply
* [PATCH v3 1/3] iio: distance: srf08: add trivial DT binding
From: Andreas Klinger @ 2017-01-17 13:49 UTC (permalink / raw)
To: jic23-DgEjT+Ai2ygdnm+yROfE0A, knaack.h-Mmb7MZpHnFY,
lars-Qo5EllUWu/uELgA04lAiVw, pmeerw-jW+XmwGofnusTnJN9+BGXg,
linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, ktsai-GubuWUlQtMwciDkP5Hr2oA,
wsa-z923LK4zBo2bacvFa/9K2g, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
galak-sgV2jX0FEOL9JmXXK+q4OQ, trivial-DgEjT+Ai2ygdnm+yROfE0A,
mranostay-Re5JQEeQqe8AvxtiuMwx3w,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: ak-n176/SwNRljddJNmlsFzeA
Add DT binding for devantech,srf08
Add vendor devantech to vendor list
Signed-off-by: Andreas Klinger <ak-n176/SwNRljddJNmlsFzeA@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
Documentation/devicetree/bindings/i2c/trivial-devices.txt | 1 +
Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
2 files changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
index 539874490492..86c6930c3c91 100644
--- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt
+++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
@@ -36,6 +36,7 @@ dallas,ds1775 Tiny Digital Thermometer and Thermostat
dallas,ds3232 Extremely Accurate I²C RTC with Integrated Crystal and SRAM
dallas,ds4510 CPU Supervisor with Nonvolatile Memory and Programmable I/O
dallas,ds75 Digital Thermometer and Thermostat
+devantech,srf08 Devantech SRF08 ultrasonic ranger
dlg,da9053 DA9053: flexible system level PMIC with multicore support
dlg,da9063 DA9063: system PMIC for quad-core application processors
epson,rx8010 I2C-BUS INTERFACE REAL TIME CLOCK MODULE
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 4696bb5c2198..80325e602403 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -65,6 +65,7 @@ dallas Maxim Integrated Products (formerly Dallas Semiconductor)
davicom DAVICOM Semiconductor, Inc.
delta Delta Electronics, Inc.
denx Denx Software Engineering
+devantech Devantech, Ltd.
digi Digi International Inc.
digilent Diglent, Inc.
dlg Dialog Semiconductor
--
2.1.4
--
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH v3 2/3] iio: distance: srf08: add IIO driver for us ranger
From: Andreas Klinger @ 2017-01-17 13:49 UTC (permalink / raw)
To: jic23-DgEjT+Ai2ygdnm+yROfE0A, knaack.h-Mmb7MZpHnFY,
lars-Qo5EllUWu/uELgA04lAiVw, pmeerw-jW+XmwGofnusTnJN9+BGXg,
linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, ktsai-GubuWUlQtMwciDkP5Hr2oA,
wsa-z923LK4zBo2bacvFa/9K2g, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
galak-sgV2jX0FEOL9JmXXK+q4OQ, trivial-DgEjT+Ai2ygdnm+yROfE0A,
mranostay-Re5JQEeQqe8AvxtiuMwx3w,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: ak-n176/SwNRljddJNmlsFzeA
This is the IIO driver for devantech srf08 ultrasonic ranger which can be
used to measure the distances to an object.
The sensor supports I2C with some registers.
Supported Features include:
- read the distance in ranging mode in centimeters
- output of the driver is directly the read value
- together with the scale the driver delivers the distance in meters
- only the first echo of the nearest object is delivered
- set sensitivity as analog value in the range of 0-31 means setting
gain register on device
- set range registers; userspace enters max. range in millimeters in
43 mm steps
Features not supported by this driver:
- ranging mode in inches or in microseconds
- ANN mode
- change I2C address through this driver
- light sensor
The driver was added in the directory "proximity" of the iio subsystem and
the menu in den config is now called "Proximity and distance sensors"
Signed-off-by: Andreas Klinger <ak-n176/SwNRljddJNmlsFzeA@public.gmane.org>
---
drivers/iio/proximity/Kconfig | 13 +-
drivers/iio/proximity/Makefile | 1 +
drivers/iio/proximity/srf08.c | 405 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 418 insertions(+), 1 deletion(-)
create mode 100644 drivers/iio/proximity/srf08.c
diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig
index ef4c73db5b53..ab96cb7a0054 100644
--- a/drivers/iio/proximity/Kconfig
+++ b/drivers/iio/proximity/Kconfig
@@ -18,7 +18,7 @@ config AS3935
endmenu
-menu "Proximity sensors"
+menu "Proximity and distance sensors"
config LIDAR_LITE_V2
tristate "PulsedLight LIDAR sensor"
@@ -45,4 +45,15 @@ config SX9500
To compile this driver as a module, choose M here: the
module will be called sx9500.
+config SRF08
+ tristate "Devantech SRF08 ultrasonic ranger sensor"
+ depends on I2C
+ help
+ Say Y here to build a driver for Devantech SRF08 ultrasonic
+ ranger sensor. This driver can be used to measure the distance
+ of objects.
+
+ To compile this driver as a module, choose M here: the
+ module will be called srf08.
+
endmenu
diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile
index 9aadd9a8ee99..e914c2a5dd49 100644
--- a/drivers/iio/proximity/Makefile
+++ b/drivers/iio/proximity/Makefile
@@ -5,4 +5,5 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AS3935) += as3935.o
obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o
+obj-$(CONFIG_SRF08) += srf08.o
obj-$(CONFIG_SX9500) += sx9500.o
diff --git a/drivers/iio/proximity/srf08.c b/drivers/iio/proximity/srf08.c
new file mode 100644
index 000000000000..faab6cf3f1a2
--- /dev/null
+++ b/drivers/iio/proximity/srf08.c
@@ -0,0 +1,405 @@
+/*
+ * srf08.c - Support for Devantech SRF08 ultrasonic ranger
+ *
+ * Copyright (c) 2016 Andreas Klinger <ak-n176/SwNRljddJNmlsFzeA@public.gmane.org>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * For details about the device see:
+ * http://www.robot-electronics.co.uk/htm/srf08tech.html
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+/* registers of SRF08 device */
+#define SRF08_WRITE_COMMAND 0x00 /* Command Register */
+#define SRF08_WRITE_MAX_GAIN 0x01 /* Max Gain Register: 0 .. 31 */
+#define SRF08_WRITE_RANGE 0x02 /* Range Register: 0 .. 255 */
+#define SRF08_READ_SW_REVISION 0x00 /* Software Revision */
+#define SRF08_READ_LIGHT 0x01 /* Light Sensor during last echo */
+#define SRF08_READ_ECHO_1_HIGH 0x02 /* Range of first echo received */
+#define SRF08_READ_ECHO_1_LOW 0x03 /* Range of first echo received */
+
+#define SRF08_CMD_RANGING_CM 0x51 /* Ranging Mode - Result in cm */
+
+#define SRF08_DEFAULT_GAIN 1025 /* default analogue value of Gain */
+#define SRF08_DEFAULT_RANGE 6020 /* default value of Range in mm */
+
+struct srf08_data {
+ struct i2c_client *client;
+ int sensitivity; /* Gain */
+ int range_mm; /* max. Range in mm */
+ struct mutex lock;
+};
+
+/*
+ * in the documentation one can read about the "Gain" of the device
+ * which is used here for amplifying the signal and filtering out unwanted
+ * ones.
+ * But with ADC's this term is already used differently and that's why it
+ * is called "Sensitivity" here.
+ */
+static const int srf08_sensitivity[] = {
+ 94, 97, 100, 103, 107, 110, 114, 118,
+ 123, 128, 133, 139, 145, 152, 159, 168,
+ 177, 187, 199, 212, 227, 245, 265, 288,
+ 317, 352, 395, 450, 524, 626, 777, 1025 };
+
+static int srf08_read_ranging(struct srf08_data *data)
+{
+ struct i2c_client *client = data->client;
+ int ret, i;
+ int waittime;
+
+ mutex_lock(&data->lock);
+
+ ret = i2c_smbus_write_byte_data(data->client,
+ SRF08_WRITE_COMMAND, SRF08_CMD_RANGING_CM);
+ if (ret < 0) {
+ dev_err(&client->dev, "write command - err: %d\n", ret);
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+
+ /*
+ * we read here until a correct version number shows up as
+ * suggested by the documentation
+ *
+ * with an ultrasonic speed of 343 m/s and a roundtrip of it
+ * sleep the expected duration and try to read from the device
+ * if nothing useful is read try it in a shorter grid
+ *
+ * polling for not more than 20 ms should be enough
+ */
+ waittime = 1 + data->range_mm / 172;
+ msleep(waittime);
+ for (i = 0; i < 4; i++) {
+ ret = i2c_smbus_read_byte_data(data->client,
+ SRF08_READ_SW_REVISION);
+
+ /* check if a valid version number is read */
+ if (ret < 255 && ret > 0)
+ break;
+ msleep(5);
+ }
+
+ if (ret >= 255 || ret <= 0) {
+ dev_err(&client->dev, "device not ready\n");
+ mutex_unlock(&data->lock);
+ return -EIO;
+ }
+
+ ret = i2c_smbus_read_word_swapped(data->client,
+ SRF08_READ_ECHO_1_HIGH);
+ if (ret < 0) {
+ dev_err(&client->dev, "cannot read distance: ret=%d\n", ret);
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+static int srf08_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *val,
+ int *val2, long mask)
+{
+ struct srf08_data *data = iio_priv(indio_dev);
+ int ret;
+
+ if (channel->type != IIO_DISTANCE)
+ return -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = srf08_read_ranging(data);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ /* 1 LSB is 1 cm */
+ *val = 0;
+ *val2 = 10000;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static ssize_t srf08_show_range_mm_available(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i, len = 0;
+
+ for (i = 0; i < 256; i++)
+ len += scnprintf(buf + len, PAGE_SIZE - len,
+ "%d ", (i + 1) * 43);
+
+ buf[len - 1] = '\n';
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(sensor_max_range_available, S_IRUGO,
+ srf08_show_range_mm_available, NULL, 0);
+
+static ssize_t srf08_show_range_mm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct srf08_data *data = iio_priv(indio_dev);
+
+ return sprintf(buf, "%d\n", data->range_mm);
+}
+
+/*
+ * set the range of the sensor to an even multiple of 43 mm
+ * which corresponds to 1 LSB in the register
+ *
+ * register value corresponding range
+ * 0x00 43 mm
+ * 0x01 86 mm
+ * 0x02 129 mm
+ * ...
+ * 0xFF 11008 mm
+ */
+static ssize_t srf08_write_range_mm(struct srf08_data *data, unsigned int val)
+{
+ int ret;
+ struct i2c_client *client = data->client;
+ unsigned int mod;
+ u8 regval;
+
+ ret = val / 43 - 1;
+ mod = val % 43;
+
+ if (mod || (ret < 0) || (ret > 255))
+ return -EINVAL;
+
+ regval = ret;
+
+ mutex_lock(&data->lock);
+
+ ret = i2c_smbus_write_byte_data(client, SRF08_WRITE_RANGE, regval);
+ if (ret < 0) {
+ dev_err(&client->dev, "write_range - err: %d\n", ret);
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+
+ data->range_mm = val;
+
+ mutex_unlock(&data->lock);
+
+ return 0;
+}
+
+static ssize_t srf08_store_range_mm(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct srf08_data *data = iio_priv(indio_dev);
+ int ret;
+ unsigned int val;
+
+ ret = kstrtouint(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ ret = srf08_write_range_mm(data, val);
+ if (ret < 0)
+ return ret;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(sensor_max_range, S_IRUGO | S_IWUSR,
+ srf08_show_range_mm, srf08_store_range_mm, 0);
+
+static ssize_t srf08_show_sensitivity_available(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i, len = 0;
+
+ for (i = 0; i < ARRAY_SIZE(srf08_sensitivity); i++)
+ len += sprintf(buf + len, "%d ", srf08_sensitivity[i]);
+
+ len += sprintf(buf + len, "\n");
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(sensor_sensitivity_available, S_IRUGO,
+ srf08_show_sensitivity_available, NULL, 0);
+
+static ssize_t srf08_show_sensitivity(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct srf08_data *data = iio_priv(indio_dev);
+ int len;
+
+ len = sprintf(buf, "%d\n", data->sensitivity);
+
+ return len;
+}
+
+static ssize_t srf08_write_sensitivity(struct srf08_data *data,
+ unsigned int val)
+{
+ struct i2c_client *client = data->client;
+ int ret, i;
+ u8 regval;
+
+ for (i = 0; i < ARRAY_SIZE(srf08_sensitivity); i++)
+ if (val == srf08_sensitivity[i]) {
+ regval = i;
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(srf08_sensitivity))
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+
+ ret = i2c_smbus_write_byte_data(client,
+ SRF08_WRITE_MAX_GAIN, regval);
+ if (ret < 0) {
+ dev_err(&client->dev, "write_sensitivity - err: %d\n", ret);
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+
+ data->sensitivity = val;
+
+ mutex_unlock(&data->lock);
+
+ return 0;
+}
+
+static ssize_t srf08_store_sensitivity(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct srf08_data *data = iio_priv(indio_dev);
+ int ret;
+ unsigned int val;
+
+ ret = kstrtouint(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ ret = srf08_write_sensitivity(data, val);
+ if (ret < 0)
+ return ret;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(sensor_sensitivity, S_IRUGO | S_IWUSR,
+ srf08_show_sensitivity, srf08_store_sensitivity, 0);
+
+static struct attribute *srf08_attributes[] = {
+ &iio_dev_attr_sensor_max_range.dev_attr.attr,
+ &iio_dev_attr_sensor_max_range_available.dev_attr.attr,
+ &iio_dev_attr_sensor_sensitivity.dev_attr.attr,
+ &iio_dev_attr_sensor_sensitivity_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group srf08_attribute_group = {
+ .attrs = srf08_attributes,
+};
+
+static const struct iio_chan_spec srf08_channels[] = {
+ {
+ .type = IIO_DISTANCE,
+ .info_mask_separate =
+ BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ },
+};
+
+static const struct iio_info srf08_info = {
+ .read_raw = srf08_read_raw,
+ .attrs = &srf08_attribute_group,
+ .driver_module = THIS_MODULE,
+};
+
+static int srf08_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iio_dev *indio_dev;
+ struct srf08_data *data;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_BYTE_DATA |
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+ I2C_FUNC_SMBUS_READ_WORD_DATA))
+ return -ENODEV;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+
+ indio_dev->name = "srf08";
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &srf08_info;
+ indio_dev->channels = srf08_channels;
+ indio_dev->num_channels = ARRAY_SIZE(srf08_channels);
+
+ mutex_init(&data->lock);
+
+ /*
+ * set default values of device here
+ * these register values cannot be read from the hardware
+ * therefore set driver specific default values
+ */
+ ret = srf08_write_sensitivity(data, SRF08_DEFAULT_GAIN);
+ if (ret < 0)
+ return ret;
+
+ ret = srf08_write_range_mm(data, SRF08_DEFAULT_RANGE);
+ if (ret < 0)
+ return ret;
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id srf08_id[] = {
+ { "srf08", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, srf08_id);
+
+static struct i2c_driver srf08_driver = {
+ .driver = {
+ .name = "srf08",
+ },
+ .probe = srf08_probe,
+ .id_table = srf08_id,
+};
+module_i2c_driver(srf08_driver);
+
+MODULE_AUTHOR("Andreas Klinger <ak-n176/SwNRljddJNmlsFzeA@public.gmane.org>");
+MODULE_DESCRIPTION("Devantech SRF08 ultrasonic ranger driver");
+MODULE_LICENSE("GPL");
--
2.1.4
--
^ permalink raw reply related
* [PATCH v3 3/3] iio: distance: srf08: add driver ABI documentation
From: Andreas Klinger @ 2017-01-17 13:50 UTC (permalink / raw)
To: jic23-DgEjT+Ai2ygdnm+yROfE0A, knaack.h-Mmb7MZpHnFY,
lars-Qo5EllUWu/uELgA04lAiVw, pmeerw-jW+XmwGofnusTnJN9+BGXg,
linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, ktsai-GubuWUlQtMwciDkP5Hr2oA,
wsa-z923LK4zBo2bacvFa/9K2g, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
galak-sgV2jX0FEOL9JmXXK+q4OQ, trivial-DgEjT+Ai2ygdnm+yROfE0A,
mranostay-Re5JQEeQqe8AvxtiuMwx3w,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: ak-n176/SwNRljddJNmlsFzeA
Add sysfs-bus-iio-distance-srf08 for individual attributes of the driver,
especially:
- sensitivity which the device documentation calls gain for amplifying the
signal
- max_range for limiting the maximum distance for expected echos and
therefore limiting the time waiting for telegrams
Signed-off-by: Andreas Klinger <ak-n176/SwNRljddJNmlsFzeA@public.gmane.org>
---
.../ABI/testing/sysfs-bus-iio-distance-srf08 | 27 ++++++++++++++++++++++
1 file changed, 27 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-distance-srf08
diff --git a/Documentation/ABI/testing/sysfs-bus-iio-distance-srf08 b/Documentation/ABI/testing/sysfs-bus-iio-distance-srf08
new file mode 100644
index 000000000000..e96c28064748
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-iio-distance-srf08
@@ -0,0 +1,27 @@
+What /sys/bus/iio/devices/iio:deviceX/in_distance_raw
+Date: January 2017
+KernelVersion: 4.11
+Contact: linux-iio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
+Description:
+ Get the current distance in meters between the sensor and
+ the first object recognized
+
+What /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity
+Date: January 2017
+KernelVersion: 4.11
+Contact: linux-iio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
+Description:
+ Show or set the gain boost of the amp, from 0-31 range.
+ default 31
+
+What /sys/bus/iio/devices/iio:deviceX/sensor_max_range
+Date: January 2017
+KernelVersion: 4.11
+Contact: linux-iio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
+Description:
+ Show or set the maximum range between the sensor and the
+ first object echoed in millimeters.
+ This setting limits the time the driver is waiting for a
+ echo.
+ Can be set between 43 and 11008 in a grid of 43 mm.
+ default 6020
--
2.1.4
--
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH] ARM: dts: am33x, da816x, da814x: Remove useless register address
From: Alexandre Bailon @ 2017-01-17 13:54 UTC (permalink / raw)
To: nsekhar-l0cyMroinI0, khilman-rdvid1DuHRBWk0Htik3J/w
Cc: vinod.koul-ral2JQCrhuEAvxtiuMwx3w,
dmaengine-u79uwXL29TY76Z2rM5mHXA, ptitiano-rdvid1DuHRBWk0Htik3J/w,
tony-4v6yS6AI5VpBDgjK7y7TUQ, linux-omap-u79uwXL29TY76Z2rM5mHXA,
b-liu-l0cyMroinI0,
sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA,
Alexandre Bailon
In order to make CPPI 4.1 DMA driver more generic, accesses to USBSS
have been removed. So it is not required anymore to define "glue"
register's address and size in DT.
Remove "glue" register from cppi41dma node.
Signed-off-by: Alexandre Bailon <abailon-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
---
arch/arm/boot/dts/am33xx.dtsi | 5 ++---
arch/arm/boot/dts/dm814x.dtsi | 5 ++---
arch/arm/boot/dts/dm816x.dtsi | 5 ++---
3 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index 9e96d60..2466ed5 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -659,11 +659,10 @@
cppi41dma: dma-controller@47402000 {
compatible = "ti,am3359-cppi41";
- reg = <0x47400000 0x1000
- 0x47402000 0x1000
+ reg = <0x47402000 0x1000
0x47403000 0x1000
0x47404000 0x4000>;
- reg-names = "glue", "controller", "scheduler", "queuemgr";
+ reg-names = "controller", "scheduler", "queuemgr";
interrupts = <17>;
interrupt-names = "glue";
#dma-cells = <2>;
diff --git a/arch/arm/boot/dts/dm814x.dtsi b/arch/arm/boot/dts/dm814x.dtsi
index 9708157..2dd727a 100644
--- a/arch/arm/boot/dts/dm814x.dtsi
+++ b/arch/arm/boot/dts/dm814x.dtsi
@@ -156,11 +156,10 @@
cppi41dma: dma-controller@47402000 {
compatible = "ti,am3359-cppi41";
- reg = <0x47400000 0x1000
- 0x47402000 0x1000
+ reg = <0x47402000 0x1000
0x47403000 0x1000
0x47404000 0x4000>;
- reg-names = "glue", "controller", "scheduler", "queuemgr";
+ reg-names = "controller", "scheduler", "queuemgr";
interrupts = <17>;
interrupt-names = "glue";
#dma-cells = <2>;
diff --git a/arch/arm/boot/dts/dm816x.dtsi b/arch/arm/boot/dts/dm816x.dtsi
index 276211e..bb78511 100644
--- a/arch/arm/boot/dts/dm816x.dtsi
+++ b/arch/arm/boot/dts/dm816x.dtsi
@@ -493,11 +493,10 @@
cppi41dma: dma-controller@47402000 {
compatible = "ti,am3359-cppi41";
- reg = <0x47400000 0x1000
- 0x47402000 0x1000
+ reg = <0x47402000 0x1000
0x47403000 0x1000
0x47404000 0x4000>;
- reg-names = "glue", "controller", "scheduler", "queuemgr";
+ reg-names = "controller", "scheduler", "queuemgr";
interrupts = <17>;
interrupt-names = "glue";
#dma-cells = <2>;
--
2.10.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 0/3] STM FingerTip S touchscreen support for TM2 board
From: Andi Shyti @ 2017-01-17 13:54 UTC (permalink / raw)
To: Dmitry Torokhov, Krzysztof Kozlowski, Rob Herring, Chanwoo Choi,
Javier Martinez Canillas
Cc: linux-input, devicetree, linux-kernel, linux-samsung-soc,
Andi Shyti, Andi Shyti
In-Reply-To: <CGME20170117135456epcas5p25968e1781a9cee833b350940ae7af70b@epcas5p2.samsung.com>
Hi,
this patchset provides support for the ST-Microelectronics
FingerTip S device driver and enables it in the tm2 and tm2e
devices.
It's tested on top of next-20170117 kernel and applies on
Krzysztof's for-next branch.
Thanks,
Andi
Andi Shyti (3):
Input: add STMicroelectronics FingerTip touchscreen driver
Input: add support for the STMicroelectronics FingerTip touchscreen
arm64: dts: exynos: Add stmfts touchscreen node for TM2 and TM2E
.../bindings/input/touchscreen/st,stmfts.txt | 43 ++
.../boot/dts/exynos/exynos5433-tm2-common.dtsi | 13 +
arch/arm64/boot/dts/exynos/exynos5433-tm2.dts | 5 +
arch/arm64/boot/dts/exynos/exynos5433-tm2e.dts | 7 +
drivers/input/touchscreen/Kconfig | 12 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/stmfts.c | 759 +++++++++++++++++++++
7 files changed, 840 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/touchscreen/st,stmfts.txt
create mode 100644 drivers/input/touchscreen/stmfts.c
--
2.11.0
^ permalink raw reply
* [PATCH 1/3] Input: add STMicroelectronics FingerTip touchscreen driver
From: Andi Shyti @ 2017-01-17 13:54 UTC (permalink / raw)
To: Dmitry Torokhov, Krzysztof Kozlowski, Rob Herring, Chanwoo Choi,
Javier Martinez Canillas
Cc: linux-input, devicetree, linux-kernel, linux-samsung-soc,
Andi Shyti, Andi Shyti
In-Reply-To: <20170117135441.31450-1-andi.shyti@samsung.com>
Add binding for the STMicroelectronics FingerTip (stmfts)
touchscreen driver.
Signed-off-by: Andi Shyti <andi.shyti@samsung.com>
---
.../bindings/input/touchscreen/st,stmfts.txt | 43 ++++++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/touchscreen/st,stmfts.txt
diff --git a/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.txt b/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.txt
new file mode 100644
index 000000000000..788f4ba744db
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/st,stmfts.txt
@@ -0,0 +1,43 @@
+* ST-Microelectronics FingerTip touchscreen controller
+
+The ST-Microelectronics FingerTip device provides a basic touchscreen
+functionality. Along with it the user can enable the touchkey which can work as
+a basic HOME and BACK key for phones.
+
+The driver supports also hovering as an absolute single touch event with x, y, z
+coordinates.
+
+Required properties:
+- compatible : must be "st,stmfts"
+- reg : I2C slave address, (e.g. 0x49)
+- interrupt-parent : the phandle to the interrupt controller which provides
+ the interrupt
+- interrupts : interrupt specification
+- avdd-supply : analogic power supply
+- vdd-supply : power supply
+- touchscreen-size-x : see touchscreen.txt
+- touchscreen-size-y : see touchscreen.txt
+
+Optional properties:
+- touch-key-connected : specifies whether the touchkey feature is connected
+- ledvdd-supply : power supply to the touch key leds
+
+Example:
+
+i2c@00000000 {
+
+ /* ... */
+
+ stmfts@49 {
+ compatible = "st,stmfts";
+ reg = <0x49>;
+ interrupt-parent = <&gpa1>;
+ interrupts = <1 IRQ_TYPE_NONE>;
+ touchscreen-size-x = <1599>;
+ touchscreen-size-y = <2559>;
+ touch-key-connected;
+ avdd-supply = <&ldo30_reg>;
+ vdd-supply = <&ldo31_reg>;
+ ledvdd-supply = <&ldo33_reg>;
+ };
+};
--
2.11.0
^ permalink raw reply related
* [PATCH 2/3] Input: add support for the STMicroelectronics FingerTip touchscreen
From: Andi Shyti @ 2017-01-17 13:54 UTC (permalink / raw)
To: Dmitry Torokhov, Krzysztof Kozlowski, Rob Herring, Chanwoo Choi,
Javier Martinez Canillas
Cc: linux-input, devicetree, linux-kernel, linux-samsung-soc,
Andi Shyti, Andi Shyti
In-Reply-To: <20170117135441.31450-1-andi.shyti@samsung.com>
The stmfts (ST-Microelectronics FingerTip S) touchscreen device
is a capacitive multi-touch controller mainly for mobile use.
It's connected through i2c bus at the address 0x49 and it
interfaces with userspace through input event interface.
At the current state it provides a touchscreen multitouch
functionality up to 10 fingers. Each finger is enumerated with a
distinctive id (from 0 to 9).
If enabled the device can support single "touch" hovering, by
providing three coordinates, x, y, z. The z coordinate is
related to the distance between the finger and the touchscreen
itself.
It is possible to select the touchkey functionality which
provides a basic two keys interface for "home" and "back" menu,
typical in mobile phones.
Signed-off-by: Andi Shyti <andi.shyti@samsung.com>
---
drivers/input/touchscreen/Kconfig | 12 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/stmfts.c | 759 +++++++++++++++++++++++++++++++++++++
3 files changed, 772 insertions(+)
create mode 100644 drivers/input/touchscreen/stmfts.c
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 8650c94e29d0..18c2f919eb79 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1092,6 +1092,18 @@ config TOUCHSCREEN_ST1232
To compile this driver as a module, choose M here: the
module will be called st1232_ts.
+config TOUCHSCREEN_STMFTS
+ tristate "STMicroelectronics STMFTS touchscreen"
+ depends on I2C
+ depends on INPUT
+ depends on LEDS_CLASS
+ help
+ Say Y here if you want support for STMicroelectronics
+ STMFTS touchscreen.
+
+ To compile this driver as a module, choose M here: the
+ module will be called stmfts.
+
config TOUCHSCREEN_STMPE
tristate "STMicroelectronics STMPE touchscreens"
depends on MFD_STMPE
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index e41e3c7aa427..be7673f9c71a 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_SILEAD) += silead.o
obj-$(CONFIG_TOUCHSCREEN_SIS_I2C) += sis_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
+obj-$(CONFIG_TOUCHSCREEN_STMFTS) += stmfts.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
new file mode 100644
index 000000000000..abccc14d06d2
--- /dev/null
+++ b/drivers/input/touchscreen/stmfts.c
@@ -0,0 +1,759 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Author: Andi Shyti <andi.shyti@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * STMicroelectronics FTS Touchscreen device driver
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+
+/* I2C commands */
+#define STMFTS_READ_INFO 0x80
+#define STMFTS_READ_STATUS 0x84
+#define STMFTS_READ_ONE_EVENT 0x85
+#define STMFTS_SLEEP_IN 0x91
+#define STMFTS_SLEEP_OUT 0x91
+#define STMFTS_MS_MT_SENSE_OFF 0x92
+#define STMFTS_MS_MT_SENSE_ON 0x93
+#define STMFTS_SS_HOVER_SENSE_OFF 0x94
+#define STMFTS_SS_HOVER_SENSE_ON 0x95
+#define STMFTS_MS_KEY_SENSE_OFF 0x9a
+#define STMFTS_MS_KEY_SENSE_ON 0x9b
+#define STMFTS_SYSTEM_RESET 0xa0
+#define STMFTS_CLEAR_EVENT_STACK 0xa1
+#define STMFTS_FULL_FORCE_CALIBRATION 0xa2
+#define STMFTS_MS_CX_TUNING 0xa3
+#define STMFTS_SS_CX_TUNING 0xa4
+
+/* events */
+#define STMFTS_EV_NO_EVENT 0x00
+#define STMFTS_EV_MULTI_TOUCH_DETECTED 0x02
+#define STMFTS_EV_MULTI_TOUCH_ENTER 0x03
+#define STMFTS_EV_MULTI_TOUCH_LEAVE 0x04
+#define STMFTS_EV_MULTI_TOUCH_MOTION 0x05
+#define STMFTS_EV_HOVER_ENTER 0x07
+#define STMFTS_EV_HOVER_LEAVE 0x08
+#define STMFTS_EV_HOVER_MOTION 0x09
+#define STMFTS_EV_KEY_STATUS 0x0e
+#define STMFTS_EV_ERROR 0x0f
+#define STMFTS_EV_CONTROLLER_READY 0x10
+#define STMFTS_EV_SLEEP_OUT_CONTROLLER_READY 0x11
+#define STMFTS_EV_STATUS 0x16
+
+/* multi touch related event masks */
+#define STMFTS_MASK_EVENT_ID 0x0f
+#define STMFTS_MASK_TOUCH_ID 0xf0
+#define STMFTS_MASK_LEFT_EVENT 0x0f
+#define STMFTS_MASK_X_MSB 0x0f
+#define STMFTS_MASK_Y_LSB 0xf0
+
+/* key related event masks */
+#define STMFTS_MASK_KEY_NO_TOUCH 0x00
+#define STMFTS_MASK_KEY_BACK 0x01
+#define STMFTS_MASK_KEY_MENU 0x02
+
+#define STMFTS_EVENT_SIZE 8
+#define STMFTS_MAX_FINGERS 10
+#define STMFTS_DEV_NAME "stmfts"
+
+enum stmfts_regulators {
+ STMFTS_REGULATOR_VDD,
+ STMFTS_REGULATOR_AVDD,
+};
+
+struct stmfts_data {
+ struct i2c_client *client;
+ struct input_dev *input_touch;
+ struct input_dev *input_key;
+ struct led_classdev led_cdev;
+ struct mutex mutex;
+ u32 x_size;
+ u32 y_size;
+
+ struct regulator_bulk_data regulators[2];
+
+ /* ledvdd will be used also to check
+ * whether the LED is supported
+ */
+ struct regulator *ledvdd;
+
+ bool use_key;
+ bool signal;
+ bool led_status;
+ u8 users;
+
+ u16 chip_id;
+ u8 chip_ver;
+ u16 fw_ver;
+ u8 config_id;
+ u8 config_ver;
+ u8 in_touch;
+
+ wait_queue_head_t wq;
+
+ bool hover_enabled;
+};
+
+static void stmfts_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct stmfts_data *sdata = container_of(led_cdev,
+ struct stmfts_data, led_cdev);
+
+ if (value == sdata->led_status)
+ return;
+
+ if (!value) {
+ regulator_disable(sdata->ledvdd);
+ } else {
+ int err = regulator_enable(sdata->ledvdd);
+
+ if (err)
+ dev_warn(&sdata->client->dev,
+ "failed to disable ledvdd regulator\n");
+ }
+
+ sdata->led_status = value;
+}
+
+static enum led_brightness stmfts_brightness_get(struct led_classdev *led_cdev)
+{
+ struct stmfts_data *sdata = container_of(led_cdev,
+ struct stmfts_data, led_cdev);
+
+ return !!regulator_is_enabled(sdata->ledvdd);
+}
+
+static void stmfts_parse_event(struct stmfts_data *sdata, u8 event[])
+{
+ int ret;
+ u8 id, t_id = 0;
+ u16 x, y, z, maj, min, orientation, area;
+
+ id = event[0];
+
+ do {
+ mutex_lock(&sdata->mutex);
+ if (sdata->in_touch) {
+ id = event[0] & STMFTS_MASK_EVENT_ID;
+ t_id = (event[0] & STMFTS_MASK_TOUCH_ID) >> 4;
+ } else {
+ id = event[0];
+ t_id = 0;
+ }
+
+ switch (id) {
+ case STMFTS_EV_NO_EVENT:
+ break;
+
+ case STMFTS_EV_MULTI_TOUCH_ENTER:
+ case STMFTS_EV_MULTI_TOUCH_LEAVE:
+ case STMFTS_EV_MULTI_TOUCH_MOTION:
+ if (id == STMFTS_EV_MULTI_TOUCH_ENTER) {
+ if (!(sdata->in_touch++))
+ input_mt_report_slot_state(
+ sdata->input_touch,
+ MT_TOOL_FINGER, true);
+ } else if (id == STMFTS_EV_MULTI_TOUCH_LEAVE) {
+ if (!(--sdata->in_touch))
+ input_mt_report_slot_state(
+ sdata->input_touch,
+ MT_TOOL_FINGER, false);
+ }
+
+ x = event[1] | ((event[2] & STMFTS_MASK_X_MSB) << 8);
+ y = (event[2] >> 4) | (event[3] << 4);
+
+ maj = event[4];
+ min = event[5];
+ orientation = event[6];
+ area = event[7];
+
+ input_mt_slot(sdata->input_touch, t_id);
+ input_report_abs(sdata->input_touch,
+ ABS_MT_POSITION_X, x);
+ input_report_abs(sdata->input_touch,
+ ABS_MT_POSITION_Y, y);
+ input_report_abs(sdata->input_touch,
+ ABS_MT_TOUCH_MAJOR, maj);
+ input_report_abs(sdata->input_touch,
+ ABS_MT_TOUCH_MINOR, min);
+ input_report_abs(sdata->input_touch,
+ ABS_MT_PRESSURE, area);
+ input_report_abs(sdata->input_touch,
+ ABS_MT_ORIENTATION, orientation);
+ input_sync(sdata->input_touch);
+
+ break;
+
+ case STMFTS_EV_HOVER_ENTER:
+ case STMFTS_EV_HOVER_LEAVE:
+ case STMFTS_EV_HOVER_MOTION:
+ x = (event[2] << 4) | (event[4] >> 4);
+ y = (event[3] << 4) | (event[4] & STMFTS_MASK_Y_LSB);
+ z = event[5];
+ orientation = event[6] & STMFTS_MASK_Y_LSB;
+
+ input_report_abs(sdata->input_touch, ABS_X, x);
+ input_report_abs(sdata->input_touch, ABS_Y, y);
+ input_report_abs(sdata->input_touch, ABS_Z, z);
+ input_sync(sdata->input_touch);
+
+ break;
+
+ case STMFTS_EV_KEY_STATUS:
+ if (!event[2]) {
+ input_report_key(sdata->input_key, KEY_BACK, 0);
+ input_report_key(sdata->input_key, KEY_MENU, 0);
+ } else {
+ if (event[2] == STMFTS_MASK_KEY_BACK)
+ input_report_key(sdata->input_key,
+ KEY_BACK, 1);
+ else if (event[2] == STMFTS_MASK_KEY_MENU)
+ input_report_key(sdata->input_key,
+ KEY_MENU, 1);
+ else /* quite impossible */
+ break;
+ }
+ input_sync(sdata->input_key);
+ break;
+
+ case STMFTS_EV_STATUS:
+ sdata->signal = true;
+ wake_up_interruptible(&sdata->wq);
+ break;
+
+ case STMFTS_EV_ERROR:
+ dev_err(&sdata->client->dev,
+ "error code: 0x%x%x%x%x%x%x",
+ event[6], event[5], event[4],
+ event[3], event[2], event[1]);
+ break;
+
+ default:
+ dev_err(&sdata->client->dev,
+ "unknown event 0x%x\n", event[0]);
+ }
+ mutex_unlock(&sdata->mutex);
+
+ ret = i2c_smbus_read_i2c_block_data(sdata->client,
+ STMFTS_READ_ONE_EVENT,
+ STMFTS_EVENT_SIZE, event);
+ if (ret) {
+ i2c_smbus_write_byte(sdata->client,
+ STMFTS_CLEAR_EVENT_STACK);
+ break;
+ }
+
+ } while (event[0]);
+}
+
+static irqreturn_t stmfts_irq_handler(int irq, void *dev)
+{
+ struct stmfts_data *sdata = dev;
+ int ret;
+ u8 event[STMFTS_EVENT_SIZE];
+
+ ret = i2c_smbus_read_i2c_block_data(sdata->client,
+ STMFTS_READ_ONE_EVENT,
+ STMFTS_EVENT_SIZE, event);
+
+ switch (event[0]) {
+ case STMFTS_EV_CONTROLLER_READY:
+ case STMFTS_EV_SLEEP_OUT_CONTROLLER_READY:
+ sdata->signal = true;
+ wake_up_interruptible(&sdata->wq);
+ break;
+ default:
+ stmfts_parse_event(sdata, event);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int stmfts_write_and_wait(struct stmfts_data *sdata, const u8 cmd)
+{
+ int err;
+
+ err = i2c_smbus_write_byte(sdata->client, cmd);
+ if (err)
+ return err;
+
+ sdata->signal = false;
+ err = wait_event_interruptible_timeout(sdata->wq, sdata->signal,
+ msecs_to_jiffies(1000));
+
+ return !err ? -ETIMEDOUT : 0;
+}
+
+static void stmfts_sleep_in(struct stmfts_data *sdata)
+{
+ mutex_lock(&sdata->mutex);
+
+ sdata->users--;
+ if (!sdata->users)
+ i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN);
+
+ mutex_unlock(&sdata->mutex);
+}
+
+static int stmfts_sleep_out(struct stmfts_data *sdata, u8 cmd)
+{
+ int ret = 0;
+
+ mutex_lock(&sdata->mutex);
+
+ if (!sdata->users)
+ ret = stmfts_write_and_wait(sdata, STMFTS_SLEEP_OUT);
+
+ /* if sleep out succeeds users increments, otherwise not */
+ sdata->users += !ret;
+
+ mutex_unlock(&sdata->mutex);
+
+ ret = i2c_smbus_write_byte(sdata->client, cmd);
+ if (ret)
+ stmfts_sleep_in(sdata);
+
+ return ret;
+}
+
+static int stmfts_input_touch_open(struct input_dev *dev)
+{
+ struct stmfts_data *sdata = input_get_drvdata(dev);
+
+ return stmfts_sleep_out(sdata, STMFTS_MS_MT_SENSE_ON);
+}
+
+static void stmfts_input_touch_close(struct input_dev *dev)
+{
+ struct stmfts_data *sdata = input_get_drvdata(dev);
+
+ i2c_smbus_write_byte(sdata->client, STMFTS_MS_MT_SENSE_OFF);
+
+ stmfts_sleep_in(sdata);
+}
+
+static int stmfts_input_key_open(struct input_dev *dev)
+{
+ struct stmfts_data *sdata = input_get_drvdata(dev);
+
+ return stmfts_sleep_out(sdata, STMFTS_MS_KEY_SENSE_ON);
+}
+
+static void stmfts_input_key_close(struct input_dev *dev)
+{
+ struct stmfts_data *sdata = input_get_drvdata(dev);
+
+ i2c_smbus_write_byte(sdata->client, STMFTS_MS_KEY_SENSE_OFF);
+ stmfts_sleep_in(sdata);
+}
+
+static ssize_t stmfts_sysfs_hwid(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct stmfts_data *sdata = dev_get_drvdata(dev);
+
+ return sprintf(buf, "ST-Microelectronics FTS 0x%x version %u\n",
+ sdata->chip_id, sdata->chip_ver);
+}
+
+static ssize_t stmfts_sysfs_fw_ver(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct stmfts_data *sdata = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", sdata->fw_ver);
+}
+
+static ssize_t stmfts_sysfs_config_id(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct stmfts_data *sdata = dev_get_drvdata(dev);
+
+ return sprintf(buf, "0x%x version %u\n",
+ sdata->config_id, sdata->config_ver);
+}
+
+static ssize_t stmfts_sysfs_read_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct stmfts_data *sdata = dev_get_drvdata(dev);
+ u8 status[4];
+ int ret;
+
+ ret = i2c_smbus_read_i2c_block_data(sdata->client,
+ STMFTS_READ_STATUS, 4, status);
+
+ return sprintf(buf, "0x%x\n", status[0]);
+}
+
+static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct stmfts_data *sdata = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", sdata->hover_enabled);
+}
+
+static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ unsigned long value;
+ int err;
+ struct stmfts_data *sdata = dev_get_drvdata(dev);
+
+ if (kstrtoul(buf, 0, &value))
+ return -EINVAL;
+
+ if (value & sdata->hover_enabled)
+ return len;
+
+ if (value) {
+ err = stmfts_sleep_out(sdata, STMFTS_SS_HOVER_SENSE_ON);
+ sdata->hover_enabled = !err;
+ } else {
+ err = i2c_smbus_write_byte(sdata->client,
+ STMFTS_SS_HOVER_SENSE_OFF);
+ stmfts_sleep_in(sdata);
+ sdata->hover_enabled = !!err;
+ }
+
+ return len;
+}
+
+static DEVICE_ATTR(hwid, 0444, stmfts_sysfs_hwid, NULL);
+static DEVICE_ATTR(fw_ver, 0444, stmfts_sysfs_fw_ver, NULL);
+static DEVICE_ATTR(config_id, 0444, stmfts_sysfs_config_id, NULL);
+static DEVICE_ATTR(status, 0444, stmfts_sysfs_read_status, NULL);
+static DEVICE_ATTR(hover_enable, 0644, stmfts_sysfs_hover_enable_read,
+ stmfts_sysfs_hover_enable_write);
+
+static struct attribute *stmfts_sysfs_attrs[] = {
+ &dev_attr_hwid.attr,
+ &dev_attr_fw_ver.attr,
+ &dev_attr_config_id.attr,
+ &dev_attr_status.attr,
+ &dev_attr_hover_enable.attr,
+ NULL
+};
+
+static struct attribute_group stmfts_attribute_group = {
+ .attrs = stmfts_sysfs_attrs
+};
+
+static int stmfts_parse_dt(struct stmfts_data *sdata)
+{
+ int ret;
+ struct device_node *np = sdata->client->dev.of_node;
+
+ if (!np)
+ return -ENOENT;
+
+ ret = of_property_read_u32(np, "touchscreen-size-x", &sdata->x_size);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(np, "touchscreen-size-y", &sdata->y_size);
+ if (ret)
+ return ret;
+
+ sdata->use_key = of_property_read_bool(np, "touch-key-connected");
+
+ return 0;
+}
+
+static int stmfts_power_on(struct stmfts_data *sdata)
+{
+ int err;
+ u8 reg[8];
+
+ err = regulator_bulk_enable(ARRAY_SIZE(sdata->regulators),
+ sdata->regulators);
+ if (err)
+ return err;
+
+ /*
+ * the datasheet does not specify the power on time, but considering
+ * that the reset time is < 10ms, I sleep 20ms to be sure
+ */
+ msleep(20);
+
+ err = i2c_smbus_read_i2c_block_data(sdata->client,
+ STMFTS_READ_INFO, 8, reg);
+ if (err < 0)
+ return err;
+ if (err != 8)
+ return -EIO;
+
+ sdata->chip_id = (reg[6] << 8) | reg[7];
+ sdata->chip_ver = reg[0];
+ sdata->fw_ver = (reg[2] << 8) | reg[3];
+ sdata->config_id = reg[4];
+ sdata->config_ver = reg[5];
+
+ enable_irq(sdata->client->irq);
+ err = stmfts_write_and_wait(sdata, STMFTS_SYSTEM_RESET);
+ if (err)
+ return err;
+
+ err = stmfts_write_and_wait(sdata, STMFTS_SLEEP_OUT);
+ if (err)
+ return err;
+
+ /* optional tuning */
+ err = stmfts_write_and_wait(sdata, STMFTS_MS_CX_TUNING);
+ if (err)
+ dev_warn(&sdata->client->dev, "failed to perform mutual auto tune\n");
+
+ /* optional tuning */
+ err = stmfts_write_and_wait(sdata, STMFTS_SS_CX_TUNING);
+ if (err)
+ dev_warn(&sdata->client->dev, "failed to perform self auto tune\n");
+
+ err = stmfts_write_and_wait(sdata, STMFTS_FULL_FORCE_CALIBRATION);
+ if (err)
+ return err;
+
+ /* at this point no one is using the touchscreen
+ * and I don't really care about the return value
+ */
+ i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN);
+
+ return 0;
+}
+
+static void stmfts_power_off(void *data)
+{
+ struct stmfts_data *sdata = data;
+
+ disable_irq(sdata->client->irq);
+ regulator_bulk_disable(ARRAY_SIZE(sdata->regulators),
+ sdata->regulators);
+}
+
+static int stmfts_enable_key(struct stmfts_data *sdata)
+{
+ int err;
+
+ sdata->input_key = devm_input_allocate_device(&sdata->client->dev);
+ if (!sdata->input_key)
+ return -ENOMEM;
+
+ sdata->input_key->name = "stmfts_key";
+ sdata->input_key->id.bustype = BUS_I2C;
+ sdata->input_key->open = stmfts_input_key_open;
+ sdata->input_key->close = stmfts_input_key_close;
+
+ input_set_capability(sdata->input_key, EV_KEY, KEY_MENU);
+ input_set_capability(sdata->input_key, EV_KEY, KEY_BACK);
+
+ input_set_drvdata(sdata->input_key, sdata);
+ err = input_register_device(sdata->input_key);
+ if (err)
+ return err;
+
+ /* get the regulator for powering the leds on */
+ sdata->ledvdd = devm_regulator_get(&sdata->client->dev, "ledvdd");
+ if (IS_ERR(sdata->ledvdd))
+ /* there is no LED connected to the touch key */
+ sdata->ledvdd = NULL;
+
+ sdata->led_cdev.name = STMFTS_DEV_NAME;
+ sdata->led_cdev.max_brightness = LED_ON;
+ sdata->led_cdev.brightness = LED_OFF;
+ sdata->led_cdev.brightness_set = stmfts_brightness_set;
+ sdata->led_cdev.brightness_get = stmfts_brightness_get;
+
+ err = devm_led_classdev_register(&sdata->client->dev, &sdata->led_cdev);
+ if (err) {
+ dev_warn(&sdata->client->dev, "unable to register led, led might not work\n");
+ sdata->ledvdd = NULL;
+
+ /* I don't want to prevent using the touch key
+ * only because the LEDs don't get registered
+ */
+ err = 0;
+ }
+
+ return err;
+}
+
+static int stmfts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int err;
+ struct stmfts_data *sdata;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK))
+ return -ENODEV;
+
+ sdata = devm_kzalloc(&client->dev, sizeof(*sdata), GFP_KERNEL);
+ if (!sdata)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, sdata);
+
+ mutex_init(&sdata->mutex);
+
+ sdata->regulators[STMFTS_REGULATOR_VDD].supply = "vdd";
+ sdata->regulators[STMFTS_REGULATOR_AVDD].supply = "avdd";
+ err = devm_regulator_bulk_get(&client->dev,
+ ARRAY_SIZE(sdata->regulators), sdata->regulators);
+ if (err)
+ return err;
+
+ err = devm_add_action_or_reset(&client->dev, stmfts_power_off, sdata);
+ if (err)
+ return err;
+
+ sdata->client = client;
+
+ err = stmfts_parse_dt(sdata);
+ if (err)
+ return err;
+
+ init_waitqueue_head(&sdata->wq);
+
+ err = sysfs_create_group(&sdata->client->dev.kobj,
+ &stmfts_attribute_group);
+ if (err)
+ return err;
+
+ err = devm_request_threaded_irq(&client->dev, client->irq,
+ NULL, stmfts_irq_handler,
+ IRQF_ONESHOT | IRQF_TRIGGER_LOW,
+ "stmfts_irq", sdata);
+ if (err)
+ return err;
+
+ disable_irq(sdata->client->irq);
+
+ dev_info(&client->dev, "initializing ST-Microelectronics FTS...\n");
+ err = stmfts_power_on(sdata);
+ if (err)
+ return err;
+
+ sdata->input_touch = devm_input_allocate_device(&client->dev);
+ if (!sdata->input_touch)
+ return -ENOMEM;
+
+ sdata->input_touch->name = STMFTS_DEV_NAME;
+ sdata->input_touch->id.bustype = BUS_I2C;
+ sdata->input_touch->open = stmfts_input_touch_open;
+ sdata->input_touch->close = stmfts_input_touch_close;
+
+ input_set_capability(sdata->input_touch, EV_ABS, ABS_MT_POSITION_Y);
+ input_set_capability(sdata->input_touch, EV_ABS, ABS_MT_POSITION_X);
+ input_set_capability(sdata->input_touch, EV_ABS, ABS_MT_TOUCH_MAJOR);
+ input_set_capability(sdata->input_touch, EV_ABS, ABS_MT_TOUCH_MINOR);
+ input_set_capability(sdata->input_touch, EV_ABS, ABS_MT_ORIENTATION);
+ input_set_capability(sdata->input_touch, EV_ABS, ABS_MT_PRESSURE);
+ input_set_capability(sdata->input_touch, EV_ABS, ABS_MT_POSITION_X);
+
+ input_set_abs_params(sdata->input_touch,
+ ABS_MT_POSITION_X, 0, sdata->x_size, 0, 0);
+ input_set_abs_params(sdata->input_touch,
+ ABS_MT_POSITION_Y, 0, sdata->y_size, 0, 0);
+ input_set_abs_params(sdata->input_touch,
+ ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+ input_set_abs_params(sdata->input_touch,
+ ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
+ input_set_abs_params(sdata->input_touch,
+ ABS_MT_ORIENTATION, 0, 255, 0, 0);
+ input_set_abs_params(sdata->input_touch,
+ ABS_MT_PRESSURE, 0, 255, 0, 0);
+ input_mt_init_slots(sdata->input_touch,
+ STMFTS_MAX_FINGERS, INPUT_MT_DIRECT);
+
+ /* for hover features */
+ input_set_capability(sdata->input_touch, EV_ABS, ABS_X);
+ input_set_capability(sdata->input_touch, EV_ABS, ABS_Y);
+ input_set_capability(sdata->input_touch, EV_ABS, ABS_Z);
+ input_set_abs_params(sdata->input_touch, ABS_X, 0, sdata->x_size, 0, 0);
+ input_set_abs_params(sdata->input_touch, ABS_Y, 0, sdata->y_size, 0, 0);
+ input_set_abs_params(sdata->input_touch, ABS_Z, 0, 255, 0, 0);
+
+ input_set_drvdata(sdata->input_touch, sdata);
+ err = input_register_device(sdata->input_touch);
+ if (err)
+ return err;
+
+ if (sdata->use_key) {
+ err = stmfts_enable_key(sdata);
+ if (err)
+ dev_warn(&client->dev, "failed to enable touchkey\n");
+ }
+
+ return 0;
+}
+
+static int stmfts_remove(struct i2c_client *client)
+{
+ struct stmfts_data *sdata = i2c_get_clientdata(client);
+
+ sysfs_remove_group(&sdata->client->dev.kobj, &stmfts_attribute_group);
+
+ return 0;
+}
+
+static int __maybe_unused stmfts_suspend(struct device *dev)
+{
+ struct stmfts_data *sdata = dev_get_drvdata(dev);
+
+ stmfts_power_off(sdata);
+
+ return 0;
+}
+
+static int __maybe_unused stmfts_resume(struct device *dev)
+{
+ struct stmfts_data *sdata = dev_get_drvdata(dev);
+
+ return stmfts_power_on(sdata);
+}
+
+static SIMPLE_DEV_PM_OPS(stmfts_pm_ops, stmfts_suspend, stmfts_resume);
+
+static const struct of_device_id stmfts_of_match[] = {
+ { .compatible = "st,stmfts", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, stmfts_of_match);
+
+static const struct i2c_device_id stmfts_id[] = {
+ { "stmfts", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, stmfts_id);
+
+static struct i2c_driver stmfts_driver = {
+ .driver = {
+ .name = STMFTS_DEV_NAME,
+ .of_match_table = of_match_ptr(stmfts_of_match),
+ .pm = &stmfts_pm_ops,
+ },
+ .probe = stmfts_probe,
+ .remove = stmfts_remove,
+ .id_table = stmfts_id,
+};
+
+module_i2c_driver(stmfts_driver);
+
+MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>");
+MODULE_DESCRIPTION("STMicroelectronics FTS Touch Screen");
+MODULE_LICENSE("GPL v2");
--
2.11.0
^ permalink raw reply related
* [PATCH 3/3] arm64: dts: exynos: Add stmfts touchscreen node for TM2 and TM2E
From: Andi Shyti @ 2017-01-17 13:54 UTC (permalink / raw)
To: Dmitry Torokhov, Krzysztof Kozlowski, Rob Herring, Chanwoo Choi,
Javier Martinez Canillas
Cc: linux-input, devicetree, linux-kernel, linux-samsung-soc,
Andi Shyti, Andi Shyti
In-Reply-To: <20170117135441.31450-1-andi.shyti@samsung.com>
TM2 and TM2E devices are provided with a ST-Microelectronics
Finger Tip S device with small differences:
- screen size
- TM2E uses the stmfts also as a touchkey for "back" and "menu"
Signed-off-by: Andi Shyti <andi.shyti@samsung.com>
---
arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi | 13 +++++++++++++
arch/arm64/boot/dts/exynos/exynos5433-tm2.dts | 5 +++++
arch/arm64/boot/dts/exynos/exynos5433-tm2e.dts | 7 +++++++
3 files changed, 25 insertions(+)
diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi b/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi
index a5c866901e93..689d5c124a49 100644
--- a/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi
+++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi
@@ -745,6 +745,19 @@
};
};
+&hsi2c_5 {
+ status = "okay";
+
+ touchscreen: stmfts@49 {
+ compatible = "st,stmfts";
+ reg = <0x49>;
+ interrupt-parent = <&gpa1>;
+ interrupts = <1 IRQ_TYPE_NONE>;
+ avdd-supply = <&ldo30_reg>;
+ vdd-supply = <&ldo31_reg>;
+ };
+};
+
&hsi2c_7 {
status = "okay";
diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
index 2449266b268f..d0311d34c6bd 100644
--- a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
+++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts
@@ -29,3 +29,8 @@
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3000000>;
};
+
+&touchscreen {
+ touchscreen-size-x = <1439>;
+ touchscreen-size-y = <2559>;
+};
diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2e.dts b/arch/arm64/boot/dts/exynos/exynos5433-tm2e.dts
index 2fbf3a860316..388880dcb5ae 100644
--- a/arch/arm64/boot/dts/exynos/exynos5433-tm2e.dts
+++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2e.dts
@@ -29,3 +29,10 @@
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
+
+&touchscreen {
+ touchscreen-size-x = <1599>;
+ touchscreen-size-y = <2559>;
+ touch-key-connected;
+ ledvdd-supply = <&ldo33_reg>;
+};
--
2.11.0
^ permalink raw reply related
* Re: [PATCH v3] mtd: spi-nor: add dt support for Everspin MRAMs
From: Cyrille Pitchen @ 2017-01-17 13:57 UTC (permalink / raw)
To: Rafał Miłecki, Uwe Kleine-König
Cc: Masahiko Iwamoto, Jagan Teki, Marek Vasut,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
Sascha Hauer, Geert Uytterhoeven, Mark Rutland,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CACna6rwSZH8697px46KitcsFTROhqAQa2Cm2-RCTH=L_5nQFYg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Le 17/01/2017 à 14:16, Rafał Miłecki a écrit :
> On 17 January 2017 at 12:03, Uwe Kleine-König
> <u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org> wrote:
>> The MR25 family doesn't support JEDEC, so they need explicit mentioning
>> in the list of supported spi IDs. This makes it possible to add these
>> using for example:
>>
>> compatible = "everspin,mr25h40";
>
> (...)
>
>> diff --git a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt
>> index 2c91c03e7eb0..3e920ec5c4d3 100644
>> --- a/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt
>> +++ b/Documentation/devicetree/bindings/mtd/jedec,spi-nor.txt
>> @@ -14,6 +14,8 @@ Required properties:
>> at25df641
>> at26df081a
>> mr25h256
>> + mr25h10
>> + mr25h40
>> mx25l4005a
>> mx25l1606e
>> mx25l6405d
>
> Uh, this is getting a never-ending-story...
> If these chipsets don't support JEDEC, should we keep them in jedec,spi-nor.txt?
>
Maybe not but I think the new compatible strings should be documented
somewhere. Currently jedec,spi-nor.txt already documents all the
"m25p*-nonjedec" memories. So maybe just renaming the jedec,spi-nor.txt
file into spi-nor.txt or mtd,spi-nor.txt could be a solution. Otherwise, we
can let it as is. I have no idea of what would be the best solution.
To be honest, I don't always fully understand the DT policy/philosophy and
its requirements. I just thought when a new property or a new value is
introduced it has to be documented.
Generally speaking, when DT is involved in some series of patches, it often
generates many discussions about the proper way to do thinks and about
choosing the best between many technically functional solutions.
If you think jedec,spi-nor.txt is not suited to document the new value for
the compatible string, why not, I perfectly understand your point.
I don't mind choosing another way. I just want to be sure that, if not all,
most of people agree on that solution and if possible, it is compliant with
DT policy so everybody is happy and works together.
That's why I involve DT people, even if it's a small detail, so they can
advise us.
Anyway, at some point we have to take a decision to carry on thinks.
So actually, I would like to avoid a never-ending story :)
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v4 4/4] arm64: dts: juno: add missing CoreSight STM component
From: Sudeep Holla @ 2017-01-17 14:01 UTC (permalink / raw)
To: Suzuki K Poulose, linux-arm-kernel, Mike Leach, Mike Leach
Cc: devicetree, Lorenzo Pieralisi, Mathieu Poirier, coresight,
Liviu Dudau, Sudeep Holla, Olof Johansson
In-Reply-To: <5c742b98-0707-67fd-d8a1-467f34d99cdb@arm.com>
On 17/01/17 13:39, Suzuki K Poulose wrote:
> On 17/01/17 12:15, Sudeep Holla wrote:
>> From: Mike Leach <mike.leach@linaro.org>
>>
>> This patch adds the missing CoreSight STM component definition to the
>> device tree of all the juno variants(r0,r1,r2)
>>
>> STM component is connected to different funnels depending on Juno
>> platform variant.
>>
>> Reviewed-and-Tested-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>> Signed-off-by: Mike Leach <mike.leach@linaro.org>
>> [sudeep.holla@arm.com: minor changelog update and reorganising the STM
>> node back into juno-base.dtsi to avoid duplication]
>> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
>> ---
>> arch/arm64/boot/dts/arm/juno-base.dtsi | 15 +++++++++++++++
>> arch/arm64/boot/dts/arm/juno-r1.dts | 4 ++++
>> arch/arm64/boot/dts/arm/juno-r2.dts | 4 ++++
>> arch/arm64/boot/dts/arm/juno.dts | 16 ++++++++++++++++
>> 4 files changed, 39 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi
>> b/arch/arm64/boot/dts/arm/juno-base.dtsi
>> index faedf357db3b..58c1773c3aa4 100644
>> --- a/arch/arm64/boot/dts/arm/juno-base.dtsi
>> +++ b/arch/arm64/boot/dts/arm/juno-base.dtsi
>> @@ -185,6 +185,21 @@
>> };
>> };
>>
>> + stm@20100000 {
>> + compatible = "arm,coresight-stm", "arm,primecell";
>> + reg = <0 0x20100000 0 0x1000>,
>> + <0 0x28000000 0 0x180000>;
>
> The size of the stimulus base is 16MB (as per TRM), implies => 0x1000000.
>
Fixed locally.
Mike,
Can you confirm ? I know TRM had some issues with size of other
coresight components.
> with that fixed :
>
> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
>
Thanks.
--
Regards,
Sudeep
^ permalink raw reply
* [PATCH v2 00/10] Add sun8i A33 audio driver
From: Mylène Josserand @ 2017-01-17 14:02 UTC (permalink / raw)
To: lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A,
perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, wens-jdAy2FN1RRM,
mturquette-rdvid1DuHRBWk0Htik3J/w, sboyd-sgV2jX0FEOL9JmXXK+q4OQ,
mark.rutland-5wv7dgnIgG8, robh+dt-DgEjT+Ai2ygdnm+yROfE0A
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
mylene.josserand-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8
Hello everyone,
This a V2 of my Allwinner A33 (sun8i) audio codec driver.
Tested on linux-next-20170105 tag with one remaining patch from Chen-Yu's
series:
http://lkml.iu.edu/hypermail/linux/kernel/1611.3/01256.html
Patch to apply before this serie:
https://patchwork.kernel.org/patch/9423999/
Changes since V1:
- Remove the analog codec driver as a better version has been
committed by Chen-Yu Tsai and is already merged.
- Remove the audio-card as simple-card can be used
- The DMA maxburst is set to 8 in the sun4i-i2s instead of
adding the maxburst of 4 in Sun6i dma engine.
- Create a new compatible for sun4i-i2s to handle the reset
line.
- Fix various problems in sun8i-codec driver according to V1's
reviews
- Add the pm_runtime hooks in sun8i-codec driver to prepare/
unprepare clocks.
- Update the DTS according to Chen-Yu's analog codec driver.
- Rename sun8i-codec's clocks to "bus" and "mod"
- The first "delay" issue from V1 is fixed by using a delay
when enabling the headphone amplifier to let the amplifier
being up.
Patch 1 increases the DMA maxburst value of sun4i-i2s to 8.
See Chen-Yu's commit log for more details:
https://patchwork.kernel.org/patch/9411805/
Patch 2 adds the CLK_SET_RATE_PARENT flag to ccu sun8i-a33 clocks.
Patches 3 and 4 add a new compatible "allwinner,sun6i-a31-i2s"
to handle the reset line for sun4i-i2s driver. It uses a quirk to
use a version with or without reset lines.
Patch 5 adds the sun8i codec driver which represents the digital part
of the A33 codec. It supports only playback features.
Path 6 fixes the previous issue of a "first time delay" in V1 (see cover
letter). Do not hesitate if you have comments on this patch.
Patches 7 adds the dt-bindings documentation for new audio driver
added in this serie (sun8i-codec).
Patch 8 adds the cpu DAI, codec and audio nodes to sun8i-a33 device tree.
Patches 9 and 10 enable the audio on Parrot and Sinlinx's boards.
The DAI for this A33 codec is the same than for A20: "sun4i-i2s".
Currently, all the drivers handle only the playback feature.
The other ones (such as capture) and all other interfaces except
headphone are not supported. I will send a patch to handle the
capture with microphones in next few weeks.
Examples of amixer commands:
amixer set 'Headphone' 75%
amixer set 'Headphone' on
amixer set 'DAC' on
amixer set 'Right DAC Mixer RSlot 0' on
amixer set 'Left DAC Mixer LSlot 0' on
It was tested on Parrot and Sinlinx boards.
Let me know if you have any comments on this serie.
Thank you in advance,
Best regards,
Mylène Josserand (10):
ASoC: sun4i-i2s: Increase DMA max burst to 8
clk: ccu-sun8i-a33: Add CLK_SET_RATE_PARENT to ac-dig
dt-bindings: sound: Add new reset compatible for sun4i-i2s
ASoC: sun4i-i2s: Add quirks to handle new compatible for reset
ASoC: Add sun8i digital audio codec
ASoC: sun8i-codec-analog: Add amplifier event to fix first delay
dt-bindings: sound: Add sun8i audio documentation
ARM: dts: sun8i: Add audio codec, dai and card for A33
ARM: dts: sun8i: parrot: Enable audio nodes
ARM: dts: sun8i: sinlinx: Enable audio nodes
.../devicetree/bindings/sound/sun4i-i2s.txt | 23 +
.../devicetree/bindings/sound/sun8i-codec.txt | 76 +++
arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts | 8 +
arch/arm/boot/dts/sun8i-a33.dtsi | 47 ++
arch/arm/boot/dts/sun8i-r16-parrot.dts | 8 +
drivers/clk/sunxi-ng/ccu-sun8i-a33.c | 2 +-
sound/soc/sunxi/Kconfig | 11 +
sound/soc/sunxi/Makefile | 1 +
sound/soc/sunxi/sun4i-i2s.c | 61 ++-
sound/soc/sunxi/sun8i-codec-analog.c | 30 +-
sound/soc/sunxi/sun8i-codec.c | 531 +++++++++++++++++++++
11 files changed, 791 insertions(+), 7 deletions(-)
create mode 100644 Documentation/devicetree/bindings/sound/sun8i-codec.txt
create mode 100644 sound/soc/sunxi/sun8i-codec.c
--
2.11.0
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v2 01/10] ASoC: sun4i-i2s: Increase DMA max burst to 8
From: Mylène Josserand @ 2017-01-17 14:02 UTC (permalink / raw)
To: lgirdwood, broonie, perex, tiwai, maxime.ripard, wens, mturquette,
sboyd, mark.rutland, robh+dt
Cc: thomas.petazzoni, devicetree, alsa-devel, linux-kernel,
linux-sunxi, alexandre.belloni, mylene.josserand, linux-clk,
linux-arm-kernel
In-Reply-To: <20170117140230.23142-1-mylene.josserand@free-electrons.com>
As done previously for sun4i-codec, the DMA maxburst of 4
is not supported by every SoCs so the DMA controller engine
returns "unsupported value".
As a maxburst of 8 is supported by all variants, this patch
increases it to 8.
For more details, see commit from Chen-Yu Tsai:
commit 730e2dd0cbc7 ("ASoC: sun4i-codec: Increase DMA max burst to 8")
Signed-off-by: Mylène Josserand <mylene.josserand@free-electrons.com>
---
sound/soc/sunxi/sun4i-i2s.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index f24d19526603..4237323ef594 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -694,10 +694,10 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
}
i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG;
- i2s->playback_dma_data.maxburst = 4;
+ i2s->playback_dma_data.maxburst = 8;
i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG;
- i2s->capture_dma_data.maxburst = 4;
+ i2s->capture_dma_data.maxburst = 8;
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
--
2.11.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 02/10] clk: ccu-sun8i-a33: Add CLK_SET_RATE_PARENT to ac-dig
From: Mylène Josserand @ 2017-01-17 14:02 UTC (permalink / raw)
To: lgirdwood, broonie, perex, tiwai, maxime.ripard, wens, mturquette,
sboyd, mark.rutland, robh+dt
Cc: thomas.petazzoni, devicetree, alsa-devel, linux-kernel,
linux-sunxi, alexandre.belloni, mylene.josserand, linux-clk,
linux-arm-kernel
In-Reply-To: <20170117140230.23142-1-mylene.josserand@free-electrons.com>
The audio DAI needs to set the clock rates of the ac-dig clock.
To make it possible, the parent PLL audio clock rates should
also be changed. This is possible via "CLK_SET_RATE_PARENT" flag.
Signed-off-by: Mylène Josserand <mylene.josserand@free-electrons.com>
---
drivers/clk/sunxi-ng/ccu-sun8i-a33.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
index 9bd1f78a0547..3cd4190ccd59 100644
--- a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
+++ b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c
@@ -440,7 +440,7 @@ static SUNXI_CCU_M_WITH_GATE(ve_clk, "ve", "pll-ve",
0x13c, 16, 3, BIT(31), CLK_SET_RATE_PARENT);
static SUNXI_CCU_GATE(ac_dig_clk, "ac-dig", "pll-audio",
- 0x140, BIT(31), 0);
+ 0x140, BIT(31), CLK_SET_RATE_PARENT);
static SUNXI_CCU_GATE(ac_dig_4x_clk, "ac-dig-4x", "pll-audio-4x",
0x140, BIT(30), 0);
static SUNXI_CCU_GATE(avs_clk, "avs", "osc24M",
--
2.11.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 03/10] dt-bindings: sound: Add new reset compatible for sun4i-i2s
From: Mylène Josserand @ 2017-01-17 14:02 UTC (permalink / raw)
To: lgirdwood, broonie, perex, tiwai, maxime.ripard, wens, mturquette,
sboyd, mark.rutland, robh+dt
Cc: linux-kernel, linux-arm-kernel, linux-clk, alsa-devel, devicetree,
linux-sunxi, thomas.petazzoni, mylene.josserand,
alexandre.belloni
In-Reply-To: <20170117140230.23142-1-mylene.josserand@free-electrons.com>
Add a new compatible for sun4i-i2s driver to handle some
SoCs that have a reset line that must be asserted/deasserted.
This new compatible, "allwinner,sun6i-a31-i2s", requires two
properties:
- resets: phandle to the reset line
- reset-names: the name of the reset line ("rst").
Except these differences, the compatible is identical to previous one
which will not handle a reset line.
Signed-off-by: Mylène Josserand <mylene.josserand@free-electrons.com>
---
.../devicetree/bindings/sound/sun4i-i2s.txt | 23 ++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
index 7a2c0945fd22..f673206e309b 100644
--- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt
@@ -7,6 +7,7 @@ Required properties:
- compatible: should be one of the following:
- "allwinner,sun4i-a10-i2s"
+ - "allwinner,sun6i-a31-i2s" for controller with reset lines
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: should contain the I2S interrupt.
@@ -19,7 +20,13 @@ Required properties:
- "mod" : module clock for the I2S controller
- #sound-dai-cells : Must be equal to 0
+Required properties for the following compatibles:
+ - "allwinner,sun6i-a31-i2s"
+- resets: phandle to the reset line for this codec
+- reset-names: Contains the reset signal name "rst"
+
Example:
+For "allwinner,sun4i-a10-i2s":
i2s0: i2s@01c22400 {
#sound-dai-cells = <0>;
@@ -32,3 +39,19 @@ i2s0: i2s@01c22400 {
<&dma SUN4I_DMA_NORMAL 3>;
dma-names = "rx", "tx";
};
+
+For "allwinner,sun6i-a31-i2s":
+
+dai: dai@01c22c00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun6i-a31-i2s";
+ reg = <0x01c22c00 0x200>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>;
+ clock-names = "apb", "mod";
+ resets = <&ccu RST_BUS_CODEC>;
+ reset-names = "rst";
+ dmas = <&dma 15>, /* AUDIO_CODEC port */
+ <&dma 15>; /* AUDIO_CODEC port */
+ dma-names = "rx", "tx";
+};
--
2.11.0
^ permalink raw reply related
* [PATCH v2 04/10] ASoC: sun4i-i2s: Add quirks to handle new compatible for reset
From: Mylène Josserand @ 2017-01-17 14:02 UTC (permalink / raw)
To: lgirdwood, broonie, perex, tiwai, maxime.ripard, wens, mturquette,
sboyd, mark.rutland, robh+dt
Cc: linux-kernel, linux-arm-kernel, linux-clk, alsa-devel, devicetree,
linux-sunxi, thomas.petazzoni, mylene.josserand,
alexandre.belloni
In-Reply-To: <20170117140230.23142-1-mylene.josserand@free-electrons.com>
Some SoCs have a reset line that must be asserted/deasserted.
This patch adds a quirk to handle the new compatible
"allwinner,sun6i-a31-i2s" which will deassert the reset
line on probe function and assert it on remove's one.
This new compatible is useful in case of A33 codec driver, for example.
Signed-off-by: Mylène Josserand <mylene.josserand@free-electrons.com>
---
sound/soc/sunxi/sun4i-i2s.c | 57 +++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c
index 4237323ef594..3635bbc72cbc 100644
--- a/sound/soc/sunxi/sun4i-i2s.c
+++ b/sound/soc/sunxi/sun4i-i2s.c
@@ -14,9 +14,11 @@
#include <linux/clk.h>
#include <linux/dmaengine.h>
#include <linux/module.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
+#include <linux/reset.h>
#include <sound/dmaengine_pcm.h>
#include <sound/pcm_params.h>
@@ -92,6 +94,7 @@ struct sun4i_i2s {
struct clk *bus_clk;
struct clk *mod_clk;
struct regmap *regmap;
+ struct reset_control *rst;
unsigned int mclk_freq;
@@ -651,9 +654,22 @@ static int sun4i_i2s_runtime_suspend(struct device *dev)
return 0;
}
+struct sun4i_i2s_quirks {
+ bool has_reset;
+};
+
+static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = {
+ .has_reset = false,
+};
+
+static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = {
+ .has_reset = true,
+};
+
static int sun4i_i2s_probe(struct platform_device *pdev)
{
struct sun4i_i2s *i2s;
+ const struct sun4i_i2s_quirks *quirks;
struct resource *res;
void __iomem *regs;
int irq, ret;
@@ -674,6 +690,12 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
return irq;
}
+ quirks = of_device_get_match_data(&pdev->dev);
+ if (!quirks) {
+ dev_err(&pdev->dev, "Failed to determine the quirks to use\n");
+ return -ENODEV;
+ }
+
i2s->bus_clk = devm_clk_get(&pdev->dev, "apb");
if (IS_ERR(i2s->bus_clk)) {
dev_err(&pdev->dev, "Can't get our bus clock\n");
@@ -692,7 +714,24 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Can't get our mod clock\n");
return PTR_ERR(i2s->mod_clk);
}
-
+
+ if (quirks->has_reset) {
+ i2s->rst = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(i2s->rst)) {
+ dev_err(&pdev->dev, "Failed to get reset control\n");
+ return PTR_ERR(i2s->rst);
+ }
+ }
+
+ if (!IS_ERR(i2s->rst)) {
+ ret = reset_control_deassert(i2s->rst);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to deassert the reset control\n");
+ return -EINVAL;
+ }
+ }
+
i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG;
i2s->playback_dma_data.maxburst = 8;
@@ -727,23 +766,37 @@ static int sun4i_i2s_probe(struct platform_device *pdev)
sun4i_i2s_runtime_suspend(&pdev->dev);
err_pm_disable:
pm_runtime_disable(&pdev->dev);
+ if (!IS_ERR(i2s->rst))
+ reset_control_assert(i2s->rst);
return ret;
}
static int sun4i_i2s_remove(struct platform_device *pdev)
{
+ struct sun4i_i2s *i2s = dev_get_drvdata(&pdev->dev);
+
snd_dmaengine_pcm_unregister(&pdev->dev);
pm_runtime_disable(&pdev->dev);
if (!pm_runtime_status_suspended(&pdev->dev))
sun4i_i2s_runtime_suspend(&pdev->dev);
+ if (!IS_ERR(i2s->rst))
+ reset_control_assert(i2s->rst);
+
return 0;
}
static const struct of_device_id sun4i_i2s_match[] = {
- { .compatible = "allwinner,sun4i-a10-i2s", },
+ {
+ .compatible = "allwinner,sun4i-a10-i2s",
+ .data = &sun4i_a10_i2s_quirks,
+ },
+ {
+ .compatible = "allwinner,sun6i-a31-i2s",
+ .data = &sun6i_a31_i2s_quirks,
+ },
{}
};
MODULE_DEVICE_TABLE(of, sun4i_i2s_match);
--
2.11.0
^ permalink raw reply related
* [PATCH v2 05/10] ASoC: Add sun8i digital audio codec
From: Mylène Josserand @ 2017-01-17 14:02 UTC (permalink / raw)
To: lgirdwood, broonie, perex, tiwai, maxime.ripard, wens, mturquette,
sboyd, mark.rutland, robh+dt
Cc: thomas.petazzoni, devicetree, alsa-devel, linux-kernel,
linux-sunxi, alexandre.belloni, mylene.josserand, linux-clk,
linux-arm-kernel
In-Reply-To: <20170117140230.23142-1-mylene.josserand@free-electrons.com>
Add the sun8i audio codec which handles the digital register of
A33 codec.
The driver handles only the basic playback from the DAC to headphones.
All other features (microphone, capture, etc) will be added later.
Signed-off-by: Mylène Josserand <mylene.josserand@free-electrons.com>
---
sound/soc/sunxi/Kconfig | 11 +
sound/soc/sunxi/Makefile | 1 +
sound/soc/sunxi/sun8i-codec.c | 531 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 543 insertions(+)
create mode 100644 sound/soc/sunxi/sun8i-codec.c
diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig
index 6c344e16aca4..13a8267f17c7 100644
--- a/sound/soc/sunxi/Kconfig
+++ b/sound/soc/sunxi/Kconfig
@@ -9,6 +9,17 @@ config SND_SUN4I_CODEC
Select Y or M to add support for the Codec embedded in the Allwinner
A10 and affiliated SoCs.
+config SND_SUN8I_CODEC
+ tristate "Allwinner SUN8I audio codec"
+ depends on OF
+ depends on MACH_SUN8I || COMPILE_TEST
+ select REGMAP_MMIO
+ help
+ This option enables the digital part of the internal audio codec for
+ Allwinner sun8i SoC (and particularly A33).
+
+ Say Y or M if you want to add sun8i digital audio codec support.
+
config SND_SUN8I_CODEC_ANALOG
tristate "Allwinner sun8i Codec Analog Controls Support"
depends on MACH_SUN8I || COMPILE_TEST
diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile
index 241c0df9ca0c..1f1af6271731 100644
--- a/sound/soc/sunxi/Makefile
+++ b/sound/soc/sunxi/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o
obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o
obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o
obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o
+obj-$(CONFIG_SND_SUN8I_CODEC) += sun8i-codec.o
diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
new file mode 100644
index 000000000000..66378c9e7794
--- /dev/null
+++ b/sound/soc/sunxi/sun8i-codec.c
@@ -0,0 +1,531 @@
+/*
+ * This driver supports the digital controls for the internal codec
+ * found in Allwinner's A33 SoCs.
+ *
+ * (C) Copyright 2010-2016
+ * Reuuimlla Technology Co., Ltd. <www.reuuimllatech.com>
+ * huangxin <huangxin@Reuuimllatech.com>
+ * Mylène Josserand <mylene.josserand@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#define SUN8I_SYSCLK_CTL 0x00c
+#define SUN8I_SYSCLK_CTL_AIF1CLK_ENA 11
+#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL 9
+#define SUN8I_SYSCLK_CTL_AIF1CLK_SRC 8
+#define SUN8I_SYSCLK_CTL_SYSCLK_ENA 3
+#define SUN8I_SYSCLK_CTL_SYSCLK_SRC 0
+#define SUN8I_MOD_CLK_ENA 0x010
+#define SUN8I_MOD_CLK_ENA_AIF1 15
+#define SUN8I_MOD_CLK_ENA_DAC 2
+#define SUN8I_MOD_RST_CTL 0x014
+#define SUN8I_MOD_RST_CTL_AIF1 15
+#define SUN8I_MOD_RST_CTL_DAC 2
+#define SUN8I_SYS_SR_CTRL 0x018
+#define SUN8I_SYS_SR_CTRL_AIF1_FS 12
+#define SUN8I_SYS_SR_CTRL_AIF2_FS 8
+#define SUN8I_AIF1CLK_CTRL 0x040
+#define SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD 15
+#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV 14
+#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV 13
+#define SUN8I_AIF1CLK_CTRL_AIF1_BCLK_DIV 9
+#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV 6
+#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16 (1 << 6)
+#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ 4
+#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16 (1 << 4)
+#define SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT 2
+#define SUN8I_AIF1_DACDAT_CTRL 0x048
+#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA 15
+#define SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA 14
+#define SUN8I_DAC_DIG_CTRL 0x120
+#define SUN8I_DAC_DIG_CTRL_ENDA 15
+#define SUN8I_DAC_MXR_SRC 0x130
+#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L 15
+#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L 14
+#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL 13
+#define SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL 12
+#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R 11
+#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R 10
+#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR 9
+#define SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR 8
+
+#define SUN8I_SYS_SR_CTRL_AIF1_FS_MASK GENMASK(15, 12)
+#define SUN8I_SYS_SR_CTRL_AIF2_FS_MASK GENMASK(11, 8)
+#define SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK GENMASK(5, 4)
+#define SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK GENMASK(8, 6)
+
+struct sun8i_codec {
+ struct device *dev;
+ struct regmap *regmap;
+ struct clk *clk_module;
+ struct clk *clk_bus;
+};
+
+static int sun8i_codec_runtime_resume(struct device *dev)
+{
+ struct sun8i_codec *scodec = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(scodec->clk_module);
+ if (ret) {
+ dev_err(dev, "Failed to enable the module clock\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(scodec->clk_bus);
+ if (ret) {
+ dev_err(dev, "Failed to enable the bus clock\n");
+ goto err_disable_modclk;
+ }
+
+ regcache_cache_only(scodec->regmap, false);
+
+ ret = regcache_sync(scodec->regmap);
+ if (ret) {
+ dev_err(dev, "Failed to sync regmap cache\n");
+ goto err_disable_clk;
+ }
+
+ return 0;
+
+err_disable_clk:
+ clk_disable_unprepare(scodec->clk_bus);
+
+err_disable_modclk:
+ clk_disable_unprepare(scodec->clk_module);
+
+ return ret;
+}
+
+static int sun8i_codec_runtime_suspend(struct device *dev)
+{
+ struct sun8i_codec *scodec = dev_get_drvdata(dev);
+
+ regcache_cache_only(scodec->regmap, true);
+ regcache_mark_dirty(scodec->regmap);
+
+ clk_disable_unprepare(scodec->clk_module);
+ clk_disable_unprepare(scodec->clk_bus);
+
+ return 0;
+}
+
+static int sun8i_codec_get_hw_rate(struct snd_pcm_hw_params *params)
+{
+ unsigned int rate = params_rate(params);
+
+ switch (rate) {
+ case 8000:
+ case 7350:
+ return 0x0;
+ case 11025:
+ return 0x1;
+ case 12000:
+ return 0x2;
+ case 16000:
+ return 0x3;
+ case 22050:
+ return 0x4;
+ case 24000:
+ return 0x5;
+ case 32000:
+ return 0x6;
+ case 44100:
+ return 0x7;
+ case 48000:
+ return 0x8;
+ case 96000:
+ return 0x9;
+ case 192000:
+ return 0xa;
+ default:
+ return -EINVAL;
+ }
+}
+
+static u32 sun8i_codec_get_mod_freq(struct snd_pcm_hw_params *params)
+{
+ unsigned int rate = params_rate(params);
+
+ switch (rate) {
+ case 176400:
+ case 88200:
+ case 44100:
+ case 22050:
+ case 11025:
+ return 22579200;
+
+ case 192000:
+ case 128000:
+ case 96000:
+ case 64000:
+ case 48000:
+ case 32000:
+ case 24000:
+ case 16000:
+ case 12000:
+ case 8000:
+ return 24576000;
+
+ default:
+ return 0;
+ }
+}
+
+static int sun8i_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct sun8i_codec *scodec = snd_soc_codec_get_drvdata(dai->codec);
+ u32 value;
+
+ /* clock masters */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS: /* DAI Slave */
+ value = 0x0; /* Codec Master */
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM: /* DAI Master */
+ value = 0x1; /* Codec Slave */
+ break;
+ default:
+ return -EINVAL;
+ }
+ regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
+ BIT(SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD),
+ value << SUN8I_AIF1CLK_CTRL_AIF1_MSTR_MOD);
+
+ /* clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF: /* Normal */
+ value = 0x0;
+ break;
+ case SND_SOC_DAIFMT_IB_IF: /* Inversion */
+ value = 0x1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
+ BIT(SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV),
+ value << SUN8I_AIF1CLK_CTRL_AIF1_BCLK_INV);
+ regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
+ BIT(SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV),
+ value << SUN8I_AIF1CLK_CTRL_AIF1_LRCK_INV);
+
+ /* DAI format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ value = 0x0;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ value = 0x1;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ value = 0x2;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ case SND_SOC_DAIFMT_DSP_B:
+ value = 0x3;
+ break;
+ default:
+ return -EINVAL;
+ }
+ regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
+ BIT(SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT),
+ value << SUN8I_AIF1CLK_CTRL_AIF1_DATA_FMT);
+
+ return 0;
+}
+
+static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct sun8i_codec *scodec = snd_soc_codec_get_drvdata(dai->codec);
+ u32 clk_freq;
+ int sample_rate, err;
+
+ /*
+ * The CPU DAI handles only a sample of 16 bits. Configure the
+ * codec to handle this type of sample resolution.
+ */
+ regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
+ SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_MASK,
+ SUN8I_AIF1CLK_CTRL_AIF1_WORD_SIZ_16);
+
+ regmap_update_bits(scodec->regmap, SUN8I_AIF1CLK_CTRL,
+ SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_MASK,
+ SUN8I_AIF1CLK_CTRL_AIF1_LRCK_DIV_16);
+
+ sample_rate = sun8i_codec_get_hw_rate(params);
+ if (sample_rate < 0)
+ return sample_rate;
+
+ regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
+ SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
+ sample_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
+ regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
+ SUN8I_SYS_SR_CTRL_AIF2_FS_MASK,
+ sample_rate << SUN8I_SYS_SR_CTRL_AIF2_FS);
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new sun8i_output_left_mixer_controls[] = {
+ SOC_DAPM_SINGLE("LSlot 0", SUN8I_DAC_MXR_SRC,
+ SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA0L, 1, 0),
+ SOC_DAPM_SINGLE("LSlot 1", SUN8I_DAC_MXR_SRC,
+ SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF1DA1L, 1, 0),
+ SOC_DAPM_SINGLE("DACL", SUN8I_DAC_MXR_SRC,
+ SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_AIF2DACL, 1, 0),
+ SOC_DAPM_SINGLE("ADCL", SUN8I_DAC_MXR_SRC,
+ SUN8I_DAC_MXR_SRC_DACL_MXR_SRC_ADCL, 1, 0),
+};
+
+static const struct snd_kcontrol_new sun8i_output_right_mixer_controls[] = {
+ SOC_DAPM_SINGLE("RSlot 0", SUN8I_DAC_MXR_SRC,
+ SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA0R, 1, 0),
+ SOC_DAPM_SINGLE("RSlot 1", SUN8I_DAC_MXR_SRC,
+ SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF1DA1R, 1, 0),
+ SOC_DAPM_SINGLE("DACR", SUN8I_DAC_MXR_SRC,
+ SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_AIF2DACR, 1, 0),
+ SOC_DAPM_SINGLE("ADCR", SUN8I_DAC_MXR_SRC,
+ SUN8I_DAC_MXR_SRC_DACR_MXR_SRC_ADCR, 1, 0),
+};
+
+static const struct snd_soc_dapm_widget sun8i_codec_dapm_widgets[] = {
+ /* Digital parts of the DACs */
+ SND_SOC_DAPM_SUPPLY("DAC", SUN8I_DAC_DIG_CTRL, SUN8I_DAC_DIG_CTRL_ENDA,
+ 0, NULL, 0),
+
+ /* Analog DAC */
+ SND_SOC_DAPM_DAC("Digital Left DAC", "Playback", SUN8I_AIF1_DACDAT_CTRL,
+ SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0L_ENA, 0),
+ SND_SOC_DAPM_DAC("Digital Right DAC", "Playback", SUN8I_AIF1_DACDAT_CTRL,
+ SUN8I_AIF1_DACDAT_CTRL_AIF1_DA0R_ENA, 0),
+
+ /* DAC Mixers */
+ SND_SOC_DAPM_MIXER("Left DAC Mixer", SND_SOC_NOPM, 0, 0,
+ sun8i_output_left_mixer_controls,
+ ARRAY_SIZE(sun8i_output_left_mixer_controls)),
+ SND_SOC_DAPM_MIXER("Right DAC Mixer", SND_SOC_NOPM, 0, 0,
+ sun8i_output_right_mixer_controls,
+ ARRAY_SIZE(sun8i_output_right_mixer_controls)),
+
+ /* Clocks */
+ SND_SOC_DAPM_SUPPLY("MODCLK AFI1", SUN8I_MOD_CLK_ENA,
+ SUN8I_MOD_CLK_ENA_AIF1, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MODCLK DAC", SUN8I_MOD_CLK_ENA,
+ SUN8I_MOD_CLK_ENA_DAC, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("AIF1", SUN8I_SYSCLK_CTL,
+ SUN8I_SYSCLK_CTL_AIF1CLK_ENA, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("SYSCLK", SUN8I_SYSCLK_CTL,
+ SUN8I_SYSCLK_CTL_SYSCLK_ENA, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("AIF1 PLL", SUN8I_SYSCLK_CTL,
+ SUN8I_SYSCLK_CTL_AIF1CLK_SRC_PLL, 0, NULL, 0),
+ /* Inversion as 0=AIF1, 1=AIF2 */
+ SND_SOC_DAPM_SUPPLY("SYSCLK AIF1", SUN8I_SYSCLK_CTL,
+ SUN8I_SYSCLK_CTL_SYSCLK_SRC, 1, NULL, 0),
+
+ /* Module reset */
+ SND_SOC_DAPM_SUPPLY("RST AIF1", SUN8I_MOD_RST_CTL,
+ SUN8I_MOD_RST_CTL_AIF1, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("RST DAC", SUN8I_MOD_RST_CTL,
+ SUN8I_MOD_RST_CTL_DAC, 0, NULL, 0),
+
+ SND_SOC_DAPM_OUTPUT("HP"),
+};
+
+static const struct snd_soc_dapm_route sun8i_codec_dapm_routes[] = {
+ /* Clock Routes */
+ { "AIF1", NULL, "SYSCLK AIF1" },
+ { "AIF1 PLL", NULL, "AIF1" },
+ { "RST AIF1", NULL, "AIF1 PLL" },
+ { "MODCLK AFI1", NULL, "RST AIF1" },
+ { "DAC", NULL, "MODCLK AFI1" },
+
+ { "RST DAC", NULL, "SYSCLK" },
+ { "MODCLK DAC", NULL, "RST DAC" },
+ { "DAC", NULL, "MODCLK DAC" },
+
+ /* DAC Routes */
+ { "Digital Left DAC", NULL, "DAC" },
+ { "Digital Right DAC", NULL, "DAC" },
+
+ /* DAC Mixer Routes */
+ { "Left DAC Mixer", "LSlot 0", "Digital Left DAC"},
+ { "Right DAC Mixer", "RSlot 0", "Digital Right DAC"},
+
+ /* End of route : HP out */
+ { "HP", NULL, "Left DAC Mixer" },
+ { "HP", NULL, "Right DAC Mixer" },
+};
+
+static struct snd_soc_dai_ops sun8i_codec_dai_ops = {
+ .hw_params = sun8i_codec_hw_params,
+ .set_fmt = sun8i_set_fmt,
+};
+
+static struct snd_soc_dai_driver sun8i_codec_dai = {
+ .name = "sun8i",
+ /* playback capabilities */
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ /* pcm operations */
+ .ops = &sun8i_codec_dai_ops,
+};
+
+static struct snd_soc_codec_driver sun8i_soc_codec = {
+ .component_driver = {
+ .dapm_widgets = sun8i_codec_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_dapm_widgets),
+ .dapm_routes = sun8i_codec_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(sun8i_codec_dapm_routes),
+ },
+};
+
+static const struct regmap_config sun8i_codec_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = SUN8I_DAC_MXR_SRC,
+
+ .cache_type = REGCACHE_FLAT,
+};
+
+static int sun8i_codec_probe(struct platform_device *pdev)
+{
+ struct resource *res_base;
+ struct sun8i_codec *scodec;
+ void __iomem *base;
+ int ret;
+
+ scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL);
+ if (!scodec)
+ return -ENOMEM;
+
+ scodec->dev = &pdev->dev;
+
+ scodec->clk_module = devm_clk_get(&pdev->dev, "mod");
+ if (IS_ERR(scodec->clk_module)) {
+ dev_err(&pdev->dev, "Failed to get the module clock\n");
+ return PTR_ERR(scodec->clk_module);
+ }
+
+ scodec->clk_bus = devm_clk_get(&pdev->dev, "bus");
+ if (IS_ERR(scodec->clk_bus)) {
+ dev_err(&pdev->dev, "Failed to get the bus clock\n");
+ return PTR_ERR(scodec->clk_bus);
+ }
+
+ res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res_base);
+ if (IS_ERR(base)) {
+ dev_err(&pdev->dev, "Failed to map the registers\n");
+ return PTR_ERR(base);
+ }
+
+ scodec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+ &sun8i_codec_regmap_config);
+ if (IS_ERR(scodec->regmap)) {
+ dev_err(&pdev->dev, "Failed to create our regmap\n");
+ return PTR_ERR(scodec->regmap);
+ }
+
+ platform_set_drvdata(pdev, scodec);
+
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = sun8i_codec_runtime_resume(&pdev->dev);
+ if (ret)
+ goto err_pm_disable;
+ }
+
+ ret = snd_soc_register_codec(&pdev->dev, &sun8i_soc_codec,
+ &sun8i_codec_dai, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register codec\n");
+ goto err_suspend;
+ }
+
+ return ret;
+
+err_suspend:
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ sun8i_codec_runtime_suspend(&pdev->dev);
+
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+
+ return ret;
+}
+
+static int sun8i_codec_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct sun8i_codec *scodec = snd_soc_card_get_drvdata(card);
+
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ sun8i_codec_runtime_suspend(&pdev->dev);
+
+ snd_soc_unregister_codec(&pdev->dev);
+ clk_disable_unprepare(scodec->clk_module);
+ clk_disable_unprepare(scodec->clk_bus);
+
+ return 0;
+}
+
+static const struct of_device_id sun8i_codec_of_match[] = {
+ { .compatible = "allwinner,sun8i-a33-codec" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sun8i_codec_of_match);
+
+static const struct dev_pm_ops sun8i_codec_pm_ops = {
+ SET_RUNTIME_PM_OPS(sun8i_codec_runtime_suspend,
+ sun8i_codec_runtime_resume, NULL)
+};
+
+static struct platform_driver sun8i_codec_driver = {
+ .driver = {
+ .name = "sun8i-codec",
+ .owner = THIS_MODULE,
+ .of_match_table = sun8i_codec_of_match,
+ .pm = &sun8i_codec_pm_ops,
+ },
+ .probe = sun8i_codec_probe,
+ .remove = sun8i_codec_remove,
+};
+module_platform_driver(sun8i_codec_driver);
+
+MODULE_DESCRIPTION("Allwinner A33 (sun8i) codec driver");
+MODULE_AUTHOR("Mylène Josserand <mylene.josserand@free-electrons.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:sun8i-codec");
--
2.11.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v2 06/10] ASoC: sun8i-codec-analog: Add amplifier event to fix first delay
From: Mylène Josserand @ 2017-01-17 14:02 UTC (permalink / raw)
To: lgirdwood, broonie, perex, tiwai, maxime.ripard, wens, mturquette,
sboyd, mark.rutland, robh+dt
Cc: linux-kernel, linux-arm-kernel, linux-clk, alsa-devel, devicetree,
linux-sunxi, thomas.petazzoni, mylene.josserand,
alexandre.belloni
In-Reply-To: <20170117140230.23142-1-mylene.josserand@free-electrons.com>
When playing a sound for the first time, a short delay, where the audio
file is not played, can be noticed.
On a second play (right after), the sound is played correctly.
If we wait a short time (~5 sec which corresponds to the aplay
timeout), the delay is back.
This patch fixes it by using an event on headphone amplifier.
It allows to keep the amplifier enable while playing a sound.
A delay of 700ms allows to wait that the amplifier is powered-up
before playing the sound.
Signed-off-by: Mylène Josserand <mylene.josserand@free-electrons.com>
---
sound/soc/sunxi/sun8i-codec-analog.c | 30 ++++++++++++++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c
index af02290ebe49..72331332b72e 100644
--- a/sound/soc/sunxi/sun8i-codec-analog.c
+++ b/sound/soc/sunxi/sun8i-codec-analog.c
@@ -398,11 +398,37 @@ static const struct snd_kcontrol_new sun8i_codec_hp_src[] = {
sun8i_codec_hp_src_enum),
};
+static int sun8i_headphone_amp_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ snd_soc_component_update_bits(component, SUN8I_ADDA_PAEN_HP_CTRL,
+ BIT(SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN),
+ BIT(SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN));
+ /*
+ * Need a delay to have the amplifier up. 700ms seems the best
+ * compromise between the time to let the amplifier up and the
+ * time not to feel this delay while playing a sound.
+ */
+ msleep(700);
+ } else if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ snd_soc_component_update_bits(component, SUN8I_ADDA_PAEN_HP_CTRL,
+ BIT(SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN),
+ 0x0);
+ }
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget sun8i_codec_headphone_widgets[] = {
SND_SOC_DAPM_MUX("Headphone Source Playback Route",
SND_SOC_NOPM, 0, 0, sun8i_codec_hp_src),
- SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN8I_ADDA_PAEN_HP_CTRL,
- SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV_E("Headphone Amp", SUN8I_ADDA_PAEN_HP_CTRL,
+ SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN, 0, NULL, 0,
+ sun8i_headphone_amp_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN8I_ADDA_PAEN_HP_CTRL,
SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN, 0, NULL, 0),
SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN8I_ADDA_PAEN_HP_CTRL,
--
2.11.0
^ permalink raw reply related
* [PATCH v2 07/10] dt-bindings: sound: Add sun8i audio documentation
From: Mylène Josserand @ 2017-01-17 14:02 UTC (permalink / raw)
To: lgirdwood, broonie, perex, tiwai, maxime.ripard, wens, mturquette,
sboyd, mark.rutland, robh+dt
Cc: linux-kernel, linux-arm-kernel, linux-clk, alsa-devel, devicetree,
linux-sunxi, thomas.petazzoni, mylene.josserand,
alexandre.belloni
In-Reply-To: <20170117140230.23142-1-mylene.josserand@free-electrons.com>
Add the documentation for dt-binding of the digital audio codec driver
and the audio card driver for Sun8i SoCs.
Signed-off-by: Mylène Josserand <mylene.josserand@free-electrons.com>
---
.../devicetree/bindings/sound/sun8i-codec.txt | 76 ++++++++++++++++++++++
1 file changed, 76 insertions(+)
create mode 100644 Documentation/devicetree/bindings/sound/sun8i-codec.txt
diff --git a/Documentation/devicetree/bindings/sound/sun8i-codec.txt b/Documentation/devicetree/bindings/sound/sun8i-codec.txt
new file mode 100644
index 000000000000..ce3c05219e33
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/sun8i-codec.txt
@@ -0,0 +1,76 @@
+Allwinner SUN8I audio codec
+------------------------------------
+
+On Sun8i SoCs, and particularly on A33, the audio is separated in
+different parts:
+ - A DAI driver. It uses the "sun4i-i2s" driver which is
+ documented here:
+ Documentation/devicetree/bindings/sound/sun4i-i2s.txt
+ - An analog part of the codec which is handled as PRCM registers.
+ See Documentation/devicetree/bindings/sound/sun8i-codec-analog.txt
+ - An digital part of the codec which is documented in this current
+ binding documentation.
+ - And finally, an audio card which links all the above components.
+ The simple-audio card will be used.
+ See Documentation/devicetree/bindings/sound/simple-card.txt
+
+This bindings documentation exposes Sun8i codec (digital part).
+
+Required properties:
+- compatible: must be "allwinner,sun8i-a33-codec"
+- reg: must contain the registers location and length
+- interrupts: must contain the codec interrupt
+- clocks: a list of phandle + clock-specifer pairs, one for each entry
+ in clock-names.
+- clock-names: should contain followings:
+ - "bus": the parent APB clock for this controller
+ - "mod": the parent module clock
+
+Example:
+codec: codec@01c22e00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun8i-a33-codec";
+ reg = <0x01c22e00 0x400>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>;
+ clock-names = "bus", "mod";
+ status = "disabled";
+};
+
+Here is an example to add a sound card and the codec binding on sun8i SoCs that
+are similar to A33 using simple-card:
+
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "Sun8i Audio Card";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,frame-master = <&link_codec>;
+ simple-audio-card,bitclock-master = <&link_codec>;
+ simple-audio-card,mclk-fs = <512>;
+ simple-audio-card,aux-devs = <&codec_analog>;
+ simple-audio-card,routing =
+ "Left DAC", "Digital Left DAC",
+ "Right DAC", "Digital Right DAC";
+
+ simple-audio-card,cpu {
+ sound-dai = <&dai>;
+ };
+
+ link_codec: simple-audio-card,codec {
+ sound-dai = <&codec>;
+ };
+
+ soc@01c00000 {
+ [...]
+
+ codec: codec@01c22e00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun8i-a33-codec";
+ reg = <0x01c22e00 0x400>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>;
+ clock-names = "bus", "mod";
+ status = "disabled";
+ };
+ };
+
--
2.11.0
^ permalink raw reply related
* [PATCH v2 08/10] ARM: dts: sun8i: Add audio codec, dai and card for A33
From: Mylène Josserand @ 2017-01-17 14:02 UTC (permalink / raw)
To: lgirdwood, broonie, perex, tiwai, maxime.ripard, wens, mturquette,
sboyd, mark.rutland, robh+dt
Cc: thomas.petazzoni, devicetree, alsa-devel, linux-kernel,
linux-sunxi, alexandre.belloni, mylene.josserand, linux-clk,
linux-arm-kernel
In-Reply-To: <20170117140230.23142-1-mylene.josserand@free-electrons.com>
Add the audio codec, dai and a simple card to be able to use the
audio stream of the builtin codec on sun8i SoC.
This commit adds also an audio-routing for the sound card node to link
the analog DAPM widgets (Right/Left DAC) and the digital one's as they
are created in different drivers.
Signed-off-by: Mylène Josserand <mylene.josserand@free-electrons.com>
---
arch/arm/boot/dts/sun8i-a33.dtsi | 47 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-a33.dtsi b/arch/arm/boot/dts/sun8i-a33.dtsi
index 63d5181ffff8..fe8a4f4760d2 100644
--- a/arch/arm/boot/dts/sun8i-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a33.dtsi
@@ -43,6 +43,7 @@
*/
#include "sun8i-a23-a33.dtsi"
+#include <dt-bindings/dma/sun4i-a10.h>
/ {
cpus {
@@ -69,6 +70,27 @@
reg = <0x40000000 0x80000000>;
};
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "Sun8i Audio Card";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,frame-master = <&link_codec>;
+ simple-audio-card,bitclock-master = <&link_codec>;
+ simple-audio-card,mclk-fs = <512>;
+ simple-audio-card,aux-devs = <&codec_analog>;
+ simple-audio-card,routing =
+ "Left DAC", "Digital Left DAC",
+ "Right DAC", "Digital Right DAC";
+
+ simple-audio-card,cpu {
+ sound-dai = <&dai>;
+ };
+
+ link_codec: simple-audio-card,codec {
+ sound-dai = <&codec>;
+ };
+ };
+
soc@01c00000 {
tcon0: lcd-controller@01c0c000 {
compatible = "allwinner,sun8i-a33-tcon";
@@ -116,6 +138,31 @@
reset-names = "ahb";
};
+ dai: dai@01c22c00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun6i-a31-i2s";
+ reg = <0x01c22c00 0x200>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>;
+ clock-names = "apb", "mod";
+ resets = <&ccu RST_BUS_CODEC>;
+ reset-names = "rst";
+ dmas = <&dma 15>, /* AUDIO_CODEC port */
+ <&dma 15>; /* AUDIO_CODEC port */
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
+ codec: codec@01c22e00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun8i-a33-codec";
+ reg = <0x01c22e00 0x400>;
+ interrupts = <GIC_SPI 29 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_CODEC>, <&ccu CLK_AC_DIG>;
+ clock-names = "bus", "mod";
+ status = "disabled";
+ };
+
fe0: display-frontend@01e00000 {
compatible = "allwinner,sun8i-a33-display-frontend";
reg = <0x01e00000 0x20000>;
--
2.11.0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox