2 * Copyright (C) 2010 MEMSIC, Inc.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include <linux/kernel.h>
25 #include <linux/init.h>
26 #include <linux/module.h>
27 #include <linux/slab.h>
28 #include <linux/jiffies.h>
29 #include <linux/i2c.h>
30 #include <linux/i2c-dev.h>
31 #include <linux/miscdevice.h>
32 #include <linux/mutex.h>
34 #include <linux/device.h>
36 #include <linux/delay.h>
37 #include <linux/sysctl.h>
38 #include <asm/uaccess.h>
43 #define MAX_FAILURE_COUNT 3
46 #define MMC328X_DELAY_TM 10 /* ms */
47 #define MMC328X_DELAY_RM 10 /* ms */
48 #define MMC328X_DELAY_STDN 1 /* ms */
50 #define MMC328X_RETRY_COUNT 3
51 #define MMC328X_RESET_INTV 10
53 #define MMC328X_DEV_NAME "mmc328x"
55 static u32 read_idx = 0;
57 static struct i2c_client *this_client;
59 static int mmc328x_i2c_rx_data(char *buf, int len)
62 struct i2c_msg msgs[] = {
64 .addr = this_client->addr,
72 .addr = this_client->addr,
81 for (i = 0; i < MMC328X_RETRY_COUNT; i++) {
82 if (i2c_transfer(this_client->adapter, msgs, 2) >= 0) {
88 if (i >= MMC328X_RETRY_COUNT) {
89 pr_err("%s: retry over %d\n", __FUNCTION__, MMC328X_RETRY_COUNT);
96 static int mmc328x_i2c_tx_data(char *buf, int len)
99 struct i2c_msg msg[] = {
101 .addr = this_client->addr,
108 for (i = 0; i < MMC328X_RETRY_COUNT; i++) {
109 if (i2c_transfer(this_client->adapter, msg, 1) >= 0) {
115 if (i >= MMC328X_RETRY_COUNT) {
116 pr_err("%s: retry over %d\n", __FUNCTION__, MMC328X_RETRY_COUNT);
122 static int mmc328x_open(struct inode *inode, struct file *file)
124 return nonseekable_open(inode, file);
127 static int mmc328x_release(struct inode *inode, struct file *file)
132 static int mmc328x_ioctl(struct inode *inode, struct file *file,
133 unsigned int cmd, unsigned long arg)
135 void __user *pa = (void __user *)arg;
136 unsigned char data[16] = {0};
142 data[0] = MMC328X_REG_CTRL;
143 data[1] = MMC328X_CTRL_TM;
144 if (mmc328x_i2c_tx_data(data, 2) < 0) {
147 /* wait TM done for coming data read */
148 msleep(MMC328X_DELAY_TM);
151 data[0] = MMC328X_REG_CTRL;
152 data[1] = MMC328X_CTRL_RM;
153 if (mmc328x_i2c_tx_data(data, 2) < 0) {
156 /* wait external capacitor charging done for next SET/RESET */
157 msleep(MMC328X_DELAY_RM);
159 case MMC328X_IOC_READ:
160 data[0] = MMC328X_REG_DATA;
161 if (mmc328x_i2c_rx_data(data, 6) < 0) {
164 vec[0] = data[1] << 8 | data[0];
165 vec[1] = data[3] << 8 | data[2];
166 vec[2] = data[5] << 8 | data[4];
168 printk("[X - %04x] [Y - %04x] [Z - %04x]\n",
169 vec[0], vec[1], vec[2]);
171 if (copy_to_user(pa, vec, sizeof(vec))) {
175 case MMC328X_IOC_READXYZ:
176 /* do RM every MMC328X_RESET_INTV times read */
177 if (!(read_idx % MMC328X_RESET_INTV)) {
179 data[0] = MMC328X_REG_CTRL;
180 data[1] = MMC328X_CTRL_RM;
181 /* not check return value here, assume it always OK */
182 mmc328x_i2c_tx_data(data, 2);
183 /* wait external capacitor charging done for next RM */
184 msleep(MMC328X_DELAY_RM);
186 /* send TM cmd before read */
187 data[0] = MMC328X_REG_CTRL;
188 data[1] = MMC328X_CTRL_TM;
189 /* not check return value here, assume it always OK */
190 mmc328x_i2c_tx_data(data, 2);
191 /* wait TM done for coming data read */
192 msleep(MMC328X_DELAY_TM);
195 data[0] = MMC328X_REG_DS;
196 if (mmc328x_i2c_rx_data(data, 1) < 0) {
199 while (!(data[0] & 0x01)) {
202 data[0] = MMC328X_REG_DS;
203 if (mmc328x_i2c_rx_data(data, 1) < 0) {
206 if (data[0] & 0x01) break;
210 printk("TM not work!!");
216 /* read xyz raw data */
218 data[0] = MMC328X_REG_DATA;
219 if (mmc328x_i2c_rx_data(data, 6) < 0) {
222 vec[0] = data[1] << 8 | data[0];
223 vec[1] = data[3] << 8 | data[2];
224 vec[2] = data[5] << 8 | data[4];
226 printk("[X - %04x] [Y - %04x] [Z - %04x]\n",
227 vec[0], vec[1], vec[2]);
229 if (copy_to_user(pa, vec, sizeof(vec))) {
241 static ssize_t mmc328x_show(struct device *dev, struct device_attribute *attr, char *buf)
245 sprintf(buf, "MMC328X");
246 ret = strlen(buf) + 1;
251 static DEVICE_ATTR(mmc328x, S_IRUGO, mmc328x_show, NULL);
253 static struct file_operations mmc328x_fops = {
254 .owner = THIS_MODULE,
255 .open = mmc328x_open,
256 .release = mmc328x_release,
257 .ioctl = mmc328x_ioctl,
260 static struct miscdevice mmc328x_device = {
261 .minor = MISC_DYNAMIC_MINOR,
262 .name = MMC328X_DEV_NAME,
263 .fops = &mmc328x_fops,
266 static int mmc328x_probe(struct i2c_client *client, const struct i2c_device_id *id)
268 unsigned char data[16] = {0};
271 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
272 pr_err("%s: functionality check failed\n", __FUNCTION__);
276 this_client = client;
278 res = misc_register(&mmc328x_device);
280 pr_err("%s: mmc328x_device register failed\n", __FUNCTION__);
283 res = device_create_file(&client->dev, &dev_attr_mmc328x);
285 pr_err("%s: device_create_file failed\n", __FUNCTION__);
289 /* send ST cmd to mag sensor first of all */
290 data[0] = MMC328X_REG_CTRL;
291 data[1] = MMC328X_CTRL_RM;
292 if (mmc328x_i2c_tx_data(data, 2) < 0) {
293 /* assume RM always success */
295 /* wait external capacitor charging done for next RM */
296 msleep(MMC328X_DELAY_RM);
301 misc_deregister(&mmc328x_device);
306 static int mmc328x_remove(struct i2c_client *client)
308 device_remove_file(&client->dev, &dev_attr_mmc328x);
309 misc_deregister(&mmc328x_device);
314 static const struct i2c_device_id mmc328x_id[] = {
315 { MMC328X_I2C_NAME, 0 },
319 static struct i2c_driver mmc328x_driver = {
320 .probe = mmc328x_probe,
321 .remove = mmc328x_remove,
322 .id_table = mmc328x_id,
324 .owner = THIS_MODULE,
325 .name = MMC328X_I2C_NAME,
330 static int __init mmc328x_init(void)
332 pr_info("mmc328x driver: init\n");
333 return i2c_add_driver(&mmc328x_driver);
336 static void __exit mmc328x_exit(void)
338 pr_info("mmc328x driver: exit\n");
339 i2c_del_driver(&mmc328x_driver);
342 module_init(mmc328x_init);
343 module_exit(mmc328x_exit);
345 MODULE_AUTHOR("Dale Hou<byhou@memsic.com>");
346 MODULE_DESCRIPTION("MEMSIC MMC328X Magnetic Sensor Driver");
347 MODULE_LICENSE("GPL");