Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH v15 06/13] irqchip: Add irq-ingenic-tcu driver
From: Marc Zyngier @ 2019-07-25  8:21 UTC (permalink / raw)
  To: Paul Cercueil, Ralf Baechle, Paul Burton, James Hogan,
	Jonathan Corbet, Lee Jones, Arnd Bergmann, Daniel Lezcano,
	Thomas Gleixner, Michael Turquette, Stephen Boyd, Jason Cooper,
	Rob Herring, Mark Rutland
  Cc: devicetree, linux-kernel, linux-doc, linux-mips, linux-clk, od,
	Mathieu Malaterre, Artur Rojek
In-Reply-To: <20190724171615.20774-7-paul@crapouillou.net>

On 24/07/2019 18:16, Paul Cercueil wrote:
> This driver handles the interrupt controller built in the Timer/Counter
> Unit (TCU) of the JZ47xx SoCs from Ingenic.
> 
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> Tested-by: Mathieu Malaterre <malat@debian.org>
> Tested-by: Artur Rojek <contact@artur-rojek.eu>
> Reviewed-by: Thomas Gleixner <tglx@linutronix.de>

Acked-by: Marc Zyngier <maz@kernel.org>

Given the various dependencies, I assume the series will get routed via
the MIPS tree.

Thanks,

	M.
-- 
Jazz is not dead, it just smells funny...

^ permalink raw reply

* Re: [PATCH v3 4/5] iio: imu: st_lsm6dsx: add support for accel/gyro unit of lsm9sd1
From: Martin Kepplinger @ 2019-07-25  8:14 UTC (permalink / raw)
  To: Lorenzo Bianconi
  Cc: jic23@kernel.org, knaack.h@gmx.de, lars@metafoo.de,
	pmeerw@pmeerw.net, linux-iio@vger.kernel.org,
	devicetree@vger.kernel.org
In-Reply-To: <CAA2SeNK-pjkSWVsrv5dehEJbakZqR0oPF3DQ5mzhiiOD3Npxkg@mail.gmail.com>

On 25.07.19 09:04, Lorenzo Bianconi wrote:
> 
>     The LSM9DS1's accelerometer / gyroscope unit and it's magnetometer
>     (separately
>     supported in iio/magnetometer/st_magn*) are located on a separate
>     i2c addresses
>     on the bus.
> 
>     For the datasheet, see
>     https://www.st.com/resource/en/datasheet/lsm9ds1.pdf
>     <https://www.st.com/resource/en/datasheet/lsm9ds1.pdf>
> 
>     Treat it just like the LSM6* devices and, despite it's name, hook it up
>     to the st_lsm6dsx driver, using it's basic functionality.
> 
>     Signed-off-by: Martin Kepplinger <martin.kepplinger@puri.sm
>     <mailto:martin.kepplinger@puri.sm>>
> 
> 
> 
>  Hi Martin,
> 
> could you please check if LSM9DS1 and LSM6DS0 have a common register map
> for the supported features (I think so)? If so I think it is better to
> rename LSM9DS1 in LSM6DS0 since st_lsm6dsx supports just acc and gyro
> (we will support LSM9DS1 with a proper dts configuration)
> 
> Regards,
> Lorenzo

Hi Lorenzo,

The register mappings of LSM6DSO and LSM9DS1 don't match (gyro out for
example). The LSM9DS1 magnetometer is a *different* device on the bus
than accel/gyro (despite being on the same chip). That one is already
supported in drivers/iio/magnetometer/st_magn_*

So LSM9DS1 in the imu driver (lsm6dsx) can also just support accel and
gyro in order to complete the support for the device.

Besides, that's the device I have and test here. I can't really name it
differently.

What are you working on (dts description)?

thanks,
                             martin

^ permalink raw reply

* [PATCH 1/1] dt-bindings: power/supply/sbs_sbs-battery: Addition of force_load binding Add device tree binding documentation for addition of force_load boolean value to allow loading a battery during boot even if not present at that time.
From: Richard Tresidder @ 2019-07-25  6:50 UTC (permalink / raw)
  To: sre, robh+dt, mark.rutland, rtresidd, linux-pm, devicetree,
	linux-kernel

Signed-off-by: Richard Tresidder <rtresidd@electromag.com.au>
---

Notes:
    Add device tree binding documentation for addition of force_load
    boolean value to allow loading a battery during boot even if not
    present at that time.
    Accompanying patch to drivers/power/supply/sbs-battery.c submitted to linux-pm@vger.kernel.org

 Documentation/devicetree/bindings/power/supply/sbs_sbs-battery.txt | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/power/supply/sbs_sbs-battery.txt b/Documentation/devicetree/bindings/power/supply/sbs_sbs-battery.txt
index 4e78e51..187d7bb 100644
--- a/Documentation/devicetree/bindings/power/supply/sbs_sbs-battery.txt
+++ b/Documentation/devicetree/bindings/power/supply/sbs_sbs-battery.txt
@@ -15,7 +15,8 @@ Optional properties :
    after an external change notification.
  - sbs,battery-detect-gpios : The gpio which signals battery detection and
    a flag specifying its polarity.
-
+ - sbs,force-load : Allow loading of a hot-pluggable battery when there is no
+   GPIO detect available and the module is statically built.
 Example:
 
 	battery@b {
@@ -24,4 +25,5 @@ Example:
 		sbs,i2c-retry-count = <2>;
 		sbs,poll-retry-count = <10>;
 		sbs,battery-detect-gpios = <&gpio-controller 122 1>;
+		sbs,force-load;
 	}
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH] ath10k: Fix HOST capability QMI incompatibility
From: Bjorn Andersson @ 2019-07-25  6:31 UTC (permalink / raw)
  To: Kalle Valo, David S. Miller, Rob Herring, Mark Rutland
  Cc: linux-wireless, netdev, devicetree, linux-kernel, ath10k, stable

