get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/955986/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 955986,
    "url": "http://patchwork.ozlabs.org/api/patches/955986/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/20180810060711.6547-41-jagan@amarulasolutions.com/",
    "project": {
        "id": 18,
        "url": "http://patchwork.ozlabs.org/api/projects/18/?format=api",
        "name": "U-Boot",
        "link_name": "uboot",
        "list_id": "u-boot.lists.denx.de",
        "list_email": "u-boot@lists.denx.de",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20180810060711.6547-41-jagan@amarulasolutions.com>",
    "list_archive_url": null,
    "date": "2018-08-10T06:06:58",
    "name": "[U-Boot,v2,40/53] spi: Add Allwinner A31 SPI driver",
    "commit_ref": null,
    "pull_url": null,
    "state": "superseded",
    "archived": false,
    "hash": "9ace3680b3b67b1e72171e94023250789cd665cc",
    "submitter": {
        "id": 69820,
        "url": "http://patchwork.ozlabs.org/api/people/69820/?format=api",
        "name": "Jagan Teki",
        "email": "jagan@amarulasolutions.com"
    },
    "delegate": {
        "id": 17739,
        "url": "http://patchwork.ozlabs.org/api/users/17739/?format=api",
        "username": "jagan",
        "first_name": "Jagannadha Sutradharudu",
        "last_name": "Teki",
        "email": "jagannadh.teki@gmail.com"
    },
    "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/20180810060711.6547-41-jagan@amarulasolutions.com/mbox/",
    "series": [
        {
            "id": 60190,
            "url": "http://patchwork.ozlabs.org/api/series/60190/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/uboot/list/?series=60190",
            "date": "2018-08-10T06:06:18",
            "name": "clk: Add Allwinner CLK, RESET support",
            "version": 2,
            "mbox": "http://patchwork.ozlabs.org/series/60190/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/955986/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/955986/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<u-boot-bounces@lists.denx.de>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org",
        "Authentication-Results": [
            "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=lists.denx.de\n\t(client-ip=81.169.180.215; helo=lists.denx.de;\n\tenvelope-from=u-boot-bounces@lists.denx.de;\n\treceiver=<UNKNOWN>)",
            "ozlabs.org; dmarc=none (p=none dis=none)\n\theader.from=amarulasolutions.com",
            "ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=amarulasolutions.com\n\theader.i=@amarulasolutions.com header.b=\"exFO9D5i\"; \n\tdkim-atps=neutral"
        ],
        "Received": [
            "from lists.denx.de (dione.denx.de [81.169.180.215])\n\tby ozlabs.org (Postfix) with ESMTP id 41mwNH65ppz9s8f\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 10 Aug 2018 16:35:11 +1000 (AEST)",
            "by lists.denx.de (Postfix, from userid 105)\n\tid 944ABC21E4E; Fri, 10 Aug 2018 06:21:10 +0000 (UTC)",
            "from lists.denx.de (localhost [IPv6:::1])\n\tby lists.denx.de (Postfix) with ESMTP id 80178C21E5B;\n\tFri, 10 Aug 2018 06:11:19 +0000 (UTC)",
            "by lists.denx.de (Postfix, from userid 105)\n\tid A0902C21E89; Fri, 10 Aug 2018 06:10:20 +0000 (UTC)",
            "from mail-pf1-f194.google.com (mail-pf1-f194.google.com\n\t[209.85.210.194])\n\tby lists.denx.de (Postfix) with ESMTPS id 1B041C21E5B\n\tfor <u-boot@lists.denx.de>; Fri, 10 Aug 2018 06:10:12 +0000 (UTC)",
            "by mail-pf1-f194.google.com with SMTP id j26-v6so4005759pfi.10\n\tfor <u-boot@lists.denx.de>; Thu, 09 Aug 2018 23:10:12 -0700 (PDT)",
            "from localhost.localdomain ([183.82.228.250])\n\tby smtp.gmail.com with ESMTPSA id\n\tr23-v6sm16880975pfj.5.2018.08.09.23.10.06\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);\n\tThu, 09 Aug 2018 23:10:10 -0700 (PDT)"
        ],
        "X-Spam-Checker-Version": "SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de",
        "X-Spam-Level": "",
        "X-Spam-Status": "No, score=-0.0 required=5.0 tests=RCVD_IN_MSPIKE_H3,\n\tRCVD_IN_MSPIKE_WL,\n\tT_DKIM_INVALID autolearn=unavailable autolearn_force=no\n\tversion=3.4.0",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=amarulasolutions.com; s=google;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references\n\t:mime-version:content-transfer-encoding;\n\tbh=NwPC03ukAqk1drwGUKaVlDl+MSjiYd5U9y11IgDY88Q=;\n\tb=exFO9D5iABkuNFgwITRDZvub5ErnjBtTuhaa3snlrWvyWzErHj6DGUHErl7mh+aLrv\n\tJsCw1sJcWXaDbIS3MuHzgoOLUkTV43SDIyczbpj68FELqhBRKPDjij3pJUTs30RFzrIA\n\tIst6KN/76okGkNXEDSHfkxN2pc94UdGT7GxSc=",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references:mime-version:content-transfer-encoding;\n\tbh=NwPC03ukAqk1drwGUKaVlDl+MSjiYd5U9y11IgDY88Q=;\n\tb=OCorc5oMxIVJgkFuThCsaueQe5kAU1fH0rAivwUlLCnVAJUNsubzeyWdULbzHRXQhV\n\tipaxXxOPLuYszDbdH/EugvV0+XYPP4I6DUM8mPP86vW7PyreYmP4sq2JqpckGSzermEe\n\t4DvjG7xQ4A3PMUoVnOGizM/l6bxBpFgzP2cZyWfA2TcnhcTbh8+CSa21w2o3kLIZNcj3\n\tPsueHH8AQn84dZAJi0fPc1ft9oysGxTLQoBCxTPkqHJoWa2IWPMq22v5nHO8hTXwUXCp\n\tATxLjPSexydcMbvbhTdqFdbH8yL4l4KmxkvZ+85r/8ww8aZQZYThjEFJdyfhdv24iM/2\n\tHeUA==",
        "X-Gm-Message-State": "AOUpUlEfug/cGwjAOPuAf7bzjfu68DhCghcTQPlSivF7jZtn0pLwQUga\n\tf1mtdptKzHb2y3NFlh0rWkFKTQ==",
        "X-Google-Smtp-Source": "AA+uWPxOn9jCfk47D5jn5pPwuvHSeiyj1desDmyZ5xbMwX6pfjq3ZGpJRom7yM9arQ1RT07IiGdOng==",
        "X-Received": "by 2002:a62:444d:: with SMTP id\n\tr74-v6mr5569880pfa.96.1533881410539; \n\tThu, 09 Aug 2018 23:10:10 -0700 (PDT)",
        "From": "Jagan Teki <jagan@amarulasolutions.com>",
        "To": "Maxime Ripard <maxime.ripard@bootlin.com>,\n\tAndre Przywara <andre.przywara@arm.com>, Chen-Yu Tsai <wens@csie.org>,\n\tIcenowy Zheng <icenowy@aosc.io>",
        "Date": "Fri, 10 Aug 2018 11:36:58 +0530",
        "Message-Id": "<20180810060711.6547-41-jagan@amarulasolutions.com>",
        "X-Mailer": "git-send-email 2.18.0.321.gffc6fa0e3",
        "In-Reply-To": "<20180810060711.6547-1-jagan@amarulasolutions.com>",
        "References": "<20180810060711.6547-1-jagan@amarulasolutions.com>",
        "MIME-Version": "1.0",
        "Cc": "Tom Rini <trini@konsulko.com>, Fahad Sadah <fahad@sadah.uk>,\n\tu-boot@lists.denx.de",
        "Subject": "[U-Boot] [PATCH v2 40/53] spi: Add Allwinner A31 SPI driver",
        "X-BeenThere": "u-boot@lists.denx.de",
        "X-Mailman-Version": "2.1.18",
        "Precedence": "list",
        "List-Id": "U-Boot discussion <u-boot.lists.denx.de>",
        "List-Unsubscribe": "<https://lists.denx.de/options/u-boot>,\n\t<mailto:u-boot-request@lists.denx.de?subject=unsubscribe>",
        "List-Archive": "<http://lists.denx.de/pipermail/u-boot/>",
        "List-Post": "<mailto:u-boot@lists.denx.de>",
        "List-Help": "<mailto:u-boot-request@lists.denx.de?subject=help>",
        "List-Subscribe": "<https://lists.denx.de/listinfo/u-boot>,\n\t<mailto:u-boot-request@lists.denx.de?subject=subscribe>",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "base64",
        "Errors-To": "u-boot-bounces@lists.denx.de",
        "Sender": "\"U-Boot\" <u-boot-bounces@lists.denx.de>"
    },
    "content": "Add Allwinner sun6i SPI driver for A31, H3/H5 an A64.\n\nCc: Fahad Sadah <fahad@sadah.uk>\nSigned-off-by: Jagan Teki <jagan@amarulasolutions.com>\n---\n drivers/spi/Kconfig     |   6 +\n drivers/spi/Makefile    |   1 +\n drivers/spi/sun6i_spi.c | 475 ++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 482 insertions(+)\n create mode 100644 drivers/spi/sun6i_spi.c",
    "diff": "diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig\nindex dcd719ff0a..671658dddc 100644\n--- a/drivers/spi/Kconfig\n+++ b/drivers/spi/Kconfig\n@@ -179,6 +179,12 @@ config SUN4I_SPI\n \thelp\n \t  SPI driver for Allwinner sun4i, sun5i and sun7i SoCs\n \n+config SUN6I_SPI\n+\tbool \"Allwinner A31 SPI controller\"\n+\tdepends on ARCH_SUNXI\n+\thelp\n+\t  This enables using the SPI controller on the Allwinner A31 SoCs.\n+\n config TEGRA114_SPI\n \tbool \"nVidia Tegra114 SPI driver\"\n \thelp\ndiff --git a/drivers/spi/Makefile b/drivers/spi/Makefile\nindex 728e30c538..6e60091bc1 100644\n--- a/drivers/spi/Makefile\n+++ b/drivers/spi/Makefile\n@@ -45,6 +45,7 @@ obj-$(CONFIG_SH_SPI) += sh_spi.o\n obj-$(CONFIG_SH_QSPI) += sh_qspi.o\n obj-$(CONFIG_STM32_QSPI) += stm32_qspi.o\n obj-$(CONFIG_SUN4I_SPI) += sun4i_spi.o\n+obj-$(CONFIG_SUN6I_SPI) += sun6i_spi.o\n obj-$(CONFIG_TEGRA114_SPI) += tegra114_spi.o\n obj-$(CONFIG_TEGRA20_SFLASH) += tegra20_sflash.o\n obj-$(CONFIG_TEGRA20_SLINK) += tegra20_slink.o\ndiff --git a/drivers/spi/sun6i_spi.c b/drivers/spi/sun6i_spi.c\nnew file mode 100644\nindex 0000000000..236ed86a25\n--- /dev/null\n+++ b/drivers/spi/sun6i_spi.c\n@@ -0,0 +1,475 @@\n+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)\n+/*\n+ * Copyright (C) 2018 Amarula Solutions.\n+ * Author: Jagan Teki <jagan@amarulasolutions.com>\n+ */\n+\n+#include <common.h>\n+#include <clk.h>\n+#include <dm.h>\n+#include <spi.h>\n+#include <errno.h>\n+#include <fdt_support.h>\n+#include <reset.h>\n+#include <wait_bit.h>\n+\n+#include <asm/bitops.h>\n+#include <asm/gpio.h>\n+#include <asm/io.h>\n+#include <asm/arch/clock.h>\n+\n+DECLARE_GLOBAL_DATA_PTR;\n+\n+#define SUN6I_FIFO_DEPTH\t\t\t128\n+#define SUN8I_FIFO_DEPTH\t\t\t64\n+\n+#define SUN6I_GBL_CTL_BUS_ENABLE\t\tBIT(0)\n+#define SUN6I_GBL_CTL_MASTER\t\t\tBIT(1)\n+#define SUN6I_GBL_CTL_TP\t\t\tBIT(7)\n+#define SUN6I_GBL_CTL_RST\t\t\tBIT(31)\n+\n+#define SUN6I_TFR_CTL_CPHA\t\t\tBIT(0)\n+#define SUN6I_TFR_CTL_CPOL\t\t\tBIT(1)\n+#define SUN6I_TFR_CTL_SPOL\t\t\tBIT(2)\n+#define SUN6I_TFR_CTL_CS_MASK\t\t\t0x30\n+#define SUN6I_TFR_CTL_CS(cs)\t\t\t(((cs) << 4) & SUN6I_TFR_CTL_CS_MASK)\n+#define SUN6I_TFR_CTL_CS_MANUAL\t\t\tBIT(6)\n+#define SUN6I_TFR_CTL_CS_LEVEL\t\t\tBIT(7)\n+#define SUN6I_TFR_CTL_DHB\t\t\tBIT(8)\n+#define SUN6I_TFR_CTL_FBS\t\t\tBIT(12)\n+#define SUN6I_TFR_CTL_XCH_MASK\t\t\t0x80000000\n+#define SUN6I_TFR_CTL_XCH\t\t\tBIT(31)\n+\n+#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_MASK\t0xff\n+#define SUN6I_FIFO_CTL_RF_RDY_TRIG_LEVEL_BITS\t0\n+#define SUN6I_FIFO_CTL_RF_RST\t\t\tBIT(15)\n+#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_MASK\t0xff\n+#define SUN6I_FIFO_CTL_TF_ERQ_TRIG_LEVEL_BITS\t16\n+#define SUN6I_FIFO_CTL_TF_RST\t\t\tBIT(31)\n+\n+#define SUN6I_CLK_CTL_CDR2_MASK\t\t\t0xff\n+#define SUN6I_CLK_CTL_CDR2(div)\t\t\t(((div) & SUN6I_CLK_CTL_CDR2_MASK) << 0)\n+#define SUN6I_CLK_CTL_CDR1_MASK\t\t\t0xf\n+#define SUN6I_CLK_CTL_CDR1(div)\t\t\t(((div) & SUN6I_CLK_CTL_CDR1_MASK) << 8)\n+#define SUN6I_CLK_CTL_DRS\t\t\tBIT(12)\n+\n+#define SUN6I_MAX_XFER_SIZE\t\t\t0xffffff\n+#define SUN6I_BURST_CNT(cnt)\t\t\t((cnt) & SUN6I_MAX_XFER_SIZE)\n+#define SUN6I_XMIT_CNT(cnt)\t\t\t((cnt) & SUN6I_MAX_XFER_SIZE)\n+#define SUN6I_BURST_CTL_CNT_STC(cnt)\t\t((cnt) & SUN6I_MAX_XFER_SIZE)\n+\n+#define SUN6I_SPI_MAX_RATE\t24000000\n+#define SUN6I_SPI_MIN_RATE\t3000\n+#define SUN6I_SPI_DEFAULT_RATE\t1000000\n+#define SUN6I_SPI_TIMEOUT_US\t1000000\n+\n+/* sun6i spi register set */\n+struct sun6i_spi_regs {\n+\tu32 res1;\t/* 0x00 */\n+\tu32 gblctl;\t/* 0x04 */\n+\tu32 tfrctl;\t/* 0x08 */\n+\tu32 res2;\t/* 0x0c */\n+\tu32 intctl;\t/* 0x10 */\n+\tu32 intsta;\t/* 0x14 */\n+\tu32 fifoctl;\t/* 0x18 */\n+\tu32 fifosta;\t/* 0x1c */\n+\tu32 res3;\t/* 0x20 */\n+\tu32 clkctl;\t/* 0x24 */\n+\tu32 res4[2];\t/* 0x28 */\n+\tu32 bc;\t\t/* 0x30 */\n+\tu32 tc;\t\t/* 0x34 */\n+\tu32 bctlc;\t/* 0x38 */\n+\tu32 res5[113];\t/* 0x3c */\n+\tu32 txdata;\t/* 0x200 */\n+\tu32 res6[63];\t/* 0x204 */\n+\tu32 rxdata;\t/* 0x300 */\n+};\n+\n+struct sun6i_spi_platdata {\n+\tu32 base_addr;\n+\tu32 max_hz;\n+};\n+\n+struct sun6i_spi_priv {\n+\tstruct sun6i_spi_regs *regs;\n+\tu32 freq;\n+\tu32 mode;\n+\tu32 fifo_depth;\n+\n+\tconst u8 *tx_buf;\n+\tu8 *rx_buf;\n+};\n+\n+static inline void sun6i_spi_drain_fifo(struct sun6i_spi_priv *priv, int len)\n+{\n+\tu8 byte;\n+\n+\twhile (len--) {\n+\t\tbyte = readb(&priv->regs->rxdata);\n+\t\t*priv->rx_buf++ = byte;\n+\t}\n+}\n+\n+static inline void sun6i_spi_fill_fifo(struct sun6i_spi_priv *priv, int len)\n+{\n+\tu8 byte;\n+\n+\twhile (len--) {\n+\t\tbyte = priv->tx_buf ? *priv->tx_buf++ : 0;\n+\t\twriteb(byte, &priv->regs->txdata);\n+\t}\n+}\n+\n+static void sun6i_spi_set_cs(struct udevice *bus, u8 cs, bool enable)\n+{\n+\tstruct sun6i_spi_priv *priv = dev_get_priv(bus);\n+\tu32 reg;\n+\n+\treg = readl(&priv->regs->tfrctl);\n+\treg &= ~SUN6I_TFR_CTL_CS_MASK;\n+\treg |= SUN6I_TFR_CTL_CS(cs);\n+\n+\tif (enable)\n+\t\treg &= ~SUN6I_TFR_CTL_CS_LEVEL;\n+\telse\n+\t\treg |= SUN6I_TFR_CTL_CS_LEVEL;\n+\n+\twritel(reg, &priv->regs->tfrctl);\n+}\n+\n+static int sun6i_spi_parse_pins(struct udevice *dev)\n+{\n+\tconst void *fdt = gd->fdt_blob;\n+\tconst char *pin_name;\n+\tconst fdt32_t *list;\n+\tu32 phandle;\n+\tint drive, pull = 0, pin, i;\n+\tint offset;\n+\tint size;\n+\n+\tlist = fdt_getprop(fdt, dev_of_offset(dev), \"pinctrl-0\", &size);\n+\tif (!list) {\n+\t\tprintf(\"WARNING: sun6i_spi: cannot find pinctrl-0 node\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\twhile (size) {\n+\t\tphandle = fdt32_to_cpu(*list++);\n+\t\tsize -= sizeof(*list);\n+\n+\t\toffset = fdt_node_offset_by_phandle(fdt, phandle);\n+\t\tif (offset < 0)\n+\t\t\treturn offset;\n+\n+\t\tdrive = fdt_getprop_u32_default_node(fdt, offset, 0,\n+\t\t\t\t\t\t     \"drive-strength\", 0);\n+\t\tif (drive) {\n+\t\t\tif (drive <= 10)\n+\t\t\t\tdrive = 0;\n+\t\t\telse if (drive <= 20)\n+\t\t\t\tdrive = 1;\n+\t\t\telse if (drive <= 30)\n+\t\t\t\tdrive = 2;\n+\t\t\telse\n+\t\t\t\tdrive = 3;\n+\t\t} else {\n+\t\t\tdrive = fdt_getprop_u32_default_node(fdt, offset, 0,\n+\t\t\t\t\t\t\t     \"allwinner,drive\",\n+\t\t\t\t\t\t\t      0);\n+\t\t\tdrive = min(drive, 3);\n+\t\t}\n+\n+\t\tif (fdt_get_property(fdt, offset, \"bias-disable\", NULL))\n+\t\t\tpull = 0;\n+\t\telse if (fdt_get_property(fdt, offset, \"bias-pull-up\", NULL))\n+\t\t\tpull = 1;\n+\t\telse if (fdt_get_property(fdt, offset, \"bias-pull-down\", NULL))\n+\t\t\tpull = 2;\n+\t\telse\n+\t\t\tpull = fdt_getprop_u32_default_node(fdt, offset, 0,\n+\t\t\t\t\t\t\t    \"allwinner,pull\",\n+\t\t\t\t\t\t\t     0);\n+\t\tpull = min(pull, 2);\n+\n+\t\tfor (i = 0; ; i++) {\n+\t\t\tpin_name = fdt_stringlist_get(fdt, offset,\n+\t\t\t\t\t\t      \"pins\", i, NULL);\n+\t\t\tif (!pin_name) {\n+\t\t\t\tpin_name = fdt_stringlist_get(fdt, offset,\n+\t\t\t\t\t\t\t      \"allwinner,pins\",\n+\t\t\t\t\t\t\t       i, NULL);\n+\t\t\t\tif (!pin_name)\n+\t\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t\tpin = name_to_gpio(pin_name);\n+\t\t\tif (pin < 0)\n+\t\t\t\tbreak;\n+\n+\t\t\tsunxi_gpio_set_cfgpin(pin, SUNXI_GPC_SPI0);\n+\t\t\tsunxi_gpio_set_drv(pin, drive);\n+\t\t\tsunxi_gpio_set_pull(pin, pull);\n+\t\t}\n+\t}\n+\treturn 0;\n+}\n+\n+static inline int sun6i_spi_enable_ccu(struct udevice *dev)\n+{\n+\tstruct clk ahb_clk, mod_clk;\n+\tstruct reset_ctl reset;\n+\tint ret;\n+\n+\tret = clk_get_by_name(dev, \"ahb\", &ahb_clk);\n+\tif (ret) {\n+\t\tdev_err(dev, \"failed to get ahb clock\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = clk_get_by_name(dev, \"mod\", &mod_clk);\n+\tif (ret) {\n+\t\tdev_err(dev, \"failed to get mod clock\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = reset_get_by_index(dev, 0, &reset);\n+\tif (ret) {\n+\t\tdev_err(dev, \"failed to get reset\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = clk_enable(&ahb_clk);\n+\tif (ret) {\n+\t\tdev_err(dev, \"failed to enable ahb clock\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = clk_enable(&mod_clk);\n+\tif (ret) {\n+\t\tdev_err(dev, \"failed to enable mod clock\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = reset_deassert(&reset);\n+\tif (ret) {\n+\t\tdev_err(dev, \"failed to deassert reset\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int sun6i_spi_ofdata_to_platdata(struct udevice *bus)\n+{\n+\tstruct sun6i_spi_platdata *plat = dev_get_platdata(bus);\n+\tint node = dev_of_offset(bus);\n+\n+\tplat->base_addr = devfdt_get_addr(bus);\n+\tplat->max_hz = fdtdec_get_int(gd->fdt_blob, node,\n+\t\t\t\t      \"spi-max-frequency\",\n+\t\t\t\t      SUN6I_SPI_DEFAULT_RATE);\n+\n+\tif (plat->max_hz > SUN6I_SPI_MAX_RATE)\n+\t\tplat->max_hz = SUN6I_SPI_MAX_RATE;\n+\n+\treturn 0;\n+}\n+\n+static int sun6i_spi_probe(struct udevice *bus)\n+{\n+\tstruct sun6i_spi_platdata *plat = dev_get_platdata(bus);\n+\tstruct sun6i_spi_priv *priv = dev_get_priv(bus);\n+\tint ret;\n+\n+\tret = sun6i_spi_enable_ccu(bus);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tsun6i_spi_parse_pins(bus);\n+\n+\tpriv->regs = (struct sun6i_spi_regs *)(uintptr_t)plat->base_addr;\n+\tpriv->freq = plat->max_hz;\n+\tpriv->fifo_depth = dev_get_driver_data(bus);\n+\n+\treturn 0;\n+}\n+\n+static int sun6i_spi_claim_bus(struct udevice *dev)\n+{\n+\tstruct sun6i_spi_priv *priv = dev_get_priv(dev->parent);\n+\n+\twritel(SUN6I_GBL_CTL_BUS_ENABLE | SUN6I_GBL_CTL_MASTER |\n+\t       SUN6I_GBL_CTL_TP, &priv->regs->gblctl);\n+\twritel(SUN6I_TFR_CTL_CS_MANUAL, &priv->regs->tfrctl);\n+\n+\treturn 0;\n+}\n+\n+static int sun6i_spi_release_bus(struct udevice *dev)\n+{\n+\tstruct sun6i_spi_priv *priv = dev_get_priv(dev->parent);\n+\tu32 reg;\n+\n+\treg = readl(&priv->regs->gblctl);\n+\treg &= ~SUN6I_GBL_CTL_BUS_ENABLE;\n+\twritel(reg, &priv->regs->gblctl);\n+\n+\treturn 0;\n+}\n+\n+static int sun6i_spi_xfer(struct udevice *dev, unsigned int bitlen,\n+\t\t\t  const void *dout, void *din, unsigned long flags)\n+{\n+\tstruct udevice *bus = dev->parent;\n+\tstruct sun6i_spi_priv *priv = dev_get_priv(bus);\n+\tstruct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev);\n+\n+\tu32 len = bitlen / 8;\n+\tu32 reg;\n+\tu8 nbytes;\n+\tint ret;\n+\n+\tpriv->tx_buf = dout;\n+\tpriv->rx_buf = din;\n+\n+\tif (bitlen % 8) {\n+\t\tdebug(\"%s: non byte-aligned SPI transfer.\\n\", __func__);\n+\t\treturn -ENAVAIL;\n+\t}\n+\n+\tif (flags & SPI_XFER_BEGIN)\n+\t\tsun6i_spi_set_cs(bus, slave_plat->cs, true);\n+\n+\t/* Reset FIFOs */\n+\twritel(SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST,\n+\t       &priv->regs->fifoctl);\n+\n+\twhile (len) {\n+\t\t/* Setup the transfer now... */\n+\t\tnbytes = min(len, priv->fifo_depth);\n+\n+\t\t/* Setup the counters */\n+\t\twritel(SUN6I_BURST_CNT(nbytes), &priv->regs->bc);\n+\t\twritel(SUN6I_XMIT_CNT(nbytes), &priv->regs->tc);\n+\t\twritel(SUN6I_BURST_CTL_CNT_STC(nbytes), &priv->regs->bctlc);\n+\n+\t\t/* Fill the TX FIFO */\n+\t\tsun6i_spi_fill_fifo(priv, nbytes);\n+\n+\t\t/* Start the transfer */\n+\t\treg = readl(&priv->regs->tfrctl);\n+\t\twritel(reg | SUN6I_TFR_CTL_XCH, &priv->regs->tfrctl);\n+\n+\t\t/* Wait transfer to complete */\n+\t\tret = wait_for_bit_le32(&priv->regs->tfrctl,\n+\t\t\t\t\tSUN6I_TFR_CTL_XCH_MASK, false,\n+\t\t\t\t\tSUN6I_SPI_TIMEOUT_US, false);\n+\t\tif (ret) {\n+\t\t\tprintf(\"ERROR: sun6i_spi: Timeout transferring data\\n\");\n+\t\t\tsun6i_spi_set_cs(bus, slave_plat->cs, false);\n+\t\t\treturn ret;\n+\t\t}\n+\n+\t\t/* Drain the RX FIFO */\n+\t\tsun6i_spi_drain_fifo(priv, nbytes);\n+\n+\t\tlen -= nbytes;\n+\t}\n+\n+\tif (flags & SPI_XFER_END)\n+\t\tsun6i_spi_set_cs(bus, slave_plat->cs, false);\n+\n+\treturn 0;\n+}\n+\n+static int sun6i_spi_set_speed(struct udevice *dev, uint speed)\n+{\n+\tstruct sun6i_spi_platdata *plat = dev_get_platdata(dev);\n+\tstruct sun6i_spi_priv *priv = dev_get_priv(dev);\n+\tunsigned int div;\n+\tu32 reg;\n+\n+\tif (speed > plat->max_hz)\n+\t\tspeed = plat->max_hz;\n+\n+\tif (speed < SUN6I_SPI_MIN_RATE)\n+\t\tspeed = SUN6I_SPI_MIN_RATE;\n+\n+\t/*\n+\t * Setup clock divider.\n+\t *\n+\t * We have two choices there. Either we can use the clock\n+\t * divide rate 1, which is calculated thanks to this formula:\n+\t * SPI_CLK = MOD_CLK / (2 ^ cdr)\n+\t * Or we can use CDR2, which is calculated with the formula:\n+\t * SPI_CLK = MOD_CLK / (2 * (cdr + 1))\n+\t * Whether we use the former or the latter is set through the\n+\t * DRS bit.\n+\t *\n+\t * First try CDR2, and if we can't reach the expected\n+\t * frequency, fall back to CDR1.\n+\t */\n+\treg = readl(&priv->regs->clkctl);\n+\tdiv = SUN6I_SPI_MAX_RATE / (2 * speed);\n+\tif (div <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {\n+\t\tif (div > 0)\n+\t\t\tdiv--;\n+\n+\t\treg |= SUN6I_CLK_CTL_CDR2(div) | SUN6I_CLK_CTL_DRS;\n+\t} else {\n+\t\tdiv = __ilog2(SUN6I_SPI_MAX_RATE) - __ilog2(speed);\n+\t\treg |= SUN6I_CLK_CTL_CDR1(div);\n+\t}\n+\n+\twritel(reg, &priv->regs->clkctl);\n+\tpriv->freq = speed;\n+\n+\treturn 0;\n+}\n+\n+static int sun6i_spi_set_mode(struct udevice *dev, uint mode)\n+{\n+\tstruct sun6i_spi_priv *priv = dev_get_priv(dev);\n+\tu32 reg;\n+\n+\treg = readl(&priv->regs->tfrctl);\n+\treg &= ~(SUN6I_TFR_CTL_CPOL | SUN6I_TFR_CTL_CPHA);\n+\n+\tif (mode & SPI_CPOL)\n+\t\treg |= SUN6I_TFR_CTL_CPOL;\n+\n+\tif (mode & SPI_CPHA)\n+\t\treg |= SUN6I_TFR_CTL_CPHA;\n+\n+\tpriv->mode = mode;\n+\twritel(reg, &priv->regs->tfrctl);\n+\n+\treturn 0;\n+}\n+\n+static const struct dm_spi_ops sun6i_spi_ops = {\n+\t.claim_bus\t\t= sun6i_spi_claim_bus,\n+\t.release_bus\t\t= sun6i_spi_release_bus,\n+\t.xfer\t\t\t= sun6i_spi_xfer,\n+\t.set_speed\t\t= sun6i_spi_set_speed,\n+\t.set_mode\t\t= sun6i_spi_set_mode,\n+};\n+\n+static const struct udevice_id sun6i_spi_ids[] = {\n+\t{ .compatible = \"allwinner,sun6i-a31-spi\",\n+\t  .data = SUN6I_FIFO_DEPTH },\n+\t{ .compatible = \"allwinner,sun8i-h3-spi\",\n+\t  .data = SUN8I_FIFO_DEPTH },\n+\t{ }\n+};\n+\n+U_BOOT_DRIVER(sun6i_spi) = {\n+\t.name\t= \"sun6i_spi\",\n+\t.id\t= UCLASS_SPI,\n+\t.of_match\t= sun6i_spi_ids,\n+\t.ops\t= &sun6i_spi_ops,\n+\t.ofdata_to_platdata\t= sun6i_spi_ofdata_to_platdata,\n+\t.platdata_auto_alloc_size\t= sizeof(struct sun6i_spi_platdata),\n+\t.priv_auto_alloc_size\t= sizeof(struct sun6i_spi_priv),\n+\t.probe\t= sun6i_spi_probe,\n+};\n",
    "prefixes": [
        "U-Boot",
        "v2",
        "40/53"
    ]
}