Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hmc6352: add driver for the HMC6352 compass

This driver will report the heading values in degrees to the sysfs
interface. The values returned are headings . e.g. 245.6

Alan: Cleanups requested now all folded in and a sysfs description to keep
Andrew happy. The sysfs description now resembles hwmon.

Signed-off-by: Kalhan Trisal <kalhan.trisal@intel.com>
Reviewed-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Alan Cox <alan@linux.intel.com>
Cc: Jonathan Cameron <jic23@cam.ac.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Kalhan Trisal and committed by
Linus Torvalds
cfa3b24c 5f1209a1

+195
+21
Documentation/ABI/testing/sysfs-bus-i2c-devices-hm6352
··· 1 + Where: /sys/bus/i2c/devices/.../heading0_input 2 + Date: April 2010 3 + Kernel Version: 2.6.36? 4 + Contact: alan.cox@intel.com 5 + Description: Reports the current heading from the compass as a floating 6 + point value in degrees. 7 + 8 + Where: /sys/bus/i2c/devices/.../power_state 9 + Date: April 2010 10 + Kernel Version: 2.6.36? 11 + Contact: alan.cox@intel.com 12 + Description: Sets the power state of the device. 0 sets the device into 13 + sleep mode, 1 wakes it up. 14 + 15 + Where: /sys/bus/i2c/devices/.../calibration 16 + Date: April 2010 17 + Kernel Version: 2.6.36? 18 + Contact: alan.cox@intel.com 19 + Description: Sets the calibration on or off (1 = on, 0 = off). See the 20 + chip data sheet. 21 +
+7
drivers/misc/Kconfig
··· 314 314 This driver can also be built as a module. If so, the module 315 315 will be called bh1780gli. 316 316 317 + config HMC6352 318 + tristate "Honeywell HMC6352 compass" 319 + depends on I2C 320 + help 321 + This driver provides support for the Honeywell HMC6352 compass, 322 + providing configuration and heading data via sysfs. 323 + 317 324 config EP93XX_PWM 318 325 tristate "EP93xx PWM support" 319 326 depends on ARCH_EP93XX
+1
drivers/misc/Makefile
··· 30 30 obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o 31 31 obj-$(CONFIG_C2PORT) += c2port/ 32 32 obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/ 33 + obj-$(CONFIG_HMC6352) += hmc6352.o 33 34 obj-y += eeprom/ 34 35 obj-y += cb710/ 35 36 obj-$(CONFIG_VMWARE_BALLOON) += vmware_balloon.o
+166
drivers/misc/hmc6352.c
··· 1 + /* 2 + * hmc6352.c - Honeywell Compass Driver 3 + * 4 + * Copyright (C) 2009 Intel Corp 5 + * 6 + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 + * 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; version 2 of the License. 11 + * 12 + * This program is distributed in the hope that it will be useful, but 13 + * WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 + * General Public License for more details. 16 + * 17 + * You should have received a copy of the GNU General Public License along 18 + * with this program; if not, write to the Free Software Foundation, Inc., 19 + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 20 + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 21 + * 22 + */ 23 + 24 + #include <linux/module.h> 25 + #include <linux/init.h> 26 + #include <linux/slab.h> 27 + #include <linux/i2c.h> 28 + #include <linux/err.h> 29 + #include <linux/delay.h> 30 + #include <linux/sysfs.h> 31 + 32 + static DEFINE_MUTEX(compass_mutex); 33 + 34 + static int compass_command(struct i2c_client *c, u8 cmd) 35 + { 36 + int ret = i2c_master_send(c, &cmd, 1); 37 + if (ret < 0) 38 + dev_warn(&c->dev, "command '%c' failed.\n", cmd); 39 + return ret; 40 + } 41 + 42 + static int compass_store(struct device *dev, const char *buf, size_t count, 43 + const char *map) 44 + { 45 + struct i2c_client *c = to_i2c_client(dev); 46 + int ret; 47 + unsigned long val; 48 + 49 + if (strict_strtoul(buf, 10, &val)) 50 + return -EINVAL; 51 + if (val >= strlen(map)) 52 + return -EINVAL; 53 + mutex_lock(&compass_mutex); 54 + ret = compass_command(c, map[val]); 55 + mutex_unlock(&compass_mutex); 56 + if (ret < 0) 57 + return ret; 58 + return count; 59 + } 60 + 61 + static ssize_t compass_calibration_store(struct device *dev, 62 + struct device_attribute *attr, const char *buf, size_t count) 63 + { 64 + return compass_store(dev, buf, count, "EC"); 65 + } 66 + 67 + static ssize_t compass_power_mode_store(struct device *dev, 68 + struct device_attribute *attr, const char *buf, size_t count) 69 + { 70 + return compass_store(dev, buf, count, "SW"); 71 + } 72 + 73 + static ssize_t compass_heading_data_show(struct device *dev, 74 + struct device_attribute *attr, char *buf) 75 + { 76 + struct i2c_client *client = to_i2c_client(dev); 77 + unsigned char i2c_data[2]; 78 + unsigned int ret; 79 + 80 + mutex_lock(&compass_mutex); 81 + ret = compass_command(client, 'A'); 82 + if (ret != 1) { 83 + mutex_unlock(&compass_mutex); 84 + return ret; 85 + } 86 + msleep(10); /* sending 'A' cmd we need to wait for 7-10 millisecs */ 87 + ret = i2c_master_recv(client, i2c_data, 2); 88 + mutex_unlock(&compass_mutex); 89 + if (ret != 1) { 90 + dev_warn(dev, "i2c read data cmd failed\n"); 91 + return ret; 92 + } 93 + ret = (i2c_data[0] << 8) | i2c_data[1]; 94 + return sprintf(buf, "%d.%d\n", ret/10, ret%10); 95 + } 96 + 97 + 98 + static DEVICE_ATTR(heading0_input, S_IRUGO, compass_heading_data_show, NULL); 99 + static DEVICE_ATTR(calibration, S_IWUSR, NULL, compass_calibration_store); 100 + static DEVICE_ATTR(power_state, S_IWUSR, NULL, compass_power_mode_store); 101 + 102 + static struct attribute *mid_att_compass[] = { 103 + &dev_attr_heading0_input.attr, 104 + &dev_attr_calibration.attr, 105 + &dev_attr_power_state.attr, 106 + NULL 107 + }; 108 + 109 + static const struct attribute_group m_compass_gr = { 110 + .name = "hmc6352", 111 + .attrs = mid_att_compass 112 + }; 113 + 114 + static int hmc6352_probe(struct i2c_client *client, 115 + const struct i2c_device_id *id) 116 + { 117 + int res; 118 + 119 + res = sysfs_create_group(&client->dev.kobj, &m_compass_gr); 120 + if (res) { 121 + dev_err(&client->dev, "device_create_file failed\n"); 122 + return res; 123 + } 124 + dev_info(&client->dev, "%s HMC6352 compass chip found\n", 125 + client->name); 126 + return 0; 127 + } 128 + 129 + static int hmc6352_remove(struct i2c_client *client) 130 + { 131 + sysfs_remove_group(&client->dev.kobj, &m_compass_gr); 132 + return 0; 133 + } 134 + 135 + static struct i2c_device_id hmc6352_id[] = { 136 + { "hmc6352", 0 }, 137 + { } 138 + }; 139 + 140 + MODULE_DEVICE_TABLE(i2c, hmc6352_id); 141 + 142 + static struct i2c_driver hmc6352_driver = { 143 + .driver = { 144 + .name = "hmc6352", 145 + }, 146 + .probe = hmc6352_probe, 147 + .remove = hmc6352_remove, 148 + .id_table = hmc6352_id, 149 + }; 150 + 151 + static int __init sensor_hmc6352_init(void) 152 + { 153 + return i2c_add_driver(&hmc6352_driver); 154 + } 155 + 156 + static void __exit sensor_hmc6352_exit(void) 157 + { 158 + i2c_del_driver(&hmc6352_driver); 159 + } 160 + 161 + module_init(sensor_hmc6352_init); 162 + module_exit(sensor_hmc6352_exit); 163 + 164 + MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com"); 165 + MODULE_DESCRIPTION("hmc6352 Compass Driver"); 166 + MODULE_LICENSE("GPL v2");