The introduction of 768ec4c012ac ("ath10k: update HOST capability QMI
message") served the purpose of supporting the new and extended HOST
capability QMI message.

But while the new message adds a slew of optional members it changes the
data type of the "daemon_support" member, which means that older
versions of the firmware will fail to decode the incoming request
message.

There is no way to detect this breakage from Linux and there's no way to
recover from sending the wrong message (i.e. we can't just try one
format and then fallback to the other), so a quirk is introduced in
DeviceTree to indicate to the driver that the firmware requires the 8bit
version of this message.

Cc: stable@vger.kernel.org
Fixes: 768ec4c012ac ("ath10k: update HOST capability qmi message")
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
 .../bindings/net/wireless/qcom,ath10k.txt     |  6 +++++
 drivers/net/wireless/ath/ath10k/qmi.c         | 13 ++++++++---
 .../net/wireless/ath/ath10k/qmi_wlfw_v01.c    | 22 +++++++++++++++++++
 .../net/wireless/ath/ath10k/qmi_wlfw_v01.h    |  1 +
 drivers/net/wireless/ath/ath10k/snoc.c        | 11 ++++++++++
 drivers/net/wireless/ath/ath10k/snoc.h        |  1 +
 6 files changed, 51 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
index ae661e65354e..f9499b20d840 100644
--- a/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath10k.txt
@@ -81,6 +81,12 @@ Optional properties:
 	Definition: Name of external front end module used. Some valid FEM names
 		    for example: "microsemi-lx5586", "sky85703-11"
 		    and "sky85803" etc.
+- qcom,snoc-host-cap-8bit-quirk:
+	Usage: Optional
+	Value type: <empty>
+	Definition: Quirk specifying that the firmware expects the 8bit version
+		    of the host capability QMI request
+
 
 Example (to supply PCI based wifi block details):
 
diff --git a/drivers/net/wireless/ath/ath10k/qmi.c b/drivers/net/wireless/ath/ath10k/qmi.c
index 3b63b6257c43..545ac1f06997 100644
--- a/drivers/net/wireless/ath/ath10k/qmi.c
+++ b/drivers/net/wireless/ath/ath10k/qmi.c
@@ -581,22 +581,29 @@ static int ath10k_qmi_host_cap_send_sync(struct ath10k_qmi *qmi)
 {
 	struct wlfw_host_cap_resp_msg_v01 resp = {};
 	struct wlfw_host_cap_req_msg_v01 req = {};
+	struct qmi_elem_info *req_ei;
 	struct ath10k *ar = qmi->ar;
+	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
 	struct qmi_txn txn;
 	int ret;
 
 	req.daemon_support_valid = 1;
 	req.daemon_support = 0;
 
-	ret = qmi_txn_init(&qmi->qmi_hdl, &txn,
-			   wlfw_host_cap_resp_msg_v01_ei, &resp);
+	ret = qmi_txn_init(&qmi->qmi_hdl, &txn, wlfw_host_cap_resp_msg_v01_ei,
+			   &resp);
 	if (ret < 0)
 		goto out;
 
+	if (test_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags))
+		req_ei = wlfw_host_cap_8bit_req_msg_v01_ei;
+	else
+		req_ei = wlfw_host_cap_req_msg_v01_ei;
+
 	ret = qmi_send_request(&qmi->qmi_hdl, NULL, &txn,
 			       QMI_WLFW_HOST_CAP_REQ_V01,
 			       WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN,
-			       wlfw_host_cap_req_msg_v01_ei, &req);
+			       req_ei, &req);
 	if (ret < 0) {
 		qmi_txn_cancel(&txn);
 		ath10k_err(ar, "failed to send host capability request: %d\n", ret);
diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c
index 1fe05c6218c3..86fcf4e1de5f 100644
--- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c
+++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.c
@@ -1988,6 +1988,28 @@ struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[] = {
 	{}
 };
 
+struct qmi_elem_info wlfw_host_cap_8bit_req_msg_v01_ei[] = {
+	{
+		.data_type      = QMI_OPT_FLAG,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type     = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   daemon_support_valid),
+	},
+	{
+		.data_type      = QMI_UNSIGNED_1_BYTE,
+		.elem_len       = 1,
+		.elem_size      = sizeof(u8),
+		.array_type     = NO_ARRAY,
+		.tlv_type       = 0x10,
+		.offset         = offsetof(struct wlfw_host_cap_req_msg_v01,
+					   daemon_support),
+	},
+	{}
+};
+
 struct qmi_elem_info wlfw_host_cap_resp_msg_v01_ei[] = {
 	{
 		.data_type      = QMI_STRUCT,
diff --git a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h
index bca1186e1560..4d107e1364a8 100644
--- a/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h
+++ b/drivers/net/wireless/ath/ath10k/qmi_wlfw_v01.h
@@ -575,6 +575,7 @@ struct wlfw_host_cap_req_msg_v01 {
 
 #define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 189
 extern struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[];
+extern struct qmi_elem_info wlfw_host_cap_8bit_req_msg_v01_ei[];
 
 struct wlfw_host_cap_resp_msg_v01 {
 	struct qmi_response_type_v01 resp;
diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c
index b491361e6ed4..fc15a0037f0e 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.c
+++ b/drivers/net/wireless/ath/ath10k/snoc.c
@@ -1261,6 +1261,15 @@ static int ath10k_snoc_resource_init(struct ath10k *ar)
 	return ret;
 }
 
+static void ath10k_snoc_quirks_init(struct ath10k *ar)
+{
+	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+	struct device *dev = &ar_snoc->dev->dev;
+
+	if (of_property_read_bool(dev->of_node, "qcom,snoc-host-cap-8bit-quirk"))
+		set_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags);
+}
+
 int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type)
 {
 	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
@@ -1678,6 +1687,8 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
 	ar->ce_priv = &ar_snoc->ce;
 	msa_size = drv_data->msa_size;
 
+	ath10k_snoc_quirks_init(ar);
+
 	ret = ath10k_snoc_resource_init(ar);
 	if (ret) {
 		ath10k_warn(ar, "failed to initialize resource: %d\n", ret);
diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h
index d62f53501fbb..9db823e46314 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.h
+++ b/drivers/net/wireless/ath/ath10k/snoc.h
@@ -63,6 +63,7 @@ enum ath10k_snoc_flags {
 	ATH10K_SNOC_FLAG_REGISTERED,
 	ATH10K_SNOC_FLAG_UNREGISTERING,
 	ATH10K_SNOC_FLAG_RECOVERY,
+	ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK,
 };
 
 struct ath10k_snoc {
-- 
2.18.0

^ permalink raw reply related

* Re: [PATCH 2/2] DTS: ARM: gta04: introduce legacy spi-cs-high to make display work again
From: H. Nikolaus Schaller @ 2019-07-25  6:23 UTC (permalink / raw)
  To: Rob Herring, Linus Walleij
  Cc: Mark Brown, Mark Rutland, Benoît Cousson, Tony Lindgren,
	Discussions about the Letux Kernel, linux-spi, devicetree,
	Linux Kernel Mailing List, Linux-OMAP, stable
In-Reply-To: <20190724194259.GA25847@bogus>

Hi Rob,

> Am 24.07.2019 um 21:42 schrieb Rob Herring <robh@kernel.org>:
> 
> On Mon, Jul 08, 2019 at 04:46:05PM +0200, H. Nikolaus Schaller wrote:
>> commit 6953c57ab172 "gpio: of: Handle SPI chipselect legacy bindings"
>> 
>> did introduce logic to centrally handle the legacy spi-cs-high property
>> in combination with cs-gpios. This assumes that the polarity
>> of the CS has to be inverted if spi-cs-high is missing, even
>> and especially if non-legacy GPIO_ACTIVE_HIGH is specified.
>> 
>> The DTS for the GTA04 was orginally introduced under the assumption
>> that there is no need for spi-cs-high if the gpio is defined with
>> proper polarity GPIO_ACTIVE_HIGH.
> 
> Given that spi-cs-high is called legacy, that would imply that DT's 
> should not have to use spi-cs-high.

Yes.

> 
>> This was not a problem until gpiolib changed the interpretation of
>> GPIO_ACTIVE_HIGH and missing spi-cs-high.
> 
> Then we should fix gpiolib...

I tried to convince Linus that this is the right way but he convinced
me that a fix that handles all cases does not exist.

There seem to be embedded devices with older DTB (potentially in ROM)
which provide a plain 0 value for a gpios definition. And either with
or without spi-cs-high.

Since "0" is the same as "GPIO_ACTIVE_HIGH", the absence of
spi-cs-high was and must be interpreted as active low for these
devices. This leads to the inversion logic in code.

AFAIR it boils down to the question if gpiolib and the bindings
should still support such legacy devices with out-of tree DTB,
but force in-tree DTS to add the legacy spi-cs-high property.

Or if we should fix the 2 or 3 cases of in-tree legacy cases
and potentially break out-of tree DTBs.

IMHO it is more general to keep the out-of-tree DTBs working
and "fix" what we can control (in-tree DTS).

> 
>> The effect is that the missing spi-cs-high is now interpreted as CS being
>> low (despite GPIO_ACTIVE_HIGH) which turns off the SPI interface when the
>> panel is to be programmed by the panel driver.
>> 
>> Therefore, we have to add the redundant and legacy spi-cs-high property
>> to properly pass through the legacy handler.
>> 
>> Since this is nowhere documented in the bindings, we add some words of
>> WARNING.
>> 
>> Cc: stable@vger.kernel.org
>> Signed-off-by: H. Nikolaus Schaller <hns@goldelico.com>
>> ---
>> Documentation/devicetree/bindings/spi/spi-bus.txt | 6 ++++++
>> arch/arm/boot/dts/omap3-gta04.dtsi                | 1 +
>> 2 files changed, 7 insertions(+)

BR,
Nikolaus

^ permalink raw reply

* Re: [PATCH 1/4] mailbox: arm_mhuv2: add device tree binding documentation
From: Jassi Brar @ 2019-07-25  5:49 UTC (permalink / raw)
  To: Tushar Khandelwal
  Cc: Linux Kernel Mailing List, tushar.2nov, morten_bp, nd,
	Morten Borup Petersen, Rob Herring, Mark Rutland, Devicetree List
In-Reply-To: <CABb+yY04vW-i35N6P57KSKgmMAYkrA2CDyUvA-bLCZMxiZaocw@mail.gmail.com>

On Sun, Jul 21, 2019 at 4:58 PM Jassi Brar <jassisinghbrar@gmail.com> wrote:
>
> On Wed, Jul 17, 2019 at 2:26 PM Tushar Khandelwal
> <tushar.khandelwal@arm.com> wrote:
>
> > diff --git a/Documentation/devicetree/bindings/mailbox/arm,mhuv2.txt b/Documentation/devicetree/bindings/mailbox/arm,mhuv2.txt
> > new file mode 100644
> > index 000000000000..3a05593414bc
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mailbox/arm,mhuv2.txt
> > @@ -0,0 +1,108 @@
> > +Arm MHUv2 Mailbox Driver
> > +========================
> > +
> > +The Arm Message-Handling-Unit (MHU) Version 2 is a mailbox controller that has
> > +between 1 and 124 channel windows to provide unidirectional communication with
> > +remote processor(s).
> > +
> > +Given the unidirectional nature of the device, an MHUv2 mailbox may only be
> > +written to or read from. If a pair of MHU devices is implemented between two
> > +processing elements to provide bidirectional communication, these must be
> > +specified as two separate mailboxes.
> > +
> > +A device tree node for an Arm MHUv2 device must specify either a receiver frame
> > +or a sender frame, indicating which end of the unidirectional MHU device which
> > +the device node entry describes.
> > +
> > +An MHU device must be specified with a transport protocol. The transport
> > +protocol of an MHU device determines the method of data transmission as well as
> > +the number of provided mailboxes.
> > +Following are the possible transport protocol types:
> > +- Single-word: An MHU device implements as many mailboxes as it
> > +               provides channel windows. Data is transmitted through
> > +               the MHU registers.
> > +- Multi-word:  An MHU device implements a single mailbox. All channel windows
> > +               will be used during transmission. Data is transmitted through
> > +               the MHU registers.
> > +- Doorbell:    An MHU device implements as many mailboxes as there are flag
> > +               bits available in its channel windows. Optionally, data may
> > +               be transmitted through a shared memory region, wherein the MHU
> > +               is used strictly as an interrupt generation mechanism.
> > +
> > +Mailbox Device Node:
> > +====================
> > +
> > +Required properties:
> > +--------------------
> > +- compatible:  Shall be "arm,mhuv2" & "arm,primecell"
> > +- reg:         Contains the mailbox register address range (base
> > +               address and length)
> > +- #mbox-cells  Shall be 1 - the index of the channel needed.
> > +- mhu-frame    Frame type of the device.
> > +               Shall be either "sender" or "receiver"
> > +- mhu-protocol Transport protocol of the device. Shall be one of the
> > +               following: "single-word", "multi-word", "doorbell"
> > +
> > +Required properties (receiver frame):
> > +-------------------------------------
> > +- interrupts:  Contains the interrupt information corresponding to the
> > +               combined interrupt of the receiver frame
> > +
> > +Example:
> > +--------
> > +
> > +       mbox_mw_tx: mhu@10000000 {
> > +               compatible = "arm,mhuv2","arm,primecell";
> > +               reg = <0x10000000 0x1000>;
> > +               clocks = <&refclk100mhz>;
> > +               clock-names = "apb_pclk";
> > +               #mbox-cells = <1>;
> > +               mhu-protocol = "multi-word";
> > +               mhu-frame = "sender";
> > +       };
> > +
> > +       mbox_sw_tx: mhu@10000000 {
> > +               compatible = "arm,mhuv2","arm,primecell";
> > +               reg = <0x11000000 0x1000>;
> > +               clocks = <&refclk100mhz>;
> > +               clock-names = "apb_pclk";
> > +               #mbox-cells = <1>;
> > +               mhu-protocol = "single-word";
> > +               mhu-frame = "sender";
> > +       };
> > +
> > +       mbox_db_rx: mhu@10000000 {
> > +               compatible = "arm,mhuv2","arm,primecell";
> > +               reg = <0x12000000 0x1000>;
> > +               clocks = <&refclk100mhz>;
> > +               clock-names = "apb_pclk";
> > +               #mbox-cells = <1>;
> > +               interrupts = <0 45 4>;
> > +               interrupt-names = "mhu_rx";
> > +               mhu-protocol = "doorbell";
> > +               mhu-frame = "receiver";
> > +       };
> > +
> > +       mhu_client: scb@2e000000 {
> > +       compatible = "fujitsu,mb86s70-scb-1.0";
> > +       reg = <0 0x2e000000 0x4000>;
> > +       mboxes =
> > +               // For multi-word frames, client may only instantiate a single
> > +               // mailbox for a mailbox controller
> > +               <&mbox_mw_tx 0>,
> > +
> > +               // For single-word frames, client may instantiate as many
> > +               // mailboxes as there are channel windows in the MHU
> > +                <&mbox_sw_tx 0>,
> > +                <&mbox_sw_tx 1>,
> > +                <&mbox_sw_tx 2>,
> > +                <&mbox_sw_tx 3>,
> > +
> > +               // For doorbell frames, client may instantiate as many mailboxes
> > +               // as there are bits available in the combined number of channel
> > +               // windows ((channel windows * 32) mailboxes)
> > +                <mbox_db_rx 0>,
> > +                <mbox_db_rx 1>,
> > +                ...
> > +                <mbox_db_rx 17>;
> > +       };
>
> If the mhuv2 instance implements, say, 3 channel windows between
> sender (linux) and receiver (firmware), and Linux runs two protocols
> each requiring 1 and 2-word sized messages respectively. The hardware
> supports that by assigning windows [0] and [1,2] to each protocol.
> However, I don't think the driver can support that. Or does it?
>
Thinking about it, IMO, the mbox-cell should carry a 128 (4x32) bit
mask specifying the set of windows (corresponding to the bits set in
the mask) associated with the channel.
And the controller driver should see any channel as associated with
variable number of windows 'N', where N is [0,124]

mhu_client1: proto1@2e000000 {
       .....
       mboxes = <&mbox 0x0 0x0 0x0 0x1>
}

mhu_client2: proto2@2f000000 {
       .....
       mboxes = <&mbox 0x0 0x0 0x0 0x6>
}

Cheers!

^ permalink raw reply

* Re: [PATCH 1/3] iio: imu: st_lsm6sdx: move some register definitions to sensor_settings struct
From: Martin Kepplinger @ 2019-07-25  5:40 UTC (permalink / raw)
  To: Martin Kepplinger, lorenzo.bianconi83, jic23, knaack.h, lars,
	pmeerw
  Cc: linux-iio, devicetree, linux-kernel
In-Reply-To: <20190715131919.31938-1-martin.kepplinger@puri.sm>

On 15.07.19 15:19, Martin Kepplinger wrote:
> Move some register definitions to the per-device array of struct
> st_lsm6dsx_sensor_settings in order to simplify adding new sensor
> devices to the driver.
> 
> Also, remove completely unused register definitions.
> 
> Signed-off-by: Martin Kepplinger <martin.kepplinger@puri.sm>
> ---
>  drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h      |  6 ++++
>  drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 31 ++++++++++++++------
>  2 files changed, 28 insertions(+), 9 deletions(-)
> 

this series has been resent (and rebased) to be more readable:
https://lore.kernel.org/linux-iio/20190725053132.9589-1-martin.kepplinger@puri.sm/

thanks,
                             martin

^ permalink raw reply

* [PATCH v3 5/5] dt-bindings: iio: imu: st_lsm6dsx: add lsm9ds1 device bindings
From: Martin Kepplinger @ 2019-07-25  5:31 UTC (permalink / raw)
  To: lorenzo.bianconi83, jic23, knaack.h, lars, pmeerw
  Cc: linux-iio, devicetree, linux-kernel, Martin Kepplinger
In-Reply-To: <20190725053132.9589-1-martin.kepplinger@puri.sm>

Signed-off-by: Martin Kepplinger <martin.kepplinger@puri.sm>
---
 Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt b/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
index 92b48f242356..fd1722fc93af 100644
--- a/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
+++ b/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
@@ -12,6 +12,7 @@ Required properties:
   "st,lsm6dsox"
   "st,lsm6dsr"
   "st,lsm6ds3tr-c"
+  "st,lsm9ds1"
 - reg: i2c address of the sensor / spi cs line
 
 Optional properties:
-- 
2.20.1

^ permalink raw reply related

* [PATCH v3 4/5] iio: imu: st_lsm6dsx: add support for accel/gyro unit of lsm9sd1
From: Martin Kepplinger @ 2019-07-25  5:31 UTC (permalink / raw)
  To: lorenzo.bianconi83, jic23, knaack.h, lars, pmeerw
  Cc: linux-iio, devicetree, linux-kernel, Martin Kepplinger
In-Reply-To: <20190725053132.9589-1-martin.kepplinger@puri.sm>

The LSM9DS1's accelerometer / gyroscope unit and it's magnetometer (separately
supported in iio/magnetometer/st_magn*) are located on a separate i2c addresses
on the bus.

For the datasheet, see https://www.st.com/resource/en/datasheet/lsm9ds1.pdf

Treat it just like the LSM6* devices and, despite it's name, hook it up
to the st_lsm6dsx driver, using it's basic functionality.

Signed-off-by: Martin Kepplinger <martin.kepplinger@puri.sm>
---
 drivers/iio/imu/st_lsm6dsx/Kconfig           |  1 +
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h      |  2 +
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 94 +++++++++++++++++++-
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c  |  5 ++
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c  |  5 ++
 5 files changed, 104 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig
index 2d8b2e1edfce..4a57bfb3c12e 100644
--- a/drivers/iio/imu/st_lsm6dsx/Kconfig
+++ b/drivers/iio/imu/st_lsm6dsx/Kconfig
@@ -11,6 +11,7 @@ config IIO_ST_LSM6DSX
 	  Say yes here to build support for STMicroelectronics LSM6DSx imu
 	  sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm,
 	  ism330dlc, lsm6dso, lsm6dsox, asm330lhh, lsm6dsr, lsm6ds3tr-c
+	  and the accelerometer/gyroscope of lsm9ds1.
 
 	  To compile this driver as a module, choose M here: the module
 	  will be called st_lsm6dsx.
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
index 3c47f5d27d30..9a30cc717de2 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
@@ -23,6 +23,7 @@
 #define ST_LSM6DSOX_DEV_NAME	"lsm6dsox"
 #define ST_LSM6DSR_DEV_NAME	"lsm6dsr"
 #define ST_LSM6DS3TRC_DEV_NAME	"lsm6ds3tr-c"
+#define ST_LSM9DS1_DEV_NAME	"lsm9ds1"
 
 enum st_lsm6dsx_hw_id {
 	ST_LSM6DS3_ID,
@@ -35,6 +36,7 @@ enum st_lsm6dsx_hw_id {
 	ST_LSM6DSOX_ID,
 	ST_LSM6DSR_ID,
 	ST_LSM6DS3TRC_ID,
+	ST_LSM9DS1_ID,
 	ST_LSM6DSX_MAX_ID,
 };
 
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
index e0d2149625cc..2f3d2bf25646 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -10,6 +10,8 @@
  * +-125/+-245/+-500/+-1000/+-2000 dps
  * LSM6DSx series has an integrated First-In-First-Out (FIFO) buffer
  * allowing dynamic batching of sensor data.
+ * LSM9DSx series is similar but includes an additional magnetometer, handled
+ * by a different driver.
  *
  * Supported sensors:
  * - LSM6DS3:
@@ -30,6 +32,13 @@
  *   - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
  *   - FIFO size: 3KB
  *
+ * - LSM9DS1:
+ *   - Accelerometer supported ODR [Hz]: 10, 50, 119, 238, 476, 952
+ *   - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
+ *   - Gyroscope supported ODR [Hz]: 15, 60, 119, 238, 476, 952
+ *   - Gyroscope supported full-scale [dps]: +-245/+-500/+-2000
+ *   - FIFO size: 32
+ *
  * Copyright 2016 STMicroelectronics Inc.
  *
  * Lorenzo Bianconi <lorenzo.bianconi@st.com>
@@ -64,7 +73,72 @@
 #define ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR	0x24
 #define ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR	0x26
 
+#define ST_LSM9DSX_REG_GYRO_OUT_X_L_ADDR	0x18
+#define ST_LSM9DSX_REG_GYRO_OUT_Y_L_ADDR	0x1a
+#define ST_LSM9DSX_REG_GYRO_OUT_Z_L_ADDR	0x1c
+
 static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
+	{
+		.wai = 0x68,
+		.int1_addr = 0x0c,
+		.int2_addr = 0x0d,
+		.reset_addr = 0x22,
+		.max_fifo_size = 32,
+		.id = {
+			{
+				.hw_id = ST_LSM9DS1_ID,
+				.name = ST_LSM9DS1_DEV_NAME,
+			},
+		},
+		.odr_table = {
+			[ST_LSM6DSX_ID_ACC] = {
+				.reg = {
+					.addr = 0x20,
+					.mask = GENMASK(7, 5),
+				},
+				.odr_avl[0] = {  10, 0x01 },
+				.odr_avl[1] = {  50, 0x02 },
+				.odr_avl[2] = { 119, 0x03 },
+				.odr_avl[3] = { 238, 0x04 },
+				.odr_avl[4] = { 476, 0x05 },
+				.odr_avl[5] = { 952, 0x06 },
+			},
+			[ST_LSM6DSX_ID_GYRO] = {
+				.reg = {
+					.addr = 0x10,
+					.mask = GENMASK(7, 5),
+				},
+				.odr_avl[0] = {  15, 0x01 },
+				.odr_avl[1] = {  60, 0x02 },
+				.odr_avl[2] = { 119, 0x03 },
+				.odr_avl[3] = { 238, 0x04 },
+				.odr_avl[4] = { 476, 0x05 },
+				.odr_avl[5] = { 952, 0x06 },
+			},
+		},
+		.fs_table = {
+			[ST_LSM6DSX_ID_ACC] = {
+				.reg = {
+					.addr = 0x20,
+					.mask = GENMASK(4, 3),
+				},
+				.fs_avl[0] = {  599, 0x0 },
+				.fs_avl[1] = { 1197, 0x2 },
+				.fs_avl[2] = { 2394, 0x3 },
+				.fs_avl[3] = { 4788, 0x1 },
+			},
+			[ST_LSM6DSX_ID_GYRO] = {
+				.reg = {
+					.addr = 0x10,
+					.mask = GENMASK(4, 3),
+				},
+				.fs_avl[0] = { IIO_DEGREE_TO_RAD(245), 0x0 },
+				.fs_avl[1] = { IIO_DEGREE_TO_RAD(500), 0x1 },
+				.fs_avl[2] = { IIO_DEGREE_TO_RAD(0), 0x2 },
+				.fs_avl[3] = { IIO_DEGREE_TO_RAD(2000), 0x3 },
+			},
+		},
+	},
 	{
 		.wai = 0x69,
 		.int1_addr = 0x0d,
@@ -733,6 +807,16 @@ static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = {
 	IIO_CHAN_SOFT_TIMESTAMP(3),
 };
 
+static const struct iio_chan_spec st_lsm9dsx_gyro_channels[] = {
+	ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM9DSX_REG_GYRO_OUT_X_L_ADDR,
+			   IIO_MOD_X, 0),
+	ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM9DSX_REG_GYRO_OUT_Y_L_ADDR,
+			   IIO_MOD_Y, 1),
+	ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM9DSX_REG_GYRO_OUT_Z_L_ADDR,
+			   IIO_MOD_Z, 2),
+	IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
 int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable)
 {
 	const struct st_lsm6dsx_shub_settings *hub_settings;
@@ -1278,7 +1362,7 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
 
 static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
 					       enum st_lsm6dsx_sensor_id id,
-					       const char *name)
+					       const char *name, int hw_id)
 {
 	struct st_lsm6dsx_sensor *sensor;
 	struct iio_dev *iio_dev;
@@ -1308,7 +1392,11 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
 			  name);
 		break;
 	case ST_LSM6DSX_ID_GYRO:
-		iio_dev->channels = st_lsm6dsx_gyro_channels;
+		if (hw_id == ST_LSM9DS1_ID)
+			iio_dev->channels = st_lsm9dsx_gyro_channels;
+		else
+			iio_dev->channels = st_lsm6dsx_gyro_channels;
+
 		iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels);
 		iio_dev->info = &st_lsm6dsx_gyro_info;
 
@@ -1354,7 +1442,7 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
 		return err;
 
 	for (i = 0; i < ST_LSM6DSX_ID_EXT0; i++) {
-		hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i, name);
+		hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i, name, hw_id);
 		if (!hw->iio_devs[i])
 			return -ENOMEM;
 	}
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
index 28581eb0532c..c36a057c36ee 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
@@ -79,6 +79,10 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
 		.compatible = "st,lsm6ds3tr-c",
 		.data = (void *)ST_LSM6DS3TRC_ID,
 	},
