Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp3739152imu; Sun, 11 Nov 2018 22:48:06 -0800 (PST) X-Google-Smtp-Source: AJdET5cpSDnFufF0eLV6U3ZIMJ445BAZA3buwCMR9jn2EMJUF6vGz4vQJicbbQhJ1nx5KPslc7ej X-Received: by 2002:a62:5e83:: with SMTP id s125-v6mr18714540pfb.232.1542005286599; Sun, 11 Nov 2018 22:48:06 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1542005286; cv=none; d=google.com; s=arc-20160816; b=Y64AUJgncJ7YwFQHpjs4pGoyZXtQdYUlMg5+pXXNglGcRzZFgrG3fUk4dj9ckp/akK 5JlSQE9oL06pt9DN4dKt8ubGiUlxNIeyF7To9U3D96btA59fM2jGPhujMjBgrDmR/5nj PYq4oNsiszlAn4KilUiV4lIcnMP98pqAzJIC2REL5N/e2E2V9mzcB9KLA8CzbCY5oQNz VGcR6ymR67SWY4reUHNF1f+3lExjKVmEZmA3nPv6unkpzcuIrdyBikxqMJd4BUJ9ebRa UuTd/Cn1rLxNZWSWBnwkb+2XEtlA+fJ2wuQCk7mXhgwWfBQydbSj9C7cVPvGr2AkTiT2 aXkA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:content-transfer-encoding :spamdiagnosticmetadata:spamdiagnosticoutput:content-language :accept-language:message-id:date:thread-index:thread-topic:subject :cc:to:from:dkim-signature; bh=DtnSiLTLGI14Tyeg46tlv7xeZod8KJB8KyFugn4NMA0=; b=NiZDGZAGAvP5IVPo4T4yxo66puAenM6ss9Yo/vq8kzSSxM/N0KvN3s/GyC1cXALNVY wST0WayyNZ3BpucmRFMtbM4lyCNuTaIHJXJSF/Nbqqav/DuiIWs1CwXINW8q/5aIXysZ nSo7uk+MZpGDnrBhybZOyEpDxnPOQ/AoLIkHEJ4c4L9M6Udu2e9FZcnlV1TTVI/iw5Pb xUyliK4CR7KRetzD7TK3ndzMesIWyilsOS3W+PntQwmvEoaesKc0PDlI3uAAgHp7qD3H UUBaTPaac6HZOPLjfCOth+cV2Mv2nwLpSUSX804usVeNnDNcnts+IwiGHF9TQJ5pMvFo e6Tg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@nxp.com header.s=selector1 header.b=q6GdXtV2; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=nxp.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 62-v6si17922938pfu.2.2018.11.11.22.47.50; Sun, 11 Nov 2018 22:48:06 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@nxp.com header.s=selector1 header.b=q6GdXtV2; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=nxp.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731884AbeKLQjH (ORCPT + 99 others); Mon, 12 Nov 2018 11:39:07 -0500 Received: from mail-eopbgr20070.outbound.protection.outlook.com ([40.107.2.70]:25378 "EHLO EUR02-VE1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1731284AbeKLQjG (ORCPT ); Mon, 12 Nov 2018 11:39:06 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nxp.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=DtnSiLTLGI14Tyeg46tlv7xeZod8KJB8KyFugn4NMA0=; b=q6GdXtV2eWNgzemZgRaIjGpVL1/8EBsR8g6S7sIDI0kp1Lubr0wl7+r6o6mvm9+xJmaF9RyAc8iWqo+e/9vlFRuCKFm1RI35bAS4QFIPqDtLNRtkQ38GpzS3aZSimxGCbqyKuEwOwX8qYhSSMLLFh688e20HnSA/q9USSiHB6IQ= Received: from VI1PR04MB5021.eurprd04.prod.outlook.com (20.177.50.90) by VI1PR04MB5023.eurprd04.prod.outlook.com (20.177.50.92) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.1294.27; Mon, 12 Nov 2018 06:47:08 +0000 Received: from VI1PR04MB5021.eurprd04.prod.outlook.com ([fe80::385c:8780:58f8:d28c]) by VI1PR04MB5021.eurprd04.prod.outlook.com ([fe80::385c:8780:58f8:d28c%4]) with mapi id 15.20.1294.044; Mon, 12 Nov 2018 06:47:08 +0000 From: Clark Wang To: "broonie@kernel.org" CC: "linux-spi@vger.kernel.org" , "linux-kernel@vger.kernel.org" , Clark Wang Subject: [PATCH] spi: lpspi: Add Slave Mode support for LPSPI Thread-Topic: [PATCH] spi: lpspi: Add Slave Mode support for LPSPI Thread-Index: AQHUelOHDMMQcioKBUeu+UtVHpt+bA== Date: Mon, 12 Nov 2018 06:47:08 +0000 Message-ID: <20181112064439.28584-1-xiaoning.wang@nxp.com> Accept-Language: zh-CN, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: SG2PR03CA0096.apcprd03.prod.outlook.com (2603:1096:4:7c::24) To VI1PR04MB5021.eurprd04.prod.outlook.com (2603:10a6:803:59::26) authentication-results: spf=none (sender IP is ) smtp.mailfrom=xiaoning.wang@nxp.com; x-ms-exchange-messagesentrepresentingtype: 1 x-originating-ip: [92.121.68.129] x-ms-publictraffictype: Email x-microsoft-exchange-diagnostics: 1;VI1PR04MB5023;6:0X855ExEBelXGWLmEpFucoxWVRosksYO2EqxheL4B9/ynx0h7V0W8hgEgyfanVtKzd+/zMNRaRaSCDC2txC+/m2fwHOW5XqX3y/cegTkDJVxc6jd7RsaVK5x9lyB5oiCN74KdhqW8ZJkAw6XErbu0eH6kFqvEtF5YzjWydb+ZsNez8x1FWnbLQsdSafxMKsNJ8G2LDqpH4p+98kNKKiJx2K8f2XQjrOz6w36MAlHcyiIFhAnG5t9PEnFkAsJZEJWlyxI/q45Ap2Dvi1SMbS/B8zuv+Iz7z95fBw4iSvViWBxTzfpSswfYO+y7CgDrhzTxuONSsRXLOnfXE0Z3kSS5QJrR/5o75Hhv5/XtR1LesdvfYTZjJy0tpc8MnMzWfyM45rcXJ9ZZndx7AhCi0xQbV8xuTBbfpH5EX0GXWspuzpknd5Kh7XEglP1+FcF8Xv9TaYSmY+MuWQdELo0HxKQ2g==;5:4/xsGm+NR4hCVrclDV7aNfiDK5q0xYS+vRL9auwQFGRJC30746YTo4K1CwgO6f2rUsN+ZUxrzpEGp+RW4qwgmoGb3ikkNF+GfW86PKxLjST+31Jh8qlNYm+gfIhC+61o2oxcz5iM9/F2/NOua+8lIQDfdtQDeSjv1i3W5d4H5gk=;7:YUy7NXMYeacP8s7jWEpoibfvt6fkLa4S9iXE/LoYYf8WV8e1uEECfjvVF48THkSMD2gUFOrFtUyHLzDIP4AOmtFH6bsMvW8aDm6h7VRysDQ65S6S1uML556Xldk30E9jTQYgE1RRzmTZ6Atpo7xhWA== x-ms-office365-filtering-correlation-id: 49e32b00-2c8a-48c5-88cd-08d6486aaa27 x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0;PCL:0;RULEID:(2390040)(7020095)(4652040)(8989299)(5600074)(711020)(4618075)(4534185)(4627221)(201703031133081)(201702281549075)(8990200)(2017052603328)(7153060)(7193020);SRVR:VI1PR04MB5023; x-ms-traffictypediagnostic: VI1PR04MB5023: x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:(185117386973197); x-ms-exchange-senderadcheck: 1 x-exchange-antispam-report-cfa-test: BCL:0;PCL:0;RULEID:(8211001083)(6040522)(2401047)(5005006)(8121501046)(10201501046)(93006095)(93001095)(3231402)(944501410)(52105112)(3002001)(6055026)(148016)(149066)(150057)(6041310)(20161123564045)(20161123562045)(20161123558120)(201703131423095)(201702281528075)(20161123555045)(201703061421075)(201703061406153)(20161123560045)(201708071742011)(7699051)(76991095);SRVR:VI1PR04MB5023;BCL:0;PCL:0;RULEID:;SRVR:VI1PR04MB5023; x-forefront-prvs: 0854128AF0 x-forefront-antispam-report: SFV:NSPM;SFS:(10009020)(346002)(396003)(366004)(136003)(39860400002)(376002)(199004)(189003)(2501003)(25786009)(14444005)(5660300001)(86362001)(256004)(186003)(4326008)(71200400001)(105586002)(106356001)(26005)(8936002)(71190400001)(2351001)(1730700003)(81156014)(386003)(99286004)(6506007)(97736004)(8676002)(81166006)(68736007)(102836004)(6916009)(1857600001)(478600001)(2616005)(6486002)(54906003)(6512007)(5640700003)(7736002)(305945005)(66066001)(2906002)(14454004)(316002)(36756003)(486006)(6116002)(476003)(4744004)(3846002)(6436002)(1076002)(52116002)(2900100001)(53936002);DIR:OUT;SFP:1101;SCL:1;SRVR:VI1PR04MB5023;H:VI1PR04MB5021.eurprd04.prod.outlook.com;FPR:;SPF:None;LANG:en;PTR:InfoNoRecords;A:1;MX:1; received-spf: None (protection.outlook.com: nxp.com does not designate permitted sender hosts) x-microsoft-antispam-message-info: CjvcDm41L2KRErpjDLfHMCqrgYsc1Ub9/nb4YVdFNDbugtPEV8qZhLdYK+7GQdpiGCkRjPm9dqH3Iy4TETD7kpxbSoZUcNhrn0vVBJp+se8wUGYgnaYBHk71aJO++i3m8ZK4+lcGcBVXuD/TEI1oFT2UE87Y6BJ4tyxRFXJb/NNLsLO3ZxQ0wvgO1riOideOUvEhZs37kbnV4G0792ITK6hNqEGQcE7TWywxBewGaa1Ku5JJ9J8fXVHNWXcD5QWhdQLtJ5jCsWVqQtZork7004C1YOAi2YOP7JjgFecFuzu+WSj/wnB4GvJrH3sq53TeNl+mAko7ZVd1Tr2rImG03/TOwdASjP1+681yJd9t+Xg= spamdiagnosticoutput: 1:99 spamdiagnosticmetadata: NSPM Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-Network-Message-Id: 49e32b00-2c8a-48c5-88cd-08d6486aaa27 X-MS-Exchange-CrossTenant-originalarrivaltime: 12 Nov 2018 06:47:08.3308 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR04MB5023 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org i.MX LPSPI controller only works in Master mode previously. This patch adds SPI slave mode support for i.MX7ulp and i.MX8qm/qxp in PIO mode. Currently SPI Slave mode support patch has the following limitations: 1. The stale data in RXFIFO will be dropped when the Slave does any new transfer. 2. One transfer can be finished only after all transfer->len data been transferred to master device 3. Slave device only accepts transfer->len data. Any data longer than this from master device will be dropped. Any data shorter than this from master will cause LPSPI to stuck due to mentioned limitation 2. 4. Only PIO transfer is supported in Slave Mode. Can add "spi-slave;" attribute in spi node of dts file to boot as LPSPI Slave Mode. Wire connection: GND, SCK, MISO(to MISO of slave), MOSI(to MOSI of slave), SCS Signed-off-by: Clark Wang --- drivers/spi/spi-fsl-lpspi.c | 209 ++++++++++++++++++++++++------------ 1 file changed, 139 insertions(+), 70 deletions(-) diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 51670976faa3..86cb38d98a39 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -3,6 +3,7 @@ // Freescale i.MX7ULP LPSPI driver // // Copyright 2016 Freescale Semiconductor, Inc. +// Copyright 2018 NXP =20 #include #include @@ -54,6 +55,7 @@ #define IER_RDIE BIT(1) #define IER_TDIE BIT(0) #define CFGR1_PCSCFG BIT(27) +#define CFGR1_PINCFG (BIT(24)|BIT(25)) #define CFGR1_PCSPOL BIT(8) #define CFGR1_NOSTALL BIT(3) #define CFGR1_MASTER BIT(0) @@ -79,6 +81,7 @@ struct fsl_lpspi_data { struct device *dev; void __iomem *base; struct clk *clk; + bool is_slave; =20 void *rx_buf; const void *tx_buf; @@ -86,11 +89,14 @@ struct fsl_lpspi_data { void (*rx)(struct fsl_lpspi_data *); =20 u32 remain; + u8 watermark; u8 txfifosize; u8 rxfifosize; =20 struct lpspi_config config; struct completion xfer_done; + + bool slave_aborted; }; =20 static const struct of_device_id fsl_lpspi_dt_ids[] =3D { @@ -137,16 +143,18 @@ static void fsl_lpspi_intctrl(struct fsl_lpspi_data *= fsl_lpspi, writel(enable, fsl_lpspi->base + IMX7ULP_IER); } =20 -static int lpspi_prepare_xfer_hardware(struct spi_master *master) +static int lpspi_prepare_xfer_hardware(struct spi_controller *controller) { - struct fsl_lpspi_data *fsl_lpspi =3D spi_master_get_devdata(master); + struct fsl_lpspi_data *fsl_lpspi =3D + spi_controller_get_devdata(controller); =20 return clk_prepare_enable(fsl_lpspi->clk); } =20 -static int lpspi_unprepare_xfer_hardware(struct spi_master *master) +static int lpspi_unprepare_xfer_hardware(struct spi_controller *controller= ) { - struct fsl_lpspi_data *fsl_lpspi =3D spi_master_get_devdata(master); + struct fsl_lpspi_data *fsl_lpspi =3D + spi_controller_get_devdata(controller); =20 clk_disable_unprepare(fsl_lpspi->clk); =20 @@ -202,22 +210,26 @@ static void fsl_lpspi_set_cmd(struct fsl_lpspi_data *= fsl_lpspi, { u32 temp =3D 0; =20 - temp |=3D fsl_lpspi->config.bpw - 1; - temp |=3D fsl_lpspi->config.prescale << 27; - temp |=3D (fsl_lpspi->config.mode & 0x3) << 30; - temp |=3D (fsl_lpspi->config.chip_select & 0x3) << 24; - - /* - * Set TCR_CONT will keep SS asserted after current transfer. - * For the first transfer, clear TCR_CONTC to assert SS. - * For subsequent transfer, set TCR_CONTC to keep SS asserted. - */ - temp |=3D TCR_CONT; - if (is_first_xfer) - temp &=3D ~TCR_CONTC; - else - temp |=3D TCR_CONTC; - + if (!fsl_lpspi->is_slave) { + temp |=3D fsl_lpspi->config.bpw - 1; + temp |=3D fsl_lpspi->config.prescale << 27; + temp |=3D (fsl_lpspi->config.mode & 0x3) << 30; + temp |=3D (fsl_lpspi->config.chip_select & 0x3) << 24; + + /* + * Set TCR_CONT will keep SS asserted after current transfer. + * For the first transfer, clear TCR_CONTC to assert SS. + * For subsequent transfer, set TCR_CONTC to keep SS asserted. + */ + temp |=3D TCR_CONT; + if (is_first_xfer) + temp &=3D ~TCR_CONTC; + else + temp |=3D TCR_CONTC; + } else { + temp |=3D fsl_lpspi->config.bpw - 1; + temp |=3D (fsl_lpspi->config.mode & 0x3) << 30; + } writel(temp, fsl_lpspi->base + IMX7ULP_TCR); =20 dev_dbg(fsl_lpspi->dev, "TCR=3D0x%x\n", temp); @@ -227,7 +239,7 @@ static void fsl_lpspi_set_watermark(struct fsl_lpspi_da= ta *fsl_lpspi) { u32 temp; =20 - temp =3D fsl_lpspi->txfifosize >> 1 | (fsl_lpspi->rxfifosize >> 1) << 16; + temp =3D fsl_lpspi->watermark >> 1 | (fsl_lpspi->watermark >> 1) << 16; =20 writel(temp, fsl_lpspi->base + IMX7ULP_FCR); =20 @@ -253,7 +265,8 @@ static int fsl_lpspi_set_bitrate(struct fsl_lpspi_data = *fsl_lpspi) if (prescale =3D=3D 8 && scldiv >=3D 256) return -EINVAL; =20 - writel(scldiv, fsl_lpspi->base + IMX7ULP_CCR); + writel(scldiv | (scldiv << 8) | ((scldiv >> 1) << 16), + fsl_lpspi->base + IMX7ULP_CCR); =20 dev_dbg(fsl_lpspi->dev, "perclk=3D%d, speed=3D%d, prescale =3D%d, scldiv= =3D%d\n", perclk_rate, config.speed_hz, prescale, scldiv); @@ -270,13 +283,18 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fs= l_lpspi) writel(temp, fsl_lpspi->base + IMX7ULP_CR); writel(0, fsl_lpspi->base + IMX7ULP_CR); =20 - ret =3D fsl_lpspi_set_bitrate(fsl_lpspi); - if (ret) - return ret; + if (!fsl_lpspi->is_slave) { + ret =3D fsl_lpspi_set_bitrate(fsl_lpspi); + if (ret) + return ret; + } =20 fsl_lpspi_set_watermark(fsl_lpspi); =20 - temp =3D CFGR1_PCSCFG | CFGR1_MASTER; + if (!fsl_lpspi->is_slave) + temp =3D CFGR1_MASTER; + else + temp =3D CFGR1_PINCFG; if (fsl_lpspi->config.mode & SPI_CS_HIGH) temp |=3D CFGR1_PCSPOL; writel(temp, fsl_lpspi->base + IMX7ULP_CFGR1); @@ -291,7 +309,8 @@ static int fsl_lpspi_config(struct fsl_lpspi_data *fsl_= lpspi) static void fsl_lpspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) { - struct fsl_lpspi_data *fsl_lpspi =3D spi_master_get_devdata(spi->master); + struct fsl_lpspi_data *fsl_lpspi =3D + spi_controller_get_devdata(spi->controller); =20 fsl_lpspi->config.mode =3D spi->mode; fsl_lpspi->config.bpw =3D t ? t->bits_per_word : spi->bits_per_word; @@ -315,14 +334,51 @@ static void fsl_lpspi_setup_transfer(struct spi_devic= e *spi, fsl_lpspi->tx =3D fsl_lpspi_buf_tx_u32; } =20 + if (t->len <=3D fsl_lpspi->txfifosize) + fsl_lpspi->watermark =3D t->len; + else + fsl_lpspi->watermark =3D fsl_lpspi->txfifosize; + fsl_lpspi_config(fsl_lpspi); } =20 -static int fsl_lpspi_transfer_one(struct spi_master *master, +static int fsl_lpspi_slave_abort(struct spi_controller *controller) +{ + struct fsl_lpspi_data *fsl_lpspi =3D + spi_controller_get_devdata(controller); + + fsl_lpspi->slave_aborted =3D true; + complete(&fsl_lpspi->xfer_done); + return 0; +} + +static int fsl_lpspi_wait_for_completion(struct spi_controller *controller= ) +{ + struct fsl_lpspi_data *fsl_lpspi =3D + spi_controller_get_devdata(controller); + + if (fsl_lpspi->is_slave) { + if (wait_for_completion_interruptible(&fsl_lpspi->xfer_done) || + fsl_lpspi->slave_aborted) { + dev_dbg(fsl_lpspi->dev, "interrupted\n"); + return -EINTR; + } + } else { + if (!wait_for_completion_timeout(&fsl_lpspi->xfer_done, HZ)) { + dev_dbg(fsl_lpspi->dev, "wait for completion timeout\n"); + return -ETIMEDOUT; + } + } + + return 0; +} + +static int fsl_lpspi_transfer_one(struct spi_controller *controller, struct spi_device *spi, struct spi_transfer *t) { - struct fsl_lpspi_data *fsl_lpspi =3D spi_master_get_devdata(master); + struct fsl_lpspi_data *fsl_lpspi =3D + spi_controller_get_devdata(controller); int ret; =20 fsl_lpspi->tx_buf =3D t->tx_buf; @@ -330,13 +386,13 @@ static int fsl_lpspi_transfer_one(struct spi_master *= master, fsl_lpspi->remain =3D t->len; =20 reinit_completion(&fsl_lpspi->xfer_done); + fsl_lpspi->slave_aborted =3D false; + fsl_lpspi_write_tx_fifo(fsl_lpspi); =20 - ret =3D wait_for_completion_timeout(&fsl_lpspi->xfer_done, HZ); - if (!ret) { - dev_dbg(fsl_lpspi->dev, "wait for completion timeout\n"); - return -ETIMEDOUT; - } + ret =3D fsl_lpspi_wait_for_completion(controller); + if (ret) + return ret; =20 ret =3D fsl_lpspi_txfifo_empty(fsl_lpspi); if (ret) @@ -347,10 +403,11 @@ static int fsl_lpspi_transfer_one(struct spi_master *= master, return 0; } =20 -static int fsl_lpspi_transfer_one_msg(struct spi_master *master, +static int fsl_lpspi_transfer_one_msg(struct spi_controller *controller, struct spi_message *msg) { - struct fsl_lpspi_data *fsl_lpspi =3D spi_master_get_devdata(master); + struct fsl_lpspi_data *fsl_lpspi =3D + spi_controller_get_devdata(controller); struct spi_device *spi =3D msg->spi; struct spi_transfer *xfer; bool is_first_xfer =3D true; @@ -366,7 +423,7 @@ static int fsl_lpspi_transfer_one_msg(struct spi_master= *master, =20 is_first_xfer =3D false; =20 - ret =3D fsl_lpspi_transfer_one(master, spi, xfer); + ret =3D fsl_lpspi_transfer_one(controller, spi, xfer); if (ret < 0) goto complete; =20 @@ -374,13 +431,15 @@ static int fsl_lpspi_transfer_one_msg(struct spi_mast= er *master, } =20 complete: - /* de-assert SS, then finalize current message */ - temp =3D readl(fsl_lpspi->base + IMX7ULP_TCR); - temp &=3D ~TCR_CONTC; - writel(temp, fsl_lpspi->base + IMX7ULP_TCR); + if (!fsl_lpspi->is_slave) { + /* de-assert SS, then finalize current message */ + temp =3D readl(fsl_lpspi->base + IMX7ULP_TCR); + temp &=3D ~TCR_CONTC; + writel(temp, fsl_lpspi->base + IMX7ULP_TCR); + } =20 msg->status =3D ret; - spi_finalize_current_message(master); + spi_finalize_current_message(controller); =20 return ret; } @@ -410,30 +469,39 @@ static irqreturn_t fsl_lpspi_isr(int irq, void *dev_i= d) static int fsl_lpspi_probe(struct platform_device *pdev) { struct fsl_lpspi_data *fsl_lpspi; - struct spi_master *master; + struct spi_controller *controller; struct resource *res; int ret, irq; u32 temp; =20 - master =3D spi_alloc_master(&pdev->dev, sizeof(struct fsl_lpspi_data)); - if (!master) + if (of_property_read_bool((&pdev->dev)->of_node, "spi-slave")) + controller =3D spi_alloc_slave(&pdev->dev, + sizeof(struct fsl_lpspi_data)); + else + controller =3D spi_alloc_master(&pdev->dev, + sizeof(struct fsl_lpspi_data)); + + if (!controller) return -ENOMEM; =20 - platform_set_drvdata(pdev, master); + platform_set_drvdata(pdev, controller); =20 - master->bits_per_word_mask =3D SPI_BPW_RANGE_MASK(8, 32); - master->bus_num =3D pdev->id; + controller->bits_per_word_mask =3D SPI_BPW_RANGE_MASK(8, 32); + controller->bus_num =3D pdev->id; =20 - fsl_lpspi =3D spi_master_get_devdata(master); + fsl_lpspi =3D spi_controller_get_devdata(controller); fsl_lpspi->dev =3D &pdev->dev; - - master->transfer_one_message =3D fsl_lpspi_transfer_one_msg; - master->prepare_transfer_hardware =3D lpspi_prepare_xfer_hardware; - master->unprepare_transfer_hardware =3D lpspi_unprepare_xfer_hardware; - master->mode_bits =3D SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; - master->flags =3D SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX; - master->dev.of_node =3D pdev->dev.of_node; - master->bus_num =3D pdev->id; + fsl_lpspi->is_slave =3D of_property_read_bool((&pdev->dev)->of_node, + "spi-slave"); + + controller->transfer_one_message =3D fsl_lpspi_transfer_one_msg; + controller->prepare_transfer_hardware =3D lpspi_prepare_xfer_hardware; + controller->unprepare_transfer_hardware =3D lpspi_unprepare_xfer_hardware= ; + controller->mode_bits =3D SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + controller->flags =3D SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX; + controller->dev.of_node =3D pdev->dev.of_node; + controller->bus_num =3D pdev->id; + controller->slave_abort =3D fsl_lpspi_slave_abort; =20 init_completion(&fsl_lpspi->xfer_done); =20 @@ -441,32 +509,32 @@ static int fsl_lpspi_probe(struct platform_device *pd= ev) fsl_lpspi->base =3D devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(fsl_lpspi->base)) { ret =3D PTR_ERR(fsl_lpspi->base); - goto out_master_put; + goto out_controller_put; } =20 irq =3D platform_get_irq(pdev, 0); if (irq < 0) { ret =3D irq; - goto out_master_put; + goto out_controller_put; } =20 ret =3D devm_request_irq(&pdev->dev, irq, fsl_lpspi_isr, 0, dev_name(&pdev->dev), fsl_lpspi); if (ret) { dev_err(&pdev->dev, "can't get irq%d: %d\n", irq, ret); - goto out_master_put; + goto out_controller_put; } =20 fsl_lpspi->clk =3D devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(fsl_lpspi->clk)) { ret =3D PTR_ERR(fsl_lpspi->clk); - goto out_master_put; + goto out_controller_put; } =20 ret =3D clk_prepare_enable(fsl_lpspi->clk); if (ret) { dev_err(&pdev->dev, "can't enable lpspi clock, ret=3D%d\n", ret); - goto out_master_put; + goto out_controller_put; } =20 temp =3D readl(fsl_lpspi->base + IMX7ULP_PARAM); @@ -475,24 +543,25 @@ static int fsl_lpspi_probe(struct platform_device *pd= ev) =20 clk_disable_unprepare(fsl_lpspi->clk); =20 - ret =3D devm_spi_register_master(&pdev->dev, master); + ret =3D devm_spi_register_controller(&pdev->dev, controller); if (ret < 0) { - dev_err(&pdev->dev, "spi_register_master error.\n"); - goto out_master_put; + dev_err(&pdev->dev, "spi_register_controller error.\n"); + goto out_controller_put; } =20 return 0; =20 -out_master_put: - spi_master_put(master); +out_controller_put: + spi_controller_put(controller); =20 return ret; } =20 static int fsl_lpspi_remove(struct platform_device *pdev) { - struct spi_master *master =3D platform_get_drvdata(pdev); - struct fsl_lpspi_data *fsl_lpspi =3D spi_master_get_devdata(master); + struct spi_controller *controller =3D platform_get_drvdata(pdev); + struct fsl_lpspi_data *fsl_lpspi =3D + spi_controller_get_devdata(controller); =20 clk_disable_unprepare(fsl_lpspi->clk); =20 @@ -509,6 +578,6 @@ static struct platform_driver fsl_lpspi_driver =3D { }; module_platform_driver(fsl_lpspi_driver); =20 -MODULE_DESCRIPTION("LPSPI Master Controller driver"); +MODULE_DESCRIPTION("LPSPI Controller driver"); MODULE_AUTHOR("Gao Pan "); MODULE_LICENSE("GPL"); --=20 2.17.1