1a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang/* 2a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * Freescale MXS I2C bus driver 3a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * 4a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * Copyright (C) 2011 Wolfram Sang, Pengutronix e.K. 5a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * 6a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * based on a (non-working) driver which was: 7a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * 8a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. 9a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * 10a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * TODO: add dma-support if platform-support for it is available 11a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * 12a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * This program is free software; you can redistribute it and/or modify 13a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * it under the terms of the GNU General Public License as published by 14a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * the Free Software Foundation; either version 2 of the License, or 15a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * (at your option) any later version. 16a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * 17a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang */ 18a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 19a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#include <linux/slab.h> 20a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#include <linux/device.h> 21a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#include <linux/module.h> 22a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#include <linux/i2c.h> 23a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#include <linux/err.h> 24a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#include <linux/interrupt.h> 25a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#include <linux/completion.h> 26a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#include <linux/platform_device.h> 27a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#include <linux/jiffies.h> 28a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#include <linux/io.h> 29a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 30a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#include <mach/common.h> 31a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 32a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define DRIVER_NAME "mxs-i2c" 33a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 34a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL0 (0x00) 35a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL0_SET (0x04) 36a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 37a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL0_SFTRST 0x80000000 38a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL0_SEND_NAK_ON_LAST 0x02000000 39a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL0_RETAIN_CLOCK 0x00200000 40a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL0_POST_SEND_STOP 0x00100000 41a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL0_PRE_SEND_START 0x00080000 42a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL0_MASTER_MODE 0x00020000 43a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL0_DIRECTION 0x00010000 44a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL0_XFER_COUNT(v) ((v) & 0x0000FFFF) 45a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 46a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL1 (0x40) 47a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL1_SET (0x44) 48a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL1_CLR (0x48) 49a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 50a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL1_BUS_FREE_IRQ 0x80 51a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ 0x40 52a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ 0x20 53a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ 0x10 54a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL1_EARLY_TERM_IRQ 0x08 55a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL1_MASTER_LOSS_IRQ 0x04 56a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL1_SLAVE_STOP_IRQ 0x02 57a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_CTRL1_SLAVE_IRQ 0x01 58a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 59a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_IRQ_MASK (MXS_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ | \ 60a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ | \ 61a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang MXS_I2C_CTRL1_EARLY_TERM_IRQ | \ 62a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang MXS_I2C_CTRL1_MASTER_LOSS_IRQ | \ 63a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang MXS_I2C_CTRL1_SLAVE_STOP_IRQ | \ 64a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang MXS_I2C_CTRL1_SLAVE_IRQ) 65a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 66a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_QUEUECTRL (0x60) 67a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_QUEUECTRL_SET (0x64) 68a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_QUEUECTRL_CLR (0x68) 69a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 70a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_QUEUECTRL_QUEUE_RUN 0x20 71a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE 0x04 72a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 73a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_QUEUESTAT (0x70) 74a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY 0x00002000 75844990daa2e69a4258049ba9c2bae1180657dac3Wolfram Sang#define MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK 0x0000001F 76a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 77a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_QUEUECMD (0x80) 78a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 79a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_QUEUEDATA (0x90) 80a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 81a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_I2C_DATA (0xa0) 82a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 83a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 84a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_CMD_I2C_SELECT (MXS_I2C_CTRL0_RETAIN_CLOCK | \ 85a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang MXS_I2C_CTRL0_PRE_SEND_START | \ 86a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang MXS_I2C_CTRL0_MASTER_MODE | \ 87a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang MXS_I2C_CTRL0_DIRECTION | \ 88a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang MXS_I2C_CTRL0_XFER_COUNT(1)) 89a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 90a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_CMD_I2C_WRITE (MXS_I2C_CTRL0_PRE_SEND_START | \ 91a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang MXS_I2C_CTRL0_MASTER_MODE | \ 92a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang MXS_I2C_CTRL0_DIRECTION) 93a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 94a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang#define MXS_CMD_I2C_READ (MXS_I2C_CTRL0_SEND_NAK_ON_LAST | \ 95a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang MXS_I2C_CTRL0_MASTER_MODE) 96a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 97a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang/** 98a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * struct mxs_i2c_dev - per device, private MXS-I2C data 99a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * 100a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * @dev: driver model device node 101a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * @regs: IO registers pointer 102a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * @cmd_complete: completion object for transaction wait 103a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * @cmd_err: error code for last transaction 104a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * @adapter: i2c subsystem adapter node 105a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang */ 106a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangstruct mxs_i2c_dev { 107a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang struct device *dev; 108a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang void __iomem *regs; 109a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang struct completion cmd_complete; 110a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang u32 cmd_err; 111a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang struct i2c_adapter adapter; 112a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang}; 113a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 114a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang/* 115a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * TODO: check if calls to here are really needed. If not, we could get rid of 116a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * mxs_reset_block and the mach-dependency. Needs an I2C analyzer, probably. 117a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang */ 118a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangstatic void mxs_i2c_reset(struct mxs_i2c_dev *i2c) 119a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang{ 120a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang mxs_reset_block(i2c->regs); 121a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET); 1226b7d815c3f37f22c355b00362bc7c7d0bac9baeaSascha Hauer writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE, 1236b7d815c3f37f22c355b00362bc7c7d0bac9baeaSascha Hauer i2c->regs + MXS_I2C_QUEUECTRL_SET); 124a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang} 125a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 126a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangstatic void mxs_i2c_pioq_setup_read(struct mxs_i2c_dev *i2c, u8 addr, int len, 127a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang int flags) 128a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang{ 129a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang u32 data; 130a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 131a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang writel(MXS_CMD_I2C_SELECT, i2c->regs + MXS_I2C_QUEUECMD); 132a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 133a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang data = (addr << 1) | I2C_SMBUS_READ; 134a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang writel(data, i2c->regs + MXS_I2C_DATA); 135a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 136a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang data = MXS_CMD_I2C_READ | MXS_I2C_CTRL0_XFER_COUNT(len) | flags; 137a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang writel(data, i2c->regs + MXS_I2C_QUEUECMD); 138a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang} 139a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 140a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangstatic void mxs_i2c_pioq_setup_write(struct mxs_i2c_dev *i2c, 141a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang u8 addr, u8 *buf, int len, int flags) 142a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang{ 143a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang u32 data; 144a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang int i, shifts_left; 145a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 146a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang data = MXS_CMD_I2C_WRITE | MXS_I2C_CTRL0_XFER_COUNT(len + 1) | flags; 147a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang writel(data, i2c->regs + MXS_I2C_QUEUECMD); 148a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 149a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang /* 150a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * We have to copy the slave address (u8) and buffer (arbitrary number 151a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * of u8) into the data register (u32). To achieve that, the u8 are put 152a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * into the MSBs of 'data' which is then shifted for the next u8. When 15325985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * appropriate, 'data' is written to MXS_I2C_DATA. So, the first u32 154a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * looks like this: 155a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * 156a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * 3 2 1 0 157a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * 10987654|32109876|54321098|76543210 158a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * --------+--------+--------+-------- 159a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * buffer+2|buffer+1|buffer+0|slave_addr 160a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang */ 161a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 162a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang data = ((addr << 1) | I2C_SMBUS_WRITE) << 24; 163a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 164a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang for (i = 0; i < len; i++) { 165a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang data >>= 8; 166a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang data |= buf[i] << 24; 167a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if ((i & 3) == 2) 168a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang writel(data, i2c->regs + MXS_I2C_DATA); 169a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang } 170a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 171a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang /* Write out the remaining bytes if any */ 172a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang shifts_left = 24 - (i & 3) * 8; 173a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (shifts_left) 174a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang writel(data >> shifts_left, i2c->regs + MXS_I2C_DATA); 175a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang} 176a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 177a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang/* 178a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * TODO: should be replaceable with a waitqueue and RD_QUEUE_IRQ (setting the 179a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * rd_threshold to 1). Couldn't get this to work, though. 180a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang */ 181a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangstatic int mxs_i2c_wait_for_data(struct mxs_i2c_dev *i2c) 182a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang{ 183a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang unsigned long timeout = jiffies + msecs_to_jiffies(1000); 184a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 185a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang while (readl(i2c->regs + MXS_I2C_QUEUESTAT) 186a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang & MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY) { 187a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (time_after(jiffies, timeout)) 188a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return -ETIMEDOUT; 189a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang cond_resched(); 190a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang } 191a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 192a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return 0; 193a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang} 194a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 195a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangstatic int mxs_i2c_finish_read(struct mxs_i2c_dev *i2c, u8 *buf, int len) 196a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang{ 197a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang u32 data; 198a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang int i; 199a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 200a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang for (i = 0; i < len; i++) { 201a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if ((i & 3) == 0) { 202a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (mxs_i2c_wait_for_data(i2c)) 203a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return -ETIMEDOUT; 204a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang data = readl(i2c->regs + MXS_I2C_QUEUEDATA); 205a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang } 206a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang buf[i] = data & 0xff; 207a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang data >>= 8; 208a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang } 209a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 210a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return 0; 211a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang} 212a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 213a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang/* 214a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang * Low level master read/write transaction. 215a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang */ 216a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangstatic int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, 217a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang int stop) 218a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang{ 219a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap); 220a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang int ret; 221a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang int flags; 222a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 223a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", 224a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang msg->addr, msg->len, msg->flags, stop); 225a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 226a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (msg->len == 0) 227a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return -EINVAL; 228a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 229844990daa2e69a4258049ba9c2bae1180657dac3Wolfram Sang init_completion(&i2c->cmd_complete); 230c95eeae9e39314273bcda057f27100603d333518Wolfram Sang i2c->cmd_err = 0; 231844990daa2e69a4258049ba9c2bae1180657dac3Wolfram Sang 232a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0; 233a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 234a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (msg->flags & I2C_M_RD) 235a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang mxs_i2c_pioq_setup_read(i2c, msg->addr, msg->len, flags); 236a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang else 237a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf, msg->len, 238a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang flags); 239a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 240a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang writel(MXS_I2C_QUEUECTRL_QUEUE_RUN, 241a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang i2c->regs + MXS_I2C_QUEUECTRL_SET); 242a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 243a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang ret = wait_for_completion_timeout(&i2c->cmd_complete, 244a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang msecs_to_jiffies(1000)); 245a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (ret == 0) 246a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang goto timeout; 247a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 248a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if ((!i2c->cmd_err) && (msg->flags & I2C_M_RD)) { 249a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang ret = mxs_i2c_finish_read(i2c, msg->buf, msg->len); 250a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (ret) 251a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang goto timeout; 252a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang } 253a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 254a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (i2c->cmd_err == -ENXIO) 255a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang mxs_i2c_reset(i2c); 2561e4f0b82577e59f23484c99056c96465e202fdd5Wolfram Sang else 2571e4f0b82577e59f23484c99056c96465e202fdd5Wolfram Sang writel(MXS_I2C_QUEUECTRL_QUEUE_RUN, 2581e4f0b82577e59f23484c99056c96465e202fdd5Wolfram Sang i2c->regs + MXS_I2C_QUEUECTRL_CLR); 259a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 260a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang dev_dbg(i2c->dev, "Done with err=%d\n", i2c->cmd_err); 261a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 262a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return i2c->cmd_err; 263a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 264a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangtimeout: 265a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang dev_dbg(i2c->dev, "Timeout!\n"); 266a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang mxs_i2c_reset(i2c); 267a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return -ETIMEDOUT; 268a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang} 269a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 270a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangstatic int mxs_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], 271a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang int num) 272a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang{ 273a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang int i; 274a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang int err; 275a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 276a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang for (i = 0; i < num; i++) { 277a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang err = mxs_i2c_xfer_msg(adap, &msgs[i], i == (num - 1)); 278a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (err) 279a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return err; 280a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang } 281a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 282a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return num; 283a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang} 284a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 285a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangstatic u32 mxs_i2c_func(struct i2c_adapter *adap) 286a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang{ 287a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); 288a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang} 289a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 290a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangstatic irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id) 291a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang{ 292a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang struct mxs_i2c_dev *i2c = dev_id; 293a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang u32 stat = readl(i2c->regs + MXS_I2C_CTRL1) & MXS_I2C_IRQ_MASK; 294844990daa2e69a4258049ba9c2bae1180657dac3Wolfram Sang bool is_last_cmd; 295a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 296a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (!stat) 297a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return IRQ_NONE; 298a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 299a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (stat & MXS_I2C_CTRL1_NO_SLAVE_ACK_IRQ) 300a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang i2c->cmd_err = -ENXIO; 301a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang else if (stat & (MXS_I2C_CTRL1_EARLY_TERM_IRQ | 302a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang MXS_I2C_CTRL1_MASTER_LOSS_IRQ | 303a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang MXS_I2C_CTRL1_SLAVE_STOP_IRQ | MXS_I2C_CTRL1_SLAVE_IRQ)) 304a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang /* MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ is only for slaves */ 305a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang i2c->cmd_err = -EIO; 306a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 307844990daa2e69a4258049ba9c2bae1180657dac3Wolfram Sang is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) & 308844990daa2e69a4258049ba9c2bae1180657dac3Wolfram Sang MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0; 309844990daa2e69a4258049ba9c2bae1180657dac3Wolfram Sang 310844990daa2e69a4258049ba9c2bae1180657dac3Wolfram Sang if (is_last_cmd || i2c->cmd_err) 311844990daa2e69a4258049ba9c2bae1180657dac3Wolfram Sang complete(&i2c->cmd_complete); 312a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 313a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR); 314844990daa2e69a4258049ba9c2bae1180657dac3Wolfram Sang 315a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return IRQ_HANDLED; 316a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang} 317a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 318a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangstatic const struct i2c_algorithm mxs_i2c_algo = { 319a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang .master_xfer = mxs_i2c_xfer, 320a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang .functionality = mxs_i2c_func, 321a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang}; 322a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 323a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangstatic int __devinit mxs_i2c_probe(struct platform_device *pdev) 324a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang{ 325a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang struct device *dev = &pdev->dev; 326a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang struct mxs_i2c_dev *i2c; 327a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang struct i2c_adapter *adap; 328a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang struct resource *res; 329a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang resource_size_t res_size; 330a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang int err, irq; 331a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 332a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang i2c = devm_kzalloc(dev, sizeof(struct mxs_i2c_dev), GFP_KERNEL); 333a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (!i2c) 334a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return -ENOMEM; 335a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 336a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 337a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (!res) 338a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return -ENOENT; 339a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 340a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang res_size = resource_size(res); 341a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (!devm_request_mem_region(dev, res->start, res_size, res->name)) 342a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return -EBUSY; 343a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 344a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang i2c->regs = devm_ioremap_nocache(dev, res->start, res_size); 345a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (!i2c->regs) 346a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return -EBUSY; 347a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 348a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang irq = platform_get_irq(pdev, 0); 349a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (irq < 0) 350a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return irq; 351a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 352a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c); 353a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (err) 354a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return err; 355a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 356a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang i2c->dev = dev; 357a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang platform_set_drvdata(pdev, i2c); 358a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 359a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang /* Do reset to enforce correct startup after pinmuxing */ 360a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang mxs_i2c_reset(i2c); 361a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 362a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang adap = &i2c->adapter; 363a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang strlcpy(adap->name, "MXS I2C adapter", sizeof(adap->name)); 364a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang adap->owner = THIS_MODULE; 365a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang adap->algo = &mxs_i2c_algo; 366a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang adap->dev.parent = dev; 367a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang adap->nr = pdev->id; 368a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang i2c_set_adapdata(adap, i2c); 369a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang err = i2c_add_numbered_adapter(adap); 370a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (err) { 371a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang dev_err(dev, "Failed to add adapter (%d)\n", err); 372a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang writel(MXS_I2C_CTRL0_SFTRST, 373a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang i2c->regs + MXS_I2C_CTRL0_SET); 374a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return err; 375a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang } 376a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 377a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return 0; 378a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang} 379a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 380a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangstatic int __devexit mxs_i2c_remove(struct platform_device *pdev) 381a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang{ 382a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang struct mxs_i2c_dev *i2c = platform_get_drvdata(pdev); 383a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang int ret; 384a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 385a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang ret = i2c_del_adapter(&i2c->adapter); 386a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang if (ret) 387a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return -EBUSY; 388a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 389a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET); 390a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 391a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang platform_set_drvdata(pdev, NULL); 392a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 393a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return 0; 394a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang} 395a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 396a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangstatic struct platform_driver mxs_i2c_driver = { 397a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang .driver = { 398a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang .name = DRIVER_NAME, 399a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang .owner = THIS_MODULE, 400a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang }, 401a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang .remove = __devexit_p(mxs_i2c_remove), 402a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang}; 403a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 404a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangstatic int __init mxs_i2c_init(void) 405a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang{ 406a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang return platform_driver_probe(&mxs_i2c_driver, mxs_i2c_probe); 407a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang} 408a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangsubsys_initcall(mxs_i2c_init); 409a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 410a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangstatic void __exit mxs_i2c_exit(void) 411a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang{ 412a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang platform_driver_unregister(&mxs_i2c_driver); 413a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang} 414a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sangmodule_exit(mxs_i2c_exit); 415a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram Sang 416a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram SangMODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); 417a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram SangMODULE_DESCRIPTION("MXS I2C Bus Driver"); 418a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram SangMODULE_LICENSE("GPL"); 419a8da7fecb6010222fe495cc2b4330b99bca20c61Wolfram SangMODULE_ALIAS("platform:" DRIVER_NAME); 420