Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/808554/?format=api
{ "id": 808554, "url": "http://patchwork.ozlabs.org/api/patches/808554/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-i2c/patch/1504251255-20469-4-git-send-email-pierre-yves.mordret@st.com/", "project": { "id": 35, "url": "http://patchwork.ozlabs.org/api/projects/35/?format=api", "name": "Linux I2C development", "link_name": "linux-i2c", "list_id": "linux-i2c.vger.kernel.org", "list_email": "linux-i2c@vger.kernel.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<1504251255-20469-4-git-send-email-pierre-yves.mordret@st.com>", "list_archive_url": null, "date": "2017-09-01T07:34:13", "name": "[RESEND,v3,3/5] i2c: i2c-stm32f7: add driver", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": false, "hash": "f37832b899866c0703ffa17dd3e182ac94ba542e", "submitter": { "id": 71499, "url": "http://patchwork.ozlabs.org/api/people/71499/?format=api", "name": "Pierre Yves MORDRET", "email": "pierre-yves.mordret@st.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linux-i2c/patch/1504251255-20469-4-git-send-email-pierre-yves.mordret@st.com/mbox/", "series": [ { "id": 965, "url": "http://patchwork.ozlabs.org/api/series/965/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-i2c/list/?series=965", "date": "2017-09-01T07:34:11", "name": "Add support for the STM32F7 I2C", "version": 3, "mbox": "http://patchwork.ozlabs.org/series/965/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/808554/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/808554/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<linux-i2c-owner@vger.kernel.org>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org", "Authentication-Results": "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=linux-i2c-owner@vger.kernel.org;\n\treceiver=<UNKNOWN>)", "Received": [ "from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3xk9yq6jw8z9s81\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 1 Sep 2017 17:36:03 +1000 (AEST)", "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1751736AbdIAHfp (ORCPT <rfc822;incoming@patchwork.ozlabs.org>);\n\tFri, 1 Sep 2017 03:35:45 -0400", "from mx08-00178001.pphosted.com ([91.207.212.93]:51079 \"EHLO\n\tmx07-00178001.pphosted.com\" rhost-flags-OK-OK-OK-FAIL)\n\tby vger.kernel.org with ESMTP id S1751330AbdIAHfm (ORCPT\n\t<rfc822;linux-i2c@vger.kernel.org>); Fri, 1 Sep 2017 03:35:42 -0400", "from pps.filterd (m0046660.ppops.net [127.0.0.1])\n\tby mx08-.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id\n\tv817YBXY017889; Fri, 1 Sep 2017 09:34:33 +0200", "from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35])\n\tby mx08-00178001.pphosted.com with ESMTP id 2cq184gtbh-1\n\t(version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT);\n\tFri, 01 Sep 2017 09:34:33 +0200", "from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9])\n\tby beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 9C04E31;\n\tFri, 1 Sep 2017 07:34:32 +0000 (GMT)", "from Webmail-eu.st.com (sfhdag5node2.st.com [10.75.127.14])\n\tby zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 42D3711E8;\n\tFri, 1 Sep 2017 07:34:32 +0000 (GMT)", "from localhost (10.75.127.49) by SFHDAG5NODE2.st.com (10.75.127.14)\n\twith Microsoft SMTP Server (TLS) id 15.0.1178.4;\n\tFri, 1 Sep 2017 09:34:31 +0200" ], "From": "Pierre-Yves MORDRET <pierre-yves.mordret@st.com>", "To": "Wolfram Sang <wsa@the-dreams.de>, Rob Herring <robh+dt@kernel.org>,\n\tMark Rutland <mark.rutland@arm.com>,\n\tMaxime Coquelin <mcoquelin.stm32@gmail.com>,\n\tAlexandre Torgue <alexandre.torgue@st.com>,\n\tRussell King <linux@armlinux.org.uk>,\n\t<linux-i2c@vger.kernel.org>, <devicetree@vger.kernel.org>,\n\t<linux-arm-kernel@lists.infradead.org>, <linux-kernel@vger.kernel.org>", "CC": "Pierre-Yves MORDRET <pierre-yves.mordret@st.com>", "Subject": "[RESEND PATCH v3 3/5] i2c: i2c-stm32f7: add driver", "Date": "Fri, 1 Sep 2017 09:34:13 +0200", "Message-ID": "<1504251255-20469-4-git-send-email-pierre-yves.mordret@st.com>", "X-Mailer": "git-send-email 2.7.4", "In-Reply-To": "<1504251255-20469-1-git-send-email-pierre-yves.mordret@st.com>", "References": "<1504251255-20469-1-git-send-email-pierre-yves.mordret@st.com>", "MIME-Version": "1.0", "Content-Type": "text/plain", "X-Originating-IP": "[10.75.127.49]", "X-ClientProxiedBy": "SFHDAG2NODE1.st.com (10.75.127.4) To SFHDAG5NODE2.st.com\n\t(10.75.127.14)", "X-Proofpoint-Virus-Version": "vendor=fsecure engine=2.50.10432:, ,\n\tdefinitions=2017-09-01_02:, , signatures=0", "Sender": "linux-i2c-owner@vger.kernel.org", "Precedence": "bulk", "List-ID": "<linux-i2c.vger.kernel.org>", "X-Mailing-List": "linux-i2c@vger.kernel.org" }, "content": "This patch adds initial support for the STM32F7 I2C controller.\n\nSigned-off-by: M'boumba Cedric Madianga <cedric.madianga@gmail.com>\nSigned-off-by: Pierre-Yves MORDRET <pierre-yves.mordret@st.com>\n---\n Version history:\n v3:\n * Move stm32f7_i2c_match above stm32f7_i2c_driver\n * of_device_get_match_data instead of of_match_device\n * Improve I2C Speed DT gathering\n * dev_err into dev_dbg for Arbitration loss\n * Remove useless space aligned\n\n v2:\n * Remove st,i2c-timing binding usage\n * Implement an I2C timings computation algorithm instead of\n static values(bindings). Algorithm uses generic I2C SCL\n Falling/Rising bindings and System clock to compute its timings.\n---\n---\n drivers/i2c/busses/Kconfig | 10 +\n drivers/i2c/busses/Makefile | 1 +\n drivers/i2c/busses/i2c-stm32f7.c | 974 +++++++++++++++++++++++++++++++++++++++\n 3 files changed, 985 insertions(+)\n create mode 100644 drivers/i2c/busses/i2c-stm32f7.c", "diff": "diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig\nindex 1006b23..97fc74b 100644\n--- a/drivers/i2c/busses/Kconfig\n+++ b/drivers/i2c/busses/Kconfig\n@@ -920,6 +920,16 @@ config I2C_STM32F4\n \t This driver can also be built as module. If so, the module\n \t will be called i2c-stm32f4.\n \n+config I2C_STM32F7\n+\ttristate \"STMicroelectronics STM32F7 I2C support\"\n+\tdepends on ARCH_STM32 || COMPILE_TEST\n+\thelp\n+\t Enable this option to add support for STM32 I2C controller embedded\n+\t in STM32F7 SoCs.\n+\n+\t This driver can also be built as module. If so, the module\n+\t will be called i2c-stm32f7.\n+\n config I2C_STU300\n \ttristate \"ST Microelectronics DDC I2C interface\"\n \tdepends on MACH_U300\ndiff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile\nindex 1b2fc81..7816a9f 100644\n--- a/drivers/i2c/busses/Makefile\n+++ b/drivers/i2c/busses/Makefile\n@@ -91,6 +91,7 @@ obj-$(CONFIG_I2C_SIMTEC)\t+= i2c-simtec.o\n obj-$(CONFIG_I2C_SIRF)\t\t+= i2c-sirf.o\n obj-$(CONFIG_I2C_ST)\t\t+= i2c-st.o\n obj-$(CONFIG_I2C_STM32F4)\t+= i2c-stm32f4.o\n+obj-$(CONFIG_I2C_STM32F7)\t+= i2c-stm32f7.o\n obj-$(CONFIG_I2C_STU300)\t+= i2c-stu300.o\n obj-$(CONFIG_I2C_SUN6I_P2WI)\t+= i2c-sun6i-p2wi.o\n obj-$(CONFIG_I2C_TEGRA)\t\t+= i2c-tegra.o\ndiff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c\nnew file mode 100644\nindex 0000000..b3ab288\n--- /dev/null\n+++ b/drivers/i2c/busses/i2c-stm32f7.c\n@@ -0,0 +1,974 @@\n+/*\n+ * Driver for STMicroelectronics STM32F7 I2C controller\n+ *\n+ * This I2C controller is described in the STM32F75xxx and STM32F74xxx Soc\n+ * reference manual.\n+ * Please see below a link to the documentation:\n+ * http://www.st.com/resource/en/reference_manual/dm00124865.pdf\n+ *\n+ * Copyright (C) M'boumba Cedric Madianga 2017\n+ * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>\n+ *\n+ * This driver is based on i2c-stm32f4.c\n+ *\n+ * License terms: GNU General Public License (GPL), version 2\n+ */\n+#include <linux/clk.h>\n+#include <linux/delay.h>\n+#include <linux/err.h>\n+#include <linux/i2c.h>\n+#include <linux/interrupt.h>\n+#include <linux/io.h>\n+#include <linux/iopoll.h>\n+#include <linux/module.h>\n+#include <linux/of.h>\n+#include <linux/of_address.h>\n+#include <linux/of_irq.h>\n+#include <linux/of_platform.h>\n+#include <linux/platform_device.h>\n+#include <linux/reset.h>\n+#include <linux/slab.h>\n+\n+#include \"i2c-stm32.h\"\n+\n+/* STM32F7 I2C registers */\n+#define STM32F7_I2C_CR1\t\t\t\t0x00\n+#define STM32F7_I2C_CR2\t\t\t\t0x04\n+#define STM32F7_I2C_TIMINGR\t\t\t0x10\n+#define STM32F7_I2C_ISR\t\t\t\t0x18\n+#define STM32F7_I2C_ICR\t\t\t\t0x1C\n+#define STM32F7_I2C_RXDR\t\t\t0x24\n+#define STM32F7_I2C_TXDR\t\t\t0x28\n+\n+/* STM32F7 I2C control 1 */\n+#define STM32F7_I2C_CR1_ANFOFF\t\t\tBIT(12)\n+#define STM32F7_I2C_CR1_ERRIE\t\t\tBIT(7)\n+#define STM32F7_I2C_CR1_TCIE\t\t\tBIT(6)\n+#define STM32F7_I2C_CR1_STOPIE\t\t\tBIT(5)\n+#define STM32F7_I2C_CR1_NACKIE\t\t\tBIT(4)\n+#define STM32F7_I2C_CR1_ADDRIE\t\t\tBIT(3)\n+#define STM32F7_I2C_CR1_RXIE\t\t\tBIT(2)\n+#define STM32F7_I2C_CR1_TXIE\t\t\tBIT(1)\n+#define STM32F7_I2C_CR1_PE\t\t\tBIT(0)\n+#define STM32F7_I2C_ALL_IRQ_MASK\t\t(STM32F7_I2C_CR1_ERRIE \\\n+\t\t\t\t\t\t| STM32F7_I2C_CR1_TCIE \\\n+\t\t\t\t\t\t| STM32F7_I2C_CR1_STOPIE \\\n+\t\t\t\t\t\t| STM32F7_I2C_CR1_NACKIE \\\n+\t\t\t\t\t\t| STM32F7_I2C_CR1_RXIE \\\n+\t\t\t\t\t\t| STM32F7_I2C_CR1_TXIE)\n+\n+/* STM32F7 I2C control 2 */\n+#define STM32F7_I2C_CR2_RELOAD\t\t\tBIT(24)\n+#define STM32F7_I2C_CR2_NBYTES_MASK\t\tGENMASK(23, 16)\n+#define STM32F7_I2C_CR2_NBYTES(n)\t\t(((n) & 0xff) << 16)\n+#define STM32F7_I2C_CR2_NACK\t\t\tBIT(15)\n+#define STM32F7_I2C_CR2_STOP\t\t\tBIT(14)\n+#define STM32F7_I2C_CR2_START\t\t\tBIT(13)\n+#define STM32F7_I2C_CR2_RD_WRN\t\t\tBIT(10)\n+#define STM32F7_I2C_CR2_SADD7_MASK\t\tGENMASK(7, 1)\n+#define STM32F7_I2C_CR2_SADD7(n)\t\t(((n) & 0x7f) << 1)\n+\n+/* STM32F7 I2C Interrupt Status */\n+#define STM32F7_I2C_ISR_BUSY\t\t\tBIT(15)\n+#define STM32F7_I2C_ISR_ARLO\t\t\tBIT(9)\n+#define STM32F7_I2C_ISR_BERR\t\t\tBIT(8)\n+#define STM32F7_I2C_ISR_TCR\t\t\tBIT(7)\n+#define STM32F7_I2C_ISR_TC\t\t\tBIT(6)\n+#define STM32F7_I2C_ISR_STOPF\t\t\tBIT(5)\n+#define STM32F7_I2C_ISR_NACKF\t\t\tBIT(4)\n+#define STM32F7_I2C_ISR_RXNE\t\t\tBIT(2)\n+#define STM32F7_I2C_ISR_TXIS\t\t\tBIT(1)\n+\n+/* STM32F7 I2C Interrupt Clear */\n+#define STM32F7_I2C_ICR_ARLOCF\t\t\tBIT(9)\n+#define STM32F7_I2C_ICR_BERRCF\t\t\tBIT(8)\n+#define STM32F7_I2C_ICR_STOPCF\t\t\tBIT(5)\n+#define STM32F7_I2C_ICR_NACKCF\t\t\tBIT(4)\n+\n+/* STM32F7 I2C Timing */\n+#define STM32F7_I2C_TIMINGR_PRESC(n)\t\t(((n) & 0xf) << 28)\n+#define STM32F7_I2C_TIMINGR_SCLDEL(n)\t\t(((n) & 0xf) << 20)\n+#define STM32F7_I2C_TIMINGR_SDADEL(n)\t\t(((n) & 0xf) << 16)\n+#define STM32F7_I2C_TIMINGR_SCLH(n)\t\t(((n) & 0xff) << 8)\n+#define STM32F7_I2C_TIMINGR_SCLL(n)\t\t((n) & 0xff)\n+\n+#define STM32F7_I2C_MAX_LEN\t\t\t0xff\n+\n+#define STM32F7_I2C_DNF_DEFAULT\t\t\t0\n+#define STM32F7_I2C_DNF_MAX\t\t\t16\n+\n+#define STM32F7_I2C_ANALOG_FILTER_ENABLE\t1\n+#define STM32F7_I2C_ANALOG_FILTER_DELAY_MIN\t50\t/* ns */\n+#define STM32F7_I2C_ANALOG_FILTER_DELAY_MAX\t260\t/* ns */\n+\n+#define STM32F7_I2C_RISE_TIME_DEFAULT\t\t25\t/* ns */\n+#define STM32F7_I2C_FALL_TIME_DEFAULT\t\t10\t/* ns */\n+\n+#define STM32F7_PRESC_MAX\t\t\tBIT(4)\n+#define STM32F7_SCLDEL_MAX\t\t\tBIT(4)\n+#define STM32F7_SDADEL_MAX\t\t\tBIT(4)\n+#define STM32F7_SCLH_MAX\t\t\tBIT(8)\n+#define STM32F7_SCLL_MAX\t\t\tBIT(8)\n+\n+/**\n+ * struct stm32f7_i2c_spec - private i2c specification timing\n+ * @rate: I2C bus speed (Hz)\n+ * @rate_min: 80% of I2C bus speed (Hz)\n+ * @rate_max: 120% of I2C bus speed (Hz)\n+ * @fall_max: Max fall time of both SDA and SCL signals (ns)\n+ * @rise_max: Max rise time of both SDA and SCL signals (ns)\n+ * @hddat_min: Min data hold time (ns)\n+ * @vddat_max: Max data valid time (ns)\n+ * @sudat_min: Min data setup time (ns)\n+ * @l_min: Min low period of the SCL clock (ns)\n+ * @h_min: Min high period of the SCL clock (ns)\n+ */\n+struct stm32f7_i2c_spec {\n+\tu32 rate;\n+\tu32 rate_min;\n+\tu32 rate_max;\n+\tu32 fall_max;\n+\tu32 rise_max;\n+\tu32 hddat_min;\n+\tu32 vddat_max;\n+\tu32 sudat_min;\n+\tu32 l_min;\n+\tu32 h_min;\n+};\n+\n+/**\n+ * struct stm32f7_i2c_setup - private I2C timing setup parameters\n+ * @speed: I2C speed mode (standard, Fast Plus)\n+ * @speed_freq: I2C speed frequency (Hz)\n+ * @clock_src: I2C clock source frequency (Hz)\n+ * @rise_time: Rise time (ns)\n+ * @fall_time: Fall time (ns)\n+ * @dnf: Digital filter coefficient (0-16)\n+ * @analog_filter: Analog filter delay (On/Off)\n+ */\n+struct stm32f7_i2c_setup {\n+\tenum stm32_i2c_speed speed;\n+\tu32 speed_freq;\n+\tu32 clock_src;\n+\tu32 rise_time;\n+\tu32 fall_time;\n+\tu8 dnf;\n+\tbool analog_filter;\n+};\n+\n+/**\n+ * struct stm32f7_i2c_timings - private I2C output parameters\n+ * @prec: Prescaler value\n+ * @scldel: Data setup time\n+ * @sdadel: Data hold time\n+ * @sclh: SCL high period (master mode)\n+ * @sclh: SCL low period (master mode)\n+ */\n+struct stm32f7_i2c_timings {\n+\tstruct list_head node;\n+\tu8 presc;\n+\tu8 scldel;\n+\tu8 sdadel;\n+\tu8 sclh;\n+\tu8 scll;\n+};\n+\n+/**\n+ * struct stm32f7_i2c_msg - client specific data\n+ * @addr: 8-bit slave addr, including r/w bit\n+ * @count: number of bytes to be transferred\n+ * @buf: data buffer\n+ * @result: result of the transfer\n+ * @stop: last I2C msg to be sent, i.e. STOP to be generated\n+ */\n+struct stm32f7_i2c_msg {\n+\tu8 addr;\n+\tu32 count;\n+\tu8 *buf;\n+\tint result;\n+\tbool stop;\n+};\n+\n+/**\n+ * struct stm32f7_i2c_dev - private data of the controller\n+ * @adap: I2C adapter for this controller\n+ * @dev: device for this controller\n+ * @base: virtual memory area\n+ * @complete: completion of I2C message\n+ * @clk: hw i2c clock\n+ * @speed: I2C clock frequency of the controller. Standard, Fast or Fast+\n+ * @msg: Pointer to data to be written\n+ * @msg_num: number of I2C messages to be executed\n+ * @msg_id: message identifiant\n+ * @f7_msg: customized i2c msg for driver usage\n+ * @setup: I2C timing input setup\n+ * @timing: I2C computed timings\n+ */\n+struct stm32f7_i2c_dev {\n+\tstruct i2c_adapter adap;\n+\tstruct device *dev;\n+\tvoid __iomem *base;\n+\tstruct completion complete;\n+\tstruct clk *clk;\n+\tint speed;\n+\tstruct i2c_msg *msg;\n+\tunsigned int msg_num;\n+\tunsigned int msg_id;\n+\tstruct stm32f7_i2c_msg f7_msg;\n+\tstruct stm32f7_i2c_setup *setup;\n+\tstruct stm32f7_i2c_timings timing;\n+};\n+\n+/**\n+ * All these values are coming from I2C Specification, Version 6.0, 4th of\n+ * April 2014.\n+ *\n+ * Table10. Characteristics of the SDA and SCL bus lines for Standard, Fast,\n+ * and Fast-mode Plus I2C-bus devices\n+ */\n+static struct stm32f7_i2c_spec i2c_specs[] = {\n+\t[STM32_I2C_SPEED_STANDARD] = {\n+\t\t.rate = 100000,\n+\t\t.rate_min = 8000,\n+\t\t.rate_max = 120000,\n+\t\t.fall_max = 300,\n+\t\t.rise_max = 1000,\n+\t\t.hddat_min = 0,\n+\t\t.vddat_max = 3450,\n+\t\t.sudat_min = 250,\n+\t\t.l_min = 4700,\n+\t\t.h_min = 4000,\n+\t},\n+\t[STM32_I2C_SPEED_FAST] = {\n+\t\t.rate = 400000,\n+\t\t.rate_min = 320000,\n+\t\t.rate_max = 480000,\n+\t\t.fall_max = 300,\n+\t\t.rise_max = 300,\n+\t\t.hddat_min = 0,\n+\t\t.vddat_max = 900,\n+\t\t.sudat_min = 100,\n+\t\t.l_min = 1300,\n+\t\t.h_min = 600,\n+\t},\n+\t[STM32_I2C_SPEED_FAST_PLUS] = {\n+\t\t.rate = 1000000,\n+\t\t.rate_min = 800000,\n+\t\t.rate_max = 1200000,\n+\t\t.fall_max = 100,\n+\t\t.rise_max = 120,\n+\t\t.hddat_min = 0,\n+\t\t.vddat_max = 450,\n+\t\t.sudat_min = 50,\n+\t\t.l_min = 500,\n+\t\t.h_min = 260,\n+\t},\n+};\n+\n+struct stm32f7_i2c_setup stm32f7_setup = {\n+\t.rise_time = STM32F7_I2C_RISE_TIME_DEFAULT,\n+\t.fall_time = STM32F7_I2C_FALL_TIME_DEFAULT,\n+\t.dnf = STM32F7_I2C_DNF_DEFAULT,\n+\t.analog_filter = STM32F7_I2C_ANALOG_FILTER_ENABLE,\n+};\n+\n+static inline void stm32f7_i2c_set_bits(void __iomem *reg, u32 mask)\n+{\n+\twritel_relaxed(readl_relaxed(reg) | mask, reg);\n+}\n+\n+static inline void stm32f7_i2c_clr_bits(void __iomem *reg, u32 mask)\n+{\n+\twritel_relaxed(readl_relaxed(reg) & ~mask, reg);\n+}\n+\n+static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,\n+\t\t\t\t struct stm32f7_i2c_setup *setup,\n+\t\t\t\t struct stm32f7_i2c_timings *output)\n+{\n+\tu32 p_prev = STM32F7_PRESC_MAX;\n+\tu32 i2cclk = DIV_ROUND_CLOSEST(NSEC_PER_SEC,\n+\t\t\t\t setup->clock_src);\n+\tu32 i2cbus = DIV_ROUND_CLOSEST(NSEC_PER_SEC,\n+\t\t\t\t setup->speed_freq);\n+\tu32 clk_error_prev = i2cbus;\n+\tu32 tsync;\n+\tu32 af_delay_min, af_delay_max;\n+\tu32 dnf_delay;\n+\tu32 clk_min, clk_max;\n+\tint sdadel_min, sdadel_max;\n+\tint scldel_min;\n+\tstruct stm32f7_i2c_timings *v, *_v, *s;\n+\tstruct list_head solutions;\n+\tu16 p, l, a, h;\n+\tint ret = 0;\n+\n+\tif (setup->speed >= STM32_I2C_SPEED_END) {\n+\t\tdev_err(i2c_dev->dev, \"speed out of bound {%d/%d}\\n\",\n+\t\t\tsetup->speed, STM32_I2C_SPEED_END - 1);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif ((setup->rise_time > i2c_specs[setup->speed].rise_max) ||\n+\t (setup->fall_time > i2c_specs[setup->speed].fall_max)) {\n+\t\tdev_err(i2c_dev->dev,\n+\t\t\t\"timings out of bound Rise{%d>%d}/Fall{%d>%d}\\n\",\n+\t\t\tsetup->rise_time, i2c_specs[setup->speed].rise_max,\n+\t\t\tsetup->fall_time, i2c_specs[setup->speed].fall_max);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (setup->dnf > STM32F7_I2C_DNF_MAX) {\n+\t\tdev_err(i2c_dev->dev,\n+\t\t\t\"DNF out of bound %d/%d\\n\",\n+\t\t\tsetup->dnf, STM32F7_I2C_DNF_MAX);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (setup->speed_freq > i2c_specs[setup->speed].rate) {\n+\t\tdev_err(i2c_dev->dev, \"ERROR: Freq {%d/%d}\\n\",\n+\t\t\tsetup->speed_freq, i2c_specs[setup->speed].rate);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\t/* Analog and Digital Filters */\n+\taf_delay_min =\n+\t\t(setup->analog_filter ?\n+\t\t STM32F7_I2C_ANALOG_FILTER_DELAY_MIN : 0);\n+\taf_delay_max =\n+\t\t(setup->analog_filter ?\n+\t\t STM32F7_I2C_ANALOG_FILTER_DELAY_MAX : 0);\n+\tdnf_delay = setup->dnf * i2cclk;\n+\n+\tsdadel_min = setup->fall_time - i2c_specs[setup->speed].hddat_min -\n+\t\taf_delay_min - (setup->dnf + 3) * i2cclk;\n+\n+\tsdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time -\n+\t\taf_delay_max - (setup->dnf + 4) * i2cclk;\n+\n+\tscldel_min = setup->rise_time + i2c_specs[setup->speed].sudat_min;\n+\n+\tif (sdadel_min < 0)\n+\t\tsdadel_min = 0;\n+\tif (sdadel_max < 0)\n+\t\tsdadel_max = 0;\n+\n+\tdev_dbg(i2c_dev->dev, \"SDADEL(min/max): %i/%i, SCLDEL(Min): %i\\n\",\n+\t\tsdadel_min, sdadel_max, scldel_min);\n+\n+\tINIT_LIST_HEAD(&solutions);\n+\t/* Compute possible values for PRESC, SCLDEL and SDADEL */\n+\tfor (p = 0; p < STM32F7_PRESC_MAX; p++) {\n+\t\tfor (l = 0; l < STM32F7_SCLDEL_MAX; l++) {\n+\t\t\tu32 scldel = (l + 1) * (p + 1) * i2cclk;\n+\n+\t\t\tif (scldel < scldel_min)\n+\t\t\t\tcontinue;\n+\n+\t\t\tfor (a = 0; a < STM32F7_SDADEL_MAX; a++) {\n+\t\t\t\tu32 sdadel = (a * (p + 1) + 1) * i2cclk;\n+\n+\t\t\t\tif (((sdadel >= sdadel_min) &&\n+\t\t\t\t (sdadel <= sdadel_max)) &&\n+\t\t\t\t (p != p_prev)) {\n+\t\t\t\t\tv = kmalloc(sizeof(*v), GFP_KERNEL);\n+\t\t\t\t\tif (!v) {\n+\t\t\t\t\t\tret = -ENOMEM;\n+\t\t\t\t\t\tgoto exit;\n+\t\t\t\t\t}\n+\n+\t\t\t\t\tv->presc = p;\n+\t\t\t\t\tv->scldel = l;\n+\t\t\t\t\tv->sdadel = a;\n+\t\t\t\t\tp_prev = p;\n+\n+\t\t\t\t\tlist_add_tail(&v->node,\n+\t\t\t\t\t\t &solutions);\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tif (list_empty(&solutions)) {\n+\t\tdev_err(i2c_dev->dev, \"no Prescaler solution\\n\");\n+\t\tret = -EPERM;\n+\t\tgoto exit;\n+\t}\n+\n+\ttsync = af_delay_min + dnf_delay + (2 * i2cclk);\n+\ts = NULL;\n+\tclk_max = NSEC_PER_SEC / i2c_specs[setup->speed].rate_min;\n+\tclk_min = NSEC_PER_SEC / i2c_specs[setup->speed].rate_max;\n+\n+\t/*\n+\t * Among Prescaler possibilities discovered above figures out SCL Low\n+\t * and High Period. Provided:\n+\t * - SCL Low Period has to be higher than Low Period of tehs SCL Clock\n+\t * defined by I2C Specification. I2C Clock has to be lower than\n+\t * (SCL Low Period - Analog/Digital filters) / 4.\n+\t * - SCL High Period has to be lower than High Period of the SCL Clock\n+\t * defined by I2C Specification\n+\t * - I2C Clock has to be lower than SCL High Period\n+\t */\n+\tlist_for_each_entry(v, &solutions, node) {\n+\t\tu32 prescaler = (v->presc + 1) * i2cclk;\n+\n+\t\tfor (l = 0; l < STM32F7_SCLL_MAX; l++) {\n+\t\t\tu32 tscl_l = (l + 1) * prescaler + tsync;\n+\n+\t\t\tif ((tscl_l < i2c_specs[setup->speed].l_min) ||\n+\t\t\t (i2cclk >=\n+\t\t\t ((tscl_l - af_delay_min - dnf_delay) / 4))) {\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\n+\t\t\tfor (h = 0; h < STM32F7_SCLH_MAX; h++) {\n+\t\t\t\tu32 tscl_h = (h + 1) * prescaler + tsync;\n+\t\t\t\tu32 tscl = tscl_l + tscl_h +\n+\t\t\t\t\tsetup->rise_time + setup->fall_time;\n+\n+\t\t\t\tif ((tscl >= clk_min) && (tscl <= clk_max) &&\n+\t\t\t\t (tscl_h >= i2c_specs[setup->speed].h_min) &&\n+\t\t\t\t (i2cclk < tscl_h)) {\n+\t\t\t\t\tint clk_error = tscl - i2cbus;\n+\n+\t\t\t\t\tif (clk_error < 0)\n+\t\t\t\t\t\tclk_error = -clk_error;\n+\n+\t\t\t\t\tif (clk_error < clk_error_prev) {\n+\t\t\t\t\t\tclk_error_prev = clk_error;\n+\t\t\t\t\t\tv->scll = l;\n+\t\t\t\t\t\tv->sclh = h;\n+\t\t\t\t\t\ts = v;\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tif (!s) {\n+\t\tdev_err(i2c_dev->dev, \"no solution at all\\n\");\n+\t\tret = -EPERM;\n+\t\tgoto exit;\n+\t}\n+\n+\toutput->presc = s->presc;\n+\toutput->scldel = s->scldel;\n+\toutput->sdadel = s->sdadel;\n+\toutput->scll = s->scll;\n+\toutput->sclh = s->sclh;\n+\n+\tdev_dbg(i2c_dev->dev,\n+\t\t\"Presc: %i, scldel: %i, sdadel: %i, scll: %i, sclh: %i\\n\",\n+\t\toutput->presc,\n+\t\toutput->scldel, output->sdadel,\n+\t\toutput->scll, output->sclh);\n+\n+exit:\n+\t/* Release list and memory */\n+\tlist_for_each_entry_safe(v, _v, &solutions, node) {\n+\t\tlist_del(&v->node);\n+\t\tkfree(v);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,\n+\t\t\t\t struct stm32f7_i2c_setup *setup)\n+{\n+\tint ret = 0;\n+\n+\tsetup->speed = i2c_dev->speed;\n+\tsetup->speed_freq = i2c_specs[setup->speed].rate;\n+\tsetup->clock_src = clk_get_rate(i2c_dev->clk);\n+\n+\tif (!setup->clock_src) {\n+\t\tdev_err(i2c_dev->dev, \"clock rate is 0\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tdo {\n+\t\tret = stm32f7_i2c_compute_timing(i2c_dev, setup,\n+\t\t\t\t\t\t &i2c_dev->timing);\n+\t\tif (ret) {\n+\t\t\tdev_err(i2c_dev->dev,\n+\t\t\t\t\"failed to compute I2C timings.\\n\");\n+\t\t\tif (i2c_dev->speed > STM32_I2C_SPEED_STANDARD) {\n+\t\t\t\ti2c_dev->speed--;\n+\t\t\t\tsetup->speed = i2c_dev->speed;\n+\t\t\t\tsetup->speed_freq =\n+\t\t\t\t\ti2c_specs[setup->speed].rate;\n+\t\t\t\tdev_warn(i2c_dev->dev,\n+\t\t\t\t\t \"downgrade I2C Speed Freq to (%i)\\n\",\n+\t\t\t\t\t i2c_specs[setup->speed].rate);\n+\t\t\t} else {\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t} while (ret);\n+\n+\tif (ret) {\n+\t\tdev_err(i2c_dev->dev, \"Impossible to compute I2C timings.\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tdev_dbg(i2c_dev->dev, \"I2C Speed(%i), Freq(%i), Clk Source(%i)\\n\",\n+\t\tsetup->speed, setup->speed_freq, setup->clock_src);\n+\tdev_dbg(i2c_dev->dev, \"I2C Rise(%i) and Fall(%i) Time\\n\",\n+\t\tsetup->rise_time, setup->fall_time);\n+\tdev_dbg(i2c_dev->dev, \"I2C Analog Filter(%s), DNF(%i)\\n\",\n+\t\t(setup->analog_filter ? \"On\" : \"Off\"), setup->dnf);\n+\n+\treturn 0;\n+}\n+\n+static void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev)\n+{\n+\tstruct stm32f7_i2c_timings *t = &i2c_dev->timing;\n+\tu32 timing = 0;\n+\n+\t/* Timing settings */\n+\ttiming |= STM32F7_I2C_TIMINGR_PRESC(t->presc);\n+\ttiming |= STM32F7_I2C_TIMINGR_SCLDEL(t->scldel);\n+\ttiming |= STM32F7_I2C_TIMINGR_SDADEL(t->sdadel);\n+\ttiming |= STM32F7_I2C_TIMINGR_SCLH(t->sclh);\n+\ttiming |= STM32F7_I2C_TIMINGR_SCLL(t->scll);\n+\twritel_relaxed(timing, i2c_dev->base + STM32F7_I2C_TIMINGR);\n+\n+\t/* Enable I2C */\n+\tif (i2c_dev->setup->analog_filter)\n+\t\tstm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,\n+\t\t\t\t STM32F7_I2C_CR1_ANFOFF);\n+\telse\n+\t\tstm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,\n+\t\t\t\t STM32F7_I2C_CR1_ANFOFF);\n+\tstm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,\n+\t\t\t STM32F7_I2C_CR1_PE);\n+}\n+\n+static void stm32f7_i2c_write_tx_data(struct stm32f7_i2c_dev *i2c_dev)\n+{\n+\tstruct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;\n+\tvoid __iomem *base = i2c_dev->base;\n+\n+\tif (f7_msg->count) {\n+\t\twriteb_relaxed(*f7_msg->buf++, base + STM32F7_I2C_TXDR);\n+\t\tf7_msg->count--;\n+\t}\n+}\n+\n+static void stm32f7_i2c_read_rx_data(struct stm32f7_i2c_dev *i2c_dev)\n+{\n+\tstruct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;\n+\tvoid __iomem *base = i2c_dev->base;\n+\n+\tif (f7_msg->count) {\n+\t\t*f7_msg->buf++ = readb_relaxed(base + STM32F7_I2C_RXDR);\n+\t\tf7_msg->count--;\n+\t}\n+}\n+\n+static void stm32f7_i2c_reload(struct stm32f7_i2c_dev *i2c_dev)\n+{\n+\tstruct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;\n+\tu32 cr2;\n+\n+\tcr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);\n+\n+\tcr2 &= ~STM32F7_I2C_CR2_NBYTES_MASK;\n+\tif (f7_msg->count > STM32F7_I2C_MAX_LEN) {\n+\t\tcr2 |= STM32F7_I2C_CR2_NBYTES(STM32F7_I2C_MAX_LEN);\n+\t} else {\n+\t\tcr2 &= ~STM32F7_I2C_CR2_RELOAD;\n+\t\tcr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);\n+\t}\n+\n+\twritel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2);\n+}\n+\n+static int stm32f7_i2c_wait_free_bus(struct stm32f7_i2c_dev *i2c_dev)\n+{\n+\tu32 status;\n+\tint ret;\n+\n+\tret = readl_relaxed_poll_timeout(i2c_dev->base + STM32F7_I2C_ISR,\n+\t\t\t\t\t status,\n+\t\t\t\t\t !(status & STM32F7_I2C_ISR_BUSY),\n+\t\t\t\t\t 10, 1000);\n+\tif (ret) {\n+\t\tdev_dbg(i2c_dev->dev, \"bus busy\\n\");\n+\t\tret = -EBUSY;\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev,\n+\t\t\t\t struct i2c_msg *msg)\n+{\n+\tstruct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;\n+\tvoid __iomem *base = i2c_dev->base;\n+\tu32 cr1, cr2;\n+\n+\tf7_msg->addr = msg->addr;\n+\tf7_msg->buf = msg->buf;\n+\tf7_msg->count = msg->len;\n+\tf7_msg->result = 0;\n+\tf7_msg->stop = (i2c_dev->msg_id >= i2c_dev->msg_num - 1);\n+\n+\treinit_completion(&i2c_dev->complete);\n+\n+\tcr1 = readl_relaxed(base + STM32F7_I2C_CR1);\n+\tcr2 = readl_relaxed(base + STM32F7_I2C_CR2);\n+\n+\t/* Set transfer direction */\n+\tcr2 &= ~STM32F7_I2C_CR2_RD_WRN;\n+\tif (msg->flags & I2C_M_RD)\n+\t\tcr2 |= STM32F7_I2C_CR2_RD_WRN;\n+\n+\t/* Set slave address */\n+\tcr2 &= ~STM32F7_I2C_CR2_SADD7_MASK;\n+\tcr2 |= STM32F7_I2C_CR2_SADD7(f7_msg->addr);\n+\n+\t/* Set nb bytes to transfer and reload if needed */\n+\tcr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD);\n+\tif (f7_msg->count > STM32F7_I2C_MAX_LEN) {\n+\t\tcr2 |= STM32F7_I2C_CR2_NBYTES(STM32F7_I2C_MAX_LEN);\n+\t\tcr2 |= STM32F7_I2C_CR2_RELOAD;\n+\t} else {\n+\t\tcr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count);\n+\t}\n+\n+\t/* Enable NACK, STOP, error and transfer complete interrupts */\n+\tcr1 |= STM32F7_I2C_CR1_ERRIE | STM32F7_I2C_CR1_TCIE |\n+\t\tSTM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE;\n+\n+\t/* Clear TX/RX interrupt */\n+\tcr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE);\n+\n+\t/* Enable RX/TX interrupt according to msg direction */\n+\tif (msg->flags & I2C_M_RD)\n+\t\tcr1 |= STM32F7_I2C_CR1_RXIE;\n+\telse\n+\t\tcr1 |= STM32F7_I2C_CR1_TXIE;\n+\n+\t/* Configure Start/Repeated Start */\n+\tcr2 |= STM32F7_I2C_CR2_START;\n+\n+\t/* Write configurations registers */\n+\twritel_relaxed(cr1, base + STM32F7_I2C_CR1);\n+\twritel_relaxed(cr2, base + STM32F7_I2C_CR2);\n+}\n+\n+static void stm32f7_i2c_disable_irq(struct stm32f7_i2c_dev *i2c_dev, u32 mask)\n+{\n+\tstm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, mask);\n+}\n+\n+static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data)\n+{\n+\tstruct stm32f7_i2c_dev *i2c_dev = data;\n+\tstruct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;\n+\tvoid __iomem *base = i2c_dev->base;\n+\tu32 status, mask;\n+\n+\tstatus = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);\n+\n+\t/* Tx empty */\n+\tif (status & STM32F7_I2C_ISR_TXIS)\n+\t\tstm32f7_i2c_write_tx_data(i2c_dev);\n+\n+\t/* RX not empty */\n+\tif (status & STM32F7_I2C_ISR_RXNE)\n+\t\tstm32f7_i2c_read_rx_data(i2c_dev);\n+\n+\t/* NACK received */\n+\tif (status & STM32F7_I2C_ISR_NACKF) {\n+\t\tdev_dbg(i2c_dev->dev, \"<%s>: Receive NACK\\n\", __func__);\n+\t\twritel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR);\n+\t\tf7_msg->result = -EBADE;\n+\t}\n+\n+\t/* STOP detection flag */\n+\tif (status & STM32F7_I2C_ISR_STOPF) {\n+\t\t/* Disable interrupts */\n+\t\tstm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK);\n+\n+\t\t/* Clear STOP flag */\n+\t\twritel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR);\n+\n+\t\tcomplete(&i2c_dev->complete);\n+\t}\n+\n+\t/* Transfer complete */\n+\tif (status & STM32F7_I2C_ISR_TC) {\n+\t\tif (f7_msg->stop) {\n+\t\t\tmask = STM32F7_I2C_CR2_STOP;\n+\t\t\tstm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask);\n+\t\t} else {\n+\t\t\ti2c_dev->msg_id++;\n+\t\t\ti2c_dev->msg++;\n+\t\t\tstm32f7_i2c_xfer_msg(i2c_dev, i2c_dev->msg);\n+\t\t}\n+\t}\n+\n+\t/*\n+\t * Transfer Complete Reload: 255 data bytes have been transferred\n+\t * We have to prepare the I2C controller to transfer the remaining\n+\t * data.\n+\t */\n+\tif (status & STM32F7_I2C_ISR_TCR)\n+\t\tstm32f7_i2c_reload(i2c_dev);\n+\n+\treturn IRQ_HANDLED;\n+}\n+\n+static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data)\n+{\n+\tstruct stm32f7_i2c_dev *i2c_dev = data;\n+\tstruct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;\n+\tvoid __iomem *base = i2c_dev->base;\n+\tstruct device *dev = i2c_dev->dev;\n+\tu32 status;\n+\n+\tstatus = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);\n+\n+\t/* Bus error */\n+\tif (status & STM32F7_I2C_ISR_BERR) {\n+\t\tdev_err(dev, \"<%s>: Bus error\\n\", __func__);\n+\t\twritel_relaxed(STM32F7_I2C_ICR_BERRCF, base + STM32F7_I2C_ICR);\n+\t\tf7_msg->result = -EIO;\n+\t}\n+\n+\t/* Arbitration loss */\n+\tif (status & STM32F7_I2C_ISR_ARLO) {\n+\t\tdev_dbg(dev, \"<%s>: Arbitration loss\\n\", __func__);\n+\t\twritel_relaxed(STM32F7_I2C_ICR_ARLOCF, base + STM32F7_I2C_ICR);\n+\t\tf7_msg->result = -EAGAIN;\n+\t}\n+\n+\tstm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK);\n+\n+\tcomplete(&i2c_dev->complete);\n+\n+\treturn IRQ_HANDLED;\n+}\n+\n+static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap,\n+\t\t\t struct i2c_msg msgs[], int num)\n+{\n+\tstruct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);\n+\tstruct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;\n+\tunsigned long timeout;\n+\tint ret;\n+\n+\ti2c_dev->msg = msgs;\n+\ti2c_dev->msg_num = num;\n+\ti2c_dev->msg_id = 0;\n+\n+\tret = clk_enable(i2c_dev->clk);\n+\tif (ret) {\n+\t\tdev_err(i2c_dev->dev, \"Failed to enable clock\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = stm32f7_i2c_wait_free_bus(i2c_dev);\n+\tif (ret)\n+\t\tgoto clk_free;\n+\n+\tstm32f7_i2c_xfer_msg(i2c_dev, msgs);\n+\n+\ttimeout = wait_for_completion_timeout(&i2c_dev->complete,\n+\t\t\t\t\t i2c_dev->adap.timeout);\n+\tret = f7_msg->result;\n+\n+\tif (!timeout) {\n+\t\tdev_dbg(i2c_dev->dev, \"Access to slave 0x%x timed out\\n\",\n+\t\t\ti2c_dev->msg->addr);\n+\t\tret = -ETIMEDOUT;\n+\t}\n+\n+clk_free:\n+\tclk_disable(i2c_dev->clk);\n+\n+\treturn (ret < 0) ? ret : num;\n+}\n+\n+static u32 stm32f7_i2c_func(struct i2c_adapter *adap)\n+{\n+\treturn I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;\n+}\n+\n+static struct i2c_algorithm stm32f7_i2c_algo = {\n+\t.master_xfer = stm32f7_i2c_xfer,\n+\t.functionality = stm32f7_i2c_func,\n+};\n+\n+static int stm32f7_i2c_probe(struct platform_device *pdev)\n+{\n+\tstruct device_node *np = pdev->dev.of_node;\n+\tstruct stm32f7_i2c_dev *i2c_dev;\n+\tconst struct stm32f7_i2c_setup *setup;\n+\tstruct resource *res;\n+\tu32 irq_error, irq_event, clk_rate, rise_time, fall_time;\n+\tstruct i2c_adapter *adap;\n+\tstruct reset_control *rst;\n+\tint ret;\n+\n+\ti2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);\n+\tif (!i2c_dev)\n+\t\treturn -ENOMEM;\n+\n+\tres = platform_get_resource(pdev, IORESOURCE_MEM, 0);\n+\ti2c_dev->base = devm_ioremap_resource(&pdev->dev, res);\n+\tif (IS_ERR(i2c_dev->base))\n+\t\treturn PTR_ERR(i2c_dev->base);\n+\n+\tirq_event = irq_of_parse_and_map(np, 0);\n+\tif (!irq_event) {\n+\t\tdev_err(&pdev->dev, \"IRQ event missing or invalid\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tirq_error = irq_of_parse_and_map(np, 1);\n+\tif (!irq_error) {\n+\t\tdev_err(&pdev->dev, \"IRQ error missing or invalid\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\ti2c_dev->clk = devm_clk_get(&pdev->dev, NULL);\n+\tif (IS_ERR(i2c_dev->clk)) {\n+\t\tdev_err(&pdev->dev, \"Error: Missing controller clock\\n\");\n+\t\treturn PTR_ERR(i2c_dev->clk);\n+\t}\n+\tret = clk_prepare_enable(i2c_dev->clk);\n+\tif (ret) {\n+\t\tdev_err(&pdev->dev, \"Failed to prepare_enable clock\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\ti2c_dev->speed = STM32_I2C_SPEED_STANDARD;\n+\tret = device_property_read_u32(&pdev->dev, \"clock-frequency\",\n+\t\t\t\t &clk_rate);\n+\tif (!ret && clk_rate >= 1000000)\n+\t\ti2c_dev->speed = STM32_I2C_SPEED_FAST_PLUS;\n+\telse if (!ret && clk_rate >= 400000)\n+\t\ti2c_dev->speed = STM32_I2C_SPEED_FAST;\n+\telse if (!ret && clk_rate >= 100000)\n+\t\ti2c_dev->speed = STM32_I2C_SPEED_STANDARD;\n+\n+\trst = devm_reset_control_get(&pdev->dev, NULL);\n+\tif (IS_ERR(rst)) {\n+\t\tdev_err(&pdev->dev, \"Error: Missing controller reset\\n\");\n+\t\tret = PTR_ERR(rst);\n+\t\tgoto clk_free;\n+\t}\n+\treset_control_assert(rst);\n+\tudelay(2);\n+\treset_control_deassert(rst);\n+\n+\ti2c_dev->dev = &pdev->dev;\n+\n+\tret = devm_request_irq(&pdev->dev, irq_event, stm32f7_i2c_isr_event, 0,\n+\t\t\t pdev->name, i2c_dev);\n+\tif (ret) {\n+\t\tdev_err(&pdev->dev, \"Failed to request irq event %i\\n\",\n+\t\t\tirq_event);\n+\t\tgoto clk_free;\n+\t}\n+\n+\tret = devm_request_irq(&pdev->dev, irq_error, stm32f7_i2c_isr_error, 0,\n+\t\t\t pdev->name, i2c_dev);\n+\tif (ret) {\n+\t\tdev_err(&pdev->dev, \"Failed to request irq error %i\\n\",\n+\t\t\tirq_error);\n+\t\tgoto clk_free;\n+\t}\n+\n+\tsetup = of_device_get_match_data(&pdev->dev);\n+\ti2c_dev->setup->rise_time = setup->rise_time;\n+\ti2c_dev->setup->fall_time = setup->fall_time;\n+\ti2c_dev->setup->dnf = setup->dnf;\n+\ti2c_dev->setup->analog_filter = setup->analog_filter;\n+\n+\tret = device_property_read_u32(i2c_dev->dev, \"i2c-scl-rising-time-ns\",\n+\t\t\t\t &rise_time);\n+\tif (!ret)\n+\t\ti2c_dev->setup->rise_time = rise_time;\n+\n+\tret = device_property_read_u32(i2c_dev->dev, \"i2c-scl-falling-time-ns\",\n+\t\t\t\t &fall_time);\n+\tif (!ret)\n+\t\ti2c_dev->setup->fall_time = fall_time;\n+\n+\tret = stm32f7_i2c_setup_timing(i2c_dev, i2c_dev->setup);\n+\tif (ret)\n+\t\tgoto clk_free;\n+\n+\tstm32f7_i2c_hw_config(i2c_dev);\n+\n+\tadap = &i2c_dev->adap;\n+\ti2c_set_adapdata(adap, i2c_dev);\n+\tsnprintf(adap->name, sizeof(adap->name), \"STM32F7 I2C(%pa)\",\n+\t\t &res->start);\n+\tadap->owner = THIS_MODULE;\n+\tadap->timeout = 2 * HZ;\n+\tadap->retries = 0;\n+\tadap->algo = &stm32f7_i2c_algo;\n+\tadap->dev.parent = &pdev->dev;\n+\tadap->dev.of_node = pdev->dev.of_node;\n+\n+\tinit_completion(&i2c_dev->complete);\n+\n+\tret = i2c_add_adapter(adap);\n+\tif (ret) {\n+\t\tdev_err(&pdev->dev, \"Failed to add adapter\\n\");\n+\t\tgoto clk_free;\n+\t}\n+\n+\tplatform_set_drvdata(pdev, i2c_dev);\n+\n+\tclk_disable(i2c_dev->clk);\n+\n+\tdev_info(i2c_dev->dev, \"STM32F7 I2C-%d bus adapter\\n\", adap->nr);\n+\n+\treturn 0;\n+\n+clk_free:\n+\tclk_disable_unprepare(i2c_dev->clk);\n+\n+\treturn ret;\n+}\n+\n+static int stm32f7_i2c_remove(struct platform_device *pdev)\n+{\n+\tstruct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev);\n+\n+\ti2c_del_adapter(&i2c_dev->adap);\n+\n+\tclk_unprepare(i2c_dev->clk);\n+\n+\treturn 0;\n+}\n+\n+static const struct of_device_id stm32f7_i2c_match[] = {\n+\t{ .compatible = \"st,stm32f7-i2c\", .data = &stm32f7_setup},\n+\t{},\n+};\n+MODULE_DEVICE_TABLE(of, stm32f7_i2c_match);\n+\n+static struct platform_driver stm32f7_i2c_driver = {\n+\t.driver = {\n+\t\t.name = \"stm32f7-i2c\",\n+\t\t.of_match_table = stm32f7_i2c_match,\n+\t},\n+\t.probe = stm32f7_i2c_probe,\n+\t.remove = stm32f7_i2c_remove,\n+};\n+\n+module_platform_driver(stm32f7_i2c_driver);\n+\n+MODULE_AUTHOR(\"M'boumba Cedric Madianga <cedric.madianga@gmail.com>\");\n+MODULE_DESCRIPTION(\"STMicroelectronics STM32F7 I2C driver\");\n+MODULE_LICENSE(\"GPL v2\");\n", "prefixes": [ "RESEND", "v3", "3/5" ] }