Devicetree
 help / color / mirror / Atom feed
* Re: [RESEND PATCH] ARM: dts: bcm28155-ap: Fix Card Detection GPIO
From: Olof Johansson @ 2014-01-31 23:11 UTC (permalink / raw)
  To: Tim Kryger
  Cc: Christian Daudt, Rob Herring, Pawel Moll, Mark Rutland,
	Stephen Warren, Ian Campbell, Broadcom Kernel Feedback List,
	Device Tree List, Linux Arm Kernel List,
	Linux Kernel Mailing List, Linaro Patches, Kevin Hilman
In-Reply-To: <CAAYSxhpSz8ZF_urMfQ4xdc1fhFdQC-_=9U1dvNn=EU_OoNsWbw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Fri, Jan 24, 2014 at 10:48:40AM -0800, Tim Kryger wrote:
> On Wed, Jan 8, 2014 at 4:54 PM, Christian Daudt <bcm-xK7y4jjYLqYh9ZMKESR00Q@public.gmane.org> wrote:
> > On Wed, Jan 8, 2014 at 4:28 PM, Tim Kryger <tim.kryger-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> >> On Wed, Jan 8, 2014 at 3:38 PM, Christian Daudt <bcm-xK7y4jjYLqYh9ZMKESR00Q@public.gmane.org> wrote:
> >>> On Tue, Jan 7, 2014 at 10:53 AM, Tim Kryger <tim.kryger-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> >>>> The board schematic states that the "SD_CARD_DET_N gets pulled to GND
> >>>> when card is inserted" so the polarity has been updated to active low.
> >>>>
> >>>> Polarity is now specified with a GPIO define instead of a magic number.
> >>>>
> >>>> Signed-off-by: Tim Kryger <tim.kryger-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> >>>> Reviewed-by: Matt Porter <matt.porter-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> >>>> ---
> >>>>  arch/arm/boot/dts/bcm28155-ap.dts | 4 +++-
> >>>>  1 file changed, 3 insertions(+), 1 deletion(-)
> >>>>
> >>>> diff --git a/arch/arm/boot/dts/bcm28155-ap.dts b/arch/arm/boot/dts/bcm28155-ap.dts
> >>>> index 08e47c2..27dd110 100644
> >>>> --- a/arch/arm/boot/dts/bcm28155-ap.dts
> >>>> +++ b/arch/arm/boot/dts/bcm28155-ap.dts
> >>>> @@ -13,6 +13,8 @@
> >>>>
> >>>>  /dts-v1/;
> >>>>
> >>>> +#include <dt-bindings/gpio/gpio.h>
> >>>> +
> >>>>  #include "bcm11351.dtsi"
> >>>>
> >>>>  / {
> >>>> @@ -40,7 +42,7 @@
> >>>>
> >>>>         sdio4: sdio@3f1b0000 {
> >>>>                 max-frequency = <48000000>;
> >>>> -               cd-gpios = <&gpio 14 0>;
> >>>> +               cd-gpios = <&gpio 14 GPIO_ACTIVE_LOW>;
> >>>>                 status = "okay";
> >>>>         };
> >>>>  };
> >>>> --
> >>>> 1.8.0.1
> >>>>
> >>> Tim,
> >>>  Does bcm11351-brt not also suffer from the same bug? If it does can
> >>> you pls update the patch to also fix it?
> >>>
> >>>  Thanks,
> >>>    csd
> >>
> >> The BRT and AP boards are similar so it may have the same problem but
> >> I don't have a BRT and wouldn't be able to test any changes to its DTS
> >> file.
> >>
> >> -Tim
> >
> > [sorry for the resend for those that get it twice]
> > Agreed - it's time that dts file go away. In this case:
> > Acked-by: Christian Daudt <bcm-xK7y4jjYLqYh9ZMKESR00Q@public.gmane.org>
> >
> > Olof - can you pls pull in this patch. This is the bugfix that was
> > discussed in irc earlier today.
> >
> >  thanks,
> >    csd
> 
> Christian,
> 
> I'm not sure Olof saw your reply.  Olof and Kevin are now on CC.

Nope, applied now. Had to touch it up a bit since we're missing some of the
patches that this was based on for 3.14, but the cd-gpios property is fixed.


-Olof
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v3 3/5] spi: sunxi: Add Allwinner A31 SPI controller driver
From: Maxime Ripard @ 2014-01-31 22:47 UTC (permalink / raw)
  To: Mark Brown
  Cc: Mike Turquette, Emilio Lopez, linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	kevin.z.m.zh-Re5JQEeQqe8AvxtiuMwx3w,
	sunny-0TFLnhJekD6UEPyfVivIlAC/G2K4zDHf,
	shuge-0TFLnhJekD6UEPyfVivIlAC/G2K4zDHf,
	zhuzhenhua-0TFLnhJekD6UEPyfVivIlAC/G2K4zDHf
In-Reply-To: <20140131124809.GE22609-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 1400 bytes --]

On Fri, Jan 31, 2014 at 12:48:09PM +0000, Mark Brown wrote:
> On Fri, Jan 31, 2014 at 11:55:50AM +0100, Maxime Ripard wrote:
> 
> > +	master = devm_spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
> > +	if (!master) {
> > +		dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
> > +		return -ENOMEM;
> > +	}
> 
> This now depends on your other series which as I said doesn't look like
> the best approach.

Indeed, I forgot to mention it in the cover letter. My bad.

> 
> > +	pm_runtime_enable(&pdev->dev);
> > +	if (!pm_runtime_enabled(&pdev->dev)) {
> > +		ret = sun6i_spi_runtime_resume(&pdev->dev);
> > +		if (ret) {
> > +			dev_err(&pdev->dev, "Couldn't resume the device\n");
> > +			return ret;
> > +		}
> > +	}
> 
> No, as discussed don't do this - notice how other drivers aren't written
> this way either.  Like I said leave the device powered on startup and
> then let it be idled by runtime PM.

Well, some SPI drivers are actually written like that (all the tegra
SPI drivers for example). It's not an excuse, but waking up the device
only to put it back in suspend right away seems kind of
inefficient. Plus, the pm_runtime_idle callback you suggested are
actually calling runtime_idle, while we want to call runtime_suspend.


-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH v2 1/2] dt: Document a compatible entry for MDIO ethernet Phys
From: Florian Fainelli @ 2014-01-31 22:30 UTC (permalink / raw)
  To: Jason Gunthorpe
  Cc: Rob Herring, Grant Likely,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, netdev,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <1391205045-1751-1-git-send-email-jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>

2014-01-31 Jason Gunthorpe <jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>:
> This describes a compatible entry of the form:
>   ethernet-phy-idAAAA,BBBB
> Which is modelled after the PCI structured compatible entry
> (pciVVVV,DDDD.SSSS.ssss.RR)
>
> If present the OF core will be able to use this information to
> directly create the correct phy without auto probing the bus.
>
> Signed-off-by: Jason Gunthorpe <jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

Looks good, thanks!

Acked-by: Florian Fainelli <f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

> ---
>  Documentation/devicetree/bindings/net/phy.txt | 10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)
> Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>
> diff --git a/Documentation/devicetree/bindings/net/phy.txt b/Documentation/devicetree/bindings/net/phy.txt
> index 7cd18fb..989122c 100644
> --- a/Documentation/devicetree/bindings/net/phy.txt
> +++ b/Documentation/devicetree/bindings/net/phy.txt
> @@ -23,10 +23,18 @@ Optional Properties:
>    assume clause 22. The compatible list may also contain other
>    elements.
>
> +  If the phy's identifier is known then the list may contain an entry
> +  of the form: "ethernet-phy-idAAAA.BBBB" where
> +     AAAA - The value of the 16 bit Phy Identifier 1 register as
> +            4 hex digits. This is the chip vendor OUI bits 3:18
> +     BBBB - The value of the 16 bit Phy Identifier 2 register as
> +            4 hex digits. This is the chip vendor OUI bits 19:24,
> +            followed by 10 bits of a vendor specific ID.
> +
>  Example:
>
>  ethernet-phy@0 {
> -       compatible = "ethernet-phy-ieee802.3-c22";
> +       compatible = "ethernet-phy-id0141.0e90", "ethernet-phy-ieee802.3-c22";
>         linux,phandle = <2452000>;
>         interrupt-parent = <40000>;
>         interrupts = <35 1>;
> --
> 1.8.1.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Florian
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH 3/3] NFC: trf7970a: Add DTS Documentation
From: Mark A. Greer @ 2014-01-31 22:17 UTC (permalink / raw)
  To: Samuel Ortiz, Lauro Ramos Venancio, Aloisio Almeida Jr
  Cc: Felipe Balbi, Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-hn68Rpc1hR1g9hUCZPvPmw,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Mark A. Greer
In-Reply-To: <1391206631-9862-1-git-send-email-mgreer-luAo+O/VEmrlveNOaEYElw@public.gmane.org>

Describe the properies used by the trf7970a
RFID/NFC/15693 transceiver driver.

Signed-off-by: Mark A. Greer <mgreer-luAo+O/VEmrlveNOaEYElw@public.gmane.org>
---
 .../devicetree/bindings/net/nfc/trf7970a.txt       | 37 ++++++++++++++++++++++
 1 file changed, 37 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/nfc/trf7970a.txt

diff --git a/Documentation/devicetree/bindings/net/nfc/trf7970a.txt b/Documentation/devicetree/bindings/net/nfc/trf7970a.txt
new file mode 100644
index 0000000..4256893
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/nfc/trf7970a.txt
@@ -0,0 +1,37 @@
+* Texas Instruments TRF7970A RFID/NFC/15693 Transceiver
+
+Required properties:
+- compatible: Should be "ti,trf7970a".
+- spi-max-frequency: Maximum SPI frequency (<= 2000000).
+- interrupt-parent: phandle of parent interrupt handler.
+- interrupts: A single interrupt specifier.
+- ti,enable-gpios: Two GPIO entries used for 'EN' and 'EN2' pins on the
+  TRF7970A.
+
+Optional properties:
+- ti,ss-gpio: GPIO used for Slave Select pin on TRF7970A.  Its presence
+  indicates that "SPI with SS mode" is used by the TRF7970A.
+
+Optional SoC Specific Properties:
+- pinctrl-names: Contains only one value - "default".
+- pintctrl-0: Specifies the pin control groups used for this controller.
+
+Example (for ARM-based BeagleBone with TRF7970A on SPI1):
+
+&spi1 {
+        status = "okay";
+
+        nfc@0 {
+                compatible = "ti,trf7970a";
+                reg = <0>;
+                pinctrl-names = "default";
+                pinctrl-0 = <&trf7970a_default>;
+                spi-max-frequency = <2000000>;
+                interrupt-parent = <&gpio2>;
+                interrupts = <14 0>;
+                ti,enable-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>,
+                                <&gpio2 5 GPIO_ACTIVE_LOW>;
+                ti,ss-gpio = <&gpio1 30 GPIO_ACTIVE_LOW>;
+                status = "okay";
+        };
+};
-- 
1.8.3.4

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH 2/3] NFC: trf7970a: Add ISO/IEC 15693 Support
From: Mark A. Greer @ 2014-01-31 22:17 UTC (permalink / raw)
  To: Samuel Ortiz, Lauro Ramos Venancio, Aloisio Almeida Jr
  Cc: Felipe Balbi, Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-hn68Rpc1hR1g9hUCZPvPmw,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Mark A. Greer
In-Reply-To: <1391206631-9862-1-git-send-email-mgreer-luAo+O/VEmrlveNOaEYElw@public.gmane.org>

Add support for ISO/IEC 15693 RF technology and Type V tags.

CC: Erick Macias <emacias-l0cyMroinI0@public.gmane.org>
CC: Felipe Balbi <balbi-l0cyMroinI0@public.gmane.org>
Signed-off-by: Mark A. Greer <mgreer-luAo+O/VEmrlveNOaEYElw@public.gmane.org>
---
 drivers/nfc/trf7970a.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 151 insertions(+), 4 deletions(-)

diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c
index 7b9cfec..5da1e78 100644
--- a/drivers/nfc/trf7970a.c
+++ b/drivers/nfc/trf7970a.c
@@ -74,9 +74,25 @@
  * Unfortunately, that means that the driver has to peek into tx frames
  * when the framing is 'NFC_DIGITAL_FRAMING_NFCA_T2T'.  This is done by
  * the trf7970a_per_cmd_config() routine.
+ *
+ * ISO/IEC 15693 frames specify whether to use single or double sub-carrier
+ * frequencies and whether to use low or high data rates in the flags byte
+ * of the frame.  This means that the driver has to peek at all 15693 frames
+ * to determine what speed to set the communication to.  In addition, Type V
+ * write and lock commands use the OPTION flag to indicate that an EOF must
+ * be sent to the tag before it will send its response.  So the driver has
+ * to examine all Type V frames for that reason too.
+ *
+ * It is unclear how long to wait before sending the EOF.  According to the
+ * Note under Table 1-1 in section 1.6 of
+ * http://www.ti.com/lit/ug/scbu011/scbu011.pdf, that wait should be at least
+ * 10 ms for TI Tag-it HF-I tags; however testing has shown that is not long
+ * enough.  For this reason, the driver waits 20 ms which seems to work
+ * reliably.
  */
 
-#define TRF7970A_SUPPORTED_PROTOCOLS		NFC_PROTO_MIFARE_MASK
+#define TRF7970A_SUPPORTED_PROTOCOLS \
+		(NFC_PROTO_MIFARE_MASK | NFC_PROTO_ISO15693_MASK)
 
 /* TX data must be prefixed with a FIFO reset cmd, a cmd that depends
  * on what the current framing is, the address of the TX length byte 1
@@ -94,6 +110,7 @@
 
 #define TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT	3
 #define TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT	3
+#define TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF	20
 
 /* Quirks */
 /* Erratum: When reading IRQ Status register on trf7970a, we must issue a
@@ -253,6 +270,36 @@
 /* NFC (ISO/IEC 14443A) Type 2 Tag commands */
 #define NFC_T2T_CMD_READ			0x30
 
+/* ISO 15693 commands codes */
+#define ISO15693_CMD_INVENTORY			0x01
+#define ISO15693_CMD_READ_SINGLE_BLOCK		0x20
+#define ISO15693_CMD_WRITE_SINGLE_BLOCK		0x21
+#define ISO15693_CMD_LOCK_BLOCK			0x22
+#define ISO15693_CMD_READ_MULTIPLE_BLOCK	0x23
+#define ISO15693_CMD_WRITE_MULTIPLE_BLOCK	0x24
+#define ISO15693_CMD_SELECT			0x25
+#define ISO15693_CMD_RESET_TO_READY		0x26
+#define ISO15693_CMD_WRITE_AFI			0x27
+#define ISO15693_CMD_LOCK_AFI			0x28
+#define ISO15693_CMD_WRITE_DSFID		0x29
+#define ISO15693_CMD_LOCK_DSFID			0x2a
+#define ISO15693_CMD_GET_SYSTEM_INFO		0x2b
+#define ISO15693_CMD_GET_MULTIPLE_BLOCK_SECURITY_STATUS	0x2c
+
+/* ISO 15693 request and response flags */
+#define ISO15693_REQ_FLAG_SUB_CARRIER		BIT(0)
+#define ISO15693_REQ_FLAG_DATA_RATE		BIT(1)
+#define ISO15693_REQ_FLAG_INVENTORY		BIT(2)
+#define ISO15693_REQ_FLAG_PROTOCOL_EXT		BIT(3)
+#define ISO15693_REQ_FLAG_SELECT		BIT(4)
+#define ISO15693_REQ_FLAG_AFI			BIT(4)
+#define ISO15693_REQ_FLAG_ADDRESS		BIT(5)
+#define ISO15693_REQ_FLAG_NB_SLOTS		BIT(5)
+#define ISO15693_REQ_FLAG_OPTION		BIT(6)
+
+#define ISO15693_REQ_FLAG_SPEED_MASK \
+		(ISO15693_REQ_FLAG_SUB_CARRIER | ISO15693_REQ_FLAG_DATA_RATE)
+
 enum trf7970a_state {
 	TRF7970A_ST_OFF,
 	TRF7970A_ST_IDLE,
@@ -260,6 +307,7 @@ enum trf7970a_state {
 	TRF7970A_ST_WAIT_FOR_TX_FIFO,
 	TRF7970A_ST_WAIT_FOR_RX_DATA,
 	TRF7970A_ST_WAIT_FOR_RX_DATA_CONT,
+	TRF7970A_ST_WAIT_TO_ISSUE_EOF,
 	TRF7970A_ST_MAX
 };
 
@@ -279,6 +327,7 @@ struct trf7970a {
 	int				technology;
 	int				framing;
 	u8				tx_cmd;
+	bool				issue_eof;
 	int				ss_gpio;
 	int				en2_gpio;
 	int				en_gpio;
@@ -532,8 +581,13 @@ static int trf7970a_transmit(struct trf7970a *trf, struct sk_buff *skb,
 		trf->state = TRF7970A_ST_WAIT_FOR_TX_FIFO;
 		timeout = TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT;
 	} else {
-		trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA;
-		timeout = trf->timeout;
+		if (trf->issue_eof) {
+			trf->state = TRF7970A_ST_WAIT_TO_ISSUE_EOF;
+			timeout = TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF;
+		} else {
+			trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA;
+			timeout = trf->timeout;
+		}
 	}
 
 	dev_dbg(trf->dev, "Setting timeout for %d ms, state: %d\n", timeout,
@@ -709,6 +763,10 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id)
 			trf7970a_abort_and_send_err(trf, -EIO);
 		}
 		break;
+	case TRF7970A_ST_WAIT_TO_ISSUE_EOF:
+		if (status != TRF7970A_IRQ_STATUS_TX)
+			trf7970a_abort_and_send_err(trf, -EIO);
+		break;
 	default:
 		dev_err(trf->dev, "%s - Driver in invalid state: %d\n",
 				__func__, trf->state);
@@ -718,6 +776,29 @@ static irqreturn_t trf7970a_irq(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static void trf7970a_issue_eof(struct trf7970a *trf)
+{
+	int ret;
+
+	dev_dbg(trf->dev, "Issuing EOF\n");
+
+	ret = trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
+	if (ret)
+		trf7970a_abort_and_send_err(trf, ret);
+
+	ret = trf7970a_cmd(trf, TRF7970A_CMD_EOF);
+	if (ret)
+		trf7970a_abort_and_send_err(trf, ret);
+
+	trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA;
+
+	dev_dbg(trf->dev, "Setting timeout for %d ms, state: %d\n",
+			trf->timeout, trf->state);
+
+	schedule_delayed_work(&trf->timeout_work,
+			msecs_to_jiffies(trf->timeout));
+}
+
 static void trf7970a_timeout_work_handler(struct work_struct *work)
 {
 	struct trf7970a *trf = container_of(work, struct trf7970a,
@@ -732,6 +813,8 @@ static void trf7970a_timeout_work_handler(struct work_struct *work)
 		trf->ignore_timeout = false;
 	else if (trf->state == TRF7970A_ST_WAIT_FOR_RX_DATA_CONT)
 		trf7970a_send_upstream(trf); /* No more rx data so send up */
+	else if (trf->state == TRF7970A_ST_WAIT_TO_ISSUE_EOF)
+		trf7970a_issue_eof(trf);
 	else
 		trf7970a_abort_and_send_err(trf, -ETIMEDOUT);
 
@@ -750,6 +833,9 @@ static int trf7970a_config_rf_tech(struct trf7970a *trf, int tech)
 	case NFC_DIGITAL_RF_TECH_106A:
 		trf->iso_ctrl = TRF7970A_ISO_CTRL_14443A_106;
 		break;
+	case NFC_DIGITAL_RF_TECH_ISO15693:
+		trf->iso_ctrl = TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648;
+		break;
 	default:
 		dev_dbg(trf->dev, "Unsupported rf technology: %d\n", tech);
 		return -EINVAL;
@@ -771,6 +857,8 @@ static int trf7970a_config_framing(struct trf7970a *trf, int framing)
 		trf->iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N;
 		break;
 	case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A:
+	case NFC_DIGITAL_FRAMING_ISO15693_INVENTORY:
+	case NFC_DIGITAL_FRAMING_ISO15693_TVT:
 		trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
 		trf->iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N;
 		break;
@@ -821,15 +909,43 @@ err_out:
 	return ret;
 }
 
+static int trf7970a_is_iso15693_write_or_lock(u8 cmd)
+{
+	int ret;
+
+	switch (cmd) {
+	case ISO15693_CMD_WRITE_SINGLE_BLOCK:
+	case ISO15693_CMD_LOCK_BLOCK:
+	case ISO15693_CMD_WRITE_MULTIPLE_BLOCK:
+	case ISO15693_CMD_WRITE_AFI:
+	case ISO15693_CMD_LOCK_AFI:
+	case ISO15693_CMD_WRITE_DSFID:
+	case ISO15693_CMD_LOCK_DSFID:
+		ret = 1;
+		break;
+	default:
+		ret = 0;
+	}
+
+	return ret;
+}
+
 static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb)
 {
 	u8 *req = skb->data;
-	u8 special_fcn_reg1;
+	u8 special_fcn_reg1, iso_ctrl;
 	int ret;
 
+	trf->issue_eof = false;
+
 	/* When issuing Type 2 read command, make sure the '4_bit_RX' bit in
 	 * special functions register 1 is cleared; otherwise, its a write or
 	 * sector select command and '4_bit_RX' must be set.
+	 *
+	 * When issuing an ISO 15693 command, inspect the flags byte to see
+	 * what speed to use.  Also, remember when the OPTION flag is set on
+	 * a Type V write or lock command so the driver will know that it
+	 * has to send an EOF in order to get a response.
 	 */
 	if ((trf->technology == NFC_DIGITAL_RF_TECH_106A) &&
 			(trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T)) {
@@ -846,6 +962,37 @@ static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb)
 
 			trf->special_fcn_reg1 = special_fcn_reg1;
 		}
+	} else if (trf->technology == NFC_DIGITAL_RF_TECH_ISO15693) {
+		iso_ctrl = trf->iso_ctrl & ~TRF7970A_ISO_CTRL_RFID_SPEED_MASK;
+
+		switch (req[0] & ISO15693_REQ_FLAG_SPEED_MASK) {
+		case 0x00:
+			iso_ctrl |= TRF7970A_ISO_CTRL_15693_SGL_1OF4_662;
+			break;
+		case ISO15693_REQ_FLAG_SUB_CARRIER:
+			iso_ctrl |= TRF7970A_ISO_CTRL_15693_DBL_1OF4_667a;
+			break;
+		case ISO15693_REQ_FLAG_DATA_RATE:
+			iso_ctrl |= TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648;
+			break;
+		case (ISO15693_REQ_FLAG_SUB_CARRIER |
+				ISO15693_REQ_FLAG_DATA_RATE):
+			iso_ctrl |= TRF7970A_ISO_CTRL_15693_DBL_1OF4_2669;
+			break;
+		}
+
+		if (iso_ctrl != trf->iso_ctrl) {
+			ret = trf7970a_write(trf, TRF7970A_ISO_CTRL, iso_ctrl);
+			if (ret)
+				return ret;
+
+			trf->iso_ctrl = iso_ctrl;
+		}
+
+		if ((trf->framing == NFC_DIGITAL_FRAMING_ISO15693_TVT) &&
+				trf7970a_is_iso15693_write_or_lock(req[1]) &&
+				(req[0] & ISO15693_REQ_FLAG_OPTION))
+			trf->issue_eof = true;
 	}
 
 	return 0;
-- 
1.8.3.4

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH 1/3] NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
From: Mark A. Greer @ 2014-01-31 22:17 UTC (permalink / raw)
  To: Samuel Ortiz, Lauro Ramos Venancio, Aloisio Almeida Jr
  Cc: Felipe Balbi, Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-hn68Rpc1hR1g9hUCZPvPmw,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Mark A. Greer
