* Re: [PATCH v3 1/2] regulator: dt-bindings: add QCOM RPMh regulator bindings
From: Mark Brown @ 2018-05-30 9:37 UTC (permalink / raw)
To: Doug Anderson
Cc: David Collins, Liam Girdwood, Rob Herring, Mark Rutland,
linux-arm-msm, Linux ARM, devicetree, LKML, Rajendra Nayak,
Stephen Boyd
In-Reply-To: <CAD=FV=W4aDxWbcaJ9GZ1KkvyiTPAPR-oUoTFzJfS+LftU5ZP=Q@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 770 bytes --]
On Tue, May 29, 2018 at 10:30:33PM -0700, Doug Anderson wrote:
> On Wed, May 23, 2018 at 8:56 AM, Mark Brown <broonie@kernel.org> wrote:
> > Yes, that's definitely not what's expected but it's unfortunately what
> > the firmware chose to implement so we may well be stuck with it
> > unfortunately.
> We're not really stuck with it if we do what I was suggesting. I was
> suggesting that every time we disable the regulator in Linux we have
> Linux vote for the lowest voltage it's comfortable with. Linux keeps
> track of the true voltage that the driver wants and will always change
> its vote back to that before enabling. Thus (assuming Linux is OK
> with 1.2 V - 1.4 V for a rail):
That's pretty much what it should do anyway with normally designed
hardware.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v5] Input: add bu21029 touch driver
From: Jonas Mark (BT-FIR/ENG1) @ 2018-05-30 9:42 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Mark Rutland
Cc: linux-input@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, hs@denx.de,
andy.shevchenko@gmail.com, ZHU Yi (BT-FIR/ENG1-Zhu),
Jonas Mark (BT-FIR/ENG1)
Hi,
> [PATCH v5] Input: add bu21029 touch driver
>
> Add Rohm BU21029 resistive touch panel controller support with I2C
> interface.
Is the patch ready to be pushed upstream? Is there anything I still need to do?
Regards,
Mark
Mark Jonas
Building Technologies, Panel Software Fire (BT-FIR/ENG1)
Bosch Sicherheitssysteme GmbH | Postfach 11 11 | 85626 Grasbrunn | GERMANY | www.boschsecurity.com
Sitz: Stuttgart, Registergericht: Amtsgericht Stuttgart HRB 23118
Aufsichtsratsvorsitzender: Stefan Hartung; Geschäftsführung: Gert van Iperen, Andreas Bartz, Thomas Quante, Bernhard Schuster
^ permalink raw reply
* Re: [PATCH v4 9/9] drm/mediatek: Add support for mediatek SOC MT2712
From: kbuild test robot @ 2018-05-30 9:42 UTC (permalink / raw)
Cc: kbuild-all, CK Hu, Philipp Zabel, Mark Rutland, devicetree,
srv_heupstream, David Airlie, linux-kernel, dri-devel,
Rob Herring, linux-mediatek, Stu Hsieh, Matthias Brugger,
linux-arm-kernel
In-Reply-To: <1527489507-24453-10-git-send-email-stu.hsieh@mediatek.com>
[-- Attachment #1: Type: text/plain, Size: 2090 bytes --]
Hi Stu,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on drm/drm-next]
[also build test ERROR on v4.17-rc7 next-20180529]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Stu-Hsieh/Add-support-for-mediatek-SOC-MT2712/20180530-032344
base: git://people.freedesktop.org/~airlied/linux.git drm-next
config: arm-allmodconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0
reproduce:
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm
All errors (new ones prefixed by >>):
>> drivers/gpu//drm/mediatek/mtk_drm_drv.c:165:2: error: 'DDP_COMPONENT_DPI1' undeclared here (not in a function); did you mean 'DDP_COMPONENT_DSI1'?
DDP_COMPONENT_DPI1,
^~~~~~~~~~~~~~~~~~
DDP_COMPONENT_DSI1
>> drivers/gpu//drm/mediatek/mtk_drm_drv.c:171:2: error: 'DDP_COMPONENT_DSI2' undeclared here (not in a function); did you mean 'DDP_COMPONENT_DSI1'?
DDP_COMPONENT_DSI2,
^~~~~~~~~~~~~~~~~~
DDP_COMPONENT_DSI1
>> drivers/gpu//drm/mediatek/mtk_drm_drv.c:171:2: error: incompatible types when initializing type 'enum mtk_ddp_comp_id' using type 'const enum mtk_ddp_comp_id *'
vim +165 drivers/gpu//drm/mediatek/mtk_drm_drv.c
158
159 static const enum mtk_ddp_comp_id mt2712_mtk_ddp_ext[] = {
160 DDP_COMPONENT_OVL1,
161 DDP_COMPONENT_COLOR1,
162 DDP_COMPONENT_AAL1,
163 DDP_COMPONENT_OD1,
164 DDP_COMPONENT_RDMA1,
> 165 DDP_COMPONENT_DPI1,
166 DDP_COMPONENT_PWM1,
167 };
168
169 static const enum mtk_ddp_comp_id mt2712_mtk_ddp_third[] = {
170 DDP_COMPONENT_RDMA2,
> 171 DDP_COMPONENT_DSI2,
172 DDP_COMPONENT_PWM2,
173 };
174
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 65217 bytes --]
^ permalink raw reply
* Re: [PATCH v2 5/6] soc: qcom: rpmh powerdomain driver
From: Viresh Kumar @ 2018-05-30 9:44 UTC (permalink / raw)
To: Rajendra Nayak
Cc: David Collins, sboyd, andy.gross, ulf.hansson, devicetree,
linux-arm-msm, linux-kernel, Lina Iyer
In-Reply-To: <36822404-bdf5-1915-03e7-e5ffcff05c9b@codeaurora.org>
On 30-05-18, 14:25, Rajendra Nayak wrote:
> []...
>
> >>> +Required Properties:
> >>> + - compatible: Should be one of the following
> >>> + * qcom,sdm845-rpmhpd: RPMh powerdomain for the sdm845 family of SoC
> >>> + - power-domain-cells: number of cells in power domain specifier
> >>> + must be 1
> >>> + - operating-points-v2: Phandle to the OPP table for the power-domain.
> >>> + Refer to Documentation/devicetree/bindings/power/power_domain.txt
> >>> + and Documentation/devicetree/bindings/opp/qcom-opp.txt for more details
> >>> +
> >>> +Example:
> >>> +
> >>> + rpmhpd: power-controller {
> >>> + compatible = "qcom,sdm845-rpmhpd";
> >>> + #power-domain-cells = <1>;
> >>> + operating-points-v2 = <&rpmhpd_opp_table>,
> >>> + <&rpmhpd_opp_table>,
> >>> + <&rpmhpd_opp_table>,
> >>> + <&rpmhpd_opp_table>,
> >>> + <&rpmhpd_opp_table>,
> >>> + <&rpmhpd_opp_table>,
> >>> + <&rpmhpd_opp_table>,
> >>> + <&rpmhpd_opp_table>,
> >>> + <&rpmhpd_opp_table>;
> >>
> >> Can this be changed to simply:
> >> operating-points-v2 = <&rpmhpd_opp_table>;
> >>
> >> The opp binding documentation [1] states that this should be ok:
> >>
> >> If only one phandle is available, then the same OPP table will be used
> >> for all power domains provided by the power domain provider.
> >
> > thanks, I mentioned this to Viresh but didn't realize he fixed it up.
> > Will remove the redundant entries.
>
> Looks like the kernel implementation does not handle this yet, and I get
> an error adding the OPP tables for the powerdomains if I just specify
> a single OPP table phandle.
>
> Viresh, is this expected with the latest patches in linux-next?
>
> It would be good if I can specify just one phandle instead of coping
> the same phandle n times.
Please try this untested hunk:
diff --git a/drivers/opp/of.c b/drivers/opp/of.c
index 6d15f05bfc28..7af0ddec936b 100644
--- a/drivers/opp/of.c
+++ b/drivers/opp/of.c
@@ -554,11 +554,24 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);
int dev_pm_opp_of_add_table_indexed(struct device *dev, int index)
{
struct device_node *opp_np;
- int ret;
+ int ret, count;
+again:
opp_np = _opp_of_get_opp_desc_node(dev->of_node, index);
- if (!opp_np)
+ if (!opp_np) {
+ /*
+ * If only one phandle is present, then the same OPP table
+ * applies for all index requests.
+ */
+ count = of_count_phandle_with_args(dev->of_node,
+ "operating-points-v2", NULL);
+ if (count == 1 && index) {
+ index = 0;
+ goto again;
+ }
+
return -ENODEV;
+ }
ret = _of_add_opp_table_v2(dev, opp_np);
of_node_put(opp_np);
^ permalink raw reply related
* Re: [PATCH 2/2] mmc: meson-gx: add device reset
From: Jerome Brunet @ 2018-05-30 9:47 UTC (permalink / raw)
To: Ulf Hansson
Cc: Carlo Caione, Kevin Hilman, devicetree,
open list:ARM/Amlogic Meson..., linux-mmc@vger.kernel.org,
Linux Kernel Mailing List, Corentin Labbe
In-Reply-To: <CAPDyKFo1ui3XyjXJt0JKrQZd52zEQfsY65LbK_exFqJ6jVDmCQ@mail.gmail.com>
On Wed, 2018-05-30 at 09:27 +0200, Ulf Hansson wrote:
> Jerome,
>
> On 15 May 2018 at 11:57, Jerome Brunet <jbrunet@baylibre.com> wrote:
> > Trigger the reset line of the mmc controller while probing, if available.
> > The reset should be optional for now, at least until all related DT nodes
> > have the reset property.
> >
> > Reviewed-by: Kevin Hilman <khilman@baylibre.com>
> > Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
>
> I got a regression boot report from kernelci. The bisect doesn't point
> to a certain commit, but I found $subject patch a possible cause. Is
> it something you can have a look at and see if it's a valid problem?
> https://kernelci.org/boot/id/5b0d68a859b514726179a899/
Hi Ulf,
Looking at the log, there is an "un-explained" power reset in the middle of the
boot sequence. With the maintainer of this lab, we have been over the logs of
this board and we have seen several other power reset at different stages. There
is no trace, error or warning, the board just resets. A few other boards show
the same issue in this lab ATM.
There has been some work done in this lab lately and we suspect a problem with
the relays controlling the power supplies. We have taken this board offline
until the problem is solved.
Thanks for reporting the problem.
Regards
Jerome
>
> Kind regards
> Uffe
>
> > ---
> > drivers/mmc/host/meson-gx-mmc.c | 9 +++++++++
> > 1 file changed, 9 insertions(+)
> >
> > diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c
> > index 4f972b879fe6..9bca359f7936 100644
> > --- a/drivers/mmc/host/meson-gx-mmc.c
> > +++ b/drivers/mmc/host/meson-gx-mmc.c
> > @@ -35,6 +35,7 @@
> > #include <linux/clk.h>
> > #include <linux/clk-provider.h>
> > #include <linux/regulator/consumer.h>
> > +#include <linux/reset.h>
> > #include <linux/interrupt.h>
> > #include <linux/bitfield.h>
> > #include <linux/pinctrl/consumer.h>
> > @@ -1184,6 +1185,14 @@ static int meson_mmc_probe(struct platform_device *pdev)
> > goto free_host;
> > }
> >
> > + ret = device_reset_optional(&pdev->dev);
> > + if (ret) {
> > + if (ret != -EPROBE_DEFER)
> > + dev_err(&pdev->dev, "device reset failed: %d\n", ret);
> > +
> > + return ret;
> > + }
> > +
> > res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > host->regs = devm_ioremap_resource(&pdev->dev, res);
> > if (IS_ERR(host->regs)) {
> > --
> > 2.14.3
> >
^ permalink raw reply
* Re: [PATCH 2/3] ASoC: simple-card: make sysclk index configurable
From: Mark Brown @ 2018-05-30 9:49 UTC (permalink / raw)
To: Daniel Mack; +Cc: devicetree, alsa-devel, lgirdwood, kuninori.morimoto.gx
In-Reply-To: <f130a86f-deca-b5cf-da34-5cf52a9c39fc@zonque.org>
[-- Attachment #1.1: Type: text/plain, Size: 1303 bytes --]
On Tue, May 29, 2018 at 10:23:48PM +0200, Daniel Mack wrote:
> On Tuesday, May 29, 2018 01:24 PM, Mark Brown wrote:
> > If we want to get more complex usage of clocks in the DT we should be
> > moving the CODECs over to using the standard clock bindings for this
> > stuff rather than inventing custom ASoC clock bindings for it. That way
> > we don't have to deal with the pain of trying to join things up in the
> > future.
> This will get rather complex too though, because most codec and cpu dais can
> act as clock source xor clock consumer, depending on how the hardware is
> built. Would you want to represent everything, bit clocks, frame clocks,
> master clocks etc as clock nodes?
We're probably OK just going down to the master clocks mostly I think.
For the clocks on the actual bus we can probably have helpers in the
core that generate the clocks and the drivers just tell the core the
rates.
> If that's the case, could you depict how the DT bindings should look like by
> example?
I've not been able to dig far enough into the clock bindings yet.
That's not super helpful for you I appreciate, TBH nobody seemed to
particularly need this so it wasn't super urgent - most of the things
using alternative clocks on devices seem to also need custom machine
drivers for other reasons.
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply
* Re: [PATCH v3 4/5] clocksource: add driver for i.MX EPIT timer
From: Clément PERON @ 2018-05-30 9:53 UTC (permalink / raw)
To: vladimir_zapolskiy
Cc: devicetree, robh, Colin Didier, s.hauer, Clément Péron,
linux-imx, kernel, fabio.estevam, linux-clk, linux-arm-kernel
In-Reply-To: <e2e8bbe6-5957-a8fa-af3c-816f0ad80e32@mentor.com>
Hi Vladimir,
Le mer. 30 mai 2018 à 08:56, Vladimir Zapolskiy <
vladimir_zapolskiy@mentor.com> a écrit :
> Hi Clément,
> please find some more review comments.
> On 05/29/2018 08:04 PM, Clément Péron wrote:
> > From: Colin Didier <colin.didier@devialet.com>
> >
> > Add driver for NXP's EPIT timer used in i.MX 6 family of SoC.
> >
> > Signed-off-by: Colin Didier <colin.didier@devialet.com>
> > Signed-off-by: Clément Peron <clement.peron@devialet.com>
> > ---
> > drivers/clocksource/Kconfig | 12 ++
> > drivers/clocksource/Makefile | 1 +
> > drivers/clocksource/timer-imx-epit.c | 283 +++++++++++++++++++++++++++
> > 3 files changed, 296 insertions(+)
> > create mode 100644 drivers/clocksource/timer-imx-epit.c
> >
> > diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> > index 8e8a09755d10..920a0874f3a4 100644
> > --- a/drivers/clocksource/Kconfig
> > +++ b/drivers/clocksource/Kconfig
> > @@ -576,6 +576,18 @@ config H8300_TPU
> > This enables the clocksource for the H8300 platform with the
> > H8S2678 cpu.
> >
> > +config CLKSRC_IMX_EPIT
> > + bool "Clocksource using i.MX EPIT"
> > + depends on ARM && CLKDEV_LOOKUP && OF && (ARCH_MXC ||
COMPILE_TEST)
> Here 'depends on ARM' can be removed, because ARCH_MXC implies it.
> Also ARCH_MXC implies ARCH_MULTIPLATFORM, which implies USE_OF in turn,
> so I would say that the following line is correct, sorry about a previous
> comment asking to add an explicit OF dependency:
> depends on CLKDEV_LOOKUP && (ARCH_MXC || COMPILE_TEST)
> However most of the clocksource drivers follow 'bool "..." if
COMPILE_TEST'
> pattern, and it might be preferable to maintainers.
Usually, the timer driver are selected in the arch Kconfig. But in this
case,
we want to keep the i.MX GPT except if the user explicitly select the i.MX
EPIT.
With the "if COMPILE_TEST" the user can't choose it.
> > + select TIMER_OF
> The driver does not have this dependency.
> > + select CLKSRC_MMIO
> > + help
> > + This enables EPIT support available on some i.MX platforms.
> > + Normally you don't have a reason to do so as the EPIT has
> > + the same features and uses the same clocks as the GPT.
> > + Anyway, on some systems the GPT may be in use for other
> > + purposes.
> > +
> > config CLKSRC_IMX_GPT
> > bool "Clocksource using i.MX GPT" if COMPILE_TEST
> > depends on ARM && CLKDEV_LOOKUP
> > diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> > index 00caf37e52f9..d9426f69ec69 100644
> > --- a/drivers/clocksource/Makefile
> > +++ b/drivers/clocksource/Makefile
> > @@ -69,6 +69,7 @@ obj-$(CONFIG_INTEGRATOR_AP_TIMER) +=
timer-integrator-ap.o
> > obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o
> > obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o
> > obj-$(CONFIG_CLKSRC_TANGO_XTAL) += tango_xtal.o
> > +obj-$(CONFIG_CLKSRC_IMX_EPIT) += timer-imx-epit.o
> > obj-$(CONFIG_CLKSRC_IMX_GPT) += timer-imx-gpt.o
> > obj-$(CONFIG_CLKSRC_IMX_TPM) += timer-imx-tpm.o
> > obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o
> > diff --git a/drivers/clocksource/timer-imx-epit.c
b/drivers/clocksource/timer-imx-epit.c
> > new file mode 100644
> > index 000000000000..87025d5f3a97
> > --- /dev/null
> > +++ b/drivers/clocksource/timer-imx-epit.c
> > @@ -0,0 +1,283 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * i.MX EPIT Timer
> > + *
> > + * Copyright (C) 2010 Sascha Hauer <s.hauer@pengutronix.de>
> > + * Copyright (C) 2018 Colin Didier <colin.didier@devialet.com>
> > + * Copyright (C) 2018 Clément Péron <clement.peron@devialet.com>
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/clockchips.h>
> > +#include <linux/err.h>
> The include above can be dropped.
> > +#include <linux/interrupt.h>
> > +#include <linux/irq.h>
> The include above can be dropped.
> > +#include <linux/of_address.h>
> > +#include <linux/of_irq.h>
> > +#include <linux/of.h>
> The include above can be dropped.
> > +#include <linux/sched_clock.h>
> > +#include <linux/slab.h>
> > +
> > +#define EPITCR 0x00
> > +#define EPITSR 0x04
> > +#define EPITLR 0x08
> > +#define EPITCMPR 0x0c
> > +#define EPITCNR 0x10
> > +
> > +#define EPITCR_EN BIT(0)
> > +#define EPITCR_ENMOD BIT(1)
> > +#define EPITCR_OCIEN BIT(2)
> > +#define EPITCR_RLD BIT(3)
> > +#define EPITCR_PRESC(x) (((x) & 0xfff) << 4)
> > +#define EPITCR_SWR BIT(16)
> > +#define EPITCR_IOVW BIT(17)
> > +#define EPITCR_DBGEN BIT(18)
> > +#define EPITCR_WAITEN BIT(19)
> > +#define EPITCR_RES BIT(20)
> > +#define EPITCR_STOPEN BIT(21)
> > +#define EPITCR_OM_DISCON (0 << 22)
> > +#define EPITCR_OM_TOGGLE (1 << 22)
> > +#define EPITCR_OM_CLEAR (2 << 22)
> > +#define EPITCR_OM_SET (3 << 22)
> > +#define EPITCR_CLKSRC_OFF (0 << 24)
> > +#define EPITCR_CLKSRC_PERIPHERAL (1 << 24)
> > +#define EPITCR_CLKSRC_REF_HIGH (2 << 24)
> > +#define EPITCR_CLKSRC_REF_LOW (3 << 24)
> > +
> > +#define EPITSR_OCIF BIT(0)
> > +
> > +struct epit_timer {
> > + void __iomem *base;
> > + int irq;
> > + struct clk *clk_per;
> > + struct clock_event_device ced;
> > + struct irqaction act;
> > +};
> > +
> > +static void __iomem *sched_clock_reg;
> > +
> > +static inline struct epit_timer *to_epit_timer(struct
clock_event_device *ced)
> > +{
> > + return container_of(ced, struct epit_timer, ced);
> > +}
> > +
> > +static inline void epit_irq_disable(struct epit_timer *epittm)
> > +{
> > + u32 val;
> > +
> > + val = readl_relaxed(epittm->base + EPITCR);
> > + writel_relaxed(val & ~EPITCR_OCIEN, epittm->base + EPITCR);
> > +}
> > +
> > +static inline void epit_irq_enable(struct epit_timer *epittm)
> > +{
> > + u32 val;
> > +
> > + val = readl_relaxed(epittm->base + EPITCR);
> > + writel_relaxed(val | EPITCR_OCIEN, epittm->base + EPITCR);
> > +}
> > +
> > +static void epit_irq_acknowledge(struct epit_timer *epittm)
> > +{
> > + writel_relaxed(EPITSR_OCIF, epittm->base + EPITSR);
> > +}
> > +
> > +static u64 notrace epit_read_sched_clock(void)
> > +{
> > + return ~readl_relaxed(sched_clock_reg);
> > +}
> > +
> > +static int __init epit_clocksource_init(struct epit_timer *epittm)
> > +{
> > + unsigned int c = clk_get_rate(epittm->clk_per);
> > +
> > + sched_clock_reg = epittm->base + EPITCNR;
> > + sched_clock_register(epit_read_sched_clock, 32, c);
> > +
> > + return clocksource_mmio_init(epittm->base + EPITCNR, "epit", c,
200, 32,
> > + clocksource_mmio_readl_down);
> > +}
> > +
> I would suggest to place epit_clocksource_init() function right before
> epit_timer_init().
> > +static int epit_set_next_event(unsigned long cycles,
> > + struct clock_event_device *ced)
> > +{
> > + struct epit_timer *epittm = to_epit_timer(ced);
> > + unsigned long tcmp;
> > +
> > + tcmp = readl_relaxed(epittm->base + EPITCNR) - cycles;
> > + writel_relaxed(tcmp, epittm->base + EPITCMPR);
> > +
> > + return 0;
> > +}
> > +
> > +/* Left event sources disabled, no more interrupts appear */
> > +static int epit_shutdown(struct clock_event_device *ced)
> > +{
> > + struct epit_timer *epittm = to_epit_timer(ced);
> > + unsigned long flags;
> > +
> > + /*
> > + * The timer interrupt generation is disabled at least
> > + * for enough time to call epit_set_next_event()
> > + */
> > + local_irq_save(flags);
> > +
> > + /* Disable interrupt in EPIT module */
> > + epit_irq_disable(epittm);
> > +
> > + /* Clear pending interrupt */
> > + epit_irq_acknowledge(epittm);
> > +
> > + local_irq_restore(flags);
> > +
> > + return 0;
> > +}
> > +
> > +static int epit_set_oneshot(struct clock_event_device *ced)
> > +{
> > + struct epit_timer *epittm = to_epit_timer(ced);
> > + unsigned long flags;
> > +
> > + /*
> > + * The timer interrupt generation is disabled at least
> > + * for enough time to call epit_set_next_event()
> > + */
> > + local_irq_save(flags);
> > +
> > + /* Disable interrupt in EPIT module */
> > + epit_irq_disable(epittm);
> > +
> > + /* Clear pending interrupt, only while switching mode */
> > + if (!clockevent_state_oneshot(ced))
> > + epit_irq_acknowledge(epittm);
> > +
> > + /*
> > + * Do not put overhead of interrupt enable/disable into
> > + * epit_set_next_event(), the core has about 4 minutes
> > + * to call epit_set_next_event() or shutdown clock after
> > + * mode switching
> > + */
> > + epit_irq_enable(epittm);
> > + local_irq_restore(flags);
> > +
> > + return 0;
> > +}
> > +
> > +static irqreturn_t epit_timer_interrupt(int irq, void *dev_id)
> > +{
> > + struct clock_event_device *ced = dev_id;
> > + struct epit_timer *epittm = to_epit_timer(ced);
> > +
> > + epit_irq_acknowledge(epittm);
> > +
> > + ced->event_handler(ced);
> > +
> > + return IRQ_HANDLED;
> > +}
> > +
> > +static int __init epit_clockevent_init(struct epit_timer *epittm)
> > +{
> > + struct clock_event_device *ced = &epittm->ced;
> > + struct irqaction *act = &epittm->act;
> > +
> > + ced->name = "epit";
> > + ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ;
> > + ced->set_state_shutdown = epit_shutdown;
> > + ced->tick_resume = epit_shutdown;
> > + ced->set_state_oneshot = epit_set_oneshot;
> > + ced->set_next_event = epit_set_next_event;
> > + ced->rating = 200;
> > + ced->cpumask = cpumask_of(0);
> > + ced->irq = epittm->irq;
> > + clockevents_config_and_register(ced,
clk_get_rate(epittm->clk_per),
> > + 0xff, 0xfffffffe);
> Please indent the wrapped line.
> > +
> > + act->name = "i.MX EPIT Timer Tick",
> > + act->flags = IRQF_TIMER | IRQF_IRQPOLL;
> > + act->handler = epit_timer_interrupt;
> > + act->dev_id = ced;
> > +
> > + /* Make irqs happen */
> > + return setup_irq(epittm->irq, act);
> > +}
> > +
> > +static int __init epit_timer_init(struct device_node *np)
> > +{
> > + struct epit_timer *epittm;
> > + struct clk *clk_ipg;
> > + int ret;
> > +
> > + epittm = kzalloc(sizeof(*epittm), GFP_KERNEL);
> > + if (!epittm)
> > + return -ENOMEM;
> > +
> > + epittm->base = of_iomap(np, 0);
> > + if (!epittm->base) {
> > + ret = -ENXIO;
> > + goto out_kfree;
> > + }
> > +
> > + epittm->irq = irq_of_parse_and_map(np, 0);
> > + if (!epittm->irq) {
> > + ret = -EINVAL;
> > + goto out_iounmap;
> > + }
> > +
> > + clk_ipg = of_clk_get_by_name(np, "ipg");
> > + if (IS_ERR(clk_ipg)) {
> > + pr_err("i.MX EPIT: unable to get clk_ipg\n");
> > + ret = PTR_ERR(clk_ipg);
> > + goto out_iounmap;
> > + }
> > +
> > + ret = clk_prepare_enable(clk_ipg);
> > + if (ret) {
> > + pr_err("i.MX EPIT: unable to prepare+enable clk_ipg\n");
> > + goto out_clk_ipg_disable;
> > + }
> > +
> > + epittm->clk_per = of_clk_get_by_name(np, "per");
> > + if (IS_ERR(epittm->clk_per)) {
> > + pr_err("i.MX EPIT: unable to get clk_per\n");
> > + ret = PTR_ERR(epittm->clk_per);
> > + goto out_clk_ipg_disable;
> > + }
> > +
> > + ret = clk_prepare_enable(epittm->clk_per);
> > + if (ret) {
> > + pr_err("i.MX EPIT: unable to prepare+enable clk_per\n");
> > + goto out_clk_ipg_disable;
> > + }
> > +
> > + /* Initialise to a known state (all timers off, and timing reset)
*/
> > + writel_relaxed(0x0, epittm->base + EPITCR);
> > + writel_relaxed(0xffffffff, epittm->base + EPITLR);
> > + writel_relaxed(EPITCR_EN | EPITCR_CLKSRC_REF_HIGH | EPITCR_WAITEN,
> > + epittm->base + EPITCR);
> > +
> > + ret = epit_clocksource_init(epittm);
> > + if(ret) {
> Add a space before left parenthesis.
> > + pr_err("i.MX EPIT: failed to init clocksource\n");
> > + goto out_clk_per_disable;
> > + }
> > +
> > + ret = epit_clockevent_init(epittm);
> > + if(ret) {
> Add a space before left parenthesis.
> > + pr_err("i.MX EPIT: failed to init clockevent\n");
> > + goto out_clk_per_disable;
> > + }
> > +
> > + return 0;
> > +
> > +out_clk_per_disable:
> > + clk_disable_unprepare(epittm->clk_per);
> > +out_clk_ipg_disable:
> > + clk_disable_unprepare(clk_ipg);
> > +out_iounmap:
> > + iounmap(epittm->base);
> > +out_kfree:
> > + kfree(epittm);
> > +
> > + return ret;
> > +}
> > +TIMER_OF_DECLARE(mx6q_timer, "fsl,imx6q-epit", epit_timer_init);
> >
> Here "fsl,imx31-epit" would be way better than "fsl,imx6q-epit", please
> fix it in the documentation as well.
> --
> With best wishes,
> Vladimir
Thanks for your review,
Clement
--
https://www.devialet.com/buy-phantom <https://www.devialet.com/buy-phantom>
- Confidential -
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 07/12] dt-bindings: tc358754: add DT bindings
From: Andrzej Hajda @ 2018-05-30 9:59 UTC (permalink / raw)
To: Laurent Pinchart, Maciej Purski
Cc: linux-kernel, linux-arm-kernel, linux-samsung-soc, devicetree,
dri-devel, David Airlie, Rob Herring, Mark Rutland,
Thierry Reding, Kukjin Kim, Krzysztof Kozlowski, Archit Taneja,
Inki Dae, Joonyoung Shim, Seung-Woo Kim, Kyungmin Park,
Marek Szyprowski, Bartlomiej Zolnierkiewicz
In-Reply-To: <2275901.CJI6BsfBlP@avalon>
On 28.05.2018 12:18, Laurent Pinchart wrote:
> Hi Maciej,
>
> Thank you for the patch.
>
> On Monday, 28 May 2018 12:47:11 EEST Maciej Purski wrote:
>> The patch adds bindings to Toshiba DSI/LVDS bridge TC358764.
>> Bindings describe power supplies, reset gpio and video interfaces.
>>
>> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
>> Signed-off-by: Maciej Purski <m.purski@samsung.com>
>> ---
>> .../bindings/display/bridge/toshiba,tc358764.txt | 42 +++++++++++++++++++
>> 1 file changed, 42 insertions(+)
>> create mode 100644
>> Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt
>>
>> diff --git
>> a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt
>> b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt new
>> file mode 100644
>> index 0000000..d09bdc2
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358764.txt
>> @@ -0,0 +1,42 @@
>> +TC358764 MIPI-DSI to LVDS panel bridge
>> +
>> +Required properties:
>> + - compatible: "toshiba,tc358764"
>> + - reg: the virtual channel number of a DSI peripheral
>> + - vddc-supply: core voltage supply
>> + - vddio-supply: I/O voltage supply
>> + - vddmipi-supply: MIPI voltage supply
>> + - vddlvds133-supply: LVDS1 3.3V voltage supply
>> + - vddlvds112-supply: LVDS1 1.2V voltage supply
> That's a lot of power supplies. Could some of them be merged together ? See
> https://patchwork.freedesktop.org/patch/216058/ for an earlier discussion on
> the same subject.
Specs says about 3 supply voltage values:
- 1.2V - digital core, DSI-RX PHY
- 1.8-3.3V - digital I/O
- 3.3V - LVDS-TX PHY
So I guess it should be minimal number of supplies. Natural candidates:
- vddc-supply: core voltage supply, 1.2V
- vddio-supply: I/O voltage supply, 1.8V or 3.3V
- vddlvds-supply: LVDS1/2 voltage supply, 3.3V
I have changed name of the latest supply to be more consistent with
other supplies, and changed 1.8-3.3 (which incorrectly suggest voltage
range), to more precise voltage alternative.
>
>> + - reset-gpios: a GPIO spec for the reset pin
>> +
>> +The device node can contain zero to two 'port' child nodes, each with one
>> +child
>> +'endpoint' node, according to the bindings defined in [1].
>> +The following are properties specific to those nodes.
>> +
>> +port:
>> + - reg: (required) can be 0 for DSI port or 1 for LVDS port;
> This seems pretty vague to me. It could be read as meaning that ports are
> completely optional, and that the port number you list can be used, but that
> something else could be used to.
>
> Let's make the port nodes mandatory. I propose the following.
>
> Required nodes:
>
> The TC358764 has DSI and LVDS ports whose connections are described using the
> OF graph bindings defined in Documentation/devicetree/bindings/graph.txt. The
> device node must contain one 'port' child node per DSI and LVDS port. The port
> nodes are numbered as follows.
>
> Port Number
> -------------------------------------------------------------------
> DSI Input 0
> LVDS Output 1
>
> Each port node must contain endpoint nodes describing the hardware
> connections.
Since the bridge is controlled via DSI bus, DSI input port is not necessary.
Regards
Andrzej
>
>> +[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
>> +
>> +Example:
>> +
>> + bridge@0 {
>> + reg = <0>;
>> + compatible = "toshiba,tc358764";
>> + vddc-supply = <&vcc_1v2_reg>;
>> + vddio-supply = <&vcc_1v8_reg>;
>> + vddmipi-supply = <&vcc_1v2_reg>;
>> + vddlvds133-supply = <&vcc_3v3_reg>;
>> + vddlvds112-supply = <&vcc_1v2_reg>;
>> + reset-gpios = <&gpd1 6 GPIO_ACTIVE_LOW>;
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> + port@1 {
>> + reg = <1>;
>> + lvds_ep: endpoint {
>> + remote-endpoint = <&panel_ep>;
>> + };
>> + };
>> + };
^ permalink raw reply
* Re: [PATCH v11 0/4] iommu/arm-smmu: Add runtime pm/sleep support
From: Vivek Gautam @ 2018-05-30 10:02 UTC (permalink / raw)
To: Robin Murphy
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
lukas-JFq808J9C/izQB+pC5nmwQ, Rafael J. Wysocki, Will Deacon,
open list,
list-Y9sIeH5OGRo@public.gmane.org:IOMMU DRIVERS <iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org>, Joerg Roedel <joro-zLv9SwRftAIdnm+yROfE0A@public.gmane.org>, ,
robh+dt, linux-arm-msm, Stephen Boyd
In-Reply-To: <dda4eee6-2144-7cbf-995b-d3f34a7c0184-5wv7dgnIgG8@public.gmane.org>
Hi Robin,
On Mon, May 21, 2018 at 7:12 PM, Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org> wrote:
> On 22/03/18 10:22, Vivek Gautam wrote:
>>
>> This series provides the support for turning on the arm-smmu's
>> clocks/power domains using runtime pm. This is done using the
>> recently introduced device links patches, which lets the smmu's
>> runtime to follow the master's runtime pm, so the smmu remains
>> powered only when the masters use it.
>> As not all implementations support clock/power gating, we are checking
>> for a valid 'smmu->dev's pm_domain' to conditionally enable the runtime
>> power management for such smmu implementations that can support it.
>>
>> This series also adds support for Qcom's arm-smmu-v2 variant that
>> has different clocks and power requirements.
>>
>> Took some reference from the exynos runtime patches [1].
>>
>> With conditional runtime pm now, we avoid touching dev->power.lock
>> in fastpaths for smmu implementations that don't need to do anything
>> useful with pm_runtime.
>> This lets us to use the much-argued pm_runtime_get_sync/put_sync()
>> calls in map/unmap callbacks so that the clients do not have to
>> worry about handling any of the arm-smmu's power.
>>
>> Previous version of this patch series is @ [5].
>>
>> [v11]
>> * Some more cleanups for device link. We don't need an explicit
>> delete for device link from the driver, but just set the flag
>> DL_FLAG_AUTOREMOVE.
>> device_link_add() API description says -
>> "If the DL_FLAG_AUTOREMOVE is set, the link will be removed
>> automatically when the consumer device driver unbinds."
>
>
> But then if the consumer subsequently rebinds, there's no opportunity to
> recreate the link, and PM will just quietly stop functioning properly. Given
> that it's a lot more reasonable for users to unload and reload modules (or
> otherwise switch drivers) for a consumer device than it is to unbind the
> SMMU driver or expect actual device hotplug, I'd rather do nothing and
> theoretically leak links than autoremove them incorrectly.
>
> AFAICS the previous discussion on this got as far as Lukas' suggestion of
> adding an equivalent flag for supplier-managed links (which FWIW sounds good
> to me), but seems to have stalled there.
Thanks for the review. I have posted a small change [1] for this.
Kindly take a look.
Best regards
Vivek
[1] https://patchwork.kernel.org/patch/10438109/
>
> Robin.
>
>
>> * Addressed the comments for 'smmu' in arm_smmu_map/unmap().
>> * Dropped the patch [10] that introduced device_link_del_dev() API.
>>
>> [v10]
>> * Introduce device_link_del_dev() API to delete the link between
>> given consumer and supplier devices. The users of device link
>> do not need to store link pointer to delete the link later.
>> They can straightaway use this API by passing consumer and
>> supplier devices.
>> * Made corresponding changes to arm-smmu driver patch handling the
>> device links.
>> * Dropped the patch [9] that was adding device_link_find() API to
>> device core layer. device_link_del_dev() serves the purpose to
>> directly delete the link between two given devices.
>>
>> [v9]
>> * Removed 'rpm_supported' flag, instead checking on pm_domain
>> to enable runtime pm.
>> * Creating device link only when the runtime pm is enabled, as we
>> don't need a device link besides managing the power dependency
>> between supplier and consumer devices.
>> * Introducing a patch to add device_link_find() API that finds
>> and existing link between supplier and consumer devices.
>> Also, made necessary change to device_link_add() to use this API.
>> * arm_smmu_remove_device() now uses this device_link_find() to find
>> the device link between smmu device and the master device, and then
>> delete this link.
>> * Dropped the destroy_domain_context() fix [8] as it was rather,
>> introducing catastrophically bad problem by destroying
>> 'good dev's domain context.
>> * Added 'Reviwed-by' tag for Tomasz's review.
>>
>> [v8]
>> * Major change -
>> - Added a flag 'rpm_supported' which each platform that supports
>> runtime pm, can enable, and we enable runtime_pm over arm-smmu
>> only when this flag is set.
>> - Adding the conditional pm_runtime_get/put() calls to .map, .unmap
>> and .attach_dev ops.
>> - Dropped the patch [6] that exported pm_runtim_get/put_suupliers(),
>> and also dropped the user driver patch [7] for these APIs.
>>
>> * Clock code further cleanup
>> - doing only clk_bulk_enable() and clk_bulk_disable() in runtime pm
>> callbacks. We shouldn't be taking a slow path
>> (clk_prepare/unprepare())
>> from these runtime pm callbacks. Thereby, moved clk_bulk_prepare()
>> to
>> arm_smmu_device_probe(), and clk_bulk_unprepare() to
>> arm_smmu_device_remove().
>> - clk data filling to a common method arm_smmu_fill_clk_data() that
>> fills the clock ids and number of clocks.
>>
>> * Addressed other nits and comments
>> - device_link_add() error path fixed.
>> - Fix for checking negative error value from pm_runtime_get_sync().
>> - Documentation redo.
>>
>> * Added another patch fixing the error path in arm_smmu_attach_dev()
>> to destroy allocated domain context.
>>
>> [v7]
>> * Addressed review comments given by Robin Murphy -
>> - Added device_link_del() in .remove_device path.
>> - Error path cleanup in arm_smmu_add_device().
>> - Added pm_runtime_get/put_sync() in .remove path, and replaced
>> pm_runtime_force_suspend() with pm_runtime_disable().
>> - clk_names cleanup in arm_smmu_init_clks()
>> * Added 'Reviewed-by' given by Rob H.
>>
>> [V6]
>> * Added Ack given by Rafael to first patch in the series.
>> * Addressed Rob Herring's comment for adding soc specific compatible
>> string as well besides 'qcom,smmu-v2'.
>>
>> [V5]
>> * Dropped runtime pm calls from "arm_smmu_unmap" op as discussed over
>> the list [3] for the last patch series.
>> * Added a patch to export pm_runtime_get/put_suppliers() APIs to the
>> series as agreed with Rafael [4].
>> * Added the related patch for msm drm iommu layer to use
>> pm_runtime_get/put_suppliers() APIs in msm_mmu_funcs.
>> * Dropped arm-mmu500 clock patch since that would break existing
>> platforms.
>> * Changed compatible 'qcom,msm8996-smmu-v2' to 'qcom,smmu-v2' to
>> reflect
>> the IP version rather than the platform on which it is used.
>> The same IP is used across multiple platforms including msm8996,
>> and sdm845 etc.
>> * Using clock bulk APIs to handle the clocks available to the IP as
>> suggested by Stephen Boyd.
>> * The first patch in v4 version of the patch-series:
>> ("iommu/arm-smmu: Fix the error path in arm_smmu_add_device") has
>> already made it to mainline.
>>
>> [V4]
>> * Reworked the clock handling part. We now take clock names as data
>> in the driver for supported compatible versions, and loop over them
>> to get, enable, and disable the clocks.
>> * Using qcom,msm8996 based compatibles for bindings instead of a
>> generic
>> qcom compatible.
>> * Refactor MMU500 patch to just add the necessary clock names data and
>> corresponding bindings.
>> * Added the pm_runtime_get/put() calls in .unmap iommu op (fix added
>> by
>> Stanimir on top of previous patch version.
>> * Added a patch to fix error path in arm_smmu_add_device()
>> * Removed patch 3/5 of V3 patch series that added qcom,smmu-v2
>> bindings.
>>
>> [V3]
>> * Reworked the patches to keep the clocks init/enabling function
>> separately for each compatible.
>>
>> * Added clocks bindings for MMU40x/500.
>>
>> * Added a new compatible for qcom,smmu-v2 implementation and
>> the clock bindings for the same.
>>
>> * Rebased on top of 4.11-rc1
>>
>> [V2]
>> * Split the patches little differently.
>>
>> * Addressed comments.
>>
>> * Removed the patch #4 [2] from previous post
>> for arm-smmu context save restore. Planning to
>> post this separately after reworking/addressing Robin's
>> feedback.
>>
>> * Reversed the sequence to disable clocks than enabling.
>> This was required for those cases where the
>> clocks are populated in a dependent order from DT.
>>
>> [1] https://lkml.org/lkml/2016/10/20/70
>> [2] https://patchwork.kernel.org/patch/9389717/
>> [3] https://patchwork.kernel.org/patch/10204925/
>> [4] https://patchwork.kernel.org/patch/10102445/
>> [5] https://lkml.org/lkml/2018/3/14/127
>> [6] https://patchwork.kernel.org/patch/10204945/
>> [7] https://patchwork.kernel.org/patch/10204925/
>> [8] https://patchwork.kernel.org/patch/10254105/
>> [9] https://patchwork.kernel.org/patch/10277975/
>> [10] https://patchwork.kernel.org/patch/10281613/
>>
>> Sricharan R (3):
>> iommu/arm-smmu: Add pm_runtime/sleep ops
>> iommu/arm-smmu: Invoke pm_runtime during probe, add/remove device
>> iommu/arm-smmu: Add the device_link between masters and smmu
>>
>> Vivek Gautam (1):
>> iommu/arm-smmu: Add support for qcom,smmu-v2 variant
>>
>> .../devicetree/bindings/iommu/arm,smmu.txt | 42 +++++
>> drivers/iommu/arm-smmu.c | 178
>> +++++++++++++++++++--
>> 2 files changed, 210 insertions(+), 10 deletions(-)
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
^ permalink raw reply
* Re: [PATCH v2 5/6] soc: qcom: rpmh powerdomain driver
From: Rajendra Nayak @ 2018-05-30 10:07 UTC (permalink / raw)
To: Viresh Kumar
Cc: David Collins, sboyd, andy.gross, ulf.hansson, devicetree,
linux-arm-msm, linux-kernel, Lina Iyer
In-Reply-To: <20180530094438.xnyukvhum7tc6roh@vireshk-i7>
On 05/30/2018 03:14 PM, Viresh Kumar wrote:
> On 30-05-18, 14:25, Rajendra Nayak wrote:
>> []...
>>
>>>>> +Required Properties:
>>>>> + - compatible: Should be one of the following
>>>>> + * qcom,sdm845-rpmhpd: RPMh powerdomain for the sdm845 family of SoC
>>>>> + - power-domain-cells: number of cells in power domain specifier
>>>>> + must be 1
>>>>> + - operating-points-v2: Phandle to the OPP table for the power-domain.
>>>>> + Refer to Documentation/devicetree/bindings/power/power_domain.txt
>>>>> + and Documentation/devicetree/bindings/opp/qcom-opp.txt for more details
>>>>> +
>>>>> +Example:
>>>>> +
>>>>> + rpmhpd: power-controller {
>>>>> + compatible = "qcom,sdm845-rpmhpd";
>>>>> + #power-domain-cells = <1>;
>>>>> + operating-points-v2 = <&rpmhpd_opp_table>,
>>>>> + <&rpmhpd_opp_table>,
>>>>> + <&rpmhpd_opp_table>,
>>>>> + <&rpmhpd_opp_table>,
>>>>> + <&rpmhpd_opp_table>,
>>>>> + <&rpmhpd_opp_table>,
>>>>> + <&rpmhpd_opp_table>,
>>>>> + <&rpmhpd_opp_table>,
>>>>> + <&rpmhpd_opp_table>;
>>>>
>>>> Can this be changed to simply:
>>>> operating-points-v2 = <&rpmhpd_opp_table>;
>>>>
>>>> The opp binding documentation [1] states that this should be ok:
>>>>
>>>> If only one phandle is available, then the same OPP table will be used
>>>> for all power domains provided by the power domain provider.
>>>
>>> thanks, I mentioned this to Viresh but didn't realize he fixed it up.
>>> Will remove the redundant entries.
>>
>> Looks like the kernel implementation does not handle this yet, and I get
>> an error adding the OPP tables for the powerdomains if I just specify
>> a single OPP table phandle.
>>
>> Viresh, is this expected with the latest patches in linux-next?
>>
>> It would be good if I can specify just one phandle instead of coping
>> the same phandle n times.
>
> Please try this untested hunk:
yes, seems to work.
> diff --git a/drivers/opp/of.c b/drivers/opp/of.c
> index 6d15f05bfc28..7af0ddec936b 100644
> --- a/drivers/opp/of.c
> +++ b/drivers/opp/of.c
> @@ -554,11 +554,24 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table);
> int dev_pm_opp_of_add_table_indexed(struct device *dev, int index)
> {
> struct device_node *opp_np;
> - int ret;
> + int ret, count;
>
> +again:
> opp_np = _opp_of_get_opp_desc_node(dev->of_node, index);
> - if (!opp_np)
> + if (!opp_np) {
> + /*
> + * If only one phandle is present, then the same OPP table
> + * applies for all index requests.
> + */
> + count = of_count_phandle_with_args(dev->of_node,
> + "operating-points-v2", NULL);
> + if (count == 1 && index) {
> + index = 0;
> + goto again;
> + }
> +
> return -ENODEV;
> + }
>
> ret = _of_add_opp_table_v2(dev, opp_np);
> of_node_put(opp_np);
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply
* Re: [PATCH 6/9] ARM: dts: wheat: Drop MTD partitioning from DT
From: Marek Vasut @ 2018-05-30 10:13 UTC (permalink / raw)
To: Simon Horman, Geert Uytterhoeven
Cc: open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Geert Uytterhoeven, Wolfram Sang, Richard Weinberger,
Linux-Renesas, Boris Brezillon, Laurent Pinchart, Linux ARM,
Marek Vasut
In-Reply-To: <20180528093602.eb36j34bbfzmpmw2@verge.net.au>
On 05/28/2018 11:36 AM, Simon Horman wrote:
> On Mon, May 28, 2018 at 10:54:57AM +0200, Geert Uytterhoeven wrote:
>> Hi Simon,
>>
>> On Mon, May 28, 2018 at 10:41 AM, Simon Horman <horms@verge.net.au> wrote:
>>> On Thu, May 24, 2018 at 04:52:59PM +0200, Marek Vasut wrote:
>>>> On 05/23/2018 08:25 AM, Geert Uytterhoeven wrote:
>>>>> On Wed, May 23, 2018 at 12:01 AM, Marek Vasut <marek.vasut@gmail.com> wrote:
>>>>>> On 05/22/2018 04:43 PM, Geert Uytterhoeven wrote:
>>>>>>> On Tue, May 22, 2018 at 2:02 PM, Marek Vasut <marek.vasut@gmail.com> wrote:
>>>>>>>> Drop the MTD partitioning from DT, since it does not describe HW
>>>>>>>> and to give way to a more flexible kernel command line partition
>>>>>>>> passing.
>>>>>>>>
>>>>>>>> To retain the original partitioning, assure you have enabled
>>>>>>>> CONFIG_MTD_CMDLINE_PARTS in your kernel config and add the
>>>>>>>> following to your kernel command line:
>>>>>>>>
>>>>>>>> mtdparts=spi0.0:256k@0(loader),4096k(user),-(flash)
>>>>>>>
>>>>>>> I think the "@0" can be dropped, as it's optional?
>>>>>>> 4m?
>>>>>>
>>>>>> My take on this is that the loader is actually at offset 0x0 of the MTD
>>>>>> device and we explicitly state that in the mtdparts to anchor the first
>>>>>> partition within the MTD device and all the other partitions are at
>>>>>> offset +(sum of the sizes of all partitions listed before the current
>>>>>> one) relative to that first partition.
>>>>>
>>>>> Where is this explicitly states for the first partition?
>>>>>
>>>>>> Removing the @0 feels fragile at best and it seems to depend on the
>>>>>> current behavior of the code.
>>>>>
>>>>> Better, it also depends on the documented behavior:
>>>>>
>>>>> Documentation/admin-guide/kernel-parameters.txt refers to
>>>>> drivers/mtd/cmdlinepart.c, which states:
>>>>>
>>>>> * <offset> := standard linux memsize
>>>>> * if omitted the part will immediately follow the previous part
>>>>> * or 0 if the first part
>>>>>
>>>>> None of the examples listed there or under the MTD_CMDLINE_PARTS Kconfig
>>>>> help text, or in a defconfig bundled with the kernel, use @0 for the first
>>>>> partition.
>>>>
>>>> I think this is exceptionally fragile and dangerous to depend on this,
>>>> but so be it.
>>>
>>> Could you respin with this change?
>>>
>>> I would also like to ask for another change, in light of recent
>>> feedback from Olof Johansson ("Re: [GIT PULL] Renesas ARM64 Based SoC DT
>>> Updates for v4.18").
>>>
>>> Please consolidate the dts patches into a single patch?
>>
>> I think it's better to keep them split, as each commit description mentions
>> what needs to be passed on the kernel command line for the corresponding
>> board.
>>
>> Combining it in a single patch makes it much harder to extract this information.
>> Unless you're fine with a list:
>>
>> koelsch: ...
>> wheat: mtdparts=spi0.0:256k@0(loader),4096k(user),-(flash)
>
> Lets try a list.
Reposted with a list, twice :/
--
Best regards,
Marek Vasut
^ permalink raw reply
* Re: [PATCH v2 1/6] soc: qcom: rpmpd: Add a powerdomain driver to model corners
From: Rajendra Nayak @ 2018-05-30 10:14 UTC (permalink / raw)
To: Ulf Hansson
Cc: Viresh Kumar, Stephen Boyd, Andy Gross, devicetree, linux-arm-msm,
Linux Kernel Mailing List, collinsd
In-Reply-To: <CAPDyKFoAJjZknWtbbQLn0Hnc3Du_1vnSUnqfwZLYK76j2rg52g@mail.gmail.com>
On 05/30/2018 02:47 PM, Ulf Hansson wrote:
> On 25 May 2018 at 12:01, Rajendra Nayak <rnayak@codeaurora.org> wrote:
>> The powerdomains for corners just pass the performance state set by the
>> consumers to the RPM (Remote Power manager) which then takes care
>> of setting the appropriate voltage on the corresponding rails to
>> meet the performance needs.
>>
>> We add all powerdomain data needed on msm8996 here. This driver can easily
>> be extended by adding data for other qualcomm SoCs as well.
>>
>> Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
>> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
>> ---
>> .../devicetree/bindings/power/qcom,rpmpd.txt | 55 ++++
>
> Please split DT doc changes into separate patches, to simplify review.
yes, i will split it when I resend the series.
>
>> drivers/soc/qcom/Kconfig | 9 +
>> drivers/soc/qcom/Makefile | 1 +
>> drivers/soc/qcom/rpmpd.c | 299 ++++++++++++++++++
>> 4 files changed, 364 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/power/qcom,rpmpd.txt
>> create mode 100644 drivers/soc/qcom/rpmpd.c
>>
>
> [...]
>
>> +++ b/drivers/soc/qcom/rpmpd.c
>> @@ -0,0 +1,299 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
>> + */
>> +
>> +#include <linux/err.h>
>> +#include <linux/export.h>
>> +#include <linux/init.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/mutex.h>
>> +#include <linux/pm_domain.h>
>> +#include <linux/mfd/qcom_rpm.h>
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/soc/qcom/smd-rpm.h>
>> +
>> +#include <dt-bindings/mfd/qcom-rpm.h>
>> +
>> +#define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd)
>> +
>> +/* Resource types */
>> +#define RPMPD_SMPA 0x61706d73
>> +#define RPMPD_LDOA 0x616f646c
>> +
>> +/* Operation Keys */
>> +#define KEY_CORNER 0x6e726f63 /* corn */
>> +#define KEY_ENABLE 0x6e657773 /* swen */
>> +#define KEY_FLOOR_CORNER 0x636676 /* vfc */
>> +
>> +#define DEFINE_RPMPD_CORN_SMPA(_platform, _name, _active, r_id) \
>> + static struct rpmpd _platform##_##_active; \
>> + static struct rpmpd _platform##_##_name = { \
>> + .pd = { .name = #_name, }, \
>> + .peer = &_platform##_##_active, \
>> + .res_type = RPMPD_SMPA, \
>> + .res_id = r_id, \
>> + .key = KEY_CORNER, \
>> + }; \
>> + static struct rpmpd _platform##_##_active = { \
>> + .pd = { .name = #_active, }, \
>> + .peer = &_platform##_##_name, \
>> + .active_only = true, \
>> + .res_type = RPMPD_SMPA, \
>> + .res_id = r_id, \
>> + .key = KEY_CORNER, \
>> + }
>> +
>> +#define DEFINE_RPMPD_CORN_LDOA(_platform, _name, r_id) \
>> + static struct rpmpd _platform##_##_name = { \
>> + .pd = { .name = #_name, }, \
>> + .res_type = RPMPD_LDOA, \
>> + .res_id = r_id, \
>> + .key = KEY_CORNER, \
>> + }
>> +
>> +#define DEFINE_RPMPD_VFC(_platform, _name, r_id, r_type) \
>> + static struct rpmpd _platform##_##_name = { \
>> + .pd = { .name = #_name, }, \
>> + .res_type = r_type, \
>> + .res_id = r_id, \
>> + .key = KEY_FLOOR_CORNER, \
>> + }
>> +
>> +#define DEFINE_RPMPD_VFC_SMPA(_platform, _name, r_id) \
>> + DEFINE_RPMPD_VFC(_platform, _name, r_id, RPMPD_SMPA)
>> +
>> +#define DEFINE_RPMPD_VFC_LDOA(_platform, _name, r_id) \
>> + DEFINE_RPMPD_VFC(_platform, _name, r_id, RPMPD_LDOA)
>> +
>> +struct rpmpd_req {
>> + __le32 key;
>> + __le32 nbytes;
>> + __le32 value;
>> +};
>> +
>> +struct rpmpd {
>> + struct generic_pm_domain pd;
>> + struct rpmpd *peer;
>> + const bool active_only;
>> + unsigned long corner;
>> + bool enabled;
>> + const char *res_name;
>> + const int res_type;
>> + const int res_id;
>> + struct qcom_smd_rpm *rpm;
>> + __le32 key;
>> +};
>> +
>> +struct rpmpd_desc {
>> + struct rpmpd **rpmpds;
>> + size_t num_pds;
>> +};
>> +
>> +static DEFINE_MUTEX(rpmpd_lock);
>> +
>> +/* msm8996 RPM powerdomains */
>> +DEFINE_RPMPD_CORN_SMPA(msm8996, vddcx, vddcx_ao, 1);
>> +DEFINE_RPMPD_CORN_SMPA(msm8996, vddmx, vddmx_ao, 2);
>> +DEFINE_RPMPD_CORN_LDOA(msm8996, vddsscx, 26);
>> +
>> +DEFINE_RPMPD_VFC_SMPA(msm8996, vddcx_vfc, 1);
>> +DEFINE_RPMPD_VFC_LDOA(msm8996, vddsscx_vfc, 26);
>> +
>> +static struct rpmpd *msm8996_rpmpds[] = {
>> + [0] = &msm8996_vddcx,
>> + [1] = &msm8996_vddcx_ao,
>> + [2] = &msm8996_vddcx_vfc,
>> + [3] = &msm8996_vddmx,
>> + [4] = &msm8996_vddmx_ao,
>> + [5] = &msm8996_vddsscx,
>> + [6] = &msm8996_vddsscx_vfc,
>> +};
>
> It's not my call, but honestly the above all macros makes the code
> less readable.
This is all static data per SoC. The macros will keep the new additions
needed for every new SoC to a minimal. Currently this supports only
msm8996.
>
> Anyway, I think you should convert to allocate these structs
> dynamically from the heap (kzalloc/kcalloc), instead of statically as
> above.
>
>> +
>> +static const struct rpmpd_desc msm8996_desc = {
>> + .rpmpds = msm8996_rpmpds,
>> + .num_pds = ARRAY_SIZE(msm8996_rpmpds),
>> +};
>> +
>> +static const struct of_device_id rpmpd_match_table[] = {
>> + { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc },
>> + { }
>> +};
>> +MODULE_DEVICE_TABLE(of, rpmpd_match_table);
>
> [...]
>
>> +static int rpmpd_aggregate_corner(struct rpmpd *pd)
>> +{
>
> Isn't the aggregation of the performance states in genpd sufficient
> for your case?
>
> I guess this is SoC specific and needed anyways, but then could you
> perhaps add a few comments about what goes on here?
Yes, this is SoC specific aggregation for active and sleep votes.
i will add comments to clarify this is different from the aggregation
done at the framework level.
>
>> + int ret;
>> + struct rpmpd *peer = pd->peer;
>> + unsigned long active_corner, sleep_corner;
>> + unsigned long this_corner = 0, this_sleep_corner = 0;
>> + unsigned long peer_corner = 0, peer_sleep_corner = 0;
>> +
>> + to_active_sleep(pd, pd->corner, &this_corner, &this_sleep_corner);
>> +
>> + if (peer && peer->enabled)
>> + to_active_sleep(peer, peer->corner, &peer_corner,
>> + &peer_sleep_corner);
>> +
>> + active_corner = max(this_corner, peer_corner);
>> +
>> + ret = rpmpd_send_corner(pd, QCOM_RPM_ACTIVE_STATE, active_corner);
>> + if (ret)
>> + return ret;
>> +
>> + sleep_corner = max(this_sleep_corner, peer_sleep_corner);
>> +
>> + return rpmpd_send_corner(pd, QCOM_RPM_SLEEP_STATE, sleep_corner);
>> +}
>
> [...]
>
>> +static int rpmpd_probe(struct platform_device *pdev)
>> +{
>> + int i;
>> + size_t num;
>> + struct genpd_onecell_data *data;
>> + struct qcom_smd_rpm *rpm;
>> + struct rpmpd **rpmpds;
>> + const struct rpmpd_desc *desc;
>> +
>> + rpm = dev_get_drvdata(pdev->dev.parent);
>> + if (!rpm) {
>> + dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n");
>> + return -ENODEV;
>> + }
>> +
>> + desc = of_device_get_match_data(&pdev->dev);
>> + if (!desc)
>> + return -EINVAL;
>> +
>> + rpmpds = desc->rpmpds;
>> + num = desc->num_pds;
>> +
>> + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
>> + if (!data)
>> + return -ENOMEM;
>> +
>> + data->domains = devm_kcalloc(&pdev->dev, num, sizeof(*data->domains),
>> + GFP_KERNEL);
>> + data->num_domains = num;
>> +
>> + for (i = 0; i < num; i++) {
>> + if (!rpmpds[i])
>> + continue;
>> +
>> + rpmpds[i]->rpm = rpm;
>> + rpmpds[i]->pd.power_off = rpmpd_power_off;
>> + rpmpds[i]->pd.power_on = rpmpd_power_on;
>> + pm_genpd_init(&rpmpds[i]->pd, NULL, true);
>
> Question: Is there no hierarchical topology of the PM domains. No
> genpd subdomains?
The hierarchy if any is all handled by the remote core (RPM in this case).
For Linux its just a flat view.
>
>> +
>> + data->domains[i] = &rpmpds[i]->pd;
>> + }
>> +
>> + return of_genpd_add_provider_onecell(pdev->dev.of_node, data);
>> +}
>> +
>> +static int rpmpd_remove(struct platform_device *pdev)
>> +{
>> + of_genpd_del_provider(pdev->dev.of_node);
>> + return 0;
>> +}
>> +
>> +static struct platform_driver rpmpd_driver = {
>> + .driver = {
>> + .name = "qcom-rpmpd",
>> + .of_match_table = rpmpd_match_table,
>> + },
>> + .probe = rpmpd_probe,
>> + .remove = rpmpd_remove,
>> +};
>> +
>> +static int __init rpmpd_init(void)
>> +{
>> + return platform_driver_register(&rpmpd_driver);
>> +}
>> +core_initcall(rpmpd_init);
>> +
>> +static void __exit rpmpd_exit(void)
>> +{
>> + platform_driver_unregister(&rpmpd_driver);
>> +}
>> +module_exit(rpmpd_exit);
>> +
>> +MODULE_DESCRIPTION("Qualcomm RPM Power Domain Driver");
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_ALIAS("platform:qcom-rpmpd");
>> --
>> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
>> of Code Aurora Forum, hosted by The Linux Foundation
>>
>
> Besides the minor things above, this looks good to me.
thanks,
Rajendra
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply
* Re: [PATCH 0/7] gnss: add new GNSS subsystem
From: Johan Hovold @ 2018-05-30 10:26 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Johan Hovold, Sebastian Reichel, Greg Kroah-Hartman, Rob Herring,
Mark Rutland, Andreas Kemnade, Arnd Bergmann,
H . Nikolaus Schaller, Pavel Machek, LKML, devicetree
In-Reply-To: <0EFEDDD9-C21B-458B-884D-FC23F3D38B94@holtmann.org>
Hi Marcel,
Sorry about the late reply. I got side-tracked with other things.
On Tue, May 08, 2018 at 10:03:57PM +0200, Marcel Holtmann wrote:
> Hi Johan,
>
> >>>>>> I have one concern, though. While providing raw data by
> >>>>>> default is fine generally, it is a problem with device
> >>>>>> auto-discovery. I think there should be some IOCTL from
> >>>>>> the start, that can be used to inform userspace about
> >>>>>> the raw protocol being used (i.e. "NMEA"). I fear, that
> >>>>>> userspace may start to just assume raw = NMEA without
> >>>>>> having this (especially since all initial drivers provide
> >>>>>> NMEA).
> >>>>>
> >>>>> One problem I see here would be that the driver does not necessarily
> >>>>> know either what protocol is currently being used. Some devices have
> >>>>> boot-pins which can be used to configure the initial protocol used (and
> >>>>> this could perhaps be reflected in DT), but this can often later be
> >>>>> changed (by user space) and even be made persistent using battery-backed
> >>>>> ram or eeproms.
> >>>>>
> >>>>> Also note that at least u-blox devices supports having more than one
> >>>>> protocol active on the same port...
> >>>>
> >>>> as long as userspace can determine that it is GNSS hardware and what
> >>>> hardware it is, then you deal with the rest in userspace.
> >>>
> >>> Yeah, I think that will do for now.
> >>
> >> I forgot to mention that this part should be simple. So providing a
> >> DEVTYPE attribute that can be easily associated to the /dev/gnssX
> >> nodes is a must have here. Doing complex mapping of USB or DT layouts
> >> to figure out this is NMEA vs some vendor vs I need extra code to
> >> change the mode etc.
> >
> > Yes, as I mentioned in the cover letter some kind of generic interface
> > for identifying the device type (and its features) should be defined
> > eventually.
>
> I think this needs to be present from the start. Half backed
> subsystems are dangerous. And I really want to avoid hacking in
> userspace to figure out details about the hardware.
Fair enough. I've now added support for determining the GNSS type, which
reflects the protocol(s) supported by the device and which should allow,
for example, the gpsd protocol probing hack to be dropped.
Currently, there are three types defined:
"NMEA" NMEA 0183
"SiRF" SiRF Binary
"UBX" UBX
Note that both SiRF and UBX type devices typically support a subset of
NMEA 0183 with vendor extensions (e.g. to allow switching to the vendor
protocol).
> > Note that this is not necessarily something that is needed from the
> > start however as, for example, gpsd implements protocol detection.
>
> That might be, but that is a total hack. Lets get this right from the
> get-go.
I agree; it's horrid.
Thanks,
Johan
^ permalink raw reply
* Re: [v5 2/6] dmaengine: fsl-qdma: Add qDMA controller driver for Layerscape SoCs
From: Vinod Koul @ 2018-05-30 10:27 UTC (permalink / raw)
To: Wen He
Cc: dmaengine@vger.kernel.org, robh+dt@kernel.org,
devicetree@vger.kernel.org, Leo Li, Jiafei Pan, Jiaheng Fan
In-Reply-To: <AM6PR0402MB3382F92D1123CDCA0E0075EDE26D0@AM6PR0402MB3382.eurprd04.prod.outlook.com>
On 29-05-18, 10:38, Wen He wrote:
> > > > > + /*
> > > > > + * Clear the command queue interrupt detect register for all
> > queues.
> > > > > + */
> > > > > + qdma_writel(fsl_qdma, 0xffffffff, block + FSL_QDMA_BCQIDR(0));
> > > >
> > > > bunch of writes with 0xffffffff, can you explain why? Also helps to
> > > > make a macro for this
> > > >
> > >
> > > Maybe I missed that I should defined the value to the macro and add
> > comment.
> > > Right?
> >
> > that would help, but why are you writing 0xffffffff at all these places?
>
> This value is from the datasheet.
> Should I write comments to here?
Yes that would help explaining what this does..
> > > > > +static void fsl_qdma_issue_pending(struct dma_chan *chan) {
> > > > > + struct fsl_qdma_chan *fsl_chan = to_fsl_qdma_chan(chan);
> > > > > + struct fsl_qdma_queue *fsl_queue = fsl_chan->queue;
> > > > > + unsigned long flags;
> > > > > +
> > > > > + spin_lock_irqsave(&fsl_queue->queue_lock, flags);
> > > > > + spin_lock(&fsl_chan->vchan.lock);
> > > > > + if (vchan_issue_pending(&fsl_chan->vchan))
> > > > > + fsl_qdma_enqueue_desc(fsl_chan);
> > > > > + spin_unlock(&fsl_chan->vchan.lock);
> > > > > + spin_unlock_irqrestore(&fsl_queue->queue_lock, flags);
> > > >
> > > > why do we need two locks, and since you are doing vchan why should
> > > > you add your own lock on top
> > > >
> > >
> > > Yes, we need two locks.
> > > As you know, the QDMA support multiple virtualized blocks for multi-core
> > support.
> > > so we need to make sure that muliti-core access issues.
> >
> > but why cant you use vchan lock for all?
> >
>
> We can't only use vchan lock for all. otherwise enqueue action will be interrupted.
I think it is possible to use only vchan lock
--
~Vinod
^ permalink raw reply
* [PATCH v2 0/8] gnss: add new GNSS subsystem
From: Johan Hovold @ 2018-05-30 10:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Mark Rutland
Cc: Andreas Kemnade, Arnd Bergmann, H . Nikolaus Schaller,
Pavel Machek, Marcel Holtmann, Sebastian Reichel, Tony Lindgren,
linux-kernel, devicetree, Johan Hovold
This series adds a new subsystem for GNSS receivers (e.g. GPS
receivers).
While GNSS receivers are typically accessed using a UART interface they
often also support other I/O interfaces such as I2C, SPI and USB, while
yet other devices use iomem or even some form of remote-processor
messaging (rpmsg).
The new GNSS subsystem abstracts the underlying interface and provides a
new "gnss" class type, which exposes a character-device interface (e.g.
/dev/gnss0) to user space. This allows GNSS receivers to have a
representation in the Linux device model, something which is important
not least for power management purposes and which also allows for easy
detection and identification of GNSS devices.
Note that the character-device interface provides raw access to whatever
protocol the receiver is (currently) using, such as NMEA 0183, UBX or
SiRF Binary. These protocols are expected to be continued to be handled
by user space for the time being, even if some hybrid solutions are also
conceivable (e.g. to have kernel drivers issue management commands).
This will still allow for better platform integration by allowing GNSS
devices and their resources (e.g. regulators and enable-gpios) to be
described by firmware and managed by kernel drivers rather than
platform-specific scripts and services.
While the current interface is kept minimal, it could be extended using
IOCTLs, sysfs or uevents as needs and proper abstraction levels are
identified and determined (e.g. for device and feature identification).
Another possible extension is to add generic 1PPS support.
I decided to go with a custom character-device interface rather than
pretend that these abstract GNSS devices are still TTY devices (e.g.
/dev/ttyGNSS0). Obviously, modifying line settings or reading modem
control signals does not make any sense for a device using, say, a
USB (not USB-serial) or iomem interface. This also means, however, that
user space would no longer be able to set the line speed to match a new
port configuration that can be set using the various GNSS protocols when
the underlying interface is indeed a UART; instead this would need to be
taken care of by the driver.
Also note that writes are always synchronous instead of requiring user
space to call tcdrain() after every command.
This all seems to work well-enough (e.g. with gpsd), but please let me
know if I've overlooked something which would indeed require a TTY
interface instead.
I have implemented drivers for receivers based on two common GNSS
chipsets; SiRFstar and u-blox. Due to lack of hardware, the sirf driver
has been tested using a mockup device and a USB-serial-based SiRFstar IV
GPS (using out-of-tree USB-serial code). [ Let me know if you've got any
evaluation kits to spare. ] The ubx driver has been tested using a
u-blox 8 GNSS evaluation kit (thanks u-blox!).
Finally, note that documentation (including kerneldoc) remains to be
written, but hopefully this will not hinder review given that the
current interfaces are fairly self-describing.
Johan
Changes in v2
- add device type support (new patch 8/8)
- fix one unprotected access to ops->write_raw
- add support for optional v_bckp supply to ubx driver
- drop unnecessary dev_dbgs (Greg)
- simplify open() error path (Greg)
- indent function parameters further
- use gserial->drvdata to access variable length data
- dt-bindings
- document required reg property for I2C, SPI and USB bindings (Rob)
- use "pin name:" prefix when referring to datasheet names (Rob)
- add vendor prefix to sirf gpios (Rob)
- add optional u-blox v-bckp supply (Rob)
- add optional u-blox extint gpio
- minor clean ups
- add Rob's Reviewed-by tag to patches (2/8 and 6/8)
Johan Hovold (8):
gnss: add GNSS receiver subsystem
dt-bindings: add generic gnss binding
gnss: add generic serial driver
dt-bindings: gnss: add u-blox binding
gnss: add driver for u-blox receivers
dt-bindings: gnss: add sirfstar binding
gnss: add driver for sirfstar-based receivers
gnss: add device type support
Documentation/ABI/testing/sysfs-class-gnss | 15 +
.../devicetree/bindings/gnss/gnss.txt | 36 ++
.../devicetree/bindings/gnss/sirfstar.txt | 45 ++
.../devicetree/bindings/gnss/u-blox.txt | 44 ++
.../devicetree/bindings/vendor-prefixes.txt | 4 +
MAINTAINERS | 8 +
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/gnss/Kconfig | 43 ++
drivers/gnss/Makefile | 16 +
drivers/gnss/core.c | 420 ++++++++++++++++++
drivers/gnss/serial.c | 275 ++++++++++++
drivers/gnss/serial.h | 47 ++
drivers/gnss/sirf.c | 408 +++++++++++++++++
drivers/gnss/ubx.c | 153 +++++++
include/linux/gnss.h | 75 ++++
16 files changed, 1592 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-class-gnss
create mode 100644 Documentation/devicetree/bindings/gnss/gnss.txt
create mode 100644 Documentation/devicetree/bindings/gnss/sirfstar.txt
create mode 100644 Documentation/devicetree/bindings/gnss/u-blox.txt
create mode 100644 drivers/gnss/Kconfig
create mode 100644 drivers/gnss/Makefile
create mode 100644 drivers/gnss/core.c
create mode 100644 drivers/gnss/serial.c
create mode 100644 drivers/gnss/serial.h
create mode 100644 drivers/gnss/sirf.c
create mode 100644 drivers/gnss/ubx.c
create mode 100644 include/linux/gnss.h
--
2.17.0
^ permalink raw reply
* [PATCH v2 1/8] gnss: add GNSS receiver subsystem
From: Johan Hovold @ 2018-05-30 10:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Mark Rutland
Cc: Andreas Kemnade, Arnd Bergmann, H . Nikolaus Schaller,
Pavel Machek, Marcel Holtmann, Sebastian Reichel, Tony Lindgren,
linux-kernel, devicetree, Johan Hovold
In-Reply-To: <20180530103242.20773-1-johan@kernel.org>
Add a new subsystem for GNSS (e.g. GPS) receivers.
While GNSS receivers are typically accessed using a UART interface they
often also support other I/O interfaces such as I2C, SPI and USB, while
yet other devices use iomem or even some form of remote-processor
messaging (rpmsg).
The new GNSS subsystem abstracts the underlying interface and provides a
new "gnss" class type, which exposes a character-device interface (e.g.
/dev/gnss0) to user space. This allows GNSS receivers to have a
representation in the Linux device model, something which is important
not least for power management purposes.
Note that the character-device interface provides raw access to whatever
protocol the receiver is (currently) using, such as NMEA 0183, UBX or
SiRF Binary. These protocols are expected to be continued to be handled
by user space for the time being, even if some hybrid solutions are also
conceivable (e.g. to have kernel drivers issue management commands).
This will still allow for better platform integration by allowing GNSS
devices and their resources (e.g. regulators and enable-gpios) to be
described by firmware and managed by kernel drivers rather than
platform-specific scripts and services.
While the current interface is kept minimal, it could be extended using
IOCTLs, sysfs or uevents as needs and proper abstraction levels are
identified and determined (e.g. for device and feature identification).
Signed-off-by: Johan Hovold <johan@kernel.org>
---
MAINTAINERS | 6 +
drivers/Kconfig | 2 +
drivers/Makefile | 1 +
drivers/gnss/Kconfig | 11 ++
drivers/gnss/Makefile | 7 +
drivers/gnss/core.c | 371 ++++++++++++++++++++++++++++++++++++++++++
include/linux/gnss.h | 66 ++++++++
7 files changed, 464 insertions(+)
create mode 100644 drivers/gnss/Kconfig
create mode 100644 drivers/gnss/Makefile
create mode 100644 drivers/gnss/core.c
create mode 100644 include/linux/gnss.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 0a1410d5a621..dc3df211c1a7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5962,6 +5962,12 @@ F: Documentation/isdn/README.gigaset
F: drivers/isdn/gigaset/
F: include/uapi/linux/gigaset_dev.h
+GNSS SUBSYSTEM
+M: Johan Hovold <johan@kernel.org>
+S: Maintained
+F: drivers/gnss/
+F: include/linux/gnss.h
+
GO7007 MPEG CODEC
M: Hans Verkuil <hans.verkuil@cisco.com>
L: linux-media@vger.kernel.org
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 95b9ccc08165..ab4d43923c4d 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -9,6 +9,8 @@ source "drivers/bus/Kconfig"
source "drivers/connector/Kconfig"
+source "drivers/gnss/Kconfig"
+
source "drivers/mtd/Kconfig"
source "drivers/of/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 24cd47014657..cc9a7c5f7d2c 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -185,3 +185,4 @@ obj-$(CONFIG_TEE) += tee/
obj-$(CONFIG_MULTIPLEXER) += mux/
obj-$(CONFIG_UNISYS_VISORBUS) += visorbus/
obj-$(CONFIG_SIOX) += siox/
+obj-$(CONFIG_GNSS) += gnss/
diff --git a/drivers/gnss/Kconfig b/drivers/gnss/Kconfig
new file mode 100644
index 000000000000..103fcc70992e
--- /dev/null
+++ b/drivers/gnss/Kconfig
@@ -0,0 +1,11 @@
+#
+# GNSS receiver configuration
+#
+
+menuconfig GNSS
+ tristate "GNSS receiver support"
+ ---help---
+ Say Y here if you have a GNSS receiver (e.g. a GPS receiver).
+
+ To compile this driver as a module, choose M here: the module will
+ be called gnss.
diff --git a/drivers/gnss/Makefile b/drivers/gnss/Makefile
new file mode 100644
index 000000000000..1f7a7baab1d9
--- /dev/null
+++ b/drivers/gnss/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the GNSS subsystem.
+#
+
+obj-$(CONFIG_GNSS) += gnss.o
+gnss-y := core.o
diff --git a/drivers/gnss/core.c b/drivers/gnss/core.c
new file mode 100644
index 000000000000..307894ca2725
--- /dev/null
+++ b/drivers/gnss/core.c
@@ -0,0 +1,371 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * GNSS receiver core
+ *
+ * Copyright (C) 2018 Johan Hovold <johan@kernel.org>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/cdev.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/gnss.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+
+#define GNSS_FLAG_HAS_WRITE_RAW BIT(0)
+
+#define GNSS_MINORS 16
+
+static DEFINE_IDA(gnss_minors);
+static dev_t gnss_first;
+
+/* FIFO size must be a power of two */
+#define GNSS_READ_FIFO_SIZE 4096
+#define GNSS_WRITE_BUF_SIZE 1024
+
+#define to_gnss_device(d) container_of((d), struct gnss_device, dev)
+
+static int gnss_open(struct inode *inode, struct file *file)
+{
+ struct gnss_device *gdev;
+ int ret = 0;
+
+ gdev = container_of(inode->i_cdev, struct gnss_device, cdev);
+
+ get_device(&gdev->dev);
+
+ nonseekable_open(inode, file);
+ file->private_data = gdev;
+
+ down_write(&gdev->rwsem);
+ if (gdev->disconnected) {
+ ret = -ENODEV;
+ goto unlock;
+ }
+
+ if (gdev->count++ == 0) {
+ ret = gdev->ops->open(gdev);
+ if (ret)
+ gdev->count--;
+ }
+unlock:
+ up_write(&gdev->rwsem);
+
+ if (ret)
+ put_device(&gdev->dev);
+
+ return ret;
+}
+
+static int gnss_release(struct inode *inode, struct file *file)
+{
+ struct gnss_device *gdev = file->private_data;
+
+ down_write(&gdev->rwsem);
+ if (gdev->disconnected)
+ goto unlock;
+
+ if (--gdev->count == 0) {
+ gdev->ops->close(gdev);
+ kfifo_reset(&gdev->read_fifo);
+ }
+unlock:
+ up_write(&gdev->rwsem);
+
+ put_device(&gdev->dev);
+
+ return 0;
+}
+
+static ssize_t gnss_read(struct file *file, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct gnss_device *gdev = file->private_data;
+ unsigned int copied;
+ int ret;
+
+ mutex_lock(&gdev->read_mutex);
+ while (kfifo_is_empty(&gdev->read_fifo)) {
+ mutex_unlock(&gdev->read_mutex);
+
+ if (gdev->disconnected)
+ return 0;
+
+ if (file->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ ret = wait_event_interruptible(gdev->read_queue,
+ gdev->disconnected ||
+ !kfifo_is_empty(&gdev->read_fifo));
+ if (ret)
+ return -ERESTARTSYS;
+
+ mutex_lock(&gdev->read_mutex);
+ }
+
+ ret = kfifo_to_user(&gdev->read_fifo, buf, count, &copied);
+ if (ret == 0)
+ ret = copied;
+
+ mutex_unlock(&gdev->read_mutex);
+
+ return ret;
+}
+
+static ssize_t gnss_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct gnss_device *gdev = file->private_data;
+ size_t written = 0;
+ int ret;
+
+ if (gdev->disconnected)
+ return -EIO;
+
+ if (!count)
+ return 0;
+
+ if (!(gdev->flags & GNSS_FLAG_HAS_WRITE_RAW))
+ return -EIO;
+
+ /* Ignoring O_NONBLOCK, write_raw() is synchronous. */
+
+ ret = mutex_lock_interruptible(&gdev->write_mutex);
+ if (ret)
+ return -ERESTARTSYS;
+
+ for (;;) {
+ size_t n = count - written;
+
+ if (n > GNSS_WRITE_BUF_SIZE)
+ n = GNSS_WRITE_BUF_SIZE;
+
+ if (copy_from_user(gdev->write_buf, buf, n)) {
+ ret = -EFAULT;
+ goto out_unlock;
+ }
+
+ /*
+ * Assumes write_raw can always accept GNSS_WRITE_BUF_SIZE
+ * bytes.
+ *
+ * FIXME: revisit
+ */
+ down_read(&gdev->rwsem);
+ if (!gdev->disconnected)
+ ret = gdev->ops->write_raw(gdev, gdev->write_buf, n);
+ else
+ ret = -EIO;
+ up_read(&gdev->rwsem);
+
+ if (ret < 0)
+ break;
+
+ written += ret;
+ buf += ret;
+
+ if (written == count)
+ break;
+ }
+
+ if (written)
+ ret = written;
+out_unlock:
+ mutex_unlock(&gdev->write_mutex);
+
+ return ret;
+}
+
+static __poll_t gnss_poll(struct file *file, poll_table *wait)
+{
+ struct gnss_device *gdev = file->private_data;
+ __poll_t mask = 0;
+
+ poll_wait(file, &gdev->read_queue, wait);
+
+ if (!kfifo_is_empty(&gdev->read_fifo))
+ mask |= EPOLLIN | EPOLLRDNORM;
+ if (gdev->disconnected)
+ mask |= EPOLLHUP;
+
+ return mask;
+}
+
+static const struct file_operations gnss_fops = {
+ .owner = THIS_MODULE,
+ .open = gnss_open,
+ .release = gnss_release,
+ .read = gnss_read,
+ .write = gnss_write,
+ .poll = gnss_poll,
+ .llseek = no_llseek,
+};
+
+static struct class *gnss_class;
+
+static void gnss_device_release(struct device *dev)
+{
+ struct gnss_device *gdev = to_gnss_device(dev);
+
+ kfree(gdev->write_buf);
+ kfifo_free(&gdev->read_fifo);
+ ida_simple_remove(&gnss_minors, gdev->id);
+ kfree(gdev);
+}
+
+struct gnss_device *gnss_allocate_device(struct device *parent)
+{
+ struct gnss_device *gdev;
+ struct device *dev;
+ int id;
+ int ret;
+
+ gdev = kzalloc(sizeof(*gdev), GFP_KERNEL);
+ if (!gdev)
+ return NULL;
+
+ id = ida_simple_get(&gnss_minors, 0, GNSS_MINORS, GFP_KERNEL);
+ if (id < 0) {
+ kfree(gdev);
+ return ERR_PTR(id);
+ }
+
+ gdev->id = id;
+
+ dev = &gdev->dev;
+ device_initialize(dev);
+ dev->devt = gnss_first + id;
+ dev->class = gnss_class;
+ dev->parent = parent;
+ dev->release = gnss_device_release;
+ dev_set_drvdata(dev, gdev);
+ dev_set_name(dev, "gnss%d", id);
+
+ init_rwsem(&gdev->rwsem);
+ mutex_init(&gdev->read_mutex);
+ mutex_init(&gdev->write_mutex);
+ init_waitqueue_head(&gdev->read_queue);
+
+ ret = kfifo_alloc(&gdev->read_fifo, GNSS_READ_FIFO_SIZE, GFP_KERNEL);
+ if (ret)
+ goto err_put_device;
+
+ gdev->write_buf = kzalloc(GNSS_WRITE_BUF_SIZE, GFP_KERNEL);
+ if (!gdev->write_buf)
+ goto err_put_device;
+
+ cdev_init(&gdev->cdev, &gnss_fops);
+ gdev->cdev.owner = THIS_MODULE;
+
+ return gdev;
+
+err_put_device:
+ put_device(dev);
+
+ return ERR_PTR(-ENOMEM);
+}
+EXPORT_SYMBOL_GPL(gnss_allocate_device);
+
+void gnss_put_device(struct gnss_device *gdev)
+{
+ put_device(&gdev->dev);
+}
+EXPORT_SYMBOL_GPL(gnss_put_device);
+
+int gnss_register_device(struct gnss_device *gdev)
+{
+ int ret;
+
+ /* Set a flag which can be accessed without holding the rwsem. */
+ if (gdev->ops->write_raw != NULL)
+ gdev->flags |= GNSS_FLAG_HAS_WRITE_RAW;
+
+ ret = cdev_device_add(&gdev->cdev, &gdev->dev);
+ if (ret) {
+ dev_err(&gdev->dev, "failed to add device: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gnss_register_device);
+
+void gnss_deregister_device(struct gnss_device *gdev)
+{
+ down_write(&gdev->rwsem);
+ gdev->disconnected = true;
+ if (gdev->count) {
+ wake_up_interruptible(&gdev->read_queue);
+ gdev->ops->close(gdev);
+ }
+ up_write(&gdev->rwsem);
+
+ cdev_device_del(&gdev->cdev, &gdev->dev);
+}
+EXPORT_SYMBOL_GPL(gnss_deregister_device);
+
+/*
+ * Caller guarantees serialisation.
+ *
+ * Must not be called for a closed device.
+ */
+int gnss_insert_raw(struct gnss_device *gdev, const unsigned char *buf,
+ size_t count)
+{
+ int ret;
+
+ ret = kfifo_in(&gdev->read_fifo, buf, count);
+
+ wake_up_interruptible(&gdev->read_queue);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(gnss_insert_raw);
+
+static int __init gnss_module_init(void)
+{
+ int ret;
+
+ ret = alloc_chrdev_region(&gnss_first, 0, GNSS_MINORS, "gnss");
+ if (ret < 0) {
+ pr_err("failed to allocate device numbers: %d\n", ret);
+ return ret;
+ }
+
+ gnss_class = class_create(THIS_MODULE, "gnss");
+ if (IS_ERR(gnss_class)) {
+ ret = PTR_ERR(gnss_class);
+ pr_err("failed to create class: %d\n", ret);
+ goto err_unregister_chrdev;
+ }
+
+ pr_info("GNSS driver registered with major %d\n", MAJOR(gnss_first));
+
+ return 0;
+
+err_unregister_chrdev:
+ unregister_chrdev_region(gnss_first, GNSS_MINORS);
+
+ return ret;
+}
+module_init(gnss_module_init);
+
+static void __exit gnss_module_exit(void)
+{
+ class_destroy(gnss_class);
+ unregister_chrdev_region(gnss_first, GNSS_MINORS);
+ ida_destroy(&gnss_minors);
+}
+module_exit(gnss_module_exit);
+
+MODULE_AUTHOR("Johan Hovold <johan@kernel.org>");
+MODULE_DESCRIPTION("GNSS receiver core");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/gnss.h b/include/linux/gnss.h
new file mode 100644
index 000000000000..e26aeac1e0e2
--- /dev/null
+++ b/include/linux/gnss.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * GNSS receiver support
+ *
+ * Copyright (C) 2018 Johan Hovold <johan@kernel.org>
+ */
+
+#ifndef _LINUX_GNSS_H
+#define _LINUX_GNSS_H
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/kfifo.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+
+struct gnss_device;
+
+struct gnss_operations {
+ int (*open)(struct gnss_device *gdev);
+ void (*close)(struct gnss_device *gdev);
+ int (*write_raw)(struct gnss_device *gdev, const unsigned char *buf,
+ size_t count);
+};
+
+struct gnss_device {
+ struct device dev;
+ struct cdev cdev;
+ int id;
+
+ unsigned long flags;
+
+ struct rw_semaphore rwsem;
+ const struct gnss_operations *ops;
+ unsigned int count;
+ unsigned int disconnected:1;
+
+ struct mutex read_mutex;
+ struct kfifo read_fifo;
+ wait_queue_head_t read_queue;
+
+ struct mutex write_mutex;
+ char *write_buf;
+};
+
+struct gnss_device *gnss_allocate_device(struct device *parent);
+void gnss_put_device(struct gnss_device *gdev);
+int gnss_register_device(struct gnss_device *gdev);
+void gnss_deregister_device(struct gnss_device *gdev);
+
+int gnss_insert_raw(struct gnss_device *gdev, const unsigned char *buf,
+ size_t count);
+
+static inline void gnss_set_drvdata(struct gnss_device *gdev, void *data)
+{
+ dev_set_drvdata(&gdev->dev, data);
+}
+
+static inline void *gnss_get_drvdata(struct gnss_device *gdev)
+{
+ return dev_get_drvdata(&gdev->dev);
+}
+
+#endif /* _LINUX_GNSS_H */
--
2.17.0
^ permalink raw reply related
* [PATCH v2 2/8] dt-bindings: add generic gnss binding
From: Johan Hovold @ 2018-05-30 10:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Mark Rutland
Cc: Andreas Kemnade, Arnd Bergmann, H . Nikolaus Schaller,
Pavel Machek, Marcel Holtmann, Sebastian Reichel, Tony Lindgren,
linux-kernel, devicetree, Johan Hovold
In-Reply-To: <20180530103242.20773-1-johan@kernel.org>
Describe generic properties for GNSS receivers.
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Johan Hovold <johan@kernel.org>
---
.../devicetree/bindings/gnss/gnss.txt | 36 +++++++++++++++++++
MAINTAINERS | 1 +
2 files changed, 37 insertions(+)
create mode 100644 Documentation/devicetree/bindings/gnss/gnss.txt
diff --git a/Documentation/devicetree/bindings/gnss/gnss.txt b/Documentation/devicetree/bindings/gnss/gnss.txt
new file mode 100644
index 000000000000..f0cfa69249f8
--- /dev/null
+++ b/Documentation/devicetree/bindings/gnss/gnss.txt
@@ -0,0 +1,36 @@
+GNSS Receiver DT binding
+
+This documents the binding structure and common properties for GNSS receiver
+devices.
+
+A GNSS receiver node is a node named "gnss" and typically resides on a serial
+bus (e.g. UART, I2C or SPI).
+
+Please refer to the following documents for generic properties:
+
+ Documentation/devicetree/bindings/serial/slave-device.txt
+ Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Required properties:
+
+- compatible : A string reflecting the vendor and specific device the node
+ represents
+
+Optional properties:
+- enable-gpios : GPIO used to enable the device
+- timepulse-gpios : Time pulse GPIO
+
+Example:
+
+serial@1234 {
+ compatible = "ns16550a";
+
+ gnss {
+ compatible = "u-blox,neo-8";
+
+ vcc-supply = <&gnss_reg>;
+ timepulse-gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>;
+
+ current-speed = <4800>;
+ };
+};
diff --git a/MAINTAINERS b/MAINTAINERS
index dc3df211c1a7..fa219e80a1f8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5965,6 +5965,7 @@ F: include/uapi/linux/gigaset_dev.h
GNSS SUBSYSTEM
M: Johan Hovold <johan@kernel.org>
S: Maintained
+F: Documentation/devicetree/bindings/gnss/
F: drivers/gnss/
F: include/linux/gnss.h
--
2.17.0
^ permalink raw reply related
* [PATCH v2 3/8] gnss: add generic serial driver
From: Johan Hovold @ 2018-05-30 10:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Mark Rutland
Cc: Andreas Kemnade, Arnd Bergmann, H . Nikolaus Schaller,
Pavel Machek, Marcel Holtmann, Sebastian Reichel, Tony Lindgren,
linux-kernel, devicetree, Johan Hovold
In-Reply-To: <20180530103242.20773-1-johan@kernel.org>
Add a generic serial GNSS driver (library) which provides a common
implementation for the gnss interface and power management (runtime and
system suspend). This allows GNSS drivers for specific chip to be
implemented by simply providing a set_power() callback to handle three
states: ACTIVE, STANDBY and OFF.
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/gnss/Kconfig | 7 ++
drivers/gnss/Makefile | 3 +
drivers/gnss/serial.c | 275 ++++++++++++++++++++++++++++++++++++++++++
drivers/gnss/serial.h | 47 ++++++++
4 files changed, 332 insertions(+)
create mode 100644 drivers/gnss/serial.c
create mode 100644 drivers/gnss/serial.h
diff --git a/drivers/gnss/Kconfig b/drivers/gnss/Kconfig
index 103fcc70992e..f8ee54f99a8d 100644
--- a/drivers/gnss/Kconfig
+++ b/drivers/gnss/Kconfig
@@ -9,3 +9,10 @@ menuconfig GNSS
To compile this driver as a module, choose M here: the module will
be called gnss.
+
+if GNSS
+
+config GNSS_SERIAL
+ tristate
+
+endif # GNSS
diff --git a/drivers/gnss/Makefile b/drivers/gnss/Makefile
index 1f7a7baab1d9..171aba71684d 100644
--- a/drivers/gnss/Makefile
+++ b/drivers/gnss/Makefile
@@ -5,3 +5,6 @@
obj-$(CONFIG_GNSS) += gnss.o
gnss-y := core.o
+
+obj-$(CONFIG_GNSS_SERIAL) += gnss-serial.o
+gnss-serial-y := serial.o
diff --git a/drivers/gnss/serial.c b/drivers/gnss/serial.c
new file mode 100644
index 000000000000..b01ba4438501
--- /dev/null
+++ b/drivers/gnss/serial.c
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Generic serial GNSS receiver driver
+ *
+ * Copyright (C) 2018 Johan Hovold <johan@kernel.org>
+ */
+
+#include <linux/errno.h>
+#include <linux/gnss.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/serdev.h>
+#include <linux/slab.h>
+
+#include "serial.h"
+
+static int gnss_serial_open(struct gnss_device *gdev)
+{
+ struct gnss_serial *gserial = gnss_get_drvdata(gdev);
+ struct serdev_device *serdev = gserial->serdev;
+ int ret;
+
+ ret = serdev_device_open(serdev);
+ if (ret)
+ return ret;
+
+ serdev_device_set_baudrate(serdev, gserial->speed);
+ serdev_device_set_flow_control(serdev, false);
+
+ ret = pm_runtime_get_sync(&serdev->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(&serdev->dev);
+ goto err_close;
+ }
+
+ return 0;
+
+err_close:
+ serdev_device_close(serdev);
+
+ return ret;
+}
+
+static void gnss_serial_close(struct gnss_device *gdev)
+{
+ struct gnss_serial *gserial = gnss_get_drvdata(gdev);
+ struct serdev_device *serdev = gserial->serdev;
+
+ serdev_device_close(serdev);
+
+ pm_runtime_put(&serdev->dev);
+}
+
+static int gnss_serial_write_raw(struct gnss_device *gdev,
+ const unsigned char *buf, size_t count)
+{
+ struct gnss_serial *gserial = gnss_get_drvdata(gdev);
+ struct serdev_device *serdev = gserial->serdev;
+ int ret;
+
+ /* write is only buffered synchronously */
+ ret = serdev_device_write(serdev, buf, count, 0);
+ if (ret < 0)
+ return ret;
+
+ /* FIXME: determine if interrupted? */
+ serdev_device_wait_until_sent(serdev, 0);
+
+ return count;
+}
+
+static const struct gnss_operations gnss_serial_gnss_ops = {
+ .open = gnss_serial_open,
+ .close = gnss_serial_close,
+ .write_raw = gnss_serial_write_raw,
+};
+
+static int gnss_serial_receive_buf(struct serdev_device *serdev,
+ const unsigned char *buf, size_t count)
+{
+ struct gnss_serial *gserial = serdev_device_get_drvdata(serdev);
+ struct gnss_device *gdev = gserial->gdev;
+
+ return gnss_insert_raw(gdev, buf, count);
+}
+
+static const struct serdev_device_ops gnss_serial_serdev_ops = {
+ .receive_buf = gnss_serial_receive_buf,
+ .write_wakeup = serdev_device_write_wakeup,
+};
+
+static int gnss_serial_set_power(struct gnss_serial *gserial,
+ enum gnss_serial_pm_state state)
+{
+ if (!gserial->ops || !gserial->ops->set_power)
+ return 0;
+
+ return gserial->ops->set_power(gserial, state);
+}
+
+/*
+ * FIXME: need to provide subdriver defaults or separate dt parsing from
+ * allocation.
+ */
+static int gnss_serial_parse_dt(struct serdev_device *serdev)
+{
+ struct gnss_serial *gserial = serdev_device_get_drvdata(serdev);
+ struct device_node *node = serdev->dev.of_node;
+ u32 speed = 4800;
+
+ of_property_read_u32(node, "current-speed", &speed);
+
+ gserial->speed = speed;
+
+ return 0;
+}
+
+struct gnss_serial *gnss_serial_allocate(struct serdev_device *serdev,
+ size_t data_size)
+{
+ struct gnss_serial *gserial;
+ struct gnss_device *gdev;
+ int ret;
+
+ gserial = kzalloc(sizeof(*gserial) + data_size, GFP_KERNEL);
+ if (!gserial)
+ return ERR_PTR(-ENOMEM);
+
+ gdev = gnss_allocate_device(&serdev->dev);
+ if (!gdev) {
+ ret = -ENOMEM;
+ goto err_free_gserial;
+ }
+
+ gdev->ops = &gnss_serial_gnss_ops;
+ gnss_set_drvdata(gdev, gserial);
+
+ gserial->serdev = serdev;
+ gserial->gdev = gdev;
+
+ serdev_device_set_drvdata(serdev, gserial);
+ serdev_device_set_client_ops(serdev, &gnss_serial_serdev_ops);
+
+ ret = gnss_serial_parse_dt(serdev);
+ if (ret)
+ goto err_put_device;
+
+ return gserial;
+
+err_put_device:
+ gnss_put_device(gserial->gdev);
+err_free_gserial:
+ kfree(gserial);
+
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(gnss_serial_allocate);
+
+void gnss_serial_free(struct gnss_serial *gserial)
+{
+ gnss_put_device(gserial->gdev);
+ kfree(gserial);
+};
+EXPORT_SYMBOL_GPL(gnss_serial_free);
+
+int gnss_serial_register(struct gnss_serial *gserial)
+{
+ struct serdev_device *serdev = gserial->serdev;
+ int ret;
+
+ if (IS_ENABLED(CONFIG_PM)) {
+ pm_runtime_enable(&serdev->dev);
+ } else {
+ ret = gnss_serial_set_power(gserial, GNSS_SERIAL_ACTIVE);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = gnss_register_device(gserial->gdev);
+ if (ret)
+ goto err_disable_rpm;
+
+ return 0;
+
+err_disable_rpm:
+ if (IS_ENABLED(CONFIG_PM))
+ pm_runtime_disable(&serdev->dev);
+ else
+ gnss_serial_set_power(gserial, GNSS_SERIAL_OFF);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(gnss_serial_register);
+
+void gnss_serial_deregister(struct gnss_serial *gserial)
+{
+ struct serdev_device *serdev = gserial->serdev;
+
+ gnss_deregister_device(gserial->gdev);
+
+ if (IS_ENABLED(CONFIG_PM))
+ pm_runtime_disable(&serdev->dev);
+ else
+ gnss_serial_set_power(gserial, GNSS_SERIAL_OFF);
+}
+EXPORT_SYMBOL_GPL(gnss_serial_deregister);
+
+#ifdef CONFIG_PM
+static int gnss_serial_runtime_suspend(struct device *dev)
+{
+ struct gnss_serial *gserial = dev_get_drvdata(dev);
+
+ return gnss_serial_set_power(gserial, GNSS_SERIAL_STANDBY);
+}
+
+static int gnss_serial_runtime_resume(struct device *dev)
+{
+ struct gnss_serial *gserial = dev_get_drvdata(dev);
+
+ return gnss_serial_set_power(gserial, GNSS_SERIAL_ACTIVE);
+}
+#endif /* CONFIG_PM */
+
+static int gnss_serial_prepare(struct device *dev)
+{
+ if (pm_runtime_suspended(dev))
+ return 1;
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int gnss_serial_suspend(struct device *dev)
+{
+ struct gnss_serial *gserial = dev_get_drvdata(dev);
+ int ret = 0;
+
+ /*
+ * FIXME: serdev currently lacks support for managing the underlying
+ * device's wakeup settings. A workaround would be to close the serdev
+ * device here if it is open.
+ */
+
+ if (!pm_runtime_suspended(dev))
+ ret = gnss_serial_set_power(gserial, GNSS_SERIAL_STANDBY);
+
+ return ret;
+}
+
+static int gnss_serial_resume(struct device *dev)
+{
+ struct gnss_serial *gserial = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (!pm_runtime_suspended(dev))
+ ret = gnss_serial_set_power(gserial, GNSS_SERIAL_ACTIVE);
+
+ return ret;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+const struct dev_pm_ops gnss_serial_pm_ops = {
+ .prepare = gnss_serial_prepare,
+ SET_SYSTEM_SLEEP_PM_OPS(gnss_serial_suspend, gnss_serial_resume)
+ SET_RUNTIME_PM_OPS(gnss_serial_runtime_suspend, gnss_serial_runtime_resume, NULL)
+};
+EXPORT_SYMBOL_GPL(gnss_serial_pm_ops);
+
+MODULE_AUTHOR("Johan Hovold <johan@kernel.org>");
+MODULE_DESCRIPTION("Generic serial GNSS receiver driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gnss/serial.h b/drivers/gnss/serial.h
new file mode 100644
index 000000000000..980ffdc86c2a
--- /dev/null
+++ b/drivers/gnss/serial.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Generic serial GNSS receiver driver
+ *
+ * Copyright (C) 2018 Johan Hovold <johan@kernel.org>
+ */
+
+#ifndef _LINUX_GNSS_SERIAL_H
+#define _LINUX_GNSS_SERIAL_H
+
+#include <asm/termbits.h>
+#include <linux/pm.h>
+
+struct gnss_serial {
+ struct serdev_device *serdev;
+ struct gnss_device *gdev;
+ speed_t speed;
+ const struct gnss_serial_ops *ops;
+ unsigned long drvdata[0];
+};
+
+enum gnss_serial_pm_state {
+ GNSS_SERIAL_OFF,
+ GNSS_SERIAL_ACTIVE,
+ GNSS_SERIAL_STANDBY,
+};
+
+struct gnss_serial_ops {
+ int (*set_power)(struct gnss_serial *gserial,
+ enum gnss_serial_pm_state state);
+};
+
+extern const struct dev_pm_ops gnss_serial_pm_ops;
+
+struct gnss_serial *gnss_serial_allocate(struct serdev_device *gserial,
+ size_t data_size);
+void gnss_serial_free(struct gnss_serial *gserial);
+
+int gnss_serial_register(struct gnss_serial *gserial);
+void gnss_serial_deregister(struct gnss_serial *gserial);
+
+static inline void *gnss_serial_get_drvdata(struct gnss_serial *gserial)
+{
+ return gserial->drvdata;
+}
+
+#endif /* _LINUX_GNSS_SERIAL_H */
--
2.17.0
^ permalink raw reply related
* [PATCH v2 4/8] dt-bindings: gnss: add u-blox binding
From: Johan Hovold @ 2018-05-30 10:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Mark Rutland
Cc: Andreas Kemnade, Arnd Bergmann, H . Nikolaus Schaller,
Pavel Machek, Marcel Holtmann, Sebastian Reichel, Tony Lindgren,
linux-kernel, devicetree, Johan Hovold
In-Reply-To: <20180530103242.20773-1-johan@kernel.org>
Add binding for u-blox GNSS receivers.
Note that the u-blox product names encodes form factor (e.g. "neo"),
chipset (e.g. "8") and variant (e.g. "q"), but that only formfactor and
chipset is used for the compatible strings (for now).
Signed-off-by: Johan Hovold <johan@kernel.org>
---
.../devicetree/bindings/gnss/u-blox.txt | 44 +++++++++++++++++++
.../devicetree/bindings/vendor-prefixes.txt | 1 +
2 files changed, 45 insertions(+)
create mode 100644 Documentation/devicetree/bindings/gnss/u-blox.txt
diff --git a/Documentation/devicetree/bindings/gnss/u-blox.txt b/Documentation/devicetree/bindings/gnss/u-blox.txt
new file mode 100644
index 000000000000..caef9ace0b0c
--- /dev/null
+++ b/Documentation/devicetree/bindings/gnss/u-blox.txt
@@ -0,0 +1,44 @@
+u-blox GNSS Receiver DT binding
+
+The u-blox GNSS receivers can use UART, DDC (I2C), SPI and USB interfaces.
+
+Please see Documentation/devicetree/bindings/gnss/gnss.txt for generic
+properties.
+
+Required properties:
+
+- compatible : Must be one of
+
+ "u-blox,neo-8"
+ "u-blox,neo-m8"
+
+- vcc-supply : Main voltage regulator
+
+Required properties (DDC):
+- reg : DDC (I2C) slave address
+
+Required properties (SPI):
+- reg : SPI chip select address
+
+Required properties (USB):
+- reg : Number of the USB hub port or the USB host-controller port
+ to which this device is attached
+
+Optional properties:
+
+- timepulse-gpios : Time pulse GPIO
+- u-blox,extint-gpios : External interrupt GPIO
+- v-bckp-supply : Backup voltage regulator
+
+Example:
+
+serial@1234 {
+ compatible = "ns16550a";
+
+ gnss {
+ compatible = "u-blox,neo-8";
+
+ v-bckp-supply = <&gnss_v_bckp_reg>;
+ vcc-supply = <&gnss_vcc_reg>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index b5f978a4cac6..2128dfdf73f1 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -374,6 +374,7 @@ tronsmart Tronsmart
truly Truly Semiconductors Limited
tsd Theobroma Systems Design und Consulting GmbH
tyan Tyan Computer Corporation
+u-blox u-blox
ucrobotics uCRobotics
ubnt Ubiquiti Networks
udoo Udoo
--
2.17.0
^ permalink raw reply related
* [PATCH v2 5/8] gnss: add driver for u-blox receivers
From: Johan Hovold @ 2018-05-30 10:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Mark Rutland
Cc: Andreas Kemnade, Arnd Bergmann, H . Nikolaus Schaller,
Pavel Machek, Marcel Holtmann, Sebastian Reichel, Tony Lindgren,
linux-kernel, devicetree, Johan Hovold
In-Reply-To: <20180530103242.20773-1-johan@kernel.org>
Add driver for serial-connected u-blox GNSS receivers.
Note that the driver uses the generic GNSS serial implementation and
therefore essentially only manages power abstracted into three power
states: ACTIVE, STANDBY, and OFF.
For u-blox receivers with a main supply and no enable-gpios, this simply
means that the main supply is disabled in STANDBY and OFF (the optional
backup supply is kept enabled while the driver is bound).
Note that timepulse-support is not yet implemented.
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/gnss/Kconfig | 13 ++++
drivers/gnss/Makefile | 3 +
drivers/gnss/ubx.c | 151 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 167 insertions(+)
create mode 100644 drivers/gnss/ubx.c
diff --git a/drivers/gnss/Kconfig b/drivers/gnss/Kconfig
index f8ee54f99a8d..784b8c0367d9 100644
--- a/drivers/gnss/Kconfig
+++ b/drivers/gnss/Kconfig
@@ -15,4 +15,17 @@ if GNSS
config GNSS_SERIAL
tristate
+config GNSS_UBX_SERIAL
+ tristate "u-blox GNSS receiver support"
+ depends on SERIAL_DEV_BUS
+ select GNSS_SERIAL
+ ---help---
+ Say Y here if you have a u-blox GNSS receiver which uses a serial
+ interface.
+
+ To compile this driver as a module, choose M here: the module will
+ be called gnss-ubx.
+
+ If unsure, say N.
+
endif # GNSS
diff --git a/drivers/gnss/Makefile b/drivers/gnss/Makefile
index 171aba71684d..d9295b20b7bc 100644
--- a/drivers/gnss/Makefile
+++ b/drivers/gnss/Makefile
@@ -8,3 +8,6 @@ gnss-y := core.o
obj-$(CONFIG_GNSS_SERIAL) += gnss-serial.o
gnss-serial-y := serial.o
+
+obj-$(CONFIG_GNSS_UBX_SERIAL) += gnss-ubx.o
+gnss-ubx-y := ubx.o
diff --git a/drivers/gnss/ubx.c b/drivers/gnss/ubx.c
new file mode 100644
index 000000000000..ecddfb362a6f
--- /dev/null
+++ b/drivers/gnss/ubx.c
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * u-blox GNSS receiver driver
+ *
+ * Copyright (C) 2018 Johan Hovold <johan@kernel.org>
+ */
+
+#include <linux/errno.h>
+#include <linux/gnss.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+#include <linux/serdev.h>
+
+#include "serial.h"
+
+struct ubx_data {
+ struct regulator *v_bckp;
+ struct regulator *vcc;
+};
+
+static int ubx_set_active(struct gnss_serial *gserial)
+{
+ struct ubx_data *data = gnss_serial_get_drvdata(gserial);
+ int ret;
+
+ ret = regulator_enable(data->vcc);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ubx_set_standby(struct gnss_serial *gserial)
+{
+ struct ubx_data *data = gnss_serial_get_drvdata(gserial);
+ int ret;
+
+ ret = regulator_disable(data->vcc);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ubx_set_power(struct gnss_serial *gserial,
+ enum gnss_serial_pm_state state)
+{
+ switch (state) {
+ case GNSS_SERIAL_ACTIVE:
+ return ubx_set_active(gserial);
+ case GNSS_SERIAL_OFF:
+ case GNSS_SERIAL_STANDBY:
+ return ubx_set_standby(gserial);
+ }
+
+ return -EINVAL;
+}
+
+const struct gnss_serial_ops ubx_gserial_ops = {
+ .set_power = ubx_set_power,
+};
+
+static int ubx_probe(struct serdev_device *serdev)
+{
+ struct gnss_serial *gserial;
+ struct ubx_data *data;
+ int ret;
+
+ gserial = gnss_serial_allocate(serdev, sizeof(*data));
+ if (IS_ERR(gserial)) {
+ ret = PTR_ERR(gserial);
+ return ret;
+ }
+
+ gserial->ops = &ubx_gserial_ops;
+
+ data = gnss_serial_get_drvdata(gserial);
+
+ data->vcc = devm_regulator_get(&serdev->dev, "vcc");
+ if (IS_ERR(data->vcc)) {
+ ret = PTR_ERR(data->vcc);
+ goto err_free_gserial;
+ }
+
+ data->v_bckp = devm_regulator_get_optional(&serdev->dev, "v-bckp");
+ if (IS_ERR(data->v_bckp)) {
+ ret = PTR_ERR(data->v_bckp);
+ if (ret == -ENODEV)
+ data->v_bckp = NULL;
+ else
+ goto err_free_gserial;
+ }
+
+ if (data->v_bckp) {
+ ret = regulator_enable(data->v_bckp);
+ if (ret)
+ goto err_free_gserial;
+ }
+
+ ret = gnss_serial_register(gserial);
+ if (ret)
+ goto err_disable_v_bckp;
+
+ return 0;
+
+err_disable_v_bckp:
+ if (data->v_bckp)
+ regulator_disable(data->v_bckp);
+err_free_gserial:
+ gnss_serial_free(gserial);
+
+ return ret;
+}
+
+static void ubx_remove(struct serdev_device *serdev)
+{
+ struct gnss_serial *gserial = serdev_device_get_drvdata(serdev);
+ struct ubx_data *data = gnss_serial_get_drvdata(gserial);
+
+ gnss_serial_deregister(gserial);
+ if (data->v_bckp)
+ regulator_disable(data->v_bckp);
+ gnss_serial_free(gserial);
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id ubx_of_match[] = {
+ { .compatible = "u-blox,neo-8" },
+ { .compatible = "u-blox,neo-m8" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ubx_of_match);
+#endif
+
+static struct serdev_device_driver ubx_driver = {
+ .driver = {
+ .name = "gnss-ubx",
+ .of_match_table = of_match_ptr(ubx_of_match),
+ .pm = &gnss_serial_pm_ops,
+ },
+ .probe = ubx_probe,
+ .remove = ubx_remove,
+};
+module_serdev_device_driver(ubx_driver);
+
+MODULE_AUTHOR("Johan Hovold <johan@kernel.org>");
+MODULE_DESCRIPTION("u-blox GNSS receiver driver");
+MODULE_LICENSE("GPL v2");
--
2.17.0
^ permalink raw reply related
* [PATCH v2 6/8] dt-bindings: gnss: add sirfstar binding
From: Johan Hovold @ 2018-05-30 10:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Mark Rutland
Cc: Andreas Kemnade, Arnd Bergmann, H . Nikolaus Schaller,
Pavel Machek, Marcel Holtmann, Sebastian Reichel, Tony Lindgren,
linux-kernel, devicetree, Johan Hovold
In-Reply-To: <20180530103242.20773-1-johan@kernel.org>
Add binding for SiRFstar-based GNSS receivers.
Note that while four compatible-strings are initially added representing
devices which differ in which I/O interfaces they support, they
otherwise essentially share the same feature set.
Pin and supply names vary slightly, as do some recommended timings.
Note that the wakeup gpio is not intended to be used as a wakeup source,
but rather to detect the current power state of the device (active or
hibernate).
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Johan Hovold <johan@kernel.org>
---
.../devicetree/bindings/gnss/sirfstar.txt | 45 +++++++++++++++++++
.../devicetree/bindings/vendor-prefixes.txt | 3 ++
2 files changed, 48 insertions(+)
create mode 100644 Documentation/devicetree/bindings/gnss/sirfstar.txt
diff --git a/Documentation/devicetree/bindings/gnss/sirfstar.txt b/Documentation/devicetree/bindings/gnss/sirfstar.txt
new file mode 100644
index 000000000000..5803a7831f81
--- /dev/null
+++ b/Documentation/devicetree/bindings/gnss/sirfstar.txt
@@ -0,0 +1,45 @@
+SiRFstar-based GNSS Receiver DT binding
+
+SiRFstar chipsets are used in GNSS-receiver modules produced by several
+vendors and can use UART, SPI or I2C interfaces.
+
+Please see Documentation/devicetree/bindings/gnss/gnss.txt for generic
+properties.
+
+Required properties:
+
+- compatible : Must be one of
+
+ "fastrax,uc430"
+ "linx,r4"
+ "wi2wi,w2sg0008i"
+ "wi2wi,w2sg0084i"
+
+- vcc-supply : Main voltage regulator (pin name: 3V3_IN, VCC, VDD)
+
+Required properties (I2C):
+- reg : I2C slave address
+
+Required properties (SPI):
+- reg : SPI chip select address
+
+Optional properties:
+
+- sirf,onoff-gpios : GPIO used to power on and off device (pin name: ON_OFF)
+- sirf,wakeup-gpios : GPIO used to determine device power state
+ (pin name: RFPWRUP, WAKEUP)
+- timepulse-gpios : Time pulse GPIO (pin name: 1PPS, TM)
+
+Example:
+
+serial@1234 {
+ compatible = "ns16550a";
+
+ gnss {
+ compatible = "wi2wi,w2sg0084i";
+
+ vcc-supply = <&gnss_reg>;
+ sirf,onoff-gpios = <&gpio0 16 GPIO_ACTIVE_HIGH>;
+ sirf,wakeup-gpios = <&gpio0 17 GPIO_ACTIVE_HIGH>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 2128dfdf73f1..61db9d2391c4 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -120,6 +120,7 @@ excito Excito
ezchip EZchip Semiconductor
fairphone Fairphone B.V.
faraday Faraday Technology Corporation
+fastrax Fastrax Oy
fcs Fairchild Semiconductor
firefly Firefly
focaltech FocalTech Systems Co.,Ltd
@@ -197,6 +198,7 @@ licheepi Lichee Pi
linaro Linaro Limited
linksys Belkin International, Inc. (Linksys)
linux Linux-specific binding
+linx Linx Technologies
lltc Linear Technology Corporation
lsi LSI Corp. (LSI Logic)
lwn Liebherr-Werk Nenzing GmbH
@@ -393,6 +395,7 @@ vot Vision Optical Technology Co., Ltd.
wd Western Digital Corp.
wetek WeTek Electronics, limited.
wexler Wexler
+wi2wi Wi2Wi, Inc.
winbond Winbond Electronics corp.
winstar Winstar Display Corp.
wlf Wolfson Microelectronics
--
2.17.0
^ permalink raw reply related
* [PATCH v2 7/8] gnss: add driver for sirfstar-based receivers
From: Johan Hovold @ 2018-05-30 10:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Mark Rutland
Cc: Andreas Kemnade, Arnd Bergmann, H . Nikolaus Schaller,
Pavel Machek, Marcel Holtmann, Sebastian Reichel, Tony Lindgren,
linux-kernel, devicetree, Johan Hovold
In-Reply-To: <20180530103242.20773-1-johan@kernel.org>
Add driver for serial-connected SiRFstar-based GNSS receivers.
These devices typically boot into hibernate mode from which they can be
woken using a pulse on the ON_OFF input pin. Once active, a pulse on the
same ON_OFF pin is used to put the device back into hibernate mode. The
current state can be determined by sampling the WAKEUP output.
Hardware configurations where WAKEUP has been connected to ON_OFF (and
where an initial WAKEUP pulse during boot is sufficient to have the
device boot into active mode) are also supported. In this case, device
power is managed using the main-supply regulator only.
Note that configurations where WAKEUP is left not connected, so that the
device power state can only indirectly be determined using the I/O
interface, is currently not supported. It should be fairly
straight-forward to extend the current implementation with such support
however (and this this is the main reason for not using the generic
serial implementation for this driver).
Note that timepulse-support is left unimplemented.
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/gnss/Kconfig | 12 ++
drivers/gnss/Makefile | 3 +
drivers/gnss/sirf.c | 407 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 422 insertions(+)
create mode 100644 drivers/gnss/sirf.c
diff --git a/drivers/gnss/Kconfig b/drivers/gnss/Kconfig
index 784b8c0367d9..6abc88514512 100644
--- a/drivers/gnss/Kconfig
+++ b/drivers/gnss/Kconfig
@@ -15,6 +15,18 @@ if GNSS
config GNSS_SERIAL
tristate
+config GNSS_SIRF_SERIAL
+ tristate "SiRFstar GNSS receiver support"
+ depends on SERIAL_DEV_BUS
+ ---help---
+ Say Y here if you have a SiRFstar-based GNSS receiver which uses a
+ serial interface.
+
+ To compile this driver as a module, choose M here: the module will
+ be called gnss-sirf.
+
+ If unsure, say N.
+
config GNSS_UBX_SERIAL
tristate "u-blox GNSS receiver support"
depends on SERIAL_DEV_BUS
diff --git a/drivers/gnss/Makefile b/drivers/gnss/Makefile
index d9295b20b7bc..5cf0ebe0330a 100644
--- a/drivers/gnss/Makefile
+++ b/drivers/gnss/Makefile
@@ -9,5 +9,8 @@ gnss-y := core.o
obj-$(CONFIG_GNSS_SERIAL) += gnss-serial.o
gnss-serial-y := serial.o
+obj-$(CONFIG_GNSS_SIRF_SERIAL) += gnss-sirf.o
+gnss-sirf-y := sirf.o
+
obj-$(CONFIG_GNSS_UBX_SERIAL) += gnss-ubx.o
gnss-ubx-y := ubx.o
diff --git a/drivers/gnss/sirf.c b/drivers/gnss/sirf.c
new file mode 100644
index 000000000000..5fb0f730db48
--- /dev/null
+++ b/drivers/gnss/sirf.c
@@ -0,0 +1,407 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SiRFstar GNSS receiver driver
+ *
+ * Copyright (C) 2018 Johan Hovold <johan@kernel.org>
+ */
+
+#include <linux/errno.h>
+#include <linux/gnss.h>
+#include <linux/gpio/consumer.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/serdev.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+#define SIRF_BOOT_DELAY 500
+#define SIRF_ON_OFF_PULSE_TIME 100
+#define SIRF_ACTIVATE_TIMEOUT 200
+#define SIRF_HIBERNATE_TIMEOUT 200
+
+struct sirf_data {
+ struct gnss_device *gdev;
+ struct serdev_device *serdev;
+ speed_t speed;
+ struct regulator *vcc;
+ struct gpio_desc *on_off;
+ struct gpio_desc *wakeup;
+ int irq;
+ bool active;
+ wait_queue_head_t power_wait;
+};
+
+static int sirf_open(struct gnss_device *gdev)
+{
+ struct sirf_data *data = gnss_get_drvdata(gdev);
+ struct serdev_device *serdev = data->serdev;
+ int ret;
+
+ ret = serdev_device_open(serdev);
+ if (ret)
+ return ret;
+
+ serdev_device_set_baudrate(serdev, data->speed);
+ serdev_device_set_flow_control(serdev, false);
+
+ ret = pm_runtime_get_sync(&serdev->dev);
+ if (ret < 0) {
+ dev_err(&gdev->dev, "failed to runtime resume: %d\n", ret);
+ pm_runtime_put_noidle(&serdev->dev);
+ goto err_close;
+ }
+
+ return 0;
+
+err_close:
+ serdev_device_close(serdev);
+
+ return ret;
+}
+
+static void sirf_close(struct gnss_device *gdev)
+{
+ struct sirf_data *data = gnss_get_drvdata(gdev);
+ struct serdev_device *serdev = data->serdev;
+
+ serdev_device_close(serdev);
+
+ pm_runtime_put(&serdev->dev);
+}
+
+static int sirf_write_raw(struct gnss_device *gdev, const unsigned char *buf,
+ size_t count)
+{
+ struct sirf_data *data = gnss_get_drvdata(gdev);
+ struct serdev_device *serdev = data->serdev;
+ int ret;
+
+ /* write is only buffered synchronously */
+ ret = serdev_device_write(serdev, buf, count, 0);
+ if (ret < 0)
+ return ret;
+
+ /* FIXME: determine if interrupted? */
+ serdev_device_wait_until_sent(serdev, 0);
+
+ return count;
+}
+
+static const struct gnss_operations sirf_gnss_ops = {
+ .open = sirf_open,
+ .close = sirf_close,
+ .write_raw = sirf_write_raw,
+};
+
+static int sirf_receive_buf(struct serdev_device *serdev,
+ const unsigned char *buf, size_t count)
+{
+ struct sirf_data *data = serdev_device_get_drvdata(serdev);
+ struct gnss_device *gdev = data->gdev;
+
+ return gnss_insert_raw(gdev, buf, count);
+}
+
+static const struct serdev_device_ops sirf_serdev_ops = {
+ .receive_buf = sirf_receive_buf,
+ .write_wakeup = serdev_device_write_wakeup,
+};
+
+static irqreturn_t sirf_wakeup_handler(int irq, void *dev_id)
+{
+ struct sirf_data *data = dev_id;
+ struct device *dev = &data->serdev->dev;
+ int ret;
+
+ ret = gpiod_get_value_cansleep(data->wakeup);
+ dev_dbg(dev, "%s - wakeup = %d\n", __func__, ret);
+ if (ret < 0)
+ goto out;
+
+ data->active = !!ret;
+ wake_up_interruptible(&data->power_wait);
+out:
+ return IRQ_HANDLED;
+}
+
+static int sirf_wait_for_power_state(struct sirf_data *data, bool active,
+ unsigned long timeout)
+{
+ int ret;
+
+ ret = wait_event_interruptible_timeout(data->power_wait,
+ data->active == active, msecs_to_jiffies(timeout));
+ if (ret < 0)
+ return ret;
+
+ if (ret == 0) {
+ dev_warn(&data->serdev->dev, "timeout waiting for active state = %d\n",
+ active);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static void sirf_pulse_on_off(struct sirf_data *data)
+{
+ gpiod_set_value_cansleep(data->on_off, 1);
+ msleep(SIRF_ON_OFF_PULSE_TIME);
+ gpiod_set_value_cansleep(data->on_off, 0);
+}
+
+static int sirf_set_active(struct sirf_data *data, bool active)
+{
+ unsigned long timeout;
+ int retries = 3;
+ int ret;
+
+ if (active)
+ timeout = SIRF_ACTIVATE_TIMEOUT;
+ else
+ timeout = SIRF_HIBERNATE_TIMEOUT;
+
+ while (retries-- > 0) {
+ sirf_pulse_on_off(data);
+ ret = sirf_wait_for_power_state(data, active, timeout);
+ if (ret < 0) {
+ if (ret == -ETIMEDOUT)
+ continue;
+
+ return ret;
+ }
+
+ break;
+ }
+
+ if (retries == 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int sirf_runtime_suspend(struct device *dev)
+{
+ struct sirf_data *data = dev_get_drvdata(dev);
+
+ if (!data->on_off)
+ return regulator_disable(data->vcc);
+
+ return sirf_set_active(data, false);
+}
+
+static int sirf_runtime_resume(struct device *dev)
+{
+ struct sirf_data *data = dev_get_drvdata(dev);
+
+ if (!data->on_off)
+ return regulator_enable(data->vcc);
+
+ return sirf_set_active(data, true);
+}
+
+static int __maybe_unused sirf_suspend(struct device *dev)
+{
+ struct sirf_data *data = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (!pm_runtime_suspended(dev))
+ ret = sirf_runtime_suspend(dev);
+
+ if (data->wakeup)
+ disable_irq(data->irq);
+
+ return ret;
+}
+
+static int __maybe_unused sirf_resume(struct device *dev)
+{
+ struct sirf_data *data = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (data->wakeup)
+ enable_irq(data->irq);
+
+ if (!pm_runtime_suspended(dev))
+ ret = sirf_runtime_resume(dev);
+
+ return ret;
+}
+
+static const struct dev_pm_ops sirf_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(sirf_suspend, sirf_resume)
+ SET_RUNTIME_PM_OPS(sirf_runtime_suspend, sirf_runtime_resume, NULL)
+};
+
+static int sirf_parse_dt(struct serdev_device *serdev)
+{
+ struct sirf_data *data = serdev_device_get_drvdata(serdev);
+ struct device_node *node = serdev->dev.of_node;
+ u32 speed = 9600;
+
+ of_property_read_u32(node, "current-speed", &speed);
+
+ data->speed = speed;
+
+ return 0;
+}
+
+static int sirf_probe(struct serdev_device *serdev)
+{
+ struct device *dev = &serdev->dev;
+ struct gnss_device *gdev;
+ struct sirf_data *data;
+ int ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ gdev = gnss_allocate_device(dev);
+ if (!gdev)
+ return -ENOMEM;
+
+ gdev->ops = &sirf_gnss_ops;
+ gnss_set_drvdata(gdev, data);
+
+ data->serdev = serdev;
+ data->gdev = gdev;
+
+ init_waitqueue_head(&data->power_wait);
+
+ serdev_device_set_drvdata(serdev, data);
+ serdev_device_set_client_ops(serdev, &sirf_serdev_ops);
+
+ ret = sirf_parse_dt(serdev);
+ if (ret)
+ goto err_put_device;
+
+ data->vcc = devm_regulator_get(dev, "vcc");
+ if (IS_ERR(data->vcc)) {
+ ret = PTR_ERR(data->vcc);
+ goto err_put_device;
+ }
+
+ data->on_off = devm_gpiod_get_optional(dev, "sirf,onoff",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(data->on_off))
+ goto err_put_device;
+
+ if (data->on_off) {
+ data->wakeup = devm_gpiod_get_optional(dev, "sirf,wakeup",
+ GPIOD_IN);
+ if (IS_ERR(data->wakeup))
+ goto err_put_device;
+
+ /*
+ * Configurations where WAKEUP has been left not connected,
+ * are currently not supported.
+ */
+ if (!data->wakeup) {
+ dev_err(dev, "no wakeup gpio specified\n");
+ ret = -ENODEV;
+ goto err_put_device;
+ }
+ }
+
+ if (data->wakeup) {
+ ret = gpiod_to_irq(data->wakeup);
+ if (ret < 0)
+ goto err_put_device;
+
+ data->irq = ret;
+
+ ret = devm_request_threaded_irq(dev, data->irq, NULL,
+ sirf_wakeup_handler,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "wakeup", data);
+ if (ret)
+ goto err_put_device;
+ }
+
+ if (data->on_off) {
+ ret = regulator_enable(data->vcc);
+ if (ret)
+ goto err_put_device;
+
+ /* Wait for chip to boot into hibernate mode */
+ msleep(SIRF_BOOT_DELAY);
+ }
+
+ if (IS_ENABLED(CONFIG_PM)) {
+ pm_runtime_set_suspended(dev); /* clear runtime_error flag */
+ pm_runtime_enable(dev);
+ } else {
+ ret = sirf_runtime_resume(dev);
+ if (ret < 0)
+ goto err_disable_vcc;
+ }
+
+ ret = gnss_register_device(gdev);
+ if (ret)
+ goto err_disable_rpm;
+
+ return 0;
+
+err_disable_rpm:
+ if (IS_ENABLED(CONFIG_PM))
+ pm_runtime_disable(dev);
+ else
+ sirf_runtime_suspend(dev);
+err_disable_vcc:
+ if (data->on_off)
+ regulator_disable(data->vcc);
+err_put_device:
+ gnss_put_device(data->gdev);
+
+ return ret;
+}
+
+static void sirf_remove(struct serdev_device *serdev)
+{
+ struct sirf_data *data = serdev_device_get_drvdata(serdev);
+
+ gnss_deregister_device(data->gdev);
+
+ if (IS_ENABLED(CONFIG_PM))
+ pm_runtime_disable(&serdev->dev);
+ else
+ sirf_runtime_suspend(&serdev->dev);
+
+ if (data->on_off)
+ regulator_disable(data->vcc);
+
+ gnss_put_device(data->gdev);
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id sirf_of_match[] = {
+ { .compatible = "fastrax,uc430" },
+ { .compatible = "linx,r4" },
+ { .compatible = "wi2wi,w2sg0008i" },
+ { .compatible = "wi2wi,w2sg0084i" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sirf_of_match);
+#endif
+
+static struct serdev_device_driver sirf_driver = {
+ .driver = {
+ .name = "gnss-sirf",
+ .of_match_table = of_match_ptr(sirf_of_match),
+ .pm = &sirf_pm_ops,
+ },
+ .probe = sirf_probe,
+ .remove = sirf_remove,
+};
+module_serdev_device_driver(sirf_driver);
+
+MODULE_AUTHOR("Johan Hovold <johan@kernel.org>");
+MODULE_DESCRIPTION("SiRFstar GNSS receiver driver");
+MODULE_LICENSE("GPL v2");
--
2.17.0
^ permalink raw reply related
* [PATCH v2 8/8] gnss: add device type support
From: Johan Hovold @ 2018-05-30 10:32 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Mark Rutland
Cc: Andreas Kemnade, Arnd Bergmann, H . Nikolaus Schaller,
Pavel Machek, Marcel Holtmann, Sebastian Reichel, Tony Lindgren,
linux-kernel, devicetree, Johan Hovold
In-Reply-To: <20180530103242.20773-1-johan@kernel.org>
Add a "type" device attribute and a "GNSS_TYPE" uevent variable which
can be used to determine the type of a GNSS device. The currently
identified types reflect the protocol(s) supported by a device:
"NMEA" NMEA 0183
"SiRF" SiRF Binary
"UBX" UBX
Note that both SiRF and UBX type devices typically support a subset of
NMEA 0183 with vendor extensions (e.g. to allow switching to the vendor
protocol).
Signed-off-by: Johan Hovold <johan@kernel.org>
---
Documentation/ABI/testing/sysfs-class-gnss | 15 +++++++
MAINTAINERS | 1 +
drivers/gnss/core.c | 49 ++++++++++++++++++++++
drivers/gnss/sirf.c | 1 +
drivers/gnss/ubx.c | 2 +
include/linux/gnss.h | 9 ++++
6 files changed, 77 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-class-gnss
diff --git a/Documentation/ABI/testing/sysfs-class-gnss b/Documentation/ABI/testing/sysfs-class-gnss
new file mode 100644
index 000000000000..3bcdf8e2496a
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-gnss
@@ -0,0 +1,15 @@
+What: /sys/class/gnss/gnssN/type
+Date: May 2018
+KernelVersion: 4.18
+Contact: Johan Hovold <johan@kernel.org>
+Description:
+ The GNSS device type. The currently identified types reflect
+ the protocol(s) supported by the device:
+
+ "NMEA" NMEA 0183
+ "SiRF" SiRF Binary
+ "UBX" UBX
+
+ Note that also non-"NMEA" type devices typically support a
+ subset of NMEA 0183 with vendor extensions (e.g. to allow
+ switching to a vendor protocol).
diff --git a/MAINTAINERS b/MAINTAINERS
index fa219e80a1f8..e666bc28a102 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5965,6 +5965,7 @@ F: include/uapi/linux/gigaset_dev.h
GNSS SUBSYSTEM
M: Johan Hovold <johan@kernel.org>
S: Maintained
+F: Documentation/ABI/testing/sysfs-class-gnss
F: Documentation/devicetree/bindings/gnss/
F: drivers/gnss/
F: include/linux/gnss.h
diff --git a/drivers/gnss/core.c b/drivers/gnss/core.c
index 307894ca2725..f30ef8338b3a 100644
--- a/drivers/gnss/core.c
+++ b/drivers/gnss/core.c
@@ -330,6 +330,52 @@ int gnss_insert_raw(struct gnss_device *gdev, const unsigned char *buf,
}
EXPORT_SYMBOL_GPL(gnss_insert_raw);
+static const char * const gnss_type_names[GNSS_TYPE_COUNT] = {
+ [GNSS_TYPE_NMEA] = "NMEA",
+ [GNSS_TYPE_SIRF] = "SiRF",
+ [GNSS_TYPE_UBX] = "UBX",
+};
+
+static const char *gnss_type_name(struct gnss_device *gdev)
+{
+ const char *name = NULL;
+
+ if (gdev->type < GNSS_TYPE_COUNT)
+ name = gnss_type_names[gdev->type];
+
+ if (!name)
+ dev_WARN(&gdev->dev, "type name not defined\n");
+
+ return name;
+}
+
+static ssize_t type_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct gnss_device *gdev = to_gnss_device(dev);
+
+ return sprintf(buf, "%s\n", gnss_type_name(gdev));
+}
+static DEVICE_ATTR_RO(type);
+
+static struct attribute *gnss_attrs[] = {
+ &dev_attr_type.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(gnss);
+
+static int gnss_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct gnss_device *gdev = to_gnss_device(dev);
+ int ret;
+
+ ret = add_uevent_var(env, "GNSS_TYPE=%s", gnss_type_name(gdev));
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static int __init gnss_module_init(void)
{
int ret;
@@ -347,6 +393,9 @@ static int __init gnss_module_init(void)
goto err_unregister_chrdev;
}
+ gnss_class->dev_groups = gnss_groups;
+ gnss_class->dev_uevent = gnss_uevent;
+
pr_info("GNSS driver registered with major %d\n", MAJOR(gnss_first));
return 0;
diff --git a/drivers/gnss/sirf.c b/drivers/gnss/sirf.c
index 5fb0f730db48..79cb98950013 100644
--- a/drivers/gnss/sirf.c
+++ b/drivers/gnss/sirf.c
@@ -267,6 +267,7 @@ static int sirf_probe(struct serdev_device *serdev)
if (!gdev)
return -ENOMEM;
+ gdev->type = GNSS_TYPE_SIRF;
gdev->ops = &sirf_gnss_ops;
gnss_set_drvdata(gdev, data);
diff --git a/drivers/gnss/ubx.c b/drivers/gnss/ubx.c
index ecddfb362a6f..902b6854b7db 100644
--- a/drivers/gnss/ubx.c
+++ b/drivers/gnss/ubx.c
@@ -77,6 +77,8 @@ static int ubx_probe(struct serdev_device *serdev)
gserial->ops = &ubx_gserial_ops;
+ gserial->gdev->type = GNSS_TYPE_UBX;
+
data = gnss_serial_get_drvdata(gserial);
data->vcc = devm_regulator_get(&serdev->dev, "vcc");
diff --git a/include/linux/gnss.h b/include/linux/gnss.h
index e26aeac1e0e2..43546977098c 100644
--- a/include/linux/gnss.h
+++ b/include/linux/gnss.h
@@ -18,6 +18,14 @@
struct gnss_device;
+enum gnss_type {
+ GNSS_TYPE_NMEA = 0,
+ GNSS_TYPE_SIRF,
+ GNSS_TYPE_UBX,
+
+ GNSS_TYPE_COUNT
+};
+
struct gnss_operations {
int (*open)(struct gnss_device *gdev);
void (*close)(struct gnss_device *gdev);
@@ -30,6 +38,7 @@ struct gnss_device {
struct cdev cdev;
int id;
+ enum gnss_type type;
unsigned long flags;
struct rw_semaphore rwsem;
--
2.17.0
^ permalink raw reply related
* Re: [PATCH v4 1/2] regulator: dt-bindings: add QCOM RPMh regulator bindings
From: Mark Brown @ 2018-05-30 10:37 UTC (permalink / raw)
To: Doug Anderson
Cc: David Collins, Liam Girdwood, Rob Herring, Mark Rutland,
linux-arm-msm, Linux ARM, devicetree, LKML, Rajendra Nayak,
Stephen Boyd
In-Reply-To: <CAD=FV=VH0bTxPOmRr+jUyV0cGNQHLcwQTV9L-t0bxZOqD8FnHA@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 705 bytes --]
On Tue, May 29, 2018 at 10:23:20PM -0700, Doug Anderson wrote:
> > + qcom,drms-mode-max-microamps = <10000 1000000>;
> Things look pretty good to me now. I'm still hesitant about the whole
> need to list the modes twice (once using the unordered
> "regulator-allowed-modes" and once to match up against the ordered
> "qcom,drms-mode-max-microamps"). I'm also still of the opinion that
> the whole "drms-mode-max-microamps" ought to be a standard property
> (not a qcom specific one) and handled in the regulator core.
I'm confused as to why we are specifying the maximum current the device
can deliver in a given mode in the DT - surely that's a fixed property
of the hardware?
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v4 0/6] mfd/regulator/clk: bd71837: ROHM BD71837 PMIC driver
From: Mark Brown @ 2018-05-30 11:00 UTC (permalink / raw)
To: Matti Vaittinen
Cc: Matti Vaittinen, mturquette, sboyd, robh+dt, mark.rutland,
lee.jones, lgirdwood, linux-clk, devicetree, linux-kernel,
mikko.mutanen, heikki.haikola
In-Reply-To: <20180530090512.GC13528@localhost.localdomain>
[-- Attachment #1: Type: text/plain, Size: 1908 bytes --]
On Wed, May 30, 2018 at 12:05:12PM +0300, Matti Vaittinen wrote:
> Other 4 can be used on PWM or PFM switching mode. When PWM is used
> voltages can be changed without disabling regulator. On PFM this should
> not be done. These latter 4 regulators can be forced to PWM mode via
> control bit in register. This driver does not support controlling this
> mode though. So this driver version just checks if regulator is enabled
> before changing the voltage and if it is the voltage change fails with
> -EBUSY
It probably should support setting modes (especially if the device isn't
smart enough to automatically shift which sounds like the case) but
that's a separate thing.
> My question is whether it would be good idea to also read the 'force
> PWM' bit when voltage is changed and allow the change if PWM mode is
> forced to be used? Problem is that the check and voltage change can't be
> atomic so there is a chance someone changes the mode (bypassing the
> driver and regulator core) after this check but before we get to modify
> the voltage. Furthermore, I doubt the 'force PWM' is widely used (but I
> can't say for sure as I can't imagine all use cases) as it is not so
> power efficient.
Why would anything else be changing the mode configuration of the
regulator while the system is running? That sounds like a bad idea.
In any case if the hardware really needs to be manually put into force
PWM to change voltage then the simplest thing would be to just move it
into force PWM mode, do the change, then change back if it wasn't
already in force PWM mode.
The tradeoff with forced PWM mode is that the quality of regulation will
be a lot better, especially if the load changes suddenly (as things like
CPUs often do). Most hardware that's at all current is able respond to
changes in load and switch modes automatically when it's appropriate,
except possibly in some very low power modes.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
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