+	{
+		.compatible = "st,lsm9ds1",
+		.data = (void *)ST_LSM9DS1_ID,
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
@@ -94,6 +98,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
 	{ ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID },
 	{ ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID },
 	{ ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID },
+	{ ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID },
 	{},
 };
 MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
index 0371e8b94a3e..138e3b985865 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
@@ -79,6 +79,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
 		.compatible = "st,lsm6ds3tr-c",
 		.data = (void *)ST_LSM6DS3TRC_ID,
 	},
+	{
+		.compatible = "st,lsm9ds1",
+		.data = (void *)ST_LSM9DS1_ID,
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
@@ -94,6 +98,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
 	{ ST_LSM6DSOX_DEV_NAME, ST_LSM6DSOX_ID },
 	{ ST_LSM6DSR_DEV_NAME, ST_LSM6DSR_ID },
 	{ ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID },
+	{ ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID },
 	{},
 };
 MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
-- 
2.20.1

^ permalink raw reply related

* [PATCH v3 3/5] iio: imu: st_lsm6sdx: move register definitions to sensor_settings struct
From: Martin Kepplinger @ 2019-07-25  5:31 UTC (permalink / raw)
  To: lorenzo.bianconi83, jic23, knaack.h, lars, pmeerw
  Cc: linux-iio, devicetree, linux-kernel, Martin Kepplinger
In-Reply-To: <20190725053132.9589-1-martin.kepplinger@puri.sm>

Move some register definitions to the per-device array of struct
st_lsm6dsx_sensor_settings in order to simplify adding new sensor
devices to the driver.

Also, remove completely unused register definitions.

Signed-off-by: Martin Kepplinger <martin.kepplinger@puri.sm>
---
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h      |  6 ++++
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 31 ++++++++++++++------
 2 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
index ab1c66615d67..3c47f5d27d30 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
@@ -198,6 +198,9 @@ struct st_lsm6dsx_ext_dev_settings {
 /**
  * struct st_lsm6dsx_settings - ST IMU sensor settings
  * @wai: Sensor WhoAmI default value.
+ * @int1_addr: Control Register address for INT1
+ * @int2_addr: Control Register address for INT2
+ * @reset_addr: register address for reset/reboot
  * @max_fifo_size: Sensor max fifo length in FIFO words.
  * @id: List of hw id/device name supported by the driver configuration.
  * @odr_table: Hw sensors odr table (Hz + val).
@@ -210,6 +213,9 @@ struct st_lsm6dsx_ext_dev_settings {
  */
 struct st_lsm6dsx_settings {
 	u8 wai;
+	u8 int1_addr;
+	u8 int2_addr;
+	u8 reset_addr;
 	u16 max_fifo_size;
 	struct {
 		enum st_lsm6dsx_hw_id hw_id;
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
index 9aa109428a52..e0d2149625cc 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -49,17 +49,12 @@
 
 #include "st_lsm6dsx.h"
 
-#define ST_LSM6DSX_REG_INT1_ADDR		0x0d
-#define ST_LSM6DSX_REG_INT2_ADDR		0x0e
 #define ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK	BIT(3)
 #define ST_LSM6DSX_REG_WHOAMI_ADDR		0x0f
-#define ST_LSM6DSX_REG_RESET_ADDR		0x12
 #define ST_LSM6DSX_REG_RESET_MASK		BIT(0)
 #define ST_LSM6DSX_REG_BOOT_MASK		BIT(7)
 #define ST_LSM6DSX_REG_BDU_ADDR			0x12
 #define ST_LSM6DSX_REG_BDU_MASK			BIT(6)
-#define ST_LSM6DSX_REG_INT2_ON_INT1_ADDR	0x13
-#define ST_LSM6DSX_REG_INT2_ON_INT1_MASK	BIT(5)
 
 #define ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR		0x28
 #define ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR		0x2a
@@ -72,6 +67,9 @@
 static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 	{
 		.wai = 0x69,
+		.int1_addr = 0x0d,
+		.int2_addr = 0x0e,
+		.reset_addr = 0x12,
 		.max_fifo_size = 1365,
 		.id = {
 			{
@@ -170,6 +168,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 	},
 	{
 		.wai = 0x69,
+		.int1_addr = 0x0d,
+		.int2_addr = 0x0e,
+		.reset_addr = 0x12,
 		.max_fifo_size = 682,
 		.id = {
 			{
@@ -268,6 +269,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 	},
 	{
 		.wai = 0x6a,
+		.int1_addr = 0x0d,
+		.int2_addr = 0x0e,
+		.reset_addr = 0x12,
 		.max_fifo_size = 682,
 		.id = {
 			{
@@ -375,6 +379,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 	},
 	{
 		.wai = 0x6c,
+		.int1_addr = 0x0d,
+		.int2_addr = 0x0e,
+		.reset_addr = 0x12,
 		.max_fifo_size = 512,
 		.id = {
 			{
@@ -494,6 +501,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 	},
 	{
 		.wai = 0x6b,
+		.int1_addr = 0x0d,
+		.int2_addr = 0x0e,
+		.reset_addr = 0x12,
 		.max_fifo_size = 512,
 		.id = {
 			{
@@ -584,6 +594,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 	},
 	{
 		.wai = 0x6b,
+		.int1_addr = 0x0d,
+		.int2_addr = 0x0e,
+		.reset_addr = 0x12,
 		.max_fifo_size = 512,
 		.id = {
 			{
@@ -1117,10 +1130,10 @@ static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg)
 
 	switch (drdy_pin) {
 	case 1:
-		*drdy_reg = ST_LSM6DSX_REG_INT1_ADDR;
+		*drdy_reg = hw->settings->int1_addr;
 		break;
 	case 2:
-		*drdy_reg = ST_LSM6DSX_REG_INT2_ADDR;
+		*drdy_reg = hw->settings->int2_addr;
 		break;
 	default:
 		dev_err(hw->dev, "unsupported data ready pin\n");
@@ -1220,7 +1233,7 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
 	int err;
 
 	/* device sw reset */
-	err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR,
+	err = regmap_update_bits(hw->regmap, hw->settings->reset_addr,
 				 ST_LSM6DSX_REG_RESET_MASK,
 				 FIELD_PREP(ST_LSM6DSX_REG_RESET_MASK, 1));
 	if (err < 0)
@@ -1229,7 +1242,7 @@ static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
 	msleep(50);
 
 	/* reload trimming parameter */
-	err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_RESET_ADDR,
+	err = regmap_update_bits(hw->regmap, hw->settings->reset_addr,
 				 ST_LSM6DSX_REG_BOOT_MASK,
 				 FIELD_PREP(ST_LSM6DSX_REG_BOOT_MASK, 1));
 	if (err < 0)
-- 
2.20.1

^ permalink raw reply related

* [PATCH v3 2/5] iio: imu: st_lsm6dsx: move fs_table in st_lsm6dsx_sensor_settings
From: Martin Kepplinger @ 2019-07-25  5:31 UTC (permalink / raw)
  To: lorenzo.bianconi83, jic23, knaack.h, lars, pmeerw
  Cc: linux-iio, devicetree, linux-kernel, Lorenzo Bianconi
In-Reply-To: <20190725053132.9589-1-martin.kepplinger@puri.sm>

From: Lorenzo Bianconi <lorenzo@kernel.org>

Move fs_table in st_lsm6dsx_sensor_settings in order to support
sensors with different gain maps. This is a preliminary patch to add
support for LSM9DS1 sensor to st_lsm6dsx driver

Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h      |   2 +
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 175 +++++++++++++++----
 2 files changed, 144 insertions(+), 33 deletions(-)

diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
index 3a89f3f6e2c7..ab1c66615d67 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
@@ -201,6 +201,7 @@ struct st_lsm6dsx_ext_dev_settings {
  * @max_fifo_size: Sensor max fifo length in FIFO words.
  * @id: List of hw id/device name supported by the driver configuration.
  * @odr_table: Hw sensors odr table (Hz + val).
+ * @fs_table: Hw sensors gain table (gain + val).
  * @decimator: List of decimator register info (addr + mask).
  * @batch: List of FIFO batching register info (addr + mask).
  * @fifo_ops: Sensor hw FIFO parameters.
@@ -215,6 +216,7 @@ struct st_lsm6dsx_settings {
 		const char *name;
 	} id[ST_LSM6DSX_MAX_ID];
 	struct st_lsm6dsx_odr_table_entry odr_table[2];
+	struct st_lsm6dsx_fs_table_entry fs_table[2];
 	struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID];
 	struct st_lsm6dsx_reg batch[ST_LSM6DSX_MAX_ID];
 	struct st_lsm6dsx_fifo_ops fifo_ops;
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
index b3c6c9792913..9aa109428a52 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -69,29 +69,6 @@
 #define ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR	0x24
 #define ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR	0x26
 
-static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = {
-	[ST_LSM6DSX_ID_ACC] = {
-		.reg = {
-			.addr = 0x10,
-			.mask = GENMASK(3, 2),
-		},
-		.fs_avl[0] = {  IIO_G_TO_M_S_2(61), 0x0 },
-		.fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 },
-		.fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 },
-		.fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 },
-	},
-	[ST_LSM6DSX_ID_GYRO] = {
-		.reg = {
-			.addr = 0x11,
-			.mask = GENMASK(3, 2),
-		},
-		.fs_avl[0] = {  IIO_DEGREE_TO_RAD(8750), 0x0 },
-		.fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 },
-		.fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 },
-		.fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 },
-	}
-};
-
 static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 	{
 		.wai = 0x69,
@@ -128,6 +105,28 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 				.odr_avl[5] = { 416, 0x06 },
 			},
 		},
+		.fs_table = {
+			[ST_LSM6DSX_ID_ACC] = {
+				.reg = {
+					.addr = 0x10,
+					.mask = GENMASK(3, 2),
+				},
+				.fs_avl[0] = {  IIO_G_TO_M_S_2(61), 0x0 },
+				.fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 },
+				.fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 },
+				.fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 },
+			},
+			[ST_LSM6DSX_ID_GYRO] = {
+				.reg = {
+					.addr = 0x11,
+					.mask = GENMASK(3, 2),
+				},
+				.fs_avl[0] = {  IIO_DEGREE_TO_RAD(8750), 0x0 },
+				.fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 },
+				.fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 },
+				.fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 },
+			},
+		},
 		.decimator = {
 			[ST_LSM6DSX_ID_ACC] = {
 				.addr = 0x08,
@@ -204,6 +203,28 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 				.odr_avl[5] = { 416, 0x06 },
 			},
 		},
+		.fs_table = {
+			[ST_LSM6DSX_ID_ACC] = {
+				.reg = {
+					.addr = 0x10,
+					.mask = GENMASK(3, 2),
+				},
+				.fs_avl[0] = {  IIO_G_TO_M_S_2(61), 0x0 },
+				.fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 },
+				.fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 },
+				.fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 },
+			},
+			[ST_LSM6DSX_ID_GYRO] = {
+				.reg = {
+					.addr = 0x11,
+					.mask = GENMASK(3, 2),
+				},
+				.fs_avl[0] = {  IIO_DEGREE_TO_RAD(8750), 0x0 },
+				.fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 },
+				.fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 },
+				.fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 },
+			},
+		},
 		.decimator = {
 			[ST_LSM6DSX_ID_ACC] = {
 				.addr = 0x08,
@@ -289,6 +310,28 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 				.odr_avl[5] = { 416, 0x06 },
 			},
 		},
