18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for STMicroelectronics STM32F7 I2C controller 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This I2C controller is described in the STM32F75xxx and STM32F74xxx Soc 68c2ecf20Sopenharmony_ci * reference manual. 78c2ecf20Sopenharmony_ci * Please see below a link to the documentation: 88c2ecf20Sopenharmony_ci * http://www.st.com/resource/en/reference_manual/dm00124865.pdf 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Copyright (C) M'boumba Cedric Madianga 2017 118c2ecf20Sopenharmony_ci * Copyright (C) STMicroelectronics 2017 128c2ecf20Sopenharmony_ci * Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com> 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * This driver is based on i2c-stm32f4.c 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci#include <linux/clk.h> 188c2ecf20Sopenharmony_ci#include <linux/delay.h> 198c2ecf20Sopenharmony_ci#include <linux/err.h> 208c2ecf20Sopenharmony_ci#include <linux/i2c.h> 218c2ecf20Sopenharmony_ci#include <linux/i2c-smbus.h> 228c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 238c2ecf20Sopenharmony_ci#include <linux/io.h> 248c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 258c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 268c2ecf20Sopenharmony_ci#include <linux/module.h> 278c2ecf20Sopenharmony_ci#include <linux/of.h> 288c2ecf20Sopenharmony_ci#include <linux/of_address.h> 298c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 308c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 318c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 328c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 338c2ecf20Sopenharmony_ci#include <linux/pm_wakeirq.h> 348c2ecf20Sopenharmony_ci#include <linux/regmap.h> 358c2ecf20Sopenharmony_ci#include <linux/reset.h> 368c2ecf20Sopenharmony_ci#include <linux/slab.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include "i2c-stm32.h" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* STM32F7 I2C registers */ 418c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR1 0x00 428c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR2 0x04 438c2ecf20Sopenharmony_ci#define STM32F7_I2C_OAR1 0x08 448c2ecf20Sopenharmony_ci#define STM32F7_I2C_OAR2 0x0C 458c2ecf20Sopenharmony_ci#define STM32F7_I2C_PECR 0x20 468c2ecf20Sopenharmony_ci#define STM32F7_I2C_TIMINGR 0x10 478c2ecf20Sopenharmony_ci#define STM32F7_I2C_ISR 0x18 488c2ecf20Sopenharmony_ci#define STM32F7_I2C_ICR 0x1C 498c2ecf20Sopenharmony_ci#define STM32F7_I2C_RXDR 0x24 508c2ecf20Sopenharmony_ci#define STM32F7_I2C_TXDR 0x28 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* STM32F7 I2C control 1 */ 538c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR1_PECEN BIT(23) 548c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR1_SMBHEN BIT(20) 558c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR1_WUPEN BIT(18) 568c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR1_SBC BIT(16) 578c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR1_RXDMAEN BIT(15) 588c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR1_TXDMAEN BIT(14) 598c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR1_ANFOFF BIT(12) 608c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR1_DNF_MASK GENMASK(11, 8) 618c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR1_DNF(n) (((n) & 0xf) << 8) 628c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR1_ERRIE BIT(7) 638c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR1_TCIE BIT(6) 648c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR1_STOPIE BIT(5) 658c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR1_NACKIE BIT(4) 668c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR1_ADDRIE BIT(3) 678c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR1_RXIE BIT(2) 688c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR1_TXIE BIT(1) 698c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR1_PE BIT(0) 708c2ecf20Sopenharmony_ci#define STM32F7_I2C_ALL_IRQ_MASK (STM32F7_I2C_CR1_ERRIE \ 718c2ecf20Sopenharmony_ci | STM32F7_I2C_CR1_TCIE \ 728c2ecf20Sopenharmony_ci | STM32F7_I2C_CR1_STOPIE \ 738c2ecf20Sopenharmony_ci | STM32F7_I2C_CR1_NACKIE \ 748c2ecf20Sopenharmony_ci | STM32F7_I2C_CR1_RXIE \ 758c2ecf20Sopenharmony_ci | STM32F7_I2C_CR1_TXIE) 768c2ecf20Sopenharmony_ci#define STM32F7_I2C_XFER_IRQ_MASK (STM32F7_I2C_CR1_TCIE \ 778c2ecf20Sopenharmony_ci | STM32F7_I2C_CR1_STOPIE \ 788c2ecf20Sopenharmony_ci | STM32F7_I2C_CR1_NACKIE \ 798c2ecf20Sopenharmony_ci | STM32F7_I2C_CR1_RXIE \ 808c2ecf20Sopenharmony_ci | STM32F7_I2C_CR1_TXIE) 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* STM32F7 I2C control 2 */ 838c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR2_PECBYTE BIT(26) 848c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR2_RELOAD BIT(24) 858c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR2_NBYTES_MASK GENMASK(23, 16) 868c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR2_NBYTES(n) (((n) & 0xff) << 16) 878c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR2_NACK BIT(15) 888c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR2_STOP BIT(14) 898c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR2_START BIT(13) 908c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR2_HEAD10R BIT(12) 918c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR2_ADD10 BIT(11) 928c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR2_RD_WRN BIT(10) 938c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR2_SADD10_MASK GENMASK(9, 0) 948c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR2_SADD10(n) (((n) & \ 958c2ecf20Sopenharmony_ci STM32F7_I2C_CR2_SADD10_MASK)) 968c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR2_SADD7_MASK GENMASK(7, 1) 978c2ecf20Sopenharmony_ci#define STM32F7_I2C_CR2_SADD7(n) (((n) & 0x7f) << 1) 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* STM32F7 I2C Own Address 1 */ 1008c2ecf20Sopenharmony_ci#define STM32F7_I2C_OAR1_OA1EN BIT(15) 1018c2ecf20Sopenharmony_ci#define STM32F7_I2C_OAR1_OA1MODE BIT(10) 1028c2ecf20Sopenharmony_ci#define STM32F7_I2C_OAR1_OA1_10_MASK GENMASK(9, 0) 1038c2ecf20Sopenharmony_ci#define STM32F7_I2C_OAR1_OA1_10(n) (((n) & \ 1048c2ecf20Sopenharmony_ci STM32F7_I2C_OAR1_OA1_10_MASK)) 1058c2ecf20Sopenharmony_ci#define STM32F7_I2C_OAR1_OA1_7_MASK GENMASK(7, 1) 1068c2ecf20Sopenharmony_ci#define STM32F7_I2C_OAR1_OA1_7(n) (((n) & 0x7f) << 1) 1078c2ecf20Sopenharmony_ci#define STM32F7_I2C_OAR1_MASK (STM32F7_I2C_OAR1_OA1_7_MASK \ 1088c2ecf20Sopenharmony_ci | STM32F7_I2C_OAR1_OA1_10_MASK \ 1098c2ecf20Sopenharmony_ci | STM32F7_I2C_OAR1_OA1EN \ 1108c2ecf20Sopenharmony_ci | STM32F7_I2C_OAR1_OA1MODE) 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* STM32F7 I2C Own Address 2 */ 1138c2ecf20Sopenharmony_ci#define STM32F7_I2C_OAR2_OA2EN BIT(15) 1148c2ecf20Sopenharmony_ci#define STM32F7_I2C_OAR2_OA2MSK_MASK GENMASK(10, 8) 1158c2ecf20Sopenharmony_ci#define STM32F7_I2C_OAR2_OA2MSK(n) (((n) & 0x7) << 8) 1168c2ecf20Sopenharmony_ci#define STM32F7_I2C_OAR2_OA2_7_MASK GENMASK(7, 1) 1178c2ecf20Sopenharmony_ci#define STM32F7_I2C_OAR2_OA2_7(n) (((n) & 0x7f) << 1) 1188c2ecf20Sopenharmony_ci#define STM32F7_I2C_OAR2_MASK (STM32F7_I2C_OAR2_OA2MSK_MASK \ 1198c2ecf20Sopenharmony_ci | STM32F7_I2C_OAR2_OA2_7_MASK \ 1208c2ecf20Sopenharmony_ci | STM32F7_I2C_OAR2_OA2EN) 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/* STM32F7 I2C Interrupt Status */ 1238c2ecf20Sopenharmony_ci#define STM32F7_I2C_ISR_ADDCODE_MASK GENMASK(23, 17) 1248c2ecf20Sopenharmony_ci#define STM32F7_I2C_ISR_ADDCODE_GET(n) \ 1258c2ecf20Sopenharmony_ci (((n) & STM32F7_I2C_ISR_ADDCODE_MASK) >> 17) 1268c2ecf20Sopenharmony_ci#define STM32F7_I2C_ISR_DIR BIT(16) 1278c2ecf20Sopenharmony_ci#define STM32F7_I2C_ISR_BUSY BIT(15) 1288c2ecf20Sopenharmony_ci#define STM32F7_I2C_ISR_PECERR BIT(11) 1298c2ecf20Sopenharmony_ci#define STM32F7_I2C_ISR_ARLO BIT(9) 1308c2ecf20Sopenharmony_ci#define STM32F7_I2C_ISR_BERR BIT(8) 1318c2ecf20Sopenharmony_ci#define STM32F7_I2C_ISR_TCR BIT(7) 1328c2ecf20Sopenharmony_ci#define STM32F7_I2C_ISR_TC BIT(6) 1338c2ecf20Sopenharmony_ci#define STM32F7_I2C_ISR_STOPF BIT(5) 1348c2ecf20Sopenharmony_ci#define STM32F7_I2C_ISR_NACKF BIT(4) 1358c2ecf20Sopenharmony_ci#define STM32F7_I2C_ISR_ADDR BIT(3) 1368c2ecf20Sopenharmony_ci#define STM32F7_I2C_ISR_RXNE BIT(2) 1378c2ecf20Sopenharmony_ci#define STM32F7_I2C_ISR_TXIS BIT(1) 1388c2ecf20Sopenharmony_ci#define STM32F7_I2C_ISR_TXE BIT(0) 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* STM32F7 I2C Interrupt Clear */ 1418c2ecf20Sopenharmony_ci#define STM32F7_I2C_ICR_PECCF BIT(11) 1428c2ecf20Sopenharmony_ci#define STM32F7_I2C_ICR_ARLOCF BIT(9) 1438c2ecf20Sopenharmony_ci#define STM32F7_I2C_ICR_BERRCF BIT(8) 1448c2ecf20Sopenharmony_ci#define STM32F7_I2C_ICR_STOPCF BIT(5) 1458c2ecf20Sopenharmony_ci#define STM32F7_I2C_ICR_NACKCF BIT(4) 1468c2ecf20Sopenharmony_ci#define STM32F7_I2C_ICR_ADDRCF BIT(3) 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci/* STM32F7 I2C Timing */ 1498c2ecf20Sopenharmony_ci#define STM32F7_I2C_TIMINGR_PRESC(n) (((n) & 0xf) << 28) 1508c2ecf20Sopenharmony_ci#define STM32F7_I2C_TIMINGR_SCLDEL(n) (((n) & 0xf) << 20) 1518c2ecf20Sopenharmony_ci#define STM32F7_I2C_TIMINGR_SDADEL(n) (((n) & 0xf) << 16) 1528c2ecf20Sopenharmony_ci#define STM32F7_I2C_TIMINGR_SCLH(n) (((n) & 0xff) << 8) 1538c2ecf20Sopenharmony_ci#define STM32F7_I2C_TIMINGR_SCLL(n) ((n) & 0xff) 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci#define STM32F7_I2C_MAX_LEN 0xff 1568c2ecf20Sopenharmony_ci#define STM32F7_I2C_DMA_LEN_MIN 0x16 1578c2ecf20Sopenharmony_cienum { 1588c2ecf20Sopenharmony_ci STM32F7_SLAVE_HOSTNOTIFY, 1598c2ecf20Sopenharmony_ci STM32F7_SLAVE_7_10_BITS_ADDR, 1608c2ecf20Sopenharmony_ci STM32F7_SLAVE_7_BITS_ADDR, 1618c2ecf20Sopenharmony_ci STM32F7_I2C_MAX_SLAVE 1628c2ecf20Sopenharmony_ci}; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci#define STM32F7_I2C_DNF_DEFAULT 0 1658c2ecf20Sopenharmony_ci#define STM32F7_I2C_DNF_MAX 15 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci#define STM32F7_I2C_ANALOG_FILTER_ENABLE 1 1688c2ecf20Sopenharmony_ci#define STM32F7_I2C_ANALOG_FILTER_DELAY_MIN 50 /* ns */ 1698c2ecf20Sopenharmony_ci#define STM32F7_I2C_ANALOG_FILTER_DELAY_MAX 260 /* ns */ 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci#define STM32F7_I2C_RISE_TIME_DEFAULT 25 /* ns */ 1728c2ecf20Sopenharmony_ci#define STM32F7_I2C_FALL_TIME_DEFAULT 10 /* ns */ 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci#define STM32F7_PRESC_MAX BIT(4) 1758c2ecf20Sopenharmony_ci#define STM32F7_SCLDEL_MAX BIT(4) 1768c2ecf20Sopenharmony_ci#define STM32F7_SDADEL_MAX BIT(4) 1778c2ecf20Sopenharmony_ci#define STM32F7_SCLH_MAX BIT(8) 1788c2ecf20Sopenharmony_ci#define STM32F7_SCLL_MAX BIT(8) 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci#define STM32F7_AUTOSUSPEND_DELAY (HZ / 100) 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/** 1838c2ecf20Sopenharmony_ci * struct stm32f7_i2c_regs - i2c f7 registers backup 1848c2ecf20Sopenharmony_ci * @cr1: Control register 1 1858c2ecf20Sopenharmony_ci * @cr2: Control register 2 1868c2ecf20Sopenharmony_ci * @oar1: Own address 1 register 1878c2ecf20Sopenharmony_ci * @oar2: Own address 2 register 1888c2ecf20Sopenharmony_ci * @tmgr: Timing register 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_cistruct stm32f7_i2c_regs { 1918c2ecf20Sopenharmony_ci u32 cr1; 1928c2ecf20Sopenharmony_ci u32 cr2; 1938c2ecf20Sopenharmony_ci u32 oar1; 1948c2ecf20Sopenharmony_ci u32 oar2; 1958c2ecf20Sopenharmony_ci u32 tmgr; 1968c2ecf20Sopenharmony_ci}; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/** 1998c2ecf20Sopenharmony_ci * struct stm32f7_i2c_spec - private i2c specification timing 2008c2ecf20Sopenharmony_ci * @rate: I2C bus speed (Hz) 2018c2ecf20Sopenharmony_ci * @fall_max: Max fall time of both SDA and SCL signals (ns) 2028c2ecf20Sopenharmony_ci * @rise_max: Max rise time of both SDA and SCL signals (ns) 2038c2ecf20Sopenharmony_ci * @hddat_min: Min data hold time (ns) 2048c2ecf20Sopenharmony_ci * @vddat_max: Max data valid time (ns) 2058c2ecf20Sopenharmony_ci * @sudat_min: Min data setup time (ns) 2068c2ecf20Sopenharmony_ci * @l_min: Min low period of the SCL clock (ns) 2078c2ecf20Sopenharmony_ci * @h_min: Min high period of the SCL clock (ns) 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_cistruct stm32f7_i2c_spec { 2108c2ecf20Sopenharmony_ci u32 rate; 2118c2ecf20Sopenharmony_ci u32 fall_max; 2128c2ecf20Sopenharmony_ci u32 rise_max; 2138c2ecf20Sopenharmony_ci u32 hddat_min; 2148c2ecf20Sopenharmony_ci u32 vddat_max; 2158c2ecf20Sopenharmony_ci u32 sudat_min; 2168c2ecf20Sopenharmony_ci u32 l_min; 2178c2ecf20Sopenharmony_ci u32 h_min; 2188c2ecf20Sopenharmony_ci}; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/** 2218c2ecf20Sopenharmony_ci * struct stm32f7_i2c_setup - private I2C timing setup parameters 2228c2ecf20Sopenharmony_ci * @speed_freq: I2C speed frequency (Hz) 2238c2ecf20Sopenharmony_ci * @clock_src: I2C clock source frequency (Hz) 2248c2ecf20Sopenharmony_ci * @rise_time: Rise time (ns) 2258c2ecf20Sopenharmony_ci * @fall_time: Fall time (ns) 2268c2ecf20Sopenharmony_ci * @dnf: Digital filter coefficient (0-16) 2278c2ecf20Sopenharmony_ci * @analog_filter: Analog filter delay (On/Off) 2288c2ecf20Sopenharmony_ci * @fmp_clr_offset: Fast Mode Plus clear register offset from set register 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_cistruct stm32f7_i2c_setup { 2318c2ecf20Sopenharmony_ci u32 speed_freq; 2328c2ecf20Sopenharmony_ci u32 clock_src; 2338c2ecf20Sopenharmony_ci u32 rise_time; 2348c2ecf20Sopenharmony_ci u32 fall_time; 2358c2ecf20Sopenharmony_ci u8 dnf; 2368c2ecf20Sopenharmony_ci bool analog_filter; 2378c2ecf20Sopenharmony_ci u32 fmp_clr_offset; 2388c2ecf20Sopenharmony_ci}; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci/** 2418c2ecf20Sopenharmony_ci * struct stm32f7_i2c_timings - private I2C output parameters 2428c2ecf20Sopenharmony_ci * @node: List entry 2438c2ecf20Sopenharmony_ci * @presc: Prescaler value 2448c2ecf20Sopenharmony_ci * @scldel: Data setup time 2458c2ecf20Sopenharmony_ci * @sdadel: Data hold time 2468c2ecf20Sopenharmony_ci * @sclh: SCL high period (master mode) 2478c2ecf20Sopenharmony_ci * @scll: SCL low period (master mode) 2488c2ecf20Sopenharmony_ci */ 2498c2ecf20Sopenharmony_cistruct stm32f7_i2c_timings { 2508c2ecf20Sopenharmony_ci struct list_head node; 2518c2ecf20Sopenharmony_ci u8 presc; 2528c2ecf20Sopenharmony_ci u8 scldel; 2538c2ecf20Sopenharmony_ci u8 sdadel; 2548c2ecf20Sopenharmony_ci u8 sclh; 2558c2ecf20Sopenharmony_ci u8 scll; 2568c2ecf20Sopenharmony_ci}; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci/** 2598c2ecf20Sopenharmony_ci * struct stm32f7_i2c_msg - client specific data 2608c2ecf20Sopenharmony_ci * @addr: 8-bit or 10-bit slave addr, including r/w bit 2618c2ecf20Sopenharmony_ci * @count: number of bytes to be transferred 2628c2ecf20Sopenharmony_ci * @buf: data buffer 2638c2ecf20Sopenharmony_ci * @result: result of the transfer 2648c2ecf20Sopenharmony_ci * @stop: last I2C msg to be sent, i.e. STOP to be generated 2658c2ecf20Sopenharmony_ci * @smbus: boolean to know if the I2C IP is used in SMBus mode 2668c2ecf20Sopenharmony_ci * @size: type of SMBus protocol 2678c2ecf20Sopenharmony_ci * @read_write: direction of SMBus protocol 2688c2ecf20Sopenharmony_ci * SMBus block read and SMBus block write - block read process call protocols 2698c2ecf20Sopenharmony_ci * @smbus_buf: buffer to be used for SMBus protocol transfer. It will 2708c2ecf20Sopenharmony_ci * contain a maximum of 32 bytes of data + byte command + byte count + PEC 2718c2ecf20Sopenharmony_ci * This buffer has to be 32-bit aligned to be compliant with memory address 2728c2ecf20Sopenharmony_ci * register in DMA mode. 2738c2ecf20Sopenharmony_ci */ 2748c2ecf20Sopenharmony_cistruct stm32f7_i2c_msg { 2758c2ecf20Sopenharmony_ci u16 addr; 2768c2ecf20Sopenharmony_ci u32 count; 2778c2ecf20Sopenharmony_ci u8 *buf; 2788c2ecf20Sopenharmony_ci int result; 2798c2ecf20Sopenharmony_ci bool stop; 2808c2ecf20Sopenharmony_ci bool smbus; 2818c2ecf20Sopenharmony_ci int size; 2828c2ecf20Sopenharmony_ci char read_write; 2838c2ecf20Sopenharmony_ci u8 smbus_buf[I2C_SMBUS_BLOCK_MAX + 3] __aligned(4); 2848c2ecf20Sopenharmony_ci}; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/** 2878c2ecf20Sopenharmony_ci * struct stm32f7_i2c_dev - private data of the controller 2888c2ecf20Sopenharmony_ci * @adap: I2C adapter for this controller 2898c2ecf20Sopenharmony_ci * @dev: device for this controller 2908c2ecf20Sopenharmony_ci * @base: virtual memory area 2918c2ecf20Sopenharmony_ci * @complete: completion of I2C message 2928c2ecf20Sopenharmony_ci * @clk: hw i2c clock 2938c2ecf20Sopenharmony_ci * @bus_rate: I2C clock frequency of the controller 2948c2ecf20Sopenharmony_ci * @msg: Pointer to data to be written 2958c2ecf20Sopenharmony_ci * @msg_num: number of I2C messages to be executed 2968c2ecf20Sopenharmony_ci * @msg_id: message identifiant 2978c2ecf20Sopenharmony_ci * @f7_msg: customized i2c msg for driver usage 2988c2ecf20Sopenharmony_ci * @setup: I2C timing input setup 2998c2ecf20Sopenharmony_ci * @timing: I2C computed timings 3008c2ecf20Sopenharmony_ci * @slave: list of slave devices registered on the I2C bus 3018c2ecf20Sopenharmony_ci * @slave_running: slave device currently used 3028c2ecf20Sopenharmony_ci * @backup_regs: backup of i2c controller registers (for suspend/resume) 3038c2ecf20Sopenharmony_ci * @slave_dir: transfer direction for the current slave device 3048c2ecf20Sopenharmony_ci * @master_mode: boolean to know in which mode the I2C is running (master or 3058c2ecf20Sopenharmony_ci * slave) 3068c2ecf20Sopenharmony_ci * @dma: dma data 3078c2ecf20Sopenharmony_ci * @use_dma: boolean to know if dma is used in the current transfer 3088c2ecf20Sopenharmony_ci * @regmap: holds SYSCFG phandle for Fast Mode Plus bits 3098c2ecf20Sopenharmony_ci * @fmp_sreg: register address for setting Fast Mode Plus bits 3108c2ecf20Sopenharmony_ci * @fmp_creg: register address for clearing Fast Mode Plus bits 3118c2ecf20Sopenharmony_ci * @fmp_mask: mask for Fast Mode Plus bits in set register 3128c2ecf20Sopenharmony_ci * @wakeup_src: boolean to know if the device is a wakeup source 3138c2ecf20Sopenharmony_ci * @smbus_mode: states that the controller is configured in SMBus mode 3148c2ecf20Sopenharmony_ci * @host_notify_client: SMBus host-notify client 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_cistruct stm32f7_i2c_dev { 3178c2ecf20Sopenharmony_ci struct i2c_adapter adap; 3188c2ecf20Sopenharmony_ci struct device *dev; 3198c2ecf20Sopenharmony_ci void __iomem *base; 3208c2ecf20Sopenharmony_ci struct completion complete; 3218c2ecf20Sopenharmony_ci struct clk *clk; 3228c2ecf20Sopenharmony_ci unsigned int bus_rate; 3238c2ecf20Sopenharmony_ci struct i2c_msg *msg; 3248c2ecf20Sopenharmony_ci unsigned int msg_num; 3258c2ecf20Sopenharmony_ci unsigned int msg_id; 3268c2ecf20Sopenharmony_ci struct stm32f7_i2c_msg f7_msg; 3278c2ecf20Sopenharmony_ci struct stm32f7_i2c_setup setup; 3288c2ecf20Sopenharmony_ci struct stm32f7_i2c_timings timing; 3298c2ecf20Sopenharmony_ci struct i2c_client *slave[STM32F7_I2C_MAX_SLAVE]; 3308c2ecf20Sopenharmony_ci struct i2c_client *slave_running; 3318c2ecf20Sopenharmony_ci struct stm32f7_i2c_regs backup_regs; 3328c2ecf20Sopenharmony_ci u32 slave_dir; 3338c2ecf20Sopenharmony_ci bool master_mode; 3348c2ecf20Sopenharmony_ci struct stm32_i2c_dma *dma; 3358c2ecf20Sopenharmony_ci bool use_dma; 3368c2ecf20Sopenharmony_ci struct regmap *regmap; 3378c2ecf20Sopenharmony_ci u32 fmp_sreg; 3388c2ecf20Sopenharmony_ci u32 fmp_creg; 3398c2ecf20Sopenharmony_ci u32 fmp_mask; 3408c2ecf20Sopenharmony_ci bool wakeup_src; 3418c2ecf20Sopenharmony_ci bool smbus_mode; 3428c2ecf20Sopenharmony_ci struct i2c_client *host_notify_client; 3438c2ecf20Sopenharmony_ci}; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci/* 3468c2ecf20Sopenharmony_ci * All these values are coming from I2C Specification, Version 6.0, 4th of 3478c2ecf20Sopenharmony_ci * April 2014. 3488c2ecf20Sopenharmony_ci * 3498c2ecf20Sopenharmony_ci * Table10. Characteristics of the SDA and SCL bus lines for Standard, Fast, 3508c2ecf20Sopenharmony_ci * and Fast-mode Plus I2C-bus devices 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_cistatic struct stm32f7_i2c_spec stm32f7_i2c_specs[] = { 3538c2ecf20Sopenharmony_ci { 3548c2ecf20Sopenharmony_ci .rate = I2C_MAX_STANDARD_MODE_FREQ, 3558c2ecf20Sopenharmony_ci .fall_max = 300, 3568c2ecf20Sopenharmony_ci .rise_max = 1000, 3578c2ecf20Sopenharmony_ci .hddat_min = 0, 3588c2ecf20Sopenharmony_ci .vddat_max = 3450, 3598c2ecf20Sopenharmony_ci .sudat_min = 250, 3608c2ecf20Sopenharmony_ci .l_min = 4700, 3618c2ecf20Sopenharmony_ci .h_min = 4000, 3628c2ecf20Sopenharmony_ci }, 3638c2ecf20Sopenharmony_ci { 3648c2ecf20Sopenharmony_ci .rate = I2C_MAX_FAST_MODE_FREQ, 3658c2ecf20Sopenharmony_ci .fall_max = 300, 3668c2ecf20Sopenharmony_ci .rise_max = 300, 3678c2ecf20Sopenharmony_ci .hddat_min = 0, 3688c2ecf20Sopenharmony_ci .vddat_max = 900, 3698c2ecf20Sopenharmony_ci .sudat_min = 100, 3708c2ecf20Sopenharmony_ci .l_min = 1300, 3718c2ecf20Sopenharmony_ci .h_min = 600, 3728c2ecf20Sopenharmony_ci }, 3738c2ecf20Sopenharmony_ci { 3748c2ecf20Sopenharmony_ci .rate = I2C_MAX_FAST_MODE_PLUS_FREQ, 3758c2ecf20Sopenharmony_ci .fall_max = 100, 3768c2ecf20Sopenharmony_ci .rise_max = 120, 3778c2ecf20Sopenharmony_ci .hddat_min = 0, 3788c2ecf20Sopenharmony_ci .vddat_max = 450, 3798c2ecf20Sopenharmony_ci .sudat_min = 50, 3808c2ecf20Sopenharmony_ci .l_min = 500, 3818c2ecf20Sopenharmony_ci .h_min = 260, 3828c2ecf20Sopenharmony_ci }, 3838c2ecf20Sopenharmony_ci}; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic const struct stm32f7_i2c_setup stm32f7_setup = { 3868c2ecf20Sopenharmony_ci .rise_time = STM32F7_I2C_RISE_TIME_DEFAULT, 3878c2ecf20Sopenharmony_ci .fall_time = STM32F7_I2C_FALL_TIME_DEFAULT, 3888c2ecf20Sopenharmony_ci .dnf = STM32F7_I2C_DNF_DEFAULT, 3898c2ecf20Sopenharmony_ci .analog_filter = STM32F7_I2C_ANALOG_FILTER_ENABLE, 3908c2ecf20Sopenharmony_ci}; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic const struct stm32f7_i2c_setup stm32mp15_setup = { 3938c2ecf20Sopenharmony_ci .rise_time = STM32F7_I2C_RISE_TIME_DEFAULT, 3948c2ecf20Sopenharmony_ci .fall_time = STM32F7_I2C_FALL_TIME_DEFAULT, 3958c2ecf20Sopenharmony_ci .dnf = STM32F7_I2C_DNF_DEFAULT, 3968c2ecf20Sopenharmony_ci .analog_filter = STM32F7_I2C_ANALOG_FILTER_ENABLE, 3978c2ecf20Sopenharmony_ci .fmp_clr_offset = 0x40, 3988c2ecf20Sopenharmony_ci}; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic inline void stm32f7_i2c_set_bits(void __iomem *reg, u32 mask) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci writel_relaxed(readl_relaxed(reg) | mask, reg); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic inline void stm32f7_i2c_clr_bits(void __iomem *reg, u32 mask) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci writel_relaxed(readl_relaxed(reg) & ~mask, reg); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic void stm32f7_i2c_disable_irq(struct stm32f7_i2c_dev *i2c_dev, u32 mask) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, mask); 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic struct stm32f7_i2c_spec *stm32f7_get_specs(u32 rate) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci int i; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(stm32f7_i2c_specs); i++) 4208c2ecf20Sopenharmony_ci if (rate <= stm32f7_i2c_specs[i].rate) 4218c2ecf20Sopenharmony_ci return &stm32f7_i2c_specs[i]; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci#define RATE_MIN(rate) ((rate) * 8 / 10) 4278c2ecf20Sopenharmony_cistatic int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, 4288c2ecf20Sopenharmony_ci struct stm32f7_i2c_setup *setup, 4298c2ecf20Sopenharmony_ci struct stm32f7_i2c_timings *output) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci struct stm32f7_i2c_spec *specs; 4328c2ecf20Sopenharmony_ci u32 p_prev = STM32F7_PRESC_MAX; 4338c2ecf20Sopenharmony_ci u32 i2cclk = DIV_ROUND_CLOSEST(NSEC_PER_SEC, 4348c2ecf20Sopenharmony_ci setup->clock_src); 4358c2ecf20Sopenharmony_ci u32 i2cbus = DIV_ROUND_CLOSEST(NSEC_PER_SEC, 4368c2ecf20Sopenharmony_ci setup->speed_freq); 4378c2ecf20Sopenharmony_ci u32 clk_error_prev = i2cbus; 4388c2ecf20Sopenharmony_ci u32 tsync; 4398c2ecf20Sopenharmony_ci u32 af_delay_min, af_delay_max; 4408c2ecf20Sopenharmony_ci u32 dnf_delay; 4418c2ecf20Sopenharmony_ci u32 clk_min, clk_max; 4428c2ecf20Sopenharmony_ci int sdadel_min, sdadel_max; 4438c2ecf20Sopenharmony_ci int scldel_min; 4448c2ecf20Sopenharmony_ci struct stm32f7_i2c_timings *v, *_v, *s; 4458c2ecf20Sopenharmony_ci struct list_head solutions; 4468c2ecf20Sopenharmony_ci u16 p, l, a, h; 4478c2ecf20Sopenharmony_ci int ret = 0; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci specs = stm32f7_get_specs(setup->speed_freq); 4508c2ecf20Sopenharmony_ci if (specs == ERR_PTR(-EINVAL)) { 4518c2ecf20Sopenharmony_ci dev_err(i2c_dev->dev, "speed out of bound {%d}\n", 4528c2ecf20Sopenharmony_ci setup->speed_freq); 4538c2ecf20Sopenharmony_ci return -EINVAL; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if ((setup->rise_time > specs->rise_max) || 4578c2ecf20Sopenharmony_ci (setup->fall_time > specs->fall_max)) { 4588c2ecf20Sopenharmony_ci dev_err(i2c_dev->dev, 4598c2ecf20Sopenharmony_ci "timings out of bound Rise{%d>%d}/Fall{%d>%d}\n", 4608c2ecf20Sopenharmony_ci setup->rise_time, specs->rise_max, 4618c2ecf20Sopenharmony_ci setup->fall_time, specs->fall_max); 4628c2ecf20Sopenharmony_ci return -EINVAL; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (setup->dnf > STM32F7_I2C_DNF_MAX) { 4668c2ecf20Sopenharmony_ci dev_err(i2c_dev->dev, 4678c2ecf20Sopenharmony_ci "DNF out of bound %d/%d\n", 4688c2ecf20Sopenharmony_ci setup->dnf, STM32F7_I2C_DNF_MAX); 4698c2ecf20Sopenharmony_ci return -EINVAL; 4708c2ecf20Sopenharmony_ci } 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* Analog and Digital Filters */ 4738c2ecf20Sopenharmony_ci af_delay_min = 4748c2ecf20Sopenharmony_ci (setup->analog_filter ? 4758c2ecf20Sopenharmony_ci STM32F7_I2C_ANALOG_FILTER_DELAY_MIN : 0); 4768c2ecf20Sopenharmony_ci af_delay_max = 4778c2ecf20Sopenharmony_ci (setup->analog_filter ? 4788c2ecf20Sopenharmony_ci STM32F7_I2C_ANALOG_FILTER_DELAY_MAX : 0); 4798c2ecf20Sopenharmony_ci dnf_delay = setup->dnf * i2cclk; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci sdadel_min = specs->hddat_min + setup->fall_time - 4828c2ecf20Sopenharmony_ci af_delay_min - (setup->dnf + 3) * i2cclk; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci sdadel_max = specs->vddat_max - setup->rise_time - 4858c2ecf20Sopenharmony_ci af_delay_max - (setup->dnf + 4) * i2cclk; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci scldel_min = setup->rise_time + specs->sudat_min; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci if (sdadel_min < 0) 4908c2ecf20Sopenharmony_ci sdadel_min = 0; 4918c2ecf20Sopenharmony_ci if (sdadel_max < 0) 4928c2ecf20Sopenharmony_ci sdadel_max = 0; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci dev_dbg(i2c_dev->dev, "SDADEL(min/max): %i/%i, SCLDEL(Min): %i\n", 4958c2ecf20Sopenharmony_ci sdadel_min, sdadel_max, scldel_min); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&solutions); 4988c2ecf20Sopenharmony_ci /* Compute possible values for PRESC, SCLDEL and SDADEL */ 4998c2ecf20Sopenharmony_ci for (p = 0; p < STM32F7_PRESC_MAX; p++) { 5008c2ecf20Sopenharmony_ci for (l = 0; l < STM32F7_SCLDEL_MAX; l++) { 5018c2ecf20Sopenharmony_ci u32 scldel = (l + 1) * (p + 1) * i2cclk; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (scldel < scldel_min) 5048c2ecf20Sopenharmony_ci continue; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci for (a = 0; a < STM32F7_SDADEL_MAX; a++) { 5078c2ecf20Sopenharmony_ci u32 sdadel = (a * (p + 1) + 1) * i2cclk; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (((sdadel >= sdadel_min) && 5108c2ecf20Sopenharmony_ci (sdadel <= sdadel_max)) && 5118c2ecf20Sopenharmony_ci (p != p_prev)) { 5128c2ecf20Sopenharmony_ci v = kmalloc(sizeof(*v), GFP_KERNEL); 5138c2ecf20Sopenharmony_ci if (!v) { 5148c2ecf20Sopenharmony_ci ret = -ENOMEM; 5158c2ecf20Sopenharmony_ci goto exit; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci v->presc = p; 5198c2ecf20Sopenharmony_ci v->scldel = l; 5208c2ecf20Sopenharmony_ci v->sdadel = a; 5218c2ecf20Sopenharmony_ci p_prev = p; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci list_add_tail(&v->node, 5248c2ecf20Sopenharmony_ci &solutions); 5258c2ecf20Sopenharmony_ci break; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (p_prev == p) 5308c2ecf20Sopenharmony_ci break; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (list_empty(&solutions)) { 5358c2ecf20Sopenharmony_ci dev_err(i2c_dev->dev, "no Prescaler solution\n"); 5368c2ecf20Sopenharmony_ci ret = -EPERM; 5378c2ecf20Sopenharmony_ci goto exit; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci tsync = af_delay_min + dnf_delay + (2 * i2cclk); 5418c2ecf20Sopenharmony_ci s = NULL; 5428c2ecf20Sopenharmony_ci clk_max = NSEC_PER_SEC / RATE_MIN(setup->speed_freq); 5438c2ecf20Sopenharmony_ci clk_min = NSEC_PER_SEC / setup->speed_freq; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci /* 5468c2ecf20Sopenharmony_ci * Among Prescaler possibilities discovered above figures out SCL Low 5478c2ecf20Sopenharmony_ci * and High Period. Provided: 5488c2ecf20Sopenharmony_ci * - SCL Low Period has to be higher than SCL Clock Low Period 5498c2ecf20Sopenharmony_ci * defined by I2C Specification. I2C Clock has to be lower than 5508c2ecf20Sopenharmony_ci * (SCL Low Period - Analog/Digital filters) / 4. 5518c2ecf20Sopenharmony_ci * - SCL High Period has to be lower than SCL Clock High Period 5528c2ecf20Sopenharmony_ci * defined by I2C Specification 5538c2ecf20Sopenharmony_ci * - I2C Clock has to be lower than SCL High Period 5548c2ecf20Sopenharmony_ci */ 5558c2ecf20Sopenharmony_ci list_for_each_entry(v, &solutions, node) { 5568c2ecf20Sopenharmony_ci u32 prescaler = (v->presc + 1) * i2cclk; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci for (l = 0; l < STM32F7_SCLL_MAX; l++) { 5598c2ecf20Sopenharmony_ci u32 tscl_l = (l + 1) * prescaler + tsync; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if ((tscl_l < specs->l_min) || 5628c2ecf20Sopenharmony_ci (i2cclk >= 5638c2ecf20Sopenharmony_ci ((tscl_l - af_delay_min - dnf_delay) / 4))) { 5648c2ecf20Sopenharmony_ci continue; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci for (h = 0; h < STM32F7_SCLH_MAX; h++) { 5688c2ecf20Sopenharmony_ci u32 tscl_h = (h + 1) * prescaler + tsync; 5698c2ecf20Sopenharmony_ci u32 tscl = tscl_l + tscl_h + 5708c2ecf20Sopenharmony_ci setup->rise_time + setup->fall_time; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if ((tscl >= clk_min) && (tscl <= clk_max) && 5738c2ecf20Sopenharmony_ci (tscl_h >= specs->h_min) && 5748c2ecf20Sopenharmony_ci (i2cclk < tscl_h)) { 5758c2ecf20Sopenharmony_ci int clk_error = tscl - i2cbus; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (clk_error < 0) 5788c2ecf20Sopenharmony_ci clk_error = -clk_error; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (clk_error < clk_error_prev) { 5818c2ecf20Sopenharmony_ci clk_error_prev = clk_error; 5828c2ecf20Sopenharmony_ci v->scll = l; 5838c2ecf20Sopenharmony_ci v->sclh = h; 5848c2ecf20Sopenharmony_ci s = v; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci if (!s) { 5928c2ecf20Sopenharmony_ci dev_err(i2c_dev->dev, "no solution at all\n"); 5938c2ecf20Sopenharmony_ci ret = -EPERM; 5948c2ecf20Sopenharmony_ci goto exit; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci output->presc = s->presc; 5988c2ecf20Sopenharmony_ci output->scldel = s->scldel; 5998c2ecf20Sopenharmony_ci output->sdadel = s->sdadel; 6008c2ecf20Sopenharmony_ci output->scll = s->scll; 6018c2ecf20Sopenharmony_ci output->sclh = s->sclh; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci dev_dbg(i2c_dev->dev, 6048c2ecf20Sopenharmony_ci "Presc: %i, scldel: %i, sdadel: %i, scll: %i, sclh: %i\n", 6058c2ecf20Sopenharmony_ci output->presc, 6068c2ecf20Sopenharmony_ci output->scldel, output->sdadel, 6078c2ecf20Sopenharmony_ci output->scll, output->sclh); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ciexit: 6108c2ecf20Sopenharmony_ci /* Release list and memory */ 6118c2ecf20Sopenharmony_ci list_for_each_entry_safe(v, _v, &solutions, node) { 6128c2ecf20Sopenharmony_ci list_del(&v->node); 6138c2ecf20Sopenharmony_ci kfree(v); 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci return ret; 6178c2ecf20Sopenharmony_ci} 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic u32 stm32f7_get_lower_rate(u32 rate) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci int i = ARRAY_SIZE(stm32f7_i2c_specs); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci while (--i) 6248c2ecf20Sopenharmony_ci if (stm32f7_i2c_specs[i].rate < rate) 6258c2ecf20Sopenharmony_ci break; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci return stm32f7_i2c_specs[i].rate; 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_cistatic int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, 6318c2ecf20Sopenharmony_ci struct stm32f7_i2c_setup *setup) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci struct i2c_timings timings, *t = &timings; 6348c2ecf20Sopenharmony_ci int ret = 0; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci t->bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ; 6378c2ecf20Sopenharmony_ci t->scl_rise_ns = i2c_dev->setup.rise_time; 6388c2ecf20Sopenharmony_ci t->scl_fall_ns = i2c_dev->setup.fall_time; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci i2c_parse_fw_timings(i2c_dev->dev, t, false); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (t->bus_freq_hz > I2C_MAX_FAST_MODE_PLUS_FREQ) { 6438c2ecf20Sopenharmony_ci dev_err(i2c_dev->dev, "Invalid bus speed (%i>%i)\n", 6448c2ecf20Sopenharmony_ci t->bus_freq_hz, I2C_MAX_FAST_MODE_PLUS_FREQ); 6458c2ecf20Sopenharmony_ci return -EINVAL; 6468c2ecf20Sopenharmony_ci } 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci setup->speed_freq = t->bus_freq_hz; 6498c2ecf20Sopenharmony_ci i2c_dev->setup.rise_time = t->scl_rise_ns; 6508c2ecf20Sopenharmony_ci i2c_dev->setup.fall_time = t->scl_fall_ns; 6518c2ecf20Sopenharmony_ci setup->clock_src = clk_get_rate(i2c_dev->clk); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci if (!setup->clock_src) { 6548c2ecf20Sopenharmony_ci dev_err(i2c_dev->dev, "clock rate is 0\n"); 6558c2ecf20Sopenharmony_ci return -EINVAL; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci do { 6598c2ecf20Sopenharmony_ci ret = stm32f7_i2c_compute_timing(i2c_dev, setup, 6608c2ecf20Sopenharmony_ci &i2c_dev->timing); 6618c2ecf20Sopenharmony_ci if (ret) { 6628c2ecf20Sopenharmony_ci dev_err(i2c_dev->dev, 6638c2ecf20Sopenharmony_ci "failed to compute I2C timings.\n"); 6648c2ecf20Sopenharmony_ci if (setup->speed_freq <= I2C_MAX_STANDARD_MODE_FREQ) 6658c2ecf20Sopenharmony_ci break; 6668c2ecf20Sopenharmony_ci setup->speed_freq = 6678c2ecf20Sopenharmony_ci stm32f7_get_lower_rate(setup->speed_freq); 6688c2ecf20Sopenharmony_ci dev_warn(i2c_dev->dev, 6698c2ecf20Sopenharmony_ci "downgrade I2C Speed Freq to (%i)\n", 6708c2ecf20Sopenharmony_ci setup->speed_freq); 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci } while (ret); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (ret) { 6758c2ecf20Sopenharmony_ci dev_err(i2c_dev->dev, "Impossible to compute I2C timings.\n"); 6768c2ecf20Sopenharmony_ci return ret; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci dev_dbg(i2c_dev->dev, "I2C Speed(%i), Clk Source(%i)\n", 6808c2ecf20Sopenharmony_ci setup->speed_freq, setup->clock_src); 6818c2ecf20Sopenharmony_ci dev_dbg(i2c_dev->dev, "I2C Rise(%i) and Fall(%i) Time\n", 6828c2ecf20Sopenharmony_ci setup->rise_time, setup->fall_time); 6838c2ecf20Sopenharmony_ci dev_dbg(i2c_dev->dev, "I2C Analog Filter(%s), DNF(%i)\n", 6848c2ecf20Sopenharmony_ci (setup->analog_filter ? "On" : "Off"), setup->dnf); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci i2c_dev->bus_rate = setup->speed_freq; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci return 0; 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic void stm32f7_i2c_disable_dma_req(struct stm32f7_i2c_dev *i2c_dev) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci void __iomem *base = i2c_dev->base; 6948c2ecf20Sopenharmony_ci u32 mask = STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask); 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_cistatic void stm32f7_i2c_dma_callback(void *arg) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci struct stm32f7_i2c_dev *i2c_dev = (struct stm32f7_i2c_dev *)arg; 7028c2ecf20Sopenharmony_ci struct stm32_i2c_dma *dma = i2c_dev->dma; 7038c2ecf20Sopenharmony_ci struct device *dev = dma->chan_using->device->dev; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci stm32f7_i2c_disable_dma_req(i2c_dev); 7068c2ecf20Sopenharmony_ci dma_unmap_single(dev, dma->dma_buf, dma->dma_len, dma->dma_data_dir); 7078c2ecf20Sopenharmony_ci complete(&dma->dma_complete); 7088c2ecf20Sopenharmony_ci} 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_cistatic void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci struct stm32f7_i2c_timings *t = &i2c_dev->timing; 7138c2ecf20Sopenharmony_ci u32 timing = 0; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci /* Timing settings */ 7168c2ecf20Sopenharmony_ci timing |= STM32F7_I2C_TIMINGR_PRESC(t->presc); 7178c2ecf20Sopenharmony_ci timing |= STM32F7_I2C_TIMINGR_SCLDEL(t->scldel); 7188c2ecf20Sopenharmony_ci timing |= STM32F7_I2C_TIMINGR_SDADEL(t->sdadel); 7198c2ecf20Sopenharmony_ci timing |= STM32F7_I2C_TIMINGR_SCLH(t->sclh); 7208c2ecf20Sopenharmony_ci timing |= STM32F7_I2C_TIMINGR_SCLL(t->scll); 7218c2ecf20Sopenharmony_ci writel_relaxed(timing, i2c_dev->base + STM32F7_I2C_TIMINGR); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci /* Enable I2C */ 7248c2ecf20Sopenharmony_ci if (i2c_dev->setup.analog_filter) 7258c2ecf20Sopenharmony_ci stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, 7268c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_ANFOFF); 7278c2ecf20Sopenharmony_ci else 7288c2ecf20Sopenharmony_ci stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1, 7298c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_ANFOFF); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* Program the Digital Filter */ 7328c2ecf20Sopenharmony_ci stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, 7338c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_DNF_MASK); 7348c2ecf20Sopenharmony_ci stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1, 7358c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_DNF(i2c_dev->setup.dnf)); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1, 7388c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_PE); 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic void stm32f7_i2c_write_tx_data(struct stm32f7_i2c_dev *i2c_dev) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; 7448c2ecf20Sopenharmony_ci void __iomem *base = i2c_dev->base; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (f7_msg->count) { 7478c2ecf20Sopenharmony_ci writeb_relaxed(*f7_msg->buf++, base + STM32F7_I2C_TXDR); 7488c2ecf20Sopenharmony_ci f7_msg->count--; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_cistatic void stm32f7_i2c_read_rx_data(struct stm32f7_i2c_dev *i2c_dev) 7538c2ecf20Sopenharmony_ci{ 7548c2ecf20Sopenharmony_ci struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; 7558c2ecf20Sopenharmony_ci void __iomem *base = i2c_dev->base; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if (f7_msg->count) { 7588c2ecf20Sopenharmony_ci *f7_msg->buf++ = readb_relaxed(base + STM32F7_I2C_RXDR); 7598c2ecf20Sopenharmony_ci f7_msg->count--; 7608c2ecf20Sopenharmony_ci } else { 7618c2ecf20Sopenharmony_ci /* Flush RX buffer has no data is expected */ 7628c2ecf20Sopenharmony_ci readb_relaxed(base + STM32F7_I2C_RXDR); 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cistatic void stm32f7_i2c_reload(struct stm32f7_i2c_dev *i2c_dev) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; 7698c2ecf20Sopenharmony_ci u32 cr2; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci if (i2c_dev->use_dma) 7728c2ecf20Sopenharmony_ci f7_msg->count -= STM32F7_I2C_MAX_LEN; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci cr2 &= ~STM32F7_I2C_CR2_NBYTES_MASK; 7778c2ecf20Sopenharmony_ci if (f7_msg->count > STM32F7_I2C_MAX_LEN) { 7788c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_NBYTES(STM32F7_I2C_MAX_LEN); 7798c2ecf20Sopenharmony_ci } else { 7808c2ecf20Sopenharmony_ci cr2 &= ~STM32F7_I2C_CR2_RELOAD; 7818c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count); 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2); 7858c2ecf20Sopenharmony_ci} 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_cistatic void stm32f7_i2c_smbus_reload(struct stm32f7_i2c_dev *i2c_dev) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; 7908c2ecf20Sopenharmony_ci u32 cr2; 7918c2ecf20Sopenharmony_ci u8 *val; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci /* 7948c2ecf20Sopenharmony_ci * For I2C_SMBUS_BLOCK_DATA && I2C_SMBUS_BLOCK_PROC_CALL, the first 7958c2ecf20Sopenharmony_ci * data received inform us how many data will follow. 7968c2ecf20Sopenharmony_ci */ 7978c2ecf20Sopenharmony_ci stm32f7_i2c_read_rx_data(i2c_dev); 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci /* 8008c2ecf20Sopenharmony_ci * Update NBYTES with the value read to continue the transfer 8018c2ecf20Sopenharmony_ci */ 8028c2ecf20Sopenharmony_ci val = f7_msg->buf - sizeof(u8); 8038c2ecf20Sopenharmony_ci f7_msg->count = *val; 8048c2ecf20Sopenharmony_ci cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2); 8058c2ecf20Sopenharmony_ci cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD); 8068c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count); 8078c2ecf20Sopenharmony_ci writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2); 8088c2ecf20Sopenharmony_ci} 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic int stm32f7_i2c_release_bus(struct i2c_adapter *i2c_adap) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci dev_info(i2c_dev->dev, "Trying to recover bus\n"); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, 8178c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_PE); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci stm32f7_i2c_hw_config(i2c_dev); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci return 0; 8228c2ecf20Sopenharmony_ci} 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_cistatic int stm32f7_i2c_wait_free_bus(struct stm32f7_i2c_dev *i2c_dev) 8258c2ecf20Sopenharmony_ci{ 8268c2ecf20Sopenharmony_ci u32 status; 8278c2ecf20Sopenharmony_ci int ret; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci ret = readl_relaxed_poll_timeout(i2c_dev->base + STM32F7_I2C_ISR, 8308c2ecf20Sopenharmony_ci status, 8318c2ecf20Sopenharmony_ci !(status & STM32F7_I2C_ISR_BUSY), 8328c2ecf20Sopenharmony_ci 10, 1000); 8338c2ecf20Sopenharmony_ci if (!ret) 8348c2ecf20Sopenharmony_ci return 0; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci dev_info(i2c_dev->dev, "bus busy\n"); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci ret = stm32f7_i2c_release_bus(&i2c_dev->adap); 8398c2ecf20Sopenharmony_ci if (ret) { 8408c2ecf20Sopenharmony_ci dev_err(i2c_dev->dev, "Failed to recover the bus (%d)\n", ret); 8418c2ecf20Sopenharmony_ci return ret; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci return -EBUSY; 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, 8488c2ecf20Sopenharmony_ci struct i2c_msg *msg) 8498c2ecf20Sopenharmony_ci{ 8508c2ecf20Sopenharmony_ci struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; 8518c2ecf20Sopenharmony_ci void __iomem *base = i2c_dev->base; 8528c2ecf20Sopenharmony_ci u32 cr1, cr2; 8538c2ecf20Sopenharmony_ci int ret; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci f7_msg->addr = msg->addr; 8568c2ecf20Sopenharmony_ci f7_msg->buf = msg->buf; 8578c2ecf20Sopenharmony_ci f7_msg->count = msg->len; 8588c2ecf20Sopenharmony_ci f7_msg->result = 0; 8598c2ecf20Sopenharmony_ci f7_msg->stop = (i2c_dev->msg_id >= i2c_dev->msg_num - 1); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci reinit_completion(&i2c_dev->complete); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci cr1 = readl_relaxed(base + STM32F7_I2C_CR1); 8648c2ecf20Sopenharmony_ci cr2 = readl_relaxed(base + STM32F7_I2C_CR2); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci /* Set transfer direction */ 8678c2ecf20Sopenharmony_ci cr2 &= ~STM32F7_I2C_CR2_RD_WRN; 8688c2ecf20Sopenharmony_ci if (msg->flags & I2C_M_RD) 8698c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_RD_WRN; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci /* Set slave address */ 8728c2ecf20Sopenharmony_ci cr2 &= ~(STM32F7_I2C_CR2_HEAD10R | STM32F7_I2C_CR2_ADD10); 8738c2ecf20Sopenharmony_ci if (msg->flags & I2C_M_TEN) { 8748c2ecf20Sopenharmony_ci cr2 &= ~STM32F7_I2C_CR2_SADD10_MASK; 8758c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_SADD10(f7_msg->addr); 8768c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_ADD10; 8778c2ecf20Sopenharmony_ci } else { 8788c2ecf20Sopenharmony_ci cr2 &= ~STM32F7_I2C_CR2_SADD7_MASK; 8798c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_SADD7(f7_msg->addr); 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci /* Set nb bytes to transfer and reload if needed */ 8838c2ecf20Sopenharmony_ci cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD); 8848c2ecf20Sopenharmony_ci if (f7_msg->count > STM32F7_I2C_MAX_LEN) { 8858c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_NBYTES(STM32F7_I2C_MAX_LEN); 8868c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_RELOAD; 8878c2ecf20Sopenharmony_ci } else { 8888c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count); 8898c2ecf20Sopenharmony_ci } 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci /* Enable NACK, STOP, error and transfer complete interrupts */ 8928c2ecf20Sopenharmony_ci cr1 |= STM32F7_I2C_CR1_ERRIE | STM32F7_I2C_CR1_TCIE | 8938c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci /* Clear DMA req and TX/RX interrupt */ 8968c2ecf20Sopenharmony_ci cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE | 8978c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci /* Configure DMA or enable RX/TX interrupt */ 9008c2ecf20Sopenharmony_ci i2c_dev->use_dma = false; 9018c2ecf20Sopenharmony_ci if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN) { 9028c2ecf20Sopenharmony_ci ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma, 9038c2ecf20Sopenharmony_ci msg->flags & I2C_M_RD, 9048c2ecf20Sopenharmony_ci f7_msg->count, f7_msg->buf, 9058c2ecf20Sopenharmony_ci stm32f7_i2c_dma_callback, 9068c2ecf20Sopenharmony_ci i2c_dev); 9078c2ecf20Sopenharmony_ci if (!ret) 9088c2ecf20Sopenharmony_ci i2c_dev->use_dma = true; 9098c2ecf20Sopenharmony_ci else 9108c2ecf20Sopenharmony_ci dev_warn(i2c_dev->dev, "can't use DMA\n"); 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (!i2c_dev->use_dma) { 9148c2ecf20Sopenharmony_ci if (msg->flags & I2C_M_RD) 9158c2ecf20Sopenharmony_ci cr1 |= STM32F7_I2C_CR1_RXIE; 9168c2ecf20Sopenharmony_ci else 9178c2ecf20Sopenharmony_ci cr1 |= STM32F7_I2C_CR1_TXIE; 9188c2ecf20Sopenharmony_ci } else { 9198c2ecf20Sopenharmony_ci if (msg->flags & I2C_M_RD) 9208c2ecf20Sopenharmony_ci cr1 |= STM32F7_I2C_CR1_RXDMAEN; 9218c2ecf20Sopenharmony_ci else 9228c2ecf20Sopenharmony_ci cr1 |= STM32F7_I2C_CR1_TXDMAEN; 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci /* Configure Start/Repeated Start */ 9268c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_START; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci i2c_dev->master_mode = true; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci /* Write configurations registers */ 9318c2ecf20Sopenharmony_ci writel_relaxed(cr1, base + STM32F7_I2C_CR1); 9328c2ecf20Sopenharmony_ci writel_relaxed(cr2, base + STM32F7_I2C_CR2); 9338c2ecf20Sopenharmony_ci} 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_cistatic int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, 9368c2ecf20Sopenharmony_ci unsigned short flags, u8 command, 9378c2ecf20Sopenharmony_ci union i2c_smbus_data *data) 9388c2ecf20Sopenharmony_ci{ 9398c2ecf20Sopenharmony_ci struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; 9408c2ecf20Sopenharmony_ci struct device *dev = i2c_dev->dev; 9418c2ecf20Sopenharmony_ci void __iomem *base = i2c_dev->base; 9428c2ecf20Sopenharmony_ci u32 cr1, cr2; 9438c2ecf20Sopenharmony_ci int i, ret; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci f7_msg->result = 0; 9468c2ecf20Sopenharmony_ci reinit_completion(&i2c_dev->complete); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci cr2 = readl_relaxed(base + STM32F7_I2C_CR2); 9498c2ecf20Sopenharmony_ci cr1 = readl_relaxed(base + STM32F7_I2C_CR1); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci /* Set transfer direction */ 9528c2ecf20Sopenharmony_ci cr2 &= ~STM32F7_I2C_CR2_RD_WRN; 9538c2ecf20Sopenharmony_ci if (f7_msg->read_write) 9548c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_RD_WRN; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci /* Set slave address */ 9578c2ecf20Sopenharmony_ci cr2 &= ~(STM32F7_I2C_CR2_ADD10 | STM32F7_I2C_CR2_SADD7_MASK); 9588c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_SADD7(f7_msg->addr); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci f7_msg->smbus_buf[0] = command; 9618c2ecf20Sopenharmony_ci switch (f7_msg->size) { 9628c2ecf20Sopenharmony_ci case I2C_SMBUS_QUICK: 9638c2ecf20Sopenharmony_ci f7_msg->stop = true; 9648c2ecf20Sopenharmony_ci f7_msg->count = 0; 9658c2ecf20Sopenharmony_ci break; 9668c2ecf20Sopenharmony_ci case I2C_SMBUS_BYTE: 9678c2ecf20Sopenharmony_ci f7_msg->stop = true; 9688c2ecf20Sopenharmony_ci f7_msg->count = 1; 9698c2ecf20Sopenharmony_ci break; 9708c2ecf20Sopenharmony_ci case I2C_SMBUS_BYTE_DATA: 9718c2ecf20Sopenharmony_ci if (f7_msg->read_write) { 9728c2ecf20Sopenharmony_ci f7_msg->stop = false; 9738c2ecf20Sopenharmony_ci f7_msg->count = 1; 9748c2ecf20Sopenharmony_ci cr2 &= ~STM32F7_I2C_CR2_RD_WRN; 9758c2ecf20Sopenharmony_ci } else { 9768c2ecf20Sopenharmony_ci f7_msg->stop = true; 9778c2ecf20Sopenharmony_ci f7_msg->count = 2; 9788c2ecf20Sopenharmony_ci f7_msg->smbus_buf[1] = data->byte; 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci break; 9818c2ecf20Sopenharmony_ci case I2C_SMBUS_WORD_DATA: 9828c2ecf20Sopenharmony_ci if (f7_msg->read_write) { 9838c2ecf20Sopenharmony_ci f7_msg->stop = false; 9848c2ecf20Sopenharmony_ci f7_msg->count = 1; 9858c2ecf20Sopenharmony_ci cr2 &= ~STM32F7_I2C_CR2_RD_WRN; 9868c2ecf20Sopenharmony_ci } else { 9878c2ecf20Sopenharmony_ci f7_msg->stop = true; 9888c2ecf20Sopenharmony_ci f7_msg->count = 3; 9898c2ecf20Sopenharmony_ci f7_msg->smbus_buf[1] = data->word & 0xff; 9908c2ecf20Sopenharmony_ci f7_msg->smbus_buf[2] = data->word >> 8; 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci break; 9938c2ecf20Sopenharmony_ci case I2C_SMBUS_BLOCK_DATA: 9948c2ecf20Sopenharmony_ci if (f7_msg->read_write) { 9958c2ecf20Sopenharmony_ci f7_msg->stop = false; 9968c2ecf20Sopenharmony_ci f7_msg->count = 1; 9978c2ecf20Sopenharmony_ci cr2 &= ~STM32F7_I2C_CR2_RD_WRN; 9988c2ecf20Sopenharmony_ci } else { 9998c2ecf20Sopenharmony_ci f7_msg->stop = true; 10008c2ecf20Sopenharmony_ci if (data->block[0] > I2C_SMBUS_BLOCK_MAX || 10018c2ecf20Sopenharmony_ci !data->block[0]) { 10028c2ecf20Sopenharmony_ci dev_err(dev, "Invalid block write size %d\n", 10038c2ecf20Sopenharmony_ci data->block[0]); 10048c2ecf20Sopenharmony_ci return -EINVAL; 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci f7_msg->count = data->block[0] + 2; 10078c2ecf20Sopenharmony_ci for (i = 1; i < f7_msg->count; i++) 10088c2ecf20Sopenharmony_ci f7_msg->smbus_buf[i] = data->block[i - 1]; 10098c2ecf20Sopenharmony_ci } 10108c2ecf20Sopenharmony_ci break; 10118c2ecf20Sopenharmony_ci case I2C_SMBUS_PROC_CALL: 10128c2ecf20Sopenharmony_ci f7_msg->stop = false; 10138c2ecf20Sopenharmony_ci f7_msg->count = 3; 10148c2ecf20Sopenharmony_ci f7_msg->smbus_buf[1] = data->word & 0xff; 10158c2ecf20Sopenharmony_ci f7_msg->smbus_buf[2] = data->word >> 8; 10168c2ecf20Sopenharmony_ci cr2 &= ~STM32F7_I2C_CR2_RD_WRN; 10178c2ecf20Sopenharmony_ci f7_msg->read_write = I2C_SMBUS_READ; 10188c2ecf20Sopenharmony_ci break; 10198c2ecf20Sopenharmony_ci case I2C_SMBUS_BLOCK_PROC_CALL: 10208c2ecf20Sopenharmony_ci f7_msg->stop = false; 10218c2ecf20Sopenharmony_ci if (data->block[0] > I2C_SMBUS_BLOCK_MAX - 1) { 10228c2ecf20Sopenharmony_ci dev_err(dev, "Invalid block write size %d\n", 10238c2ecf20Sopenharmony_ci data->block[0]); 10248c2ecf20Sopenharmony_ci return -EINVAL; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci f7_msg->count = data->block[0] + 2; 10278c2ecf20Sopenharmony_ci for (i = 1; i < f7_msg->count; i++) 10288c2ecf20Sopenharmony_ci f7_msg->smbus_buf[i] = data->block[i - 1]; 10298c2ecf20Sopenharmony_ci cr2 &= ~STM32F7_I2C_CR2_RD_WRN; 10308c2ecf20Sopenharmony_ci f7_msg->read_write = I2C_SMBUS_READ; 10318c2ecf20Sopenharmony_ci break; 10328c2ecf20Sopenharmony_ci case I2C_SMBUS_I2C_BLOCK_DATA: 10338c2ecf20Sopenharmony_ci /* Rely on emulated i2c transfer (through master_xfer) */ 10348c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10358c2ecf20Sopenharmony_ci default: 10368c2ecf20Sopenharmony_ci dev_err(dev, "Unsupported smbus protocol %d\n", f7_msg->size); 10378c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci f7_msg->buf = f7_msg->smbus_buf; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci /* Configure PEC */ 10438c2ecf20Sopenharmony_ci if ((flags & I2C_CLIENT_PEC) && f7_msg->size != I2C_SMBUS_QUICK) { 10448c2ecf20Sopenharmony_ci cr1 |= STM32F7_I2C_CR1_PECEN; 10458c2ecf20Sopenharmony_ci if (!f7_msg->read_write) { 10468c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_PECBYTE; 10478c2ecf20Sopenharmony_ci f7_msg->count++; 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci } else { 10508c2ecf20Sopenharmony_ci cr1 &= ~STM32F7_I2C_CR1_PECEN; 10518c2ecf20Sopenharmony_ci cr2 &= ~STM32F7_I2C_CR2_PECBYTE; 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci /* Set number of bytes to be transferred */ 10558c2ecf20Sopenharmony_ci cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK | STM32F7_I2C_CR2_RELOAD); 10568c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci /* Enable NACK, STOP, error and transfer complete interrupts */ 10598c2ecf20Sopenharmony_ci cr1 |= STM32F7_I2C_CR1_ERRIE | STM32F7_I2C_CR1_TCIE | 10608c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci /* Clear DMA req and TX/RX interrupt */ 10638c2ecf20Sopenharmony_ci cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE | 10648c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN); 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci /* Configure DMA or enable RX/TX interrupt */ 10678c2ecf20Sopenharmony_ci i2c_dev->use_dma = false; 10688c2ecf20Sopenharmony_ci if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN) { 10698c2ecf20Sopenharmony_ci ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma, 10708c2ecf20Sopenharmony_ci cr2 & STM32F7_I2C_CR2_RD_WRN, 10718c2ecf20Sopenharmony_ci f7_msg->count, f7_msg->buf, 10728c2ecf20Sopenharmony_ci stm32f7_i2c_dma_callback, 10738c2ecf20Sopenharmony_ci i2c_dev); 10748c2ecf20Sopenharmony_ci if (!ret) 10758c2ecf20Sopenharmony_ci i2c_dev->use_dma = true; 10768c2ecf20Sopenharmony_ci else 10778c2ecf20Sopenharmony_ci dev_warn(i2c_dev->dev, "can't use DMA\n"); 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci if (!i2c_dev->use_dma) { 10818c2ecf20Sopenharmony_ci if (cr2 & STM32F7_I2C_CR2_RD_WRN) 10828c2ecf20Sopenharmony_ci cr1 |= STM32F7_I2C_CR1_RXIE; 10838c2ecf20Sopenharmony_ci else 10848c2ecf20Sopenharmony_ci cr1 |= STM32F7_I2C_CR1_TXIE; 10858c2ecf20Sopenharmony_ci } else { 10868c2ecf20Sopenharmony_ci if (cr2 & STM32F7_I2C_CR2_RD_WRN) 10878c2ecf20Sopenharmony_ci cr1 |= STM32F7_I2C_CR1_RXDMAEN; 10888c2ecf20Sopenharmony_ci else 10898c2ecf20Sopenharmony_ci cr1 |= STM32F7_I2C_CR1_TXDMAEN; 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci /* Set Start bit */ 10938c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_START; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci i2c_dev->master_mode = true; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci /* Write configurations registers */ 10988c2ecf20Sopenharmony_ci writel_relaxed(cr1, base + STM32F7_I2C_CR1); 10998c2ecf20Sopenharmony_ci writel_relaxed(cr2, base + STM32F7_I2C_CR2); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci return 0; 11028c2ecf20Sopenharmony_ci} 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_cistatic void stm32f7_i2c_smbus_rep_start(struct stm32f7_i2c_dev *i2c_dev) 11058c2ecf20Sopenharmony_ci{ 11068c2ecf20Sopenharmony_ci struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; 11078c2ecf20Sopenharmony_ci void __iomem *base = i2c_dev->base; 11088c2ecf20Sopenharmony_ci u32 cr1, cr2; 11098c2ecf20Sopenharmony_ci int ret; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci cr2 = readl_relaxed(base + STM32F7_I2C_CR2); 11128c2ecf20Sopenharmony_ci cr1 = readl_relaxed(base + STM32F7_I2C_CR1); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci /* Set transfer direction */ 11158c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_RD_WRN; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci switch (f7_msg->size) { 11188c2ecf20Sopenharmony_ci case I2C_SMBUS_BYTE_DATA: 11198c2ecf20Sopenharmony_ci f7_msg->count = 1; 11208c2ecf20Sopenharmony_ci break; 11218c2ecf20Sopenharmony_ci case I2C_SMBUS_WORD_DATA: 11228c2ecf20Sopenharmony_ci case I2C_SMBUS_PROC_CALL: 11238c2ecf20Sopenharmony_ci f7_msg->count = 2; 11248c2ecf20Sopenharmony_ci break; 11258c2ecf20Sopenharmony_ci case I2C_SMBUS_BLOCK_DATA: 11268c2ecf20Sopenharmony_ci case I2C_SMBUS_BLOCK_PROC_CALL: 11278c2ecf20Sopenharmony_ci f7_msg->count = 1; 11288c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_RELOAD; 11298c2ecf20Sopenharmony_ci break; 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci f7_msg->buf = f7_msg->smbus_buf; 11338c2ecf20Sopenharmony_ci f7_msg->stop = true; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci /* Add one byte for PEC if needed */ 11368c2ecf20Sopenharmony_ci if (cr1 & STM32F7_I2C_CR1_PECEN) { 11378c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_PECBYTE; 11388c2ecf20Sopenharmony_ci f7_msg->count++; 11398c2ecf20Sopenharmony_ci } 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci /* Set number of bytes to be transferred */ 11428c2ecf20Sopenharmony_ci cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK); 11438c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_NBYTES(f7_msg->count); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci /* 11468c2ecf20Sopenharmony_ci * Configure RX/TX interrupt: 11478c2ecf20Sopenharmony_ci */ 11488c2ecf20Sopenharmony_ci cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE); 11498c2ecf20Sopenharmony_ci cr1 |= STM32F7_I2C_CR1_RXIE; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci /* 11528c2ecf20Sopenharmony_ci * Configure DMA or enable RX/TX interrupt: 11538c2ecf20Sopenharmony_ci * For I2C_SMBUS_BLOCK_DATA and I2C_SMBUS_BLOCK_PROC_CALL we don't use 11548c2ecf20Sopenharmony_ci * dma as we don't know in advance how many data will be received 11558c2ecf20Sopenharmony_ci */ 11568c2ecf20Sopenharmony_ci cr1 &= ~(STM32F7_I2C_CR1_RXIE | STM32F7_I2C_CR1_TXIE | 11578c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_RXDMAEN | STM32F7_I2C_CR1_TXDMAEN); 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci i2c_dev->use_dma = false; 11608c2ecf20Sopenharmony_ci if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN && 11618c2ecf20Sopenharmony_ci f7_msg->size != I2C_SMBUS_BLOCK_DATA && 11628c2ecf20Sopenharmony_ci f7_msg->size != I2C_SMBUS_BLOCK_PROC_CALL) { 11638c2ecf20Sopenharmony_ci ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma, 11648c2ecf20Sopenharmony_ci cr2 & STM32F7_I2C_CR2_RD_WRN, 11658c2ecf20Sopenharmony_ci f7_msg->count, f7_msg->buf, 11668c2ecf20Sopenharmony_ci stm32f7_i2c_dma_callback, 11678c2ecf20Sopenharmony_ci i2c_dev); 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci if (!ret) 11708c2ecf20Sopenharmony_ci i2c_dev->use_dma = true; 11718c2ecf20Sopenharmony_ci else 11728c2ecf20Sopenharmony_ci dev_warn(i2c_dev->dev, "can't use DMA\n"); 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci if (!i2c_dev->use_dma) 11768c2ecf20Sopenharmony_ci cr1 |= STM32F7_I2C_CR1_RXIE; 11778c2ecf20Sopenharmony_ci else 11788c2ecf20Sopenharmony_ci cr1 |= STM32F7_I2C_CR1_RXDMAEN; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci /* Configure Repeated Start */ 11818c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_START; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci /* Write configurations registers */ 11848c2ecf20Sopenharmony_ci writel_relaxed(cr1, base + STM32F7_I2C_CR1); 11858c2ecf20Sopenharmony_ci writel_relaxed(cr2, base + STM32F7_I2C_CR2); 11868c2ecf20Sopenharmony_ci} 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_cistatic int stm32f7_i2c_smbus_check_pec(struct stm32f7_i2c_dev *i2c_dev) 11898c2ecf20Sopenharmony_ci{ 11908c2ecf20Sopenharmony_ci struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; 11918c2ecf20Sopenharmony_ci u8 count, internal_pec, received_pec; 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci internal_pec = readl_relaxed(i2c_dev->base + STM32F7_I2C_PECR); 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci switch (f7_msg->size) { 11968c2ecf20Sopenharmony_ci case I2C_SMBUS_BYTE: 11978c2ecf20Sopenharmony_ci case I2C_SMBUS_BYTE_DATA: 11988c2ecf20Sopenharmony_ci received_pec = f7_msg->smbus_buf[1]; 11998c2ecf20Sopenharmony_ci break; 12008c2ecf20Sopenharmony_ci case I2C_SMBUS_WORD_DATA: 12018c2ecf20Sopenharmony_ci case I2C_SMBUS_PROC_CALL: 12028c2ecf20Sopenharmony_ci received_pec = f7_msg->smbus_buf[2]; 12038c2ecf20Sopenharmony_ci break; 12048c2ecf20Sopenharmony_ci case I2C_SMBUS_BLOCK_DATA: 12058c2ecf20Sopenharmony_ci case I2C_SMBUS_BLOCK_PROC_CALL: 12068c2ecf20Sopenharmony_ci count = f7_msg->smbus_buf[0]; 12078c2ecf20Sopenharmony_ci received_pec = f7_msg->smbus_buf[count]; 12088c2ecf20Sopenharmony_ci break; 12098c2ecf20Sopenharmony_ci default: 12108c2ecf20Sopenharmony_ci dev_err(i2c_dev->dev, "Unsupported smbus protocol for PEC\n"); 12118c2ecf20Sopenharmony_ci return -EINVAL; 12128c2ecf20Sopenharmony_ci } 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci if (internal_pec != received_pec) { 12158c2ecf20Sopenharmony_ci dev_err(i2c_dev->dev, "Bad PEC 0x%02x vs. 0x%02x\n", 12168c2ecf20Sopenharmony_ci internal_pec, received_pec); 12178c2ecf20Sopenharmony_ci return -EBADMSG; 12188c2ecf20Sopenharmony_ci } 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci return 0; 12218c2ecf20Sopenharmony_ci} 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_cistatic bool stm32f7_i2c_is_addr_match(struct i2c_client *slave, u32 addcode) 12248c2ecf20Sopenharmony_ci{ 12258c2ecf20Sopenharmony_ci u32 addr; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci if (!slave) 12288c2ecf20Sopenharmony_ci return false; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci if (slave->flags & I2C_CLIENT_TEN) { 12318c2ecf20Sopenharmony_ci /* 12328c2ecf20Sopenharmony_ci * For 10-bit addr, addcode = 11110XY with 12338c2ecf20Sopenharmony_ci * X = Bit 9 of slave address 12348c2ecf20Sopenharmony_ci * Y = Bit 8 of slave address 12358c2ecf20Sopenharmony_ci */ 12368c2ecf20Sopenharmony_ci addr = slave->addr >> 8; 12378c2ecf20Sopenharmony_ci addr |= 0x78; 12388c2ecf20Sopenharmony_ci if (addr == addcode) 12398c2ecf20Sopenharmony_ci return true; 12408c2ecf20Sopenharmony_ci } else { 12418c2ecf20Sopenharmony_ci addr = slave->addr & 0x7f; 12428c2ecf20Sopenharmony_ci if (addr == addcode) 12438c2ecf20Sopenharmony_ci return true; 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci return false; 12478c2ecf20Sopenharmony_ci} 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_cistatic void stm32f7_i2c_slave_start(struct stm32f7_i2c_dev *i2c_dev) 12508c2ecf20Sopenharmony_ci{ 12518c2ecf20Sopenharmony_ci struct i2c_client *slave = i2c_dev->slave_running; 12528c2ecf20Sopenharmony_ci void __iomem *base = i2c_dev->base; 12538c2ecf20Sopenharmony_ci u32 mask; 12548c2ecf20Sopenharmony_ci u8 value = 0; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci if (i2c_dev->slave_dir) { 12578c2ecf20Sopenharmony_ci /* Notify i2c slave that new read transfer is starting */ 12588c2ecf20Sopenharmony_ci i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value); 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci /* 12618c2ecf20Sopenharmony_ci * Disable slave TX config in case of I2C combined message 12628c2ecf20Sopenharmony_ci * (I2C Write followed by I2C Read) 12638c2ecf20Sopenharmony_ci */ 12648c2ecf20Sopenharmony_ci mask = STM32F7_I2C_CR2_RELOAD; 12658c2ecf20Sopenharmony_ci stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR2, mask); 12668c2ecf20Sopenharmony_ci mask = STM32F7_I2C_CR1_SBC | STM32F7_I2C_CR1_RXIE | 12678c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_TCIE; 12688c2ecf20Sopenharmony_ci stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci /* Enable TX empty, STOP, NACK interrupts */ 12718c2ecf20Sopenharmony_ci mask = STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE | 12728c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_TXIE; 12738c2ecf20Sopenharmony_ci stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci /* Write 1st data byte */ 12768c2ecf20Sopenharmony_ci writel_relaxed(value, base + STM32F7_I2C_TXDR); 12778c2ecf20Sopenharmony_ci } else { 12788c2ecf20Sopenharmony_ci /* Notify i2c slave that new write transfer is starting */ 12798c2ecf20Sopenharmony_ci i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci /* Set reload mode to be able to ACK/NACK each received byte */ 12828c2ecf20Sopenharmony_ci mask = STM32F7_I2C_CR2_RELOAD; 12838c2ecf20Sopenharmony_ci stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask); 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci /* 12868c2ecf20Sopenharmony_ci * Set STOP, NACK, RX empty and transfer complete interrupts.* 12878c2ecf20Sopenharmony_ci * Set Slave Byte Control to be able to ACK/NACK each data 12888c2ecf20Sopenharmony_ci * byte received 12898c2ecf20Sopenharmony_ci */ 12908c2ecf20Sopenharmony_ci mask = STM32F7_I2C_CR1_STOPIE | STM32F7_I2C_CR1_NACKIE | 12918c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_SBC | STM32F7_I2C_CR1_RXIE | 12928c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_TCIE; 12938c2ecf20Sopenharmony_ci stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask); 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci} 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_cistatic void stm32f7_i2c_slave_addr(struct stm32f7_i2c_dev *i2c_dev) 12988c2ecf20Sopenharmony_ci{ 12998c2ecf20Sopenharmony_ci void __iomem *base = i2c_dev->base; 13008c2ecf20Sopenharmony_ci u32 isr, addcode, dir, mask; 13018c2ecf20Sopenharmony_ci int i; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci isr = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); 13048c2ecf20Sopenharmony_ci addcode = STM32F7_I2C_ISR_ADDCODE_GET(isr); 13058c2ecf20Sopenharmony_ci dir = isr & STM32F7_I2C_ISR_DIR; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) { 13088c2ecf20Sopenharmony_ci if (stm32f7_i2c_is_addr_match(i2c_dev->slave[i], addcode)) { 13098c2ecf20Sopenharmony_ci i2c_dev->slave_running = i2c_dev->slave[i]; 13108c2ecf20Sopenharmony_ci i2c_dev->slave_dir = dir; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci /* Start I2C slave processing */ 13138c2ecf20Sopenharmony_ci stm32f7_i2c_slave_start(i2c_dev); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci /* Clear ADDR flag */ 13168c2ecf20Sopenharmony_ci mask = STM32F7_I2C_ICR_ADDRCF; 13178c2ecf20Sopenharmony_ci writel_relaxed(mask, base + STM32F7_I2C_ICR); 13188c2ecf20Sopenharmony_ci break; 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci} 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_cistatic int stm32f7_i2c_get_slave_id(struct stm32f7_i2c_dev *i2c_dev, 13248c2ecf20Sopenharmony_ci struct i2c_client *slave, int *id) 13258c2ecf20Sopenharmony_ci{ 13268c2ecf20Sopenharmony_ci int i; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) { 13298c2ecf20Sopenharmony_ci if (i2c_dev->slave[i] == slave) { 13308c2ecf20Sopenharmony_ci *id = i; 13318c2ecf20Sopenharmony_ci return 0; 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci } 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci dev_err(i2c_dev->dev, "Slave 0x%x not registered\n", slave->addr); 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci return -ENODEV; 13388c2ecf20Sopenharmony_ci} 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_cistatic int stm32f7_i2c_get_free_slave_id(struct stm32f7_i2c_dev *i2c_dev, 13418c2ecf20Sopenharmony_ci struct i2c_client *slave, int *id) 13428c2ecf20Sopenharmony_ci{ 13438c2ecf20Sopenharmony_ci struct device *dev = i2c_dev->dev; 13448c2ecf20Sopenharmony_ci int i; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci /* 13478c2ecf20Sopenharmony_ci * slave[STM32F7_SLAVE_HOSTNOTIFY] support only SMBus Host address (0x8) 13488c2ecf20Sopenharmony_ci * slave[STM32F7_SLAVE_7_10_BITS_ADDR] supports 7-bit and 10-bit slave address 13498c2ecf20Sopenharmony_ci * slave[STM32F7_SLAVE_7_BITS_ADDR] supports 7-bit slave address only 13508c2ecf20Sopenharmony_ci */ 13518c2ecf20Sopenharmony_ci if (i2c_dev->smbus_mode && (slave->addr == 0x08)) { 13528c2ecf20Sopenharmony_ci if (i2c_dev->slave[STM32F7_SLAVE_HOSTNOTIFY]) 13538c2ecf20Sopenharmony_ci goto fail; 13548c2ecf20Sopenharmony_ci *id = STM32F7_SLAVE_HOSTNOTIFY; 13558c2ecf20Sopenharmony_ci return 0; 13568c2ecf20Sopenharmony_ci } 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci for (i = STM32F7_I2C_MAX_SLAVE - 1; i > STM32F7_SLAVE_HOSTNOTIFY; i--) { 13598c2ecf20Sopenharmony_ci if ((i == STM32F7_SLAVE_7_BITS_ADDR) && 13608c2ecf20Sopenharmony_ci (slave->flags & I2C_CLIENT_TEN)) 13618c2ecf20Sopenharmony_ci continue; 13628c2ecf20Sopenharmony_ci if (!i2c_dev->slave[i]) { 13638c2ecf20Sopenharmony_ci *id = i; 13648c2ecf20Sopenharmony_ci return 0; 13658c2ecf20Sopenharmony_ci } 13668c2ecf20Sopenharmony_ci } 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_cifail: 13698c2ecf20Sopenharmony_ci dev_err(dev, "Slave 0x%x could not be registered\n", slave->addr); 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci return -EINVAL; 13728c2ecf20Sopenharmony_ci} 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_cistatic bool stm32f7_i2c_is_slave_registered(struct stm32f7_i2c_dev *i2c_dev) 13758c2ecf20Sopenharmony_ci{ 13768c2ecf20Sopenharmony_ci int i; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) { 13798c2ecf20Sopenharmony_ci if (i2c_dev->slave[i]) 13808c2ecf20Sopenharmony_ci return true; 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci return false; 13848c2ecf20Sopenharmony_ci} 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_cistatic bool stm32f7_i2c_is_slave_busy(struct stm32f7_i2c_dev *i2c_dev) 13878c2ecf20Sopenharmony_ci{ 13888c2ecf20Sopenharmony_ci int i, busy; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci busy = 0; 13918c2ecf20Sopenharmony_ci for (i = 0; i < STM32F7_I2C_MAX_SLAVE; i++) { 13928c2ecf20Sopenharmony_ci if (i2c_dev->slave[i]) 13938c2ecf20Sopenharmony_ci busy++; 13948c2ecf20Sopenharmony_ci } 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci return i == busy; 13978c2ecf20Sopenharmony_ci} 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_cistatic irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev) 14008c2ecf20Sopenharmony_ci{ 14018c2ecf20Sopenharmony_ci void __iomem *base = i2c_dev->base; 14028c2ecf20Sopenharmony_ci u32 cr2, status, mask; 14038c2ecf20Sopenharmony_ci u8 val; 14048c2ecf20Sopenharmony_ci int ret; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci /* Slave transmitter mode */ 14098c2ecf20Sopenharmony_ci if (status & STM32F7_I2C_ISR_TXIS) { 14108c2ecf20Sopenharmony_ci i2c_slave_event(i2c_dev->slave_running, 14118c2ecf20Sopenharmony_ci I2C_SLAVE_READ_PROCESSED, 14128c2ecf20Sopenharmony_ci &val); 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci /* Write data byte */ 14158c2ecf20Sopenharmony_ci writel_relaxed(val, base + STM32F7_I2C_TXDR); 14168c2ecf20Sopenharmony_ci } 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci /* Transfer Complete Reload for Slave receiver mode */ 14198c2ecf20Sopenharmony_ci if (status & STM32F7_I2C_ISR_TCR || status & STM32F7_I2C_ISR_RXNE) { 14208c2ecf20Sopenharmony_ci /* 14218c2ecf20Sopenharmony_ci * Read data byte then set NBYTES to receive next byte or NACK 14228c2ecf20Sopenharmony_ci * the current received byte 14238c2ecf20Sopenharmony_ci */ 14248c2ecf20Sopenharmony_ci val = readb_relaxed(i2c_dev->base + STM32F7_I2C_RXDR); 14258c2ecf20Sopenharmony_ci ret = i2c_slave_event(i2c_dev->slave_running, 14268c2ecf20Sopenharmony_ci I2C_SLAVE_WRITE_RECEIVED, 14278c2ecf20Sopenharmony_ci &val); 14288c2ecf20Sopenharmony_ci if (!ret) { 14298c2ecf20Sopenharmony_ci cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2); 14308c2ecf20Sopenharmony_ci cr2 |= STM32F7_I2C_CR2_NBYTES(1); 14318c2ecf20Sopenharmony_ci writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2); 14328c2ecf20Sopenharmony_ci } else { 14338c2ecf20Sopenharmony_ci mask = STM32F7_I2C_CR2_NACK; 14348c2ecf20Sopenharmony_ci stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask); 14358c2ecf20Sopenharmony_ci } 14368c2ecf20Sopenharmony_ci } 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci /* NACK received */ 14398c2ecf20Sopenharmony_ci if (status & STM32F7_I2C_ISR_NACKF) { 14408c2ecf20Sopenharmony_ci dev_dbg(i2c_dev->dev, "<%s>: Receive NACK\n", __func__); 14418c2ecf20Sopenharmony_ci writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR); 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci /* STOP received */ 14458c2ecf20Sopenharmony_ci if (status & STM32F7_I2C_ISR_STOPF) { 14468c2ecf20Sopenharmony_ci /* Disable interrupts */ 14478c2ecf20Sopenharmony_ci stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_XFER_IRQ_MASK); 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci if (i2c_dev->slave_dir) { 14508c2ecf20Sopenharmony_ci /* 14518c2ecf20Sopenharmony_ci * Flush TX buffer in order to not used the byte in 14528c2ecf20Sopenharmony_ci * TXDR for the next transfer 14538c2ecf20Sopenharmony_ci */ 14548c2ecf20Sopenharmony_ci mask = STM32F7_I2C_ISR_TXE; 14558c2ecf20Sopenharmony_ci stm32f7_i2c_set_bits(base + STM32F7_I2C_ISR, mask); 14568c2ecf20Sopenharmony_ci } 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci /* Clear STOP flag */ 14598c2ecf20Sopenharmony_ci writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR); 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci /* Notify i2c slave that a STOP flag has been detected */ 14628c2ecf20Sopenharmony_ci i2c_slave_event(i2c_dev->slave_running, I2C_SLAVE_STOP, &val); 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci i2c_dev->slave_running = NULL; 14658c2ecf20Sopenharmony_ci } 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci /* Address match received */ 14688c2ecf20Sopenharmony_ci if (status & STM32F7_I2C_ISR_ADDR) 14698c2ecf20Sopenharmony_ci stm32f7_i2c_slave_addr(i2c_dev); 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci return IRQ_HANDLED; 14728c2ecf20Sopenharmony_ci} 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_cistatic irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) 14758c2ecf20Sopenharmony_ci{ 14768c2ecf20Sopenharmony_ci struct stm32f7_i2c_dev *i2c_dev = data; 14778c2ecf20Sopenharmony_ci struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; 14788c2ecf20Sopenharmony_ci struct stm32_i2c_dma *dma = i2c_dev->dma; 14798c2ecf20Sopenharmony_ci void __iomem *base = i2c_dev->base; 14808c2ecf20Sopenharmony_ci u32 status, mask; 14818c2ecf20Sopenharmony_ci int ret = IRQ_HANDLED; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci /* Check if the interrupt if for a slave device */ 14848c2ecf20Sopenharmony_ci if (!i2c_dev->master_mode) { 14858c2ecf20Sopenharmony_ci ret = stm32f7_i2c_slave_isr_event(i2c_dev); 14868c2ecf20Sopenharmony_ci return ret; 14878c2ecf20Sopenharmony_ci } 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci /* Tx empty */ 14928c2ecf20Sopenharmony_ci if (status & STM32F7_I2C_ISR_TXIS) 14938c2ecf20Sopenharmony_ci stm32f7_i2c_write_tx_data(i2c_dev); 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci /* RX not empty */ 14968c2ecf20Sopenharmony_ci if (status & STM32F7_I2C_ISR_RXNE) 14978c2ecf20Sopenharmony_ci stm32f7_i2c_read_rx_data(i2c_dev); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci /* NACK received */ 15008c2ecf20Sopenharmony_ci if (status & STM32F7_I2C_ISR_NACKF) { 15018c2ecf20Sopenharmony_ci dev_dbg(i2c_dev->dev, "<%s>: Receive NACK (addr %x)\n", 15028c2ecf20Sopenharmony_ci __func__, f7_msg->addr); 15038c2ecf20Sopenharmony_ci writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR); 15048c2ecf20Sopenharmony_ci if (i2c_dev->use_dma) { 15058c2ecf20Sopenharmony_ci stm32f7_i2c_disable_dma_req(i2c_dev); 15068c2ecf20Sopenharmony_ci dmaengine_terminate_all(dma->chan_using); 15078c2ecf20Sopenharmony_ci } 15088c2ecf20Sopenharmony_ci f7_msg->result = -ENXIO; 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci /* STOP detection flag */ 15128c2ecf20Sopenharmony_ci if (status & STM32F7_I2C_ISR_STOPF) { 15138c2ecf20Sopenharmony_ci /* Disable interrupts */ 15148c2ecf20Sopenharmony_ci if (stm32f7_i2c_is_slave_registered(i2c_dev)) 15158c2ecf20Sopenharmony_ci mask = STM32F7_I2C_XFER_IRQ_MASK; 15168c2ecf20Sopenharmony_ci else 15178c2ecf20Sopenharmony_ci mask = STM32F7_I2C_ALL_IRQ_MASK; 15188c2ecf20Sopenharmony_ci stm32f7_i2c_disable_irq(i2c_dev, mask); 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci /* Clear STOP flag */ 15218c2ecf20Sopenharmony_ci writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR); 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci if (i2c_dev->use_dma && !f7_msg->result) { 15248c2ecf20Sopenharmony_ci ret = IRQ_WAKE_THREAD; 15258c2ecf20Sopenharmony_ci } else { 15268c2ecf20Sopenharmony_ci i2c_dev->master_mode = false; 15278c2ecf20Sopenharmony_ci complete(&i2c_dev->complete); 15288c2ecf20Sopenharmony_ci } 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci /* Transfer complete */ 15328c2ecf20Sopenharmony_ci if (status & STM32F7_I2C_ISR_TC) { 15338c2ecf20Sopenharmony_ci if (f7_msg->stop) { 15348c2ecf20Sopenharmony_ci mask = STM32F7_I2C_CR2_STOP; 15358c2ecf20Sopenharmony_ci stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask); 15368c2ecf20Sopenharmony_ci } else if (i2c_dev->use_dma && !f7_msg->result) { 15378c2ecf20Sopenharmony_ci ret = IRQ_WAKE_THREAD; 15388c2ecf20Sopenharmony_ci } else if (f7_msg->smbus) { 15398c2ecf20Sopenharmony_ci stm32f7_i2c_smbus_rep_start(i2c_dev); 15408c2ecf20Sopenharmony_ci } else { 15418c2ecf20Sopenharmony_ci i2c_dev->msg_id++; 15428c2ecf20Sopenharmony_ci i2c_dev->msg++; 15438c2ecf20Sopenharmony_ci stm32f7_i2c_xfer_msg(i2c_dev, i2c_dev->msg); 15448c2ecf20Sopenharmony_ci } 15458c2ecf20Sopenharmony_ci } 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci if (status & STM32F7_I2C_ISR_TCR) { 15488c2ecf20Sopenharmony_ci if (f7_msg->smbus) 15498c2ecf20Sopenharmony_ci stm32f7_i2c_smbus_reload(i2c_dev); 15508c2ecf20Sopenharmony_ci else 15518c2ecf20Sopenharmony_ci stm32f7_i2c_reload(i2c_dev); 15528c2ecf20Sopenharmony_ci } 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci return ret; 15558c2ecf20Sopenharmony_ci} 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_cistatic irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data) 15588c2ecf20Sopenharmony_ci{ 15598c2ecf20Sopenharmony_ci struct stm32f7_i2c_dev *i2c_dev = data; 15608c2ecf20Sopenharmony_ci struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; 15618c2ecf20Sopenharmony_ci struct stm32_i2c_dma *dma = i2c_dev->dma; 15628c2ecf20Sopenharmony_ci u32 status; 15638c2ecf20Sopenharmony_ci int ret; 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci /* 15668c2ecf20Sopenharmony_ci * Wait for dma transfer completion before sending next message or 15678c2ecf20Sopenharmony_ci * notity the end of xfer to the client 15688c2ecf20Sopenharmony_ci */ 15698c2ecf20Sopenharmony_ci ret = wait_for_completion_timeout(&i2c_dev->dma->dma_complete, HZ); 15708c2ecf20Sopenharmony_ci if (!ret) { 15718c2ecf20Sopenharmony_ci dev_dbg(i2c_dev->dev, "<%s>: Timed out\n", __func__); 15728c2ecf20Sopenharmony_ci stm32f7_i2c_disable_dma_req(i2c_dev); 15738c2ecf20Sopenharmony_ci dmaengine_terminate_all(dma->chan_using); 15748c2ecf20Sopenharmony_ci f7_msg->result = -ETIMEDOUT; 15758c2ecf20Sopenharmony_ci } 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci if (status & STM32F7_I2C_ISR_TC) { 15808c2ecf20Sopenharmony_ci if (f7_msg->smbus) { 15818c2ecf20Sopenharmony_ci stm32f7_i2c_smbus_rep_start(i2c_dev); 15828c2ecf20Sopenharmony_ci } else { 15838c2ecf20Sopenharmony_ci i2c_dev->msg_id++; 15848c2ecf20Sopenharmony_ci i2c_dev->msg++; 15858c2ecf20Sopenharmony_ci stm32f7_i2c_xfer_msg(i2c_dev, i2c_dev->msg); 15868c2ecf20Sopenharmony_ci } 15878c2ecf20Sopenharmony_ci } else { 15888c2ecf20Sopenharmony_ci i2c_dev->master_mode = false; 15898c2ecf20Sopenharmony_ci complete(&i2c_dev->complete); 15908c2ecf20Sopenharmony_ci } 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci return IRQ_HANDLED; 15938c2ecf20Sopenharmony_ci} 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_cistatic irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) 15968c2ecf20Sopenharmony_ci{ 15978c2ecf20Sopenharmony_ci struct stm32f7_i2c_dev *i2c_dev = data; 15988c2ecf20Sopenharmony_ci struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; 15998c2ecf20Sopenharmony_ci void __iomem *base = i2c_dev->base; 16008c2ecf20Sopenharmony_ci struct device *dev = i2c_dev->dev; 16018c2ecf20Sopenharmony_ci struct stm32_i2c_dma *dma = i2c_dev->dma; 16028c2ecf20Sopenharmony_ci u32 status; 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci /* Bus error */ 16078c2ecf20Sopenharmony_ci if (status & STM32F7_I2C_ISR_BERR) { 16088c2ecf20Sopenharmony_ci dev_err(dev, "<%s>: Bus error\n", __func__); 16098c2ecf20Sopenharmony_ci writel_relaxed(STM32F7_I2C_ICR_BERRCF, base + STM32F7_I2C_ICR); 16108c2ecf20Sopenharmony_ci stm32f7_i2c_release_bus(&i2c_dev->adap); 16118c2ecf20Sopenharmony_ci f7_msg->result = -EIO; 16128c2ecf20Sopenharmony_ci } 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci /* Arbitration loss */ 16158c2ecf20Sopenharmony_ci if (status & STM32F7_I2C_ISR_ARLO) { 16168c2ecf20Sopenharmony_ci dev_dbg(dev, "<%s>: Arbitration loss\n", __func__); 16178c2ecf20Sopenharmony_ci writel_relaxed(STM32F7_I2C_ICR_ARLOCF, base + STM32F7_I2C_ICR); 16188c2ecf20Sopenharmony_ci f7_msg->result = -EAGAIN; 16198c2ecf20Sopenharmony_ci } 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci if (status & STM32F7_I2C_ISR_PECERR) { 16228c2ecf20Sopenharmony_ci dev_err(dev, "<%s>: PEC error in reception\n", __func__); 16238c2ecf20Sopenharmony_ci writel_relaxed(STM32F7_I2C_ICR_PECCF, base + STM32F7_I2C_ICR); 16248c2ecf20Sopenharmony_ci f7_msg->result = -EINVAL; 16258c2ecf20Sopenharmony_ci } 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci if (!i2c_dev->slave_running) { 16288c2ecf20Sopenharmony_ci u32 mask; 16298c2ecf20Sopenharmony_ci /* Disable interrupts */ 16308c2ecf20Sopenharmony_ci if (stm32f7_i2c_is_slave_registered(i2c_dev)) 16318c2ecf20Sopenharmony_ci mask = STM32F7_I2C_XFER_IRQ_MASK; 16328c2ecf20Sopenharmony_ci else 16338c2ecf20Sopenharmony_ci mask = STM32F7_I2C_ALL_IRQ_MASK; 16348c2ecf20Sopenharmony_ci stm32f7_i2c_disable_irq(i2c_dev, mask); 16358c2ecf20Sopenharmony_ci } 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci /* Disable dma */ 16388c2ecf20Sopenharmony_ci if (i2c_dev->use_dma) { 16398c2ecf20Sopenharmony_ci stm32f7_i2c_disable_dma_req(i2c_dev); 16408c2ecf20Sopenharmony_ci dmaengine_terminate_all(dma->chan_using); 16418c2ecf20Sopenharmony_ci } 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci i2c_dev->master_mode = false; 16448c2ecf20Sopenharmony_ci complete(&i2c_dev->complete); 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci return IRQ_HANDLED; 16478c2ecf20Sopenharmony_ci} 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_cistatic int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, 16508c2ecf20Sopenharmony_ci struct i2c_msg msgs[], int num) 16518c2ecf20Sopenharmony_ci{ 16528c2ecf20Sopenharmony_ci struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap); 16538c2ecf20Sopenharmony_ci struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; 16548c2ecf20Sopenharmony_ci struct stm32_i2c_dma *dma = i2c_dev->dma; 16558c2ecf20Sopenharmony_ci unsigned long time_left; 16568c2ecf20Sopenharmony_ci int ret; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci i2c_dev->msg = msgs; 16598c2ecf20Sopenharmony_ci i2c_dev->msg_num = num; 16608c2ecf20Sopenharmony_ci i2c_dev->msg_id = 0; 16618c2ecf20Sopenharmony_ci f7_msg->smbus = false; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(i2c_dev->dev); 16648c2ecf20Sopenharmony_ci if (ret < 0) 16658c2ecf20Sopenharmony_ci return ret; 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci ret = stm32f7_i2c_wait_free_bus(i2c_dev); 16688c2ecf20Sopenharmony_ci if (ret) 16698c2ecf20Sopenharmony_ci goto pm_free; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci stm32f7_i2c_xfer_msg(i2c_dev, msgs); 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci time_left = wait_for_completion_timeout(&i2c_dev->complete, 16748c2ecf20Sopenharmony_ci i2c_dev->adap.timeout); 16758c2ecf20Sopenharmony_ci ret = f7_msg->result; 16768c2ecf20Sopenharmony_ci if (ret) { 16778c2ecf20Sopenharmony_ci /* 16788c2ecf20Sopenharmony_ci * It is possible that some unsent data have already been 16798c2ecf20Sopenharmony_ci * written into TXDR. To avoid sending old data in a 16808c2ecf20Sopenharmony_ci * further transfer, flush TXDR in case of any error 16818c2ecf20Sopenharmony_ci */ 16828c2ecf20Sopenharmony_ci writel_relaxed(STM32F7_I2C_ISR_TXE, 16838c2ecf20Sopenharmony_ci i2c_dev->base + STM32F7_I2C_ISR); 16848c2ecf20Sopenharmony_ci goto pm_free; 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci if (!time_left) { 16888c2ecf20Sopenharmony_ci dev_dbg(i2c_dev->dev, "Access to slave 0x%x timed out\n", 16898c2ecf20Sopenharmony_ci i2c_dev->msg->addr); 16908c2ecf20Sopenharmony_ci if (i2c_dev->use_dma) 16918c2ecf20Sopenharmony_ci dmaengine_terminate_all(dma->chan_using); 16928c2ecf20Sopenharmony_ci stm32f7_i2c_wait_free_bus(i2c_dev); 16938c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 16948c2ecf20Sopenharmony_ci } 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_cipm_free: 16978c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(i2c_dev->dev); 16988c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(i2c_dev->dev); 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci return (ret < 0) ? ret : num; 17018c2ecf20Sopenharmony_ci} 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_cistatic int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, 17048c2ecf20Sopenharmony_ci unsigned short flags, char read_write, 17058c2ecf20Sopenharmony_ci u8 command, int size, 17068c2ecf20Sopenharmony_ci union i2c_smbus_data *data) 17078c2ecf20Sopenharmony_ci{ 17088c2ecf20Sopenharmony_ci struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(adapter); 17098c2ecf20Sopenharmony_ci struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; 17108c2ecf20Sopenharmony_ci struct stm32_i2c_dma *dma = i2c_dev->dma; 17118c2ecf20Sopenharmony_ci struct device *dev = i2c_dev->dev; 17128c2ecf20Sopenharmony_ci unsigned long timeout; 17138c2ecf20Sopenharmony_ci int i, ret; 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci f7_msg->addr = addr; 17168c2ecf20Sopenharmony_ci f7_msg->size = size; 17178c2ecf20Sopenharmony_ci f7_msg->read_write = read_write; 17188c2ecf20Sopenharmony_ci f7_msg->smbus = true; 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(dev); 17218c2ecf20Sopenharmony_ci if (ret < 0) 17228c2ecf20Sopenharmony_ci return ret; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci ret = stm32f7_i2c_wait_free_bus(i2c_dev); 17258c2ecf20Sopenharmony_ci if (ret) 17268c2ecf20Sopenharmony_ci goto pm_free; 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci ret = stm32f7_i2c_smbus_xfer_msg(i2c_dev, flags, command, data); 17298c2ecf20Sopenharmony_ci if (ret) 17308c2ecf20Sopenharmony_ci goto pm_free; 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci timeout = wait_for_completion_timeout(&i2c_dev->complete, 17338c2ecf20Sopenharmony_ci i2c_dev->adap.timeout); 17348c2ecf20Sopenharmony_ci ret = f7_msg->result; 17358c2ecf20Sopenharmony_ci if (ret) { 17368c2ecf20Sopenharmony_ci /* 17378c2ecf20Sopenharmony_ci * It is possible that some unsent data have already been 17388c2ecf20Sopenharmony_ci * written into TXDR. To avoid sending old data in a 17398c2ecf20Sopenharmony_ci * further transfer, flush TXDR in case of any error 17408c2ecf20Sopenharmony_ci */ 17418c2ecf20Sopenharmony_ci writel_relaxed(STM32F7_I2C_ISR_TXE, 17428c2ecf20Sopenharmony_ci i2c_dev->base + STM32F7_I2C_ISR); 17438c2ecf20Sopenharmony_ci goto pm_free; 17448c2ecf20Sopenharmony_ci } 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci if (!timeout) { 17478c2ecf20Sopenharmony_ci dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr); 17488c2ecf20Sopenharmony_ci if (i2c_dev->use_dma) 17498c2ecf20Sopenharmony_ci dmaengine_terminate_all(dma->chan_using); 17508c2ecf20Sopenharmony_ci stm32f7_i2c_wait_free_bus(i2c_dev); 17518c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 17528c2ecf20Sopenharmony_ci goto pm_free; 17538c2ecf20Sopenharmony_ci } 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci /* Check PEC */ 17568c2ecf20Sopenharmony_ci if ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && read_write) { 17578c2ecf20Sopenharmony_ci ret = stm32f7_i2c_smbus_check_pec(i2c_dev); 17588c2ecf20Sopenharmony_ci if (ret) 17598c2ecf20Sopenharmony_ci goto pm_free; 17608c2ecf20Sopenharmony_ci } 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci if (read_write && size != I2C_SMBUS_QUICK) { 17638c2ecf20Sopenharmony_ci switch (size) { 17648c2ecf20Sopenharmony_ci case I2C_SMBUS_BYTE: 17658c2ecf20Sopenharmony_ci case I2C_SMBUS_BYTE_DATA: 17668c2ecf20Sopenharmony_ci data->byte = f7_msg->smbus_buf[0]; 17678c2ecf20Sopenharmony_ci break; 17688c2ecf20Sopenharmony_ci case I2C_SMBUS_WORD_DATA: 17698c2ecf20Sopenharmony_ci case I2C_SMBUS_PROC_CALL: 17708c2ecf20Sopenharmony_ci data->word = f7_msg->smbus_buf[0] | 17718c2ecf20Sopenharmony_ci (f7_msg->smbus_buf[1] << 8); 17728c2ecf20Sopenharmony_ci break; 17738c2ecf20Sopenharmony_ci case I2C_SMBUS_BLOCK_DATA: 17748c2ecf20Sopenharmony_ci case I2C_SMBUS_BLOCK_PROC_CALL: 17758c2ecf20Sopenharmony_ci for (i = 0; i <= f7_msg->smbus_buf[0]; i++) 17768c2ecf20Sopenharmony_ci data->block[i] = f7_msg->smbus_buf[i]; 17778c2ecf20Sopenharmony_ci break; 17788c2ecf20Sopenharmony_ci default: 17798c2ecf20Sopenharmony_ci dev_err(dev, "Unsupported smbus transaction\n"); 17808c2ecf20Sopenharmony_ci ret = -EINVAL; 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci } 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_cipm_free: 17858c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(dev); 17868c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(dev); 17878c2ecf20Sopenharmony_ci return ret; 17888c2ecf20Sopenharmony_ci} 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_cistatic void stm32f7_i2c_enable_wakeup(struct stm32f7_i2c_dev *i2c_dev, 17918c2ecf20Sopenharmony_ci bool enable) 17928c2ecf20Sopenharmony_ci{ 17938c2ecf20Sopenharmony_ci void __iomem *base = i2c_dev->base; 17948c2ecf20Sopenharmony_ci u32 mask = STM32F7_I2C_CR1_WUPEN; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci if (!i2c_dev->wakeup_src) 17978c2ecf20Sopenharmony_ci return; 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci if (enable) { 18008c2ecf20Sopenharmony_ci device_set_wakeup_enable(i2c_dev->dev, true); 18018c2ecf20Sopenharmony_ci stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask); 18028c2ecf20Sopenharmony_ci } else { 18038c2ecf20Sopenharmony_ci device_set_wakeup_enable(i2c_dev->dev, false); 18048c2ecf20Sopenharmony_ci stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, mask); 18058c2ecf20Sopenharmony_ci } 18068c2ecf20Sopenharmony_ci} 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_cistatic int stm32f7_i2c_reg_slave(struct i2c_client *slave) 18098c2ecf20Sopenharmony_ci{ 18108c2ecf20Sopenharmony_ci struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter); 18118c2ecf20Sopenharmony_ci void __iomem *base = i2c_dev->base; 18128c2ecf20Sopenharmony_ci struct device *dev = i2c_dev->dev; 18138c2ecf20Sopenharmony_ci u32 oar1, oar2, mask; 18148c2ecf20Sopenharmony_ci int id, ret; 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci if (slave->flags & I2C_CLIENT_PEC) { 18178c2ecf20Sopenharmony_ci dev_err(dev, "SMBus PEC not supported in slave mode\n"); 18188c2ecf20Sopenharmony_ci return -EINVAL; 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci if (stm32f7_i2c_is_slave_busy(i2c_dev)) { 18228c2ecf20Sopenharmony_ci dev_err(dev, "Too much slave registered\n"); 18238c2ecf20Sopenharmony_ci return -EBUSY; 18248c2ecf20Sopenharmony_ci } 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci ret = stm32f7_i2c_get_free_slave_id(i2c_dev, slave, &id); 18278c2ecf20Sopenharmony_ci if (ret) 18288c2ecf20Sopenharmony_ci return ret; 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(dev); 18318c2ecf20Sopenharmony_ci if (ret < 0) 18328c2ecf20Sopenharmony_ci return ret; 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci if (!stm32f7_i2c_is_slave_registered(i2c_dev)) 18358c2ecf20Sopenharmony_ci stm32f7_i2c_enable_wakeup(i2c_dev, true); 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_ci switch (id) { 18388c2ecf20Sopenharmony_ci case 0: 18398c2ecf20Sopenharmony_ci /* Slave SMBus Host */ 18408c2ecf20Sopenharmony_ci i2c_dev->slave[id] = slave; 18418c2ecf20Sopenharmony_ci break; 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci case 1: 18448c2ecf20Sopenharmony_ci /* Configure Own Address 1 */ 18458c2ecf20Sopenharmony_ci oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1); 18468c2ecf20Sopenharmony_ci oar1 &= ~STM32F7_I2C_OAR1_MASK; 18478c2ecf20Sopenharmony_ci if (slave->flags & I2C_CLIENT_TEN) { 18488c2ecf20Sopenharmony_ci oar1 |= STM32F7_I2C_OAR1_OA1_10(slave->addr); 18498c2ecf20Sopenharmony_ci oar1 |= STM32F7_I2C_OAR1_OA1MODE; 18508c2ecf20Sopenharmony_ci } else { 18518c2ecf20Sopenharmony_ci oar1 |= STM32F7_I2C_OAR1_OA1_7(slave->addr); 18528c2ecf20Sopenharmony_ci } 18538c2ecf20Sopenharmony_ci oar1 |= STM32F7_I2C_OAR1_OA1EN; 18548c2ecf20Sopenharmony_ci i2c_dev->slave[id] = slave; 18558c2ecf20Sopenharmony_ci writel_relaxed(oar1, i2c_dev->base + STM32F7_I2C_OAR1); 18568c2ecf20Sopenharmony_ci break; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci case 2: 18598c2ecf20Sopenharmony_ci /* Configure Own Address 2 */ 18608c2ecf20Sopenharmony_ci oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2); 18618c2ecf20Sopenharmony_ci oar2 &= ~STM32F7_I2C_OAR2_MASK; 18628c2ecf20Sopenharmony_ci if (slave->flags & I2C_CLIENT_TEN) { 18638c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 18648c2ecf20Sopenharmony_ci goto pm_free; 18658c2ecf20Sopenharmony_ci } 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci oar2 |= STM32F7_I2C_OAR2_OA2_7(slave->addr); 18688c2ecf20Sopenharmony_ci oar2 |= STM32F7_I2C_OAR2_OA2EN; 18698c2ecf20Sopenharmony_ci i2c_dev->slave[id] = slave; 18708c2ecf20Sopenharmony_ci writel_relaxed(oar2, i2c_dev->base + STM32F7_I2C_OAR2); 18718c2ecf20Sopenharmony_ci break; 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci default: 18748c2ecf20Sopenharmony_ci dev_err(dev, "I2C slave id not supported\n"); 18758c2ecf20Sopenharmony_ci ret = -ENODEV; 18768c2ecf20Sopenharmony_ci goto pm_free; 18778c2ecf20Sopenharmony_ci } 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci /* Enable ACK */ 18808c2ecf20Sopenharmony_ci stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR2, STM32F7_I2C_CR2_NACK); 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci /* Enable Address match interrupt, error interrupt and enable I2C */ 18838c2ecf20Sopenharmony_ci mask = STM32F7_I2C_CR1_ADDRIE | STM32F7_I2C_CR1_ERRIE | 18848c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_PE; 18858c2ecf20Sopenharmony_ci stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, mask); 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci ret = 0; 18888c2ecf20Sopenharmony_cipm_free: 18898c2ecf20Sopenharmony_ci if (!stm32f7_i2c_is_slave_registered(i2c_dev)) 18908c2ecf20Sopenharmony_ci stm32f7_i2c_enable_wakeup(i2c_dev, false); 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(dev); 18938c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(dev); 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci return ret; 18968c2ecf20Sopenharmony_ci} 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_cistatic int stm32f7_i2c_unreg_slave(struct i2c_client *slave) 18998c2ecf20Sopenharmony_ci{ 19008c2ecf20Sopenharmony_ci struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(slave->adapter); 19018c2ecf20Sopenharmony_ci void __iomem *base = i2c_dev->base; 19028c2ecf20Sopenharmony_ci u32 mask; 19038c2ecf20Sopenharmony_ci int id, ret; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci ret = stm32f7_i2c_get_slave_id(i2c_dev, slave, &id); 19068c2ecf20Sopenharmony_ci if (ret) 19078c2ecf20Sopenharmony_ci return ret; 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci WARN_ON(!i2c_dev->slave[id]); 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(i2c_dev->dev); 19128c2ecf20Sopenharmony_ci if (ret < 0) 19138c2ecf20Sopenharmony_ci return ret; 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci if (id == 1) { 19168c2ecf20Sopenharmony_ci mask = STM32F7_I2C_OAR1_OA1EN; 19178c2ecf20Sopenharmony_ci stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR1, mask); 19188c2ecf20Sopenharmony_ci } else if (id == 2) { 19198c2ecf20Sopenharmony_ci mask = STM32F7_I2C_OAR2_OA2EN; 19208c2ecf20Sopenharmony_ci stm32f7_i2c_clr_bits(base + STM32F7_I2C_OAR2, mask); 19218c2ecf20Sopenharmony_ci } 19228c2ecf20Sopenharmony_ci 19238c2ecf20Sopenharmony_ci i2c_dev->slave[id] = NULL; 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci if (!stm32f7_i2c_is_slave_registered(i2c_dev)) { 19268c2ecf20Sopenharmony_ci stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_ALL_IRQ_MASK); 19278c2ecf20Sopenharmony_ci stm32f7_i2c_enable_wakeup(i2c_dev, false); 19288c2ecf20Sopenharmony_ci } 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(i2c_dev->dev); 19318c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(i2c_dev->dev); 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci return 0; 19348c2ecf20Sopenharmony_ci} 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_cistatic int stm32f7_i2c_write_fm_plus_bits(struct stm32f7_i2c_dev *i2c_dev, 19378c2ecf20Sopenharmony_ci bool enable) 19388c2ecf20Sopenharmony_ci{ 19398c2ecf20Sopenharmony_ci int ret; 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci if (i2c_dev->bus_rate <= I2C_MAX_FAST_MODE_FREQ || 19428c2ecf20Sopenharmony_ci IS_ERR_OR_NULL(i2c_dev->regmap)) 19438c2ecf20Sopenharmony_ci /* Optional */ 19448c2ecf20Sopenharmony_ci return 0; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci if (i2c_dev->fmp_sreg == i2c_dev->fmp_creg) 19478c2ecf20Sopenharmony_ci ret = regmap_update_bits(i2c_dev->regmap, 19488c2ecf20Sopenharmony_ci i2c_dev->fmp_sreg, 19498c2ecf20Sopenharmony_ci i2c_dev->fmp_mask, 19508c2ecf20Sopenharmony_ci enable ? i2c_dev->fmp_mask : 0); 19518c2ecf20Sopenharmony_ci else 19528c2ecf20Sopenharmony_ci ret = regmap_write(i2c_dev->regmap, 19538c2ecf20Sopenharmony_ci enable ? i2c_dev->fmp_sreg : 19548c2ecf20Sopenharmony_ci i2c_dev->fmp_creg, 19558c2ecf20Sopenharmony_ci i2c_dev->fmp_mask); 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci return ret; 19588c2ecf20Sopenharmony_ci} 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_cistatic int stm32f7_i2c_setup_fm_plus_bits(struct platform_device *pdev, 19618c2ecf20Sopenharmony_ci struct stm32f7_i2c_dev *i2c_dev) 19628c2ecf20Sopenharmony_ci{ 19638c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 19648c2ecf20Sopenharmony_ci int ret; 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci i2c_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg-fmp"); 19678c2ecf20Sopenharmony_ci if (IS_ERR(i2c_dev->regmap)) 19688c2ecf20Sopenharmony_ci /* Optional */ 19698c2ecf20Sopenharmony_ci return 0; 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci ret = of_property_read_u32_index(np, "st,syscfg-fmp", 1, 19728c2ecf20Sopenharmony_ci &i2c_dev->fmp_sreg); 19738c2ecf20Sopenharmony_ci if (ret) 19748c2ecf20Sopenharmony_ci return ret; 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci i2c_dev->fmp_creg = i2c_dev->fmp_sreg + 19778c2ecf20Sopenharmony_ci i2c_dev->setup.fmp_clr_offset; 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci return of_property_read_u32_index(np, "st,syscfg-fmp", 2, 19808c2ecf20Sopenharmony_ci &i2c_dev->fmp_mask); 19818c2ecf20Sopenharmony_ci} 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_cistatic int stm32f7_i2c_enable_smbus_host(struct stm32f7_i2c_dev *i2c_dev) 19848c2ecf20Sopenharmony_ci{ 19858c2ecf20Sopenharmony_ci struct i2c_adapter *adap = &i2c_dev->adap; 19868c2ecf20Sopenharmony_ci void __iomem *base = i2c_dev->base; 19878c2ecf20Sopenharmony_ci struct i2c_client *client; 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci client = i2c_new_slave_host_notify_device(adap); 19908c2ecf20Sopenharmony_ci if (IS_ERR(client)) 19918c2ecf20Sopenharmony_ci return PTR_ERR(client); 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci i2c_dev->host_notify_client = client; 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci /* Enable SMBus Host address */ 19968c2ecf20Sopenharmony_ci stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_SMBHEN); 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci return 0; 19998c2ecf20Sopenharmony_ci} 20008c2ecf20Sopenharmony_ci 20018c2ecf20Sopenharmony_cistatic void stm32f7_i2c_disable_smbus_host(struct stm32f7_i2c_dev *i2c_dev) 20028c2ecf20Sopenharmony_ci{ 20038c2ecf20Sopenharmony_ci void __iomem *base = i2c_dev->base; 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci if (i2c_dev->host_notify_client) { 20068c2ecf20Sopenharmony_ci /* Disable SMBus Host address */ 20078c2ecf20Sopenharmony_ci stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1, 20088c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_SMBHEN); 20098c2ecf20Sopenharmony_ci i2c_free_slave_host_notify_device(i2c_dev->host_notify_client); 20108c2ecf20Sopenharmony_ci } 20118c2ecf20Sopenharmony_ci} 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_cistatic u32 stm32f7_i2c_func(struct i2c_adapter *adap) 20148c2ecf20Sopenharmony_ci{ 20158c2ecf20Sopenharmony_ci struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(adap); 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci u32 func = I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SLAVE | 20188c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | 20198c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | 20208c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL | 20218c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PEC | 20228c2ecf20Sopenharmony_ci I2C_FUNC_SMBUS_I2C_BLOCK; 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_ci if (i2c_dev->smbus_mode) 20258c2ecf20Sopenharmony_ci func |= I2C_FUNC_SMBUS_HOST_NOTIFY; 20268c2ecf20Sopenharmony_ci 20278c2ecf20Sopenharmony_ci return func; 20288c2ecf20Sopenharmony_ci} 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_cistatic const struct i2c_algorithm stm32f7_i2c_algo = { 20318c2ecf20Sopenharmony_ci .master_xfer = stm32f7_i2c_xfer, 20328c2ecf20Sopenharmony_ci .smbus_xfer = stm32f7_i2c_smbus_xfer, 20338c2ecf20Sopenharmony_ci .functionality = stm32f7_i2c_func, 20348c2ecf20Sopenharmony_ci .reg_slave = stm32f7_i2c_reg_slave, 20358c2ecf20Sopenharmony_ci .unreg_slave = stm32f7_i2c_unreg_slave, 20368c2ecf20Sopenharmony_ci}; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_cistatic int stm32f7_i2c_probe(struct platform_device *pdev) 20398c2ecf20Sopenharmony_ci{ 20408c2ecf20Sopenharmony_ci struct stm32f7_i2c_dev *i2c_dev; 20418c2ecf20Sopenharmony_ci const struct stm32f7_i2c_setup *setup; 20428c2ecf20Sopenharmony_ci struct resource *res; 20438c2ecf20Sopenharmony_ci struct i2c_adapter *adap; 20448c2ecf20Sopenharmony_ci struct reset_control *rst; 20458c2ecf20Sopenharmony_ci dma_addr_t phy_addr; 20468c2ecf20Sopenharmony_ci int irq_error, irq_event, ret; 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); 20498c2ecf20Sopenharmony_ci if (!i2c_dev) 20508c2ecf20Sopenharmony_ci return -ENOMEM; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 20538c2ecf20Sopenharmony_ci if (IS_ERR(i2c_dev->base)) 20548c2ecf20Sopenharmony_ci return PTR_ERR(i2c_dev->base); 20558c2ecf20Sopenharmony_ci phy_addr = (dma_addr_t)res->start; 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci irq_event = platform_get_irq(pdev, 0); 20588c2ecf20Sopenharmony_ci if (irq_event <= 0) { 20598c2ecf20Sopenharmony_ci if (irq_event != -EPROBE_DEFER) 20608c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to get IRQ event: %d\n", 20618c2ecf20Sopenharmony_ci irq_event); 20628c2ecf20Sopenharmony_ci return irq_event ? : -ENOENT; 20638c2ecf20Sopenharmony_ci } 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci irq_error = platform_get_irq(pdev, 1); 20668c2ecf20Sopenharmony_ci if (irq_error <= 0) { 20678c2ecf20Sopenharmony_ci if (irq_error != -EPROBE_DEFER) 20688c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to get IRQ error: %d\n", 20698c2ecf20Sopenharmony_ci irq_error); 20708c2ecf20Sopenharmony_ci return irq_error ? : -ENOENT; 20718c2ecf20Sopenharmony_ci } 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci i2c_dev->wakeup_src = of_property_read_bool(pdev->dev.of_node, 20748c2ecf20Sopenharmony_ci "wakeup-source"); 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci i2c_dev->clk = devm_clk_get(&pdev->dev, NULL); 20778c2ecf20Sopenharmony_ci if (IS_ERR(i2c_dev->clk)) 20788c2ecf20Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(i2c_dev->clk), 20798c2ecf20Sopenharmony_ci "Failed to get controller clock\n"); 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci ret = clk_prepare_enable(i2c_dev->clk); 20828c2ecf20Sopenharmony_ci if (ret) { 20838c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to prepare_enable clock\n"); 20848c2ecf20Sopenharmony_ci return ret; 20858c2ecf20Sopenharmony_ci } 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci rst = devm_reset_control_get(&pdev->dev, NULL); 20888c2ecf20Sopenharmony_ci if (IS_ERR(rst)) { 20898c2ecf20Sopenharmony_ci ret = dev_err_probe(&pdev->dev, PTR_ERR(rst), 20908c2ecf20Sopenharmony_ci "Error: Missing reset ctrl\n"); 20918c2ecf20Sopenharmony_ci goto clk_free; 20928c2ecf20Sopenharmony_ci } 20938c2ecf20Sopenharmony_ci reset_control_assert(rst); 20948c2ecf20Sopenharmony_ci udelay(2); 20958c2ecf20Sopenharmony_ci reset_control_deassert(rst); 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci i2c_dev->dev = &pdev->dev; 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, irq_event, 21008c2ecf20Sopenharmony_ci stm32f7_i2c_isr_event, 21018c2ecf20Sopenharmony_ci stm32f7_i2c_isr_event_thread, 21028c2ecf20Sopenharmony_ci IRQF_ONESHOT, 21038c2ecf20Sopenharmony_ci pdev->name, i2c_dev); 21048c2ecf20Sopenharmony_ci if (ret) { 21058c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to request irq event %i\n", 21068c2ecf20Sopenharmony_ci irq_event); 21078c2ecf20Sopenharmony_ci goto clk_free; 21088c2ecf20Sopenharmony_ci } 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq_error, stm32f7_i2c_isr_error, 0, 21118c2ecf20Sopenharmony_ci pdev->name, i2c_dev); 21128c2ecf20Sopenharmony_ci if (ret) { 21138c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to request irq error %i\n", 21148c2ecf20Sopenharmony_ci irq_error); 21158c2ecf20Sopenharmony_ci goto clk_free; 21168c2ecf20Sopenharmony_ci } 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci setup = of_device_get_match_data(&pdev->dev); 21198c2ecf20Sopenharmony_ci if (!setup) { 21208c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Can't get device data\n"); 21218c2ecf20Sopenharmony_ci ret = -ENODEV; 21228c2ecf20Sopenharmony_ci goto clk_free; 21238c2ecf20Sopenharmony_ci } 21248c2ecf20Sopenharmony_ci i2c_dev->setup = *setup; 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci ret = stm32f7_i2c_setup_timing(i2c_dev, &i2c_dev->setup); 21278c2ecf20Sopenharmony_ci if (ret) 21288c2ecf20Sopenharmony_ci goto clk_free; 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci /* Setup Fast mode plus if necessary */ 21318c2ecf20Sopenharmony_ci if (i2c_dev->bus_rate > I2C_MAX_FAST_MODE_FREQ) { 21328c2ecf20Sopenharmony_ci ret = stm32f7_i2c_setup_fm_plus_bits(pdev, i2c_dev); 21338c2ecf20Sopenharmony_ci if (ret) 21348c2ecf20Sopenharmony_ci goto clk_free; 21358c2ecf20Sopenharmony_ci ret = stm32f7_i2c_write_fm_plus_bits(i2c_dev, true); 21368c2ecf20Sopenharmony_ci if (ret) 21378c2ecf20Sopenharmony_ci goto clk_free; 21388c2ecf20Sopenharmony_ci } 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci adap = &i2c_dev->adap; 21418c2ecf20Sopenharmony_ci i2c_set_adapdata(adap, i2c_dev); 21428c2ecf20Sopenharmony_ci snprintf(adap->name, sizeof(adap->name), "STM32F7 I2C(%pa)", 21438c2ecf20Sopenharmony_ci &res->start); 21448c2ecf20Sopenharmony_ci adap->owner = THIS_MODULE; 21458c2ecf20Sopenharmony_ci adap->timeout = 2 * HZ; 21468c2ecf20Sopenharmony_ci adap->retries = 3; 21478c2ecf20Sopenharmony_ci adap->algo = &stm32f7_i2c_algo; 21488c2ecf20Sopenharmony_ci adap->dev.parent = &pdev->dev; 21498c2ecf20Sopenharmony_ci adap->dev.of_node = pdev->dev.of_node; 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci init_completion(&i2c_dev->complete); 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci /* Init DMA config if supported */ 21548c2ecf20Sopenharmony_ci i2c_dev->dma = stm32_i2c_dma_request(i2c_dev->dev, phy_addr, 21558c2ecf20Sopenharmony_ci STM32F7_I2C_TXDR, 21568c2ecf20Sopenharmony_ci STM32F7_I2C_RXDR); 21578c2ecf20Sopenharmony_ci if (IS_ERR(i2c_dev->dma)) { 21588c2ecf20Sopenharmony_ci ret = PTR_ERR(i2c_dev->dma); 21598c2ecf20Sopenharmony_ci /* DMA support is optional, only report other errors */ 21608c2ecf20Sopenharmony_ci if (ret != -ENODEV) 21618c2ecf20Sopenharmony_ci goto fmp_clear; 21628c2ecf20Sopenharmony_ci dev_dbg(i2c_dev->dev, "No DMA option: fallback using interrupts\n"); 21638c2ecf20Sopenharmony_ci i2c_dev->dma = NULL; 21648c2ecf20Sopenharmony_ci } 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci if (i2c_dev->wakeup_src) { 21678c2ecf20Sopenharmony_ci device_set_wakeup_capable(i2c_dev->dev, true); 21688c2ecf20Sopenharmony_ci 21698c2ecf20Sopenharmony_ci ret = dev_pm_set_wake_irq(i2c_dev->dev, irq_event); 21708c2ecf20Sopenharmony_ci if (ret) { 21718c2ecf20Sopenharmony_ci dev_err(i2c_dev->dev, "Failed to set wake up irq\n"); 21728c2ecf20Sopenharmony_ci goto clr_wakeup_capable; 21738c2ecf20Sopenharmony_ci } 21748c2ecf20Sopenharmony_ci } 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, i2c_dev); 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(i2c_dev->dev, 21798c2ecf20Sopenharmony_ci STM32F7_AUTOSUSPEND_DELAY); 21808c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(i2c_dev->dev); 21818c2ecf20Sopenharmony_ci pm_runtime_set_active(i2c_dev->dev); 21828c2ecf20Sopenharmony_ci pm_runtime_enable(i2c_dev->dev); 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci pm_runtime_get_noresume(&pdev->dev); 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci stm32f7_i2c_hw_config(i2c_dev); 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci i2c_dev->smbus_mode = of_property_read_bool(pdev->dev.of_node, "smbus"); 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci ret = i2c_add_adapter(adap); 21918c2ecf20Sopenharmony_ci if (ret) 21928c2ecf20Sopenharmony_ci goto pm_disable; 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci if (i2c_dev->smbus_mode) { 21958c2ecf20Sopenharmony_ci ret = stm32f7_i2c_enable_smbus_host(i2c_dev); 21968c2ecf20Sopenharmony_ci if (ret) { 21978c2ecf20Sopenharmony_ci dev_err(i2c_dev->dev, 21988c2ecf20Sopenharmony_ci "failed to enable SMBus Host-Notify protocol (%d)\n", 21998c2ecf20Sopenharmony_ci ret); 22008c2ecf20Sopenharmony_ci goto i2c_adapter_remove; 22018c2ecf20Sopenharmony_ci } 22028c2ecf20Sopenharmony_ci } 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci dev_info(i2c_dev->dev, "STM32F7 I2C-%d bus adapter\n", adap->nr); 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(i2c_dev->dev); 22078c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(i2c_dev->dev); 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci return 0; 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_cii2c_adapter_remove: 22128c2ecf20Sopenharmony_ci i2c_del_adapter(adap); 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_cipm_disable: 22158c2ecf20Sopenharmony_ci pm_runtime_put_noidle(i2c_dev->dev); 22168c2ecf20Sopenharmony_ci pm_runtime_disable(i2c_dev->dev); 22178c2ecf20Sopenharmony_ci pm_runtime_set_suspended(i2c_dev->dev); 22188c2ecf20Sopenharmony_ci pm_runtime_dont_use_autosuspend(i2c_dev->dev); 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci if (i2c_dev->wakeup_src) 22218c2ecf20Sopenharmony_ci dev_pm_clear_wake_irq(i2c_dev->dev); 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ciclr_wakeup_capable: 22248c2ecf20Sopenharmony_ci if (i2c_dev->wakeup_src) 22258c2ecf20Sopenharmony_ci device_set_wakeup_capable(i2c_dev->dev, false); 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci if (i2c_dev->dma) { 22288c2ecf20Sopenharmony_ci stm32_i2c_dma_free(i2c_dev->dma); 22298c2ecf20Sopenharmony_ci i2c_dev->dma = NULL; 22308c2ecf20Sopenharmony_ci } 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_cifmp_clear: 22338c2ecf20Sopenharmony_ci stm32f7_i2c_write_fm_plus_bits(i2c_dev, false); 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ciclk_free: 22368c2ecf20Sopenharmony_ci clk_disable_unprepare(i2c_dev->clk); 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci return ret; 22398c2ecf20Sopenharmony_ci} 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_cistatic int stm32f7_i2c_remove(struct platform_device *pdev) 22428c2ecf20Sopenharmony_ci{ 22438c2ecf20Sopenharmony_ci struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev); 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci stm32f7_i2c_disable_smbus_host(i2c_dev); 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci i2c_del_adapter(&i2c_dev->adap); 22488c2ecf20Sopenharmony_ci pm_runtime_get_sync(i2c_dev->dev); 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci if (i2c_dev->wakeup_src) { 22518c2ecf20Sopenharmony_ci dev_pm_clear_wake_irq(i2c_dev->dev); 22528c2ecf20Sopenharmony_ci /* 22538c2ecf20Sopenharmony_ci * enforce that wakeup is disabled and that the device 22548c2ecf20Sopenharmony_ci * is marked as non wakeup capable 22558c2ecf20Sopenharmony_ci */ 22568c2ecf20Sopenharmony_ci device_init_wakeup(i2c_dev->dev, false); 22578c2ecf20Sopenharmony_ci } 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci pm_runtime_put_noidle(i2c_dev->dev); 22608c2ecf20Sopenharmony_ci pm_runtime_disable(i2c_dev->dev); 22618c2ecf20Sopenharmony_ci pm_runtime_set_suspended(i2c_dev->dev); 22628c2ecf20Sopenharmony_ci pm_runtime_dont_use_autosuspend(i2c_dev->dev); 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci if (i2c_dev->dma) { 22658c2ecf20Sopenharmony_ci stm32_i2c_dma_free(i2c_dev->dma); 22668c2ecf20Sopenharmony_ci i2c_dev->dma = NULL; 22678c2ecf20Sopenharmony_ci } 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci stm32f7_i2c_write_fm_plus_bits(i2c_dev, false); 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci clk_disable_unprepare(i2c_dev->clk); 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci return 0; 22748c2ecf20Sopenharmony_ci} 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_cistatic int __maybe_unused stm32f7_i2c_runtime_suspend(struct device *dev) 22778c2ecf20Sopenharmony_ci{ 22788c2ecf20Sopenharmony_ci struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci if (!stm32f7_i2c_is_slave_registered(i2c_dev)) 22818c2ecf20Sopenharmony_ci clk_disable_unprepare(i2c_dev->clk); 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci return 0; 22848c2ecf20Sopenharmony_ci} 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_cistatic int __maybe_unused stm32f7_i2c_runtime_resume(struct device *dev) 22878c2ecf20Sopenharmony_ci{ 22888c2ecf20Sopenharmony_ci struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); 22898c2ecf20Sopenharmony_ci int ret; 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_ci if (!stm32f7_i2c_is_slave_registered(i2c_dev)) { 22928c2ecf20Sopenharmony_ci ret = clk_prepare_enable(i2c_dev->clk); 22938c2ecf20Sopenharmony_ci if (ret) { 22948c2ecf20Sopenharmony_ci dev_err(dev, "failed to prepare_enable clock\n"); 22958c2ecf20Sopenharmony_ci return ret; 22968c2ecf20Sopenharmony_ci } 22978c2ecf20Sopenharmony_ci } 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci return 0; 23008c2ecf20Sopenharmony_ci} 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 23038c2ecf20Sopenharmony_cistatic int stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev) 23048c2ecf20Sopenharmony_ci{ 23058c2ecf20Sopenharmony_ci int ret; 23068c2ecf20Sopenharmony_ci struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs; 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(i2c_dev->dev); 23098c2ecf20Sopenharmony_ci if (ret < 0) 23108c2ecf20Sopenharmony_ci return ret; 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci backup_regs->cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1); 23138c2ecf20Sopenharmony_ci backup_regs->cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2); 23148c2ecf20Sopenharmony_ci backup_regs->oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1); 23158c2ecf20Sopenharmony_ci backup_regs->oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2); 23168c2ecf20Sopenharmony_ci backup_regs->tmgr = readl_relaxed(i2c_dev->base + STM32F7_I2C_TIMINGR); 23178c2ecf20Sopenharmony_ci stm32f7_i2c_write_fm_plus_bits(i2c_dev, false); 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci pm_runtime_put_sync(i2c_dev->dev); 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci return ret; 23228c2ecf20Sopenharmony_ci} 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_cistatic int stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev) 23258c2ecf20Sopenharmony_ci{ 23268c2ecf20Sopenharmony_ci u32 cr1; 23278c2ecf20Sopenharmony_ci int ret; 23288c2ecf20Sopenharmony_ci struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs; 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci ret = pm_runtime_resume_and_get(i2c_dev->dev); 23318c2ecf20Sopenharmony_ci if (ret < 0) 23328c2ecf20Sopenharmony_ci return ret; 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1); 23358c2ecf20Sopenharmony_ci if (cr1 & STM32F7_I2C_CR1_PE) 23368c2ecf20Sopenharmony_ci stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, 23378c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_PE); 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci writel_relaxed(backup_regs->tmgr, i2c_dev->base + STM32F7_I2C_TIMINGR); 23408c2ecf20Sopenharmony_ci writel_relaxed(backup_regs->cr1 & ~STM32F7_I2C_CR1_PE, 23418c2ecf20Sopenharmony_ci i2c_dev->base + STM32F7_I2C_CR1); 23428c2ecf20Sopenharmony_ci if (backup_regs->cr1 & STM32F7_I2C_CR1_PE) 23438c2ecf20Sopenharmony_ci stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1, 23448c2ecf20Sopenharmony_ci STM32F7_I2C_CR1_PE); 23458c2ecf20Sopenharmony_ci writel_relaxed(backup_regs->cr2, i2c_dev->base + STM32F7_I2C_CR2); 23468c2ecf20Sopenharmony_ci writel_relaxed(backup_regs->oar1, i2c_dev->base + STM32F7_I2C_OAR1); 23478c2ecf20Sopenharmony_ci writel_relaxed(backup_regs->oar2, i2c_dev->base + STM32F7_I2C_OAR2); 23488c2ecf20Sopenharmony_ci stm32f7_i2c_write_fm_plus_bits(i2c_dev, true); 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci pm_runtime_put_sync(i2c_dev->dev); 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_ci return ret; 23538c2ecf20Sopenharmony_ci} 23548c2ecf20Sopenharmony_ci 23558c2ecf20Sopenharmony_cistatic int stm32f7_i2c_suspend(struct device *dev) 23568c2ecf20Sopenharmony_ci{ 23578c2ecf20Sopenharmony_ci struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); 23588c2ecf20Sopenharmony_ci int ret; 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci i2c_mark_adapter_suspended(&i2c_dev->adap); 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci if (!device_may_wakeup(dev) && !dev->power.wakeup_path) { 23638c2ecf20Sopenharmony_ci ret = stm32f7_i2c_regs_backup(i2c_dev); 23648c2ecf20Sopenharmony_ci if (ret < 0) { 23658c2ecf20Sopenharmony_ci i2c_mark_adapter_resumed(&i2c_dev->adap); 23668c2ecf20Sopenharmony_ci return ret; 23678c2ecf20Sopenharmony_ci } 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci pinctrl_pm_select_sleep_state(dev); 23708c2ecf20Sopenharmony_ci pm_runtime_force_suspend(dev); 23718c2ecf20Sopenharmony_ci } 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci return 0; 23748c2ecf20Sopenharmony_ci} 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_cistatic int stm32f7_i2c_resume(struct device *dev) 23778c2ecf20Sopenharmony_ci{ 23788c2ecf20Sopenharmony_ci struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); 23798c2ecf20Sopenharmony_ci int ret; 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci if (!device_may_wakeup(dev) && !dev->power.wakeup_path) { 23828c2ecf20Sopenharmony_ci ret = pm_runtime_force_resume(dev); 23838c2ecf20Sopenharmony_ci if (ret < 0) 23848c2ecf20Sopenharmony_ci return ret; 23858c2ecf20Sopenharmony_ci pinctrl_pm_select_default_state(dev); 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci ret = stm32f7_i2c_regs_restore(i2c_dev); 23888c2ecf20Sopenharmony_ci if (ret < 0) 23898c2ecf20Sopenharmony_ci return ret; 23908c2ecf20Sopenharmony_ci } 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci i2c_mark_adapter_resumed(&i2c_dev->adap); 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci return 0; 23958c2ecf20Sopenharmony_ci} 23968c2ecf20Sopenharmony_ci#endif 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_cistatic const struct dev_pm_ops stm32f7_i2c_pm_ops = { 23998c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(stm32f7_i2c_runtime_suspend, 24008c2ecf20Sopenharmony_ci stm32f7_i2c_runtime_resume, NULL) 24018c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(stm32f7_i2c_suspend, stm32f7_i2c_resume) 24028c2ecf20Sopenharmony_ci}; 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_cistatic const struct of_device_id stm32f7_i2c_match[] = { 24058c2ecf20Sopenharmony_ci { .compatible = "st,stm32f7-i2c", .data = &stm32f7_setup}, 24068c2ecf20Sopenharmony_ci { .compatible = "st,stm32mp15-i2c", .data = &stm32mp15_setup}, 24078c2ecf20Sopenharmony_ci {}, 24088c2ecf20Sopenharmony_ci}; 24098c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, stm32f7_i2c_match); 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_cistatic struct platform_driver stm32f7_i2c_driver = { 24128c2ecf20Sopenharmony_ci .driver = { 24138c2ecf20Sopenharmony_ci .name = "stm32f7-i2c", 24148c2ecf20Sopenharmony_ci .of_match_table = stm32f7_i2c_match, 24158c2ecf20Sopenharmony_ci .pm = &stm32f7_i2c_pm_ops, 24168c2ecf20Sopenharmony_ci }, 24178c2ecf20Sopenharmony_ci .probe = stm32f7_i2c_probe, 24188c2ecf20Sopenharmony_ci .remove = stm32f7_i2c_remove, 24198c2ecf20Sopenharmony_ci}; 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_cimodule_platform_driver(stm32f7_i2c_driver); 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_ciMODULE_AUTHOR("M'boumba Cedric Madianga <cedric.madianga@gmail.com>"); 24248c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("STMicroelectronics STM32F7 I2C driver"); 24258c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 2426