In-Reply-To: <1391206631-9862-1-git-send-email-mgreer-luAo+O/VEmrlveNOaEYElw@public.gmane.org>

Add a driver for the Texas Instruments TRF7970a RFID/NFC/15693
transceiver.  The driver currently supports ISO/IEC 14443 Type 2
tags only (MIFARE Ultralight and Ultralight C but not Classic).

CC: Erick Macias <emacias-l0cyMroinI0@public.gmane.org>
CC: Felipe Balbi <balbi-l0cyMroinI0@public.gmane.org>
Signed-off-by: Mark A. Greer <mgreer-luAo+O/VEmrlveNOaEYElw@public.gmane.org>
---
 drivers/nfc/Kconfig    |   12 +
 drivers/nfc/Makefile   |    1 +
 drivers/nfc/trf7970a.c | 1191 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1204 insertions(+)
 create mode 100644 drivers/nfc/trf7970a.c

diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index fe20e1c..65d4ca1 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -26,6 +26,18 @@ config NFC_WILINK
 	  Say Y here to compile support for Texas Instrument's NFC WiLink driver
 	  into the kernel or say M to compile it as module.
 
+config NFC_TRF7970A
+	tristate "Texas Instruments TRF7970a NFC driver"
+	depends on SPI && NFC_DIGITAL
+	help
+	  This option enables the NFC driver for Texas Instruments' TRF7970a
+	  device. Such device supports 5 different protocols: ISO14443A,
+	  ISO14443B, FeLiCa, ISO15693 and ISO18000-3.
+
+	  Say Y here to compile support for TRF7970a into the kernel or
+	  say M  to compile it as a module. The module will be called
+	  trf7970a.ko.
+
 config NFC_MEI_PHY
 	tristate "MEI bus NFC device support"
 	depends on INTEL_MEI && NFC_HCI
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index 56ab822..ae42a3f 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -10,5 +10,6 @@ obj-$(CONFIG_NFC_MEI_PHY)	+= mei_phy.o
 obj-$(CONFIG_NFC_SIM)		+= nfcsim.o
 obj-$(CONFIG_NFC_PORT100)	+= port100.o
 obj-$(CONFIG_NFC_MRVL)		+= nfcmrvl/
+obj-$(CONFIG_NFC_TRF7970A)	+= trf7970a.o
 
 ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c