+		.fs_table = {
+			[ST_LSM6DSX_ID_ACC] = {
+				.reg = {
+					.addr = 0x10,
+					.mask = GENMASK(3, 2),
+				},
+				.fs_avl[0] = {  IIO_G_TO_M_S_2(61), 0x0 },
+				.fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 },
+				.fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 },
+				.fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 },
+			},
+			[ST_LSM6DSX_ID_GYRO] = {
+				.reg = {
+					.addr = 0x11,
+					.mask = GENMASK(3, 2),
+				},
+				.fs_avl[0] = {  IIO_DEGREE_TO_RAD(8750), 0x0 },
+				.fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 },
+				.fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 },
+				.fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 },
+			},
+		},
 		.decimator = {
 			[ST_LSM6DSX_ID_ACC] = {
 				.addr = 0x08,
@@ -368,6 +411,28 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 				.odr_avl[5] = { 416, 0x06 },
 			},
 		},
+		.fs_table = {
+			[ST_LSM6DSX_ID_ACC] = {
+				.reg = {
+					.addr = 0x10,
+					.mask = GENMASK(3, 2),
+				},
+				.fs_avl[0] = {  IIO_G_TO_M_S_2(61), 0x0 },
+				.fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 },
+				.fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 },
+				.fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 },
+			},
+			[ST_LSM6DSX_ID_GYRO] = {
+				.reg = {
+					.addr = 0x11,
+					.mask = GENMASK(3, 2),
+				},
+				.fs_avl[0] = {  IIO_DEGREE_TO_RAD(8750), 0x0 },
+				.fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 },
+				.fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 },
+				.fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 },
+			},
+		},
 		.batch = {
 			[ST_LSM6DSX_ID_ACC] = {
 				.addr = 0x09,
@@ -462,6 +527,28 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 				.odr_avl[5] = { 416, 0x06 },
 			},
 		},
+		.fs_table = {
+			[ST_LSM6DSX_ID_ACC] = {
+				.reg = {
+					.addr = 0x10,
+					.mask = GENMASK(3, 2),
+				},
+				.fs_avl[0] = {  IIO_G_TO_M_S_2(61), 0x0 },
+				.fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 },
+				.fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 },
+				.fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 },
+			},
+			[ST_LSM6DSX_ID_GYRO] = {
+				.reg = {
+					.addr = 0x11,
+					.mask = GENMASK(3, 2),
+				},
+				.fs_avl[0] = {  IIO_DEGREE_TO_RAD(8750), 0x0 },
+				.fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 },
+				.fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 },
+				.fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 },
+			},
+		},
 		.batch = {
 			[ST_LSM6DSX_ID_ACC] = {
 				.addr = 0x09,
@@ -530,6 +617,28 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 				.odr_avl[5] = { 416, 0x06 },
 			},
 		},
+		.fs_table = {
+			[ST_LSM6DSX_ID_ACC] = {
+				.reg = {
+					.addr = 0x10,
+					.mask = GENMASK(3, 2),
+				},
+				.fs_avl[0] = {  IIO_G_TO_M_S_2(61), 0x0 },
+				.fs_avl[1] = { IIO_G_TO_M_S_2(122), 0x2 },
+				.fs_avl[2] = { IIO_G_TO_M_S_2(244), 0x3 },
+				.fs_avl[3] = { IIO_G_TO_M_S_2(488), 0x1 },
+			},
+			[ST_LSM6DSX_ID_GYRO] = {
+				.reg = {
+					.addr = 0x11,
+					.mask = GENMASK(3, 2),
+				},
+				.fs_avl[0] = {  IIO_DEGREE_TO_RAD(8750), 0x0 },
+				.fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 },
+				.fs_avl[2] = { IIO_DEGREE_TO_RAD(35000), 0x2 },
+				.fs_avl[3] = { IIO_DEGREE_TO_RAD(70000), 0x3 },
+			},
+		},
 		.batch = {
 			[ST_LSM6DSX_ID_ACC] = {
 				.addr = 0x09,
@@ -665,23 +774,22 @@ static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id,
 static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor,
 				     u32 gain)
 {
-	struct st_lsm6dsx_hw *hw = sensor->hw;
-	const struct st_lsm6dsx_reg *reg;
+	const struct st_lsm6dsx_fs_table_entry *fs_table;
 	unsigned int data;
 	int i, err;
-	u8 val;
 
+	fs_table = &sensor->hw->settings->fs_table[sensor->id];
 	for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++)
-		if (st_lsm6dsx_fs_table[sensor->id].fs_avl[i].gain == gain)
+		if (fs_table->fs_avl[i].gain == gain)
 			break;
 
 	if (i == ST_LSM6DSX_FS_LIST_SIZE)
 		return -EINVAL;
 
-	val = st_lsm6dsx_fs_table[sensor->id].fs_avl[i].val;
-	reg = &st_lsm6dsx_fs_table[sensor->id].reg;
-	data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask);
-	err = st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data);
+	data = ST_LSM6DSX_SHIFT_VAL(fs_table->fs_avl[i].val,
+				    fs_table->reg.mask);
+	err = st_lsm6dsx_update_bits_locked(sensor->hw, fs_table->reg.addr,
+					    fs_table->reg.mask, data);
 	if (err < 0)
 		return err;
 
@@ -934,11 +1042,12 @@ static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev,
 {
 	struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
 	enum st_lsm6dsx_sensor_id id = sensor->id;
+	struct st_lsm6dsx_hw *hw = sensor->hw;
 	int i, len = 0;
 
 	for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++)
 		len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
-				 st_lsm6dsx_fs_table[id].fs_avl[i].gain);
+				 hw->settings->fs_table[id].fs_avl[i].gain);
 	buf[len - 1] = '\n';
 
 	return len;
@@ -1173,7 +1282,7 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
 	sensor->id = id;
 	sensor->hw = hw;
 	sensor->odr = hw->settings->odr_table[id].odr_avl[0].hz;
-	sensor->gain = st_lsm6dsx_fs_table[id].fs_avl[0].gain;
+	sensor->gain = hw->settings->fs_table[id].fs_avl[0].gain;
 	sensor->watermark = 1;
 
 	switch (id) {
-- 
2.20.1

^ permalink raw reply related

* [PATCH v3 1/5] iio: imu: st_lsm6dsx: move odr_table in st_lsm6dsx_sensor_settings
From: Martin Kepplinger @ 2019-07-25  5:31 UTC (permalink / raw)
  To: lorenzo.bianconi83, jic23, knaack.h, lars, pmeerw
  Cc: linux-iio, devicetree, linux-kernel, Lorenzo Bianconi
In-Reply-To: <20190725053132.9589-1-martin.kepplinger@puri.sm>

From: Lorenzo Bianconi <lorenzo@kernel.org>

Move sensor odr table in st_lsm6dsx_sensor_settings in order to support
sensors with different odr maps. This is a preliminary patch to add
support for LSM9DS1 sensor to st_lsm6dsx driver

Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h      |   2 +
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 196 ++++++++++++++++---
 2 files changed, 166 insertions(+), 32 deletions(-)

diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
index af379a5429ed..3a89f3f6e2c7 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
@@ -200,6 +200,7 @@ struct st_lsm6dsx_ext_dev_settings {
  * @wai: Sensor WhoAmI default value.
  * @max_fifo_size: Sensor max fifo length in FIFO words.
  * @id: List of hw id/device name supported by the driver configuration.
+ * @odr_table: Hw sensors odr table (Hz + val).
  * @decimator: List of decimator register info (addr + mask).
  * @batch: List of FIFO batching register info (addr + mask).
  * @fifo_ops: Sensor hw FIFO parameters.
@@ -213,6 +214,7 @@ struct st_lsm6dsx_settings {
 		enum st_lsm6dsx_hw_id hw_id;
 		const char *name;
 	} id[ST_LSM6DSX_MAX_ID];
+	struct st_lsm6dsx_odr_table_entry odr_table[2];
 	struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID];
 	struct st_lsm6dsx_reg batch[ST_LSM6DSX_MAX_ID];
 	struct st_lsm6dsx_fifo_ops fifo_ops;
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
index d8c4417cf4eb..b3c6c9792913 100644
--- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -69,33 +69,6 @@
 #define ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR	0x24
 #define ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR	0x26
 
-static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = {
-	[ST_LSM6DSX_ID_ACC] = {
-		.reg = {
-			.addr = 0x10,
-			.mask = GENMASK(7, 4),
-		},
-		.odr_avl[0] = {  13, 0x01 },
-		.odr_avl[1] = {  26, 0x02 },
-		.odr_avl[2] = {  52, 0x03 },
-		.odr_avl[3] = { 104, 0x04 },
-		.odr_avl[4] = { 208, 0x05 },
-		.odr_avl[5] = { 416, 0x06 },
-	},
-	[ST_LSM6DSX_ID_GYRO] = {
-		.reg = {
-			.addr = 0x11,
-			.mask = GENMASK(7, 4),
-		},
-		.odr_avl[0] = {  13, 0x01 },
-		.odr_avl[1] = {  26, 0x02 },
-		.odr_avl[2] = {  52, 0x03 },
-		.odr_avl[3] = { 104, 0x04 },
-		.odr_avl[4] = { 208, 0x05 },
-		.odr_avl[5] = { 416, 0x06 },
-	}
-};
-
 static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = {
 	[ST_LSM6DSX_ID_ACC] = {
 		.reg = {
@@ -129,6 +102,32 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 				.name = ST_LSM6DS3_DEV_NAME,
 			},
 		},
+		.odr_table = {
+			[ST_LSM6DSX_ID_ACC] = {
+				.reg = {
+					.addr = 0x10,
+					.mask = GENMASK(7, 4),
+				},
+				.odr_avl[0] = {  13, 0x01 },
+				.odr_avl[1] = {  26, 0x02 },
+				.odr_avl[2] = {  52, 0x03 },
+				.odr_avl[3] = { 104, 0x04 },
+				.odr_avl[4] = { 208, 0x05 },
+				.odr_avl[5] = { 416, 0x06 },
+			},
+			[ST_LSM6DSX_ID_GYRO] = {
+				.reg = {
+					.addr = 0x11,
+					.mask = GENMASK(7, 4),
+				},
+				.odr_avl[0] = {  13, 0x01 },
+				.odr_avl[1] = {  26, 0x02 },
+				.odr_avl[2] = {  52, 0x03 },
+				.odr_avl[3] = { 104, 0x04 },
+				.odr_avl[4] = { 208, 0x05 },
+				.odr_avl[5] = { 416, 0x06 },
+			},
+		},
 		.decimator = {
 			[ST_LSM6DSX_ID_ACC] = {
 				.addr = 0x08,
@@ -179,6 +178,32 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 				.name = ST_LSM6DS3H_DEV_NAME,
 			},
 		},
+		.odr_table = {
+			[ST_LSM6DSX_ID_ACC] = {
+				.reg = {
+					.addr = 0x10,
+					.mask = GENMASK(7, 4),
+				},
+				.odr_avl[0] = {  13, 0x01 },
+				.odr_avl[1] = {  26, 0x02 },
+				.odr_avl[2] = {  52, 0x03 },
+				.odr_avl[3] = { 104, 0x04 },
+				.odr_avl[4] = { 208, 0x05 },
+				.odr_avl[5] = { 416, 0x06 },
+			},
+			[ST_LSM6DSX_ID_GYRO] = {
+				.reg = {
+					.addr = 0x11,
+					.mask = GENMASK(7, 4),
+				},
+				.odr_avl[0] = {  13, 0x01 },
+				.odr_avl[1] = {  26, 0x02 },
+				.odr_avl[2] = {  52, 0x03 },
+				.odr_avl[3] = { 104, 0x04 },
+				.odr_avl[4] = { 208, 0x05 },
+				.odr_avl[5] = { 416, 0x06 },
+			},
+		},
 		.decimator = {
 			[ST_LSM6DSX_ID_ACC] = {
 				.addr = 0x08,
@@ -238,6 +263,32 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 				.name = ST_LSM6DS3TRC_DEV_NAME,
 			},
 		},
+		.odr_table = {
+			[ST_LSM6DSX_ID_ACC] = {
+				.reg = {
+					.addr = 0x10,
+					.mask = GENMASK(7, 4),
+				},
+				.odr_avl[0] = {  13, 0x01 },
+				.odr_avl[1] = {  26, 0x02 },
+				.odr_avl[2] = {  52, 0x03 },
+				.odr_avl[3] = { 104, 0x04 },
+				.odr_avl[4] = { 208, 0x05 },
+				.odr_avl[5] = { 416, 0x06 },
+			},
+			[ST_LSM6DSX_ID_GYRO] = {
+				.reg = {
+					.addr = 0x11,
+					.mask = GENMASK(7, 4),
+				},
+				.odr_avl[0] = {  13, 0x01 },
+				.odr_avl[1] = {  26, 0x02 },
+				.odr_avl[2] = {  52, 0x03 },
+				.odr_avl[3] = { 104, 0x04 },
+				.odr_avl[4] = { 208, 0x05 },
+				.odr_avl[5] = { 416, 0x06 },
+			},
+		},
 		.decimator = {
 			[ST_LSM6DSX_ID_ACC] = {
 				.addr = 0x08,
@@ -291,6 +342,32 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 				.name = ST_LSM6DSOX_DEV_NAME,
 			},
 		},
+		.odr_table = {
+			[ST_LSM6DSX_ID_ACC] = {
+				.reg = {
+					.addr = 0x10,
+					.mask = GENMASK(7, 4),
+				},
+				.odr_avl[0] = {  13, 0x01 },
+				.odr_avl[1] = {  26, 0x02 },
+				.odr_avl[2] = {  52, 0x03 },
+				.odr_avl[3] = { 104, 0x04 },
+				.odr_avl[4] = { 208, 0x05 },
+				.odr_avl[5] = { 416, 0x06 },
+			},
+			[ST_LSM6DSX_ID_GYRO] = {
+				.reg = {
+					.addr = 0x11,
+					.mask = GENMASK(7, 4),
+				},
+				.odr_avl[0] = {  13, 0x01 },
+				.odr_avl[1] = {  26, 0x02 },
+				.odr_avl[2] = {  52, 0x03 },
+				.odr_avl[3] = { 104, 0x04 },
+				.odr_avl[4] = { 208, 0x05 },
+				.odr_avl[5] = { 416, 0x06 },
+			},
+		},
 		.batch = {
 			[ST_LSM6DSX_ID_ACC] = {
 				.addr = 0x09,
@@ -359,6 +436,32 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 				.name = ST_ASM330LHH_DEV_NAME,
 			},
 		},
+		.odr_table = {
+			[ST_LSM6DSX_ID_ACC] = {
+				.reg = {
+					.addr = 0x10,
+					.mask = GENMASK(7, 4),
+				},
+				.odr_avl[0] = {  13, 0x01 },
+				.odr_avl[1] = {  26, 0x02 },
+				.odr_avl[2] = {  52, 0x03 },
+				.odr_avl[3] = { 104, 0x04 },
+				.odr_avl[4] = { 208, 0x05 },
+				.odr_avl[5] = { 416, 0x06 },
+			},
+			[ST_LSM6DSX_ID_GYRO] = {
+				.reg = {
+					.addr = 0x11,
+					.mask = GENMASK(7, 4),
+				},
+				.odr_avl[0] = {  13, 0x01 },
+				.odr_avl[1] = {  26, 0x02 },
+				.odr_avl[2] = {  52, 0x03 },
+				.odr_avl[3] = { 104, 0x04 },
+				.odr_avl[4] = { 208, 0x05 },
+				.odr_avl[5] = { 416, 0x06 },
+			},
+		},
 		.batch = {
 			[ST_LSM6DSX_ID_ACC] = {
 				.addr = 0x09,
@@ -401,6 +504,32 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
 				.name = ST_LSM6DSR_DEV_NAME,
 			},
 		},
+		.odr_table = {
+			[ST_LSM6DSX_ID_ACC] = {
+				.reg = {
+					.addr = 0x10,
+					.mask = GENMASK(7, 4),
+				},
+				.odr_avl[0] = {  13, 0x01 },
+				.odr_avl[1] = {  26, 0x02 },
+				.odr_avl[2] = {  52, 0x03 },
+				.odr_avl[3] = { 104, 0x04 },
+				.odr_avl[4] = { 208, 0x05 },
+				.odr_avl[5] = { 416, 0x06 },
+			},
+			[ST_LSM6DSX_ID_GYRO] = {
+				.reg = {
+					.addr = 0x11,
+					.mask = GENMASK(7, 4),
+				},
+				.odr_avl[0] = {  13, 0x01 },
+				.odr_avl[1] = {  26, 0x02 },
+				.odr_avl[2] = {  52, 0x03 },
+				.odr_avl[3] = { 104, 0x04 },
+				.odr_avl[4] = { 208, 0x05 },
+				.odr_avl[5] = { 416, 0x06 },
+			},
+		},
 		.batch = {
 			[ST_LSM6DSX_ID_ACC] = {
 				.addr = 0x09,
@@ -563,20 +692,22 @@ static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor,
 
 int st_lsm6dsx_check_odr(struct st_lsm6dsx_sensor *sensor, u16 odr, u8 *val)
 {
+	const struct st_lsm6dsx_odr_table_entry *odr_table;
 	int i;
 
+	odr_table = &sensor->hw->settings->odr_table[sensor->id];
 	for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
 		/*
 		 * ext devices can run at different odr respect to
 		 * accel sensor
 		 */
-		if (st_lsm6dsx_odr_table[sensor->id].odr_avl[i].hz >= odr)
+		if (odr_table->odr_avl[i].hz >= odr)
 			break;
 
 	if (i == ST_LSM6DSX_ODR_LIST_SIZE)
 		return -EINVAL;
 
-	*val = st_lsm6dsx_odr_table[sensor->id].odr_avl[i].val;
+	*val = odr_table->odr_avl[i].val;
 
 	return 0;
 }
@@ -641,7 +772,7 @@ static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 req_odr)
 			return err;
 	}
 
-	reg = &st_lsm6dsx_odr_table[ref_sensor->id].reg;
+	reg = &hw->settings->odr_table[ref_sensor->id].reg;
 	data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask);
 	return st_lsm6dsx_update_bits_locked(hw, reg->addr, reg->mask, data);
 }
