From patchwork Wed Jan 9 17:31:09 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lars-Peter Clausen X-Patchwork-Id: 1953731 Return-Path: X-Original-To: patchwork-spi-devel-general@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from lists.sourceforge.net (lists.sourceforge.net [216.34.181.88]) by patchwork2.kernel.org (Postfix) with ESMTP id 161C7E007B for ; Wed, 9 Jan 2013 17:30:43 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=sfs-ml-2.v29.ch3.sourceforge.com) by sfs-ml-2.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1TszU9-00015p-ST; Wed, 09 Jan 2013 17:30:41 +0000 Received: from sog-mx-2.v43.ch3.sourceforge.com ([172.29.43.192] helo=mx.sourceforge.net) by sfs-ml-2.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1TszU7-00015X-SR for spi-devel-general@lists.sourceforge.net; Wed, 09 Jan 2013 17:30:39 +0000 X-ACL-Warn: Received: from smtp-out-052.synserver.de ([212.40.185.52]) by sog-mx-2.v43.ch3.sourceforge.com with esmtp (Exim 4.76) id 1TszU5-00044j-Gl for spi-devel-general@lists.sourceforge.net; Wed, 09 Jan 2013 17:30:39 +0000 Received: (qmail 5520 invoked by uid 0); 9 Jan 2013 17:30:29 -0000 X-SynServer-TrustedSrc: 1 X-SynServer-AuthUser: lars@metafoo.de X-SynServer-PPID: 5469 Received: from eisbaer.ursus-maritimus.org (HELO lars-adi-laptop.analog.com) [78.47.220.141] by 217.119.54.87 with SMTP; 9 Jan 2013 17:30:29 -0000 From: Lars-Peter Clausen To: Grant Likely Subject: [PATCH 1/3] spi: Add helper functions for setting up transfers Date: Wed, 9 Jan 2013 18:31:09 +0100 Message-Id: <1357752671-30222-1-git-send-email-lars@metafoo.de> X-Mailer: git-send-email 1.8.0 X-Spam-Score: 0.0 (/) X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [212.40.185.52 listed in list.dnswl.org] X-Headers-End: 1TszU5-00044j-Gl Cc: Lars-Peter Clausen , linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, Julia Lawall , Jonathan Cameron , spi-devel-general@lists.sourceforge.net X-BeenThere: spi-devel-general@lists.sourceforge.net X-Mailman-Version: 2.1.9 Precedence: list List-Id: Linux SPI core/device drivers discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: spi-devel-general-bounces@lists.sourceforge.net Quite often the pattern used for setting up and transferring a synchronous SPI transaction looks very much like the following: struct spi_message msg; struct spi_transfer xfers[] = { ... }; spi_message_init(&msg); spi_message_add_tail(&xfers[0], &msg); ... spi_message_add_tail(&xfers[ARRAY_SIZE(xfers) - 1], &msg); ret = spi_sync(&msg); This patch adds two new helper functions for handling this case. The first helper function spi_message_init_with_transfers() takes a spi_message and an array of spi_transfers. It will initialize the message and then call spi_message_add_tail() for each transfer in the array. E.g. the following spi_message_init(&msg); spi_message_add_tail(&xfers[0], &msg); ... spi_message_add_tail(&xfers[ARRAY_SIZE(xfers) - 1], &msg); can be rewritten as spi_message_init_with_transfers(&msg, xfers, ARRAY_SIZE(xfers)); The second function spi_sync_transfer() takes a SPI device and an array of spi_transfers. It will allocate a new spi_message (on the stack) and add all transfers in the array to the message. Finally it will call spi_sync() on the message. E.g. the follwing struct spi_message msg; struct spi_transfer xfers[] = { ... }; spi_message_init(&msg); spi_message_add_tail(&xfers[0], &msg); ... spi_message_add_tail(&xfers[ARRAY_SIZE(xfers) - 1], &msg); ret = spi_sync(spi, &msg); can be rewritten as struct spi_transfer xfers[] = { ... }; ret = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers)); The patch also adds a new cocci script which can detect such sequences as described above and transform them automatically to use the new helper functions. Signed-off-by: Lars-Peter Clausen Acked-by: Jonathan Cameron Reviewed-by: Mark Brown --- I'm not entirely happy with names of the two new functions and I'm open for better suggestions. --- include/linux/spi/spi.h | 44 ++++++++ scripts/coccinelle/api/spi_sync_transfer.cocci | 141 +++++++++++++++++++++++++ 2 files changed, 185 insertions(+) create mode 100644 scripts/coccinelle/api/spi_sync_transfer.cocci diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index f629189..7dbe586 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -591,6 +591,26 @@ spi_transfer_del(struct spi_transfer *t) list_del(&t->transfer_list); } +/** + * spi_message_init_with_transfers - Initialize spi_message and append transfers + * @m: spi_message to be initialized + * @xfers: An array of spi transfers + * @num_xfers: Number of items in the xfer array + * + * This function initializes the given spi_message and adds each spi_transfer in + * the given array to the message. + */ +static inline void +spi_message_init_with_transfers(struct spi_message *m, +struct spi_transfer *xfers, unsigned int num_xfers) +{ + unsigned int i; + + spi_message_init(m); + for (i = 0; i < num_xfers; ++i) + spi_message_add_tail(&xfers[i], m); +} + /* It's fine to embed message and transaction structures in other data * structures so long as you don't free them while they're in use. */ @@ -683,6 +703,30 @@ spi_read(struct spi_device *spi, void *buf, size_t len) return spi_sync(spi, &m); } +/** + * spi_sync_transfer - synchronous SPI data transfer + * @spi: device with which data will be exchanged + * @xfers: An array of spi_transfers + * @num_xfers: Number of items in the xfer array + * Context: can sleep + * + * Does a synchronous SPI data transfer of the given spi_transfer array. + * + * For more specific semantics see spi_sync(). + * + * It returns zero on success, else a negative error code. + */ +static inline int +spi_sync_transfer(struct spi_device *spi, struct spi_transfer *xfers, + unsigned int num_xfers) +{ + struct spi_message msg; + + spi_message_init_with_transfers(&msg, xfers, num_xfers); + + return spi_sync(spi, &msg); +} + /* this copies txbuf and rxbuf data; for small transfers only! */ extern int spi_write_then_read(struct spi_device *spi, const void *txbuf, unsigned n_tx, diff --git a/scripts/coccinelle/api/spi_sync_transfer.cocci b/scripts/coccinelle/api/spi_sync_transfer.cocci new file mode 100644 index 0000000..1e2efe3 --- /dev/null +++ b/scripts/coccinelle/api/spi_sync_transfer.cocci @@ -0,0 +1,141 @@ +/// +/// Use spi_sync_transfer instead of open-coding it +/// +// Confidence: High +// Options: --no-includes +// +// Keywords: spi_sync, spi_sync_transfer +// Version min: 3.9 +// + +virtual context +virtual patch +virtual org +virtual report + +@r1@ +identifier fn; +identifier xfers; +@@ +fn(...) +{ + ... +( + struct spi_transfer xfers[...]; +| + struct spi_transfer xfers[]; +) + ... +} + +@depends on patch@ +identifier msg; +expression spi; +identifier r1.fn; +identifier r1.xfers; +@@ +fn(...) +{ +... +-struct spi_message msg; +... +-spi_message_init(&msg); +<... +-spi_message_add_tail(&xfers[...], &msg); +...> + +-spi_sync(spi, &msg) ++spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers)) +... +} + +@r3 depends on context || org || report@ +identifier msg; +expression spi; +identifier r1.xfers; +identifier r1.fn; +position p; +@@ +fn(...) +{ +... +*struct spi_message msg; +... +*spi_message_init(&msg); +<... +*spi_message_add_tail(&xfers[...], &msg); +...> +*spi_sync@p(spi, &msg) +... +} + +@r2@ +identifier fn; +identifier xfer; +@@ +fn(...) +{ + ... + struct spi_transfer xfer; + ... +} + +@depends on patch@ +identifier msg; +expression spi; +identifier r2.xfer; +identifier r2.fn; +@@ +fn(...) +{ +... +-struct spi_message msg; +... +-spi_message_init(&msg); +... +-spi_message_add_tail(&xfer, &msg); +... +-spi_sync(spi, &msg) ++spi_sync_transfer(spi, &xfer, 1) +... +} + +@r4 depends on context || org || report@ +identifier msg; +expression spi; +identifier r2.xfer; +identifier r2.fn; +position p; +@@ +fn(...) +{ +... +*struct spi_message msg; +... +*spi_message_init(&msg); +... +*spi_message_add_tail(&xfer, &msg); +... +*spi_sync@p(spi, &msg) +... +} + +@script:python depends on report@ +p << r3.p; +@@ +coccilib.report.print_report(p[0], "Consider using spi_sync_transfer instead of open-conding it.") + +@script:python depends on report@ +p << r4.p; +@@ +coccilib.report.print_report(p[0], "Consider using spi_sync_transfer instead of open-conding it.") + +@script:python depends on org@ +p << r3.p; +@@ +coccilib.org.print_todo(p[0], "Consider using spi_sync_transfer instead of open-conding it.") + +@script:python depends on org@ +p << r4.p; +@@ +coccilib.org.print_todo(p[0], "Consider using spi_sync_transfer instead of open-conding it.")