new file mode 100644
index 0000000..7b9cfec
--- /dev/null
+++ b/drivers/nfc/trf7970a.c
@@ -0,0 +1,1191 @@
+/*
+ * TI TRF7970a RFID/NFC Transceiver Driver
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Erick Macias <emacias-l0cyMroinI0@public.gmane.org>
+ * Author: Felipe Balbi <balbi-l0cyMroinI0@public.gmane.org>
+ * Author: Mark A. Greer <mgreer-luAo+O/VEmrlveNOaEYElw@public.gmane.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/nfc.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/spi/spi.h>
+
+#include <net/nfc/nfc.h>
+#include <net/nfc/digital.h>
+
+/* There are 3 ways the host can communicate with the trf7970a:
+ * parallel mode, SPI with Slave Select (SS) mode, and SPI without
+ * SS mode.  The driver only supports the two SPI modes.
+ * When the "ti,ss-gpio" device tree property is present, SPI with
+ * SS mode is used; otherwise, SPI without SS mode is used.
+ *
+ * The trf7970a is very timing sensitive and the SS (I/O_4), EN2,
+ * and EN pins must enabled in that order and with specific delays
+ * in between.  The delays used in the driver were provided by TI
+ * and have been confirmed to work with this driver.
+ *
+ * Timeouts are implemented using the delayed workqueue kernel facility.
+ * Timeouts are required so things don't hang when there is no response
+ * from the trf7970a (or tag).  Using this mechanism creates a race with
+ * interrupts, however.  That is, an interrupt and a timeout could occur
+ * closely enough together that one is blocked by the mutex while the other
+ * executes.  When the timeout handler executes first and blocks the
+ * interrupt handler, it will eventually set the state to IDLE so the
+ * interrupt handler will check the state and exit with no harm done.
+ * When the interrupt handler executes first and blocks the timeout handler,
+ * the cancel_delayed_work() call will know that it didn't cancel the
+ * work item (i.e., timeout) and will return zero.  That return code is
+ * used by the timer handler to indicate that it should ignore the timeout
+ * once its unblocked.
+ *
+ * When recieving data from a tag and the interrupt status register has
+ * only the SRX bit set, it means that all of the data has been received
+ * (once what's in the fifo has been read).  However, depending on timing
+ * an interrupt status with only the SRX bit set may not be recived.  In
+ * those cases, the timeout mechanism is used to wait 3 ms in case more
+ * data arrives.  After 3 ms, it is assumed that all of the data has been
+ * received and the accumulated rx data is sent upstream.  The
+ * 'TRF7970A_ST_WAIT_FOR_RX_DATA_CONT' state is used for this purpose
+ * (i.e., it indicates that some data has been received but we're not sure
+ * if there is more coming so a timeout in this state means all data has
+ * been received and there isn't an error).  The delay is 3 ms since delays
+ * over 2 ms have been observed during testing.
+ *
+ * Type 2 write and sector select commands respond with a 4-bit ACK or NACK.
+ * Having only 4 bits in the FIFO won't normally generate an interrupt so
+ * driver enables the '4_bit_RX' bit of the Special Functions register 1
+ * to cause an interrupt in that case.  Leaving that bit for a read command
+ * messes up the data returned so it is only enabled when the framing is
+ * 'NFC_DIGITAL_FRAMING_NFCA_T2T' and the command is not a read command.
+ * Unfortunately, that means that the driver has to peek into tx frames
+ * when the framing is 'NFC_DIGITAL_FRAMING_NFCA_T2T'.  This is done by
+ * the trf7970a_per_cmd_config() routine.
+ */
+
+#define TRF7970A_SUPPORTED_PROTOCOLS		NFC_PROTO_MIFARE_MASK
+
+/* TX data must be prefixed with a FIFO reset cmd, a cmd that depends
+ * on what the current framing is, the address of the TX length byte 1
+ * register (0x1d), and the 2 byte length of the data to be transmitted.
+ * That totals 5 bytes.
+ */
+#define TRF7970A_TX_SKB_HEADROOM		5
+
+#define TRF7970A_RX_SKB_ALLOC_SIZE		256
+
+#define TRF7970A_FIFO_SIZE			128
+
+/* TX length is 3 nibbles long ==> 4KB - 1 bytes max */
+#define TRF7970A_TX_MAX				(4096 - 1)
+
+#define TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT	3
+#define TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT	3
+
+/* Quirks */
+/* Erratum: When reading IRQ Status register on trf7970a, we must issue a
+ * read continuous command for IRQ Status and Collision Position registers.
+ */
+#define TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA	BIT(0)
+
+/* Direct commands */
+#define TRF7970A_CMD_IDLE			0x00
+#define TRF7970A_CMD_SOFT_INIT			0x03
+#define TRF7970A_CMD_RF_COLLISION		0x04
+#define TRF7970A_CMD_RF_COLLISION_RESPONSE_N	0x05
+#define TRF7970A_CMD_RF_COLLISION_RESPONSE_0	0x06
+#define TRF7970A_CMD_FIFO_RESET			0x0f
+#define TRF7970A_CMD_TRANSMIT_NO_CRC		0x10
+#define TRF7970A_CMD_TRANSMIT			0x11
+#define TRF7970A_CMD_DELAY_TRANSMIT_NO_CRC	0x12
+#define TRF7970A_CMD_DELAY_TRANSMIT		0x13
+#define TRF7970A_CMD_EOF			0x14
+#define TRF7970A_CMD_CLOSE_SLOT			0x15
+#define TRF7970A_CMD_BLOCK_RX			0x16
+#define TRF7970A_CMD_ENABLE_RX			0x17
+#define TRF7970A_CMD_TEST_EXT_RF		0x18
+#define TRF7970A_CMD_TEST_INT_RF		0x19
+#define TRF7970A_CMD_RX_GAIN_ADJUST		0x1a
+
+/* Bits determining whether its a direct command or register R/W,
+ * whether to use a continuous SPI transaction or not, and the actual
+ * direct cmd opcode or regster address.
+ */
+#define TRF7970A_CMD_BIT_CTRL			BIT(7)
+#define TRF7970A_CMD_BIT_RW			BIT(6)
+#define TRF7970A_CMD_BIT_CONTINUOUS		BIT(5)
+#define TRF7970A_CMD_BIT_OPCODE(opcode)		((opcode) & 0x1f)
+
+/* Registers addresses */
+#define TRF7970A_CHIP_STATUS_CTRL		0x00
+#define TRF7970A_ISO_CTRL			0x01
+#define TRF7970A_ISO14443B_TX_OPTIONS		0x02
+#define TRF7970A_ISO14443A_HIGH_BITRATE_OPTIONS	0x03
+#define TRF7970A_TX_TIMER_SETTING_H_BYTE	0x04
+#define TRF7970A_TX_TIMER_SETTING_L_BYTE	0x05
+#define TRF7970A_TX_PULSE_LENGTH_CTRL		0x06
+#define TRF7970A_RX_NO_RESPONSE_WAIT		0x07
+#define TRF7970A_RX_WAIT_TIME			0x08
+#define TRF7970A_MODULATOR_SYS_CLK_CTRL		0x09
+#define TRF7970A_RX_SPECIAL_SETTINGS		0x0a
+#define TRF7970A_REG_IO_CTRL			0x0b
+#define TRF7970A_IRQ_STATUS			0x0c
+#define TRF7970A_COLLISION_IRQ_MASK		0x0d
+#define TRF7970A_COLLISION_POSITION		0x0e
+#define TRF7970A_RSSI_OSC_STATUS		0x0f
+#define TRF7970A_SPECIAL_FCN_REG1		0x10
+#define TRF7970A_SPECIAL_FCN_REG2		0x11
+#define TRF7970A_RAM1				0x12
+#define TRF7970A_RAM2				0x13
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS	0x14
+#define TRF7970A_NFC_LOW_FIELD_LEVEL		0x16
+#define TRF7970A_NFCID1				0x17
+#define TRF7970A_NFC_TARGET_LEVEL		0x18
+#define TRF79070A_NFC_TARGET_PROTOCOL		0x19
+#define TRF7970A_TEST_REGISTER1			0x1a
+#define TRF7970A_TEST_REGISTER2			0x1b
+#define TRF7970A_FIFO_STATUS			0x1c
+#define TRF7970A_TX_LENGTH_BYTE1		0x1d
+#define TRF7970A_TX_LENGTH_BYTE2		0x1e
+#define TRF7970A_FIFO_IO_REGISTER		0x1f
+
+/* Chip Status Control Register Bits */
+#define TRF7970A_CHIP_STATUS_VRS5_3		BIT(0)
+#define TRF7970A_CHIP_STATUS_REC_ON		BIT(1)
+#define TRF7970A_CHIP_STATUS_AGC_ON		BIT(2)
+#define TRF7970A_CHIP_STATUS_PM_ON		BIT(3)
+#define TRF7970A_CHIP_STATUS_RF_PWR		BIT(4)
+#define TRF7970A_CHIP_STATUS_RF_ON		BIT(5)
+#define TRF7970A_CHIP_STATUS_DIRECT		BIT(6)
+#define TRF7970A_CHIP_STATUS_STBY		BIT(7)
+
+/* ISO Control Register Bits */
+#define TRF7970A_ISO_CTRL_15693_SGL_1OF4_662	0x00
+#define TRF7970A_ISO_CTRL_15693_SGL_1OF256_662	0x01
+#define TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648	0x02
+#define TRF7970A_ISO_CTRL_15693_SGL_1OF256_2648	0x03
+#define TRF7970A_ISO_CTRL_15693_DBL_1OF4_667a	0x04
+#define TRF7970A_ISO_CTRL_15693_DBL_1OF256_667	0x05
+#define TRF7970A_ISO_CTRL_15693_DBL_1OF4_2669	0x06
+#define TRF7970A_ISO_CTRL_15693_DBL_1OF256_2669	0x07
+#define TRF7970A_ISO_CTRL_14443A_106		0x08
+#define TRF7970A_ISO_CTRL_14443A_212		0x09
+#define TRF7970A_ISO_CTRL_14443A_424		0x0a
+#define TRF7970A_ISO_CTRL_14443A_848		0x0b
+#define TRF7970A_ISO_CTRL_14443B_106		0x0c
+#define TRF7970A_ISO_CTRL_14443B_212		0x0d
+#define TRF7970A_ISO_CTRL_14443B_424		0x0e
+#define TRF7970A_ISO_CTRL_14443B_848		0x0f
+#define TRF7970A_ISO_CTRL_FELICA_212		0x1a
+#define TRF7970A_ISO_CTRL_FELICA_424		0x1b
+#define TRF7970A_ISO_CTRL_RFID			BIT(5)
+#define TRF7970A_ISO_CTRL_DIR_MODE		BIT(6)
+#define TRF7970A_ISO_CTRL_RX_CRC_N		BIT(7)	/* true == No CRC */
+
+#define TRF7970A_ISO_CTRL_RFID_SPEED_MASK	0x1f
+
+/* Modulator and SYS_CLK Control Register Bits */
+#define TRF7970A_MODULATOR_DEPTH(n)		((n) & 0x7)
+#define TRF7970A_MODULATOR_DEPTH_ASK10		(TRF7970A_MODULATOR_DEPTH(0))
+#define TRF7970A_MODULATOR_DEPTH_OOK		(TRF7970A_MODULATOR_DEPTH(1))
+#define TRF7970A_MODULATOR_DEPTH_ASK7		(TRF7970A_MODULATOR_DEPTH(2))
+#define TRF7970A_MODULATOR_DEPTH_ASK8_5		(TRF7970A_MODULATOR_DEPTH(3))
+#define TRF7970A_MODULATOR_DEPTH_ASK13		(TRF7970A_MODULATOR_DEPTH(4))
+#define TRF7970A_MODULATOR_DEPTH_ASK16		(TRF7970A_MODULATOR_DEPTH(5))
+#define TRF7970A_MODULATOR_DEPTH_ASK22		(TRF7970A_MODULATOR_DEPTH(6))
+#define TRF7970A_MODULATOR_DEPTH_ASK30		(TRF7970A_MODULATOR_DEPTH(7))
+#define TRF7970A_MODULATOR_EN_ANA		BIT(3)
+#define TRF7970A_MODULATOR_CLK(n)		(((n) & 0x3) << 4)
+#define TRF7970A_MODULATOR_CLK_DISABLED		(TRF7970A_MODULATOR_CLK(0))
+#define TRF7970A_MODULATOR_CLK_3_6		(TRF7970A_MODULATOR_CLK(1))
+#define TRF7970A_MODULATOR_CLK_6_13		(TRF7970A_MODULATOR_CLK(2))
+#define TRF7970A_MODULATOR_CLK_13_27		(TRF7970A_MODULATOR_CLK(3))
+#define TRF7970A_MODULATOR_EN_OOK		BIT(6)
+#define TRF7970A_MODULATOR_27MHZ		BIT(7)
+
+/* IRQ Status Register Bits */
+#define TRF7970A_IRQ_STATUS_NORESP		BIT(0) /* ISO15693 only */
+#define TRF7970A_IRQ_STATUS_COL			BIT(1)
+#define TRF7970A_IRQ_STATUS_FRAMING_EOF_ERROR	BIT(2)
+#define TRF7970A_IRQ_STATUS_PARITY_ERROR	BIT(3)
+#define TRF7970A_IRQ_STATUS_CRC_ERROR		BIT(4)
+#define TRF7970A_IRQ_STATUS_FIFO		BIT(5)
+#define TRF7970A_IRQ_STATUS_SRX			BIT(6)
+#define TRF7970A_IRQ_STATUS_TX			BIT(7)
+
+#define TRF7970A_IRQ_STATUS_ERROR				\
+		(TRF7970A_IRQ_STATUS_COL |			\
+		 TRF7970A_IRQ_STATUS_FRAMING_EOF_ERROR |	\
+		 TRF7970A_IRQ_STATUS_PARITY_ERROR |		\
+		 TRF7970A_IRQ_STATUS_CRC_ERROR)
+
+#define TRF7970A_SPECIAL_FCN_REG1_COL_7_6		BIT(0)
+#define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL		BIT(1)
+#define TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX		BIT(2)
+#define TRF7970A_SPECIAL_FCN_REG1_SP_DIR_MODE		BIT(3)
+#define TRF7970A_SPECIAL_FCN_REG1_NEXT_SLOT_37US	BIT(4)
+#define TRF7970A_SPECIAL_FCN_REG1_PAR43			BIT(5)
+
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_124	(0x0 << 2)
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_120	(0x1 << 2)
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_112	(0x2 << 2)
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_96	(0x3 << 2)
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_4	0x0
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_8	0x1
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_16	0x2
+#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_32	0x3
+
+#define TRF7970A_FIFO_STATUS_OVERFLOW		BIT(7)
+
+/* NFC (ISO/IEC 14443A) Type 2 Tag commands */
+#define NFC_T2T_CMD_READ			0x30
+
+enum trf7970a_state {
+	TRF7970A_ST_OFF,
+	TRF7970A_ST_IDLE,
+	TRF7970A_ST_IDLE_RX_BLOCKED,
+	TRF7970A_ST_WAIT_FOR_TX_FIFO,
+	TRF7970A_ST_WAIT_FOR_RX_DATA,
+	TRF7970A_ST_WAIT_FOR_RX_DATA_CONT,
+	TRF7970A_ST_MAX
+};
+
+struct trf7970a {
+	enum trf7970a_state		state;
+	struct device			*dev;
+	struct spi_device		*spi;
+	struct nfc_digital_dev		*ddev;
+	u32				quirks;
+	bool				initialized;
+	struct sk_buff			*tx_skb;
+	struct sk_buff			*rx_skb;
+	nfc_digital_cmd_complete_t	cb;
+	void				*cb_arg;
+	u8				iso_ctrl;
+	u8				special_fcn_reg1;
+	int				technology;
+	int				framing;
+	u8				tx_cmd;
+	int				ss_gpio;
+	int				en2_gpio;
+	int				en_gpio;
+	struct mutex			lock;
+	unsigned int			timeout;
+	bool				ignore_timeout;
+	struct delayed_work		timeout_work;
+};
+
+
+static int trf7970a_cmd(struct trf7970a *trf, u8 opcode)
+{
+	u8 cmd = TRF7970A_CMD_BIT_CTRL | TRF7970A_CMD_BIT_OPCODE(opcode);
+	int ret;
+
+	dev_dbg(trf->dev, "cmd: 0x%x\n", cmd);
+
+	ret = spi_write(trf->spi, &cmd, 1);
+	if (ret)
+		dev_err(trf->dev, "%s - cmd: 0x%x, ret: %d\n", __func__, cmd,
+				ret);
+	return ret;
+}
+
+static int trf7970a_read(struct trf7970a *trf, u8 reg, u8 *val)
+{
+	u8 addr = TRF7970A_CMD_BIT_RW | reg;
+	int ret;
+
+	ret = spi_write_then_read(trf->spi, &addr, 1, val, 1);
+	if (ret)
+		dev_err(trf->dev, "%s - addr: 0x%x, ret: %d\n", __func__, addr,
+				ret);
+
+	dev_dbg(trf->dev, "read(0x%x): 0x%x\n", addr, *val);
+
+	return ret;
+}
+
+static int trf7970a_read_cont(struct trf7970a *trf, u8 reg,
+		u8 *buf, size_t len)
+{
+	u8 addr = reg | TRF7970A_CMD_BIT_RW | TRF7970A_CMD_BIT_CONTINUOUS;
+	int ret;
+
+	dev_dbg(trf->dev, "read_cont(0x%x, %d)\n", addr, len);
+
+	ret = spi_write_then_read(trf->spi, &addr, 1, buf, len);
+	if (ret)
+		dev_err(trf->dev, "%s - addr: 0x%x, ret: %d\n", __func__, addr,
+				ret);
+	return ret;
+}
+
+static int trf7970a_write(struct trf7970a *trf, u8 reg, u8 val)
+{
+	u8 buf[2] = { reg, val };
+	int ret;
+
+	dev_dbg(trf->dev, "write(0x%x): 0x%x\n", reg, val);
+
+	ret = spi_write(trf->spi, buf, 2);
+	if (ret)
+		dev_err(trf->dev, "%s - write: 0x%x 0x%x, ret: %d\n", __func__,
+				buf[0], buf[1], ret);
+
+	return ret;
+}
+
+static int trf7970a_read_irqstatus(struct trf7970a *trf, u8 *status)
+{
+	int ret;
+	u8 buf[2];
+	u8 addr;
+
+	addr = TRF7970A_IRQ_STATUS | TRF7970A_CMD_BIT_RW;
+
+	if (trf->quirks & TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA) {
+		addr |= TRF7970A_CMD_BIT_CONTINUOUS;
+		ret = spi_write_then_read(trf->spi, &addr, 1, buf, 2);
+	} else {
+		ret = spi_write_then_read(trf->spi, &addr, 1, buf, 1);
+	}
+
+	if (ret)
+		dev_err(trf->dev, "%s - irqstatus: Status read failed: %d\n",
+				__func__, ret);
+	else
+		*status = buf[0];
+
+	return ret;
+}
+
+static void trf7970a_switch_rf_off(struct trf7970a *trf)
+{
+	dev_dbg(trf->dev, "Switching rf off\n");
+
+	gpio_set_value(trf->en_gpio, 0);
+	gpio_set_value(trf->en2_gpio, 0);
+
+	trf->state = TRF7970A_ST_OFF;
+}
+
+static int trf7970a_init(struct trf7970a *trf)
+{
+	int ret;
+
+	dev_dbg(trf->dev, "Initializing device - state: %d\n", trf->state);
+
+	ret = trf7970a_cmd(trf, TRF7970A_CMD_SOFT_INIT);
+	if (ret)
+		goto err_out;
+
+	ret = trf7970a_cmd(trf, TRF7970A_CMD_IDLE);
+	if (ret)
+		goto err_out;
+
+	ret = trf7970a_write(trf, TRF7970A_MODULATOR_SYS_CLK_CTRL,
+			TRF7970A_MODULATOR_DEPTH_OOK);
+	if (ret)
+		goto err_out;
+
+	ret = trf7970a_write(trf, TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS,
+			TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_96 |
+			TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_32);
+	if (ret)
+		goto err_out;
+
+	ret = trf7970a_write(trf, TRF7970A_SPECIAL_FCN_REG1, 0);
+	if (ret)
+		goto err_out;
+
+	trf->special_fcn_reg1 = 0;
+
+	ret = trf7970a_write(trf, TRF7970A_CHIP_STATUS_CTRL,
+			TRF7970A_CHIP_STATUS_RF_ON |
+				TRF7970A_CHIP_STATUS_VRS5_3);
+	if (ret)
+		goto err_out;
+
+	trf->state = TRF7970A_ST_IDLE;
+
+	return 0;
+
+err_out:
+	dev_dbg(trf->dev, "Couldn't init device: %d\n", ret);
+
+	trf7970a_switch_rf_off(trf);
+	return ret;
+}
+
+static int trf7970a_switch_rf_on(struct trf7970a *trf)
+{
+	unsigned long delay;
+
+	dev_dbg(trf->dev, "Switching rf on\n");
+
+	gpio_set_value(trf->en2_gpio, 1);
+	usleep_range(1000, 2000);
+	gpio_set_value(trf->en_gpio, 1);
+
+	/* The delay between enabling the trf7970a and issuing the first
+	 * command is significantly longer the very first time after powering
+	 * up.  Make sure the longer delay is only done the first time.
+	 */
+	if (!trf->initialized) {
+		delay = 20000;
+		trf->initialized = true;
+	} else {
+		delay = 5000;
+	}
+
+	usleep_range(delay, delay + 1000);
+
+	return trf7970a_init(trf);
+}
+
+static void _trf7970a_abort_cmd(struct trf7970a *trf)
+{
+	dev_dbg(trf->dev, "Aborting cmd - state: %d\n", trf->state);
+
+	if ((trf->state != TRF7970A_ST_IDLE) &&
+			(trf->state != TRF7970A_ST_IDLE_RX_BLOCKED))
+		trf->ignore_timeout = !cancel_delayed_work(&trf->timeout_work);
+
+	trf7970a_init(trf);
+
+	dev_kfree_skb_any(trf->tx_skb);
+	trf->tx_skb = NULL;
+
+	kfree_skb(trf->rx_skb);
+	trf->rx_skb = NULL;
+
+	trf->state = TRF7970A_ST_IDLE; /* In case trf7970a_init() fails */
+}
+
+static void trf7970a_send_upstream(struct trf7970a *trf)
+{
+	u8 rssi;
+
+	dev_kfree_skb_any(trf->tx_skb);
+	trf->tx_skb = NULL;
+
+	if (trf->rx_skb && !IS_ERR(trf->rx_skb))
+		print_hex_dump_debug("trf7970a rx data: ", DUMP_PREFIX_NONE,
+				16, 1, trf->rx_skb->data, trf->rx_skb->len,
+				false);
+
+	/* According to the manual it is "good form" to reset the fifo and
+	 * read the RSSI levels & oscillator status register here.  It doesn't
+	 * explain why.
+	 */
+	trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
+	trf7970a_read(trf, TRF7970A_RSSI_OSC_STATUS, &rssi);
+
+	trf->cb(trf->ddev, trf->cb_arg, trf->rx_skb);
+	trf->rx_skb = NULL;
+
+	trf->state = TRF7970A_ST_IDLE;
+}
+
+static void trf7970a_abort_and_send_err(struct trf7970a *trf, int errno)
+{
+	dev_dbg(trf->dev, "Error - state: %d, errno: %d\n", trf->state, errno);
+
+	_trf7970a_abort_cmd(trf);
+
+	trf->rx_skb = ERR_PTR(errno);
+	trf7970a_send_upstream(trf);
+}
+
+static int trf7970a_transmit(struct trf7970a *trf, struct sk_buff *skb,
+		unsigned int len)
+{
+	unsigned int timeout;
+	int ret;
+
+	print_hex_dump_debug("trf7970a tx data: ", DUMP_PREFIX_NONE,
+			16, 1, skb->data, len, false);
+
+	ret = spi_write(trf->spi, skb->data, len);
+	if (ret) {
+		dev_err(trf->dev, "%s - Can't send tx data: %d\n", __func__,
+				ret);
+		return ret;
+	}
+
+	skb_pull(skb, len);
+
+	if (skb->len > 0) {
+		trf->state = TRF7970A_ST_WAIT_FOR_TX_FIFO;
+		timeout = TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT;
+	} else {
+		trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA;
+		timeout = trf->timeout;
+	}
+
+	dev_dbg(trf->dev, "Setting timeout for %d ms, state: %d\n", timeout,
+			trf->state);
+
+	schedule_delayed_work(&trf->timeout_work, msecs_to_jiffies(timeout));
+
+	return 0;
+}
+
+static void trf7970a_fill_fifo(struct trf7970a *trf)
+{
+	struct sk_buff *skb = trf->tx_skb;
+	unsigned int len;
+	int ret;
+	u8 fifo_bytes;
+
+	ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes);
+	if (ret) {
+		trf7970a_abort_and_send_err(trf, ret);
+		return;
+	}
+
+	dev_dbg(trf->dev, "fifo_bytes: 0x%x\n", fifo_bytes);
+
+	if (fifo_bytes & TRF7970A_FIFO_STATUS_OVERFLOW) {
+		dev_err(trf->dev, "%s - fifo overflow: 0x%x\n", __func__,
+				fifo_bytes);
+		trf7970a_abort_and_send_err(trf, -EIO);
+		return;
+	}
+
+	/* Calculate how much more data can be written to the fifo */
+	len = TRF7970A_FIFO_SIZE - fifo_bytes;
+	len = min(skb->len, len);
+
+	ret = trf7970a_transmit(trf, skb, len);
+	if (ret)
+		trf7970a_abort_and_send_err(trf, ret);
+}
+
+static void trf7970a_drain_fifo(struct trf7970a *trf, u8 status)
+{
+	struct sk_buff *skb = trf->rx_skb;
+	int ret;
+	u8 fifo_bytes;
+
+	if (status & TRF7970A_IRQ_STATUS_ERROR) {
+		trf7970a_abort_and_send_err(trf, -EIO);
+		return;
+	}
+
+	ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes);
+	if (ret) {
+		trf7970a_abort_and_send_err(trf, ret);
+		return;
+	}
+
+	dev_dbg(trf->dev, "fifo_bytes: 0x%x\n", fifo_bytes);
+
+	if (!fifo_bytes)
+		goto no_rx_data;
+
+	if (fifo_bytes & TRF7970A_FIFO_STATUS_OVERFLOW) {
+		dev_err(trf->dev, "%s - fifo overflow: 0x%x\n", __func__,
+				fifo_bytes);
+		trf7970a_abort_and_send_err(trf, -EIO);
+		return;
+	}
+
+	if (fifo_bytes > skb_tailroom(skb)) {
+		skb = skb_copy_expand(skb, skb_headroom(skb),
+				max_t(int, fifo_bytes,
+					TRF7970A_RX_SKB_ALLOC_SIZE),
+				GFP_KERNEL);
+		if (!skb) {
+			trf7970a_abort_and_send_err(trf, -ENOMEM);
+			return;
+		}
+
+		kfree_skb(trf->rx_skb);
+		trf->rx_skb = skb;
+	}
+
+	ret = trf7970a_read_cont(trf, TRF7970A_FIFO_IO_REGISTER,
+			skb_put(skb, fifo_bytes), fifo_bytes);
+	if (ret) {
+		trf7970a_abort_and_send_err(trf, ret);
+		return;
+	}
+
+	/* If received Type 2 ACK/NACK, shift right 4 bits and pass up */
+	if ((trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T) && (skb->len == 1) &&
+			(trf->special_fcn_reg1 ==
+				 TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX)) {
+		skb->data[0] >>= 4;
+		status = TRF7970A_IRQ_STATUS_SRX;
+	} else {
+		trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA_CONT;
+	}
+
+no_rx_data:
+	if (status == TRF7970A_IRQ_STATUS_SRX) { /* Receive complete */
+		trf7970a_send_upstream(trf);
+		return;
+	}
+
+	dev_dbg(trf->dev, "Setting timeout for %d ms\n",
+			TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT);
+
+	schedule_delayed_work(&trf->timeout_work,
+			msecs_to_jiffies(TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT));
+}
+
+static irqreturn_t trf7970a_irq(int irq, void *dev_id)
+{
+	struct trf7970a *trf = dev_id;
+	int ret;
+	u8 status;
+
+	mutex_lock(&trf->lock);
+
+	if (trf->state == TRF7970A_ST_OFF) {
+		mutex_unlock(&trf->lock);
+		return IRQ_NONE;
+	}
+
+	ret = trf7970a_read_irqstatus(trf, &status);
+	if (ret) {
+		mutex_unlock(&trf->lock);
+		return IRQ_NONE;
+	}
+
+	dev_dbg(trf->dev, "IRQ - state: %d, status: 0x%x\n", trf->state,
+			status);
+
+	if (!status) {
+		mutex_unlock(&trf->lock);
+		return IRQ_NONE;
+	}
+
+	switch (trf->state) {
+	case TRF7970A_ST_IDLE:
+	case TRF7970A_ST_IDLE_RX_BLOCKED:
+		/* If getting interrupts caused by RF noise, turn off the
+		 * receiver to avoid unnecessary interrupts.  It will be
+		 * turned back on in trf7970a_in_send_cmd() when the next
+		 * command is issued.
+		 */
+		if (status & TRF7970A_IRQ_STATUS_ERROR) {
+			trf7970a_cmd(trf, TRF7970A_CMD_BLOCK_RX);
+			trf->state = TRF7970A_ST_IDLE_RX_BLOCKED;
+		}
+
+		trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET);
+		break;
+	case TRF7970A_ST_WAIT_FOR_TX_FIFO:
+		if (status & TRF7970A_IRQ_STATUS_TX) {
+			trf->ignore_timeout =
+				!cancel_delayed_work(&trf->timeout_work);
+			trf7970a_fill_fifo(trf);
+		} else {
+			trf7970a_abort_and_send_err(trf, -EIO);
+		}
+		break;
+	case TRF7970A_ST_WAIT_FOR_RX_DATA:
+	case TRF7970A_ST_WAIT_FOR_RX_DATA_CONT:
+		if (status & TRF7970A_IRQ_STATUS_SRX) {
+			trf->ignore_timeout =
+				!cancel_delayed_work(&trf->timeout_work);
+			trf7970a_drain_fifo(trf, status);
+		} else if (!(status & TRF7970A_IRQ_STATUS_TX)) {
+			trf7970a_abort_and_send_err(trf, -EIO);
+		}
+		break;
+	default:
+		dev_err(trf->dev, "%s - Driver in invalid state: %d\n",
+				__func__, trf->state);
+	}
+
+	mutex_unlock(&trf->lock);
+	return IRQ_HANDLED;
+}
+
+static void trf7970a_timeout_work_handler(struct work_struct *work)
+{
+	struct trf7970a *trf = container_of(work, struct trf7970a,
+			timeout_work.work);
+
+	dev_dbg(trf->dev, "TIMEOUT - state: %d, ignore_timeout: %d\n",
+			trf->state, trf->ignore_timeout);
+
+	mutex_lock(&trf->lock);
+
+	if (trf->ignore_timeout)
+		trf->ignore_timeout = false;
+	else if (trf->state == TRF7970A_ST_WAIT_FOR_RX_DATA_CONT)
+		trf7970a_send_upstream(trf); /* No more rx data so send up */
+	else
+		trf7970a_abort_and_send_err(trf, -ETIMEDOUT);
+
+	mutex_unlock(&trf->lock);
+}
+
+/* ----------------------------------------------------------------- */
+
+static int trf7970a_config_rf_tech(struct trf7970a *trf, int tech)
+{
+	int ret = 0;
+
+	dev_dbg(trf->dev, "rf technology: %d\n", tech);
+
+	switch (tech) {
+	case NFC_DIGITAL_RF_TECH_106A:
+		trf->iso_ctrl = TRF7970A_ISO_CTRL_14443A_106;
+		break;
+	default:
+		dev_dbg(trf->dev, "Unsupported rf technology: %d\n", tech);
+		return -EINVAL;
+	}
+
+	trf->technology = tech;
+
+	return ret;
+}
+
+static int trf7970a_config_framing(struct trf7970a *trf, int framing)
+{
+	dev_dbg(trf->dev, "framing: %d\n", framing);
+
+	switch (framing) {
+	case NFC_DIGITAL_FRAMING_NFCA_SHORT:
+	case NFC_DIGITAL_FRAMING_NFCA_STANDARD:
+		trf->tx_cmd = TRF7970A_CMD_TRANSMIT_NO_CRC;
+		trf->iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N;
+		break;
+	case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A:
+		trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
+		trf->iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N;
+		break;
+	case NFC_DIGITAL_FRAMING_NFCA_T2T:
+		trf->tx_cmd = TRF7970A_CMD_TRANSMIT;
+		trf->iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N;
+		break;
+	default:
+		dev_dbg(trf->dev, "Unsupported Framing: %d\n", framing);
+		return -EINVAL;
+	}
+
+	trf->framing = framing;
+
+	return trf7970a_write(trf, TRF7970A_ISO_CTRL, trf->iso_ctrl);
+}
+
+static int trf7970a_in_configure_hw(struct nfc_digital_dev *ddev, int type,
+		int param)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+	int ret = 0;
+
+	dev_dbg(trf->dev, "Configure hw - type: %d, param: %d\n", type, param);
+
+	mutex_lock(&trf->lock);
+
+	if (trf->state == TRF7970A_ST_OFF) {
+		ret = trf7970a_switch_rf_on(trf);
+		if (ret)
+			goto err_out;
+	}
+
+	switch (type) {
+	case NFC_DIGITAL_CONFIG_RF_TECH:
+		ret = trf7970a_config_rf_tech(trf, param);
+		break;
+	case NFC_DIGITAL_CONFIG_FRAMING:
+		ret = trf7970a_config_framing(trf, param);
+		break;
+	default:
+		dev_dbg(trf->dev, "Unknown type: %d\n", type);
+		ret = -EINVAL;
+	}
+
+err_out:
+	mutex_unlock(&trf->lock);
+	return ret;
+}
+
+static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb)
+{
+	u8 *req = skb->data;
+	u8 special_fcn_reg1;
+	int ret;
+
+	/* When issuing Type 2 read command, make sure the '4_bit_RX' bit in
+	 * special functions register 1 is cleared; otherwise, its a write or
+	 * sector select command and '4_bit_RX' must be set.
+	 */
+	if ((trf->technology == NFC_DIGITAL_RF_TECH_106A) &&
+			(trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T)) {
+		if (req[0] == NFC_T2T_CMD_READ)
+			special_fcn_reg1 = 0;
+		else
+			special_fcn_reg1 = TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX;
+
+		if (special_fcn_reg1 != trf->special_fcn_reg1) {
+			ret = trf7970a_write(trf, TRF7970A_SPECIAL_FCN_REG1,
+					special_fcn_reg1);
+			if (ret)
+				return ret;
+
+			trf->special_fcn_reg1 = special_fcn_reg1;
+		}
+	}
+
+	return 0;
+}
+
+static int trf7970a_in_send_cmd(struct nfc_digital_dev *ddev,
+		struct sk_buff *skb, u16 timeout,
+		nfc_digital_cmd_complete_t cb, void *arg)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+	char *prefix;
+	unsigned int len;
+	int ret;
+
+	dev_dbg(trf->dev, "New request - state: %d, timeout: %d ms, len: %d\n",
+			trf->state, timeout, skb->len);
+
+	if (skb->len > TRF7970A_TX_MAX)
+		return -EINVAL;
+
+	mutex_lock(&trf->lock);
+
+	if ((trf->state != TRF7970A_ST_IDLE) &&
+			(trf->state != TRF7970A_ST_IDLE_RX_BLOCKED)) {
+		dev_err(trf->dev, "%s - Bogus state: %d\n", __func__,
+				trf->state);
+		ret = -EIO;
+		goto out_err;
+	}
+
+	trf->rx_skb = nfc_alloc_recv_skb(TRF7970A_RX_SKB_ALLOC_SIZE,
+			GFP_KERNEL);
+	if (!trf->rx_skb) {
+		dev_dbg(trf->dev, "Can't alloc rx_skb\n");
+		ret = -ENOMEM;
+		goto out_err;
+	}
+
+	if (trf->state == TRF7970A_ST_IDLE_RX_BLOCKED) {
+		ret = trf7970a_cmd(trf, TRF7970A_CMD_ENABLE_RX);
+		if (ret)
+			goto out_err;
+
+		trf->state = TRF7970A_ST_IDLE;
+	}
+
+	ret = trf7970a_per_cmd_config(trf, skb);
+	if (ret)
+		goto out_err;
+
+	trf->ddev = ddev;
+	trf->tx_skb = skb;
+	trf->cb = cb;
+	trf->cb_arg = arg;
+	trf->timeout = timeout;
+	trf->ignore_timeout = false;
+
+	len = skb->len;
+	prefix = skb_push(skb, TRF7970A_TX_SKB_HEADROOM);
+
+	/* TX data must be prefixed with a FIFO reset cmd, a cmd that depends
+	 * on what the current framing is, the address of the TX length byte 1
+	 * register (0x1d), and the 2 byte length of the data to be transmitted.
+	 */
+	prefix[0] = TRF7970A_CMD_BIT_CTRL |
+			TRF7970A_CMD_BIT_OPCODE(TRF7970A_CMD_FIFO_RESET);
+	prefix[1] = TRF7970A_CMD_BIT_CTRL |
+			TRF7970A_CMD_BIT_OPCODE(trf->tx_cmd);
+	prefix[2] = TRF7970A_CMD_BIT_CONTINUOUS | TRF7970A_TX_LENGTH_BYTE1;
+
+	if (trf->framing == NFC_DIGITAL_FRAMING_NFCA_SHORT) {
+		prefix[3] = 0x00;
+		prefix[4] = 0x0f; /* 7 bits */
+	} else {
+		prefix[3] = (len & 0xf00) >> 4;
+		prefix[3] |= ((len & 0xf0) >> 4);
+		prefix[4] = ((len & 0x0f) << 4);
+	}
+
+	len = min_t(int, skb->len, TRF7970A_FIFO_SIZE);
+
+	usleep_range(1000, 2000);
+
+	ret = trf7970a_transmit(trf, skb, len);
+	if (ret) {
+		kfree_skb(trf->rx_skb);
+		trf->rx_skb = NULL;
+	}
+
+out_err:
+	mutex_unlock(&trf->lock);
+	return ret;
+}
+
+static int trf7970a_tg_configure_hw(struct nfc_digital_dev *ddev,
+		int type, int param)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+
+	dev_dbg(trf->dev, "Unsupported interface\n");
+
+	return -EINVAL;
+}
+
+static int trf7970a_tg_send_cmd(struct nfc_digital_dev *ddev,
+		struct sk_buff *skb, u16 timeout,
+		nfc_digital_cmd_complete_t cb, void *arg)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+
+	dev_dbg(trf->dev, "Unsupported interface\n");
+
+	return -EINVAL;
+}
+
+static int trf7970a_tg_listen(struct nfc_digital_dev *ddev,
+		u16 timeout, nfc_digital_cmd_complete_t cb, void *arg)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+
+	dev_dbg(trf->dev, "Unsupported interface\n");
+
+	return -EINVAL;
+}
+
+static int trf7970a_tg_listen_mdaa(struct nfc_digital_dev *ddev,
+		struct digital_tg_mdaa_params *mdaa_params,
+		u16 timeout, nfc_digital_cmd_complete_t cb, void *arg)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+
+	dev_dbg(trf->dev, "Unsupported interface\n");
+
+	return -EINVAL;
+}
+
+static int trf7970a_switch_rf(struct nfc_digital_dev *ddev, bool on)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+	int ret = 0;
+
+	dev_dbg(trf->dev, "state: %d, on: %d\n", trf->state, on);
+
+	mutex_lock(&trf->lock);
+
+	if (on) {
+		switch (trf->state) {
+		case TRF7970A_ST_OFF:
+			ret = trf7970a_switch_rf_on(trf);
+			break;
+		case TRF7970A_ST_IDLE:
+		case TRF7970A_ST_IDLE_RX_BLOCKED:
+			break;
+		default:
+			dev_err(trf->dev, "%s - Invalid request: %d %d\n",
+					__func__, trf->state, on);
+			trf7970a_switch_rf_off(trf);
+		}
+	} else {
+		switch (trf->state) {
+		case TRF7970A_ST_OFF:
+			break;
+		default:
+			dev_err(trf->dev, "%s - Invalid request: %d %d\n",
+					__func__, trf->state, on);
+			/* FALLTHROUGH */
+		case TRF7970A_ST_IDLE:
+		case TRF7970A_ST_IDLE_RX_BLOCKED:
+			trf7970a_switch_rf_off(trf);
+		}
+	}
+
+	mutex_unlock(&trf->lock);
+	return ret;
+}
+
+static void trf7970a_abort_cmd(struct nfc_digital_dev *ddev)
+{
+	struct trf7970a *trf = nfc_digital_get_drvdata(ddev);
+
+	mutex_lock(&trf->lock);
+	_trf7970a_abort_cmd(trf);
+	mutex_unlock(&trf->lock);
+}
+
+static struct nfc_digital_ops trf7970a_nfc_ops = {
+	.in_configure_hw	= trf7970a_in_configure_hw,
+	.in_send_cmd		= trf7970a_in_send_cmd,
+	.tg_configure_hw	= trf7970a_tg_configure_hw,
+	.tg_send_cmd		= trf7970a_tg_send_cmd,
+	.tg_listen		= trf7970a_tg_listen,
+	.tg_listen_mdaa		= trf7970a_tg_listen_mdaa,
+	.switch_rf		= trf7970a_switch_rf,
+	.abort_cmd		= trf7970a_abort_cmd,
+};
+
+static int trf7970a_probe(struct spi_device *spi)
+{
+	struct device_node *np = spi->dev.of_node;
+	const struct spi_device_id *id = spi_get_device_id(spi);
+	struct trf7970a *trf;
+	int ret;
+
+	if (!np) {
+		dev_err(&spi->dev, "No Device Tree entry\n");
+		return -EINVAL;
+	}
+
+	trf = devm_kzalloc(&spi->dev, sizeof(*trf), GFP_KERNEL);
+	if (!trf)
+		return -ENOMEM;
+
+	trf->state = TRF7970A_ST_OFF;
+	trf->dev = &spi->dev;
+	trf->spi = spi;
+	trf->quirks = id->driver_data;
+	trf->initialized = false;
+
+	spi->mode = SPI_MODE_1;
+	spi->bits_per_word = 8;
+
+	/* Get the optional Slave Select GPIO used for SPI with SS mode */
+	trf->ss_gpio = of_get_named_gpio(np, "ti,ss-gpio", 0);
+	if (trf->ss_gpio >= 0) {
+		ret = devm_gpio_request_one(trf->dev, trf->ss_gpio,
+				GPIOF_DIR_OUT | GPIOF_INIT_LOW, "SS");
+		if (ret) {
+			dev_err(trf->dev, "Can't request SS GPIO: %d\n", ret);
+			return ret;
+		}
+	} else {
+		dev_info(trf->dev, "Using SPI without SS mode\n");
+	}
+
+	/* There are two enable pins - both must be present */
+	trf->en_gpio = of_get_named_gpio(np, "ti,enable-gpios", 0);
+	if (trf->en_gpio < 0) {
+		dev_err(trf->dev, "No EN GPIO property\n");
+		return ret;
+	}
+
+	ret = devm_gpio_request_one(trf->dev, trf->en_gpio,
+			GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN");
+	if (ret) {
+		dev_err(trf->dev, "Can't request EN GPIO: %d\n", ret);
+		return ret;
+	}
+
+	trf->en2_gpio = of_get_named_gpio(np, "ti,enable-gpios", 1);
+	if (trf->en2_gpio < 0) {
+		dev_err(trf->dev, "No EN2 GPIO property\n");
+		return ret;
+	}
+
+	ret = devm_gpio_request_one(trf->dev, trf->en2_gpio,
+			GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN2");
+	if (ret) {
+		dev_err(trf->dev, "Can't request EN2 GPIO: %d\n", ret);
+		return ret;
+	}
+
+	usleep_range(2000, 3000);
+	if (trf->ss_gpio >= 0)
+		gpio_set_value(trf->ss_gpio, 1);
+	usleep_range(3000, 4000);
+
+	ret = devm_request_threaded_irq(trf->dev, spi->irq, NULL,
+			trf7970a_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+			"trf7970a", trf);
+	if (ret) {
+		dev_err(trf->dev, "Can't request IRQ#%d: %d\n", spi->irq, ret);
+		return ret;
+	}
+
+	trf->ddev = nfc_digital_allocate_device(&trf7970a_nfc_ops,
+			TRF7970A_SUPPORTED_PROTOCOLS,
+			NFC_DIGITAL_DRV_CAPS_IN_CRC, TRF7970A_TX_SKB_HEADROOM,
+			0);
+	if (!trf->ddev) {
+		dev_err(trf->dev, "Can't allocate NFC digital device\n");
+		return -ENOMEM;
+	}
+
+	nfc_digital_set_parent_dev(trf->ddev, trf->dev);
+	nfc_digital_set_drvdata(trf->ddev, trf);
+	spi_set_drvdata(spi, trf);
+
+	ret = nfc_digital_register_device(trf->ddev);
+	if (ret) {
+		dev_err(trf->dev, "Can't register NFC digital device: %d\n",
+				ret);
+		goto err_free_ddev;
+	}
+
+	mutex_init(&trf->lock);
+	INIT_DELAYED_WORK(&trf->timeout_work, trf7970a_timeout_work_handler);
+
+	return 0;
+
+err_free_ddev:
+	nfc_digital_free_device(trf->ddev);
+	return ret;
+}
+
+static int trf7970a_remove(struct spi_device *spi)
+{
+	struct trf7970a *trf = spi_get_drvdata(spi);
+
+	_trf7970a_abort_cmd(trf);
+	trf7970a_switch_rf_off(trf);
+
+	if (trf->ss_gpio >= 0)
+		gpio_set_value(trf->ss_gpio, 0);
+
+	mutex_destroy(&trf->lock);
+
+	nfc_digital_unregister_device(trf->ddev);
+	nfc_digital_free_device(trf->ddev);
+
+	return 0;
+}
+
+static const struct spi_device_id trf7970a_id_table[] = {
+	{ "trf7970a", TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, trf7970a_id_table);
+
+static struct spi_driver trf7970a_spi_driver = {
+	.probe		= trf7970a_probe,
+	.remove		= trf7970a_remove,
+	.id_table	= trf7970a_id_table,
+	.driver		= {
+		.name	= "trf7970a",
+		.owner	= THIS_MODULE,
+	},
+};
+
+module_spi_driver(trf7970a_spi_driver);
+
+MODULE_AUTHOR("Mark A. Greer <mgreer-luAo+O/VEmrlveNOaEYElw@public.gmane.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI trf7970a RFID/NFC Transceiver Driver");
-- 
1.8.3.4

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH 0/3] NFC: trf7970a: Add driver with NFC Type 2 and Type V Support
From: Mark A. Greer @ 2014-01-31 22:17 UTC (permalink / raw)
  To: Samuel Ortiz, Lauro Ramos Venancio, Aloisio Almeida Jr
  Cc: Felipe Balbi, Erick Macias, Thierry Escande,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	linux-nfc-hn68Rpc1hR1g9hUCZPvPmw,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Mark A. Greer

This is a driver for the TI TRF7970A RFID/NFC/15693 Transceiver.
The driver was started by Erick Macias and Felipe Balbi but has
been changed significantly by me.  Because of that, Felipe has
allowed me to replace his name by mine in the MODULE_AUTHOR()
line.

The trf7970a has a low-level interface so it requires the NFC
digital layer.

It has been tested on a couple different consumer Type 2 tags
and 3 different types of TI Tag-it HF-I tags.  It seems stable
but the device often reports a CRC or collision error when moving
a tag into the RF field while actively polling.  That means that
an EIO error will be reported and you'll have to retry the poll
in order to communicate with the tag.

The driver is broken into two patches: one for the majority of
the driver which includes 14443 Type 2 (MIFARE Ultralight and
Ultralight C) tags and another for 15693 Type V support.  The
third patch adds DTS documentation.

Mark A. Greer (3):
  NFC: trf7970a: Add driver with ISO/IEC 14443 Type 2 Tag Support
  NFC: trf7970a: Add ISO/IEC 15693 Support
  NFC: trf7970a: Add DTS Documentation

 .../devicetree/bindings/net/nfc/trf7970a.txt       |   37 +
 drivers/nfc/Kconfig                                |   12 +
 drivers/nfc/Makefile                               |    1 +
 drivers/nfc/trf7970a.c                             | 1338 ++++++++++++++++++++
 4 files changed, 1388 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/nfc/trf7970a.txt
 create mode 100644 drivers/nfc/trf7970a.c

-- 
1.8.3.4

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v7 0/7] ARM: rockchip: add smp functionality
From: Rob Herring @ 2014-01-31 22:12 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	arm-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org, Philipp Zabel,
	Mark Rutland, Grant Likely,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Greg Kroah-Hartman, Pawel Moll, Stephen Warren, Ian Campbell
In-Reply-To: <13010296.nzTT2PqdSR@phil>

On Fri, Jan 31, 2014 at 4:03 PM, Heiko Stübner <heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org> wrote:
> On Monday, 20. January 2014 16:41:43 Heiko Stübner wrote:
>> This series enables the use of the additional cores on Rockchip
>> Cortex-A9 SoCs.
>
> So, two weeks without any general complaints, but I guess part of the more
> general patches could use an ack.
>
> Going forward, what would be best way to merge them?
> As one pull request to arm-soc, or for example splitting them into the first
> three patches going through the misc tree and the rockchip specific stuff going
> through arm-soc? Or something else altogether?
>
>
>> Heiko Stuebner (7):
>>   of: add functions to count number of elements in a property
>
> One of the intermediate versions of this patch got a
>         Reviewed-by: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org> .
> Mark, is this still true for this variant addressing some additional wished
> from Rob?
>
> And this final version got a "Looks good" from Rob Herring in the original
> thread, but a more formal "ack" might be nice :-) .

Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