@@ -786,11 +917,12 @@ st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev,
 {
 	struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
 	enum st_lsm6dsx_sensor_id id = sensor->id;
+	struct st_lsm6dsx_hw *hw = sensor->hw;
 	int i, len = 0;
 
 	for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
 		len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
-				 st_lsm6dsx_odr_table[id].odr_avl[i].hz);
+				 hw->settings->odr_table[id].odr_avl[i].hz);
 	buf[len - 1] = '\n';
 
 	return len;
@@ -1040,7 +1172,7 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
 	sensor = iio_priv(iio_dev);
 	sensor->id = id;
 	sensor->hw = hw;
-	sensor->odr = st_lsm6dsx_odr_table[id].odr_avl[0].hz;
+	sensor->odr = hw->settings->odr_table[id].odr_avl[0].hz;
 	sensor->gain = st_lsm6dsx_fs_table[id].fs_avl[0].gain;
 	sensor->watermark = 1;
 
-- 
2.20.1

^ permalink raw reply related

* [PATCH v3 0/5] iio: imu: st_lsm6dsx: Add support for LSM9DS1
From: Martin Kepplinger @ 2019-07-25  5:31 UTC (permalink / raw)
  To: lorenzo.bianconi83, jic23, knaack.h, lars, pmeerw
  Cc: linux-iio, devicetree, linux-kernel, Martin Kepplinger

Resend 2 of Lorenzo's patches that this builds upon. They have been previously
posted to linux-iio only:
https://lore.kernel.org/linux-iio/cover.1563226641.git.lorenzo@kernel.org/

Then, add support for the LSM9DS1 accel/gyro unit in 3 simple steps. This
is also only a resend and rebase of the v2:
https://lore.kernel.org/linux-iio/20190716093325.7683-1-martin.kepplinger@puri.sm/

So I call this v3 and Lorenzo, I hope that it's fine for you that I just
take your patches here - also since they mention to be intended for supporting
the device.


revision history
----------------
v3: rebase and add Lorenzo's patches in order to apply to the iio testing brach
v2: further simplifications based on Lorenzo's feedback
v1: initial change for adding lsm9ds1 support




Lorenzo Bianconi (2):
  iio: imu: st_lsm6dsx: move odr_table in st_lsm6dsx_sensor_settings
  iio: imu: st_lsm6dsx: move fs_table in st_lsm6dsx_sensor_settings

Martin Kepplinger (3):
  iio: imu: st_lsm6sdx: move register definitions to sensor_settings
    struct
  iio: imu: st_lsm6dsx: add support for accel/gyro unit of lsm9sd1
  dt-bindings: iio: imu: st_lsm6dsx: add lsm9ds1 device bindings

 .../bindings/iio/imu/st_lsm6dsx.txt           |   1 +
 drivers/iio/imu/st_lsm6dsx/Kconfig            |   1 +
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h       |  12 +
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c  | 490 +++++++++++++++---
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c   |   5 +
 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c   |   5 +
 6 files changed, 440 insertions(+), 74 deletions(-)

-- 
2.20.1

^ permalink raw reply

* RE: [PATCH V2 1/4] dt-bindings: opp: Support multiple opp-suspend properties
From: Anson Huang @ 2019-07-25  5:01 UTC (permalink / raw)
  To: Viresh Kumar
  Cc: vireshk@kernel.org, nm@ti.com, sboyd@kernel.org,
	robh+dt@kernel.org, mark.rutland@arm.com, shawnguo@kernel.org,
	s.hauer@pengutronix.de, kernel@pengutronix.de, festevam@gmail.com,
	Leonard Crestez, p.zabel@pengutronix.de, Jacky Bai, Daniel Baluta,
	l.stach@pengutronix.de, Abel Vesa, angus@akkea.ca,
	andrew.smirnov@gmail.com, ccaione@baylibre.com
In-Reply-To: <20190725022611.f6dirdstu3yndcwy@vireshk-i7>

Hi, Shawn

> On 09-07-19, 16:00, Anson.Huang@nxp.com wrote:
> > From: Anson Huang <Anson.Huang@nxp.com>
> >
> > Update opp-suspend property's description to support multiple
> > opp-suspend properties defined in DT, the OPP with highest opp-hz and
> > with opp-suspend property present will be used as suspend opp.
> >
> > Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> > ---
> > New patch.
> > ---
> >  Documentation/devicetree/bindings/opp/opp.txt | 4 ++--
> >  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> Applied. Thanks.

Would you pick up the DT patches in this series? Thanks.

Anson

^ permalink raw reply

* Re: [PATCH v4, 05/33] dt-bindings: mediatek: add RDMA1 description for mt8183 display
From: CK Hu @ 2019-07-25  3:20 UTC (permalink / raw)
  To: Rob Herring
  Cc: Mark Rutland, devicetree, David Airlie, linux-kernel, dri-devel,
	yongqiang.niu, linux-mediatek, Matthias Brugger, linux-arm-kernel
In-Reply-To: <20190724201635.GA18345@bogus>

Hi, Rob:

On Wed, 2019-07-24 at 14:16 -0600, Rob Herring wrote:
> On Tue, Jul 09, 2019 at 06:33:45AM +0800, yongqiang.niu@mediatek.com wrote:
> > From: Yongqiang Niu <yongqiang.niu@mediatek.com>
> > 
> > This patch add RDMA1 description for mt8183 display
> > 
> > Signed-off-by: Yongqiang Niu <yongqiang.niu@mediatek.com>
> > ---
> >  Documentation/devicetree/bindings/display/mediatek/mediatek,disp.txt | 1 +
> >  1 file changed, 1 insertion(+)
> > 
> > diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,disp.txt b/Documentation/devicetree/bindings/display/mediatek/mediatek,disp.txt
> > index afd3c90..bb9274a 100644
> > --- a/Documentation/devicetree/bindings/display/mediatek/mediatek,disp.txt
> > +++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,disp.txt
> > @@ -30,6 +30,7 @@ Required properties (all function blocks):
> >  	"mediatek,<chip>-disp-ovl"   		- overlay (4 layers, blending, csc)
> >  	"mediatek,<chip>-disp-ovl-2l"           - overlay (2 layers, blending, csc)
> >  	"mediatek,<chip>-disp-rdma"  		- read DMA / line buffer
> > +	"mediatek,<chip>-disp-rdma1"            - function is same with RDMA, fifo size is different
> 
> This can't be determined by which chip it is? IOW, a chip may have both 
> rdma and rdma1?

In MT8183, there are two different rdma. The difference is the fifo size
in each one. I've a question: is it better to have two compatible string
for each one, or just one compatible string for both but with a property
to set fifo size?

Regards,
CK

> 
> >  	"mediatek,<chip>-disp-wdma"  		- write DMA
> >  	"mediatek,<chip>-disp-ccorr"            - color correction
> >  	"mediatek,<chip>-disp-color" 		- color processor
> > -- 
> > 1.8.1.1.dirty
> > 


_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* RE: [PATCH V2 1/2] usb: dwc3: Add node to update cache type setting
From: Ran Wang @ 2019-07-25  2:29 UTC (permalink / raw)
  To: Rob Herring
  Cc: Greg Kroah-Hartman, Mark Rutland, Felipe Balbi,
	linux-usb@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <20190724204222.GA1234@bogus>

Hi Rob,

On Thursday, July 25, 2019 04:42 Rob Herring <robh@kernel.org> wrote:
> 
> On Fri, Jul 12, 2019 at 02:42:05PM +0800, Ran Wang wrote:
> > Some Layerscape paltforms (such as LS1088A, LS2088A, etc) encounter
> > USB detect failues when adding dma-coherent to DWC3 node. This is
> > because the HW default cache type configuration of those SoC are not
> > right, need to be updated in DTS.
> >
> > Signed-off-by: Ran Wang <ran.wang_1@nxp.com>
> > ---
> > Change in v2:
> > 	- New file.
> >
> >  Documentation/devicetree/bindings/usb/dwc3.txt | 43
> > ++++++++++++++++++++++++++
> >  1 file changed, 43 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt
> > b/Documentation/devicetree/bindings/usb/dwc3.txt
> > index 8e5265e..7bc1cef 100644
> > --- a/Documentation/devicetree/bindings/usb/dwc3.txt
> > +++ b/Documentation/devicetree/bindings/usb/dwc3.txt
> > @@ -110,6 +110,43 @@ Optional properties:
> >   - in addition all properties from usb-xhci.txt from the current directory are
> >     supported as well
> >
> > +* Cache type nodes (optional)
> > +
> > +The Cache type node is used to tell how to configure cache type on 4
> > +different transfer types: Data Read, Desc Read, Data Write and Desc
> > +write. For each treasfer type, controller has a 4-bit register field
> > +to enable different cache type. Quoted from DWC3 data book Table 6-5
> Cache Type Bit Assignments:
> > +----------------------------------------------------------------
> > +MBUS_TYPE| bit[3]       |bit[2]       |bit[1]     |bit[0]
> > +----------------------------------------------------------------
> > +AHB      |Cacheable     |Bufferable   |Privilegge |Data
> > +AXI3     |Write Allocate|Read Allocate|Cacheable  |Bufferable
> > +AXI4     |Allocate Other|Allocate     |Modifiable |Bufferable
> > +AXI4     |Other Allocate|Allocate     |Modifiable |Bufferable
> > +Native   |Same as AXI   |Same as AXI  |Same as AXI|Same as AXI
> > +----------------------------------------------------------------
> > +Note: The AHB, AXI3, AXI4, and PCIe busses use different names for
> > +certain signals, which have the same meaning:
> > +  Bufferable = Posted
> > +  Cacheable = Modifiable = Snoop (negation of No Snoop)
> 
> This should all be implied from the SoC specific compatible strings.

Did you mean I could implement a soc driver which can be matched by compatible of 'fsl,ls1088a-dwc3' which will pass known bus type to DWC3 driver? If yes, how to pass?

Or I need to add a property snps,mbus_type="AXI3" to DWC3 node, which will co-work with property  transfer_type-datard = "cacheable" to set cache type properly?

Thanks & Regards,
Ran

^ permalink raw reply

* Re: [PATCH V2 2/4] opp: of: Support multiple suspend OPPs defined in DT
From: Viresh Kumar @ 2019-07-25  2:26 UTC (permalink / raw)
  To: Anson.Huang
  Cc: vireshk, nm, sboyd, robh+dt, mark.rutland, shawnguo, s.hauer,
	kernel, festevam, leonard.crestez, p.zabel, ping.bai,
	daniel.baluta, l.stach, abel.vesa, angus, andrew.smirnov, ccaione,
	agx, linux-pm, devicetree, linux-kernel, linux-arm-kernel,
	Linux-imx
In-Reply-To: <20190709080015.43442-2-Anson.Huang@nxp.com>

On 09-07-19, 16:00, Anson.Huang@nxp.com wrote:
> From: Anson Huang <Anson.Huang@nxp.com>
> 
> With property "opp-supported-hw" introduced, the OPP table
> in DT could be a large OPP table and ONLY a subset of OPPs
> are available, based on the version of the hardware running
> on. That introduces restriction of using "opp-suspend"
> property to define the suspend OPP, as we are NOT sure if the
> OPP containing "opp-suspend" property is available for the
> hardware running on, and the of opp core does NOT allow multiple
> suspend OPPs defined in DT OPP table.
> 
> To eliminate this restrition, make of opp core allow multiple
> suspend OPPs defined in DT, and pick the OPP with highest rate
> and with "opp-suspend" property present to be suspend OPP, it
> can speed up the suspend/resume process.
> 
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> ---
> No changes.
> ---
>  drivers/opp/of.c | 9 ++++++---
>  1 file changed, 6 insertions(+), 3 deletions(-)

Applied. Thanks.

-- 
viresh

^ permalink raw reply

