diff options
| author | Len Brown <len.brown@intel.com> | 2010-08-15 01:06:31 -0400 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2010-08-15 01:06:31 -0400 |
| commit | 95ee46aa8698f2000647dfb362400fadbb5807cf (patch) | |
| tree | e5a05c7297f997e191c73091934e42e3195c0e40 /drivers/misc | |
| parent | cfa806f059801dbe7e435745eb2e187c8bfe1e7f (diff) | |
| parent | 92fa5bd9a946b6e7aab6764e7312e4e3d9bed295 (diff) | |
Merge branch 'linus' into release
Conflicts:
drivers/acpi/debug.c
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/misc')
| -rw-r--r-- | drivers/misc/Kconfig | 41 | ||||
| -rw-r--r-- | drivers/misc/Makefile | 4 | ||||
| -rw-r--r-- | drivers/misc/arm-charlcd.c | 396 | ||||
| -rw-r--r-- | drivers/misc/bh1780gli.c | 273 | ||||
| -rw-r--r-- | drivers/misc/bmp085.c | 482 | ||||
| -rw-r--r-- | drivers/misc/cs5535-mfgpt.c | 11 | ||||
| -rw-r--r-- | drivers/misc/enclosure.c | 7 | ||||
| -rw-r--r-- | drivers/misc/hmc6352.c | 166 | ||||
| -rw-r--r-- | drivers/misc/hpilo.c | 17 | ||||
| -rw-r--r-- | drivers/misc/hpilo.h | 8 | ||||
| -rw-r--r-- | drivers/misc/lkdtm.c | 4 |
11 files changed, 1391 insertions, 18 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 26386a92f5aa..0b591b658243 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
| @@ -72,7 +72,7 @@ config ATMEL_TCLIB | |||
| 72 | 72 | ||
| 73 | config ATMEL_TCB_CLKSRC | 73 | config ATMEL_TCB_CLKSRC |
| 74 | bool "TC Block Clocksource" | 74 | bool "TC Block Clocksource" |
| 75 | depends on ATMEL_TCLIB && GENERIC_TIME | 75 | depends on ATMEL_TCLIB |
| 76 | default y | 76 | default y |
| 77 | help | 77 | help |
| 78 | Select this to get a high precision clocksource based on a | 78 | Select this to get a high precision clocksource based on a |
| @@ -240,7 +240,7 @@ config CS5535_MFGPT_DEFAULT_IRQ | |||
| 240 | 240 | ||
| 241 | config CS5535_CLOCK_EVENT_SRC | 241 | config CS5535_CLOCK_EVENT_SRC |
| 242 | tristate "CS5535/CS5536 high-res timer (MFGPT) events" | 242 | tristate "CS5535/CS5536 high-res timer (MFGPT) events" |
| 243 | depends on GENERIC_TIME && GENERIC_CLOCKEVENTS && CS5535_MFGPT | 243 | depends on GENERIC_CLOCKEVENTS && CS5535_MFGPT |
| 244 | help | 244 | help |
| 245 | This driver provides a clock event source based on the MFGPT | 245 | This driver provides a clock event source based on the MFGPT |
| 246 | timer(s) in the CS5535 and CS5536 companion chips. | 246 | timer(s) in the CS5535 and CS5536 companion chips. |
| @@ -304,6 +304,23 @@ config SENSORS_TSL2550 | |||
| 304 | This driver can also be built as a module. If so, the module | 304 | This driver can also be built as a module. If so, the module |
| 305 | will be called tsl2550. | 305 | will be called tsl2550. |
| 306 | 306 | ||
| 307 | config SENSORS_BH1780 | ||
| 308 | tristate "ROHM BH1780GLI ambient light sensor" | ||
| 309 | depends on I2C && SYSFS | ||
| 310 | help | ||
| 311 | If you say yes here you get support for the ROHM BH1780GLI | ||
| 312 | ambient light sensor. | ||
| 313 | |||
| 314 | This driver can also be built as a module. If so, the module | ||
| 315 | will be called bh1780gli. | ||
| 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 | |||
| 307 | config EP93XX_PWM | 324 | config EP93XX_PWM |
| 308 | tristate "EP93xx PWM support" | 325 | tristate "EP93xx PWM support" |
| 309 | depends on ARCH_EP93XX | 326 | depends on ARCH_EP93XX |
| @@ -353,6 +370,26 @@ config VMWARE_BALLOON | |||
| 353 | To compile this driver as a module, choose M here: the | 370 | To compile this driver as a module, choose M here: the |
| 354 | module will be called vmware_balloon. | 371 | module will be called vmware_balloon. |
| 355 | 372 | ||
| 373 | config ARM_CHARLCD | ||
| 374 | bool "ARM Ltd. Character LCD Driver" | ||
| 375 | depends on PLAT_VERSATILE | ||
| 376 | help | ||
| 377 | This is a driver for the character LCD found on the ARM Ltd. | ||
| 378 | Versatile and RealView Platform Baseboards. It doesn't do | ||
| 379 | very much more than display the text "ARM Linux" on the first | ||
| 380 | line and the Linux version on the second line, but that's | ||
| 381 | still useful. | ||
| 382 | |||
| 383 | config BMP085 | ||
| 384 | tristate "BMP085 digital pressure sensor" | ||
| 385 | depends on I2C && SYSFS | ||
| 386 | help | ||
| 387 | If you say yes here you get support for the Bosch Sensortec | ||
| 388 | BMP086 digital pressure sensor. | ||
| 389 | |||
| 390 | To compile this driver as a module, choose M here: the | ||
| 391 | module will be called bmp085. | ||
| 392 | |||
| 356 | source "drivers/misc/c2port/Kconfig" | 393 | source "drivers/misc/c2port/Kconfig" |
| 357 | source "drivers/misc/eeprom/Kconfig" | 394 | source "drivers/misc/eeprom/Kconfig" |
| 358 | source "drivers/misc/cb710/Kconfig" | 395 | source "drivers/misc/cb710/Kconfig" |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 6ed06a19474a..255a80dc9d73 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
| @@ -9,11 +9,13 @@ obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o | |||
| 9 | obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o | 9 | obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o |
| 10 | obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o | 10 | obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o |
| 11 | obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o | 11 | obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o |
| 12 | obj-$(CONFIG_BMP085) += bmp085.o | ||
| 12 | obj-$(CONFIG_ICS932S401) += ics932s401.o | 13 | obj-$(CONFIG_ICS932S401) += ics932s401.o |
| 13 | obj-$(CONFIG_LKDTM) += lkdtm.o | 14 | obj-$(CONFIG_LKDTM) += lkdtm.o |
| 14 | obj-$(CONFIG_TIFM_CORE) += tifm_core.o | 15 | obj-$(CONFIG_TIFM_CORE) += tifm_core.o |
| 15 | obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o | 16 | obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o |
| 16 | obj-$(CONFIG_PHANTOM) += phantom.o | 17 | obj-$(CONFIG_PHANTOM) += phantom.o |
| 18 | obj-$(CONFIG_SENSORS_BH1780) += bh1780gli.o | ||
| 17 | obj-$(CONFIG_SGI_IOC4) += ioc4.o | 19 | obj-$(CONFIG_SGI_IOC4) += ioc4.o |
| 18 | obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o | 20 | obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o |
| 19 | obj-$(CONFIG_KGDB_TESTS) += kgdbts.o | 21 | obj-$(CONFIG_KGDB_TESTS) += kgdbts.o |
| @@ -28,6 +30,8 @@ obj-$(CONFIG_DS1682) += ds1682.o | |||
| 28 | obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o | 30 | obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o |
| 29 | obj-$(CONFIG_C2PORT) += c2port/ | 31 | obj-$(CONFIG_C2PORT) += c2port/ |
| 30 | obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/ | 32 | obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/ |
| 33 | obj-$(CONFIG_HMC6352) += hmc6352.o | ||
| 31 | obj-y += eeprom/ | 34 | obj-y += eeprom/ |
| 32 | obj-y += cb710/ | 35 | obj-y += cb710/ |
| 33 | obj-$(CONFIG_VMWARE_BALLOON) += vmware_balloon.o | 36 | obj-$(CONFIG_VMWARE_BALLOON) += vmware_balloon.o |
| 37 | obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o | ||
diff --git a/drivers/misc/arm-charlcd.c b/drivers/misc/arm-charlcd.c new file mode 100644 index 000000000000..9e3879ef58f2 --- /dev/null +++ b/drivers/misc/arm-charlcd.c | |||
| @@ -0,0 +1,396 @@ | |||
| 1 | /* | ||
| 2 | * Driver for the on-board character LCD found on some ARM reference boards | ||
| 3 | * This is basically an Hitachi HD44780 LCD with a custom IP block to drive it | ||
| 4 | * http://en.wikipedia.org/wiki/HD44780_Character_LCD | ||
| 5 | * Currently it will just display the text "ARM Linux" and the linux version | ||
| 6 | * | ||
| 7 | * License terms: GNU General Public License (GPL) version 2 | ||
| 8 | * Author: Linus Walleij <triad@df.lth.se> | ||
| 9 | */ | ||
| 10 | #include <linux/init.h> | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/interrupt.h> | ||
| 13 | #include <linux/platform_device.h> | ||
| 14 | #include <linux/completion.h> | ||
| 15 | #include <linux/delay.h> | ||
| 16 | #include <linux/io.h> | ||
| 17 | #include <linux/slab.h> | ||
| 18 | #include <linux/workqueue.h> | ||
| 19 | #include <generated/utsrelease.h> | ||
| 20 | |||
| 21 | #define DRIVERNAME "arm-charlcd" | ||
| 22 | #define CHARLCD_TIMEOUT (msecs_to_jiffies(1000)) | ||
| 23 | |||
| 24 | /* Offsets to registers */ | ||
| 25 | #define CHAR_COM 0x00U | ||
| 26 | #define CHAR_DAT 0x04U | ||
| 27 | #define CHAR_RD 0x08U | ||
| 28 | #define CHAR_RAW 0x0CU | ||
| 29 | #define CHAR_MASK 0x10U | ||
| 30 | #define CHAR_STAT 0x14U | ||
| 31 | |||
| 32 | #define CHAR_RAW_CLEAR 0x00000000U | ||
| 33 | #define CHAR_RAW_VALID 0x00000100U | ||
| 34 | |||
| 35 | /* Hitachi HD44780 display commands */ | ||
| 36 | #define HD_CLEAR 0x01U | ||
| 37 | #define HD_HOME 0x02U | ||
| 38 | #define HD_ENTRYMODE 0x04U | ||
| 39 | #define HD_ENTRYMODE_INCREMENT 0x02U | ||
| 40 | #define HD_ENTRYMODE_SHIFT 0x01U | ||
| 41 | #define HD_DISPCTRL 0x08U | ||
| 42 | #define HD_DISPCTRL_ON 0x04U | ||
| 43 | #define HD_DISPCTRL_CURSOR_ON 0x02U | ||
| 44 | #define HD_DISPCTRL_CURSOR_BLINK 0x01U | ||
| 45 | #define HD_CRSR_SHIFT 0x10U | ||
| 46 | #define HD_CRSR_SHIFT_DISPLAY 0x08U | ||
| 47 | #define HD_CRSR_SHIFT_DISPLAY_RIGHT 0x04U | ||
| 48 | #define HD_FUNCSET 0x20U | ||
| 49 | #define HD_FUNCSET_8BIT 0x10U | ||
| 50 | #define HD_FUNCSET_2_LINES 0x08U | ||
| 51 | #define HD_FUNCSET_FONT_5X10 0x04U | ||
| 52 | #define HD_SET_CGRAM 0x40U | ||
| 53 | #define HD_SET_DDRAM 0x80U | ||
| 54 | #define HD_BUSY_FLAG 0x80U | ||
| 55 | |||
| 56 | /** | ||
| 57 | * @dev: a pointer back to containing device | ||
| 58 | * @phybase: the offset to the controller in physical memory | ||
| 59 | * @physize: the size of the physical page | ||
| 60 | * @virtbase: the offset to the controller in virtual memory | ||
| 61 | * @irq: reserved interrupt number | ||
| 62 | * @complete: completion structure for the last LCD command | ||
| 63 | */ | ||
| 64 | struct charlcd { | ||
| 65 | struct device *dev; | ||
| 66 | u32 phybase; | ||
| 67 | u32 physize; | ||
| 68 | void __iomem *virtbase; | ||
| 69 | int irq; | ||
| 70 | struct completion complete; | ||
| 71 | struct delayed_work init_work; | ||
| 72 | }; | ||
| 73 | |||
| 74 | static irqreturn_t charlcd_interrupt(int irq, void *data) | ||
| 75 | { | ||
| 76 | struct charlcd *lcd = data; | ||
| 77 | u8 status; | ||
| 78 | |||
| 79 | status = readl(lcd->virtbase + CHAR_STAT) & 0x01; | ||
| 80 | /* Clear IRQ */ | ||
| 81 | writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW); | ||
| 82 | if (status) | ||
| 83 | complete(&lcd->complete); | ||
| 84 | else | ||
| 85 | dev_info(lcd->dev, "Spurious IRQ (%02x)\n", status); | ||
| 86 | return IRQ_HANDLED; | ||
| 87 | } | ||
| 88 | |||
| 89 | |||
| 90 | static void charlcd_wait_complete_irq(struct charlcd *lcd) | ||
| 91 | { | ||
| 92 | int ret; | ||
| 93 | |||
| 94 | ret = wait_for_completion_interruptible_timeout(&lcd->complete, | ||
| 95 | CHARLCD_TIMEOUT); | ||
| 96 | /* Disable IRQ after completion */ | ||
| 97 | writel(0x00, lcd->virtbase + CHAR_MASK); | ||
| 98 | |||
| 99 | if (ret < 0) { | ||
| 100 | dev_err(lcd->dev, | ||
| 101 | "wait_for_completion_interruptible_timeout() " | ||
| 102 | "returned %d waiting for ready\n", ret); | ||
| 103 | return; | ||
| 104 | } | ||
| 105 | |||
| 106 | if (ret == 0) { | ||
| 107 | dev_err(lcd->dev, "charlcd controller timed out " | ||
| 108 | "waiting for ready\n"); | ||
| 109 | return; | ||
| 110 | } | ||
| 111 | } | ||
| 112 | |||
| 113 | static u8 charlcd_4bit_read_char(struct charlcd *lcd) | ||
| 114 | { | ||
| 115 | u8 data; | ||
| 116 | u32 val; | ||
| 117 | int i; | ||
| 118 | |||
| 119 | /* If we can, use an IRQ to wait for the data, else poll */ | ||
| 120 | if (lcd->irq >= 0) | ||
| 121 | charlcd_wait_complete_irq(lcd); | ||
| 122 | else { | ||
| 123 | i = 0; | ||
| 124 | val = 0; | ||
| 125 | while (!(val & CHAR_RAW_VALID) && i < 10) { | ||
| 126 | udelay(100); | ||
| 127 | val = readl(lcd->virtbase + CHAR_RAW); | ||
| 128 | i++; | ||
| 129 | } | ||
| 130 | |||
| 131 | writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW); | ||
| 132 | } | ||
| 133 | msleep(1); | ||
| 134 | |||
| 135 | /* Read the 4 high bits of the data */ | ||
| 136 | data = readl(lcd->virtbase + CHAR_RD) & 0xf0; | ||
| 137 | |||
| 138 | /* | ||
| 139 | * The second read for the low bits does not trigger an IRQ | ||
| 140 | * so in this case we have to poll for the 4 lower bits | ||
| 141 | */ | ||
| 142 | i = 0; | ||
| 143 | val = 0; | ||
| 144 | while (!(val & CHAR_RAW_VALID) && i < 10) { | ||
| 145 | udelay(100); | ||
| 146 | val = readl(lcd->virtbase + CHAR_RAW); | ||
| 147 | i++; | ||
| 148 | } | ||
| 149 | writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW); | ||
| 150 | msleep(1); | ||
| 151 | |||
| 152 | /* Read the 4 low bits of the data */ | ||
| 153 | data |= (readl(lcd->virtbase + CHAR_RD) >> 4) & 0x0f; | ||
| 154 | |||
| 155 | return data; | ||
| 156 | } | ||
| 157 | |||
| 158 | static bool charlcd_4bit_read_bf(struct charlcd *lcd) | ||
| 159 | { | ||
| 160 | if (lcd->irq >= 0) { | ||
| 161 | /* | ||
| 162 | * If we'll use IRQs to wait for the busyflag, clear any | ||
| 163 | * pending flag and enable IRQ | ||
| 164 | */ | ||
| 165 | writel(CHAR_RAW_CLEAR, lcd->virtbase + CHAR_RAW); | ||
| 166 | init_completion(&lcd->complete); | ||
| 167 | writel(0x01, lcd->virtbase + CHAR_MASK); | ||
| 168 | } | ||
| 169 | readl(lcd->virtbase + CHAR_COM); | ||
| 170 | return charlcd_4bit_read_char(lcd) & HD_BUSY_FLAG ? true : false; | ||
| 171 | } | ||
| 172 | |||
| 173 | static void charlcd_4bit_wait_busy(struct charlcd *lcd) | ||
| 174 | { | ||
| 175 | int retries = 50; | ||
| 176 | |||
| 177 | udelay(100); | ||
| 178 | while (charlcd_4bit_read_bf(lcd) && retries) | ||
| 179 | retries--; | ||
| 180 | if (!retries) | ||
| 181 | dev_err(lcd->dev, "timeout waiting for busyflag\n"); | ||
| 182 | } | ||
| 183 | |||
| 184 | static void charlcd_4bit_command(struct charlcd *lcd, u8 cmd) | ||
| 185 | { | ||
| 186 | u32 cmdlo = (cmd << 4) & 0xf0; | ||
| 187 | u32 cmdhi = (cmd & 0xf0); | ||
| 188 | |||
| 189 | writel(cmdhi, lcd->virtbase + CHAR_COM); | ||
| 190 | udelay(10); | ||
| 191 | writel(cmdlo, lcd->virtbase + CHAR_COM); | ||
| 192 | charlcd_4bit_wait_busy(lcd); | ||
| 193 | } | ||
| 194 | |||
| 195 | static void charlcd_4bit_char(struct charlcd *lcd, u8 ch) | ||
| 196 | { | ||
| 197 | u32 chlo = (ch << 4) & 0xf0; | ||
| 198 | u32 chhi = (ch & 0xf0); | ||
| 199 | |||
| 200 | writel(chhi, lcd->virtbase + CHAR_DAT); | ||
| 201 | udelay(10); | ||
| 202 | writel(chlo, lcd->virtbase + CHAR_DAT); | ||
| 203 | charlcd_4bit_wait_busy(lcd); | ||
| 204 | } | ||
| 205 | |||
| 206 | static void charlcd_4bit_print(struct charlcd *lcd, int line, const char *str) | ||
| 207 | { | ||
| 208 | u8 offset; | ||
| 209 | int i; | ||
| 210 | |||
| 211 | /* | ||
| 212 | * We support line 0, 1 | ||
| 213 | * Line 1 runs from 0x00..0x27 | ||
| 214 | * Line 2 runs from 0x28..0x4f | ||
| 215 | */ | ||
| 216 | if (line == 0) | ||
| 217 | offset = 0; | ||
| 218 | else if (line == 1) | ||
| 219 | offset = 0x28; | ||
| 220 | else | ||
| 221 | return; | ||
| 222 | |||
| 223 | /* Set offset */ | ||
| 224 | charlcd_4bit_command(lcd, HD_SET_DDRAM | offset); | ||
| 225 | |||
| 226 | /* Send string */ | ||
| 227 | for (i = 0; i < strlen(str) && i < 0x28; i++) | ||
| 228 | charlcd_4bit_char(lcd, str[i]); | ||
| 229 | } | ||
| 230 | |||
| 231 | static void charlcd_4bit_init(struct charlcd *lcd) | ||
| 232 | { | ||
| 233 | /* These commands cannot be checked with the busy flag */ | ||
| 234 | writel(HD_FUNCSET | HD_FUNCSET_8BIT, lcd->virtbase + CHAR_COM); | ||
| 235 | msleep(5); | ||
| 236 | writel(HD_FUNCSET | HD_FUNCSET_8BIT, lcd->virtbase + CHAR_COM); | ||
| 237 | udelay(100); | ||
| 238 | writel(HD_FUNCSET | HD_FUNCSET_8BIT, lcd->virtbase + CHAR_COM); | ||
| 239 | udelay(100); | ||
| 240 | /* Go to 4bit mode */ | ||
| 241 | writel(HD_FUNCSET, lcd->virtbase + CHAR_COM); | ||
| 242 | udelay(100); | ||
| 243 | /* | ||
| 244 | * 4bit mode, 2 lines, 5x8 font, after this the number of lines | ||
| 245 | * and the font cannot be changed until the next initialization sequence | ||
| 246 | */ | ||
| 247 | charlcd_4bit_command(lcd, HD_FUNCSET | HD_FUNCSET_2_LINES); | ||
| 248 | charlcd_4bit_command(lcd, HD_DISPCTRL | HD_DISPCTRL_ON); | ||
| 249 | charlcd_4bit_command(lcd, HD_ENTRYMODE | HD_ENTRYMODE_INCREMENT); | ||
| 250 | charlcd_4bit_command(lcd, HD_CLEAR); | ||
| 251 | charlcd_4bit_command(lcd, HD_HOME); | ||
| 252 | /* Put something useful in the display */ | ||
| 253 | charlcd_4bit_print(lcd, 0, "ARM Linux"); | ||
| 254 | charlcd_4bit_print(lcd, 1, UTS_RELEASE); | ||
| 255 | } | ||
| 256 | |||
| 257 | static void charlcd_init_work(struct work_struct *work) | ||
| 258 | { | ||
| 259 | struct charlcd *lcd = | ||
| 260 | container_of(work, struct charlcd, init_work.work); | ||
| 261 | |||
| 262 | charlcd_4bit_init(lcd); | ||
| 263 | } | ||
| 264 | |||
| 265 | static int __init charlcd_probe(struct platform_device *pdev) | ||
| 266 | { | ||
| 267 | int ret; | ||
| 268 | struct charlcd *lcd; | ||
| 269 | struct resource *res; | ||
| 270 | |||
| 271 | lcd = kzalloc(sizeof(struct charlcd), GFP_KERNEL); | ||
| 272 | if (!lcd) | ||
| 273 | return -ENOMEM; | ||
| 274 | |||
| 275 | lcd->dev = &pdev->dev; | ||
| 276 | |||
| 277 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 278 | if (!res) { | ||
| 279 | ret = -ENOENT; | ||
| 280 | goto out_no_resource; | ||
| 281 | } | ||
| 282 | lcd->phybase = res->start; | ||
| 283 | lcd->physize = resource_size(res); | ||
| 284 | |||
| 285 | if (request_mem_region(lcd->phybase, lcd->physize, | ||
| 286 | DRIVERNAME) == NULL) { | ||
| 287 | ret = -EBUSY; | ||
| 288 | goto out_no_memregion; | ||
| 289 | } | ||
| 290 | |||
| 291 | lcd->virtbase = ioremap(lcd->phybase, lcd->physize); | ||
| 292 | if (!lcd->virtbase) { | ||
| 293 | ret = -ENOMEM; | ||
| 294 | goto out_no_remap; | ||
| 295 | } | ||
| 296 | |||
| 297 | lcd->irq = platform_get_irq(pdev, 0); | ||
| 298 | /* If no IRQ is supplied, we'll survive without it */ | ||
| 299 | if (lcd->irq >= 0) { | ||
| 300 | if (request_irq(lcd->irq, charlcd_interrupt, IRQF_DISABLED, | ||
| 301 | DRIVERNAME, lcd)) { | ||
| 302 | ret = -EIO; | ||
| 303 | goto out_no_irq; | ||
| 304 | } | ||
| 305 | } | ||
| 306 | |||
| 307 | platform_set_drvdata(pdev, lcd); | ||
| 308 | |||
| 309 | /* | ||
| 310 | * Initialize the display in a delayed work, because | ||
| 311 | * it is VERY slow and would slow down the boot of the system. | ||
| 312 | */ | ||
| 313 | INIT_DELAYED_WORK(&lcd->init_work, charlcd_init_work); | ||
| 314 | schedule_delayed_work(&lcd->init_work, 0); | ||
| 315 | |||
| 316 | dev_info(&pdev->dev, "initalized ARM character LCD at %08x\n", | ||
| 317 | lcd->phybase); | ||
| 318 | |||
| 319 | return 0; | ||
| 320 | |||
| 321 | out_no_irq: | ||
| 322 | iounmap(lcd->virtbase); | ||
| 323 | out_no_remap: | ||
| 324 | platform_set_drvdata(pdev, NULL); | ||
| 325 | out_no_memregion: | ||
| 326 | release_mem_region(lcd->phybase, SZ_4K); | ||
| 327 | out_no_resource: | ||
| 328 | kfree(lcd); | ||
| 329 | return ret; | ||
| 330 | } | ||
| 331 | |||
| 332 | static int __exit charlcd_remove(struct platform_device *pdev) | ||
| 333 | { | ||
| 334 | struct charlcd *lcd = platform_get_drvdata(pdev); | ||
| 335 | |||
| 336 | if (lcd) { | ||
| 337 | free_irq(lcd->irq, lcd); | ||
| 338 | iounmap(lcd->virtbase); | ||
| 339 | release_mem_region(lcd->phybase, lcd->physize); | ||
| 340 | platform_set_drvdata(pdev, NULL); | ||
| 341 | kfree(lcd); | ||
| 342 | } | ||
| 343 | |||
| 344 | return 0; | ||
| 345 | } | ||
| 346 | |||
| 347 | static int charlcd_suspend(struct device *dev) | ||
| 348 | { | ||
| 349 | struct platform_device *pdev = to_platform_device(dev); | ||
| 350 | struct charlcd *lcd = platform_get_drvdata(pdev); | ||
| 351 | |||
| 352 | /* Power the display off */ | ||
| 353 | charlcd_4bit_command(lcd, HD_DISPCTRL); | ||
| 354 | return 0; | ||
| 355 | } | ||
| 356 | |||
| 357 | static int charlcd_resume(struct device *dev) | ||
| 358 | { | ||
| 359 | struct platform_device *pdev = to_platform_device(dev); | ||
| 360 | struct charlcd *lcd = platform_get_drvdata(pdev); | ||
| 361 | |||
| 362 | /* Turn the display back on */ | ||
| 363 | charlcd_4bit_command(lcd, HD_DISPCTRL | HD_DISPCTRL_ON); | ||
| 364 | return 0; | ||
| 365 | } | ||
| 366 | |||
| 367 | static const struct dev_pm_ops charlcd_pm_ops = { | ||
| 368 | .suspend = charlcd_suspend, | ||
| 369 | .resume = charlcd_resume, | ||
| 370 | }; | ||
| 371 | |||
| 372 | static struct platform_driver charlcd_driver = { | ||
| 373 | .driver = { | ||
| 374 | .name = DRIVERNAME, | ||
| 375 | .owner = THIS_MODULE, | ||
| 376 | .pm = &charlcd_pm_ops, | ||
| 377 | }, | ||
| 378 | .remove = __exit_p(charlcd_remove), | ||
| 379 | }; | ||
| 380 | |||
| 381 | static int __init charlcd_init(void) | ||
| 382 | { | ||
| 383 | return platform_driver_probe(&charlcd_driver, charlcd_probe); | ||
| 384 | } | ||
| 385 | |||
| 386 | static void __exit charlcd_exit(void) | ||
| 387 | { | ||
| 388 | platform_driver_unregister(&charlcd_driver); | ||
| 389 | } | ||
| 390 | |||
| 391 | module_init(charlcd_init); | ||
| 392 | module_exit(charlcd_exit); | ||
| 393 | |||
| 394 | MODULE_AUTHOR("Linus Walleij <triad@df.lth.se>"); | ||
| 395 | MODULE_DESCRIPTION("ARM Character LCD Driver"); | ||
| 396 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c new file mode 100644 index 000000000000..714c6b487313 --- /dev/null +++ b/drivers/misc/bh1780gli.c | |||
| @@ -0,0 +1,273 @@ | |||
| 1 | /* | ||
| 2 | * bh1780gli.c | ||
| 3 | * ROHM Ambient Light Sensor Driver | ||
| 4 | * | ||
| 5 | * Copyright (C) 2010 Texas Instruments | ||
| 6 | * Author: Hemanth V <hemanthv@ti.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify it | ||
| 9 | * under the terms of the GNU General Public License version 2 as published by | ||
| 10 | * the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
| 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 15 | * more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License along with | ||
| 18 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | #include <linux/i2c.h> | ||
| 21 | #include <linux/slab.h> | ||
| 22 | #include <linux/mutex.h> | ||
| 23 | #include <linux/platform_device.h> | ||
| 24 | #include <linux/delay.h> | ||
| 25 | |||
| 26 | #define BH1780_REG_CONTROL 0x80 | ||
| 27 | #define BH1780_REG_PARTID 0x8A | ||
| 28 | #define BH1780_REG_MANFID 0x8B | ||
| 29 | #define BH1780_REG_DLOW 0x8C | ||
| 30 | #define BH1780_REG_DHIGH 0x8D | ||
| 31 | |||
| 32 | #define BH1780_REVMASK (0xf) | ||
| 33 | #define BH1780_POWMASK (0x3) | ||
| 34 | #define BH1780_POFF (0x0) | ||
| 35 | #define BH1780_PON (0x3) | ||
| 36 | |||
| 37 | /* power on settling time in ms */ | ||
| 38 | #define BH1780_PON_DELAY 2 | ||
| 39 | |||
| 40 | struct bh1780_data { | ||
| 41 | struct i2c_client *client; | ||
| 42 | int power_state; | ||
| 43 | /* lock for sysfs operations */ | ||
| 44 | struct mutex lock; | ||
| 45 | }; | ||
| 46 | |||
| 47 | static int bh1780_write(struct bh1780_data *ddata, u8 reg, u8 val, char *msg) | ||
| 48 | { | ||
| 49 | int ret = i2c_smbus_write_byte_data(ddata->client, reg, val); | ||
| 50 | if (ret < 0) | ||
| 51 | dev_err(&ddata->client->dev, | ||
| 52 | "i2c_smbus_write_byte_data failed error %d\ | ||
| 53 | Register (%s)\n", ret, msg); | ||
| 54 | return ret; | ||
| 55 | } | ||
| 56 | |||
| 57 | static int bh1780_read(struct bh1780_data *ddata, u8 reg, char *msg) | ||
| 58 | { | ||
| 59 | int ret = i2c_smbus_read_byte_data(ddata->client, reg); | ||
| 60 | if (ret < 0) | ||
| 61 | dev_err(&ddata->client->dev, | ||
| 62 | "i2c_smbus_read_byte_data failed error %d\ | ||
| 63 | Register (%s)\n", ret, msg); | ||
| 64 | return ret; | ||
| 65 | } | ||
| 66 | |||
| 67 | static ssize_t bh1780_show_lux(struct device *dev, | ||
| 68 | struct device_attribute *attr, char *buf) | ||
| 69 | { | ||
| 70 | struct platform_device *pdev = to_platform_device(dev); | ||
| 71 | struct bh1780_data *ddata = platform_get_drvdata(pdev); | ||
| 72 | int lsb, msb; | ||
| 73 | |||
| 74 | lsb = bh1780_read(ddata, BH1780_REG_DLOW, "DLOW"); | ||
| 75 | if (lsb < 0) | ||
| 76 | return lsb; | ||
| 77 | |||
| 78 | msb = bh1780_read(ddata, BH1780_REG_DHIGH, "DHIGH"); | ||
| 79 | if (msb < 0) | ||
| 80 | return msb; | ||
| 81 | |||
| 82 | return sprintf(buf, "%d\n", (msb << 8) | lsb); | ||
| 83 | } | ||
| 84 | |||
| 85 | static ssize_t bh1780_show_power_state(struct device *dev, | ||
| 86 | struct device_attribute *attr, | ||
| 87 | char *buf) | ||
| 88 | { | ||
| 89 | struct platform_device *pdev = to_platform_device(dev); | ||
| 90 | struct bh1780_data *ddata = platform_get_drvdata(pdev); | ||
| 91 | int state; | ||
| 92 | |||
| 93 | state = bh1780_read(ddata, BH1780_REG_CONTROL, "CONTROL"); | ||
| 94 | if (state < 0) | ||
| 95 | return state; | ||
| 96 | |||
| 97 | return sprintf(buf, "%d\n", state & BH1780_POWMASK); | ||
| 98 | } | ||
| 99 | |||
| 100 | static ssize_t bh1780_store_power_state(struct device *dev, | ||
| 101 | struct device_attribute *attr, | ||
| 102 | const char *buf, size_t count) | ||
| 103 | { | ||
| 104 | struct platform_device *pdev = to_platform_device(dev); | ||
| 105 | struct bh1780_data *ddata = platform_get_drvdata(pdev); | ||
| 106 | unsigned long val; | ||
| 107 | int error; | ||
| 108 | |||
| 109 | error = strict_strtoul(buf, 0, &val); | ||
| 110 | if (error) | ||
| 111 | return error; | ||
| 112 | |||
| 113 | if (val < BH1780_POFF || val > BH1780_PON) | ||
| 114 | return -EINVAL; | ||
| 115 | |||
| 116 | mutex_lock(&ddata->lock); | ||
| 117 | |||
| 118 | error = bh1780_write(ddata, BH1780_REG_CONTROL, val, "CONTROL"); | ||
| 119 | if (error < 0) { | ||
| 120 | mutex_unlock(&ddata->lock); | ||
| 121 | return error; | ||
| 122 | } | ||
| 123 | |||
| 124 | msleep(BH1780_PON_DELAY); | ||
| 125 | ddata->power_state = val; | ||
| 126 | mutex_unlock(&ddata->lock); | ||
| 127 | |||
| 128 | return count; | ||
| 129 | } | ||
| 130 | |||
| 131 | static DEVICE_ATTR(lux, S_IRUGO, bh1780_show_lux, NULL); | ||
| 132 | |||
| 133 | static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO, | ||
| 134 | bh1780_show_power_state, bh1780_store_power_state); | ||
| 135 | |||
| 136 | static struct attribute *bh1780_attributes[] = { | ||
| 137 | &dev_attr_power_state.attr, | ||
| 138 | &dev_attr_lux.attr, | ||
| 139 | NULL | ||
| 140 | }; | ||
| 141 | |||
| 142 | static const struct attribute_group bh1780_attr_group = { | ||
| 143 | .attrs = bh1780_attributes, | ||
| 144 | }; | ||
| 145 | |||
| 146 | static int __devinit bh1780_probe(struct i2c_client *client, | ||
| 147 | const struct i2c_device_id *id) | ||
| 148 | { | ||
| 149 | int ret; | ||
| 150 | struct bh1780_data *ddata = NULL; | ||
| 151 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | ||
| 152 | |||
| 153 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) { | ||
| 154 | ret = -EIO; | ||
| 155 | goto err_op_failed; | ||
| 156 | } | ||
| 157 | |||
| 158 | ddata = kzalloc(sizeof(struct bh1780_data), GFP_KERNEL); | ||
| 159 | if (ddata == NULL) { | ||
| 160 | ret = -ENOMEM; | ||
| 161 | goto err_op_failed; | ||
| 162 | } | ||
| 163 | |||
| 164 | ddata->client = client; | ||
| 165 | i2c_set_clientdata(client, ddata); | ||
| 166 | |||
| 167 | ret = bh1780_read(ddata, BH1780_REG_PARTID, "PART ID"); | ||
| 168 | if (ret < 0) | ||
| 169 | goto err_op_failed; | ||
| 170 | |||
| 171 | dev_info(&client->dev, "Ambient Light Sensor, Rev : %d\n", | ||
| 172 | (ret & BH1780_REVMASK)); | ||
| 173 | |||
| 174 | mutex_init(&ddata->lock); | ||
| 175 | |||
| 176 | ret = sysfs_create_group(&client->dev.kobj, &bh1780_attr_group); | ||
| 177 | if (ret) | ||
| 178 | goto err_op_failed; | ||
| 179 | |||
| 180 | return 0; | ||
| 181 | |||
| 182 | err_op_failed: | ||
| 183 | kfree(ddata); | ||
| 184 | return ret; | ||
| 185 | } | ||
| 186 | |||
| 187 | static int __devexit bh1780_remove(struct i2c_client *client) | ||
| 188 | { | ||
| 189 | struct bh1780_data *ddata; | ||
| 190 | |||
| 191 | ddata = i2c_get_clientdata(client); | ||
| 192 | sysfs_remove_group(&client->dev.kobj, &bh1780_attr_group); | ||
| 193 | i2c_set_clientdata(client, NULL); | ||
| 194 | kfree(ddata); | ||
| 195 | |||
| 196 | return 0; | ||
| 197 | } | ||
| 198 | |||
| 199 | #ifdef CONFIG_PM | ||
| 200 | static int bh1780_suspend(struct i2c_client *client, pm_message_t mesg) | ||
| 201 | { | ||
| 202 | struct bh1780_data *ddata; | ||
| 203 | int state, ret; | ||
| 204 | |||
| 205 | ddata = i2c_get_clientdata(client); | ||
| 206 | state = bh1780_read(ddata, BH1780_REG_CONTROL, "CONTROL"); | ||
| 207 | if (state < 0) | ||
| 208 | return state; | ||
| 209 | |||
| 210 | ddata->power_state = state & BH1780_POWMASK; | ||
| 211 | |||
| 212 | ret = bh1780_write(ddata, BH1780_REG_CONTROL, BH1780_POFF, | ||
| 213 | "CONTROL"); | ||
| 214 | |||
| 215 | if (ret < 0) | ||
| 216 | return ret; | ||
| 217 | |||
| 218 | return 0; | ||
| 219 | } | ||
| 220 | |||
| 221 | static int bh1780_resume(struct i2c_client *client) | ||
| 222 | { | ||
| 223 | struct bh1780_data *ddata; | ||
| 224 | int state, ret; | ||
| 225 | |||
| 226 | ddata = i2c_get_clientdata(client); | ||
| 227 | state = ddata->power_state; | ||
| 228 | |||
| 229 | ret = bh1780_write(ddata, BH1780_REG_CONTROL, state, | ||
| 230 | "CONTROL"); | ||
| 231 | |||
| 232 | if (ret < 0) | ||
| 233 | return ret; | ||
| 234 | |||
| 235 | return 0; | ||
| 236 | } | ||
| 237 | #else | ||
| 238 | #define bh1780_suspend NULL | ||
| 239 | #define bh1780_resume NULL | ||
| 240 | #endif /* CONFIG_PM */ | ||
| 241 | |||
| 242 | static const struct i2c_device_id bh1780_id[] = { | ||
| 243 | { "bh1780", 0 }, | ||
| 244 | { }, | ||
| 245 | }; | ||
| 246 | |||
| 247 | static struct i2c_driver bh1780_driver = { | ||
| 248 | .probe = bh1780_probe, | ||
| 249 | .remove = bh1780_remove, | ||
| 250 | .id_table = bh1780_id, | ||
| 251 | .suspend = bh1780_suspend, | ||
| 252 | .resume = bh1780_resume, | ||
| 253 | .driver = { | ||
| 254 | .name = "bh1780" | ||
| 255 | }, | ||
| 256 | }; | ||
| 257 | |||
| 258 | static int __init bh1780_init(void) | ||
| 259 | { | ||
| 260 | return i2c_add_driver(&bh1780_driver); | ||
| 261 | } | ||
| 262 | |||
| 263 | static void __exit bh1780_exit(void) | ||
| 264 | { | ||
| 265 | i2c_del_driver(&bh1780_driver); | ||
| 266 | } | ||
| 267 | |||
| 268 | module_init(bh1780_init) | ||
| 269 | module_exit(bh1780_exit) | ||
| 270 | |||
| 271 | MODULE_DESCRIPTION("BH1780GLI Ambient Light Sensor Driver"); | ||
| 272 | MODULE_LICENSE("GPL"); | ||
| 273 | MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>"); | ||
diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c new file mode 100644 index 000000000000..63ee4c1a5315 --- /dev/null +++ b/drivers/misc/bmp085.c | |||
| @@ -0,0 +1,482 @@ | |||
| 1 | /* Copyright (c) 2010 Christoph Mair <christoph.mair@gmail.com> | ||
| 2 | |||
| 3 | This driver supports the bmp085 digital barometric pressure | ||
| 4 | and temperature sensor from Bosch Sensortec. The datasheet | ||
| 5 | is avaliable from their website: | ||
| 6 | http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP085-DS000-05.pdf | ||
| 7 | |||
| 8 | A pressure measurement is issued by reading from pressure0_input. | ||
| 9 | The return value ranges from 30000 to 110000 pascal with a resulution | ||
| 10 | of 1 pascal (0.01 millibar) which enables measurements from 9000m above | ||
| 11 | to 500m below sea level. | ||
| 12 | |||
| 13 | The temperature can be read from temp0_input. Values range from | ||
| 14 | -400 to 850 representing the ambient temperature in degree celsius | ||
| 15 | multiplied by 10.The resolution is 0.1 celsius. | ||
| 16 | |||
| 17 | Because ambient pressure is temperature dependent, a temperature | ||
| 18 | measurement will be executed automatically even if the user is reading | ||
| 19 | from pressure0_input. This happens if the last temperature measurement | ||
| 20 | has been executed more then one second ago. | ||
| 21 | |||
| 22 | To decrease RMS noise from pressure measurements, the bmp085 can | ||
| 23 | autonomously calculate the average of up to eight samples. This is | ||
| 24 | set up by writing to the oversampling sysfs file. Accepted values | ||
| 25 | are 0, 1, 2 and 3. 2^x when x is the value written to this file | ||
| 26 | specifies the number of samples used to calculate the ambient pressure. | ||
| 27 | RMS noise is specified with six pascal (without averaging) and decreases | ||
| 28 | down to 3 pascal when using an oversampling setting of 3. | ||
| 29 | |||
| 30 | This program is free software; you can redistribute it and/or modify | ||
| 31 | it under the terms of the GNU General Public License as published by | ||
| 32 | the Free Software Foundation; either version 2 of the License, or | ||
| 33 | (at your option) any later version. | ||
| 34 | |||
| 35 | This program is distributed in the hope that it will be useful, | ||
| 36 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 37 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 38 | GNU General Public License for more details. | ||
| 39 | |||
| 40 | You should have received a copy of the GNU General Public License | ||
| 41 | along with this program; if not, write to the Free Software | ||
| 42 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 43 | */ | ||
| 44 | |||
| 45 | |||
| 46 | #include <linux/module.h> | ||
| 47 | #include <linux/init.h> | ||
| 48 | #include <linux/i2c.h> | ||
| 49 | #include <linux/slab.h> | ||
| 50 | #include <linux/delay.h> | ||
| 51 | |||
| 52 | |||
| 53 | #define BMP085_I2C_ADDRESS 0x77 | ||
| 54 | #define BMP085_CHIP_ID 0x55 | ||
| 55 | |||
| 56 | #define BMP085_CALIBRATION_DATA_START 0xAA | ||
| 57 | #define BMP085_CALIBRATION_DATA_LENGTH 11 /* 16 bit values */ | ||
| 58 | #define BMP085_CHIP_ID_REG 0xD0 | ||
| 59 | #define BMP085_VERSION_REG 0xD1 | ||
| 60 | #define BMP085_CTRL_REG 0xF4 | ||
| 61 | #define BMP085_TEMP_MEASUREMENT 0x2E | ||
| 62 | #define BMP085_PRESSURE_MEASUREMENT 0x34 | ||
| 63 | #define BMP085_CONVERSION_REGISTER_MSB 0xF6 | ||
| 64 | #define BMP085_CONVERSION_REGISTER_LSB 0xF7 | ||
| 65 | #define BMP085_CONVERSION_REGISTER_XLSB 0xF8 | ||
| 66 | #define BMP085_TEMP_CONVERSION_TIME 5 | ||
| 67 | |||
| 68 | #define BMP085_CLIENT_NAME "bmp085" | ||
| 69 | |||
| 70 | |||
| 71 | static const unsigned short normal_i2c[] = { BMP085_I2C_ADDRESS, | ||
| 72 | I2C_CLIENT_END }; | ||
| 73 | |||
| 74 | struct bmp085_calibration_data { | ||
| 75 | s16 AC1, AC2, AC3; | ||
| 76 | u16 AC4, AC5, AC6; | ||
| 77 | s16 B1, B2; | ||
| 78 | s16 MB, MC, MD; | ||
| 79 | }; | ||
| 80 | |||
| 81 | |||
| 82 | /* Each client has this additional data */ | ||
| 83 | struct bmp085_data { | ||
| 84 | struct i2c_client *client; | ||
| 85 | struct mutex lock; | ||
| 86 | struct bmp085_calibration_data calibration; | ||
| 87 | u32 raw_temperature; | ||
| 88 | u32 raw_pressure; | ||
| 89 | unsigned char oversampling_setting; | ||
| 90 | u32 last_temp_measurement; | ||
| 91 | s32 b6; /* calculated temperature correction coefficient */ | ||
| 92 | }; | ||
| 93 | |||
| 94 | |||
| 95 | static s32 bmp085_read_calibration_data(struct i2c_client *client) | ||
| 96 | { | ||
| 97 | u16 tmp[BMP085_CALIBRATION_DATA_LENGTH]; | ||
| 98 | struct bmp085_data *data = i2c_get_clientdata(client); | ||
| 99 | struct bmp085_calibration_data *cali = &(data->calibration); | ||
| 100 | s32 status = i2c_smbus_read_i2c_block_data(client, | ||
| 101 | BMP085_CALIBRATION_DATA_START, | ||
| 102 | BMP085_CALIBRATION_DATA_LENGTH*sizeof(u16), | ||
| 103 | (u8 *)tmp); | ||
| 104 | if (status < 0) | ||
| 105 | return status; | ||
| 106 | |||
| 107 | if (status != BMP085_CALIBRATION_DATA_LENGTH*sizeof(u16)) | ||
| 108 | return -EIO; | ||
| 109 | |||
| 110 | cali->AC1 = be16_to_cpu(tmp[0]); | ||
| 111 | cali->AC2 = be16_to_cpu(tmp[1]); | ||
| 112 | cali->AC3 = be16_to_cpu(tmp[2]); | ||
| 113 | cali->AC4 = be16_to_cpu(tmp[3]); | ||
| 114 | cali->AC5 = be16_to_cpu(tmp[4]); | ||
| 115 | cali->AC6 = be16_to_cpu(tmp[5]); | ||
| 116 | cali->B1 = be16_to_cpu(tmp[6]); | ||
| 117 | cali->B2 = be16_to_cpu(tmp[7]); | ||
| 118 | cali->MB = be16_to_cpu(tmp[8]); | ||
| 119 | cali->MC = be16_to_cpu(tmp[9]); | ||
| 120 | cali->MD = be16_to_cpu(tmp[10]); | ||
| 121 | return 0; | ||
| 122 | } | ||
| 123 | |||
| 124 | |||
| 125 | static s32 bmp085_update_raw_temperature(struct bmp085_data *data) | ||
| 126 | { | ||
| 127 | u16 tmp; | ||
| 128 | s32 status; | ||
| 129 | |||
| 130 | mutex_lock(&data->lock); | ||
| 131 | status = i2c_smbus_write_byte_data(data->client, BMP085_CTRL_REG, | ||
| 132 | BMP085_TEMP_MEASUREMENT); | ||
| 133 | if (status != 0) { | ||
| 134 | dev_err(&data->client->dev, | ||
| 135 | "Error while requesting temperature measurement.\n"); | ||
| 136 | goto exit; | ||
| 137 | } | ||
| 138 | msleep(BMP085_TEMP_CONVERSION_TIME); | ||
| 139 | |||
| 140 | status = i2c_smbus_read_i2c_block_data(data->client, | ||
| 141 | BMP085_CONVERSION_REGISTER_MSB, sizeof(tmp), (u8 *)&tmp); | ||
| 142 | if (status < 0) | ||
| 143 | goto exit; | ||
| 144 | if (status != sizeof(tmp)) { | ||
| 145 | dev_err(&data->client->dev, | ||
| 146 | "Error while reading temperature measurement result\n"); | ||
| 147 | status = -EIO; | ||
| 148 | goto exit; | ||
| 149 | } | ||
| 150 | data->raw_temperature = be16_to_cpu(tmp); | ||
| 151 | data->last_temp_measurement = jiffies; | ||
| 152 | status = 0; /* everything ok, return 0 */ | ||
| 153 | |||
| 154 | exit: | ||
| 155 | mutex_unlock(&data->lock); | ||
| 156 | return status; | ||
| 157 | } | ||
| 158 | |||
| 159 | static s32 bmp085_update_raw_pressure(struct bmp085_data *data) | ||
| 160 | { | ||
| 161 | u32 tmp = 0; | ||
| 162 | s32 status; | ||
| 163 | |||
| 164 | mutex_lock(&data->lock); | ||
| 165 | status = i2c_smbus_write_byte_data(data->client, BMP085_CTRL_REG, | ||
| 166 | BMP085_PRESSURE_MEASUREMENT + (data->oversampling_setting<<6)); | ||
| 167 | if (status != 0) { | ||
| 168 | dev_err(&data->client->dev, | ||
| 169 | "Error while requesting pressure measurement.\n"); | ||
| 170 | goto exit; | ||
| 171 | } | ||
| 172 | |||
| 173 | /* wait for the end of conversion */ | ||
| 174 | msleep(2+(3 << data->oversampling_setting)); | ||
| 175 | |||
| 176 | /* copy data into a u32 (4 bytes), but skip the first byte. */ | ||
| 177 | status = i2c_smbus_read_i2c_block_data(data->client, | ||
| 178 | BMP085_CONVERSION_REGISTER_MSB, 3, ((u8 *)&tmp)+1); | ||
| 179 | if (status < 0) | ||
| 180 | goto exit; | ||
| 181 | if (status != 3) { | ||
| 182 | dev_err(&data->client->dev, | ||
| 183 | "Error while reading pressure measurement results\n"); | ||
| 184 | status = -EIO; | ||
| 185 | goto exit; | ||
| 186 | } | ||
| 187 | data->raw_pressure = be32_to_cpu((tmp)); | ||
| 188 | data->raw_pressure >>= (8-data->oversampling_setting); | ||
| 189 | status = 0; /* everything ok, return 0 */ | ||
| 190 | |||
| 191 | exit: | ||
| 192 | mutex_unlock(&data->lock); | ||
| 193 | return status; | ||
| 194 | } | ||
| 195 | |||
| 196 | |||
| 197 | /* | ||
| 198 | * This function starts the temperature measurement and returns the value | ||
| 199 | * in tenth of a degree celsius. | ||
| 200 | */ | ||
| 201 | static s32 bmp085_get_temperature(struct bmp085_data *data, int *temperature) | ||
| 202 | { | ||
| 203 | struct bmp085_calibration_data *cali = &data->calibration; | ||
| 204 | long x1, x2; | ||
| 205 | int status; | ||
| 206 | |||
| 207 | status = bmp085_update_raw_temperature(data); | ||
| 208 | if (status != 0) | ||
| 209 | goto exit; | ||
| 210 | |||
| 211 | x1 = ((data->raw_temperature - cali->AC6) * cali->AC5) >> 15; | ||
| 212 | x2 = (cali->MC << 11) / (x1 + cali->MD); | ||
| 213 | data->b6 = x1 + x2 - 4000; | ||
| 214 | /* if NULL just update b6. Used for pressure only measurements */ | ||
| 215 | if (temperature != NULL) | ||
| 216 | *temperature = (x1+x2+8) >> 4; | ||
| 217 | |||
| 218 | exit: | ||
| 219 | return status;; | ||
| 220 | } | ||
| 221 | |||
| 222 | /* | ||
| 223 | * This function starts the pressure measurement and returns the value | ||
| 224 | * in millibar. Since the pressure depends on the ambient temperature, | ||
| 225 | * a temperature measurement is executed if the last known value is older | ||
| 226 | * than one second. | ||
| 227 | */ | ||
| 228 | static s32 bmp085_get_pressure(struct bmp085_data *data, int *pressure) | ||
| 229 | { | ||
| 230 | struct bmp085_calibration_data *cali = &data->calibration; | ||
| 231 | s32 x1, x2, x3, b3; | ||
| 232 | u32 b4, b7; | ||
| 233 | s32 p; | ||
| 234 | int status; | ||
| 235 | |||
| 236 | /* alt least every second force an update of the ambient temperature */ | ||
| 237 | if (data->last_temp_measurement + 1*HZ < jiffies) { | ||
| 238 | status = bmp085_get_temperature(data, NULL); | ||
| 239 | if (status != 0) | ||
| 240 | goto exit; | ||
| 241 | } | ||
| 242 | |||
| 243 | status = bmp085_update_raw_pressure(data); | ||
| 244 | if (status != 0) | ||
| 245 | goto exit; | ||
| 246 | |||
| 247 | x1 = (data->b6 * data->b6) >> 12; | ||
| 248 | x1 *= cali->B2; | ||
| 249 | x1 >>= 11; | ||
| 250 | |||
| 251 | x2 = cali->AC2 * data->b6; | ||
| 252 | x2 >>= 11; | ||
| 253 | |||
| 254 | x3 = x1 + x2; | ||
| 255 | |||
| 256 | b3 = (((((s32)cali->AC1) * 4 + x3) << data->oversampling_setting) + 2); | ||
| 257 | b3 >>= 2; | ||
| 258 | |||
| 259 | x1 = (cali->AC3 * data->b6) >> 13; | ||
| 260 | x2 = (cali->B1 * ((data->b6 * data->b6) >> 12)) >> 16; | ||
| 261 | x3 = (x1 + x2 + 2) >> 2; | ||
| 262 | b4 = (cali->AC4 * (u32)(x3 + 32768)) >> 15; | ||
| 263 | |||
| 264 | b7 = ((u32)data->raw_pressure - b3) * | ||
| 265 | (50000 >> data->oversampling_setting); | ||
| 266 | p = ((b7 < 0x80000000) ? ((b7 << 1) / b4) : ((b7 / b4) * 2)); | ||
| 267 | |||
| 268 | x1 = p >> 8; | ||
| 269 | x1 *= x1; | ||
| 270 | x1 = (x1 * 3038) >> 16; | ||
| 271 | x2 = (-7357 * p) >> 16; | ||
| 272 | p += (x1 + x2 + 3791) >> 4; | ||
| 273 | |||
| 274 | *pressure = p; | ||
| 275 | |||
| 276 | exit: | ||
| 277 | return status; | ||
| 278 | } | ||
| 279 | |||
| 280 | /* | ||
| 281 | * This function sets the chip-internal oversampling. Valid values are 0..3. | ||
| 282 | * The chip will use 2^oversampling samples for internal averaging. | ||
| 283 | * This influences the measurement time and the accuracy; larger values | ||
| 284 | * increase both. The datasheet gives on overview on how measurement time, | ||
| 285 | * accuracy and noise correlate. | ||
| 286 | */ | ||
| 287 | static void bmp085_set_oversampling(struct bmp085_data *data, | ||
| 288 | unsigned char oversampling) | ||
| 289 | { | ||
| 290 | if (oversampling > 3) | ||
| 291 | oversampling = 3; | ||
| 292 | data->oversampling_setting = oversampling; | ||
| 293 | } | ||
| 294 | |||
| 295 | /* | ||
| 296 | * Returns the currently selected oversampling. Range: 0..3 | ||
| 297 | */ | ||
| 298 | static unsigned char bmp085_get_oversampling(struct bmp085_data *data) | ||
| 299 | { | ||
| 300 | return data->oversampling_setting; | ||
| 301 | } | ||
| 302 | |||
| 303 | /* sysfs callbacks */ | ||
| 304 | static ssize_t set_oversampling(struct device *dev, | ||
| 305 | struct device_attribute *attr, | ||
| 306 | const char *buf, size_t count) | ||
| 307 | { | ||
| 308 | struct i2c_client *client = to_i2c_client(dev); | ||
| 309 | struct bmp085_data *data = i2c_get_clientdata(client); | ||
| 310 | unsigned long oversampling; | ||
| 311 | int success = strict_strtoul(buf, 10, &oversampling); | ||
| 312 | if (success == 0) { | ||
| 313 | bmp085_set_oversampling(data, oversampling); | ||
| 314 | return count; | ||
| 315 | } | ||
| 316 | return success; | ||
| 317 | } | ||
| 318 | |||
| 319 | static ssize_t show_oversampling(struct device *dev, | ||
| 320 | struct device_attribute *attr, char *buf) | ||
| 321 | { | ||
| 322 | struct i2c_client *client = to_i2c_client(dev); | ||
| 323 | struct bmp085_data *data = i2c_get_clientdata(client); | ||
| 324 | return sprintf(buf, "%u\n", bmp085_get_oversampling(data)); | ||
| 325 | } | ||
| 326 | static DEVICE_ATTR(oversampling, S_IWUSR | S_IRUGO, | ||
| 327 | show_oversampling, set_oversampling); | ||
| 328 | |||
| 329 | |||
| 330 | static ssize_t show_temperature(struct device *dev, | ||
| 331 | struct device_attribute *attr, char *buf) | ||
| 332 | { | ||
| 333 | int temperature; | ||
| 334 | int status; | ||
| 335 | struct i2c_client *client = to_i2c_client(dev); | ||
| 336 | struct bmp085_data *data = i2c_get_clientdata(client); | ||
| 337 | |||
| 338 | status = bmp085_get_temperature(data, &temperature); | ||
| 339 | if (status != 0) | ||
| 340 | return status; | ||
| 341 | else | ||
| 342 | return sprintf(buf, "%d\n", temperature); | ||
| 343 | } | ||
| 344 | static DEVICE_ATTR(temp0_input, S_IRUGO, show_temperature, NULL); | ||
| 345 | |||
| 346 | |||
| 347 | static ssize_t show_pressure(struct device *dev, | ||
| 348 | struct device_attribute *attr, char *buf) | ||
| 349 | { | ||
| 350 | int pressure; | ||
| 351 | int status; | ||
| 352 | struct i2c_client *client = to_i2c_client(dev); | ||
| 353 | struct bmp085_data *data = i2c_get_clientdata(client); | ||
| 354 | |||
| 355 | status = bmp085_get_pressure(data, &pressure); | ||
| 356 | if (status != 0) | ||
| 357 | return status; | ||
| 358 | else | ||
| 359 | return sprintf(buf, "%d\n", pressure); | ||
| 360 | } | ||
| 361 | static DEVICE_ATTR(pressure0_input, S_IRUGO, show_pressure, NULL); | ||
| 362 | |||
| 363 | |||
| 364 | static struct attribute *bmp085_attributes[] = { | ||
| 365 | &dev_attr_temp0_input.attr, | ||
| 366 | &dev_attr_pressure0_input.attr, | ||
| 367 | &dev_attr_oversampling.attr, | ||
| 368 | NULL | ||
| 369 | }; | ||
| 370 | |||
| 371 | static const struct attribute_group bmp085_attr_group = { | ||
| 372 | .attrs = bmp085_attributes, | ||
| 373 | }; | ||
| 374 | |||
| 375 | static int bmp085_detect(struct i2c_client *client, struct i2c_board_info *info) | ||
| 376 | { | ||
| 377 | if (client->addr != BMP085_I2C_ADDRESS) | ||
| 378 | return -ENODEV; | ||
| 379 | |||
| 380 | if (i2c_smbus_read_byte_data(client, BMP085_CHIP_ID_REG) != BMP085_CHIP_ID) | ||
| 381 | return -ENODEV; | ||
| 382 | |||
| 383 | return 0; | ||
| 384 | } | ||
| 385 | |||
| 386 | static int bmp085_init_client(struct i2c_client *client) | ||
| 387 | { | ||
| 388 | unsigned char version; | ||
| 389 | int status; | ||
| 390 | struct bmp085_data *data = i2c_get_clientdata(client); | ||
| 391 | data->client = client; | ||
| 392 | status = bmp085_read_calibration_data(client); | ||
| 393 | if (status != 0) | ||
| 394 | goto exit; | ||
| 395 | version = i2c_smbus_read_byte_data(client, BMP085_VERSION_REG); | ||
| 396 | data->last_temp_measurement = 0; | ||
| 397 | data->oversampling_setting = 3; | ||
| 398 | mutex_init(&data->lock); | ||
| 399 | dev_info(&data->client->dev, "BMP085 ver. %d.%d found.\n", | ||
| 400 | (version & 0x0F), (version & 0xF0) >> 4); | ||
| 401 | exit: | ||
| 402 | return status; | ||
| 403 | } | ||
| 404 | |||
| 405 | static int bmp085_probe(struct i2c_client *client, | ||
| 406 | const struct i2c_device_id *id) | ||
| 407 | { | ||
| 408 | struct bmp085_data *data; | ||
| 409 | int err = 0; | ||
| 410 | |||
| 411 | data = kzalloc(sizeof(struct bmp085_data), GFP_KERNEL); | ||
| 412 | if (!data) { | ||
| 413 | err = -ENOMEM; | ||
| 414 | goto exit; | ||
| 415 | } | ||
| 416 | |||
| 417 | /* default settings after POR */ | ||
| 418 | data->oversampling_setting = 0x00; | ||
| 419 | |||
| 420 | i2c_set_clientdata(client, data); | ||
| 421 | |||
| 422 | /* Initialize the BMP085 chip */ | ||
| 423 | err = bmp085_init_client(client); | ||
| 424 | if (err != 0) | ||
| 425 | goto exit_free; | ||
| 426 | |||
| 427 | /* Register sysfs hooks */ | ||
| 428 | err = sysfs_create_group(&client->dev.kobj, &bmp085_attr_group); | ||
| 429 | if (err) | ||
| 430 | goto exit_free; | ||
| 431 | |||
| 432 | dev_info(&data->client->dev, "Succesfully initialized bmp085!\n"); | ||
| 433 | goto exit; | ||
| 434 | |||
| 435 | exit_free: | ||
| 436 | kfree(data); | ||
| 437 | exit: | ||
| 438 | return err; | ||
| 439 | } | ||
| 440 | |||
| 441 | static int bmp085_remove(struct i2c_client *client) | ||
| 442 | { | ||
| 443 | sysfs_remove_group(&client->dev.kobj, &bmp085_attr_group); | ||
| 444 | kfree(i2c_get_clientdata(client)); | ||
| 445 | return 0; | ||
| 446 | } | ||
| 447 | |||
| 448 | static const struct i2c_device_id bmp085_id[] = { | ||
| 449 | { "bmp085", 0 }, | ||
| 450 | { } | ||
| 451 | }; | ||
| 452 | |||
| 453 | static struct i2c_driver bmp085_driver = { | ||
| 454 | .driver = { | ||
| 455 | .owner = THIS_MODULE, | ||
| 456 | .name = "bmp085" | ||
| 457 | }, | ||
| 458 | .id_table = bmp085_id, | ||
| 459 | .probe = bmp085_probe, | ||
| 460 | .remove = bmp085_remove, | ||
| 461 | |||
| 462 | .detect = bmp085_detect, | ||
| 463 | .address_list = normal_i2c | ||
| 464 | }; | ||
| 465 | |||
| 466 | static int __init bmp085_init(void) | ||
| 467 | { | ||
| 468 | return i2c_add_driver(&bmp085_driver); | ||
| 469 | } | ||
| 470 | |||
| 471 | static void __exit bmp085_exit(void) | ||
| 472 | { | ||
| 473 | i2c_del_driver(&bmp085_driver); | ||
| 474 | } | ||
| 475 | |||
| 476 | |||
| 477 | MODULE_AUTHOR("Christoph Mair <christoph.mair@gmail.com"); | ||
| 478 | MODULE_DESCRIPTION("BMP085 driver"); | ||
| 479 | MODULE_LICENSE("GPL"); | ||
| 480 | |||
| 481 | module_init(bmp085_init); | ||
| 482 | module_exit(bmp085_exit); | ||
diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c index 2d44b3300104..6f6218061b0d 100644 --- a/drivers/misc/cs5535-mfgpt.c +++ b/drivers/misc/cs5535-mfgpt.c | |||
| @@ -211,6 +211,17 @@ EXPORT_SYMBOL_GPL(cs5535_mfgpt_alloc_timer); | |||
| 211 | */ | 211 | */ |
| 212 | void cs5535_mfgpt_free_timer(struct cs5535_mfgpt_timer *timer) | 212 | void cs5535_mfgpt_free_timer(struct cs5535_mfgpt_timer *timer) |
| 213 | { | 213 | { |
| 214 | unsigned long flags; | ||
| 215 | uint16_t val; | ||
| 216 | |||
| 217 | /* timer can be made available again only if never set up */ | ||
| 218 | val = cs5535_mfgpt_read(timer, MFGPT_REG_SETUP); | ||
| 219 | if (!(val & MFGPT_SETUP_SETUP)) { | ||
| 220 | spin_lock_irqsave(&timer->chip->lock, flags); | ||
| 221 | __set_bit(timer->nr, timer->chip->avail); | ||
| 222 | spin_unlock_irqrestore(&timer->chip->lock, flags); | ||
| 223 | } | ||
| 224 | |||
| 214 | kfree(timer); | 225 | kfree(timer); |
| 215 | } | 226 | } |
| 216 | EXPORT_SYMBOL_GPL(cs5535_mfgpt_free_timer); | 227 | EXPORT_SYMBOL_GPL(cs5535_mfgpt_free_timer); |
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 48c84a58163e..00e5fcac8fdf 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c | |||
| @@ -285,8 +285,11 @@ enclosure_component_register(struct enclosure_device *edev, | |||
| 285 | cdev->groups = enclosure_groups; | 285 | cdev->groups = enclosure_groups; |
| 286 | 286 | ||
| 287 | err = device_register(cdev); | 287 | err = device_register(cdev); |
| 288 | if (err) | 288 | if (err) { |
| 289 | ERR_PTR(err); | 289 | ecomp->number = -1; |
| 290 | put_device(cdev); | ||
| 291 | return ERR_PTR(err); | ||
| 292 | } | ||
| 290 | 293 | ||
| 291 | return ecomp; | 294 | return ecomp; |
| 292 | } | 295 | } |
diff --git a/drivers/misc/hmc6352.c b/drivers/misc/hmc6352.c new file mode 100644 index 000000000000..234bfcaf2099 --- /dev/null +++ b/drivers/misc/hmc6352.c | |||
| @@ -0,0 +1,166 @@ | |||
| 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"); | ||
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index 98ad0120aa9b..557a8c2a7336 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c | |||
| @@ -256,7 +256,8 @@ static void ilo_ccb_close(struct pci_dev *pdev, struct ccb_data *data) | |||
| 256 | 256 | ||
| 257 | static int ilo_ccb_setup(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) | 257 | static int ilo_ccb_setup(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) |
| 258 | { | 258 | { |
| 259 | char *dma_va, *dma_pa; | 259 | char *dma_va; |
| 260 | dma_addr_t dma_pa; | ||
| 260 | struct ccb *driver_ccb, *ilo_ccb; | 261 | struct ccb *driver_ccb, *ilo_ccb; |
| 261 | 262 | ||
| 262 | driver_ccb = &data->driver_ccb; | 263 | driver_ccb = &data->driver_ccb; |
| @@ -272,12 +273,12 @@ static int ilo_ccb_setup(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) | |||
| 272 | return -ENOMEM; | 273 | return -ENOMEM; |
| 273 | 274 | ||
| 274 | dma_va = (char *)data->dma_va; | 275 | dma_va = (char *)data->dma_va; |
| 275 | dma_pa = (char *)data->dma_pa; | 276 | dma_pa = data->dma_pa; |
| 276 | 277 | ||
| 277 | memset(dma_va, 0, data->dma_size); | 278 | memset(dma_va, 0, data->dma_size); |
| 278 | 279 | ||
| 279 | dma_va = (char *)roundup((unsigned long)dma_va, ILO_START_ALIGN); | 280 | dma_va = (char *)roundup((unsigned long)dma_va, ILO_START_ALIGN); |
| 280 | dma_pa = (char *)roundup((unsigned long)dma_pa, ILO_START_ALIGN); | 281 | dma_pa = roundup(dma_pa, ILO_START_ALIGN); |
| 281 | 282 | ||
| 282 | /* | 283 | /* |
| 283 | * Create two ccb's, one with virt addrs, one with phys addrs. | 284 | * Create two ccb's, one with virt addrs, one with phys addrs. |
| @@ -288,26 +289,26 @@ static int ilo_ccb_setup(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) | |||
| 288 | 289 | ||
| 289 | fifo_setup(dma_va, NR_QENTRY); | 290 | fifo_setup(dma_va, NR_QENTRY); |
| 290 | driver_ccb->ccb_u1.send_fifobar = dma_va + FIFOHANDLESIZE; | 291 | driver_ccb->ccb_u1.send_fifobar = dma_va + FIFOHANDLESIZE; |
| 291 | ilo_ccb->ccb_u1.send_fifobar = dma_pa + FIFOHANDLESIZE; | 292 | ilo_ccb->ccb_u1.send_fifobar_pa = dma_pa + FIFOHANDLESIZE; |
| 292 | dma_va += fifo_sz(NR_QENTRY); | 293 | dma_va += fifo_sz(NR_QENTRY); |
| 293 | dma_pa += fifo_sz(NR_QENTRY); | 294 | dma_pa += fifo_sz(NR_QENTRY); |
| 294 | 295 | ||
| 295 | dma_va = (char *)roundup((unsigned long)dma_va, ILO_CACHE_SZ); | 296 | dma_va = (char *)roundup((unsigned long)dma_va, ILO_CACHE_SZ); |
| 296 | dma_pa = (char *)roundup((unsigned long)dma_pa, ILO_CACHE_SZ); | 297 | dma_pa = roundup(dma_pa, ILO_CACHE_SZ); |
| 297 | 298 | ||
| 298 | fifo_setup(dma_va, NR_QENTRY); | 299 | fifo_setup(dma_va, NR_QENTRY); |
| 299 | driver_ccb->ccb_u3.recv_fifobar = dma_va + FIFOHANDLESIZE; | 300 | driver_ccb->ccb_u3.recv_fifobar = dma_va + FIFOHANDLESIZE; |
| 300 | ilo_ccb->ccb_u3.recv_fifobar = dma_pa + FIFOHANDLESIZE; | 301 | ilo_ccb->ccb_u3.recv_fifobar_pa = dma_pa + FIFOHANDLESIZE; |
| 301 | dma_va += fifo_sz(NR_QENTRY); | 302 | dma_va += fifo_sz(NR_QENTRY); |
| 302 | dma_pa += fifo_sz(NR_QENTRY); | 303 | dma_pa += fifo_sz(NR_QENTRY); |
| 303 | 304 | ||
| 304 | driver_ccb->ccb_u2.send_desc = dma_va; | 305 | driver_ccb->ccb_u2.send_desc = dma_va; |
| 305 | ilo_ccb->ccb_u2.send_desc = dma_pa; | 306 | ilo_ccb->ccb_u2.send_desc_pa = dma_pa; |
| 306 | dma_pa += desc_mem_sz(NR_QENTRY); | 307 | dma_pa += desc_mem_sz(NR_QENTRY); |
| 307 | dma_va += desc_mem_sz(NR_QENTRY); | 308 | dma_va += desc_mem_sz(NR_QENTRY); |
| 308 | 309 | ||
| 309 | driver_ccb->ccb_u4.recv_desc = dma_va; | 310 | driver_ccb->ccb_u4.recv_desc = dma_va; |
| 310 | ilo_ccb->ccb_u4.recv_desc = dma_pa; | 311 | ilo_ccb->ccb_u4.recv_desc_pa = dma_pa; |
| 311 | 312 | ||
| 312 | driver_ccb->channel = slot; | 313 | driver_ccb->channel = slot; |
| 313 | ilo_ccb->channel = slot; | 314 | ilo_ccb->channel = slot; |
diff --git a/drivers/misc/hpilo.h b/drivers/misc/hpilo.h index 247eb386a973..54e43adbdea1 100644 --- a/drivers/misc/hpilo.h +++ b/drivers/misc/hpilo.h | |||
| @@ -79,21 +79,21 @@ struct ilo_hwinfo { | |||
| 79 | struct ccb { | 79 | struct ccb { |
| 80 | union { | 80 | union { |
| 81 | char *send_fifobar; | 81 | char *send_fifobar; |
| 82 | u64 padding1; | 82 | u64 send_fifobar_pa; |
| 83 | } ccb_u1; | 83 | } ccb_u1; |
| 84 | union { | 84 | union { |
| 85 | char *send_desc; | 85 | char *send_desc; |
| 86 | u64 padding2; | 86 | u64 send_desc_pa; |
| 87 | } ccb_u2; | 87 | } ccb_u2; |
| 88 | u64 send_ctrl; | 88 | u64 send_ctrl; |
| 89 | 89 | ||
| 90 | union { | 90 | union { |
| 91 | char *recv_fifobar; | 91 | char *recv_fifobar; |
| 92 | u64 padding3; | 92 | u64 recv_fifobar_pa; |
| 93 | } ccb_u3; | 93 | } ccb_u3; |
| 94 | union { | 94 | union { |
| 95 | char *recv_desc; | 95 | char *recv_desc; |
| 96 | u64 padding4; | 96 | u64 recv_desc_pa; |
| 97 | } ccb_u4; | 97 | } ccb_u4; |
| 98 | u64 recv_ctrl; | 98 | u64 recv_ctrl; |
| 99 | 99 | ||
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c index 5bfb2a2041b8..ef34de7a8026 100644 --- a/drivers/misc/lkdtm.c +++ b/drivers/misc/lkdtm.c | |||
| @@ -124,9 +124,9 @@ static int count = DEFAULT_COUNT; | |||
| 124 | module_param(recur_count, int, 0644); | 124 | module_param(recur_count, int, 0644); |
| 125 | MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\ | 125 | MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\ |
| 126 | "default is 10"); | 126 | "default is 10"); |
| 127 | module_param(cpoint_name, charp, 0644); | 127 | module_param(cpoint_name, charp, 0444); |
| 128 | MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed"); | 128 | MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed"); |
| 129 | module_param(cpoint_type, charp, 0644); | 129 | module_param(cpoint_type, charp, 0444); |
| 130 | MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\ | 130 | MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\ |
| 131 | "hitting the crash point"); | 131 | "hitting the crash point"); |
| 132 | module_param(cpoint_count, int, 0644); | 132 | module_param(cpoint_count, int, 0644); |