Rob

>
>
>>   dt-bindings: sram: describe option to reserve parts of the memory
>>   misc: sram: implement mmio-sram-reserved option
>
> Philipp, you acked an intermediate version, and this v7 now should also
> contain the two separate loops (1st gathering data and 2nd creating the pool
> parts) you asked for.
>
> Could I persuade you to take a look again?
>
>
> Thanks
> Heiko
>
>
>>   ARM: rockchip: add snoop-control-unit
>>   ARM: rockchip: add sram dt nodes and documentation
>>   ARM: rockchip: add power-management-unit
>>   ARM: rockchip: add smp bringup code
>>
>>  .../devicetree/bindings/arm/rockchip/pmu.txt       |   16 ++
>>  .../devicetree/bindings/arm/rockchip/smp-sram.txt  |   23 +++
>>  Documentation/devicetree/bindings/misc/sram.txt    |    8 +
>>  arch/arm/boot/dts/rk3066a.dtsi                     |    6 +
>>  arch/arm/boot/dts/rk3188.dtsi                      |    6 +
>>  arch/arm/boot/dts/rk3xxx.dtsi                      |   10 +
>>  arch/arm/mach-rockchip/Kconfig                     |    1 +
>>  arch/arm/mach-rockchip/Makefile                    |    1 +
>>  arch/arm/mach-rockchip/core.h                      |   22 +++
>>  arch/arm/mach-rockchip/headsmp.S                   |   30 +++
>>  arch/arm/mach-rockchip/platsmp.c                   |  208
>> ++++++++++++++++++++ arch/arm/mach-rockchip/rockchip.c                  |
>>  2 +
>>  drivers/misc/sram.c                                |  121 +++++++++++-
>>  drivers/of/base.c                                  |   32 +++
>>  include/linux/of.h                                 |   76 +++++++
>>  15 files changed, 554 insertions(+), 8 deletions(-)
>>  create mode 100644 Documentation/devicetree/bindings/arm/rockchip/pmu.txt
>>  create mode 100644
>> Documentation/devicetree/bindings/arm/rockchip/smp-sram.txt create mode
>> 100644 arch/arm/mach-rockchip/core.h
>>  create mode 100644 arch/arm/mach-rockchip/headsmp.S
>>  create mode 100644 arch/arm/mach-rockchip/platsmp.c
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v7 0/7] ARM: rockchip: add smp functionality
From: Heiko Stübner @ 2014-01-31 22:03 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	arm-DgEjT+Ai2ygdnm+yROfE0A, Rob Herring, Philipp Zabel,
	Mark Rutland
  Cc: Grant Likely, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Greg Kroah-Hartman,
	Pawel Moll, Stephen Warren, Ian Campbell