* Re: [PATCH V2 1/4] dt-bindings: opp: Support multiple opp-suspend properties
From: Viresh Kumar @ 2019-07-25  2:26 UTC (permalink / raw)
  To: Anson.Huang
  Cc: vireshk, nm, sboyd, robh+dt, mark.rutland, shawnguo, s.hauer,
	kernel, festevam, leonard.crestez, p.zabel, ping.bai,
	daniel.baluta, l.stach, abel.vesa, angus, andrew.smirnov, ccaione,
	agx, linux-pm, devicetree, linux-kernel, linux-arm-kernel,
	Linux-imx
In-Reply-To: <20190709080015.43442-1-Anson.Huang@nxp.com>

On 09-07-19, 16:00, Anson.Huang@nxp.com wrote:
> From: Anson Huang <Anson.Huang@nxp.com>
> 
> Update opp-suspend property's description to support multiple
> opp-suspend properties defined in DT, the OPP with highest opp-hz
> and with opp-suspend property present will be used as suspend opp.
> 
> Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> ---
> New patch.
> ---
>  Documentation/devicetree/bindings/opp/opp.txt | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)

Applied. Thanks.

-- 
viresh

^ permalink raw reply

* Re: [PATCH v2 0/9] Exynos Adaptive Supply Voltage support
From: Viresh Kumar @ 2019-07-25  2:23 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: Sylwester Nawrocki, krzk, robh+dt, vireshk, devicetree, kgene,
	pankaj.dubey, linux-samsung-soc, linux-arm-kernel, linux-kernel,
	linux-pm, b.zolnierkie
In-Reply-To: <5ef302a4-5bbf-483d-dfdf-cf76f6f69cee@samsung.com>

On 24-07-19, 15:10, Marek Szyprowski wrote:
> Hi Viresh,
> 
> On 2019-07-23 04:04, Viresh Kumar wrote:
> > On 18-07-19, 16:30, Sylwester Nawrocki wrote:
> >> This is second iteration of patch series adding ASV (Adaptive Supply
> >> Voltage) support for Exynos SoCs. The first one can be found at:
> >> https://lore.kernel.org/lkml/20190404171735.12815-1-s.nawrocki@samsung.com
> >>
> >> The main changes comparing to the first (RFC) version are:
> >>   - moving ASV data tables from DT to the driver,
> >>   - converting the chipid and the ASV drivers to use regmap,
> >>   - converting the ASV driver to proper platform driver.
> >>
> >> I tried the opp-supported-hw bitmask approach as in the Qualcomm CPUFreq
> >> DT bindings but it resulted in too many OPPs and DT nodes, around 200
> >> per CPU cluster. So the ASV OPP tables are now in the ASV driver, as in
> >> downstream kernels.
> > Hmm. Can you explain why do you have so many OPPs? How many
> > frequencies do you actually support per cluster and what all varies
> > per frequency based on hw ? How many hw version do u have ?
> 
> For big cores there are 20 frequencies (2100MHz .. 200MHz). Each SoC 
> might belong to one of the 3 production 'sets' and each set contains 14 
> so called 'asv groups', which assign the certain voltage values for each 
> of those 20 frequencies (the lower asv group means lower voltage needed 
> for given frequency).

There is another property which might be useful in this case:
"opp-microvolt-<name>" and then you can use API
dev_pm_opp_set_prop_name() to choose which voltage value to apply to
all OPPs.

opp-supported-hw property is more useful for the cases where only a
subset of frequencies will be supported for different versions of the
SoC. And what you need is a different voltage value for all
frequencies based on some h/w version.

-- 
viresh

^ permalink raw reply

* RE: [PATCH V5 1/5] dt-bindings: imx: Add clock binding doc for i.MX8MN
From: Anson Huang @ 2019-07-25  2:17 UTC (permalink / raw)
  To: Rob Herring, Shawn Guo
  Cc: Michael Turquette, Stephen Boyd, Mark Rutland, Sascha Hauer,
	Sascha Hauer, Fabio Estevam, Catalin Marinas, Will Deacon,
	Maxime Ripard, Olof Johansson, Simon Horman, Jagan Teki,
	Leonard Crestez, Bjorn Andersson, Dinh Nguyen,
	Enric Balletbo i Serra, Aisheng Dong, Jacky Bai, Abel Vesa, Lucas
In-Reply-To: <CAL_JsqKv39XdFABuRvxwiXg6qQpHSuykwgqTwsGw1g+D2wA1+w@mail.gmail.com>



> On Sun, Jul 21, 2019 at 7:51 PM Shawn Guo <shawnguo@kernel.org> wrote:
> >
> > On Wed, Jun 19, 2019 at 01:52:43PM +0800, Anson.Huang@nxp.com wrote:
> > > From: Anson Huang <Anson.Huang@nxp.com>
> > >
> > > Add the clock binding doc for i.MX8MN.
> > >
> > > Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
> > > Reviewed-by: Maxime Ripard <maxime.ripard@bootlin.com>
> >
> > Applied all, thanks.
> 
> This breaks building of 'dt_binding_check'. Looks like there are tabs in the file
> which doesn't mix with YAML. Please fix.

Ah, yes, there is a tab in file and break the YAML format, I have send out a patch to
fix it, and YAML file check now can pass. Sorry for it.

https://patchwork.kernel.org/patch/11057815/

-       clock-output-names = "osc_32k";
+        clock-output-names = "osc_32k";
     };

Thanks,
Anson

^ permalink raw reply

* [PATCH] dt-bindings: clock: imx8mn: Fix tab indentation for yaml file
From: Anson.Huang @ 2019-07-25  2:05 UTC (permalink / raw)
  To: mturquette, sboyd, robh+dt, mark.rutland, shawnguo, s.hauer,
	kernel, festevam, linux-clk, devicetree, linux-arm-kernel,
	linux-kernel
  Cc: Linux-imx

From: Anson Huang <Anson.Huang@nxp.com>

YAML file can NOT contain tab as indentation, fix it.

Fixes: 6d6062553e3d ("dt-bindings: imx: Add clock binding doc for i.MX8MN")
Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
---
 Documentation/devicetree/bindings/clock/imx8mn-clock.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/clock/imx8mn-clock.yaml b/Documentation/devicetree/bindings/clock/imx8mn-clock.yaml
index 454c5b4..622f365 100644
--- a/Documentation/devicetree/bindings/clock/imx8mn-clock.yaml
+++ b/Documentation/devicetree/bindings/clock/imx8mn-clock.yaml
@@ -71,7 +71,7 @@ examples:
         compatible = "fixed-clock";
         #clock-cells = <0>;
         clock-frequency = <32768>;
-	clock-output-names = "osc_32k";
+        clock-output-names = "osc_32k";
     };
 
     osc_24m: clock-osc-24m {
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH v8 0/7] Unify CPU topology across ARM & RISC-V
From: Atish Patra @ 2019-07-25  1:24 UTC (permalink / raw)
  To: Paul Walmsley
  Cc: linux-kernel@vger.kernel.org, Jeremy Linton, Albert Ou,
	Anup Patel, Catalin Marinas, David S. Miller,
	devicetree@vger.kernel.org, Greg Kroah-Hartman, Ingo Molnar,
	Johan Hovold, Linus Walleij, linux-riscv@lists.infradead.org,
	Mark Rutland, Mauro Carvalho Chehab, Morten Rasmussen,
	Otto Sabart, Palmer Dabbelt, Peter 
In-Reply-To: <alpine.DEB.2.21.9999.1907221224170.23563@viisi.sifive.com>

On 7/22/19 12:25 PM, Paul Walmsley wrote:
> On Fri, 12 Jul 2019, Paul Walmsley wrote:
> 
>> On Thu, 27 Jun 2019, Atish Patra wrote:
>>
>>> The cpu-map DT entry in ARM can describe the CPU topology in much better
>>> way compared to other existing approaches. RISC-V can easily adopt this
>>> binding to represent its own CPU topology. Thus, both cpu-map DT
>>> binding and topology parsing code can be moved to a common location so
>>> that RISC-V or any other architecture can leverage that.
>>> different config for the architectures that do not support them.
>>
>> Once v5.3-rc1 is released, let's plan to get these patches rebased and
>> reposted and into linux-next as soon as possible.
> 
> These CPU topology patches are now queued for v5.4-rc1.  They should enter
> linux-next shortly.
> 
> 
> - Paul
> 

Thanks!!

-- 
Regards,
Atish

^ permalink raw reply

* [PATCH v5 2/2] EDAC: add EDAC driver for DMC520
From: Lei Wang @ 2019-07-25  0:49 UTC (permalink / raw)
  To: bp@alien8.de, james.morse@arm.com, robh+dt@kernel.org,
	mark.rutland@arm.com
  Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	mchehab@kernel.org, linux-edac@vger.kernel.org, sashal@kernel.org,
	hangl@microsoft.com, lewan@microsoft.com, ruizhao@microsoft.com,
	Lei Wang

New driver supports error detection and correction on the devices with ARM
DMC-520 memory controller.

Signed-off-by: Lei Wang <leiwang_git@outlook.com>
Reviewed-by: James Morse <james.morse@arm.com>
---
    Changes in v5:
        - When enable configured interrupts, do not potentially disable
          other irrelevant interrupts.
        - fix return type of dmc520_get_scrub_type to enum scrub_type
        - Use capital letters for enum
        - Retrieve memory width from dmc register format_control
        - use cheaper spin_lock API.
        - Remove compatible line for "brcm,dmc-520"
        - Add James' Reviewed-by
---
 MAINTAINERS                |   6 +
 drivers/edac/Kconfig       |   7 +
 drivers/edac/Makefile      |   1 +
 drivers/edac/dmc520_edac.c | 632 +++++++++++++++++++++++++++++++++++++
 4 files changed, 646 insertions(+)
 create mode 100644 drivers/edac/dmc520_edac.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 77eae44bf5de..7c1ac8bc8ea1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5703,6 +5703,12 @@ F:	Documentation/driver-api/edac.rst
 F:	drivers/edac/
 F:	include/linux/edac.h
 
+EDAC-DMC520
+M:	Lei Wang <lewan@microsoft.com>
+L:	linux-edac@vger.kernel.org
+S:	Supported
+F:	drivers/edac/dmc520_edac.c
+
 EDAC-E752X
 M:	Mark Gross <mark.gross@intel.com>
 L:	linux-edac@vger.kernel.org
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 200c04ce5b0e..7fde5aea0c1a 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -510,4 +510,11 @@ config EDAC_ASPEED
 	  First, ECC must be configured in the bootloader. Then, this driver
 	  will expose error counters via the EDAC kernel framework.
 
+config EDAC_DMC520
+       tristate "ARM DMC-520 ECC"
+       depends on ARM64
+       help
+         Support for error detection and correction on the
+         SoCs with ARM DMC-520 DRAM controller.
+
 endif # EDAC
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 165ca65e1a3a..e0d98f5b2045 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -85,3 +85,4 @@ obj-$(CONFIG_EDAC_XGENE)		+= xgene_edac.o
 obj-$(CONFIG_EDAC_TI)			+= ti_edac.o
 obj-$(CONFIG_EDAC_QCOM)			+= qcom_edac.o
 obj-$(CONFIG_EDAC_ASPEED)		+= aspeed_edac.o
