162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2002 Motorola GSG-China 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: 662306a36Sopenharmony_ci * Darius Augulis, Teltonika Inc. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Desc.: 962306a36Sopenharmony_ci * Implementation of I2C Adapter/Algorithm Driver 1062306a36Sopenharmony_ci * for I2C Bus integrated in Freescale i.MX/MXC processors 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Derived from Motorola GSG China I2C example driver 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Copyright (C) 2005 Torsten Koschorrek <koschorrek at synertronixx.de 1562306a36Sopenharmony_ci * Copyright (C) 2005 Matthias Blaschke <blaschke at synertronixx.de 1662306a36Sopenharmony_ci * Copyright (C) 2007 RightHand Technologies, Inc. 1762306a36Sopenharmony_ci * Copyright (C) 2008 Darius Augulis <darius.augulis at teltonika.lt> 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Copyright 2013 Freescale Semiconductor, Inc. 2062306a36Sopenharmony_ci * Copyright 2020 NXP 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <linux/acpi.h> 2562306a36Sopenharmony_ci#include <linux/clk.h> 2662306a36Sopenharmony_ci#include <linux/completion.h> 2762306a36Sopenharmony_ci#include <linux/delay.h> 2862306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2962306a36Sopenharmony_ci#include <linux/dmaengine.h> 3062306a36Sopenharmony_ci#include <linux/dmapool.h> 3162306a36Sopenharmony_ci#include <linux/err.h> 3262306a36Sopenharmony_ci#include <linux/errno.h> 3362306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 3462306a36Sopenharmony_ci#include <linux/i2c.h> 3562306a36Sopenharmony_ci#include <linux/init.h> 3662306a36Sopenharmony_ci#include <linux/interrupt.h> 3762306a36Sopenharmony_ci#include <linux/io.h> 3862306a36Sopenharmony_ci#include <linux/iopoll.h> 3962306a36Sopenharmony_ci#include <linux/kernel.h> 4062306a36Sopenharmony_ci#include <linux/spinlock.h> 4162306a36Sopenharmony_ci#include <linux/hrtimer.h> 4262306a36Sopenharmony_ci#include <linux/module.h> 4362306a36Sopenharmony_ci#include <linux/of.h> 4462306a36Sopenharmony_ci#include <linux/of_dma.h> 4562306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 4662306a36Sopenharmony_ci#include <linux/platform_data/i2c-imx.h> 4762306a36Sopenharmony_ci#include <linux/platform_device.h> 4862306a36Sopenharmony_ci#include <linux/pm_runtime.h> 4962306a36Sopenharmony_ci#include <linux/sched.h> 5062306a36Sopenharmony_ci#include <linux/slab.h> 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* This will be the driver name the kernel reports */ 5362306a36Sopenharmony_ci#define DRIVER_NAME "imx-i2c" 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define I2C_IMX_CHECK_DELAY 30000 /* Time to check for bus idle, in NS */ 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* 5862306a36Sopenharmony_ci * Enable DMA if transfer byte size is bigger than this threshold. 5962306a36Sopenharmony_ci * As the hardware request, it must bigger than 4 bytes.\ 6062306a36Sopenharmony_ci * I have set '16' here, maybe it's not the best but I think it's 6162306a36Sopenharmony_ci * the appropriate. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_ci#define DMA_THRESHOLD 16 6462306a36Sopenharmony_ci#define DMA_TIMEOUT 1000 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* IMX I2C registers: 6762306a36Sopenharmony_ci * the I2C register offset is different between SoCs, 6862306a36Sopenharmony_ci * to provide support for all these chips, split the 6962306a36Sopenharmony_ci * register offset into a fixed base address and a 7062306a36Sopenharmony_ci * variable shift value, then the full register offset 7162306a36Sopenharmony_ci * will be calculated by 7262306a36Sopenharmony_ci * reg_off = ( reg_base_addr << reg_shift) 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci#define IMX_I2C_IADR 0x00 /* i2c slave address */ 7562306a36Sopenharmony_ci#define IMX_I2C_IFDR 0x01 /* i2c frequency divider */ 7662306a36Sopenharmony_ci#define IMX_I2C_I2CR 0x02 /* i2c control */ 7762306a36Sopenharmony_ci#define IMX_I2C_I2SR 0x03 /* i2c status */ 7862306a36Sopenharmony_ci#define IMX_I2C_I2DR 0x04 /* i2c transfer data */ 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* 8162306a36Sopenharmony_ci * All of the layerscape series SoCs support IBIC register. 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_ci#define IMX_I2C_IBIC 0x05 /* i2c bus interrupt config */ 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#define IMX_I2C_REGSHIFT 2 8662306a36Sopenharmony_ci#define VF610_I2C_REGSHIFT 0 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/* Bits of IMX I2C registers */ 8962306a36Sopenharmony_ci#define I2SR_RXAK 0x01 9062306a36Sopenharmony_ci#define I2SR_IIF 0x02 9162306a36Sopenharmony_ci#define I2SR_SRW 0x04 9262306a36Sopenharmony_ci#define I2SR_IAL 0x10 9362306a36Sopenharmony_ci#define I2SR_IBB 0x20 9462306a36Sopenharmony_ci#define I2SR_IAAS 0x40 9562306a36Sopenharmony_ci#define I2SR_ICF 0x80 9662306a36Sopenharmony_ci#define I2CR_DMAEN 0x02 9762306a36Sopenharmony_ci#define I2CR_RSTA 0x04 9862306a36Sopenharmony_ci#define I2CR_TXAK 0x08 9962306a36Sopenharmony_ci#define I2CR_MTX 0x10 10062306a36Sopenharmony_ci#define I2CR_MSTA 0x20 10162306a36Sopenharmony_ci#define I2CR_IIEN 0x40 10262306a36Sopenharmony_ci#define I2CR_IEN 0x80 10362306a36Sopenharmony_ci#define IBIC_BIIE 0x80 /* Bus idle interrupt enable */ 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* register bits different operating codes definition: 10662306a36Sopenharmony_ci * 1) I2SR: Interrupt flags clear operation differ between SoCs: 10762306a36Sopenharmony_ci * - write zero to clear(w0c) INT flag on i.MX, 10862306a36Sopenharmony_ci * - but write one to clear(w1c) INT flag on Vybrid. 10962306a36Sopenharmony_ci * 2) I2CR: I2C module enable operation also differ between SoCs: 11062306a36Sopenharmony_ci * - set I2CR_IEN bit enable the module on i.MX, 11162306a36Sopenharmony_ci * - but clear I2CR_IEN bit enable the module on Vybrid. 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_ci#define I2SR_CLR_OPCODE_W0C 0x0 11462306a36Sopenharmony_ci#define I2SR_CLR_OPCODE_W1C (I2SR_IAL | I2SR_IIF) 11562306a36Sopenharmony_ci#define I2CR_IEN_OPCODE_0 0x0 11662306a36Sopenharmony_ci#define I2CR_IEN_OPCODE_1 I2CR_IEN 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci#define I2C_PM_TIMEOUT 10 /* ms */ 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci/* 12162306a36Sopenharmony_ci * sorted list of clock divider, register value pairs 12262306a36Sopenharmony_ci * taken from table 26-5, p.26-9, Freescale i.MX 12362306a36Sopenharmony_ci * Integrated Portable System Processor Reference Manual 12462306a36Sopenharmony_ci * Document Number: MC9328MXLRM, Rev. 5.1, 06/2007 12562306a36Sopenharmony_ci * 12662306a36Sopenharmony_ci * Duplicated divider values removed from list 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_cistruct imx_i2c_clk_pair { 12962306a36Sopenharmony_ci u16 div; 13062306a36Sopenharmony_ci u16 val; 13162306a36Sopenharmony_ci}; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic struct imx_i2c_clk_pair imx_i2c_clk_div[] = { 13462306a36Sopenharmony_ci { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 }, 13562306a36Sopenharmony_ci { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 }, 13662306a36Sopenharmony_ci { 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 }, 13762306a36Sopenharmony_ci { 56, 0x29 }, { 60, 0x06 }, { 64, 0x2A }, { 72, 0x2B }, 13862306a36Sopenharmony_ci { 80, 0x2C }, { 88, 0x09 }, { 96, 0x2D }, { 104, 0x0A }, 13962306a36Sopenharmony_ci { 112, 0x2E }, { 128, 0x2F }, { 144, 0x0C }, { 160, 0x30 }, 14062306a36Sopenharmony_ci { 192, 0x31 }, { 224, 0x32 }, { 240, 0x0F }, { 256, 0x33 }, 14162306a36Sopenharmony_ci { 288, 0x10 }, { 320, 0x34 }, { 384, 0x35 }, { 448, 0x36 }, 14262306a36Sopenharmony_ci { 480, 0x13 }, { 512, 0x37 }, { 576, 0x14 }, { 640, 0x38 }, 14362306a36Sopenharmony_ci { 768, 0x39 }, { 896, 0x3A }, { 960, 0x17 }, { 1024, 0x3B }, 14462306a36Sopenharmony_ci { 1152, 0x18 }, { 1280, 0x3C }, { 1536, 0x3D }, { 1792, 0x3E }, 14562306a36Sopenharmony_ci { 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D }, 14662306a36Sopenharmony_ci { 3072, 0x1E }, { 3840, 0x1F } 14762306a36Sopenharmony_ci}; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci/* Vybrid VF610 clock divider, register value pairs */ 15062306a36Sopenharmony_cistatic struct imx_i2c_clk_pair vf610_i2c_clk_div[] = { 15162306a36Sopenharmony_ci { 20, 0x00 }, { 22, 0x01 }, { 24, 0x02 }, { 26, 0x03 }, 15262306a36Sopenharmony_ci { 28, 0x04 }, { 30, 0x05 }, { 32, 0x09 }, { 34, 0x06 }, 15362306a36Sopenharmony_ci { 36, 0x0A }, { 40, 0x07 }, { 44, 0x0C }, { 48, 0x0D }, 15462306a36Sopenharmony_ci { 52, 0x43 }, { 56, 0x0E }, { 60, 0x45 }, { 64, 0x12 }, 15562306a36Sopenharmony_ci { 68, 0x0F }, { 72, 0x13 }, { 80, 0x14 }, { 88, 0x15 }, 15662306a36Sopenharmony_ci { 96, 0x19 }, { 104, 0x16 }, { 112, 0x1A }, { 128, 0x17 }, 15762306a36Sopenharmony_ci { 136, 0x4F }, { 144, 0x1C }, { 160, 0x1D }, { 176, 0x55 }, 15862306a36Sopenharmony_ci { 192, 0x1E }, { 208, 0x56 }, { 224, 0x22 }, { 228, 0x24 }, 15962306a36Sopenharmony_ci { 240, 0x1F }, { 256, 0x23 }, { 288, 0x5C }, { 320, 0x25 }, 16062306a36Sopenharmony_ci { 384, 0x26 }, { 448, 0x2A }, { 480, 0x27 }, { 512, 0x2B }, 16162306a36Sopenharmony_ci { 576, 0x2C }, { 640, 0x2D }, { 768, 0x31 }, { 896, 0x32 }, 16262306a36Sopenharmony_ci { 960, 0x2F }, { 1024, 0x33 }, { 1152, 0x34 }, { 1280, 0x35 }, 16362306a36Sopenharmony_ci { 1536, 0x36 }, { 1792, 0x3A }, { 1920, 0x37 }, { 2048, 0x3B }, 16462306a36Sopenharmony_ci { 2304, 0x3C }, { 2560, 0x3D }, { 3072, 0x3E }, { 3584, 0x7A }, 16562306a36Sopenharmony_ci { 3840, 0x3F }, { 4096, 0x7B }, { 5120, 0x7D }, { 6144, 0x7E }, 16662306a36Sopenharmony_ci}; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cienum imx_i2c_type { 16962306a36Sopenharmony_ci IMX1_I2C, 17062306a36Sopenharmony_ci IMX21_I2C, 17162306a36Sopenharmony_ci VF610_I2C, 17262306a36Sopenharmony_ci}; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistruct imx_i2c_hwdata { 17562306a36Sopenharmony_ci enum imx_i2c_type devtype; 17662306a36Sopenharmony_ci unsigned int regshift; 17762306a36Sopenharmony_ci struct imx_i2c_clk_pair *clk_div; 17862306a36Sopenharmony_ci unsigned int ndivs; 17962306a36Sopenharmony_ci unsigned int i2sr_clr_opcode; 18062306a36Sopenharmony_ci unsigned int i2cr_ien_opcode; 18162306a36Sopenharmony_ci /* 18262306a36Sopenharmony_ci * Errata ERR007805 or e7805: 18362306a36Sopenharmony_ci * I2C: When the I2C clock speed is configured for 400 kHz, 18462306a36Sopenharmony_ci * the SCL low period violates the I2C spec of 1.3 uS min. 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_ci bool has_err007805; 18762306a36Sopenharmony_ci}; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistruct imx_i2c_dma { 19062306a36Sopenharmony_ci struct dma_chan *chan_tx; 19162306a36Sopenharmony_ci struct dma_chan *chan_rx; 19262306a36Sopenharmony_ci struct dma_chan *chan_using; 19362306a36Sopenharmony_ci struct completion cmd_complete; 19462306a36Sopenharmony_ci dma_addr_t dma_buf; 19562306a36Sopenharmony_ci unsigned int dma_len; 19662306a36Sopenharmony_ci enum dma_transfer_direction dma_transfer_dir; 19762306a36Sopenharmony_ci enum dma_data_direction dma_data_dir; 19862306a36Sopenharmony_ci}; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistruct imx_i2c_struct { 20162306a36Sopenharmony_ci struct i2c_adapter adapter; 20262306a36Sopenharmony_ci struct clk *clk; 20362306a36Sopenharmony_ci struct notifier_block clk_change_nb; 20462306a36Sopenharmony_ci void __iomem *base; 20562306a36Sopenharmony_ci wait_queue_head_t queue; 20662306a36Sopenharmony_ci unsigned long i2csr; 20762306a36Sopenharmony_ci unsigned int disable_delay; 20862306a36Sopenharmony_ci int stopped; 20962306a36Sopenharmony_ci unsigned int ifdr; /* IMX_I2C_IFDR */ 21062306a36Sopenharmony_ci unsigned int cur_clk; 21162306a36Sopenharmony_ci unsigned int bitrate; 21262306a36Sopenharmony_ci const struct imx_i2c_hwdata *hwdata; 21362306a36Sopenharmony_ci struct i2c_bus_recovery_info rinfo; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci struct pinctrl *pinctrl; 21662306a36Sopenharmony_ci struct pinctrl_state *pinctrl_pins_default; 21762306a36Sopenharmony_ci struct pinctrl_state *pinctrl_pins_gpio; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci struct imx_i2c_dma *dma; 22062306a36Sopenharmony_ci struct i2c_client *slave; 22162306a36Sopenharmony_ci enum i2c_slave_event last_slave_event; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* For checking slave events. */ 22462306a36Sopenharmony_ci spinlock_t slave_lock; 22562306a36Sopenharmony_ci struct hrtimer slave_timer; 22662306a36Sopenharmony_ci}; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic const struct imx_i2c_hwdata imx1_i2c_hwdata = { 22962306a36Sopenharmony_ci .devtype = IMX1_I2C, 23062306a36Sopenharmony_ci .regshift = IMX_I2C_REGSHIFT, 23162306a36Sopenharmony_ci .clk_div = imx_i2c_clk_div, 23262306a36Sopenharmony_ci .ndivs = ARRAY_SIZE(imx_i2c_clk_div), 23362306a36Sopenharmony_ci .i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C, 23462306a36Sopenharmony_ci .i2cr_ien_opcode = I2CR_IEN_OPCODE_1, 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci}; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic const struct imx_i2c_hwdata imx21_i2c_hwdata = { 23962306a36Sopenharmony_ci .devtype = IMX21_I2C, 24062306a36Sopenharmony_ci .regshift = IMX_I2C_REGSHIFT, 24162306a36Sopenharmony_ci .clk_div = imx_i2c_clk_div, 24262306a36Sopenharmony_ci .ndivs = ARRAY_SIZE(imx_i2c_clk_div), 24362306a36Sopenharmony_ci .i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C, 24462306a36Sopenharmony_ci .i2cr_ien_opcode = I2CR_IEN_OPCODE_1, 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci}; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic const struct imx_i2c_hwdata imx6_i2c_hwdata = { 24962306a36Sopenharmony_ci .devtype = IMX21_I2C, 25062306a36Sopenharmony_ci .regshift = IMX_I2C_REGSHIFT, 25162306a36Sopenharmony_ci .clk_div = imx_i2c_clk_div, 25262306a36Sopenharmony_ci .ndivs = ARRAY_SIZE(imx_i2c_clk_div), 25362306a36Sopenharmony_ci .i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C, 25462306a36Sopenharmony_ci .i2cr_ien_opcode = I2CR_IEN_OPCODE_1, 25562306a36Sopenharmony_ci .has_err007805 = true, 25662306a36Sopenharmony_ci}; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic struct imx_i2c_hwdata vf610_i2c_hwdata = { 25962306a36Sopenharmony_ci .devtype = VF610_I2C, 26062306a36Sopenharmony_ci .regshift = VF610_I2C_REGSHIFT, 26162306a36Sopenharmony_ci .clk_div = vf610_i2c_clk_div, 26262306a36Sopenharmony_ci .ndivs = ARRAY_SIZE(vf610_i2c_clk_div), 26362306a36Sopenharmony_ci .i2sr_clr_opcode = I2SR_CLR_OPCODE_W1C, 26462306a36Sopenharmony_ci .i2cr_ien_opcode = I2CR_IEN_OPCODE_0, 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci}; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic const struct platform_device_id imx_i2c_devtype[] = { 26962306a36Sopenharmony_ci { 27062306a36Sopenharmony_ci .name = "imx1-i2c", 27162306a36Sopenharmony_ci .driver_data = (kernel_ulong_t)&imx1_i2c_hwdata, 27262306a36Sopenharmony_ci }, { 27362306a36Sopenharmony_ci .name = "imx21-i2c", 27462306a36Sopenharmony_ci .driver_data = (kernel_ulong_t)&imx21_i2c_hwdata, 27562306a36Sopenharmony_ci }, { 27662306a36Sopenharmony_ci /* sentinel */ 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci}; 27962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, imx_i2c_devtype); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic const struct of_device_id i2c_imx_dt_ids[] = { 28262306a36Sopenharmony_ci { .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, }, 28362306a36Sopenharmony_ci { .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, }, 28462306a36Sopenharmony_ci { .compatible = "fsl,imx6q-i2c", .data = &imx6_i2c_hwdata, }, 28562306a36Sopenharmony_ci { .compatible = "fsl,imx6sl-i2c", .data = &imx6_i2c_hwdata, }, 28662306a36Sopenharmony_ci { .compatible = "fsl,imx6sll-i2c", .data = &imx6_i2c_hwdata, }, 28762306a36Sopenharmony_ci { .compatible = "fsl,imx6sx-i2c", .data = &imx6_i2c_hwdata, }, 28862306a36Sopenharmony_ci { .compatible = "fsl,imx6ul-i2c", .data = &imx6_i2c_hwdata, }, 28962306a36Sopenharmony_ci { .compatible = "fsl,imx7s-i2c", .data = &imx6_i2c_hwdata, }, 29062306a36Sopenharmony_ci { .compatible = "fsl,imx8mm-i2c", .data = &imx6_i2c_hwdata, }, 29162306a36Sopenharmony_ci { .compatible = "fsl,imx8mn-i2c", .data = &imx6_i2c_hwdata, }, 29262306a36Sopenharmony_ci { .compatible = "fsl,imx8mp-i2c", .data = &imx6_i2c_hwdata, }, 29362306a36Sopenharmony_ci { .compatible = "fsl,imx8mq-i2c", .data = &imx6_i2c_hwdata, }, 29462306a36Sopenharmony_ci { .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, }, 29562306a36Sopenharmony_ci { /* sentinel */ } 29662306a36Sopenharmony_ci}; 29762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, i2c_imx_dt_ids); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic const struct acpi_device_id i2c_imx_acpi_ids[] = { 30062306a36Sopenharmony_ci {"NXP0001", .driver_data = (kernel_ulong_t)&vf610_i2c_hwdata}, 30162306a36Sopenharmony_ci { } 30262306a36Sopenharmony_ci}; 30362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, i2c_imx_acpi_ids); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic inline int is_imx1_i2c(struct imx_i2c_struct *i2c_imx) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci return i2c_imx->hwdata->devtype == IMX1_I2C; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic inline int is_vf610_i2c(struct imx_i2c_struct *i2c_imx) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci return i2c_imx->hwdata->devtype == VF610_I2C; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic inline void imx_i2c_write_reg(unsigned int val, 31662306a36Sopenharmony_ci struct imx_i2c_struct *i2c_imx, unsigned int reg) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci writeb(val, i2c_imx->base + (reg << i2c_imx->hwdata->regshift)); 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic inline unsigned char imx_i2c_read_reg(struct imx_i2c_struct *i2c_imx, 32262306a36Sopenharmony_ci unsigned int reg) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci return readb(i2c_imx->base + (reg << i2c_imx->hwdata->regshift)); 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic void i2c_imx_clear_irq(struct imx_i2c_struct *i2c_imx, unsigned int bits) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci unsigned int temp; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* 33262306a36Sopenharmony_ci * i2sr_clr_opcode is the value to clear all interrupts. Here we want to 33362306a36Sopenharmony_ci * clear only <bits>, so we write ~i2sr_clr_opcode with just <bits> 33462306a36Sopenharmony_ci * toggled. This is required because i.MX needs W0C and Vybrid uses W1C. 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_ci temp = ~i2c_imx->hwdata->i2sr_clr_opcode ^ bits; 33762306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci/* Set up i2c controller register and i2c status register to default value. */ 34162306a36Sopenharmony_cistatic void i2c_imx_reset_regs(struct imx_i2c_struct *i2c_imx) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, 34462306a36Sopenharmony_ci i2c_imx, IMX_I2C_I2CR); 34562306a36Sopenharmony_ci i2c_imx_clear_irq(i2c_imx, I2SR_IIF | I2SR_IAL); 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci/* Functions for DMA support */ 34962306a36Sopenharmony_cistatic void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, 35062306a36Sopenharmony_ci dma_addr_t phy_addr) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci struct imx_i2c_dma *dma; 35362306a36Sopenharmony_ci struct dma_slave_config dma_sconfig; 35462306a36Sopenharmony_ci struct device *dev = &i2c_imx->adapter.dev; 35562306a36Sopenharmony_ci int ret; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); 35862306a36Sopenharmony_ci if (!dma) 35962306a36Sopenharmony_ci return; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci dma->chan_tx = dma_request_chan(dev, "tx"); 36262306a36Sopenharmony_ci if (IS_ERR(dma->chan_tx)) { 36362306a36Sopenharmony_ci ret = PTR_ERR(dma->chan_tx); 36462306a36Sopenharmony_ci if (ret != -ENODEV && ret != -EPROBE_DEFER) 36562306a36Sopenharmony_ci dev_err(dev, "can't request DMA tx channel (%d)\n", ret); 36662306a36Sopenharmony_ci goto fail_al; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci dma_sconfig.dst_addr = phy_addr + 37062306a36Sopenharmony_ci (IMX_I2C_I2DR << i2c_imx->hwdata->regshift); 37162306a36Sopenharmony_ci dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 37262306a36Sopenharmony_ci dma_sconfig.dst_maxburst = 1; 37362306a36Sopenharmony_ci dma_sconfig.direction = DMA_MEM_TO_DEV; 37462306a36Sopenharmony_ci ret = dmaengine_slave_config(dma->chan_tx, &dma_sconfig); 37562306a36Sopenharmony_ci if (ret < 0) { 37662306a36Sopenharmony_ci dev_err(dev, "can't configure tx channel (%d)\n", ret); 37762306a36Sopenharmony_ci goto fail_tx; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci dma->chan_rx = dma_request_chan(dev, "rx"); 38162306a36Sopenharmony_ci if (IS_ERR(dma->chan_rx)) { 38262306a36Sopenharmony_ci ret = PTR_ERR(dma->chan_rx); 38362306a36Sopenharmony_ci if (ret != -ENODEV && ret != -EPROBE_DEFER) 38462306a36Sopenharmony_ci dev_err(dev, "can't request DMA rx channel (%d)\n", ret); 38562306a36Sopenharmony_ci goto fail_tx; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci dma_sconfig.src_addr = phy_addr + 38962306a36Sopenharmony_ci (IMX_I2C_I2DR << i2c_imx->hwdata->regshift); 39062306a36Sopenharmony_ci dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 39162306a36Sopenharmony_ci dma_sconfig.src_maxburst = 1; 39262306a36Sopenharmony_ci dma_sconfig.direction = DMA_DEV_TO_MEM; 39362306a36Sopenharmony_ci ret = dmaengine_slave_config(dma->chan_rx, &dma_sconfig); 39462306a36Sopenharmony_ci if (ret < 0) { 39562306a36Sopenharmony_ci dev_err(dev, "can't configure rx channel (%d)\n", ret); 39662306a36Sopenharmony_ci goto fail_rx; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci i2c_imx->dma = dma; 40062306a36Sopenharmony_ci init_completion(&dma->cmd_complete); 40162306a36Sopenharmony_ci dev_info(dev, "using %s (tx) and %s (rx) for DMA transfers\n", 40262306a36Sopenharmony_ci dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx)); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci return; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cifail_rx: 40762306a36Sopenharmony_ci dma_release_channel(dma->chan_rx); 40862306a36Sopenharmony_cifail_tx: 40962306a36Sopenharmony_ci dma_release_channel(dma->chan_tx); 41062306a36Sopenharmony_cifail_al: 41162306a36Sopenharmony_ci devm_kfree(dev, dma); 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic void i2c_imx_dma_callback(void *arg) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci struct imx_i2c_struct *i2c_imx = (struct imx_i2c_struct *)arg; 41762306a36Sopenharmony_ci struct imx_i2c_dma *dma = i2c_imx->dma; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci dma_unmap_single(dma->chan_using->device->dev, dma->dma_buf, 42062306a36Sopenharmony_ci dma->dma_len, dma->dma_data_dir); 42162306a36Sopenharmony_ci complete(&dma->cmd_complete); 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx, 42562306a36Sopenharmony_ci struct i2c_msg *msgs) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci struct imx_i2c_dma *dma = i2c_imx->dma; 42862306a36Sopenharmony_ci struct dma_async_tx_descriptor *txdesc; 42962306a36Sopenharmony_ci struct device *dev = &i2c_imx->adapter.dev; 43062306a36Sopenharmony_ci struct device *chan_dev = dma->chan_using->device->dev; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci dma->dma_buf = dma_map_single(chan_dev, msgs->buf, 43362306a36Sopenharmony_ci dma->dma_len, dma->dma_data_dir); 43462306a36Sopenharmony_ci if (dma_mapping_error(chan_dev, dma->dma_buf)) { 43562306a36Sopenharmony_ci dev_err(dev, "DMA mapping failed\n"); 43662306a36Sopenharmony_ci goto err_map; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci txdesc = dmaengine_prep_slave_single(dma->chan_using, dma->dma_buf, 44062306a36Sopenharmony_ci dma->dma_len, dma->dma_transfer_dir, 44162306a36Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 44262306a36Sopenharmony_ci if (!txdesc) { 44362306a36Sopenharmony_ci dev_err(dev, "Not able to get desc for DMA xfer\n"); 44462306a36Sopenharmony_ci goto err_desc; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci reinit_completion(&dma->cmd_complete); 44862306a36Sopenharmony_ci txdesc->callback = i2c_imx_dma_callback; 44962306a36Sopenharmony_ci txdesc->callback_param = i2c_imx; 45062306a36Sopenharmony_ci if (dma_submit_error(dmaengine_submit(txdesc))) { 45162306a36Sopenharmony_ci dev_err(dev, "DMA submit failed\n"); 45262306a36Sopenharmony_ci goto err_submit; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci dma_async_issue_pending(dma->chan_using); 45662306a36Sopenharmony_ci return 0; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_cierr_submit: 45962306a36Sopenharmony_ci dmaengine_terminate_sync(dma->chan_using); 46062306a36Sopenharmony_cierr_desc: 46162306a36Sopenharmony_ci dma_unmap_single(chan_dev, dma->dma_buf, 46262306a36Sopenharmony_ci dma->dma_len, dma->dma_data_dir); 46362306a36Sopenharmony_cierr_map: 46462306a36Sopenharmony_ci return -EINVAL; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_cistatic void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci struct imx_i2c_dma *dma = i2c_imx->dma; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci dma->dma_buf = 0; 47262306a36Sopenharmony_ci dma->dma_len = 0; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci dma_release_channel(dma->chan_tx); 47562306a36Sopenharmony_ci dma->chan_tx = NULL; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci dma_release_channel(dma->chan_rx); 47862306a36Sopenharmony_ci dma->chan_rx = NULL; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci dma->chan_using = NULL; 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool atomic) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci unsigned long orig_jiffies = jiffies; 48662306a36Sopenharmony_ci unsigned int temp; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci while (1) { 48962306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* check for arbitration lost */ 49262306a36Sopenharmony_ci if (temp & I2SR_IAL) { 49362306a36Sopenharmony_ci i2c_imx_clear_irq(i2c_imx, I2SR_IAL); 49462306a36Sopenharmony_ci return -EAGAIN; 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (for_busy && (temp & I2SR_IBB)) { 49862306a36Sopenharmony_ci i2c_imx->stopped = 0; 49962306a36Sopenharmony_ci break; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci if (!for_busy && !(temp & I2SR_IBB)) { 50262306a36Sopenharmony_ci i2c_imx->stopped = 1; 50362306a36Sopenharmony_ci break; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) { 50662306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, 50762306a36Sopenharmony_ci "<%s> I2C bus is busy\n", __func__); 50862306a36Sopenharmony_ci return -ETIMEDOUT; 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci if (atomic) 51162306a36Sopenharmony_ci udelay(100); 51262306a36Sopenharmony_ci else 51362306a36Sopenharmony_ci schedule(); 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci return 0; 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx, bool atomic) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci if (atomic) { 52262306a36Sopenharmony_ci void __iomem *addr = i2c_imx->base + (IMX_I2C_I2SR << i2c_imx->hwdata->regshift); 52362306a36Sopenharmony_ci unsigned int regval; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci /* 52662306a36Sopenharmony_ci * The formula for the poll timeout is documented in the RM 52762306a36Sopenharmony_ci * Rev.5 on page 1878: 52862306a36Sopenharmony_ci * T_min = 10/F_scl 52962306a36Sopenharmony_ci * Set the value hard as it is done for the non-atomic use-case. 53062306a36Sopenharmony_ci * Use 10 kHz for the calculation since this is the minimum 53162306a36Sopenharmony_ci * allowed SMBus frequency. Also add an offset of 100us since it 53262306a36Sopenharmony_ci * turned out that the I2SR_IIF bit isn't set correctly within 53362306a36Sopenharmony_ci * the minimum timeout in polling mode. 53462306a36Sopenharmony_ci */ 53562306a36Sopenharmony_ci readb_poll_timeout_atomic(addr, regval, regval & I2SR_IIF, 5, 1000 + 100); 53662306a36Sopenharmony_ci i2c_imx->i2csr = regval; 53762306a36Sopenharmony_ci i2c_imx_clear_irq(i2c_imx, I2SR_IIF | I2SR_IAL); 53862306a36Sopenharmony_ci } else { 53962306a36Sopenharmony_ci wait_event_timeout(i2c_imx->queue, i2c_imx->i2csr & I2SR_IIF, HZ / 10); 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (unlikely(!(i2c_imx->i2csr & I2SR_IIF))) { 54362306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, "<%s> Timeout\n", __func__); 54462306a36Sopenharmony_ci return -ETIMEDOUT; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* check for arbitration lost */ 54862306a36Sopenharmony_ci if (i2c_imx->i2csr & I2SR_IAL) { 54962306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, "<%s> Arbitration lost\n", __func__); 55062306a36Sopenharmony_ci i2c_imx_clear_irq(i2c_imx, I2SR_IAL); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci i2c_imx->i2csr = 0; 55362306a36Sopenharmony_ci return -EAGAIN; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, "<%s> TRX complete\n", __func__); 55762306a36Sopenharmony_ci i2c_imx->i2csr = 0; 55862306a36Sopenharmony_ci return 0; 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic int i2c_imx_acked(struct imx_i2c_struct *i2c_imx) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci if (imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR) & I2SR_RXAK) { 56462306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, "<%s> No ACK\n", __func__); 56562306a36Sopenharmony_ci return -ENXIO; /* No ACK */ 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, "<%s> ACK received\n", __func__); 56962306a36Sopenharmony_ci return 0; 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_cistatic void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, 57362306a36Sopenharmony_ci unsigned int i2c_clk_rate) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div; 57662306a36Sopenharmony_ci unsigned int div; 57762306a36Sopenharmony_ci int i; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (i2c_imx->hwdata->has_err007805 && i2c_imx->bitrate > 384000) { 58062306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, 58162306a36Sopenharmony_ci "SoC errata ERR007805 or e7805 applies, bus frequency limited from %d Hz to 384000 Hz.\n", 58262306a36Sopenharmony_ci i2c_imx->bitrate); 58362306a36Sopenharmony_ci i2c_imx->bitrate = 384000; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci /* Divider value calculation */ 58762306a36Sopenharmony_ci if (i2c_imx->cur_clk == i2c_clk_rate) 58862306a36Sopenharmony_ci return; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci i2c_imx->cur_clk = i2c_clk_rate; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci div = DIV_ROUND_UP(i2c_clk_rate, i2c_imx->bitrate); 59362306a36Sopenharmony_ci if (div < i2c_clk_div[0].div) 59462306a36Sopenharmony_ci i = 0; 59562306a36Sopenharmony_ci else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div) 59662306a36Sopenharmony_ci i = i2c_imx->hwdata->ndivs - 1; 59762306a36Sopenharmony_ci else 59862306a36Sopenharmony_ci for (i = 0; i2c_clk_div[i].div < div; i++) 59962306a36Sopenharmony_ci ; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* Store divider value */ 60262306a36Sopenharmony_ci i2c_imx->ifdr = i2c_clk_div[i].val; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci /* 60562306a36Sopenharmony_ci * There dummy delay is calculated. 60662306a36Sopenharmony_ci * It should be about one I2C clock period long. 60762306a36Sopenharmony_ci * This delay is used in I2C bus disable function 60862306a36Sopenharmony_ci * to fix chip hardware bug. 60962306a36Sopenharmony_ci */ 61062306a36Sopenharmony_ci i2c_imx->disable_delay = DIV_ROUND_UP(500000U * i2c_clk_div[i].div, 61162306a36Sopenharmony_ci i2c_clk_rate / 2); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci#ifdef CONFIG_I2C_DEBUG_BUS 61462306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, "I2C_CLK=%d, REQ DIV=%d\n", 61562306a36Sopenharmony_ci i2c_clk_rate, div); 61662306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, "IFDR[IC]=0x%x, REAL DIV=%d\n", 61762306a36Sopenharmony_ci i2c_clk_div[i].val, i2c_clk_div[i].div); 61862306a36Sopenharmony_ci#endif 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cistatic int i2c_imx_clk_notifier_call(struct notifier_block *nb, 62262306a36Sopenharmony_ci unsigned long action, void *data) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci struct clk_notifier_data *ndata = data; 62562306a36Sopenharmony_ci struct imx_i2c_struct *i2c_imx = container_of(nb, 62662306a36Sopenharmony_ci struct imx_i2c_struct, 62762306a36Sopenharmony_ci clk_change_nb); 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci if (action & POST_RATE_CHANGE) 63062306a36Sopenharmony_ci i2c_imx_set_clk(i2c_imx, ndata->new_rate); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci return NOTIFY_OK; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic int i2c_imx_start(struct imx_i2c_struct *i2c_imx, bool atomic) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci unsigned int temp = 0; 63862306a36Sopenharmony_ci int result; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci imx_i2c_write_reg(i2c_imx->ifdr, i2c_imx, IMX_I2C_IFDR); 64162306a36Sopenharmony_ci /* Enable I2C controller */ 64262306a36Sopenharmony_ci imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR); 64362306a36Sopenharmony_ci imx_i2c_write_reg(i2c_imx->hwdata->i2cr_ien_opcode, i2c_imx, IMX_I2C_I2CR); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci /* Wait controller to be stable */ 64662306a36Sopenharmony_ci if (atomic) 64762306a36Sopenharmony_ci udelay(50); 64862306a36Sopenharmony_ci else 64962306a36Sopenharmony_ci usleep_range(50, 150); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci /* Start I2C transaction */ 65262306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); 65362306a36Sopenharmony_ci temp |= I2CR_MSTA; 65462306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); 65562306a36Sopenharmony_ci result = i2c_imx_bus_busy(i2c_imx, 1, atomic); 65662306a36Sopenharmony_ci if (result) 65762306a36Sopenharmony_ci return result; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci temp |= I2CR_IIEN | I2CR_MTX | I2CR_TXAK; 66062306a36Sopenharmony_ci if (atomic) 66162306a36Sopenharmony_ci temp &= ~I2CR_IIEN; /* Disable interrupt */ 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci temp &= ~I2CR_DMAEN; 66462306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); 66562306a36Sopenharmony_ci return result; 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic void i2c_imx_stop(struct imx_i2c_struct *i2c_imx, bool atomic) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci unsigned int temp = 0; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (!i2c_imx->stopped) { 67362306a36Sopenharmony_ci /* Stop I2C transaction */ 67462306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); 67562306a36Sopenharmony_ci if (!(temp & I2CR_MSTA)) 67662306a36Sopenharmony_ci i2c_imx->stopped = 1; 67762306a36Sopenharmony_ci temp &= ~(I2CR_MSTA | I2CR_MTX); 67862306a36Sopenharmony_ci if (i2c_imx->dma) 67962306a36Sopenharmony_ci temp &= ~I2CR_DMAEN; 68062306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci if (is_imx1_i2c(i2c_imx)) { 68362306a36Sopenharmony_ci /* 68462306a36Sopenharmony_ci * This delay caused by an i.MXL hardware bug. 68562306a36Sopenharmony_ci * If no (or too short) delay, no "STOP" bit will be generated. 68662306a36Sopenharmony_ci */ 68762306a36Sopenharmony_ci udelay(i2c_imx->disable_delay); 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (!i2c_imx->stopped) 69162306a36Sopenharmony_ci i2c_imx_bus_busy(i2c_imx, 0, atomic); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci /* Disable I2C controller */ 69462306a36Sopenharmony_ci temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, 69562306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci/* 69962306a36Sopenharmony_ci * Enable bus idle interrupts 70062306a36Sopenharmony_ci * Note: IBIC register will be cleared after disabled i2c module. 70162306a36Sopenharmony_ci * All of layerscape series SoCs support IBIC register. 70262306a36Sopenharmony_ci */ 70362306a36Sopenharmony_cistatic void i2c_imx_enable_bus_idle(struct imx_i2c_struct *i2c_imx) 70462306a36Sopenharmony_ci{ 70562306a36Sopenharmony_ci if (is_vf610_i2c(i2c_imx)) { 70662306a36Sopenharmony_ci unsigned int temp; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_IBIC); 70962306a36Sopenharmony_ci temp |= IBIC_BIIE; 71062306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_IBIC); 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_cistatic void i2c_imx_slave_event(struct imx_i2c_struct *i2c_imx, 71562306a36Sopenharmony_ci enum i2c_slave_event event, u8 *val) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci i2c_slave_event(i2c_imx->slave, event, val); 71862306a36Sopenharmony_ci i2c_imx->last_slave_event = event; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic void i2c_imx_slave_finish_op(struct imx_i2c_struct *i2c_imx) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci u8 val = 0; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci while (i2c_imx->last_slave_event != I2C_SLAVE_STOP) { 72662306a36Sopenharmony_ci switch (i2c_imx->last_slave_event) { 72762306a36Sopenharmony_ci case I2C_SLAVE_READ_REQUESTED: 72862306a36Sopenharmony_ci i2c_imx_slave_event(i2c_imx, I2C_SLAVE_READ_PROCESSED, 72962306a36Sopenharmony_ci &val); 73062306a36Sopenharmony_ci break; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci case I2C_SLAVE_WRITE_REQUESTED: 73362306a36Sopenharmony_ci case I2C_SLAVE_READ_PROCESSED: 73462306a36Sopenharmony_ci case I2C_SLAVE_WRITE_RECEIVED: 73562306a36Sopenharmony_ci i2c_imx_slave_event(i2c_imx, I2C_SLAVE_STOP, &val); 73662306a36Sopenharmony_ci break; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci case I2C_SLAVE_STOP: 73962306a36Sopenharmony_ci break; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci/* Returns true if the timer should be restarted, false if not. */ 74562306a36Sopenharmony_cistatic irqreturn_t i2c_imx_slave_handle(struct imx_i2c_struct *i2c_imx, 74662306a36Sopenharmony_ci unsigned int status, unsigned int ctl) 74762306a36Sopenharmony_ci{ 74862306a36Sopenharmony_ci u8 value = 0; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci if (status & I2SR_IAL) { /* Arbitration lost */ 75162306a36Sopenharmony_ci i2c_imx_clear_irq(i2c_imx, I2SR_IAL); 75262306a36Sopenharmony_ci if (!(status & I2SR_IAAS)) 75362306a36Sopenharmony_ci return IRQ_HANDLED; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if (!(status & I2SR_IBB)) { 75762306a36Sopenharmony_ci /* No master on the bus, that could mean a stop condition. */ 75862306a36Sopenharmony_ci i2c_imx_slave_finish_op(i2c_imx); 75962306a36Sopenharmony_ci return IRQ_HANDLED; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci if (!(status & I2SR_ICF)) 76362306a36Sopenharmony_ci /* Data transfer still in progress, ignore this. */ 76462306a36Sopenharmony_ci goto out; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci if (status & I2SR_IAAS) { /* Addressed as a slave */ 76762306a36Sopenharmony_ci i2c_imx_slave_finish_op(i2c_imx); 76862306a36Sopenharmony_ci if (status & I2SR_SRW) { /* Master wants to read from us*/ 76962306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, "read requested"); 77062306a36Sopenharmony_ci i2c_imx_slave_event(i2c_imx, 77162306a36Sopenharmony_ci I2C_SLAVE_READ_REQUESTED, &value); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci /* Slave transmit */ 77462306a36Sopenharmony_ci ctl |= I2CR_MTX; 77562306a36Sopenharmony_ci imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci /* Send data */ 77862306a36Sopenharmony_ci imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR); 77962306a36Sopenharmony_ci } else { /* Master wants to write to us */ 78062306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, "write requested"); 78162306a36Sopenharmony_ci i2c_imx_slave_event(i2c_imx, 78262306a36Sopenharmony_ci I2C_SLAVE_WRITE_REQUESTED, &value); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci /* Slave receive */ 78562306a36Sopenharmony_ci ctl &= ~I2CR_MTX; 78662306a36Sopenharmony_ci imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR); 78762306a36Sopenharmony_ci /* Dummy read */ 78862306a36Sopenharmony_ci imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci } else if (!(ctl & I2CR_MTX)) { /* Receive mode */ 79162306a36Sopenharmony_ci value = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); 79262306a36Sopenharmony_ci i2c_imx_slave_event(i2c_imx, 79362306a36Sopenharmony_ci I2C_SLAVE_WRITE_RECEIVED, &value); 79462306a36Sopenharmony_ci } else if (!(status & I2SR_RXAK)) { /* Transmit mode received ACK */ 79562306a36Sopenharmony_ci ctl |= I2CR_MTX; 79662306a36Sopenharmony_ci imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci i2c_imx_slave_event(i2c_imx, 79962306a36Sopenharmony_ci I2C_SLAVE_READ_PROCESSED, &value); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR); 80262306a36Sopenharmony_ci } else { /* Transmit mode received NAK, operation is done */ 80362306a36Sopenharmony_ci ctl &= ~I2CR_MTX; 80462306a36Sopenharmony_ci imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR); 80562306a36Sopenharmony_ci imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci /* flag the last byte as processed */ 80862306a36Sopenharmony_ci i2c_imx_slave_event(i2c_imx, 80962306a36Sopenharmony_ci I2C_SLAVE_READ_PROCESSED, &value); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci i2c_imx_slave_finish_op(i2c_imx); 81262306a36Sopenharmony_ci return IRQ_HANDLED; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ciout: 81662306a36Sopenharmony_ci /* 81762306a36Sopenharmony_ci * No need to check the return value here. If it returns 0 or 81862306a36Sopenharmony_ci * 1, then everything is fine. If it returns -1, then the 81962306a36Sopenharmony_ci * timer is running in the handler. This will still work, 82062306a36Sopenharmony_ci * though it may be redone (or already have been done) by the 82162306a36Sopenharmony_ci * timer function. 82262306a36Sopenharmony_ci */ 82362306a36Sopenharmony_ci hrtimer_try_to_cancel(&i2c_imx->slave_timer); 82462306a36Sopenharmony_ci hrtimer_forward_now(&i2c_imx->slave_timer, I2C_IMX_CHECK_DELAY); 82562306a36Sopenharmony_ci hrtimer_restart(&i2c_imx->slave_timer); 82662306a36Sopenharmony_ci return IRQ_HANDLED; 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_cistatic enum hrtimer_restart i2c_imx_slave_timeout(struct hrtimer *t) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci struct imx_i2c_struct *i2c_imx = container_of(t, struct imx_i2c_struct, 83262306a36Sopenharmony_ci slave_timer); 83362306a36Sopenharmony_ci unsigned int ctl, status; 83462306a36Sopenharmony_ci unsigned long flags; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci spin_lock_irqsave(&i2c_imx->slave_lock, flags); 83762306a36Sopenharmony_ci status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); 83862306a36Sopenharmony_ci ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); 83962306a36Sopenharmony_ci i2c_imx_slave_handle(i2c_imx, status, ctl); 84062306a36Sopenharmony_ci spin_unlock_irqrestore(&i2c_imx->slave_lock, flags); 84162306a36Sopenharmony_ci return HRTIMER_NORESTART; 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_cistatic void i2c_imx_slave_init(struct imx_i2c_struct *i2c_imx) 84562306a36Sopenharmony_ci{ 84662306a36Sopenharmony_ci int temp; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci /* Set slave addr. */ 84962306a36Sopenharmony_ci imx_i2c_write_reg((i2c_imx->slave->addr << 1), i2c_imx, IMX_I2C_IADR); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci i2c_imx_reset_regs(i2c_imx); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci /* Enable module */ 85462306a36Sopenharmony_ci temp = i2c_imx->hwdata->i2cr_ien_opcode; 85562306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci /* Enable interrupt from i2c module */ 85862306a36Sopenharmony_ci temp |= I2CR_IIEN; 85962306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci i2c_imx_enable_bus_idle(i2c_imx); 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_cistatic int i2c_imx_reg_slave(struct i2c_client *client) 86562306a36Sopenharmony_ci{ 86662306a36Sopenharmony_ci struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(client->adapter); 86762306a36Sopenharmony_ci int ret; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci if (i2c_imx->slave) 87062306a36Sopenharmony_ci return -EBUSY; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci i2c_imx->slave = client; 87362306a36Sopenharmony_ci i2c_imx->last_slave_event = I2C_SLAVE_STOP; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci /* Resume */ 87662306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(i2c_imx->adapter.dev.parent); 87762306a36Sopenharmony_ci if (ret < 0) { 87862306a36Sopenharmony_ci dev_err(&i2c_imx->adapter.dev, "failed to resume i2c controller"); 87962306a36Sopenharmony_ci return ret; 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci i2c_imx_slave_init(i2c_imx); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci return 0; 88562306a36Sopenharmony_ci} 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_cistatic int i2c_imx_unreg_slave(struct i2c_client *client) 88862306a36Sopenharmony_ci{ 88962306a36Sopenharmony_ci struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(client->adapter); 89062306a36Sopenharmony_ci int ret; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if (!i2c_imx->slave) 89362306a36Sopenharmony_ci return -EINVAL; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci /* Reset slave address. */ 89662306a36Sopenharmony_ci imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR); 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci i2c_imx_reset_regs(i2c_imx); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci i2c_imx->slave = NULL; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci /* Suspend */ 90362306a36Sopenharmony_ci ret = pm_runtime_put_sync(i2c_imx->adapter.dev.parent); 90462306a36Sopenharmony_ci if (ret < 0) 90562306a36Sopenharmony_ci dev_err(&i2c_imx->adapter.dev, "failed to suspend i2c controller"); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci return ret; 90862306a36Sopenharmony_ci} 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_cistatic irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx, unsigned int status) 91162306a36Sopenharmony_ci{ 91262306a36Sopenharmony_ci /* save status register */ 91362306a36Sopenharmony_ci i2c_imx->i2csr = status; 91462306a36Sopenharmony_ci wake_up(&i2c_imx->queue); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci return IRQ_HANDLED; 91762306a36Sopenharmony_ci} 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_cistatic irqreturn_t i2c_imx_isr(int irq, void *dev_id) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci struct imx_i2c_struct *i2c_imx = dev_id; 92262306a36Sopenharmony_ci unsigned int ctl, status; 92362306a36Sopenharmony_ci unsigned long flags; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci spin_lock_irqsave(&i2c_imx->slave_lock, flags); 92662306a36Sopenharmony_ci status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); 92762306a36Sopenharmony_ci ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (status & I2SR_IIF) { 93062306a36Sopenharmony_ci i2c_imx_clear_irq(i2c_imx, I2SR_IIF); 93162306a36Sopenharmony_ci if (i2c_imx->slave) { 93262306a36Sopenharmony_ci if (!(ctl & I2CR_MSTA)) { 93362306a36Sopenharmony_ci irqreturn_t ret; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci ret = i2c_imx_slave_handle(i2c_imx, 93662306a36Sopenharmony_ci status, ctl); 93762306a36Sopenharmony_ci spin_unlock_irqrestore(&i2c_imx->slave_lock, 93862306a36Sopenharmony_ci flags); 93962306a36Sopenharmony_ci return ret; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci i2c_imx_slave_finish_op(i2c_imx); 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci spin_unlock_irqrestore(&i2c_imx->slave_lock, flags); 94462306a36Sopenharmony_ci return i2c_imx_master_isr(i2c_imx, status); 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci spin_unlock_irqrestore(&i2c_imx->slave_lock, flags); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci return IRQ_NONE; 94962306a36Sopenharmony_ci} 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_cistatic int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, 95262306a36Sopenharmony_ci struct i2c_msg *msgs) 95362306a36Sopenharmony_ci{ 95462306a36Sopenharmony_ci int result; 95562306a36Sopenharmony_ci unsigned long time_left; 95662306a36Sopenharmony_ci unsigned int temp = 0; 95762306a36Sopenharmony_ci unsigned long orig_jiffies = jiffies; 95862306a36Sopenharmony_ci struct imx_i2c_dma *dma = i2c_imx->dma; 95962306a36Sopenharmony_ci struct device *dev = &i2c_imx->adapter.dev; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci dma->chan_using = dma->chan_tx; 96262306a36Sopenharmony_ci dma->dma_transfer_dir = DMA_MEM_TO_DEV; 96362306a36Sopenharmony_ci dma->dma_data_dir = DMA_TO_DEVICE; 96462306a36Sopenharmony_ci dma->dma_len = msgs->len - 1; 96562306a36Sopenharmony_ci result = i2c_imx_dma_xfer(i2c_imx, msgs); 96662306a36Sopenharmony_ci if (result) 96762306a36Sopenharmony_ci return result; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); 97062306a36Sopenharmony_ci temp |= I2CR_DMAEN; 97162306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci /* 97462306a36Sopenharmony_ci * Write slave address. 97562306a36Sopenharmony_ci * The first byte must be transmitted by the CPU. 97662306a36Sopenharmony_ci */ 97762306a36Sopenharmony_ci imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); 97862306a36Sopenharmony_ci time_left = wait_for_completion_timeout( 97962306a36Sopenharmony_ci &i2c_imx->dma->cmd_complete, 98062306a36Sopenharmony_ci msecs_to_jiffies(DMA_TIMEOUT)); 98162306a36Sopenharmony_ci if (time_left == 0) { 98262306a36Sopenharmony_ci dmaengine_terminate_sync(dma->chan_using); 98362306a36Sopenharmony_ci return -ETIMEDOUT; 98462306a36Sopenharmony_ci } 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci /* Waiting for transfer complete. */ 98762306a36Sopenharmony_ci while (1) { 98862306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); 98962306a36Sopenharmony_ci if (temp & I2SR_ICF) 99062306a36Sopenharmony_ci break; 99162306a36Sopenharmony_ci if (time_after(jiffies, orig_jiffies + 99262306a36Sopenharmony_ci msecs_to_jiffies(DMA_TIMEOUT))) { 99362306a36Sopenharmony_ci dev_dbg(dev, "<%s> Timeout\n", __func__); 99462306a36Sopenharmony_ci return -ETIMEDOUT; 99562306a36Sopenharmony_ci } 99662306a36Sopenharmony_ci schedule(); 99762306a36Sopenharmony_ci } 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); 100062306a36Sopenharmony_ci temp &= ~I2CR_DMAEN; 100162306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci /* The last data byte must be transferred by the CPU. */ 100462306a36Sopenharmony_ci imx_i2c_write_reg(msgs->buf[msgs->len-1], 100562306a36Sopenharmony_ci i2c_imx, IMX_I2C_I2DR); 100662306a36Sopenharmony_ci result = i2c_imx_trx_complete(i2c_imx, false); 100762306a36Sopenharmony_ci if (result) 100862306a36Sopenharmony_ci return result; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci return i2c_imx_acked(i2c_imx); 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_cistatic int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, 101462306a36Sopenharmony_ci struct i2c_msg *msgs, bool is_lastmsg) 101562306a36Sopenharmony_ci{ 101662306a36Sopenharmony_ci int result; 101762306a36Sopenharmony_ci unsigned long time_left; 101862306a36Sopenharmony_ci unsigned int temp; 101962306a36Sopenharmony_ci unsigned long orig_jiffies = jiffies; 102062306a36Sopenharmony_ci struct imx_i2c_dma *dma = i2c_imx->dma; 102162306a36Sopenharmony_ci struct device *dev = &i2c_imx->adapter.dev; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci dma->chan_using = dma->chan_rx; 102562306a36Sopenharmony_ci dma->dma_transfer_dir = DMA_DEV_TO_MEM; 102662306a36Sopenharmony_ci dma->dma_data_dir = DMA_FROM_DEVICE; 102762306a36Sopenharmony_ci /* The last two data bytes must be transferred by the CPU. */ 102862306a36Sopenharmony_ci dma->dma_len = msgs->len - 2; 102962306a36Sopenharmony_ci result = i2c_imx_dma_xfer(i2c_imx, msgs); 103062306a36Sopenharmony_ci if (result) 103162306a36Sopenharmony_ci return result; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci time_left = wait_for_completion_timeout( 103462306a36Sopenharmony_ci &i2c_imx->dma->cmd_complete, 103562306a36Sopenharmony_ci msecs_to_jiffies(DMA_TIMEOUT)); 103662306a36Sopenharmony_ci if (time_left == 0) { 103762306a36Sopenharmony_ci dmaengine_terminate_sync(dma->chan_using); 103862306a36Sopenharmony_ci return -ETIMEDOUT; 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci /* waiting for transfer complete. */ 104262306a36Sopenharmony_ci while (1) { 104362306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); 104462306a36Sopenharmony_ci if (temp & I2SR_ICF) 104562306a36Sopenharmony_ci break; 104662306a36Sopenharmony_ci if (time_after(jiffies, orig_jiffies + 104762306a36Sopenharmony_ci msecs_to_jiffies(DMA_TIMEOUT))) { 104862306a36Sopenharmony_ci dev_dbg(dev, "<%s> Timeout\n", __func__); 104962306a36Sopenharmony_ci return -ETIMEDOUT; 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci schedule(); 105262306a36Sopenharmony_ci } 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); 105562306a36Sopenharmony_ci temp &= ~I2CR_DMAEN; 105662306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci /* read n-1 byte data */ 105962306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); 106062306a36Sopenharmony_ci temp |= I2CR_TXAK; 106162306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci msgs->buf[msgs->len-2] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); 106462306a36Sopenharmony_ci /* read n byte data */ 106562306a36Sopenharmony_ci result = i2c_imx_trx_complete(i2c_imx, false); 106662306a36Sopenharmony_ci if (result) 106762306a36Sopenharmony_ci return result; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if (is_lastmsg) { 107062306a36Sopenharmony_ci /* 107162306a36Sopenharmony_ci * It must generate STOP before read I2DR to prevent 107262306a36Sopenharmony_ci * controller from generating another clock cycle 107362306a36Sopenharmony_ci */ 107462306a36Sopenharmony_ci dev_dbg(dev, "<%s> clear MSTA\n", __func__); 107562306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); 107662306a36Sopenharmony_ci if (!(temp & I2CR_MSTA)) 107762306a36Sopenharmony_ci i2c_imx->stopped = 1; 107862306a36Sopenharmony_ci temp &= ~(I2CR_MSTA | I2CR_MTX); 107962306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); 108062306a36Sopenharmony_ci if (!i2c_imx->stopped) 108162306a36Sopenharmony_ci i2c_imx_bus_busy(i2c_imx, 0, false); 108262306a36Sopenharmony_ci } else { 108362306a36Sopenharmony_ci /* 108462306a36Sopenharmony_ci * For i2c master receiver repeat restart operation like: 108562306a36Sopenharmony_ci * read -> repeat MSTA -> read/write 108662306a36Sopenharmony_ci * The controller must set MTX before read the last byte in 108762306a36Sopenharmony_ci * the first read operation, otherwise the first read cost 108862306a36Sopenharmony_ci * one extra clock cycle. 108962306a36Sopenharmony_ci */ 109062306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); 109162306a36Sopenharmony_ci temp |= I2CR_MTX; 109262306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci msgs->buf[msgs->len-1] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci return 0; 109762306a36Sopenharmony_ci} 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_cistatic int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, 110062306a36Sopenharmony_ci bool atomic) 110162306a36Sopenharmony_ci{ 110262306a36Sopenharmony_ci int i, result; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n", 110562306a36Sopenharmony_ci __func__, i2c_8bit_addr_from_msg(msgs)); 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci /* write slave address */ 110862306a36Sopenharmony_ci imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); 110962306a36Sopenharmony_ci result = i2c_imx_trx_complete(i2c_imx, atomic); 111062306a36Sopenharmony_ci if (result) 111162306a36Sopenharmony_ci return result; 111262306a36Sopenharmony_ci result = i2c_imx_acked(i2c_imx); 111362306a36Sopenharmony_ci if (result) 111462306a36Sopenharmony_ci return result; 111562306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, "<%s> write data\n", __func__); 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci /* write data */ 111862306a36Sopenharmony_ci for (i = 0; i < msgs->len; i++) { 111962306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, 112062306a36Sopenharmony_ci "<%s> write byte: B%d=0x%X\n", 112162306a36Sopenharmony_ci __func__, i, msgs->buf[i]); 112262306a36Sopenharmony_ci imx_i2c_write_reg(msgs->buf[i], i2c_imx, IMX_I2C_I2DR); 112362306a36Sopenharmony_ci result = i2c_imx_trx_complete(i2c_imx, atomic); 112462306a36Sopenharmony_ci if (result) 112562306a36Sopenharmony_ci return result; 112662306a36Sopenharmony_ci result = i2c_imx_acked(i2c_imx); 112762306a36Sopenharmony_ci if (result) 112862306a36Sopenharmony_ci return result; 112962306a36Sopenharmony_ci } 113062306a36Sopenharmony_ci return 0; 113162306a36Sopenharmony_ci} 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_cistatic int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, 113462306a36Sopenharmony_ci bool is_lastmsg, bool atomic) 113562306a36Sopenharmony_ci{ 113662306a36Sopenharmony_ci int i, result; 113762306a36Sopenharmony_ci unsigned int temp; 113862306a36Sopenharmony_ci int block_data = msgs->flags & I2C_M_RECV_LEN; 113962306a36Sopenharmony_ci int use_dma = i2c_imx->dma && msgs->flags & I2C_M_DMA_SAFE && 114062306a36Sopenharmony_ci msgs->len >= DMA_THRESHOLD && !block_data; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, 114362306a36Sopenharmony_ci "<%s> write slave address: addr=0x%x\n", 114462306a36Sopenharmony_ci __func__, i2c_8bit_addr_from_msg(msgs)); 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci /* write slave address */ 114762306a36Sopenharmony_ci imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); 114862306a36Sopenharmony_ci result = i2c_imx_trx_complete(i2c_imx, atomic); 114962306a36Sopenharmony_ci if (result) 115062306a36Sopenharmony_ci return result; 115162306a36Sopenharmony_ci result = i2c_imx_acked(i2c_imx); 115262306a36Sopenharmony_ci if (result) 115362306a36Sopenharmony_ci return result; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, "<%s> setup bus\n", __func__); 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci /* setup bus to read data */ 115862306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); 115962306a36Sopenharmony_ci temp &= ~I2CR_MTX; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci /* 116262306a36Sopenharmony_ci * Reset the I2CR_TXAK flag initially for SMBus block read since the 116362306a36Sopenharmony_ci * length is unknown 116462306a36Sopenharmony_ci */ 116562306a36Sopenharmony_ci if ((msgs->len - 1) || block_data) 116662306a36Sopenharmony_ci temp &= ~I2CR_TXAK; 116762306a36Sopenharmony_ci if (use_dma) 116862306a36Sopenharmony_ci temp |= I2CR_DMAEN; 116962306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); 117062306a36Sopenharmony_ci imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */ 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__); 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci if (use_dma) 117562306a36Sopenharmony_ci return i2c_imx_dma_read(i2c_imx, msgs, is_lastmsg); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci /* read data */ 117862306a36Sopenharmony_ci for (i = 0; i < msgs->len; i++) { 117962306a36Sopenharmony_ci u8 len = 0; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci result = i2c_imx_trx_complete(i2c_imx, atomic); 118262306a36Sopenharmony_ci if (result) 118362306a36Sopenharmony_ci return result; 118462306a36Sopenharmony_ci /* 118562306a36Sopenharmony_ci * First byte is the length of remaining packet 118662306a36Sopenharmony_ci * in the SMBus block data read. Add it to 118762306a36Sopenharmony_ci * msgs->len. 118862306a36Sopenharmony_ci */ 118962306a36Sopenharmony_ci if ((!i) && block_data) { 119062306a36Sopenharmony_ci len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); 119162306a36Sopenharmony_ci if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) 119262306a36Sopenharmony_ci return -EPROTO; 119362306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, 119462306a36Sopenharmony_ci "<%s> read length: 0x%X\n", 119562306a36Sopenharmony_ci __func__, len); 119662306a36Sopenharmony_ci msgs->len += len; 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci if (i == (msgs->len - 1)) { 119962306a36Sopenharmony_ci if (is_lastmsg) { 120062306a36Sopenharmony_ci /* 120162306a36Sopenharmony_ci * It must generate STOP before read I2DR to prevent 120262306a36Sopenharmony_ci * controller from generating another clock cycle 120362306a36Sopenharmony_ci */ 120462306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, 120562306a36Sopenharmony_ci "<%s> clear MSTA\n", __func__); 120662306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); 120762306a36Sopenharmony_ci if (!(temp & I2CR_MSTA)) 120862306a36Sopenharmony_ci i2c_imx->stopped = 1; 120962306a36Sopenharmony_ci temp &= ~(I2CR_MSTA | I2CR_MTX); 121062306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); 121162306a36Sopenharmony_ci if (!i2c_imx->stopped) 121262306a36Sopenharmony_ci i2c_imx_bus_busy(i2c_imx, 0, atomic); 121362306a36Sopenharmony_ci } else { 121462306a36Sopenharmony_ci /* 121562306a36Sopenharmony_ci * For i2c master receiver repeat restart operation like: 121662306a36Sopenharmony_ci * read -> repeat MSTA -> read/write 121762306a36Sopenharmony_ci * The controller must set MTX before read the last byte in 121862306a36Sopenharmony_ci * the first read operation, otherwise the first read cost 121962306a36Sopenharmony_ci * one extra clock cycle. 122062306a36Sopenharmony_ci */ 122162306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); 122262306a36Sopenharmony_ci temp |= I2CR_MTX; 122362306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci } else if (i == (msgs->len - 2)) { 122662306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, 122762306a36Sopenharmony_ci "<%s> set TXAK\n", __func__); 122862306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); 122962306a36Sopenharmony_ci temp |= I2CR_TXAK; 123062306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); 123162306a36Sopenharmony_ci } 123262306a36Sopenharmony_ci if ((!i) && block_data) 123362306a36Sopenharmony_ci msgs->buf[0] = len; 123462306a36Sopenharmony_ci else 123562306a36Sopenharmony_ci msgs->buf[i] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); 123662306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, 123762306a36Sopenharmony_ci "<%s> read byte: B%d=0x%X\n", 123862306a36Sopenharmony_ci __func__, i, msgs->buf[i]); 123962306a36Sopenharmony_ci } 124062306a36Sopenharmony_ci return 0; 124162306a36Sopenharmony_ci} 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_cistatic int i2c_imx_xfer_common(struct i2c_adapter *adapter, 124462306a36Sopenharmony_ci struct i2c_msg *msgs, int num, bool atomic) 124562306a36Sopenharmony_ci{ 124662306a36Sopenharmony_ci unsigned int i, temp; 124762306a36Sopenharmony_ci int result; 124862306a36Sopenharmony_ci bool is_lastmsg = false; 124962306a36Sopenharmony_ci struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter); 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci /* Start I2C transfer */ 125262306a36Sopenharmony_ci result = i2c_imx_start(i2c_imx, atomic); 125362306a36Sopenharmony_ci if (result) { 125462306a36Sopenharmony_ci /* 125562306a36Sopenharmony_ci * Bus recovery uses gpiod_get_value_cansleep() which is not 125662306a36Sopenharmony_ci * allowed within atomic context. 125762306a36Sopenharmony_ci */ 125862306a36Sopenharmony_ci if (!atomic && i2c_imx->adapter.bus_recovery_info) { 125962306a36Sopenharmony_ci i2c_recover_bus(&i2c_imx->adapter); 126062306a36Sopenharmony_ci result = i2c_imx_start(i2c_imx, atomic); 126162306a36Sopenharmony_ci } 126262306a36Sopenharmony_ci } 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci if (result) 126562306a36Sopenharmony_ci goto fail0; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci /* read/write data */ 126862306a36Sopenharmony_ci for (i = 0; i < num; i++) { 126962306a36Sopenharmony_ci if (i == num - 1) 127062306a36Sopenharmony_ci is_lastmsg = true; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci if (i) { 127362306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, 127462306a36Sopenharmony_ci "<%s> repeated start\n", __func__); 127562306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); 127662306a36Sopenharmony_ci temp |= I2CR_RSTA; 127762306a36Sopenharmony_ci imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); 127862306a36Sopenharmony_ci result = i2c_imx_bus_busy(i2c_imx, 1, atomic); 127962306a36Sopenharmony_ci if (result) 128062306a36Sopenharmony_ci goto fail0; 128162306a36Sopenharmony_ci } 128262306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, 128362306a36Sopenharmony_ci "<%s> transfer message: %d\n", __func__, i); 128462306a36Sopenharmony_ci /* write/read data */ 128562306a36Sopenharmony_ci#ifdef CONFIG_I2C_DEBUG_BUS 128662306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); 128762306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, 128862306a36Sopenharmony_ci "<%s> CONTROL: IEN=%d, IIEN=%d, MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n", 128962306a36Sopenharmony_ci __func__, 129062306a36Sopenharmony_ci (temp & I2CR_IEN ? 1 : 0), (temp & I2CR_IIEN ? 1 : 0), 129162306a36Sopenharmony_ci (temp & I2CR_MSTA ? 1 : 0), (temp & I2CR_MTX ? 1 : 0), 129262306a36Sopenharmony_ci (temp & I2CR_TXAK ? 1 : 0), (temp & I2CR_RSTA ? 1 : 0)); 129362306a36Sopenharmony_ci temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); 129462306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, 129562306a36Sopenharmony_ci "<%s> STATUS: ICF=%d, IAAS=%d, IBB=%d, IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n", 129662306a36Sopenharmony_ci __func__, 129762306a36Sopenharmony_ci (temp & I2SR_ICF ? 1 : 0), (temp & I2SR_IAAS ? 1 : 0), 129862306a36Sopenharmony_ci (temp & I2SR_IBB ? 1 : 0), (temp & I2SR_IAL ? 1 : 0), 129962306a36Sopenharmony_ci (temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0), 130062306a36Sopenharmony_ci (temp & I2SR_RXAK ? 1 : 0)); 130162306a36Sopenharmony_ci#endif 130262306a36Sopenharmony_ci if (msgs[i].flags & I2C_M_RD) { 130362306a36Sopenharmony_ci result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg, atomic); 130462306a36Sopenharmony_ci } else { 130562306a36Sopenharmony_ci if (!atomic && 130662306a36Sopenharmony_ci i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD && 130762306a36Sopenharmony_ci msgs[i].flags & I2C_M_DMA_SAFE) 130862306a36Sopenharmony_ci result = i2c_imx_dma_write(i2c_imx, &msgs[i]); 130962306a36Sopenharmony_ci else 131062306a36Sopenharmony_ci result = i2c_imx_write(i2c_imx, &msgs[i], atomic); 131162306a36Sopenharmony_ci } 131262306a36Sopenharmony_ci if (result) 131362306a36Sopenharmony_ci goto fail0; 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_cifail0: 131762306a36Sopenharmony_ci /* Stop I2C transfer */ 131862306a36Sopenharmony_ci i2c_imx_stop(i2c_imx, atomic); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__, 132162306a36Sopenharmony_ci (result < 0) ? "error" : "success msg", 132262306a36Sopenharmony_ci (result < 0) ? result : num); 132362306a36Sopenharmony_ci /* After data is transferred, switch to slave mode(as a receiver) */ 132462306a36Sopenharmony_ci if (i2c_imx->slave) 132562306a36Sopenharmony_ci i2c_imx_slave_init(i2c_imx); 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci return (result < 0) ? result : num; 132862306a36Sopenharmony_ci} 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_cistatic int i2c_imx_xfer(struct i2c_adapter *adapter, 133162306a36Sopenharmony_ci struct i2c_msg *msgs, int num) 133262306a36Sopenharmony_ci{ 133362306a36Sopenharmony_ci struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter); 133462306a36Sopenharmony_ci int result; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci result = pm_runtime_resume_and_get(i2c_imx->adapter.dev.parent); 133762306a36Sopenharmony_ci if (result < 0) 133862306a36Sopenharmony_ci return result; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci result = i2c_imx_xfer_common(adapter, msgs, num, false); 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci pm_runtime_mark_last_busy(i2c_imx->adapter.dev.parent); 134362306a36Sopenharmony_ci pm_runtime_put_autosuspend(i2c_imx->adapter.dev.parent); 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci return result; 134662306a36Sopenharmony_ci} 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_cistatic int i2c_imx_xfer_atomic(struct i2c_adapter *adapter, 134962306a36Sopenharmony_ci struct i2c_msg *msgs, int num) 135062306a36Sopenharmony_ci{ 135162306a36Sopenharmony_ci struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter); 135262306a36Sopenharmony_ci int result; 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci result = clk_enable(i2c_imx->clk); 135562306a36Sopenharmony_ci if (result) 135662306a36Sopenharmony_ci return result; 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci result = i2c_imx_xfer_common(adapter, msgs, num, true); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci clk_disable(i2c_imx->clk); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci return result; 136362306a36Sopenharmony_ci} 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_cistatic void i2c_imx_prepare_recovery(struct i2c_adapter *adap) 136662306a36Sopenharmony_ci{ 136762306a36Sopenharmony_ci struct imx_i2c_struct *i2c_imx; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci i2c_imx = container_of(adap, struct imx_i2c_struct, adapter); 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_gpio); 137262306a36Sopenharmony_ci} 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_cistatic void i2c_imx_unprepare_recovery(struct i2c_adapter *adap) 137562306a36Sopenharmony_ci{ 137662306a36Sopenharmony_ci struct imx_i2c_struct *i2c_imx; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci i2c_imx = container_of(adap, struct imx_i2c_struct, adapter); 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_default); 138162306a36Sopenharmony_ci} 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci/* 138462306a36Sopenharmony_ci * We switch SCL and SDA to their GPIO function and do some bitbanging 138562306a36Sopenharmony_ci * for bus recovery. These alternative pinmux settings can be 138662306a36Sopenharmony_ci * described in the device tree by a separate pinctrl state "gpio". If 138762306a36Sopenharmony_ci * this is missing this is not a big problem, the only implication is 138862306a36Sopenharmony_ci * that we can't do bus recovery. 138962306a36Sopenharmony_ci */ 139062306a36Sopenharmony_cistatic int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, 139162306a36Sopenharmony_ci struct platform_device *pdev) 139262306a36Sopenharmony_ci{ 139362306a36Sopenharmony_ci struct i2c_bus_recovery_info *rinfo = &i2c_imx->rinfo; 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci i2c_imx->pinctrl = devm_pinctrl_get(&pdev->dev); 139662306a36Sopenharmony_ci if (!i2c_imx->pinctrl) { 139762306a36Sopenharmony_ci dev_info(&pdev->dev, "pinctrl unavailable, bus recovery not supported\n"); 139862306a36Sopenharmony_ci return 0; 139962306a36Sopenharmony_ci } 140062306a36Sopenharmony_ci if (IS_ERR(i2c_imx->pinctrl)) { 140162306a36Sopenharmony_ci dev_info(&pdev->dev, "can't get pinctrl, bus recovery not supported\n"); 140262306a36Sopenharmony_ci return PTR_ERR(i2c_imx->pinctrl); 140362306a36Sopenharmony_ci } 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci i2c_imx->pinctrl_pins_default = pinctrl_lookup_state(i2c_imx->pinctrl, 140662306a36Sopenharmony_ci PINCTRL_STATE_DEFAULT); 140762306a36Sopenharmony_ci i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl, 140862306a36Sopenharmony_ci "gpio"); 140962306a36Sopenharmony_ci rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN); 141062306a36Sopenharmony_ci rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", GPIOD_OUT_HIGH_OPEN_DRAIN); 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER || 141362306a36Sopenharmony_ci PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER) { 141462306a36Sopenharmony_ci return -EPROBE_DEFER; 141562306a36Sopenharmony_ci } else if (IS_ERR(rinfo->sda_gpiod) || 141662306a36Sopenharmony_ci IS_ERR(rinfo->scl_gpiod) || 141762306a36Sopenharmony_ci IS_ERR(i2c_imx->pinctrl_pins_default) || 141862306a36Sopenharmony_ci IS_ERR(i2c_imx->pinctrl_pins_gpio)) { 141962306a36Sopenharmony_ci dev_dbg(&pdev->dev, "recovery information incomplete\n"); 142062306a36Sopenharmony_ci return 0; 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci dev_dbg(&pdev->dev, "using scl%s for recovery\n", 142462306a36Sopenharmony_ci rinfo->sda_gpiod ? ",sda" : ""); 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci rinfo->prepare_recovery = i2c_imx_prepare_recovery; 142762306a36Sopenharmony_ci rinfo->unprepare_recovery = i2c_imx_unprepare_recovery; 142862306a36Sopenharmony_ci rinfo->recover_bus = i2c_generic_scl_recovery; 142962306a36Sopenharmony_ci i2c_imx->adapter.bus_recovery_info = rinfo; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci return 0; 143262306a36Sopenharmony_ci} 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_cistatic u32 i2c_imx_func(struct i2c_adapter *adapter) 143562306a36Sopenharmony_ci{ 143662306a36Sopenharmony_ci return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL 143762306a36Sopenharmony_ci | I2C_FUNC_SMBUS_READ_BLOCK_DATA; 143862306a36Sopenharmony_ci} 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_cistatic const struct i2c_algorithm i2c_imx_algo = { 144162306a36Sopenharmony_ci .master_xfer = i2c_imx_xfer, 144262306a36Sopenharmony_ci .master_xfer_atomic = i2c_imx_xfer_atomic, 144362306a36Sopenharmony_ci .functionality = i2c_imx_func, 144462306a36Sopenharmony_ci .reg_slave = i2c_imx_reg_slave, 144562306a36Sopenharmony_ci .unreg_slave = i2c_imx_unreg_slave, 144662306a36Sopenharmony_ci}; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_cistatic int i2c_imx_probe(struct platform_device *pdev) 144962306a36Sopenharmony_ci{ 145062306a36Sopenharmony_ci struct imx_i2c_struct *i2c_imx; 145162306a36Sopenharmony_ci struct resource *res; 145262306a36Sopenharmony_ci struct imxi2c_platform_data *pdata = dev_get_platdata(&pdev->dev); 145362306a36Sopenharmony_ci void __iomem *base; 145462306a36Sopenharmony_ci int irq, ret; 145562306a36Sopenharmony_ci dma_addr_t phy_addr; 145662306a36Sopenharmony_ci const struct imx_i2c_hwdata *match; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 145962306a36Sopenharmony_ci if (irq < 0) 146062306a36Sopenharmony_ci return irq; 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 146362306a36Sopenharmony_ci if (IS_ERR(base)) 146462306a36Sopenharmony_ci return PTR_ERR(base); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci phy_addr = (dma_addr_t)res->start; 146762306a36Sopenharmony_ci i2c_imx = devm_kzalloc(&pdev->dev, sizeof(*i2c_imx), GFP_KERNEL); 146862306a36Sopenharmony_ci if (!i2c_imx) 146962306a36Sopenharmony_ci return -ENOMEM; 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci spin_lock_init(&i2c_imx->slave_lock); 147262306a36Sopenharmony_ci hrtimer_init(&i2c_imx->slave_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 147362306a36Sopenharmony_ci i2c_imx->slave_timer.function = i2c_imx_slave_timeout; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci match = device_get_match_data(&pdev->dev); 147662306a36Sopenharmony_ci if (match) 147762306a36Sopenharmony_ci i2c_imx->hwdata = match; 147862306a36Sopenharmony_ci else 147962306a36Sopenharmony_ci i2c_imx->hwdata = (struct imx_i2c_hwdata *) 148062306a36Sopenharmony_ci platform_get_device_id(pdev)->driver_data; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci /* Setup i2c_imx driver structure */ 148362306a36Sopenharmony_ci strscpy(i2c_imx->adapter.name, pdev->name, sizeof(i2c_imx->adapter.name)); 148462306a36Sopenharmony_ci i2c_imx->adapter.owner = THIS_MODULE; 148562306a36Sopenharmony_ci i2c_imx->adapter.algo = &i2c_imx_algo; 148662306a36Sopenharmony_ci i2c_imx->adapter.dev.parent = &pdev->dev; 148762306a36Sopenharmony_ci i2c_imx->adapter.nr = pdev->id; 148862306a36Sopenharmony_ci i2c_imx->adapter.dev.of_node = pdev->dev.of_node; 148962306a36Sopenharmony_ci i2c_imx->base = base; 149062306a36Sopenharmony_ci ACPI_COMPANION_SET(&i2c_imx->adapter.dev, ACPI_COMPANION(&pdev->dev)); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci /* Get I2C clock */ 149362306a36Sopenharmony_ci i2c_imx->clk = devm_clk_get_enabled(&pdev->dev, NULL); 149462306a36Sopenharmony_ci if (IS_ERR(i2c_imx->clk)) 149562306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(i2c_imx->clk), 149662306a36Sopenharmony_ci "can't get I2C clock\n"); 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci /* Init queue */ 149962306a36Sopenharmony_ci init_waitqueue_head(&i2c_imx->queue); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci /* Set up adapter data */ 150262306a36Sopenharmony_ci i2c_set_adapdata(&i2c_imx->adapter, i2c_imx); 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci /* Set up platform driver data */ 150562306a36Sopenharmony_ci platform_set_drvdata(pdev, i2c_imx); 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT); 150862306a36Sopenharmony_ci pm_runtime_use_autosuspend(&pdev->dev); 150962306a36Sopenharmony_ci pm_runtime_set_active(&pdev->dev); 151062306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci ret = pm_runtime_get_sync(&pdev->dev); 151362306a36Sopenharmony_ci if (ret < 0) 151462306a36Sopenharmony_ci goto rpm_disable; 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci /* Request IRQ */ 151762306a36Sopenharmony_ci ret = request_irq(irq, i2c_imx_isr, IRQF_SHARED, pdev->name, i2c_imx); 151862306a36Sopenharmony_ci if (ret) { 151962306a36Sopenharmony_ci dev_err(&pdev->dev, "can't claim irq %d\n", irq); 152062306a36Sopenharmony_ci goto rpm_disable; 152162306a36Sopenharmony_ci } 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci /* Set up clock divider */ 152462306a36Sopenharmony_ci i2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ; 152562306a36Sopenharmony_ci ret = of_property_read_u32(pdev->dev.of_node, 152662306a36Sopenharmony_ci "clock-frequency", &i2c_imx->bitrate); 152762306a36Sopenharmony_ci if (ret < 0 && pdata && pdata->bitrate) 152862306a36Sopenharmony_ci i2c_imx->bitrate = pdata->bitrate; 152962306a36Sopenharmony_ci i2c_imx->clk_change_nb.notifier_call = i2c_imx_clk_notifier_call; 153062306a36Sopenharmony_ci clk_notifier_register(i2c_imx->clk, &i2c_imx->clk_change_nb); 153162306a36Sopenharmony_ci i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk)); 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci i2c_imx_reset_regs(i2c_imx); 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci /* Init optional bus recovery function */ 153662306a36Sopenharmony_ci ret = i2c_imx_init_recovery_info(i2c_imx, pdev); 153762306a36Sopenharmony_ci /* Give it another chance if pinctrl used is not ready yet */ 153862306a36Sopenharmony_ci if (ret == -EPROBE_DEFER) 153962306a36Sopenharmony_ci goto clk_notifier_unregister; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci /* Add I2C adapter */ 154262306a36Sopenharmony_ci ret = i2c_add_numbered_adapter(&i2c_imx->adapter); 154362306a36Sopenharmony_ci if (ret < 0) 154462306a36Sopenharmony_ci goto clk_notifier_unregister; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci pm_runtime_mark_last_busy(&pdev->dev); 154762306a36Sopenharmony_ci pm_runtime_put_autosuspend(&pdev->dev); 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", irq); 155062306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, "device resources: %pR\n", res); 155162306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n", 155262306a36Sopenharmony_ci i2c_imx->adapter.name); 155362306a36Sopenharmony_ci dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n"); 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci /* Init DMA config if supported */ 155662306a36Sopenharmony_ci i2c_imx_dma_request(i2c_imx, phy_addr); 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci return 0; /* Return OK */ 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ciclk_notifier_unregister: 156162306a36Sopenharmony_ci clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb); 156262306a36Sopenharmony_ci free_irq(irq, i2c_imx); 156362306a36Sopenharmony_cirpm_disable: 156462306a36Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 156562306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 156662306a36Sopenharmony_ci pm_runtime_set_suspended(&pdev->dev); 156762306a36Sopenharmony_ci pm_runtime_dont_use_autosuspend(&pdev->dev); 156862306a36Sopenharmony_ci return ret; 156962306a36Sopenharmony_ci} 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_cistatic void i2c_imx_remove(struct platform_device *pdev) 157262306a36Sopenharmony_ci{ 157362306a36Sopenharmony_ci struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev); 157462306a36Sopenharmony_ci int irq, ret; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci ret = pm_runtime_get_sync(&pdev->dev); 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci hrtimer_cancel(&i2c_imx->slave_timer); 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci /* remove adapter */ 158162306a36Sopenharmony_ci dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n"); 158262306a36Sopenharmony_ci i2c_del_adapter(&i2c_imx->adapter); 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci if (i2c_imx->dma) 158562306a36Sopenharmony_ci i2c_imx_dma_free(i2c_imx); 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci if (ret >= 0) { 158862306a36Sopenharmony_ci /* setup chip registers to defaults */ 158962306a36Sopenharmony_ci imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR); 159062306a36Sopenharmony_ci imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR); 159162306a36Sopenharmony_ci imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR); 159262306a36Sopenharmony_ci imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR); 159362306a36Sopenharmony_ci } 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb); 159662306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 159762306a36Sopenharmony_ci if (irq >= 0) 159862306a36Sopenharmony_ci free_irq(irq, i2c_imx); 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 160162306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 160262306a36Sopenharmony_ci} 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_cistatic int __maybe_unused i2c_imx_runtime_suspend(struct device *dev) 160562306a36Sopenharmony_ci{ 160662306a36Sopenharmony_ci struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev); 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci clk_disable(i2c_imx->clk); 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci return 0; 161162306a36Sopenharmony_ci} 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_cistatic int __maybe_unused i2c_imx_runtime_resume(struct device *dev) 161462306a36Sopenharmony_ci{ 161562306a36Sopenharmony_ci struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev); 161662306a36Sopenharmony_ci int ret; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci ret = clk_enable(i2c_imx->clk); 161962306a36Sopenharmony_ci if (ret) 162062306a36Sopenharmony_ci dev_err(dev, "can't enable I2C clock, ret=%d\n", ret); 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci return ret; 162362306a36Sopenharmony_ci} 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_cistatic const struct dev_pm_ops i2c_imx_pm_ops = { 162662306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(i2c_imx_runtime_suspend, 162762306a36Sopenharmony_ci i2c_imx_runtime_resume, NULL) 162862306a36Sopenharmony_ci}; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_cistatic struct platform_driver i2c_imx_driver = { 163162306a36Sopenharmony_ci .probe = i2c_imx_probe, 163262306a36Sopenharmony_ci .remove_new = i2c_imx_remove, 163362306a36Sopenharmony_ci .driver = { 163462306a36Sopenharmony_ci .name = DRIVER_NAME, 163562306a36Sopenharmony_ci .pm = &i2c_imx_pm_ops, 163662306a36Sopenharmony_ci .of_match_table = i2c_imx_dt_ids, 163762306a36Sopenharmony_ci .acpi_match_table = i2c_imx_acpi_ids, 163862306a36Sopenharmony_ci }, 163962306a36Sopenharmony_ci .id_table = imx_i2c_devtype, 164062306a36Sopenharmony_ci}; 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_cistatic int __init i2c_adap_imx_init(void) 164362306a36Sopenharmony_ci{ 164462306a36Sopenharmony_ci return platform_driver_register(&i2c_imx_driver); 164562306a36Sopenharmony_ci} 164662306a36Sopenharmony_cisubsys_initcall(i2c_adap_imx_init); 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_cistatic void __exit i2c_adap_imx_exit(void) 164962306a36Sopenharmony_ci{ 165062306a36Sopenharmony_ci platform_driver_unregister(&i2c_imx_driver); 165162306a36Sopenharmony_ci} 165262306a36Sopenharmony_cimodule_exit(i2c_adap_imx_exit); 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 165562306a36Sopenharmony_ciMODULE_AUTHOR("Darius Augulis"); 165662306a36Sopenharmony_ciMODULE_DESCRIPTION("I2C adapter driver for IMX I2C bus"); 165762306a36Sopenharmony_ciMODULE_ALIAS("platform:" DRIVER_NAME); 1658