In-Reply-To: <4970034.fqvMoHdOyd@phil>

On Monday, 20. January 2014 16:41:43 Heiko Stübner wrote:
> This series enables the use of the additional cores on Rockchip
> Cortex-A9 SoCs.

So, two weeks without any general complaints, but I guess part of the more 
general patches could use an ack.

Going forward, what would be best way to merge them?
As one pull request to arm-soc, or for example splitting them into the first 
three patches going through the misc tree and the rockchip specific stuff going 
through arm-soc? Or something else altogether?


> Heiko Stuebner (7):
>   of: add functions to count number of elements in a property

One of the intermediate versions of this patch got a
	Reviewed-by: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org> .
Mark, is this still true for this variant addressing some additional wished 
from Rob?

And this final version got a "Looks good" from Rob Herring in the original 
thread, but a more formal "ack" might be nice :-) .


>   dt-bindings: sram: describe option to reserve parts of the memory
>   misc: sram: implement mmio-sram-reserved option

Philipp, you acked an intermediate version, and this v7 now should also 
contain the two separate loops (1st gathering data and 2nd creating the pool 
parts) you asked for.

Could I persuade you to take a look again?


Thanks
Heiko


>   ARM: rockchip: add snoop-control-unit
>   ARM: rockchip: add sram dt nodes and documentation
>   ARM: rockchip: add power-management-unit
>   ARM: rockchip: add smp bringup code
> 
>  .../devicetree/bindings/arm/rockchip/pmu.txt       |   16 ++
>  .../devicetree/bindings/arm/rockchip/smp-sram.txt  |   23 +++
>  Documentation/devicetree/bindings/misc/sram.txt    |    8 +
>  arch/arm/boot/dts/rk3066a.dtsi                     |    6 +
>  arch/arm/boot/dts/rk3188.dtsi                      |    6 +
>  arch/arm/boot/dts/rk3xxx.dtsi                      |   10 +
>  arch/arm/mach-rockchip/Kconfig                     |    1 +
>  arch/arm/mach-rockchip/Makefile                    |    1 +
>  arch/arm/mach-rockchip/core.h                      |   22 +++
>  arch/arm/mach-rockchip/headsmp.S                   |   30 +++
>  arch/arm/mach-rockchip/platsmp.c                   |  208
> ++++++++++++++++++++ arch/arm/mach-rockchip/rockchip.c                  |  
>  2 +
>  drivers/misc/sram.c                                |  121 +++++++++++-
>  drivers/of/base.c                                  |   32 +++
>  include/linux/of.h                                 |   76 +++++++
>  15 files changed, 554 insertions(+), 8 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/arm/rockchip/pmu.txt
>  create mode 100644
> Documentation/devicetree/bindings/arm/rockchip/smp-sram.txt create mode
> 100644 arch/arm/mach-rockchip/core.h
>  create mode 100644 arch/arm/mach-rockchip/headsmp.S
>  create mode 100644 arch/arm/mach-rockchip/platsmp.c

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH v2 1/2] dt: Document a compatible entry for MDIO ethernet Phys
From: Jason Gunthorpe @ 2014-01-31 21:50 UTC (permalink / raw)
  To: Rob Herring
  Cc: Grant Likely, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA

This describes a compatible entry of the form:
  ethernet-phy-idAAAA,BBBB
Which is modelled after the PCI structured compatible entry
(pciVVVV,DDDD.SSSS.ssss.RR)

If present the OF core will be able to use this information to
directly create the correct phy without auto probing the bus.

Signed-off-by: Jason Gunthorpe <jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
 Documentation/devicetree/bindings/net/phy.txt | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org

diff --git a/Documentation/devicetree/bindings/net/phy.txt b/Documentation/devicetree/bindings/net/phy.txt
index 7cd18fb..989122c 100644
--- a/Documentation/devicetree/bindings/net/phy.txt
+++ b/Documentation/devicetree/bindings/net/phy.txt
@@ -23,10 +23,18 @@ Optional Properties:
   assume clause 22. The compatible list may also contain other
   elements.
 
+  If the phy's identifier is known then the list may contain an entry
+  of the form: "ethernet-phy-idAAAA.BBBB" where
+     AAAA - The value of the 16 bit Phy Identifier 1 register as
+            4 hex digits. This is the chip vendor OUI bits 3:18
+     BBBB - The value of the 16 bit Phy Identifier 2 register as
+            4 hex digits. This is the chip vendor OUI bits 19:24,
+            followed by 10 bits of a vendor specific ID.
+
 Example:
 
 ethernet-phy@0 {
-	compatible = "ethernet-phy-ieee802.3-c22";
+	compatible = "ethernet-phy-id0141.0e90", "ethernet-phy-ieee802.3-c22";
 	linux,phandle = <2452000>;
 	interrupt-parent = <40000>;
 	interrupts = <35 1>;
-- 
1.8.1.2

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v1] ARM: tegra: add nvidia,wdt-timer-id optional property
From: Andrew Chew @ 2014-01-31 21:46 UTC (permalink / raw)
  To: robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, rob,
	swarren, thierry.reding, abrestic, dgreid, katierh
  Cc: devicetree, linux-doc, linux-tegra, linux-kernel, Andrew Chew

This optional property can be used to specify which timers are to be used
for hardware watchdog timeouts (via a tegra wdt driver).

Signed-off-by: Andrew Chew <achew@nvidia.com>
---
 Documentation/devicetree/bindings/timer/nvidia,tegra30-timer.txt | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/Documentation/devicetree/bindings/timer/nvidia,tegra30-timer.txt b/Documentation/devicetree/bindings/timer/nvidia,tegra30-timer.txt
index b5082a1..e87fa70 100644
--- a/Documentation/devicetree/bindings/timer/nvidia,tegra30-timer.txt
+++ b/Documentation/devicetree/bindings/timer/nvidia,tegra30-timer.txt
@@ -13,6 +13,13 @@ Required properties:
 - clocks : Must contain one entry, for the module clock.
   See ../clocks/clock-bindings.txt for details.
 