+obj-$(CONFIG_EDAC_DMC520)		+= dmc520_edac.o
diff --git a/drivers/edac/dmc520_edac.c b/drivers/edac/dmc520_edac.c
new file mode 100644
index 000000000000..aeb8d84405cf
--- /dev/null
+++ b/drivers/edac/dmc520_edac.c
@@ -0,0 +1,632 @@
+// SPDX-License-Identifier: GPL-2.0
+/* EDAC driver for DMC-520 */
+
+
+#include <linux/bitfield.h>
+#include <linux/edac.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include "edac_mc.h"
+
+/* DMC-520 registers */
+#define REG_OFFSET_FEATURE_CONFIG		0x130
+#define REG_OFFSET_ECC_ERRC_COUNT_31_00		0x158
+#define REG_OFFSET_ECC_ERRC_COUNT_63_32		0x15C
+#define REG_OFFSET_ECC_ERRD_COUNT_31_00		0x160
+#define REG_OFFSET_ECC_ERRD_COUNT_63_32		0x164
+#define REG_OFFSET_INTERRUPT_CONTROL		0x500
+#define REG_OFFSET_INTERRUPT_CLR		0x508
+#define REG_OFFSET_INTERRUPT_STATUS		0x510
+#define REG_OFFSET_DRAM_ECC_ERRC_INT_INFO_31_00	0x528
+#define REG_OFFSET_DRAM_ECC_ERRC_INT_INFO_63_32	0x52C
+#define REG_OFFSET_DRAM_ECC_ERRD_INT_INFO_31_00	0x530
+#define REG_OFFSET_DRAM_ECC_ERRD_INT_INFO_63_32	0x534
+#define REG_OFFSET_ADDRESS_CONTROL_NOW		0x1010
+#define REG_OFFSET_MEMORY_TYPE_NOW		0x1128
+#define REG_OFFSET_SCRUB_CONTROL0_NOW		0x1170
+#define REG_OFFSET_FORMAT_CONTROL	0x18
+
+/* DMC-520 types, masks and bitfields */
+#define DRAM_ECC_INT_CE_BIT			BIT(2)
+#define DRAM_ECC_INT_UE_BIT			BIT(3)
+#define ALL_INT_MASK				GENMASK(9, 0)
+#define MEMORY_WIDTH_MASK			GENMASK(1, 0)
+#define SCRUB_TRIGGER0_NEXT_MASK		GENMASK(1, 0)
+#define REG_FIELD_DRAM_ECC_ENABLED		GENMASK(1, 0)
+#define REG_FIELD_MEMORY_TYPE			GENMASK(2, 0)
+#define REG_FIELD_DEVICE_WIDTH			GENMASK(9, 8)
+#define REG_FIELD_ADDRESS_CONTROL_COL		GENMASK(2, 0)
+#define REG_FIELD_ADDRESS_CONTROL_ROW		GENMASK(10, 8)
+#define REG_FIELD_ADDRESS_CONTROL_BANK		GENMASK(18, 16)
+#define REG_FIELD_ADDRESS_CONTROL_RANK		GENMASK(25, 24)
+#define REG_FIELD_ERR_INFO_LOW_VALID		BIT(0)
+#define REG_FIELD_ERR_INFO_LOW_COL		GENMASK(10, 1)
+#define REG_FIELD_ERR_INFO_LOW_ROW		GENMASK(28, 11)
+#define REG_FIELD_ERR_INFO_LOW_RANK		GENMASK(31, 29)
+#define REG_FIELD_ERR_INFO_HIGH_BANK		GENMASK(3, 0)
+#define REG_FIELD_ERR_INFO_HIGH_VALID		BIT(31)
+
+#define DRAM_ADDRESS_CONTROL_MIN_COL_BITS	8
+#define DRAM_ADDRESS_CONTROL_MIN_ROW_BITS	11
+
+#define DMC520_SCRUB_TRIGGER_ERR_DETECT		2
+#define DMC520_SCRUB_TRIGGER_IDLE			3
+
+/* Driver settings */
+/* The max-length message would be: "rank:7 bank:15 row:262143 col:1023".
+ * Max length is 34. Using a 40-size buffer is enough.
+ */
+#define EDAC_MSG_BUF_SIZE			40
+#define EDAC_MOD_NAME				"dmc520-edac"
+#define EDAC_CTL_NAME				"dmc520"
+
+/* the data bus width for the attached memory chips. */
+enum dmc520_mem_width {
+	MEM_WIDTH_X32 = 2,
+	MEM_WIDTH_X64 = 3
+};
+
+/* memory type */
+enum dmc520_mem_type {
+	MEM_TYPE_DDR3 = 1,
+	MEM_TYPE_DDR4 = 2
+};
+
+/* memory device width */
+enum dmc520_dev_width {
+	DEV_WIDTH_X4 = 0,
+	DEV_WIDTH_X8 = 1,
+	DEV_WIDTH_X16 = 2
+};
+
+struct ecc_error_info {
+	u32 col;
+	u32 row;
+	u32 bank;
+	u32 rank;
+};
+
+/* The EDAC driver private data */
+struct dmc520_edac {
+	void __iomem *reg_base;
+	u32 nintr;
+	u32 interrupt_mask_all;
+	spinlock_t ecc_lock;
+	u32 interrupt_masks[0];
+};
+
+static int dmc520_mc_idx;
+
+static irqreturn_t
+dmc520_edac_dram_all_isr(int irq, struct mem_ctl_info *mci, u32 interrupt_mask);
+
+#define DECLARE_ISR(index) \
+static irqreturn_t dmc520_isr_##index (int irq, void *data) \
+{ \
+	struct mem_ctl_info *mci; \
+	struct dmc520_edac *edac; \
+	mci = data; \
+	edac = mci->pvt_info; \
+	return dmc520_edac_dram_all_isr(irq, mci, edac->interrupt_masks[index]); \
+}
+
+DECLARE_ISR(0)
+DECLARE_ISR(1)
+/* More DECLARE_ISR(index) can be added to support more interrupt lines. */
+
+irq_handler_t dmc520_isr_array[] = {
+	dmc520_isr_0,
+	dmc520_isr_1
+	/* More dmc520_isr_index can be added to support more interrupt lines. */
+};
+
+static u32 dmc520_read_reg(struct dmc520_edac *edac, u32 offset)
+{
+	return readl(edac->reg_base + offset);
+}
+
+static void dmc520_write_reg(struct dmc520_edac *edac, u32 val, u32 offset)
+{
+	writel(val, edac->reg_base + offset);
+}
+
+static u32 dmc520_calc_dram_ecc_error(u32 value)
+{
+	u32 total = 0;
+
+	/* Each rank's error counter takes one byte */
+	while (value > 0) {
+		total += (value & 0xFF);
+		value >>= 8;
+	}
+	return total;
+}
+
+static u32 dmc520_get_dram_ecc_error_count(struct dmc520_edac *edac,
+					   bool is_ce)
+{
+	u32 reg_offset_low, reg_offset_high;
+	u32 err_low, err_high;
+	u32 err_count;
+
+	reg_offset_low = is_ce ? REG_OFFSET_ECC_ERRC_COUNT_31_00 :
+				 REG_OFFSET_ECC_ERRD_COUNT_31_00;
+	reg_offset_high = is_ce ? REG_OFFSET_ECC_ERRC_COUNT_63_32 :
+				  REG_OFFSET_ECC_ERRD_COUNT_63_32;
+
+	err_low = dmc520_read_reg(edac, reg_offset_low);
+	err_high = dmc520_read_reg(edac, reg_offset_high);
+	/* Reset error counters */
+	dmc520_write_reg(edac, 0, reg_offset_low);
+	dmc520_write_reg(edac, 0, reg_offset_high);
+
+	err_count = dmc520_calc_dram_ecc_error(err_low) +
+		   dmc520_calc_dram_ecc_error(err_high);
+
+	return err_count;
+}
+
+static void dmc520_get_dram_ecc_error_info(struct dmc520_edac *edac,
+					   bool is_ce,
+					   struct ecc_error_info *info)
+{
+	u32 reg_offset_low, reg_offset_high;
+	u32 reg_val_low, reg_val_high;
+	bool valid;
+
+	reg_offset_low = is_ce ? REG_OFFSET_DRAM_ECC_ERRC_INT_INFO_31_00 :
+				 REG_OFFSET_DRAM_ECC_ERRD_INT_INFO_31_00;
+	reg_offset_high = is_ce ? REG_OFFSET_DRAM_ECC_ERRC_INT_INFO_63_32 :
+				  REG_OFFSET_DRAM_ECC_ERRD_INT_INFO_63_32;
+
+	reg_val_low = dmc520_read_reg(edac, reg_offset_low);
+	reg_val_high = dmc520_read_reg(edac, reg_offset_high);
+
+	valid = (FIELD_GET(REG_FIELD_ERR_INFO_LOW_VALID, reg_val_low) != 0) &&
+		(FIELD_GET(REG_FIELD_ERR_INFO_HIGH_VALID, reg_val_high) != 0);
+
+	if (valid) {
+		info->col = FIELD_GET(REG_FIELD_ERR_INFO_LOW_COL, reg_val_low);
+		info->row = FIELD_GET(REG_FIELD_ERR_INFO_LOW_ROW, reg_val_low);
+		info->rank = FIELD_GET(REG_FIELD_ERR_INFO_LOW_RANK, reg_val_low);
+		info->bank = FIELD_GET(REG_FIELD_ERR_INFO_HIGH_BANK, reg_val_high);
+	} else {
+		memset(info, 0, sizeof(struct ecc_error_info));
+	}
+}
+
+static bool dmc520_is_ecc_enabled(void __iomem *reg_base)
+{
+	u32 reg_val = readl(reg_base + REG_OFFSET_FEATURE_CONFIG);
+
+	return (FIELD_GET(REG_FIELD_DRAM_ECC_ENABLED, reg_val) != 0);
+}
+
+static enum scrub_type dmc520_get_scrub_type(struct dmc520_edac *edac)
+{
+	enum scrub_type type = SCRUB_NONE;
+	u32 reg_val, scrub_cfg;
+
+	reg_val = dmc520_read_reg(edac, REG_OFFSET_SCRUB_CONTROL0_NOW);
+	scrub_cfg = FIELD_GET(SCRUB_TRIGGER0_NEXT_MASK, reg_val);
+
+	if (DMC520_SCRUB_TRIGGER_ERR_DETECT == scrub_cfg ||
+		DMC520_SCRUB_TRIGGER_IDLE == scrub_cfg)
+		type = SCRUB_HW_PROG;
+
+	return type;
+}
+
+/* Get the memory data bus width, in number of bytes. */
+static u32 dmc520_get_memory_width(struct dmc520_edac *edac)
+{
+	static u32 mem_width;
+	u32 reg_val;
+	enum dmc520_mem_width mem_width_field;
+
+	if (mem_width == 0) {
+		reg_val = dmc520_read_reg(edac, REG_OFFSET_FORMAT_CONTROL);
+		mem_width_field = FIELD_GET(MEMORY_WIDTH_MASK, reg_val);
+
+		if (mem_width_field == MEM_WIDTH_X32)
+			mem_width = 4; /* 32-bits, 4 bytes */
+		else if (mem_width_field == MEM_WIDTH_X64)
+			mem_width = 8; /* 64-bits, 8 bytes */
+	}
+
+	return mem_width;
+}
+
+static enum mem_type dmc520_get_mtype(struct dmc520_edac *edac)
+{
+	enum mem_type mt = MEM_UNKNOWN;
+	u32 reg_val;
+	enum dmc520_mem_type type;
+
+	reg_val = dmc520_read_reg(edac, REG_OFFSET_MEMORY_TYPE_NOW);
+	type = FIELD_GET(REG_FIELD_MEMORY_TYPE, reg_val);
+
+	switch (type) {
+	case MEM_TYPE_DDR3:
+		mt = MEM_DDR3;
+		break;
+
+	case MEM_TYPE_DDR4:
+		mt = MEM_DDR4;
+		break;
+	}
+
+	return mt;
+}
+
+static enum dev_type dmc520_get_dtype(struct dmc520_edac *edac)
+{
+	enum dev_type dt = DEV_UNKNOWN;
+	u32 reg_val;
+	enum dmc520_dev_width device_width;
+
+	reg_val = dmc520_read_reg(edac, REG_OFFSET_MEMORY_TYPE_NOW);
+	device_width = FIELD_GET(REG_FIELD_DEVICE_WIDTH, reg_val);
+
+	switch (device_width) {
+	case DEV_WIDTH_X4:
+		dt = DEV_X4;
+		break;
+
+	case DEV_WIDTH_X8:
+		dt = DEV_X8;
+		break;
+
+	case DEV_WIDTH_X16:
+		dt = DEV_X16;
+		break;
+	}
+
+	return dt;
+}
+
+static u32 dmc520_get_rank_count(void __iomem *reg_base)
+{
+	u32 reg_val, rank_bits;
+
+	reg_val = readl(reg_base + REG_OFFSET_ADDRESS_CONTROL_NOW);
+	rank_bits = FIELD_GET(REG_FIELD_ADDRESS_CONTROL_RANK, reg_val);
+
+	return (1 << rank_bits);
+}
+
+static u64 dmc520_get_rank_size(struct dmc520_edac *edac)
+{
+	u32 reg_val, col_bits, row_bits, bank_bits;
+
+	reg_val = dmc520_read_reg(edac, REG_OFFSET_ADDRESS_CONTROL_NOW);
+
+	col_bits = FIELD_GET(REG_FIELD_ADDRESS_CONTROL_COL, reg_val) +
+		   DRAM_ADDRESS_CONTROL_MIN_COL_BITS;
+	row_bits = FIELD_GET(REG_FIELD_ADDRESS_CONTROL_ROW, reg_val) +
+		   DRAM_ADDRESS_CONTROL_MIN_ROW_BITS;
+	bank_bits = FIELD_GET(REG_FIELD_ADDRESS_CONTROL_BANK, reg_val);
+
+	return (u64)dmc520_get_memory_width(edac) << (col_bits + row_bits + bank_bits);
+}
+
+static void dmc520_handle_dram_ecc_errors(struct mem_ctl_info *mci,
+					  bool is_ce)
+{
+	struct ecc_error_info info;
+	struct dmc520_edac *edac;
+	u32 cnt;
+	char message[EDAC_MSG_BUF_SIZE];
+
+	edac = mci->pvt_info;
+	dmc520_get_dram_ecc_error_info(edac, is_ce, &info);
+
+	cnt = dmc520_get_dram_ecc_error_count(edac, is_ce);
+
+	if (cnt > 0) {
+		snprintf(message, ARRAY_SIZE(message),
+			 "rank:%d bank:%d row:%d col:%d",
+			 info.rank, info.bank,
+			 info.row, info.col);
+
+		spin_lock(&edac->ecc_lock);
+		edac_mc_handle_error((is_ce ? HW_EVENT_ERR_CORRECTED :
+				     HW_EVENT_ERR_UNCORRECTED),
+				     mci, cnt, 0, 0, 0, info.rank, -1, -1,
+				     message, "");
+		spin_unlock(&edac->ecc_lock);
+	}
+}
+
+static irqreturn_t dmc520_edac_dram_ecc_isr(int irq, struct mem_ctl_info *mci, bool is_ce)
+{
+	u32 i_mask;
+	struct dmc520_edac *edac;
+
+	edac = mci->pvt_info;
+
+	i_mask = is_ce ? DRAM_ECC_INT_CE_BIT : DRAM_ECC_INT_UE_BIT;
+
+	dmc520_handle_dram_ecc_errors(mci, is_ce);
+
+	dmc520_write_reg(edac, i_mask, REG_OFFSET_INTERRUPT_CLR);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t
+dmc520_edac_dram_all_isr(int irq, struct mem_ctl_info *mci, u32 interrupt_mask)
+{
+	struct dmc520_edac *edac;
+	u32 status;
+	irqreturn_t irq_ret = IRQ_NONE;
+
+	edac = mci->pvt_info;
+
+	status = dmc520_read_reg(edac, REG_OFFSET_INTERRUPT_STATUS);
+
+	if ((interrupt_mask & DRAM_ECC_INT_CE_BIT) &&
+		(status & DRAM_ECC_INT_CE_BIT))
+		irq_ret = dmc520_edac_dram_ecc_isr(irq, mci, true);
+
+	if ((interrupt_mask & DRAM_ECC_INT_UE_BIT) &&
+		(status & DRAM_ECC_INT_UE_BIT))
+		irq_ret = dmc520_edac_dram_ecc_isr(irq, mci, false);
+
+	/* If in the future there are more supported interrupts in a different
+	 * platform, more condition statements can be added here for each
+	 * interrupt flag, together with its corresponding isr implementations.
+	 */
+
+	return irq_ret;
+}
+
+static void dmc520_init_csrow(struct mem_ctl_info *mci)
+{
+	struct csrow_info *csi;
+	struct dimm_info *dimm;
+	int row, ch;
+	enum dev_type dt;
+	enum mem_type mt;
+	u64 rs;
+	u32 pages_per_rank;
+	struct dmc520_edac *edac = mci->pvt_info;
+
+	dt = dmc520_get_dtype(edac);
+	mt = dmc520_get_mtype(edac);
+	rs = dmc520_get_rank_size(edac);
+	pages_per_rank = rs >> PAGE_SHIFT;
+
+	for (row = 0; row < mci->nr_csrows; row++) {
+		csi = mci->csrows[row];
+
+		for (ch = 0; ch < csi->nr_channels; ch++) {
+			dimm		= csi->channels[ch]->dimm;
+			dimm->grain	= dmc520_get_memory_width(edac);
+			dimm->dtype	= dt;
+			dimm->mtype	= mt;
+			dimm->edac_mode	= EDAC_FLAG_SECDED;
+			dimm->nr_pages	= pages_per_rank / csi->nr_channels;
+		}
+	}
+}
+
+static int dmc520_edac_probe(struct platform_device *pdev)
+{
+	struct device *dev;
+	struct dmc520_edac *edac;
+	struct mem_ctl_info *mci;
+	struct edac_mc_layer layers[1];
+	int ret, intr_index, nintr, nintr_registered = 0;
+	struct resource *res;
+	void __iomem *reg_base;
+	u32 reg_val;
+
+	/* Parsing the device node */
+	dev = &pdev->dev;
+
+	nintr = of_property_count_u32_elems(dev->of_node, "interrupt-config");
+	if (nintr <= 0) {
+		edac_printk(KERN_ERR, EDAC_MOD_NAME,
+			"Invalid device node configuration: at least one interrupt "
+			"line & config is expected.\n");
+		return -EINVAL;
+	}
+
+	if (nintr > ARRAY_SIZE(dmc520_isr_array)) {
+		edac_printk(KERN_ERR, EDAC_MOD_NAME,
+			"Invalid device node configuration: # of interrupt config "
+			"elements (%d) can not exceed %ld.\n",
+			nintr, ARRAY_SIZE(dmc520_isr_array));
+		return -EINVAL;
+	}
+
+	/* Initialize dmc520 edac */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	reg_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(reg_base))
+		return PTR_ERR(reg_base);
+
+	if (!dmc520_is_ecc_enabled(reg_base))
+		return -ENXIO;
+
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = dmc520_get_rank_count(reg_base);
+	layers[0].is_virt_csrow = true;
+
+	mci = edac_mc_alloc(dmc520_mc_idx++, ARRAY_SIZE(layers), layers,
+			    sizeof(struct dmc520_edac) + sizeof(u32) * nintr);
+	if (!mci) {
+		edac_printk(KERN_ERR, EDAC_MOD_NAME,
+			    "Failed to allocate memory for mc instance\n");
+		return -ENOMEM;
+	}
+
+	edac = mci->pvt_info;
+	edac->reg_base = reg_base;
+	edac->nintr = nintr;
+	edac->interrupt_mask_all = 0;
+	spin_lock_init(&edac->ecc_lock);
+
+	ret = of_property_read_u32_array(dev->of_node, "interrupt-config",
+			edac->interrupt_masks, nintr);
+	if (ret) {
+		edac_printk(KERN_ERR, EDAC_MOD_NAME,
+			"Failed to get interrupt-config arrays.\n");
+		goto err_free_mc;
+	}
+
+	for (intr_index = 0; intr_index < nintr; ++intr_index) {
+		if (edac->interrupt_mask_all & edac->interrupt_masks[intr_index]) {
+			edac_printk(KERN_ERR, EDAC_MC,
+				"interrupt-config error: "
+				"element %d's interrupt mask %d has overlap.\n",
+				intr_index, edac->interrupt_masks[intr_index]);
+			goto err_free_mc;
+		}
+
+		edac->interrupt_mask_all |= edac->interrupt_masks[intr_index];
+	}
+
+	if ((edac->interrupt_mask_all | ALL_INT_MASK) != ALL_INT_MASK) {
+		edac_printk(KERN_WARNING, EDAC_MOD_NAME,
+			"interrupt-config warning: "
+			"interrupt mask (0x%x) is not supported by dmc520 (0x%lx).\n",
+			edac->interrupt_mask_all, ALL_INT_MASK);
+	}
+	edac->interrupt_mask_all &= ALL_INT_MASK;
+
+	platform_set_drvdata(pdev, mci);
+
+	mci->pdev = dev;
+	mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR4;
+	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+	mci->edac_cap = EDAC_FLAG_SECDED;
+	mci->scrub_cap = SCRUB_FLAG_HW_SRC;
+	mci->scrub_mode = dmc520_get_scrub_type(edac);
+	mci->ctl_name = EDAC_CTL_NAME;
+	mci->dev_name = dev_name(mci->pdev);
+	mci->mod_name = EDAC_MOD_NAME;
+	mci->ctl_page_to_phys = NULL;
+
+	edac_op_state = EDAC_OPSTATE_INT;
+
+	dmc520_init_csrow(mci);
+
+	ret = edac_mc_add_mc(mci);
+	if (ret) {
+		edac_printk(KERN_ERR, EDAC_MOD_NAME,
+			"Failed to register with EDAC core\n");
+		goto err_free_mc;
+	}
+
+	/* Clear interrupts, not affecting other unrelated interrupts */
+	reg_val = dmc520_read_reg(edac, REG_OFFSET_INTERRUPT_CONTROL);
+	dmc520_write_reg(edac, reg_val & (~(edac->interrupt_mask_all)),
+			REG_OFFSET_INTERRUPT_CONTROL);
+	dmc520_write_reg(edac, edac->interrupt_mask_all,
+			REG_OFFSET_INTERRUPT_CLR);
+
+	for (intr_index = 0; intr_index < nintr; ++intr_index) {
+		int irq_id = platform_get_irq(pdev, intr_index);
+
+		if (irq_id < 0) {
+			edac_printk(KERN_ERR, EDAC_MC,
+				    "Failed to get irq #%d\n", intr_index);
+			ret = -ENODEV;
+			goto err_free_irq;
+		}
+
+		ret = devm_request_irq(&pdev->dev, irq_id,
+				dmc520_isr_array[intr_index], IRQF_SHARED,
+				dev_name(&pdev->dev), mci);
+		if (ret < 0) {
+			edac_printk(KERN_ERR, EDAC_MC,
+				    "Failed to request irq %d\n", irq_id);
+			goto err_free_irq;
+		}
+
+		++nintr_registered;
+	}
+
+	/* Reset DRAM CE/UE counters */
+	if (edac->interrupt_mask_all & DRAM_ECC_INT_CE_BIT)
+		dmc520_get_dram_ecc_error_count(edac, true);
+
+	if (edac->interrupt_mask_all & DRAM_ECC_INT_UE_BIT)
+		dmc520_get_dram_ecc_error_count(edac, false);
+
+	/* Enable interrupts, not affecting other unrelated interrupts */
+	dmc520_write_reg(edac,
+		reg_val | edac->interrupt_mask_all,
+		REG_OFFSET_INTERRUPT_CONTROL);
+
+	return 0;
+
+err_free_irq:
+	for (intr_index = 0; intr_index < nintr_registered; ++intr_index) {
+		int irq_id = platform_get_irq(pdev, intr_index);
+
+		devm_free_irq(&pdev->dev, irq_id, mci);
+	}
+	edac_mc_del_mc(&pdev->dev);
+err_free_mc:
+	edac_mc_free(mci);
+
+	return ret;
+}
+
+static int dmc520_edac_remove(struct platform_device *pdev)
+{
+	struct dmc520_edac *edac;
+	struct mem_ctl_info *mci;
+	u32 reg_val, intr_index;
+
+	mci = platform_get_drvdata(pdev);
+	edac = mci->pvt_info;
+
+	/* Disable interrupts */
+	reg_val = dmc520_read_reg(edac, REG_OFFSET_INTERRUPT_CONTROL);
+	dmc520_write_reg(edac, reg_val & (~(edac->interrupt_mask_all)),
+			REG_OFFSET_INTERRUPT_CONTROL);
+
+	/* free irq's */
+	for (intr_index = 0; intr_index < edac->nintr; ++intr_index) {
+		int irq_id = platform_get_irq(pdev, intr_index);
+
+		devm_free_irq(&pdev->dev, irq_id, mci);
+	}
+
+	edac_mc_del_mc(&pdev->dev);
+	edac_mc_free(mci);
+
+	return 0;
+}
+
+static const struct of_device_id dmc520_edac_driver_id[] = {
+	{ .compatible = "arm,dmc-520", },
+	{ /* end of table */ }
+};
+
+MODULE_DEVICE_TABLE(of, dmc520_edac_driver_id);
+
+static struct platform_driver dmc520_edac_driver = {
+	.driver = {
+		.name = "dmc520",
+		.of_match_table = dmc520_edac_driver_id,
+	},
+
+	.probe = dmc520_edac_probe,
+	.remove = dmc520_edac_remove
+};
+
+module_platform_driver(dmc520_edac_driver);
+
+MODULE_AUTHOR(
+	"Rui Zhao <ruizhao@microsoft.com>, Lei Wang <lewan@microsoft.com>");
+MODULE_DESCRIPTION("DMC-520 ECC driver");
+MODULE_LICENSE("GPL v2");
-- 
2.17.1

