* imx: RS-485 problems during TX, maybe DMA related
From: Clemens Gruber @ 2017-01-07 15:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAOMZO5ALSQj3C6Yn-avMZdzTvtWCZPQ5+pNdzYi03G-GZB_t+w@mail.gmail.com>
Hi Fabio,
On Sat, Jan 07, 2017 at 12:57:10PM -0200, Fabio Estevam wrote:
> The MX6QDL_PAD_CSI0_DAT16__UART4_CTS_B option is only valid in dte mode.
Ah, the input select is limited in that way, I see.
You wrote that you tried rts-gpios.
What about setting cts-gpios to gpio6 2 in the DT?
Or can you remux RX and TX to be switched to work in dte mode?
Regards,
Clemens
^ permalink raw reply
* [linux-sunxi] [PATCH] clk: sunxi-ng: fix PLL_CPUX adjusting on H3
From: Ondřej Jirman @ 2017-01-07 15:49 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125002852.18097-1-megous@megous.com>
Maxime,
Dne 25.11.2016 v 01:28 megous at megous.com napsal(a):
> From: Ondrej Jirman <megous@megous.com>
>
> When adjusting PLL_CPUX on H3, the PLL is temporarily driven
> too high, and the system becomes unstable (oopses or hangs).
>
> Add a notifier to avoid this situation by temporarily switching
> to a known stable 24 MHz oscillator.
I have done more thorough testing on H3 and this approach with switching
to 24MHz oscillator does not work. Motivation being that my Orange Pi
One still gets lockups even with this patch under certain circumstances.
So I have created a small test program for CPUS (additional OpenRISC CPU
on the SoC) which randomly changes PLL_CPUX settings while main CPU is
running a loop that sends messages to CPUS via msgbox.
Assumption being that while CPUS is successfully receiving messages via
msgbox, the main CPU didn't lock up, yet.
With this I am able to quickly and thoroughly test various PLL_CPUX
change and factor selection algorithms.
Results are that bypassing CPUX clock by switching to 24 MHz oscillator
does not work at all. Main CPU locks up in about 1 second into the test.
Don't ask me why.
What works is selecting NKMP factors so that M is always 1 and P is
anything other than /1 only for frequencies under 288MHz. As mandated by
the H3 datasheet. Mainline ccu_nkmp_find_best doesn't respect these
conditions. With that I can change CPUX frequencies randomly 20x a
second so far indefinitely without the main CPU ever locking up.
Please drop or revert this patch. It is not a correct approach to the
problem. I'd suggest dropping the entire clock notifier mechanism, too,
unless it can be proven to work reliably. The bypass makes some
intuitive sense, but for some reason it doesn't work in practice (on H3
at least).
Aside from this, uboot also needs to be changed to set that it uses M
and P factors correctly.
Whatever else I try, I always hit lockups sooner or later with the test
program. I tried 24MHz bypass and staged application of multipliers and
dividers as discussed before.
I'll send a proper patch for nkmp clock driver and u-boot later.
regards,
o.
> Signed-off-by: Ondrej Jirman <megous@megous.com>
> Tested-by: Lutz Sammer <johns98@gmx.net>
> ---
> drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
> index 614d47c..cf266c9 100644
> --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
> +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c
> @@ -809,6 +809,13 @@ static const struct sunxi_ccu_desc sun8i_h3_ccu_desc = {
> .num_resets = ARRAY_SIZE(sun8i_h3_ccu_resets),
> };
>
> +static struct ccu_mux_nb sun8i_h3_cpu_nb = {
> + .common = &cpux_clk.common,
> + .cm = &cpux_clk.mux,
> + .delay_us = 1, /* > 8 clock cycles at 24 MHz */
> + .bypass_index = 1, /* index of 24 MHz oscillator */
> +};
> +
> static void __init sun8i_h3_ccu_setup(struct device_node *node)
> {
> void __iomem *reg;
> @@ -827,6 +834,9 @@ static void __init sun8i_h3_ccu_setup(struct device_node *node)
> writel(val | (3 << 16), reg + SUN8I_H3_PLL_AUDIO_REG);
>
> sunxi_ccu_probe(node, reg, &sun8i_h3_ccu_desc);
> +
> + ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk,
> + &sun8i_h3_cpu_nb);
> }
> CLK_OF_DECLARE(sun8i_h3_ccu, "allwinner,sun8i-h3-ccu",
> sun8i_h3_ccu_setup);
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20170107/ecd3a56f/attachment-0001.sig>
^ permalink raw reply
* imx: RS-485 problems during TX, maybe DMA related
From: Fabio Estevam @ 2017-01-07 16:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170107153434.GA13307@archie.localdomain>
On Sat, Jan 7, 2017 at 1:34 PM, Clemens Gruber
<clemens.gruber@pqgruber.com> wrote:
> Hi Fabio,
>
> On Sat, Jan 07, 2017 at 12:57:10PM -0200, Fabio Estevam wrote:
>> The MX6QDL_PAD_CSI0_DAT16__UART4_CTS_B option is only valid in dte mode.
>
> Ah, the input select is limited in that way, I see.
>
> You wrote that you tried rts-gpios.
> What about setting cts-gpios to gpio6 2 in the DT?
>
> Or can you remux RX and TX to be switched to work in dte mode?
I managed to get RS485 in half-duplex working with rts-gios. Will send
a patch shortly.
Thanks
^ permalink raw reply
* [PATCH V9] thermal: bcm2835: add thermal driver for bcm2835 soc
From: kernel at martin.sperl.org @ 2017-01-07 16:55 UTC (permalink / raw)
To: linux-arm-kernel
From: Martin Sperl <kernel@martin.sperl.org>
Add basic thermal driver for bcm2835 SOC.
This driver currently relies on the firmware setting up the
tsense HW block and does not set it up itself.
Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
Acked-by: Eric Anholt <eric@anholt.net>
Acked-by: Stefan Wahren <stefan.wahren@i2se.com>
---
drivers/thermal/Kconfig | 8 +
drivers/thermal/Makefile | 1 +
drivers/thermal/bcm2835_thermal.c | 354 ++++++++++++++++++++++++++++++++++++++
3 files changed, 363 insertions(+)
create mode 100644 drivers/thermal/bcm2835_thermal.c
ChangeLog:
V1 -> V2: added specific settings depending on compatiblity
added trip point based on register
setting up ctrl-register if HW is not enabled by firmware
as per recommendation of Eric (untested)
check that clock frequency is in range
(1.9 - 5MHz - as per comment in clk-bcm2835.c)
V2 -> V4: moved back to thermal (not using bcm sub-directory)
set polling interval to 1second (was 0ms, so interrupt driven)
V5 -> V6: added correct depends in KConfig
removed defined default for RESET_DELAY
removed obvious comments
clarify HW setup comments if not set up by FW already
move clk_prepare_enable to an earlier stage and add error handling
clarify warning when TS-clock runs out of recommended range
clk_disable_unprepare added in bcm2835_thermal_remove
added comment on recommended temperature ranges for SOC
V6 -> V7: removed depends on ARCH_BCM2836 || ARCH_BCM2837 in Kconfig
V7 -> V8: rebased
V8 -> V9: moved to use the thermal framework offset and slope in
thermal_zone_parameters as per request
A few additional notes on this latest patch:
* all the other portions of the patch (dt, bindings, defconf) have already
been merged into 4.10.0-rc2 - this only leaves the driver itself which
is now just a single patch to get applied.
* the driver has been moved to use thermal_zone_parameters->offset and slope
making use of the thermal_zone_get_offset and thermal_zone_get_slope
methods where relevant
Note that we cannot use those during initial setup of the HW - this code
section is typically not used anyway, as the FW sets up the device already.
This so modified patch actually increases code size by 14 lines:
drivers/thermal/bcm2835_thermal.c | 42 ++++++++++++++++++++++++++-------------
1 file changed, 28 insertions(+), 14 deletions(-)
* /sys/class/thermal/*/ contains now slope and offset files
and those expose the correct values
* for some reason on module load the kernel emits now the message:
(NULL device *): hwmon_device_register() is deprecated. Please convert the driver to use hwmon_device_register_with_info().
But this seems framework specific and needs to get addressed there.
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index c2c056c..18f2de6 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -436,4 +436,12 @@ depends on (ARCH_QCOM && OF) || COMPILE_TEST
source "drivers/thermal/qcom/Kconfig"
endmenu
+config BCM2835_THERMAL
+ tristate "Thermal sensors on bcm2835 SoC"
+ depends on ARCH_BCM2835 || COMPILE_TEST
+ depends on HAS_IOMEM
+ depends on OF
+ help
+ Support for thermal sensors on Broadcom bcm2835 SoCs.
+
endif
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 6a3d7b5..677c6d9 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -56,3 +56,4 @@ obj-$(CONFIG_TEGRA_SOCTHERM) += tegra/
obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
+obj-$(CONFIG_BCM2835_THERMAL) += bcm2835_thermal.o
diff --git a/drivers/thermal/bcm2835_thermal.c b/drivers/thermal/bcm2835_thermal.c
new file mode 100644
index 0000000..5e2fea9
--- /dev/null
+++ b/drivers/thermal/bcm2835_thermal.c
@@ -0,0 +1,354 @@
+/*
+ * Driver for Broadcom BCM2835 soc temperature sensor
+ *
+ * Copyright (C) 2016 Martin Sperl
+ *
+ * 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/clk.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/thermal.h>
+
+#define BCM2835_TS_TSENSCTL 0x00
+#define BCM2835_TS_TSENSSTAT 0x04
+
+#define BCM2835_TS_TSENSCTL_PRWDW BIT(0)
+#define BCM2835_TS_TSENSCTL_RSTB BIT(1)
+#define BCM2835_TS_TSENSCTL_CTRL_BITS 3
+#define BCM2835_TS_TSENSCTL_CTRL_SHIFT 2
+#define BCM2835_TS_TSENSCTL_CTRL_MASK \
+ GENMASK(BCM2835_TS_TSENSCTL_CTRL_BITS + \
+ BCM2835_TS_TSENSCTL_CTRL_SHIFT - 1, \
+ BCM2835_TS_TSENSCTL_CTRL_SHIFT)
+#define BCM2835_TS_TSENSCTL_CTRL_DEFAULT 1
+#define BCM2835_TS_TSENSCTL_EN_INT BIT(5)
+#define BCM2835_TS_TSENSCTL_DIRECT BIT(6)
+#define BCM2835_TS_TSENSCTL_CLR_INT BIT(7)
+#define BCM2835_TS_TSENSCTL_THOLD_SHIFT 8
+#define BCM2835_TS_TSENSCTL_THOLD_BITS 10
+#define BCM2835_TS_TSENSCTL_THOLD_MASK \
+ GENMASK(BCM2835_TS_TSENSCTL_THOLD_BITS + \
+ BCM2835_TS_TSENSCTL_THOLD_SHIFT - 1, \
+ BCM2835_TS_TSENSCTL_THOLD_SHIFT)
+#define BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT 18
+#define BCM2835_TS_TSENSCTL_RSTDELAY_BITS 8
+#define BCM2835_TS_TSENSCTL_REGULEN BIT(26)
+
+#define BCM2835_TS_TSENSSTAT_DATA_BITS 10
+#define BCM2835_TS_TSENSSTAT_DATA_SHIFT 0
+#define BCM2835_TS_TSENSSTAT_DATA_MASK \
+ GENMASK(BCM2835_TS_TSENSSTAT_DATA_BITS + \
+ BCM2835_TS_TSENSSTAT_DATA_SHIFT - 1, \
+ BCM2835_TS_TSENSSTAT_DATA_SHIFT)
+#define BCM2835_TS_TSENSSTAT_VALID BIT(10)
+#define BCM2835_TS_TSENSSTAT_INTERRUPT BIT(11)
+
+struct bcm2835_thermal_info {
+ int offset;
+ int slope;
+ int trip_temp;
+};
+
+struct bcm2835_thermal_data {
+ const struct bcm2835_thermal_info *info;
+ void __iomem *regs;
+ struct clk *clk;
+ struct dentry *debugfsdir;
+};
+
+static int bcm2835_thermal_adc2temp(u32 adc, int offset, int slope)
+{
+ return offset + slope * adc;
+}
+
+static int bcm2835_thermal_temp2adc(int temp, int offset, int slope)
+{
+ temp -= offset;
+ temp /= slope;
+
+ if (temp < 0)
+ temp = 0;
+ if (temp >= BIT(BCM2835_TS_TSENSSTAT_DATA_BITS))
+ temp = BIT(BCM2835_TS_TSENSSTAT_DATA_BITS) - 1;
+
+ return temp;
+}
+
+static int bcm2835_thermal_get_trip_type(
+ struct thermal_zone_device *tz, int trip,
+ enum thermal_trip_type *type)
+{
+ *type = THERMAL_TRIP_CRITICAL;
+ return 0;
+}
+
+static int bcm2835_thermal_get_trip_temp(
+ struct thermal_zone_device *tz, int trip, int *temp)
+{
+ struct bcm2835_thermal_data *data = tz->devdata;
+ u32 val = readl(data->regs + BCM2835_TS_TSENSCTL);
+
+ /* get the THOLD bits */
+ val &= BCM2835_TS_TSENSCTL_THOLD_MASK;
+ val >>= BCM2835_TS_TSENSCTL_THOLD_SHIFT;
+
+ /* if it is zero then use the info value */
+ if (val)
+ *temp = bcm2835_thermal_adc2temp(
+ val,
+ thermal_zone_get_offset(tz),
+ thermal_zone_get_slope(tz));
+ else
+ *temp = data->info->trip_temp;
+
+ return 0;
+}
+
+static int bcm2835_thermal_get_temp(struct thermal_zone_device *tz,
+ int *temp)
+{
+ struct bcm2835_thermal_data *data = tz->devdata;
+ u32 val = readl(data->regs + BCM2835_TS_TSENSSTAT);
+
+ if (!(val & BCM2835_TS_TSENSSTAT_VALID))
+ return -EIO;
+
+ val &= BCM2835_TS_TSENSSTAT_DATA_MASK;
+
+ *temp = bcm2835_thermal_adc2temp(
+ val,
+ thermal_zone_get_offset(tz),
+ thermal_zone_get_slope(tz));
+
+ return 0;
+}
+
+static const struct debugfs_reg32 bcm2835_thermal_regs[] = {
+ {
+ .name = "ctl",
+ .offset = 0
+ },
+ {
+ .name = "stat",
+ .offset = 4
+ }
+};
+
+static void bcm2835_thermal_debugfs(struct platform_device *pdev)
+{
+ struct thermal_zone_device *tz = platform_get_drvdata(pdev);
+ struct bcm2835_thermal_data *data = tz->devdata;
+ struct debugfs_regset32 *regset;
+
+ data->debugfsdir = debugfs_create_dir("bcm2835_thermal", NULL);
+ if (!data->debugfsdir)
+ return;
+
+ regset = devm_kzalloc(&pdev->dev, sizeof(*regset), GFP_KERNEL);
+ if (!regset)
+ return;
+
+ regset->regs = bcm2835_thermal_regs;
+ regset->nregs = ARRAY_SIZE(bcm2835_thermal_regs);
+ regset->base = data->regs;
+
+ debugfs_create_regset32("regset", S_IRUGO,
+ data->debugfsdir, regset);
+}
+
+static struct thermal_zone_device_ops bcm2835_thermal_ops = {
+ .get_temp = bcm2835_thermal_get_temp,
+ .get_trip_temp = bcm2835_thermal_get_trip_temp,
+ .get_trip_type = bcm2835_thermal_get_trip_type,
+};
+
+static const struct of_device_id bcm2835_thermal_of_match_table[];
+static int bcm2835_thermal_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct thermal_zone_device *tz;
+ struct thermal_zone_params *tzp;
+ const struct bcm2835_thermal_info *ti;
+ struct bcm2835_thermal_data *data;
+ struct resource *res;
+ int err;
+ u32 val;
+ unsigned long rate;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ tzp = devm_kzalloc(&pdev->dev, sizeof(*tzp), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ match = of_match_device(bcm2835_thermal_of_match_table,
+ &pdev->dev);
+ if (!match)
+ return -EINVAL;
+ ti = match->data;
+ data->info = ti;
+ tzp->slope = ti->slope;
+ tzp->offset = ti->offset;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(data->regs)) {
+ err = PTR_ERR(data->regs);
+ dev_err(&pdev->dev, "Could not get registers: %d\n", err);
+ return err;
+ }
+
+ data->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(data->clk)) {
+ err = PTR_ERR(data->clk);
+ if (err != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Could not get clk: %d\n", err);
+ return err;
+ }
+
+ err = clk_prepare_enable(data->clk);
+ if (err)
+ return err;
+
+ rate = clk_get_rate(data->clk);
+ if ((rate < 1920000) || (rate > 5000000))
+ dev_warn(&pdev->dev,
+ "Clock %pCn running at %pCr Hz is outside of the recommended range: 1.92 to 5MHz\n",
+ data->clk, data->clk);
+
+ /*
+ * right now the FW does set up the HW-block, so we are not
+ * touching the configuration registers.
+ * But if the HW is not enabled, then set it up
+ * using "sane" values used by the firmware right now.
+ */
+ val = readl(data->regs + BCM2835_TS_TSENSCTL);
+ if (!(val & BCM2835_TS_TSENSCTL_RSTB)) {
+ /* the basic required flags */
+ val = (BCM2835_TS_TSENSCTL_CTRL_DEFAULT <<
+ BCM2835_TS_TSENSCTL_CTRL_SHIFT) |
+ BCM2835_TS_TSENSCTL_REGULEN;
+
+ /*
+ * reset delay using the current firmware value of 14
+ * - units of time are unknown.
+ */
+ val |= (14 << BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT);
+
+ /* trip_adc value from info */
+ val |= bcm2835_thermal_temp2adc(data->info->trip_temp,
+ data->info->offset,
+ data->info->slope)
+ << BCM2835_TS_TSENSCTL_THOLD_SHIFT;
+
+ /* write the value back to the register as 2 steps */
+ writel(val, data->regs + BCM2835_TS_TSENSCTL);
+ val |= BCM2835_TS_TSENSCTL_RSTB;
+ writel(val, data->regs + BCM2835_TS_TSENSCTL);
+ }
+
+ /* register thermal zone with 1 trip point an 1s polling */
+ tz = thermal_zone_device_register("bcm2835_thermal",
+ 1, 0, data,
+ &bcm2835_thermal_ops,
+ tzp,
+ 0, 1000);
+ if (IS_ERR(tz)) {
+ clk_disable_unprepare(data->clk);
+ err = PTR_ERR(tz);
+ dev_err(&pdev->dev,
+ "Failed to register the thermal device: %d\n",
+ err);
+ return err;
+ }
+
+ platform_set_drvdata(pdev, tz);
+
+ bcm2835_thermal_debugfs(pdev);
+
+ return 0;
+}
+
+static int bcm2835_thermal_remove(struct platform_device *pdev)
+{
+ struct thermal_zone_device *tz = platform_get_drvdata(pdev);
+ struct bcm2835_thermal_data *data = tz->devdata;
+
+ debugfs_remove_recursive(data->debugfsdir);
+ thermal_zone_device_unregister(tz);
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+/*
+ * Note: as per Raspberry Foundation FAQ
+ * (https://www.raspberrypi.org/help/faqs/#performanceOperatingTemperature)
+ * the recommended temperature range for the SOC -40C to +85C
+ * so the trip limit is set to 80C.
+ * this applies to all the BCM283X SOC
+ */
+
+static const struct of_device_id bcm2835_thermal_of_match_table[] = {
+ {
+ .compatible = "brcm,bcm2835-thermal",
+ .data = &(struct bcm2835_thermal_info) {
+ .offset = 407000,
+ .slope = -538,
+ .trip_temp = 80000
+ }
+ },
+ {
+ .compatible = "brcm,bcm2836-thermal",
+ .data = &(struct bcm2835_thermal_info) {
+ .offset = 407000,
+ .slope = -538,
+ .trip_temp = 80000
+ }
+ },
+ {
+ .compatible = "brcm,bcm2837-thermal",
+ .data = &(struct bcm2835_thermal_info) {
+ /* the bcm2837 needs adjustment of +5C */
+ .offset = 407000 + 5000,
+ .slope = -538,
+ .trip_temp = 80000
+ }
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bcm2835_thermal_of_match_table);
+
+static struct platform_driver bcm2835_thermal_driver = {
+ .probe = bcm2835_thermal_probe,
+ .remove = bcm2835_thermal_remove,
+ .driver = {
+ .name = "bcm2835_thermal",
+ .of_match_table = bcm2835_thermal_of_match_table,
+ },
+};
+module_platform_driver(bcm2835_thermal_driver);
+
+MODULE_AUTHOR("Martin Sperl");
+MODULE_DESCRIPTION("Thermal driver for bcm2835 chip");
+MODULE_LICENSE("GPL");
--
2.1.4
^ permalink raw reply related
* [PATCH RFC 2/2] ARM: nommu: remap exception base address to RAM
From: Afzal Mohammed @ 2017-01-07 17:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161213100226.GW14217@n2100.armlinux.org.uk>
Hi,
On Tue, Dec 13, 2016 at 10:02:26AM +0000, Russell King - ARM Linux wrote:
> Is there really any need to do this in head.S ? I believe it's
> entirely possible to do it later - arch/arm/mm/nommu.c:paging_init().
As memblock_reserve() for exception address was done before
paging_init(), seems it has to be done by arm_mm_memblock_reserve() in
arch/arm/mm/nommu.c, WIP patch follows, but not that happy -
conditional compilation's make it not so readable, still better to
see in C.
> Also, if the region setup for the vectors was moved as well, it would
> then be possible to check the ID registers to determine whether this
> is supported, and make the decision where to locate the vectors base
> more dynamically.
This would affect Cortex-R's, which is a bit concerning due to lack of
those platforms with me, let me try to get it right. Seems
translating __setup_mpu() altogether to C & installing at a later, but
suitable place might be better.
And feeling something strange about Cortex-R support in mainline,
don't know whether it boots out of the box, there are no Cortex-R cpu
compatibles in dts(i), but devicetree documentation documents it.
Still wrecking Cortex-R's could get counted as a regression as dts is
not considered Kernel. Looks like there is a Cortex-R mafia around
mainline ;)
> That leaves one pr_notice() call using the CONFIG_VECTORS_BASE
> constant...
Seems you want to completely kick out CONFIG_VECTORS_BASE.
Saw 2 interesting MMU cases,
1. in devicemaps_init(), if Hivecs is not set, it is being mapped to
virtual address zero, was wondering how MMU Kernel can handle
exceptions with zero address base (& still prints 0xffff0000 as vector
base)
2. One of the platform does a ioremap of CONFIG_VECTORS_BASE
Once i take care of the above, the ugly conditional compilation in
3/4th patch (@arch/arm/mm/init.c) of WIP patch series that follows
will be removed.
Please let know if you have any comments on the above.
Also !MMU Kernel could boot on 3 ARM v7-A platforms - AM335x Beagle
Bone (A8), AM437x IDK (A9) & Vybrid VF610 (on A5 core, note that it
has M4 core too) with same Kernel image*.
Vybrid did not need any platform specific tweaks, just 1/2th patch
(put in patch system as 8635/1) & WIP series over Vladimir's one,
while TI Sitara AMx3's needed one w.r.t remap.
Please bear my delay - to fill the stomach, work not on Linux and then
the vacations.
Regards
afzal
* Since initramfs was used, tty port had to be changed in initramfs
build for Vybrid, but Kernel except for above initramfs change, was
identical.
^ permalink raw reply
* [PATCH WIP 1/4] ARM: nommu: dynamic exception base address setting
From: afzal mohammed @ 2017-01-07 17:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170107171339.GA5044@afzalpc>
No-MMU dynamic exception base address configuration on processors
with CP15.
TODO: Handle MMU case as well as ARM_MPU scenario dynamically
Signed-off-by: afzal mohammed <afzal.mohd.ma@gmail.com>
---
arch/arm/mm/nommu.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 60 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
index 681cec879caf..e82056df0635 100644
--- a/arch/arm/mm/nommu.c
+++ b/arch/arm/mm/nommu.c
@@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <asm/cacheflush.h>
+#include <asm/cp15.h>
#include <asm/sections.h>
#include <asm/page.h>
#include <asm/setup.h>
@@ -23,6 +24,8 @@
#include "mm.h"
+unsigned long vectors_base;
+
#ifdef CONFIG_ARM_MPU
struct mpu_rgn_info mpu_rgn_info;
@@ -279,15 +282,70 @@ static void sanity_check_meminfo_mpu(void) {}
static void __init mpu_setup(void) {}
#endif /* CONFIG_ARM_MPU */
+#ifdef CONFIG_CPU_CP15
+/*
+ * ID_PRF1 bits (CP#15 ID_PFR1)
+ */
+#define ID_PFR1_SE (0x3 << 4) /* Security extension enable bits */
+
+#ifndef CONFIG_CPU_HIGH_VECTOR
+static inline unsigned long get_id_pfr1(void)
+{
+ unsigned long val;
+ asm("mrc p15, 0, %0, c0, c1, 1" : "=r" (val) : : "cc");
+ return val;
+}
+
+static inline void set_vbar(unsigned long val)
+{
+ asm("mcr p15, 0, %0, c12, c0, 0" : : "r" (val) : "cc");
+}
+
+static bool __init security_extensions_enabled(void)
+{
+ return !!(get_id_pfr1() & ID_PFR1_SE);
+}
+#endif
+
+static unsigned long __init setup_vector_base(void)
+{
+ unsigned long reg, base;
+
+ reg = get_cr();
+
+#ifdef CONFIG_CPU_HIGH_VECTOR
+ set_cr(reg | CR_V);
+ base = 0xFFFF0000;
+#else
+ set_cr(reg & ~CR_V);
+ base = 0;
+ if (security_extensions_enabled()) {
+#ifdef CONFIG_REMAP_VECTORS_TO_RAM
+ base = CONFIG_DRAM_BASE;
+#endif
+ set_vbar(base);
+ }
+#endif /* CONFIG_CPU_HIGH_VECTOR */
+
+ return base;
+}
+#endif /* CONFIG_CPU_CP15 */
+
void __init arm_mm_memblock_reserve(void)
{
#ifndef CONFIG_CPU_V7M
+
+#ifdef CONFIG_CPU_CP15
+ vectors_base = setup_vector_base();
+#else
+ vectors_base = CONFIG_VECTORS_BASE;
+#endif
/*
* Register the exception vector page.
* some architectures which the DRAM is the exception vector to trap,
* alloc_page breaks with error, although it is not NULL, but "0."
*/
- memblock_reserve(CONFIG_VECTORS_BASE, 2 * PAGE_SIZE);
+ memblock_reserve(vectors_base, 2 * PAGE_SIZE);
#else /* ifndef CONFIG_CPU_V7M */
/*
* There is no dedicated vector page on V7-M. So nothing needs to be
@@ -311,7 +369,7 @@ void __init sanity_check_meminfo(void)
*/
void __init paging_init(const struct machine_desc *mdesc)
{
- early_trap_init((void *)CONFIG_VECTORS_BASE);
+ early_trap_init((void *)vectors_base);
mpu_setup();
bootmem_init();
}
--
2.11.0
^ permalink raw reply related
* [PATCH WIP 2/4] ARM: nommu: remove Hivecs configuration is asm
From: afzal mohammed @ 2017-01-07 17:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170107171339.GA5044@afzalpc>
Now that exception based address is handled dynamically for
processors with CP15, remove Hivecs configuration in assembly.
Signed-off-by: afzal mohammed <afzal.mohd.ma@gmail.com>
---
arch/arm/kernel/head-nommu.S | 5 -----
1 file changed, 5 deletions(-)
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
index 2ab026ffc270..e0565d73e49e 100644
--- a/arch/arm/kernel/head-nommu.S
+++ b/arch/arm/kernel/head-nommu.S
@@ -162,11 +162,6 @@ ENDPROC(secondary_startup_arm)
#ifdef CONFIG_CPU_ICACHE_DISABLE
bic r0, r0, #CR_I
#endif
-#ifdef CONFIG_CPU_HIGH_VECTOR
- orr r0, r0, #CR_V
-#else
- bic r0, r0, #CR_V
-#endif
mcr p15, 0, r0, c1, c0, 0 @ write control reg
#elif defined (CONFIG_CPU_V7M)
/* For V7M systems we want to modify the CCR similarly to the SCTLR */
--
2.11.0
^ permalink raw reply related
* [PATCH WIP 3/4] ARM: mm: nommu: display dynamic exception base
From: afzal mohammed @ 2017-01-07 17:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170107171339.GA5044@afzalpc>
Display dynamically estimated nommu exception base.
TODO: Dynamically update MMU case too.
Signed-off-by: afzal mohammed <afzal.mohd.ma@gmail.com>
---
arch/arm/mm/init.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 370581aeb871..1777ee23a6a2 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -39,6 +39,10 @@
#include "mm.h"
+#ifndef CONFIG_MMU
+extern unsigned long vectors_base;
+#endif
+
#ifdef CONFIG_CPU_CP15_MMU
unsigned long __init __clear_cr(unsigned long mask)
{
@@ -521,8 +525,13 @@ void __init mem_init(void)
" .data : 0x%p" " - 0x%p" " (%4td kB)\n"
" .bss : 0x%p" " - 0x%p" " (%4td kB)\n",
+#ifdef CONFIG_MMU
MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) +
(PAGE_SIZE)),
+#else
+ MLK_ROUNDUP(vectors_base, vectors_base + PAGE_SIZE),
+#endif
+
#ifdef CONFIG_HAVE_TCM
MLK(DTCM_OFFSET, (unsigned long) dtcm_end),
MLK(ITCM_OFFSET, (unsigned long) itcm_end),
--
2.11.0
^ permalink raw reply related
* [PATCH WIP 4/4] ARM: remove compile time vector base for CP15 case
From: afzal mohammed @ 2017-01-07 17:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170107171339.GA5044@afzalpc>
vectors base is now dynamically updated for Hivecs as well as for
REMAP_VECTORS_TO_RAM case to DRAM_START. Hence remove these CP15
cases.
TODO:
Kill off VECTORS_BASE completely - this would require to handle MMU
case as well as ARM_MPU scenario dynamically.
Signed-off-by: afzal mohammed <afzal.mohd.ma@gmail.com>
---
arch/arm/Kconfig | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index bc6f4065840e..720ee62b4955 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -232,8 +232,7 @@ config ARCH_MTD_XIP
config VECTORS_BASE
hex
- default 0xffff0000 if MMU || CPU_HIGH_VECTOR
- default DRAM_BASE if REMAP_VECTORS_TO_RAM
+ default 0xffff0000 if MMU
default 0x00000000
help
The base address of exception vectors. This must be two pages
--
2.11.0
^ permalink raw reply related
* [PATCH WIP 4/4] ARM: remove compile time vector base for CP15 case
From: Russell King - ARM Linux @ 2017-01-07 17:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170107172228.6451-1-afzal.mohd.ma@gmail.com>
On Sat, Jan 07, 2017 at 10:52:28PM +0530, afzal mohammed wrote:
> vectors base is now dynamically updated for Hivecs as well as for
> REMAP_VECTORS_TO_RAM case to DRAM_START. Hence remove these CP15
> cases.
>
> TODO:
> Kill off VECTORS_BASE completely - this would require to handle MMU
> case as well as ARM_MPU scenario dynamically.
Why do you think MMU doesn't already handle it?
> config VECTORS_BASE
> hex
> - default 0xffff0000 if MMU || CPU_HIGH_VECTOR
> - default DRAM_BASE if REMAP_VECTORS_TO_RAM
> + default 0xffff0000 if MMU
> default 0x00000000
When MMU=y, the resulting VECTORS_BASE is always 0xffff0000. The only
case where this ends up zero after your change is when MMU=n.
In any case here's the places it's used:
For nommu:
arch/arm/kernel/head-nommu.S: mov r0, #CONFIG_VECTORS_BASE @ Cover from VECTORS_BASE
arch/arm/kernel/head-nommu.S: setup_region r0, r5, r6, MPU_DATA_SIDE @ VECTORS_BASE, PL0 NA, enabled
arch/arm/kernel/head-nommu.S: setup_region r0, r5, r6, MPU_INSTR_SIDE @ VECTORS_BASE, PL0 NA, enabled
arch/arm/mm/nommu.c: memblock_reserve(CONFIG_VECTORS_BASE, 2 * PAGE_SIZE);
arch/arm/mm/nommu.c: early_trap_init((void *)CONFIG_VECTORS_BASE);
To intercept the reset vector for secondary CPUs (because we hide it
away from platforms, so platforms end up hacking around to get at it.)
arch/arm/mach-berlin/platsmp.c: vectors_base = ioremap(CONFIG_VECTORS_BASE, SZ_32K);
For printing:
arch/arm/mm/init.c: MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) +
For dumping the page tables (but since this is only built for MMU=y,
we know what CONFIG_VECTORS_BASE is here.)
arch/arm/mm/dump.c: { CONFIG_VECTORS_BASE, "Vectors" },
arch/arm/mm/dump.c: { CONFIG_VECTORS_BASE + PAGE_SIZE * 2, "Vectors End" },
For the Berlin and mm/dump code, we could very easily just have a
#define VECTORS_BASE 0xffff0000 in a header file and drop the CONFIG_
prefix.
The MMU case does have to cater for CPUs wanting vectors at 0xffff0000
and at 0x00000000, and this is handled via the page tables - but this
has nothing to do with CONFIG_VECTORS_BASE. CONFIG_VECTORS_BASE
exists primarily for noMMU.
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
^ permalink raw reply
* [PATCH WIP 4/4] ARM: remove compile time vector base for CP15 case
From: Afzal Mohammed @ 2017-01-07 18:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170107173832.GN14217@n2100.armlinux.org.uk>
Hi,
On Sat, Jan 07, 2017 at 05:38:32PM +0000, Russell King - ARM Linux wrote:
> On Sat, Jan 07, 2017 at 10:52:28PM +0530, afzal mohammed wrote:
> > TODO:
> > Kill off VECTORS_BASE completely - this would require to handle MMU
> > case as well as ARM_MPU scenario dynamically.
> Why do you think MMU doesn't already handle it?
i meant here w.r.t displaying vector base address in
arch/arm/mm/init.c, i.e. dynamically get it based on Hivecs setting as
either 0xffff0000 or 0x00000000
>
> > config VECTORS_BASE
> > hex
> > - default 0xffff0000 if MMU || CPU_HIGH_VECTOR
> > - default DRAM_BASE if REMAP_VECTORS_TO_RAM
> > + default 0xffff0000 if MMU
> > default 0x00000000
>
> When MMU=y, the resulting VECTORS_BASE is always 0xffff0000. The only
> case where this ends up zero after your change is when MMU=n.
> The MMU case does have to cater for CPUs wanting vectors at 0xffff0000
> and at 0x00000000, and this is handled via the page tables - but this
> has nothing to do with CONFIG_VECTORS_BASE. CONFIG_VECTORS_BASE
> exists primarily for noMMU.
i had thought that for MMU case if Hivecs is not enabled,
CONFIG_VECTOR_BASE has to be considered as 0x00000000 at least for the
purpose of displaying exception base address.
One thing i have not yet understood is how CPU can take exception with
it base address as 0x00000000 (for Hivecs not enabled case) virtual
address as it is below Kernel memory map.
> For the Berlin and mm/dump code, we could very easily just have a
> #define VECTORS_BASE 0xffff0000 in a header file and drop the CONFIG_
> prefix.
Okay, thanks for the tip.
Regards
afzal
^ permalink raw reply
* [PATCH WIP 4/4] ARM: remove compile time vector base for CP15 case
From: Afzal Mohammed @ 2017-01-07 18:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170107180227.GA8130@afzalpc>
Hi,
On Sat, Jan 07, 2017 at 11:32:27PM +0530, Afzal Mohammed wrote:
> i had thought that for MMU case if Hivecs is not enabled,
> CONFIG_VECTOR_BASE has to be considered as 0x00000000 at least for the
s/CONFIG_VECTOR_BASE/exception base address
> purpose of displaying exception base address.
Regards
afzal
^ permalink raw reply
* [PATCH WIP 4/4] ARM: remove compile time vector base for CP15 case
From: Russell King - ARM Linux @ 2017-01-07 18:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170107180227.GA8130@afzalpc>
On Sat, Jan 07, 2017 at 11:32:27PM +0530, Afzal Mohammed wrote:
> Hi,
>
> On Sat, Jan 07, 2017 at 05:38:32PM +0000, Russell King - ARM Linux wrote:
> > On Sat, Jan 07, 2017 at 10:52:28PM +0530, afzal mohammed wrote:
>
> > > TODO:
> > > Kill off VECTORS_BASE completely - this would require to handle MMU
> > > case as well as ARM_MPU scenario dynamically.
>
> > Why do you think MMU doesn't already handle it?
>
> i meant here w.r.t displaying vector base address in
> arch/arm/mm/init.c, i.e. dynamically get it based on Hivecs setting as
> either 0xffff0000 or 0x00000000
You mean:
pr_notice("Virtual kernel memory layout:\n"
" vector : 0x%08lx - 0x%08lx (%4ld kB)\n"
...
MLK(UL(CONFIG_VECTORS_BASE), UL(CONFIG_VECTORS_BASE) +
(PAGE_SIZE)),
As I've said, CONFIG_VECTORS_BASE is _always_ 0xffff0000 on MMU, so
this always displays 0xffff0000 - 0xffff1000 here.
> i had thought that for MMU case if Hivecs is not enabled,
> CONFIG_VECTOR_BASE has to be considered as 0x00000000 at least for the
> purpose of displaying exception base address.
>
> One thing i have not yet understood is how CPU can take exception with
> it base address as 0x00000000 (for Hivecs not enabled case) virtual
> address as it is below Kernel memory map.
Older ARM CPUs without the V bit (ARMv3 and early ARMv4) expect the
vectors to be at virtual address zero.
Most of these systems place ROM at physical address 0, so when the CPU
starts from reset (with the MMU off) it starts executing from ROM. Once
the MMU is initialised, RAM can be placed there and the ROM vectors
replaced. The side effect of this is that NULL pointer dereferences
are not always caught... of course, it makes sense that the page at
address 0 is write protected even from the kernel, so a NULL pointer
write dereference doesn't corrupt the vectors.
How we handle it in Linux is that we always map the page for the vectors
at 0xffff0000, and then only map that same page at 0x00000000 if we have
a CPU that needs it there.
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
^ permalink raw reply
* [PATCH resend v3] ASoC: sun4i-codec: Add "Right Mixer" to "Line Out Mono Diff." route
From: Chen-Yu Tsai @ 2017-01-07 18:57 UTC (permalink / raw)
To: linux-arm-kernel
The mono differential output for "Line Out" downmixes the stereo audio
from the mixer, instead of just taking the left channel.
Add a route from the "Right Mixer" to "Line Out Source Playback Route"
through the "Mono Differential" path, so DAPM doesn't shut down
everything if the left channel is muted.
Fixes: 0f909f98d7cb ("ASoC: sun4i-codec: Add support for A31 Line Out
playback")
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
Last sent 2016/11/24. Resending with Maxime's ack.
---
sound/soc/sunxi/sun4i-codec.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index 848af01692a0..c3aab10fa085 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -1058,6 +1058,7 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = {
{ "Line Out Source Playback Route", "Stereo", "Left Mixer" },
{ "Line Out Source Playback Route", "Stereo", "Right Mixer" },
{ "Line Out Source Playback Route", "Mono Differential", "Left Mixer" },
+ { "Line Out Source Playback Route", "Mono Differential", "Right Mixer" },
{ "LINEOUT", NULL, "Line Out Source Playback Route" },
/* ADC Routes */
--
2.11.0
^ permalink raw reply related
* [PATCH v2 0/8] ASoC: sunxi: Add support for audio codec in A23/H3 SoCs
From: Chen-Yu Tsai @ 2017-01-07 19:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161125123442.28410-1-wens@csie.org>
Hi Maxime,
On Fri, Nov 25, 2016 at 8:34 PM, Chen-Yu Tsai <wens@csie.org> wrote:
> Hi everyone,
>
> This is v2 of my Allwinner A23 and H3 audio codec support series.
>
> Changes since v1:
>
> - Use DEFINE_RES_MEM for the analog path controls block resources.
> - Added Rob's ack.
>
> This series adds support for the audio codec found in Allwinner A23 and
> H3 SoCs. The design and data paths are similar to the audio codec found
> in earlier SoCs such as the A31. The analog audio paths are symmetrical
> with left/right channels and down-mix selectors for mono differential
> output.
>
> What deviates from previous SoCs is that the analog path controls have
> been moved to a separate control bus, accessed through a message box
> like register interface in the PRCM block. This necessitates writing
> a separate component driver for it, which is then tied into the sound
> card as an ASoC auxiliary device.
>
> Patch 1 adds the analog path controls block to the sun6i-prcm driver as
> a sub-device, for the A23. The H3 currently does not use the PRCM driver.
>
> Patch 2 adds PCM and card support for the A23 codec to the sun4i-codec
> driver.
>
> Patch 3 adds a device node for the analog path controls block to the A23
> dtsi.
>
> Patch 4 adds a device node for the audio codec, and the phandle for the
> analog path controls block to the A23 dtsi.
>
> Patch 5 enables the audio codec for the A23 Q8 tablets. On these tablets
> the headphone output is driven in DC coupled, or "direct drive", mode.
>
> Patch 6 adds PCM and card support for the H3 codec to the sun4i-codec
> driver.
>
> Patch 7 adds device nodes for the audio codec and analog path controls
> block to the H3 dtsi.
>
> Patch 8 enables the audio codec on the Orange Pi PC. The audio output
> jack on the board is tied to the line out pins on the SoC.
All the driver bits are in. Can you pick up the dts patches?
Thanks
ChenYu
>
>
> Please take a look and let me know what you think.
>
> In addition, the sun4i-codec driver is getting pretty large. Maybe we
> want to split the different parts into different files?
>
>
> Regards
> ChenYu
>
>
> Chen-Yu Tsai (8):
> mfd: sun6i-prcm: Add codec analog controls sub-device for Allwinner
> A23
> ASoC: sun4i-codec: Add support for A23 codec
> ARM: dts: sun8i: Add codec analog path controls node in PRCM for
> A23/A33
> ARM: dts: sun8i-a23: Add device node for internal audio codec
> ARM: dts: sun8i-a23: q8-tablet: Enable internal audio codec
> ASoC: sun4i-codec: Add support for H3 codec
> ARM: dts: sun8i-h3: Add device nodes for audio codec and its analog
> controls
> ARM: dts: sun8i-h3: orange-pi-pc: Enable audio codec
>
> .../devicetree/bindings/sound/sun4i-codec.txt | 14 +-
> arch/arm/boot/dts/sun8i-a23-a33.dtsi | 4 +
> arch/arm/boot/dts/sun8i-a23-q8-tablet.dts | 23 +++
> arch/arm/boot/dts/sun8i-a23.dtsi | 16 ++
> arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts | 8 +
> arch/arm/boot/dts/sun8i-h3.dtsi | 19 +++
> drivers/mfd/sun6i-prcm.c | 13 ++
> sound/soc/sunxi/sun4i-codec.c | 179 +++++++++++++++++++++
> 8 files changed, 274 insertions(+), 2 deletions(-)
>
> --
> 2.10.2
>
^ permalink raw reply
* [PATCH 03/22] iio: adc: add support for X-Powers AXP20X and AXP22X PMICs ADCs
From: Jonathan Cameron @ 2017-01-07 19:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170102163723.7939-4-quentin.schulz@free-electrons.com>
On 02/01/17 11:37, Quentin Schulz wrote:
> The X-Powers AXP20X and AXP22X PMICs have multiple ADCs. They expose the
> battery voltage, battery charge and discharge currents, AC-in and VBUS
> voltages and currents, 2 GPIOs muxable in ADC mode and PMIC temperature.
>
> This adds support for most of AXP20X and AXP22X ADCs.
>
> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
Couple of little bits from me. Peter got the bigger stuff.
Jonathan
> ---
> drivers/iio/adc/Kconfig | 10 +
> drivers/iio/adc/Makefile | 1 +
> drivers/iio/adc/axp20x_adc.c | 490 +++++++++++++++++++++++++++++++++++++++++++
> include/linux/mfd/axp20x.h | 4 +
> 4 files changed, 505 insertions(+)
> create mode 100644 drivers/iio/adc/axp20x_adc.c
>
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 38bc319..5c5b51f 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -154,6 +154,16 @@ config AT91_SAMA5D2_ADC
> To compile this driver as a module, choose M here: the module will be
> called at91-sama5d2_adc.
>
> +config AXP20X_ADC
> + tristate "X-Powers AXP20X and AXP22X ADC driver"
> + depends on MFD_AXP20X
> + help
> + Say yes here to have support for X-Powers power management IC (PMIC)
> + AXP20X and AXP22X ADC devices.
> +
> + To compile this driver as a module, choose M here: the module will be
> + called axp20x_adc.
> +
> config AXP288_ADC
> tristate "X-Powers AXP288 ADC driver"
> depends on MFD_AXP20X
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index d36c4be..f5c28a5 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -16,6 +16,7 @@ obj-$(CONFIG_AD7887) += ad7887.o
> obj-$(CONFIG_AD799X) += ad799x.o
> obj-$(CONFIG_AT91_ADC) += at91_adc.o
> obj-$(CONFIG_AT91_SAMA5D2_ADC) += at91-sama5d2_adc.o
> +obj-$(CONFIG_AXP20X_ADC) += axp20x_adc.o
> obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
> obj-$(CONFIG_BCM_IPROC_ADC) += bcm_iproc_adc.o
> obj-$(CONFIG_BERLIN2_ADC) += berlin2-adc.o
> diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
> new file mode 100644
> index 0000000..8df972a
> --- /dev/null
> +++ b/drivers/iio/adc/axp20x_adc.c
> @@ -0,0 +1,490 @@
> +/* ADC driver for AXP20X and AXP22X PMICs
> + *
> + * Copyright (c) 2016 Free Electrons NextThing Co.
> + * Quentin Schulz <quentin.schulz@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 version 2 as published by the
> + * Free Software Foundation.
> + *
Pet hate : why a blank line here? ;) I'm grumpy - my flight home is delayed.
> + */
> +
> +#include <linux/completion.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +#include <linux/thermal.h>
> +
> +#include <linux/iio/iio.h>
> +#include <linux/mfd/axp20x.h>
> +
> +#define AXP20X_ADC_EN1_MASK GENMASK(7, 0)
> +
> +#define AXP20X_ADC_EN2_MASK (GENMASK(3, 2) | BIT(7))
> +#define AXP22X_ADC_EN1_MASK (GENMASK(7, 5) | BIT(0))
> +#define AXP20X_ADC_EN2_TEMP_ADC BIT(7)
> +#define AXP20X_ADC_EN2_GPIO0_ADC BIT(3)
> +#define AXP20X_ADC_EN2_GPIO1_ADC BIT(2)
> +
> +#define AXP20X_GPIO10_IN_RANGE_GPIO0 BIT(0)
> +#define AXP20X_GPIO10_IN_RANGE_GPIO1 BIT(1)
> +#define AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(x) ((x) & BIT(0))
> +#define AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(x) (((x) & BIT(0)) << 1)
> +
> +#define AXP20X_ADC_RATE_MASK (3 << 6)
> +#define AXP20X_ADC_RATE_25HZ (0 << 6)
> +#define AXP20X_ADC_RATE_50HZ BIT(6)
> +#define AXP20X_ADC_RATE_100HZ (2 << 6)
> +#define AXP20X_ADC_RATE_200HZ (3 << 6)
> +
> +#define AXP22X_ADC_RATE_100HZ (0 << 6)
> +#define AXP22X_ADC_RATE_200HZ BIT(6)
> +#define AXP22X_ADC_RATE_400HZ (2 << 6)
> +#define AXP22X_ADC_RATE_800HZ (3 << 6)
> +
> +#define AXP20X_ADC_CHANNEL(_channel, _name, _type, _reg) \
> + { \
> + .type = _type, \
> + .indexed = 1, \
> + .channel = _channel, \
> + .address = _reg, \
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
> + BIT(IIO_CHAN_INFO_SCALE), \
> + .datasheet_name = _name, \
> + }
> +
> +#define AXP20X_ADC_CHANNEL_OFFSET(_channel, _name, _type, _reg) \
> + { \
> + .type = _type, \
> + .indexed = 1, \
> + .channel = _channel, \
> + .address = _reg, \
> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
> + BIT(IIO_CHAN_INFO_SCALE) |\
> + BIT(IIO_CHAN_INFO_OFFSET),\
> + .datasheet_name = _name, \
> + }
> +
> +struct axp20x_adc_iio {
Why? I'm not seeing this used anywhere.
> + struct iio_dev *indio_dev;
> + struct regmap *regmap;
> +};
> +
> +enum axp20x_adc_channel {
> + AXP20X_ACIN_V = 0,
> + AXP20X_ACIN_I,
> + AXP20X_VBUS_V,
> + AXP20X_VBUS_I,
> + AXP20X_TEMP_ADC,
> + AXP20X_GPIO0_V,
> + AXP20X_GPIO1_V,
> + AXP20X_BATT_V,
> + AXP20X_BATT_CHRG_I,
> + AXP20X_BATT_DISCHRG_I,
> + AXP20X_IPSOUT_V,
> +};
> +
> +enum axp22x_adc_channel {
> + AXP22X_TEMP_ADC = 0,
> + AXP22X_BATT_V,
> + AXP22X_BATT_CHRG_I,
> + AXP22X_BATT_DISCHRG_I,
> +};
> +
> +static const struct iio_chan_spec axp20x_adc_channels[] = {
> + AXP20X_ADC_CHANNEL(AXP20X_ACIN_V, "acin_v", IIO_VOLTAGE,
> + AXP20X_ACIN_V_ADC_H),
> + AXP20X_ADC_CHANNEL(AXP20X_ACIN_I, "acin_i", IIO_CURRENT,
> + AXP20X_ACIN_I_ADC_H),
> + AXP20X_ADC_CHANNEL(AXP20X_VBUS_V, "vbus_v", IIO_VOLTAGE,
> + AXP20X_VBUS_V_ADC_H),
> + AXP20X_ADC_CHANNEL(AXP20X_VBUS_I, "vbus_i", IIO_CURRENT,
> + AXP20X_VBUS_I_ADC_H),
> + AXP20X_ADC_CHANNEL_OFFSET(AXP20X_TEMP_ADC, "temp_adc", IIO_TEMP,
> + AXP20X_TEMP_ADC_H),
> + AXP20X_ADC_CHANNEL_OFFSET(AXP20X_GPIO0_V, "gpio0_v", IIO_VOLTAGE,
> + AXP20X_GPIO0_V_ADC_H),
> + AXP20X_ADC_CHANNEL_OFFSET(AXP20X_GPIO1_V, "gpio1_v", IIO_VOLTAGE,
> + AXP20X_GPIO1_V_ADC_H),
> + AXP20X_ADC_CHANNEL(AXP20X_BATT_V, "batt_v", IIO_VOLTAGE,
> + AXP20X_BATT_V_H),
> + AXP20X_ADC_CHANNEL(AXP20X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
> + AXP20X_BATT_CHRG_I_H),
> + AXP20X_ADC_CHANNEL(AXP20X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
> + AXP20X_BATT_DISCHRG_I_H),
> + AXP20X_ADC_CHANNEL(AXP20X_IPSOUT_V, "ipsout_v", IIO_VOLTAGE,
> + AXP20X_IPSOUT_V_HIGH_H),
> +};
> +
> +static const struct iio_chan_spec axp22x_adc_channels[] = {
> + AXP20X_ADC_CHANNEL_OFFSET(AXP22X_TEMP_ADC, "temp_adc", IIO_TEMP,
> + AXP22X_TEMP_ADC_H),
> + AXP20X_ADC_CHANNEL(AXP22X_BATT_V, "batt_v", IIO_VOLTAGE,
> + AXP20X_BATT_V_H),
> + AXP20X_ADC_CHANNEL(AXP22X_BATT_CHRG_I, "batt_chrg_i", IIO_CURRENT,
> + AXP20X_BATT_CHRG_I_H),
> + AXP20X_ADC_CHANNEL(AXP22X_BATT_DISCHRG_I, "batt_dischrg_i", IIO_CURRENT,
> + AXP20X_BATT_DISCHRG_I_H),
> +};
> +
> +static int axp20x_adc_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *channel, int *val,
> + int *val2)
> +{
> + struct axp20x_adc_iio *info = iio_priv(indio_dev);
> + int size = 12, ret;
> +
> + switch (channel->channel) {
> + case AXP20X_BATT_DISCHRG_I:
> + size = 13;
> + case AXP20X_ACIN_V:
> + case AXP20X_ACIN_I:
> + case AXP20X_VBUS_V:
> + case AXP20X_VBUS_I:
> + case AXP20X_TEMP_ADC:
> + case AXP20X_BATT_V:
> + case AXP20X_BATT_CHRG_I:
> + case AXP20X_IPSOUT_V:
> + case AXP20X_GPIO0_V:
> + case AXP20X_GPIO1_V:
> + ret = axp20x_read_variable_width(info->regmap, channel->address,
> + size);
> + if (ret < 0)
> + return ret;
> + *val = ret;
> + return IIO_VAL_INT;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int axp22x_adc_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *channel, int *val,
> + int *val2)
> +{
> + struct axp20x_adc_iio *info = iio_priv(indio_dev);
> + int size = 12, ret;
> +
> + switch (channel->channel) {
> + case AXP22X_BATT_DISCHRG_I:
> + size = 13;
> + case AXP22X_TEMP_ADC:
> + case AXP22X_BATT_V:
> + case AXP22X_BATT_CHRG_I:
> + ret = axp20x_read_variable_width(info->regmap, channel->address,
> + size);
> + if (ret < 0)
> + return ret;
> + *val = ret;
> + return IIO_VAL_INT;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int axp20x_adc_scale(int channel, int *val, int *val2)
> +{
> + switch (channel) {
> + case AXP20X_ACIN_V:
> + case AXP20X_VBUS_V:
> + *val = 1;
> + *val2 = 700000;
> + return IIO_VAL_INT_PLUS_MICRO;
> +
> + case AXP20X_ACIN_I:
> + *val = 0;
> + *val2 = 625000;
> + return IIO_VAL_INT_PLUS_MICRO;
> +
> + case AXP20X_VBUS_I:
> + *val = 0;
> + *val2 = 375000;
> + return IIO_VAL_INT_PLUS_MICRO;
> +
> + case AXP20X_TEMP_ADC:
> + *val = 100;
> + return IIO_VAL_INT;
> +
> + case AXP20X_GPIO0_V:
> + case AXP20X_GPIO1_V:
> + *val = 0;
> + *val2 = 500000;
> + return IIO_VAL_INT_PLUS_MICRO;
> +
> + case AXP20X_BATT_V:
> + *val = 1;
> + *val2 = 100000;
> + return IIO_VAL_INT_PLUS_MICRO;
> +
> + case AXP20X_BATT_DISCHRG_I:
> + case AXP20X_BATT_CHRG_I:
> + *val = 0;
> + *val2 = 500000;
> + return IIO_VAL_INT_PLUS_MICRO;
> +
> + case AXP20X_IPSOUT_V:
> + *val = 1;
> + *val2 = 400000;
> + return IIO_VAL_INT_PLUS_MICRO;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int axp22x_adc_scale(int channel, int *val, int *val2)
> +{
> + switch (channel) {
> + case AXP22X_TEMP_ADC:
> + *val = 100;
> + return IIO_VAL_INT;
> +
> + case AXP22X_BATT_V:
> + *val = 1;
> + *val2 = 100000;
> + return IIO_VAL_INT_PLUS_MICRO;
> +
> + case AXP22X_BATT_DISCHRG_I:
> + case AXP22X_BATT_CHRG_I:
> + *val = 0;
> + *val2 = 500000;
> + return IIO_VAL_INT_PLUS_MICRO;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int axp20x_adc_offset(struct iio_dev *indio_dev, int channel, int *val)
> +{
> + struct axp20x_adc_iio *info = iio_priv(indio_dev);
> + int ret, reg;
> +
> + switch (channel) {
> + case AXP20X_TEMP_ADC:
> + *val = -1447;
> + return IIO_VAL_INT;
> +
> + case AXP20X_GPIO0_V:
> + case AXP20X_GPIO1_V:
> + ret = regmap_read(info->regmap, AXP20X_GPIO10_IN_RANGE, ®);
> + if (ret < 0)
> + return ret;
> +
> + if (channel == AXP20X_GPIO0_V)
> + *val = reg & AXP20X_GPIO10_IN_RANGE_GPIO0;
> + else
> + *val = reg & AXP20X_GPIO10_IN_RANGE_GPIO1;
> +
> + *val = !!(*val) * 700000;
> +
> + return IIO_VAL_INT;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int axp20x_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan, int *val,
> + int *val2, long mask)
> +{
> + switch (mask) {
> + case IIO_CHAN_INFO_OFFSET:
> + return axp20x_adc_offset(indio_dev, chan->channel, val);
> +
> + case IIO_CHAN_INFO_SCALE:
> + return axp20x_adc_scale(chan->channel, val, val2);
> +
> + case IIO_CHAN_INFO_RAW:
> + return axp20x_adc_read_raw(indio_dev, chan, val, val2);
> +
> + default:
> + return -EINVAL;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int axp22x_read_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan, int *val,
> + int *val2, long mask)
> +{
> + switch (mask) {
> + case IIO_CHAN_INFO_OFFSET:
> + *val = -2667;
> + return IIO_VAL_INT;
> +
> + case IIO_CHAN_INFO_SCALE:
> + return axp22x_adc_scale(chan->channel, val, val2);
> +
> + case IIO_CHAN_INFO_RAW:
> + return axp22x_adc_read_raw(indio_dev, chan, val, val2);
> +
> + default:
> + return -EINVAL;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static int axp20x_write_raw(struct iio_dev *indio_dev,
> + struct iio_chan_spec const *chan, int val, int val2,
> + long mask)
> +{
> + struct axp20x_adc_iio *info = iio_priv(indio_dev);
> +
> + /*
> + * The AXP20X PMIC allows the user to choose between 0V and 0.7V offsets
> + * for (independently) GPIO0 and GPIO1 when in ADC mode.
> + */
> + if (mask != IIO_CHAN_INFO_OFFSET)
> + return -EINVAL;
> +
> + if (chan->channel != AXP20X_GPIO0_V && chan->channel != AXP20X_GPIO1_V)
> + return -EINVAL;
> +
> + if (val != 0 && val != 700000)
> + return -EINVAL;
> +
> + if (chan->channel == AXP20X_GPIO0_V)
> + return regmap_update_bits(info->regmap, AXP20X_GPIO10_IN_RANGE,
> + AXP20X_GPIO10_IN_RANGE_GPIO0,
> + AXP20X_GPIO10_IN_RANGE_GPIO0_VAL(!!val));
> +
> + return regmap_update_bits(info->regmap, AXP20X_GPIO10_IN_RANGE,
> + AXP20X_GPIO10_IN_RANGE_GPIO1,
> + AXP20X_GPIO10_IN_RANGE_GPIO1_VAL(!!val));
> +}
> +
> +static const struct iio_info axp20x_adc_iio_info = {
> + .read_raw = axp20x_read_raw,
> + .write_raw = axp20x_write_raw,
> + .driver_module = THIS_MODULE,
> +};
> +
> +static const struct iio_info axp22x_adc_iio_info = {
> + .read_raw = axp22x_read_raw,
> + .driver_module = THIS_MODULE,
> +};
> +
> +static const struct of_device_id axp20x_adc_of_match[] = {
> + { .compatible = "x-powers,axp209-adc", .data = (void *)AXP209_ID, },
> + { .compatible = "x-powers,axp221-adc", .data = (void *)AXP221_ID, },
> + { /* sentinel */ },
> +};
> +
> +static int axp20x_probe(struct platform_device *pdev)
> +{
> + struct axp20x_adc_iio *info;
> + struct iio_dev *indio_dev;
> + struct axp20x_dev *axp20x_dev;
> + int ret, axp20x_id;
> +
> + axp20x_dev = dev_get_drvdata(pdev->dev.parent);
> +
> + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
> + if (!indio_dev)
> + return -ENOMEM;
> +
> + info = iio_priv(indio_dev);
> + platform_set_drvdata(pdev, indio_dev);
> +
> + info->regmap = axp20x_dev->regmap;
> + info->indio_dev = indio_dev;
> + indio_dev->name = dev_name(&pdev->dev);
> + indio_dev->dev.parent = &pdev->dev;
> + indio_dev->dev.of_node = pdev->dev.of_node;
> + indio_dev->modes = INDIO_DIRECT_MODE;
> +
> + axp20x_id = (int)of_device_get_match_data(&pdev->dev);
> +
> + switch (axp20x_id) {
> + case AXP209_ID:
> + indio_dev->info = &axp20x_adc_iio_info;
> + indio_dev->num_channels = ARRAY_SIZE(axp20x_adc_channels);
> + indio_dev->channels = axp20x_adc_channels;
> +
> + /* Enable the ADCs on IP */
> + regmap_write(info->regmap, AXP20X_ADC_EN1, AXP20X_ADC_EN1_MASK);
> +
> + /* Enable GPIO0/1 and internal temperature ADCs */
> + regmap_update_bits(info->regmap, AXP20X_ADC_EN2,
> + AXP20X_ADC_EN2_MASK, AXP20X_ADC_EN2_MASK);
> +
> + /* Configure ADCs rate */
> + regmap_update_bits(info->regmap, AXP20X_ADC_RATE,
> + AXP20X_ADC_RATE_MASK, AXP20X_ADC_RATE_50HZ);
> + break;
> +
> + case AXP221_ID:
> + indio_dev->info = &axp22x_adc_iio_info;
> + indio_dev->num_channels = ARRAY_SIZE(axp22x_adc_channels);
> + indio_dev->channels = axp22x_adc_channels;
> +
> + /* Enable the ADCs on IP */
> + regmap_write(info->regmap, AXP20X_ADC_EN1, AXP22X_ADC_EN1_MASK);
> +
> + /* Configure ADCs rate */
> + regmap_update_bits(info->regmap, AXP20X_ADC_RATE,
> + AXP20X_ADC_RATE_MASK, AXP22X_ADC_RATE_200HZ);
> + break;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + ret = devm_iio_device_register(&pdev->dev, indio_dev);
> + if (ret < 0) {
> + dev_err(&pdev->dev, "could not register the device\n");
> + regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
> + regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int axp20x_remove(struct platform_device *pdev)
> +{
> + struct axp20x_adc_iio *info;
> + struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> +
> + info = iio_priv(indio_dev);
> + regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
> + regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
> +
> + return 0;
> +}
> +
> +static struct platform_driver axp20x_adc_driver = {
> + .driver = {
> + .name = "axp20x-adc",
> + .of_match_table = axp20x_adc_of_match,
> + },
> + .probe = axp20x_probe,
> + .remove = axp20x_remove,
> +};
> +
> +module_platform_driver(axp20x_adc_driver);
> +
> +MODULE_DESCRIPTION("ADC driver for AXP20X and AXP22X PMICs");
> +MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
> index a4860bc..650c6f6 100644
> --- a/include/linux/mfd/axp20x.h
> +++ b/include/linux/mfd/axp20x.h
> @@ -150,6 +150,10 @@ enum {
> #define AXP20X_VBUS_I_ADC_L 0x5d
> #define AXP20X_TEMP_ADC_H 0x5e
> #define AXP20X_TEMP_ADC_L 0x5f
> +
> +#define AXP22X_TEMP_ADC_H 0x56
> +#define AXP22X_TEMP_ADC_L 0x57
> +
> #define AXP20X_TS_IN_H 0x62
> #define AXP20X_TS_IN_L 0x63
> #define AXP20X_GPIO0_V_ADC_H 0x64
>
^ permalink raw reply
* [linux-sunxi][PATCH 3/3] ARM: dts: sun6i: Add SPDIF to the Mele I7
From: Chen-Yu Tsai @ 2017-01-07 19:16 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161220104038.22532-4-codekipper@gmail.com>
On Tue, Dec 20, 2016 at 6:40 PM, <codekipper@gmail.com> wrote:
> From: Marcus Cooper <codekipper@gmail.com>
>
> Enable the S/PDIF transmitter that is present on the Mele I7.
>
> Signed-off-by: Marcus Cooper <codekipper@gmail.com>
Acked-by: Chen-Yu Tsai <wens@csie.org>
This patch should be ready to be merged. The associated clk
and dtsi changes are already in Maxime's tree.
> ---
> arch/arm/boot/dts/sun6i-a31-i7.dts | 24 ++++++++++++++++++++++++
> 1 file changed, 24 insertions(+)
>
> diff --git a/arch/arm/boot/dts/sun6i-a31-i7.dts b/arch/arm/boot/dts/sun6i-a31-i7.dts
> index a2193309a199..2bc57d2dcd80 100644
> --- a/arch/arm/boot/dts/sun6i-a31-i7.dts
> +++ b/arch/arm/boot/dts/sun6i-a31-i7.dts
> @@ -69,6 +69,23 @@
> gpios = <&pio 7 13 GPIO_ACTIVE_HIGH>;
> };
> };
> +
> + sound {
> + compatible = "simple-audio-card";
> + simple-audio-card,name = "On-board SPDIF";
> + simple-audio-card,cpu {
> + sound-dai = <&spdif>;
> + };
> +
> + simple-audio-card,codec {
> + sound-dai = <&spdif_out>;
> + };
> + };
> +
> + spdif_out: spdif-out {
> + #sound-dai-cells = <0>;
> + compatible = "linux,spdif-dit";
> + };
> };
>
> &codec {
> @@ -138,6 +155,13 @@
> status = "okay";
> };
>
> +&spdif {
> + pinctrl-names = "default";
> + pinctrl-0 = <&spdif_pins_a>;
> + spdif-out = "okay";
> + status = "okay";
> +};
> +
> &uart0 {
> pinctrl-names = "default";
> pinctrl-0 = <&uart0_pins_a>;
> --
> 2.11.0
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe at googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply
* [PATCH 03/22] iio: adc: add support for X-Powers AXP20X and AXP22X PMICs ADCs
From: Jonathan Cameron @ 2017-01-07 19:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cf4590d1-5381-f1da-7271-e6e7fee0c479@free-electrons.com>
On 05/01/17 04:50, Quentin Schulz wrote:
> On 05/01/2017 09:27, Chen-Yu Tsai wrote:
>> On Thu, Jan 5, 2017 at 4:06 PM, Quentin Schulz
>> <quentin.schulz@free-electrons.com> wrote:
>>> Hi Chen-Yu,
>>>
>>> On 05/01/2017 06:42, Chen-Yu Tsai wrote:
>>>> On Tue, Jan 3, 2017 at 12:37 AM, Quentin Schulz
>>>> <quentin.schulz@free-electrons.com> wrote:
>>> [...]
>>>>> +
>>>>> +#define AXP20X_ADC_RATE_MASK (3 << 6)
>>>>> +#define AXP20X_ADC_RATE_25HZ (0 << 6)
>>>>> +#define AXP20X_ADC_RATE_50HZ BIT(6)
>>>>
>>>> Please be consistent with the format.
>>>>
>>>>> +#define AXP20X_ADC_RATE_100HZ (2 << 6)
>>>>> +#define AXP20X_ADC_RATE_200HZ (3 << 6)
>>>>> +
>>>>> +#define AXP22X_ADC_RATE_100HZ (0 << 6)
>>>>> +#define AXP22X_ADC_RATE_200HZ BIT(6)
>>>>> +#define AXP22X_ADC_RATE_400HZ (2 << 6)
>>>>> +#define AXP22X_ADC_RATE_800HZ (3 << 6)
>>>>
>>>> These are power-of-2 multiples of some base rate. May I suggest
>>>> a formula macro instead. Either way, you seem to be using only
>>>> one value. Will this be made configurable in the future?
>>>>
>>>
>>> Yes, I could use a formula macro instead. No plan to make it
>>> configurable, should I make it configurable?
>>
>> I don't see a use case for that atm.
>>
>>>>> +
>>>>> +#define AXP20X_ADC_CHANNEL(_channel, _name, _type, _reg) \
>>>>> + { \
>>>>> + .type = _type, \
>>>>> + .indexed = 1, \
>>>>> + .channel = _channel, \
>>>>> + .address = _reg, \
>>>>> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
>>>>> + BIT(IIO_CHAN_INFO_SCALE), \
>>>>> + .datasheet_name = _name, \
>>>>> + }
>>>>> +
>>>>> +#define AXP20X_ADC_CHANNEL_OFFSET(_channel, _name, _type, _reg) \
>>>>> + { \
>>>>> + .type = _type, \
>>>>> + .indexed = 1, \
>>>>> + .channel = _channel, \
>>>>> + .address = _reg, \
>>>>> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
>>>>> + BIT(IIO_CHAN_INFO_SCALE) |\
>>>>> + BIT(IIO_CHAN_INFO_OFFSET),\
>>>>> + .datasheet_name = _name, \
>>>>> + }
>>>>> +
>>>>> +struct axp20x_adc_iio {
>>>>> + struct iio_dev *indio_dev;
>>>>> + struct regmap *regmap;
>>>>> +};
>>>>> +
>>>>> +enum axp20x_adc_channel {
>>>>> + AXP20X_ACIN_V = 0,
>>>>> + AXP20X_ACIN_I,
>>>>> + AXP20X_VBUS_V,
>>>>> + AXP20X_VBUS_I,
>>>>> + AXP20X_TEMP_ADC,
>>>>
>>>> PMIC_TEMP would be better. And please save a slot for TS input.
>>>>
>>>
>>> ACK.
>>>
>>> Hum.. I'm wondering what should be the IIO type of the TS input channel
>>> then? The TS Pin can be used in two modes: either to monitor the
>>> temperature of the battery or as an external ADC, at least that's what I
>>> understand from the datasheet.
>>
>> AFAIK the battery charge/discharge high/low temperature threshold
>> registers take values in terms of voltage, not actual temperature.
>> And the temperature readout kind of depends on the thermoresistor
>> one is using. So I think "voltage" would be the proper type.
>>
>
> ACK. Should I just add TS_IN in axp20x_adc_channel enum but not add it
> in the exposed IIO channels ("saving" the slot but not using it)?
Ideally we'd put an IIO consumer driver on the channel that handles the
thermoresistor explicitly. Would need consumer support for events
though to be much use.
>
>>>
>>>>> + AXP20X_GPIO0_V,
>>>>> + AXP20X_GPIO1_V,
>>>>
>>>> Please skip a slot for "battery instantaneous power".
>>>>
>>>>> + AXP20X_BATT_V,
>>>>> + AXP20X_BATT_CHRG_I,
>>>>> + AXP20X_BATT_DISCHRG_I,
>>>>> + AXP20X_IPSOUT_V,
>>>>> +};
>>>>> +
>>>>> +enum axp22x_adc_channel {
>>>>> + AXP22X_TEMP_ADC = 0,
>>>>
>>>> Same comments as AXP20X_TEMP_ADC.
>>>>
>>>>> + AXP22X_BATT_V,
>>>>> + AXP22X_BATT_CHRG_I,
>>>>> + AXP22X_BATT_DISCHRG_I,
>>>>> +};
>>>>
>>>> Shouldn't these channel numbers be exported as part of the device tree
>>>> bindings? At the very least, they shouldn't be changed.
>>>>
>>>
>>> I don't understand what you mean by that. Do you mean you want a
>>> consistent numbering between the AXP20X and the AXP22X, so that
>>> AXP22X_BATT_V would have the same channel number than AXP20X_BATT_V?
>>>
>>> Could you explain a bit more your thoughts on the channel numbers being
>>> exported as part of the device tree bindings?
>>
>> What I meant was that, since you are referencing the channels in the
>> device tree, the numbering scheme would be part of the device tree
>> binding, and should never be changed. So either these would be macros
>> in include/dt-bindings/, or a big warning should be put before it.
>>
>
> ACK.
>
>> But see my reply on patch 7, about do we actually need to expose this
>> in the device tree.
>>
>
> I don't know what's the best.
>
>>>> Also please add a comment saying that the channels are numbered
>>>> in the order of their respective registers, and not the table
>>>> describing the ADCs in the datasheet (9.7 Signal Capture for AXP209
>>>> and 9.5 E-Gauge for AXP221).
>>>>
>>>
>>> Yes I can.
>>>
>>> What about Rob wanting channel numbers to start at zero for each
>>> different IIO type (i.e., today we have AXP22X_BATT_CHRG_I being
>>> exported as in_current1_raw whereas he wants in_current0_raw).
>>
>> Hmm... I missed this. Are you talking about IIO or hwmon? IIRC
>> hwmon numbers things starting at 1.
>>
>
> About IIO.
>
> Today, we have exposed:
> in_voltage0_raw for acin_v
> in_current1_raw for acin_i
> in_voltage2_raw for vbus_v
> in_current3_raw for vbus_i
> in_temp4_raw for adc_temp
> in_voltage5_raw for gpio0_v
> in_voltage6_raw for gpio1_v
> in_voltage7_raw for batt_v
> in_current8_raw for batt_chrg_i
> in_current9_raw for batt_dischrg_i
> in_voltage10_raw for ipsout_v
>
> but I think what Rob wants is:
>
> in_voltage0_raw acin_v
> in_current0_raw for acin_i
> in_voltage1_raw for vbus_v
> in_current1_raw for vbus_i
> in_temp_raw for adc_temp
> in_voltage2_raw for gpio0_v
> in_voltage3_raw for gpio1_v
> in_voltage4_raw for batt_v
> in_current2_raw for batt_chrg_i
> in_current3_raw for batt_dischrg_i
> in_voltage5_raw for ipsout_v
That would be standard choice. It's not disastrous to skip numbers but
it tends to not be what userspace expects.
>
>>> [...]
>>>>> +static int axp22x_adc_read_raw(struct iio_dev *indio_dev,
>>>>> + struct iio_chan_spec const *channel, int *val,
>>>>> + int *val2)
>>>>> +{
>>>>> + struct axp20x_adc_iio *info = iio_priv(indio_dev);
>>>>> + int size = 12, ret;
>>>>> +
>>>>> + switch (channel->channel) {
>>>>> + case AXP22X_BATT_DISCHRG_I:
>>>>> + size = 13;
>>>>> + case AXP22X_TEMP_ADC:
>>>>> + case AXP22X_BATT_V:
>>>>> + case AXP22X_BATT_CHRG_I:
>>>>
>>>> According to the datasheet, AXP22X_BATT_CHRG_I is also 13 bits wide.
>>>>
>>>
>>> Where did you get that?
>>>
>>> Also, the datasheet is inconsistent:
>>> - 9.5 E-Gauge Fuel Gauge system => the min value is at 0x0 and the max
>>> value at 0xfff for all channels, that's 12 bits.
>>> - 10.1.4 ADC Data => all channels except battery discharge current are
>>> on 12 bits (8 high, 4 low).
>>
>> My datasheets (AXP221 v1.6, AXP221s v1.2, AXP223 v1.1, all Chinese) say
>> in 10.1.4:
>>
>> - 7A: battery charge current high 5 bits
>> - 7B: battery charge current low 8 bits
>> - 7C: battery discharge current high 5 bits
>> - 7D: battery discharge current low 8 bits
>>
>
> AXP223 v1.1 in English in 10.1.4[1]:
> - 7A: battery charge current high 8 bits
> - 7B: battery charge current low 4 bits
> - 7C: battery discharge current high 8 bits
> - 7D: battery discharge current low 5 bits
>
> Note that it's 8 bits for high and 4/5 bits for low while you wrote 4/5
> bits high and low 8 bits (typos or actually what's written in the
> datasheet?).
>
> Hum.. from the reg reading function[2] I would say that the correct
> formula is high on 8 bits and low on 4/5 bits.
>
> So hum.. what do we do?
>
> [1] http://dl.linux-sunxi.org/AXP/AXP223-en.pdf
> [2] http://lxr.free-electrons.com/source/include/linux/mfd/axp20x.h#L564
>
>>>
>>> [...]
>>>>> +static int axp22x_read_raw(struct iio_dev *indio_dev,
>>>>> + struct iio_chan_spec const *chan, int *val,
>>>>> + int *val2, long mask)
>>>>> +{
>>>>> + switch (mask) {
>>>>> + case IIO_CHAN_INFO_OFFSET:
>>>>> + *val = -2667;
>>>>
>>>> Datasheet says -267.7 C, or -2677 here.
>>>>
>>>
>>> The formula in the datasheet is (in milli Celsius):
>>> processed = raw * 100 - 266700;
>>>
>>> while the IIO framework asks for a scale and an offset which are then
>>> applied as:
>>> processed = (raw + offset) * scale;
>>>
>>> Thus by factorizing, we get:
>>> processed = (raw - 2667) * 100;
>>
>> What I meant was that your lower end value is off by one degree,
>> -266.7 in your code vs -267.7 in the datasheet.
>>
>
> Indeed. Thanks.
>
>>>
>>> [...]
>>>>> +static int axp20x_remove(struct platform_device *pdev)
>>>>> +{
>>>>> + struct axp20x_adc_iio *info;
>>>>> + struct iio_dev *indio_dev = platform_get_drvdata(pdev);
>>>>> +
>>>>> + info = iio_priv(indio_dev);
>>>>
>>>> Nit: you could just reverse the 2 declarations above and join this
>>>> line after struct axp20x_adc_iio *info;
>>>>
>>>>> + regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
>>>>> + regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
>>>>
>>>> The existing VBUS power supply driver enables the VBUS ADC bits itself,
>>>> and does not check them later on. This means if one were to remove this
>>>> axp20x-adc module, the voltage/current readings in the VBUS power supply
>>>> would be invalid. Some sort of workaround would be needed here in this
>>>> driver of the VBUS driver.
>>>>
>>>
>>> That would be one reason to migrate the VBUS driver to use the IIO
>>> channels, wouldn't it?
>>
>> It is, preferably without changing the device tree.
>>
>
> Yes, of course.
>
> Thanks,
> Quentin
>
^ permalink raw reply
* [PATCH 03/22] iio: adc: add support for X-Powers AXP20X and AXP22X PMICs ADCs
From: Jonathan Cameron @ 2017-01-07 19:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGb2v654a898jhPL+CJ0K4acTENq+sRo+ZJ4EG1zHqu73o=CGA@mail.gmail.com>
On 05/01/17 05:28, Chen-Yu Tsai wrote:
> On Thu, Jan 5, 2017 at 5:50 PM, Quentin Schulz
> <quentin.schulz@free-electrons.com> wrote:
>> On 05/01/2017 09:27, Chen-Yu Tsai wrote:
>>> On Thu, Jan 5, 2017 at 4:06 PM, Quentin Schulz
>>> <quentin.schulz@free-electrons.com> wrote:
>>>> Hi Chen-Yu,
>>>>
>>>> On 05/01/2017 06:42, Chen-Yu Tsai wrote:
>>>>> On Tue, Jan 3, 2017 at 12:37 AM, Quentin Schulz
>>>>> <quentin.schulz@free-electrons.com> wrote:
>>>> [...]
>>>>>> +
>>>>>> +#define AXP20X_ADC_RATE_MASK (3 << 6)
>>>>>> +#define AXP20X_ADC_RATE_25HZ (0 << 6)
>>>>>> +#define AXP20X_ADC_RATE_50HZ BIT(6)
>>>>>
>>>>> Please be consistent with the format.
>>>>>
>>>>>> +#define AXP20X_ADC_RATE_100HZ (2 << 6)
>>>>>> +#define AXP20X_ADC_RATE_200HZ (3 << 6)
>>>>>> +
>>>>>> +#define AXP22X_ADC_RATE_100HZ (0 << 6)
>>>>>> +#define AXP22X_ADC_RATE_200HZ BIT(6)
>>>>>> +#define AXP22X_ADC_RATE_400HZ (2 << 6)
>>>>>> +#define AXP22X_ADC_RATE_800HZ (3 << 6)
>>>>>
>>>>> These are power-of-2 multiples of some base rate. May I suggest
>>>>> a formula macro instead. Either way, you seem to be using only
>>>>> one value. Will this be made configurable in the future?
>>>>>
>>>>
>>>> Yes, I could use a formula macro instead. No plan to make it
>>>> configurable, should I make it configurable?
>>>
>>> I don't see a use case for that atm.
>>>
>>>>>> +
>>>>>> +#define AXP20X_ADC_CHANNEL(_channel, _name, _type, _reg) \
>>>>>> + { \
>>>>>> + .type = _type, \
>>>>>> + .indexed = 1, \
>>>>>> + .channel = _channel, \
>>>>>> + .address = _reg, \
>>>>>> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
>>>>>> + BIT(IIO_CHAN_INFO_SCALE), \
>>>>>> + .datasheet_name = _name, \
>>>>>> + }
>>>>>> +
>>>>>> +#define AXP20X_ADC_CHANNEL_OFFSET(_channel, _name, _type, _reg) \
>>>>>> + { \
>>>>>> + .type = _type, \
>>>>>> + .indexed = 1, \
>>>>>> + .channel = _channel, \
>>>>>> + .address = _reg, \
>>>>>> + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
>>>>>> + BIT(IIO_CHAN_INFO_SCALE) |\
>>>>>> + BIT(IIO_CHAN_INFO_OFFSET),\
>>>>>> + .datasheet_name = _name, \
>>>>>> + }
>>>>>> +
>>>>>> +struct axp20x_adc_iio {
>>>>>> + struct iio_dev *indio_dev;
>>>>>> + struct regmap *regmap;
>>>>>> +};
>>>>>> +
>>>>>> +enum axp20x_adc_channel {
>>>>>> + AXP20X_ACIN_V = 0,
>>>>>> + AXP20X_ACIN_I,
>>>>>> + AXP20X_VBUS_V,
>>>>>> + AXP20X_VBUS_I,
>>>>>> + AXP20X_TEMP_ADC,
>>>>>
>>>>> PMIC_TEMP would be better. And please save a slot for TS input.
>>>>>
>>>>
>>>> ACK.
>>>>
>>>> Hum.. I'm wondering what should be the IIO type of the TS input channel
>>>> then? The TS Pin can be used in two modes: either to monitor the
>>>> temperature of the battery or as an external ADC, at least that's what I
>>>> understand from the datasheet.
>>>
>>> AFAIK the battery charge/discharge high/low temperature threshold
>>> registers take values in terms of voltage, not actual temperature.
>>> And the temperature readout kind of depends on the thermoresistor
>>> one is using. So I think "voltage" would be the proper type.
>>>
>>
>> ACK. Should I just add TS_IN in axp20x_adc_channel enum but not add it
>> in the exposed IIO channels ("saving" the slot but not using it)?
>
> Sure. Or you could skip the number with
>
> AXP20X_GPIO0_V = 6,
>
>>>>
>>>>>> + AXP20X_GPIO0_V,
>>>>>> + AXP20X_GPIO1_V,
>>>>>
>>>>> Please skip a slot for "battery instantaneous power".
>>>>>
>>>>>> + AXP20X_BATT_V,
>>>>>> + AXP20X_BATT_CHRG_I,
>>>>>> + AXP20X_BATT_DISCHRG_I,
>>>>>> + AXP20X_IPSOUT_V,
>>>>>> +};
>>>>>> +
>>>>>> +enum axp22x_adc_channel {
>>>>>> + AXP22X_TEMP_ADC = 0,
>>>>>
>>>>> Same comments as AXP20X_TEMP_ADC.
>>>>>
>>>>>> + AXP22X_BATT_V,
>>>>>> + AXP22X_BATT_CHRG_I,
>>>>>> + AXP22X_BATT_DISCHRG_I,
>>>>>> +};
>>>>>
>>>>> Shouldn't these channel numbers be exported as part of the device tree
>>>>> bindings? At the very least, they shouldn't be changed.
>>>>>
>>>>
>>>> I don't understand what you mean by that. Do you mean you want a
>>>> consistent numbering between the AXP20X and the AXP22X, so that
>>>> AXP22X_BATT_V would have the same channel number than AXP20X_BATT_V?
>>>>
>>>> Could you explain a bit more your thoughts on the channel numbers being
>>>> exported as part of the device tree bindings?
>>>
>>> What I meant was that, since you are referencing the channels in the
>>> device tree, the numbering scheme would be part of the device tree
>>> binding, and should never be changed. So either these would be macros
>>> in include/dt-bindings/, or a big warning should be put before it.
>>>
>>
>> ACK.
>>
>>> But see my reply on patch 7, about do we actually need to expose this
>>> in the device tree.
>>>
>>
>> I don't know what's the best.
>
> Then let's not expose it in the device tree for now. It's easier to
> add it later than to remove it.
>
>>
>>>>> Also please add a comment saying that the channels are numbered
>>>>> in the order of their respective registers, and not the table
>>>>> describing the ADCs in the datasheet (9.7 Signal Capture for AXP209
>>>>> and 9.5 E-Gauge for AXP221).
>>>>>
>>>>
>>>> Yes I can.
>>>>
>>>> What about Rob wanting channel numbers to start at zero for each
>>>> different IIO type (i.e., today we have AXP22X_BATT_CHRG_I being
>>>> exported as in_current1_raw whereas he wants in_current0_raw).
>>>
>>> Hmm... I missed this. Are you talking about IIO or hwmon? IIRC
>>> hwmon numbers things starting at 1.
>>>
>>
>> About IIO.
>>
>> Today, we have exposed:
>> in_voltage0_raw for acin_v
>> in_current1_raw for acin_i
>> in_voltage2_raw for vbus_v
>> in_current3_raw for vbus_i
>> in_temp4_raw for adc_temp
>> in_voltage5_raw for gpio0_v
>> in_voltage6_raw for gpio1_v
>> in_voltage7_raw for batt_v
>> in_current8_raw for batt_chrg_i
>> in_current9_raw for batt_dischrg_i
>> in_voltage10_raw for ipsout_v
>>
>> but I think what Rob wants is:
>>
>> in_voltage0_raw acin_v
>> in_current0_raw for acin_i
>> in_voltage1_raw for vbus_v
>> in_current1_raw for vbus_i
>> in_temp_raw for adc_temp
>> in_voltage2_raw for gpio0_v
>> in_voltage3_raw for gpio1_v
>> in_voltage4_raw for batt_v
>> in_current2_raw for batt_chrg_i
>> in_current3_raw for batt_dischrg_i
>> in_voltage5_raw for ipsout_v
>
> I think that's doable. If I understand IIO code correctly, the channel
> number is not used anywhere in the core code for dereferencing. It's
> used for sysfs entries (when .indexed is set) and events. However
> the twl4030 and twl6030 drivers use our current exposed scheme.
> I suppose its best to get some input from the IIO maintainer.
If we are doing it to superficially group channels that are measuring
different things about the same physical system then I'm fine with
mappings with holes in them.
It's not actually specified anywhere that we can't allow this and
IIRC there are a few drivers doing exactly this.
>
> So if we want, we could have the following channel mapping:
>
> 0 -> acin
> 1 -> vbus
> 2 -> pmic
> 3 -> gpio0
> 4 -> gpio1
> 5 -> ipsout
> 6 -> battery
>
> Each channel could have mulitple entries in axp20x_adc_channels[],
> one for each type of reading. You might need multiple channels for
> the battery to cover charge and discharge currents.
>
> Your callback functions would get a bit messier though.
>
>>
>>>> [...]
>>>>>> +static int axp22x_adc_read_raw(struct iio_dev *indio_dev,
>>>>>> + struct iio_chan_spec const *channel, int *val,
>>>>>> + int *val2)
>>>>>> +{
>>>>>> + struct axp20x_adc_iio *info = iio_priv(indio_dev);
>>>>>> + int size = 12, ret;
>>>>>> +
>>>>>> + switch (channel->channel) {
>>>>>> + case AXP22X_BATT_DISCHRG_I:
>>>>>> + size = 13;
>>>>>> + case AXP22X_TEMP_ADC:
>>>>>> + case AXP22X_BATT_V:
>>>>>> + case AXP22X_BATT_CHRG_I:
>>>>>
>>>>> According to the datasheet, AXP22X_BATT_CHRG_I is also 13 bits wide.
>>>>>
>>>>
>>>> Where did you get that?
>>>>
>>>> Also, the datasheet is inconsistent:
>>>> - 9.5 E-Gauge Fuel Gauge system => the min value is at 0x0 and the max
>>>> value at 0xfff for all channels, that's 12 bits.
>>>> - 10.1.4 ADC Data => all channels except battery discharge current are
>>>> on 12 bits (8 high, 4 low).
>>>
>>> My datasheets (AXP221 v1.6, AXP221s v1.2, AXP223 v1.1, all Chinese) say
>>> in 10.1.4:
>>>
>>> - 7A: battery charge current high 5 bits
>>> - 7B: battery charge current low 8 bits
>>> - 7C: battery discharge current high 5 bits
>>> - 7D: battery discharge current low 8 bits
>>>
>>
>> AXP223 v1.1 in English in 10.1.4[1]:
>> - 7A: battery charge current high 8 bits
>> - 7B: battery charge current low 4 bits
>> - 7C: battery discharge current high 8 bits
>> - 7D: battery discharge current low 5 bits
>>
>> Note that it's 8 bits for high and 4/5 bits for low while you wrote 4/5
>> bits high and low 8 bits (typos or actually what's written in the
>> datasheet?).
>
> Typo on my end, sorry. It's high 8bits and low 5/4 bits.
>
> Apart from that, the Chinese and English versions don't match for the
> battery charge current. :(
>
> Would it be possible for you to test this? As in, have the module running,
> and charging a battery, and have a multimeter in series with the battery
> to verify the readings.
>
> Regards
> ChenYu
>
>>
>> Hum.. from the reg reading function[2] I would say that the correct
>> formula is high on 8 bits and low on 4/5 bits.
>>
>> So hum.. what do we do?
>>
>> [1] http://dl.linux-sunxi.org/AXP/AXP223-en.pdf
>> [2] http://lxr.free-electrons.com/source/include/linux/mfd/axp20x.h#L564
>>
>>>>
>>>> [...]
>>>>>> +static int axp22x_read_raw(struct iio_dev *indio_dev,
>>>>>> + struct iio_chan_spec const *chan, int *val,
>>>>>> + int *val2, long mask)
>>>>>> +{
>>>>>> + switch (mask) {
>>>>>> + case IIO_CHAN_INFO_OFFSET:
>>>>>> + *val = -2667;
>>>>>
>>>>> Datasheet says -267.7 C, or -2677 here.
>>>>>
>>>>
>>>> The formula in the datasheet is (in milli Celsius):
>>>> processed = raw * 100 - 266700;
>>>>
>>>> while the IIO framework asks for a scale and an offset which are then
>>>> applied as:
>>>> processed = (raw + offset) * scale;
>>>>
>>>> Thus by factorizing, we get:
>>>> processed = (raw - 2667) * 100;
>>>
>>> What I meant was that your lower end value is off by one degree,
>>> -266.7 in your code vs -267.7 in the datasheet.
>>>
>>
>> Indeed. Thanks.
>>
>>>>
>>>> [...]
>>>>>> +static int axp20x_remove(struct platform_device *pdev)
>>>>>> +{
>>>>>> + struct axp20x_adc_iio *info;
>>>>>> + struct iio_dev *indio_dev = platform_get_drvdata(pdev);
>>>>>> +
>>>>>> + info = iio_priv(indio_dev);
>>>>>
>>>>> Nit: you could just reverse the 2 declarations above and join this
>>>>> line after struct axp20x_adc_iio *info;
>>>>>
>>>>>> + regmap_write(info->regmap, AXP20X_ADC_EN1, 0);
>>>>>> + regmap_write(info->regmap, AXP20X_ADC_EN2, 0);
>>>>>
>>>>> The existing VBUS power supply driver enables the VBUS ADC bits itself,
>>>>> and does not check them later on. This means if one were to remove this
>>>>> axp20x-adc module, the voltage/current readings in the VBUS power supply
>>>>> would be invalid. Some sort of workaround would be needed here in this
>>>>> driver of the VBUS driver.
>>>>>
>>>>
>>>> That would be one reason to migrate the VBUS driver to use the IIO
>>>> channels, wouldn't it?
>>>
>>> It is, preferably without changing the device tree.
>>>
>>
>> Yes, of course.
>>
>> Thanks,
>> Quentin
>>
>> --
>> Quentin Schulz, Free Electrons
>> Embedded Linux and Kernel engineering
>> http://free-electrons.com
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* [PATCH 07/22] dt-bindings: power: supply: add AXP20X/AXP22X AC power supply
From: Jonathan Cameron @ 2017-01-07 19:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAGb2v67V6oGEyYGsBWfp3rVVm_VWQta0szeBiNSKUQR7awm5ng@mail.gmail.com>
On 05/01/17 01:17, Chen-Yu Tsai wrote:
> Hi Quentin,
>
> On Wed, Jan 4, 2017 at 9:14 PM, Rob Herring <robh@kernel.org> wrote:
>> On Mon, Jan 02, 2017 at 05:37:07PM +0100, Quentin Schulz wrote:
>>> The X-Powers AXP20X and AXP22X PMICs have an AC entry to supply power to
>>> the board. They have a few registers dedicated to the status of the AC
>>> power supply.
>>>
>>> This adds the DT binding documentation for the AC power supply for
>>> AXP20X and AXP22X PMICs.
>>>
>>> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
>>> ---
>>> .../bindings/power/supply/axp20x_ac_power.txt | 28 ++++++++++++++++++++++
>>> 1 file changed, 28 insertions(+)
>>> create mode 100644 Documentation/devicetree/bindings/power/supply/axp20x_ac_power.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/power/supply/axp20x_ac_power.txt b/Documentation/devicetree/bindings/power/supply/axp20x_ac_power.txt
>>> new file mode 100644
>>> index 0000000..16d0de4
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/power/supply/axp20x_ac_power.txt
>>> @@ -0,0 +1,28 @@
>>> +AXP20X and AXP22X PMICs' AC power supply
>>> +
>>> +Required Properties:
>>> + - compatible: One of:
>>> + "x-powers,axp202-ac-power-supply"
>>> + "x-powers,axp221-ac-power-supply"
>>> +
>>> +More Required Properties for AXP20X PMICs:
>>> + - io-channels: phandles to ACIN voltage and current ADC channels
>>> + - io-channel-names = "acin_v", "acin_i";
>>> +
>>> +This node is a subnode of the axp20x PMIC.
>>> +
>>> +The AXP20X can read the current current and voltage supplied by AC by
>>> +reading ADC channels from the AXP20X ADC.
>>> +
>>> +The AXP22X is only able to tell if an AC power supply is present and
>>> +usable.
>>> +
>>> +Example:
>>> +
>>> +&axp209 {
>>> + ac_power_supply: ac_power_supply {
>>
>> power-supply {
>>
>>> + compatible = "x-powers,axp202-ac-power-supply";
>>> + io-channels = <&axp209_adc 0>, <&axp209_adc 1>;
>>
>> Is this assignment fixed? If so, then it doesn't need to be in DT.
>
> Is there any case that we actually need to use the IIO channels
> from the device tree? Seems to me its limited to the other AXP
> sub-devices.
>
> If so you could use struct iio_map to map the channels to other
> devices by name. See axp288_adc for an example.
Agreed. When we are within a device (so it's not flexible) that
is the way to go.
>
> Regards
> ChenYu
>
>>> + io-channel-names = "acin_v", "acin_i";
>>> + };
>>> +};
>>> --
>>> 2.9.3
>>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* [PATCH 08/22] power: supply: add AC power supply driver for AXP20X and AXP22X PMICs
From: Jonathan Cameron @ 2017-01-07 19:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170102163723.7939-9-quentin.schulz@free-electrons.com>
On 02/01/17 11:37, Quentin Schulz wrote:
> The X-Powers AXP20X and AXP22X PMICs expose the status of AC power
> supply.
>
> Moreover, the AXP20X can also expose the current current and voltage
> values of the AC power supply.
>
> This adds the driver which exposes the status of the AC power supply of
> the AXP20X and AXP22X PMICs.
>
> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
For the IIO bits
Acked-by: Jonathan Cameron <jic23@kernel.org>
Trivial comment inline.
> ---
> drivers/power/supply/Kconfig | 12 ++
> drivers/power/supply/Makefile | 1 +
> drivers/power/supply/axp20x_ac_power.c | 251 +++++++++++++++++++++++++++++++++
> 3 files changed, 264 insertions(+)
> create mode 100644 drivers/power/supply/axp20x_ac_power.c
>
> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
> index 76806a0..c552b4b 100644
> --- a/drivers/power/supply/Kconfig
> +++ b/drivers/power/supply/Kconfig
> @@ -214,6 +214,18 @@ config BATTERY_DA9150
> This driver can also be built as a module. If so, the module will be
> called da9150-fg.
>
> +config CHARGER_AXP20X
> + tristate "X-Powers AXP20X and AXP22X AC power supply driver"
> + depends on MFD_AXP20X
> + depends on AXP20X_ADC
> + depends on IIO
> + help
> + Say Y here to enable support for X-Powers AXP20X and AXP22X PMICs' AC
> + power supply.
> +
> + This driver can also be built as a module. If so, the module will be
> + called axp20x_ac_power.
> +
> config AXP288_CHARGER
> tristate "X-Powers AXP288 Charger"
> depends on MFD_AXP20X && EXTCON_AXP288
> diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
> index 36c599d..7d22417 100644
> --- a/drivers/power/supply/Makefile
> +++ b/drivers/power/supply/Makefile
> @@ -18,6 +18,7 @@ obj-$(CONFIG_TEST_POWER) += test_power.o
>
> obj-$(CONFIG_BATTERY_88PM860X) += 88pm860x_battery.o
> obj-$(CONFIG_BATTERY_ACT8945A) += act8945a_charger.o
> +obj-$(CONFIG_CHARGER_AXP20X) += axp20x_ac_power.o
> obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
> obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o
> obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o
> diff --git a/drivers/power/supply/axp20x_ac_power.c b/drivers/power/supply/axp20x_ac_power.c
> new file mode 100644
> index 0000000..d7bc25c
> --- /dev/null
> +++ b/drivers/power/supply/axp20x_ac_power.c
> @@ -0,0 +1,251 @@
> +/*
> + * AXP20X and AXP22X PMICs' ACIN power supply driver
> + *
> + * Copyright (C) 2016 Free Electrons
> + * Quentin Schulz <quentin.schulz@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.
> + */
> +
> +#include <linux/device.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/axp20x.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/power_supply.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +#include <linux/iio/consumer.h>
> +
> +#define AXP20X_PWR_STATUS_ACIN_PRESENT BIT(7)
> +#define AXP20X_PWR_STATUS_ACIN_AVAIL BIT(6)
> +
> +#define DRVNAME "axp20x-ac-power-supply"
> +
> +struct axp20x_ac_power {
> + struct device_node *np;
> + struct regmap *regmap;
> + struct power_supply *supply;
> + int axp20x_id;
> + struct iio_channel *acin_v;
> + struct iio_channel *acin_i;
> +};
> +
> +static irqreturn_t axp20x_ac_power_irq(int irq, void *devid)
> +{
> + struct axp20x_ac_power *power = devid;
> +
> + power_supply_changed(power->supply);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int axp20x_ac_power_get_property(struct power_supply *psy,
> + enum power_supply_property psp,
> + union power_supply_propval *val)
> +{
> + struct axp20x_ac_power *power = power_supply_get_drvdata(psy);
> + int ret, reg;
> +
> + switch (psp) {
> + case POWER_SUPPLY_PROP_HEALTH:
> + ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, ®);
> + if (ret)
> + return ret;
> +
> + if (reg & AXP20X_PWR_STATUS_ACIN_PRESENT) {
> + val->intval = POWER_SUPPLY_HEALTH_GOOD;
> + return 0;
> + }
> +
> + val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
> + return 0;
> +
> + case POWER_SUPPLY_PROP_PRESENT:
> + ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, ®);
> + if (ret)
> + return ret;
> +
> + val->intval = !!(reg & AXP20X_PWR_STATUS_ACIN_PRESENT);
> + return 0;
> +
> + case POWER_SUPPLY_PROP_ONLINE:
> + ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, ®);
> + if (ret)
> + return ret;
> +
> + val->intval = !!(reg & AXP20X_PWR_STATUS_ACIN_AVAIL);
> + return 0;
> +
> + case POWER_SUPPLY_PROP_VOLTAGE_NOW:
> + ret = iio_read_channel_processed(power->acin_v, &val->intval);
> + if (ret)
> + return ret;
> +
> + /*
> + * IIO framework gives mV but Power Supply framework gives ?V.
> + */
single line comment syntax throughout or we'll have to face a patch 'fixing' it.
> + val->intval *= 1000;
> +
> + return 0;
> +
> + case POWER_SUPPLY_PROP_CURRENT_NOW:
> + ret = iio_read_channel_processed(power->acin_i, &val->intval);
> + if (ret)
> + return ret;
> +
> + /*
> + * IIO framework gives mV but Power Supply framework gives ?V.
> + */
> + val->intval *= 1000;
> +
> + return 0;
> +
> + default:
> + return -EINVAL;
> + }
> +
> + return -EINVAL;
> +}
> +
> +static enum power_supply_property axp20x_ac_power_properties[] = {
> + POWER_SUPPLY_PROP_HEALTH,
> + POWER_SUPPLY_PROP_PRESENT,
> + POWER_SUPPLY_PROP_ONLINE,
> + POWER_SUPPLY_PROP_VOLTAGE_NOW,
> + POWER_SUPPLY_PROP_CURRENT_NOW,
> +};
> +
> +static enum power_supply_property axp22x_ac_power_properties[] = {
> + POWER_SUPPLY_PROP_HEALTH,
> + POWER_SUPPLY_PROP_PRESENT,
> + POWER_SUPPLY_PROP_ONLINE,
> +};
> +
> +static const struct power_supply_desc axp20x_ac_power_desc = {
> + .name = "axp20x-ac",
> + .type = POWER_SUPPLY_TYPE_MAINS,
> + .properties = axp20x_ac_power_properties,
> + .num_properties = ARRAY_SIZE(axp20x_ac_power_properties),
> + .get_property = axp20x_ac_power_get_property,
> +};
> +
> +static const struct power_supply_desc axp22x_ac_power_desc = {
> + .name = "axp22x-ac",
> + .type = POWER_SUPPLY_TYPE_MAINS,
> + .properties = axp22x_ac_power_properties,
> + .num_properties = ARRAY_SIZE(axp22x_ac_power_properties),
> + .get_property = axp20x_ac_power_get_property,
> +};
> +
> +static int axp20x_ac_power_probe(struct platform_device *pdev)
> +{
> + struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
> + struct power_supply_config psy_cfg = {};
> + struct axp20x_ac_power *power;
> + static const char * const axp20x_irq_names[] = { "ACIN_PLUGIN",
> + "ACIN_REMOVAL", NULL };
> + static const char * const *irq_names;
> + const struct power_supply_desc *ac_power_desc;
> + int i, irq, ret;
> +
> + if (!of_device_is_available(pdev->dev.of_node))
> + return -ENODEV;
> +
> + if (!axp20x) {
> + dev_err(&pdev->dev, "Parent drvdata not set\n");
> + return -EINVAL;
> + }
> +
> + power = devm_kzalloc(&pdev->dev, sizeof(*power), GFP_KERNEL);
> + if (!power)
> + return -ENOMEM;
> +
> + power->axp20x_id = (int)of_device_get_match_data(&pdev->dev);
> +
> + irq_names = axp20x_irq_names;
> +
> + if (power->axp20x_id == AXP202_ID) {
> + ac_power_desc = &axp20x_ac_power_desc;
> +
> + power->acin_v = devm_iio_channel_get(&pdev->dev, "acin_v");
> + if (IS_ERR(power->acin_v)) {
> + if (PTR_ERR(power->acin_v) == -ENODEV)
> + return -EPROBE_DEFER;
> + return PTR_ERR(power->acin_v);
> + }
> +
> + power->acin_i = devm_iio_channel_get(&pdev->dev, "acin_i");
> + if (IS_ERR(power->acin_i)) {
> + if (PTR_ERR(power->acin_i) == -ENODEV)
> + return -EPROBE_DEFER;
> + return PTR_ERR(power->acin_i);
> + }
> + } else {
> + ac_power_desc = &axp22x_ac_power_desc;
> + }
> +
> + power->np = pdev->dev.of_node;
> + power->regmap = axp20x->regmap;
> +
> + platform_set_drvdata(pdev, power);
> +
> + psy_cfg.of_node = pdev->dev.of_node;
> + psy_cfg.drv_data = power;
> +
> + power->supply = devm_power_supply_register(&pdev->dev, ac_power_desc,
> + &psy_cfg);
> + if (IS_ERR(power->supply))
> + return PTR_ERR(power->supply);
> +
> + /* Request irqs after registering, as irqs may trigger immediately */
> + for (i = 0; irq_names[i]; i++) {
> + irq = platform_get_irq_byname(pdev, irq_names[i]);
> + if (irq < 0) {
> + dev_warn(&pdev->dev, "No IRQ for %s: %d\n",
> + irq_names[i], irq);
> + continue;
> + }
> + irq = regmap_irq_get_virq(axp20x->regmap_irqc, irq);
> + ret = devm_request_any_context_irq(&pdev->dev, irq,
> + axp20x_ac_power_irq, 0,
> + DRVNAME, power);
> + if (ret < 0)
> + dev_warn(&pdev->dev, "Error requesting %s IRQ: %d\n",
> + irq_names[i], ret);
> + }
> +
> + return 0;
> +}
> +
> +static const struct of_device_id axp20x_ac_power_match[] = {
> + {
> + .compatible = "x-powers,axp202-ac-power-supply",
> + .data = (void *)AXP202_ID,
> + }, {
> + .compatible = "x-powers,axp221-ac-power-supply",
> + .data = (void *)AXP221_ID,
> + }, { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, axp20x_ac_power_match);
> +
> +static struct platform_driver axp20x_ac_power_driver = {
> + .probe = axp20x_ac_power_probe,
> + .driver = {
> + .name = DRVNAME,
> + .of_match_table = axp20x_ac_power_match,
> + },
> +};
> +
> +module_platform_driver(axp20x_ac_power_driver);
> +
> +MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
> +MODULE_DESCRIPTION("AXP20X and AXP22X PMICs' AC power supply driver");
> +MODULE_LICENSE("GPL");
>
^ permalink raw reply
* [PATCH 14/22] dt-bindings: power: supply: add AXP20X/AXP22X battery DT binding
From: Jonathan Cameron @ 2017-01-07 19:33 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170104132107.tciklylgqvhftb6f@rob-hp-laptop>
On 04/01/17 08:21, Rob Herring wrote:
> On Mon, Jan 02, 2017 at 05:37:14PM +0100, Quentin Schulz wrote:
>> The X-Powers AXP20X and AXP22X PMICs can have a battery as power supply.
>>
>> This patch adds the DT binding documentation for the battery power
>> supply which gets various data from the PMIC, such as the battery status
>> (charging, discharging, full, dead), current max limit, current current,
>> battery capacity (in percentage), voltage max and min limits, current
>> voltage and battery capacity (in Ah).
>>
>> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
>> ---
>> .../bindings/power/supply/axp20x_battery.txt | 27 ++++++++++++++++++++++
>> 1 file changed, 27 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/power/supply/axp20x_battery.txt
>>
>> diff --git a/Documentation/devicetree/bindings/power/supply/axp20x_battery.txt b/Documentation/devicetree/bindings/power/supply/axp20x_battery.txt
>> new file mode 100644
>> index 0000000..5489d0d
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/power/supply/axp20x_battery.txt
>> @@ -0,0 +1,27 @@
>> +AXP20x and AXP22x battery power supply
>> +
>> +Required Properties:
>> + - compatible, one of:
>> + "x-powers,axp209-battery-power-supply"
>> + "x-powers,axp221-battery-power-supply"
>> + - io-channels: phandles to battery voltage, charge and discharge
>> + currents ADC channels
>> + - io-channel-names = "batt_v", "batt_chrg_i", "batt_dischrg_i";
>> +
>> +This node is a subnode of the axp20x/axp22x PMIC.
>> +
>> +The AXP20X and AXP22X can read the battery voltage, charge and discharge
>> +currents of the battery by reading ADC channels from the AXP20X/AXP22X
>> +ADC.
>> +
>> +Example:
>> +
>> +&axp209 {
>> + battery_power_supply: battery_power_supply {
>
> Humm, I guess you power-supply is not sufficient, so
> 'battery-power-supply' and similar for ac.
>
>> + compatible = "x-powers,axp209-battery-power-supply";
>> + io-channels = <&axp209_adc 7>, <&axp209_adc 8>,
>> + <&axp209_adc 9>;
>> + io-channel-names = "batt_v", "batt_chrg_i",
>> + "batt_dischrg_i";
Is this stuff fixed for the device?
>> + }
>> +};
>> --
>> 2.9.3
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* [PATCH v5 1/2] ARM: dts: vf610-zii-dev-rev-b: Remove leftover PWM pingroup
From: Andrey Smirnov @ 2017-01-07 20:06 UTC (permalink / raw)
To: linux-arm-kernel
Remove pwm0grp since it is:
a) Not referenced anywhere in the DTS file (unlike Tower board it
is based on, this board does not use/expose FTM0)
b) Configures PTB2 and PTB3 in a way that contradicts
pinctrl-mdio-mux
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Russell King <linux@armlinux.org.uk>
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: Stefan Agner <stefan@agner.ch>
Cc: devicetree at vger.kernel.org
Cc: linux-kernel at vger.kernel.org
Cc: andrew at lunn.ch
Cc: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Cc: cphealy at gmail.com
Tested-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
No changes since v4
arch/arm/boot/dts/vf610-zii-dev-rev-b.dts | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts b/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts
index fa19cfd..2210811 100644
--- a/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts
+++ b/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts
@@ -677,15 +677,6 @@
>;
};
- pinctrl_pwm0: pwm0grp {
- fsl,pins = <
- VF610_PAD_PTB0__FTM0_CH0 0x1582
- VF610_PAD_PTB1__FTM0_CH1 0x1582
- VF610_PAD_PTB2__FTM0_CH2 0x1582
- VF610_PAD_PTB3__FTM0_CH3 0x1582
- >;
- };
-
pinctrl_qspi0: qspi0grp {
fsl,pins = <
VF610_PAD_PTD7__QSPI0_B_QSCK 0x31c3
--
2.9.3
^ permalink raw reply related
* [PATCH v5 2/2] ARM: dts: vf610-zii-dev: Add .dts file for rev. C
From: Andrey Smirnov @ 2017-01-07 20:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170107200654.26056-1-andrew.smirnov@gmail.com>
Add .dts file for rev. C of the board by factoring out commonalities
into a shared include file (vf610-zii-dev-rev-b-c.dtsi) and deriving
revision specific file from it (vf610-zii-dev-rev-b.dts and
vf610-zii-dev-reb-c.dts).
Cc: Shawn Guo <shawnguo@kernel.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Russell King <linux@armlinux.org.uk>
Cc: Sascha Hauer <kernel@pengutronix.de>
Cc: Stefan Agner <stefan@agner.ch>
Cc: devicetree at vger.kernel.org
Cc: linux-kernel at vger.kernel.org
Cc: andrew at lunn.ch
Cc: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
Cc: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
Cc: cphealy at gmail.com
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
Changes since v3:
- Added node for AT86RF233 chip on SPI0
Changes since v4:
- Renamed switch0 at 0 and switch1 at 0 to just switch at 0 (switch ID
is still retained in those nodes' labels)
- Added spacing between children and properties of nodes
arch/arm/boot/dts/Makefile | 3 +-
arch/arm/boot/dts/vf610-zii-dev-rev-b.dts | 315 +----------------------
arch/arm/boot/dts/vf610-zii-dev-rev-c.dts | 414 ++++++++++++++++++++++++++++++
arch/arm/boot/dts/vf610-zii-dev.dtsi | 383 +++++++++++++++++++++++++++
4 files changed, 813 insertions(+), 302 deletions(-)
create mode 100644 arch/arm/boot/dts/vf610-zii-dev-rev-c.dts
create mode 100644 arch/arm/boot/dts/vf610-zii-dev.dtsi
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index befcd26..9f0d2a1 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -442,7 +442,8 @@ dtb-$(CONFIG_SOC_VF610) += \
vf610-cosmic.dtb \
vf610m4-cosmic.dtb \
vf610-twr.dtb \
- vf610-zii-dev-rev-b.dtb
+ vf610-zii-dev-rev-b.dtb \
+ vf610-zii-dev-rev-c.dtb
dtb-$(CONFIG_ARCH_MXS) += \
imx23-evk.dtb \
imx23-olinuxino.dtb \
diff --git a/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts b/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts
index 2210811..a6e9275 100644
--- a/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts
+++ b/arch/arm/boot/dts/vf610-zii-dev-rev-b.dts
@@ -43,32 +43,12 @@
*/
/dts-v1/;
-#include "vf610.dtsi"
+#include "vf610-zii-dev.dtsi"
/ {
model = "ZII VF610 Development Board, Rev B";
compatible = "zii,vf610dev-b", "zii,vf610dev", "fsl,vf610";
- chosen {
- stdout-path = "serial0:115200n8";
- };
-
- memory {
- reg = <0x80000000 0x20000000>;
- };
-
- gpio-leds {
- compatible = "gpio-leds";
- pinctrl-0 = <&pinctrl_leds_debug>;
- pinctrl-names = "default";
-
- debug {
- label = "zii:green:debug1";
- gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>;
- linux,default-trigger = "heartbeat";
- };
- };
-
mdio-mux {
compatible = "mdio-mux-gpio";
pinctrl-0 = <&pinctrl_mdio_mux>;
@@ -86,7 +66,7 @@
#address-cells = <1>;
#size-cells = <0>;
- switch0: switch0 at 0 {
+ switch0: switch at 0 {
compatible = "marvell,mv88e6085";
#address-cells = <1>;
#size-cells = <0>;
@@ -96,6 +76,7 @@
ports {
#address-cells = <1>;
#size-cells = <0>;
+
port at 0 {
reg = <0>;
label = "lan0";
@@ -127,6 +108,7 @@
reg = <6>;
label = "cpu";
ethernet = <&fec1>;
+
fixed-link {
speed = <100>;
full-duplex;
@@ -141,7 +123,7 @@
#address-cells = <1>;
#size-cells = <0>;
- switch1: switch1 at 0 {
+ switch1: switch at 0 {
compatible = "marvell,mv88e6085";
#address-cells = <1>;
#size-cells = <0>;
@@ -151,6 +133,7 @@
ports {
#address-cells = <1>;
#size-cells = <0>;
+
port at 0 {
reg = <0>;
label = "lan3";
@@ -174,6 +157,7 @@
label = "dsa";
link = <&switch2port9>;
phy-mode = "rgmii-txid";
+
fixed-link {
speed = <1000>;
full-duplex;
@@ -194,12 +178,15 @@
mdio {
#address-cells = <1>;
#size-cells = <0>;
+
switch1phy0: switch1phy0 at 0 {
reg = <0>;
};
+
switch1phy1: switch1phy0 at 1 {
reg = <1>;
};
+
switch1phy2: switch1phy0 at 2 {
reg = <2>;
};
@@ -222,6 +209,7 @@
ports {
#address-cells = <1>;
#size-cells = <0>;
+
port at 0 {
reg = <0>;
label = "lan6";
@@ -240,6 +228,7 @@
port at 3 {
reg = <3>;
label = "optical3";
+
fixed-link {
speed = <1000>;
full-duplex;
@@ -251,6 +240,7 @@
port at 4 {
reg = <4>;
label = "optical4";
+
fixed-link {
speed = <1000>;
full-duplex;
@@ -265,6 +255,7 @@
phy-mode = "rgmii-txid";
link = <&switch1port5
&switch0port5>;
+
fixed-link {
speed = <1000>;
full-duplex;
@@ -281,25 +272,6 @@
};
};
- reg_vcc_3v3_mcu: regulator-vcc-3v3-mcu {
- compatible = "regulator-fixed";
- regulator-name = "vcc_3v3_mcu";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- };
-
- usb0_vbus: regulator-usb0-vbus {
- compatible = "regulator-fixed";
- pinctrl-0 = <&pinctrl_usb_vbus>;
- regulator-name = "usb_vbus";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- enable-active-high;
- regulator-always-on;
- regulator-boot-on;
- gpio = <&gpio0 6 0>;
- };
-
spi0 {
compatible = "spi-gpio";
pinctrl-0 = <&pinctrl_gpio_spi0>;
@@ -336,49 +308,6 @@
};
};
-&adc0 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_adc0_ad5>;
- vref-supply = <®_vcc_3v3_mcu>;
- status = "okay";
-};
-
-&edma0 {
- status = "okay";
-};
-
-&esdhc1 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_esdhc1>;
- bus-width = <4>;
- status = "okay";
-};
-
-&fec0 {
- phy-mode = "rmii";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_fec0>;
- status = "okay";
-};
-
-&fec1 {
- phy-mode = "rmii";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_fec1>;
- status = "okay";
-
- fixed-link {
- speed = <100>;
- full-duplex;
- };
-
- mdio1: mdio {
- #address-cells = <1>;
- #size-cells = <0>;
- status = "okay";
- };
-};
-
&i2c0 {
clock-frequency = <100000>;
pinctrl-names = "default";
@@ -403,33 +332,6 @@
interrupt-parent = <&gpio2>;
interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
};
-
- lm75 at 48 {
- compatible = "national,lm75";
- reg = <0x48>;
- };
-
- at24c04 at 50 {
- compatible = "atmel,24c04";
- reg = <0x50>;
- };
-
- at24c04 at 52 {
- compatible = "atmel,24c04";
- reg = <0x52>;
- };
-
- ds1682 at 6b {
- compatible = "dallas,ds1682";
- reg = <0x6b>;
- };
-};
-
-&i2c1 {
- clock-frequency = <100000>;
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c1>;
- status = "okay";
};
&i2c2 {
@@ -499,120 +401,8 @@
};
};
-&uart0 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart0>;
- status = "okay";
-};
-
-&uart1 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart1>;
- status = "okay";
-};
-
-&uart2 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart2>;
- status = "okay";
-};
-
-&usbdev0 {
- disable-over-current;
- vbus-supply = <&usb0_vbus>;
- dr_mode = "host";
- status = "okay";
-};
-
-&usbh1 {
- disable-over-current;
- status = "okay";
-};
-
-&usbmisc0 {
- status = "okay";
-};
-
-&usbmisc1 {
- status = "okay";
-};
-
-&usbphy0 {
- status = "okay";
-};
-
-&usbphy1 {
- status = "okay";
-};
&iomuxc {
- pinctrl_adc0_ad5: adc0ad5grp {
- fsl,pins = <
- VF610_PAD_PTC30__ADC0_SE5 0x00a1
- >;
- };
-
- pinctrl_dspi0: dspi0grp {
- fsl,pins = <
- VF610_PAD_PTB18__DSPI0_CS1 0x1182
- VF610_PAD_PTB19__DSPI0_CS0 0x1182
- VF610_PAD_PTB20__DSPI0_SIN 0x1181
- VF610_PAD_PTB21__DSPI0_SOUT 0x1182
- VF610_PAD_PTB22__DSPI0_SCK 0x1182
- >;
- };
-
- pinctrl_dspi2: dspi2grp {
- fsl,pins = <
- VF610_PAD_PTD31__DSPI2_CS1 0x1182
- VF610_PAD_PTD30__DSPI2_CS0 0x1182
- VF610_PAD_PTD29__DSPI2_SIN 0x1181
- VF610_PAD_PTD28__DSPI2_SOUT 0x1182
- VF610_PAD_PTD27__DSPI2_SCK 0x1182
- >;
- };
-
- pinctrl_esdhc1: esdhc1grp {
- fsl,pins = <
- VF610_PAD_PTA24__ESDHC1_CLK 0x31ef
- VF610_PAD_PTA25__ESDHC1_CMD 0x31ef
- VF610_PAD_PTA26__ESDHC1_DAT0 0x31ef
- VF610_PAD_PTA27__ESDHC1_DAT1 0x31ef
- VF610_PAD_PTA28__ESDHC1_DATA2 0x31ef
- VF610_PAD_PTA29__ESDHC1_DAT3 0x31ef
- VF610_PAD_PTA7__GPIO_134 0x219d
- >;
- };
-
- pinctrl_fec0: fec0grp {
- fsl,pins = <
- VF610_PAD_PTC0__ENET_RMII0_MDC 0x30d2
- VF610_PAD_PTC1__ENET_RMII0_MDIO 0x30d3
- VF610_PAD_PTC2__ENET_RMII0_CRS 0x30d1
- VF610_PAD_PTC3__ENET_RMII0_RXD1 0x30d1
- VF610_PAD_PTC4__ENET_RMII0_RXD0 0x30d1
- VF610_PAD_PTC5__ENET_RMII0_RXER 0x30d1
- VF610_PAD_PTC6__ENET_RMII0_TXD1 0x30d2
- VF610_PAD_PTC7__ENET_RMII0_TXD0 0x30d2
- VF610_PAD_PTC8__ENET_RMII0_TXEN 0x30d2
- >;
- };
-
- pinctrl_fec1: fec1grp {
- fsl,pins = <
- VF610_PAD_PTA6__RMII_CLKIN 0x30d1
- VF610_PAD_PTC9__ENET_RMII1_MDC 0x30d2
- VF610_PAD_PTC10__ENET_RMII1_MDIO 0x30d3
- VF610_PAD_PTC11__ENET_RMII1_CRS 0x30d1
- VF610_PAD_PTC12__ENET_RMII1_RXD1 0x30d1
- VF610_PAD_PTC13__ENET_RMII1_RXD0 0x30d1
- VF610_PAD_PTC14__ENET_RMII1_RXER 0x30d1
- VF610_PAD_PTC15__ENET_RMII1_TXD1 0x30d2
- VF610_PAD_PTC16__ENET_RMII1_TXD0 0x30d2
- VF610_PAD_PTC17__ENET_RMII1_TXEN 0x30d2
- >;
- };
-
pinctrl_gpio_e6185_eeprom_sel: pinctrl-gpio-e6185-eeprom-spi0 {
fsl,pins = <
VF610_PAD_PTE27__GPIO_132 0x33e2
@@ -629,39 +419,6 @@
>;
};
- pinctrl_i2c_mux_reset: pinctrl-i2c-mux-reset {
- fsl,pins = <
- VF610_PAD_PTE14__GPIO_119 0x31c2
- >;
- };
-
- pinctrl_i2c0: i2c0grp {
- fsl,pins = <
- VF610_PAD_PTB14__I2C0_SCL 0x37ff
- VF610_PAD_PTB15__I2C0_SDA 0x37ff
- >;
- };
-
- pinctrl_i2c1: i2c1grp {
- fsl,pins = <
- VF610_PAD_PTB16__I2C1_SCL 0x37ff
- VF610_PAD_PTB17__I2C1_SDA 0x37ff
- >;
- };
-
- pinctrl_i2c2: i2c2grp {
- fsl,pins = <
- VF610_PAD_PTA22__I2C2_SCL 0x37ff
- VF610_PAD_PTA23__I2C2_SDA 0x37ff
- >;
- };
-
- pinctrl_leds_debug: pinctrl-leds-debug {
- fsl,pins = <
- VF610_PAD_PTD20__GPIO_74 0x31c2
- >;
- };
-
pinctrl_mdio_mux: pinctrl-mdio-mux {
fsl,pins = <
VF610_PAD_PTA18__GPIO_8 0x31c2
@@ -676,48 +433,4 @@
VF610_PAD_PTB28__GPIO_98 0x219d
>;
};
-
- pinctrl_qspi0: qspi0grp {
- fsl,pins = <
- VF610_PAD_PTD7__QSPI0_B_QSCK 0x31c3
- VF610_PAD_PTD8__QSPI0_B_CS0 0x31ff
- VF610_PAD_PTD9__QSPI0_B_DATA3 0x31c3
- VF610_PAD_PTD10__QSPI0_B_DATA2 0x31c3
- VF610_PAD_PTD11__QSPI0_B_DATA1 0x31c3
- VF610_PAD_PTD12__QSPI0_B_DATA0 0x31c3
- >;
- };
-
- pinctrl_uart0: uart0grp {
- fsl,pins = <
- VF610_PAD_PTB10__UART0_TX 0x21a2
- VF610_PAD_PTB11__UART0_RX 0x21a1
- >;
- };
-
- pinctrl_uart1: uart1grp {
- fsl,pins = <
- VF610_PAD_PTB23__UART1_TX 0x21a2
- VF610_PAD_PTB24__UART1_RX 0x21a1
- >;
- };
-
- pinctrl_uart2: uart2grp {
- fsl,pins = <
- VF610_PAD_PTD0__UART2_TX 0x21a2
- VF610_PAD_PTD1__UART2_RX 0x21a1
- >;
- };
-
- pinctrl_usb_vbus: pinctrl-usb-vbus {
- fsl,pins = <
- VF610_PAD_PTA16__GPIO_6 0x31c2
- >;
- };
-
- pinctrl_usb0_host: usb0-host-grp {
- fsl,pins = <
- VF610_PAD_PTD6__GPIO_85 0x0062
- >;
- };
};
diff --git a/arch/arm/boot/dts/vf610-zii-dev-rev-c.dts b/arch/arm/boot/dts/vf610-zii-dev-rev-c.dts
new file mode 100644
index 0000000..55c9473
--- /dev/null
+++ b/arch/arm/boot/dts/vf610-zii-dev-rev-c.dts
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2015, 2016 Zodiac Inflight Innovations
+ *
+ * Based on an original 'vf610-twr.dts' which is Copyright 2015,
+ * Freescale Semiconductor, Inc.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file 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.
+ *
+ * This file 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.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "vf610-zii-dev.dtsi"
+
+/ {
+ model = "ZII VF610 Development Board, Rev C";
+ compatible = "zii,vf610dev-c", "zii,vf610dev", "fsl,vf610";
+
+ mdio-mux {
+ compatible = "mdio-mux-gpio";
+ pinctrl-0 = <&pinctrl_mdio_mux>;
+ pinctrl-names = "default";
+ gpios = <&gpio0 8 GPIO_ACTIVE_HIGH
+ &gpio0 9 GPIO_ACTIVE_HIGH
+ &gpio0 25 GPIO_ACTIVE_HIGH>;
+ mdio-parent-bus = <&mdio1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mdio_mux_1: mdio at 1 {
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ switch0: switch at 0 {
+ compatible = "marvell,mv88e6190";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ dsa,member = <0 0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port at 0 {
+ reg = <0>;
+ label = "cpu";
+ ethernet = <&fec1>;
+
+ fixed-link {
+ speed = <100>;
+ full-duplex;
+ };
+ };
+
+ port at 1 {
+ reg = <1>;
+ label = "lan1";
+ };
+
+ port at 2 {
+ reg = <2>;
+ label = "lan2";
+ };
+
+ port at 3 {
+ reg = <3>;
+ label = "lan3";
+ };
+
+ port at 4 {
+ reg = <4>;
+ label = "lan4";
+ };
+
+ switch0port10: port at 10 {
+ reg = <10>;
+ label = "dsa";
+ phy-mode = "xgmii";
+ link = <&switch1port10>;
+ };
+ };
+ };
+ };
+
+ mdio_mux_2: mdio at 2 {
+ reg = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ switch1: switch at 0 {
+ compatible = "marvell,mv88e6190";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ dsa,member = <0 1>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port at 1 {
+ reg = <1>;
+ label = "lan5";
+ };
+
+ port at 2 {
+ reg = <2>;
+ label = "lan6";
+ };
+
+ port at 3 {
+ reg = <3>;
+ label = "lan7";
+ };
+
+ port at 4 {
+ reg = <4>;
+ label = "lan8";
+ };
+
+
+ switch1port10: port at 10 {
+ reg = <10>;
+ label = "dsa";
+ phy-mode = "xgmii";
+ link = <&switch0port10>;
+ };
+ };
+ };
+ };
+
+ mdio_mux_4: mdio at 4 {
+ reg = <4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+};
+
+&dspi0 {
+ bus-num = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_dspi0>;
+ status = "okay";
+ spi-num-chipselects = <2>;
+
+ m25p128 at 0 {
+ compatible = "m25p128", "jedec,spi-nor";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+ };
+
+ atzb-rf-233 at 1 {
+ compatible = "atmel,at86rf233";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctr_atzb_rf_233>;
+
+ spi-max-frequency = <7500000>;
+ reg = <1>;
+ interrupts = <4 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-parent = <&gpio3>;
+ xtal-trim = /bits/ 8 <0x06>;
+
+ sleep-gpio = <&gpio0 24 GPIO_ACTIVE_HIGH>;
+ reset-gpio = <&gpio6 10 GPIO_ACTIVE_HIGH>;
+
+ fsl,spi-cs-sck-delay = <180>;
+ fsl,spi-sck-cs-delay = <250>;
+ };
+};
+
+&i2c0 {
+ /*
+ * U712
+ *
+ * Exposed signals:
+ * P1 - WE2_CMD
+ * P2 - WE2_CLK
+ */
+ gpio5: pca9557 at 18 {
+ compatible = "nxp,pca9557";
+ reg = <0x18>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ /*
+ * U121
+ *
+ * Exposed signals:
+ * I/O0 - ENET_SWR_EN
+ * I/O1 - ESW1_RESETn
+ * I/O2 - ARINC_RESET
+ * I/O3 - DD1_IO_RESET
+ * I/O4 - ESW2_RESETn
+ * I/O5 - ESW3_RESETn
+ * I/O6 - ESW4_RESETn
+ * I/O8 - TP909
+ * I/O9 - FEM_SEL
+ * I/O10 - WIFI_RESETn
+ * I/O11 - PHY_RSTn
+ * I/O12 - OPT1_SD
+ * I/O13 - OPT2_SD
+ * I/O14 - OPT1_TX_DIS
+ * I/O15 - OPT2_TX_DIS
+ */
+ gpio6: sx1503 at 20 {
+ compatible = "semtech,sx1503q";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sx1503_20>;
+ #gpio-cells = <2>;
+ #interrupt-cells = <2>;
+ reg = <0x20>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <23 IRQ_TYPE_EDGE_FALLING>;
+ gpio-controller;
+ interrupt-controller;
+
+ enet_swr_en {
+ gpio-hog;
+ gpios = <0 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "enet-swr-en";
+ };
+ };
+
+ /*
+ * U715
+ *
+ * Exposed signals:
+ * IO0 - WE1_CLK
+ * IO1 - WE1_CMD
+ */
+ gpio7: pca9554 at 22 {
+ compatible = "nxp,pca9554";
+ reg = <0x22>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ };
+};
+
+&i2c1 {
+ at24mac602 at 00 {
+ compatible = "atmel,24c02";
+ reg = <0x50>;
+ read-only;
+ };
+};
+
+&i2c2 {
+ tca9548 at 70 {
+ compatible = "nxp,pca9548";
+ pinctrl-0 = <&pinctrl_i2c_mux_reset>;
+ pinctrl-names = "default";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x70>;
+ reset-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>;
+
+ i2c at 0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+ };
+
+ i2c at 1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ sfp2: at24c04 at 50 {
+ compatible = "atmel,24c02";
+ reg = <0x50>;
+ };
+ };
+
+ i2c at 2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2>;
+
+ sfp3: at24c04 at 50 {
+ compatible = "atmel,24c02";
+ reg = <0x50>;
+ };
+ };
+
+ i2c at 3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <3>;
+ };
+ };
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ status = "okay";
+};
+
+&gpio0 {
+ eth0_intrp {
+ gpio-hog;
+ gpios = <23 GPIO_ACTIVE_HIGH>;
+ input;
+ line-name = "sx1503-irq";
+ };
+};
+
+&gpio3 {
+ eth0_intrp {
+ gpio-hog;
+ gpios = <2 GPIO_ACTIVE_HIGH>;
+ input;
+ line-name = "eth0-intrp";
+ };
+};
+
+&fec0 {
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ ethernet-phy at 0 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fec0_phy_int>;
+
+ interrupt-parent = <&gpio3>;
+ interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+ reg = <0>;
+ };
+ };
+};
+
+&iomuxc {
+ pinctr_atzb_rf_233: pinctrl-atzb-rf-233 {
+ fsl,pins = <
+ VF610_PAD_PTB2__GPIO_24 0x31c2
+ VF610_PAD_PTE27__GPIO_132 0x33e2
+ >;
+ };
+
+
+ pinctrl_sx1503_20: pinctrl-sx1503-20 {
+ fsl,pins = <
+ VF610_PAD_PTB1__GPIO_23 0x219d
+ >;
+ };
+
+ pinctrl_uart3: uart3grp {
+ fsl,pins = <
+ VF610_PAD_PTA20__UART3_TX 0x21a2
+ VF610_PAD_PTA21__UART3_RX 0x21a1
+ >;
+ };
+
+ pinctrl_mdio_mux: pinctrl-mdio-mux {
+ fsl,pins = <
+ VF610_PAD_PTA18__GPIO_8 0x31c2
+ VF610_PAD_PTA19__GPIO_9 0x31c2
+ VF610_PAD_PTB3__GPIO_25 0x31c2
+ >;
+ };
+
+ pinctrl_fec0_phy_int: pinctrl-fec0-phy-int {
+ fsl,pins = <
+ VF610_PAD_PTB28__GPIO_98 0x219d
+ >;
+ };
+};
diff --git a/arch/arm/boot/dts/vf610-zii-dev.dtsi b/arch/arm/boot/dts/vf610-zii-dev.dtsi
new file mode 100644
index 0000000..9f5e2e7
--- /dev/null
+++ b/arch/arm/boot/dts/vf610-zii-dev.dtsi
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2015, 2016 Zodiac Inflight Innovations
+ *
+ * Based on an original 'vf610-twr.dts' which is Copyright 2015,
+ * Freescale Semiconductor, Inc.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file 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.
+ *
+ * This file 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.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+n * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "vf610.dtsi"
+
+/ {
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ reg = <0x80000000 0x20000000>;
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+ pinctrl-0 = <&pinctrl_leds_debug>;
+ pinctrl-names = "default";
+
+ debug {
+ label = "zii:green:debug1";
+ gpios = <&gpio2 10 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ reg_vcc_3v3_mcu: regulator-vcc-3v3-mcu {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_3v3_mcu";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ usb0_vbus: regulator-usb0-vbus {
+ compatible = "regulator-fixed";
+ pinctrl-0 = <&pinctrl_usb_vbus>;
+ regulator-name = "usb_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ enable-active-high;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&gpio0 6 0>;
+ };
+};
+
+&adc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_adc0_ad5>;
+ vref-supply = <®_vcc_3v3_mcu>;
+ status = "okay";
+};
+
+&edma0 {
+ status = "okay";
+};
+
+&esdhc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_esdhc1>;
+ bus-width = <4>;
+ status = "okay";
+};
+
+&fec0 {
+ phy-mode = "rmii";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fec0>;
+ status = "okay";
+};
+
+&fec1 {
+ phy-mode = "rmii";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fec1>;
+ status = "okay";
+
+ fixed-link {
+ speed = <100>;
+ full-duplex;
+ };
+
+ mdio1: mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+ };
+};
+
+&i2c0 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default", "gpio";
+ pinctrl-0 = <&pinctrl_i2c0>;
+ pinctrl-1 = <&pinctrl_i2c0_gpio>;
+ scl-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
+ sda-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+
+ lm75 at 48 {
+ compatible = "national,lm75";
+ reg = <0x48>;
+ };
+
+ at24c04 at 50 {
+ compatible = "atmel,24c04";
+ reg = <0x50>;
+ };
+
+ at24c04 at 52 {
+ compatible = "atmel,24c04";
+ reg = <0x52>;
+ };
+
+ ds1682 at 6b {
+ compatible = "dallas,ds1682";
+ reg = <0x6b>;
+ };
+};
+
+&i2c1 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "okay";
+};
+
+&i2c2 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart0>;
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ status = "okay";
+};
+
+&usbdev0 {
+ disable-over-current;
+ vbus-supply = <&usb0_vbus>;
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbh1 {
+ disable-over-current;
+ status = "okay";
+};
+
+&usbmisc0 {
+ status = "okay";
+};
+
+&usbmisc1 {
+ status = "okay";
+};
+
+&usbphy0 {
+ status = "okay";
+};
+
+&usbphy1 {
+ status = "okay";
+};
+
+&iomuxc {
+ pinctrl_adc0_ad5: adc0ad5grp {
+ fsl,pins = <
+ VF610_PAD_PTC30__ADC0_SE5 0x00a1
+ >;
+ };
+
+ pinctrl_dspi0: dspi0grp {
+ fsl,pins = <
+ VF610_PAD_PTB18__DSPI0_CS1 0x1182
+ VF610_PAD_PTB19__DSPI0_CS0 0x1182
+ VF610_PAD_PTB20__DSPI0_SIN 0x1181
+ VF610_PAD_PTB21__DSPI0_SOUT 0x1182
+ VF610_PAD_PTB22__DSPI0_SCK 0x1182
+ >;
+ };
+
+ pinctrl_dspi2: dspi2grp {
+ fsl,pins = <
+ VF610_PAD_PTD31__DSPI2_CS1 0x1182
+ VF610_PAD_PTD30__DSPI2_CS0 0x1182
+ VF610_PAD_PTD29__DSPI2_SIN 0x1181
+ VF610_PAD_PTD28__DSPI2_SOUT 0x1182
+ VF610_PAD_PTD27__DSPI2_SCK 0x1182
+ >;
+ };
+
+ pinctrl_esdhc1: esdhc1grp {
+ fsl,pins = <
+ VF610_PAD_PTA24__ESDHC1_CLK 0x31ef
+ VF610_PAD_PTA25__ESDHC1_CMD 0x31ef
+ VF610_PAD_PTA26__ESDHC1_DAT0 0x31ef
+ VF610_PAD_PTA27__ESDHC1_DAT1 0x31ef
+ VF610_PAD_PTA28__ESDHC1_DATA2 0x31ef
+ VF610_PAD_PTA29__ESDHC1_DAT3 0x31ef
+ VF610_PAD_PTA7__GPIO_134 0x219d
+ >;
+ };
+
+ pinctrl_fec0: fec0grp {
+ fsl,pins = <
+ VF610_PAD_PTC0__ENET_RMII0_MDC 0x30d2
+ VF610_PAD_PTC1__ENET_RMII0_MDIO 0x30d3
+ VF610_PAD_PTC2__ENET_RMII0_CRS 0x30d1
+ VF610_PAD_PTC3__ENET_RMII0_RXD1 0x30d1
+ VF610_PAD_PTC4__ENET_RMII0_RXD0 0x30d1
+ VF610_PAD_PTC5__ENET_RMII0_RXER 0x30d1
+ VF610_PAD_PTC6__ENET_RMII0_TXD1 0x30d2
+ VF610_PAD_PTC7__ENET_RMII0_TXD0 0x30d2
+ VF610_PAD_PTC8__ENET_RMII0_TXEN 0x30d2
+ >;
+ };
+
+ pinctrl_fec1: fec1grp {
+ fsl,pins = <
+ VF610_PAD_PTA6__RMII_CLKIN 0x30d1
+ VF610_PAD_PTC9__ENET_RMII1_MDC 0x30d2
+ VF610_PAD_PTC10__ENET_RMII1_MDIO 0x30d3
+ VF610_PAD_PTC11__ENET_RMII1_CRS 0x30d1
+ VF610_PAD_PTC12__ENET_RMII1_RXD1 0x30d1
+ VF610_PAD_PTC13__ENET_RMII1_RXD0 0x30d1
+ VF610_PAD_PTC14__ENET_RMII1_RXER 0x30d1
+ VF610_PAD_PTC15__ENET_RMII1_TXD1 0x30d2
+ VF610_PAD_PTC16__ENET_RMII1_TXD0 0x30d2
+ VF610_PAD_PTC17__ENET_RMII1_TXEN 0x30d2
+ >;
+ };
+
+ pinctrl_gpio_spi0: pinctrl-gpio-spi0 {
+ fsl,pins = <
+ VF610_PAD_PTB22__GPIO_44 0x33e2
+ VF610_PAD_PTB21__GPIO_43 0x33e2
+ VF610_PAD_PTB20__GPIO_42 0x33e1
+ VF610_PAD_PTB19__GPIO_41 0x33e2
+ VF610_PAD_PTB18__GPIO_40 0x33e2
+ >;
+ };
+
+ pinctrl_i2c_mux_reset: pinctrl-i2c-mux-reset {
+ fsl,pins = <
+ VF610_PAD_PTE14__GPIO_119 0x31c2
+ >;
+ };
+
+ pinctrl_i2c0: i2c0grp {
+ fsl,pins = <
+ VF610_PAD_PTB14__I2C0_SCL 0x37ff
+ VF610_PAD_PTB15__I2C0_SDA 0x37ff
+ >;
+ };
+
+ pinctrl_i2c0_gpio: i2c0grp-gpio {
+ fsl,pins = <
+ VF610_PAD_PTB14__GPIO_36 0x31c2
+ VF610_PAD_PTB15__GPIO_37 0x31c2
+ >;
+ };
+
+
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ VF610_PAD_PTB16__I2C1_SCL 0x37ff
+ VF610_PAD_PTB17__I2C1_SDA 0x37ff
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ VF610_PAD_PTA22__I2C2_SCL 0x37ff
+ VF610_PAD_PTA23__I2C2_SDA 0x37ff
+ >;
+ };
+
+ pinctrl_leds_debug: pinctrl-leds-debug {
+ fsl,pins = <
+ VF610_PAD_PTD20__GPIO_74 0x31c2
+ >;
+ };
+
+ pinctrl_qspi0: qspi0grp {
+ fsl,pins = <
+ VF610_PAD_PTD7__QSPI0_B_QSCK 0x31c3
+ VF610_PAD_PTD8__QSPI0_B_CS0 0x31ff
+ VF610_PAD_PTD9__QSPI0_B_DATA3 0x31c3
+ VF610_PAD_PTD10__QSPI0_B_DATA2 0x31c3
+ VF610_PAD_PTD11__QSPI0_B_DATA1 0x31c3
+ VF610_PAD_PTD12__QSPI0_B_DATA0 0x31c3
+ >;
+ };
+
+ pinctrl_uart0: uart0grp {
+ fsl,pins = <
+ VF610_PAD_PTB10__UART0_TX 0x21a2
+ VF610_PAD_PTB11__UART0_RX 0x21a1
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ VF610_PAD_PTB23__UART1_TX 0x21a2
+ VF610_PAD_PTB24__UART1_RX 0x21a1
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ VF610_PAD_PTD0__UART2_TX 0x21a2
+ VF610_PAD_PTD1__UART2_RX 0x21a1
+ >;
+ };
+
+ pinctrl_usb_vbus: pinctrl-usb-vbus {
+ fsl,pins = <
+ VF610_PAD_PTA16__GPIO_6 0x31c2
+ >;
+ };
+
+ pinctrl_usb0_host: usb0-host-grp {
+ fsl,pins = <
+ VF610_PAD_PTD6__GPIO_85 0x0062
+ >;
+ };
+};
--
2.9.3
^ permalink raw reply related
* [PATCHv2 net-next 11/16] net: mvpp2: handle misc PPv2.1/PPv2.2 differences
From: Russell King - ARM Linux @ 2017-01-07 20:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170107093834.GJ14217@n2100.armlinux.org.uk>
On Sat, Jan 07, 2017 at 09:38:34AM +0000, Russell King - ARM Linux wrote:
> On Wed, Dec 28, 2016 at 05:46:27PM +0100, Thomas Petazzoni wrote:
> > @@ -6511,7 +6515,9 @@ static int mvpp2_port_probe(struct platform_device *pdev,
> > dev_err(&pdev->dev, "failed to init port %d\n", id);
> > goto err_free_stats;
> > }
> > - mvpp2_port_power_up(port);
> > +
> > + if (priv->hw_version == MVPP21)
> > + mvpp21_port_power_up(port);
>
> This has the side effect that nothing clears the port reset bit in the
> GMAC, which means there's no hope of the interface working - with the
> reset bit set, the port is well and truely held in "link down" state.
>
> In any case, the GMAC part is much the same as mvneta, and I think
> that code should be shared rather than writing new versions of it.
> There are some subtle differences between neta, pp2.1 and pp2.2, but
> it's entirely doable (I have an implementation here as I wasn't going
> to duplicate this code for my phylink conversion.)
In addition to comphy configuration and the above, I also need the
following to have working SGMII. The change of MACMODE is needed
because uboot has configured the port for 10Gbase-R mode (it has a
10G PHY on it, but the PHY switches to SGMII in <10G modes.) The
GMAC control register 4 is needed to properly configure for SGMII
mode. I also included RGMII mode as well in there, as I expect you'd
need it to have GMAC properly configured for RGMII.
With this in place (and the other bits mentioned above), I can ping
the clearfog switch on the other end of eth0's cable:
# ping6 -I eth0 fe80::250:43ff:fe02:302
PING fe80::250:43ff:fe02:302(fe80::250:43ff:fe02:302) from fe80::200:ff:fe00:1 eth0: 56 data bytes
64 bytes from fe80::250:43ff:fe02:302: icmp_seq=1 ttl=64 time=0.297 ms
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index bc97eebf7eee..4b6ec6213e9c 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -345,7 +345,17 @@
#define MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK 0x1fc0
#define MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(v) (((v) << 6) & \
MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK)
+#define MVPP22_GMAC_CTRL_4_REG 0x90
+#define MVPP22_CTRL4_EXT_PIN_GMII_SEL BIT(0)
+#define MVPP22_CTRL4_DP_CLK_SEL BIT(5)
+#define MVPP22_CTRL4_SYNC_BYPASS BIT(6)
+#define MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE BIT(7)
+
+#define MVPP22_XLG_CTRL3_REG 0x11c
+#define MVPP22_XLG_CTRL3_MACMODESELECT_MASK (7 << 13)
+#define MVPP22_XLG_CTRL3_MACMODESELECT_GMAC (0 << 13)
+/* offsets from iface_base */
#define MVPP22_SMI_MISC_CFG_REG 0x2a204
#define MVPP22_SMI_POLLING_EN BIT(10)
@@ -4171,6 +4181,23 @@ static void mvpp2_port_mii_set(struct mvpp2_port *port)
{
u32 val;
+ if (port->priv->hw_version == MVPP22) {
+ val = readl(port->base + MVPP22_XLG_CTRL3_REG);
+ val &= ~MVPP22_XLG_CTRL3_MACMODESELECT_MASK;
+ val |= MVPP22_XLG_CTRL3_MACMODESELECT_GMAC;
+ writel(val, port->base + MVPP22_XLG_CTRL3_REG);
+
+ val = readl(port->base + MVPP22_GMAC_CTRL_4_REG);
+ if (port->phy_interface == PHY_INTERFACE_MODE_RGMII)
+ val |= MVPP22_CTRL4_EXT_PIN_GMII_SEL;
+ else
+ val &= ~MVPP22_CTRL4_EXT_PIN_GMII_SEL;
+ val &= ~MVPP22_CTRL4_DP_CLK_SEL;
+ val |= MVPP22_CTRL4_SYNC_BYPASS;
+ val |= MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE;
+ writel(val, port->base + MVPP22_GMAC_CTRL_4_REG);
+ }
+
val = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
switch (port->phy_interface) {
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
^ 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