+Optional properties:
+
+- nvidia,wdt-timer-id: A list of timer IDs to be used for watchdogs.
+    Watchdog 0 will be assigned to the first timer listed, watchdog 1 will
+    be assigned to the second timer listed, etc. up to the number of watchdogs
+    available.
+
 timer {
 	compatible = "nvidia,tegra30-timer", "nvidia,tegra20-timer";
 	reg = <0x60005000 0x400>;
@@ -23,4 +30,5 @@ timer {
 		      0 121 0x04
 		      0 122 0x04>;
 	clocks = <&tegra_car 214>;
+	nvidia,wdt-timer-id = <7 8>;
 };
-- 
1.8.1.5

^ permalink raw reply related

* Re: [PATCH] of: add vendor prefix for Honeywell
From: Belisko Marek @ 2014-01-31 21:46 UTC (permalink / raw)
  To: Olof Johansson
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Rob Landley, devicetree@vger.kernel.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <CAOesGMhFEMNFbAC4rUdccYVHM8yX9Mz+Vx73jGxBYGrSOa4Gaw@mail.gmail.com>

On Fri, Jan 31, 2014 at 7:53 PM, Olof Johansson <olof@lixom.net> wrote:
> On Sat, Jan 25, 2014 at 1:38 PM, Marek Belisko <marek@goldelico.com> wrote:
>> Signed-off-by: Marek Belisko <marek@goldelico.com>
>> ---
>>  Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
>>  1 file changed, 1 insertion(+)
>>
>> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
>> index 3f900cd..b14c617 100644
>> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
>> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
>> @@ -40,6 +40,7 @@ gmt   Global Mixed-mode Technology, Inc.
>>  gumstix        Gumstix, Inc.
>>  haoyu  Haoyu Microelectronic Co. Ltd.
>>  hisilicon      Hisilicon Limited.
>> +honeywell      Honeywell
>
> The norm has usually been to use the the stock ticker symbol of a
> public company if it is available. In other words, I think the prefix
> here should be 'hon', since Honeywell is a publicly traded company
> under that ticker.
OK I didn't know about that. I just pick name from here:
Documentation/devicetree/bindings/iio/magnetometer/hmc5843.txt
So we need to update also compatible property in mentioned file.
>
>
> -Olof

BR,

marek

-- 
as simple and primitive as possible
-------------------------------------------------
Marek Belisko - OPEN-NANDRA
Freelance Developer

Ruska Nova Ves 219 | Presov, 08005 Slovak Republic
Tel: +421 915 052 184
skype: marekwhite
twitter: #opennandra
web: http://open-nandra.com

^ permalink raw reply

* [WIP PATCH] dts: Generate binaries for all relevant platforms
From: Simon Glass @ 2014-01-31 21:07 UTC (permalink / raw)
  To: U-Boot Mailing List
  Cc: Masahiro Yamada, Vadim Bendebury, Simon Glass, Devicetree Discuss

From: Vadim Bendebury <vbendeb-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>

(sent for the benefit of the Kbuild series - this does not apply as is)

Similar targets can use the same u-boot binary with different device
trees. It is convenient to have all similar device trees compiled and
published when u-boot is made: it allows for later easy repackaging
without the need to re-run the make file.

This follows the Linux kernel suite, which also compiles all similar
device tree targets at once.

For the purposes of exynos u-boot, as of now similar targets are those
which have the same device tree file prefix (before the first '-').

This change modifies the dts makefile to allow concurrent processing
of multiple device trees. As previously, one device tree is still
published at 'u-boot.dtb', this is a copy of the compiled default
device tree.

The problem with some DTC compiler versions generating stderr output
even when there is no compilation errors has been also addressed: all
DTC output is collected in a file, and only in case of error is the
file sent to stderr.

 Chrome OS tests:
  . emerge-{link|daisy} chromeos-u-boot - both succeed

  . to verify that all device tres get compiled run the following
    commands (the doit script below configures and builds u-boot for
    the target passed through TARGET='):

    $ rm -rf /tmp/u-*
    $ for t in link peach daisy; do
       USE_STDINT=1 U_BOOT_ROOT=$(pwd)  TARGET=$t doit
      done
    $ find /tmp/u-* -name '*.dtb'
   /tmp/u-daisy/u-boot.dtb
   /tmp/u-daisy/dts/exynos5250-snow.dtb
   /tmp/u-daisy/dts/exynos5250-smdk5250.dtb
   /tmp/u-daisy/dts/exynos5250-spring.dtb
   /tmp/u-link/u-boot.dtb
   /tmp/u-link/dts/link.dtb
   /tmp/u-peach/u-boot.dtb
   /tmp/u-peach/dts/exynos5420-smdk5420.dtb
   /tmp/u-peach/dts/exynos5420-peach_pit.dtb
   /tmp/u-peach/dts/exynos5420-peach-pit-adv.dtb

  . to verify that dt.o still builds when required run the following
    commands

   $ find /tmp/u-peach/ -name 'dt.o'
   $ CONFIG_OF_EMBED=y   TARGET=peach USE_STDINT=1 U_BOOT_ROOT=$(pwd)  doit
   $ find /tmp/u-peach/ -name 'dt.o'
   /tmp/u-peach/dts/dt.o

  . to verify that corrupting device tree still stops the build, add a
    syntax error to exynos5420-peach_pit.dts and rerun the build:

   $ TARGET=peach USE_STDINT=1 U_BOOT_ROOT=$(pwd)  doit
   Building in /tmp/u-peach
   DTC: dts->dtb  on file "/tmp/u-peach/dts/exynos5420-peach_pit.dtb.in"
   FATAL ERROR: Unable to parse input tree
   Error: /tmp/u-peach/dts/exynos5420-peach_pit.dtb.in:6.1-4 syntax error
   make[1]: *** [/tmp/u-peach/dts/exynos5420-peach_pit.dtb] Error 1
   make[1]: Target 'binary' not remade because of errors.
   make: *** [/tmp/u-peach/u-boot.dtb] Error 2
   make: Target `all' not remade because of errors.
END

Signed-off-by: Vadim Bendebury <vbendeb-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
Signed-off-by: Simon Glass <sjg-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
---
 dts/Makefile | 49 ++++++++++++++++++++++++++++++-------------------
 1 file changed, 30 insertions(+), 19 deletions(-)

diff --git a/dts/Makefile b/dts/Makefile
index 684ead3..a024b6a 100644
--- a/dts/Makefile
+++ b/dts/Makefile
@@ -30,7 +30,12 @@ LIB	= $(obj)libdts.o
 ifeq ($(DEVICE_TREE),)
 $(if $(CONFIG_DEFAULT_DEVICE_TREE),,\
 $(error Please define CONFIG_DEFAULT_DEVICE_TREE in your board header file))
-DEVICE_TREE = $(subst ",,$(CONFIG_DEFAULT_DEVICE_TREE))
+# This gets rid both of the double quotes and a possible suffix.
+DEV_TREE_BASE := $(shell echo $(CONFIG_DEFAULT_DEVICE_TREE) | sed 's/-.*//')
+DEFAULT_TREE := $(subst ",,$(obj)$(CONFIG_DEFAULT_DEVICE_TREE).dtb)
+else
+DEV_TREE_BASE := $(DEVICE_TREE)
+DEFAULT_TREE := $(obj)$(DEVICE_TREE).dtb)
 endif
 
 $(if $(CONFIG_ARCH_DEVICE_TREE),,\
@@ -52,14 +57,12 @@ DTS_FLAGS := $(shell if ! dtc -i 2>&1 | grep -q "invalid option"; then \
 # Undefine 'linux' since it might be used in device tree files
 DTS_CPPFLAGS := -x assembler-with-cpp -Ulinux \
 		-DARCH_CPU_DTS=\"$(SRCTREE)/arch/$(ARCH)/dts/$(CONFIG_ARCH_DEVICE_TREE).dtsi\" \
-		-DBOARD_DTS=\"$(SRCTREE)/board/$(VENDOR)/$(BOARD)/dts/$(DEVICE_TREE).dts\" \
 		-D__ASSEMBLY__ -I$(OBJTREE)/include -I$(SRCTREE)/include \
 		-I$(OBJTREE)/include2 \
 		-I$(SRCTREE)/board/$(VENDOR)/dts -I$(SRCTREE)/arch/$(ARCH)/dts \
 		-include $(OBJTREE)/include/config.h
 
-DTS_TMP := $(OBJTREE)/include/generated/$(DEVICE_TREE).dts.in
-DTS_SRC := board/$(VENDOR)/dts/$(DEVICE_TREE).dts
+DTS_DIR := $(TOPDIR)/board/$(VENDOR)/dts
 
 all:	$(obj).depend $(LIB)
 
@@ -68,20 +71,28 @@ all:	$(obj).depend $(LIB)
 # the filename.
 DT_BIN	:= $(obj)dt.dtb
 
-DTC_CMD := $(DTC) -R 4 -p 0x1000 -O dtb -o ${DT_BIN} $(DTS_FLAGS) $(DTS_TMP)
-
-$(DT_BIN): $(TOPDIR)/$(DTS_SRC)
-	rc=$$( \
-		cat $< | $(CPP) -P $(DTS_CPPFLAGS) - > $(DTS_TMP); \
-		{ { $(DTC_CMD)  2>&1 ; \
-		    echo $$? >&3 ; } | \
-		  grep -v '^DTC: dts->dtb  on file' ; \
-	        } 3>&1 1>&2 ) ; \
-	if [ $$rc != 0 ]; then \
-		echo "Source file is $(DTS_SRC)"; \
-		echo "Compiler: $(DTC_CMD)"; \
-	fi; \
-	exit $$rc
+DT_SOURCES := $(notdir $(wildcard $(DTS_DIR)/$(DEV_TREE_BASE)-*))
+DT_BINS := $(addprefix $(obj),$(addsuffix .dtb,$(basename $(DT_SOURCES)))) \
+	$(DT_BIN)
+
+$(obj)dt.dtb: $(DEFAULT_TREE)
+	cp $< $@
+
+# Get preprocessed version of the tree.
+$(obj)%.dts.in : $(DTS_DIR)/%.dts
+	$(CPP) -P $(DTS_CPPFLAGS) -DBOARD_DTS=$< $< -o $@
+
+# Compile the preprocessed device tree. Some DTC versions insist on sending
+# output to stderr even when everything is fine, which wrecs havoc on
+# automated testing tools watching for stderr output.
+#
+# To address this issue collect all DTC output in a file and send the file to
+# stderr only if there has been a DTC error. '&& false' enforces a make error.
+#
+$(obj)%.dtb : $(obj)%.dts.in
+	$(DTC) -R 4 -p 0x1000 -O dtb $(DTS_FLAGS) -o $@ $< > $@.errmsg 2>&1 || \
+	(export rc=$$? && cat $@.errmsg >&2 && exit $$rc)
+	rm -f $@.errmsg
 
 process_lds = \
 	$(1) | sed -r -n 's/^OUTPUT_$(2)[ ("]*([^")]*).*/\1/p'
@@ -122,7 +133,7 @@ COBJS	:= $(OBJS-y)
 
 OBJS	:= $(addprefix $(obj),$(COBJS))
 
-binary:	$(DT_BIN)
+binary:	$(DT_BINS)
 
 $(LIB):	$(OBJS) $(DTB)
 	$(call cmd_link_o_target, $(OBJS))
-- 
1.9.rc1.175.g0b1dcb5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: [PATCH v3] DT: net: document Ethernet bindings in one place
From: Sergei Shtylyov @ 2014-01-31 20:54 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, galak,
	devicetree@vger.kernel.org, Rob Landley,
	linux-doc@vger.kernel.org, Max Filippov
In-Reply-To: <CAMuHMdV6QNGAh8s40z766N6HMboUW_eO85Gs7p0JBAuZ6vW1Nw@mail.gmail.com>

Hello.

On 01/28/2014 11:26 AM, Geert Uytterhoeven wrote:

>> --- /dev/null
>> +++ net-next/Documentation/devicetree/bindings/net/ethernet.txt
>> @@ -0,0 +1,23 @@
>> +The following properties are common to the Ethernet controllers:
>> +
>> +- local-mac-address: array of 6 bytes, specifies the MAC address that was
>> +  assigned to the network device;
>> +- mac-address: array of 6 bytes, specifies the MAC address that was last used by
>> +  the boot program; should be used in cases where the MAC address assigned to
>> +  the device by the boot program is different from the "local-mac-address"
>> +  property;
>> +- max-speed: number, specifies maximum speed in Mbit/s supported by the device;
>> +- max-frame-size: number, maximum transfer unit (IEEE defined MTU), rather than
>> +  the maximum frame size (there's contradiction in ePAPR).
>> +- phy-mode: string, operation mode of the PHY interface; supported values are
>> +  "mii", "gmii", "sgmii", "tbi", "rev-mii", "rmii", "rgmii", "rgmii-id",
>> +  "rgmii-rxid", "rgmii-txid", "rtbi", "smii", "xgmii"; not recommended for new
>> +  bindings;
>> +- phy-connection-type: the same as "phy-mode" property but described in ePAPR;
>> +- phy-handle: phandle, specifies a reference to a node representing a PHY
>> +  device; this property is described in ePAPR and so preferred;
>> +- phy: the same as "phy-handle" property, not recommended for new bindings.

> I think it would be more clear to move the not recommended ones to a new
> paragraph, with a preamble stating they're not recommended for new bindings.

    In fact, at the moment, only "phy" prop can be named as not recommended, 
the "phy-mode" should better be described as de facto standard as it's 
mentioned even in ePAPR 1.1 examples (and of_get_phy_mode() patch to recognize 
"phy-connection-type" as well as "phy-mode" prop probably got lost somewhere). 
Thus I'm not sure it's worth creating separate paragraph for the sake of one 
prop is worth it now. Although there's also "phy-device" which I didn't 
mention here (and IIRC there's some more non-standard ways to address the PHY)...

WBR, Sergei


^ permalink raw reply

* [PATCH net-next 2/2] stmmac: add extended set multicast filter & devicetree options
From: Vince Bridgers @ 2014-01-31 20:15 UTC (permalink / raw)
  To: devicetree, netdev
  Cc: peppe.cavallaro, robh+dt, pawel.moll, mark.rutland,
	ijc+devicetree, galak, dinguyen, rayagond, vbridgers2013
In-Reply-To: <1391199356-27226-1-git-send-email-vbridgers2013@gmail.com>

The synopsys EMAC can be configured for different numbers of multicast hash
bins and perfect filter entries at device creation time and there's no way
to query this configuration information at runtime. As a result, a devicetree
parameter is required in order for the driver to program these filters
correctly for a particular device instance. This patch extends the current
driver by providing a different multicast filter programming function if
different than the currently supported 64 multicast hash bins and 32
perfect unicast addresses. This patch is required to correct multicast
filtering for the Altera Cyclone V SOC.

Signed-off-by: Vince Bridgers <vbridgers2013@gmail.com>
---
 drivers/net/ethernet/stmicro/stmmac/common.h       |   42 +++--
 drivers/net/ethernet/stmicro/stmmac/dwmac1000.h    |    5 +-
 .../net/ethernet/stmicro/stmmac/dwmac1000_core.c   |  161 +++++++++++++++++---
 .../net/ethernet/stmicro/stmmac/dwmac100_core.c    |   29 ++--
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |    6 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |   36 ++---
 .../net/ethernet/stmicro/stmmac/stmmac_platform.c  |   51 +++++++
 include/linux/stmmac.h                             |    2 +
 8 files changed, 261 insertions(+), 71 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 7834a39..ca07afe 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -294,6 +294,8 @@ struct dma_features {
 
 #define JUMBO_LEN		9000
 
+#define GMAC_MAX_PERFECT_ADDRESSES 32
+
 struct stmmac_desc_ops {
 	/* DMA RX descriptor ring initialization */
 	void (*init_rx_desc) (struct dma_desc *p, int disable_rx_ic, int mode,
@@ -368,34 +370,37 @@ struct stmmac_dma_ops {
 	void (*rx_watchdog) (void __iomem *ioaddr, u32 riwt);
 };
 
+struct mac_device_info;
+
 struct stmmac_ops {
 	/* MAC core initialization */
-	void (*core_init) (void __iomem *ioaddr, int mtu);
+	void (*core_init)(struct mac_device_info *hw, int mtu);
 	/* Enable and verify that the IPC module is supported */
-	int (*rx_ipc) (void __iomem *ioaddr);
+	int (*rx_ipc)(struct mac_device_info *hw);
 	/* Dump MAC registers */
-	void (*dump_regs) (void __iomem *ioaddr);
+	void (*dump_regs)(struct mac_device_info *hw);
 	/* Handle extra events on specific interrupts hw dependent */
-	int (*host_irq_status) (void __iomem *ioaddr,
+	int (*host_irq_status)(struct mac_device_info *hw,
 				struct stmmac_extra_stats *x);
 	/* Multicast filter setting */
-	void (*set_filter) (struct net_device *dev, int id);
+	void (*set_filter)(struct mac_device_info *hw,
+			    struct net_device *dev);
 	/* Flow control setting */
-	void (*flow_ctrl) (void __iomem *ioaddr, unsigned int duplex,
+	void (*flow_ctrl)(struct mac_device_info *hw, unsigned int duplex,
 			   unsigned int fc, unsigned int pause_time);
 	/* Set power management mode (e.g. magic frame) */
-	void (*pmt) (void __iomem *ioaddr, unsigned long mode);
+	void (*pmt)(struct mac_device_info *hw, unsigned long mode);
 	/* Set/Get Unicast MAC addresses */
-	void (*set_umac_addr) (void __iomem *ioaddr, unsigned char *addr,
+	void (*set_umac_addr)(struct mac_device_info *hw, unsigned char *addr,
 			       unsigned int reg_n);
-	void (*get_umac_addr) (void __iomem *ioaddr, unsigned char *addr,
+	void (*get_umac_addr)(struct mac_device_info *hw, unsigned char *addr,
 			       unsigned int reg_n);
-	void (*set_eee_mode) (void __iomem *ioaddr);
-	void (*reset_eee_mode) (void __iomem *ioaddr);
-	void (*set_eee_timer) (void __iomem *ioaddr, int ls, int tw);
-	void (*set_eee_pls) (void __iomem *ioaddr, int link);
-	void (*ctrl_ane) (void __iomem *ioaddr, bool restart);
-	void (*get_adv) (void __iomem *ioaddr, struct rgmii_adv *adv);
+	void (*set_eee_mode)(struct mac_device_info *hw);
+	void (*reset_eee_mode)(struct mac_device_info *hw);
+	void (*set_eee_timer)(struct mac_device_info *hw, int ls, int tw);
+	void (*set_eee_pls)(struct mac_device_info *hw, int link);
+	void (*ctrl_ane)(struct mac_device_info *hw, bool restart);
+	void (*get_adv)(struct mac_device_info *hw, struct rgmii_adv *adv);
 };
 
 struct stmmac_hwtimestamp {
@@ -447,9 +452,14 @@ struct mac_device_info {
 	struct mii_regs mii;	/* MII register Addresses */
 	struct mac_link link;
 	unsigned int synopsys_uid;
+	void __iomem *pcsr;	/* vpointer to device CSRs */
+	int multicast_filter_bins;
+	int unicast_filter_entries;
+	int mcast_bits_log2;
 };
 
-struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr);
+struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr,
+					int mcbins, int perfect_uc_entries);
 struct mac_device_info *dwmac100_setup(void __iomem *ioaddr);
 
 void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
index f37d90f..40b8533 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
@@ -87,7 +87,6 @@ enum power_event {
 				(reg * 8))
 #define GMAC_ADDR_LOW(reg)	(((reg > 15) ? 0x00000804 : 0x00000044) + \
 				(reg * 8))
-#define GMAC_MAX_PERFECT_ADDRESSES	32
 
 /* PCS registers (AN/TBI/SGMII/RGMII) offset */
 #define GMAC_AN_CTRL	0x000000c0	/* AN control */
@@ -130,6 +129,8 @@ enum power_event {
 #define GMAC_CONTROL_2K 0x08000000	/* IEEE 802.3as 2K packets */
 #define GMAC_CONTROL_TC	0x01000000	/* Transmit Conf. in RGMII/SGMII */
 #define GMAC_CONTROL_WD	0x00800000	/* Disable Watchdog on receive */
+
+/* GMAC Configuration defines */
 #define GMAC_CONTROL_JD	0x00400000	/* Jabber disable */
 #define GMAC_CONTROL_BE	0x00200000	/* Frame Burst Enable */
 #define GMAC_CONTROL_JE	0x00100000	/* Jumbo frame */
@@ -262,5 +263,7 @@ enum rtc_control {
 #define GMAC_MMC_TX_INTR   0x108
 #define GMAC_MMC_RX_CSUM_OFFLOAD   0x208
 
+#define GMAC_EXTHASH_BASE  0x500
+
 extern const struct stmmac_dma_ops dwmac1000_dma_ops;
 #endif /* __DWMAC1000_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
index b3e148e..44db9fb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
@@ -26,14 +26,15 @@
   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
 *******************************************************************************/
 
+#include <linux/io.h>
 #include <linux/crc32.h>
-#include <linux/slab.h>
 #include <linux/ethtool.h>
-#include <asm/io.h>
+#include <linux/slab.h>
 #include "dwmac1000.h"
 
-static void dwmac1000_core_init(void __iomem *ioaddr, int mtu)
+static void dwmac1000_core_init(struct mac_device_info *hw, int mtu)
 {
+	void __iomem *ioaddr = hw->pcsr;
 	u32 value = readl(ioaddr + GMAC_CONTROL);
 	value |= GMAC_CORE_INIT;
 	if (mtu > 1500)
@@ -52,8 +53,9 @@ static void dwmac1000_core_init(void __iomem *ioaddr, int mtu)
 #endif
 }
 
-static int dwmac1000_rx_ipc_enable(void __iomem *ioaddr)
+static int dwmac1000_rx_ipc_enable(struct mac_device_info *hw)
 {
+	void __iomem *ioaddr = hw->pcsr;
 	u32 value = readl(ioaddr + GMAC_CONTROL);
 
 	value |= GMAC_CONTROL_IPC;
@@ -64,8 +66,9 @@ static int dwmac1000_rx_ipc_enable(void __iomem *ioaddr)
 	return !!(value & GMAC_CONTROL_IPC);
 }
 
-static void dwmac1000_dump_regs(void __iomem *ioaddr)
+static void dwmac1000_dump_regs(struct mac_device_info *hw)
 {
+	void __iomem *ioaddr = hw->pcsr;
 	int i;
 	pr_info("\tDWMAC1000 regs (base addr = 0x%p)\n", ioaddr);
 
@@ -76,21 +79,113 @@ static void dwmac1000_dump_regs(void __iomem *ioaddr)
 	}
 }
 
-static void dwmac1000_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
+static void dwmac1000_set_umac_addr(struct mac_device_info *hw,
+				    unsigned char *addr,
 				    unsigned int reg_n)
 {
-	stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
+	stmmac_set_mac_addr(hw->pcsr, addr, GMAC_ADDR_HIGH(reg_n),
 			    GMAC_ADDR_LOW(reg_n));
 }
 
-static void dwmac1000_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
+static void dwmac1000_get_umac_addr(struct mac_device_info *hw,
+				    unsigned char *addr,
 				    unsigned int reg_n)
 {
-	stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
+	stmmac_get_mac_addr(hw->pcsr, addr, GMAC_ADDR_HIGH(reg_n),
 			    GMAC_ADDR_LOW(reg_n));
 }
 
-static void dwmac1000_set_filter(struct net_device *dev, int id)
+static void dwmac1000_set_extmchash(void __iomem *ioaddr, u32 *mcfilterbits,
+				    int numhashregs)
+{
+	int regs;
+	for (regs = 0; regs < numhashregs; regs++)
+		writel(mcfilterbits[regs],
+		       ioaddr + GMAC_EXTHASH_BASE + regs * 4);
+}
+
+static void dwmac1000_set_filterex(struct mac_device_info *hw,
+				   struct net_device *dev)
+{
+	void __iomem *ioaddr = (void __iomem *)dev->base_addr;
+	unsigned int value = 0;
+	unsigned int perfect_addr_number;
+	u32 mc_filter[8];
+
+	pr_debug("%s: # mcasts %d, # unicast %d\n", __func__,
+		 netdev_mc_count(dev), netdev_uc_count(dev));
+
+	if (dev->flags & IFF_PROMISC) {
+		value = GMAC_FRAME_FILTER_PR;
+	} else if (dev->flags & IFF_ALLMULTI) {
+		value = GMAC_FRAME_FILTER_PM;	/* pass all multi */
+	} else if (!netdev_mc_empty(dev)) {
+		struct netdev_hw_addr *ha;
+
+		memset(mc_filter, 0, sizeof(mc_filter));
+
+		/* Hash filter for multicast */
+		value = GMAC_FRAME_FILTER_HMC;
+
+		netdev_for_each_mc_addr(ha, dev) {
+			/* The upper n bits of the calculated CRC are used to
+			 * index the contents of the hash table depending
+			 * on the particular core's multicast hash size
+			 * configured through Synopsys Core Consultant
+			 */
+			int bit_nr = bitrev32(~crc32_le(~0, ha->addr,
+					      ETH_ALEN)) >>
+					     (32 - hw->mcast_bits_log2);
+
+			/* The most significant bit determines the register to
+			 * use (H/L) while the other 5 bits determine the bit
+			 * within the register.
+			 */
+			mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+		}
+		if (hw->mcast_bits_log2 == 6) {
+			writel(mc_filter[0], ioaddr + GMAC_HASH_LOW);
+			writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH);
+		} else if (hw->mcast_bits_log2 == 7) {
+			dwmac1000_set_extmchash(ioaddr, mc_filter, 4);
+		} else if (hw->mcast_bits_log2 == 8) {
+			dwmac1000_set_extmchash(ioaddr, mc_filter, 8);
+		} else {
+			pr_debug("STMMAC: err in setting mulitcast filter\n");
+		}
+	}
+
+	/* Extra 16 regs are available in cores newer than the 3.40. */
+	if (hw->synopsys_uid > DWMAC_CORE_3_40)
+		perfect_addr_number = hw->unicast_filter_entries;
+	else
+		perfect_addr_number = hw->unicast_filter_entries / 2;
+
+	/* Handle multiple unicast addresses (perfect filtering) */
+	if (netdev_uc_count(dev) > perfect_addr_number)
+		/* Switch to promiscuous mode if more than 16 addrs
+		 * are required
+		 */
+		value |= GMAC_FRAME_FILTER_PR;
+	else {
+		int reg = 1;
+		struct netdev_hw_addr *ha;
+
+		netdev_for_each_uc_addr(ha, dev) {
+			dwmac1000_set_umac_addr(hw, ha->addr, reg);
+			reg++;
+		}
+	}
+
+#ifdef FRAME_FILTER_DEBUG
+	/* Enable Receive all mode (to debug filtering_fail errors) */
+	value |= GMAC_FRAME_FILTER_RA;
+#endif
+	writel(value, ioaddr + GMAC_FRAME_FILTER);
+}
+
+static void dwmac1000_set_filter(struct mac_device_info *hw,
+				 struct net_device *dev)
 {
 	void __iomem *ioaddr = (void __iomem *)dev->base_addr;
 	unsigned int value = 0;
@@ -130,7 +225,7 @@ static void dwmac1000_set_filter(struct net_device *dev, int id)
 	}
 
 	/* Extra 16 regs are available in cores newer than the 3.40. */
-	if (id > DWMAC_CORE_3_40)
+	if (hw->synopsys_uid > DWMAC_CORE_3_40)
 		perfect_addr_number = GMAC_MAX_PERFECT_ADDRESSES;
 	else
 		perfect_addr_number = GMAC_MAX_PERFECT_ADDRESSES / 2;
@@ -146,7 +241,7 @@ static void dwmac1000_set_filter(struct net_device *dev, int id)
 		struct netdev_hw_addr *ha;
 
 		netdev_for_each_uc_addr(ha, dev) {
-			dwmac1000_set_umac_addr(ioaddr, ha->addr, reg);
+			dwmac1000_set_umac_addr(hw, ha->addr, reg);
 			reg++;
 		}
 	}
@@ -162,9 +257,10 @@ static void dwmac1000_set_filter(struct net_device *dev, int id)
 		 readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW));
 }
 
-static void dwmac1000_flow_ctrl(void __iomem *ioaddr, unsigned int duplex,
+static void dwmac1000_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
 				unsigned int fc, unsigned int pause_time)
 {
+	void __iomem *ioaddr = hw->pcsr;
 	unsigned int flow = 0;
 
 	pr_debug("GMAC Flow-Control:\n");
@@ -185,8 +281,9 @@ static void dwmac1000_flow_ctrl(void __iomem *ioaddr, unsigned int duplex,
 	writel(flow, ioaddr + GMAC_FLOW_CTRL);
 }
 
-static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode)
+static void dwmac1000_pmt(struct mac_device_info *hw, unsigned long mode)
 {
+	void __iomem *ioaddr = hw->pcsr;
 	unsigned int pmt = 0;
 
 	if (mode & WAKE_MAGIC) {
@@ -201,9 +298,10 @@ static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode)
 	writel(pmt, ioaddr + GMAC_PMT);
 }
 
-static int dwmac1000_irq_status(void __iomem *ioaddr,
+static int dwmac1000_irq_status(struct mac_device_info *hw,
 				struct stmmac_extra_stats *x)
 {
+	void __iomem *ioaddr = hw->pcsr;
 	u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
 	int ret = 0;
 
@@ -268,8 +366,9 @@ static int dwmac1000_irq_status(void __iomem *ioaddr,
 	return ret;
 }
 
-static void dwmac1000_set_eee_mode(void __iomem *ioaddr)
+static void dwmac1000_set_eee_mode(struct mac_device_info *hw)
 {
+	void __iomem *ioaddr = hw->pcsr;
 	u32 value;
 
 	/* Enable the link status receive on RGMII, SGMII ore SMII
@@ -281,8 +380,9 @@ static void dwmac1000_set_eee_mode(void __iomem *ioaddr)
 	writel(value, ioaddr + LPI_CTRL_STATUS);
 }
 
-static void dwmac1000_reset_eee_mode(void __iomem *ioaddr)
+static void dwmac1000_reset_eee_mode(struct mac_device_info *hw)
 {
+	void __iomem *ioaddr = hw->pcsr;
 	u32 value;
 
 	value = readl(ioaddr + LPI_CTRL_STATUS);
@@ -290,8 +390,9 @@ static void dwmac1000_reset_eee_mode(void __iomem *ioaddr)
 	writel(value, ioaddr + LPI_CTRL_STATUS);
 }
 
-static void dwmac1000_set_eee_pls(void __iomem *ioaddr, int link)
+static void dwmac1000_set_eee_pls(struct mac_device_info *hw, int link)
 {
+	void __iomem *ioaddr = hw->pcsr;
 	u32 value;
 
 	value = readl(ioaddr + LPI_CTRL_STATUS);
@@ -304,8 +405,9 @@ static void dwmac1000_set_eee_pls(void __iomem *ioaddr, int link)
 	writel(value, ioaddr + LPI_CTRL_STATUS);
 }
 
-static void dwmac1000_set_eee_timer(void __iomem *ioaddr, int ls, int tw)
+static void dwmac1000_set_eee_timer(struct mac_device_info *hw, int ls, int tw)
 {
+	void __iomem *ioaddr = hw->pcsr;
 	int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16);
 
 	/* Program the timers in the LPI timer control register:
@@ -318,8 +420,9 @@ static void dwmac1000_set_eee_timer(void __iomem *ioaddr, int ls, int tw)
 	writel(value, ioaddr + LPI_TIMER_CTRL);
 }
 
-static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool restart)
+static void dwmac1000_ctrl_ane(struct mac_device_info *hw, bool restart)
 {
+	void __iomem *ioaddr = hw->pcsr;
 	u32 value;
 
 	value = readl(ioaddr + GMAC_AN_CTRL);
@@ -332,8 +435,9 @@ static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool restart)
 	writel(value, ioaddr + GMAC_AN_CTRL);
 }
 
-static void dwmac1000_get_adv(void __iomem *ioaddr, struct rgmii_adv *adv)
+static void dwmac1000_get_adv(struct mac_device_info *hw, struct rgmii_adv *adv)
 {
+	void __iomem *ioaddr = hw->pcsr;
 	u32 value = readl(ioaddr + GMAC_ANE_ADV);
 
 	if (value & GMAC_ANE_FD)
@@ -353,7 +457,7 @@ static void dwmac1000_get_adv(void __iomem *ioaddr, struct rgmii_adv *adv)
 	adv->lp_pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT;
 }
 
-static const struct stmmac_ops dwmac1000_ops = {
+static struct stmmac_ops dwmac1000_ops = {
 	.core_init = dwmac1000_core_init,
 	.rx_ipc = dwmac1000_rx_ipc_enable,
 	.dump_regs = dwmac1000_dump_regs,
@@ -371,7 +475,8 @@ static const struct stmmac_ops dwmac1000_ops = {
 	.get_adv = dwmac1000_get_adv,
 };
 
-struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr)
+struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins,
+					int perfect_uc_entries)
 {
 	struct mac_device_info *mac;
 	u32 hwid = readl(ioaddr + GMAC_VERSION);
@@ -380,6 +485,16 @@ struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr)
 	if (!mac)
 		return NULL;
 
+	mac->pcsr = ioaddr;
+	mac->multicast_filter_bins = mcbins;
+	mac->unicast_filter_entries = perfect_uc_entries;
+	mac->mcast_bits_log2 = 0;
+	if (mac->multicast_filter_bins)
+		mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins);
+
+	if (mac->mcast_bits_log2 != 64)
+		dwmac1000_ops.set_filter = dwmac1000_set_filterex;
+
 	mac->mac = &dwmac1000_ops;
 	mac->dma = &dwmac1000_dma_ops;
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
index 2ff767b..3ee3ab5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
@@ -28,12 +28,13 @@
   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
 *******************************************************************************/
 
-#include <linux/crc32.h>
 #include <asm/io.h>
+#include <linux/crc32.h>
 #include "dwmac100.h"
 
-static void dwmac100_core_init(void __iomem *ioaddr, int mtu)
+static void dwmac100_core_init(struct mac_device_info *hw, int mtu)
 {
+	void __iomem *ioaddr = hw->pcsr;
 	u32 value = readl(ioaddr + MAC_CONTROL);
 
 	writel((value | MAC_CORE_INIT), ioaddr + MAC_CONTROL);
@@ -43,8 +44,9 @@ static void dwmac100_core_init(void __iomem *ioaddr, int mtu)
 #endif
 }
 
-static void dwmac100_dump_mac_regs(void __iomem *ioaddr)
+static void dwmac100_dump_mac_regs(struct mac_device_info *hw)
 {
+	void __iomem *ioaddr = hw->pcsr;
 	pr_info("\t----------------------------------------------\n"
 		"\t  DWMAC 100 CSR (base addr = 0x%p)\n"
 		"\t----------------------------------------------\n", ioaddr);
@@ -66,30 +68,35 @@ static void dwmac100_dump_mac_regs(void __iomem *ioaddr)
 		readl(ioaddr + MAC_VLAN2));
 }
 
-static int dwmac100_rx_ipc_enable(void __iomem *ioaddr)
+static int dwmac100_rx_ipc_enable(struct mac_device_info *hw)
 {
 	return 0;
 }
 
-static int dwmac100_irq_status(void __iomem *ioaddr,
+static int dwmac100_irq_status(struct mac_device_info *hw,
 			       struct stmmac_extra_stats *x)
 {
 	return 0;
 }
 
-static void dwmac100_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
+static void dwmac100_set_umac_addr(struct mac_device_info *hw,
+				   unsigned char *addr,
 				   unsigned int reg_n)
 {
+	void __iomem *ioaddr = hw->pcsr;
 	stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
 }
 
-static void dwmac100_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
+static void dwmac100_get_umac_addr(struct mac_device_info *hw,
+				   unsigned char *addr,
 				   unsigned int reg_n)
 {
+	void __iomem *ioaddr = hw->pcsr;
 	stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
 }
 
-static void dwmac100_set_filter(struct net_device *dev, int id)
+static void dwmac100_set_filter(struct mac_device_info *hw,
+				struct net_device *dev)
 {
 	void __iomem *ioaddr = (void __iomem *)dev->base_addr;
 	u32 value = readl(ioaddr + MAC_CONTROL);
@@ -137,9 +144,10 @@ static void dwmac100_set_filter(struct net_device *dev, int id)
 	writel(value, ioaddr + MAC_CONTROL);
 }
 
-static void dwmac100_flow_ctrl(void __iomem *ioaddr, unsigned int duplex,
+static void dwmac100_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,
 			       unsigned int fc, unsigned int pause_time)
 {
+	void __iomem *ioaddr = hw->pcsr;
 	unsigned int flow = MAC_FLOW_CTRL_ENABLE;
 
 	if (duplex)
@@ -148,7 +156,7 @@ static void dwmac100_flow_ctrl(void __iomem *ioaddr, unsigned int duplex,
 }
 
 /* No PMT module supported on ST boards with this Eth chip. */
-static void dwmac100_pmt(void __iomem *ioaddr, unsigned long mode)
+static void dwmac100_pmt(struct mac_device_info *hw, unsigned long mode)
 {
 	return;
 }
@@ -175,6 +183,7 @@ struct mac_device_info *dwmac100_setup(void __iomem *ioaddr)
 
 	pr_info("\tDWMAC100\n");
 
+	mac->pcsr = ioaddr;
 	mac->mac = &dwmac100_ops;
 	mac->dma = &dwmac100_dma_ops;
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index c5f9cb8..e679fa6 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -262,7 +262,7 @@ static int stmmac_ethtool_getsettings(struct net_device *dev,
 
 		/* Get and convert ADV/LP_ADV from the HW AN registers */
 		if (priv->hw->mac->get_adv)
-			priv->hw->mac->get_adv(priv->ioaddr, &adv);
+			priv->hw->mac->get_adv(priv->hw, &adv);
 		else
 			return -EOPNOTSUPP;	/* should never happen indeed */
 
@@ -352,7 +352,7 @@ static int stmmac_ethtool_setsettings(struct net_device *dev,
 
 			spin_lock(&priv->lock);
 			if (priv->hw->mac->ctrl_ane)
-				priv->hw->mac->ctrl_ane(priv->ioaddr, 1);
+				priv->hw->mac->ctrl_ane(priv->hw, 1);
 			spin_unlock(&priv->lock);
 		}
 
@@ -471,7 +471,7 @@ stmmac_set_pauseparam(struct net_device *netdev,
 		if (netif_running(netdev))
 			ret = phy_start_aneg(phy);
 	} else
-		priv->hw->mac->flow_ctrl(priv->ioaddr, phy->duplex,
+		priv->hw->mac->flow_ctrl(priv->hw, phy->duplex,
 					 priv->flow_ctrl, priv->pause);
 	spin_unlock(&priv->lock);
 	return ret;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index d93aa87..aaa14b2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -233,7 +233,7 @@ static void stmmac_enable_eee_mode(struct stmmac_priv *priv)
 	/* Check and enter in LPI mode */
 	if ((priv->dirty_tx == priv->cur_tx) &&
 	    (priv->tx_path_in_lpi_mode == false))
-		priv->hw->mac->set_eee_mode(priv->ioaddr);
+		priv->hw->mac->set_eee_mode(priv->hw);
 }
 
 /**
@@ -244,7 +244,7 @@ static void stmmac_enable_eee_mode(struct stmmac_priv *priv)
  */
 void stmmac_disable_eee_mode(struct stmmac_priv *priv)
 {
-	priv->hw->mac->reset_eee_mode(priv->ioaddr);
+	priv->hw->mac->reset_eee_mode(priv->hw);
 	del_timer_sync(&priv->eee_ctrl_timer);
 	priv->tx_path_in_lpi_mode = false;
 }
@@ -298,12 +298,12 @@ bool stmmac_eee_init(struct stmmac_priv *priv)
 			priv->eee_ctrl_timer.expires = STMMAC_LPI_T(eee_timer);
 			add_timer(&priv->eee_ctrl_timer);
 
-			priv->hw->mac->set_eee_timer(priv->ioaddr,
+			priv->hw->mac->set_eee_timer(priv->hw,
 						     STMMAC_DEFAULT_LIT_LS,
 						     priv->tx_lpi_timer);
 		} else
 			/* Set HW EEE according to the speed */
-			priv->hw->mac->set_eee_pls(priv->ioaddr,
+			priv->hw->mac->set_eee_pls(priv->hw,
 						   priv->phydev->link);
 
 		pr_info("stmmac: Energy-Efficient Ethernet initialized\n");
@@ -678,7 +678,7 @@ static void stmmac_adjust_link(struct net_device *dev)
 		}
 		/* Flow Control operation */
 		if (phydev->pause)
-			priv->hw->mac->flow_ctrl(priv->ioaddr, phydev->duplex,
+			priv->hw->mac->flow_ctrl(priv->hw, phydev->duplex,
 						 fc, pause_time);
 
 		if (phydev->speed != priv->speed) {
@@ -1519,8 +1519,7 @@ static int stmmac_get_hw_features(struct stmmac_priv *priv)
 static void stmmac_check_ether_addr(struct stmmac_priv *priv)
 {
 	if (!is_valid_ether_addr(priv->dev->dev_addr)) {
-		priv->hw->mac->get_umac_addr((void __iomem *)
-					     priv->dev->base_addr,
+		priv->hw->mac->get_umac_addr(priv->hw,
 					     priv->dev->dev_addr, 0);
 		if (!is_valid_ether_addr(priv->dev->dev_addr))
 			eth_hw_addr_random(priv->dev);
@@ -1617,14 +1616,14 @@ static int stmmac_hw_setup(struct net_device *dev)
 	}
 
 	/* Copy the MAC addr into the HW  */
-	priv->hw->mac->set_umac_addr(priv->ioaddr, dev->dev_addr, 0);
+	priv->hw->mac->set_umac_addr(priv->hw, dev->dev_addr, 0);
 
 	/* If required, perform hw setup of the bus. */
 	if (priv->plat->bus_setup)
 		priv->plat->bus_setup(priv->ioaddr);
 
 	/* Initialize the MAC Core */
-	priv->hw->mac->core_init(priv->ioaddr, dev->mtu);
+	priv->hw->mac->core_init(priv->hw, dev->mtu);
 
 	/* Enable the MAC Rx/Tx */
 	stmmac_set_mac(priv->ioaddr, true);
@@ -1650,7 +1649,7 @@ static int stmmac_hw_setup(struct net_device *dev)
 
 	/* Dump DMA/MAC registers */
 	if (netif_msg_hw(priv)) {
-		priv->hw->mac->dump_regs(priv->ioaddr);
+		priv->hw->mac->dump_regs(priv->hw);
 		priv->hw->dma->dump_regs(priv->ioaddr);
 	}
 	priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS;
@@ -1665,7 +1664,7 @@ static int stmmac_hw_setup(struct net_device *dev)
 	}
 
 	if (priv->pcs && priv->hw->mac->ctrl_ane)
-		priv->hw->mac->ctrl_ane(priv->ioaddr, 0);
+		priv->hw->mac->ctrl_ane(priv->hw, 0);
 
 	return 0;
 }
@@ -2244,7 +2243,7 @@ static void stmmac_set_rx_mode(struct net_device *dev)
 	struct stmmac_priv *priv = netdev_priv(dev);
 
 	spin_lock(&priv->lock);
-	priv->hw->mac->set_filter(dev, priv->synopsys_id);
+	priv->hw->mac->set_filter(priv->hw, dev);
 	spin_unlock(&priv->lock);
 }
 
@@ -2334,8 +2333,7 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
 
 	/* To handle GMAC own interrupts */
 	if (priv->plat->has_gmac) {
-		int status = priv->hw->mac->host_irq_status((void __iomem *)
-							    dev->base_addr,
+		int status = priv->hw->mac->host_irq_status(priv->hw,
 							    &priv->xstats);
 		if (unlikely(status)) {
 			/* For LPI we need to save the tx status */
@@ -2619,7 +2617,9 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
 	/* Identify the MAC HW device */
 	if (priv->plat->has_gmac) {
 		priv->dev->priv_flags |= IFF_UNICAST_FLT;
-		mac = dwmac1000_setup(priv->ioaddr);
+		mac = dwmac1000_setup(priv->ioaddr,
+				      priv->plat->multicast_filter_bins,
+				      priv->plat->unicast_filter_entries);
 	} else {
 		mac = dwmac100_setup(priv->ioaddr);
 	}
@@ -2668,7 +2668,7 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
 	/* To use alternate (extended) or normal descriptor structures */
 	stmmac_selec_desc_mode(priv);
 
-	ret = priv->hw->mac->rx_ipc(priv->ioaddr);
+	ret = priv->hw->mac->rx_ipc(priv->hw);
 	if (!ret) {
 		pr_warn(" RX IPC Checksum Offload not configured.\n");
 		priv->plat->rx_coe = STMMAC_RX_COE_NONE;
@@ -2888,7 +2888,7 @@ int stmmac_suspend(struct net_device *ndev)
 
 	/* Enable Power down mode by programming the PMT regs */
 	if (device_may_wakeup(priv->device)) {
-		priv->hw->mac->pmt(priv->ioaddr, priv->wolopts);
+		priv->hw->mac->pmt(priv->hw, priv->wolopts);
 		priv->irq_wake = 1;
 	} else {
 		stmmac_set_mac(priv->ioaddr, false);
@@ -2917,7 +2917,7 @@ int stmmac_resume(struct net_device *ndev)
 	 * from another devices (e.g. serial console).
 	 */
 	if (device_may_wakeup(priv->device)) {
-		priv->hw->mac->pmt(priv->ioaddr, 0);
+		priv->hw->mac->pmt(priv->hw, 0);
 		priv->irq_wake = 0;
 	} else {
 		pinctrl_pm_select_default_state(priv->device);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 5884a7d..4502cde 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -43,6 +43,42 @@ static const struct of_device_id stmmac_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, stmmac_dt_ids);
 
+
+static int stmmac_validate_mcast_bins(int mcast_bins)
+{
+	int x = mcast_bins;
+	switch (x) {
+	case 0:
+	case HASH_TABLE_SIZE:
+	case 128:
+	case 256:
+		break;
+	default:
+		x = HASH_TABLE_SIZE;
+		pr_info("Hash table entries set to unexpected value %d",
+			mcast_bins);
+		break;
+	}
+	return x;
+}
+
+static int stmmac_validate_ucast_entries(int ucast_entries)
+{
+	int x = ucast_entries;
+	switch (x) {
+	case 32:
+	case 64:
+	case 128:
+		break;
+	default:
+		x = 32;
+		pr_info("Unicast table entries set to unexpected value %d\n",
+			ucast_entries);
+		break;
+	}
+	return x;
+}
+
 #ifdef CONFIG_OF
 static int stmmac_probe_config_dt(struct platform_device *pdev,
 				  struct plat_stmmacenet_data *plat,
@@ -107,6 +143,13 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
 	 */
 	plat->maxmtu = JUMBO_LEN;
 
+	/* Set default value for multicast hash bins */
+	plat->multicast_filter_bins = HASH_TABLE_SIZE;
+
+	/* Set default value for unicast filter entries */
+	plat->unicast_filter_entries = GMAC_MAX_PERFECT_ADDRESSES;
+
+
 	/*
 	 * Currently only the properties needed on SPEAr600
 	 * are provided. All other properties should be added
@@ -123,6 +166,14 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
 		 * are clearly MTUs
 		 */
 		of_property_read_u32(np, "max-frame-size", &plat->maxmtu);
+		of_property_read_u32(np, "snps,multicast-filter-bins",
+				     &plat->multicast_filter_bins);
+		of_property_read_u32(np, "snps,perfect-filter-entries",
+				     &plat->unicast_filter_entries);
+		plat->unicast_filter_entries = stmmac_validate_ucast_entries(
+				     plat->unicast_filter_entries);
+		plat->multicast_filter_bins = stmmac_validate_mcast_bins(
+				     plat->multicast_filter_bins);
 		plat->has_gmac = 1;
 		plat->pmt = 1;
 	}
diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
index 6f27d4f..cd63851 100644
--- a/include/linux/stmmac.h
+++ b/include/linux/stmmac.h
@@ -112,6 +112,8 @@ struct plat_stmmacenet_data {
 	int riwt_off;
 	int max_speed;
 	int maxmtu;
+	int multicast_filter_bins;
+	int unicast_filter_entries;
 	void (*fix_mac_speed)(void *priv, unsigned int speed);
 	void (*bus_setup)(void __iomem *ioaddr);
 	void *(*setup)(struct platform_device *pdev);
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH net-next 1/2] dts: Add bindings for multicast hash bins and perfect filter entries
From: Vince Bridgers @ 2014-01-31 20:15 UTC (permalink / raw)
  To: devicetree-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA
  Cc: peppe.cavallaro-qxv4g6HH51o, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	pawel.moll-5wv7dgnIgG8, mark.rutland-5wv7dgnIgG8,
	ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg,
	galak-sgV2jX0FEOL9JmXXK+q4OQ, dinguyen-EIB2kfCEclfQT0dZR+AlfA,
	rayagond-AmucfkJibqKGw+nKnLezzg,
	vbridgers2013-Re5JQEeQqe8AvxtiuMwx3w
In-Reply-To: <1391199356-27226-1-git-send-email-vbridgers2013-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

This change adds bindings for the number of multicast hash bins and perfect
filter entries supported by the Synopsys EMAC. The Synopsys EMAC core is
configurable at device creation time, and can be configured for a different
number of multicast hash bins and a different number of perfect filter entries.
The device does not provide a way to query these parameters, therefore
parameters are required. The Altera Cyclone V SOC has support for 256
multicast hash bins and 128 perfect filter entries, and is different than
what's currently provided in the stmmac driver.

Signed-off-by: Vince Bridgers <vbridgers2013-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 Documentation/devicetree/bindings/net/stmmac.txt |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/net/stmmac.txt b/Documentation/devicetree/bindings/net/stmmac.txt
index 9d92d42..dbf7498 100644
--- a/Documentation/devicetree/bindings/net/stmmac.txt
+++ b/Documentation/devicetree/bindings/net/stmmac.txt
@@ -34,6 +34,10 @@ Optional properties:
 	reset phandle is given
 - max-frame-size:	Maximum Transfer Unit (IEEE defined MTU), rather
 			than the maximum frame size.
+- snps,multicast-filter-bins:	Number of multicast filter hash bins
+				supported by this device instance
+- snps,perfect-filter-entries:	Number of perfect filter entries supported
+				by this device instance
 
 Examples:
 
@@ -46,4 +50,6 @@ Examples:
 		mac-address = [000000000000]; /* Filled in by U-Boot */
 		max-frame-size = <3800>;
 		phy-mode = "gmii";
+		snps,multicast-filter-bins = <256>;
+		snps,perfect-filter-entries = <128>;
 	};
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH net-next 0/2] stmmac: Add extended multicast filtering for
From: Vince Bridgers @ 2014-01-31 20:15 UTC (permalink / raw)
  To: devicetree, netdev
  Cc: peppe.cavallaro, robh+dt, pawel.moll, mark.rutland,
	ijc+devicetree, galak, dinguyen, rayagond, vbridgers2013

These patches add and correct multicast address filtering for the Altera 
Cyclone 5 SOC, and configuration parameters for multicast and perfect
filtering capabilities of a particular Synopsys EMAC. 

Filtering has been put through regression testing for the Altera C5 SOC, 
but not for other implementations. This implementation extends the filter
programming by examining the device characteristics and using either the
current set_multicast function or the new extended function that supports
all possible multicast filter configurations for the Synopsys EMAC. Review
comments are welcome. 

Thanks

Vince Bridgers (2):
  dts: Add bindings for multicast hash bins and perfect filter entries
  stmmac: add extended set multicast filter & devicetree options

 Documentation/devicetree/bindings/net/stmmac.txt   |    6 +
 drivers/net/ethernet/stmicro/stmmac/common.h       |   42 +++--
 drivers/net/ethernet/stmicro/stmmac/dwmac1000.h    |    5 +-
 .../net/ethernet/stmicro/stmmac/dwmac1000_core.c   |  161 +++++++++++++++++---
 .../net/ethernet/stmicro/stmmac/dwmac100_core.c    |   29 ++--
 .../net/ethernet/stmicro/stmmac/stmmac_ethtool.c   |    6 +-
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c  |   36 ++---
 .../net/ethernet/stmicro/stmmac/stmmac_platform.c  |   51 +++++++
 include/linux/stmmac.h                             |    2 +
 9 files changed, 267 insertions(+), 71 deletions(-)

-- 
1.7.9.5

^ permalink raw reply

* Re: [PATCH 1/4] ARM: STi: add stid127 soc support
From: Arnd Bergmann @ 2014-01-31 20:15 UTC (permalink / raw)
  To: srinivas kandagatla
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Russell King,
	kernel-F5mvAk5X5gdBDgjK7y7TUQ, Linus Walleij, Patrice CHOTARD,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Stuart Menefy, Rob Herring,
	Grant Likely, Giuseppe Cavallaro, maxime.coquelin-qxv4g6HH51o,
	alexandre.torgue-qxv4g6HH51o
In-Reply-To: <52EB96BB.6070800-qxv4g6HH51o@public.gmane.org>

On Friday 31 January 2014, srinivas kandagatla wrote:

> > Sorry if I missed the initial review, but can you explain
> > why this is needed to start with?
>
> On ST SoCs the default value for L2 AUX_CTRL register is 0x0, so we  set
> the way-size explicit here.

Unfortunately, we keep going back and forth on the L2 cache controller
setup between "it should work automatically" and "we don't want to
have configuration data in DT", where my personal opinion is that
the first one is more important here.

Now, there are a couple of properties that are defined in
Documentation/devicetree/bindings/arm/l2cc.txt to let some of the
things get set up automatically already. Can you check which bits
are missing there, if any? Are they better described as "configuration"
or "hardware" settings?

	Arnd
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] of: add vendor prefix for Honeywell
From: Olof Johansson @ 2014-01-31 18:53 UTC (permalink / raw)
  To: Marek Belisko
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Rob Landley, devicetree@vger.kernel.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <1390685924-11877-1-git-send-email-marek@goldelico.com>

On Sat, Jan 25, 2014 at 1:38 PM, Marek Belisko <marek@goldelico.com> wrote:
> Signed-off-by: Marek Belisko <marek@goldelico.com>
> ---
>  Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index 3f900cd..b14c617 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -40,6 +40,7 @@ gmt   Global Mixed-mode Technology, Inc.
>  gumstix        Gumstix, Inc.
>  haoyu  Haoyu Microelectronic Co. Ltd.
>  hisilicon      Hisilicon Limited.
> +honeywell      Honeywell

The norm has usually been to use the the stock ticker symbol of a
public company if it is available. In other words, I think the prefix
here should be 'hon', since Honeywell is a publicly traded company
under that ticker.


-Olof

^ permalink raw reply

* Re: [PATCH] dt-bindings: add vendor-prefix for neonode
From: Rob Herring @ 2014-01-31 18:20 UTC (permalink / raw)
  To: Heiko Stübner
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <2809570.RstiYk4HG8@phil>

On Thu, Jan 30, 2014 at 8:18 AM, Heiko Stübner <heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org> wrote:
> From: Heiko Stuebner <heiko.stuebner-HCpLIkUQxWGakBO8gow8eQ@public.gmane.org>
>
> Neonode Inc. is the Manufacturer of the zforce infraread touchscreens
> used in a lot of ebook readers and supported by the zforce_ts driver.
>
> Signed-off-by: Heiko Stuebner <heiko.stuebner-HCpLIkUQxWGakBO8gow8eQ@public.gmane.org>
> ---
> Dmitry, the input maintainer, didn't want to carry the vendor-prefix
> addition [0], therefore add it separately.

Applied.

Rob

>
> [0] http://permalink.gmane.org/gmane.linux.kernel.input/33887
>
>  Documentation/devicetree/bindings/vendor-prefixes.txt |    1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index edbb8d8..32a60a9 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -47,6 +47,7 @@ maxim Maxim Integrated Products
>  microchip      Microchip Technology Inc.
>  mosaixtech     Mosaix Technologies, Inc.
>  national       National Semiconductor
> +neonode                Neonode Inc.
>  nintendo       Nintendo
>  nvidia NVIDIA
>  nxp    NXP Semiconductors
> --
> 1.7.10.4
>
>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] of: add vendor prefix for Allwinner Technology
From: Rob Herring @ 2014-01-31 18:20 UTC (permalink / raw)
  To: Emilio López
  Cc: Rob Herring, Rob Landley, Mark Rutland, Maxime Ripard,
	linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org,
	devicetree@vger.kernel.org
In-Reply-To: <1391045798-7053-1-git-send-email-emilio@elopez.com.ar>

On Wed, Jan 29, 2014 at 7:36 PM, Emilio López <emilio@elopez.com.ar> wrote:
> We have been using the "allwinner" prefix for everything so far; let's
> document it here.
>
> Signed-off-by: Emilio López <emilio@elopez.com.ar>
> ---
>  Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
>  1 file changed, 1 insertion(+)

Applied.

Rob

>
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index edbb8d8..5a2904b 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -7,6 +7,7 @@ ad      Avionic Design GmbH
>  adi    Analog Devices, Inc.
>  aeroflexgaisler        Aeroflex Gaisler AB
>  ak     Asahi Kasei Corp.
> +allwinner      Allwinner Technology Co., Ltd.
>  altr   Altera Corp.
>  amcc   Applied Micro Circuits Corporation (APM, formally AMCC)
>  apm    Applied Micro Circuits Corporation (APM)
> --
> 1.8.5.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] of: add vendor prefix for Honeywell
From: Rob Herring @ 2014-01-31 18:20 UTC (permalink / raw)
  To: Marek Belisko
  Cc: Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Rob Landley, devicetree@vger.kernel.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <1390685924-11877-1-git-send-email-marek@goldelico.com>

On Sat, Jan 25, 2014 at 3:38 PM, Marek Belisko <marek@goldelico.com> wrote:
> Signed-off-by: Marek Belisko <marek@goldelico.com>
> ---
>  Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
>  1 file changed, 1 insertion(+)

Applied.

Rob

>
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
> index 3f900cd..b14c617 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
> @@ -40,6 +40,7 @@ gmt   Global Mixed-mode Technology, Inc.
>  gumstix        Gumstix, Inc.
>  haoyu  Haoyu Microelectronic Co. Ltd.
>  hisilicon      Hisilicon Limited.
> +honeywell      Honeywell
>  hp     Hewlett Packard
>  ibm    International Business Machines (IBM)
>  idt    Integrated Device Technologies, Inc.
> --
> 1.8.3.2
>

^ permalink raw reply

* Re: Extending OPP bindings
From: Lorenzo Pieralisi @ 2014-01-31 18:09 UTC (permalink / raw)
  To: Rob Herring
  Cc: Nishanth Menon, Sudeep Holla, devicetree@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, linux-pm@vger.kernel.org,
	Mark Rutland, Charles Garcia-Tobin, Rob Herring,
	grant.likely@linaro.org, Morten Rasmussen, Shawn Guo,
	mturquette@linaro.org, Mark Brown, Eduardo Valentin
In-Reply-To: <CAL_Jsq+Kq9C39xr9tY8gSX+6QFkNDqwmTyC+dBhLNcxKMweCpw@mail.gmail.com>

Hi Rob,

thanks for having a look.

On Fri, Jan 31, 2014 at 05:17:51PM +0000, Rob Herring wrote:
> On Fri, Jan 31, 2014 at 6:46 AM, Lorenzo Pieralisi
> <lorenzo.pieralisi@arm.com> wrote:
> > Hi Nishanth,
> >
> > On Fri, Jan 31, 2014 at 12:43:54AM +0000, Nishanth Menon wrote:
> >> Hi Sudeep,
> >>
> >> On 01/30/2014 07:43 AM, Sudeep Holla wrote:
> >>
> >> >
> >> > I am looking into a couple shortcomings in the current OPP bindings and
> >> > how to address them. Feel free to add to the list if you think of any more
> >> > issues that needs to be addressed or if and how any problem mentioned below
> >> > can be handled with the existing bindings.
> >> >
> >> > 1. indexing: currently there are no indices in the operating-points.
> >> indexing is based on frequency which is why the accessors use
> >> frequency to pull out the OPP data.
> >>
> >> indexing is a horrible idea - on platforms where OPP may be disabled
> >> or enabled for various reasons(see arch/arm/mach-imx/mach-imx6q.c,
> >> arch/arm/mach-omap2/board-omap3beagle.c etc) - the indexing you see in
> >> dts is just a myth that may not exist once the nodes are loaded and
> >> operated upon depending on SoC variations (example efuse describing
> >> which OPPs can be used and which not).
> >
> > I do not understand why. As long as a mapping from DT to data structures
> > in the kernel is done at boot, I can see how by indexing device nodes
> > can refer to specific OPPs. If they are disabled, amen, as long as we
> > can point at specific operating points that should be ok.
> >
> > Indexing does not mean that the index in the DT is the same as the one
> > allocated by the OS. Indexing is there to point at specific OPPs from
> > different DT nodes, a good example are clock bindings and that's exactly
> > how they work.
> 
> That is not a good comparison. With clocks, you are describing which
> physical signal coming out of a hardware block much like interrupts.
> Granted the h/w is not typically documented that way for clocks
> although the numbering could correspond to register bit locations as
> interrupt numbers do. With OPP indexes, they are a totally made up
> software construct.

Well ok, it might be, what I know is that current OPPs do not allow
other nodes to reference their properties properly, I am not sure that adding
an index make things worse, actually they are already broken as they are.

> Perhaps OPPs should be nodes so new fields can be added easily and
> then you have a phandle for each OPP.

Yeah, but the end result is the same, it has more to do with how to
express dependencies with DT than the question on whether to use a phandle
or an index. If we have to add phandles so be it, it is still just a way
to reference properties for me.

> > Can you provide me with an example where the indexing would go wrong
> > please ?
> 
> Putting s/w indexes into DT. Using cell-index for uarts to define
> their tty number was one example.

The idea was not related to using that index in the kernel at all, but
since you are all against using this mechanism, I think that's for a good
reason so we will not do that. How to do it, it has to be seen though.

> > Certainly relying on implicit ordering is not great either, actually I
> > would say that it is broken.
> >
> >> That said, the original OPP[1][2] series discussion started by trying
> >> to kill indexing precisely for the same reason.. once you have it - it
> >> becomes just crazy to deal with.
> >
> > I could not find any "index killing" :) discussion in there, but I will
> > keep reading.
> >
> >> >     It's assumed that the list is either in ascending or descending
> >> >     order of frequency but not explicit in the binding document.
> >> >     There are arch/arm/boot/dts/* files with opps in both styles.
> >> it should not matter -> opp library should do an insertion sort and
> >> organize it in ascending order once all the data is inserted. (line
> >> 449ish in opp.c)
> >
> > That's OS details and they must not be mandated by the bindings.
> > We cannot rely on word of mouth for things to work, I do not like
> > implicit rules, so the bindings should speficy the ordering or better
> > a way to reference OPPs.
> >
> >> if you see issues with the insertion sort not functioning, it is a bug
> >> and should be easy to track down and fix.
> >
> > Problem is not the insertion sort, problem is that DT bindings do not
> > define a way to refer to a specific OPP, unless we do that implicitly
> > and again, I rest my case, that is broken.
> >
> >> >     Few other bindings like thermal defines bindings like
> >> >     cooling-{min,max}-state assuming some order which is broken IMO.
> >> Now that you bring it up, I missed it :(.. yeah, I might have
> >> preferred it to be min frequency and max_frequency - I agree it is
> >> probably broken. I'd let Eduardo comment more about it.
> >>
> >> >
> >> >     One such use-case that came up recently[0] is the c-state latencies
> >> >     which could be different for each OPP. It would be good if the
> >> >     latencies are specified with the indices to OPP table to avoid
> >> >     inconsistency between the bindings.
> >>
> >> You can define C states based on frequencies as well - which really
> >> makes sense - since that sounds really like our constraint (say
> >> valid-at-frequency "xyz"
> >
> > I do not think that's generic enough, I do not like the idea of looking
> > up frequencies (eg a C-state target_residency does not depend on the
> > frequency only - ie voltage and other factors play a role, it really
> > depends on an operating point- looking it up by frequency is misleading IMO).
> 
> It seems we are trying to fit a square peg into a round hole here.

Do you mean that this is something not worth describing ? That it has to
be described differently ? Or that current DT semantics is not suitable for
describing it ?

We have to find a solution and we are keen on reworking it, otherwise we just
pretend there are no dependencies on the OPPs from other DT nodes, but I
am afraid that's already the case now.

Thank you,
Lorenzo


^ permalink raw reply

* Re: [PATCH] arm: document "mach-virt" platform.
From: Rob Herring @ 2014-01-31 17:48 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: Arnd Bergmann,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	Ian Campbell,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Pawel Moll, Stefano Stabellini, Will Deacon, Rob Herring,
	Kumar Gala, Olof Johansson
In-Reply-To: <52EA8CFE.7020404-5wv7dgnIgG8@public.gmane.org>

On Thu, Jan 30, 2014 at 11:33 AM, Marc Zyngier <marc.zyngier-5wv7dgnIgG8@public.gmane.org> wrote:
> On 30/01/14 17:28, Arnd Bergmann wrote:
>> On Thursday 30 January 2014, Ian Campbell wrote:
>>> mach-virt has existed for a while but it is not written down what it actually
>>> consists of. Although it seems a bit unusual to document a binding for an
>>> entire platform since mach-virt is entirely virtual it is helpful to have
>>> something to refer to in the absence of a single concrete implementation.
>>>
>>> I've done my best to capture the requirements based on the git log and my
>>> memory/understanding.
>>>
>>> While here remove the xenvm dts example, the Xen tools will now build a
>>> suitable mach-virt compatible dts when launching the guest.
>>
>> It might be worth noting in the changeset comment that the 'compatible'
>> string is actually no longer needed on newer kernels: All the members
>> of the machine descriptor are now the defaults (we should remove the
>> virt_init() function as well), and the fallback machine descriptor should
>> work just fine if any other string gets passed.
>
> I will ack the patch that removes the mach-virt directory altogether!

Did I never send that one out? I know I started something. Finding new
employment has had me distracted...

Rob
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v2] dma: Add Xilinx AXI Video Direct Memory Access Engine driver support
From: Andy Gross @ 2014-01-31 17:44 UTC (permalink / raw)
  To: Lars-Peter Clausen
  Cc: Srikanth Thokala, dan.j.williams, vinod.koul, michal.simek,
	Grant Likely, robh+dt, linux-arm-kernel,
	linux-kernel@vger.kernel.org, devicetree, dmaengine
In-Reply-To: <52E2698B.6070001@metafoo.de>

On Fri, Jan 24, 2014 at 02:24:27PM +0100, Lars-Peter Clausen wrote:
> On 01/24/2014 12:16 PM, Srikanth Thokala wrote:
> > Hi Lars,
> > 
> > On Thu, Jan 23, 2014 at 4:55 PM, Lars-Peter Clausen <lars@metafoo.de> wrote:
> >> On 01/22/2014 05:52 PM, Srikanth Thokala wrote:
> >> [...]
> >>> +/**
> >>> + * xilinx_vdma_device_control - Configure DMA channel of the device
> >>> + * @dchan: DMA Channel pointer
> >>> + * @cmd: DMA control command
> >>> + * @arg: Channel configuration
> >>> + *
> >>> + * Return: '0' on success and failure value on error
> >>> + */
> >>> +static int xilinx_vdma_device_control(struct dma_chan *dchan,
> >>> +                                   enum dma_ctrl_cmd cmd, unsigned long arg)
> >>> +{
> >>> +     struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
> >>> +
> >>> +     switch (cmd) {
> >>> +     case DMA_TERMINATE_ALL:
> >>> +             xilinx_vdma_terminate_all(chan);
> >>> +             return 0;
> >>> +     case DMA_SLAVE_CONFIG:
> >>> +             return xilinx_vdma_slave_config(chan,
> >>> +                                     (struct xilinx_vdma_config *)arg);
> >>
> >> You really shouldn't be overloading the generic API with your own semantics.
> >> DMA_SLAVE_CONFIG should take a dma_slave_config and nothing else.
> > 
> > Ok.  The driver needs few additional configuration from the slave
> > device like Vertical
> > Size, Horizontal Size,  Stride etc., for the DMA transfers, in that case do you
> > suggest me to define a separate dma_ctrl_cmd like the one FSLDMA_EXTERNAL_START
> > defined for Freescale drivers?
> 
> In my opinion it is not a good idea to have driver implement a generic API,
> but at the same time let the driver have custom semantics for those API
> calls. It's a bit like having a gpio driver that expects 23 and 42 as the
> values passed to gpio_set_value instead of 0 and 1. It completely defeats
> the purpose of a generic API, namely that you are able to write generic code
> that makes use of the API without having to know about which implementation
> API it is talking to. The dmaengine framework provides the
> dmaengine_prep_interleaved_dma() function to setup two dimensional
> transfers, e.g. take a look at sirf-dma.c or imx-dma.c.
> 

The comments in the include/linux/dmaengine.h state that if you have
non-generic, non-fixed configuration then you can just create your own
structure and embed the dma_slave_config.  Using the container_of you can get
back your structure.

I agree that we should always use the generic structure if possible, but
sometimes there are some non-standard things that you have to do for your
hardware.  I am currently in a bind for adding some quirky features that are
required by peripherals who want to use the QCOM DMA devices.

If the context field in prep_slave_sg and prep_dma_cyclic was exposed to
everyone, that would allow an easy way to pass in hardware specific
configuration without bastardizing the slave_config.  I noticed that rapidio is
the only consumer of that field and that they have their own prep function.

If we are not going to allow people to do their own slave_config when they need
to, then we need to remove the comments from the include file and expose the
context to the dmaengine_prep_slave_sg and dmaengine_prep_dma_cyclic.

-- 
sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply


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