^ permalink raw reply related

* [PATCH v5 1/2] dt-bindings: edac: arm-dmc520.txt
From: Lei Wang @ 2019-07-25  0:48 UTC (permalink / raw)
  To: bp@alien8.de, james.morse@arm.com, robh+dt@kernel.org,
	mark.rutland@arm.com
  Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	mchehab@kernel.org, linux-edac@vger.kernel.org, sashal@kernel.org,
	hangl@microsoft.com, lewan@microsoft.com, ruizhao@microsoft.com,
	Lei Wang

This is the device tree bindings for new EDAC driver dmc520_edac.c.

Signed-off-by: Lei Wang <leiwang_git@outlook.com>
Reviewed-by: James Morse <james.morse@arm.com>

---
    No change in v5.
---
 .../devicetree/bindings/edac/arm-dmc520.txt   | 26 +++++++++++++++++++
 1 file changed, 26 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/edac/arm-dmc520.txt

diff --git a/Documentation/devicetree/bindings/edac/arm-dmc520.txt b/Documentation/devicetree/bindings/edac/arm-dmc520.txt
new file mode 100644
index 000000000000..71e7aa32971a
--- /dev/null
+++ b/Documentation/devicetree/bindings/edac/arm-dmc520.txt
@@ -0,0 +1,26 @@
+* ARM DMC-520 EDAC node
+
+Required properties:
+- compatible		: "brcm,dmc-520", "arm,dmc-520".
+- reg			: Address range of the DMC-520 registers.
+- interrupts		: DMC-520 interrupt numbers. The example below specifies
+			  two interrupt lines for dram_ecc_errc_int and
+			  dram_ecc_errd_int.
+- interrupt-config	: This is an array of interrupt masks. For each of the
+			  above interrupt line, add one interrupt mask element to
+			  it. That is, there is a 1:1 mapping from each interrupt
+			  line to an interrupt mask. An interrupt mask can represent
+			  multiple interrupts being enabled. Refer to interrupt_control
+			  register in DMC-520 TRM for interrupt mapping. In the example
+			  below, the interrupt configuration enables dram_ecc_errc_int
+			  and dram_ecc_errd_int. And each interrupt is connected to
+			  a separate interrupt line.
+
+Example:
+
+dmc0: dmc@200000 {
+	compatible = "brcm,dmc-520", "arm,dmc-520";
+	reg = <0x200000 0x80000>;
+	interrupts = <0x0 0x349 0x4>, <0x0 0x34B 0x4>;
+	interrupt-config = <0x4>, <0x8>;
+};
-- 
2.17.1

^ permalink raw reply related

* [PATCH v2 4/4] arm64: dts: ti: k3-j721e-common-proc-board: Add IPC sub-mailbox nodes
From: Suman Anna @ 2019-07-25  0:10 UTC (permalink / raw)
  To: Tero Kristo, Nishanth Menon; +Cc: devicetree, linux-arm-kernel
In-Reply-To: <20190725001020.23781-1-s-anna@ti.com>

Add the sub-mailbox nodes that are used to communicate between MPU and
various remote processors present in the J721E SoCs to the J721E common
processor board. These include the R5F remote processors in the dual-R5F
cluster (MCU_R5FSS0) in the MCU domain and the two dual-R5F clusters
(MAIN_R5FSS0 & MAIN_R5FSS1) in the MAIN domain; the two C66x DSP remote
processors and the single C71x DSP remote processor in the MAIN domain.
These sub-mailbox nodes utilize the System Mailbox clusters 0 through 4.
All the remaining mailbox clusters are currently not used on A72 core,
and so are disabled.

The sub-mailbox nodes added match the hard-coded mailbox configuration
used within the TI RTOS IPC software packages. The R5F processor
sub-systems are assumed to be running in Split mode, so a sub-mailbox
node is used by each of the R5F cores. Only the sub-mailbox node for
the first R5F core in each cluster is used in case of a Lockstep mode
for that R5F cluster.

NOTE:
The GIC_SPI interrupts to be used are dynamically allocated and managed
by the System Firmware through the ti-sci-intr irqchip driver. So, only
valid interrupts (each cluster's User 0 IRQ output) that are used by the
sub-mailbox devices are enabled. This is done to minimize the number of
NavSS Interrupt Router outputs utilized.

Signed-off-by: Suman Anna <s-anna@ti.com>
---
v2:
 - Sub-mailboxes added in board dts file instead of base dtsi file
 - Unused mailbox clusters 5 through 11 disabled
 - Patch description and title updated
v1: https://patchwork.kernel.org/patch/11053409/

 .../dts/ti/k3-j721e-common-proc-board.dts     | 93 +++++++++++++++++++
 1 file changed, 93 insertions(+)

diff --git a/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts
index c680123f067c..93ae1d49dcc1 100644
--- a/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts
+++ b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board.dts
@@ -48,3 +48,96 @@
 	/* UART not brought out */
 	status = "disabled";
 };
+
+&mailbox0_cluster0 {
+	interrupts = <214 0>;
+
+	mbox_mcu_r5fss0_core0: mbox-mcu-r5fss0-core0 {
+		ti,mbox-rx = <0 0 0>;
+		ti,mbox-tx = <1 0 0>;
+	};
+
+	mbox_mcu_r5fss0_core1: mbox-mcu-r5fss0-core1 {
+		ti,mbox-rx = <2 0 0>;
+		ti,mbox-tx = <3 0 0>;
+	};
+};
+
+&mailbox0_cluster1 {
+	interrupts = <215 0>;
+
+	mbox_main_r5fss0_core0: mbox-main-r5fss0-core0 {
+		ti,mbox-rx = <0 0 0>;
+		ti,mbox-tx = <1 0 0>;
+	};
+
+	mbox_main_r5fss0_core1: mbox-main-r5fss0-core1 {
+		ti,mbox-rx = <2 0 0>;
+		ti,mbox-tx = <3 0 0>;
+	};
+};
+
+&mailbox0_cluster2 {
+	interrupts = <216 0>;
+
+	mbox_main_r5fss1_core0: mbox-main-r5fss1-core0 {
+		ti,mbox-rx = <0 0 0>;
+		ti,mbox-tx = <1 0 0>;
+	};
+
+	mbox_main_r5fss1_core1: mbox-main-r5fss1-core1 {
+		ti,mbox-rx = <2 0 0>;
+		ti,mbox-tx = <3 0 0>;
+	};
+};
+
+&mailbox0_cluster3 {
+	interrupts = <217 0>;
+
+	mbox_c66_0: mbox-c66-0 {
+		ti,mbox-rx = <0 0 0>;
+		ti,mbox-tx = <1 0 0>;
+	};
+
+	mbox_c66_1: mbox-c66-1 {
+		ti,mbox-rx = <2 0 0>;
+		ti,mbox-tx = <3 0 0>;
+	};
+};
+
+&mailbox0_cluster4 {
+	interrupts = <218 0>;
+
+	mbox_c71_0: mbox-c71-0 {
+		ti,mbox-rx = <0 0 0>;
+		ti,mbox-tx = <1 0 0>;
+	};
+};
+
+&mailbox0_cluster5 {
+	status = "disabled";
+};
+
+&mailbox0_cluster6 {
+	status = "disabled";
+};
+
+&mailbox0_cluster7 {
+	status = "disabled";
+};
+
+&mailbox0_cluster8 {
+	status = "disabled";
+};
+
+&mailbox0_cluster9 {
+	status = "disabled";
+};
+
+&mailbox0_cluster10 {
+	status = "disabled";
+};
+
+&mailbox0_cluster11 {
+	status = "disabled";
+};
-- 
2.22.0

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox