diff options
Diffstat (limited to 'drivers/misc')
61 files changed, 12981 insertions, 304 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index b74331260744..4e349cd98bcf 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -2,9 +2,16 @@ | |||
2 | # Misc strange devices | 2 | # Misc strange devices |
3 | # | 3 | # |
4 | 4 | ||
5 | # This one has to live outside of the MISC_DEVICES conditional, | ||
6 | # because it may be selected by drivers/platform/x86/hp_accel. | ||
7 | config SENSORS_LIS3LV02D | ||
8 | tristate | ||
9 | depends on INPUT | ||
10 | select INPUT_POLLDEV | ||
11 | default n | ||
12 | |||
5 | menuconfig MISC_DEVICES | 13 | menuconfig MISC_DEVICES |
6 | bool "Misc devices" | 14 | bool "Misc devices" |
7 | default y | ||
8 | ---help--- | 15 | ---help--- |
9 | Say Y here to get to see options for device drivers from various | 16 | Say Y here to get to see options for device drivers from various |
10 | different categories. This option alone does not add any kernel code. | 17 | different categories. This option alone does not add any kernel code. |
@@ -24,7 +31,8 @@ config AD525X_DPOT | |||
24 | AD5260, AD5262, AD5263, AD5290, AD5291, AD5292, AD5293, | 31 | AD5260, AD5262, AD5263, AD5290, AD5291, AD5292, AD5293, |
25 | AD7376, AD8400, AD8402, AD8403, ADN2850, AD5241, AD5242, | 32 | AD7376, AD8400, AD8402, AD8403, ADN2850, AD5241, AD5242, |
26 | AD5243, AD5245, AD5246, AD5247, AD5248, AD5280, AD5282, | 33 | AD5243, AD5245, AD5246, AD5247, AD5248, AD5280, AD5282, |
27 | ADN2860, AD5273, AD5171, AD5170, AD5172, AD5173 | 34 | ADN2860, AD5273, AD5171, AD5170, AD5172, AD5173, AD5270, |
35 | AD5271, AD5272, AD5274 | ||
28 | digital potentiometer chips. | 36 | digital potentiometer chips. |
29 | 37 | ||
30 | See Documentation/misc-devices/ad525x_dpot.txt for the | 38 | See Documentation/misc-devices/ad525x_dpot.txt for the |
@@ -62,6 +70,15 @@ config ATMEL_PWM | |||
62 | purposes including software controlled power-efficient backlights | 70 | purposes including software controlled power-efficient backlights |
63 | on LCD displays, motor control, and waveform generation. | 71 | on LCD displays, motor control, and waveform generation. |
64 | 72 | ||
73 | config AB8500_PWM | ||
74 | bool "AB8500 PWM support" | ||
75 | depends on AB8500_CORE && ARCH_U8500 | ||
76 | select HAVE_PWM | ||
77 | help | ||
78 | This driver exports functions to enable/disble/config/free Pulse | ||
79 | Width Modulation in the Analog Baseband Chip AB8500. | ||
80 | It is used by led and backlight driver to control the intensity. | ||
81 | |||
65 | config ATMEL_TCLIB | 82 | config ATMEL_TCLIB |
66 | bool "Atmel AT32/AT91 Timer/Counter Library" | 83 | bool "Atmel AT32/AT91 Timer/Counter Library" |
67 | depends on (AVR32 || ARCH_AT91) | 84 | depends on (AVR32 || ARCH_AT91) |
@@ -112,8 +129,8 @@ config IBM_ASM | |||
112 | 129 | ||
113 | WARNING: This software may not be supported or function | 130 | WARNING: This software may not be supported or function |
114 | correctly on your IBM server. Please consult the IBM ServerProven | 131 | correctly on your IBM server. Please consult the IBM ServerProven |
115 | website <http://www.pc.ibm.com/ww/eserver/xseries/serverproven> for | 132 | website <http://www-03.ibm.com/systems/info/x86servers/serverproven/compat/us/> |
116 | information on the specific driver level and support statement | 133 | for information on the specific driver level and support statement |
117 | for your IBM server. | 134 | for your IBM server. |
118 | 135 | ||
119 | config PHANTOM | 136 | config PHANTOM |
@@ -127,6 +144,19 @@ config PHANTOM | |||
127 | If you choose to build module, its name will be phantom. If unsure, | 144 | If you choose to build module, its name will be phantom. If unsure, |
128 | say N here. | 145 | say N here. |
129 | 146 | ||
147 | config INTEL_MID_PTI | ||
148 | tristate "Parallel Trace Interface for MIPI P1149.7 cJTAG standard" | ||
149 | default n | ||
150 | help | ||
151 | The PTI (Parallel Trace Interface) driver directs | ||
152 | trace data routed from various parts in the system out | ||
153 | through an Intel Penwell PTI port and out of the mobile | ||
154 | device for analysis with a debugging tool (Lauterbach or Fido). | ||
155 | |||
156 | You should select this driver if the target kernel is meant for | ||
157 | an Intel Atom (non-netbook) mobile device containing a MIPI | ||
158 | P1149.7 standard implementation. | ||
159 | |||
130 | config SGI_IOC4 | 160 | config SGI_IOC4 |
131 | tristate "SGI IOC4 Base IO support" | 161 | tristate "SGI IOC4 Base IO support" |
132 | depends on PCI | 162 | depends on PCI |
@@ -248,15 +278,15 @@ config CS5535_CLOCK_EVENT_SRC | |||
248 | generic PIT, and are suitable for use as high-res timers. | 278 | generic PIT, and are suitable for use as high-res timers. |
249 | 279 | ||
250 | config HP_ILO | 280 | config HP_ILO |
251 | tristate "Channel interface driver for HP iLO/iLO2 processor" | 281 | tristate "Channel interface driver for the HP iLO processor" |
252 | depends on PCI | 282 | depends on PCI |
253 | default n | 283 | default n |
254 | help | 284 | help |
255 | The channel interface driver allows applications to communicate | 285 | The channel interface driver allows applications to communicate |
256 | with iLO/iLO2 management processors present on HP ProLiant | 286 | with iLO management processors present on HP ProLiant servers. |
257 | servers. Upon loading, the driver creates /dev/hpilo/dXccbN files, | 287 | Upon loading, the driver creates /dev/hpilo/dXccbN files, which |
258 | which can be used to gather data from the management processor, | 288 | can be used to gather data from the management processor, via |
259 | via read and write system calls. | 289 | read and write system calls. |
260 | 290 | ||
261 | To compile this driver as a module, choose M here: the | 291 | To compile this driver as a module, choose M here: the |
262 | module will be called hpilo. | 292 | module will be called hpilo. |
@@ -284,6 +314,16 @@ config SGI_GRU_DEBUG | |||
284 | This option enables addition debugging code for the SGI GRU driver. If | 314 | This option enables addition debugging code for the SGI GRU driver. If |
285 | you are unsure, say N. | 315 | you are unsure, say N. |
286 | 316 | ||
317 | config APDS9802ALS | ||
318 | tristate "Medfield Avago APDS9802 ALS Sensor module" | ||
319 | depends on I2C | ||
320 | help | ||
321 | If you say yes here you get support for the ALS APDS9802 ambient | ||
322 | light sensor. | ||
323 | |||
324 | This driver can also be built as a module. If so, the module | ||
325 | will be called apds9802als. | ||
326 | |||
287 | config ISL29003 | 327 | config ISL29003 |
288 | tristate "Intersil ISL29003 ambient light sensor" | 328 | tristate "Intersil ISL29003 ambient light sensor" |
289 | depends on I2C && SYSFS | 329 | depends on I2C && SYSFS |
@@ -294,6 +334,16 @@ config ISL29003 | |||
294 | This driver can also be built as a module. If so, the module | 334 | This driver can also be built as a module. If so, the module |
295 | will be called isl29003. | 335 | will be called isl29003. |
296 | 336 | ||
337 | config ISL29020 | ||
338 | tristate "Intersil ISL29020 ambient light sensor" | ||
339 | depends on I2C | ||
340 | help | ||
341 | If you say yes here you get support for the Intersil ISL29020 | ||
342 | ambient light sensor. | ||
343 | |||
344 | This driver can also be built as a module. If so, the module | ||
345 | will be called isl29020. | ||
346 | |||
297 | config SENSORS_TSL2550 | 347 | config SENSORS_TSL2550 |
298 | tristate "Taos TSL2550 ambient light sensor" | 348 | tristate "Taos TSL2550 ambient light sensor" |
299 | depends on I2C && SYSFS | 349 | depends on I2C && SYSFS |
@@ -314,6 +364,27 @@ config SENSORS_BH1780 | |||
314 | This driver can also be built as a module. If so, the module | 364 | This driver can also be built as a module. If so, the module |
315 | will be called bh1780gli. | 365 | will be called bh1780gli. |
316 | 366 | ||
367 | config SENSORS_BH1770 | ||
368 | tristate "BH1770GLC / SFH7770 combined ALS - Proximity sensor" | ||
369 | depends on I2C | ||
370 | ---help--- | ||
371 | Say Y here if you want to build a driver for BH1770GLC (ROHM) or | ||
372 | SFH7770 (Osram) combined ambient light and proximity sensor chip. | ||
373 | |||
374 | To compile this driver as a module, choose M here: the | ||
375 | module will be called bh1770glc. If unsure, say N here. | ||
376 | |||
377 | config SENSORS_APDS990X | ||
378 | tristate "APDS990X combined als and proximity sensors" | ||
379 | depends on I2C | ||
380 | default n | ||
381 | ---help--- | ||
382 | Say Y here if you want to build a driver for Avago APDS990x | ||
383 | combined ambient light and proximity sensor chip. | ||
384 | |||
385 | To compile this driver as a module, choose M here: the | ||
386 | module will be called apds990x. If unsure, say N here. | ||
387 | |||
317 | config HMC6352 | 388 | config HMC6352 |
318 | tristate "Honeywell HMC6352 compass" | 389 | tristate "Honeywell HMC6352 compass" |
319 | depends on I2C | 390 | depends on I2C |
@@ -344,6 +415,16 @@ config DS1682 | |||
344 | This driver can also be built as a module. If so, the module | 415 | This driver can also be built as a module. If so, the module |
345 | will be called ds1682. | 416 | will be called ds1682. |
346 | 417 | ||
418 | config SPEAR13XX_PCIE_GADGET | ||
419 | bool "PCIe gadget support for SPEAr13XX platform" | ||
420 | depends on ARCH_SPEAR13XX | ||
421 | default n | ||
422 | help | ||
423 | This option enables gadget support for PCIe controller. If | ||
424 | board file defines any controller as PCIe endpoint then a sysfs | ||
425 | entry will be created for that controller. User can use these | ||
426 | sysfs node to configure PCIe EP as per his requirements. | ||
427 | |||
347 | config TI_DAC7512 | 428 | config TI_DAC7512 |
348 | tristate "Texas Instruments DAC7512" | 429 | tristate "Texas Instruments DAC7512" |
349 | depends on SPI && SYSFS | 430 | depends on SPI && SYSFS |
@@ -352,7 +433,7 @@ config TI_DAC7512 | |||
352 | DAC7512 16-bit digital-to-analog converter. | 433 | DAC7512 16-bit digital-to-analog converter. |
353 | 434 | ||
354 | This driver can also be built as a module. If so, the module | 435 | This driver can also be built as a module. If so, the module |
355 | will be calles ti_dac7512. | 436 | will be called ti_dac7512. |
356 | 437 | ||
357 | config VMWARE_BALLOON | 438 | config VMWARE_BALLOON |
358 | tristate "VMware Balloon Driver" | 439 | tristate "VMware Balloon Driver" |
@@ -385,14 +466,36 @@ config BMP085 | |||
385 | depends on I2C && SYSFS | 466 | depends on I2C && SYSFS |
386 | help | 467 | help |
387 | If you say yes here you get support for the Bosch Sensortec | 468 | If you say yes here you get support for the Bosch Sensortec |
388 | BMP086 digital pressure sensor. | 469 | BMP085 digital pressure sensor. |
389 | 470 | ||
390 | To compile this driver as a module, choose M here: the | 471 | To compile this driver as a module, choose M here: the |
391 | module will be called bmp085. | 472 | module will be called bmp085. |
392 | 473 | ||
474 | config PCH_PHUB | ||
475 | tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223) PHUB" | ||
476 | depends on PCI | ||
477 | help | ||
478 | This driver is for PCH(Platform controller Hub) PHUB(Packet Hub) of | ||
479 | Intel Topcliff which is an IOH(Input/Output Hub) for x86 embedded | ||
480 | processor. The Topcliff has MAC address and Option ROM data in SROM. | ||
481 | This driver can access MAC address and Option ROM data in SROM. | ||
482 | |||
483 | This driver also can be used for OKI SEMICONDUCTOR IOH(Input/ | ||
484 | Output Hub), ML7213 and ML7223. | ||
485 | ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is | ||
486 | for MP(Media Phone) use. | ||
487 | ML7213/ML7223 is companion chip for Intel Atom E6xx series. | ||
488 | ML7213/ML7223 is completely compatible for Intel EG20T PCH. | ||
489 | |||
490 | To compile this driver as a module, choose M here: the module will | ||
491 | be called pch_phub. | ||
492 | |||
393 | source "drivers/misc/c2port/Kconfig" | 493 | source "drivers/misc/c2port/Kconfig" |
394 | source "drivers/misc/eeprom/Kconfig" | 494 | source "drivers/misc/eeprom/Kconfig" |
395 | source "drivers/misc/cb710/Kconfig" | 495 | source "drivers/misc/cb710/Kconfig" |
396 | source "drivers/misc/iwmc3200top/Kconfig" | 496 | source "drivers/misc/iwmc3200top/Kconfig" |
497 | source "drivers/misc/ti-st/Kconfig" | ||
498 | source "drivers/misc/lis3lv02d/Kconfig" | ||
499 | source "drivers/misc/carma/Kconfig" | ||
397 | 500 | ||
398 | endif # MISC_DEVICES | 501 | endif # MISC_DEVICES |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 42eab95cde2a..5f03172cc0b5 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
@@ -6,6 +6,7 @@ obj-$(CONFIG_IBM_ASM) += ibmasm/ | |||
6 | obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o | 6 | obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o |
7 | obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o | 7 | obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o |
8 | obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o | 8 | obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o |
9 | 0bj-$(CONFIG_INTEL_MID_PTI) += pti.o | ||
9 | obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o | 10 | obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o |
10 | obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o | 11 | obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o |
11 | obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o | 12 | obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o |
@@ -16,6 +17,8 @@ obj-$(CONFIG_TIFM_CORE) += tifm_core.o | |||
16 | obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o | 17 | obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o |
17 | obj-$(CONFIG_PHANTOM) += phantom.o | 18 | obj-$(CONFIG_PHANTOM) += phantom.o |
18 | obj-$(CONFIG_SENSORS_BH1780) += bh1780gli.o | 19 | obj-$(CONFIG_SENSORS_BH1780) += bh1780gli.o |
20 | obj-$(CONFIG_SENSORS_BH1770) += bh1770glc.o | ||
21 | obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o | ||
19 | obj-$(CONFIG_SGI_IOC4) += ioc4.o | 22 | obj-$(CONFIG_SGI_IOC4) += ioc4.o |
20 | obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o | 23 | obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o |
21 | obj-$(CONFIG_KGDB_TESTS) += kgdbts.o | 24 | obj-$(CONFIG_KGDB_TESTS) += kgdbts.o |
@@ -23,7 +26,9 @@ obj-$(CONFIG_SGI_XP) += sgi-xp/ | |||
23 | obj-$(CONFIG_SGI_GRU) += sgi-gru/ | 26 | obj-$(CONFIG_SGI_GRU) += sgi-gru/ |
24 | obj-$(CONFIG_CS5535_MFGPT) += cs5535-mfgpt.o | 27 | obj-$(CONFIG_CS5535_MFGPT) += cs5535-mfgpt.o |
25 | obj-$(CONFIG_HP_ILO) += hpilo.o | 28 | obj-$(CONFIG_HP_ILO) += hpilo.o |
29 | obj-$(CONFIG_APDS9802ALS) += apds9802als.o | ||
26 | obj-$(CONFIG_ISL29003) += isl29003.o | 30 | obj-$(CONFIG_ISL29003) += isl29003.o |
31 | obj-$(CONFIG_ISL29020) += isl29020.o | ||
27 | obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o | 32 | obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o |
28 | obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o | 33 | obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o |
29 | obj-$(CONFIG_DS1682) += ds1682.o | 34 | obj-$(CONFIG_DS1682) += ds1682.o |
@@ -33,5 +38,11 @@ obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/ | |||
33 | obj-$(CONFIG_HMC6352) += hmc6352.o | 38 | obj-$(CONFIG_HMC6352) += hmc6352.o |
34 | obj-y += eeprom/ | 39 | obj-y += eeprom/ |
35 | obj-y += cb710/ | 40 | obj-y += cb710/ |
41 | obj-$(CONFIG_SPEAR13XX_PCIE_GADGET) += spear13xx_pcie_gadget.o | ||
36 | obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o | 42 | obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o |
37 | obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o | 43 | obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o |
44 | obj-$(CONFIG_PCH_PHUB) += pch_phub.o | ||
45 | obj-y += ti-st/ | ||
46 | obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o | ||
47 | obj-y += lis3lv02d/ | ||
48 | obj-y += carma/ | ||
diff --git a/drivers/misc/ab8500-pwm.c b/drivers/misc/ab8500-pwm.c new file mode 100644 index 000000000000..54e3d05b63cc --- /dev/null +++ b/drivers/misc/ab8500-pwm.c | |||
@@ -0,0 +1,168 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * Author: Arun R Murthy <arun.murthy@stericsson.com> | ||
5 | * License terms: GNU General Public License (GPL) version 2 | ||
6 | */ | ||
7 | #include <linux/err.h> | ||
8 | #include <linux/platform_device.h> | ||
9 | #include <linux/slab.h> | ||
10 | #include <linux/pwm.h> | ||
11 | #include <linux/mfd/ab8500.h> | ||
12 | #include <linux/mfd/abx500.h> | ||
13 | |||
14 | /* | ||
15 | * PWM Out generators | ||
16 | * Bank: 0x10 | ||
17 | */ | ||
18 | #define AB8500_PWM_OUT_CTRL1_REG 0x60 | ||
19 | #define AB8500_PWM_OUT_CTRL2_REG 0x61 | ||
20 | #define AB8500_PWM_OUT_CTRL7_REG 0x66 | ||
21 | |||
22 | /* backlight driver constants */ | ||
23 | #define ENABLE_PWM 1 | ||
24 | #define DISABLE_PWM 0 | ||
25 | |||
26 | struct pwm_device { | ||
27 | struct device *dev; | ||
28 | struct list_head node; | ||
29 | const char *label; | ||
30 | unsigned int pwm_id; | ||
31 | }; | ||
32 | |||
33 | static LIST_HEAD(pwm_list); | ||
34 | |||
35 | int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) | ||
36 | { | ||
37 | int ret = 0; | ||
38 | unsigned int higher_val, lower_val; | ||
39 | u8 reg; | ||
40 | |||
41 | /* | ||
42 | * get the first 8 bits that are be written to | ||
43 | * AB8500_PWM_OUT_CTRL1_REG[0:7] | ||
44 | */ | ||
45 | lower_val = duty_ns & 0x00FF; | ||
46 | /* | ||
47 | * get bits [9:10] that are to be written to | ||
48 | * AB8500_PWM_OUT_CTRL2_REG[0:1] | ||
49 | */ | ||
50 | higher_val = ((duty_ns & 0x0300) >> 8); | ||
51 | |||
52 | reg = AB8500_PWM_OUT_CTRL1_REG + ((pwm->pwm_id - 1) * 2); | ||
53 | |||
54 | ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC, | ||
55 | reg, (u8)lower_val); | ||
56 | if (ret < 0) | ||
57 | return ret; | ||
58 | ret = abx500_set_register_interruptible(pwm->dev, AB8500_MISC, | ||
59 | (reg + 1), (u8)higher_val); | ||
60 | |||
61 | return ret; | ||
62 | } | ||
63 | EXPORT_SYMBOL(pwm_config); | ||
64 | |||
65 | int pwm_enable(struct pwm_device *pwm) | ||
66 | { | ||
67 | int ret; | ||
68 | |||
69 | ret = abx500_mask_and_set_register_interruptible(pwm->dev, | ||
70 | AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG, | ||
71 | 1 << (pwm->pwm_id-1), ENABLE_PWM); | ||
72 | if (ret < 0) | ||
73 | dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n", | ||
74 | pwm->label, ret); | ||
75 | return ret; | ||
76 | } | ||
77 | EXPORT_SYMBOL(pwm_enable); | ||
78 | |||
79 | void pwm_disable(struct pwm_device *pwm) | ||
80 | { | ||
81 | int ret; | ||
82 | |||
83 | ret = abx500_mask_and_set_register_interruptible(pwm->dev, | ||
84 | AB8500_MISC, AB8500_PWM_OUT_CTRL7_REG, | ||
85 | 1 << (pwm->pwm_id-1), DISABLE_PWM); | ||
86 | if (ret < 0) | ||
87 | dev_err(pwm->dev, "%s: Failed to disable PWM, Error %d\n", | ||
88 | pwm->label, ret); | ||
89 | return; | ||
90 | } | ||
91 | EXPORT_SYMBOL(pwm_disable); | ||
92 | |||
93 | struct pwm_device *pwm_request(int pwm_id, const char *label) | ||
94 | { | ||
95 | struct pwm_device *pwm; | ||
96 | |||
97 | list_for_each_entry(pwm, &pwm_list, node) { | ||
98 | if (pwm->pwm_id == pwm_id) { | ||
99 | pwm->label = label; | ||
100 | pwm->pwm_id = pwm_id; | ||
101 | return pwm; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | return ERR_PTR(-ENOENT); | ||
106 | } | ||
107 | EXPORT_SYMBOL(pwm_request); | ||
108 | |||
109 | void pwm_free(struct pwm_device *pwm) | ||
110 | { | ||
111 | pwm_disable(pwm); | ||
112 | } | ||
113 | EXPORT_SYMBOL(pwm_free); | ||
114 | |||
115 | static int __devinit ab8500_pwm_probe(struct platform_device *pdev) | ||
116 | { | ||
117 | struct pwm_device *pwm; | ||
118 | /* | ||
119 | * Nothing to be done in probe, this is required to get the | ||
120 | * device which is required for ab8500 read and write | ||
121 | */ | ||
122 | pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); | ||
123 | if (pwm == NULL) { | ||
124 | dev_err(&pdev->dev, "failed to allocate memory\n"); | ||
125 | return -ENOMEM; | ||
126 | } | ||
127 | pwm->dev = &pdev->dev; | ||
128 | pwm->pwm_id = pdev->id; | ||
129 | list_add_tail(&pwm->node, &pwm_list); | ||
130 | platform_set_drvdata(pdev, pwm); | ||
131 | dev_dbg(pwm->dev, "pwm probe successful\n"); | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static int __devexit ab8500_pwm_remove(struct platform_device *pdev) | ||
136 | { | ||
137 | struct pwm_device *pwm = platform_get_drvdata(pdev); | ||
138 | list_del(&pwm->node); | ||
139 | dev_dbg(&pdev->dev, "pwm driver removed\n"); | ||
140 | kfree(pwm); | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static struct platform_driver ab8500_pwm_driver = { | ||
145 | .driver = { | ||
146 | .name = "ab8500-pwm", | ||
147 | .owner = THIS_MODULE, | ||
148 | }, | ||
149 | .probe = ab8500_pwm_probe, | ||
150 | .remove = __devexit_p(ab8500_pwm_remove), | ||
151 | }; | ||
152 | |||
153 | static int __init ab8500_pwm_init(void) | ||
154 | { | ||
155 | return platform_driver_register(&ab8500_pwm_driver); | ||
156 | } | ||
157 | |||
158 | static void __exit ab8500_pwm_exit(void) | ||
159 | { | ||
160 | platform_driver_unregister(&ab8500_pwm_driver); | ||
161 | } | ||
162 | |||
163 | subsys_initcall(ab8500_pwm_init); | ||
164 | module_exit(ab8500_pwm_exit); | ||
165 | MODULE_AUTHOR("Arun MURTHY <arun.murthy@stericsson.com>"); | ||
166 | MODULE_DESCRIPTION("AB8500 Pulse Width Modulation Driver"); | ||
167 | MODULE_ALIAS("AB8500 PWM driver"); | ||
168 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/misc/ad525x_dpot-i2c.c b/drivers/misc/ad525x_dpot-i2c.c index 374352af7979..4ff73c215746 100644 --- a/drivers/misc/ad525x_dpot-i2c.c +++ b/drivers/misc/ad525x_dpot-i2c.c | |||
@@ -102,6 +102,8 @@ static const struct i2c_device_id ad_dpot_id[] = { | |||
102 | {"ad5170", AD5170_ID}, | 102 | {"ad5170", AD5170_ID}, |
103 | {"ad5172", AD5172_ID}, | 103 | {"ad5172", AD5172_ID}, |
104 | {"ad5173", AD5173_ID}, | 104 | {"ad5173", AD5173_ID}, |
105 | {"ad5272", AD5272_ID}, | ||
106 | {"ad5274", AD5274_ID}, | ||
105 | {} | 107 | {} |
106 | }; | 108 | }; |
107 | MODULE_DEVICE_TABLE(i2c, ad_dpot_id); | 109 | MODULE_DEVICE_TABLE(i2c, ad_dpot_id); |
diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c index b8c6df9c8437..7f9a55afe05d 100644 --- a/drivers/misc/ad525x_dpot-spi.c +++ b/drivers/misc/ad525x_dpot-spi.c | |||
@@ -38,6 +38,8 @@ static const struct ad_dpot_id ad_dpot_spi_devlist[] = { | |||
38 | {.name = "ad8402", .devid = AD8402_ID}, | 38 | {.name = "ad8402", .devid = AD8402_ID}, |
39 | {.name = "ad8403", .devid = AD8403_ID}, | 39 | {.name = "ad8403", .devid = AD8403_ID}, |
40 | {.name = "adn2850", .devid = ADN2850_ID}, | 40 | {.name = "adn2850", .devid = ADN2850_ID}, |
41 | {.name = "ad5270", .devid = AD5270_ID}, | ||
42 | {.name = "ad5271", .devid = AD5271_ID}, | ||
41 | {} | 43 | {} |
42 | }; | 44 | }; |
43 | 45 | ||
@@ -53,13 +55,13 @@ static int write8(void *client, u8 val) | |||
53 | static int write16(void *client, u8 reg, u8 val) | 55 | static int write16(void *client, u8 reg, u8 val) |
54 | { | 56 | { |
55 | u8 data[2] = {reg, val}; | 57 | u8 data[2] = {reg, val}; |
56 | return spi_write(client, data, 1); | 58 | return spi_write(client, data, 2); |
57 | } | 59 | } |
58 | 60 | ||
59 | static int write24(void *client, u8 reg, u16 val) | 61 | static int write24(void *client, u8 reg, u16 val) |
60 | { | 62 | { |
61 | u8 data[3] = {reg, val >> 8, val}; | 63 | u8 data[3] = {reg, val >> 8, val}; |
62 | return spi_write(client, data, 1); | 64 | return spi_write(client, data, 3); |
63 | } | 65 | } |
64 | 66 | ||
65 | static int read8(void *client) | 67 | static int read8(void *client) |
diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c index 5e6fa8449e8b..7cb911028d09 100644 --- a/drivers/misc/ad525x_dpot.c +++ b/drivers/misc/ad525x_dpot.c | |||
@@ -29,9 +29,9 @@ | |||
29 | * AD5262 2 256 20, 50, 200 | 29 | * AD5262 2 256 20, 50, 200 |
30 | * AD5263 4 256 20, 50, 200 | 30 | * AD5263 4 256 20, 50, 200 |
31 | * AD5290 1 256 10, 50, 100 | 31 | * AD5290 1 256 10, 50, 100 |
32 | * AD5291 1 256 20 | 32 | * AD5291 1 256 20, 50, 100 (20-TP) |
33 | * AD5292 1 1024 20 | 33 | * AD5292 1 1024 20, 50, 100 (20-TP) |
34 | * AD5293 1 1024 20 | 34 | * AD5293 1 1024 20, 50, 100 |
35 | * AD7376 1 128 10, 50, 100, 1M | 35 | * AD7376 1 128 10, 50, 100, 1M |
36 | * AD8400 1 256 1, 10, 50, 100 | 36 | * AD8400 1 256 1, 10, 50, 100 |
37 | * AD8402 2 256 1, 10, 50, 100 | 37 | * AD8402 2 256 1, 10, 50, 100 |
@@ -52,6 +52,10 @@ | |||
52 | * AD5170 1 256 2.5, 10, 50, 100 (OTP) | 52 | * AD5170 1 256 2.5, 10, 50, 100 (OTP) |
53 | * AD5172 2 256 2.5, 10, 50, 100 (OTP) | 53 | * AD5172 2 256 2.5, 10, 50, 100 (OTP) |
54 | * AD5173 2 256 2.5, 10, 50, 100 (OTP) | 54 | * AD5173 2 256 2.5, 10, 50, 100 (OTP) |
55 | * AD5270 1 1024 20, 50, 100 (50-TP) | ||
56 | * AD5271 1 256 20, 50, 100 (50-TP) | ||
57 | * AD5272 1 1024 20, 50, 100 (50-TP) | ||
58 | * AD5274 1 256 20, 50, 100 (50-TP) | ||
55 | * | 59 | * |
56 | * See Documentation/misc-devices/ad525x_dpot.txt for more info. | 60 | * See Documentation/misc-devices/ad525x_dpot.txt for more info. |
57 | * | 61 | * |
@@ -126,18 +130,38 @@ static inline int dpot_write_r8d16(struct dpot_data *dpot, u8 reg, u16 val) | |||
126 | static s32 dpot_read_spi(struct dpot_data *dpot, u8 reg) | 130 | static s32 dpot_read_spi(struct dpot_data *dpot, u8 reg) |
127 | { | 131 | { |
128 | unsigned ctrl = 0; | 132 | unsigned ctrl = 0; |
133 | int value; | ||
129 | 134 | ||
130 | if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) { | 135 | if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) { |
131 | 136 | ||
132 | if (dpot->feat & F_RDACS_WONLY) | 137 | if (dpot->feat & F_RDACS_WONLY) |
133 | return dpot->rdac_cache[reg & DPOT_RDAC_MASK]; | 138 | return dpot->rdac_cache[reg & DPOT_RDAC_MASK]; |
134 | |||
135 | if (dpot->uid == DPOT_UID(AD5291_ID) || | 139 | if (dpot->uid == DPOT_UID(AD5291_ID) || |
136 | dpot->uid == DPOT_UID(AD5292_ID) || | 140 | dpot->uid == DPOT_UID(AD5292_ID) || |
137 | dpot->uid == DPOT_UID(AD5293_ID)) | 141 | dpot->uid == DPOT_UID(AD5293_ID)) { |
138 | return dpot_read_r8d8(dpot, | 142 | |
143 | value = dpot_read_r8d8(dpot, | ||
139 | DPOT_AD5291_READ_RDAC << 2); | 144 | DPOT_AD5291_READ_RDAC << 2); |
140 | 145 | ||
146 | if (dpot->uid == DPOT_UID(AD5291_ID)) | ||
147 | value = value >> 2; | ||
148 | |||
149 | return value; | ||
150 | } else if (dpot->uid == DPOT_UID(AD5270_ID) || | ||
151 | dpot->uid == DPOT_UID(AD5271_ID)) { | ||
152 | |||
153 | value = dpot_read_r8d8(dpot, | ||
154 | DPOT_AD5270_1_2_4_READ_RDAC << 2); | ||
155 | |||
156 | if (value < 0) | ||
157 | return value; | ||
158 | |||
159 | if (dpot->uid == DPOT_UID(AD5271_ID)) | ||
160 | value = value >> 2; | ||
161 | |||
162 | return value; | ||
163 | } | ||
164 | |||
141 | ctrl = DPOT_SPI_READ_RDAC; | 165 | ctrl = DPOT_SPI_READ_RDAC; |
142 | } else if (reg & DPOT_ADDR_EEPROM) { | 166 | } else if (reg & DPOT_ADDR_EEPROM) { |
143 | ctrl = DPOT_SPI_READ_EEPROM; | 167 | ctrl = DPOT_SPI_READ_EEPROM; |
@@ -153,6 +177,7 @@ static s32 dpot_read_spi(struct dpot_data *dpot, u8 reg) | |||
153 | 177 | ||
154 | static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg) | 178 | static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg) |
155 | { | 179 | { |
180 | int value; | ||
156 | unsigned ctrl = 0; | 181 | unsigned ctrl = 0; |
157 | switch (dpot->uid) { | 182 | switch (dpot->uid) { |
158 | case DPOT_UID(AD5246_ID): | 183 | case DPOT_UID(AD5246_ID): |
@@ -166,7 +191,7 @@ static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg) | |||
166 | case DPOT_UID(AD5280_ID): | 191 | case DPOT_UID(AD5280_ID): |
167 | case DPOT_UID(AD5282_ID): | 192 | case DPOT_UID(AD5282_ID): |
168 | ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ? | 193 | ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ? |
169 | 0 : DPOT_AD5291_RDAC_AB; | 194 | 0 : DPOT_AD5282_RDAC_AB; |
170 | return dpot_read_r8d8(dpot, ctrl); | 195 | return dpot_read_r8d8(dpot, ctrl); |
171 | case DPOT_UID(AD5170_ID): | 196 | case DPOT_UID(AD5170_ID): |
172 | case DPOT_UID(AD5171_ID): | 197 | case DPOT_UID(AD5171_ID): |
@@ -175,8 +200,27 @@ static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg) | |||
175 | case DPOT_UID(AD5172_ID): | 200 | case DPOT_UID(AD5172_ID): |
176 | case DPOT_UID(AD5173_ID): | 201 | case DPOT_UID(AD5173_ID): |
177 | ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ? | 202 | ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ? |
178 | 0 : DPOT_AD5272_3_A0; | 203 | 0 : DPOT_AD5172_3_A0; |
179 | return dpot_read_r8d8(dpot, ctrl); | 204 | return dpot_read_r8d8(dpot, ctrl); |
205 | case DPOT_UID(AD5272_ID): | ||
206 | case DPOT_UID(AD5274_ID): | ||
207 | dpot_write_r8d8(dpot, | ||
208 | (DPOT_AD5270_1_2_4_READ_RDAC << 2), 0); | ||
209 | |||
210 | value = dpot_read_r8d16(dpot, | ||
211 | DPOT_AD5270_1_2_4_RDAC << 2); | ||
212 | |||
213 | if (value < 0) | ||
214 | return value; | ||
215 | /* | ||
216 | * AD5272/AD5274 returns high byte first, however | ||
217 | * underling smbus expects low byte first. | ||
218 | */ | ||
219 | value = swab16(value); | ||
220 | |||
221 | if (dpot->uid == DPOT_UID(AD5271_ID)) | ||
222 | value = value >> 2; | ||
223 | return value; | ||
180 | default: | 224 | default: |
181 | if ((reg & DPOT_REG_TOL) || (dpot->max_pos > 256)) | 225 | if ((reg & DPOT_REG_TOL) || (dpot->max_pos > 256)) |
182 | return dpot_read_r8d16(dpot, (reg & 0xF8) | | 226 | return dpot_read_r8d16(dpot, (reg & 0xF8) | |
@@ -198,7 +242,7 @@ static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value) | |||
198 | { | 242 | { |
199 | unsigned val = 0; | 243 | unsigned val = 0; |
200 | 244 | ||
201 | if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) { | 245 | if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD | DPOT_ADDR_OTP))) { |
202 | if (dpot->feat & F_RDACS_WONLY) | 246 | if (dpot->feat & F_RDACS_WONLY) |
203 | dpot->rdac_cache[reg & DPOT_RDAC_MASK] = value; | 247 | dpot->rdac_cache[reg & DPOT_RDAC_MASK] = value; |
204 | 248 | ||
@@ -219,11 +263,30 @@ static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value) | |||
219 | } else { | 263 | } else { |
220 | if (dpot->uid == DPOT_UID(AD5291_ID) || | 264 | if (dpot->uid == DPOT_UID(AD5291_ID) || |
221 | dpot->uid == DPOT_UID(AD5292_ID) || | 265 | dpot->uid == DPOT_UID(AD5292_ID) || |
222 | dpot->uid == DPOT_UID(AD5293_ID)) | 266 | dpot->uid == DPOT_UID(AD5293_ID)) { |
267 | |||
268 | dpot_write_r8d8(dpot, DPOT_AD5291_CTRLREG << 2, | ||
269 | DPOT_AD5291_UNLOCK_CMD); | ||
270 | |||
271 | if (dpot->uid == DPOT_UID(AD5291_ID)) | ||
272 | value = value << 2; | ||
273 | |||
223 | return dpot_write_r8d8(dpot, | 274 | return dpot_write_r8d8(dpot, |
224 | (DPOT_AD5291_RDAC << 2) | | 275 | (DPOT_AD5291_RDAC << 2) | |
225 | (value >> 8), value & 0xFF); | 276 | (value >> 8), value & 0xFF); |
277 | } else if (dpot->uid == DPOT_UID(AD5270_ID) || | ||
278 | dpot->uid == DPOT_UID(AD5271_ID)) { | ||
279 | dpot_write_r8d8(dpot, | ||
280 | DPOT_AD5270_1_2_4_CTRLREG << 2, | ||
281 | DPOT_AD5270_1_2_4_UNLOCK_CMD); | ||
282 | |||
283 | if (dpot->uid == DPOT_UID(AD5271_ID)) | ||
284 | value = value << 2; | ||
226 | 285 | ||
286 | return dpot_write_r8d8(dpot, | ||
287 | (DPOT_AD5270_1_2_4_RDAC << 2) | | ||
288 | (value >> 8), value & 0xFF); | ||
289 | } | ||
227 | val = DPOT_SPI_RDAC | (reg & DPOT_RDAC_MASK); | 290 | val = DPOT_SPI_RDAC | (reg & DPOT_RDAC_MASK); |
228 | } | 291 | } |
229 | } else if (reg & DPOT_ADDR_EEPROM) { | 292 | } else if (reg & DPOT_ADDR_EEPROM) { |
@@ -243,6 +306,16 @@ static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value) | |||
243 | val = DPOT_SPI_INC_ALL; | 306 | val = DPOT_SPI_INC_ALL; |
244 | break; | 307 | break; |
245 | } | 308 | } |
309 | } else if (reg & DPOT_ADDR_OTP) { | ||
310 | if (dpot->uid == DPOT_UID(AD5291_ID) || | ||
311 | dpot->uid == DPOT_UID(AD5292_ID)) { | ||
312 | return dpot_write_r8d8(dpot, | ||
313 | DPOT_AD5291_STORE_XTPM << 2, 0); | ||
314 | } else if (dpot->uid == DPOT_UID(AD5270_ID) || | ||
315 | dpot->uid == DPOT_UID(AD5271_ID)) { | ||
316 | return dpot_write_r8d8(dpot, | ||
317 | DPOT_AD5270_1_2_4_STORE_XTPM << 2, 0); | ||
318 | } | ||
246 | } else | 319 | } else |
247 | BUG(); | 320 | BUG(); |
248 | 321 | ||
@@ -273,7 +346,7 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value) | |||
273 | case DPOT_UID(AD5280_ID): | 346 | case DPOT_UID(AD5280_ID): |
274 | case DPOT_UID(AD5282_ID): | 347 | case DPOT_UID(AD5282_ID): |
275 | ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ? | 348 | ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ? |
276 | 0 : DPOT_AD5291_RDAC_AB; | 349 | 0 : DPOT_AD5282_RDAC_AB; |
277 | return dpot_write_r8d8(dpot, ctrl, value); | 350 | return dpot_write_r8d8(dpot, ctrl, value); |
278 | break; | 351 | break; |
279 | case DPOT_UID(AD5171_ID): | 352 | case DPOT_UID(AD5171_ID): |
@@ -289,12 +362,12 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value) | |||
289 | case DPOT_UID(AD5172_ID): | 362 | case DPOT_UID(AD5172_ID): |
290 | case DPOT_UID(AD5173_ID): | 363 | case DPOT_UID(AD5173_ID): |
291 | ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ? | 364 | ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ? |
292 | 0 : DPOT_AD5272_3_A0; | 365 | 0 : DPOT_AD5172_3_A0; |
293 | if (reg & DPOT_ADDR_OTP) { | 366 | if (reg & DPOT_ADDR_OTP) { |
294 | tmp = dpot_read_r8d16(dpot, ctrl); | 367 | tmp = dpot_read_r8d16(dpot, ctrl); |
295 | if (tmp >> 14) /* Ready to Program? */ | 368 | if (tmp >> 14) /* Ready to Program? */ |
296 | return -EFAULT; | 369 | return -EFAULT; |
297 | ctrl |= DPOT_AD5270_2_3_FUSE; | 370 | ctrl |= DPOT_AD5170_2_3_FUSE; |
298 | } | 371 | } |
299 | return dpot_write_r8d8(dpot, ctrl, value); | 372 | return dpot_write_r8d8(dpot, ctrl, value); |
300 | break; | 373 | break; |
@@ -303,10 +376,25 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value) | |||
303 | tmp = dpot_read_r8d16(dpot, tmp); | 376 | tmp = dpot_read_r8d16(dpot, tmp); |
304 | if (tmp >> 14) /* Ready to Program? */ | 377 | if (tmp >> 14) /* Ready to Program? */ |
305 | return -EFAULT; | 378 | return -EFAULT; |
306 | ctrl = DPOT_AD5270_2_3_FUSE; | 379 | ctrl = DPOT_AD5170_2_3_FUSE; |
307 | } | 380 | } |
308 | return dpot_write_r8d8(dpot, ctrl, value); | 381 | return dpot_write_r8d8(dpot, ctrl, value); |
309 | break; | 382 | break; |
383 | case DPOT_UID(AD5272_ID): | ||
384 | case DPOT_UID(AD5274_ID): | ||
385 | dpot_write_r8d8(dpot, DPOT_AD5270_1_2_4_CTRLREG << 2, | ||
386 | DPOT_AD5270_1_2_4_UNLOCK_CMD); | ||
387 | |||
388 | if (reg & DPOT_ADDR_OTP) | ||
389 | return dpot_write_r8d8(dpot, | ||
390 | DPOT_AD5270_1_2_4_STORE_XTPM << 2, 0); | ||
391 | |||
392 | if (dpot->uid == DPOT_UID(AD5274_ID)) | ||
393 | value = value << 2; | ||
394 | |||
395 | return dpot_write_r8d8(dpot, (DPOT_AD5270_1_2_4_RDAC << 2) | | ||
396 | (value >> 8), value & 0xFF); | ||
397 | break; | ||
310 | default: | 398 | default: |
311 | if (reg & DPOT_ADDR_CMD) | 399 | if (reg & DPOT_ADDR_CMD) |
312 | return dpot_write_d8(dpot, reg); | 400 | return dpot_write_d8(dpot, reg); |
@@ -320,7 +408,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value) | |||
320 | } | 408 | } |
321 | } | 409 | } |
322 | 410 | ||
323 | |||
324 | static s32 dpot_write(struct dpot_data *dpot, u8 reg, u16 value) | 411 | static s32 dpot_write(struct dpot_data *dpot, u8 reg, u16 value) |
325 | { | 412 | { |
326 | if (dpot->feat & F_SPI) | 413 | if (dpot->feat & F_SPI) |
diff --git a/drivers/misc/ad525x_dpot.h b/drivers/misc/ad525x_dpot.h index 78b89fd2e2fd..a662f5987b68 100644 --- a/drivers/misc/ad525x_dpot.h +++ b/drivers/misc/ad525x_dpot.h | |||
@@ -47,9 +47,9 @@ enum dpot_devid { | |||
47 | AD5258_ID = DPOT_CONF(F_RDACS_RW_TOL, BRDAC0, 6, 0), /* I2C */ | 47 | AD5258_ID = DPOT_CONF(F_RDACS_RW_TOL, BRDAC0, 6, 0), /* I2C */ |
48 | AD5259_ID = DPOT_CONF(F_RDACS_RW_TOL, BRDAC0, 8, 1), | 48 | AD5259_ID = DPOT_CONF(F_RDACS_RW_TOL, BRDAC0, 8, 1), |
49 | AD5251_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC, | 49 | AD5251_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC, |
50 | BRDAC0 | BRDAC3, 6, 2), | 50 | BRDAC1 | BRDAC3, 6, 2), |
51 | AD5252_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC, | 51 | AD5252_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC, |
52 | BRDAC0 | BRDAC3, 8, 3), | 52 | BRDAC1 | BRDAC3, 8, 3), |
53 | AD5253_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC, | 53 | AD5253_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC, |
54 | BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 6, 4), | 54 | BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 6, 4), |
55 | AD5254_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC, | 55 | AD5254_ID = DPOT_CONF(F_RDACS_RW_TOL | F_CMD_INC, |
@@ -93,8 +93,10 @@ enum dpot_devid { | |||
93 | BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 8, 23), | 93 | BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 8, 23), |
94 | AD5290_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT, | 94 | AD5290_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT, |
95 | BRDAC0, 8, 24), | 95 | BRDAC0, 8, 24), |
96 | AD5291_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 8, 25), | 96 | AD5291_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT | F_CMD_OTP, |
97 | AD5292_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 10, 26), | 97 | BRDAC0, 8, 25), |
98 | AD5292_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT | F_CMD_OTP, | ||
99 | BRDAC0, 10, 26), | ||
98 | AD5293_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 10, 27), | 100 | AD5293_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 10, 27), |
99 | AD7376_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT, | 101 | AD7376_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT, |
100 | BRDAC0, 7, 28), | 102 | BRDAC0, 7, 28), |
@@ -122,6 +124,12 @@ enum dpot_devid { | |||
122 | AD5170_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 8, 45), | 124 | AD5170_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 8, 45), |
123 | AD5172_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0 | BRDAC1, 8, 46), | 125 | AD5172_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0 | BRDAC1, 8, 46), |
124 | AD5173_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0 | BRDAC1, 8, 47), | 126 | AD5173_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0 | BRDAC1, 8, 47), |
127 | AD5270_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP | F_SPI_16BIT, | ||
128 | BRDAC0, 10, 48), | ||
129 | AD5271_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP | F_SPI_16BIT, | ||
130 | BRDAC0, 8, 49), | ||
131 | AD5272_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 10, 50), | ||
132 | AD5274_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 8, 51), | ||
125 | }; | 133 | }; |
126 | 134 | ||
127 | #define DPOT_RDAC0 0 | 135 | #define DPOT_RDAC0 0 |
@@ -165,15 +173,24 @@ enum dpot_devid { | |||
165 | /* AD5291/2/3 use special commands */ | 173 | /* AD5291/2/3 use special commands */ |
166 | #define DPOT_AD5291_RDAC 0x01 | 174 | #define DPOT_AD5291_RDAC 0x01 |
167 | #define DPOT_AD5291_READ_RDAC 0x02 | 175 | #define DPOT_AD5291_READ_RDAC 0x02 |
176 | #define DPOT_AD5291_STORE_XTPM 0x03 | ||
177 | #define DPOT_AD5291_CTRLREG 0x06 | ||
178 | #define DPOT_AD5291_UNLOCK_CMD 0x03 | ||
168 | 179 | ||
169 | /* AD524x use special commands */ | 180 | /* AD5270/1/2/4 use special commands */ |
170 | #define DPOT_AD5291_RDAC_AB 0x80 | 181 | #define DPOT_AD5270_1_2_4_RDAC 0x01 |
182 | #define DPOT_AD5270_1_2_4_READ_RDAC 0x02 | ||
183 | #define DPOT_AD5270_1_2_4_STORE_XTPM 0x03 | ||
184 | #define DPOT_AD5270_1_2_4_CTRLREG 0x07 | ||
185 | #define DPOT_AD5270_1_2_4_UNLOCK_CMD 0x03 | ||
186 | |||
187 | #define DPOT_AD5282_RDAC_AB 0x80 | ||
171 | 188 | ||
172 | #define DPOT_AD5273_FUSE 0x80 | 189 | #define DPOT_AD5273_FUSE 0x80 |
173 | #define DPOT_AD5270_2_3_FUSE 0x20 | 190 | #define DPOT_AD5170_2_3_FUSE 0x20 |
174 | #define DPOT_AD5270_2_3_OW 0x08 | 191 | #define DPOT_AD5170_2_3_OW 0x08 |
175 | #define DPOT_AD5272_3_A0 0x08 | 192 | #define DPOT_AD5172_3_A0 0x08 |
176 | #define DPOT_AD5270_2FUSE 0x80 | 193 | #define DPOT_AD5170_2FUSE 0x80 |
177 | 194 | ||
178 | struct dpot_data; | 195 | struct dpot_data; |
179 | 196 | ||
diff --git a/drivers/misc/apds9802als.c b/drivers/misc/apds9802als.c new file mode 100644 index 000000000000..81db7811cf68 --- /dev/null +++ b/drivers/misc/apds9802als.c | |||
@@ -0,0 +1,349 @@ | |||
1 | /* | ||
2 | * apds9802als.c - apds9802 ALS 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/mutex.h> | ||
31 | #include <linux/sysfs.h> | ||
32 | #include <linux/pm_runtime.h> | ||
33 | |||
34 | #define ALS_MIN_RANGE_VAL 1 | ||
35 | #define ALS_MAX_RANGE_VAL 2 | ||
36 | #define POWER_STA_ENABLE 1 | ||
37 | #define POWER_STA_DISABLE 0 | ||
38 | |||
39 | #define DRIVER_NAME "apds9802als" | ||
40 | |||
41 | struct als_data { | ||
42 | struct mutex mutex; | ||
43 | }; | ||
44 | |||
45 | static ssize_t als_sensing_range_show(struct device *dev, | ||
46 | struct device_attribute *attr, char *buf) | ||
47 | { | ||
48 | struct i2c_client *client = to_i2c_client(dev); | ||
49 | int val; | ||
50 | |||
51 | val = i2c_smbus_read_byte_data(client, 0x81); | ||
52 | if (val < 0) | ||
53 | return val; | ||
54 | if (val & 1) | ||
55 | return sprintf(buf, "4095\n"); | ||
56 | else | ||
57 | return sprintf(buf, "65535\n"); | ||
58 | } | ||
59 | |||
60 | static int als_wait_for_data_ready(struct device *dev) | ||
61 | { | ||
62 | struct i2c_client *client = to_i2c_client(dev); | ||
63 | int ret; | ||
64 | int retry = 10; | ||
65 | |||
66 | do { | ||
67 | msleep(30); | ||
68 | ret = i2c_smbus_read_byte_data(client, 0x86); | ||
69 | } while (!(ret & 0x80) && retry--); | ||
70 | |||
71 | if (!retry) { | ||
72 | dev_warn(dev, "timeout waiting for data ready\n"); | ||
73 | return -ETIMEDOUT; | ||
74 | } | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static ssize_t als_lux0_input_data_show(struct device *dev, | ||
80 | struct device_attribute *attr, char *buf) | ||
81 | { | ||
82 | struct i2c_client *client = to_i2c_client(dev); | ||
83 | struct als_data *data = i2c_get_clientdata(client); | ||
84 | int ret_val; | ||
85 | int temp; | ||
86 | |||
87 | /* Protect against parallel reads */ | ||
88 | pm_runtime_get_sync(dev); | ||
89 | mutex_lock(&data->mutex); | ||
90 | |||
91 | /* clear EOC interrupt status */ | ||
92 | i2c_smbus_write_byte(client, 0x40); | ||
93 | /* start measurement */ | ||
94 | temp = i2c_smbus_read_byte_data(client, 0x81); | ||
95 | i2c_smbus_write_byte_data(client, 0x81, temp | 0x08); | ||
96 | |||
97 | ret_val = als_wait_for_data_ready(dev); | ||
98 | if (ret_val < 0) | ||
99 | goto failed; | ||
100 | |||
101 | temp = i2c_smbus_read_byte_data(client, 0x8C); /* LSB data */ | ||
102 | if (temp < 0) { | ||
103 | ret_val = temp; | ||
104 | goto failed; | ||
105 | } | ||
106 | ret_val = i2c_smbus_read_byte_data(client, 0x8D); /* MSB data */ | ||
107 | if (ret_val < 0) | ||
108 | goto failed; | ||
109 | |||
110 | mutex_unlock(&data->mutex); | ||
111 | pm_runtime_put_sync(dev); | ||
112 | |||
113 | temp = (ret_val << 8) | temp; | ||
114 | return sprintf(buf, "%d\n", temp); | ||
115 | failed: | ||
116 | mutex_unlock(&data->mutex); | ||
117 | pm_runtime_put_sync(dev); | ||
118 | return ret_val; | ||
119 | } | ||
120 | |||
121 | static ssize_t als_sensing_range_store(struct device *dev, | ||
122 | struct device_attribute *attr, const char *buf, size_t count) | ||
123 | { | ||
124 | struct i2c_client *client = to_i2c_client(dev); | ||
125 | struct als_data *data = i2c_get_clientdata(client); | ||
126 | int ret_val; | ||
127 | unsigned long val; | ||
128 | |||
129 | if (strict_strtoul(buf, 10, &val)) | ||
130 | return -EINVAL; | ||
131 | |||
132 | if (val < 4096) | ||
133 | val = 1; | ||
134 | else if (val < 65536) | ||
135 | val = 2; | ||
136 | else | ||
137 | return -ERANGE; | ||
138 | |||
139 | pm_runtime_get_sync(dev); | ||
140 | |||
141 | /* Make sure nobody else reads/modifies/writes 0x81 while we | ||
142 | are active */ | ||
143 | mutex_lock(&data->mutex); | ||
144 | |||
145 | ret_val = i2c_smbus_read_byte_data(client, 0x81); | ||
146 | if (ret_val < 0) | ||
147 | goto fail; | ||
148 | |||
149 | /* Reset the bits before setting them */ | ||
150 | ret_val = ret_val & 0xFA; | ||
151 | |||
152 | if (val == 1) /* Setting detection range up to 4k LUX */ | ||
153 | ret_val = (ret_val | 0x01); | ||
154 | else /* Setting detection range up to 64k LUX*/ | ||
155 | ret_val = (ret_val | 0x00); | ||
156 | |||
157 | ret_val = i2c_smbus_write_byte_data(client, 0x81, ret_val); | ||
158 | |||
159 | if (ret_val >= 0) { | ||
160 | /* All OK */ | ||
161 | mutex_unlock(&data->mutex); | ||
162 | pm_runtime_put_sync(dev); | ||
163 | return count; | ||
164 | } | ||
165 | fail: | ||
166 | mutex_unlock(&data->mutex); | ||
167 | pm_runtime_put_sync(dev); | ||
168 | return ret_val; | ||
169 | } | ||
170 | |||
171 | static int als_set_power_state(struct i2c_client *client, bool on_off) | ||
172 | { | ||
173 | int ret_val; | ||
174 | struct als_data *data = i2c_get_clientdata(client); | ||
175 | |||
176 | mutex_lock(&data->mutex); | ||
177 | ret_val = i2c_smbus_read_byte_data(client, 0x80); | ||
178 | if (ret_val < 0) | ||
179 | goto fail; | ||
180 | if (on_off) | ||
181 | ret_val = ret_val | 0x01; | ||
182 | else | ||
183 | ret_val = ret_val & 0xFE; | ||
184 | ret_val = i2c_smbus_write_byte_data(client, 0x80, ret_val); | ||
185 | fail: | ||
186 | mutex_unlock(&data->mutex); | ||
187 | return ret_val; | ||
188 | } | ||
189 | |||
190 | static DEVICE_ATTR(lux0_sensor_range, S_IRUGO | S_IWUSR, | ||
191 | als_sensing_range_show, als_sensing_range_store); | ||
192 | static DEVICE_ATTR(lux0_input, S_IRUGO, als_lux0_input_data_show, NULL); | ||
193 | |||
194 | static struct attribute *mid_att_als[] = { | ||
195 | &dev_attr_lux0_sensor_range.attr, | ||
196 | &dev_attr_lux0_input.attr, | ||
197 | NULL | ||
198 | }; | ||
199 | |||
200 | static struct attribute_group m_als_gr = { | ||
201 | .name = "apds9802als", | ||
202 | .attrs = mid_att_als | ||
203 | }; | ||
204 | |||
205 | static int als_set_default_config(struct i2c_client *client) | ||
206 | { | ||
207 | int ret_val; | ||
208 | /* Write the command and then switch on */ | ||
209 | ret_val = i2c_smbus_write_byte_data(client, 0x80, 0x01); | ||
210 | if (ret_val < 0) { | ||
211 | dev_err(&client->dev, "failed default switch on write\n"); | ||
212 | return ret_val; | ||
213 | } | ||
214 | /* detection range: 1~64K Lux, maunal measurement */ | ||
215 | ret_val = i2c_smbus_write_byte_data(client, 0x81, 0x08); | ||
216 | if (ret_val < 0) | ||
217 | dev_err(&client->dev, "failed default LUX on write\n"); | ||
218 | |||
219 | /* We always get 0 for the 1st measurement after system power on, | ||
220 | * so make sure it is finished before user asks for data. | ||
221 | */ | ||
222 | als_wait_for_data_ready(&client->dev); | ||
223 | |||
224 | return ret_val; | ||
225 | } | ||
226 | |||
227 | static int apds9802als_probe(struct i2c_client *client, | ||
228 | const struct i2c_device_id *id) | ||
229 | { | ||
230 | int res; | ||
231 | struct als_data *data; | ||
232 | |||
233 | data = kzalloc(sizeof(struct als_data), GFP_KERNEL); | ||
234 | if (data == NULL) { | ||
235 | dev_err(&client->dev, "Memory allocation failed\n"); | ||
236 | return -ENOMEM; | ||
237 | } | ||
238 | i2c_set_clientdata(client, data); | ||
239 | res = sysfs_create_group(&client->dev.kobj, &m_als_gr); | ||
240 | if (res) { | ||
241 | dev_err(&client->dev, "device create file failed\n"); | ||
242 | goto als_error1; | ||
243 | } | ||
244 | dev_info(&client->dev, "ALS chip found\n"); | ||
245 | als_set_default_config(client); | ||
246 | mutex_init(&data->mutex); | ||
247 | |||
248 | pm_runtime_set_active(&client->dev); | ||
249 | pm_runtime_enable(&client->dev); | ||
250 | |||
251 | return res; | ||
252 | als_error1: | ||
253 | kfree(data); | ||
254 | return res; | ||
255 | } | ||
256 | |||
257 | static int __devexit apds9802als_remove(struct i2c_client *client) | ||
258 | { | ||
259 | struct als_data *data = i2c_get_clientdata(client); | ||
260 | |||
261 | pm_runtime_get_sync(&client->dev); | ||
262 | |||
263 | als_set_power_state(client, false); | ||
264 | sysfs_remove_group(&client->dev.kobj, &m_als_gr); | ||
265 | |||
266 | pm_runtime_disable(&client->dev); | ||
267 | pm_runtime_set_suspended(&client->dev); | ||
268 | pm_runtime_put_noidle(&client->dev); | ||
269 | |||
270 | kfree(data); | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | #ifdef CONFIG_PM | ||
275 | static int apds9802als_suspend(struct i2c_client *client, pm_message_t mesg) | ||
276 | { | ||
277 | als_set_power_state(client, false); | ||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | static int apds9802als_resume(struct i2c_client *client) | ||
282 | { | ||
283 | als_set_default_config(client); | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static int apds9802als_runtime_suspend(struct device *dev) | ||
288 | { | ||
289 | struct i2c_client *client = to_i2c_client(dev); | ||
290 | |||
291 | als_set_power_state(client, false); | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static int apds9802als_runtime_resume(struct device *dev) | ||
296 | { | ||
297 | struct i2c_client *client = to_i2c_client(dev); | ||
298 | |||
299 | als_set_power_state(client, true); | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static const struct dev_pm_ops apds9802als_pm_ops = { | ||
304 | .runtime_suspend = apds9802als_runtime_suspend, | ||
305 | .runtime_resume = apds9802als_runtime_resume, | ||
306 | }; | ||
307 | |||
308 | #define APDS9802ALS_PM_OPS (&apds9802als_pm_ops) | ||
309 | |||
310 | #else /* CONFIG_PM */ | ||
311 | #define apds9802als_suspend NULL | ||
312 | #define apds9802als_resume NULL | ||
313 | #define APDS9802ALS_PM_OPS NULL | ||
314 | #endif /* CONFIG_PM */ | ||
315 | |||
316 | static struct i2c_device_id apds9802als_id[] = { | ||
317 | { DRIVER_NAME, 0 }, | ||
318 | { } | ||
319 | }; | ||
320 | |||
321 | MODULE_DEVICE_TABLE(i2c, apds9802als_id); | ||
322 | |||
323 | static struct i2c_driver apds9802als_driver = { | ||
324 | .driver = { | ||
325 | .name = DRIVER_NAME, | ||
326 | .pm = APDS9802ALS_PM_OPS, | ||
327 | }, | ||
328 | .probe = apds9802als_probe, | ||
329 | .remove = __devexit_p(apds9802als_remove), | ||
330 | .suspend = apds9802als_suspend, | ||
331 | .resume = apds9802als_resume, | ||
332 | .id_table = apds9802als_id, | ||
333 | }; | ||
334 | |||
335 | static int __init sensor_apds9802als_init(void) | ||
336 | { | ||
337 | return i2c_add_driver(&apds9802als_driver); | ||
338 | } | ||
339 | |||
340 | static void __exit sensor_apds9802als_exit(void) | ||
341 | { | ||
342 | i2c_del_driver(&apds9802als_driver); | ||
343 | } | ||
344 | module_init(sensor_apds9802als_init); | ||
345 | module_exit(sensor_apds9802als_exit); | ||
346 | |||
347 | MODULE_AUTHOR("Anantha Narayanan <Anantha.Narayanan@intel.com"); | ||
348 | MODULE_DESCRIPTION("Avago apds9802als ALS Driver"); | ||
349 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c new file mode 100644 index 000000000000..e2a52e5cf449 --- /dev/null +++ b/drivers/misc/apds990x.c | |||
@@ -0,0 +1,1297 @@ | |||
1 | /* | ||
2 | * This file is part of the APDS990x sensor driver. | ||
3 | * Chip is combined proximity and ambient light sensor. | ||
4 | * | ||
5 | * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). | ||
6 | * | ||
7 | * Contact: Samu Onkalo <samu.p.onkalo@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
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., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/mutex.h> | ||
30 | #include <linux/regulator/consumer.h> | ||
31 | #include <linux/pm_runtime.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/wait.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/i2c/apds990x.h> | ||
36 | |||
37 | /* Register map */ | ||
38 | #define APDS990X_ENABLE 0x00 /* Enable of states and interrupts */ | ||
39 | #define APDS990X_ATIME 0x01 /* ALS ADC time */ | ||
40 | #define APDS990X_PTIME 0x02 /* Proximity ADC time */ | ||
41 | #define APDS990X_WTIME 0x03 /* Wait time */ | ||
42 | #define APDS990X_AILTL 0x04 /* ALS interrupt low threshold low byte */ | ||
43 | #define APDS990X_AILTH 0x05 /* ALS interrupt low threshold hi byte */ | ||
44 | #define APDS990X_AIHTL 0x06 /* ALS interrupt hi threshold low byte */ | ||
45 | #define APDS990X_AIHTH 0x07 /* ALS interrupt hi threshold hi byte */ | ||
46 | #define APDS990X_PILTL 0x08 /* Proximity interrupt low threshold low byte */ | ||
47 | #define APDS990X_PILTH 0x09 /* Proximity interrupt low threshold hi byte */ | ||
48 | #define APDS990X_PIHTL 0x0a /* Proximity interrupt hi threshold low byte */ | ||
49 | #define APDS990X_PIHTH 0x0b /* Proximity interrupt hi threshold hi byte */ | ||
50 | #define APDS990X_PERS 0x0c /* Interrupt persistence filters */ | ||
51 | #define APDS990X_CONFIG 0x0d /* Configuration */ | ||
52 | #define APDS990X_PPCOUNT 0x0e /* Proximity pulse count */ | ||
53 | #define APDS990X_CONTROL 0x0f /* Gain control register */ | ||
54 | #define APDS990X_REV 0x11 /* Revision Number */ | ||
55 | #define APDS990X_ID 0x12 /* Device ID */ | ||
56 | #define APDS990X_STATUS 0x13 /* Device status */ | ||
57 | #define APDS990X_CDATAL 0x14 /* Clear ADC low data register */ | ||
58 | #define APDS990X_CDATAH 0x15 /* Clear ADC high data register */ | ||
59 | #define APDS990X_IRDATAL 0x16 /* IR ADC low data register */ | ||
60 | #define APDS990X_IRDATAH 0x17 /* IR ADC high data register */ | ||
61 | #define APDS990X_PDATAL 0x18 /* Proximity ADC low data register */ | ||
62 | #define APDS990X_PDATAH 0x19 /* Proximity ADC high data register */ | ||
63 | |||
64 | /* Control */ | ||
65 | #define APDS990X_MAX_AGAIN 3 | ||
66 | |||
67 | /* Enable register */ | ||
68 | #define APDS990X_EN_PIEN (0x1 << 5) | ||
69 | #define APDS990X_EN_AIEN (0x1 << 4) | ||
70 | #define APDS990X_EN_WEN (0x1 << 3) | ||
71 | #define APDS990X_EN_PEN (0x1 << 2) | ||
72 | #define APDS990X_EN_AEN (0x1 << 1) | ||
73 | #define APDS990X_EN_PON (0x1 << 0) | ||
74 | #define APDS990X_EN_DISABLE_ALL 0 | ||
75 | |||
76 | /* Status register */ | ||
77 | #define APDS990X_ST_PINT (0x1 << 5) | ||
78 | #define APDS990X_ST_AINT (0x1 << 4) | ||
79 | |||
80 | /* I2C access types */ | ||
81 | #define APDS990x_CMD_TYPE_MASK (0x03 << 5) | ||
82 | #define APDS990x_CMD_TYPE_RB (0x00 << 5) /* Repeated byte */ | ||
83 | #define APDS990x_CMD_TYPE_INC (0x01 << 5) /* Auto increment */ | ||
84 | #define APDS990x_CMD_TYPE_SPE (0x03 << 5) /* Special function */ | ||
85 | |||
86 | #define APDS990x_ADDR_SHIFT 0 | ||
87 | #define APDS990x_CMD 0x80 | ||
88 | |||
89 | /* Interrupt ack commands */ | ||
90 | #define APDS990X_INT_ACK_ALS 0x6 | ||
91 | #define APDS990X_INT_ACK_PS 0x5 | ||
92 | #define APDS990X_INT_ACK_BOTH 0x7 | ||
93 | |||
94 | /* ptime */ | ||
95 | #define APDS990X_PTIME_DEFAULT 0xff /* Recommended conversion time 2.7ms*/ | ||
96 | |||
97 | /* wtime */ | ||
98 | #define APDS990X_WTIME_DEFAULT 0xee /* ~50ms wait time */ | ||
99 | |||
100 | #define APDS990X_TIME_TO_ADC 1024 /* One timetick as ADC count value */ | ||
101 | |||
102 | /* Persistence */ | ||
103 | #define APDS990X_APERS_SHIFT 0 | ||
104 | #define APDS990X_PPERS_SHIFT 4 | ||
105 | |||
106 | /* Supported ID:s */ | ||
107 | #define APDS990X_ID_0 0x0 | ||
108 | #define APDS990X_ID_4 0x4 | ||
109 | #define APDS990X_ID_29 0x29 | ||
110 | |||
111 | /* pgain and pdiode settings */ | ||
112 | #define APDS_PGAIN_1X 0x0 | ||
113 | #define APDS_PDIODE_IR 0x2 | ||
114 | |||
115 | #define APDS990X_LUX_OUTPUT_SCALE 10 | ||
116 | |||
117 | /* Reverse chip factors for threshold calculation */ | ||
118 | struct reverse_factors { | ||
119 | u32 afactor; | ||
120 | int cf1; | ||
121 | int irf1; | ||
122 | int cf2; | ||
123 | int irf2; | ||
124 | }; | ||
125 | |||
126 | struct apds990x_chip { | ||
127 | struct apds990x_platform_data *pdata; | ||
128 | struct i2c_client *client; | ||
129 | struct mutex mutex; /* avoid parallel access */ | ||
130 | struct regulator_bulk_data regs[2]; | ||
131 | wait_queue_head_t wait; | ||
132 | |||
133 | int prox_en; | ||
134 | bool prox_continuous_mode; | ||
135 | bool lux_wait_fresh_res; | ||
136 | |||
137 | /* Chip parameters */ | ||
138 | struct apds990x_chip_factors cf; | ||
139 | struct reverse_factors rcf; | ||
140 | u16 atime; /* als integration time */ | ||
141 | u16 arate; /* als reporting rate */ | ||
142 | u16 a_max_result; /* Max possible ADC value with current atime */ | ||
143 | u8 again_meas; /* Gain used in last measurement */ | ||
144 | u8 again_next; /* Next calculated gain */ | ||
145 | u8 pgain; | ||
146 | u8 pdiode; | ||
147 | u8 pdrive; | ||
148 | u8 lux_persistence; | ||
149 | u8 prox_persistence; | ||
150 | |||
151 | u32 lux_raw; | ||
152 | u32 lux; | ||
153 | u16 lux_clear; | ||
154 | u16 lux_ir; | ||
155 | u16 lux_calib; | ||
156 | u32 lux_thres_hi; | ||
157 | u32 lux_thres_lo; | ||
158 | |||
159 | u32 prox_thres; | ||
160 | u16 prox_data; | ||
161 | u16 prox_calib; | ||
162 | |||
163 | char chipname[10]; | ||
164 | u8 revision; | ||
165 | }; | ||
166 | |||
167 | #define APDS_CALIB_SCALER 8192 | ||
168 | #define APDS_LUX_NEUTRAL_CALIB_VALUE (1 * APDS_CALIB_SCALER) | ||
169 | #define APDS_PROX_NEUTRAL_CALIB_VALUE (1 * APDS_CALIB_SCALER) | ||
170 | |||
171 | #define APDS_PROX_DEF_THRES 600 | ||
172 | #define APDS_PROX_HYSTERESIS 50 | ||
173 | #define APDS_LUX_DEF_THRES_HI 101 | ||
174 | #define APDS_LUX_DEF_THRES_LO 100 | ||
175 | #define APDS_DEFAULT_PROX_PERS 1 | ||
176 | |||
177 | #define APDS_TIMEOUT 2000 | ||
178 | #define APDS_STARTUP_DELAY 25000 /* us */ | ||
179 | #define APDS_RANGE 65535 | ||
180 | #define APDS_PROX_RANGE 1023 | ||
181 | #define APDS_LUX_GAIN_LO_LIMIT 100 | ||
182 | #define APDS_LUX_GAIN_LO_LIMIT_STRICT 25 | ||
183 | |||
184 | #define TIMESTEP 87 /* 2.7ms is about 87 / 32 */ | ||
185 | #define TIME_STEP_SCALER 32 | ||
186 | |||
187 | #define APDS_LUX_AVERAGING_TIME 50 /* tolerates 50/60Hz ripple */ | ||
188 | #define APDS_LUX_DEFAULT_RATE 200 | ||
189 | |||
190 | static const u8 again[] = {1, 8, 16, 120}; /* ALS gain steps */ | ||
191 | static const u8 ir_currents[] = {100, 50, 25, 12}; /* IRled currents in mA */ | ||
192 | |||
193 | /* Following two tables must match i.e 10Hz rate means 1 as persistence value */ | ||
194 | static const u16 arates_hz[] = {10, 5, 2, 1}; | ||
195 | static const u8 apersis[] = {1, 2, 4, 5}; | ||
196 | |||
197 | /* Regulators */ | ||
198 | static const char reg_vcc[] = "Vdd"; | ||
199 | static const char reg_vled[] = "Vled"; | ||
200 | |||
201 | static int apds990x_read_byte(struct apds990x_chip *chip, u8 reg, u8 *data) | ||
202 | { | ||
203 | struct i2c_client *client = chip->client; | ||
204 | s32 ret; | ||
205 | |||
206 | reg &= ~APDS990x_CMD_TYPE_MASK; | ||
207 | reg |= APDS990x_CMD | APDS990x_CMD_TYPE_RB; | ||
208 | |||
209 | ret = i2c_smbus_read_byte_data(client, reg); | ||
210 | *data = ret; | ||
211 | return (int)ret; | ||
212 | } | ||
213 | |||
214 | static int apds990x_read_word(struct apds990x_chip *chip, u8 reg, u16 *data) | ||
215 | { | ||
216 | struct i2c_client *client = chip->client; | ||
217 | s32 ret; | ||
218 | |||
219 | reg &= ~APDS990x_CMD_TYPE_MASK; | ||
220 | reg |= APDS990x_CMD | APDS990x_CMD_TYPE_INC; | ||
221 | |||
222 | ret = i2c_smbus_read_word_data(client, reg); | ||
223 | *data = ret; | ||
224 | return (int)ret; | ||
225 | } | ||
226 | |||
227 | static int apds990x_write_byte(struct apds990x_chip *chip, u8 reg, u8 data) | ||
228 | { | ||
229 | struct i2c_client *client = chip->client; | ||
230 | s32 ret; | ||
231 | |||
232 | reg &= ~APDS990x_CMD_TYPE_MASK; | ||
233 | reg |= APDS990x_CMD | APDS990x_CMD_TYPE_RB; | ||
234 | |||
235 | ret = i2c_smbus_write_byte_data(client, reg, data); | ||
236 | return (int)ret; | ||
237 | } | ||
238 | |||
239 | static int apds990x_write_word(struct apds990x_chip *chip, u8 reg, u16 data) | ||
240 | { | ||
241 | struct i2c_client *client = chip->client; | ||
242 | s32 ret; | ||
243 | |||
244 | reg &= ~APDS990x_CMD_TYPE_MASK; | ||
245 | reg |= APDS990x_CMD | APDS990x_CMD_TYPE_INC; | ||
246 | |||
247 | ret = i2c_smbus_write_word_data(client, reg, data); | ||
248 | return (int)ret; | ||
249 | } | ||
250 | |||
251 | static int apds990x_mode_on(struct apds990x_chip *chip) | ||
252 | { | ||
253 | /* ALS is mandatory, proximity optional */ | ||
254 | u8 reg = APDS990X_EN_AIEN | APDS990X_EN_PON | APDS990X_EN_AEN | | ||
255 | APDS990X_EN_WEN; | ||
256 | |||
257 | if (chip->prox_en) | ||
258 | reg |= APDS990X_EN_PIEN | APDS990X_EN_PEN; | ||
259 | |||
260 | return apds990x_write_byte(chip, APDS990X_ENABLE, reg); | ||
261 | } | ||
262 | |||
263 | static u16 apds990x_lux_to_threshold(struct apds990x_chip *chip, u32 lux) | ||
264 | { | ||
265 | u32 thres; | ||
266 | u32 cpl; | ||
267 | u32 ir; | ||
268 | |||
269 | if (lux == 0) | ||
270 | return 0; | ||
271 | else if (lux == APDS_RANGE) | ||
272 | return APDS_RANGE; | ||
273 | |||
274 | /* | ||
275 | * Reported LUX value is a combination of the IR and CLEAR channel | ||
276 | * values. However, interrupt threshold is only for clear channel. | ||
277 | * This function approximates needed HW threshold value for a given | ||
278 | * LUX value in the current lightning type. | ||
279 | * IR level compared to visible light varies heavily depending on the | ||
280 | * source of the light | ||
281 | * | ||
282 | * Calculate threshold value for the next measurement period. | ||
283 | * Math: threshold = lux * cpl where | ||
284 | * cpl = atime * again / (glass_attenuation * device_factor) | ||
285 | * (count-per-lux) | ||
286 | * | ||
287 | * First remove calibration. Division by four is to avoid overflow | ||
288 | */ | ||
289 | lux = lux * (APDS_CALIB_SCALER / 4) / (chip->lux_calib / 4); | ||
290 | |||
291 | /* Multiplication by 64 is to increase accuracy */ | ||
292 | cpl = ((u32)chip->atime * (u32)again[chip->again_next] * | ||
293 | APDS_PARAM_SCALE * 64) / (chip->cf.ga * chip->cf.df); | ||
294 | |||
295 | thres = lux * cpl / 64; | ||
296 | /* | ||
297 | * Convert IR light from the latest result to match with | ||
298 | * new gain step. This helps to adapt with the current | ||
299 | * source of light. | ||
300 | */ | ||
301 | ir = (u32)chip->lux_ir * (u32)again[chip->again_next] / | ||
302 | (u32)again[chip->again_meas]; | ||
303 | |||
304 | /* | ||
305 | * Compensate count with IR light impact | ||
306 | * IAC1 > IAC2 (see apds990x_get_lux for formulas) | ||
307 | */ | ||
308 | if (chip->lux_clear * APDS_PARAM_SCALE >= | ||
309 | chip->rcf.afactor * chip->lux_ir) | ||
310 | thres = (chip->rcf.cf1 * thres + chip->rcf.irf1 * ir) / | ||
311 | APDS_PARAM_SCALE; | ||
312 | else | ||
313 | thres = (chip->rcf.cf2 * thres + chip->rcf.irf2 * ir) / | ||
314 | APDS_PARAM_SCALE; | ||
315 | |||
316 | if (thres >= chip->a_max_result) | ||
317 | thres = chip->a_max_result - 1; | ||
318 | return thres; | ||
319 | } | ||
320 | |||
321 | static inline int apds990x_set_atime(struct apds990x_chip *chip, u32 time_ms) | ||
322 | { | ||
323 | u8 reg_value; | ||
324 | |||
325 | chip->atime = time_ms; | ||
326 | /* Formula is specified in the data sheet */ | ||
327 | reg_value = 256 - ((time_ms * TIME_STEP_SCALER) / TIMESTEP); | ||
328 | /* Calculate max ADC value for given integration time */ | ||
329 | chip->a_max_result = (u16)(256 - reg_value) * APDS990X_TIME_TO_ADC; | ||
330 | return apds990x_write_byte(chip, APDS990X_ATIME, reg_value); | ||
331 | } | ||
332 | |||
333 | /* Called always with mutex locked */ | ||
334 | static int apds990x_refresh_pthres(struct apds990x_chip *chip, int data) | ||
335 | { | ||
336 | int ret, lo, hi; | ||
337 | |||
338 | /* If the chip is not in use, don't try to access it */ | ||
339 | if (pm_runtime_suspended(&chip->client->dev)) | ||
340 | return 0; | ||
341 | |||
342 | if (data < chip->prox_thres) { | ||
343 | lo = 0; | ||
344 | hi = chip->prox_thres; | ||
345 | } else { | ||
346 | lo = chip->prox_thres - APDS_PROX_HYSTERESIS; | ||
347 | if (chip->prox_continuous_mode) | ||
348 | hi = chip->prox_thres; | ||
349 | else | ||
350 | hi = APDS_RANGE; | ||
351 | } | ||
352 | |||
353 | ret = apds990x_write_word(chip, APDS990X_PILTL, lo); | ||
354 | ret |= apds990x_write_word(chip, APDS990X_PIHTL, hi); | ||
355 | return ret; | ||
356 | } | ||
357 | |||
358 | /* Called always with mutex locked */ | ||
359 | static int apds990x_refresh_athres(struct apds990x_chip *chip) | ||
360 | { | ||
361 | int ret; | ||
362 | /* If the chip is not in use, don't try to access it */ | ||
363 | if (pm_runtime_suspended(&chip->client->dev)) | ||
364 | return 0; | ||
365 | |||
366 | ret = apds990x_write_word(chip, APDS990X_AILTL, | ||
367 | apds990x_lux_to_threshold(chip, chip->lux_thres_lo)); | ||
368 | ret |= apds990x_write_word(chip, APDS990X_AIHTL, | ||
369 | apds990x_lux_to_threshold(chip, chip->lux_thres_hi)); | ||
370 | |||
371 | return ret; | ||
372 | } | ||
373 | |||
374 | /* Called always with mutex locked */ | ||
375 | static void apds990x_force_a_refresh(struct apds990x_chip *chip) | ||
376 | { | ||
377 | /* This will force ALS interrupt after the next measurement. */ | ||
378 | apds990x_write_word(chip, APDS990X_AILTL, APDS_LUX_DEF_THRES_LO); | ||
379 | apds990x_write_word(chip, APDS990X_AIHTL, APDS_LUX_DEF_THRES_HI); | ||
380 | } | ||
381 | |||
382 | /* Called always with mutex locked */ | ||
383 | static void apds990x_force_p_refresh(struct apds990x_chip *chip) | ||
384 | { | ||
385 | /* This will force proximity interrupt after the next measurement. */ | ||
386 | apds990x_write_word(chip, APDS990X_PILTL, APDS_PROX_DEF_THRES - 1); | ||
387 | apds990x_write_word(chip, APDS990X_PIHTL, APDS_PROX_DEF_THRES); | ||
388 | } | ||
389 | |||
390 | /* Called always with mutex locked */ | ||
391 | static int apds990x_calc_again(struct apds990x_chip *chip) | ||
392 | { | ||
393 | int curr_again = chip->again_meas; | ||
394 | int next_again = chip->again_meas; | ||
395 | int ret = 0; | ||
396 | |||
397 | /* Calculate suitable als gain */ | ||
398 | if (chip->lux_clear == chip->a_max_result) | ||
399 | next_again -= 2; /* ALS saturated. Decrease gain by 2 steps */ | ||
400 | else if (chip->lux_clear > chip->a_max_result / 2) | ||
401 | next_again--; | ||
402 | else if (chip->lux_clear < APDS_LUX_GAIN_LO_LIMIT_STRICT) | ||
403 | next_again += 2; /* Too dark. Increase gain by 2 steps */ | ||
404 | else if (chip->lux_clear < APDS_LUX_GAIN_LO_LIMIT) | ||
405 | next_again++; | ||
406 | |||
407 | /* Limit gain to available range */ | ||
408 | if (next_again < 0) | ||
409 | next_again = 0; | ||
410 | else if (next_again > APDS990X_MAX_AGAIN) | ||
411 | next_again = APDS990X_MAX_AGAIN; | ||
412 | |||
413 | /* Let's check can we trust the measured result */ | ||
414 | if (chip->lux_clear == chip->a_max_result) | ||
415 | /* Result can be totally garbage due to saturation */ | ||
416 | ret = -ERANGE; | ||
417 | else if (next_again != curr_again && | ||
418 | chip->lux_clear < APDS_LUX_GAIN_LO_LIMIT_STRICT) | ||
419 | /* | ||
420 | * Gain is changed and measurement result is very small. | ||
421 | * Result can be totally garbage due to underflow | ||
422 | */ | ||
423 | ret = -ERANGE; | ||
424 | |||
425 | chip->again_next = next_again; | ||
426 | apds990x_write_byte(chip, APDS990X_CONTROL, | ||
427 | (chip->pdrive << 6) | | ||
428 | (chip->pdiode << 4) | | ||
429 | (chip->pgain << 2) | | ||
430 | (chip->again_next << 0)); | ||
431 | |||
432 | /* | ||
433 | * Error means bad result -> re-measurement is needed. The forced | ||
434 | * refresh uses fastest possible persistence setting to get result | ||
435 | * as soon as possible. | ||
436 | */ | ||
437 | if (ret < 0) | ||
438 | apds990x_force_a_refresh(chip); | ||
439 | else | ||
440 | apds990x_refresh_athres(chip); | ||
441 | |||
442 | return ret; | ||
443 | } | ||
444 | |||
445 | /* Called always with mutex locked */ | ||
446 | static int apds990x_get_lux(struct apds990x_chip *chip, int clear, int ir) | ||
447 | { | ||
448 | int iac, iac1, iac2; /* IR adjusted counts */ | ||
449 | u32 lpc; /* Lux per count */ | ||
450 | |||
451 | /* Formulas: | ||
452 | * iac1 = CF1 * CLEAR_CH - IRF1 * IR_CH | ||
453 | * iac2 = CF2 * CLEAR_CH - IRF2 * IR_CH | ||
454 | */ | ||
455 | iac1 = (chip->cf.cf1 * clear - chip->cf.irf1 * ir) / APDS_PARAM_SCALE; | ||
456 | iac2 = (chip->cf.cf2 * clear - chip->cf.irf2 * ir) / APDS_PARAM_SCALE; | ||
457 | |||
458 | iac = max(iac1, iac2); | ||
459 | iac = max(iac, 0); | ||
460 | |||
461 | lpc = APDS990X_LUX_OUTPUT_SCALE * (chip->cf.df * chip->cf.ga) / | ||
462 | (u32)(again[chip->again_meas] * (u32)chip->atime); | ||
463 | |||
464 | return (iac * lpc) / APDS_PARAM_SCALE; | ||
465 | } | ||
466 | |||
467 | static int apds990x_ack_int(struct apds990x_chip *chip, u8 mode) | ||
468 | { | ||
469 | struct i2c_client *client = chip->client; | ||
470 | s32 ret; | ||
471 | u8 reg = APDS990x_CMD | APDS990x_CMD_TYPE_SPE; | ||
472 | |||
473 | switch (mode & (APDS990X_ST_AINT | APDS990X_ST_PINT)) { | ||
474 | case APDS990X_ST_AINT: | ||
475 | reg |= APDS990X_INT_ACK_ALS; | ||
476 | break; | ||
477 | case APDS990X_ST_PINT: | ||
478 | reg |= APDS990X_INT_ACK_PS; | ||
479 | break; | ||
480 | default: | ||
481 | reg |= APDS990X_INT_ACK_BOTH; | ||
482 | break; | ||
483 | } | ||
484 | |||
485 | ret = i2c_smbus_read_byte_data(client, reg); | ||
486 | return (int)ret; | ||
487 | } | ||
488 | |||
489 | static irqreturn_t apds990x_irq(int irq, void *data) | ||
490 | { | ||
491 | struct apds990x_chip *chip = data; | ||
492 | u8 status; | ||
493 | |||
494 | apds990x_read_byte(chip, APDS990X_STATUS, &status); | ||
495 | apds990x_ack_int(chip, status); | ||
496 | |||
497 | mutex_lock(&chip->mutex); | ||
498 | if (!pm_runtime_suspended(&chip->client->dev)) { | ||
499 | if (status & APDS990X_ST_AINT) { | ||
500 | apds990x_read_word(chip, APDS990X_CDATAL, | ||
501 | &chip->lux_clear); | ||
502 | apds990x_read_word(chip, APDS990X_IRDATAL, | ||
503 | &chip->lux_ir); | ||
504 | /* Store used gain for calculations */ | ||
505 | chip->again_meas = chip->again_next; | ||
506 | |||
507 | chip->lux_raw = apds990x_get_lux(chip, | ||
508 | chip->lux_clear, | ||
509 | chip->lux_ir); | ||
510 | |||
511 | if (apds990x_calc_again(chip) == 0) { | ||
512 | /* Result is valid */ | ||
513 | chip->lux = chip->lux_raw; | ||
514 | chip->lux_wait_fresh_res = false; | ||
515 | wake_up(&chip->wait); | ||
516 | sysfs_notify(&chip->client->dev.kobj, | ||
517 | NULL, "lux0_input"); | ||
518 | } | ||
519 | } | ||
520 | |||
521 | if ((status & APDS990X_ST_PINT) && chip->prox_en) { | ||
522 | u16 clr_ch; | ||
523 | |||
524 | apds990x_read_word(chip, APDS990X_CDATAL, &clr_ch); | ||
525 | /* | ||
526 | * If ALS channel is saturated at min gain, | ||
527 | * proximity gives false posivite values. | ||
528 | * Just ignore them. | ||
529 | */ | ||
530 | if (chip->again_meas == 0 && | ||
531 | clr_ch == chip->a_max_result) | ||
532 | chip->prox_data = 0; | ||
533 | else | ||
534 | apds990x_read_word(chip, | ||
535 | APDS990X_PDATAL, | ||
536 | &chip->prox_data); | ||
537 | |||
538 | apds990x_refresh_pthres(chip, chip->prox_data); | ||
539 | if (chip->prox_data < chip->prox_thres) | ||
540 | chip->prox_data = 0; | ||
541 | else if (!chip->prox_continuous_mode) | ||
542 | chip->prox_data = APDS_PROX_RANGE; | ||
543 | sysfs_notify(&chip->client->dev.kobj, | ||
544 | NULL, "prox0_raw"); | ||
545 | } | ||
546 | } | ||
547 | mutex_unlock(&chip->mutex); | ||
548 | return IRQ_HANDLED; | ||
549 | } | ||
550 | |||
551 | static int apds990x_configure(struct apds990x_chip *chip) | ||
552 | { | ||
553 | /* It is recommended to use disabled mode during these operations */ | ||
554 | apds990x_write_byte(chip, APDS990X_ENABLE, APDS990X_EN_DISABLE_ALL); | ||
555 | |||
556 | /* conversion and wait times for different state machince states */ | ||
557 | apds990x_write_byte(chip, APDS990X_PTIME, APDS990X_PTIME_DEFAULT); | ||
558 | apds990x_write_byte(chip, APDS990X_WTIME, APDS990X_WTIME_DEFAULT); | ||
559 | apds990x_set_atime(chip, APDS_LUX_AVERAGING_TIME); | ||
560 | |||
561 | apds990x_write_byte(chip, APDS990X_CONFIG, 0); | ||
562 | |||
563 | /* Persistence levels */ | ||
564 | apds990x_write_byte(chip, APDS990X_PERS, | ||
565 | (chip->lux_persistence << APDS990X_APERS_SHIFT) | | ||
566 | (chip->prox_persistence << APDS990X_PPERS_SHIFT)); | ||
567 | |||
568 | apds990x_write_byte(chip, APDS990X_PPCOUNT, chip->pdata->ppcount); | ||
569 | |||
570 | /* Start with relatively small gain */ | ||
571 | chip->again_meas = 1; | ||
572 | chip->again_next = 1; | ||
573 | apds990x_write_byte(chip, APDS990X_CONTROL, | ||
574 | (chip->pdrive << 6) | | ||
575 | (chip->pdiode << 4) | | ||
576 | (chip->pgain << 2) | | ||
577 | (chip->again_next << 0)); | ||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | static int apds990x_detect(struct apds990x_chip *chip) | ||
582 | { | ||
583 | struct i2c_client *client = chip->client; | ||
584 | int ret; | ||
585 | u8 id; | ||
586 | |||
587 | ret = apds990x_read_byte(chip, APDS990X_ID, &id); | ||
588 | if (ret < 0) { | ||
589 | dev_err(&client->dev, "ID read failed\n"); | ||
590 | return ret; | ||
591 | } | ||
592 | |||
593 | ret = apds990x_read_byte(chip, APDS990X_REV, &chip->revision); | ||
594 | if (ret < 0) { | ||
595 | dev_err(&client->dev, "REV read failed\n"); | ||
596 | return ret; | ||
597 | } | ||
598 | |||
599 | switch (id) { | ||
600 | case APDS990X_ID_0: | ||
601 | case APDS990X_ID_4: | ||
602 | case APDS990X_ID_29: | ||
603 | snprintf(chip->chipname, sizeof(chip->chipname), "APDS-990x"); | ||
604 | break; | ||
605 | default: | ||
606 | ret = -ENODEV; | ||
607 | break; | ||
608 | } | ||
609 | return ret; | ||
610 | } | ||
611 | |||
612 | #if defined(CONFIG_PM) || defined(CONFIG_PM_RUNTIME) | ||
613 | static int apds990x_chip_on(struct apds990x_chip *chip) | ||
614 | { | ||
615 | int err = regulator_bulk_enable(ARRAY_SIZE(chip->regs), | ||
616 | chip->regs); | ||
617 | if (err < 0) | ||
618 | return err; | ||
619 | |||
620 | usleep_range(APDS_STARTUP_DELAY, 2 * APDS_STARTUP_DELAY); | ||
621 | |||
622 | /* Refresh all configs in case of regulators were off */ | ||
623 | chip->prox_data = 0; | ||
624 | apds990x_configure(chip); | ||
625 | apds990x_mode_on(chip); | ||
626 | return 0; | ||
627 | } | ||
628 | #endif | ||
629 | |||
630 | static int apds990x_chip_off(struct apds990x_chip *chip) | ||
631 | { | ||
632 | apds990x_write_byte(chip, APDS990X_ENABLE, APDS990X_EN_DISABLE_ALL); | ||
633 | regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs); | ||
634 | return 0; | ||
635 | } | ||
636 | |||
637 | static ssize_t apds990x_lux_show(struct device *dev, | ||
638 | struct device_attribute *attr, char *buf) | ||
639 | { | ||
640 | struct apds990x_chip *chip = dev_get_drvdata(dev); | ||
641 | ssize_t ret; | ||
642 | u32 result; | ||
643 | long timeout; | ||
644 | |||
645 | if (pm_runtime_suspended(dev)) | ||
646 | return -EIO; | ||
647 | |||
648 | timeout = wait_event_interruptible_timeout(chip->wait, | ||
649 | !chip->lux_wait_fresh_res, | ||
650 | msecs_to_jiffies(APDS_TIMEOUT)); | ||
651 | if (!timeout) | ||
652 | return -EIO; | ||
653 | |||
654 | mutex_lock(&chip->mutex); | ||
655 | result = (chip->lux * chip->lux_calib) / APDS_CALIB_SCALER; | ||
656 | if (result > (APDS_RANGE * APDS990X_LUX_OUTPUT_SCALE)) | ||
657 | result = APDS_RANGE * APDS990X_LUX_OUTPUT_SCALE; | ||
658 | |||
659 | ret = sprintf(buf, "%d.%d\n", | ||
660 | result / APDS990X_LUX_OUTPUT_SCALE, | ||
661 | result % APDS990X_LUX_OUTPUT_SCALE); | ||
662 | mutex_unlock(&chip->mutex); | ||
663 | return ret; | ||
664 | } | ||
665 | |||
666 | static DEVICE_ATTR(lux0_input, S_IRUGO, apds990x_lux_show, NULL); | ||
667 | |||
668 | static ssize_t apds990x_lux_range_show(struct device *dev, | ||
669 | struct device_attribute *attr, char *buf) | ||
670 | { | ||
671 | return sprintf(buf, "%u\n", APDS_RANGE); | ||
672 | } | ||
673 | |||
674 | static DEVICE_ATTR(lux0_sensor_range, S_IRUGO, apds990x_lux_range_show, NULL); | ||
675 | |||
676 | static ssize_t apds990x_lux_calib_format_show(struct device *dev, | ||
677 | struct device_attribute *attr, char *buf) | ||
678 | { | ||
679 | return sprintf(buf, "%u\n", APDS_CALIB_SCALER); | ||
680 | } | ||
681 | |||
682 | static DEVICE_ATTR(lux0_calibscale_default, S_IRUGO, | ||
683 | apds990x_lux_calib_format_show, NULL); | ||
684 | |||
685 | static ssize_t apds990x_lux_calib_show(struct device *dev, | ||
686 | struct device_attribute *attr, char *buf) | ||
687 | { | ||
688 | struct apds990x_chip *chip = dev_get_drvdata(dev); | ||
689 | |||
690 | return sprintf(buf, "%u\n", chip->lux_calib); | ||
691 | } | ||
692 | |||
693 | static ssize_t apds990x_lux_calib_store(struct device *dev, | ||
694 | struct device_attribute *attr, | ||
695 | const char *buf, size_t len) | ||
696 | { | ||
697 | struct apds990x_chip *chip = dev_get_drvdata(dev); | ||
698 | unsigned long value; | ||
699 | |||
700 | if (strict_strtoul(buf, 0, &value)) | ||
701 | return -EINVAL; | ||
702 | |||
703 | if (chip->lux_calib > APDS_RANGE) | ||
704 | return -EINVAL; | ||
705 | |||
706 | chip->lux_calib = value; | ||
707 | |||
708 | return len; | ||
709 | } | ||
710 | |||
711 | static DEVICE_ATTR(lux0_calibscale, S_IRUGO | S_IWUSR, apds990x_lux_calib_show, | ||
712 | apds990x_lux_calib_store); | ||
713 | |||
714 | static ssize_t apds990x_rate_avail(struct device *dev, | ||
715 | struct device_attribute *attr, char *buf) | ||
716 | { | ||
717 | int i; | ||
718 | int pos = 0; | ||
719 | for (i = 0; i < ARRAY_SIZE(arates_hz); i++) | ||
720 | pos += sprintf(buf + pos, "%d ", arates_hz[i]); | ||
721 | sprintf(buf + pos - 1, "\n"); | ||
722 | return pos; | ||
723 | } | ||
724 | |||
725 | static ssize_t apds990x_rate_show(struct device *dev, | ||
726 | struct device_attribute *attr, char *buf) | ||
727 | { | ||
728 | struct apds990x_chip *chip = dev_get_drvdata(dev); | ||
729 | return sprintf(buf, "%d\n", chip->arate); | ||
730 | } | ||
731 | |||
732 | static int apds990x_set_arate(struct apds990x_chip *chip, int rate) | ||
733 | { | ||
734 | int i; | ||
735 | |||
736 | for (i = 0; i < ARRAY_SIZE(arates_hz); i++) | ||
737 | if (rate >= arates_hz[i]) | ||
738 | break; | ||
739 | |||
740 | if (i == ARRAY_SIZE(arates_hz)) | ||
741 | return -EINVAL; | ||
742 | |||
743 | /* Pick up corresponding persistence value */ | ||
744 | chip->lux_persistence = apersis[i]; | ||
745 | chip->arate = arates_hz[i]; | ||
746 | |||
747 | /* If the chip is not in use, don't try to access it */ | ||
748 | if (pm_runtime_suspended(&chip->client->dev)) | ||
749 | return 0; | ||
750 | |||
751 | /* Persistence levels */ | ||
752 | return apds990x_write_byte(chip, APDS990X_PERS, | ||
753 | (chip->lux_persistence << APDS990X_APERS_SHIFT) | | ||
754 | (chip->prox_persistence << APDS990X_PPERS_SHIFT)); | ||
755 | } | ||
756 | |||
757 | static ssize_t apds990x_rate_store(struct device *dev, | ||
758 | struct device_attribute *attr, | ||
759 | const char *buf, size_t len) | ||
760 | { | ||
761 | struct apds990x_chip *chip = dev_get_drvdata(dev); | ||
762 | unsigned long value; | ||
763 | int ret; | ||
764 | |||
765 | if (strict_strtoul(buf, 0, &value)) | ||
766 | return -EINVAL; | ||
767 | |||
768 | mutex_lock(&chip->mutex); | ||
769 | ret = apds990x_set_arate(chip, value); | ||
770 | mutex_unlock(&chip->mutex); | ||
771 | |||
772 | if (ret < 0) | ||
773 | return ret; | ||
774 | return len; | ||
775 | } | ||
776 | |||
777 | static DEVICE_ATTR(lux0_rate_avail, S_IRUGO, apds990x_rate_avail, NULL); | ||
778 | |||
779 | static DEVICE_ATTR(lux0_rate, S_IRUGO | S_IWUSR, apds990x_rate_show, | ||
780 | apds990x_rate_store); | ||
781 | |||
782 | static ssize_t apds990x_prox_show(struct device *dev, | ||
783 | struct device_attribute *attr, char *buf) | ||
784 | { | ||
785 | ssize_t ret; | ||
786 | struct apds990x_chip *chip = dev_get_drvdata(dev); | ||
787 | if (pm_runtime_suspended(dev) || !chip->prox_en) | ||
788 | return -EIO; | ||
789 | |||
790 | mutex_lock(&chip->mutex); | ||
791 | ret = sprintf(buf, "%d\n", chip->prox_data); | ||
792 | mutex_unlock(&chip->mutex); | ||
793 | return ret; | ||
794 | } | ||
795 | |||
796 | static DEVICE_ATTR(prox0_raw, S_IRUGO, apds990x_prox_show, NULL); | ||
797 | |||
798 | static ssize_t apds990x_prox_range_show(struct device *dev, | ||
799 | struct device_attribute *attr, char *buf) | ||
800 | { | ||
801 | return sprintf(buf, "%u\n", APDS_PROX_RANGE); | ||
802 | } | ||
803 | |||
804 | static DEVICE_ATTR(prox0_sensor_range, S_IRUGO, apds990x_prox_range_show, NULL); | ||
805 | |||
806 | static ssize_t apds990x_prox_enable_show(struct device *dev, | ||
807 | struct device_attribute *attr, char *buf) | ||
808 | { | ||
809 | struct apds990x_chip *chip = dev_get_drvdata(dev); | ||
810 | return sprintf(buf, "%d\n", chip->prox_en); | ||
811 | } | ||
812 | |||
813 | static ssize_t apds990x_prox_enable_store(struct device *dev, | ||
814 | struct device_attribute *attr, | ||
815 | const char *buf, size_t len) | ||
816 | { | ||
817 | struct apds990x_chip *chip = dev_get_drvdata(dev); | ||
818 | unsigned long value; | ||
819 | |||
820 | if (strict_strtoul(buf, 0, &value)) | ||
821 | return -EINVAL; | ||
822 | |||
823 | mutex_lock(&chip->mutex); | ||
824 | |||
825 | if (!chip->prox_en) | ||
826 | chip->prox_data = 0; | ||
827 | |||
828 | if (value) | ||
829 | chip->prox_en++; | ||
830 | else if (chip->prox_en > 0) | ||
831 | chip->prox_en--; | ||
832 | |||
833 | if (!pm_runtime_suspended(dev)) | ||
834 | apds990x_mode_on(chip); | ||
835 | mutex_unlock(&chip->mutex); | ||
836 | return len; | ||
837 | } | ||
838 | |||
839 | static DEVICE_ATTR(prox0_raw_en, S_IRUGO | S_IWUSR, apds990x_prox_enable_show, | ||
840 | apds990x_prox_enable_store); | ||
841 | |||
842 | static const char reporting_modes[][9] = {"trigger", "periodic"}; | ||
843 | |||
844 | static ssize_t apds990x_prox_reporting_mode_show(struct device *dev, | ||
845 | struct device_attribute *attr, char *buf) | ||
846 | { | ||
847 | struct apds990x_chip *chip = dev_get_drvdata(dev); | ||
848 | return sprintf(buf, "%s\n", | ||
849 | reporting_modes[!!chip->prox_continuous_mode]); | ||
850 | } | ||
851 | |||
852 | static ssize_t apds990x_prox_reporting_mode_store(struct device *dev, | ||
853 | struct device_attribute *attr, | ||
854 | const char *buf, size_t len) | ||
855 | { | ||
856 | struct apds990x_chip *chip = dev_get_drvdata(dev); | ||
857 | |||
858 | if (sysfs_streq(buf, reporting_modes[0])) | ||
859 | chip->prox_continuous_mode = 0; | ||
860 | else if (sysfs_streq(buf, reporting_modes[1])) | ||
861 | chip->prox_continuous_mode = 1; | ||
862 | else | ||
863 | return -EINVAL; | ||
864 | return len; | ||
865 | } | ||
866 | |||
867 | static DEVICE_ATTR(prox0_reporting_mode, S_IRUGO | S_IWUSR, | ||
868 | apds990x_prox_reporting_mode_show, | ||
869 | apds990x_prox_reporting_mode_store); | ||
870 | |||
871 | static ssize_t apds990x_prox_reporting_avail_show(struct device *dev, | ||
872 | struct device_attribute *attr, char *buf) | ||
873 | { | ||
874 | return sprintf(buf, "%s %s\n", reporting_modes[0], reporting_modes[1]); | ||
875 | } | ||
876 | |||
877 | static DEVICE_ATTR(prox0_reporting_mode_avail, S_IRUGO | S_IWUSR, | ||
878 | apds990x_prox_reporting_avail_show, NULL); | ||
879 | |||
880 | |||
881 | static ssize_t apds990x_lux_thresh_above_show(struct device *dev, | ||
882 | struct device_attribute *attr, char *buf) | ||
883 | { | ||
884 | struct apds990x_chip *chip = dev_get_drvdata(dev); | ||
885 | return sprintf(buf, "%d\n", chip->lux_thres_hi); | ||
886 | } | ||
887 | |||
888 | static ssize_t apds990x_lux_thresh_below_show(struct device *dev, | ||
889 | struct device_attribute *attr, char *buf) | ||
890 | { | ||
891 | struct apds990x_chip *chip = dev_get_drvdata(dev); | ||
892 | return sprintf(buf, "%d\n", chip->lux_thres_lo); | ||
893 | } | ||
894 | |||
895 | static ssize_t apds990x_set_lux_thresh(struct apds990x_chip *chip, u32 *target, | ||
896 | const char *buf) | ||
897 | { | ||
898 | int ret = 0; | ||
899 | unsigned long thresh; | ||
900 | |||
901 | if (strict_strtoul(buf, 0, &thresh)) | ||
902 | return -EINVAL; | ||
903 | |||
904 | if (thresh > APDS_RANGE) | ||
905 | return -EINVAL; | ||
906 | |||
907 | mutex_lock(&chip->mutex); | ||
908 | *target = thresh; | ||
909 | /* | ||
910 | * Don't update values in HW if we are still waiting for | ||
911 | * first interrupt to come after device handle open call. | ||
912 | */ | ||
913 | if (!chip->lux_wait_fresh_res) | ||
914 | apds990x_refresh_athres(chip); | ||
915 | mutex_unlock(&chip->mutex); | ||
916 | return ret; | ||
917 | |||
918 | } | ||
919 | |||
920 | static ssize_t apds990x_lux_thresh_above_store(struct device *dev, | ||
921 | struct device_attribute *attr, | ||
922 | const char *buf, size_t len) | ||
923 | { | ||
924 | struct apds990x_chip *chip = dev_get_drvdata(dev); | ||
925 | int ret = apds990x_set_lux_thresh(chip, &chip->lux_thres_hi, buf); | ||
926 | if (ret < 0) | ||
927 | return ret; | ||
928 | return len; | ||
929 | } | ||
930 | |||
931 | static ssize_t apds990x_lux_thresh_below_store(struct device *dev, | ||
932 | struct device_attribute *attr, | ||
933 | const char *buf, size_t len) | ||
934 | { | ||
935 | struct apds990x_chip *chip = dev_get_drvdata(dev); | ||
936 | int ret = apds990x_set_lux_thresh(chip, &chip->lux_thres_lo, buf); | ||
937 | if (ret < 0) | ||
938 | return ret; | ||
939 | return len; | ||
940 | } | ||
941 | |||
942 | static DEVICE_ATTR(lux0_thresh_above_value, S_IRUGO | S_IWUSR, | ||
943 | apds990x_lux_thresh_above_show, | ||
944 | apds990x_lux_thresh_above_store); | ||
945 | |||
946 | static DEVICE_ATTR(lux0_thresh_below_value, S_IRUGO | S_IWUSR, | ||
947 | apds990x_lux_thresh_below_show, | ||
948 | apds990x_lux_thresh_below_store); | ||
949 | |||
950 | static ssize_t apds990x_prox_threshold_show(struct device *dev, | ||
951 | struct device_attribute *attr, char *buf) | ||
952 | { | ||
953 | struct apds990x_chip *chip = dev_get_drvdata(dev); | ||
954 | return sprintf(buf, "%d\n", chip->prox_thres); | ||
955 | } | ||
956 | |||
957 | static ssize_t apds990x_prox_threshold_store(struct device *dev, | ||
958 | struct device_attribute *attr, | ||
959 | const char *buf, size_t len) | ||
960 | { | ||
961 | struct apds990x_chip *chip = dev_get_drvdata(dev); | ||
962 | unsigned long value; | ||
963 | |||
964 | if (strict_strtoul(buf, 0, &value)) | ||
965 | return -EINVAL; | ||
966 | |||
967 | if ((value > APDS_RANGE) || (value == 0) || | ||
968 | (value < APDS_PROX_HYSTERESIS)) | ||
969 | return -EINVAL; | ||
970 | |||
971 | mutex_lock(&chip->mutex); | ||
972 | chip->prox_thres = value; | ||
973 | |||
974 | apds990x_force_p_refresh(chip); | ||
975 | mutex_unlock(&chip->mutex); | ||
976 | return len; | ||
977 | } | ||
978 | |||
979 | static DEVICE_ATTR(prox0_thresh_above_value, S_IRUGO | S_IWUSR, | ||
980 | apds990x_prox_threshold_show, | ||
981 | apds990x_prox_threshold_store); | ||
982 | |||
983 | static ssize_t apds990x_power_state_show(struct device *dev, | ||
984 | struct device_attribute *attr, char *buf) | ||
985 | { | ||
986 | return sprintf(buf, "%d\n", !pm_runtime_suspended(dev)); | ||
987 | return 0; | ||
988 | } | ||
989 | |||
990 | static ssize_t apds990x_power_state_store(struct device *dev, | ||
991 | struct device_attribute *attr, | ||
992 | const char *buf, size_t len) | ||
993 | { | ||
994 | struct apds990x_chip *chip = dev_get_drvdata(dev); | ||
995 | unsigned long value; | ||
996 | |||
997 | if (strict_strtoul(buf, 0, &value)) | ||
998 | return -EINVAL; | ||
999 | if (value) { | ||
1000 | pm_runtime_get_sync(dev); | ||
1001 | mutex_lock(&chip->mutex); | ||
1002 | chip->lux_wait_fresh_res = true; | ||
1003 | apds990x_force_a_refresh(chip); | ||
1004 | apds990x_force_p_refresh(chip); | ||
1005 | mutex_unlock(&chip->mutex); | ||
1006 | } else { | ||
1007 | if (!pm_runtime_suspended(dev)) | ||
1008 | pm_runtime_put(dev); | ||
1009 | } | ||
1010 | return len; | ||
1011 | } | ||
1012 | |||
1013 | static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, | ||
1014 | apds990x_power_state_show, | ||
1015 | apds990x_power_state_store); | ||
1016 | |||
1017 | static ssize_t apds990x_chip_id_show(struct device *dev, | ||
1018 | struct device_attribute *attr, char *buf) | ||
1019 | { | ||
1020 | struct apds990x_chip *chip = dev_get_drvdata(dev); | ||
1021 | return sprintf(buf, "%s %d\n", chip->chipname, chip->revision); | ||
1022 | } | ||
1023 | |||
1024 | static DEVICE_ATTR(chip_id, S_IRUGO, apds990x_chip_id_show, NULL); | ||
1025 | |||
1026 | static struct attribute *sysfs_attrs_ctrl[] = { | ||
1027 | &dev_attr_lux0_calibscale.attr, | ||
1028 | &dev_attr_lux0_calibscale_default.attr, | ||
1029 | &dev_attr_lux0_input.attr, | ||
1030 | &dev_attr_lux0_sensor_range.attr, | ||
1031 | &dev_attr_lux0_rate.attr, | ||
1032 | &dev_attr_lux0_rate_avail.attr, | ||
1033 | &dev_attr_lux0_thresh_above_value.attr, | ||
1034 | &dev_attr_lux0_thresh_below_value.attr, | ||
1035 | &dev_attr_prox0_raw_en.attr, | ||
1036 | &dev_attr_prox0_raw.attr, | ||
1037 | &dev_attr_prox0_sensor_range.attr, | ||
1038 | &dev_attr_prox0_thresh_above_value.attr, | ||
1039 | &dev_attr_prox0_reporting_mode.attr, | ||
1040 | &dev_attr_prox0_reporting_mode_avail.attr, | ||
1041 | &dev_attr_chip_id.attr, | ||
1042 | &dev_attr_power_state.attr, | ||
1043 | NULL | ||
1044 | }; | ||
1045 | |||
1046 | static struct attribute_group apds990x_attribute_group[] = { | ||
1047 | {.attrs = sysfs_attrs_ctrl }, | ||
1048 | }; | ||
1049 | |||
1050 | static int __devinit apds990x_probe(struct i2c_client *client, | ||
1051 | const struct i2c_device_id *id) | ||
1052 | { | ||
1053 | struct apds990x_chip *chip; | ||
1054 | int err; | ||
1055 | |||
1056 | chip = kzalloc(sizeof *chip, GFP_KERNEL); | ||
1057 | if (!chip) | ||
1058 | return -ENOMEM; | ||
1059 | |||
1060 | i2c_set_clientdata(client, chip); | ||
1061 | chip->client = client; | ||
1062 | |||
1063 | init_waitqueue_head(&chip->wait); | ||
1064 | mutex_init(&chip->mutex); | ||
1065 | chip->pdata = client->dev.platform_data; | ||
1066 | |||
1067 | if (chip->pdata == NULL) { | ||
1068 | dev_err(&client->dev, "platform data is mandatory\n"); | ||
1069 | err = -EINVAL; | ||
1070 | goto fail1; | ||
1071 | } | ||
1072 | |||
1073 | if (chip->pdata->cf.ga == 0) { | ||
1074 | /* set uncovered sensor default parameters */ | ||
1075 | chip->cf.ga = 1966; /* 0.48 * APDS_PARAM_SCALE */ | ||
1076 | chip->cf.cf1 = 4096; /* 1.00 * APDS_PARAM_SCALE */ | ||
1077 | chip->cf.irf1 = 9134; /* 2.23 * APDS_PARAM_SCALE */ | ||
1078 | chip->cf.cf2 = 2867; /* 0.70 * APDS_PARAM_SCALE */ | ||
1079 | chip->cf.irf2 = 5816; /* 1.42 * APDS_PARAM_SCALE */ | ||
1080 | chip->cf.df = 52; | ||
1081 | } else { | ||
1082 | chip->cf = chip->pdata->cf; | ||
1083 | } | ||
1084 | |||
1085 | /* precalculate inverse chip factors for threshold control */ | ||
1086 | chip->rcf.afactor = | ||
1087 | (chip->cf.irf1 - chip->cf.irf2) * APDS_PARAM_SCALE / | ||
1088 | (chip->cf.cf1 - chip->cf.cf2); | ||
1089 | chip->rcf.cf1 = APDS_PARAM_SCALE * APDS_PARAM_SCALE / | ||
1090 | chip->cf.cf1; | ||
1091 | chip->rcf.irf1 = chip->cf.irf1 * APDS_PARAM_SCALE / | ||
1092 | chip->cf.cf1; | ||
1093 | chip->rcf.cf2 = APDS_PARAM_SCALE * APDS_PARAM_SCALE / | ||
1094 | chip->cf.cf2; | ||
1095 | chip->rcf.irf2 = chip->cf.irf2 * APDS_PARAM_SCALE / | ||
1096 | chip->cf.cf2; | ||
1097 | |||
1098 | /* Set something to start with */ | ||
1099 | chip->lux_thres_hi = APDS_LUX_DEF_THRES_HI; | ||
1100 | chip->lux_thres_lo = APDS_LUX_DEF_THRES_LO; | ||
1101 | chip->lux_calib = APDS_LUX_NEUTRAL_CALIB_VALUE; | ||
1102 | |||
1103 | chip->prox_thres = APDS_PROX_DEF_THRES; | ||
1104 | chip->pdrive = chip->pdata->pdrive; | ||
1105 | chip->pdiode = APDS_PDIODE_IR; | ||
1106 | chip->pgain = APDS_PGAIN_1X; | ||
1107 | chip->prox_calib = APDS_PROX_NEUTRAL_CALIB_VALUE; | ||
1108 | chip->prox_persistence = APDS_DEFAULT_PROX_PERS; | ||
1109 | chip->prox_continuous_mode = false; | ||
1110 | |||
1111 | chip->regs[0].supply = reg_vcc; | ||
1112 | chip->regs[1].supply = reg_vled; | ||
1113 | |||
1114 | err = regulator_bulk_get(&client->dev, | ||
1115 | ARRAY_SIZE(chip->regs), chip->regs); | ||
1116 | if (err < 0) { | ||
1117 | dev_err(&client->dev, "Cannot get regulators\n"); | ||
1118 | goto fail1; | ||
1119 | } | ||
1120 | |||
1121 | err = regulator_bulk_enable(ARRAY_SIZE(chip->regs), chip->regs); | ||
1122 | if (err < 0) { | ||
1123 | dev_err(&client->dev, "Cannot enable regulators\n"); | ||
1124 | goto fail2; | ||
1125 | } | ||
1126 | |||
1127 | usleep_range(APDS_STARTUP_DELAY, 2 * APDS_STARTUP_DELAY); | ||
1128 | |||
1129 | err = apds990x_detect(chip); | ||
1130 | if (err < 0) { | ||
1131 | dev_err(&client->dev, "APDS990X not found\n"); | ||
1132 | goto fail3; | ||
1133 | } | ||
1134 | |||
1135 | pm_runtime_set_active(&client->dev); | ||
1136 | |||
1137 | apds990x_configure(chip); | ||
1138 | apds990x_set_arate(chip, APDS_LUX_DEFAULT_RATE); | ||
1139 | apds990x_mode_on(chip); | ||
1140 | |||
1141 | pm_runtime_enable(&client->dev); | ||
1142 | |||
1143 | if (chip->pdata->setup_resources) { | ||
1144 | err = chip->pdata->setup_resources(); | ||
1145 | if (err) { | ||
1146 | err = -EINVAL; | ||
1147 | goto fail3; | ||
1148 | } | ||
1149 | } | ||
1150 | |||
1151 | err = sysfs_create_group(&chip->client->dev.kobj, | ||
1152 | apds990x_attribute_group); | ||
1153 | if (err < 0) { | ||
1154 | dev_err(&chip->client->dev, "Sysfs registration failed\n"); | ||
1155 | goto fail4; | ||
1156 | } | ||
1157 | |||
1158 | err = request_threaded_irq(client->irq, NULL, | ||
1159 | apds990x_irq, | ||
1160 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW | | ||
1161 | IRQF_ONESHOT, | ||
1162 | "apds990x", chip); | ||
1163 | if (err) { | ||
1164 | dev_err(&client->dev, "could not get IRQ %d\n", | ||
1165 | client->irq); | ||
1166 | goto fail5; | ||
1167 | } | ||
1168 | return err; | ||
1169 | fail5: | ||
1170 | sysfs_remove_group(&chip->client->dev.kobj, | ||
1171 | &apds990x_attribute_group[0]); | ||
1172 | fail4: | ||
1173 | if (chip->pdata && chip->pdata->release_resources) | ||
1174 | chip->pdata->release_resources(); | ||
1175 | fail3: | ||
1176 | regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs); | ||
1177 | fail2: | ||
1178 | regulator_bulk_free(ARRAY_SIZE(chip->regs), chip->regs); | ||
1179 | fail1: | ||
1180 | kfree(chip); | ||
1181 | return err; | ||
1182 | } | ||
1183 | |||
1184 | static int __devexit apds990x_remove(struct i2c_client *client) | ||
1185 | { | ||
1186 | struct apds990x_chip *chip = i2c_get_clientdata(client); | ||
1187 | |||
1188 | free_irq(client->irq, chip); | ||
1189 | sysfs_remove_group(&chip->client->dev.kobj, | ||
1190 | apds990x_attribute_group); | ||
1191 | |||
1192 | if (chip->pdata && chip->pdata->release_resources) | ||
1193 | chip->pdata->release_resources(); | ||
1194 | |||
1195 | if (!pm_runtime_suspended(&client->dev)) | ||
1196 | apds990x_chip_off(chip); | ||
1197 | |||
1198 | pm_runtime_disable(&client->dev); | ||
1199 | pm_runtime_set_suspended(&client->dev); | ||
1200 | |||
1201 | regulator_bulk_free(ARRAY_SIZE(chip->regs), chip->regs); | ||
1202 | |||
1203 | kfree(chip); | ||
1204 | return 0; | ||
1205 | } | ||
1206 | |||
1207 | #ifdef CONFIG_PM | ||
1208 | static int apds990x_suspend(struct device *dev) | ||
1209 | { | ||
1210 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
1211 | struct apds990x_chip *chip = i2c_get_clientdata(client); | ||
1212 | |||
1213 | apds990x_chip_off(chip); | ||
1214 | return 0; | ||
1215 | } | ||
1216 | |||
1217 | static int apds990x_resume(struct device *dev) | ||
1218 | { | ||
1219 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
1220 | struct apds990x_chip *chip = i2c_get_clientdata(client); | ||
1221 | |||
1222 | /* | ||
1223 | * If we were enabled at suspend time, it is expected | ||
1224 | * everything works nice and smoothly. Chip_on is enough | ||
1225 | */ | ||
1226 | apds990x_chip_on(chip); | ||
1227 | |||
1228 | return 0; | ||
1229 | } | ||
1230 | #else | ||
1231 | #define apds990x_suspend NULL | ||
1232 | #define apds990x_resume NULL | ||
1233 | #define apds990x_shutdown NULL | ||
1234 | #endif | ||
1235 | |||
1236 | #ifdef CONFIG_PM_RUNTIME | ||
1237 | static int apds990x_runtime_suspend(struct device *dev) | ||
1238 | { | ||
1239 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
1240 | struct apds990x_chip *chip = i2c_get_clientdata(client); | ||
1241 | |||
1242 | apds990x_chip_off(chip); | ||
1243 | return 0; | ||
1244 | } | ||
1245 | |||
1246 | static int apds990x_runtime_resume(struct device *dev) | ||
1247 | { | ||
1248 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
1249 | struct apds990x_chip *chip = i2c_get_clientdata(client); | ||
1250 | |||
1251 | apds990x_chip_on(chip); | ||
1252 | return 0; | ||
1253 | } | ||
1254 | |||
1255 | #endif | ||
1256 | |||
1257 | static const struct i2c_device_id apds990x_id[] = { | ||
1258 | {"apds990x", 0 }, | ||
1259 | {} | ||
1260 | }; | ||
1261 | |||
1262 | MODULE_DEVICE_TABLE(i2c, apds990x_id); | ||
1263 | |||
1264 | static const struct dev_pm_ops apds990x_pm_ops = { | ||
1265 | SET_SYSTEM_SLEEP_PM_OPS(apds990x_suspend, apds990x_resume) | ||
1266 | SET_RUNTIME_PM_OPS(apds990x_runtime_suspend, | ||
1267 | apds990x_runtime_resume, | ||
1268 | NULL) | ||
1269 | }; | ||
1270 | |||
1271 | static struct i2c_driver apds990x_driver = { | ||
1272 | .driver = { | ||
1273 | .name = "apds990x", | ||
1274 | .owner = THIS_MODULE, | ||
1275 | .pm = &apds990x_pm_ops, | ||
1276 | }, | ||
1277 | .probe = apds990x_probe, | ||
1278 | .remove = __devexit_p(apds990x_remove), | ||
1279 | .id_table = apds990x_id, | ||
1280 | }; | ||
1281 | |||
1282 | static int __init apds990x_init(void) | ||
1283 | { | ||
1284 | return i2c_add_driver(&apds990x_driver); | ||
1285 | } | ||
1286 | |||
1287 | static void __exit apds990x_exit(void) | ||
1288 | { | ||
1289 | i2c_del_driver(&apds990x_driver); | ||
1290 | } | ||
1291 | |||
1292 | MODULE_DESCRIPTION("APDS990X combined ALS and proximity sensor"); | ||
1293 | MODULE_AUTHOR("Samu Onkalo, Nokia Corporation"); | ||
1294 | MODULE_LICENSE("GPL v2"); | ||
1295 | |||
1296 | module_init(apds990x_init); | ||
1297 | module_exit(apds990x_exit); | ||
diff --git a/drivers/misc/arm-charlcd.c b/drivers/misc/arm-charlcd.c index 9e3879ef58f2..fe8616a8d287 100644 --- a/drivers/misc/arm-charlcd.c +++ b/drivers/misc/arm-charlcd.c | |||
@@ -313,7 +313,7 @@ static int __init charlcd_probe(struct platform_device *pdev) | |||
313 | INIT_DELAYED_WORK(&lcd->init_work, charlcd_init_work); | 313 | INIT_DELAYED_WORK(&lcd->init_work, charlcd_init_work); |
314 | schedule_delayed_work(&lcd->init_work, 0); | 314 | schedule_delayed_work(&lcd->init_work, 0); |
315 | 315 | ||
316 | dev_info(&pdev->dev, "initalized ARM character LCD at %08x\n", | 316 | dev_info(&pdev->dev, "initialized ARM character LCD at %08x\n", |
317 | lcd->phybase); | 317 | lcd->phybase); |
318 | 318 | ||
319 | return 0; | 319 | return 0; |
diff --git a/drivers/misc/atmel_tclib.c b/drivers/misc/atmel_tclib.c index 3891124001f2..a844810b50f6 100644 --- a/drivers/misc/atmel_tclib.c +++ b/drivers/misc/atmel_tclib.c | |||
@@ -75,7 +75,7 @@ out: | |||
75 | return tc; | 75 | return tc; |
76 | 76 | ||
77 | fail_ioremap: | 77 | fail_ioremap: |
78 | release_resource(r); | 78 | release_mem_region(r->start, ATMEL_TC_IOMEM_SIZE); |
79 | fail: | 79 | fail: |
80 | tc = NULL; | 80 | tc = NULL; |
81 | goto out; | 81 | goto out; |
@@ -95,7 +95,7 @@ void atmel_tc_free(struct atmel_tc *tc) | |||
95 | spin_lock(&tc_list_lock); | 95 | spin_lock(&tc_list_lock); |
96 | if (tc->regs) { | 96 | if (tc->regs) { |
97 | iounmap(tc->regs); | 97 | iounmap(tc->regs); |
98 | release_resource(tc->iomem); | 98 | release_mem_region(tc->iomem->start, ATMEL_TC_IOMEM_SIZE); |
99 | tc->regs = NULL; | 99 | tc->regs = NULL; |
100 | tc->iomem = NULL; | 100 | tc->iomem = NULL; |
101 | } | 101 | } |
diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c new file mode 100644 index 000000000000..d79a972f2c79 --- /dev/null +++ b/drivers/misc/bh1770glc.c | |||
@@ -0,0 +1,1417 @@ | |||
1 | /* | ||
2 | * This file is part of the ROHM BH1770GLC / OSRAM SFH7770 sensor driver. | ||
3 | * Chip is combined proximity and ambient light sensor. | ||
4 | * | ||
5 | * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). | ||
6 | * | ||
7 | * Contact: Samu Onkalo <samu.p.onkalo@nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
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., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/mutex.h> | ||
30 | #include <linux/i2c/bh1770glc.h> | ||
31 | #include <linux/regulator/consumer.h> | ||
32 | #include <linux/pm_runtime.h> | ||
33 | #include <linux/workqueue.h> | ||
34 | #include <linux/delay.h> | ||
35 | #include <linux/wait.h> | ||
36 | #include <linux/slab.h> | ||
37 | |||
38 | #define BH1770_ALS_CONTROL 0x80 /* ALS operation mode control */ | ||
39 | #define BH1770_PS_CONTROL 0x81 /* PS operation mode control */ | ||
40 | #define BH1770_I_LED 0x82 /* active LED and LED1, LED2 current */ | ||
41 | #define BH1770_I_LED3 0x83 /* LED3 current setting */ | ||
42 | #define BH1770_ALS_PS_MEAS 0x84 /* Forced mode trigger */ | ||
43 | #define BH1770_PS_MEAS_RATE 0x85 /* PS meas. rate at stand alone mode */ | ||
44 | #define BH1770_ALS_MEAS_RATE 0x86 /* ALS meas. rate at stand alone mode */ | ||
45 | #define BH1770_PART_ID 0x8a /* Part number and revision ID */ | ||
46 | #define BH1770_MANUFACT_ID 0x8b /* Manufacturerer ID */ | ||
47 | #define BH1770_ALS_DATA_0 0x8c /* ALS DATA low byte */ | ||
48 | #define BH1770_ALS_DATA_1 0x8d /* ALS DATA high byte */ | ||
49 | #define BH1770_ALS_PS_STATUS 0x8e /* Measurement data and int status */ | ||
50 | #define BH1770_PS_DATA_LED1 0x8f /* PS data from LED1 */ | ||
51 | #define BH1770_PS_DATA_LED2 0x90 /* PS data from LED2 */ | ||
52 | #define BH1770_PS_DATA_LED3 0x91 /* PS data from LED3 */ | ||
53 | #define BH1770_INTERRUPT 0x92 /* Interrupt setting */ | ||
54 | #define BH1770_PS_TH_LED1 0x93 /* PS interrupt threshold for LED1 */ | ||
55 | #define BH1770_PS_TH_LED2 0x94 /* PS interrupt threshold for LED2 */ | ||
56 | #define BH1770_PS_TH_LED3 0x95 /* PS interrupt threshold for LED3 */ | ||
57 | #define BH1770_ALS_TH_UP_0 0x96 /* ALS upper threshold low byte */ | ||
58 | #define BH1770_ALS_TH_UP_1 0x97 /* ALS upper threshold high byte */ | ||
59 | #define BH1770_ALS_TH_LOW_0 0x98 /* ALS lower threshold low byte */ | ||
60 | #define BH1770_ALS_TH_LOW_1 0x99 /* ALS lower threshold high byte */ | ||
61 | |||
62 | /* MANUFACT_ID */ | ||
63 | #define BH1770_MANUFACT_ROHM 0x01 | ||
64 | #define BH1770_MANUFACT_OSRAM 0x03 | ||
65 | |||
66 | /* PART_ID */ | ||
67 | #define BH1770_PART 0x90 | ||
68 | #define BH1770_PART_MASK 0xf0 | ||
69 | #define BH1770_REV_MASK 0x0f | ||
70 | #define BH1770_REV_SHIFT 0 | ||
71 | #define BH1770_REV_0 0x00 | ||
72 | #define BH1770_REV_1 0x01 | ||
73 | |||
74 | /* Operating modes for both */ | ||
75 | #define BH1770_STANDBY 0x00 | ||
76 | #define BH1770_FORCED 0x02 | ||
77 | #define BH1770_STANDALONE 0x03 | ||
78 | #define BH1770_SWRESET (0x01 << 2) | ||
79 | |||
80 | #define BH1770_PS_TRIG_MEAS (1 << 0) | ||
81 | #define BH1770_ALS_TRIG_MEAS (1 << 1) | ||
82 | |||
83 | /* Interrupt control */ | ||
84 | #define BH1770_INT_OUTPUT_MODE (1 << 3) /* 0 = latched */ | ||
85 | #define BH1770_INT_POLARITY (1 << 2) /* 1 = active high */ | ||
86 | #define BH1770_INT_ALS_ENA (1 << 1) | ||
87 | #define BH1770_INT_PS_ENA (1 << 0) | ||
88 | |||
89 | /* Interrupt status */ | ||
90 | #define BH1770_INT_LED1_DATA (1 << 0) | ||
91 | #define BH1770_INT_LED1_INT (1 << 1) | ||
92 | #define BH1770_INT_LED2_DATA (1 << 2) | ||
93 | #define BH1770_INT_LED2_INT (1 << 3) | ||
94 | #define BH1770_INT_LED3_DATA (1 << 4) | ||
95 | #define BH1770_INT_LED3_INT (1 << 5) | ||
96 | #define BH1770_INT_LEDS_INT ((1 << 1) | (1 << 3) | (1 << 5)) | ||
97 | #define BH1770_INT_ALS_DATA (1 << 6) | ||
98 | #define BH1770_INT_ALS_INT (1 << 7) | ||
99 | |||
100 | /* Led channels */ | ||
101 | #define BH1770_LED1 0x00 | ||
102 | |||
103 | #define BH1770_DISABLE 0 | ||
104 | #define BH1770_ENABLE 1 | ||
105 | #define BH1770_PROX_CHANNELS 1 | ||
106 | |||
107 | #define BH1770_LUX_DEFAULT_RATE 1 /* Index to lux rate table */ | ||
108 | #define BH1770_PROX_DEFAULT_RATE 1 /* Direct HW value =~ 50Hz */ | ||
109 | #define BH1770_PROX_DEF_RATE_THRESH 6 /* Direct HW value =~ 5 Hz */ | ||
110 | #define BH1770_STARTUP_DELAY 50 | ||
111 | #define BH1770_RESET_TIME 10 | ||
112 | #define BH1770_TIMEOUT 2100 /* Timeout in 2.1 seconds */ | ||
113 | |||
114 | #define BH1770_LUX_RANGE 65535 | ||
115 | #define BH1770_PROX_RANGE 255 | ||
116 | #define BH1770_COEF_SCALER 1024 | ||
117 | #define BH1770_CALIB_SCALER 8192 | ||
118 | #define BH1770_LUX_NEUTRAL_CALIB_VALUE (1 * BH1770_CALIB_SCALER) | ||
119 | #define BH1770_LUX_DEF_THRES 1000 | ||
120 | #define BH1770_PROX_DEF_THRES 70 | ||
121 | #define BH1770_PROX_DEF_ABS_THRES 100 | ||
122 | #define BH1770_DEFAULT_PERSISTENCE 10 | ||
123 | #define BH1770_PROX_MAX_PERSISTENCE 50 | ||
124 | #define BH1770_LUX_GA_SCALE 16384 | ||
125 | #define BH1770_LUX_CF_SCALE 2048 /* CF ChipFactor */ | ||
126 | #define BH1770_NEUTRAL_CF BH1770_LUX_CF_SCALE | ||
127 | #define BH1770_LUX_CORR_SCALE 4096 | ||
128 | |||
129 | #define PROX_ABOVE_THRESHOLD 1 | ||
130 | #define PROX_BELOW_THRESHOLD 0 | ||
131 | |||
132 | #define PROX_IGNORE_LUX_LIMIT 500 | ||
133 | |||
134 | struct bh1770_chip { | ||
135 | struct bh1770_platform_data *pdata; | ||
136 | char chipname[10]; | ||
137 | u8 revision; | ||
138 | struct i2c_client *client; | ||
139 | struct regulator_bulk_data regs[2]; | ||
140 | struct mutex mutex; /* avoid parallel access */ | ||
141 | wait_queue_head_t wait; | ||
142 | |||
143 | bool int_mode_prox; | ||
144 | bool int_mode_lux; | ||
145 | struct delayed_work prox_work; | ||
146 | u32 lux_cf; /* Chip specific factor */ | ||
147 | u32 lux_ga; | ||
148 | u32 lux_calib; | ||
149 | int lux_rate_index; | ||
150 | u32 lux_corr; | ||
151 | u16 lux_data_raw; | ||
152 | u16 lux_threshold_hi; | ||
153 | u16 lux_threshold_lo; | ||
154 | u16 lux_thres_hi_onchip; | ||
155 | u16 lux_thres_lo_onchip; | ||
156 | bool lux_wait_result; | ||
157 | |||
158 | int prox_enable_count; | ||
159 | u16 prox_coef; | ||
160 | u16 prox_const; | ||
161 | int prox_rate; | ||
162 | int prox_rate_threshold; | ||
163 | u8 prox_persistence; | ||
164 | u8 prox_persistence_counter; | ||
165 | u8 prox_data; | ||
166 | u8 prox_threshold; | ||
167 | u8 prox_threshold_hw; | ||
168 | bool prox_force_update; | ||
169 | u8 prox_abs_thres; | ||
170 | u8 prox_led; | ||
171 | }; | ||
172 | |||
173 | static const char reg_vcc[] = "Vcc"; | ||
174 | static const char reg_vleds[] = "Vleds"; | ||
175 | |||
176 | /* | ||
177 | * Supported stand alone rates in ms from chip data sheet | ||
178 | * {10, 20, 30, 40, 70, 100, 200, 500, 1000, 2000}; | ||
179 | */ | ||
180 | static const s16 prox_rates_hz[] = {100, 50, 33, 25, 14, 10, 5, 2}; | ||
181 | static const s16 prox_rates_ms[] = {10, 20, 30, 40, 70, 100, 200, 500}; | ||
182 | |||
183 | /* Supported IR-led currents in mA */ | ||
184 | static const u8 prox_curr_ma[] = {5, 10, 20, 50, 100, 150, 200}; | ||
185 | |||
186 | /* | ||
187 | * Supported stand alone rates in ms from chip data sheet | ||
188 | * {100, 200, 500, 1000, 2000}; | ||
189 | */ | ||
190 | static const s16 lux_rates_hz[] = {10, 5, 2, 1, 0}; | ||
191 | |||
192 | /* | ||
193 | * interrupt control functions are called while keeping chip->mutex | ||
194 | * excluding module probe / remove | ||
195 | */ | ||
196 | static inline int bh1770_lux_interrupt_control(struct bh1770_chip *chip, | ||
197 | int lux) | ||
198 | { | ||
199 | chip->int_mode_lux = lux; | ||
200 | /* Set interrupt modes, interrupt active low, latched */ | ||
201 | return i2c_smbus_write_byte_data(chip->client, | ||
202 | BH1770_INTERRUPT, | ||
203 | (lux << 1) | chip->int_mode_prox); | ||
204 | } | ||
205 | |||
206 | static inline int bh1770_prox_interrupt_control(struct bh1770_chip *chip, | ||
207 | int ps) | ||
208 | { | ||
209 | chip->int_mode_prox = ps; | ||
210 | return i2c_smbus_write_byte_data(chip->client, | ||
211 | BH1770_INTERRUPT, | ||
212 | (chip->int_mode_lux << 1) | (ps << 0)); | ||
213 | } | ||
214 | |||
215 | /* chip->mutex is always kept here */ | ||
216 | static int bh1770_lux_rate(struct bh1770_chip *chip, int rate_index) | ||
217 | { | ||
218 | /* sysfs may call this when the chip is powered off */ | ||
219 | if (pm_runtime_suspended(&chip->client->dev)) | ||
220 | return 0; | ||
221 | |||
222 | /* Proper proximity response needs fastest lux rate (100ms) */ | ||
223 | if (chip->prox_enable_count) | ||
224 | rate_index = 0; | ||
225 | |||
226 | return i2c_smbus_write_byte_data(chip->client, | ||
227 | BH1770_ALS_MEAS_RATE, | ||
228 | rate_index); | ||
229 | } | ||
230 | |||
231 | static int bh1770_prox_rate(struct bh1770_chip *chip, int mode) | ||
232 | { | ||
233 | int rate; | ||
234 | |||
235 | rate = (mode == PROX_ABOVE_THRESHOLD) ? | ||
236 | chip->prox_rate_threshold : chip->prox_rate; | ||
237 | |||
238 | return i2c_smbus_write_byte_data(chip->client, | ||
239 | BH1770_PS_MEAS_RATE, | ||
240 | rate); | ||
241 | } | ||
242 | |||
243 | /* InfraredLED is controlled by the chip during proximity scanning */ | ||
244 | static inline int bh1770_led_cfg(struct bh1770_chip *chip) | ||
245 | { | ||
246 | /* LED cfg, current for leds 1 and 2 */ | ||
247 | return i2c_smbus_write_byte_data(chip->client, | ||
248 | BH1770_I_LED, | ||
249 | (BH1770_LED1 << 6) | | ||
250 | (BH1770_LED_5mA << 3) | | ||
251 | chip->prox_led); | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * Following two functions converts raw ps values from HW to normalized | ||
256 | * values. Purpose is to compensate differences between different sensor | ||
257 | * versions and variants so that result means about the same between | ||
258 | * versions. | ||
259 | */ | ||
260 | static inline u8 bh1770_psraw_to_adjusted(struct bh1770_chip *chip, u8 psraw) | ||
261 | { | ||
262 | u16 adjusted; | ||
263 | adjusted = (u16)(((u32)(psraw + chip->prox_const) * chip->prox_coef) / | ||
264 | BH1770_COEF_SCALER); | ||
265 | if (adjusted > BH1770_PROX_RANGE) | ||
266 | adjusted = BH1770_PROX_RANGE; | ||
267 | return adjusted; | ||
268 | } | ||
269 | |||
270 | static inline u8 bh1770_psadjusted_to_raw(struct bh1770_chip *chip, u8 ps) | ||
271 | { | ||
272 | u16 raw; | ||
273 | |||
274 | raw = (((u32)ps * BH1770_COEF_SCALER) / chip->prox_coef); | ||
275 | if (raw > chip->prox_const) | ||
276 | raw = raw - chip->prox_const; | ||
277 | else | ||
278 | raw = 0; | ||
279 | return raw; | ||
280 | } | ||
281 | |||
282 | /* | ||
283 | * Following two functions converts raw lux values from HW to normalized | ||
284 | * values. Purpose is to compensate differences between different sensor | ||
285 | * versions and variants so that result means about the same between | ||
286 | * versions. Chip->mutex is kept when this is called. | ||
287 | */ | ||
288 | static int bh1770_prox_set_threshold(struct bh1770_chip *chip) | ||
289 | { | ||
290 | u8 tmp = 0; | ||
291 | |||
292 | /* sysfs may call this when the chip is powered off */ | ||
293 | if (pm_runtime_suspended(&chip->client->dev)) | ||
294 | return 0; | ||
295 | |||
296 | tmp = bh1770_psadjusted_to_raw(chip, chip->prox_threshold); | ||
297 | chip->prox_threshold_hw = tmp; | ||
298 | |||
299 | return i2c_smbus_write_byte_data(chip->client, BH1770_PS_TH_LED1, | ||
300 | tmp); | ||
301 | } | ||
302 | |||
303 | static inline u16 bh1770_lux_raw_to_adjusted(struct bh1770_chip *chip, u16 raw) | ||
304 | { | ||
305 | u32 lux; | ||
306 | lux = ((u32)raw * chip->lux_corr) / BH1770_LUX_CORR_SCALE; | ||
307 | return min(lux, (u32)BH1770_LUX_RANGE); | ||
308 | } | ||
309 | |||
310 | static inline u16 bh1770_lux_adjusted_to_raw(struct bh1770_chip *chip, | ||
311 | u16 adjusted) | ||
312 | { | ||
313 | return (u32)adjusted * BH1770_LUX_CORR_SCALE / chip->lux_corr; | ||
314 | } | ||
315 | |||
316 | /* chip->mutex is kept when this is called */ | ||
317 | static int bh1770_lux_update_thresholds(struct bh1770_chip *chip, | ||
318 | u16 threshold_hi, u16 threshold_lo) | ||
319 | { | ||
320 | u8 data[4]; | ||
321 | int ret; | ||
322 | |||
323 | /* sysfs may call this when the chip is powered off */ | ||
324 | if (pm_runtime_suspended(&chip->client->dev)) | ||
325 | return 0; | ||
326 | |||
327 | /* | ||
328 | * Compensate threshold values with the correction factors if not | ||
329 | * set to minimum or maximum. | ||
330 | * Min & max values disables interrupts. | ||
331 | */ | ||
332 | if (threshold_hi != BH1770_LUX_RANGE && threshold_hi != 0) | ||
333 | threshold_hi = bh1770_lux_adjusted_to_raw(chip, threshold_hi); | ||
334 | |||
335 | if (threshold_lo != BH1770_LUX_RANGE && threshold_lo != 0) | ||
336 | threshold_lo = bh1770_lux_adjusted_to_raw(chip, threshold_lo); | ||
337 | |||
338 | if (chip->lux_thres_hi_onchip == threshold_hi && | ||
339 | chip->lux_thres_lo_onchip == threshold_lo) | ||
340 | return 0; | ||
341 | |||
342 | chip->lux_thres_hi_onchip = threshold_hi; | ||
343 | chip->lux_thres_lo_onchip = threshold_lo; | ||
344 | |||
345 | data[0] = threshold_hi; | ||
346 | data[1] = threshold_hi >> 8; | ||
347 | data[2] = threshold_lo; | ||
348 | data[3] = threshold_lo >> 8; | ||
349 | |||
350 | ret = i2c_smbus_write_i2c_block_data(chip->client, | ||
351 | BH1770_ALS_TH_UP_0, | ||
352 | ARRAY_SIZE(data), | ||
353 | data); | ||
354 | return ret; | ||
355 | } | ||
356 | |||
357 | static int bh1770_lux_get_result(struct bh1770_chip *chip) | ||
358 | { | ||
359 | u16 data; | ||
360 | int ret; | ||
361 | |||
362 | ret = i2c_smbus_read_byte_data(chip->client, BH1770_ALS_DATA_0); | ||
363 | if (ret < 0) | ||
364 | return ret; | ||
365 | |||
366 | data = ret & 0xff; | ||
367 | ret = i2c_smbus_read_byte_data(chip->client, BH1770_ALS_DATA_1); | ||
368 | if (ret < 0) | ||
369 | return ret; | ||
370 | |||
371 | chip->lux_data_raw = data | ((ret & 0xff) << 8); | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | /* Calculate correction value which contains chip and device specific parts */ | ||
377 | static u32 bh1770_get_corr_value(struct bh1770_chip *chip) | ||
378 | { | ||
379 | u32 tmp; | ||
380 | /* Impact of glass attenuation correction */ | ||
381 | tmp = (BH1770_LUX_CORR_SCALE * chip->lux_ga) / BH1770_LUX_GA_SCALE; | ||
382 | /* Impact of chip factor correction */ | ||
383 | tmp = (tmp * chip->lux_cf) / BH1770_LUX_CF_SCALE; | ||
384 | /* Impact of Device specific calibration correction */ | ||
385 | tmp = (tmp * chip->lux_calib) / BH1770_CALIB_SCALER; | ||
386 | return tmp; | ||
387 | } | ||
388 | |||
389 | static int bh1770_lux_read_result(struct bh1770_chip *chip) | ||
390 | { | ||
391 | bh1770_lux_get_result(chip); | ||
392 | return bh1770_lux_raw_to_adjusted(chip, chip->lux_data_raw); | ||
393 | } | ||
394 | |||
395 | /* | ||
396 | * Chip on / off functions are called while keeping mutex except probe | ||
397 | * or remove phase | ||
398 | */ | ||
399 | static int bh1770_chip_on(struct bh1770_chip *chip) | ||
400 | { | ||
401 | int ret = regulator_bulk_enable(ARRAY_SIZE(chip->regs), | ||
402 | chip->regs); | ||
403 | if (ret < 0) | ||
404 | return ret; | ||
405 | |||
406 | usleep_range(BH1770_STARTUP_DELAY, BH1770_STARTUP_DELAY * 2); | ||
407 | |||
408 | /* Reset the chip */ | ||
409 | i2c_smbus_write_byte_data(chip->client, BH1770_ALS_CONTROL, | ||
410 | BH1770_SWRESET); | ||
411 | usleep_range(BH1770_RESET_TIME, BH1770_RESET_TIME * 2); | ||
412 | |||
413 | /* | ||
414 | * ALS is started always since proximity needs als results | ||
415 | * for realibility estimation. | ||
416 | * Let's assume dark until the first ALS measurement is ready. | ||
417 | */ | ||
418 | chip->lux_data_raw = 0; | ||
419 | chip->prox_data = 0; | ||
420 | ret = i2c_smbus_write_byte_data(chip->client, | ||
421 | BH1770_ALS_CONTROL, BH1770_STANDALONE); | ||
422 | |||
423 | /* Assume reset defaults */ | ||
424 | chip->lux_thres_hi_onchip = BH1770_LUX_RANGE; | ||
425 | chip->lux_thres_lo_onchip = 0; | ||
426 | |||
427 | return ret; | ||
428 | } | ||
429 | |||
430 | static void bh1770_chip_off(struct bh1770_chip *chip) | ||
431 | { | ||
432 | i2c_smbus_write_byte_data(chip->client, | ||
433 | BH1770_INTERRUPT, BH1770_DISABLE); | ||
434 | i2c_smbus_write_byte_data(chip->client, | ||
435 | BH1770_ALS_CONTROL, BH1770_STANDBY); | ||
436 | i2c_smbus_write_byte_data(chip->client, | ||
437 | BH1770_PS_CONTROL, BH1770_STANDBY); | ||
438 | regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs); | ||
439 | } | ||
440 | |||
441 | /* chip->mutex is kept when this is called */ | ||
442 | static int bh1770_prox_mode_control(struct bh1770_chip *chip) | ||
443 | { | ||
444 | if (chip->prox_enable_count) { | ||
445 | chip->prox_force_update = true; /* Force immediate update */ | ||
446 | |||
447 | bh1770_lux_rate(chip, chip->lux_rate_index); | ||
448 | bh1770_prox_set_threshold(chip); | ||
449 | bh1770_led_cfg(chip); | ||
450 | bh1770_prox_rate(chip, PROX_BELOW_THRESHOLD); | ||
451 | bh1770_prox_interrupt_control(chip, BH1770_ENABLE); | ||
452 | i2c_smbus_write_byte_data(chip->client, | ||
453 | BH1770_PS_CONTROL, BH1770_STANDALONE); | ||
454 | } else { | ||
455 | chip->prox_data = 0; | ||
456 | bh1770_lux_rate(chip, chip->lux_rate_index); | ||
457 | bh1770_prox_interrupt_control(chip, BH1770_DISABLE); | ||
458 | i2c_smbus_write_byte_data(chip->client, | ||
459 | BH1770_PS_CONTROL, BH1770_STANDBY); | ||
460 | } | ||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | /* chip->mutex is kept when this is called */ | ||
465 | static int bh1770_prox_read_result(struct bh1770_chip *chip) | ||
466 | { | ||
467 | int ret; | ||
468 | bool above; | ||
469 | u8 mode; | ||
470 | |||
471 | ret = i2c_smbus_read_byte_data(chip->client, BH1770_PS_DATA_LED1); | ||
472 | if (ret < 0) | ||
473 | goto out; | ||
474 | |||
475 | if (ret > chip->prox_threshold_hw) | ||
476 | above = true; | ||
477 | else | ||
478 | above = false; | ||
479 | |||
480 | /* | ||
481 | * when ALS levels goes above limit, proximity result may be | ||
482 | * false proximity. Thus ignore the result. With real proximity | ||
483 | * there is a shadow causing low als levels. | ||
484 | */ | ||
485 | if (chip->lux_data_raw > PROX_IGNORE_LUX_LIMIT) | ||
486 | ret = 0; | ||
487 | |||
488 | chip->prox_data = bh1770_psraw_to_adjusted(chip, ret); | ||
489 | |||
490 | /* Strong proximity level or force mode requires immediate response */ | ||
491 | if (chip->prox_data >= chip->prox_abs_thres || | ||
492 | chip->prox_force_update) | ||
493 | chip->prox_persistence_counter = chip->prox_persistence; | ||
494 | |||
495 | chip->prox_force_update = false; | ||
496 | |||
497 | /* Persistence filttering to reduce false proximity events */ | ||
498 | if (likely(above)) { | ||
499 | if (chip->prox_persistence_counter < chip->prox_persistence) { | ||
500 | chip->prox_persistence_counter++; | ||
501 | ret = -ENODATA; | ||
502 | } else { | ||
503 | mode = PROX_ABOVE_THRESHOLD; | ||
504 | ret = 0; | ||
505 | } | ||
506 | } else { | ||
507 | chip->prox_persistence_counter = 0; | ||
508 | mode = PROX_BELOW_THRESHOLD; | ||
509 | chip->prox_data = 0; | ||
510 | ret = 0; | ||
511 | } | ||
512 | |||
513 | /* Set proximity detection rate based on above or below value */ | ||
514 | if (ret == 0) { | ||
515 | bh1770_prox_rate(chip, mode); | ||
516 | sysfs_notify(&chip->client->dev.kobj, NULL, "prox0_raw"); | ||
517 | } | ||
518 | out: | ||
519 | return ret; | ||
520 | } | ||
521 | |||
522 | static int bh1770_detect(struct bh1770_chip *chip) | ||
523 | { | ||
524 | struct i2c_client *client = chip->client; | ||
525 | s32 ret; | ||
526 | u8 manu, part; | ||
527 | |||
528 | ret = i2c_smbus_read_byte_data(client, BH1770_MANUFACT_ID); | ||
529 | if (ret < 0) | ||
530 | goto error; | ||
531 | manu = (u8)ret; | ||
532 | |||
533 | ret = i2c_smbus_read_byte_data(client, BH1770_PART_ID); | ||
534 | if (ret < 0) | ||
535 | goto error; | ||
536 | part = (u8)ret; | ||
537 | |||
538 | chip->revision = (part & BH1770_REV_MASK) >> BH1770_REV_SHIFT; | ||
539 | chip->prox_coef = BH1770_COEF_SCALER; | ||
540 | chip->prox_const = 0; | ||
541 | chip->lux_cf = BH1770_NEUTRAL_CF; | ||
542 | |||
543 | if ((manu == BH1770_MANUFACT_ROHM) && | ||
544 | ((part & BH1770_PART_MASK) == BH1770_PART)) { | ||
545 | snprintf(chip->chipname, sizeof(chip->chipname), "BH1770GLC"); | ||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | if ((manu == BH1770_MANUFACT_OSRAM) && | ||
550 | ((part & BH1770_PART_MASK) == BH1770_PART)) { | ||
551 | snprintf(chip->chipname, sizeof(chip->chipname), "SFH7770"); | ||
552 | /* Values selected by comparing different versions */ | ||
553 | chip->prox_coef = 819; /* 0.8 * BH1770_COEF_SCALER */ | ||
554 | chip->prox_const = 40; | ||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | ret = -ENODEV; | ||
559 | error: | ||
560 | dev_dbg(&client->dev, "BH1770 or SFH7770 not found\n"); | ||
561 | |||
562 | return ret; | ||
563 | } | ||
564 | |||
565 | /* | ||
566 | * This work is re-scheduled at every proximity interrupt. | ||
567 | * If this work is running, it means that there hasn't been any | ||
568 | * proximity interrupt in time. Situation is handled as no-proximity. | ||
569 | * It would be nice to have low-threshold interrupt or interrupt | ||
570 | * when measurement and hi-threshold are both 0. But neither of those exists. | ||
571 | * This is a workaroud for missing HW feature. | ||
572 | */ | ||
573 | |||
574 | static void bh1770_prox_work(struct work_struct *work) | ||
575 | { | ||
576 | struct bh1770_chip *chip = | ||
577 | container_of(work, struct bh1770_chip, prox_work.work); | ||
578 | |||
579 | mutex_lock(&chip->mutex); | ||
580 | bh1770_prox_read_result(chip); | ||
581 | mutex_unlock(&chip->mutex); | ||
582 | } | ||
583 | |||
584 | /* This is threaded irq handler */ | ||
585 | static irqreturn_t bh1770_irq(int irq, void *data) | ||
586 | { | ||
587 | struct bh1770_chip *chip = data; | ||
588 | int status; | ||
589 | int rate = 0; | ||
590 | |||
591 | mutex_lock(&chip->mutex); | ||
592 | status = i2c_smbus_read_byte_data(chip->client, BH1770_ALS_PS_STATUS); | ||
593 | |||
594 | /* Acknowledge interrupt by reading this register */ | ||
595 | i2c_smbus_read_byte_data(chip->client, BH1770_INTERRUPT); | ||
596 | |||
597 | /* | ||
598 | * Check if there is fresh data available for als. | ||
599 | * If this is the very first data, update thresholds after that. | ||
600 | */ | ||
601 | if (status & BH1770_INT_ALS_DATA) { | ||
602 | bh1770_lux_get_result(chip); | ||
603 | if (unlikely(chip->lux_wait_result)) { | ||
604 | chip->lux_wait_result = false; | ||
605 | wake_up(&chip->wait); | ||
606 | bh1770_lux_update_thresholds(chip, | ||
607 | chip->lux_threshold_hi, | ||
608 | chip->lux_threshold_lo); | ||
609 | } | ||
610 | } | ||
611 | |||
612 | /* Disable interrupt logic to guarantee acknowledgement */ | ||
613 | i2c_smbus_write_byte_data(chip->client, BH1770_INTERRUPT, | ||
614 | (0 << 1) | (0 << 0)); | ||
615 | |||
616 | if ((status & BH1770_INT_ALS_INT)) | ||
617 | sysfs_notify(&chip->client->dev.kobj, NULL, "lux0_input"); | ||
618 | |||
619 | if (chip->int_mode_prox && (status & BH1770_INT_LEDS_INT)) { | ||
620 | rate = prox_rates_ms[chip->prox_rate_threshold]; | ||
621 | bh1770_prox_read_result(chip); | ||
622 | } | ||
623 | |||
624 | /* Re-enable interrupt logic */ | ||
625 | i2c_smbus_write_byte_data(chip->client, BH1770_INTERRUPT, | ||
626 | (chip->int_mode_lux << 1) | | ||
627 | (chip->int_mode_prox << 0)); | ||
628 | mutex_unlock(&chip->mutex); | ||
629 | |||
630 | /* | ||
631 | * Can't cancel work while keeping mutex since the work uses the | ||
632 | * same mutex. | ||
633 | */ | ||
634 | if (rate) { | ||
635 | /* | ||
636 | * Simulate missing no-proximity interrupt 50ms after the | ||
637 | * next expected interrupt time. | ||
638 | */ | ||
639 | cancel_delayed_work_sync(&chip->prox_work); | ||
640 | schedule_delayed_work(&chip->prox_work, | ||
641 | msecs_to_jiffies(rate + 50)); | ||
642 | } | ||
643 | return IRQ_HANDLED; | ||
644 | } | ||
645 | |||
646 | static ssize_t bh1770_power_state_store(struct device *dev, | ||
647 | struct device_attribute *attr, | ||
648 | const char *buf, size_t count) | ||
649 | { | ||
650 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
651 | unsigned long value; | ||
652 | ssize_t ret; | ||
653 | |||
654 | if (strict_strtoul(buf, 0, &value)) | ||
655 | return -EINVAL; | ||
656 | |||
657 | mutex_lock(&chip->mutex); | ||
658 | if (value) { | ||
659 | pm_runtime_get_sync(dev); | ||
660 | |||
661 | ret = bh1770_lux_rate(chip, chip->lux_rate_index); | ||
662 | if (ret < 0) { | ||
663 | pm_runtime_put(dev); | ||
664 | goto leave; | ||
665 | } | ||
666 | |||
667 | ret = bh1770_lux_interrupt_control(chip, BH1770_ENABLE); | ||
668 | if (ret < 0) { | ||
669 | pm_runtime_put(dev); | ||
670 | goto leave; | ||
671 | } | ||
672 | |||
673 | /* This causes interrupt after the next measurement cycle */ | ||
674 | bh1770_lux_update_thresholds(chip, BH1770_LUX_DEF_THRES, | ||
675 | BH1770_LUX_DEF_THRES); | ||
676 | /* Inform that we are waiting for a result from ALS */ | ||
677 | chip->lux_wait_result = true; | ||
678 | bh1770_prox_mode_control(chip); | ||
679 | } else if (!pm_runtime_suspended(dev)) { | ||
680 | pm_runtime_put(dev); | ||
681 | } | ||
682 | ret = count; | ||
683 | leave: | ||
684 | mutex_unlock(&chip->mutex); | ||
685 | return ret; | ||
686 | } | ||
687 | |||
688 | static ssize_t bh1770_power_state_show(struct device *dev, | ||
689 | struct device_attribute *attr, char *buf) | ||
690 | { | ||
691 | return sprintf(buf, "%d\n", !pm_runtime_suspended(dev)); | ||
692 | } | ||
693 | |||
694 | static ssize_t bh1770_lux_result_show(struct device *dev, | ||
695 | struct device_attribute *attr, char *buf) | ||
696 | { | ||
697 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
698 | ssize_t ret; | ||
699 | long timeout; | ||
700 | |||
701 | if (pm_runtime_suspended(dev)) | ||
702 | return -EIO; /* Chip is not enabled at all */ | ||
703 | |||
704 | timeout = wait_event_interruptible_timeout(chip->wait, | ||
705 | !chip->lux_wait_result, | ||
706 | msecs_to_jiffies(BH1770_TIMEOUT)); | ||
707 | if (!timeout) | ||
708 | return -EIO; | ||
709 | |||
710 | mutex_lock(&chip->mutex); | ||
711 | ret = sprintf(buf, "%d\n", bh1770_lux_read_result(chip)); | ||
712 | mutex_unlock(&chip->mutex); | ||
713 | |||
714 | return ret; | ||
715 | } | ||
716 | |||
717 | static ssize_t bh1770_lux_range_show(struct device *dev, | ||
718 | struct device_attribute *attr, char *buf) | ||
719 | { | ||
720 | return sprintf(buf, "%d\n", BH1770_LUX_RANGE); | ||
721 | } | ||
722 | |||
723 | static ssize_t bh1770_prox_enable_store(struct device *dev, | ||
724 | struct device_attribute *attr, | ||
725 | const char *buf, size_t count) | ||
726 | { | ||
727 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
728 | unsigned long value; | ||
729 | |||
730 | if (strict_strtoul(buf, 0, &value)) | ||
731 | return -EINVAL; | ||
732 | |||
733 | mutex_lock(&chip->mutex); | ||
734 | /* Assume no proximity. Sensor will tell real state soon */ | ||
735 | if (!chip->prox_enable_count) | ||
736 | chip->prox_data = 0; | ||
737 | |||
738 | if (value) | ||
739 | chip->prox_enable_count++; | ||
740 | else if (chip->prox_enable_count > 0) | ||
741 | chip->prox_enable_count--; | ||
742 | else | ||
743 | goto leave; | ||
744 | |||
745 | /* Run control only when chip is powered on */ | ||
746 | if (!pm_runtime_suspended(dev)) | ||
747 | bh1770_prox_mode_control(chip); | ||
748 | leave: | ||
749 | mutex_unlock(&chip->mutex); | ||
750 | return count; | ||
751 | } | ||
752 | |||
753 | static ssize_t bh1770_prox_enable_show(struct device *dev, | ||
754 | struct device_attribute *attr, char *buf) | ||
755 | { | ||
756 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
757 | ssize_t len; | ||
758 | |||
759 | mutex_lock(&chip->mutex); | ||
760 | len = sprintf(buf, "%d\n", chip->prox_enable_count); | ||
761 | mutex_unlock(&chip->mutex); | ||
762 | return len; | ||
763 | } | ||
764 | |||
765 | static ssize_t bh1770_prox_result_show(struct device *dev, | ||
766 | struct device_attribute *attr, char *buf) | ||
767 | { | ||
768 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
769 | ssize_t ret; | ||
770 | |||
771 | mutex_lock(&chip->mutex); | ||
772 | if (chip->prox_enable_count && !pm_runtime_suspended(dev)) | ||
773 | ret = sprintf(buf, "%d\n", chip->prox_data); | ||
774 | else | ||
775 | ret = -EIO; | ||
776 | mutex_unlock(&chip->mutex); | ||
777 | return ret; | ||
778 | } | ||
779 | |||
780 | static ssize_t bh1770_prox_range_show(struct device *dev, | ||
781 | struct device_attribute *attr, char *buf) | ||
782 | { | ||
783 | return sprintf(buf, "%d\n", BH1770_PROX_RANGE); | ||
784 | } | ||
785 | |||
786 | static ssize_t bh1770_get_prox_rate_avail(struct device *dev, | ||
787 | struct device_attribute *attr, char *buf) | ||
788 | { | ||
789 | int i; | ||
790 | int pos = 0; | ||
791 | for (i = 0; i < ARRAY_SIZE(prox_rates_hz); i++) | ||
792 | pos += sprintf(buf + pos, "%d ", prox_rates_hz[i]); | ||
793 | sprintf(buf + pos - 1, "\n"); | ||
794 | return pos; | ||
795 | } | ||
796 | |||
797 | static ssize_t bh1770_get_prox_rate_above(struct device *dev, | ||
798 | struct device_attribute *attr, char *buf) | ||
799 | { | ||
800 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
801 | return sprintf(buf, "%d\n", prox_rates_hz[chip->prox_rate_threshold]); | ||
802 | } | ||
803 | |||
804 | static ssize_t bh1770_get_prox_rate_below(struct device *dev, | ||
805 | struct device_attribute *attr, char *buf) | ||
806 | { | ||
807 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
808 | return sprintf(buf, "%d\n", prox_rates_hz[chip->prox_rate]); | ||
809 | } | ||
810 | |||
811 | static int bh1770_prox_rate_validate(int rate) | ||
812 | { | ||
813 | int i; | ||
814 | |||
815 | for (i = 0; i < ARRAY_SIZE(prox_rates_hz) - 1; i++) | ||
816 | if (rate >= prox_rates_hz[i]) | ||
817 | break; | ||
818 | return i; | ||
819 | } | ||
820 | |||
821 | static ssize_t bh1770_set_prox_rate_above(struct device *dev, | ||
822 | struct device_attribute *attr, | ||
823 | const char *buf, size_t count) | ||
824 | { | ||
825 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
826 | unsigned long value; | ||
827 | |||
828 | if (strict_strtoul(buf, 0, &value)) | ||
829 | return -EINVAL; | ||
830 | |||
831 | mutex_lock(&chip->mutex); | ||
832 | chip->prox_rate_threshold = bh1770_prox_rate_validate(value); | ||
833 | mutex_unlock(&chip->mutex); | ||
834 | return count; | ||
835 | } | ||
836 | |||
837 | static ssize_t bh1770_set_prox_rate_below(struct device *dev, | ||
838 | struct device_attribute *attr, | ||
839 | const char *buf, size_t count) | ||
840 | { | ||
841 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
842 | unsigned long value; | ||
843 | |||
844 | if (strict_strtoul(buf, 0, &value)) | ||
845 | return -EINVAL; | ||
846 | |||
847 | mutex_lock(&chip->mutex); | ||
848 | chip->prox_rate = bh1770_prox_rate_validate(value); | ||
849 | mutex_unlock(&chip->mutex); | ||
850 | return count; | ||
851 | } | ||
852 | |||
853 | static ssize_t bh1770_get_prox_thres(struct device *dev, | ||
854 | struct device_attribute *attr, char *buf) | ||
855 | { | ||
856 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
857 | return sprintf(buf, "%d\n", chip->prox_threshold); | ||
858 | } | ||
859 | |||
860 | static ssize_t bh1770_set_prox_thres(struct device *dev, | ||
861 | struct device_attribute *attr, | ||
862 | const char *buf, size_t count) | ||
863 | { | ||
864 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
865 | unsigned long value; | ||
866 | int ret; | ||
867 | |||
868 | if (strict_strtoul(buf, 0, &value)) | ||
869 | return -EINVAL; | ||
870 | if (value > BH1770_PROX_RANGE) | ||
871 | return -EINVAL; | ||
872 | |||
873 | mutex_lock(&chip->mutex); | ||
874 | chip->prox_threshold = value; | ||
875 | ret = bh1770_prox_set_threshold(chip); | ||
876 | mutex_unlock(&chip->mutex); | ||
877 | if (ret < 0) | ||
878 | return ret; | ||
879 | return count; | ||
880 | } | ||
881 | |||
882 | static ssize_t bh1770_prox_persistence_show(struct device *dev, | ||
883 | struct device_attribute *attr, char *buf) | ||
884 | { | ||
885 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
886 | |||
887 | return sprintf(buf, "%u\n", chip->prox_persistence); | ||
888 | } | ||
889 | |||
890 | static ssize_t bh1770_prox_persistence_store(struct device *dev, | ||
891 | struct device_attribute *attr, | ||
892 | const char *buf, size_t len) | ||
893 | { | ||
894 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
895 | unsigned long value; | ||
896 | |||
897 | if (strict_strtoul(buf, 0, &value)) | ||
898 | return -EINVAL; | ||
899 | |||
900 | if (value > BH1770_PROX_MAX_PERSISTENCE) | ||
901 | return -EINVAL; | ||
902 | |||
903 | chip->prox_persistence = value; | ||
904 | |||
905 | return len; | ||
906 | } | ||
907 | |||
908 | static ssize_t bh1770_prox_abs_thres_show(struct device *dev, | ||
909 | struct device_attribute *attr, char *buf) | ||
910 | { | ||
911 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
912 | return sprintf(buf, "%u\n", chip->prox_abs_thres); | ||
913 | } | ||
914 | |||
915 | static ssize_t bh1770_prox_abs_thres_store(struct device *dev, | ||
916 | struct device_attribute *attr, | ||
917 | const char *buf, size_t len) | ||
918 | { | ||
919 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
920 | unsigned long value; | ||
921 | |||
922 | if (strict_strtoul(buf, 0, &value)) | ||
923 | return -EINVAL; | ||
924 | |||
925 | if (value > BH1770_PROX_RANGE) | ||
926 | return -EINVAL; | ||
927 | |||
928 | chip->prox_abs_thres = value; | ||
929 | |||
930 | return len; | ||
931 | } | ||
932 | |||
933 | static ssize_t bh1770_chip_id_show(struct device *dev, | ||
934 | struct device_attribute *attr, char *buf) | ||
935 | { | ||
936 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
937 | return sprintf(buf, "%s rev %d\n", chip->chipname, chip->revision); | ||
938 | } | ||
939 | |||
940 | static ssize_t bh1770_lux_calib_default_show(struct device *dev, | ||
941 | struct device_attribute *attr, char *buf) | ||
942 | { | ||
943 | return sprintf(buf, "%u\n", BH1770_CALIB_SCALER); | ||
944 | } | ||
945 | |||
946 | static ssize_t bh1770_lux_calib_show(struct device *dev, | ||
947 | struct device_attribute *attr, char *buf) | ||
948 | { | ||
949 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
950 | ssize_t len; | ||
951 | |||
952 | mutex_lock(&chip->mutex); | ||
953 | len = sprintf(buf, "%u\n", chip->lux_calib); | ||
954 | mutex_unlock(&chip->mutex); | ||
955 | return len; | ||
956 | } | ||
957 | |||
958 | static ssize_t bh1770_lux_calib_store(struct device *dev, | ||
959 | struct device_attribute *attr, | ||
960 | const char *buf, size_t len) | ||
961 | { | ||
962 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
963 | unsigned long value; | ||
964 | u32 old_calib; | ||
965 | u32 new_corr; | ||
966 | |||
967 | if (strict_strtoul(buf, 0, &value)) | ||
968 | return -EINVAL; | ||
969 | |||
970 | mutex_lock(&chip->mutex); | ||
971 | old_calib = chip->lux_calib; | ||
972 | chip->lux_calib = value; | ||
973 | new_corr = bh1770_get_corr_value(chip); | ||
974 | if (new_corr == 0) { | ||
975 | chip->lux_calib = old_calib; | ||
976 | mutex_unlock(&chip->mutex); | ||
977 | return -EINVAL; | ||
978 | } | ||
979 | chip->lux_corr = new_corr; | ||
980 | /* Refresh thresholds on HW after changing correction value */ | ||
981 | bh1770_lux_update_thresholds(chip, chip->lux_threshold_hi, | ||
982 | chip->lux_threshold_lo); | ||
983 | |||
984 | mutex_unlock(&chip->mutex); | ||
985 | |||
986 | return len; | ||
987 | } | ||
988 | |||
989 | static ssize_t bh1770_get_lux_rate_avail(struct device *dev, | ||
990 | struct device_attribute *attr, char *buf) | ||
991 | { | ||
992 | int i; | ||
993 | int pos = 0; | ||
994 | for (i = 0; i < ARRAY_SIZE(lux_rates_hz); i++) | ||
995 | pos += sprintf(buf + pos, "%d ", lux_rates_hz[i]); | ||
996 | sprintf(buf + pos - 1, "\n"); | ||
997 | return pos; | ||
998 | } | ||
999 | |||
1000 | static ssize_t bh1770_get_lux_rate(struct device *dev, | ||
1001 | struct device_attribute *attr, char *buf) | ||
1002 | { | ||
1003 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
1004 | return sprintf(buf, "%d\n", lux_rates_hz[chip->lux_rate_index]); | ||
1005 | } | ||
1006 | |||
1007 | static ssize_t bh1770_set_lux_rate(struct device *dev, | ||
1008 | struct device_attribute *attr, | ||
1009 | const char *buf, size_t count) | ||
1010 | { | ||
1011 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
1012 | unsigned long rate_hz; | ||
1013 | int ret, i; | ||
1014 | |||
1015 | if (strict_strtoul(buf, 0, &rate_hz)) | ||
1016 | return -EINVAL; | ||
1017 | |||
1018 | for (i = 0; i < ARRAY_SIZE(lux_rates_hz) - 1; i++) | ||
1019 | if (rate_hz >= lux_rates_hz[i]) | ||
1020 | break; | ||
1021 | |||
1022 | mutex_lock(&chip->mutex); | ||
1023 | chip->lux_rate_index = i; | ||
1024 | ret = bh1770_lux_rate(chip, i); | ||
1025 | mutex_unlock(&chip->mutex); | ||
1026 | |||
1027 | if (ret < 0) | ||
1028 | return ret; | ||
1029 | |||
1030 | return count; | ||
1031 | } | ||
1032 | |||
1033 | static ssize_t bh1770_get_lux_thresh_above(struct device *dev, | ||
1034 | struct device_attribute *attr, char *buf) | ||
1035 | { | ||
1036 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
1037 | return sprintf(buf, "%d\n", chip->lux_threshold_hi); | ||
1038 | } | ||
1039 | |||
1040 | static ssize_t bh1770_get_lux_thresh_below(struct device *dev, | ||
1041 | struct device_attribute *attr, char *buf) | ||
1042 | { | ||
1043 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
1044 | return sprintf(buf, "%d\n", chip->lux_threshold_lo); | ||
1045 | } | ||
1046 | |||
1047 | static ssize_t bh1770_set_lux_thresh(struct bh1770_chip *chip, u16 *target, | ||
1048 | const char *buf) | ||
1049 | { | ||
1050 | int ret = 0; | ||
1051 | unsigned long thresh; | ||
1052 | |||
1053 | if (strict_strtoul(buf, 0, &thresh)) | ||
1054 | return -EINVAL; | ||
1055 | |||
1056 | if (thresh > BH1770_LUX_RANGE) | ||
1057 | return -EINVAL; | ||
1058 | |||
1059 | mutex_lock(&chip->mutex); | ||
1060 | *target = thresh; | ||
1061 | /* | ||
1062 | * Don't update values in HW if we are still waiting for | ||
1063 | * first interrupt to come after device handle open call. | ||
1064 | */ | ||
1065 | if (!chip->lux_wait_result) | ||
1066 | ret = bh1770_lux_update_thresholds(chip, | ||
1067 | chip->lux_threshold_hi, | ||
1068 | chip->lux_threshold_lo); | ||
1069 | mutex_unlock(&chip->mutex); | ||
1070 | return ret; | ||
1071 | |||
1072 | } | ||
1073 | |||
1074 | static ssize_t bh1770_set_lux_thresh_above(struct device *dev, | ||
1075 | struct device_attribute *attr, | ||
1076 | const char *buf, size_t len) | ||
1077 | { | ||
1078 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
1079 | int ret = bh1770_set_lux_thresh(chip, &chip->lux_threshold_hi, buf); | ||
1080 | if (ret < 0) | ||
1081 | return ret; | ||
1082 | return len; | ||
1083 | } | ||
1084 | |||
1085 | static ssize_t bh1770_set_lux_thresh_below(struct device *dev, | ||
1086 | struct device_attribute *attr, | ||
1087 | const char *buf, size_t len) | ||
1088 | { | ||
1089 | struct bh1770_chip *chip = dev_get_drvdata(dev); | ||
1090 | int ret = bh1770_set_lux_thresh(chip, &chip->lux_threshold_lo, buf); | ||
1091 | if (ret < 0) | ||
1092 | return ret; | ||
1093 | return len; | ||
1094 | } | ||
1095 | |||
1096 | static DEVICE_ATTR(prox0_raw_en, S_IRUGO | S_IWUSR, bh1770_prox_enable_show, | ||
1097 | bh1770_prox_enable_store); | ||
1098 | static DEVICE_ATTR(prox0_thresh_above1_value, S_IRUGO | S_IWUSR, | ||
1099 | bh1770_prox_abs_thres_show, | ||
1100 | bh1770_prox_abs_thres_store); | ||
1101 | static DEVICE_ATTR(prox0_thresh_above0_value, S_IRUGO | S_IWUSR, | ||
1102 | bh1770_get_prox_thres, | ||
1103 | bh1770_set_prox_thres); | ||
1104 | static DEVICE_ATTR(prox0_raw, S_IRUGO, bh1770_prox_result_show, NULL); | ||
1105 | static DEVICE_ATTR(prox0_sensor_range, S_IRUGO, bh1770_prox_range_show, NULL); | ||
1106 | static DEVICE_ATTR(prox0_thresh_above_count, S_IRUGO | S_IWUSR, | ||
1107 | bh1770_prox_persistence_show, | ||
1108 | bh1770_prox_persistence_store); | ||
1109 | static DEVICE_ATTR(prox0_rate_above, S_IRUGO | S_IWUSR, | ||
1110 | bh1770_get_prox_rate_above, | ||
1111 | bh1770_set_prox_rate_above); | ||
1112 | static DEVICE_ATTR(prox0_rate_below, S_IRUGO | S_IWUSR, | ||
1113 | bh1770_get_prox_rate_below, | ||
1114 | bh1770_set_prox_rate_below); | ||
1115 | static DEVICE_ATTR(prox0_rate_avail, S_IRUGO, bh1770_get_prox_rate_avail, NULL); | ||
1116 | |||
1117 | static DEVICE_ATTR(lux0_calibscale, S_IRUGO | S_IWUSR, bh1770_lux_calib_show, | ||
1118 | bh1770_lux_calib_store); | ||
1119 | static DEVICE_ATTR(lux0_calibscale_default, S_IRUGO, | ||
1120 | bh1770_lux_calib_default_show, | ||
1121 | NULL); | ||
1122 | static DEVICE_ATTR(lux0_input, S_IRUGO, bh1770_lux_result_show, NULL); | ||
1123 | static DEVICE_ATTR(lux0_sensor_range, S_IRUGO, bh1770_lux_range_show, NULL); | ||
1124 | static DEVICE_ATTR(lux0_rate, S_IRUGO | S_IWUSR, bh1770_get_lux_rate, | ||
1125 | bh1770_set_lux_rate); | ||
1126 | static DEVICE_ATTR(lux0_rate_avail, S_IRUGO, bh1770_get_lux_rate_avail, NULL); | ||
1127 | static DEVICE_ATTR(lux0_thresh_above_value, S_IRUGO | S_IWUSR, | ||
1128 | bh1770_get_lux_thresh_above, | ||
1129 | bh1770_set_lux_thresh_above); | ||
1130 | static DEVICE_ATTR(lux0_thresh_below_value, S_IRUGO | S_IWUSR, | ||
1131 | bh1770_get_lux_thresh_below, | ||
1132 | bh1770_set_lux_thresh_below); | ||
1133 | static DEVICE_ATTR(chip_id, S_IRUGO, bh1770_chip_id_show, NULL); | ||
1134 | static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR, bh1770_power_state_show, | ||
1135 | bh1770_power_state_store); | ||
1136 | |||
1137 | |||
1138 | static struct attribute *sysfs_attrs[] = { | ||
1139 | &dev_attr_lux0_calibscale.attr, | ||
1140 | &dev_attr_lux0_calibscale_default.attr, | ||
1141 | &dev_attr_lux0_input.attr, | ||
1142 | &dev_attr_lux0_sensor_range.attr, | ||
1143 | &dev_attr_lux0_rate.attr, | ||
1144 | &dev_attr_lux0_rate_avail.attr, | ||
1145 | &dev_attr_lux0_thresh_above_value.attr, | ||
1146 | &dev_attr_lux0_thresh_below_value.attr, | ||
1147 | &dev_attr_prox0_raw.attr, | ||
1148 | &dev_attr_prox0_sensor_range.attr, | ||
1149 | &dev_attr_prox0_raw_en.attr, | ||
1150 | &dev_attr_prox0_thresh_above_count.attr, | ||
1151 | &dev_attr_prox0_rate_above.attr, | ||
1152 | &dev_attr_prox0_rate_below.attr, | ||
1153 | &dev_attr_prox0_rate_avail.attr, | ||
1154 | &dev_attr_prox0_thresh_above0_value.attr, | ||
1155 | &dev_attr_prox0_thresh_above1_value.attr, | ||
1156 | &dev_attr_chip_id.attr, | ||
1157 | &dev_attr_power_state.attr, | ||
1158 | NULL | ||
1159 | }; | ||
1160 | |||
1161 | static struct attribute_group bh1770_attribute_group = { | ||
1162 | .attrs = sysfs_attrs | ||
1163 | }; | ||
1164 | |||
1165 | static int __devinit bh1770_probe(struct i2c_client *client, | ||
1166 | const struct i2c_device_id *id) | ||
1167 | { | ||
1168 | struct bh1770_chip *chip; | ||
1169 | int err; | ||
1170 | |||
1171 | chip = kzalloc(sizeof *chip, GFP_KERNEL); | ||
1172 | if (!chip) | ||
1173 | return -ENOMEM; | ||
1174 | |||
1175 | i2c_set_clientdata(client, chip); | ||
1176 | chip->client = client; | ||
1177 | |||
1178 | mutex_init(&chip->mutex); | ||
1179 | init_waitqueue_head(&chip->wait); | ||
1180 | INIT_DELAYED_WORK(&chip->prox_work, bh1770_prox_work); | ||
1181 | |||
1182 | if (client->dev.platform_data == NULL) { | ||
1183 | dev_err(&client->dev, "platform data is mandatory\n"); | ||
1184 | err = -EINVAL; | ||
1185 | goto fail1; | ||
1186 | } | ||
1187 | |||
1188 | chip->pdata = client->dev.platform_data; | ||
1189 | chip->lux_calib = BH1770_LUX_NEUTRAL_CALIB_VALUE; | ||
1190 | chip->lux_rate_index = BH1770_LUX_DEFAULT_RATE; | ||
1191 | chip->lux_threshold_lo = BH1770_LUX_DEF_THRES; | ||
1192 | chip->lux_threshold_hi = BH1770_LUX_DEF_THRES; | ||
1193 | |||
1194 | if (chip->pdata->glass_attenuation == 0) | ||
1195 | chip->lux_ga = BH1770_NEUTRAL_GA; | ||
1196 | else | ||
1197 | chip->lux_ga = chip->pdata->glass_attenuation; | ||
1198 | |||
1199 | chip->prox_threshold = BH1770_PROX_DEF_THRES; | ||
1200 | chip->prox_led = chip->pdata->led_def_curr; | ||
1201 | chip->prox_abs_thres = BH1770_PROX_DEF_ABS_THRES; | ||
1202 | chip->prox_persistence = BH1770_DEFAULT_PERSISTENCE; | ||
1203 | chip->prox_rate_threshold = BH1770_PROX_DEF_RATE_THRESH; | ||
1204 | chip->prox_rate = BH1770_PROX_DEFAULT_RATE; | ||
1205 | chip->prox_data = 0; | ||
1206 | |||
1207 | chip->regs[0].supply = reg_vcc; | ||
1208 | chip->regs[1].supply = reg_vleds; | ||
1209 | |||
1210 | err = regulator_bulk_get(&client->dev, | ||
1211 | ARRAY_SIZE(chip->regs), chip->regs); | ||
1212 | if (err < 0) { | ||
1213 | dev_err(&client->dev, "Cannot get regulators\n"); | ||
1214 | goto fail1; | ||
1215 | } | ||
1216 | |||
1217 | err = regulator_bulk_enable(ARRAY_SIZE(chip->regs), | ||
1218 | chip->regs); | ||
1219 | if (err < 0) { | ||
1220 | dev_err(&client->dev, "Cannot enable regulators\n"); | ||
1221 | goto fail2; | ||
1222 | } | ||
1223 | |||
1224 | usleep_range(BH1770_STARTUP_DELAY, BH1770_STARTUP_DELAY * 2); | ||
1225 | err = bh1770_detect(chip); | ||
1226 | if (err < 0) | ||
1227 | goto fail3; | ||
1228 | |||
1229 | /* Start chip */ | ||
1230 | bh1770_chip_on(chip); | ||
1231 | pm_runtime_set_active(&client->dev); | ||
1232 | pm_runtime_enable(&client->dev); | ||
1233 | |||
1234 | chip->lux_corr = bh1770_get_corr_value(chip); | ||
1235 | if (chip->lux_corr == 0) { | ||
1236 | dev_err(&client->dev, "Improper correction values\n"); | ||
1237 | err = -EINVAL; | ||
1238 | goto fail3; | ||
1239 | } | ||
1240 | |||
1241 | if (chip->pdata->setup_resources) { | ||
1242 | err = chip->pdata->setup_resources(); | ||
1243 | if (err) { | ||
1244 | err = -EINVAL; | ||
1245 | goto fail3; | ||
1246 | } | ||
1247 | } | ||
1248 | |||
1249 | err = sysfs_create_group(&chip->client->dev.kobj, | ||
1250 | &bh1770_attribute_group); | ||
1251 | if (err < 0) { | ||
1252 | dev_err(&chip->client->dev, "Sysfs registration failed\n"); | ||
1253 | goto fail4; | ||
1254 | } | ||
1255 | |||
1256 | /* | ||
1257 | * Chip needs level triggered interrupt to work. However, | ||
1258 | * level triggering doesn't work always correctly with power | ||
1259 | * management. Select both | ||
1260 | */ | ||
1261 | err = request_threaded_irq(client->irq, NULL, | ||
1262 | bh1770_irq, | ||
1263 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT | | ||
1264 | IRQF_TRIGGER_LOW, | ||
1265 | "bh1770", chip); | ||
1266 | if (err) { | ||
1267 | dev_err(&client->dev, "could not get IRQ %d\n", | ||
1268 | client->irq); | ||
1269 | goto fail5; | ||
1270 | } | ||
1271 | regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs); | ||
1272 | return err; | ||
1273 | fail5: | ||
1274 | sysfs_remove_group(&chip->client->dev.kobj, | ||
1275 | &bh1770_attribute_group); | ||
1276 | fail4: | ||
1277 | if (chip->pdata->release_resources) | ||
1278 | chip->pdata->release_resources(); | ||
1279 | fail3: | ||
1280 | regulator_bulk_disable(ARRAY_SIZE(chip->regs), chip->regs); | ||
1281 | fail2: | ||
1282 | regulator_bulk_free(ARRAY_SIZE(chip->regs), chip->regs); | ||
1283 | fail1: | ||
1284 | kfree(chip); | ||
1285 | return err; | ||
1286 | } | ||
1287 | |||
1288 | static int __devexit bh1770_remove(struct i2c_client *client) | ||
1289 | { | ||
1290 | struct bh1770_chip *chip = i2c_get_clientdata(client); | ||
1291 | |||
1292 | free_irq(client->irq, chip); | ||
1293 | |||
1294 | sysfs_remove_group(&chip->client->dev.kobj, | ||
1295 | &bh1770_attribute_group); | ||
1296 | |||
1297 | if (chip->pdata->release_resources) | ||
1298 | chip->pdata->release_resources(); | ||
1299 | |||
1300 | cancel_delayed_work_sync(&chip->prox_work); | ||
1301 | |||
1302 | if (!pm_runtime_suspended(&client->dev)) | ||
1303 | bh1770_chip_off(chip); | ||
1304 | |||
1305 | pm_runtime_disable(&client->dev); | ||
1306 | pm_runtime_set_suspended(&client->dev); | ||
1307 | |||
1308 | regulator_bulk_free(ARRAY_SIZE(chip->regs), chip->regs); | ||
1309 | kfree(chip); | ||
1310 | return 0; | ||
1311 | } | ||
1312 | |||
1313 | #ifdef CONFIG_PM | ||
1314 | static int bh1770_suspend(struct device *dev) | ||
1315 | { | ||
1316 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
1317 | struct bh1770_chip *chip = i2c_get_clientdata(client); | ||
1318 | |||
1319 | bh1770_chip_off(chip); | ||
1320 | |||
1321 | return 0; | ||
1322 | } | ||
1323 | |||
1324 | static int bh1770_resume(struct device *dev) | ||
1325 | { | ||
1326 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
1327 | struct bh1770_chip *chip = i2c_get_clientdata(client); | ||
1328 | int ret = 0; | ||
1329 | |||
1330 | bh1770_chip_on(chip); | ||
1331 | |||
1332 | if (!pm_runtime_suspended(dev)) { | ||
1333 | /* | ||
1334 | * If we were enabled at suspend time, it is expected | ||
1335 | * everything works nice and smoothly | ||
1336 | */ | ||
1337 | ret = bh1770_lux_rate(chip, chip->lux_rate_index); | ||
1338 | ret |= bh1770_lux_interrupt_control(chip, BH1770_ENABLE); | ||
1339 | |||
1340 | /* This causes interrupt after the next measurement cycle */ | ||
1341 | bh1770_lux_update_thresholds(chip, BH1770_LUX_DEF_THRES, | ||
1342 | BH1770_LUX_DEF_THRES); | ||
1343 | /* Inform that we are waiting for a result from ALS */ | ||
1344 | chip->lux_wait_result = true; | ||
1345 | bh1770_prox_mode_control(chip); | ||
1346 | } | ||
1347 | return ret; | ||
1348 | } | ||
1349 | |||
1350 | #else | ||
1351 | #define bh1770_suspend NULL | ||
1352 | #define bh1770_shutdown NULL | ||
1353 | #define bh1770_resume NULL | ||
1354 | #endif | ||
1355 | |||
1356 | #ifdef CONFIG_PM_RUNTIME | ||
1357 | static int bh1770_runtime_suspend(struct device *dev) | ||
1358 | { | ||
1359 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
1360 | struct bh1770_chip *chip = i2c_get_clientdata(client); | ||
1361 | |||
1362 | bh1770_chip_off(chip); | ||
1363 | |||
1364 | return 0; | ||
1365 | } | ||
1366 | |||
1367 | static int bh1770_runtime_resume(struct device *dev) | ||
1368 | { | ||
1369 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
1370 | struct bh1770_chip *chip = i2c_get_clientdata(client); | ||
1371 | |||
1372 | bh1770_chip_on(chip); | ||
1373 | |||
1374 | return 0; | ||
1375 | } | ||
1376 | #endif | ||
1377 | |||
1378 | static const struct i2c_device_id bh1770_id[] = { | ||
1379 | {"bh1770glc", 0 }, | ||
1380 | {"sfh7770", 0 }, | ||
1381 | {} | ||
1382 | }; | ||
1383 | |||
1384 | MODULE_DEVICE_TABLE(i2c, bh1770_id); | ||
1385 | |||
1386 | static const struct dev_pm_ops bh1770_pm_ops = { | ||
1387 | SET_SYSTEM_SLEEP_PM_OPS(bh1770_suspend, bh1770_resume) | ||
1388 | SET_RUNTIME_PM_OPS(bh1770_runtime_suspend, bh1770_runtime_resume, NULL) | ||
1389 | }; | ||
1390 | |||
1391 | static struct i2c_driver bh1770_driver = { | ||
1392 | .driver = { | ||
1393 | .name = "bh1770glc", | ||
1394 | .owner = THIS_MODULE, | ||
1395 | .pm = &bh1770_pm_ops, | ||
1396 | }, | ||
1397 | .probe = bh1770_probe, | ||
1398 | .remove = __devexit_p(bh1770_remove), | ||
1399 | .id_table = bh1770_id, | ||
1400 | }; | ||
1401 | |||
1402 | static int __init bh1770_init(void) | ||
1403 | { | ||
1404 | return i2c_add_driver(&bh1770_driver); | ||
1405 | } | ||
1406 | |||
1407 | static void __exit bh1770_exit(void) | ||
1408 | { | ||
1409 | i2c_del_driver(&bh1770_driver); | ||
1410 | } | ||
1411 | |||
1412 | MODULE_DESCRIPTION("BH1770GLC / SFH7770 combined ALS and proximity sensor"); | ||
1413 | MODULE_AUTHOR("Samu Onkalo, Nokia Corporation"); | ||
1414 | MODULE_LICENSE("GPL v2"); | ||
1415 | |||
1416 | module_init(bh1770_init); | ||
1417 | module_exit(bh1770_exit); | ||
diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c index d5f3a3fd2319..82fe2d067827 100644 --- a/drivers/misc/bh1780gli.c +++ b/drivers/misc/bh1780gli.c | |||
@@ -49,8 +49,8 @@ static int bh1780_write(struct bh1780_data *ddata, u8 reg, u8 val, char *msg) | |||
49 | int ret = i2c_smbus_write_byte_data(ddata->client, reg, val); | 49 | int ret = i2c_smbus_write_byte_data(ddata->client, reg, val); |
50 | if (ret < 0) | 50 | if (ret < 0) |
51 | dev_err(&ddata->client->dev, | 51 | dev_err(&ddata->client->dev, |
52 | "i2c_smbus_write_byte_data failed error %d\ | 52 | "i2c_smbus_write_byte_data failed error %d Register (%s)\n", |
53 | Register (%s)\n", ret, msg); | 53 | ret, msg); |
54 | return ret; | 54 | return ret; |
55 | } | 55 | } |
56 | 56 | ||
@@ -59,8 +59,8 @@ static int bh1780_read(struct bh1780_data *ddata, u8 reg, char *msg) | |||
59 | int ret = i2c_smbus_read_byte_data(ddata->client, reg); | 59 | int ret = i2c_smbus_read_byte_data(ddata->client, reg); |
60 | if (ret < 0) | 60 | if (ret < 0) |
61 | dev_err(&ddata->client->dev, | 61 | dev_err(&ddata->client->dev, |
62 | "i2c_smbus_read_byte_data failed error %d\ | 62 | "i2c_smbus_read_byte_data failed error %d Register (%s)\n", |
63 | Register (%s)\n", ret, msg); | 63 | ret, msg); |
64 | return ret; | 64 | return ret; |
65 | } | 65 | } |
66 | 66 | ||
@@ -196,10 +196,11 @@ static int __devexit bh1780_remove(struct i2c_client *client) | |||
196 | } | 196 | } |
197 | 197 | ||
198 | #ifdef CONFIG_PM | 198 | #ifdef CONFIG_PM |
199 | static int bh1780_suspend(struct i2c_client *client, pm_message_t mesg) | 199 | static int bh1780_suspend(struct device *dev) |
200 | { | 200 | { |
201 | struct bh1780_data *ddata; | 201 | struct bh1780_data *ddata; |
202 | int state, ret; | 202 | int state, ret; |
203 | struct i2c_client *client = to_i2c_client(dev); | ||
203 | 204 | ||
204 | ddata = i2c_get_clientdata(client); | 205 | ddata = i2c_get_clientdata(client); |
205 | state = bh1780_read(ddata, BH1780_REG_CONTROL, "CONTROL"); | 206 | state = bh1780_read(ddata, BH1780_REG_CONTROL, "CONTROL"); |
@@ -217,14 +218,14 @@ static int bh1780_suspend(struct i2c_client *client, pm_message_t mesg) | |||
217 | return 0; | 218 | return 0; |
218 | } | 219 | } |
219 | 220 | ||
220 | static int bh1780_resume(struct i2c_client *client) | 221 | static int bh1780_resume(struct device *dev) |
221 | { | 222 | { |
222 | struct bh1780_data *ddata; | 223 | struct bh1780_data *ddata; |
223 | int state, ret; | 224 | int state, ret; |
225 | struct i2c_client *client = to_i2c_client(dev); | ||
224 | 226 | ||
225 | ddata = i2c_get_clientdata(client); | 227 | ddata = i2c_get_clientdata(client); |
226 | state = ddata->power_state; | 228 | state = ddata->power_state; |
227 | |||
228 | ret = bh1780_write(ddata, BH1780_REG_CONTROL, state, | 229 | ret = bh1780_write(ddata, BH1780_REG_CONTROL, state, |
229 | "CONTROL"); | 230 | "CONTROL"); |
230 | 231 | ||
@@ -233,9 +234,10 @@ static int bh1780_resume(struct i2c_client *client) | |||
233 | 234 | ||
234 | return 0; | 235 | return 0; |
235 | } | 236 | } |
237 | static SIMPLE_DEV_PM_OPS(bh1780_pm, bh1780_suspend, bh1780_resume); | ||
238 | #define BH1780_PMOPS (&bh1780_pm) | ||
236 | #else | 239 | #else |
237 | #define bh1780_suspend NULL | 240 | #define BH1780_PMOPS NULL |
238 | #define bh1780_resume NULL | ||
239 | #endif /* CONFIG_PM */ | 241 | #endif /* CONFIG_PM */ |
240 | 242 | ||
241 | static const struct i2c_device_id bh1780_id[] = { | 243 | static const struct i2c_device_id bh1780_id[] = { |
@@ -247,11 +249,10 @@ static struct i2c_driver bh1780_driver = { | |||
247 | .probe = bh1780_probe, | 249 | .probe = bh1780_probe, |
248 | .remove = bh1780_remove, | 250 | .remove = bh1780_remove, |
249 | .id_table = bh1780_id, | 251 | .id_table = bh1780_id, |
250 | .suspend = bh1780_suspend, | ||
251 | .resume = bh1780_resume, | ||
252 | .driver = { | 252 | .driver = { |
253 | .name = "bh1780" | 253 | .name = "bh1780", |
254 | }, | 254 | .pm = BH1780_PMOPS, |
255 | }, | ||
255 | }; | 256 | }; |
256 | 257 | ||
257 | static int __init bh1780_init(void) | 258 | static int __init bh1780_init(void) |
diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c index 63ee4c1a5315..5f898cb706a6 100644 --- a/drivers/misc/bmp085.c +++ b/drivers/misc/bmp085.c | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | This driver supports the bmp085 digital barometric pressure | 3 | This driver supports the bmp085 digital barometric pressure |
4 | and temperature sensor from Bosch Sensortec. The datasheet | 4 | and temperature sensor from Bosch Sensortec. The datasheet |
5 | is avaliable from their website: | 5 | is available from their website: |
6 | http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP085-DS000-05.pdf | 6 | http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP085-DS000-05.pdf |
7 | 7 | ||
8 | A pressure measurement is issued by reading from pressure0_input. | 8 | A pressure measurement is issued by reading from pressure0_input. |
@@ -402,7 +402,7 @@ exit: | |||
402 | return status; | 402 | return status; |
403 | } | 403 | } |
404 | 404 | ||
405 | static int bmp085_probe(struct i2c_client *client, | 405 | static int __devinit bmp085_probe(struct i2c_client *client, |
406 | const struct i2c_device_id *id) | 406 | const struct i2c_device_id *id) |
407 | { | 407 | { |
408 | struct bmp085_data *data; | 408 | struct bmp085_data *data; |
@@ -429,7 +429,7 @@ static int bmp085_probe(struct i2c_client *client, | |||
429 | if (err) | 429 | if (err) |
430 | goto exit_free; | 430 | goto exit_free; |
431 | 431 | ||
432 | dev_info(&data->client->dev, "Succesfully initialized bmp085!\n"); | 432 | dev_info(&data->client->dev, "Successfully initialized bmp085!\n"); |
433 | goto exit; | 433 | goto exit; |
434 | 434 | ||
435 | exit_free: | 435 | exit_free: |
@@ -438,7 +438,7 @@ exit: | |||
438 | return err; | 438 | return err; |
439 | } | 439 | } |
440 | 440 | ||
441 | static int bmp085_remove(struct i2c_client *client) | 441 | static int __devexit bmp085_remove(struct i2c_client *client) |
442 | { | 442 | { |
443 | sysfs_remove_group(&client->dev.kobj, &bmp085_attr_group); | 443 | sysfs_remove_group(&client->dev.kobj, &bmp085_attr_group); |
444 | kfree(i2c_get_clientdata(client)); | 444 | kfree(i2c_get_clientdata(client)); |
@@ -449,6 +449,7 @@ static const struct i2c_device_id bmp085_id[] = { | |||
449 | { "bmp085", 0 }, | 449 | { "bmp085", 0 }, |
450 | { } | 450 | { } |
451 | }; | 451 | }; |
452 | MODULE_DEVICE_TABLE(i2c, bmp085_id); | ||
452 | 453 | ||
453 | static struct i2c_driver bmp085_driver = { | 454 | static struct i2c_driver bmp085_driver = { |
454 | .driver = { | 455 | .driver = { |
@@ -457,7 +458,7 @@ static struct i2c_driver bmp085_driver = { | |||
457 | }, | 458 | }, |
458 | .id_table = bmp085_id, | 459 | .id_table = bmp085_id, |
459 | .probe = bmp085_probe, | 460 | .probe = bmp085_probe, |
460 | .remove = bmp085_remove, | 461 | .remove = __devexit_p(bmp085_remove), |
461 | 462 | ||
462 | .detect = bmp085_detect, | 463 | .detect = bmp085_detect, |
463 | .address_list = normal_i2c | 464 | .address_list = normal_i2c |
diff --git a/drivers/misc/c2port/c2port-duramar2150.c b/drivers/misc/c2port/c2port-duramar2150.c index 338dcc121507..778fc3fdfb9b 100644 --- a/drivers/misc/c2port/c2port-duramar2150.c +++ b/drivers/misc/c2port/c2port-duramar2150.c | |||
@@ -41,7 +41,7 @@ static void duramar2150_c2port_access(struct c2port_device *dev, int status) | |||
41 | outb(v | (C2D | C2CK), DIR_PORT); | 41 | outb(v | (C2D | C2CK), DIR_PORT); |
42 | else | 42 | else |
43 | /* When access is "off" is important that both lines are set | 43 | /* When access is "off" is important that both lines are set |
44 | * as inputs or hi-impedence */ | 44 | * as inputs or hi-impedance */ |
45 | outb(v & ~(C2D | C2CK), DIR_PORT); | 45 | outb(v & ~(C2D | C2CK), DIR_PORT); |
46 | 46 | ||
47 | mutex_unlock(&update_lock); | 47 | mutex_unlock(&update_lock); |
diff --git a/drivers/misc/carma/Kconfig b/drivers/misc/carma/Kconfig new file mode 100644 index 000000000000..c90370ed712b --- /dev/null +++ b/drivers/misc/carma/Kconfig | |||
@@ -0,0 +1,17 @@ | |||
1 | config CARMA_FPGA | ||
2 | tristate "CARMA DATA-FPGA Access Driver" | ||
3 | depends on FSL_SOC && PPC_83xx && MEDIA_SUPPORT && HAS_DMA && FSL_DMA | ||
4 | select VIDEOBUF_DMA_SG | ||
5 | default n | ||
6 | help | ||
7 | Say Y here to include support for communicating with the data | ||
8 | processing FPGAs on the OVRO CARMA board. | ||
9 | |||
10 | config CARMA_FPGA_PROGRAM | ||
11 | tristate "CARMA DATA-FPGA Programmer" | ||
12 | depends on FSL_SOC && PPC_83xx && MEDIA_SUPPORT && HAS_DMA && FSL_DMA | ||
13 | select VIDEOBUF_DMA_SG | ||
14 | default n | ||
15 | help | ||
16 | Say Y here to include support for programming the data processing | ||
17 | FPGAs on the OVRO CARMA board. | ||
diff --git a/drivers/misc/carma/Makefile b/drivers/misc/carma/Makefile new file mode 100644 index 000000000000..ff36ac2ce534 --- /dev/null +++ b/drivers/misc/carma/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | obj-$(CONFIG_CARMA_FPGA) += carma-fpga.o | ||
2 | obj-$(CONFIG_CARMA_FPGA_PROGRAM) += carma-fpga-program.o | ||
diff --git a/drivers/misc/carma/carma-fpga-program.c b/drivers/misc/carma/carma-fpga-program.c new file mode 100644 index 000000000000..7ce6065dc20e --- /dev/null +++ b/drivers/misc/carma/carma-fpga-program.c | |||
@@ -0,0 +1,1141 @@ | |||
1 | /* | ||
2 | * CARMA Board DATA-FPGA Programmer | ||
3 | * | ||
4 | * Copyright (c) 2009-2011 Ira W. Snyder <iws@ovro.caltech.edu> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/dma-mapping.h> | ||
13 | #include <linux/of_platform.h> | ||
14 | #include <linux/completion.h> | ||
15 | #include <linux/miscdevice.h> | ||
16 | #include <linux/dmaengine.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/highmem.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/mutex.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/leds.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/kref.h> | ||
27 | #include <linux/fs.h> | ||
28 | #include <linux/io.h> | ||
29 | |||
30 | #include <media/videobuf-dma-sg.h> | ||
31 | |||
32 | /* MPC8349EMDS specific get_immrbase() */ | ||
33 | #include <sysdev/fsl_soc.h> | ||
34 | |||
35 | static const char drv_name[] = "carma-fpga-program"; | ||
36 | |||
37 | /* | ||
38 | * Firmware images are always this exact size | ||
39 | * | ||
40 | * 12849552 bytes for a CARMA Digitizer Board (EP2S90 FPGAs) | ||
41 | * 18662880 bytes for a CARMA Correlator Board (EP2S130 FPGAs) | ||
42 | */ | ||
43 | #define FW_SIZE_EP2S90 12849552 | ||
44 | #define FW_SIZE_EP2S130 18662880 | ||
45 | |||
46 | struct fpga_dev { | ||
47 | struct miscdevice miscdev; | ||
48 | |||
49 | /* Reference count */ | ||
50 | struct kref ref; | ||
51 | |||
52 | /* Device Registers */ | ||
53 | struct device *dev; | ||
54 | void __iomem *regs; | ||
55 | void __iomem *immr; | ||
56 | |||
57 | /* Freescale DMA Device */ | ||
58 | struct dma_chan *chan; | ||
59 | |||
60 | /* Interrupts */ | ||
61 | int irq, status; | ||
62 | struct completion completion; | ||
63 | |||
64 | /* FPGA Bitfile */ | ||
65 | struct mutex lock; | ||
66 | |||
67 | struct videobuf_dmabuf vb; | ||
68 | bool vb_allocated; | ||
69 | |||
70 | /* max size and written bytes */ | ||
71 | size_t fw_size; | ||
72 | size_t bytes; | ||
73 | }; | ||
74 | |||
75 | /* | ||
76 | * FPGA Bitfile Helpers | ||
77 | */ | ||
78 | |||
79 | /** | ||
80 | * fpga_drop_firmware_data() - drop the bitfile image from memory | ||
81 | * @priv: the driver's private data structure | ||
82 | * | ||
83 | * LOCKING: must hold priv->lock | ||
84 | */ | ||
85 | static void fpga_drop_firmware_data(struct fpga_dev *priv) | ||
86 | { | ||
87 | videobuf_dma_free(&priv->vb); | ||
88 | priv->vb_allocated = false; | ||
89 | priv->bytes = 0; | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * Private Data Reference Count | ||
94 | */ | ||
95 | |||
96 | static void fpga_dev_remove(struct kref *ref) | ||
97 | { | ||
98 | struct fpga_dev *priv = container_of(ref, struct fpga_dev, ref); | ||
99 | |||
100 | /* free any firmware image that was not programmed */ | ||
101 | fpga_drop_firmware_data(priv); | ||
102 | |||
103 | mutex_destroy(&priv->lock); | ||
104 | kfree(priv); | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | * LED Trigger (could be a seperate module) | ||
109 | */ | ||
110 | |||
111 | /* | ||
112 | * NOTE: this whole thing does have the problem that whenever the led's are | ||
113 | * NOTE: first set to use the fpga trigger, they could be in the wrong state | ||
114 | */ | ||
115 | |||
116 | DEFINE_LED_TRIGGER(ledtrig_fpga); | ||
117 | |||
118 | static void ledtrig_fpga_programmed(bool enabled) | ||
119 | { | ||
120 | if (enabled) | ||
121 | led_trigger_event(ledtrig_fpga, LED_FULL); | ||
122 | else | ||
123 | led_trigger_event(ledtrig_fpga, LED_OFF); | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * FPGA Register Helpers | ||
128 | */ | ||
129 | |||
130 | /* Register Definitions */ | ||
131 | #define FPGA_CONFIG_CONTROL 0x40 | ||
132 | #define FPGA_CONFIG_STATUS 0x44 | ||
133 | #define FPGA_CONFIG_FIFO_SIZE 0x48 | ||
134 | #define FPGA_CONFIG_FIFO_USED 0x4C | ||
135 | #define FPGA_CONFIG_TOTAL_BYTE_COUNT 0x50 | ||
136 | #define FPGA_CONFIG_CUR_BYTE_COUNT 0x54 | ||
137 | |||
138 | #define FPGA_FIFO_ADDRESS 0x3000 | ||
139 | |||
140 | static int fpga_fifo_size(void __iomem *regs) | ||
141 | { | ||
142 | return ioread32be(regs + FPGA_CONFIG_FIFO_SIZE); | ||
143 | } | ||
144 | |||
145 | #define CFG_STATUS_ERR_MASK 0xfffe | ||
146 | |||
147 | static int fpga_config_error(void __iomem *regs) | ||
148 | { | ||
149 | return ioread32be(regs + FPGA_CONFIG_STATUS) & CFG_STATUS_ERR_MASK; | ||
150 | } | ||
151 | |||
152 | static int fpga_fifo_empty(void __iomem *regs) | ||
153 | { | ||
154 | return ioread32be(regs + FPGA_CONFIG_FIFO_USED) == 0; | ||
155 | } | ||
156 | |||
157 | static void fpga_fifo_write(void __iomem *regs, u32 val) | ||
158 | { | ||
159 | iowrite32be(val, regs + FPGA_FIFO_ADDRESS); | ||
160 | } | ||
161 | |||
162 | static void fpga_set_byte_count(void __iomem *regs, u32 count) | ||
163 | { | ||
164 | iowrite32be(count, regs + FPGA_CONFIG_TOTAL_BYTE_COUNT); | ||
165 | } | ||
166 | |||
167 | #define CFG_CTL_ENABLE (1 << 0) | ||
168 | #define CFG_CTL_RESET (1 << 1) | ||
169 | #define CFG_CTL_DMA (1 << 2) | ||
170 | |||
171 | static void fpga_programmer_enable(struct fpga_dev *priv, bool dma) | ||
172 | { | ||
173 | u32 val; | ||
174 | |||
175 | val = (dma) ? (CFG_CTL_ENABLE | CFG_CTL_DMA) : CFG_CTL_ENABLE; | ||
176 | iowrite32be(val, priv->regs + FPGA_CONFIG_CONTROL); | ||
177 | } | ||
178 | |||
179 | static void fpga_programmer_disable(struct fpga_dev *priv) | ||
180 | { | ||
181 | iowrite32be(0x0, priv->regs + FPGA_CONFIG_CONTROL); | ||
182 | } | ||
183 | |||
184 | static void fpga_dump_registers(struct fpga_dev *priv) | ||
185 | { | ||
186 | u32 control, status, size, used, total, curr; | ||
187 | |||
188 | /* good status: do nothing */ | ||
189 | if (priv->status == 0) | ||
190 | return; | ||
191 | |||
192 | /* Dump all status registers */ | ||
193 | control = ioread32be(priv->regs + FPGA_CONFIG_CONTROL); | ||
194 | status = ioread32be(priv->regs + FPGA_CONFIG_STATUS); | ||
195 | size = ioread32be(priv->regs + FPGA_CONFIG_FIFO_SIZE); | ||
196 | used = ioread32be(priv->regs + FPGA_CONFIG_FIFO_USED); | ||
197 | total = ioread32be(priv->regs + FPGA_CONFIG_TOTAL_BYTE_COUNT); | ||
198 | curr = ioread32be(priv->regs + FPGA_CONFIG_CUR_BYTE_COUNT); | ||
199 | |||
200 | dev_err(priv->dev, "Configuration failed, dumping status registers\n"); | ||
201 | dev_err(priv->dev, "Control: 0x%.8x\n", control); | ||
202 | dev_err(priv->dev, "Status: 0x%.8x\n", status); | ||
203 | dev_err(priv->dev, "FIFO Size: 0x%.8x\n", size); | ||
204 | dev_err(priv->dev, "FIFO Used: 0x%.8x\n", used); | ||
205 | dev_err(priv->dev, "FIFO Total: 0x%.8x\n", total); | ||
206 | dev_err(priv->dev, "FIFO Curr: 0x%.8x\n", curr); | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * FPGA Power Supply Code | ||
211 | */ | ||
212 | |||
213 | #define CTL_PWR_CONTROL 0x2006 | ||
214 | #define CTL_PWR_STATUS 0x200A | ||
215 | #define CTL_PWR_FAIL 0x200B | ||
216 | |||
217 | #define PWR_CONTROL_ENABLE 0x01 | ||
218 | |||
219 | #define PWR_STATUS_ERROR_MASK 0x10 | ||
220 | #define PWR_STATUS_GOOD 0x0f | ||
221 | |||
222 | /* | ||
223 | * Determine if the FPGA power is good for all supplies | ||
224 | */ | ||
225 | static bool fpga_power_good(struct fpga_dev *priv) | ||
226 | { | ||
227 | u8 val; | ||
228 | |||
229 | val = ioread8(priv->regs + CTL_PWR_STATUS); | ||
230 | if (val & PWR_STATUS_ERROR_MASK) | ||
231 | return false; | ||
232 | |||
233 | return val == PWR_STATUS_GOOD; | ||
234 | } | ||
235 | |||
236 | /* | ||
237 | * Disable the FPGA power supplies | ||
238 | */ | ||
239 | static void fpga_disable_power_supplies(struct fpga_dev *priv) | ||
240 | { | ||
241 | unsigned long start; | ||
242 | u8 val; | ||
243 | |||
244 | iowrite8(0x0, priv->regs + CTL_PWR_CONTROL); | ||
245 | |||
246 | /* | ||
247 | * Wait 500ms for the power rails to discharge | ||
248 | * | ||
249 | * Without this delay, the CTL-CPLD state machine can get into a | ||
250 | * state where it is waiting for the power-goods to assert, but they | ||
251 | * never do. This only happens when enabling and disabling the | ||
252 | * power sequencer very rapidly. | ||
253 | * | ||
254 | * The loop below will also wait for the power goods to de-assert, | ||
255 | * but testing has shown that they are always disabled by the time | ||
256 | * the sleep completes. However, omitting the sleep and only waiting | ||
257 | * for the power-goods to de-assert was not sufficient to ensure | ||
258 | * that the power sequencer would not wedge itself. | ||
259 | */ | ||
260 | msleep(500); | ||
261 | |||
262 | start = jiffies; | ||
263 | while (time_before(jiffies, start + HZ)) { | ||
264 | val = ioread8(priv->regs + CTL_PWR_STATUS); | ||
265 | if (!(val & PWR_STATUS_GOOD)) | ||
266 | break; | ||
267 | |||
268 | usleep_range(5000, 10000); | ||
269 | } | ||
270 | |||
271 | val = ioread8(priv->regs + CTL_PWR_STATUS); | ||
272 | if (val & PWR_STATUS_GOOD) { | ||
273 | dev_err(priv->dev, "power disable failed: " | ||
274 | "power goods: status 0x%.2x\n", val); | ||
275 | } | ||
276 | |||
277 | if (val & PWR_STATUS_ERROR_MASK) { | ||
278 | dev_err(priv->dev, "power disable failed: " | ||
279 | "alarm bit set: status 0x%.2x\n", val); | ||
280 | } | ||
281 | } | ||
282 | |||
283 | /** | ||
284 | * fpga_enable_power_supplies() - enable the DATA-FPGA power supplies | ||
285 | * @priv: the driver's private data structure | ||
286 | * | ||
287 | * Enable the DATA-FPGA power supplies, waiting up to 1 second for | ||
288 | * them to enable successfully. | ||
289 | * | ||
290 | * Returns 0 on success, -ERRNO otherwise | ||
291 | */ | ||
292 | static int fpga_enable_power_supplies(struct fpga_dev *priv) | ||
293 | { | ||
294 | unsigned long start = jiffies; | ||
295 | |||
296 | if (fpga_power_good(priv)) { | ||
297 | dev_dbg(priv->dev, "power was already good\n"); | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | iowrite8(PWR_CONTROL_ENABLE, priv->regs + CTL_PWR_CONTROL); | ||
302 | while (time_before(jiffies, start + HZ)) { | ||
303 | if (fpga_power_good(priv)) | ||
304 | return 0; | ||
305 | |||
306 | usleep_range(5000, 10000); | ||
307 | } | ||
308 | |||
309 | return fpga_power_good(priv) ? 0 : -ETIMEDOUT; | ||
310 | } | ||
311 | |||
312 | /* | ||
313 | * Determine if the FPGA power supplies are all enabled | ||
314 | */ | ||
315 | static bool fpga_power_enabled(struct fpga_dev *priv) | ||
316 | { | ||
317 | u8 val; | ||
318 | |||
319 | val = ioread8(priv->regs + CTL_PWR_CONTROL); | ||
320 | if (val & PWR_CONTROL_ENABLE) | ||
321 | return true; | ||
322 | |||
323 | return false; | ||
324 | } | ||
325 | |||
326 | /* | ||
327 | * Determine if the FPGA's are programmed and running correctly | ||
328 | */ | ||
329 | static bool fpga_running(struct fpga_dev *priv) | ||
330 | { | ||
331 | if (!fpga_power_good(priv)) | ||
332 | return false; | ||
333 | |||
334 | /* Check the config done bit */ | ||
335 | return ioread32be(priv->regs + FPGA_CONFIG_STATUS) & (1 << 18); | ||
336 | } | ||
337 | |||
338 | /* | ||
339 | * FPGA Programming Code | ||
340 | */ | ||
341 | |||
342 | /** | ||
343 | * fpga_program_block() - put a block of data into the programmer's FIFO | ||
344 | * @priv: the driver's private data structure | ||
345 | * @buf: the data to program | ||
346 | * @count: the length of data to program (must be a multiple of 4 bytes) | ||
347 | * | ||
348 | * Returns 0 on success, -ERRNO otherwise | ||
349 | */ | ||
350 | static int fpga_program_block(struct fpga_dev *priv, void *buf, size_t count) | ||
351 | { | ||
352 | u32 *data = buf; | ||
353 | int size = fpga_fifo_size(priv->regs); | ||
354 | int i, len; | ||
355 | unsigned long timeout; | ||
356 | |||
357 | /* enforce correct data length for the FIFO */ | ||
358 | BUG_ON(count % 4 != 0); | ||
359 | |||
360 | while (count > 0) { | ||
361 | |||
362 | /* Get the size of the block to write (maximum is FIFO_SIZE) */ | ||
363 | len = min_t(size_t, count, size); | ||
364 | timeout = jiffies + HZ / 4; | ||
365 | |||
366 | /* Write the block */ | ||
367 | for (i = 0; i < len / 4; i++) | ||
368 | fpga_fifo_write(priv->regs, data[i]); | ||
369 | |||
370 | /* Update the amounts left */ | ||
371 | count -= len; | ||
372 | data += len / 4; | ||
373 | |||
374 | /* Wait for the fifo to empty */ | ||
375 | while (true) { | ||
376 | |||
377 | if (fpga_fifo_empty(priv->regs)) { | ||
378 | break; | ||
379 | } else { | ||
380 | dev_dbg(priv->dev, "Fifo not empty\n"); | ||
381 | cpu_relax(); | ||
382 | } | ||
383 | |||
384 | if (fpga_config_error(priv->regs)) { | ||
385 | dev_err(priv->dev, "Error detected\n"); | ||
386 | return -EIO; | ||
387 | } | ||
388 | |||
389 | if (time_after(jiffies, timeout)) { | ||
390 | dev_err(priv->dev, "Fifo drain timeout\n"); | ||
391 | return -ETIMEDOUT; | ||
392 | } | ||
393 | |||
394 | usleep_range(5000, 10000); | ||
395 | } | ||
396 | } | ||
397 | |||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | /** | ||
402 | * fpga_program_cpu() - program the DATA-FPGA's using the CPU | ||
403 | * @priv: the driver's private data structure | ||
404 | * | ||
405 | * This is useful when the DMA programming method fails. It is possible to | ||
406 | * wedge the Freescale DMA controller such that the DMA programming method | ||
407 | * always fails. This method has always succeeded. | ||
408 | * | ||
409 | * Returns 0 on success, -ERRNO otherwise | ||
410 | */ | ||
411 | static noinline int fpga_program_cpu(struct fpga_dev *priv) | ||
412 | { | ||
413 | int ret; | ||
414 | |||
415 | /* Disable the programmer */ | ||
416 | fpga_programmer_disable(priv); | ||
417 | |||
418 | /* Set the total byte count */ | ||
419 | fpga_set_byte_count(priv->regs, priv->bytes); | ||
420 | dev_dbg(priv->dev, "total byte count %u bytes\n", priv->bytes); | ||
421 | |||
422 | /* Enable the controller for programming */ | ||
423 | fpga_programmer_enable(priv, false); | ||
424 | dev_dbg(priv->dev, "enabled the controller\n"); | ||
425 | |||
426 | /* Write each chunk of the FPGA bitfile to FPGA programmer */ | ||
427 | ret = fpga_program_block(priv, priv->vb.vaddr, priv->bytes); | ||
428 | if (ret) | ||
429 | goto out_disable_controller; | ||
430 | |||
431 | /* Wait for the interrupt handler to signal that programming finished */ | ||
432 | ret = wait_for_completion_timeout(&priv->completion, 2 * HZ); | ||
433 | if (!ret) { | ||
434 | dev_err(priv->dev, "Timed out waiting for completion\n"); | ||
435 | ret = -ETIMEDOUT; | ||
436 | goto out_disable_controller; | ||
437 | } | ||
438 | |||
439 | /* Retrieve the status from the interrupt handler */ | ||
440 | ret = priv->status; | ||
441 | |||
442 | out_disable_controller: | ||
443 | fpga_programmer_disable(priv); | ||
444 | return ret; | ||
445 | } | ||
446 | |||
447 | #define FIFO_DMA_ADDRESS 0xf0003000 | ||
448 | #define FIFO_MAX_LEN 4096 | ||
449 | |||
450 | /** | ||
451 | * fpga_program_dma() - program the DATA-FPGA's using the DMA engine | ||
452 | * @priv: the driver's private data structure | ||
453 | * | ||
454 | * Program the DATA-FPGA's using the Freescale DMA engine. This requires that | ||
455 | * the engine is programmed such that the hardware DMA request lines can | ||
456 | * control the entire DMA transaction. The system controller FPGA then | ||
457 | * completely offloads the programming from the CPU. | ||
458 | * | ||
459 | * Returns 0 on success, -ERRNO otherwise | ||
460 | */ | ||
461 | static noinline int fpga_program_dma(struct fpga_dev *priv) | ||
462 | { | ||
463 | struct videobuf_dmabuf *vb = &priv->vb; | ||
464 | struct dma_chan *chan = priv->chan; | ||
465 | struct dma_async_tx_descriptor *tx; | ||
466 | size_t num_pages, len, avail = 0; | ||
467 | struct dma_slave_config config; | ||
468 | struct scatterlist *sg; | ||
469 | struct sg_table table; | ||
470 | dma_cookie_t cookie; | ||
471 | int ret, i; | ||
472 | |||
473 | /* Disable the programmer */ | ||
474 | fpga_programmer_disable(priv); | ||
475 | |||
476 | /* Allocate a scatterlist for the DMA destination */ | ||
477 | num_pages = DIV_ROUND_UP(priv->bytes, FIFO_MAX_LEN); | ||
478 | ret = sg_alloc_table(&table, num_pages, GFP_KERNEL); | ||
479 | if (ret) { | ||
480 | dev_err(priv->dev, "Unable to allocate dst scatterlist\n"); | ||
481 | ret = -ENOMEM; | ||
482 | goto out_return; | ||
483 | } | ||
484 | |||
485 | /* | ||
486 | * This is an ugly hack | ||
487 | * | ||
488 | * We fill in a scatterlist as if it were mapped for DMA. This is | ||
489 | * necessary because there exists no better structure for this | ||
490 | * inside the kernel code. | ||
491 | * | ||
492 | * As an added bonus, we can use the DMAEngine API for all of this, | ||
493 | * rather than inventing another extremely similar API. | ||
494 | */ | ||
495 | avail = priv->bytes; | ||
496 | for_each_sg(table.sgl, sg, num_pages, i) { | ||
497 | len = min_t(size_t, avail, FIFO_MAX_LEN); | ||
498 | sg_dma_address(sg) = FIFO_DMA_ADDRESS; | ||
499 | sg_dma_len(sg) = len; | ||
500 | |||
501 | avail -= len; | ||
502 | } | ||
503 | |||
504 | /* Map the buffer for DMA */ | ||
505 | ret = videobuf_dma_map(priv->dev, &priv->vb); | ||
506 | if (ret) { | ||
507 | dev_err(priv->dev, "Unable to map buffer for DMA\n"); | ||
508 | goto out_free_table; | ||
509 | } | ||
510 | |||
511 | /* | ||
512 | * Configure the DMA channel to transfer FIFO_SIZE / 2 bytes per | ||
513 | * transaction, and then put it under external control | ||
514 | */ | ||
515 | memset(&config, 0, sizeof(config)); | ||
516 | config.direction = DMA_TO_DEVICE; | ||
517 | config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
518 | config.dst_maxburst = fpga_fifo_size(priv->regs) / 2 / 4; | ||
519 | ret = chan->device->device_control(chan, DMA_SLAVE_CONFIG, | ||
520 | (unsigned long)&config); | ||
521 | if (ret) { | ||
522 | dev_err(priv->dev, "DMA slave configuration failed\n"); | ||
523 | goto out_dma_unmap; | ||
524 | } | ||
525 | |||
526 | ret = chan->device->device_control(chan, FSLDMA_EXTERNAL_START, 1); | ||
527 | if (ret) { | ||
528 | dev_err(priv->dev, "DMA external control setup failed\n"); | ||
529 | goto out_dma_unmap; | ||
530 | } | ||
531 | |||
532 | /* setup and submit the DMA transaction */ | ||
533 | tx = chan->device->device_prep_dma_sg(chan, | ||
534 | table.sgl, num_pages, | ||
535 | vb->sglist, vb->sglen, 0); | ||
536 | if (!tx) { | ||
537 | dev_err(priv->dev, "Unable to prep DMA transaction\n"); | ||
538 | ret = -ENOMEM; | ||
539 | goto out_dma_unmap; | ||
540 | } | ||
541 | |||
542 | cookie = tx->tx_submit(tx); | ||
543 | if (dma_submit_error(cookie)) { | ||
544 | dev_err(priv->dev, "Unable to submit DMA transaction\n"); | ||
545 | ret = -ENOMEM; | ||
546 | goto out_dma_unmap; | ||
547 | } | ||
548 | |||
549 | dma_async_memcpy_issue_pending(chan); | ||
550 | |||
551 | /* Set the total byte count */ | ||
552 | fpga_set_byte_count(priv->regs, priv->bytes); | ||
553 | dev_dbg(priv->dev, "total byte count %u bytes\n", priv->bytes); | ||
554 | |||
555 | /* Enable the controller for DMA programming */ | ||
556 | fpga_programmer_enable(priv, true); | ||
557 | dev_dbg(priv->dev, "enabled the controller\n"); | ||
558 | |||
559 | /* Wait for the interrupt handler to signal that programming finished */ | ||
560 | ret = wait_for_completion_timeout(&priv->completion, 2 * HZ); | ||
561 | if (!ret) { | ||
562 | dev_err(priv->dev, "Timed out waiting for completion\n"); | ||
563 | ret = -ETIMEDOUT; | ||
564 | goto out_disable_controller; | ||
565 | } | ||
566 | |||
567 | /* Retrieve the status from the interrupt handler */ | ||
568 | ret = priv->status; | ||
569 | |||
570 | out_disable_controller: | ||
571 | fpga_programmer_disable(priv); | ||
572 | out_dma_unmap: | ||
573 | videobuf_dma_unmap(priv->dev, vb); | ||
574 | out_free_table: | ||
575 | sg_free_table(&table); | ||
576 | out_return: | ||
577 | return ret; | ||
578 | } | ||
579 | |||
580 | /* | ||
581 | * Interrupt Handling | ||
582 | */ | ||
583 | |||
584 | static irqreturn_t fpga_irq(int irq, void *dev_id) | ||
585 | { | ||
586 | struct fpga_dev *priv = dev_id; | ||
587 | |||
588 | /* Save the status */ | ||
589 | priv->status = fpga_config_error(priv->regs) ? -EIO : 0; | ||
590 | dev_dbg(priv->dev, "INTERRUPT status %d\n", priv->status); | ||
591 | fpga_dump_registers(priv); | ||
592 | |||
593 | /* Disabling the programmer clears the interrupt */ | ||
594 | fpga_programmer_disable(priv); | ||
595 | |||
596 | /* Notify any waiters */ | ||
597 | complete(&priv->completion); | ||
598 | |||
599 | return IRQ_HANDLED; | ||
600 | } | ||
601 | |||
602 | /* | ||
603 | * SYSFS Helpers | ||
604 | */ | ||
605 | |||
606 | /** | ||
607 | * fpga_do_stop() - deconfigure (reset) the DATA-FPGA's | ||
608 | * @priv: the driver's private data structure | ||
609 | * | ||
610 | * LOCKING: must hold priv->lock | ||
611 | */ | ||
612 | static int fpga_do_stop(struct fpga_dev *priv) | ||
613 | { | ||
614 | u32 val; | ||
615 | |||
616 | /* Set the led to unprogrammed */ | ||
617 | ledtrig_fpga_programmed(false); | ||
618 | |||
619 | /* Pulse the config line to reset the FPGA's */ | ||
620 | val = CFG_CTL_ENABLE | CFG_CTL_RESET; | ||
621 | iowrite32be(val, priv->regs + FPGA_CONFIG_CONTROL); | ||
622 | iowrite32be(0x0, priv->regs + FPGA_CONFIG_CONTROL); | ||
623 | |||
624 | return 0; | ||
625 | } | ||
626 | |||
627 | static noinline int fpga_do_program(struct fpga_dev *priv) | ||
628 | { | ||
629 | int ret; | ||
630 | |||
631 | if (priv->bytes != priv->fw_size) { | ||
632 | dev_err(priv->dev, "Incorrect bitfile size: got %zu bytes, " | ||
633 | "should be %zu bytes\n", | ||
634 | priv->bytes, priv->fw_size); | ||
635 | return -EINVAL; | ||
636 | } | ||
637 | |||
638 | if (!fpga_power_enabled(priv)) { | ||
639 | dev_err(priv->dev, "Power not enabled\n"); | ||
640 | return -EINVAL; | ||
641 | } | ||
642 | |||
643 | if (!fpga_power_good(priv)) { | ||
644 | dev_err(priv->dev, "Power not good\n"); | ||
645 | return -EINVAL; | ||
646 | } | ||
647 | |||
648 | /* Set the LED to unprogrammed */ | ||
649 | ledtrig_fpga_programmed(false); | ||
650 | |||
651 | /* Try to program the FPGA's using DMA */ | ||
652 | ret = fpga_program_dma(priv); | ||
653 | |||
654 | /* If DMA failed or doesn't exist, try with CPU */ | ||
655 | if (ret) { | ||
656 | dev_warn(priv->dev, "Falling back to CPU programming\n"); | ||
657 | ret = fpga_program_cpu(priv); | ||
658 | } | ||
659 | |||
660 | if (ret) { | ||
661 | dev_err(priv->dev, "Unable to program FPGA's\n"); | ||
662 | return ret; | ||
663 | } | ||
664 | |||
665 | /* Drop the firmware bitfile from memory */ | ||
666 | fpga_drop_firmware_data(priv); | ||
667 | |||
668 | dev_dbg(priv->dev, "FPGA programming successful\n"); | ||
669 | ledtrig_fpga_programmed(true); | ||
670 | |||
671 | return 0; | ||
672 | } | ||
673 | |||
674 | /* | ||
675 | * File Operations | ||
676 | */ | ||
677 | |||
678 | static int fpga_open(struct inode *inode, struct file *filp) | ||
679 | { | ||
680 | /* | ||
681 | * The miscdevice layer puts our struct miscdevice into the | ||
682 | * filp->private_data field. We use this to find our private | ||
683 | * data and then overwrite it with our own private structure. | ||
684 | */ | ||
685 | struct fpga_dev *priv = container_of(filp->private_data, | ||
686 | struct fpga_dev, miscdev); | ||
687 | unsigned int nr_pages; | ||
688 | int ret; | ||
689 | |||
690 | /* We only allow one process at a time */ | ||
691 | ret = mutex_lock_interruptible(&priv->lock); | ||
692 | if (ret) | ||
693 | return ret; | ||
694 | |||
695 | filp->private_data = priv; | ||
696 | kref_get(&priv->ref); | ||
697 | |||
698 | /* Truncation: drop any existing data */ | ||
699 | if (filp->f_flags & O_TRUNC) | ||
700 | priv->bytes = 0; | ||
701 | |||
702 | /* Check if we have already allocated a buffer */ | ||
703 | if (priv->vb_allocated) | ||
704 | return 0; | ||
705 | |||
706 | /* Allocate a buffer to hold enough data for the bitfile */ | ||
707 | nr_pages = DIV_ROUND_UP(priv->fw_size, PAGE_SIZE); | ||
708 | ret = videobuf_dma_init_kernel(&priv->vb, DMA_TO_DEVICE, nr_pages); | ||
709 | if (ret) { | ||
710 | dev_err(priv->dev, "unable to allocate data buffer\n"); | ||
711 | mutex_unlock(&priv->lock); | ||
712 | kref_put(&priv->ref, fpga_dev_remove); | ||
713 | return ret; | ||
714 | } | ||
715 | |||
716 | priv->vb_allocated = true; | ||
717 | return 0; | ||
718 | } | ||
719 | |||
720 | static int fpga_release(struct inode *inode, struct file *filp) | ||
721 | { | ||
722 | struct fpga_dev *priv = filp->private_data; | ||
723 | |||
724 | mutex_unlock(&priv->lock); | ||
725 | kref_put(&priv->ref, fpga_dev_remove); | ||
726 | return 0; | ||
727 | } | ||
728 | |||
729 | static ssize_t fpga_write(struct file *filp, const char __user *buf, | ||
730 | size_t count, loff_t *f_pos) | ||
731 | { | ||
732 | struct fpga_dev *priv = filp->private_data; | ||
733 | |||
734 | /* FPGA bitfiles have an exact size: disallow anything else */ | ||
735 | if (priv->bytes >= priv->fw_size) | ||
736 | return -ENOSPC; | ||
737 | |||
738 | count = min_t(size_t, priv->fw_size - priv->bytes, count); | ||
739 | if (copy_from_user(priv->vb.vaddr + priv->bytes, buf, count)) | ||
740 | return -EFAULT; | ||
741 | |||
742 | priv->bytes += count; | ||
743 | return count; | ||
744 | } | ||
745 | |||
746 | static ssize_t fpga_read(struct file *filp, char __user *buf, size_t count, | ||
747 | loff_t *f_pos) | ||
748 | { | ||
749 | struct fpga_dev *priv = filp->private_data; | ||
750 | |||
751 | count = min_t(size_t, priv->bytes - *f_pos, count); | ||
752 | if (copy_to_user(buf, priv->vb.vaddr + *f_pos, count)) | ||
753 | return -EFAULT; | ||
754 | |||
755 | *f_pos += count; | ||
756 | return count; | ||
757 | } | ||
758 | |||
759 | static loff_t fpga_llseek(struct file *filp, loff_t offset, int origin) | ||
760 | { | ||
761 | struct fpga_dev *priv = filp->private_data; | ||
762 | loff_t newpos; | ||
763 | |||
764 | /* only read-only opens are allowed to seek */ | ||
765 | if ((filp->f_flags & O_ACCMODE) != O_RDONLY) | ||
766 | return -EINVAL; | ||
767 | |||
768 | switch (origin) { | ||
769 | case SEEK_SET: /* seek relative to the beginning of the file */ | ||
770 | newpos = offset; | ||
771 | break; | ||
772 | case SEEK_CUR: /* seek relative to current position in the file */ | ||
773 | newpos = filp->f_pos + offset; | ||
774 | break; | ||
775 | case SEEK_END: /* seek relative to the end of the file */ | ||
776 | newpos = priv->fw_size - offset; | ||
777 | break; | ||
778 | default: | ||
779 | return -EINVAL; | ||
780 | } | ||
781 | |||
782 | /* check for sanity */ | ||
783 | if (newpos > priv->fw_size) | ||
784 | return -EINVAL; | ||
785 | |||
786 | filp->f_pos = newpos; | ||
787 | return newpos; | ||
788 | } | ||
789 | |||
790 | static const struct file_operations fpga_fops = { | ||
791 | .open = fpga_open, | ||
792 | .release = fpga_release, | ||
793 | .write = fpga_write, | ||
794 | .read = fpga_read, | ||
795 | .llseek = fpga_llseek, | ||
796 | }; | ||
797 | |||
798 | /* | ||
799 | * Device Attributes | ||
800 | */ | ||
801 | |||
802 | static ssize_t pfail_show(struct device *dev, struct device_attribute *attr, | ||
803 | char *buf) | ||
804 | { | ||
805 | struct fpga_dev *priv = dev_get_drvdata(dev); | ||
806 | u8 val; | ||
807 | |||
808 | val = ioread8(priv->regs + CTL_PWR_FAIL); | ||
809 | return snprintf(buf, PAGE_SIZE, "0x%.2x\n", val); | ||
810 | } | ||
811 | |||
812 | static ssize_t pgood_show(struct device *dev, struct device_attribute *attr, | ||
813 | char *buf) | ||
814 | { | ||
815 | struct fpga_dev *priv = dev_get_drvdata(dev); | ||
816 | return snprintf(buf, PAGE_SIZE, "%d\n", fpga_power_good(priv)); | ||
817 | } | ||
818 | |||
819 | static ssize_t penable_show(struct device *dev, struct device_attribute *attr, | ||
820 | char *buf) | ||
821 | { | ||
822 | struct fpga_dev *priv = dev_get_drvdata(dev); | ||
823 | return snprintf(buf, PAGE_SIZE, "%d\n", fpga_power_enabled(priv)); | ||
824 | } | ||
825 | |||
826 | static ssize_t penable_store(struct device *dev, struct device_attribute *attr, | ||
827 | const char *buf, size_t count) | ||
828 | { | ||
829 | struct fpga_dev *priv = dev_get_drvdata(dev); | ||
830 | unsigned long val; | ||
831 | int ret; | ||
832 | |||
833 | if (strict_strtoul(buf, 0, &val)) | ||
834 | return -EINVAL; | ||
835 | |||
836 | if (val) { | ||
837 | ret = fpga_enable_power_supplies(priv); | ||
838 | if (ret) | ||
839 | return ret; | ||
840 | } else { | ||
841 | fpga_do_stop(priv); | ||
842 | fpga_disable_power_supplies(priv); | ||
843 | } | ||
844 | |||
845 | return count; | ||
846 | } | ||
847 | |||
848 | static ssize_t program_show(struct device *dev, struct device_attribute *attr, | ||
849 | char *buf) | ||
850 | { | ||
851 | struct fpga_dev *priv = dev_get_drvdata(dev); | ||
852 | return snprintf(buf, PAGE_SIZE, "%d\n", fpga_running(priv)); | ||
853 | } | ||
854 | |||
855 | static ssize_t program_store(struct device *dev, struct device_attribute *attr, | ||
856 | const char *buf, size_t count) | ||
857 | { | ||
858 | struct fpga_dev *priv = dev_get_drvdata(dev); | ||
859 | unsigned long val; | ||
860 | int ret; | ||
861 | |||
862 | if (strict_strtoul(buf, 0, &val)) | ||
863 | return -EINVAL; | ||
864 | |||
865 | /* We can't have an image writer and be programming simultaneously */ | ||
866 | if (mutex_lock_interruptible(&priv->lock)) | ||
867 | return -ERESTARTSYS; | ||
868 | |||
869 | /* Program or Reset the FPGA's */ | ||
870 | ret = val ? fpga_do_program(priv) : fpga_do_stop(priv); | ||
871 | if (ret) | ||
872 | goto out_unlock; | ||
873 | |||
874 | /* Success */ | ||
875 | ret = count; | ||
876 | |||
877 | out_unlock: | ||
878 | mutex_unlock(&priv->lock); | ||
879 | return ret; | ||
880 | } | ||
881 | |||
882 | static DEVICE_ATTR(power_fail, S_IRUGO, pfail_show, NULL); | ||
883 | static DEVICE_ATTR(power_good, S_IRUGO, pgood_show, NULL); | ||
884 | static DEVICE_ATTR(power_enable, S_IRUGO | S_IWUSR, | ||
885 | penable_show, penable_store); | ||
886 | |||
887 | static DEVICE_ATTR(program, S_IRUGO | S_IWUSR, | ||
888 | program_show, program_store); | ||
889 | |||
890 | static struct attribute *fpga_attributes[] = { | ||
891 | &dev_attr_power_fail.attr, | ||
892 | &dev_attr_power_good.attr, | ||
893 | &dev_attr_power_enable.attr, | ||
894 | &dev_attr_program.attr, | ||
895 | NULL, | ||
896 | }; | ||
897 | |||
898 | static const struct attribute_group fpga_attr_group = { | ||
899 | .attrs = fpga_attributes, | ||
900 | }; | ||
901 | |||
902 | /* | ||
903 | * OpenFirmware Device Subsystem | ||
904 | */ | ||
905 | |||
906 | #define SYS_REG_VERSION 0x00 | ||
907 | #define SYS_REG_GEOGRAPHIC 0x10 | ||
908 | |||
909 | static bool dma_filter(struct dma_chan *chan, void *data) | ||
910 | { | ||
911 | /* | ||
912 | * DMA Channel #0 is the only acceptable device | ||
913 | * | ||
914 | * This probably won't survive an unload/load cycle of the Freescale | ||
915 | * DMAEngine driver, but that won't be a problem | ||
916 | */ | ||
917 | return chan->chan_id == 0 && chan->device->dev_id == 0; | ||
918 | } | ||
919 | |||
920 | static int fpga_of_remove(struct platform_device *op) | ||
921 | { | ||
922 | struct fpga_dev *priv = dev_get_drvdata(&op->dev); | ||
923 | struct device *this_device = priv->miscdev.this_device; | ||
924 | |||
925 | sysfs_remove_group(&this_device->kobj, &fpga_attr_group); | ||
926 | misc_deregister(&priv->miscdev); | ||
927 | |||
928 | free_irq(priv->irq, priv); | ||
929 | irq_dispose_mapping(priv->irq); | ||
930 | |||
931 | /* make sure the power supplies are off */ | ||
932 | fpga_disable_power_supplies(priv); | ||
933 | |||
934 | /* unmap registers */ | ||
935 | iounmap(priv->immr); | ||
936 | iounmap(priv->regs); | ||
937 | |||
938 | dma_release_channel(priv->chan); | ||
939 | |||
940 | /* drop our reference to the private data structure */ | ||
941 | kref_put(&priv->ref, fpga_dev_remove); | ||
942 | return 0; | ||
943 | } | ||
944 | |||
945 | /* CTL-CPLD Version Register */ | ||
946 | #define CTL_CPLD_VERSION 0x2000 | ||
947 | |||
948 | static int fpga_of_probe(struct platform_device *op, | ||
949 | const struct of_device_id *match) | ||
950 | { | ||
951 | struct device_node *of_node = op->dev.of_node; | ||
952 | struct device *this_device; | ||
953 | struct fpga_dev *priv; | ||
954 | dma_cap_mask_t mask; | ||
955 | u32 ver; | ||
956 | int ret; | ||
957 | |||
958 | /* Allocate private data */ | ||
959 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
960 | if (!priv) { | ||
961 | dev_err(&op->dev, "Unable to allocate private data\n"); | ||
962 | ret = -ENOMEM; | ||
963 | goto out_return; | ||
964 | } | ||
965 | |||
966 | /* Setup the miscdevice */ | ||
967 | priv->miscdev.minor = MISC_DYNAMIC_MINOR; | ||
968 | priv->miscdev.name = drv_name; | ||
969 | priv->miscdev.fops = &fpga_fops; | ||
970 | |||
971 | kref_init(&priv->ref); | ||
972 | |||
973 | dev_set_drvdata(&op->dev, priv); | ||
974 | priv->dev = &op->dev; | ||
975 | mutex_init(&priv->lock); | ||
976 | init_completion(&priv->completion); | ||
977 | videobuf_dma_init(&priv->vb); | ||
978 | |||
979 | dev_set_drvdata(priv->dev, priv); | ||
980 | dma_cap_zero(mask); | ||
981 | dma_cap_set(DMA_MEMCPY, mask); | ||
982 | dma_cap_set(DMA_INTERRUPT, mask); | ||
983 | dma_cap_set(DMA_SLAVE, mask); | ||
984 | dma_cap_set(DMA_SG, mask); | ||
985 | |||
986 | /* Get control of DMA channel #0 */ | ||
987 | priv->chan = dma_request_channel(mask, dma_filter, NULL); | ||
988 | if (!priv->chan) { | ||
989 | dev_err(&op->dev, "Unable to acquire DMA channel #0\n"); | ||
990 | ret = -ENODEV; | ||
991 | goto out_free_priv; | ||
992 | } | ||
993 | |||
994 | /* Remap the registers for use */ | ||
995 | priv->regs = of_iomap(of_node, 0); | ||
996 | if (!priv->regs) { | ||
997 | dev_err(&op->dev, "Unable to ioremap registers\n"); | ||
998 | ret = -ENOMEM; | ||
999 | goto out_dma_release_channel; | ||
1000 | } | ||
1001 | |||
1002 | /* Remap the IMMR for use */ | ||
1003 | priv->immr = ioremap(get_immrbase(), 0x100000); | ||
1004 | if (!priv->immr) { | ||
1005 | dev_err(&op->dev, "Unable to ioremap IMMR\n"); | ||
1006 | ret = -ENOMEM; | ||
1007 | goto out_unmap_regs; | ||
1008 | } | ||
1009 | |||
1010 | /* | ||
1011 | * Check that external DMA is configured | ||
1012 | * | ||
1013 | * U-Boot does this for us, but we should check it and bail out if | ||
1014 | * there is a problem. Failing to have this register setup correctly | ||
1015 | * will cause the DMA controller to transfer a single cacheline | ||
1016 | * worth of data, then wedge itself. | ||
1017 | */ | ||
1018 | if ((ioread32be(priv->immr + 0x114) & 0xE00) != 0xE00) { | ||
1019 | dev_err(&op->dev, "External DMA control not configured\n"); | ||
1020 | ret = -ENODEV; | ||
1021 | goto out_unmap_immr; | ||
1022 | } | ||
1023 | |||
1024 | /* | ||
1025 | * Check the CTL-CPLD version | ||
1026 | * | ||
1027 | * This driver uses the CTL-CPLD DATA-FPGA power sequencer, and we | ||
1028 | * don't want to run on any version of the CTL-CPLD that does not use | ||
1029 | * a compatible register layout. | ||
1030 | * | ||
1031 | * v2: changed register layout, added power sequencer | ||
1032 | * v3: added glitch filter on the i2c overcurrent/overtemp outputs | ||
1033 | */ | ||
1034 | ver = ioread8(priv->regs + CTL_CPLD_VERSION); | ||
1035 | if (ver != 0x02 && ver != 0x03) { | ||
1036 | dev_err(&op->dev, "CTL-CPLD is not version 0x02 or 0x03!\n"); | ||
1037 | ret = -ENODEV; | ||
1038 | goto out_unmap_immr; | ||
1039 | } | ||
1040 | |||
1041 | /* Set the exact size that the firmware image should be */ | ||
1042 | ver = ioread32be(priv->regs + SYS_REG_VERSION); | ||
1043 | priv->fw_size = (ver & (1 << 18)) ? FW_SIZE_EP2S130 : FW_SIZE_EP2S90; | ||
1044 | |||
1045 | /* Find the correct IRQ number */ | ||
1046 | priv->irq = irq_of_parse_and_map(of_node, 0); | ||
1047 | if (priv->irq == NO_IRQ) { | ||
1048 | dev_err(&op->dev, "Unable to find IRQ line\n"); | ||
1049 | ret = -ENODEV; | ||
1050 | goto out_unmap_immr; | ||
1051 | } | ||
1052 | |||
1053 | /* Request the IRQ */ | ||
1054 | ret = request_irq(priv->irq, fpga_irq, IRQF_SHARED, drv_name, priv); | ||
1055 | if (ret) { | ||
1056 | dev_err(&op->dev, "Unable to request IRQ %d\n", priv->irq); | ||
1057 | ret = -ENODEV; | ||
1058 | goto out_irq_dispose_mapping; | ||
1059 | } | ||
1060 | |||
1061 | /* Reset and stop the FPGA's, just in case */ | ||
1062 | fpga_do_stop(priv); | ||
1063 | |||
1064 | /* Register the miscdevice */ | ||
1065 | ret = misc_register(&priv->miscdev); | ||
1066 | if (ret) { | ||
1067 | dev_err(&op->dev, "Unable to register miscdevice\n"); | ||
1068 | goto out_free_irq; | ||
1069 | } | ||
1070 | |||
1071 | /* Create the sysfs files */ | ||
1072 | this_device = priv->miscdev.this_device; | ||
1073 | dev_set_drvdata(this_device, priv); | ||
1074 | ret = sysfs_create_group(&this_device->kobj, &fpga_attr_group); | ||
1075 | if (ret) { | ||
1076 | dev_err(&op->dev, "Unable to create sysfs files\n"); | ||
1077 | goto out_misc_deregister; | ||
1078 | } | ||
1079 | |||
1080 | dev_info(priv->dev, "CARMA FPGA Programmer: %s rev%s with %s FPGAs\n", | ||
1081 | (ver & (1 << 17)) ? "Correlator" : "Digitizer", | ||
1082 | (ver & (1 << 16)) ? "B" : "A", | ||
1083 | (ver & (1 << 18)) ? "EP2S130" : "EP2S90"); | ||
1084 | |||
1085 | return 0; | ||
1086 | |||
1087 | out_misc_deregister: | ||
1088 | misc_deregister(&priv->miscdev); | ||
1089 | out_free_irq: | ||
1090 | free_irq(priv->irq, priv); | ||
1091 | out_irq_dispose_mapping: | ||
1092 | irq_dispose_mapping(priv->irq); | ||
1093 | out_unmap_immr: | ||
1094 | iounmap(priv->immr); | ||
1095 | out_unmap_regs: | ||
1096 | iounmap(priv->regs); | ||
1097 | out_dma_release_channel: | ||
1098 | dma_release_channel(priv->chan); | ||
1099 | out_free_priv: | ||
1100 | kref_put(&priv->ref, fpga_dev_remove); | ||
1101 | out_return: | ||
1102 | return ret; | ||
1103 | } | ||
1104 | |||
1105 | static struct of_device_id fpga_of_match[] = { | ||
1106 | { .compatible = "carma,fpga-programmer", }, | ||
1107 | {}, | ||
1108 | }; | ||
1109 | |||
1110 | static struct of_platform_driver fpga_of_driver = { | ||
1111 | .probe = fpga_of_probe, | ||
1112 | .remove = fpga_of_remove, | ||
1113 | .driver = { | ||
1114 | .name = drv_name, | ||
1115 | .of_match_table = fpga_of_match, | ||
1116 | .owner = THIS_MODULE, | ||
1117 | }, | ||
1118 | }; | ||
1119 | |||
1120 | /* | ||
1121 | * Module Init / Exit | ||
1122 | */ | ||
1123 | |||
1124 | static int __init fpga_init(void) | ||
1125 | { | ||
1126 | led_trigger_register_simple("fpga", &ledtrig_fpga); | ||
1127 | return of_register_platform_driver(&fpga_of_driver); | ||
1128 | } | ||
1129 | |||
1130 | static void __exit fpga_exit(void) | ||
1131 | { | ||
1132 | of_unregister_platform_driver(&fpga_of_driver); | ||
1133 | led_trigger_unregister_simple(ledtrig_fpga); | ||
1134 | } | ||
1135 | |||
1136 | MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>"); | ||
1137 | MODULE_DESCRIPTION("CARMA Board DATA-FPGA Programmer"); | ||
1138 | MODULE_LICENSE("GPL"); | ||
1139 | |||
1140 | module_init(fpga_init); | ||
1141 | module_exit(fpga_exit); | ||
diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c new file mode 100644 index 000000000000..3965821fef17 --- /dev/null +++ b/drivers/misc/carma/carma-fpga.c | |||
@@ -0,0 +1,1433 @@ | |||
1 | /* | ||
2 | * CARMA DATA-FPGA Access Driver | ||
3 | * | ||
4 | * Copyright (c) 2009-2011 Ira W. Snyder <iws@ovro.caltech.edu> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * FPGA Memory Dump Format | ||
14 | * | ||
15 | * FPGA #0 control registers (32 x 32-bit words) | ||
16 | * FPGA #1 control registers (32 x 32-bit words) | ||
17 | * FPGA #2 control registers (32 x 32-bit words) | ||
18 | * FPGA #3 control registers (32 x 32-bit words) | ||
19 | * SYSFPGA control registers (32 x 32-bit words) | ||
20 | * FPGA #0 correlation array (NUM_CORL0 correlation blocks) | ||
21 | * FPGA #1 correlation array (NUM_CORL1 correlation blocks) | ||
22 | * FPGA #2 correlation array (NUM_CORL2 correlation blocks) | ||
23 | * FPGA #3 correlation array (NUM_CORL3 correlation blocks) | ||
24 | * | ||
25 | * Each correlation array consists of: | ||
26 | * | ||
27 | * Correlation Data (2 x NUM_LAGSn x 32-bit words) | ||
28 | * Pipeline Metadata (2 x NUM_METAn x 32-bit words) | ||
29 | * Quantization Counters (2 x NUM_QCNTn x 32-bit words) | ||
30 | * | ||
31 | * The NUM_CORLn, NUM_LAGSn, NUM_METAn, and NUM_QCNTn values come from | ||
32 | * the FPGA configuration registers. They do not change once the FPGA's | ||
33 | * have been programmed, they only change on re-programming. | ||
34 | */ | ||
35 | |||
36 | /* | ||
37 | * Basic Description: | ||
38 | * | ||
39 | * This driver is used to capture correlation spectra off of the four data | ||
40 | * processing FPGAs. The FPGAs are often reprogrammed at runtime, therefore | ||
41 | * this driver supports dynamic enable/disable of capture while the device | ||
42 | * remains open. | ||
43 | * | ||
44 | * The nominal capture rate is 64Hz (every 15.625ms). To facilitate this fast | ||
45 | * capture rate, all buffers are pre-allocated to avoid any potentially long | ||
46 | * running memory allocations while capturing. | ||
47 | * | ||
48 | * There are two lists and one pointer which are used to keep track of the | ||
49 | * different states of data buffers. | ||
50 | * | ||
51 | * 1) free list | ||
52 | * This list holds all empty data buffers which are ready to receive data. | ||
53 | * | ||
54 | * 2) inflight pointer | ||
55 | * This pointer holds the currently inflight data buffer. This buffer is having | ||
56 | * data copied into it by the DMA engine. | ||
57 | * | ||
58 | * 3) used list | ||
59 | * This list holds data buffers which have been filled, and are waiting to be | ||
60 | * read by userspace. | ||
61 | * | ||
62 | * All buffers start life on the free list, then move successively to the | ||
63 | * inflight pointer, and then to the used list. After they have been read by | ||
64 | * userspace, they are moved back to the free list. The cycle repeats as long | ||
65 | * as necessary. | ||
66 | * | ||
67 | * It should be noted that all buffers are mapped and ready for DMA when they | ||
68 | * are on any of the three lists. They are only unmapped when they are in the | ||
69 | * process of being read by userspace. | ||
70 | */ | ||
71 | |||
72 | /* | ||
73 | * Notes on the IRQ masking scheme: | ||
74 | * | ||
75 | * The IRQ masking scheme here is different than most other hardware. The only | ||
76 | * way for the DATA-FPGAs to detect if the kernel has taken too long to copy | ||
77 | * the data is if the status registers are not cleared before the next | ||
78 | * correlation data dump is ready. | ||
79 | * | ||
80 | * The interrupt line is connected to the status registers, such that when they | ||
81 | * are cleared, the interrupt is de-asserted. Therein lies our problem. We need | ||
82 | * to schedule a long-running DMA operation and return from the interrupt | ||
83 | * handler quickly, but we cannot clear the status registers. | ||
84 | * | ||
85 | * To handle this, the system controller FPGA has the capability to connect the | ||
86 | * interrupt line to a user-controlled GPIO pin. This pin is driven high | ||
87 | * (unasserted) and left that way. To mask the interrupt, we change the | ||
88 | * interrupt source to the GPIO pin. Tada, we hid the interrupt. :) | ||
89 | */ | ||
90 | |||
91 | #include <linux/of_platform.h> | ||
92 | #include <linux/dma-mapping.h> | ||
93 | #include <linux/miscdevice.h> | ||
94 | #include <linux/interrupt.h> | ||
95 | #include <linux/dmaengine.h> | ||
96 | #include <linux/seq_file.h> | ||
97 | #include <linux/highmem.h> | ||
98 | #include <linux/debugfs.h> | ||
99 | #include <linux/kernel.h> | ||
100 | #include <linux/module.h> | ||
101 | #include <linux/poll.h> | ||
102 | #include <linux/init.h> | ||
103 | #include <linux/slab.h> | ||
104 | #include <linux/kref.h> | ||
105 | #include <linux/io.h> | ||
106 | |||
107 | #include <media/videobuf-dma-sg.h> | ||
108 | |||
109 | /* system controller registers */ | ||
110 | #define SYS_IRQ_SOURCE_CTL 0x24 | ||
111 | #define SYS_IRQ_OUTPUT_EN 0x28 | ||
112 | #define SYS_IRQ_OUTPUT_DATA 0x2C | ||
113 | #define SYS_IRQ_INPUT_DATA 0x30 | ||
114 | #define SYS_FPGA_CONFIG_STATUS 0x44 | ||
115 | |||
116 | /* GPIO IRQ line assignment */ | ||
117 | #define IRQ_CORL_DONE 0x10 | ||
118 | |||
119 | /* FPGA registers */ | ||
120 | #define MMAP_REG_VERSION 0x00 | ||
121 | #define MMAP_REG_CORL_CONF1 0x08 | ||
122 | #define MMAP_REG_CORL_CONF2 0x0C | ||
123 | #define MMAP_REG_STATUS 0x48 | ||
124 | |||
125 | #define SYS_FPGA_BLOCK 0xF0000000 | ||
126 | |||
127 | #define DATA_FPGA_START 0x400000 | ||
128 | #define DATA_FPGA_SIZE 0x80000 | ||
129 | |||
130 | static const char drv_name[] = "carma-fpga"; | ||
131 | |||
132 | #define NUM_FPGA 4 | ||
133 | |||
134 | #define MIN_DATA_BUFS 8 | ||
135 | #define MAX_DATA_BUFS 64 | ||
136 | |||
137 | struct fpga_info { | ||
138 | unsigned int num_lag_ram; | ||
139 | unsigned int blk_size; | ||
140 | }; | ||
141 | |||
142 | struct data_buf { | ||
143 | struct list_head entry; | ||
144 | struct videobuf_dmabuf vb; | ||
145 | size_t size; | ||
146 | }; | ||
147 | |||
148 | struct fpga_device { | ||
149 | /* character device */ | ||
150 | struct miscdevice miscdev; | ||
151 | struct device *dev; | ||
152 | struct mutex mutex; | ||
153 | |||
154 | /* reference count */ | ||
155 | struct kref ref; | ||
156 | |||
157 | /* FPGA registers and information */ | ||
158 | struct fpga_info info[NUM_FPGA]; | ||
159 | void __iomem *regs; | ||
160 | int irq; | ||
161 | |||
162 | /* FPGA Physical Address/Size Information */ | ||
163 | resource_size_t phys_addr; | ||
164 | size_t phys_size; | ||
165 | |||
166 | /* DMA structures */ | ||
167 | struct sg_table corl_table; | ||
168 | unsigned int corl_nents; | ||
169 | struct dma_chan *chan; | ||
170 | |||
171 | /* Protection for all members below */ | ||
172 | spinlock_t lock; | ||
173 | |||
174 | /* Device enable/disable flag */ | ||
175 | bool enabled; | ||
176 | |||
177 | /* Correlation data buffers */ | ||
178 | wait_queue_head_t wait; | ||
179 | struct list_head free; | ||
180 | struct list_head used; | ||
181 | struct data_buf *inflight; | ||
182 | |||
183 | /* Information about data buffers */ | ||
184 | unsigned int num_dropped; | ||
185 | unsigned int num_buffers; | ||
186 | size_t bufsize; | ||
187 | struct dentry *dbg_entry; | ||
188 | }; | ||
189 | |||
190 | struct fpga_reader { | ||
191 | struct fpga_device *priv; | ||
192 | struct data_buf *buf; | ||
193 | off_t buf_start; | ||
194 | }; | ||
195 | |||
196 | static void fpga_device_release(struct kref *ref) | ||
197 | { | ||
198 | struct fpga_device *priv = container_of(ref, struct fpga_device, ref); | ||
199 | |||
200 | /* the last reader has exited, cleanup the last bits */ | ||
201 | mutex_destroy(&priv->mutex); | ||
202 | kfree(priv); | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * Data Buffer Allocation Helpers | ||
207 | */ | ||
208 | |||
209 | /** | ||
210 | * data_free_buffer() - free a single data buffer and all allocated memory | ||
211 | * @buf: the buffer to free | ||
212 | * | ||
213 | * This will free all of the pages allocated to the given data buffer, and | ||
214 | * then free the structure itself | ||
215 | */ | ||
216 | static void data_free_buffer(struct data_buf *buf) | ||
217 | { | ||
218 | /* It is ok to free a NULL buffer */ | ||
219 | if (!buf) | ||
220 | return; | ||
221 | |||
222 | /* free all memory */ | ||
223 | videobuf_dma_free(&buf->vb); | ||
224 | kfree(buf); | ||
225 | } | ||
226 | |||
227 | /** | ||
228 | * data_alloc_buffer() - allocate and fill a data buffer with pages | ||
229 | * @bytes: the number of bytes required | ||
230 | * | ||
231 | * This allocates all space needed for a data buffer. It must be mapped before | ||
232 | * use in a DMA transaction using videobuf_dma_map(). | ||
233 | * | ||
234 | * Returns NULL on failure | ||
235 | */ | ||
236 | static struct data_buf *data_alloc_buffer(const size_t bytes) | ||
237 | { | ||
238 | unsigned int nr_pages; | ||
239 | struct data_buf *buf; | ||
240 | int ret; | ||
241 | |||
242 | /* calculate the number of pages necessary */ | ||
243 | nr_pages = DIV_ROUND_UP(bytes, PAGE_SIZE); | ||
244 | |||
245 | /* allocate the buffer structure */ | ||
246 | buf = kzalloc(sizeof(*buf), GFP_KERNEL); | ||
247 | if (!buf) | ||
248 | goto out_return; | ||
249 | |||
250 | /* initialize internal fields */ | ||
251 | INIT_LIST_HEAD(&buf->entry); | ||
252 | buf->size = bytes; | ||
253 | |||
254 | /* allocate the videobuf */ | ||
255 | videobuf_dma_init(&buf->vb); | ||
256 | ret = videobuf_dma_init_kernel(&buf->vb, DMA_FROM_DEVICE, nr_pages); | ||
257 | if (ret) | ||
258 | goto out_free_buf; | ||
259 | |||
260 | return buf; | ||
261 | |||
262 | out_free_buf: | ||
263 | kfree(buf); | ||
264 | out_return: | ||
265 | return NULL; | ||
266 | } | ||
267 | |||
268 | /** | ||
269 | * data_free_buffers() - free all allocated buffers | ||
270 | * @priv: the driver's private data structure | ||
271 | * | ||
272 | * Free all buffers allocated by the driver (except those currently in the | ||
273 | * process of being read by userspace). | ||
274 | * | ||
275 | * LOCKING: must hold dev->mutex | ||
276 | * CONTEXT: user | ||
277 | */ | ||
278 | static void data_free_buffers(struct fpga_device *priv) | ||
279 | { | ||
280 | struct data_buf *buf, *tmp; | ||
281 | |||
282 | /* the device should be stopped, no DMA in progress */ | ||
283 | BUG_ON(priv->inflight != NULL); | ||
284 | |||
285 | list_for_each_entry_safe(buf, tmp, &priv->free, entry) { | ||
286 | list_del_init(&buf->entry); | ||
287 | videobuf_dma_unmap(priv->dev, &buf->vb); | ||
288 | data_free_buffer(buf); | ||
289 | } | ||
290 | |||
291 | list_for_each_entry_safe(buf, tmp, &priv->used, entry) { | ||
292 | list_del_init(&buf->entry); | ||
293 | videobuf_dma_unmap(priv->dev, &buf->vb); | ||
294 | data_free_buffer(buf); | ||
295 | } | ||
296 | |||
297 | priv->num_buffers = 0; | ||
298 | priv->bufsize = 0; | ||
299 | } | ||
300 | |||
301 | /** | ||
302 | * data_alloc_buffers() - allocate 1 seconds worth of data buffers | ||
303 | * @priv: the driver's private data structure | ||
304 | * | ||
305 | * Allocate enough buffers for a whole second worth of data | ||
306 | * | ||
307 | * This routine will attempt to degrade nicely by succeeding even if a full | ||
308 | * second worth of data buffers could not be allocated, as long as a minimum | ||
309 | * number were allocated. In this case, it will print a message to the kernel | ||
310 | * log. | ||
311 | * | ||
312 | * The device must not be modifying any lists when this is called. | ||
313 | * | ||
314 | * CONTEXT: user | ||
315 | * LOCKING: must hold dev->mutex | ||
316 | * | ||
317 | * Returns 0 on success, -ERRNO otherwise | ||
318 | */ | ||
319 | static int data_alloc_buffers(struct fpga_device *priv) | ||
320 | { | ||
321 | struct data_buf *buf; | ||
322 | int i, ret; | ||
323 | |||
324 | for (i = 0; i < MAX_DATA_BUFS; i++) { | ||
325 | |||
326 | /* allocate a buffer */ | ||
327 | buf = data_alloc_buffer(priv->bufsize); | ||
328 | if (!buf) | ||
329 | break; | ||
330 | |||
331 | /* map it for DMA */ | ||
332 | ret = videobuf_dma_map(priv->dev, &buf->vb); | ||
333 | if (ret) { | ||
334 | data_free_buffer(buf); | ||
335 | break; | ||
336 | } | ||
337 | |||
338 | /* add it to the list of free buffers */ | ||
339 | list_add_tail(&buf->entry, &priv->free); | ||
340 | priv->num_buffers++; | ||
341 | } | ||
342 | |||
343 | /* Make sure we allocated the minimum required number of buffers */ | ||
344 | if (priv->num_buffers < MIN_DATA_BUFS) { | ||
345 | dev_err(priv->dev, "Unable to allocate enough data buffers\n"); | ||
346 | data_free_buffers(priv); | ||
347 | return -ENOMEM; | ||
348 | } | ||
349 | |||
350 | /* Warn if we are running in a degraded state, but do not fail */ | ||
351 | if (priv->num_buffers < MAX_DATA_BUFS) { | ||
352 | dev_warn(priv->dev, | ||
353 | "Unable to allocate %d buffers, using %d buffers instead\n", | ||
354 | MAX_DATA_BUFS, i); | ||
355 | } | ||
356 | |||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | /* | ||
361 | * DMA Operations Helpers | ||
362 | */ | ||
363 | |||
364 | /** | ||
365 | * fpga_start_addr() - get the physical address a DATA-FPGA | ||
366 | * @priv: the driver's private data structure | ||
367 | * @fpga: the DATA-FPGA number (zero based) | ||
368 | */ | ||
369 | static dma_addr_t fpga_start_addr(struct fpga_device *priv, unsigned int fpga) | ||
370 | { | ||
371 | return priv->phys_addr + 0x400000 + (0x80000 * fpga); | ||
372 | } | ||
373 | |||
374 | /** | ||
375 | * fpga_block_addr() - get the physical address of a correlation data block | ||
376 | * @priv: the driver's private data structure | ||
377 | * @fpga: the DATA-FPGA number (zero based) | ||
378 | * @blknum: the correlation block number (zero based) | ||
379 | */ | ||
380 | static dma_addr_t fpga_block_addr(struct fpga_device *priv, unsigned int fpga, | ||
381 | unsigned int blknum) | ||
382 | { | ||
383 | return fpga_start_addr(priv, fpga) + (0x10000 * (1 + blknum)); | ||
384 | } | ||
385 | |||
386 | #define REG_BLOCK_SIZE (32 * 4) | ||
387 | |||
388 | /** | ||
389 | * data_setup_corl_table() - create the scatterlist for correlation dumps | ||
390 | * @priv: the driver's private data structure | ||
391 | * | ||
392 | * Create the scatterlist for transferring a correlation dump from the | ||
393 | * DATA FPGAs. This structure will be reused for each buffer than needs | ||
394 | * to be filled with correlation data. | ||
395 | * | ||
396 | * Returns 0 on success, -ERRNO otherwise | ||
397 | */ | ||
398 | static int data_setup_corl_table(struct fpga_device *priv) | ||
399 | { | ||
400 | struct sg_table *table = &priv->corl_table; | ||
401 | struct scatterlist *sg; | ||
402 | struct fpga_info *info; | ||
403 | int i, j, ret; | ||
404 | |||
405 | /* Calculate the number of entries needed */ | ||
406 | priv->corl_nents = (1 + NUM_FPGA) * REG_BLOCK_SIZE; | ||
407 | for (i = 0; i < NUM_FPGA; i++) | ||
408 | priv->corl_nents += priv->info[i].num_lag_ram; | ||
409 | |||
410 | /* Allocate the scatterlist table */ | ||
411 | ret = sg_alloc_table(table, priv->corl_nents, GFP_KERNEL); | ||
412 | if (ret) { | ||
413 | dev_err(priv->dev, "unable to allocate DMA table\n"); | ||
414 | return ret; | ||
415 | } | ||
416 | |||
417 | /* Add the DATA FPGA registers to the scatterlist */ | ||
418 | sg = table->sgl; | ||
419 | for (i = 0; i < NUM_FPGA; i++) { | ||
420 | sg_dma_address(sg) = fpga_start_addr(priv, i); | ||
421 | sg_dma_len(sg) = REG_BLOCK_SIZE; | ||
422 | sg = sg_next(sg); | ||
423 | } | ||
424 | |||
425 | /* Add the SYS-FPGA registers to the scatterlist */ | ||
426 | sg_dma_address(sg) = SYS_FPGA_BLOCK; | ||
427 | sg_dma_len(sg) = REG_BLOCK_SIZE; | ||
428 | sg = sg_next(sg); | ||
429 | |||
430 | /* Add the FPGA correlation data blocks to the scatterlist */ | ||
431 | for (i = 0; i < NUM_FPGA; i++) { | ||
432 | info = &priv->info[i]; | ||
433 | for (j = 0; j < info->num_lag_ram; j++) { | ||
434 | sg_dma_address(sg) = fpga_block_addr(priv, i, j); | ||
435 | sg_dma_len(sg) = info->blk_size; | ||
436 | sg = sg_next(sg); | ||
437 | } | ||
438 | } | ||
439 | |||
440 | /* | ||
441 | * All physical addresses and lengths are present in the structure | ||
442 | * now. It can be reused for every FPGA DATA interrupt | ||
443 | */ | ||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | /* | ||
448 | * FPGA Register Access Helpers | ||
449 | */ | ||
450 | |||
451 | static void fpga_write_reg(struct fpga_device *priv, unsigned int fpga, | ||
452 | unsigned int reg, u32 val) | ||
453 | { | ||
454 | const int fpga_start = DATA_FPGA_START + (fpga * DATA_FPGA_SIZE); | ||
455 | iowrite32be(val, priv->regs + fpga_start + reg); | ||
456 | } | ||
457 | |||
458 | static u32 fpga_read_reg(struct fpga_device *priv, unsigned int fpga, | ||
459 | unsigned int reg) | ||
460 | { | ||
461 | const int fpga_start = DATA_FPGA_START + (fpga * DATA_FPGA_SIZE); | ||
462 | return ioread32be(priv->regs + fpga_start + reg); | ||
463 | } | ||
464 | |||
465 | /** | ||
466 | * data_calculate_bufsize() - calculate the data buffer size required | ||
467 | * @priv: the driver's private data structure | ||
468 | * | ||
469 | * Calculate the total buffer size needed to hold a single block | ||
470 | * of correlation data | ||
471 | * | ||
472 | * CONTEXT: user | ||
473 | * | ||
474 | * Returns 0 on success, -ERRNO otherwise | ||
475 | */ | ||
476 | static int data_calculate_bufsize(struct fpga_device *priv) | ||
477 | { | ||
478 | u32 num_corl, num_lags, num_meta, num_qcnt, num_pack; | ||
479 | u32 conf1, conf2, version; | ||
480 | u32 num_lag_ram, blk_size; | ||
481 | int i; | ||
482 | |||
483 | /* Each buffer starts with the 5 FPGA register areas */ | ||
484 | priv->bufsize = (1 + NUM_FPGA) * REG_BLOCK_SIZE; | ||
485 | |||
486 | /* Read and store the configuration data for each FPGA */ | ||
487 | for (i = 0; i < NUM_FPGA; i++) { | ||
488 | version = fpga_read_reg(priv, i, MMAP_REG_VERSION); | ||
489 | conf1 = fpga_read_reg(priv, i, MMAP_REG_CORL_CONF1); | ||
490 | conf2 = fpga_read_reg(priv, i, MMAP_REG_CORL_CONF2); | ||
491 | |||
492 | /* minor version 2 and later */ | ||
493 | if ((version & 0x000000FF) >= 2) { | ||
494 | num_corl = (conf1 & 0x000000F0) >> 4; | ||
495 | num_pack = (conf1 & 0x00000F00) >> 8; | ||
496 | num_lags = (conf1 & 0x00FFF000) >> 12; | ||
497 | num_meta = (conf1 & 0x7F000000) >> 24; | ||
498 | num_qcnt = (conf2 & 0x00000FFF) >> 0; | ||
499 | } else { | ||
500 | num_corl = (conf1 & 0x000000F0) >> 4; | ||
501 | num_pack = 1; /* implied */ | ||
502 | num_lags = (conf1 & 0x000FFF00) >> 8; | ||
503 | num_meta = (conf1 & 0x7FF00000) >> 20; | ||
504 | num_qcnt = (conf2 & 0x00000FFF) >> 0; | ||
505 | } | ||
506 | |||
507 | num_lag_ram = (num_corl + num_pack - 1) / num_pack; | ||
508 | blk_size = ((num_pack * num_lags) + num_meta + num_qcnt) * 8; | ||
509 | |||
510 | priv->info[i].num_lag_ram = num_lag_ram; | ||
511 | priv->info[i].blk_size = blk_size; | ||
512 | priv->bufsize += num_lag_ram * blk_size; | ||
513 | |||
514 | dev_dbg(priv->dev, "FPGA %d NUM_CORL: %d\n", i, num_corl); | ||
515 | dev_dbg(priv->dev, "FPGA %d NUM_PACK: %d\n", i, num_pack); | ||
516 | dev_dbg(priv->dev, "FPGA %d NUM_LAGS: %d\n", i, num_lags); | ||
517 | dev_dbg(priv->dev, "FPGA %d NUM_META: %d\n", i, num_meta); | ||
518 | dev_dbg(priv->dev, "FPGA %d NUM_QCNT: %d\n", i, num_qcnt); | ||
519 | dev_dbg(priv->dev, "FPGA %d BLK_SIZE: %d\n", i, blk_size); | ||
520 | } | ||
521 | |||
522 | dev_dbg(priv->dev, "TOTAL BUFFER SIZE: %zu bytes\n", priv->bufsize); | ||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | /* | ||
527 | * Interrupt Handling | ||
528 | */ | ||
529 | |||
530 | /** | ||
531 | * data_disable_interrupts() - stop the device from generating interrupts | ||
532 | * @priv: the driver's private data structure | ||
533 | * | ||
534 | * Hide interrupts by switching to GPIO interrupt source | ||
535 | * | ||
536 | * LOCKING: must hold dev->lock | ||
537 | */ | ||
538 | static void data_disable_interrupts(struct fpga_device *priv) | ||
539 | { | ||
540 | /* hide the interrupt by switching the IRQ driver to GPIO */ | ||
541 | iowrite32be(0x2F, priv->regs + SYS_IRQ_SOURCE_CTL); | ||
542 | } | ||
543 | |||
544 | /** | ||
545 | * data_enable_interrupts() - allow the device to generate interrupts | ||
546 | * @priv: the driver's private data structure | ||
547 | * | ||
548 | * Unhide interrupts by switching to the FPGA interrupt source. At the | ||
549 | * same time, clear the DATA-FPGA status registers. | ||
550 | * | ||
551 | * LOCKING: must hold dev->lock | ||
552 | */ | ||
553 | static void data_enable_interrupts(struct fpga_device *priv) | ||
554 | { | ||
555 | /* clear the actual FPGA corl_done interrupt */ | ||
556 | fpga_write_reg(priv, 0, MMAP_REG_STATUS, 0x0); | ||
557 | fpga_write_reg(priv, 1, MMAP_REG_STATUS, 0x0); | ||
558 | fpga_write_reg(priv, 2, MMAP_REG_STATUS, 0x0); | ||
559 | fpga_write_reg(priv, 3, MMAP_REG_STATUS, 0x0); | ||
560 | |||
561 | /* flush the writes */ | ||
562 | fpga_read_reg(priv, 0, MMAP_REG_STATUS); | ||
563 | |||
564 | /* switch back to the external interrupt source */ | ||
565 | iowrite32be(0x3F, priv->regs + SYS_IRQ_SOURCE_CTL); | ||
566 | } | ||
567 | |||
568 | /** | ||
569 | * data_dma_cb() - DMAEngine callback for DMA completion | ||
570 | * @data: the driver's private data structure | ||
571 | * | ||
572 | * Complete a DMA transfer from the DATA-FPGA's | ||
573 | * | ||
574 | * This is called via the DMA callback mechanism, and will handle moving the | ||
575 | * completed DMA transaction to the used list, and then wake any processes | ||
576 | * waiting for new data | ||
577 | * | ||
578 | * CONTEXT: any, softirq expected | ||
579 | */ | ||
580 | static void data_dma_cb(void *data) | ||
581 | { | ||
582 | struct fpga_device *priv = data; | ||
583 | unsigned long flags; | ||
584 | |||
585 | spin_lock_irqsave(&priv->lock, flags); | ||
586 | |||
587 | /* If there is no inflight buffer, we've got a bug */ | ||
588 | BUG_ON(priv->inflight == NULL); | ||
589 | |||
590 | /* Move the inflight buffer onto the used list */ | ||
591 | list_move_tail(&priv->inflight->entry, &priv->used); | ||
592 | priv->inflight = NULL; | ||
593 | |||
594 | /* clear the FPGA status and re-enable interrupts */ | ||
595 | data_enable_interrupts(priv); | ||
596 | |||
597 | spin_unlock_irqrestore(&priv->lock, flags); | ||
598 | |||
599 | /* | ||
600 | * We've changed both the inflight and used lists, so we need | ||
601 | * to wake up any processes that are blocking for those events | ||
602 | */ | ||
603 | wake_up(&priv->wait); | ||
604 | } | ||
605 | |||
606 | /** | ||
607 | * data_submit_dma() - prepare and submit the required DMA to fill a buffer | ||
608 | * @priv: the driver's private data structure | ||
609 | * @buf: the data buffer | ||
610 | * | ||
611 | * Prepare and submit the necessary DMA transactions to fill a correlation | ||
612 | * data buffer. | ||
613 | * | ||
614 | * LOCKING: must hold dev->lock | ||
615 | * CONTEXT: hardirq only | ||
616 | * | ||
617 | * Returns 0 on success, -ERRNO otherwise | ||
618 | */ | ||
619 | static int data_submit_dma(struct fpga_device *priv, struct data_buf *buf) | ||
620 | { | ||
621 | struct scatterlist *dst_sg, *src_sg; | ||
622 | unsigned int dst_nents, src_nents; | ||
623 | struct dma_chan *chan = priv->chan; | ||
624 | struct dma_async_tx_descriptor *tx; | ||
625 | dma_cookie_t cookie; | ||
626 | dma_addr_t dst, src; | ||
627 | |||
628 | dst_sg = buf->vb.sglist; | ||
629 | dst_nents = buf->vb.sglen; | ||
630 | |||
631 | src_sg = priv->corl_table.sgl; | ||
632 | src_nents = priv->corl_nents; | ||
633 | |||
634 | /* | ||
635 | * All buffers passed to this function should be ready and mapped | ||
636 | * for DMA already. Therefore, we don't need to do anything except | ||
637 | * submit it to the Freescale DMA Engine for processing | ||
638 | */ | ||
639 | |||
640 | /* setup the scatterlist to scatterlist transfer */ | ||
641 | tx = chan->device->device_prep_dma_sg(chan, | ||
642 | dst_sg, dst_nents, | ||
643 | src_sg, src_nents, | ||
644 | 0); | ||
645 | if (!tx) { | ||
646 | dev_err(priv->dev, "unable to prep scatterlist DMA\n"); | ||
647 | return -ENOMEM; | ||
648 | } | ||
649 | |||
650 | /* submit the transaction to the DMA controller */ | ||
651 | cookie = tx->tx_submit(tx); | ||
652 | if (dma_submit_error(cookie)) { | ||
653 | dev_err(priv->dev, "unable to submit scatterlist DMA\n"); | ||
654 | return -ENOMEM; | ||
655 | } | ||
656 | |||
657 | /* Prepare the re-read of the SYS-FPGA block */ | ||
658 | dst = sg_dma_address(dst_sg) + (NUM_FPGA * REG_BLOCK_SIZE); | ||
659 | src = SYS_FPGA_BLOCK; | ||
660 | tx = chan->device->device_prep_dma_memcpy(chan, dst, src, | ||
661 | REG_BLOCK_SIZE, | ||
662 | DMA_PREP_INTERRUPT); | ||
663 | if (!tx) { | ||
664 | dev_err(priv->dev, "unable to prep SYS-FPGA DMA\n"); | ||
665 | return -ENOMEM; | ||
666 | } | ||
667 | |||
668 | /* Setup the callback */ | ||
669 | tx->callback = data_dma_cb; | ||
670 | tx->callback_param = priv; | ||
671 | |||
672 | /* submit the transaction to the DMA controller */ | ||
673 | cookie = tx->tx_submit(tx); | ||
674 | if (dma_submit_error(cookie)) { | ||
675 | dev_err(priv->dev, "unable to submit SYS-FPGA DMA\n"); | ||
676 | return -ENOMEM; | ||
677 | } | ||
678 | |||
679 | return 0; | ||
680 | } | ||
681 | |||
682 | #define CORL_DONE 0x1 | ||
683 | #define CORL_ERR 0x2 | ||
684 | |||
685 | static irqreturn_t data_irq(int irq, void *dev_id) | ||
686 | { | ||
687 | struct fpga_device *priv = dev_id; | ||
688 | bool submitted = false; | ||
689 | struct data_buf *buf; | ||
690 | u32 status; | ||
691 | int i; | ||
692 | |||
693 | /* detect spurious interrupts via FPGA status */ | ||
694 | for (i = 0; i < 4; i++) { | ||
695 | status = fpga_read_reg(priv, i, MMAP_REG_STATUS); | ||
696 | if (!(status & (CORL_DONE | CORL_ERR))) { | ||
697 | dev_err(priv->dev, "spurious irq detected (FPGA)\n"); | ||
698 | return IRQ_NONE; | ||
699 | } | ||
700 | } | ||
701 | |||
702 | /* detect spurious interrupts via raw IRQ pin readback */ | ||
703 | status = ioread32be(priv->regs + SYS_IRQ_INPUT_DATA); | ||
704 | if (status & IRQ_CORL_DONE) { | ||
705 | dev_err(priv->dev, "spurious irq detected (IRQ)\n"); | ||
706 | return IRQ_NONE; | ||
707 | } | ||
708 | |||
709 | spin_lock(&priv->lock); | ||
710 | |||
711 | /* hide the interrupt by switching the IRQ driver to GPIO */ | ||
712 | data_disable_interrupts(priv); | ||
713 | |||
714 | /* If there are no free buffers, drop this data */ | ||
715 | if (list_empty(&priv->free)) { | ||
716 | priv->num_dropped++; | ||
717 | goto out; | ||
718 | } | ||
719 | |||
720 | buf = list_first_entry(&priv->free, struct data_buf, entry); | ||
721 | list_del_init(&buf->entry); | ||
722 | BUG_ON(buf->size != priv->bufsize); | ||
723 | |||
724 | /* Submit a DMA transfer to get the correlation data */ | ||
725 | if (data_submit_dma(priv, buf)) { | ||
726 | dev_err(priv->dev, "Unable to setup DMA transfer\n"); | ||
727 | list_move_tail(&buf->entry, &priv->free); | ||
728 | goto out; | ||
729 | } | ||
730 | |||
731 | /* Save the buffer for the DMA callback */ | ||
732 | priv->inflight = buf; | ||
733 | submitted = true; | ||
734 | |||
735 | /* Start the DMA Engine */ | ||
736 | dma_async_memcpy_issue_pending(priv->chan); | ||
737 | |||
738 | out: | ||
739 | /* If no DMA was submitted, re-enable interrupts */ | ||
740 | if (!submitted) | ||
741 | data_enable_interrupts(priv); | ||
742 | |||
743 | spin_unlock(&priv->lock); | ||
744 | return IRQ_HANDLED; | ||
745 | } | ||
746 | |||
747 | /* | ||
748 | * Realtime Device Enable Helpers | ||
749 | */ | ||
750 | |||
751 | /** | ||
752 | * data_device_enable() - enable the device for buffered dumping | ||
753 | * @priv: the driver's private data structure | ||
754 | * | ||
755 | * Enable the device for buffered dumping. Allocates buffers and hooks up | ||
756 | * the interrupt handler. When this finishes, data will come pouring in. | ||
757 | * | ||
758 | * LOCKING: must hold dev->mutex | ||
759 | * CONTEXT: user context only | ||
760 | * | ||
761 | * Returns 0 on success, -ERRNO otherwise | ||
762 | */ | ||
763 | static int data_device_enable(struct fpga_device *priv) | ||
764 | { | ||
765 | u32 val; | ||
766 | int ret; | ||
767 | |||
768 | /* multiple enables are safe: they do nothing */ | ||
769 | if (priv->enabled) | ||
770 | return 0; | ||
771 | |||
772 | /* check that the FPGAs are programmed */ | ||
773 | val = ioread32be(priv->regs + SYS_FPGA_CONFIG_STATUS); | ||
774 | if (!(val & (1 << 18))) { | ||
775 | dev_err(priv->dev, "DATA-FPGAs are not enabled\n"); | ||
776 | return -ENODATA; | ||
777 | } | ||
778 | |||
779 | /* read the FPGAs to calculate the buffer size */ | ||
780 | ret = data_calculate_bufsize(priv); | ||
781 | if (ret) { | ||
782 | dev_err(priv->dev, "unable to calculate buffer size\n"); | ||
783 | goto out_error; | ||
784 | } | ||
785 | |||
786 | /* allocate the correlation data buffers */ | ||
787 | ret = data_alloc_buffers(priv); | ||
788 | if (ret) { | ||
789 | dev_err(priv->dev, "unable to allocate buffers\n"); | ||
790 | goto out_error; | ||
791 | } | ||
792 | |||
793 | /* setup the source scatterlist for dumping correlation data */ | ||
794 | ret = data_setup_corl_table(priv); | ||
795 | if (ret) { | ||
796 | dev_err(priv->dev, "unable to setup correlation DMA table\n"); | ||
797 | goto out_error; | ||
798 | } | ||
799 | |||
800 | /* hookup the irq handler */ | ||
801 | ret = request_irq(priv->irq, data_irq, IRQF_SHARED, drv_name, priv); | ||
802 | if (ret) { | ||
803 | dev_err(priv->dev, "unable to request IRQ handler\n"); | ||
804 | goto out_error; | ||
805 | } | ||
806 | |||
807 | /* switch to the external FPGA IRQ line */ | ||
808 | data_enable_interrupts(priv); | ||
809 | |||
810 | /* success, we're enabled */ | ||
811 | priv->enabled = true; | ||
812 | return 0; | ||
813 | |||
814 | out_error: | ||
815 | sg_free_table(&priv->corl_table); | ||
816 | priv->corl_nents = 0; | ||
817 | |||
818 | data_free_buffers(priv); | ||
819 | return ret; | ||
820 | } | ||
821 | |||
822 | /** | ||
823 | * data_device_disable() - disable the device for buffered dumping | ||
824 | * @priv: the driver's private data structure | ||
825 | * | ||
826 | * Disable the device for buffered dumping. Stops new DMA transactions from | ||
827 | * being generated, waits for all outstanding DMA to complete, and then frees | ||
828 | * all buffers. | ||
829 | * | ||
830 | * LOCKING: must hold dev->mutex | ||
831 | * CONTEXT: user only | ||
832 | * | ||
833 | * Returns 0 on success, -ERRNO otherwise | ||
834 | */ | ||
835 | static int data_device_disable(struct fpga_device *priv) | ||
836 | { | ||
837 | int ret; | ||
838 | |||
839 | /* allow multiple disable */ | ||
840 | if (!priv->enabled) | ||
841 | return 0; | ||
842 | |||
843 | /* switch to the internal GPIO IRQ line */ | ||
844 | data_disable_interrupts(priv); | ||
845 | |||
846 | /* unhook the irq handler */ | ||
847 | free_irq(priv->irq, priv); | ||
848 | |||
849 | /* | ||
850 | * wait for all outstanding DMA to complete | ||
851 | * | ||
852 | * Device interrupts are disabled, therefore another buffer cannot | ||
853 | * be marked inflight. | ||
854 | */ | ||
855 | ret = wait_event_interruptible(priv->wait, priv->inflight == NULL); | ||
856 | if (ret) | ||
857 | return ret; | ||
858 | |||
859 | /* free the correlation table */ | ||
860 | sg_free_table(&priv->corl_table); | ||
861 | priv->corl_nents = 0; | ||
862 | |||
863 | /* | ||
864 | * We are taking the spinlock not to protect priv->enabled, but instead | ||
865 | * to make sure that there are no readers in the process of altering | ||
866 | * the free or used lists while we are setting this flag. | ||
867 | */ | ||
868 | spin_lock_irq(&priv->lock); | ||
869 | priv->enabled = false; | ||
870 | spin_unlock_irq(&priv->lock); | ||
871 | |||
872 | /* free all buffers: the free and used lists are not being changed */ | ||
873 | data_free_buffers(priv); | ||
874 | return 0; | ||
875 | } | ||
876 | |||
877 | /* | ||
878 | * DEBUGFS Interface | ||
879 | */ | ||
880 | #ifdef CONFIG_DEBUG_FS | ||
881 | |||
882 | /* | ||
883 | * Count the number of entries in the given list | ||
884 | */ | ||
885 | static unsigned int list_num_entries(struct list_head *list) | ||
886 | { | ||
887 | struct list_head *entry; | ||
888 | unsigned int ret = 0; | ||
889 | |||
890 | list_for_each(entry, list) | ||
891 | ret++; | ||
892 | |||
893 | return ret; | ||
894 | } | ||
895 | |||
896 | static int data_debug_show(struct seq_file *f, void *offset) | ||
897 | { | ||
898 | struct fpga_device *priv = f->private; | ||
899 | int ret; | ||
900 | |||
901 | /* | ||
902 | * Lock the mutex first, so that we get an accurate value for enable | ||
903 | * Lock the spinlock next, to get accurate list counts | ||
904 | */ | ||
905 | ret = mutex_lock_interruptible(&priv->mutex); | ||
906 | if (ret) | ||
907 | return ret; | ||
908 | |||
909 | spin_lock_irq(&priv->lock); | ||
910 | |||
911 | seq_printf(f, "enabled: %d\n", priv->enabled); | ||
912 | seq_printf(f, "bufsize: %d\n", priv->bufsize); | ||
913 | seq_printf(f, "num_buffers: %d\n", priv->num_buffers); | ||
914 | seq_printf(f, "num_free: %d\n", list_num_entries(&priv->free)); | ||
915 | seq_printf(f, "inflight: %d\n", priv->inflight != NULL); | ||
916 | seq_printf(f, "num_used: %d\n", list_num_entries(&priv->used)); | ||
917 | seq_printf(f, "num_dropped: %d\n", priv->num_dropped); | ||
918 | |||
919 | spin_unlock_irq(&priv->lock); | ||
920 | mutex_unlock(&priv->mutex); | ||
921 | return 0; | ||
922 | } | ||
923 | |||
924 | static int data_debug_open(struct inode *inode, struct file *file) | ||
925 | { | ||
926 | return single_open(file, data_debug_show, inode->i_private); | ||
927 | } | ||
928 | |||
929 | static const struct file_operations data_debug_fops = { | ||
930 | .owner = THIS_MODULE, | ||
931 | .open = data_debug_open, | ||
932 | .read = seq_read, | ||
933 | .llseek = seq_lseek, | ||
934 | .release = single_release, | ||
935 | }; | ||
936 | |||
937 | static int data_debugfs_init(struct fpga_device *priv) | ||
938 | { | ||
939 | priv->dbg_entry = debugfs_create_file(drv_name, S_IRUGO, NULL, priv, | ||
940 | &data_debug_fops); | ||
941 | if (IS_ERR(priv->dbg_entry)) | ||
942 | return PTR_ERR(priv->dbg_entry); | ||
943 | |||
944 | return 0; | ||
945 | } | ||
946 | |||
947 | static void data_debugfs_exit(struct fpga_device *priv) | ||
948 | { | ||
949 | debugfs_remove(priv->dbg_entry); | ||
950 | } | ||
951 | |||
952 | #else | ||
953 | |||
954 | static inline int data_debugfs_init(struct fpga_device *priv) | ||
955 | { | ||
956 | return 0; | ||
957 | } | ||
958 | |||
959 | static inline void data_debugfs_exit(struct fpga_device *priv) | ||
960 | { | ||
961 | } | ||
962 | |||
963 | #endif /* CONFIG_DEBUG_FS */ | ||
964 | |||
965 | /* | ||
966 | * SYSFS Attributes | ||
967 | */ | ||
968 | |||
969 | static ssize_t data_en_show(struct device *dev, struct device_attribute *attr, | ||
970 | char *buf) | ||
971 | { | ||
972 | struct fpga_device *priv = dev_get_drvdata(dev); | ||
973 | return snprintf(buf, PAGE_SIZE, "%u\n", priv->enabled); | ||
974 | } | ||
975 | |||
976 | static ssize_t data_en_set(struct device *dev, struct device_attribute *attr, | ||
977 | const char *buf, size_t count) | ||
978 | { | ||
979 | struct fpga_device *priv = dev_get_drvdata(dev); | ||
980 | unsigned long enable; | ||
981 | int ret; | ||
982 | |||
983 | ret = strict_strtoul(buf, 0, &enable); | ||
984 | if (ret) { | ||
985 | dev_err(priv->dev, "unable to parse enable input\n"); | ||
986 | return -EINVAL; | ||
987 | } | ||
988 | |||
989 | ret = mutex_lock_interruptible(&priv->mutex); | ||
990 | if (ret) | ||
991 | return ret; | ||
992 | |||
993 | if (enable) | ||
994 | ret = data_device_enable(priv); | ||
995 | else | ||
996 | ret = data_device_disable(priv); | ||
997 | |||
998 | if (ret) { | ||
999 | dev_err(priv->dev, "device %s failed\n", | ||
1000 | enable ? "enable" : "disable"); | ||
1001 | count = ret; | ||
1002 | goto out_unlock; | ||
1003 | } | ||
1004 | |||
1005 | out_unlock: | ||
1006 | mutex_unlock(&priv->mutex); | ||
1007 | return count; | ||
1008 | } | ||
1009 | |||
1010 | static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, data_en_show, data_en_set); | ||
1011 | |||
1012 | static struct attribute *data_sysfs_attrs[] = { | ||
1013 | &dev_attr_enable.attr, | ||
1014 | NULL, | ||
1015 | }; | ||
1016 | |||
1017 | static const struct attribute_group rt_sysfs_attr_group = { | ||
1018 | .attrs = data_sysfs_attrs, | ||
1019 | }; | ||
1020 | |||
1021 | /* | ||
1022 | * FPGA Realtime Data Character Device | ||
1023 | */ | ||
1024 | |||
1025 | static int data_open(struct inode *inode, struct file *filp) | ||
1026 | { | ||
1027 | /* | ||
1028 | * The miscdevice layer puts our struct miscdevice into the | ||
1029 | * filp->private_data field. We use this to find our private | ||
1030 | * data and then overwrite it with our own private structure. | ||
1031 | */ | ||
1032 | struct fpga_device *priv = container_of(filp->private_data, | ||
1033 | struct fpga_device, miscdev); | ||
1034 | struct fpga_reader *reader; | ||
1035 | int ret; | ||
1036 | |||
1037 | /* allocate private data */ | ||
1038 | reader = kzalloc(sizeof(*reader), GFP_KERNEL); | ||
1039 | if (!reader) | ||
1040 | return -ENOMEM; | ||
1041 | |||
1042 | reader->priv = priv; | ||
1043 | reader->buf = NULL; | ||
1044 | |||
1045 | filp->private_data = reader; | ||
1046 | ret = nonseekable_open(inode, filp); | ||
1047 | if (ret) { | ||
1048 | dev_err(priv->dev, "nonseekable-open failed\n"); | ||
1049 | kfree(reader); | ||
1050 | return ret; | ||
1051 | } | ||
1052 | |||
1053 | /* | ||
1054 | * success, increase the reference count of the private data structure | ||
1055 | * so that it doesn't disappear if the device is unbound | ||
1056 | */ | ||
1057 | kref_get(&priv->ref); | ||
1058 | return 0; | ||
1059 | } | ||
1060 | |||
1061 | static int data_release(struct inode *inode, struct file *filp) | ||
1062 | { | ||
1063 | struct fpga_reader *reader = filp->private_data; | ||
1064 | struct fpga_device *priv = reader->priv; | ||
1065 | |||
1066 | /* free the per-reader structure */ | ||
1067 | data_free_buffer(reader->buf); | ||
1068 | kfree(reader); | ||
1069 | filp->private_data = NULL; | ||
1070 | |||
1071 | /* decrement our reference count to the private data */ | ||
1072 | kref_put(&priv->ref, fpga_device_release); | ||
1073 | return 0; | ||
1074 | } | ||
1075 | |||
1076 | static ssize_t data_read(struct file *filp, char __user *ubuf, size_t count, | ||
1077 | loff_t *f_pos) | ||
1078 | { | ||
1079 | struct fpga_reader *reader = filp->private_data; | ||
1080 | struct fpga_device *priv = reader->priv; | ||
1081 | struct list_head *used = &priv->used; | ||
1082 | struct data_buf *dbuf; | ||
1083 | size_t avail; | ||
1084 | void *data; | ||
1085 | int ret; | ||
1086 | |||
1087 | /* check if we already have a partial buffer */ | ||
1088 | if (reader->buf) { | ||
1089 | dbuf = reader->buf; | ||
1090 | goto have_buffer; | ||
1091 | } | ||
1092 | |||
1093 | spin_lock_irq(&priv->lock); | ||
1094 | |||
1095 | /* Block until there is at least one buffer on the used list */ | ||
1096 | while (list_empty(used)) { | ||
1097 | spin_unlock_irq(&priv->lock); | ||
1098 | |||
1099 | if (filp->f_flags & O_NONBLOCK) | ||
1100 | return -EAGAIN; | ||
1101 | |||
1102 | ret = wait_event_interruptible(priv->wait, !list_empty(used)); | ||
1103 | if (ret) | ||
1104 | return ret; | ||
1105 | |||
1106 | spin_lock_irq(&priv->lock); | ||
1107 | } | ||
1108 | |||
1109 | /* Grab the first buffer off of the used list */ | ||
1110 | dbuf = list_first_entry(used, struct data_buf, entry); | ||
1111 | list_del_init(&dbuf->entry); | ||
1112 | |||
1113 | spin_unlock_irq(&priv->lock); | ||
1114 | |||
1115 | /* Buffers are always mapped: unmap it */ | ||
1116 | videobuf_dma_unmap(priv->dev, &dbuf->vb); | ||
1117 | |||
1118 | /* save the buffer for later */ | ||
1119 | reader->buf = dbuf; | ||
1120 | reader->buf_start = 0; | ||
1121 | |||
1122 | have_buffer: | ||
1123 | /* Get the number of bytes available */ | ||
1124 | avail = dbuf->size - reader->buf_start; | ||
1125 | data = dbuf->vb.vaddr + reader->buf_start; | ||
1126 | |||
1127 | /* Get the number of bytes we can transfer */ | ||
1128 | count = min(count, avail); | ||
1129 | |||
1130 | /* Copy the data to the userspace buffer */ | ||
1131 | if (copy_to_user(ubuf, data, count)) | ||
1132 | return -EFAULT; | ||
1133 | |||
1134 | /* Update the amount of available space */ | ||
1135 | avail -= count; | ||
1136 | |||
1137 | /* | ||
1138 | * If there is still some data available, save the buffer for the | ||
1139 | * next userspace call to read() and return | ||
1140 | */ | ||
1141 | if (avail > 0) { | ||
1142 | reader->buf_start += count; | ||
1143 | reader->buf = dbuf; | ||
1144 | return count; | ||
1145 | } | ||
1146 | |||
1147 | /* | ||
1148 | * Get the buffer ready to be reused for DMA | ||
1149 | * | ||
1150 | * If it fails, we pretend that the read never happed and return | ||
1151 | * -EFAULT to userspace. The read will be retried. | ||
1152 | */ | ||
1153 | ret = videobuf_dma_map(priv->dev, &dbuf->vb); | ||
1154 | if (ret) { | ||
1155 | dev_err(priv->dev, "unable to remap buffer for DMA\n"); | ||
1156 | return -EFAULT; | ||
1157 | } | ||
1158 | |||
1159 | /* Lock against concurrent enable/disable */ | ||
1160 | spin_lock_irq(&priv->lock); | ||
1161 | |||
1162 | /* the reader is finished with this buffer */ | ||
1163 | reader->buf = NULL; | ||
1164 | |||
1165 | /* | ||
1166 | * One of two things has happened, the device is disabled, or the | ||
1167 | * device has been reconfigured underneath us. In either case, we | ||
1168 | * should just throw away the buffer. | ||
1169 | */ | ||
1170 | if (!priv->enabled || dbuf->size != priv->bufsize) { | ||
1171 | videobuf_dma_unmap(priv->dev, &dbuf->vb); | ||
1172 | data_free_buffer(dbuf); | ||
1173 | goto out_unlock; | ||
1174 | } | ||
1175 | |||
1176 | /* The buffer is safe to reuse, so add it back to the free list */ | ||
1177 | list_add_tail(&dbuf->entry, &priv->free); | ||
1178 | |||
1179 | out_unlock: | ||
1180 | spin_unlock_irq(&priv->lock); | ||
1181 | return count; | ||
1182 | } | ||
1183 | |||
1184 | static unsigned int data_poll(struct file *filp, struct poll_table_struct *tbl) | ||
1185 | { | ||
1186 | struct fpga_reader *reader = filp->private_data; | ||
1187 | struct fpga_device *priv = reader->priv; | ||
1188 | unsigned int mask = 0; | ||
1189 | |||
1190 | poll_wait(filp, &priv->wait, tbl); | ||
1191 | |||
1192 | if (!list_empty(&priv->used)) | ||
1193 | mask |= POLLIN | POLLRDNORM; | ||
1194 | |||
1195 | return mask; | ||
1196 | } | ||
1197 | |||
1198 | static int data_mmap(struct file *filp, struct vm_area_struct *vma) | ||
1199 | { | ||
1200 | struct fpga_reader *reader = filp->private_data; | ||
1201 | struct fpga_device *priv = reader->priv; | ||
1202 | unsigned long offset, vsize, psize, addr; | ||
1203 | |||
1204 | /* VMA properties */ | ||
1205 | offset = vma->vm_pgoff << PAGE_SHIFT; | ||
1206 | vsize = vma->vm_end - vma->vm_start; | ||
1207 | psize = priv->phys_size - offset; | ||
1208 | addr = (priv->phys_addr + offset) >> PAGE_SHIFT; | ||
1209 | |||
1210 | /* Check against the FPGA region's physical memory size */ | ||
1211 | if (vsize > psize) { | ||
1212 | dev_err(priv->dev, "requested mmap mapping too large\n"); | ||
1213 | return -EINVAL; | ||
1214 | } | ||
1215 | |||
1216 | /* IO memory (stop cacheing) */ | ||
1217 | vma->vm_flags |= VM_IO | VM_RESERVED; | ||
1218 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
1219 | |||
1220 | return io_remap_pfn_range(vma, vma->vm_start, addr, vsize, | ||
1221 | vma->vm_page_prot); | ||
1222 | } | ||
1223 | |||
1224 | static const struct file_operations data_fops = { | ||
1225 | .owner = THIS_MODULE, | ||
1226 | .open = data_open, | ||
1227 | .release = data_release, | ||
1228 | .read = data_read, | ||
1229 | .poll = data_poll, | ||
1230 | .mmap = data_mmap, | ||
1231 | .llseek = no_llseek, | ||
1232 | }; | ||
1233 | |||
1234 | /* | ||
1235 | * OpenFirmware Device Subsystem | ||
1236 | */ | ||
1237 | |||
1238 | static bool dma_filter(struct dma_chan *chan, void *data) | ||
1239 | { | ||
1240 | /* | ||
1241 | * DMA Channel #0 is used for the FPGA Programmer, so ignore it | ||
1242 | * | ||
1243 | * This probably won't survive an unload/load cycle of the Freescale | ||
1244 | * DMAEngine driver, but that won't be a problem | ||
1245 | */ | ||
1246 | if (chan->chan_id == 0 && chan->device->dev_id == 0) | ||
1247 | return false; | ||
1248 | |||
1249 | return true; | ||
1250 | } | ||
1251 | |||
1252 | static int data_of_probe(struct platform_device *op, | ||
1253 | const struct of_device_id *match) | ||
1254 | { | ||
1255 | struct device_node *of_node = op->dev.of_node; | ||
1256 | struct device *this_device; | ||
1257 | struct fpga_device *priv; | ||
1258 | struct resource res; | ||
1259 | dma_cap_mask_t mask; | ||
1260 | int ret; | ||
1261 | |||
1262 | /* Allocate private data */ | ||
1263 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
1264 | if (!priv) { | ||
1265 | dev_err(&op->dev, "Unable to allocate device private data\n"); | ||
1266 | ret = -ENOMEM; | ||
1267 | goto out_return; | ||
1268 | } | ||
1269 | |||
1270 | dev_set_drvdata(&op->dev, priv); | ||
1271 | priv->dev = &op->dev; | ||
1272 | kref_init(&priv->ref); | ||
1273 | mutex_init(&priv->mutex); | ||
1274 | |||
1275 | dev_set_drvdata(priv->dev, priv); | ||
1276 | spin_lock_init(&priv->lock); | ||
1277 | INIT_LIST_HEAD(&priv->free); | ||
1278 | INIT_LIST_HEAD(&priv->used); | ||
1279 | init_waitqueue_head(&priv->wait); | ||
1280 | |||
1281 | /* Setup the misc device */ | ||
1282 | priv->miscdev.minor = MISC_DYNAMIC_MINOR; | ||
1283 | priv->miscdev.name = drv_name; | ||
1284 | priv->miscdev.fops = &data_fops; | ||
1285 | |||
1286 | /* Get the physical address of the FPGA registers */ | ||
1287 | ret = of_address_to_resource(of_node, 0, &res); | ||
1288 | if (ret) { | ||
1289 | dev_err(&op->dev, "Unable to find FPGA physical address\n"); | ||
1290 | ret = -ENODEV; | ||
1291 | goto out_free_priv; | ||
1292 | } | ||
1293 | |||
1294 | priv->phys_addr = res.start; | ||
1295 | priv->phys_size = resource_size(&res); | ||
1296 | |||
1297 | /* ioremap the registers for use */ | ||
1298 | priv->regs = of_iomap(of_node, 0); | ||
1299 | if (!priv->regs) { | ||
1300 | dev_err(&op->dev, "Unable to ioremap registers\n"); | ||
1301 | ret = -ENOMEM; | ||
1302 | goto out_free_priv; | ||
1303 | } | ||
1304 | |||
1305 | dma_cap_zero(mask); | ||
1306 | dma_cap_set(DMA_MEMCPY, mask); | ||
1307 | dma_cap_set(DMA_INTERRUPT, mask); | ||
1308 | dma_cap_set(DMA_SLAVE, mask); | ||
1309 | dma_cap_set(DMA_SG, mask); | ||
1310 | |||
1311 | /* Request a DMA channel */ | ||
1312 | priv->chan = dma_request_channel(mask, dma_filter, NULL); | ||
1313 | if (!priv->chan) { | ||
1314 | dev_err(&op->dev, "Unable to request DMA channel\n"); | ||
1315 | ret = -ENODEV; | ||
1316 | goto out_unmap_regs; | ||
1317 | } | ||
1318 | |||
1319 | /* Find the correct IRQ number */ | ||
1320 | priv->irq = irq_of_parse_and_map(of_node, 0); | ||
1321 | if (priv->irq == NO_IRQ) { | ||
1322 | dev_err(&op->dev, "Unable to find IRQ line\n"); | ||
1323 | ret = -ENODEV; | ||
1324 | goto out_release_dma; | ||
1325 | } | ||
1326 | |||
1327 | /* Drive the GPIO for FPGA IRQ high (no interrupt) */ | ||
1328 | iowrite32be(IRQ_CORL_DONE, priv->regs + SYS_IRQ_OUTPUT_DATA); | ||
1329 | |||
1330 | /* Register the miscdevice */ | ||
1331 | ret = misc_register(&priv->miscdev); | ||
1332 | if (ret) { | ||
1333 | dev_err(&op->dev, "Unable to register miscdevice\n"); | ||
1334 | goto out_irq_dispose_mapping; | ||
1335 | } | ||
1336 | |||
1337 | /* Create the debugfs files */ | ||
1338 | ret = data_debugfs_init(priv); | ||
1339 | if (ret) { | ||
1340 | dev_err(&op->dev, "Unable to create debugfs files\n"); | ||
1341 | goto out_misc_deregister; | ||
1342 | } | ||
1343 | |||
1344 | /* Create the sysfs files */ | ||
1345 | this_device = priv->miscdev.this_device; | ||
1346 | dev_set_drvdata(this_device, priv); | ||
1347 | ret = sysfs_create_group(&this_device->kobj, &rt_sysfs_attr_group); | ||
1348 | if (ret) { | ||
1349 | dev_err(&op->dev, "Unable to create sysfs files\n"); | ||
1350 | goto out_data_debugfs_exit; | ||
1351 | } | ||
1352 | |||
1353 | dev_info(&op->dev, "CARMA FPGA Realtime Data Driver Loaded\n"); | ||
1354 | return 0; | ||
1355 | |||
1356 | out_data_debugfs_exit: | ||
1357 | data_debugfs_exit(priv); | ||
1358 | out_misc_deregister: | ||
1359 | misc_deregister(&priv->miscdev); | ||
1360 | out_irq_dispose_mapping: | ||
1361 | irq_dispose_mapping(priv->irq); | ||
1362 | out_release_dma: | ||
1363 | dma_release_channel(priv->chan); | ||
1364 | out_unmap_regs: | ||
1365 | iounmap(priv->regs); | ||
1366 | out_free_priv: | ||
1367 | kref_put(&priv->ref, fpga_device_release); | ||
1368 | out_return: | ||
1369 | return ret; | ||
1370 | } | ||
1371 | |||
1372 | static int data_of_remove(struct platform_device *op) | ||
1373 | { | ||
1374 | struct fpga_device *priv = dev_get_drvdata(&op->dev); | ||
1375 | struct device *this_device = priv->miscdev.this_device; | ||
1376 | |||
1377 | /* remove all sysfs files, now the device cannot be re-enabled */ | ||
1378 | sysfs_remove_group(&this_device->kobj, &rt_sysfs_attr_group); | ||
1379 | |||
1380 | /* remove all debugfs files */ | ||
1381 | data_debugfs_exit(priv); | ||
1382 | |||
1383 | /* disable the device from generating data */ | ||
1384 | data_device_disable(priv); | ||
1385 | |||
1386 | /* remove the character device to stop new readers from appearing */ | ||
1387 | misc_deregister(&priv->miscdev); | ||
1388 | |||
1389 | /* cleanup everything not needed by readers */ | ||
1390 | irq_dispose_mapping(priv->irq); | ||
1391 | dma_release_channel(priv->chan); | ||
1392 | iounmap(priv->regs); | ||
1393 | |||
1394 | /* release our reference */ | ||
1395 | kref_put(&priv->ref, fpga_device_release); | ||
1396 | return 0; | ||
1397 | } | ||
1398 | |||
1399 | static struct of_device_id data_of_match[] = { | ||
1400 | { .compatible = "carma,carma-fpga", }, | ||
1401 | {}, | ||
1402 | }; | ||
1403 | |||
1404 | static struct of_platform_driver data_of_driver = { | ||
1405 | .probe = data_of_probe, | ||
1406 | .remove = data_of_remove, | ||
1407 | .driver = { | ||
1408 | .name = drv_name, | ||
1409 | .of_match_table = data_of_match, | ||
1410 | .owner = THIS_MODULE, | ||
1411 | }, | ||
1412 | }; | ||
1413 | |||
1414 | /* | ||
1415 | * Module Init / Exit | ||
1416 | */ | ||
1417 | |||
1418 | static int __init data_init(void) | ||
1419 | { | ||
1420 | return of_register_platform_driver(&data_of_driver); | ||
1421 | } | ||
1422 | |||
1423 | static void __exit data_exit(void) | ||
1424 | { | ||
1425 | of_unregister_platform_driver(&data_of_driver); | ||
1426 | } | ||
1427 | |||
1428 | MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>"); | ||
1429 | MODULE_DESCRIPTION("CARMA DATA-FPGA Access Driver"); | ||
1430 | MODULE_LICENSE("GPL"); | ||
1431 | |||
1432 | module_init(data_init); | ||
1433 | module_exit(data_exit); | ||
diff --git a/drivers/misc/cb710/Makefile b/drivers/misc/cb710/Makefile index 7b80cbf1a609..467c8e9ca3c9 100644 --- a/drivers/misc/cb710/Makefile +++ b/drivers/misc/cb710/Makefile | |||
@@ -1,6 +1,4 @@ | |||
1 | ifeq ($(CONFIG_CB710_DEBUG),y) | 1 | ccflags-$(CONFIG_CB710_DEBUG) := -DDEBUG |
2 | EXTRA_CFLAGS += -DDEBUG | ||
3 | endif | ||
4 | 2 | ||
5 | obj-$(CONFIG_CB710_CORE) += cb710.o | 3 | obj-$(CONFIG_CB710_CORE) += cb710.o |
6 | 4 | ||
diff --git a/drivers/misc/cb710/sgbuf2.c b/drivers/misc/cb710/sgbuf2.c index d019746551f3..2a40d0efdff5 100644 --- a/drivers/misc/cb710/sgbuf2.c +++ b/drivers/misc/cb710/sgbuf2.c | |||
@@ -47,7 +47,7 @@ static uint32_t sg_dwiter_read_buffer(struct sg_mapping_iter *miter) | |||
47 | 47 | ||
48 | static inline bool needs_unaligned_copy(const void *ptr) | 48 | static inline bool needs_unaligned_copy(const void *ptr) |
49 | { | 49 | { |
50 | #ifdef HAVE_EFFICIENT_UNALIGNED_ACCESS | 50 | #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS |
51 | return false; | 51 | return false; |
52 | #else | 52 | #else |
53 | return ((ptr - NULL) & 3) != 0; | 53 | return ((ptr - NULL) & 3) != 0; |
diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c index 6f6218061b0d..bc685bfc4c33 100644 --- a/drivers/misc/cs5535-mfgpt.c +++ b/drivers/misc/cs5535-mfgpt.c | |||
@@ -16,12 +16,11 @@ | |||
16 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/pci.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/cs5535.h> | 20 | #include <linux/cs5535.h> |
21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
22 | 22 | ||
23 | #define DRV_NAME "cs5535-mfgpt" | 23 | #define DRV_NAME "cs5535-mfgpt" |
24 | #define MFGPT_BAR 2 | ||
25 | 24 | ||
26 | static int mfgpt_reset_timers; | 25 | static int mfgpt_reset_timers; |
27 | module_param_named(mfgptfix, mfgpt_reset_timers, int, 0644); | 26 | module_param_named(mfgptfix, mfgpt_reset_timers, int, 0644); |
@@ -37,7 +36,7 @@ static struct cs5535_mfgpt_chip { | |||
37 | DECLARE_BITMAP(avail, MFGPT_MAX_TIMERS); | 36 | DECLARE_BITMAP(avail, MFGPT_MAX_TIMERS); |
38 | resource_size_t base; | 37 | resource_size_t base; |
39 | 38 | ||
40 | struct pci_dev *pdev; | 39 | struct platform_device *pdev; |
41 | spinlock_t lock; | 40 | spinlock_t lock; |
42 | int initialized; | 41 | int initialized; |
43 | } cs5535_mfgpt_chip; | 42 | } cs5535_mfgpt_chip; |
@@ -175,7 +174,7 @@ struct cs5535_mfgpt_timer *cs5535_mfgpt_alloc_timer(int timer_nr, int domain) | |||
175 | timer_nr = t < max ? (int) t : -1; | 174 | timer_nr = t < max ? (int) t : -1; |
176 | } else { | 175 | } else { |
177 | /* check if the requested timer's available */ | 176 | /* check if the requested timer's available */ |
178 | if (test_bit(timer_nr, mfgpt->avail)) | 177 | if (!test_bit(timer_nr, mfgpt->avail)) |
179 | timer_nr = -1; | 178 | timer_nr = -1; |
180 | } | 179 | } |
181 | 180 | ||
@@ -290,10 +289,10 @@ static int __init scan_timers(struct cs5535_mfgpt_chip *mfgpt) | |||
290 | return timers; | 289 | return timers; |
291 | } | 290 | } |
292 | 291 | ||
293 | static int __init cs5535_mfgpt_probe(struct pci_dev *pdev, | 292 | static int __devinit cs5535_mfgpt_probe(struct platform_device *pdev) |
294 | const struct pci_device_id *pci_id) | ||
295 | { | 293 | { |
296 | int err, t; | 294 | struct resource *res; |
295 | int err = -EIO, t; | ||
297 | 296 | ||
298 | /* There are two ways to get the MFGPT base address; one is by | 297 | /* There are two ways to get the MFGPT base address; one is by |
299 | * fetching it from MSR_LBAR_MFGPT, the other is by reading the | 298 | * fetching it from MSR_LBAR_MFGPT, the other is by reading the |
@@ -302,29 +301,27 @@ static int __init cs5535_mfgpt_probe(struct pci_dev *pdev, | |||
302 | * it turns out to be unreliable in the face of crappy BIOSes, we | 301 | * it turns out to be unreliable in the face of crappy BIOSes, we |
303 | * can always go back to using MSRs.. */ | 302 | * can always go back to using MSRs.. */ |
304 | 303 | ||
305 | err = pci_enable_device_io(pdev); | 304 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); |
306 | if (err) { | 305 | if (!res) { |
307 | dev_err(&pdev->dev, "can't enable device IO\n"); | 306 | dev_err(&pdev->dev, "can't fetch device resource info\n"); |
308 | goto done; | 307 | goto done; |
309 | } | 308 | } |
310 | 309 | ||
311 | err = pci_request_region(pdev, MFGPT_BAR, DRV_NAME); | 310 | if (!request_region(res->start, resource_size(res), pdev->name)) { |
312 | if (err) { | 311 | dev_err(&pdev->dev, "can't request region\n"); |
313 | dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", MFGPT_BAR); | ||
314 | goto done; | 312 | goto done; |
315 | } | 313 | } |
316 | 314 | ||
317 | /* set up the driver-specific struct */ | 315 | /* set up the driver-specific struct */ |
318 | cs5535_mfgpt_chip.base = pci_resource_start(pdev, MFGPT_BAR); | 316 | cs5535_mfgpt_chip.base = res->start; |
319 | cs5535_mfgpt_chip.pdev = pdev; | 317 | cs5535_mfgpt_chip.pdev = pdev; |
320 | spin_lock_init(&cs5535_mfgpt_chip.lock); | 318 | spin_lock_init(&cs5535_mfgpt_chip.lock); |
321 | 319 | ||
322 | dev_info(&pdev->dev, "allocated PCI BAR #%d: base 0x%llx\n", MFGPT_BAR, | 320 | dev_info(&pdev->dev, "reserved resource region %pR\n", res); |
323 | (unsigned long long) cs5535_mfgpt_chip.base); | ||
324 | 321 | ||
325 | /* detect the available timers */ | 322 | /* detect the available timers */ |
326 | t = scan_timers(&cs5535_mfgpt_chip); | 323 | t = scan_timers(&cs5535_mfgpt_chip); |
327 | dev_info(&pdev->dev, DRV_NAME ": %d MFGPT timers available\n", t); | 324 | dev_info(&pdev->dev, "%d MFGPT timers available\n", t); |
328 | cs5535_mfgpt_chip.initialized = 1; | 325 | cs5535_mfgpt_chip.initialized = 1; |
329 | return 0; | 326 | return 0; |
330 | 327 | ||
@@ -332,47 +329,18 @@ done: | |||
332 | return err; | 329 | return err; |
333 | } | 330 | } |
334 | 331 | ||
335 | static struct pci_device_id cs5535_mfgpt_pci_tbl[] = { | 332 | static struct platform_driver cs5535_mfgpt_driver = { |
336 | { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) }, | 333 | .driver = { |
337 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, | 334 | .name = DRV_NAME, |
338 | { 0, }, | 335 | .owner = THIS_MODULE, |
336 | }, | ||
337 | .probe = cs5535_mfgpt_probe, | ||
339 | }; | 338 | }; |
340 | MODULE_DEVICE_TABLE(pci, cs5535_mfgpt_pci_tbl); | ||
341 | 339 | ||
342 | /* | ||
343 | * Just like with the cs5535-gpio driver, we can't use the standard PCI driver | ||
344 | * registration stuff. It only allows only one driver to bind to each PCI | ||
345 | * device, and we want the GPIO and MFGPT drivers to be able to share a PCI | ||
346 | * device. Instead, we manually scan for the PCI device, request a single | ||
347 | * region, and keep track of the devices that we're using. | ||
348 | */ | ||
349 | |||
350 | static int __init cs5535_mfgpt_scan_pci(void) | ||
351 | { | ||
352 | struct pci_dev *pdev; | ||
353 | int err = -ENODEV; | ||
354 | int i; | ||
355 | |||
356 | for (i = 0; i < ARRAY_SIZE(cs5535_mfgpt_pci_tbl); i++) { | ||
357 | pdev = pci_get_device(cs5535_mfgpt_pci_tbl[i].vendor, | ||
358 | cs5535_mfgpt_pci_tbl[i].device, NULL); | ||
359 | if (pdev) { | ||
360 | err = cs5535_mfgpt_probe(pdev, | ||
361 | &cs5535_mfgpt_pci_tbl[i]); | ||
362 | if (err) | ||
363 | pci_dev_put(pdev); | ||
364 | |||
365 | /* we only support a single CS5535/6 southbridge */ | ||
366 | break; | ||
367 | } | ||
368 | } | ||
369 | |||
370 | return err; | ||
371 | } | ||
372 | 340 | ||
373 | static int __init cs5535_mfgpt_init(void) | 341 | static int __init cs5535_mfgpt_init(void) |
374 | { | 342 | { |
375 | return cs5535_mfgpt_scan_pci(); | 343 | return platform_driver_register(&cs5535_mfgpt_driver); |
376 | } | 344 | } |
377 | 345 | ||
378 | module_init(cs5535_mfgpt_init); | 346 | module_init(cs5535_mfgpt_init); |
@@ -380,3 +348,4 @@ module_init(cs5535_mfgpt_init); | |||
380 | MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>"); | 348 | MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>"); |
381 | MODULE_DESCRIPTION("CS5535/CS5536 MFGPT timer driver"); | 349 | MODULE_DESCRIPTION("CS5535/CS5536 MFGPT timer driver"); |
382 | MODULE_LICENSE("GPL"); | 350 | MODULE_LICENSE("GPL"); |
351 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 559b0b3c16c3..ab1ad41786d1 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/log2.h> | 20 | #include <linux/log2.h> |
21 | #include <linux/bitops.h> | 21 | #include <linux/bitops.h> |
22 | #include <linux/jiffies.h> | 22 | #include <linux/jiffies.h> |
23 | #include <linux/of.h> | ||
23 | #include <linux/i2c.h> | 24 | #include <linux/i2c.h> |
24 | #include <linux/i2c/at24.h> | 25 | #include <linux/i2c/at24.h> |
25 | 26 | ||
@@ -457,6 +458,27 @@ static ssize_t at24_macc_write(struct memory_accessor *macc, const char *buf, | |||
457 | 458 | ||
458 | /*-------------------------------------------------------------------------*/ | 459 | /*-------------------------------------------------------------------------*/ |
459 | 460 | ||
461 | #ifdef CONFIG_OF | ||
462 | static void at24_get_ofdata(struct i2c_client *client, | ||
463 | struct at24_platform_data *chip) | ||
464 | { | ||
465 | const __be32 *val; | ||
466 | struct device_node *node = client->dev.of_node; | ||
467 | |||
468 | if (node) { | ||
469 | if (of_get_property(node, "read-only", NULL)) | ||
470 | chip->flags |= AT24_FLAG_READONLY; | ||
471 | val = of_get_property(node, "pagesize", NULL); | ||
472 | if (val) | ||
473 | chip->page_size = be32_to_cpup(val); | ||
474 | } | ||
475 | } | ||
476 | #else | ||
477 | static void at24_get_ofdata(struct i2c_client *client, | ||
478 | struct at24_platform_data *chip) | ||
479 | { } | ||
480 | #endif /* CONFIG_OF */ | ||
481 | |||
460 | static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | 482 | static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) |
461 | { | 483 | { |
462 | struct at24_platform_data chip; | 484 | struct at24_platform_data chip; |
@@ -485,6 +507,9 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
485 | */ | 507 | */ |
486 | chip.page_size = 1; | 508 | chip.page_size = 1; |
487 | 509 | ||
510 | /* update chipdata if OF is present */ | ||
511 | at24_get_ofdata(client, &chip); | ||
512 | |||
488 | chip.setup = NULL; | 513 | chip.setup = NULL; |
489 | chip.context = NULL; | 514 | chip.context = NULL; |
490 | } | 515 | } |
@@ -492,6 +517,11 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
492 | if (!is_power_of_2(chip.byte_len)) | 517 | if (!is_power_of_2(chip.byte_len)) |
493 | dev_warn(&client->dev, | 518 | dev_warn(&client->dev, |
494 | "byte_len looks suspicious (no power of 2)!\n"); | 519 | "byte_len looks suspicious (no power of 2)!\n"); |
520 | if (!chip.page_size) { | ||
521 | dev_err(&client->dev, "page_size must not be 0!\n"); | ||
522 | err = -EINVAL; | ||
523 | goto err_out; | ||
524 | } | ||
495 | if (!is_power_of_2(chip.page_size)) | 525 | if (!is_power_of_2(chip.page_size)) |
496 | dev_warn(&client->dev, | 526 | dev_warn(&client->dev, |
497 | "page_size looks suspicious (no power of 2)!\n"); | 527 | "page_size looks suspicious (no power of 2)!\n"); |
@@ -597,19 +627,15 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
597 | 627 | ||
598 | i2c_set_clientdata(client, at24); | 628 | i2c_set_clientdata(client, at24); |
599 | 629 | ||
600 | dev_info(&client->dev, "%zu byte %s EEPROM %s\n", | 630 | dev_info(&client->dev, "%zu byte %s EEPROM, %s, %u bytes/write\n", |
601 | at24->bin.size, client->name, | 631 | at24->bin.size, client->name, |
602 | writable ? "(writable)" : "(read-only)"); | 632 | writable ? "writable" : "read-only", at24->write_max); |
603 | if (use_smbus == I2C_SMBUS_WORD_DATA || | 633 | if (use_smbus == I2C_SMBUS_WORD_DATA || |
604 | use_smbus == I2C_SMBUS_BYTE_DATA) { | 634 | use_smbus == I2C_SMBUS_BYTE_DATA) { |
605 | dev_notice(&client->dev, "Falling back to %s reads, " | 635 | dev_notice(&client->dev, "Falling back to %s reads, " |
606 | "performance will suffer\n", use_smbus == | 636 | "performance will suffer\n", use_smbus == |
607 | I2C_SMBUS_WORD_DATA ? "word" : "byte"); | 637 | I2C_SMBUS_WORD_DATA ? "word" : "byte"); |
608 | } | 638 | } |
609 | dev_dbg(&client->dev, | ||
610 | "page_size %d, num_addresses %d, write_max %d, use_smbus %d\n", | ||
611 | chip.page_size, num_addresses, | ||
612 | at24->write_max, use_smbus); | ||
613 | 639 | ||
614 | /* export data to kernel code */ | 640 | /* export data to kernel code */ |
615 | if (chip.setup) | 641 | if (chip.setup) |
@@ -660,6 +686,11 @@ static struct i2c_driver at24_driver = { | |||
660 | 686 | ||
661 | static int __init at24_init(void) | 687 | static int __init at24_init(void) |
662 | { | 688 | { |
689 | if (!io_limit) { | ||
690 | pr_err("at24: io_limit must not be 0!\n"); | ||
691 | return -EINVAL; | ||
692 | } | ||
693 | |||
663 | io_limit = rounddown_pow_of_two(io_limit); | 694 | io_limit = rounddown_pow_of_two(io_limit); |
664 | return i2c_add_driver(&at24_driver); | 695 | return i2c_add_driver(&at24_driver); |
665 | } | 696 | } |
diff --git a/drivers/misc/ep93xx_pwm.c b/drivers/misc/ep93xx_pwm.c index 46b3439673e9..16d7179e2f9b 100644 --- a/drivers/misc/ep93xx_pwm.c +++ b/drivers/misc/ep93xx_pwm.c | |||
@@ -249,11 +249,11 @@ static ssize_t ep93xx_pwm_set_invert(struct device *dev, | |||
249 | 249 | ||
250 | static DEVICE_ATTR(min_freq, S_IRUGO, ep93xx_pwm_get_min_freq, NULL); | 250 | static DEVICE_ATTR(min_freq, S_IRUGO, ep93xx_pwm_get_min_freq, NULL); |
251 | static DEVICE_ATTR(max_freq, S_IRUGO, ep93xx_pwm_get_max_freq, NULL); | 251 | static DEVICE_ATTR(max_freq, S_IRUGO, ep93xx_pwm_get_max_freq, NULL); |
252 | static DEVICE_ATTR(freq, S_IWUGO | S_IRUGO, | 252 | static DEVICE_ATTR(freq, S_IWUSR | S_IRUGO, |
253 | ep93xx_pwm_get_freq, ep93xx_pwm_set_freq); | 253 | ep93xx_pwm_get_freq, ep93xx_pwm_set_freq); |
254 | static DEVICE_ATTR(duty_percent, S_IWUGO | S_IRUGO, | 254 | static DEVICE_ATTR(duty_percent, S_IWUSR | S_IRUGO, |
255 | ep93xx_pwm_get_duty_percent, ep93xx_pwm_set_duty_percent); | 255 | ep93xx_pwm_get_duty_percent, ep93xx_pwm_set_duty_percent); |
256 | static DEVICE_ATTR(invert, S_IWUGO | S_IRUGO, | 256 | static DEVICE_ATTR(invert, S_IWUSR | S_IRUGO, |
257 | ep93xx_pwm_get_invert, ep93xx_pwm_set_invert); | 257 | ep93xx_pwm_get_invert, ep93xx_pwm_set_invert); |
258 | 258 | ||
259 | static struct attribute *ep93xx_pwm_attrs[] = { | 259 | static struct attribute *ep93xx_pwm_attrs[] = { |
diff --git a/drivers/misc/hmc6352.c b/drivers/misc/hmc6352.c index 234bfcaf2099..ca938fc8a8d6 100644 --- a/drivers/misc/hmc6352.c +++ b/drivers/misc/hmc6352.c | |||
@@ -75,7 +75,7 @@ static ssize_t compass_heading_data_show(struct device *dev, | |||
75 | { | 75 | { |
76 | struct i2c_client *client = to_i2c_client(dev); | 76 | struct i2c_client *client = to_i2c_client(dev); |
77 | unsigned char i2c_data[2]; | 77 | unsigned char i2c_data[2]; |
78 | unsigned int ret; | 78 | int ret; |
79 | 79 | ||
80 | mutex_lock(&compass_mutex); | 80 | mutex_lock(&compass_mutex); |
81 | ret = compass_command(client, 'A'); | 81 | ret = compass_command(client, 'A'); |
@@ -86,7 +86,7 @@ static ssize_t compass_heading_data_show(struct device *dev, | |||
86 | msleep(10); /* sending 'A' cmd we need to wait for 7-10 millisecs */ | 86 | msleep(10); /* sending 'A' cmd we need to wait for 7-10 millisecs */ |
87 | ret = i2c_master_recv(client, i2c_data, 2); | 87 | ret = i2c_master_recv(client, i2c_data, 2); |
88 | mutex_unlock(&compass_mutex); | 88 | mutex_unlock(&compass_mutex); |
89 | if (ret != 1) { | 89 | if (ret < 0) { |
90 | dev_warn(dev, "i2c read data cmd failed\n"); | 90 | dev_warn(dev, "i2c read data cmd failed\n"); |
91 | return ret; | 91 | return ret; |
92 | } | 92 | } |
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index 557a8c2a7336..fffc227181b0 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for HP iLO/iLO2 management processor. | 2 | * Driver for the HP iLO management processor. |
3 | * | 3 | * |
4 | * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. | 4 | * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. |
5 | * David Altobelli <david.altobelli@hp.com> | 5 | * David Altobelli <david.altobelli@hp.com> |
@@ -640,6 +640,7 @@ static const struct file_operations ilo_fops = { | |||
640 | .poll = ilo_poll, | 640 | .poll = ilo_poll, |
641 | .open = ilo_open, | 641 | .open = ilo_open, |
642 | .release = ilo_close, | 642 | .release = ilo_close, |
643 | .llseek = noop_llseek, | ||
643 | }; | 644 | }; |
644 | 645 | ||
645 | static irqreturn_t ilo_isr(int irq, void *data) | 646 | static irqreturn_t ilo_isr(int irq, void *data) |
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index 8844a3f45381..89947723a27d 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c | |||
@@ -29,7 +29,7 @@ | |||
29 | 29 | ||
30 | /* | 30 | /* |
31 | * The IBMASM file virtual filesystem. It creates the following hierarchy | 31 | * The IBMASM file virtual filesystem. It creates the following hierarchy |
32 | * dymamically when mounted from user space: | 32 | * dynamically when mounted from user space: |
33 | * | 33 | * |
34 | * /ibmasm | 34 | * /ibmasm |
35 | * |-- 0 | 35 | * |-- 0 |
@@ -91,11 +91,10 @@ static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root); | |||
91 | static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent); | 91 | static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent); |
92 | 92 | ||
93 | 93 | ||
94 | static int ibmasmfs_get_super(struct file_system_type *fst, | 94 | static struct dentry *ibmasmfs_mount(struct file_system_type *fst, |
95 | int flags, const char *name, void *data, | 95 | int flags, const char *name, void *data) |
96 | struct vfsmount *mnt) | ||
97 | { | 96 | { |
98 | return get_sb_single(fst, flags, data, ibmasmfs_fill_super, mnt); | 97 | return mount_single(fst, flags, data, ibmasmfs_fill_super); |
99 | } | 98 | } |
100 | 99 | ||
101 | static const struct super_operations ibmasmfs_s_ops = { | 100 | static const struct super_operations ibmasmfs_s_ops = { |
@@ -108,7 +107,7 @@ static const struct file_operations *ibmasmfs_dir_ops = &simple_dir_operations; | |||
108 | static struct file_system_type ibmasmfs_type = { | 107 | static struct file_system_type ibmasmfs_type = { |
109 | .owner = THIS_MODULE, | 108 | .owner = THIS_MODULE, |
110 | .name = "ibmasmfs", | 109 | .name = "ibmasmfs", |
111 | .get_sb = ibmasmfs_get_super, | 110 | .mount = ibmasmfs_mount, |
112 | .kill_sb = kill_litter_super, | 111 | .kill_sb = kill_litter_super, |
113 | }; | 112 | }; |
114 | 113 | ||
@@ -146,6 +145,7 @@ static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode) | |||
146 | struct inode *ret = new_inode(sb); | 145 | struct inode *ret = new_inode(sb); |
147 | 146 | ||
148 | if (ret) { | 147 | if (ret) { |
148 | ret->i_ino = get_next_ino(); | ||
149 | ret->i_mode = mode; | 149 | ret->i_mode = mode; |
150 | ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME; | 150 | ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME; |
151 | } | 151 | } |
@@ -584,6 +584,7 @@ static const struct file_operations command_fops = { | |||
584 | .release = command_file_close, | 584 | .release = command_file_close, |
585 | .read = command_file_read, | 585 | .read = command_file_read, |
586 | .write = command_file_write, | 586 | .write = command_file_write, |
587 | .llseek = generic_file_llseek, | ||
587 | }; | 588 | }; |
588 | 589 | ||
589 | static const struct file_operations event_fops = { | 590 | static const struct file_operations event_fops = { |
@@ -591,6 +592,7 @@ static const struct file_operations event_fops = { | |||
591 | .release = event_file_close, | 592 | .release = event_file_close, |
592 | .read = event_file_read, | 593 | .read = event_file_read, |
593 | .write = event_file_write, | 594 | .write = event_file_write, |
595 | .llseek = generic_file_llseek, | ||
594 | }; | 596 | }; |
595 | 597 | ||
596 | static const struct file_operations r_heartbeat_fops = { | 598 | static const struct file_operations r_heartbeat_fops = { |
@@ -598,6 +600,7 @@ static const struct file_operations r_heartbeat_fops = { | |||
598 | .release = r_heartbeat_file_close, | 600 | .release = r_heartbeat_file_close, |
599 | .read = r_heartbeat_file_read, | 601 | .read = r_heartbeat_file_read, |
600 | .write = r_heartbeat_file_write, | 602 | .write = r_heartbeat_file_write, |
603 | .llseek = generic_file_llseek, | ||
601 | }; | 604 | }; |
602 | 605 | ||
603 | static const struct file_operations remote_settings_fops = { | 606 | static const struct file_operations remote_settings_fops = { |
@@ -605,6 +608,7 @@ static const struct file_operations remote_settings_fops = { | |||
605 | .release = remote_settings_file_close, | 608 | .release = remote_settings_file_close, |
606 | .read = remote_settings_file_read, | 609 | .read = remote_settings_file_read, |
607 | .write = remote_settings_file_write, | 610 | .write = remote_settings_file_write, |
611 | .llseek = generic_file_llseek, | ||
608 | }; | 612 | }; |
609 | 613 | ||
610 | 614 | ||
diff --git a/drivers/misc/ibmasm/remote.h b/drivers/misc/ibmasm/remote.h index 72acf5af7a2a..00dbf1d4373a 100644 --- a/drivers/misc/ibmasm/remote.h +++ b/drivers/misc/ibmasm/remote.h | |||
@@ -20,7 +20,7 @@ | |||
20 | * | 20 | * |
21 | * Author: Max Asböck <amax@us.ibm.com> | 21 | * Author: Max Asböck <amax@us.ibm.com> |
22 | * | 22 | * |
23 | * Orignally written by Pete Reynolds | 23 | * Originally written by Pete Reynolds |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #ifndef _IBMASM_REMOTE_H_ | 26 | #ifndef _IBMASM_REMOTE_H_ |
diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c index 193206602d88..df03dd3bd0e2 100644 --- a/drivers/misc/ioc4.c +++ b/drivers/misc/ioc4.c | |||
@@ -270,16 +270,14 @@ ioc4_variant(struct ioc4_driver_data *idd) | |||
270 | return IOC4_VARIANT_PCI_RT; | 270 | return IOC4_VARIANT_PCI_RT; |
271 | } | 271 | } |
272 | 272 | ||
273 | static void __devinit | 273 | static void |
274 | ioc4_load_modules(struct work_struct *work) | 274 | ioc4_load_modules(struct work_struct *work) |
275 | { | 275 | { |
276 | /* arg just has to be freed */ | ||
277 | |||
278 | request_module("sgiioc4"); | 276 | request_module("sgiioc4"); |
279 | |||
280 | kfree(work); | ||
281 | } | 277 | } |
282 | 278 | ||
279 | static DECLARE_WORK(ioc4_load_modules_work, ioc4_load_modules); | ||
280 | |||
283 | /* Adds a new instance of an IOC4 card */ | 281 | /* Adds a new instance of an IOC4 card */ |
284 | static int __devinit | 282 | static int __devinit |
285 | ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) | 283 | ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) |
@@ -396,21 +394,12 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) | |||
396 | * PCI device. | 394 | * PCI device. |
397 | */ | 395 | */ |
398 | if (idd->idd_variant != IOC4_VARIANT_PCI_RT) { | 396 | if (idd->idd_variant != IOC4_VARIANT_PCI_RT) { |
399 | struct work_struct *work; | 397 | /* Request the module from a work procedure as the modprobe |
400 | work = kzalloc(sizeof(struct work_struct), GFP_KERNEL); | 398 | * goes out to a userland helper and that will hang if done |
401 | if (!work) { | 399 | * directly from ioc4_probe(). |
402 | printk(KERN_WARNING | 400 | */ |
403 | "%s: IOC4 unable to allocate memory for " | 401 | printk(KERN_INFO "IOC4 loading sgiioc4 submodule\n"); |
404 | "load of sub-modules.\n", __func__); | 402 | schedule_work(&ioc4_load_modules_work); |
405 | } else { | ||
406 | /* Request the module from a work procedure as the | ||
407 | * modprobe goes out to a userland helper and that | ||
408 | * will hang if done directly from ioc4_probe(). | ||
409 | */ | ||
410 | printk(KERN_INFO "IOC4 loading sgiioc4 submodule\n"); | ||
411 | INIT_WORK(work, ioc4_load_modules); | ||
412 | schedule_work(work); | ||
413 | } | ||
414 | } | 403 | } |
415 | 404 | ||
416 | return 0; | 405 | return 0; |
@@ -498,7 +487,7 @@ static void __exit | |||
498 | ioc4_exit(void) | 487 | ioc4_exit(void) |
499 | { | 488 | { |
500 | /* Ensure ioc4_load_modules() has completed before exiting */ | 489 | /* Ensure ioc4_load_modules() has completed before exiting */ |
501 | flush_scheduled_work(); | 490 | flush_work_sync(&ioc4_load_modules_work); |
502 | pci_unregister_driver(&ioc4_driver); | 491 | pci_unregister_driver(&ioc4_driver); |
503 | } | 492 | } |
504 | 493 | ||
diff --git a/drivers/misc/isl29020.c b/drivers/misc/isl29020.c new file mode 100644 index 000000000000..307aada5fffe --- /dev/null +++ b/drivers/misc/isl29020.c | |||
@@ -0,0 +1,248 @@ | |||
1 | /* | ||
2 | * isl29020.c - Intersil ALS Driver | ||
3 | * | ||
4 | * Copyright (C) 2008 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 | * Data sheet at: http://www.intersil.com/data/fn/fn6505.pdf | ||
23 | */ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/i2c.h> | ||
29 | #include <linux/err.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/sysfs.h> | ||
32 | #include <linux/pm_runtime.h> | ||
33 | |||
34 | static DEFINE_MUTEX(mutex); | ||
35 | |||
36 | static ssize_t als_sensing_range_show(struct device *dev, | ||
37 | struct device_attribute *attr, char *buf) | ||
38 | { | ||
39 | struct i2c_client *client = to_i2c_client(dev); | ||
40 | int val; | ||
41 | |||
42 | val = i2c_smbus_read_byte_data(client, 0x00); | ||
43 | |||
44 | if (val < 0) | ||
45 | return val; | ||
46 | return sprintf(buf, "%d000\n", 1 << (2 * (val & 3))); | ||
47 | |||
48 | } | ||
49 | |||
50 | static ssize_t als_lux_input_data_show(struct device *dev, | ||
51 | struct device_attribute *attr, char *buf) | ||
52 | { | ||
53 | struct i2c_client *client = to_i2c_client(dev); | ||
54 | int ret_val, val; | ||
55 | unsigned long int lux; | ||
56 | int temp; | ||
57 | |||
58 | pm_runtime_get_sync(dev); | ||
59 | msleep(100); | ||
60 | |||
61 | mutex_lock(&mutex); | ||
62 | temp = i2c_smbus_read_byte_data(client, 0x02); /* MSB data */ | ||
63 | if (temp < 0) { | ||
64 | pm_runtime_put_sync(dev); | ||
65 | mutex_unlock(&mutex); | ||
66 | return temp; | ||
67 | } | ||
68 | |||
69 | ret_val = i2c_smbus_read_byte_data(client, 0x01); /* LSB data */ | ||
70 | mutex_unlock(&mutex); | ||
71 | |||
72 | if (ret_val < 0) { | ||
73 | pm_runtime_put_sync(dev); | ||
74 | return ret_val; | ||
75 | } | ||
76 | |||
77 | ret_val |= temp << 8; | ||
78 | val = i2c_smbus_read_byte_data(client, 0x00); | ||
79 | pm_runtime_put_sync(dev); | ||
80 | if (val < 0) | ||
81 | return val; | ||
82 | lux = ((((1 << (2 * (val & 3))))*1000) * ret_val) / 65536; | ||
83 | return sprintf(buf, "%ld\n", lux); | ||
84 | } | ||
85 | |||
86 | static ssize_t als_sensing_range_store(struct device *dev, | ||
87 | struct device_attribute *attr, const char *buf, size_t count) | ||
88 | { | ||
89 | struct i2c_client *client = to_i2c_client(dev); | ||
90 | int ret_val; | ||
91 | unsigned long val; | ||
92 | |||
93 | if (strict_strtoul(buf, 10, &val)) | ||
94 | return -EINVAL; | ||
95 | if (val < 1 || val > 64000) | ||
96 | return -EINVAL; | ||
97 | |||
98 | /* Pick the smallest sensor range that will meet our requirements */ | ||
99 | if (val <= 1000) | ||
100 | val = 1; | ||
101 | else if (val <= 4000) | ||
102 | val = 2; | ||
103 | else if (val <= 16000) | ||
104 | val = 3; | ||
105 | else | ||
106 | val = 4; | ||
107 | |||
108 | ret_val = i2c_smbus_read_byte_data(client, 0x00); | ||
109 | if (ret_val < 0) | ||
110 | return ret_val; | ||
111 | |||
112 | ret_val &= 0xFC; /*reset the bit before setting them */ | ||
113 | ret_val |= val - 1; | ||
114 | ret_val = i2c_smbus_write_byte_data(client, 0x00, ret_val); | ||
115 | |||
116 | if (ret_val < 0) | ||
117 | return ret_val; | ||
118 | return count; | ||
119 | } | ||
120 | |||
121 | static void als_set_power_state(struct i2c_client *client, int enable) | ||
122 | { | ||
123 | int ret_val; | ||
124 | |||
125 | ret_val = i2c_smbus_read_byte_data(client, 0x00); | ||
126 | if (ret_val < 0) | ||
127 | return; | ||
128 | |||
129 | if (enable) | ||
130 | ret_val |= 0x80; | ||
131 | else | ||
132 | ret_val &= 0x7F; | ||
133 | |||
134 | i2c_smbus_write_byte_data(client, 0x00, ret_val); | ||
135 | } | ||
136 | |||
137 | static DEVICE_ATTR(lux0_sensor_range, S_IRUGO | S_IWUSR, | ||
138 | als_sensing_range_show, als_sensing_range_store); | ||
139 | static DEVICE_ATTR(lux0_input, S_IRUGO, als_lux_input_data_show, NULL); | ||
140 | |||
141 | static struct attribute *mid_att_als[] = { | ||
142 | &dev_attr_lux0_sensor_range.attr, | ||
143 | &dev_attr_lux0_input.attr, | ||
144 | NULL | ||
145 | }; | ||
146 | |||
147 | static struct attribute_group m_als_gr = { | ||
148 | .name = "isl29020", | ||
149 | .attrs = mid_att_als | ||
150 | }; | ||
151 | |||
152 | static int als_set_default_config(struct i2c_client *client) | ||
153 | { | ||
154 | int retval; | ||
155 | |||
156 | retval = i2c_smbus_write_byte_data(client, 0x00, 0xc0); | ||
157 | if (retval < 0) { | ||
158 | dev_err(&client->dev, "default write failed."); | ||
159 | return retval; | ||
160 | } | ||
161 | return 0;; | ||
162 | } | ||
163 | |||
164 | static int isl29020_probe(struct i2c_client *client, | ||
165 | const struct i2c_device_id *id) | ||
166 | { | ||
167 | int res; | ||
168 | |||
169 | res = als_set_default_config(client); | ||
170 | if (res < 0) | ||
171 | return res; | ||
172 | |||
173 | res = sysfs_create_group(&client->dev.kobj, &m_als_gr); | ||
174 | if (res) { | ||
175 | dev_err(&client->dev, "isl29020: device create file failed\n"); | ||
176 | return res; | ||
177 | } | ||
178 | dev_info(&client->dev, "%s isl29020: ALS chip found\n", client->name); | ||
179 | als_set_power_state(client, 0); | ||
180 | pm_runtime_enable(&client->dev); | ||
181 | return res; | ||
182 | } | ||
183 | |||
184 | static int isl29020_remove(struct i2c_client *client) | ||
185 | { | ||
186 | sysfs_remove_group(&client->dev.kobj, &m_als_gr); | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static struct i2c_device_id isl29020_id[] = { | ||
191 | { "isl29020", 0 }, | ||
192 | { } | ||
193 | }; | ||
194 | |||
195 | MODULE_DEVICE_TABLE(i2c, isl29020_id); | ||
196 | |||
197 | #ifdef CONFIG_PM | ||
198 | |||
199 | static int isl29020_runtime_suspend(struct device *dev) | ||
200 | { | ||
201 | struct i2c_client *client = to_i2c_client(dev); | ||
202 | als_set_power_state(client, 0); | ||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static int isl29020_runtime_resume(struct device *dev) | ||
207 | { | ||
208 | struct i2c_client *client = to_i2c_client(dev); | ||
209 | als_set_power_state(client, 1); | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static const struct dev_pm_ops isl29020_pm_ops = { | ||
214 | .runtime_suspend = isl29020_runtime_suspend, | ||
215 | .runtime_resume = isl29020_runtime_resume, | ||
216 | }; | ||
217 | |||
218 | #define ISL29020_PM_OPS (&isl29020_pm_ops) | ||
219 | #else /* CONFIG_PM */ | ||
220 | #define ISL29020_PM_OPS NULL | ||
221 | #endif /* CONFIG_PM */ | ||
222 | |||
223 | static struct i2c_driver isl29020_driver = { | ||
224 | .driver = { | ||
225 | .name = "isl29020", | ||
226 | .pm = ISL29020_PM_OPS, | ||
227 | }, | ||
228 | .probe = isl29020_probe, | ||
229 | .remove = isl29020_remove, | ||
230 | .id_table = isl29020_id, | ||
231 | }; | ||
232 | |||
233 | static int __init sensor_isl29020_init(void) | ||
234 | { | ||
235 | return i2c_add_driver(&isl29020_driver); | ||
236 | } | ||
237 | |||
238 | static void __exit sensor_isl29020_exit(void) | ||
239 | { | ||
240 | i2c_del_driver(&isl29020_driver); | ||
241 | } | ||
242 | |||
243 | module_init(sensor_isl29020_init); | ||
244 | module_exit(sensor_isl29020_exit); | ||
245 | |||
246 | MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com>"); | ||
247 | MODULE_DESCRIPTION("Intersil isl29020 ALS Driver"); | ||
248 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/misc/iwmc3200top/debugfs.c b/drivers/misc/iwmc3200top/debugfs.c index e9eda471f6e0..62fbaec48207 100644 --- a/drivers/misc/iwmc3200top/debugfs.c +++ b/drivers/misc/iwmc3200top/debugfs.c | |||
@@ -71,6 +71,7 @@ ssize_t iwmct_dbgfs_##name##_write(struct file *file, \ | |||
71 | static const struct file_operations iwmct_dbgfs_##name##_ops = { \ | 71 | static const struct file_operations iwmct_dbgfs_##name##_ops = { \ |
72 | .read = iwmct_dbgfs_##name##_read, \ | 72 | .read = iwmct_dbgfs_##name##_read, \ |
73 | .open = iwmct_dbgfs_open_file_generic, \ | 73 | .open = iwmct_dbgfs_open_file_generic, \ |
74 | .llseek = generic_file_llseek, \ | ||
74 | }; | 75 | }; |
75 | 76 | ||
76 | #define DEBUGFS_WRITE_FILE_OPS(name) \ | 77 | #define DEBUGFS_WRITE_FILE_OPS(name) \ |
@@ -78,6 +79,7 @@ ssize_t iwmct_dbgfs_##name##_write(struct file *file, \ | |||
78 | static const struct file_operations iwmct_dbgfs_##name##_ops = { \ | 79 | static const struct file_operations iwmct_dbgfs_##name##_ops = { \ |
79 | .write = iwmct_dbgfs_##name##_write, \ | 80 | .write = iwmct_dbgfs_##name##_write, \ |
80 | .open = iwmct_dbgfs_open_file_generic, \ | 81 | .open = iwmct_dbgfs_open_file_generic, \ |
82 | .llseek = generic_file_llseek, \ | ||
81 | }; | 83 | }; |
82 | 84 | ||
83 | #define DEBUGFS_READ_WRITE_FILE_OPS(name) \ | 85 | #define DEBUGFS_READ_WRITE_FILE_OPS(name) \ |
@@ -87,6 +89,7 @@ ssize_t iwmct_dbgfs_##name##_write(struct file *file, \ | |||
87 | .write = iwmct_dbgfs_##name##_write, \ | 89 | .write = iwmct_dbgfs_##name##_write, \ |
88 | .read = iwmct_dbgfs_##name##_read, \ | 90 | .read = iwmct_dbgfs_##name##_read, \ |
89 | .open = iwmct_dbgfs_open_file_generic, \ | 91 | .open = iwmct_dbgfs_open_file_generic, \ |
92 | .llseek = generic_file_llseek, \ | ||
90 | }; | 93 | }; |
91 | 94 | ||
92 | 95 | ||
diff --git a/drivers/misc/iwmc3200top/iwmc3200top.h b/drivers/misc/iwmc3200top/iwmc3200top.h index 740ff0738ea8..620973ed8bf9 100644 --- a/drivers/misc/iwmc3200top/iwmc3200top.h +++ b/drivers/misc/iwmc3200top/iwmc3200top.h | |||
@@ -183,9 +183,7 @@ struct iwmct_priv { | |||
183 | u32 barker; | 183 | u32 barker; |
184 | struct iwmct_dbg dbg; | 184 | struct iwmct_dbg dbg; |
185 | 185 | ||
186 | /* drivers work queue */ | 186 | /* drivers work items */ |
187 | struct workqueue_struct *wq; | ||
188 | struct workqueue_struct *bus_rescan_wq; | ||
189 | struct work_struct bus_rescan_worker; | 187 | struct work_struct bus_rescan_worker; |
190 | struct work_struct isr_worker; | 188 | struct work_struct isr_worker; |
191 | 189 | ||
diff --git a/drivers/misc/iwmc3200top/main.c b/drivers/misc/iwmc3200top/main.c index c73cef2c3c5e..b1f4563be9ae 100644 --- a/drivers/misc/iwmc3200top/main.c +++ b/drivers/misc/iwmc3200top/main.c | |||
@@ -89,7 +89,7 @@ static void op_top_message(struct iwmct_priv *priv, struct top_msg *msg) | |||
89 | switch (msg->hdr.opcode) { | 89 | switch (msg->hdr.opcode) { |
90 | case OP_OPR_ALIVE: | 90 | case OP_OPR_ALIVE: |
91 | LOG_INFO(priv, FW_MSG, "Got ALIVE from device, wake rescan\n"); | 91 | LOG_INFO(priv, FW_MSG, "Got ALIVE from device, wake rescan\n"); |
92 | queue_work(priv->bus_rescan_wq, &priv->bus_rescan_worker); | 92 | schedule_work(&priv->bus_rescan_worker); |
93 | break; | 93 | break; |
94 | default: | 94 | default: |
95 | LOG_INFO(priv, FW_MSG, "Received msg opcode 0x%X\n", | 95 | LOG_INFO(priv, FW_MSG, "Received msg opcode 0x%X\n", |
@@ -268,7 +268,7 @@ static void iwmct_irq_read_worker(struct work_struct *ws) | |||
268 | LOG_INFO(priv, IRQ, "ACK barker arrived " | 268 | LOG_INFO(priv, IRQ, "ACK barker arrived " |
269 | "- starting FW download\n"); | 269 | "- starting FW download\n"); |
270 | } else { /* REBOOT barker */ | 270 | } else { /* REBOOT barker */ |
271 | LOG_INFO(priv, IRQ, "Recieved reboot barker: %x\n", barker); | 271 | LOG_INFO(priv, IRQ, "Received reboot barker: %x\n", barker); |
272 | priv->barker = barker; | 272 | priv->barker = barker; |
273 | 273 | ||
274 | if (barker & BARKER_DNLOAD_SYNC_MSK) { | 274 | if (barker & BARKER_DNLOAD_SYNC_MSK) { |
@@ -360,7 +360,7 @@ static void iwmct_irq(struct sdio_func *func) | |||
360 | /* clear the function's interrupt request bit (write 1 to clear) */ | 360 | /* clear the function's interrupt request bit (write 1 to clear) */ |
361 | sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret); | 361 | sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret); |
362 | 362 | ||
363 | queue_work(priv->wq, &priv->isr_worker); | 363 | schedule_work(&priv->isr_worker); |
364 | 364 | ||
365 | LOG_TRACE(priv, IRQ, "exit iwmct_irq\n"); | 365 | LOG_TRACE(priv, IRQ, "exit iwmct_irq\n"); |
366 | 366 | ||
@@ -506,10 +506,6 @@ static int iwmct_probe(struct sdio_func *func, | |||
506 | priv->func = func; | 506 | priv->func = func; |
507 | sdio_set_drvdata(func, priv); | 507 | sdio_set_drvdata(func, priv); |
508 | 508 | ||
509 | |||
510 | /* create drivers work queue */ | ||
511 | priv->wq = create_workqueue(DRV_NAME "_wq"); | ||
512 | priv->bus_rescan_wq = create_workqueue(DRV_NAME "_rescan_wq"); | ||
513 | INIT_WORK(&priv->bus_rescan_worker, iwmct_rescan_worker); | 509 | INIT_WORK(&priv->bus_rescan_worker, iwmct_rescan_worker); |
514 | INIT_WORK(&priv->isr_worker, iwmct_irq_read_worker); | 510 | INIT_WORK(&priv->isr_worker, iwmct_irq_read_worker); |
515 | 511 | ||
@@ -604,9 +600,9 @@ static void iwmct_remove(struct sdio_func *func) | |||
604 | sdio_release_irq(func); | 600 | sdio_release_irq(func); |
605 | sdio_release_host(func); | 601 | sdio_release_host(func); |
606 | 602 | ||
607 | /* Safely destroy osc workqueue */ | 603 | /* Make sure works are finished */ |
608 | destroy_workqueue(priv->bus_rescan_wq); | 604 | flush_work_sync(&priv->bus_rescan_worker); |
609 | destroy_workqueue(priv->wq); | 605 | flush_work_sync(&priv->isr_worker); |
610 | 606 | ||
611 | sdio_claim_host(func); | 607 | sdio_claim_host(func); |
612 | sdio_disable_func(func); | 608 | sdio_disable_func(func); |
diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 72450237a0f4..8cebec5e85ee 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c | |||
@@ -285,32 +285,28 @@ static void hw_break_val_write(void) | |||
285 | static int check_and_rewind_pc(char *put_str, char *arg) | 285 | static int check_and_rewind_pc(char *put_str, char *arg) |
286 | { | 286 | { |
287 | unsigned long addr = lookup_addr(arg); | 287 | unsigned long addr = lookup_addr(arg); |
288 | unsigned long ip; | ||
288 | int offset = 0; | 289 | int offset = 0; |
289 | 290 | ||
290 | kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs, | 291 | kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs, |
291 | NUMREGBYTES); | 292 | NUMREGBYTES); |
292 | gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs); | 293 | gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs); |
293 | v2printk("Stopped at IP: %lx\n", instruction_pointer(&kgdbts_regs)); | 294 | ip = instruction_pointer(&kgdbts_regs); |
294 | #ifdef CONFIG_X86 | 295 | v2printk("Stopped at IP: %lx\n", ip); |
295 | /* On x86 a breakpoint stop requires it to be decremented */ | 296 | #ifdef GDB_ADJUSTS_BREAK_OFFSET |
296 | if (addr + 1 == kgdbts_regs.ip) | 297 | /* On some arches, a breakpoint stop requires it to be decremented */ |
297 | offset = -1; | 298 | if (addr + BREAK_INSTR_SIZE == ip) |
298 | #elif defined(CONFIG_SUPERH) | 299 | offset = -BREAK_INSTR_SIZE; |
299 | /* On SUPERH a breakpoint stop requires it to be decremented */ | ||
300 | if (addr + 2 == kgdbts_regs.pc) | ||
301 | offset = -2; | ||
302 | #endif | 300 | #endif |
303 | if (strcmp(arg, "silent") && | 301 | if (strcmp(arg, "silent") && ip + offset != addr) { |
304 | instruction_pointer(&kgdbts_regs) + offset != addr) { | ||
305 | eprintk("kgdbts: BP mismatch %lx expected %lx\n", | 302 | eprintk("kgdbts: BP mismatch %lx expected %lx\n", |
306 | instruction_pointer(&kgdbts_regs) + offset, addr); | 303 | ip + offset, addr); |
307 | return 1; | 304 | return 1; |
308 | } | 305 | } |
309 | #ifdef CONFIG_X86 | 306 | /* Readjust the instruction pointer if needed */ |
310 | /* On x86 adjust the instruction pointer if needed */ | 307 | ip += offset; |
311 | kgdbts_regs.ip += offset; | 308 | #ifdef GDB_ADJUSTS_BREAK_OFFSET |
312 | #elif defined(CONFIG_SUPERH) | 309 | instruction_pointer_set(&kgdbts_regs, ip); |
313 | kgdbts_regs.pc += offset; | ||
314 | #endif | 310 | #endif |
315 | return 0; | 311 | return 0; |
316 | } | 312 | } |
@@ -645,7 +641,7 @@ static int validate_simple_test(char *put_str) | |||
645 | 641 | ||
646 | while (*chk_str != '\0' && *put_str != '\0') { | 642 | while (*chk_str != '\0' && *put_str != '\0') { |
647 | /* If someone does a * to match the rest of the string, allow | 643 | /* If someone does a * to match the rest of the string, allow |
648 | * it, or stop if the recieved string is complete. | 644 | * it, or stop if the received string is complete. |
649 | */ | 645 | */ |
650 | if (*put_str == '#' || *chk_str == '*') | 646 | if (*put_str == '#' || *chk_str == '*') |
651 | return 0; | 647 | return 0; |
@@ -988,7 +984,7 @@ static void kgdbts_run_tests(void) | |||
988 | 984 | ||
989 | static int kgdbts_option_setup(char *opt) | 985 | static int kgdbts_option_setup(char *opt) |
990 | { | 986 | { |
991 | if (strlen(opt) > MAX_CONFIG_LEN) { | 987 | if (strlen(opt) >= MAX_CONFIG_LEN) { |
992 | printk(KERN_ERR "kgdbts: config string too long\n"); | 988 | printk(KERN_ERR "kgdbts: config string too long\n"); |
993 | return -ENOSPC; | 989 | return -ENOSPC; |
994 | } | 990 | } |
@@ -1044,12 +1040,6 @@ static int __init init_kgdbts(void) | |||
1044 | return configure_kgdbts(); | 1040 | return configure_kgdbts(); |
1045 | } | 1041 | } |
1046 | 1042 | ||
1047 | static void cleanup_kgdbts(void) | ||
1048 | { | ||
1049 | if (configured == 1) | ||
1050 | kgdb_unregister_io_module(&kgdbts_io_ops); | ||
1051 | } | ||
1052 | |||
1053 | static int kgdbts_get_char(void) | 1043 | static int kgdbts_get_char(void) |
1054 | { | 1044 | { |
1055 | int val = 0; | 1045 | int val = 0; |
@@ -1081,10 +1071,8 @@ static int param_set_kgdbts_var(const char *kmessage, struct kernel_param *kp) | |||
1081 | return 0; | 1071 | return 0; |
1082 | } | 1072 | } |
1083 | 1073 | ||
1084 | if (kgdb_connected) { | 1074 | if (configured == 1) { |
1085 | printk(KERN_ERR | 1075 | printk(KERN_ERR "kgdbts: ERROR: Already configured and running.\n"); |
1086 | "kgdbts: Cannot reconfigure while KGDB is connected.\n"); | ||
1087 | |||
1088 | return -EBUSY; | 1076 | return -EBUSY; |
1089 | } | 1077 | } |
1090 | 1078 | ||
@@ -1093,9 +1081,6 @@ static int param_set_kgdbts_var(const char *kmessage, struct kernel_param *kp) | |||
1093 | if (config[len - 1] == '\n') | 1081 | if (config[len - 1] == '\n') |
1094 | config[len - 1] = '\0'; | 1082 | config[len - 1] = '\0'; |
1095 | 1083 | ||
1096 | if (configured == 1) | ||
1097 | cleanup_kgdbts(); | ||
1098 | |||
1099 | /* Go and configure with the new params. */ | 1084 | /* Go and configure with the new params. */ |
1100 | return configure_kgdbts(); | 1085 | return configure_kgdbts(); |
1101 | } | 1086 | } |
@@ -1123,7 +1108,6 @@ static struct kgdb_io kgdbts_io_ops = { | |||
1123 | }; | 1108 | }; |
1124 | 1109 | ||
1125 | module_init(init_kgdbts); | 1110 | module_init(init_kgdbts); |
1126 | module_exit(cleanup_kgdbts); | ||
1127 | module_param_call(kgdbts, param_set_kgdbts_var, param_get_string, &kps, 0644); | 1111 | module_param_call(kgdbts, param_set_kgdbts_var, param_get_string, &kps, 0644); |
1128 | MODULE_PARM_DESC(kgdbts, "<A|V1|V2>[F#|S#][N#]"); | 1112 | MODULE_PARM_DESC(kgdbts, "<A|V1|V2>[F#|S#][N#]"); |
1129 | MODULE_DESCRIPTION("KGDB Test Suite"); | 1113 | MODULE_DESCRIPTION("KGDB Test Suite"); |
diff --git a/drivers/misc/lis3lv02d/Kconfig b/drivers/misc/lis3lv02d/Kconfig new file mode 100644 index 000000000000..8f474e6fc7b4 --- /dev/null +++ b/drivers/misc/lis3lv02d/Kconfig | |||
@@ -0,0 +1,37 @@ | |||
1 | # | ||
2 | # STMicroelectonics LIS3LV02D and similar accelerometers | ||
3 | # | ||
4 | |||
5 | config SENSORS_LIS3_SPI | ||
6 | tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)" | ||
7 | depends on !ACPI && SPI_MASTER && INPUT | ||
8 | select SENSORS_LIS3LV02D | ||
9 | default n | ||
10 | help | ||
11 | This driver provides support for the LIS3LV02Dx accelerometer connected | ||
12 | via SPI. The accelerometer data is readable via | ||
13 | /sys/devices/platform/lis3lv02d. | ||
14 | |||
15 | This driver also provides an absolute input class device, allowing | ||
16 | the laptop to act as a pinball machine-esque joystick. | ||
17 | |||
18 | This driver can also be built as modules. If so, the core module | ||
19 | will be called lis3lv02d and a specific module for the SPI transport | ||
20 | is called lis3lv02d_spi. | ||
21 | |||
22 | config SENSORS_LIS3_I2C | ||
23 | tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (I2C)" | ||
24 | depends on I2C && INPUT | ||
25 | select SENSORS_LIS3LV02D | ||
26 | default n | ||
27 | help | ||
28 | This driver provides support for the LIS3LV02Dx accelerometer connected | ||
29 | via I2C. The accelerometer data is readable via | ||
30 | /sys/devices/platform/lis3lv02d. | ||
31 | |||
32 | This driver also provides an absolute input class device, allowing | ||
33 | the device to act as a pinball machine-esque joystick. | ||
34 | |||
35 | This driver can also be built as modules. If so, the core module | ||
36 | will be called lis3lv02d and a specific module for the I2C transport | ||
37 | is called lis3lv02d_i2c. | ||
diff --git a/drivers/misc/lis3lv02d/Makefile b/drivers/misc/lis3lv02d/Makefile new file mode 100644 index 000000000000..4bf58b16fcf8 --- /dev/null +++ b/drivers/misc/lis3lv02d/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # STMicroelectonics LIS3LV02D and similar accelerometers | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o | ||
6 | obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d_spi.o | ||
7 | obj-$(CONFIG_SENSORS_LIS3_I2C) += lis3lv02d_i2c.o | ||
diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c new file mode 100644 index 000000000000..b928bc14e97b --- /dev/null +++ b/drivers/misc/lis3lv02d/lis3lv02d.c | |||
@@ -0,0 +1,999 @@ | |||
1 | /* | ||
2 | * lis3lv02d.c - ST LIS3LV02DL accelerometer driver | ||
3 | * | ||
4 | * Copyright (C) 2007-2008 Yan Burman | ||
5 | * Copyright (C) 2008 Eric Piel | ||
6 | * Copyright (C) 2008-2009 Pavel Machek | ||
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; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
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. | ||
17 | * | ||
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 | ||
21 | */ | ||
22 | |||
23 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
24 | |||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/dmi.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/types.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/interrupt.h> | ||
32 | #include <linux/input-polldev.h> | ||
33 | #include <linux/delay.h> | ||
34 | #include <linux/wait.h> | ||
35 | #include <linux/poll.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <linux/freezer.h> | ||
38 | #include <linux/uaccess.h> | ||
39 | #include <linux/miscdevice.h> | ||
40 | #include <linux/pm_runtime.h> | ||
41 | #include <linux/atomic.h> | ||
42 | #include "lis3lv02d.h" | ||
43 | |||
44 | #define DRIVER_NAME "lis3lv02d" | ||
45 | |||
46 | /* joystick device poll interval in milliseconds */ | ||
47 | #define MDPS_POLL_INTERVAL 50 | ||
48 | #define MDPS_POLL_MIN 0 | ||
49 | #define MDPS_POLL_MAX 2000 | ||
50 | |||
51 | #define LIS3_SYSFS_POWERDOWN_DELAY 5000 /* In milliseconds */ | ||
52 | |||
53 | #define SELFTEST_OK 0 | ||
54 | #define SELFTEST_FAIL -1 | ||
55 | #define SELFTEST_IRQ -2 | ||
56 | |||
57 | #define IRQ_LINE0 0 | ||
58 | #define IRQ_LINE1 1 | ||
59 | |||
60 | /* | ||
61 | * The sensor can also generate interrupts (DRDY) but it's pretty pointless | ||
62 | * because they are generated even if the data do not change. So it's better | ||
63 | * to keep the interrupt for the free-fall event. The values are updated at | ||
64 | * 40Hz (at the lowest frequency), but as it can be pretty time consuming on | ||
65 | * some low processor, we poll the sensor only at 20Hz... enough for the | ||
66 | * joystick. | ||
67 | */ | ||
68 | |||
69 | #define LIS3_PWRON_DELAY_WAI_12B (5000) | ||
70 | #define LIS3_PWRON_DELAY_WAI_8B (3000) | ||
71 | |||
72 | /* | ||
73 | * LIS3LV02D spec says 1024 LSBs corresponds 1 G -> 1LSB is 1000/1024 mG | ||
74 | * LIS302D spec says: 18 mG / digit | ||
75 | * LIS3_ACCURACY is used to increase accuracy of the intermediate | ||
76 | * calculation results. | ||
77 | */ | ||
78 | #define LIS3_ACCURACY 1024 | ||
79 | /* Sensitivity values for -2G +2G scale */ | ||
80 | #define LIS3_SENSITIVITY_12B ((LIS3_ACCURACY * 1000) / 1024) | ||
81 | #define LIS3_SENSITIVITY_8B (18 * LIS3_ACCURACY) | ||
82 | |||
83 | #define LIS3_DEFAULT_FUZZ_12B 3 | ||
84 | #define LIS3_DEFAULT_FLAT_12B 3 | ||
85 | #define LIS3_DEFAULT_FUZZ_8B 1 | ||
86 | #define LIS3_DEFAULT_FLAT_8B 1 | ||
87 | |||
88 | struct lis3lv02d lis3_dev = { | ||
89 | .misc_wait = __WAIT_QUEUE_HEAD_INITIALIZER(lis3_dev.misc_wait), | ||
90 | }; | ||
91 | EXPORT_SYMBOL_GPL(lis3_dev); | ||
92 | |||
93 | /* just like param_set_int() but does sanity-check so that it won't point | ||
94 | * over the axis array size | ||
95 | */ | ||
96 | static int param_set_axis(const char *val, const struct kernel_param *kp) | ||
97 | { | ||
98 | int ret = param_set_int(val, kp); | ||
99 | if (!ret) { | ||
100 | int val = *(int *)kp->arg; | ||
101 | if (val < 0) | ||
102 | val = -val; | ||
103 | if (!val || val > 3) | ||
104 | return -EINVAL; | ||
105 | } | ||
106 | return ret; | ||
107 | } | ||
108 | |||
109 | static struct kernel_param_ops param_ops_axis = { | ||
110 | .set = param_set_axis, | ||
111 | .get = param_get_int, | ||
112 | }; | ||
113 | |||
114 | module_param_array_named(axes, lis3_dev.ac.as_array, axis, NULL, 0644); | ||
115 | MODULE_PARM_DESC(axes, "Axis-mapping for x,y,z directions"); | ||
116 | |||
117 | static s16 lis3lv02d_read_8(struct lis3lv02d *lis3, int reg) | ||
118 | { | ||
119 | s8 lo; | ||
120 | if (lis3->read(lis3, reg, &lo) < 0) | ||
121 | return 0; | ||
122 | |||
123 | return lo; | ||
124 | } | ||
125 | |||
126 | static s16 lis3lv02d_read_12(struct lis3lv02d *lis3, int reg) | ||
127 | { | ||
128 | u8 lo, hi; | ||
129 | |||
130 | lis3->read(lis3, reg - 1, &lo); | ||
131 | lis3->read(lis3, reg, &hi); | ||
132 | /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */ | ||
133 | return (s16)((hi << 8) | lo); | ||
134 | } | ||
135 | |||
136 | /** | ||
137 | * lis3lv02d_get_axis - For the given axis, give the value converted | ||
138 | * @axis: 1,2,3 - can also be negative | ||
139 | * @hw_values: raw values returned by the hardware | ||
140 | * | ||
141 | * Returns the converted value. | ||
142 | */ | ||
143 | static inline int lis3lv02d_get_axis(s8 axis, int hw_values[3]) | ||
144 | { | ||
145 | if (axis > 0) | ||
146 | return hw_values[axis - 1]; | ||
147 | else | ||
148 | return -hw_values[-axis - 1]; | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * lis3lv02d_get_xyz - Get X, Y and Z axis values from the accelerometer | ||
153 | * @lis3: pointer to the device struct | ||
154 | * @x: where to store the X axis value | ||
155 | * @y: where to store the Y axis value | ||
156 | * @z: where to store the Z axis value | ||
157 | * | ||
158 | * Note that 40Hz input device can eat up about 10% CPU at 800MHZ | ||
159 | */ | ||
160 | static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z) | ||
161 | { | ||
162 | int position[3]; | ||
163 | int i; | ||
164 | |||
165 | if (lis3->blkread) { | ||
166 | if (lis3_dev.whoami == WAI_12B) { | ||
167 | u16 data[3]; | ||
168 | lis3->blkread(lis3, OUTX_L, 6, (u8 *)data); | ||
169 | for (i = 0; i < 3; i++) | ||
170 | position[i] = (s16)le16_to_cpu(data[i]); | ||
171 | } else { | ||
172 | u8 data[5]; | ||
173 | /* Data: x, dummy, y, dummy, z */ | ||
174 | lis3->blkread(lis3, OUTX, 5, data); | ||
175 | for (i = 0; i < 3; i++) | ||
176 | position[i] = (s8)data[i * 2]; | ||
177 | } | ||
178 | } else { | ||
179 | position[0] = lis3->read_data(lis3, OUTX); | ||
180 | position[1] = lis3->read_data(lis3, OUTY); | ||
181 | position[2] = lis3->read_data(lis3, OUTZ); | ||
182 | } | ||
183 | |||
184 | for (i = 0; i < 3; i++) | ||
185 | position[i] = (position[i] * lis3->scale) / LIS3_ACCURACY; | ||
186 | |||
187 | *x = lis3lv02d_get_axis(lis3->ac.x, position); | ||
188 | *y = lis3lv02d_get_axis(lis3->ac.y, position); | ||
189 | *z = lis3lv02d_get_axis(lis3->ac.z, position); | ||
190 | } | ||
191 | |||
192 | /* conversion btw sampling rate and the register values */ | ||
193 | static int lis3_12_rates[4] = {40, 160, 640, 2560}; | ||
194 | static int lis3_8_rates[2] = {100, 400}; | ||
195 | static int lis3_3dc_rates[16] = {0, 1, 10, 25, 50, 100, 200, 400, 1600, 5000}; | ||
196 | |||
197 | /* ODR is Output Data Rate */ | ||
198 | static int lis3lv02d_get_odr(void) | ||
199 | { | ||
200 | u8 ctrl; | ||
201 | int shift; | ||
202 | |||
203 | lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl); | ||
204 | ctrl &= lis3_dev.odr_mask; | ||
205 | shift = ffs(lis3_dev.odr_mask) - 1; | ||
206 | return lis3_dev.odrs[(ctrl >> shift)]; | ||
207 | } | ||
208 | |||
209 | static int lis3lv02d_set_odr(int rate) | ||
210 | { | ||
211 | u8 ctrl; | ||
212 | int i, len, shift; | ||
213 | |||
214 | if (!rate) | ||
215 | return -EINVAL; | ||
216 | |||
217 | lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl); | ||
218 | ctrl &= ~lis3_dev.odr_mask; | ||
219 | len = 1 << hweight_long(lis3_dev.odr_mask); /* # of possible values */ | ||
220 | shift = ffs(lis3_dev.odr_mask) - 1; | ||
221 | |||
222 | for (i = 0; i < len; i++) | ||
223 | if (lis3_dev.odrs[i] == rate) { | ||
224 | lis3_dev.write(&lis3_dev, CTRL_REG1, | ||
225 | ctrl | (i << shift)); | ||
226 | return 0; | ||
227 | } | ||
228 | return -EINVAL; | ||
229 | } | ||
230 | |||
231 | static int lis3lv02d_selftest(struct lis3lv02d *lis3, s16 results[3]) | ||
232 | { | ||
233 | u8 ctlreg, reg; | ||
234 | s16 x, y, z; | ||
235 | u8 selftest; | ||
236 | int ret; | ||
237 | u8 ctrl_reg_data; | ||
238 | unsigned char irq_cfg; | ||
239 | |||
240 | mutex_lock(&lis3->mutex); | ||
241 | |||
242 | irq_cfg = lis3->irq_cfg; | ||
243 | if (lis3_dev.whoami == WAI_8B) { | ||
244 | lis3->data_ready_count[IRQ_LINE0] = 0; | ||
245 | lis3->data_ready_count[IRQ_LINE1] = 0; | ||
246 | |||
247 | /* Change interrupt cfg to data ready for selftest */ | ||
248 | atomic_inc(&lis3_dev.wake_thread); | ||
249 | lis3->irq_cfg = LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY; | ||
250 | lis3->read(lis3, CTRL_REG3, &ctrl_reg_data); | ||
251 | lis3->write(lis3, CTRL_REG3, (ctrl_reg_data & | ||
252 | ~(LIS3_IRQ1_MASK | LIS3_IRQ2_MASK)) | | ||
253 | (LIS3_IRQ1_DATA_READY | LIS3_IRQ2_DATA_READY)); | ||
254 | } | ||
255 | |||
256 | if (lis3_dev.whoami == WAI_3DC) { | ||
257 | ctlreg = CTRL_REG4; | ||
258 | selftest = CTRL4_ST0; | ||
259 | } else { | ||
260 | ctlreg = CTRL_REG1; | ||
261 | if (lis3_dev.whoami == WAI_12B) | ||
262 | selftest = CTRL1_ST; | ||
263 | else | ||
264 | selftest = CTRL1_STP; | ||
265 | } | ||
266 | |||
267 | lis3->read(lis3, ctlreg, ®); | ||
268 | lis3->write(lis3, ctlreg, (reg | selftest)); | ||
269 | msleep(lis3->pwron_delay / lis3lv02d_get_odr()); | ||
270 | |||
271 | /* Read directly to avoid axis remap */ | ||
272 | x = lis3->read_data(lis3, OUTX); | ||
273 | y = lis3->read_data(lis3, OUTY); | ||
274 | z = lis3->read_data(lis3, OUTZ); | ||
275 | |||
276 | /* back to normal settings */ | ||
277 | lis3->write(lis3, ctlreg, reg); | ||
278 | msleep(lis3->pwron_delay / lis3lv02d_get_odr()); | ||
279 | |||
280 | results[0] = x - lis3->read_data(lis3, OUTX); | ||
281 | results[1] = y - lis3->read_data(lis3, OUTY); | ||
282 | results[2] = z - lis3->read_data(lis3, OUTZ); | ||
283 | |||
284 | ret = 0; | ||
285 | |||
286 | if (lis3_dev.whoami == WAI_8B) { | ||
287 | /* Restore original interrupt configuration */ | ||
288 | atomic_dec(&lis3_dev.wake_thread); | ||
289 | lis3->write(lis3, CTRL_REG3, ctrl_reg_data); | ||
290 | lis3->irq_cfg = irq_cfg; | ||
291 | |||
292 | if ((irq_cfg & LIS3_IRQ1_MASK) && | ||
293 | lis3->data_ready_count[IRQ_LINE0] < 2) { | ||
294 | ret = SELFTEST_IRQ; | ||
295 | goto fail; | ||
296 | } | ||
297 | |||
298 | if ((irq_cfg & LIS3_IRQ2_MASK) && | ||
299 | lis3->data_ready_count[IRQ_LINE1] < 2) { | ||
300 | ret = SELFTEST_IRQ; | ||
301 | goto fail; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | if (lis3->pdata) { | ||
306 | int i; | ||
307 | for (i = 0; i < 3; i++) { | ||
308 | /* Check against selftest acceptance limits */ | ||
309 | if ((results[i] < lis3->pdata->st_min_limits[i]) || | ||
310 | (results[i] > lis3->pdata->st_max_limits[i])) { | ||
311 | ret = SELFTEST_FAIL; | ||
312 | goto fail; | ||
313 | } | ||
314 | } | ||
315 | } | ||
316 | |||
317 | /* test passed */ | ||
318 | fail: | ||
319 | mutex_unlock(&lis3->mutex); | ||
320 | return ret; | ||
321 | } | ||
322 | |||
323 | /* | ||
324 | * Order of registers in the list affects to order of the restore process. | ||
325 | * Perhaps it is a good idea to set interrupt enable register as a last one | ||
326 | * after all other configurations | ||
327 | */ | ||
328 | static u8 lis3_wai8_regs[] = { FF_WU_CFG_1, FF_WU_THS_1, FF_WU_DURATION_1, | ||
329 | FF_WU_CFG_2, FF_WU_THS_2, FF_WU_DURATION_2, | ||
330 | CLICK_CFG, CLICK_SRC, CLICK_THSY_X, CLICK_THSZ, | ||
331 | CLICK_TIMELIMIT, CLICK_LATENCY, CLICK_WINDOW, | ||
332 | CTRL_REG1, CTRL_REG2, CTRL_REG3}; | ||
333 | |||
334 | static u8 lis3_wai12_regs[] = {FF_WU_CFG, FF_WU_THS_L, FF_WU_THS_H, | ||
335 | FF_WU_DURATION, DD_CFG, DD_THSI_L, DD_THSI_H, | ||
336 | DD_THSE_L, DD_THSE_H, | ||
337 | CTRL_REG1, CTRL_REG3, CTRL_REG2}; | ||
338 | |||
339 | static inline void lis3_context_save(struct lis3lv02d *lis3) | ||
340 | { | ||
341 | int i; | ||
342 | for (i = 0; i < lis3->regs_size; i++) | ||
343 | lis3->read(lis3, lis3->regs[i], &lis3->reg_cache[i]); | ||
344 | lis3->regs_stored = true; | ||
345 | } | ||
346 | |||
347 | static inline void lis3_context_restore(struct lis3lv02d *lis3) | ||
348 | { | ||
349 | int i; | ||
350 | if (lis3->regs_stored) | ||
351 | for (i = 0; i < lis3->regs_size; i++) | ||
352 | lis3->write(lis3, lis3->regs[i], lis3->reg_cache[i]); | ||
353 | } | ||
354 | |||
355 | void lis3lv02d_poweroff(struct lis3lv02d *lis3) | ||
356 | { | ||
357 | if (lis3->reg_ctrl) | ||
358 | lis3_context_save(lis3); | ||
359 | /* disable X,Y,Z axis and power down */ | ||
360 | lis3->write(lis3, CTRL_REG1, 0x00); | ||
361 | if (lis3->reg_ctrl) | ||
362 | lis3->reg_ctrl(lis3, LIS3_REG_OFF); | ||
363 | } | ||
364 | EXPORT_SYMBOL_GPL(lis3lv02d_poweroff); | ||
365 | |||
366 | void lis3lv02d_poweron(struct lis3lv02d *lis3) | ||
367 | { | ||
368 | u8 reg; | ||
369 | |||
370 | lis3->init(lis3); | ||
371 | |||
372 | /* | ||
373 | * Common configuration | ||
374 | * BDU: (12 bits sensors only) LSB and MSB values are not updated until | ||
375 | * both have been read. So the value read will always be correct. | ||
376 | * Set BOOT bit to refresh factory tuning values. | ||
377 | */ | ||
378 | lis3->read(lis3, CTRL_REG2, ®); | ||
379 | if (lis3->whoami == WAI_12B) | ||
380 | reg |= CTRL2_BDU | CTRL2_BOOT; | ||
381 | else | ||
382 | reg |= CTRL2_BOOT_8B; | ||
383 | lis3->write(lis3, CTRL_REG2, reg); | ||
384 | |||
385 | /* LIS3 power on delay is quite long */ | ||
386 | msleep(lis3->pwron_delay / lis3lv02d_get_odr()); | ||
387 | |||
388 | if (lis3->reg_ctrl) | ||
389 | lis3_context_restore(lis3); | ||
390 | } | ||
391 | EXPORT_SYMBOL_GPL(lis3lv02d_poweron); | ||
392 | |||
393 | |||
394 | static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev) | ||
395 | { | ||
396 | int x, y, z; | ||
397 | |||
398 | mutex_lock(&lis3_dev.mutex); | ||
399 | lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); | ||
400 | input_report_abs(pidev->input, ABS_X, x); | ||
401 | input_report_abs(pidev->input, ABS_Y, y); | ||
402 | input_report_abs(pidev->input, ABS_Z, z); | ||
403 | input_sync(pidev->input); | ||
404 | mutex_unlock(&lis3_dev.mutex); | ||
405 | } | ||
406 | |||
407 | static void lis3lv02d_joystick_open(struct input_polled_dev *pidev) | ||
408 | { | ||
409 | if (lis3_dev.pm_dev) | ||
410 | pm_runtime_get_sync(lis3_dev.pm_dev); | ||
411 | |||
412 | if (lis3_dev.pdata && lis3_dev.whoami == WAI_8B && lis3_dev.idev) | ||
413 | atomic_set(&lis3_dev.wake_thread, 1); | ||
414 | /* | ||
415 | * Update coordinates for the case where poll interval is 0 and | ||
416 | * the chip in running purely under interrupt control | ||
417 | */ | ||
418 | lis3lv02d_joystick_poll(pidev); | ||
419 | } | ||
420 | |||
421 | static void lis3lv02d_joystick_close(struct input_polled_dev *pidev) | ||
422 | { | ||
423 | atomic_set(&lis3_dev.wake_thread, 0); | ||
424 | if (lis3_dev.pm_dev) | ||
425 | pm_runtime_put(lis3_dev.pm_dev); | ||
426 | } | ||
427 | |||
428 | static irqreturn_t lis302dl_interrupt(int irq, void *dummy) | ||
429 | { | ||
430 | if (!test_bit(0, &lis3_dev.misc_opened)) | ||
431 | goto out; | ||
432 | |||
433 | /* | ||
434 | * Be careful: on some HP laptops the bios force DD when on battery and | ||
435 | * the lid is closed. This leads to interrupts as soon as a little move | ||
436 | * is done. | ||
437 | */ | ||
438 | atomic_inc(&lis3_dev.count); | ||
439 | |||
440 | wake_up_interruptible(&lis3_dev.misc_wait); | ||
441 | kill_fasync(&lis3_dev.async_queue, SIGIO, POLL_IN); | ||
442 | out: | ||
443 | if (atomic_read(&lis3_dev.wake_thread)) | ||
444 | return IRQ_WAKE_THREAD; | ||
445 | return IRQ_HANDLED; | ||
446 | } | ||
447 | |||
448 | static void lis302dl_interrupt_handle_click(struct lis3lv02d *lis3) | ||
449 | { | ||
450 | struct input_dev *dev = lis3->idev->input; | ||
451 | u8 click_src; | ||
452 | |||
453 | mutex_lock(&lis3->mutex); | ||
454 | lis3->read(lis3, CLICK_SRC, &click_src); | ||
455 | |||
456 | if (click_src & CLICK_SINGLE_X) { | ||
457 | input_report_key(dev, lis3->mapped_btns[0], 1); | ||
458 | input_report_key(dev, lis3->mapped_btns[0], 0); | ||
459 | } | ||
460 | |||
461 | if (click_src & CLICK_SINGLE_Y) { | ||
462 | input_report_key(dev, lis3->mapped_btns[1], 1); | ||
463 | input_report_key(dev, lis3->mapped_btns[1], 0); | ||
464 | } | ||
465 | |||
466 | if (click_src & CLICK_SINGLE_Z) { | ||
467 | input_report_key(dev, lis3->mapped_btns[2], 1); | ||
468 | input_report_key(dev, lis3->mapped_btns[2], 0); | ||
469 | } | ||
470 | input_sync(dev); | ||
471 | mutex_unlock(&lis3->mutex); | ||
472 | } | ||
473 | |||
474 | static inline void lis302dl_data_ready(struct lis3lv02d *lis3, int index) | ||
475 | { | ||
476 | int dummy; | ||
477 | |||
478 | /* Dummy read to ack interrupt */ | ||
479 | lis3lv02d_get_xyz(lis3, &dummy, &dummy, &dummy); | ||
480 | lis3->data_ready_count[index]++; | ||
481 | } | ||
482 | |||
483 | static irqreturn_t lis302dl_interrupt_thread1_8b(int irq, void *data) | ||
484 | { | ||
485 | struct lis3lv02d *lis3 = data; | ||
486 | u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ1_MASK; | ||
487 | |||
488 | if (irq_cfg == LIS3_IRQ1_CLICK) | ||
489 | lis302dl_interrupt_handle_click(lis3); | ||
490 | else if (unlikely(irq_cfg == LIS3_IRQ1_DATA_READY)) | ||
491 | lis302dl_data_ready(lis3, IRQ_LINE0); | ||
492 | else | ||
493 | lis3lv02d_joystick_poll(lis3->idev); | ||
494 | |||
495 | return IRQ_HANDLED; | ||
496 | } | ||
497 | |||
498 | static irqreturn_t lis302dl_interrupt_thread2_8b(int irq, void *data) | ||
499 | { | ||
500 | struct lis3lv02d *lis3 = data; | ||
501 | u8 irq_cfg = lis3->irq_cfg & LIS3_IRQ2_MASK; | ||
502 | |||
503 | if (irq_cfg == LIS3_IRQ2_CLICK) | ||
504 | lis302dl_interrupt_handle_click(lis3); | ||
505 | else if (unlikely(irq_cfg == LIS3_IRQ2_DATA_READY)) | ||
506 | lis302dl_data_ready(lis3, IRQ_LINE1); | ||
507 | else | ||
508 | lis3lv02d_joystick_poll(lis3->idev); | ||
509 | |||
510 | return IRQ_HANDLED; | ||
511 | } | ||
512 | |||
513 | static int lis3lv02d_misc_open(struct inode *inode, struct file *file) | ||
514 | { | ||
515 | if (test_and_set_bit(0, &lis3_dev.misc_opened)) | ||
516 | return -EBUSY; /* already open */ | ||
517 | |||
518 | if (lis3_dev.pm_dev) | ||
519 | pm_runtime_get_sync(lis3_dev.pm_dev); | ||
520 | |||
521 | atomic_set(&lis3_dev.count, 0); | ||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | static int lis3lv02d_misc_release(struct inode *inode, struct file *file) | ||
526 | { | ||
527 | fasync_helper(-1, file, 0, &lis3_dev.async_queue); | ||
528 | clear_bit(0, &lis3_dev.misc_opened); /* release the device */ | ||
529 | if (lis3_dev.pm_dev) | ||
530 | pm_runtime_put(lis3_dev.pm_dev); | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf, | ||
535 | size_t count, loff_t *pos) | ||
536 | { | ||
537 | DECLARE_WAITQUEUE(wait, current); | ||
538 | u32 data; | ||
539 | unsigned char byte_data; | ||
540 | ssize_t retval = 1; | ||
541 | |||
542 | if (count < 1) | ||
543 | return -EINVAL; | ||
544 | |||
545 | add_wait_queue(&lis3_dev.misc_wait, &wait); | ||
546 | while (true) { | ||
547 | set_current_state(TASK_INTERRUPTIBLE); | ||
548 | data = atomic_xchg(&lis3_dev.count, 0); | ||
549 | if (data) | ||
550 | break; | ||
551 | |||
552 | if (file->f_flags & O_NONBLOCK) { | ||
553 | retval = -EAGAIN; | ||
554 | goto out; | ||
555 | } | ||
556 | |||
557 | if (signal_pending(current)) { | ||
558 | retval = -ERESTARTSYS; | ||
559 | goto out; | ||
560 | } | ||
561 | |||
562 | schedule(); | ||
563 | } | ||
564 | |||
565 | if (data < 255) | ||
566 | byte_data = data; | ||
567 | else | ||
568 | byte_data = 255; | ||
569 | |||
570 | /* make sure we are not going into copy_to_user() with | ||
571 | * TASK_INTERRUPTIBLE state */ | ||
572 | set_current_state(TASK_RUNNING); | ||
573 | if (copy_to_user(buf, &byte_data, sizeof(byte_data))) | ||
574 | retval = -EFAULT; | ||
575 | |||
576 | out: | ||
577 | __set_current_state(TASK_RUNNING); | ||
578 | remove_wait_queue(&lis3_dev.misc_wait, &wait); | ||
579 | |||
580 | return retval; | ||
581 | } | ||
582 | |||
583 | static unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait) | ||
584 | { | ||
585 | poll_wait(file, &lis3_dev.misc_wait, wait); | ||
586 | if (atomic_read(&lis3_dev.count)) | ||
587 | return POLLIN | POLLRDNORM; | ||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | static int lis3lv02d_misc_fasync(int fd, struct file *file, int on) | ||
592 | { | ||
593 | return fasync_helper(fd, file, on, &lis3_dev.async_queue); | ||
594 | } | ||
595 | |||
596 | static const struct file_operations lis3lv02d_misc_fops = { | ||
597 | .owner = THIS_MODULE, | ||
598 | .llseek = no_llseek, | ||
599 | .read = lis3lv02d_misc_read, | ||
600 | .open = lis3lv02d_misc_open, | ||
601 | .release = lis3lv02d_misc_release, | ||
602 | .poll = lis3lv02d_misc_poll, | ||
603 | .fasync = lis3lv02d_misc_fasync, | ||
604 | }; | ||
605 | |||
606 | static struct miscdevice lis3lv02d_misc_device = { | ||
607 | .minor = MISC_DYNAMIC_MINOR, | ||
608 | .name = "freefall", | ||
609 | .fops = &lis3lv02d_misc_fops, | ||
610 | }; | ||
611 | |||
612 | int lis3lv02d_joystick_enable(void) | ||
613 | { | ||
614 | struct input_dev *input_dev; | ||
615 | int err; | ||
616 | int max_val, fuzz, flat; | ||
617 | int btns[] = {BTN_X, BTN_Y, BTN_Z}; | ||
618 | |||
619 | if (lis3_dev.idev) | ||
620 | return -EINVAL; | ||
621 | |||
622 | lis3_dev.idev = input_allocate_polled_device(); | ||
623 | if (!lis3_dev.idev) | ||
624 | return -ENOMEM; | ||
625 | |||
626 | lis3_dev.idev->poll = lis3lv02d_joystick_poll; | ||
627 | lis3_dev.idev->open = lis3lv02d_joystick_open; | ||
628 | lis3_dev.idev->close = lis3lv02d_joystick_close; | ||
629 | lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL; | ||
630 | lis3_dev.idev->poll_interval_min = MDPS_POLL_MIN; | ||
631 | lis3_dev.idev->poll_interval_max = MDPS_POLL_MAX; | ||
632 | input_dev = lis3_dev.idev->input; | ||
633 | |||
634 | input_dev->name = "ST LIS3LV02DL Accelerometer"; | ||
635 | input_dev->phys = DRIVER_NAME "/input0"; | ||
636 | input_dev->id.bustype = BUS_HOST; | ||
637 | input_dev->id.vendor = 0; | ||
638 | input_dev->dev.parent = &lis3_dev.pdev->dev; | ||
639 | |||
640 | set_bit(EV_ABS, input_dev->evbit); | ||
641 | max_val = (lis3_dev.mdps_max_val * lis3_dev.scale) / LIS3_ACCURACY; | ||
642 | if (lis3_dev.whoami == WAI_12B) { | ||
643 | fuzz = LIS3_DEFAULT_FUZZ_12B; | ||
644 | flat = LIS3_DEFAULT_FLAT_12B; | ||
645 | } else { | ||
646 | fuzz = LIS3_DEFAULT_FUZZ_8B; | ||
647 | flat = LIS3_DEFAULT_FLAT_8B; | ||
648 | } | ||
649 | fuzz = (fuzz * lis3_dev.scale) / LIS3_ACCURACY; | ||
650 | flat = (flat * lis3_dev.scale) / LIS3_ACCURACY; | ||
651 | |||
652 | input_set_abs_params(input_dev, ABS_X, -max_val, max_val, fuzz, flat); | ||
653 | input_set_abs_params(input_dev, ABS_Y, -max_val, max_val, fuzz, flat); | ||
654 | input_set_abs_params(input_dev, ABS_Z, -max_val, max_val, fuzz, flat); | ||
655 | |||
656 | lis3_dev.mapped_btns[0] = lis3lv02d_get_axis(abs(lis3_dev.ac.x), btns); | ||
657 | lis3_dev.mapped_btns[1] = lis3lv02d_get_axis(abs(lis3_dev.ac.y), btns); | ||
658 | lis3_dev.mapped_btns[2] = lis3lv02d_get_axis(abs(lis3_dev.ac.z), btns); | ||
659 | |||
660 | err = input_register_polled_device(lis3_dev.idev); | ||
661 | if (err) { | ||
662 | input_free_polled_device(lis3_dev.idev); | ||
663 | lis3_dev.idev = NULL; | ||
664 | } | ||
665 | |||
666 | return err; | ||
667 | } | ||
668 | EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable); | ||
669 | |||
670 | void lis3lv02d_joystick_disable(void) | ||
671 | { | ||
672 | if (lis3_dev.irq) | ||
673 | free_irq(lis3_dev.irq, &lis3_dev); | ||
674 | if (lis3_dev.pdata && lis3_dev.pdata->irq2) | ||
675 | free_irq(lis3_dev.pdata->irq2, &lis3_dev); | ||
676 | |||
677 | if (!lis3_dev.idev) | ||
678 | return; | ||
679 | |||
680 | if (lis3_dev.irq) | ||
681 | misc_deregister(&lis3lv02d_misc_device); | ||
682 | input_unregister_polled_device(lis3_dev.idev); | ||
683 | input_free_polled_device(lis3_dev.idev); | ||
684 | lis3_dev.idev = NULL; | ||
685 | } | ||
686 | EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); | ||
687 | |||
688 | /* Sysfs stuff */ | ||
689 | static void lis3lv02d_sysfs_poweron(struct lis3lv02d *lis3) | ||
690 | { | ||
691 | /* | ||
692 | * SYSFS functions are fast visitors so put-call | ||
693 | * immediately after the get-call. However, keep | ||
694 | * chip running for a while and schedule delayed | ||
695 | * suspend. This way periodic sysfs calls doesn't | ||
696 | * suffer from relatively long power up time. | ||
697 | */ | ||
698 | |||
699 | if (lis3->pm_dev) { | ||
700 | pm_runtime_get_sync(lis3->pm_dev); | ||
701 | pm_runtime_put_noidle(lis3->pm_dev); | ||
702 | pm_schedule_suspend(lis3->pm_dev, LIS3_SYSFS_POWERDOWN_DELAY); | ||
703 | } | ||
704 | } | ||
705 | |||
706 | static ssize_t lis3lv02d_selftest_show(struct device *dev, | ||
707 | struct device_attribute *attr, char *buf) | ||
708 | { | ||
709 | s16 values[3]; | ||
710 | |||
711 | static const char ok[] = "OK"; | ||
712 | static const char fail[] = "FAIL"; | ||
713 | static const char irq[] = "FAIL_IRQ"; | ||
714 | const char *res; | ||
715 | |||
716 | lis3lv02d_sysfs_poweron(&lis3_dev); | ||
717 | switch (lis3lv02d_selftest(&lis3_dev, values)) { | ||
718 | case SELFTEST_FAIL: | ||
719 | res = fail; | ||
720 | break; | ||
721 | case SELFTEST_IRQ: | ||
722 | res = irq; | ||
723 | break; | ||
724 | case SELFTEST_OK: | ||
725 | default: | ||
726 | res = ok; | ||
727 | break; | ||
728 | } | ||
729 | return sprintf(buf, "%s %d %d %d\n", res, | ||
730 | values[0], values[1], values[2]); | ||
731 | } | ||
732 | |||
733 | static ssize_t lis3lv02d_position_show(struct device *dev, | ||
734 | struct device_attribute *attr, char *buf) | ||
735 | { | ||
736 | int x, y, z; | ||
737 | |||
738 | lis3lv02d_sysfs_poweron(&lis3_dev); | ||
739 | mutex_lock(&lis3_dev.mutex); | ||
740 | lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z); | ||
741 | mutex_unlock(&lis3_dev.mutex); | ||
742 | return sprintf(buf, "(%d,%d,%d)\n", x, y, z); | ||
743 | } | ||
744 | |||
745 | static ssize_t lis3lv02d_rate_show(struct device *dev, | ||
746 | struct device_attribute *attr, char *buf) | ||
747 | { | ||
748 | lis3lv02d_sysfs_poweron(&lis3_dev); | ||
749 | return sprintf(buf, "%d\n", lis3lv02d_get_odr()); | ||
750 | } | ||
751 | |||
752 | static ssize_t lis3lv02d_rate_set(struct device *dev, | ||
753 | struct device_attribute *attr, const char *buf, | ||
754 | size_t count) | ||
755 | { | ||
756 | unsigned long rate; | ||
757 | |||
758 | if (strict_strtoul(buf, 0, &rate)) | ||
759 | return -EINVAL; | ||
760 | |||
761 | lis3lv02d_sysfs_poweron(&lis3_dev); | ||
762 | if (lis3lv02d_set_odr(rate)) | ||
763 | return -EINVAL; | ||
764 | |||
765 | return count; | ||
766 | } | ||
767 | |||
768 | static DEVICE_ATTR(selftest, S_IRUSR, lis3lv02d_selftest_show, NULL); | ||
769 | static DEVICE_ATTR(position, S_IRUGO, lis3lv02d_position_show, NULL); | ||
770 | static DEVICE_ATTR(rate, S_IRUGO | S_IWUSR, lis3lv02d_rate_show, | ||
771 | lis3lv02d_rate_set); | ||
772 | |||
773 | static struct attribute *lis3lv02d_attributes[] = { | ||
774 | &dev_attr_selftest.attr, | ||
775 | &dev_attr_position.attr, | ||
776 | &dev_attr_rate.attr, | ||
777 | NULL | ||
778 | }; | ||
779 | |||
780 | static struct attribute_group lis3lv02d_attribute_group = { | ||
781 | .attrs = lis3lv02d_attributes | ||
782 | }; | ||
783 | |||
784 | |||
785 | static int lis3lv02d_add_fs(struct lis3lv02d *lis3) | ||
786 | { | ||
787 | lis3->pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); | ||
788 | if (IS_ERR(lis3->pdev)) | ||
789 | return PTR_ERR(lis3->pdev); | ||
790 | |||
791 | return sysfs_create_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group); | ||
792 | } | ||
793 | |||
794 | int lis3lv02d_remove_fs(struct lis3lv02d *lis3) | ||
795 | { | ||
796 | sysfs_remove_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group); | ||
797 | platform_device_unregister(lis3->pdev); | ||
798 | if (lis3->pm_dev) { | ||
799 | /* Barrier after the sysfs remove */ | ||
800 | pm_runtime_barrier(lis3->pm_dev); | ||
801 | |||
802 | /* SYSFS may have left chip running. Turn off if necessary */ | ||
803 | if (!pm_runtime_suspended(lis3->pm_dev)) | ||
804 | lis3lv02d_poweroff(&lis3_dev); | ||
805 | |||
806 | pm_runtime_disable(lis3->pm_dev); | ||
807 | pm_runtime_set_suspended(lis3->pm_dev); | ||
808 | } | ||
809 | kfree(lis3->reg_cache); | ||
810 | return 0; | ||
811 | } | ||
812 | EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs); | ||
813 | |||
814 | static void lis3lv02d_8b_configure(struct lis3lv02d *dev, | ||
815 | struct lis3lv02d_platform_data *p) | ||
816 | { | ||
817 | int err; | ||
818 | int ctrl2 = p->hipass_ctrl; | ||
819 | |||
820 | if (p->click_flags) { | ||
821 | dev->write(dev, CLICK_CFG, p->click_flags); | ||
822 | dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit); | ||
823 | dev->write(dev, CLICK_LATENCY, p->click_latency); | ||
824 | dev->write(dev, CLICK_WINDOW, p->click_window); | ||
825 | dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf); | ||
826 | dev->write(dev, CLICK_THSY_X, | ||
827 | (p->click_thresh_x & 0xf) | | ||
828 | (p->click_thresh_y << 4)); | ||
829 | |||
830 | if (dev->idev) { | ||
831 | struct input_dev *input_dev = lis3_dev.idev->input; | ||
832 | input_set_capability(input_dev, EV_KEY, BTN_X); | ||
833 | input_set_capability(input_dev, EV_KEY, BTN_Y); | ||
834 | input_set_capability(input_dev, EV_KEY, BTN_Z); | ||
835 | } | ||
836 | } | ||
837 | |||
838 | if (p->wakeup_flags) { | ||
839 | dev->write(dev, FF_WU_CFG_1, p->wakeup_flags); | ||
840 | dev->write(dev, FF_WU_THS_1, p->wakeup_thresh & 0x7f); | ||
841 | /* pdata value + 1 to keep this backward compatible*/ | ||
842 | dev->write(dev, FF_WU_DURATION_1, p->duration1 + 1); | ||
843 | ctrl2 ^= HP_FF_WU1; /* Xor to keep compatible with old pdata*/ | ||
844 | } | ||
845 | |||
846 | if (p->wakeup_flags2) { | ||
847 | dev->write(dev, FF_WU_CFG_2, p->wakeup_flags2); | ||
848 | dev->write(dev, FF_WU_THS_2, p->wakeup_thresh2 & 0x7f); | ||
849 | /* pdata value + 1 to keep this backward compatible*/ | ||
850 | dev->write(dev, FF_WU_DURATION_2, p->duration2 + 1); | ||
851 | ctrl2 ^= HP_FF_WU2; /* Xor to keep compatible with old pdata*/ | ||
852 | } | ||
853 | /* Configure hipass filters */ | ||
854 | dev->write(dev, CTRL_REG2, ctrl2); | ||
855 | |||
856 | if (p->irq2) { | ||
857 | err = request_threaded_irq(p->irq2, | ||
858 | NULL, | ||
859 | lis302dl_interrupt_thread2_8b, | ||
860 | IRQF_TRIGGER_RISING | IRQF_ONESHOT | | ||
861 | (p->irq_flags2 & IRQF_TRIGGER_MASK), | ||
862 | DRIVER_NAME, &lis3_dev); | ||
863 | if (err < 0) | ||
864 | pr_err("No second IRQ. Limited functionality\n"); | ||
865 | } | ||
866 | } | ||
867 | |||
868 | /* | ||
869 | * Initialise the accelerometer and the various subsystems. | ||
870 | * Should be rather independent of the bus system. | ||
871 | */ | ||
872 | int lis3lv02d_init_device(struct lis3lv02d *dev) | ||
873 | { | ||
874 | int err; | ||
875 | irq_handler_t thread_fn; | ||
876 | int irq_flags = 0; | ||
877 | |||
878 | dev->whoami = lis3lv02d_read_8(dev, WHO_AM_I); | ||
879 | |||
880 | switch (dev->whoami) { | ||
881 | case WAI_12B: | ||
882 | pr_info("12 bits sensor found\n"); | ||
883 | dev->read_data = lis3lv02d_read_12; | ||
884 | dev->mdps_max_val = 2048; | ||
885 | dev->pwron_delay = LIS3_PWRON_DELAY_WAI_12B; | ||
886 | dev->odrs = lis3_12_rates; | ||
887 | dev->odr_mask = CTRL1_DF0 | CTRL1_DF1; | ||
888 | dev->scale = LIS3_SENSITIVITY_12B; | ||
889 | dev->regs = lis3_wai12_regs; | ||
890 | dev->regs_size = ARRAY_SIZE(lis3_wai12_regs); | ||
891 | break; | ||
892 | case WAI_8B: | ||
893 | pr_info("8 bits sensor found\n"); | ||
894 | dev->read_data = lis3lv02d_read_8; | ||
895 | dev->mdps_max_val = 128; | ||
896 | dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B; | ||
897 | dev->odrs = lis3_8_rates; | ||
898 | dev->odr_mask = CTRL1_DR; | ||
899 | dev->scale = LIS3_SENSITIVITY_8B; | ||
900 | dev->regs = lis3_wai8_regs; | ||
901 | dev->regs_size = ARRAY_SIZE(lis3_wai8_regs); | ||
902 | break; | ||
903 | case WAI_3DC: | ||
904 | pr_info("8 bits 3DC sensor found\n"); | ||
905 | dev->read_data = lis3lv02d_read_8; | ||
906 | dev->mdps_max_val = 128; | ||
907 | dev->pwron_delay = LIS3_PWRON_DELAY_WAI_8B; | ||
908 | dev->odrs = lis3_3dc_rates; | ||
909 | dev->odr_mask = CTRL1_ODR0|CTRL1_ODR1|CTRL1_ODR2|CTRL1_ODR3; | ||
910 | dev->scale = LIS3_SENSITIVITY_8B; | ||
911 | break; | ||
912 | default: | ||
913 | pr_err("unknown sensor type 0x%X\n", dev->whoami); | ||
914 | return -EINVAL; | ||
915 | } | ||
916 | |||
917 | dev->reg_cache = kzalloc(max(sizeof(lis3_wai8_regs), | ||
918 | sizeof(lis3_wai12_regs)), GFP_KERNEL); | ||
919 | |||
920 | if (dev->reg_cache == NULL) { | ||
921 | printk(KERN_ERR DRIVER_NAME "out of memory\n"); | ||
922 | return -ENOMEM; | ||
923 | } | ||
924 | |||
925 | mutex_init(&dev->mutex); | ||
926 | atomic_set(&dev->wake_thread, 0); | ||
927 | |||
928 | lis3lv02d_add_fs(dev); | ||
929 | lis3lv02d_poweron(dev); | ||
930 | |||
931 | if (dev->pm_dev) { | ||
932 | pm_runtime_set_active(dev->pm_dev); | ||
933 | pm_runtime_enable(dev->pm_dev); | ||
934 | } | ||
935 | |||
936 | if (lis3lv02d_joystick_enable()) | ||
937 | pr_err("joystick initialization failed\n"); | ||
938 | |||
939 | /* passing in platform specific data is purely optional and only | ||
940 | * used by the SPI transport layer at the moment */ | ||
941 | if (dev->pdata) { | ||
942 | struct lis3lv02d_platform_data *p = dev->pdata; | ||
943 | |||
944 | if (dev->whoami == WAI_8B) | ||
945 | lis3lv02d_8b_configure(dev, p); | ||
946 | |||
947 | irq_flags = p->irq_flags1 & IRQF_TRIGGER_MASK; | ||
948 | |||
949 | dev->irq_cfg = p->irq_cfg; | ||
950 | if (p->irq_cfg) | ||
951 | dev->write(dev, CTRL_REG3, p->irq_cfg); | ||
952 | |||
953 | if (p->default_rate) | ||
954 | lis3lv02d_set_odr(p->default_rate); | ||
955 | } | ||
956 | |||
957 | /* bail if we did not get an IRQ from the bus layer */ | ||
958 | if (!dev->irq) { | ||
959 | pr_debug("No IRQ. Disabling /dev/freefall\n"); | ||
960 | goto out; | ||
961 | } | ||
962 | |||
963 | /* | ||
964 | * The sensor can generate interrupts for free-fall and direction | ||
965 | * detection (distinguishable with FF_WU_SRC and DD_SRC) but to keep | ||
966 | * the things simple and _fast_ we activate it only for free-fall, so | ||
967 | * no need to read register (very slow with ACPI). For the same reason, | ||
968 | * we forbid shared interrupts. | ||
969 | * | ||
970 | * IRQF_TRIGGER_RISING seems pointless on HP laptops because the | ||
971 | * io-apic is not configurable (and generates a warning) but I keep it | ||
972 | * in case of support for other hardware. | ||
973 | */ | ||
974 | if (dev->pdata && dev->whoami == WAI_8B) | ||
975 | thread_fn = lis302dl_interrupt_thread1_8b; | ||
976 | else | ||
977 | thread_fn = NULL; | ||
978 | |||
979 | err = request_threaded_irq(dev->irq, lis302dl_interrupt, | ||
980 | thread_fn, | ||
981 | IRQF_TRIGGER_RISING | IRQF_ONESHOT | | ||
982 | irq_flags, | ||
983 | DRIVER_NAME, &lis3_dev); | ||
984 | |||
985 | if (err < 0) { | ||
986 | pr_err("Cannot get IRQ\n"); | ||
987 | goto out; | ||
988 | } | ||
989 | |||
990 | if (misc_register(&lis3lv02d_misc_device)) | ||
991 | pr_err("misc_register failed\n"); | ||
992 | out: | ||
993 | return 0; | ||
994 | } | ||
995 | EXPORT_SYMBOL_GPL(lis3lv02d_init_device); | ||
996 | |||
997 | MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver"); | ||
998 | MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); | ||
999 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/misc/lis3lv02d/lis3lv02d.h b/drivers/misc/lis3lv02d/lis3lv02d.h new file mode 100644 index 000000000000..a1939589eb2c --- /dev/null +++ b/drivers/misc/lis3lv02d/lis3lv02d.h | |||
@@ -0,0 +1,291 @@ | |||
1 | /* | ||
2 | * lis3lv02d.h - ST LIS3LV02DL accelerometer driver | ||
3 | * | ||
4 | * Copyright (C) 2007-2008 Yan Burman | ||
5 | * Copyright (C) 2008-2009 Eric Piel | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/input-polldev.h> | ||
23 | #include <linux/regulator/consumer.h> | ||
24 | |||
25 | /* | ||
26 | * This driver tries to support the "digital" accelerometer chips from | ||
27 | * STMicroelectronics such as LIS3LV02DL, LIS302DL, LIS3L02DQ, LIS331DL, | ||
28 | * LIS35DE, or LIS202DL. They are very similar in terms of programming, with | ||
29 | * almost the same registers. In addition to differing on physical properties, | ||
30 | * they differ on the number of axes (2/3), precision (8/12 bits), and special | ||
31 | * features (freefall detection, click...). Unfortunately, not all the | ||
32 | * differences can be probed via a register. | ||
33 | * They can be connected either via I²C or SPI. | ||
34 | */ | ||
35 | |||
36 | #include <linux/lis3lv02d.h> | ||
37 | |||
38 | enum lis3_reg { | ||
39 | WHO_AM_I = 0x0F, | ||
40 | OFFSET_X = 0x16, | ||
41 | OFFSET_Y = 0x17, | ||
42 | OFFSET_Z = 0x18, | ||
43 | GAIN_X = 0x19, | ||
44 | GAIN_Y = 0x1A, | ||
45 | GAIN_Z = 0x1B, | ||
46 | CTRL_REG1 = 0x20, | ||
47 | CTRL_REG2 = 0x21, | ||
48 | CTRL_REG3 = 0x22, | ||
49 | CTRL_REG4 = 0x23, | ||
50 | HP_FILTER_RESET = 0x23, | ||
51 | STATUS_REG = 0x27, | ||
52 | OUTX_L = 0x28, | ||
53 | OUTX_H = 0x29, | ||
54 | OUTX = 0x29, | ||
55 | OUTY_L = 0x2A, | ||
56 | OUTY_H = 0x2B, | ||
57 | OUTY = 0x2B, | ||
58 | OUTZ_L = 0x2C, | ||
59 | OUTZ_H = 0x2D, | ||
60 | OUTZ = 0x2D, | ||
61 | }; | ||
62 | |||
63 | enum lis302d_reg { | ||
64 | FF_WU_CFG_1 = 0x30, | ||
65 | FF_WU_SRC_1 = 0x31, | ||
66 | FF_WU_THS_1 = 0x32, | ||
67 | FF_WU_DURATION_1 = 0x33, | ||
68 | FF_WU_CFG_2 = 0x34, | ||
69 | FF_WU_SRC_2 = 0x35, | ||
70 | FF_WU_THS_2 = 0x36, | ||
71 | FF_WU_DURATION_2 = 0x37, | ||
72 | CLICK_CFG = 0x38, | ||
73 | CLICK_SRC = 0x39, | ||
74 | CLICK_THSY_X = 0x3B, | ||
75 | CLICK_THSZ = 0x3C, | ||
76 | CLICK_TIMELIMIT = 0x3D, | ||
77 | CLICK_LATENCY = 0x3E, | ||
78 | CLICK_WINDOW = 0x3F, | ||
79 | }; | ||
80 | |||
81 | enum lis3lv02d_reg { | ||
82 | FF_WU_CFG = 0x30, | ||
83 | FF_WU_SRC = 0x31, | ||
84 | FF_WU_ACK = 0x32, | ||
85 | FF_WU_THS_L = 0x34, | ||
86 | FF_WU_THS_H = 0x35, | ||
87 | FF_WU_DURATION = 0x36, | ||
88 | DD_CFG = 0x38, | ||
89 | DD_SRC = 0x39, | ||
90 | DD_ACK = 0x3A, | ||
91 | DD_THSI_L = 0x3C, | ||
92 | DD_THSI_H = 0x3D, | ||
93 | DD_THSE_L = 0x3E, | ||
94 | DD_THSE_H = 0x3F, | ||
95 | }; | ||
96 | |||
97 | enum lis3_who_am_i { | ||
98 | WAI_3DC = 0x33, /* 8 bits: LIS3DC, HP3DC */ | ||
99 | WAI_12B = 0x3A, /* 12 bits: LIS3LV02D[LQ]... */ | ||
100 | WAI_8B = 0x3B, /* 8 bits: LIS[23]02D[LQ]... */ | ||
101 | WAI_6B = 0x52, /* 6 bits: LIS331DLF - not supported */ | ||
102 | }; | ||
103 | |||
104 | enum lis3lv02d_ctrl1_12b { | ||
105 | CTRL1_Xen = 0x01, | ||
106 | CTRL1_Yen = 0x02, | ||
107 | CTRL1_Zen = 0x04, | ||
108 | CTRL1_ST = 0x08, | ||
109 | CTRL1_DF0 = 0x10, | ||
110 | CTRL1_DF1 = 0x20, | ||
111 | CTRL1_PD0 = 0x40, | ||
112 | CTRL1_PD1 = 0x80, | ||
113 | }; | ||
114 | |||
115 | /* Delta to ctrl1_12b version */ | ||
116 | enum lis3lv02d_ctrl1_8b { | ||
117 | CTRL1_STM = 0x08, | ||
118 | CTRL1_STP = 0x10, | ||
119 | CTRL1_FS = 0x20, | ||
120 | CTRL1_PD = 0x40, | ||
121 | CTRL1_DR = 0x80, | ||
122 | }; | ||
123 | |||
124 | enum lis3lv02d_ctrl1_3dc { | ||
125 | CTRL1_ODR0 = 0x10, | ||
126 | CTRL1_ODR1 = 0x20, | ||
127 | CTRL1_ODR2 = 0x40, | ||
128 | CTRL1_ODR3 = 0x80, | ||
129 | }; | ||
130 | |||
131 | enum lis3lv02d_ctrl2 { | ||
132 | CTRL2_DAS = 0x01, | ||
133 | CTRL2_SIM = 0x02, | ||
134 | CTRL2_DRDY = 0x04, | ||
135 | CTRL2_IEN = 0x08, | ||
136 | CTRL2_BOOT = 0x10, | ||
137 | CTRL2_BLE = 0x20, | ||
138 | CTRL2_BDU = 0x40, /* Block Data Update */ | ||
139 | CTRL2_FS = 0x80, /* Full Scale selection */ | ||
140 | }; | ||
141 | |||
142 | enum lis3lv02d_ctrl4_3dc { | ||
143 | CTRL4_SIM = 0x01, | ||
144 | CTRL4_ST0 = 0x02, | ||
145 | CTRL4_ST1 = 0x04, | ||
146 | CTRL4_FS0 = 0x10, | ||
147 | CTRL4_FS1 = 0x20, | ||
148 | }; | ||
149 | |||
150 | enum lis302d_ctrl2 { | ||
151 | HP_FF_WU2 = 0x08, | ||
152 | HP_FF_WU1 = 0x04, | ||
153 | CTRL2_BOOT_8B = 0x40, | ||
154 | }; | ||
155 | |||
156 | enum lis3lv02d_ctrl3 { | ||
157 | CTRL3_CFS0 = 0x01, | ||
158 | CTRL3_CFS1 = 0x02, | ||
159 | CTRL3_FDS = 0x10, | ||
160 | CTRL3_HPFF = 0x20, | ||
161 | CTRL3_HPDD = 0x40, | ||
162 | CTRL3_ECK = 0x80, | ||
163 | }; | ||
164 | |||
165 | enum lis3lv02d_status_reg { | ||
166 | STATUS_XDA = 0x01, | ||
167 | STATUS_YDA = 0x02, | ||
168 | STATUS_ZDA = 0x04, | ||
169 | STATUS_XYZDA = 0x08, | ||
170 | STATUS_XOR = 0x10, | ||
171 | STATUS_YOR = 0x20, | ||
172 | STATUS_ZOR = 0x40, | ||
173 | STATUS_XYZOR = 0x80, | ||
174 | }; | ||
175 | |||
176 | enum lis3lv02d_ff_wu_cfg { | ||
177 | FF_WU_CFG_XLIE = 0x01, | ||
178 | FF_WU_CFG_XHIE = 0x02, | ||
179 | FF_WU_CFG_YLIE = 0x04, | ||
180 | FF_WU_CFG_YHIE = 0x08, | ||
181 | FF_WU_CFG_ZLIE = 0x10, | ||
182 | FF_WU_CFG_ZHIE = 0x20, | ||
183 | FF_WU_CFG_LIR = 0x40, | ||
184 | FF_WU_CFG_AOI = 0x80, | ||
185 | }; | ||
186 | |||
187 | enum lis3lv02d_ff_wu_src { | ||
188 | FF_WU_SRC_XL = 0x01, | ||
189 | FF_WU_SRC_XH = 0x02, | ||
190 | FF_WU_SRC_YL = 0x04, | ||
191 | FF_WU_SRC_YH = 0x08, | ||
192 | FF_WU_SRC_ZL = 0x10, | ||
193 | FF_WU_SRC_ZH = 0x20, | ||
194 | FF_WU_SRC_IA = 0x40, | ||
195 | }; | ||
196 | |||
197 | enum lis3lv02d_dd_cfg { | ||
198 | DD_CFG_XLIE = 0x01, | ||
199 | DD_CFG_XHIE = 0x02, | ||
200 | DD_CFG_YLIE = 0x04, | ||
201 | DD_CFG_YHIE = 0x08, | ||
202 | DD_CFG_ZLIE = 0x10, | ||
203 | DD_CFG_ZHIE = 0x20, | ||
204 | DD_CFG_LIR = 0x40, | ||
205 | DD_CFG_IEND = 0x80, | ||
206 | }; | ||
207 | |||
208 | enum lis3lv02d_dd_src { | ||
209 | DD_SRC_XL = 0x01, | ||
210 | DD_SRC_XH = 0x02, | ||
211 | DD_SRC_YL = 0x04, | ||
212 | DD_SRC_YH = 0x08, | ||
213 | DD_SRC_ZL = 0x10, | ||
214 | DD_SRC_ZH = 0x20, | ||
215 | DD_SRC_IA = 0x40, | ||
216 | }; | ||
217 | |||
218 | enum lis3lv02d_click_src_8b { | ||
219 | CLICK_SINGLE_X = 0x01, | ||
220 | CLICK_DOUBLE_X = 0x02, | ||
221 | CLICK_SINGLE_Y = 0x04, | ||
222 | CLICK_DOUBLE_Y = 0x08, | ||
223 | CLICK_SINGLE_Z = 0x10, | ||
224 | CLICK_DOUBLE_Z = 0x20, | ||
225 | CLICK_IA = 0x40, | ||
226 | }; | ||
227 | |||
228 | enum lis3lv02d_reg_state { | ||
229 | LIS3_REG_OFF = 0x00, | ||
230 | LIS3_REG_ON = 0x01, | ||
231 | }; | ||
232 | |||
233 | union axis_conversion { | ||
234 | struct { | ||
235 | int x, y, z; | ||
236 | }; | ||
237 | int as_array[3]; | ||
238 | |||
239 | }; | ||
240 | |||
241 | struct lis3lv02d { | ||
242 | void *bus_priv; /* used by the bus layer only */ | ||
243 | struct device *pm_dev; /* for pm_runtime purposes */ | ||
244 | int (*init) (struct lis3lv02d *lis3); | ||
245 | int (*write) (struct lis3lv02d *lis3, int reg, u8 val); | ||
246 | int (*read) (struct lis3lv02d *lis3, int reg, u8 *ret); | ||
247 | int (*blkread) (struct lis3lv02d *lis3, int reg, int len, u8 *ret); | ||
248 | int (*reg_ctrl) (struct lis3lv02d *lis3, bool state); | ||
249 | |||
250 | int *odrs; /* Supported output data rates */ | ||
251 | u8 *regs; /* Regs to store / restore */ | ||
252 | int regs_size; | ||
253 | u8 *reg_cache; | ||
254 | bool regs_stored; | ||
255 | u8 odr_mask; /* ODR bit mask */ | ||
256 | u8 whoami; /* indicates measurement precision */ | ||
257 | s16 (*read_data) (struct lis3lv02d *lis3, int reg); | ||
258 | int mdps_max_val; | ||
259 | int pwron_delay; | ||
260 | int scale; /* | ||
261 | * relationship between 1 LBS and mG | ||
262 | * (1/1000th of earth gravity) | ||
263 | */ | ||
264 | |||
265 | struct input_polled_dev *idev; /* input device */ | ||
266 | struct platform_device *pdev; /* platform device */ | ||
267 | struct regulator_bulk_data regulators[2]; | ||
268 | atomic_t count; /* interrupt count after last read */ | ||
269 | union axis_conversion ac; /* hw -> logical axis */ | ||
270 | int mapped_btns[3]; | ||
271 | |||
272 | u32 irq; /* IRQ number */ | ||
273 | struct fasync_struct *async_queue; /* queue for the misc device */ | ||
274 | wait_queue_head_t misc_wait; /* Wait queue for the misc device */ | ||
275 | unsigned long misc_opened; /* bit0: whether the device is open */ | ||
276 | int data_ready_count[2]; | ||
277 | atomic_t wake_thread; | ||
278 | unsigned char irq_cfg; | ||
279 | |||
280 | struct lis3lv02d_platform_data *pdata; /* for passing board config */ | ||
281 | struct mutex mutex; /* Serialize poll and selftest */ | ||
282 | }; | ||
283 | |||
284 | int lis3lv02d_init_device(struct lis3lv02d *lis3); | ||
285 | int lis3lv02d_joystick_enable(void); | ||
286 | void lis3lv02d_joystick_disable(void); | ||
287 | void lis3lv02d_poweroff(struct lis3lv02d *lis3); | ||
288 | void lis3lv02d_poweron(struct lis3lv02d *lis3); | ||
289 | int lis3lv02d_remove_fs(struct lis3lv02d *lis3); | ||
290 | |||
291 | extern struct lis3lv02d lis3_dev; | ||
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c new file mode 100644 index 000000000000..b20dfb4522d2 --- /dev/null +++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c | |||
@@ -0,0 +1,279 @@ | |||
1 | /* | ||
2 | * drivers/hwmon/lis3lv02d_i2c.c | ||
3 | * | ||
4 | * Implements I2C interface for lis3lv02d (STMicroelectronics) accelerometer. | ||
5 | * Driver is based on corresponding SPI driver written by Daniel Mack | ||
6 | * (lis3lv02d_spi.c (C) 2009 Daniel Mack <daniel@caiaq.de> ). | ||
7 | * | ||
8 | * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). | ||
9 | * | ||
10 | * Contact: Samu Onkalo <samu.p.onkalo@nokia.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * version 2 as published by the Free Software Foundation. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, but | ||
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
24 | * 02110-1301 USA | ||
25 | */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/err.h> | ||
31 | #include <linux/i2c.h> | ||
32 | #include <linux/pm_runtime.h> | ||
33 | #include <linux/delay.h> | ||
34 | #include "lis3lv02d.h" | ||
35 | |||
36 | #define DRV_NAME "lis3lv02d_i2c" | ||
37 | |||
38 | static const char reg_vdd[] = "Vdd"; | ||
39 | static const char reg_vdd_io[] = "Vdd_IO"; | ||
40 | |||
41 | static int lis3_reg_ctrl(struct lis3lv02d *lis3, bool state) | ||
42 | { | ||
43 | int ret; | ||
44 | if (state == LIS3_REG_OFF) { | ||
45 | ret = regulator_bulk_disable(ARRAY_SIZE(lis3->regulators), | ||
46 | lis3->regulators); | ||
47 | } else { | ||
48 | ret = regulator_bulk_enable(ARRAY_SIZE(lis3->regulators), | ||
49 | lis3->regulators); | ||
50 | /* Chip needs time to wakeup. Not mentioned in datasheet */ | ||
51 | usleep_range(10000, 20000); | ||
52 | } | ||
53 | return ret; | ||
54 | } | ||
55 | |||
56 | static inline s32 lis3_i2c_write(struct lis3lv02d *lis3, int reg, u8 value) | ||
57 | { | ||
58 | struct i2c_client *c = lis3->bus_priv; | ||
59 | return i2c_smbus_write_byte_data(c, reg, value); | ||
60 | } | ||
61 | |||
62 | static inline s32 lis3_i2c_read(struct lis3lv02d *lis3, int reg, u8 *v) | ||
63 | { | ||
64 | struct i2c_client *c = lis3->bus_priv; | ||
65 | *v = i2c_smbus_read_byte_data(c, reg); | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static inline s32 lis3_i2c_blockread(struct lis3lv02d *lis3, int reg, int len, | ||
70 | u8 *v) | ||
71 | { | ||
72 | struct i2c_client *c = lis3->bus_priv; | ||
73 | reg |= (1 << 7); /* 7th bit enables address auto incrementation */ | ||
74 | return i2c_smbus_read_i2c_block_data(c, reg, len, v); | ||
75 | } | ||
76 | |||
77 | static int lis3_i2c_init(struct lis3lv02d *lis3) | ||
78 | { | ||
79 | u8 reg; | ||
80 | int ret; | ||
81 | |||
82 | if (lis3->reg_ctrl) | ||
83 | lis3_reg_ctrl(lis3, LIS3_REG_ON); | ||
84 | |||
85 | lis3->read(lis3, WHO_AM_I, ®); | ||
86 | if (reg != lis3->whoami) | ||
87 | printk(KERN_ERR "lis3: power on failure\n"); | ||
88 | |||
89 | /* power up the device */ | ||
90 | ret = lis3->read(lis3, CTRL_REG1, ®); | ||
91 | if (ret < 0) | ||
92 | return ret; | ||
93 | |||
94 | reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen; | ||
95 | return lis3->write(lis3, CTRL_REG1, reg); | ||
96 | } | ||
97 | |||
98 | /* Default axis mapping but it can be overwritten by platform data */ | ||
99 | static union axis_conversion lis3lv02d_axis_map = | ||
100 | { .as_array = { LIS3_DEV_X, LIS3_DEV_Y, LIS3_DEV_Z } }; | ||
101 | |||
102 | static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client, | ||
103 | const struct i2c_device_id *id) | ||
104 | { | ||
105 | int ret = 0; | ||
106 | struct lis3lv02d_platform_data *pdata = client->dev.platform_data; | ||
107 | |||
108 | if (pdata) { | ||
109 | /* Regulator control is optional */ | ||
110 | if (pdata->driver_features & LIS3_USE_REGULATOR_CTRL) | ||
111 | lis3_dev.reg_ctrl = lis3_reg_ctrl; | ||
112 | |||
113 | if ((pdata->driver_features & LIS3_USE_BLOCK_READ) && | ||
114 | (i2c_check_functionality(client->adapter, | ||
115 | I2C_FUNC_SMBUS_I2C_BLOCK))) | ||
116 | lis3_dev.blkread = lis3_i2c_blockread; | ||
117 | |||
118 | if (pdata->axis_x) | ||
119 | lis3lv02d_axis_map.x = pdata->axis_x; | ||
120 | |||
121 | if (pdata->axis_y) | ||
122 | lis3lv02d_axis_map.y = pdata->axis_y; | ||
123 | |||
124 | if (pdata->axis_z) | ||
125 | lis3lv02d_axis_map.z = pdata->axis_z; | ||
126 | |||
127 | if (pdata->setup_resources) | ||
128 | ret = pdata->setup_resources(); | ||
129 | |||
130 | if (ret) | ||
131 | goto fail; | ||
132 | } | ||
133 | |||
134 | if (lis3_dev.reg_ctrl) { | ||
135 | lis3_dev.regulators[0].supply = reg_vdd; | ||
136 | lis3_dev.regulators[1].supply = reg_vdd_io; | ||
137 | ret = regulator_bulk_get(&client->dev, | ||
138 | ARRAY_SIZE(lis3_dev.regulators), | ||
139 | lis3_dev.regulators); | ||
140 | if (ret < 0) | ||
141 | goto fail; | ||
142 | } | ||
143 | |||
144 | lis3_dev.pdata = pdata; | ||
145 | lis3_dev.bus_priv = client; | ||
146 | lis3_dev.init = lis3_i2c_init; | ||
147 | lis3_dev.read = lis3_i2c_read; | ||
148 | lis3_dev.write = lis3_i2c_write; | ||
149 | lis3_dev.irq = client->irq; | ||
150 | lis3_dev.ac = lis3lv02d_axis_map; | ||
151 | lis3_dev.pm_dev = &client->dev; | ||
152 | |||
153 | i2c_set_clientdata(client, &lis3_dev); | ||
154 | |||
155 | /* Provide power over the init call */ | ||
156 | if (lis3_dev.reg_ctrl) | ||
157 | lis3_reg_ctrl(&lis3_dev, LIS3_REG_ON); | ||
158 | |||
159 | ret = lis3lv02d_init_device(&lis3_dev); | ||
160 | |||
161 | if (lis3_dev.reg_ctrl) | ||
162 | lis3_reg_ctrl(&lis3_dev, LIS3_REG_OFF); | ||
163 | |||
164 | if (ret == 0) | ||
165 | return 0; | ||
166 | fail: | ||
167 | if (pdata && pdata->release_resources) | ||
168 | pdata->release_resources(); | ||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client) | ||
173 | { | ||
174 | struct lis3lv02d *lis3 = i2c_get_clientdata(client); | ||
175 | struct lis3lv02d_platform_data *pdata = client->dev.platform_data; | ||
176 | |||
177 | if (pdata && pdata->release_resources) | ||
178 | pdata->release_resources(); | ||
179 | |||
180 | lis3lv02d_joystick_disable(); | ||
181 | lis3lv02d_remove_fs(&lis3_dev); | ||
182 | |||
183 | if (lis3_dev.reg_ctrl) | ||
184 | regulator_bulk_free(ARRAY_SIZE(lis3->regulators), | ||
185 | lis3_dev.regulators); | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | #ifdef CONFIG_PM_SLEEP | ||
190 | static int lis3lv02d_i2c_suspend(struct device *dev) | ||
191 | { | ||
192 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
193 | struct lis3lv02d *lis3 = i2c_get_clientdata(client); | ||
194 | |||
195 | if (!lis3->pdata || !lis3->pdata->wakeup_flags) | ||
196 | lis3lv02d_poweroff(lis3); | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static int lis3lv02d_i2c_resume(struct device *dev) | ||
201 | { | ||
202 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
203 | struct lis3lv02d *lis3 = i2c_get_clientdata(client); | ||
204 | |||
205 | /* | ||
206 | * pm_runtime documentation says that devices should always | ||
207 | * be powered on at resume. Pm_runtime turns them off after system | ||
208 | * wide resume is complete. | ||
209 | */ | ||
210 | if (!lis3->pdata || !lis3->pdata->wakeup_flags || | ||
211 | pm_runtime_suspended(dev)) | ||
212 | lis3lv02d_poweron(lis3); | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | #endif /* CONFIG_PM_SLEEP */ | ||
217 | |||
218 | #ifdef CONFIG_PM_RUNTIME | ||
219 | static int lis3_i2c_runtime_suspend(struct device *dev) | ||
220 | { | ||
221 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
222 | struct lis3lv02d *lis3 = i2c_get_clientdata(client); | ||
223 | |||
224 | lis3lv02d_poweroff(lis3); | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static int lis3_i2c_runtime_resume(struct device *dev) | ||
229 | { | ||
230 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
231 | struct lis3lv02d *lis3 = i2c_get_clientdata(client); | ||
232 | |||
233 | lis3lv02d_poweron(lis3); | ||
234 | return 0; | ||
235 | } | ||
236 | #endif /* CONFIG_PM_RUNTIME */ | ||
237 | |||
238 | static const struct i2c_device_id lis3lv02d_id[] = { | ||
239 | {"lis3lv02d", 0 }, | ||
240 | {} | ||
241 | }; | ||
242 | |||
243 | MODULE_DEVICE_TABLE(i2c, lis3lv02d_id); | ||
244 | |||
245 | static const struct dev_pm_ops lis3_pm_ops = { | ||
246 | SET_SYSTEM_SLEEP_PM_OPS(lis3lv02d_i2c_suspend, | ||
247 | lis3lv02d_i2c_resume) | ||
248 | SET_RUNTIME_PM_OPS(lis3_i2c_runtime_suspend, | ||
249 | lis3_i2c_runtime_resume, | ||
250 | NULL) | ||
251 | }; | ||
252 | |||
253 | static struct i2c_driver lis3lv02d_i2c_driver = { | ||
254 | .driver = { | ||
255 | .name = DRV_NAME, | ||
256 | .owner = THIS_MODULE, | ||
257 | .pm = &lis3_pm_ops, | ||
258 | }, | ||
259 | .probe = lis3lv02d_i2c_probe, | ||
260 | .remove = __devexit_p(lis3lv02d_i2c_remove), | ||
261 | .id_table = lis3lv02d_id, | ||
262 | }; | ||
263 | |||
264 | static int __init lis3lv02d_init(void) | ||
265 | { | ||
266 | return i2c_add_driver(&lis3lv02d_i2c_driver); | ||
267 | } | ||
268 | |||
269 | static void __exit lis3lv02d_exit(void) | ||
270 | { | ||
271 | i2c_del_driver(&lis3lv02d_i2c_driver); | ||
272 | } | ||
273 | |||
274 | MODULE_AUTHOR("Nokia Corporation"); | ||
275 | MODULE_DESCRIPTION("lis3lv02d I2C interface"); | ||
276 | MODULE_LICENSE("GPL"); | ||
277 | |||
278 | module_init(lis3lv02d_init); | ||
279 | module_exit(lis3lv02d_exit); | ||
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_spi.c b/drivers/misc/lis3lv02d/lis3lv02d_spi.c new file mode 100644 index 000000000000..c1f8a8fbf694 --- /dev/null +++ b/drivers/misc/lis3lv02d/lis3lv02d_spi.c | |||
@@ -0,0 +1,145 @@ | |||
1 | /* | ||
2 | * lis3lv02d_spi - SPI glue layer for lis3lv02d | ||
3 | * | ||
4 | * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * publishhed by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/input.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/workqueue.h> | ||
18 | #include <linux/spi/spi.h> | ||
19 | #include <linux/pm.h> | ||
20 | |||
21 | #include "lis3lv02d.h" | ||
22 | |||
23 | #define DRV_NAME "lis3lv02d_spi" | ||
24 | #define LIS3_SPI_READ 0x80 | ||
25 | |||
26 | static int lis3_spi_read(struct lis3lv02d *lis3, int reg, u8 *v) | ||
27 | { | ||
28 | struct spi_device *spi = lis3->bus_priv; | ||
29 | int ret = spi_w8r8(spi, reg | LIS3_SPI_READ); | ||
30 | if (ret < 0) | ||
31 | return -EINVAL; | ||
32 | |||
33 | *v = (u8) ret; | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | static int lis3_spi_write(struct lis3lv02d *lis3, int reg, u8 val) | ||
38 | { | ||
39 | u8 tmp[2] = { reg, val }; | ||
40 | struct spi_device *spi = lis3->bus_priv; | ||
41 | return spi_write(spi, tmp, sizeof(tmp)); | ||
42 | } | ||
43 | |||
44 | static int lis3_spi_init(struct lis3lv02d *lis3) | ||
45 | { | ||
46 | u8 reg; | ||
47 | int ret; | ||
48 | |||
49 | /* power up the device */ | ||
50 | ret = lis3->read(lis3, CTRL_REG1, ®); | ||
51 | if (ret < 0) | ||
52 | return ret; | ||
53 | |||
54 | reg |= CTRL1_PD0 | CTRL1_Xen | CTRL1_Yen | CTRL1_Zen; | ||
55 | return lis3->write(lis3, CTRL_REG1, reg); | ||
56 | } | ||
57 | |||
58 | static union axis_conversion lis3lv02d_axis_normal = | ||
59 | { .as_array = { 1, 2, 3 } }; | ||
60 | |||
61 | static int __devinit lis302dl_spi_probe(struct spi_device *spi) | ||
62 | { | ||
63 | int ret; | ||
64 | |||
65 | spi->bits_per_word = 8; | ||
66 | spi->mode = SPI_MODE_0; | ||
67 | ret = spi_setup(spi); | ||
68 | if (ret < 0) | ||
69 | return ret; | ||
70 | |||
71 | lis3_dev.bus_priv = spi; | ||
72 | lis3_dev.init = lis3_spi_init; | ||
73 | lis3_dev.read = lis3_spi_read; | ||
74 | lis3_dev.write = lis3_spi_write; | ||
75 | lis3_dev.irq = spi->irq; | ||
76 | lis3_dev.ac = lis3lv02d_axis_normal; | ||
77 | lis3_dev.pdata = spi->dev.platform_data; | ||
78 | spi_set_drvdata(spi, &lis3_dev); | ||
79 | |||
80 | return lis3lv02d_init_device(&lis3_dev); | ||
81 | } | ||
82 | |||
83 | static int __devexit lis302dl_spi_remove(struct spi_device *spi) | ||
84 | { | ||
85 | struct lis3lv02d *lis3 = spi_get_drvdata(spi); | ||
86 | lis3lv02d_joystick_disable(); | ||
87 | lis3lv02d_poweroff(lis3); | ||
88 | |||
89 | return lis3lv02d_remove_fs(&lis3_dev); | ||
90 | } | ||
91 | |||
92 | #ifdef CONFIG_PM_SLEEP | ||
93 | static int lis3lv02d_spi_suspend(struct device *dev) | ||
94 | { | ||
95 | struct spi_device *spi = to_spi_device(dev); | ||
96 | struct lis3lv02d *lis3 = spi_get_drvdata(spi); | ||
97 | |||
98 | if (!lis3->pdata || !lis3->pdata->wakeup_flags) | ||
99 | lis3lv02d_poweroff(&lis3_dev); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int lis3lv02d_spi_resume(struct device *dev) | ||
105 | { | ||
106 | struct spi_device *spi = to_spi_device(dev); | ||
107 | struct lis3lv02d *lis3 = spi_get_drvdata(spi); | ||
108 | |||
109 | if (!lis3->pdata || !lis3->pdata->wakeup_flags) | ||
110 | lis3lv02d_poweron(lis3); | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | #endif | ||
115 | |||
116 | static SIMPLE_DEV_PM_OPS(lis3lv02d_spi_pm, lis3lv02d_spi_suspend, | ||
117 | lis3lv02d_spi_resume); | ||
118 | |||
119 | static struct spi_driver lis302dl_spi_driver = { | ||
120 | .driver = { | ||
121 | .name = DRV_NAME, | ||
122 | .owner = THIS_MODULE, | ||
123 | .pm = &lis3lv02d_spi_pm, | ||
124 | }, | ||
125 | .probe = lis302dl_spi_probe, | ||
126 | .remove = __devexit_p(lis302dl_spi_remove), | ||
127 | }; | ||
128 | |||
129 | static int __init lis302dl_init(void) | ||
130 | { | ||
131 | return spi_register_driver(&lis302dl_spi_driver); | ||
132 | } | ||
133 | |||
134 | static void __exit lis302dl_exit(void) | ||
135 | { | ||
136 | spi_unregister_driver(&lis302dl_spi_driver); | ||
137 | } | ||
138 | |||
139 | module_init(lis302dl_init); | ||
140 | module_exit(lis302dl_exit); | ||
141 | |||
142 | MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); | ||
143 | MODULE_DESCRIPTION("lis3lv02d SPI glue layer"); | ||
144 | MODULE_LICENSE("GPL"); | ||
145 | MODULE_ALIAS("spi:" DRV_NAME); | ||
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c index ef34de7a8026..150cd7061b80 100644 --- a/drivers/misc/lkdtm.c +++ b/drivers/misc/lkdtm.c | |||
@@ -52,32 +52,32 @@ | |||
52 | #define REC_NUM_DEFAULT 10 | 52 | #define REC_NUM_DEFAULT 10 |
53 | 53 | ||
54 | enum cname { | 54 | enum cname { |
55 | INVALID, | 55 | CN_INVALID, |
56 | INT_HARDWARE_ENTRY, | 56 | CN_INT_HARDWARE_ENTRY, |
57 | INT_HW_IRQ_EN, | 57 | CN_INT_HW_IRQ_EN, |
58 | INT_TASKLET_ENTRY, | 58 | CN_INT_TASKLET_ENTRY, |
59 | FS_DEVRW, | 59 | CN_FS_DEVRW, |
60 | MEM_SWAPOUT, | 60 | CN_MEM_SWAPOUT, |
61 | TIMERADD, | 61 | CN_TIMERADD, |
62 | SCSI_DISPATCH_CMD, | 62 | CN_SCSI_DISPATCH_CMD, |
63 | IDE_CORE_CP, | 63 | CN_IDE_CORE_CP, |
64 | DIRECT, | 64 | CN_DIRECT, |
65 | }; | 65 | }; |
66 | 66 | ||
67 | enum ctype { | 67 | enum ctype { |
68 | NONE, | 68 | CT_NONE, |
69 | PANIC, | 69 | CT_PANIC, |
70 | BUG, | 70 | CT_BUG, |
71 | EXCEPTION, | 71 | CT_EXCEPTION, |
72 | LOOP, | 72 | CT_LOOP, |
73 | OVERFLOW, | 73 | CT_OVERFLOW, |
74 | CORRUPT_STACK, | 74 | CT_CORRUPT_STACK, |
75 | UNALIGNED_LOAD_STORE_WRITE, | 75 | CT_UNALIGNED_LOAD_STORE_WRITE, |
76 | OVERWRITE_ALLOCATION, | 76 | CT_OVERWRITE_ALLOCATION, |
77 | WRITE_AFTER_FREE, | 77 | CT_WRITE_AFTER_FREE, |
78 | SOFTLOCKUP, | 78 | CT_SOFTLOCKUP, |
79 | HARDLOCKUP, | 79 | CT_HARDLOCKUP, |
80 | HUNG_TASK, | 80 | CT_HUNG_TASK, |
81 | }; | 81 | }; |
82 | 82 | ||
83 | static char* cp_name[] = { | 83 | static char* cp_name[] = { |
@@ -117,9 +117,10 @@ static char* cpoint_type; | |||
117 | static int cpoint_count = DEFAULT_COUNT; | 117 | static int cpoint_count = DEFAULT_COUNT; |
118 | static int recur_count = REC_NUM_DEFAULT; | 118 | static int recur_count = REC_NUM_DEFAULT; |
119 | 119 | ||
120 | static enum cname cpoint = INVALID; | 120 | static enum cname cpoint = CN_INVALID; |
121 | static enum ctype cptype = NONE; | 121 | static enum ctype cptype = CT_NONE; |
122 | static int count = DEFAULT_COUNT; | 122 | static int count = DEFAULT_COUNT; |
123 | static DEFINE_SPINLOCK(count_lock); | ||
123 | 124 | ||
124 | module_param(recur_count, int, 0644); | 125 | module_param(recur_count, int, 0644); |
125 | MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\ | 126 | MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\ |
@@ -207,12 +208,12 @@ static enum ctype parse_cp_type(const char *what, size_t count) | |||
207 | return i + 1; | 208 | return i + 1; |
208 | } | 209 | } |
209 | 210 | ||
210 | return NONE; | 211 | return CT_NONE; |
211 | } | 212 | } |
212 | 213 | ||
213 | static const char *cp_type_to_str(enum ctype type) | 214 | static const char *cp_type_to_str(enum ctype type) |
214 | { | 215 | { |
215 | if (type == NONE || type < 0 || type > ARRAY_SIZE(cp_type)) | 216 | if (type == CT_NONE || type < 0 || type > ARRAY_SIZE(cp_type)) |
216 | return "None"; | 217 | return "None"; |
217 | 218 | ||
218 | return cp_type[type - 1]; | 219 | return cp_type[type - 1]; |
@@ -220,7 +221,7 @@ static const char *cp_type_to_str(enum ctype type) | |||
220 | 221 | ||
221 | static const char *cp_name_to_str(enum cname name) | 222 | static const char *cp_name_to_str(enum cname name) |
222 | { | 223 | { |
223 | if (name == INVALID || name < 0 || name > ARRAY_SIZE(cp_name)) | 224 | if (name == CN_INVALID || name < 0 || name > ARRAY_SIZE(cp_name)) |
224 | return "INVALID"; | 225 | return "INVALID"; |
225 | 226 | ||
226 | return cp_name[name - 1]; | 227 | return cp_name[name - 1]; |
@@ -230,11 +231,14 @@ static const char *cp_name_to_str(enum cname name) | |||
230 | static int lkdtm_parse_commandline(void) | 231 | static int lkdtm_parse_commandline(void) |
231 | { | 232 | { |
232 | int i; | 233 | int i; |
234 | unsigned long flags; | ||
233 | 235 | ||
234 | if (cpoint_count < 1 || recur_count < 1) | 236 | if (cpoint_count < 1 || recur_count < 1) |
235 | return -EINVAL; | 237 | return -EINVAL; |
236 | 238 | ||
239 | spin_lock_irqsave(&count_lock, flags); | ||
237 | count = cpoint_count; | 240 | count = cpoint_count; |
241 | spin_unlock_irqrestore(&count_lock, flags); | ||
238 | 242 | ||
239 | /* No special parameters */ | 243 | /* No special parameters */ |
240 | if (!cpoint_type && !cpoint_name) | 244 | if (!cpoint_type && !cpoint_name) |
@@ -245,7 +249,7 @@ static int lkdtm_parse_commandline(void) | |||
245 | return -EINVAL; | 249 | return -EINVAL; |
246 | 250 | ||
247 | cptype = parse_cp_type(cpoint_type, strlen(cpoint_type)); | 251 | cptype = parse_cp_type(cpoint_type, strlen(cpoint_type)); |
248 | if (cptype == NONE) | 252 | if (cptype == CT_NONE) |
249 | return -EINVAL; | 253 | return -EINVAL; |
250 | 254 | ||
251 | for (i = 0; i < ARRAY_SIZE(cp_name); i++) { | 255 | for (i = 0; i < ARRAY_SIZE(cp_name); i++) { |
@@ -274,30 +278,30 @@ static int recursive_loop(int a) | |||
274 | static void lkdtm_do_action(enum ctype which) | 278 | static void lkdtm_do_action(enum ctype which) |
275 | { | 279 | { |
276 | switch (which) { | 280 | switch (which) { |
277 | case PANIC: | 281 | case CT_PANIC: |
278 | panic("dumptest"); | 282 | panic("dumptest"); |
279 | break; | 283 | break; |
280 | case BUG: | 284 | case CT_BUG: |
281 | BUG(); | 285 | BUG(); |
282 | break; | 286 | break; |
283 | case EXCEPTION: | 287 | case CT_EXCEPTION: |
284 | *((int *) 0) = 0; | 288 | *((int *) 0) = 0; |
285 | break; | 289 | break; |
286 | case LOOP: | 290 | case CT_LOOP: |
287 | for (;;) | 291 | for (;;) |
288 | ; | 292 | ; |
289 | break; | 293 | break; |
290 | case OVERFLOW: | 294 | case CT_OVERFLOW: |
291 | (void) recursive_loop(0); | 295 | (void) recursive_loop(0); |
292 | break; | 296 | break; |
293 | case CORRUPT_STACK: { | 297 | case CT_CORRUPT_STACK: { |
294 | volatile u32 data[8]; | 298 | volatile u32 data[8]; |
295 | volatile u32 *p = data; | 299 | volatile u32 *p = data; |
296 | 300 | ||
297 | p[12] = 0x12345678; | 301 | p[12] = 0x12345678; |
298 | break; | 302 | break; |
299 | } | 303 | } |
300 | case UNALIGNED_LOAD_STORE_WRITE: { | 304 | case CT_UNALIGNED_LOAD_STORE_WRITE: { |
301 | static u8 data[5] __attribute__((aligned(4))) = {1, 2, | 305 | static u8 data[5] __attribute__((aligned(4))) = {1, 2, |
302 | 3, 4, 5}; | 306 | 3, 4, 5}; |
303 | u32 *p; | 307 | u32 *p; |
@@ -309,7 +313,7 @@ static void lkdtm_do_action(enum ctype which) | |||
309 | *p = val; | 313 | *p = val; |
310 | break; | 314 | break; |
311 | } | 315 | } |
312 | case OVERWRITE_ALLOCATION: { | 316 | case CT_OVERWRITE_ALLOCATION: { |
313 | size_t len = 1020; | 317 | size_t len = 1020; |
314 | u32 *data = kmalloc(len, GFP_KERNEL); | 318 | u32 *data = kmalloc(len, GFP_KERNEL); |
315 | 319 | ||
@@ -317,7 +321,7 @@ static void lkdtm_do_action(enum ctype which) | |||
317 | kfree(data); | 321 | kfree(data); |
318 | break; | 322 | break; |
319 | } | 323 | } |
320 | case WRITE_AFTER_FREE: { | 324 | case CT_WRITE_AFTER_FREE: { |
321 | size_t len = 1024; | 325 | size_t len = 1024; |
322 | u32 *data = kmalloc(len, GFP_KERNEL); | 326 | u32 *data = kmalloc(len, GFP_KERNEL); |
323 | 327 | ||
@@ -326,21 +330,21 @@ static void lkdtm_do_action(enum ctype which) | |||
326 | memset(data, 0x78, len); | 330 | memset(data, 0x78, len); |
327 | break; | 331 | break; |
328 | } | 332 | } |
329 | case SOFTLOCKUP: | 333 | case CT_SOFTLOCKUP: |
330 | preempt_disable(); | 334 | preempt_disable(); |
331 | for (;;) | 335 | for (;;) |
332 | cpu_relax(); | 336 | cpu_relax(); |
333 | break; | 337 | break; |
334 | case HARDLOCKUP: | 338 | case CT_HARDLOCKUP: |
335 | local_irq_disable(); | 339 | local_irq_disable(); |
336 | for (;;) | 340 | for (;;) |
337 | cpu_relax(); | 341 | cpu_relax(); |
338 | break; | 342 | break; |
339 | case HUNG_TASK: | 343 | case CT_HUNG_TASK: |
340 | set_current_state(TASK_UNINTERRUPTIBLE); | 344 | set_current_state(TASK_UNINTERRUPTIBLE); |
341 | schedule(); | 345 | schedule(); |
342 | break; | 346 | break; |
343 | case NONE: | 347 | case CT_NONE: |
344 | default: | 348 | default: |
345 | break; | 349 | break; |
346 | } | 350 | } |
@@ -349,6 +353,9 @@ static void lkdtm_do_action(enum ctype which) | |||
349 | 353 | ||
350 | static void lkdtm_handler(void) | 354 | static void lkdtm_handler(void) |
351 | { | 355 | { |
356 | unsigned long flags; | ||
357 | |||
358 | spin_lock_irqsave(&count_lock, flags); | ||
352 | count--; | 359 | count--; |
353 | printk(KERN_INFO "lkdtm: Crash point %s of type %s hit, trigger in %d rounds\n", | 360 | printk(KERN_INFO "lkdtm: Crash point %s of type %s hit, trigger in %d rounds\n", |
354 | cp_name_to_str(cpoint), cp_type_to_str(cptype), count); | 361 | cp_name_to_str(cpoint), cp_type_to_str(cptype), count); |
@@ -357,49 +364,50 @@ static void lkdtm_handler(void) | |||
357 | lkdtm_do_action(cptype); | 364 | lkdtm_do_action(cptype); |
358 | count = cpoint_count; | 365 | count = cpoint_count; |
359 | } | 366 | } |
367 | spin_unlock_irqrestore(&count_lock, flags); | ||
360 | } | 368 | } |
361 | 369 | ||
362 | static int lkdtm_register_cpoint(enum cname which) | 370 | static int lkdtm_register_cpoint(enum cname which) |
363 | { | 371 | { |
364 | int ret; | 372 | int ret; |
365 | 373 | ||
366 | cpoint = INVALID; | 374 | cpoint = CN_INVALID; |
367 | if (lkdtm.entry != NULL) | 375 | if (lkdtm.entry != NULL) |
368 | unregister_jprobe(&lkdtm); | 376 | unregister_jprobe(&lkdtm); |
369 | 377 | ||
370 | switch (which) { | 378 | switch (which) { |
371 | case DIRECT: | 379 | case CN_DIRECT: |
372 | lkdtm_do_action(cptype); | 380 | lkdtm_do_action(cptype); |
373 | return 0; | 381 | return 0; |
374 | case INT_HARDWARE_ENTRY: | 382 | case CN_INT_HARDWARE_ENTRY: |
375 | lkdtm.kp.symbol_name = "do_IRQ"; | 383 | lkdtm.kp.symbol_name = "do_IRQ"; |
376 | lkdtm.entry = (kprobe_opcode_t*) jp_do_irq; | 384 | lkdtm.entry = (kprobe_opcode_t*) jp_do_irq; |
377 | break; | 385 | break; |
378 | case INT_HW_IRQ_EN: | 386 | case CN_INT_HW_IRQ_EN: |
379 | lkdtm.kp.symbol_name = "handle_IRQ_event"; | 387 | lkdtm.kp.symbol_name = "handle_IRQ_event"; |
380 | lkdtm.entry = (kprobe_opcode_t*) jp_handle_irq_event; | 388 | lkdtm.entry = (kprobe_opcode_t*) jp_handle_irq_event; |
381 | break; | 389 | break; |
382 | case INT_TASKLET_ENTRY: | 390 | case CN_INT_TASKLET_ENTRY: |
383 | lkdtm.kp.symbol_name = "tasklet_action"; | 391 | lkdtm.kp.symbol_name = "tasklet_action"; |
384 | lkdtm.entry = (kprobe_opcode_t*) jp_tasklet_action; | 392 | lkdtm.entry = (kprobe_opcode_t*) jp_tasklet_action; |
385 | break; | 393 | break; |
386 | case FS_DEVRW: | 394 | case CN_FS_DEVRW: |
387 | lkdtm.kp.symbol_name = "ll_rw_block"; | 395 | lkdtm.kp.symbol_name = "ll_rw_block"; |
388 | lkdtm.entry = (kprobe_opcode_t*) jp_ll_rw_block; | 396 | lkdtm.entry = (kprobe_opcode_t*) jp_ll_rw_block; |
389 | break; | 397 | break; |
390 | case MEM_SWAPOUT: | 398 | case CN_MEM_SWAPOUT: |
391 | lkdtm.kp.symbol_name = "shrink_inactive_list"; | 399 | lkdtm.kp.symbol_name = "shrink_inactive_list"; |
392 | lkdtm.entry = (kprobe_opcode_t*) jp_shrink_inactive_list; | 400 | lkdtm.entry = (kprobe_opcode_t*) jp_shrink_inactive_list; |
393 | break; | 401 | break; |
394 | case TIMERADD: | 402 | case CN_TIMERADD: |
395 | lkdtm.kp.symbol_name = "hrtimer_start"; | 403 | lkdtm.kp.symbol_name = "hrtimer_start"; |
396 | lkdtm.entry = (kprobe_opcode_t*) jp_hrtimer_start; | 404 | lkdtm.entry = (kprobe_opcode_t*) jp_hrtimer_start; |
397 | break; | 405 | break; |
398 | case SCSI_DISPATCH_CMD: | 406 | case CN_SCSI_DISPATCH_CMD: |
399 | lkdtm.kp.symbol_name = "scsi_dispatch_cmd"; | 407 | lkdtm.kp.symbol_name = "scsi_dispatch_cmd"; |
400 | lkdtm.entry = (kprobe_opcode_t*) jp_scsi_dispatch_cmd; | 408 | lkdtm.entry = (kprobe_opcode_t*) jp_scsi_dispatch_cmd; |
401 | break; | 409 | break; |
402 | case IDE_CORE_CP: | 410 | case CN_IDE_CORE_CP: |
403 | #ifdef CONFIG_IDE | 411 | #ifdef CONFIG_IDE |
404 | lkdtm.kp.symbol_name = "generic_ide_ioctl"; | 412 | lkdtm.kp.symbol_name = "generic_ide_ioctl"; |
405 | lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl; | 413 | lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl; |
@@ -416,7 +424,7 @@ static int lkdtm_register_cpoint(enum cname which) | |||
416 | cpoint = which; | 424 | cpoint = which; |
417 | if ((ret = register_jprobe(&lkdtm)) < 0) { | 425 | if ((ret = register_jprobe(&lkdtm)) < 0) { |
418 | printk(KERN_INFO "lkdtm: Couldn't register jprobe\n"); | 426 | printk(KERN_INFO "lkdtm: Couldn't register jprobe\n"); |
419 | cpoint = INVALID; | 427 | cpoint = CN_INVALID; |
420 | } | 428 | } |
421 | 429 | ||
422 | return ret; | 430 | return ret; |
@@ -445,7 +453,7 @@ static ssize_t do_register_entry(enum cname which, struct file *f, | |||
445 | cptype = parse_cp_type(buf, count); | 453 | cptype = parse_cp_type(buf, count); |
446 | free_page((unsigned long) buf); | 454 | free_page((unsigned long) buf); |
447 | 455 | ||
448 | if (cptype == NONE) | 456 | if (cptype == CT_NONE) |
449 | return -EINVAL; | 457 | return -EINVAL; |
450 | 458 | ||
451 | err = lkdtm_register_cpoint(which); | 459 | err = lkdtm_register_cpoint(which); |
@@ -487,49 +495,49 @@ static int lkdtm_debugfs_open(struct inode *inode, struct file *file) | |||
487 | static ssize_t int_hardware_entry(struct file *f, const char __user *buf, | 495 | static ssize_t int_hardware_entry(struct file *f, const char __user *buf, |
488 | size_t count, loff_t *off) | 496 | size_t count, loff_t *off) |
489 | { | 497 | { |
490 | return do_register_entry(INT_HARDWARE_ENTRY, f, buf, count, off); | 498 | return do_register_entry(CN_INT_HARDWARE_ENTRY, f, buf, count, off); |
491 | } | 499 | } |
492 | 500 | ||
493 | static ssize_t int_hw_irq_en(struct file *f, const char __user *buf, | 501 | static ssize_t int_hw_irq_en(struct file *f, const char __user *buf, |
494 | size_t count, loff_t *off) | 502 | size_t count, loff_t *off) |
495 | { | 503 | { |
496 | return do_register_entry(INT_HW_IRQ_EN, f, buf, count, off); | 504 | return do_register_entry(CN_INT_HW_IRQ_EN, f, buf, count, off); |
497 | } | 505 | } |
498 | 506 | ||
499 | static ssize_t int_tasklet_entry(struct file *f, const char __user *buf, | 507 | static ssize_t int_tasklet_entry(struct file *f, const char __user *buf, |
500 | size_t count, loff_t *off) | 508 | size_t count, loff_t *off) |
501 | { | 509 | { |
502 | return do_register_entry(INT_TASKLET_ENTRY, f, buf, count, off); | 510 | return do_register_entry(CN_INT_TASKLET_ENTRY, f, buf, count, off); |
503 | } | 511 | } |
504 | 512 | ||
505 | static ssize_t fs_devrw_entry(struct file *f, const char __user *buf, | 513 | static ssize_t fs_devrw_entry(struct file *f, const char __user *buf, |
506 | size_t count, loff_t *off) | 514 | size_t count, loff_t *off) |
507 | { | 515 | { |
508 | return do_register_entry(FS_DEVRW, f, buf, count, off); | 516 | return do_register_entry(CN_FS_DEVRW, f, buf, count, off); |
509 | } | 517 | } |
510 | 518 | ||
511 | static ssize_t mem_swapout_entry(struct file *f, const char __user *buf, | 519 | static ssize_t mem_swapout_entry(struct file *f, const char __user *buf, |
512 | size_t count, loff_t *off) | 520 | size_t count, loff_t *off) |
513 | { | 521 | { |
514 | return do_register_entry(MEM_SWAPOUT, f, buf, count, off); | 522 | return do_register_entry(CN_MEM_SWAPOUT, f, buf, count, off); |
515 | } | 523 | } |
516 | 524 | ||
517 | static ssize_t timeradd_entry(struct file *f, const char __user *buf, | 525 | static ssize_t timeradd_entry(struct file *f, const char __user *buf, |
518 | size_t count, loff_t *off) | 526 | size_t count, loff_t *off) |
519 | { | 527 | { |
520 | return do_register_entry(TIMERADD, f, buf, count, off); | 528 | return do_register_entry(CN_TIMERADD, f, buf, count, off); |
521 | } | 529 | } |
522 | 530 | ||
523 | static ssize_t scsi_dispatch_cmd_entry(struct file *f, | 531 | static ssize_t scsi_dispatch_cmd_entry(struct file *f, |
524 | const char __user *buf, size_t count, loff_t *off) | 532 | const char __user *buf, size_t count, loff_t *off) |
525 | { | 533 | { |
526 | return do_register_entry(SCSI_DISPATCH_CMD, f, buf, count, off); | 534 | return do_register_entry(CN_SCSI_DISPATCH_CMD, f, buf, count, off); |
527 | } | 535 | } |
528 | 536 | ||
529 | static ssize_t ide_core_cp_entry(struct file *f, const char __user *buf, | 537 | static ssize_t ide_core_cp_entry(struct file *f, const char __user *buf, |
530 | size_t count, loff_t *off) | 538 | size_t count, loff_t *off) |
531 | { | 539 | { |
532 | return do_register_entry(IDE_CORE_CP, f, buf, count, off); | 540 | return do_register_entry(CN_IDE_CORE_CP, f, buf, count, off); |
533 | } | 541 | } |
534 | 542 | ||
535 | /* Special entry to just crash directly. Available without KPROBEs */ | 543 | /* Special entry to just crash directly. Available without KPROBEs */ |
@@ -557,7 +565,7 @@ static ssize_t direct_entry(struct file *f, const char __user *user_buf, | |||
557 | 565 | ||
558 | type = parse_cp_type(buf, count); | 566 | type = parse_cp_type(buf, count); |
559 | free_page((unsigned long) buf); | 567 | free_page((unsigned long) buf); |
560 | if (type == NONE) | 568 | if (type == CT_NONE) |
561 | return -EINVAL; | 569 | return -EINVAL; |
562 | 570 | ||
563 | printk(KERN_INFO "lkdtm: Performing direct entry %s\n", | 571 | printk(KERN_INFO "lkdtm: Performing direct entry %s\n", |
@@ -575,30 +583,39 @@ struct crash_entry { | |||
575 | 583 | ||
576 | static const struct crash_entry crash_entries[] = { | 584 | static const struct crash_entry crash_entries[] = { |
577 | {"DIRECT", {.read = lkdtm_debugfs_read, | 585 | {"DIRECT", {.read = lkdtm_debugfs_read, |
586 | .llseek = generic_file_llseek, | ||
578 | .open = lkdtm_debugfs_open, | 587 | .open = lkdtm_debugfs_open, |
579 | .write = direct_entry} }, | 588 | .write = direct_entry} }, |
580 | {"INT_HARDWARE_ENTRY", {.read = lkdtm_debugfs_read, | 589 | {"INT_HARDWARE_ENTRY", {.read = lkdtm_debugfs_read, |
590 | .llseek = generic_file_llseek, | ||
581 | .open = lkdtm_debugfs_open, | 591 | .open = lkdtm_debugfs_open, |
582 | .write = int_hardware_entry} }, | 592 | .write = int_hardware_entry} }, |
583 | {"INT_HW_IRQ_EN", {.read = lkdtm_debugfs_read, | 593 | {"INT_HW_IRQ_EN", {.read = lkdtm_debugfs_read, |
594 | .llseek = generic_file_llseek, | ||
584 | .open = lkdtm_debugfs_open, | 595 | .open = lkdtm_debugfs_open, |
585 | .write = int_hw_irq_en} }, | 596 | .write = int_hw_irq_en} }, |
586 | {"INT_TASKLET_ENTRY", {.read = lkdtm_debugfs_read, | 597 | {"INT_TASKLET_ENTRY", {.read = lkdtm_debugfs_read, |
598 | .llseek = generic_file_llseek, | ||
587 | .open = lkdtm_debugfs_open, | 599 | .open = lkdtm_debugfs_open, |
588 | .write = int_tasklet_entry} }, | 600 | .write = int_tasklet_entry} }, |
589 | {"FS_DEVRW", {.read = lkdtm_debugfs_read, | 601 | {"FS_DEVRW", {.read = lkdtm_debugfs_read, |
602 | .llseek = generic_file_llseek, | ||
590 | .open = lkdtm_debugfs_open, | 603 | .open = lkdtm_debugfs_open, |
591 | .write = fs_devrw_entry} }, | 604 | .write = fs_devrw_entry} }, |
592 | {"MEM_SWAPOUT", {.read = lkdtm_debugfs_read, | 605 | {"MEM_SWAPOUT", {.read = lkdtm_debugfs_read, |
606 | .llseek = generic_file_llseek, | ||
593 | .open = lkdtm_debugfs_open, | 607 | .open = lkdtm_debugfs_open, |
594 | .write = mem_swapout_entry} }, | 608 | .write = mem_swapout_entry} }, |
595 | {"TIMERADD", {.read = lkdtm_debugfs_read, | 609 | {"TIMERADD", {.read = lkdtm_debugfs_read, |
610 | .llseek = generic_file_llseek, | ||
596 | .open = lkdtm_debugfs_open, | 611 | .open = lkdtm_debugfs_open, |
597 | .write = timeradd_entry} }, | 612 | .write = timeradd_entry} }, |
598 | {"SCSI_DISPATCH_CMD", {.read = lkdtm_debugfs_read, | 613 | {"SCSI_DISPATCH_CMD", {.read = lkdtm_debugfs_read, |
614 | .llseek = generic_file_llseek, | ||
599 | .open = lkdtm_debugfs_open, | 615 | .open = lkdtm_debugfs_open, |
600 | .write = scsi_dispatch_cmd_entry} }, | 616 | .write = scsi_dispatch_cmd_entry} }, |
601 | {"IDE_CORE_CP", {.read = lkdtm_debugfs_read, | 617 | {"IDE_CORE_CP", {.read = lkdtm_debugfs_read, |
618 | .llseek = generic_file_llseek, | ||
602 | .open = lkdtm_debugfs_open, | 619 | .open = lkdtm_debugfs_open, |
603 | .write = ide_core_cp_entry} }, | 620 | .write = ide_core_cp_entry} }, |
604 | }; | 621 | }; |
@@ -640,7 +657,7 @@ static int __init lkdtm_module_init(void) | |||
640 | goto out_err; | 657 | goto out_err; |
641 | } | 658 | } |
642 | 659 | ||
643 | if (cpoint != INVALID && cptype != NONE) { | 660 | if (cpoint != CN_INVALID && cptype != CT_NONE) { |
644 | ret = lkdtm_register_cpoint(cpoint); | 661 | ret = lkdtm_register_cpoint(cpoint); |
645 | if (ret < 0) { | 662 | if (ret < 0) { |
646 | printk(KERN_INFO "lkdtm: Invalid crash point %d\n", | 663 | printk(KERN_INFO "lkdtm: Invalid crash point %d\n", |
diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c new file mode 100644 index 000000000000..5fe79df44838 --- /dev/null +++ b/drivers/misc/pch_phub.c | |||
@@ -0,0 +1,868 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; version 2 of the License. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/fs.h> | ||
22 | #include <linux/uaccess.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/pci.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/mutex.h> | ||
28 | #include <linux/if_ether.h> | ||
29 | #include <linux/ctype.h> | ||
30 | #include <linux/dmi.h> | ||
31 | |||
32 | #define PHUB_STATUS 0x00 /* Status Register offset */ | ||
33 | #define PHUB_CONTROL 0x04 /* Control Register offset */ | ||
34 | #define PHUB_TIMEOUT 0x05 /* Time out value for Status Register */ | ||
35 | #define PCH_PHUB_ROM_WRITE_ENABLE 0x01 /* Enabling for writing ROM */ | ||
36 | #define PCH_PHUB_ROM_WRITE_DISABLE 0x00 /* Disabling for writing ROM */ | ||
37 | #define PCH_PHUB_MAC_START_ADDR_EG20T 0x14 /* MAC data area start address | ||
38 | offset */ | ||
39 | #define PCH_PHUB_MAC_START_ADDR_ML7223 0x20C /* MAC data area start address | ||
40 | offset */ | ||
41 | #define PCH_PHUB_ROM_START_ADDR_EG20T 0x80 /* ROM data area start address offset | ||
42 | (Intel EG20T PCH)*/ | ||
43 | #define PCH_PHUB_ROM_START_ADDR_ML7213 0x400 /* ROM data area start address | ||
44 | offset(OKI SEMICONDUCTOR ML7213) | ||
45 | */ | ||
46 | #define PCH_PHUB_ROM_START_ADDR_ML7223 0x400 /* ROM data area start address | ||
47 | offset(OKI SEMICONDUCTOR ML7223) | ||
48 | */ | ||
49 | |||
50 | /* MAX number of INT_REDUCE_CONTROL registers */ | ||
51 | #define MAX_NUM_INT_REDUCE_CONTROL_REG 128 | ||
52 | #define PCI_DEVICE_ID_PCH1_PHUB 0x8801 | ||
53 | #define PCH_MINOR_NOS 1 | ||
54 | #define CLKCFG_CAN_50MHZ 0x12000000 | ||
55 | #define CLKCFG_CANCLK_MASK 0xFF000000 | ||
56 | #define CLKCFG_UART_MASK 0xFFFFFF | ||
57 | |||
58 | /* CM-iTC */ | ||
59 | #define CLKCFG_UART_48MHZ (1 << 16) | ||
60 | #define CLKCFG_BAUDDIV (2 << 20) | ||
61 | #define CLKCFG_PLL2VCO (8 << 9) | ||
62 | #define CLKCFG_UARTCLKSEL (1 << 18) | ||
63 | |||
64 | /* Macros for ML7213 */ | ||
65 | #define PCI_VENDOR_ID_ROHM 0x10db | ||
66 | #define PCI_DEVICE_ID_ROHM_ML7213_PHUB 0x801A | ||
67 | |||
68 | /* Macros for ML7213 */ | ||
69 | #define PCI_VENDOR_ID_ROHM 0x10db | ||
70 | #define PCI_DEVICE_ID_ROHM_ML7213_PHUB 0x801A | ||
71 | |||
72 | /* Macros for ML7223 */ | ||
73 | #define PCI_DEVICE_ID_ROHM_ML7223_mPHUB 0x8012 /* for Bus-m */ | ||
74 | #define PCI_DEVICE_ID_ROHM_ML7223_nPHUB 0x8002 /* for Bus-n */ | ||
75 | |||
76 | /* SROM ACCESS Macro */ | ||
77 | #define PCH_WORD_ADDR_MASK (~((1 << 2) - 1)) | ||
78 | |||
79 | /* Registers address offset */ | ||
80 | #define PCH_PHUB_ID_REG 0x0000 | ||
81 | #define PCH_PHUB_QUEUE_PRI_VAL_REG 0x0004 | ||
82 | #define PCH_PHUB_RC_QUEUE_MAXSIZE_REG 0x0008 | ||
83 | #define PCH_PHUB_BRI_QUEUE_MAXSIZE_REG 0x000C | ||
84 | #define PCH_PHUB_COMP_RESP_TIMEOUT_REG 0x0010 | ||
85 | #define PCH_PHUB_BUS_SLAVE_CONTROL_REG 0x0014 | ||
86 | #define PCH_PHUB_DEADLOCK_AVOID_TYPE_REG 0x0018 | ||
87 | #define PCH_PHUB_INTPIN_REG_WPERMIT_REG0 0x0020 | ||
88 | #define PCH_PHUB_INTPIN_REG_WPERMIT_REG1 0x0024 | ||
89 | #define PCH_PHUB_INTPIN_REG_WPERMIT_REG2 0x0028 | ||
90 | #define PCH_PHUB_INTPIN_REG_WPERMIT_REG3 0x002C | ||
91 | #define PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE 0x0040 | ||
92 | #define CLKCFG_REG_OFFSET 0x500 | ||
93 | |||
94 | #define PCH_PHUB_OROM_SIZE 15360 | ||
95 | |||
96 | /** | ||
97 | * struct pch_phub_reg - PHUB register structure | ||
98 | * @phub_id_reg: PHUB_ID register val | ||
99 | * @q_pri_val_reg: QUEUE_PRI_VAL register val | ||
100 | * @rc_q_maxsize_reg: RC_QUEUE_MAXSIZE register val | ||
101 | * @bri_q_maxsize_reg: BRI_QUEUE_MAXSIZE register val | ||
102 | * @comp_resp_timeout_reg: COMP_RESP_TIMEOUT register val | ||
103 | * @bus_slave_control_reg: BUS_SLAVE_CONTROL_REG register val | ||
104 | * @deadlock_avoid_type_reg: DEADLOCK_AVOID_TYPE register val | ||
105 | * @intpin_reg_wpermit_reg0: INTPIN_REG_WPERMIT register 0 val | ||
106 | * @intpin_reg_wpermit_reg1: INTPIN_REG_WPERMIT register 1 val | ||
107 | * @intpin_reg_wpermit_reg2: INTPIN_REG_WPERMIT register 2 val | ||
108 | * @intpin_reg_wpermit_reg3: INTPIN_REG_WPERMIT register 3 val | ||
109 | * @int_reduce_control_reg: INT_REDUCE_CONTROL registers val | ||
110 | * @clkcfg_reg: CLK CFG register val | ||
111 | * @pch_phub_base_address: Register base address | ||
112 | * @pch_phub_extrom_base_address: external rom base address | ||
113 | * @pch_mac_start_address: MAC address area start address | ||
114 | * @pch_opt_rom_start_address: Option ROM start address | ||
115 | * @ioh_type: Save IOH type | ||
116 | */ | ||
117 | struct pch_phub_reg { | ||
118 | u32 phub_id_reg; | ||
119 | u32 q_pri_val_reg; | ||
120 | u32 rc_q_maxsize_reg; | ||
121 | u32 bri_q_maxsize_reg; | ||
122 | u32 comp_resp_timeout_reg; | ||
123 | u32 bus_slave_control_reg; | ||
124 | u32 deadlock_avoid_type_reg; | ||
125 | u32 intpin_reg_wpermit_reg0; | ||
126 | u32 intpin_reg_wpermit_reg1; | ||
127 | u32 intpin_reg_wpermit_reg2; | ||
128 | u32 intpin_reg_wpermit_reg3; | ||
129 | u32 int_reduce_control_reg[MAX_NUM_INT_REDUCE_CONTROL_REG]; | ||
130 | u32 clkcfg_reg; | ||
131 | void __iomem *pch_phub_base_address; | ||
132 | void __iomem *pch_phub_extrom_base_address; | ||
133 | u32 pch_mac_start_address; | ||
134 | u32 pch_opt_rom_start_address; | ||
135 | int ioh_type; | ||
136 | }; | ||
137 | |||
138 | /* SROM SPEC for MAC address assignment offset */ | ||
139 | static const int pch_phub_mac_offset[ETH_ALEN] = {0x3, 0x2, 0x1, 0x0, 0xb, 0xa}; | ||
140 | |||
141 | static DEFINE_MUTEX(pch_phub_mutex); | ||
142 | |||
143 | /** | ||
144 | * pch_phub_read_modify_write_reg() - Reading modifying and writing register | ||
145 | * @reg_addr_offset: Register offset address value. | ||
146 | * @data: Writing value. | ||
147 | * @mask: Mask value. | ||
148 | */ | ||
149 | static void pch_phub_read_modify_write_reg(struct pch_phub_reg *chip, | ||
150 | unsigned int reg_addr_offset, | ||
151 | unsigned int data, unsigned int mask) | ||
152 | { | ||
153 | void __iomem *reg_addr = chip->pch_phub_base_address + reg_addr_offset; | ||
154 | iowrite32(((ioread32(reg_addr) & ~mask)) | data, reg_addr); | ||
155 | } | ||
156 | |||
157 | /* pch_phub_save_reg_conf - saves register configuration */ | ||
158 | static void pch_phub_save_reg_conf(struct pci_dev *pdev) | ||
159 | { | ||
160 | unsigned int i; | ||
161 | struct pch_phub_reg *chip = pci_get_drvdata(pdev); | ||
162 | |||
163 | void __iomem *p = chip->pch_phub_base_address; | ||
164 | |||
165 | chip->phub_id_reg = ioread32(p + PCH_PHUB_ID_REG); | ||
166 | chip->q_pri_val_reg = ioread32(p + PCH_PHUB_QUEUE_PRI_VAL_REG); | ||
167 | chip->rc_q_maxsize_reg = ioread32(p + PCH_PHUB_RC_QUEUE_MAXSIZE_REG); | ||
168 | chip->bri_q_maxsize_reg = ioread32(p + PCH_PHUB_BRI_QUEUE_MAXSIZE_REG); | ||
169 | chip->comp_resp_timeout_reg = | ||
170 | ioread32(p + PCH_PHUB_COMP_RESP_TIMEOUT_REG); | ||
171 | chip->bus_slave_control_reg = | ||
172 | ioread32(p + PCH_PHUB_BUS_SLAVE_CONTROL_REG); | ||
173 | chip->deadlock_avoid_type_reg = | ||
174 | ioread32(p + PCH_PHUB_DEADLOCK_AVOID_TYPE_REG); | ||
175 | chip->intpin_reg_wpermit_reg0 = | ||
176 | ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG0); | ||
177 | chip->intpin_reg_wpermit_reg1 = | ||
178 | ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG1); | ||
179 | chip->intpin_reg_wpermit_reg2 = | ||
180 | ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG2); | ||
181 | chip->intpin_reg_wpermit_reg3 = | ||
182 | ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG3); | ||
183 | dev_dbg(&pdev->dev, "%s : " | ||
184 | "chip->phub_id_reg=%x, " | ||
185 | "chip->q_pri_val_reg=%x, " | ||
186 | "chip->rc_q_maxsize_reg=%x, " | ||
187 | "chip->bri_q_maxsize_reg=%x, " | ||
188 | "chip->comp_resp_timeout_reg=%x, " | ||
189 | "chip->bus_slave_control_reg=%x, " | ||
190 | "chip->deadlock_avoid_type_reg=%x, " | ||
191 | "chip->intpin_reg_wpermit_reg0=%x, " | ||
192 | "chip->intpin_reg_wpermit_reg1=%x, " | ||
193 | "chip->intpin_reg_wpermit_reg2=%x, " | ||
194 | "chip->intpin_reg_wpermit_reg3=%x\n", __func__, | ||
195 | chip->phub_id_reg, | ||
196 | chip->q_pri_val_reg, | ||
197 | chip->rc_q_maxsize_reg, | ||
198 | chip->bri_q_maxsize_reg, | ||
199 | chip->comp_resp_timeout_reg, | ||
200 | chip->bus_slave_control_reg, | ||
201 | chip->deadlock_avoid_type_reg, | ||
202 | chip->intpin_reg_wpermit_reg0, | ||
203 | chip->intpin_reg_wpermit_reg1, | ||
204 | chip->intpin_reg_wpermit_reg2, | ||
205 | chip->intpin_reg_wpermit_reg3); | ||
206 | for (i = 0; i < MAX_NUM_INT_REDUCE_CONTROL_REG; i++) { | ||
207 | chip->int_reduce_control_reg[i] = | ||
208 | ioread32(p + PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE + 4 * i); | ||
209 | dev_dbg(&pdev->dev, "%s : " | ||
210 | "chip->int_reduce_control_reg[%d]=%x\n", | ||
211 | __func__, i, chip->int_reduce_control_reg[i]); | ||
212 | } | ||
213 | chip->clkcfg_reg = ioread32(p + CLKCFG_REG_OFFSET); | ||
214 | } | ||
215 | |||
216 | /* pch_phub_restore_reg_conf - restore register configuration */ | ||
217 | static void pch_phub_restore_reg_conf(struct pci_dev *pdev) | ||
218 | { | ||
219 | unsigned int i; | ||
220 | struct pch_phub_reg *chip = pci_get_drvdata(pdev); | ||
221 | void __iomem *p; | ||
222 | p = chip->pch_phub_base_address; | ||
223 | |||
224 | iowrite32(chip->phub_id_reg, p + PCH_PHUB_ID_REG); | ||
225 | iowrite32(chip->q_pri_val_reg, p + PCH_PHUB_QUEUE_PRI_VAL_REG); | ||
226 | iowrite32(chip->rc_q_maxsize_reg, p + PCH_PHUB_RC_QUEUE_MAXSIZE_REG); | ||
227 | iowrite32(chip->bri_q_maxsize_reg, p + PCH_PHUB_BRI_QUEUE_MAXSIZE_REG); | ||
228 | iowrite32(chip->comp_resp_timeout_reg, | ||
229 | p + PCH_PHUB_COMP_RESP_TIMEOUT_REG); | ||
230 | iowrite32(chip->bus_slave_control_reg, | ||
231 | p + PCH_PHUB_BUS_SLAVE_CONTROL_REG); | ||
232 | iowrite32(chip->deadlock_avoid_type_reg, | ||
233 | p + PCH_PHUB_DEADLOCK_AVOID_TYPE_REG); | ||
234 | iowrite32(chip->intpin_reg_wpermit_reg0, | ||
235 | p + PCH_PHUB_INTPIN_REG_WPERMIT_REG0); | ||
236 | iowrite32(chip->intpin_reg_wpermit_reg1, | ||
237 | p + PCH_PHUB_INTPIN_REG_WPERMIT_REG1); | ||
238 | iowrite32(chip->intpin_reg_wpermit_reg2, | ||
239 | p + PCH_PHUB_INTPIN_REG_WPERMIT_REG2); | ||
240 | iowrite32(chip->intpin_reg_wpermit_reg3, | ||
241 | p + PCH_PHUB_INTPIN_REG_WPERMIT_REG3); | ||
242 | dev_dbg(&pdev->dev, "%s : " | ||
243 | "chip->phub_id_reg=%x, " | ||
244 | "chip->q_pri_val_reg=%x, " | ||
245 | "chip->rc_q_maxsize_reg=%x, " | ||
246 | "chip->bri_q_maxsize_reg=%x, " | ||
247 | "chip->comp_resp_timeout_reg=%x, " | ||
248 | "chip->bus_slave_control_reg=%x, " | ||
249 | "chip->deadlock_avoid_type_reg=%x, " | ||
250 | "chip->intpin_reg_wpermit_reg0=%x, " | ||
251 | "chip->intpin_reg_wpermit_reg1=%x, " | ||
252 | "chip->intpin_reg_wpermit_reg2=%x, " | ||
253 | "chip->intpin_reg_wpermit_reg3=%x\n", __func__, | ||
254 | chip->phub_id_reg, | ||
255 | chip->q_pri_val_reg, | ||
256 | chip->rc_q_maxsize_reg, | ||
257 | chip->bri_q_maxsize_reg, | ||
258 | chip->comp_resp_timeout_reg, | ||
259 | chip->bus_slave_control_reg, | ||
260 | chip->deadlock_avoid_type_reg, | ||
261 | chip->intpin_reg_wpermit_reg0, | ||
262 | chip->intpin_reg_wpermit_reg1, | ||
263 | chip->intpin_reg_wpermit_reg2, | ||
264 | chip->intpin_reg_wpermit_reg3); | ||
265 | for (i = 0; i < MAX_NUM_INT_REDUCE_CONTROL_REG; i++) { | ||
266 | iowrite32(chip->int_reduce_control_reg[i], | ||
267 | p + PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE + 4 * i); | ||
268 | dev_dbg(&pdev->dev, "%s : " | ||
269 | "chip->int_reduce_control_reg[%d]=%x\n", | ||
270 | __func__, i, chip->int_reduce_control_reg[i]); | ||
271 | } | ||
272 | |||
273 | iowrite32(chip->clkcfg_reg, p + CLKCFG_REG_OFFSET); | ||
274 | } | ||
275 | |||
276 | /** | ||
277 | * pch_phub_read_serial_rom() - Reading Serial ROM | ||
278 | * @offset_address: Serial ROM offset address to read. | ||
279 | * @data: Read buffer for specified Serial ROM value. | ||
280 | */ | ||
281 | static void pch_phub_read_serial_rom(struct pch_phub_reg *chip, | ||
282 | unsigned int offset_address, u8 *data) | ||
283 | { | ||
284 | void __iomem *mem_addr = chip->pch_phub_extrom_base_address + | ||
285 | offset_address; | ||
286 | |||
287 | *data = ioread8(mem_addr); | ||
288 | } | ||
289 | |||
290 | /** | ||
291 | * pch_phub_write_serial_rom() - Writing Serial ROM | ||
292 | * @offset_address: Serial ROM offset address. | ||
293 | * @data: Serial ROM value to write. | ||
294 | */ | ||
295 | static int pch_phub_write_serial_rom(struct pch_phub_reg *chip, | ||
296 | unsigned int offset_address, u8 data) | ||
297 | { | ||
298 | void __iomem *mem_addr = chip->pch_phub_extrom_base_address + | ||
299 | (offset_address & PCH_WORD_ADDR_MASK); | ||
300 | int i; | ||
301 | unsigned int word_data; | ||
302 | unsigned int pos; | ||
303 | unsigned int mask; | ||
304 | pos = (offset_address % 4) * 8; | ||
305 | mask = ~(0xFF << pos); | ||
306 | |||
307 | iowrite32(PCH_PHUB_ROM_WRITE_ENABLE, | ||
308 | chip->pch_phub_extrom_base_address + PHUB_CONTROL); | ||
309 | |||
310 | word_data = ioread32(mem_addr); | ||
311 | iowrite32((word_data & mask) | (u32)data << pos, mem_addr); | ||
312 | |||
313 | i = 0; | ||
314 | while (ioread8(chip->pch_phub_extrom_base_address + | ||
315 | PHUB_STATUS) != 0x00) { | ||
316 | msleep(1); | ||
317 | if (i == PHUB_TIMEOUT) | ||
318 | return -ETIMEDOUT; | ||
319 | i++; | ||
320 | } | ||
321 | |||
322 | iowrite32(PCH_PHUB_ROM_WRITE_DISABLE, | ||
323 | chip->pch_phub_extrom_base_address + PHUB_CONTROL); | ||
324 | |||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | /** | ||
329 | * pch_phub_read_serial_rom_val() - Read Serial ROM value | ||
330 | * @offset_address: Serial ROM address offset value. | ||
331 | * @data: Serial ROM value to read. | ||
332 | */ | ||
333 | static void pch_phub_read_serial_rom_val(struct pch_phub_reg *chip, | ||
334 | unsigned int offset_address, u8 *data) | ||
335 | { | ||
336 | unsigned int mem_addr; | ||
337 | |||
338 | mem_addr = chip->pch_mac_start_address + | ||
339 | pch_phub_mac_offset[offset_address]; | ||
340 | |||
341 | pch_phub_read_serial_rom(chip, mem_addr, data); | ||
342 | } | ||
343 | |||
344 | /** | ||
345 | * pch_phub_write_serial_rom_val() - writing Serial ROM value | ||
346 | * @offset_address: Serial ROM address offset value. | ||
347 | * @data: Serial ROM value. | ||
348 | */ | ||
349 | static int pch_phub_write_serial_rom_val(struct pch_phub_reg *chip, | ||
350 | unsigned int offset_address, u8 data) | ||
351 | { | ||
352 | int retval; | ||
353 | unsigned int mem_addr; | ||
354 | |||
355 | mem_addr = chip->pch_mac_start_address + | ||
356 | pch_phub_mac_offset[offset_address]; | ||
357 | |||
358 | retval = pch_phub_write_serial_rom(chip, mem_addr, data); | ||
359 | |||
360 | return retval; | ||
361 | } | ||
362 | |||
363 | /* pch_phub_gbe_serial_rom_conf - makes Serial ROM header format configuration | ||
364 | * for Gigabit Ethernet MAC address | ||
365 | */ | ||
366 | static int pch_phub_gbe_serial_rom_conf(struct pch_phub_reg *chip) | ||
367 | { | ||
368 | int retval; | ||
369 | |||
370 | retval = pch_phub_write_serial_rom(chip, 0x0b, 0xbc); | ||
371 | retval |= pch_phub_write_serial_rom(chip, 0x0a, 0x10); | ||
372 | retval |= pch_phub_write_serial_rom(chip, 0x09, 0x01); | ||
373 | retval |= pch_phub_write_serial_rom(chip, 0x08, 0x02); | ||
374 | |||
375 | retval |= pch_phub_write_serial_rom(chip, 0x0f, 0x00); | ||
376 | retval |= pch_phub_write_serial_rom(chip, 0x0e, 0x00); | ||
377 | retval |= pch_phub_write_serial_rom(chip, 0x0d, 0x00); | ||
378 | retval |= pch_phub_write_serial_rom(chip, 0x0c, 0x80); | ||
379 | |||
380 | retval |= pch_phub_write_serial_rom(chip, 0x13, 0xbc); | ||
381 | retval |= pch_phub_write_serial_rom(chip, 0x12, 0x10); | ||
382 | retval |= pch_phub_write_serial_rom(chip, 0x11, 0x01); | ||
383 | retval |= pch_phub_write_serial_rom(chip, 0x10, 0x18); | ||
384 | |||
385 | retval |= pch_phub_write_serial_rom(chip, 0x1b, 0xbc); | ||
386 | retval |= pch_phub_write_serial_rom(chip, 0x1a, 0x10); | ||
387 | retval |= pch_phub_write_serial_rom(chip, 0x19, 0x01); | ||
388 | retval |= pch_phub_write_serial_rom(chip, 0x18, 0x19); | ||
389 | |||
390 | retval |= pch_phub_write_serial_rom(chip, 0x23, 0xbc); | ||
391 | retval |= pch_phub_write_serial_rom(chip, 0x22, 0x10); | ||
392 | retval |= pch_phub_write_serial_rom(chip, 0x21, 0x01); | ||
393 | retval |= pch_phub_write_serial_rom(chip, 0x20, 0x3a); | ||
394 | |||
395 | retval |= pch_phub_write_serial_rom(chip, 0x27, 0x01); | ||
396 | retval |= pch_phub_write_serial_rom(chip, 0x26, 0x00); | ||
397 | retval |= pch_phub_write_serial_rom(chip, 0x25, 0x00); | ||
398 | retval |= pch_phub_write_serial_rom(chip, 0x24, 0x00); | ||
399 | |||
400 | return retval; | ||
401 | } | ||
402 | |||
403 | /* pch_phub_gbe_serial_rom_conf_mp - makes SerialROM header format configuration | ||
404 | * for Gigabit Ethernet MAC address | ||
405 | */ | ||
406 | static int pch_phub_gbe_serial_rom_conf_mp(struct pch_phub_reg *chip) | ||
407 | { | ||
408 | int retval; | ||
409 | u32 offset_addr; | ||
410 | |||
411 | offset_addr = 0x200; | ||
412 | retval = pch_phub_write_serial_rom(chip, 0x03 + offset_addr, 0xbc); | ||
413 | retval |= pch_phub_write_serial_rom(chip, 0x02 + offset_addr, 0x00); | ||
414 | retval |= pch_phub_write_serial_rom(chip, 0x01 + offset_addr, 0x40); | ||
415 | retval |= pch_phub_write_serial_rom(chip, 0x00 + offset_addr, 0x02); | ||
416 | |||
417 | retval |= pch_phub_write_serial_rom(chip, 0x07 + offset_addr, 0x00); | ||
418 | retval |= pch_phub_write_serial_rom(chip, 0x06 + offset_addr, 0x00); | ||
419 | retval |= pch_phub_write_serial_rom(chip, 0x05 + offset_addr, 0x00); | ||
420 | retval |= pch_phub_write_serial_rom(chip, 0x04 + offset_addr, 0x80); | ||
421 | |||
422 | retval |= pch_phub_write_serial_rom(chip, 0x0b + offset_addr, 0xbc); | ||
423 | retval |= pch_phub_write_serial_rom(chip, 0x0a + offset_addr, 0x00); | ||
424 | retval |= pch_phub_write_serial_rom(chip, 0x09 + offset_addr, 0x40); | ||
425 | retval |= pch_phub_write_serial_rom(chip, 0x08 + offset_addr, 0x18); | ||
426 | |||
427 | retval |= pch_phub_write_serial_rom(chip, 0x13 + offset_addr, 0xbc); | ||
428 | retval |= pch_phub_write_serial_rom(chip, 0x12 + offset_addr, 0x00); | ||
429 | retval |= pch_phub_write_serial_rom(chip, 0x11 + offset_addr, 0x40); | ||
430 | retval |= pch_phub_write_serial_rom(chip, 0x10 + offset_addr, 0x19); | ||
431 | |||
432 | retval |= pch_phub_write_serial_rom(chip, 0x1b + offset_addr, 0xbc); | ||
433 | retval |= pch_phub_write_serial_rom(chip, 0x1a + offset_addr, 0x00); | ||
434 | retval |= pch_phub_write_serial_rom(chip, 0x19 + offset_addr, 0x40); | ||
435 | retval |= pch_phub_write_serial_rom(chip, 0x18 + offset_addr, 0x3a); | ||
436 | |||
437 | retval |= pch_phub_write_serial_rom(chip, 0x1f + offset_addr, 0x01); | ||
438 | retval |= pch_phub_write_serial_rom(chip, 0x1e + offset_addr, 0x00); | ||
439 | retval |= pch_phub_write_serial_rom(chip, 0x1d + offset_addr, 0x00); | ||
440 | retval |= pch_phub_write_serial_rom(chip, 0x1c + offset_addr, 0x00); | ||
441 | |||
442 | return retval; | ||
443 | } | ||
444 | |||
445 | /** | ||
446 | * pch_phub_read_gbe_mac_addr() - Read Gigabit Ethernet MAC address | ||
447 | * @offset_address: Gigabit Ethernet MAC address offset value. | ||
448 | * @data: Buffer of the Gigabit Ethernet MAC address value. | ||
449 | */ | ||
450 | static void pch_phub_read_gbe_mac_addr(struct pch_phub_reg *chip, u8 *data) | ||
451 | { | ||
452 | int i; | ||
453 | for (i = 0; i < ETH_ALEN; i++) | ||
454 | pch_phub_read_serial_rom_val(chip, i, &data[i]); | ||
455 | } | ||
456 | |||
457 | /** | ||
458 | * pch_phub_write_gbe_mac_addr() - Write MAC address | ||
459 | * @offset_address: Gigabit Ethernet MAC address offset value. | ||
460 | * @data: Gigabit Ethernet MAC address value. | ||
461 | */ | ||
462 | static int pch_phub_write_gbe_mac_addr(struct pch_phub_reg *chip, u8 *data) | ||
463 | { | ||
464 | int retval; | ||
465 | int i; | ||
466 | |||
467 | if (chip->ioh_type == 1) /* EG20T */ | ||
468 | retval = pch_phub_gbe_serial_rom_conf(chip); | ||
469 | else /* ML7223 */ | ||
470 | retval = pch_phub_gbe_serial_rom_conf_mp(chip); | ||
471 | if (retval) | ||
472 | return retval; | ||
473 | |||
474 | for (i = 0; i < ETH_ALEN; i++) { | ||
475 | retval = pch_phub_write_serial_rom_val(chip, i, data[i]); | ||
476 | if (retval) | ||
477 | return retval; | ||
478 | } | ||
479 | |||
480 | return retval; | ||
481 | } | ||
482 | |||
483 | static ssize_t pch_phub_bin_read(struct file *filp, struct kobject *kobj, | ||
484 | struct bin_attribute *attr, char *buf, | ||
485 | loff_t off, size_t count) | ||
486 | { | ||
487 | unsigned int rom_signature; | ||
488 | unsigned char rom_length; | ||
489 | unsigned int tmp; | ||
490 | unsigned int addr_offset; | ||
491 | unsigned int orom_size; | ||
492 | int ret; | ||
493 | int err; | ||
494 | |||
495 | struct pch_phub_reg *chip = | ||
496 | dev_get_drvdata(container_of(kobj, struct device, kobj)); | ||
497 | |||
498 | ret = mutex_lock_interruptible(&pch_phub_mutex); | ||
499 | if (ret) { | ||
500 | err = -ERESTARTSYS; | ||
501 | goto return_err_nomutex; | ||
502 | } | ||
503 | |||
504 | /* Get Rom signature */ | ||
505 | pch_phub_read_serial_rom(chip, chip->pch_opt_rom_start_address, | ||
506 | (unsigned char *)&rom_signature); | ||
507 | rom_signature &= 0xff; | ||
508 | pch_phub_read_serial_rom(chip, chip->pch_opt_rom_start_address + 1, | ||
509 | (unsigned char *)&tmp); | ||
510 | rom_signature |= (tmp & 0xff) << 8; | ||
511 | if (rom_signature == 0xAA55) { | ||
512 | pch_phub_read_serial_rom(chip, | ||
513 | chip->pch_opt_rom_start_address + 2, | ||
514 | &rom_length); | ||
515 | orom_size = rom_length * 512; | ||
516 | if (orom_size < off) { | ||
517 | addr_offset = 0; | ||
518 | goto return_ok; | ||
519 | } | ||
520 | if (orom_size < count) { | ||
521 | addr_offset = 0; | ||
522 | goto return_ok; | ||
523 | } | ||
524 | |||
525 | for (addr_offset = 0; addr_offset < count; addr_offset++) { | ||
526 | pch_phub_read_serial_rom(chip, | ||
527 | chip->pch_opt_rom_start_address + addr_offset + off, | ||
528 | &buf[addr_offset]); | ||
529 | } | ||
530 | } else { | ||
531 | err = -ENODATA; | ||
532 | goto return_err; | ||
533 | } | ||
534 | return_ok: | ||
535 | mutex_unlock(&pch_phub_mutex); | ||
536 | return addr_offset; | ||
537 | |||
538 | return_err: | ||
539 | mutex_unlock(&pch_phub_mutex); | ||
540 | return_err_nomutex: | ||
541 | return err; | ||
542 | } | ||
543 | |||
544 | static ssize_t pch_phub_bin_write(struct file *filp, struct kobject *kobj, | ||
545 | struct bin_attribute *attr, | ||
546 | char *buf, loff_t off, size_t count) | ||
547 | { | ||
548 | int err; | ||
549 | unsigned int addr_offset; | ||
550 | int ret; | ||
551 | struct pch_phub_reg *chip = | ||
552 | dev_get_drvdata(container_of(kobj, struct device, kobj)); | ||
553 | |||
554 | ret = mutex_lock_interruptible(&pch_phub_mutex); | ||
555 | if (ret) | ||
556 | return -ERESTARTSYS; | ||
557 | |||
558 | if (off > PCH_PHUB_OROM_SIZE) { | ||
559 | addr_offset = 0; | ||
560 | goto return_ok; | ||
561 | } | ||
562 | if (count > PCH_PHUB_OROM_SIZE) { | ||
563 | addr_offset = 0; | ||
564 | goto return_ok; | ||
565 | } | ||
566 | |||
567 | for (addr_offset = 0; addr_offset < count; addr_offset++) { | ||
568 | if (PCH_PHUB_OROM_SIZE < off + addr_offset) | ||
569 | goto return_ok; | ||
570 | |||
571 | ret = pch_phub_write_serial_rom(chip, | ||
572 | chip->pch_opt_rom_start_address + addr_offset + off, | ||
573 | buf[addr_offset]); | ||
574 | if (ret) { | ||
575 | err = ret; | ||
576 | goto return_err; | ||
577 | } | ||
578 | } | ||
579 | |||
580 | return_ok: | ||
581 | mutex_unlock(&pch_phub_mutex); | ||
582 | return addr_offset; | ||
583 | |||
584 | return_err: | ||
585 | mutex_unlock(&pch_phub_mutex); | ||
586 | return err; | ||
587 | } | ||
588 | |||
589 | static ssize_t show_pch_mac(struct device *dev, struct device_attribute *attr, | ||
590 | char *buf) | ||
591 | { | ||
592 | u8 mac[8]; | ||
593 | struct pch_phub_reg *chip = dev_get_drvdata(dev); | ||
594 | |||
595 | pch_phub_read_gbe_mac_addr(chip, mac); | ||
596 | |||
597 | return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", | ||
598 | mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); | ||
599 | } | ||
600 | |||
601 | static ssize_t store_pch_mac(struct device *dev, struct device_attribute *attr, | ||
602 | const char *buf, size_t count) | ||
603 | { | ||
604 | u8 mac[6]; | ||
605 | struct pch_phub_reg *chip = dev_get_drvdata(dev); | ||
606 | |||
607 | if (count != 18) | ||
608 | return -EINVAL; | ||
609 | |||
610 | sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", | ||
611 | (u32 *)&mac[0], (u32 *)&mac[1], (u32 *)&mac[2], (u32 *)&mac[3], | ||
612 | (u32 *)&mac[4], (u32 *)&mac[5]); | ||
613 | |||
614 | pch_phub_write_gbe_mac_addr(chip, mac); | ||
615 | |||
616 | return count; | ||
617 | } | ||
618 | |||
619 | static DEVICE_ATTR(pch_mac, S_IRUGO | S_IWUSR, show_pch_mac, store_pch_mac); | ||
620 | |||
621 | static struct bin_attribute pch_bin_attr = { | ||
622 | .attr = { | ||
623 | .name = "pch_firmware", | ||
624 | .mode = S_IRUGO | S_IWUSR, | ||
625 | }, | ||
626 | .size = PCH_PHUB_OROM_SIZE + 1, | ||
627 | .read = pch_phub_bin_read, | ||
628 | .write = pch_phub_bin_write, | ||
629 | }; | ||
630 | |||
631 | static int __devinit pch_phub_probe(struct pci_dev *pdev, | ||
632 | const struct pci_device_id *id) | ||
633 | { | ||
634 | int retval; | ||
635 | |||
636 | int ret; | ||
637 | ssize_t rom_size; | ||
638 | struct pch_phub_reg *chip; | ||
639 | |||
640 | chip = kzalloc(sizeof(struct pch_phub_reg), GFP_KERNEL); | ||
641 | if (chip == NULL) | ||
642 | return -ENOMEM; | ||
643 | |||
644 | ret = pci_enable_device(pdev); | ||
645 | if (ret) { | ||
646 | dev_err(&pdev->dev, | ||
647 | "%s : pci_enable_device FAILED(ret=%d)", __func__, ret); | ||
648 | goto err_pci_enable_dev; | ||
649 | } | ||
650 | dev_dbg(&pdev->dev, "%s : pci_enable_device returns %d\n", __func__, | ||
651 | ret); | ||
652 | |||
653 | ret = pci_request_regions(pdev, KBUILD_MODNAME); | ||
654 | if (ret) { | ||
655 | dev_err(&pdev->dev, | ||
656 | "%s : pci_request_regions FAILED(ret=%d)", __func__, ret); | ||
657 | goto err_req_regions; | ||
658 | } | ||
659 | dev_dbg(&pdev->dev, "%s : " | ||
660 | "pci_request_regions returns %d\n", __func__, ret); | ||
661 | |||
662 | chip->pch_phub_base_address = pci_iomap(pdev, 1, 0); | ||
663 | |||
664 | |||
665 | if (chip->pch_phub_base_address == 0) { | ||
666 | dev_err(&pdev->dev, "%s : pci_iomap FAILED", __func__); | ||
667 | ret = -ENOMEM; | ||
668 | goto err_pci_iomap; | ||
669 | } | ||
670 | dev_dbg(&pdev->dev, "%s : pci_iomap SUCCESS and value " | ||
671 | "in pch_phub_base_address variable is %p\n", __func__, | ||
672 | chip->pch_phub_base_address); | ||
673 | |||
674 | if (id->driver_data != 3) { | ||
675 | chip->pch_phub_extrom_base_address =\ | ||
676 | pci_map_rom(pdev, &rom_size); | ||
677 | if (chip->pch_phub_extrom_base_address == 0) { | ||
678 | dev_err(&pdev->dev, "%s: pci_map_rom FAILED", __func__); | ||
679 | ret = -ENOMEM; | ||
680 | goto err_pci_map; | ||
681 | } | ||
682 | dev_dbg(&pdev->dev, "%s : " | ||
683 | "pci_map_rom SUCCESS and value in " | ||
684 | "pch_phub_extrom_base_address variable is %p\n", | ||
685 | __func__, chip->pch_phub_extrom_base_address); | ||
686 | } | ||
687 | |||
688 | if (id->driver_data == 1) { /* EG20T PCH */ | ||
689 | retval = sysfs_create_file(&pdev->dev.kobj, | ||
690 | &dev_attr_pch_mac.attr); | ||
691 | if (retval) | ||
692 | goto err_sysfs_create; | ||
693 | |||
694 | retval = sysfs_create_bin_file(&pdev->dev.kobj, &pch_bin_attr); | ||
695 | if (retval) | ||
696 | goto exit_bin_attr; | ||
697 | |||
698 | pch_phub_read_modify_write_reg(chip, | ||
699 | (unsigned int)CLKCFG_REG_OFFSET, | ||
700 | CLKCFG_CAN_50MHZ, | ||
701 | CLKCFG_CANCLK_MASK); | ||
702 | |||
703 | /* quirk for CM-iTC board */ | ||
704 | if (strstr(dmi_get_system_info(DMI_BOARD_NAME), "CM-iTC")) | ||
705 | pch_phub_read_modify_write_reg(chip, | ||
706 | (unsigned int)CLKCFG_REG_OFFSET, | ||
707 | CLKCFG_UART_48MHZ | CLKCFG_BAUDDIV | | ||
708 | CLKCFG_PLL2VCO | CLKCFG_UARTCLKSEL, | ||
709 | CLKCFG_UART_MASK); | ||
710 | |||
711 | /* set the prefech value */ | ||
712 | iowrite32(0x000affaa, chip->pch_phub_base_address + 0x14); | ||
713 | /* set the interrupt delay value */ | ||
714 | iowrite32(0x25, chip->pch_phub_base_address + 0x44); | ||
715 | chip->pch_opt_rom_start_address = PCH_PHUB_ROM_START_ADDR_EG20T; | ||
716 | chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_EG20T; | ||
717 | } else if (id->driver_data == 2) { /* ML7213 IOH */ | ||
718 | retval = sysfs_create_bin_file(&pdev->dev.kobj, &pch_bin_attr); | ||
719 | if (retval) | ||
720 | goto err_sysfs_create; | ||
721 | /* set the prefech value | ||
722 | * Device2(USB OHCI #1/ USB EHCI #1/ USB Device):a | ||
723 | * Device4(SDIO #0,1,2):f | ||
724 | * Device6(SATA 2):f | ||
725 | * Device8(USB OHCI #0/ USB EHCI #0):a | ||
726 | */ | ||
727 | iowrite32(0x000affa0, chip->pch_phub_base_address + 0x14); | ||
728 | chip->pch_opt_rom_start_address =\ | ||
729 | PCH_PHUB_ROM_START_ADDR_ML7213; | ||
730 | } else if (id->driver_data == 3) { /* ML7223 IOH Bus-m*/ | ||
731 | /* set the prefech value | ||
732 | * Device8(GbE) | ||
733 | */ | ||
734 | iowrite32(0x000a0000, chip->pch_phub_base_address + 0x14); | ||
735 | chip->pch_opt_rom_start_address =\ | ||
736 | PCH_PHUB_ROM_START_ADDR_ML7223; | ||
737 | chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_ML7223; | ||
738 | } else if (id->driver_data == 4) { /* ML7223 IOH Bus-n*/ | ||
739 | retval = sysfs_create_file(&pdev->dev.kobj, | ||
740 | &dev_attr_pch_mac.attr); | ||
741 | if (retval) | ||
742 | goto err_sysfs_create; | ||
743 | retval = sysfs_create_bin_file(&pdev->dev.kobj, &pch_bin_attr); | ||
744 | if (retval) | ||
745 | goto exit_bin_attr; | ||
746 | /* set the prefech value | ||
747 | * Device2(USB OHCI #0,1,2,3/ USB EHCI #0):a | ||
748 | * Device4(SDIO #0,1):f | ||
749 | * Device6(SATA 2):f | ||
750 | */ | ||
751 | iowrite32(0x0000ffa0, chip->pch_phub_base_address + 0x14); | ||
752 | /* set the interrupt delay value */ | ||
753 | iowrite32(0x25, chip->pch_phub_base_address + 0x140); | ||
754 | chip->pch_opt_rom_start_address =\ | ||
755 | PCH_PHUB_ROM_START_ADDR_ML7223; | ||
756 | chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_ML7223; | ||
757 | } | ||
758 | |||
759 | chip->ioh_type = id->driver_data; | ||
760 | pci_set_drvdata(pdev, chip); | ||
761 | |||
762 | return 0; | ||
763 | exit_bin_attr: | ||
764 | sysfs_remove_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); | ||
765 | |||
766 | err_sysfs_create: | ||
767 | pci_unmap_rom(pdev, chip->pch_phub_extrom_base_address); | ||
768 | err_pci_map: | ||
769 | pci_iounmap(pdev, chip->pch_phub_base_address); | ||
770 | err_pci_iomap: | ||
771 | pci_release_regions(pdev); | ||
772 | err_req_regions: | ||
773 | pci_disable_device(pdev); | ||
774 | err_pci_enable_dev: | ||
775 | kfree(chip); | ||
776 | dev_err(&pdev->dev, "%s returns %d\n", __func__, ret); | ||
777 | return ret; | ||
778 | } | ||
779 | |||
780 | static void __devexit pch_phub_remove(struct pci_dev *pdev) | ||
781 | { | ||
782 | struct pch_phub_reg *chip = pci_get_drvdata(pdev); | ||
783 | |||
784 | sysfs_remove_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); | ||
785 | sysfs_remove_bin_file(&pdev->dev.kobj, &pch_bin_attr); | ||
786 | pci_unmap_rom(pdev, chip->pch_phub_extrom_base_address); | ||
787 | pci_iounmap(pdev, chip->pch_phub_base_address); | ||
788 | pci_release_regions(pdev); | ||
789 | pci_disable_device(pdev); | ||
790 | kfree(chip); | ||
791 | } | ||
792 | |||
793 | #ifdef CONFIG_PM | ||
794 | |||
795 | static int pch_phub_suspend(struct pci_dev *pdev, pm_message_t state) | ||
796 | { | ||
797 | int ret; | ||
798 | |||
799 | pch_phub_save_reg_conf(pdev); | ||
800 | ret = pci_save_state(pdev); | ||
801 | if (ret) { | ||
802 | dev_err(&pdev->dev, | ||
803 | " %s -pci_save_state returns %d\n", __func__, ret); | ||
804 | return ret; | ||
805 | } | ||
806 | pci_enable_wake(pdev, PCI_D3hot, 0); | ||
807 | pci_disable_device(pdev); | ||
808 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | ||
809 | |||
810 | return 0; | ||
811 | } | ||
812 | |||
813 | static int pch_phub_resume(struct pci_dev *pdev) | ||
814 | { | ||
815 | int ret; | ||
816 | |||
817 | pci_set_power_state(pdev, PCI_D0); | ||
818 | pci_restore_state(pdev); | ||
819 | ret = pci_enable_device(pdev); | ||
820 | if (ret) { | ||
821 | dev_err(&pdev->dev, | ||
822 | "%s-pci_enable_device failed(ret=%d) ", __func__, ret); | ||
823 | return ret; | ||
824 | } | ||
825 | |||
826 | pci_enable_wake(pdev, PCI_D3hot, 0); | ||
827 | pch_phub_restore_reg_conf(pdev); | ||
828 | |||
829 | return 0; | ||
830 | } | ||
831 | #else | ||
832 | #define pch_phub_suspend NULL | ||
833 | #define pch_phub_resume NULL | ||
834 | #endif /* CONFIG_PM */ | ||
835 | |||
836 | static struct pci_device_id pch_phub_pcidev_id[] = { | ||
837 | { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH1_PHUB), 1, }, | ||
838 | { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7213_PHUB), 2, }, | ||
839 | { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7223_mPHUB), 3, }, | ||
840 | { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7223_nPHUB), 4, }, | ||
841 | { } | ||
842 | }; | ||
843 | MODULE_DEVICE_TABLE(pci, pch_phub_pcidev_id); | ||
844 | |||
845 | static struct pci_driver pch_phub_driver = { | ||
846 | .name = "pch_phub", | ||
847 | .id_table = pch_phub_pcidev_id, | ||
848 | .probe = pch_phub_probe, | ||
849 | .remove = __devexit_p(pch_phub_remove), | ||
850 | .suspend = pch_phub_suspend, | ||
851 | .resume = pch_phub_resume | ||
852 | }; | ||
853 | |||
854 | static int __init pch_phub_pci_init(void) | ||
855 | { | ||
856 | return pci_register_driver(&pch_phub_driver); | ||
857 | } | ||
858 | |||
859 | static void __exit pch_phub_pci_exit(void) | ||
860 | { | ||
861 | pci_unregister_driver(&pch_phub_driver); | ||
862 | } | ||
863 | |||
864 | module_init(pch_phub_pci_init); | ||
865 | module_exit(pch_phub_pci_exit); | ||
866 | |||
867 | MODULE_DESCRIPTION("Intel EG20T PCH/OKI SEMICONDUCTOR IOH(ML7213/ML7223) PHUB"); | ||
868 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index 75ee0d3f6f45..b05db55c8c8e 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/phantom.h> | 25 | #include <linux/phantom.h> |
26 | #include <linux/sched.h> | 26 | #include <linux/sched.h> |
27 | #include <linux/smp_lock.h> | 27 | #include <linux/mutex.h> |
28 | 28 | ||
29 | #include <asm/atomic.h> | 29 | #include <asm/atomic.h> |
30 | #include <asm/io.h> | 30 | #include <asm/io.h> |
@@ -38,6 +38,7 @@ | |||
38 | #define PHB_RUNNING 1 | 38 | #define PHB_RUNNING 1 |
39 | #define PHB_NOT_OH 2 | 39 | #define PHB_NOT_OH 2 |
40 | 40 | ||
41 | static DEFINE_MUTEX(phantom_mutex); | ||
41 | static struct class *phantom_class; | 42 | static struct class *phantom_class; |
42 | static int phantom_major; | 43 | static int phantom_major; |
43 | 44 | ||
@@ -215,17 +216,17 @@ static int phantom_open(struct inode *inode, struct file *file) | |||
215 | struct phantom_device *dev = container_of(inode->i_cdev, | 216 | struct phantom_device *dev = container_of(inode->i_cdev, |
216 | struct phantom_device, cdev); | 217 | struct phantom_device, cdev); |
217 | 218 | ||
218 | lock_kernel(); | 219 | mutex_lock(&phantom_mutex); |
219 | nonseekable_open(inode, file); | 220 | nonseekable_open(inode, file); |
220 | 221 | ||
221 | if (mutex_lock_interruptible(&dev->open_lock)) { | 222 | if (mutex_lock_interruptible(&dev->open_lock)) { |
222 | unlock_kernel(); | 223 | mutex_unlock(&phantom_mutex); |
223 | return -ERESTARTSYS; | 224 | return -ERESTARTSYS; |
224 | } | 225 | } |
225 | 226 | ||
226 | if (dev->opened) { | 227 | if (dev->opened) { |
227 | mutex_unlock(&dev->open_lock); | 228 | mutex_unlock(&dev->open_lock); |
228 | unlock_kernel(); | 229 | mutex_unlock(&phantom_mutex); |
229 | return -EINVAL; | 230 | return -EINVAL; |
230 | } | 231 | } |
231 | 232 | ||
@@ -236,7 +237,7 @@ static int phantom_open(struct inode *inode, struct file *file) | |||
236 | atomic_set(&dev->counter, 0); | 237 | atomic_set(&dev->counter, 0); |
237 | dev->opened++; | 238 | dev->opened++; |
238 | mutex_unlock(&dev->open_lock); | 239 | mutex_unlock(&dev->open_lock); |
239 | unlock_kernel(); | 240 | mutex_unlock(&phantom_mutex); |
240 | return 0; | 241 | return 0; |
241 | } | 242 | } |
242 | 243 | ||
@@ -279,6 +280,7 @@ static const struct file_operations phantom_file_ops = { | |||
279 | .unlocked_ioctl = phantom_ioctl, | 280 | .unlocked_ioctl = phantom_ioctl, |
280 | .compat_ioctl = phantom_compat_ioctl, | 281 | .compat_ioctl = phantom_compat_ioctl, |
281 | .poll = phantom_poll, | 282 | .poll = phantom_poll, |
283 | .llseek = no_llseek, | ||
282 | }; | 284 | }; |
283 | 285 | ||
284 | static irqreturn_t phantom_isr(int irq, void *data) | 286 | static irqreturn_t phantom_isr(int irq, void *data) |
@@ -341,8 +343,10 @@ static int __devinit phantom_probe(struct pci_dev *pdev, | |||
341 | int retval; | 343 | int retval; |
342 | 344 | ||
343 | retval = pci_enable_device(pdev); | 345 | retval = pci_enable_device(pdev); |
344 | if (retval) | 346 | if (retval) { |
347 | dev_err(&pdev->dev, "pci_enable_device failed!\n"); | ||
345 | goto err; | 348 | goto err; |
349 | } | ||
346 | 350 | ||
347 | minor = phantom_get_free(); | 351 | minor = phantom_get_free(); |
348 | if (minor == PHANTOM_MAX_MINORS) { | 352 | if (minor == PHANTOM_MAX_MINORS) { |
@@ -354,8 +358,10 @@ static int __devinit phantom_probe(struct pci_dev *pdev, | |||
354 | phantom_devices[minor] = 1; | 358 | phantom_devices[minor] = 1; |
355 | 359 | ||
356 | retval = pci_request_regions(pdev, "phantom"); | 360 | retval = pci_request_regions(pdev, "phantom"); |
357 | if (retval) | 361 | if (retval) { |
362 | dev_err(&pdev->dev, "pci_request_regions failed!\n"); | ||
358 | goto err_null; | 363 | goto err_null; |
364 | } | ||
359 | 365 | ||
360 | retval = -ENOMEM; | 366 | retval = -ENOMEM; |
361 | pht = kzalloc(sizeof(*pht), GFP_KERNEL); | 367 | pht = kzalloc(sizeof(*pht), GFP_KERNEL); |
diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c new file mode 100644 index 000000000000..374dfcfccd07 --- /dev/null +++ b/drivers/misc/pti.c | |||
@@ -0,0 +1,983 @@ | |||
1 | /* | ||
2 | * pti.c - PTI driver for cJTAG data extration | ||
3 | * | ||
4 | * Copyright (C) Intel 2010 | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
16 | * | ||
17 | * The PTI (Parallel Trace Interface) driver directs trace data routed from | ||
18 | * various parts in the system out through the Intel Penwell PTI port and | ||
19 | * out of the mobile device for analysis with a debugging tool | ||
20 | * (Lauterbach, Fido). This is part of a solution for the MIPI P1149.7, | ||
21 | * compact JTAG, standard. | ||
22 | */ | ||
23 | |||
24 | #include <linux/init.h> | ||
25 | #include <linux/sched.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/console.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/tty.h> | ||
31 | #include <linux/tty_driver.h> | ||
32 | #include <linux/pci.h> | ||
33 | #include <linux/mutex.h> | ||
34 | #include <linux/miscdevice.h> | ||
35 | #include <linux/pti.h> | ||
36 | |||
37 | #define DRIVERNAME "pti" | ||
38 | #define PCINAME "pciPTI" | ||
39 | #define TTYNAME "ttyPTI" | ||
40 | #define CHARNAME "pti" | ||
41 | #define PTITTY_MINOR_START 0 | ||
42 | #define PTITTY_MINOR_NUM 2 | ||
43 | #define MAX_APP_IDS 16 /* 128 channel ids / u8 bit size */ | ||
44 | #define MAX_OS_IDS 16 /* 128 channel ids / u8 bit size */ | ||
45 | #define MAX_MODEM_IDS 16 /* 128 channel ids / u8 bit size */ | ||
46 | #define MODEM_BASE_ID 71 /* modem master ID address */ | ||
47 | #define CONTROL_ID 72 /* control master ID address */ | ||
48 | #define CONSOLE_ID 73 /* console master ID address */ | ||
49 | #define OS_BASE_ID 74 /* base OS master ID address */ | ||
50 | #define APP_BASE_ID 80 /* base App master ID address */ | ||
51 | #define CONTROL_FRAME_LEN 32 /* PTI control frame maximum size */ | ||
52 | #define USER_COPY_SIZE 8192 /* 8Kb buffer for user space copy */ | ||
53 | #define APERTURE_14 0x3800000 /* offset to first OS write addr */ | ||
54 | #define APERTURE_LEN 0x400000 /* address length */ | ||
55 | |||
56 | struct pti_tty { | ||
57 | struct pti_masterchannel *mc; | ||
58 | }; | ||
59 | |||
60 | struct pti_dev { | ||
61 | struct tty_port port; | ||
62 | unsigned long pti_addr; | ||
63 | unsigned long aperture_base; | ||
64 | void __iomem *pti_ioaddr; | ||
65 | u8 ia_app[MAX_APP_IDS]; | ||
66 | u8 ia_os[MAX_OS_IDS]; | ||
67 | u8 ia_modem[MAX_MODEM_IDS]; | ||
68 | }; | ||
69 | |||
70 | /* | ||
71 | * This protects access to ia_app, ia_os, and ia_modem, | ||
72 | * which keeps track of channels allocated in | ||
73 | * an aperture write id. | ||
74 | */ | ||
75 | static DEFINE_MUTEX(alloclock); | ||
76 | |||
77 | static struct pci_device_id pci_ids[] __devinitconst = { | ||
78 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x82B)}, | ||
79 | {0} | ||
80 | }; | ||
81 | |||
82 | static struct tty_driver *pti_tty_driver; | ||
83 | static struct pti_dev *drv_data; | ||
84 | |||
85 | static unsigned int pti_console_channel; | ||
86 | static unsigned int pti_control_channel; | ||
87 | |||
88 | /** | ||
89 | * pti_write_to_aperture()- The private write function to PTI HW. | ||
90 | * | ||
91 | * @mc: The 'aperture'. It's part of a write address that holds | ||
92 | * a master and channel ID. | ||
93 | * @buf: Data being written to the HW that will ultimately be seen | ||
94 | * in a debugging tool (Fido, Lauterbach). | ||
95 | * @len: Size of buffer. | ||
96 | * | ||
97 | * Since each aperture is specified by a unique | ||
98 | * master/channel ID, no two processes will be writing | ||
99 | * to the same aperture at the same time so no lock is required. The | ||
100 | * PTI-Output agent will send these out in the order that they arrived, and | ||
101 | * thus, it will intermix these messages. The debug tool can then later | ||
102 | * regroup the appropriate message segments together reconstituting each | ||
103 | * message. | ||
104 | */ | ||
105 | static void pti_write_to_aperture(struct pti_masterchannel *mc, | ||
106 | u8 *buf, | ||
107 | int len) | ||
108 | { | ||
109 | int dwordcnt; | ||
110 | int final; | ||
111 | int i; | ||
112 | u32 ptiword; | ||
113 | u32 __iomem *aperture; | ||
114 | u8 *p = buf; | ||
115 | |||
116 | /* | ||
117 | * calculate the aperture offset from the base using the master and | ||
118 | * channel id's. | ||
119 | */ | ||
120 | aperture = drv_data->pti_ioaddr + (mc->master << 15) | ||
121 | + (mc->channel << 8); | ||
122 | |||
123 | dwordcnt = len >> 2; | ||
124 | final = len - (dwordcnt << 2); /* final = trailing bytes */ | ||
125 | if (final == 0 && dwordcnt != 0) { /* always need a final dword */ | ||
126 | final += 4; | ||
127 | dwordcnt--; | ||
128 | } | ||
129 | |||
130 | for (i = 0; i < dwordcnt; i++) { | ||
131 | ptiword = be32_to_cpu(*(u32 *)p); | ||
132 | p += 4; | ||
133 | iowrite32(ptiword, aperture); | ||
134 | } | ||
135 | |||
136 | aperture += PTI_LASTDWORD_DTS; /* adding DTS signals that is EOM */ | ||
137 | |||
138 | ptiword = 0; | ||
139 | for (i = 0; i < final; i++) | ||
140 | ptiword |= *p++ << (24-(8*i)); | ||
141 | |||
142 | iowrite32(ptiword, aperture); | ||
143 | return; | ||
144 | } | ||
145 | |||
146 | /** | ||
147 | * pti_control_frame_built_and_sent()- control frame build and send function. | ||
148 | * | ||
149 | * @mc: The master / channel structure on which the function | ||
150 | * built a control frame. | ||
151 | * | ||
152 | * To be able to post process the PTI contents on host side, a control frame | ||
153 | * is added before sending any PTI content. So the host side knows on | ||
154 | * each PTI frame the name of the thread using a dedicated master / channel. | ||
155 | * The thread name is retrieved from the 'current' global variable. | ||
156 | * This function builds this frame and sends it to a master ID CONTROL_ID. | ||
157 | * The overhead is only 32 bytes since the driver only writes to HW | ||
158 | * in 32 byte chunks. | ||
159 | */ | ||
160 | |||
161 | static void pti_control_frame_built_and_sent(struct pti_masterchannel *mc) | ||
162 | { | ||
163 | struct pti_masterchannel mccontrol = {.master = CONTROL_ID, | ||
164 | .channel = 0}; | ||
165 | const char *control_format = "%3d %3d %s"; | ||
166 | u8 control_frame[CONTROL_FRAME_LEN]; | ||
167 | |||
168 | /* | ||
169 | * Since we access the comm member in current's task_struct, | ||
170 | * we only need to be as large as what 'comm' in that | ||
171 | * structure is. | ||
172 | */ | ||
173 | char comm[TASK_COMM_LEN]; | ||
174 | |||
175 | if (!in_interrupt()) | ||
176 | get_task_comm(comm, current); | ||
177 | else | ||
178 | strncpy(comm, "Interrupt", TASK_COMM_LEN); | ||
179 | |||
180 | /* Absolutely ensure our buffer is zero terminated. */ | ||
181 | comm[TASK_COMM_LEN-1] = 0; | ||
182 | |||
183 | mccontrol.channel = pti_control_channel; | ||
184 | pti_control_channel = (pti_control_channel + 1) & 0x7f; | ||
185 | |||
186 | snprintf(control_frame, CONTROL_FRAME_LEN, control_format, mc->master, | ||
187 | mc->channel, comm); | ||
188 | pti_write_to_aperture(&mccontrol, control_frame, strlen(control_frame)); | ||
189 | } | ||
190 | |||
191 | /** | ||
192 | * pti_write_full_frame_to_aperture()- high level function to | ||
193 | * write to PTI. | ||
194 | * | ||
195 | * @mc: The 'aperture'. It's part of a write address that holds | ||
196 | * a master and channel ID. | ||
197 | * @buf: Data being written to the HW that will ultimately be seen | ||
198 | * in a debugging tool (Fido, Lauterbach). | ||
199 | * @len: Size of buffer. | ||
200 | * | ||
201 | * All threads sending data (either console, user space application, ...) | ||
202 | * are calling the high level function to write to PTI meaning that it is | ||
203 | * possible to add a control frame before sending the content. | ||
204 | */ | ||
205 | static void pti_write_full_frame_to_aperture(struct pti_masterchannel *mc, | ||
206 | const unsigned char *buf, | ||
207 | int len) | ||
208 | { | ||
209 | pti_control_frame_built_and_sent(mc); | ||
210 | pti_write_to_aperture(mc, (u8 *)buf, len); | ||
211 | } | ||
212 | |||
213 | /** | ||
214 | * get_id()- Allocate a master and channel ID. | ||
215 | * | ||
216 | * @id_array: an array of bits representing what channel | ||
217 | * id's are allocated for writing. | ||
218 | * @max_ids: The max amount of available write IDs to use. | ||
219 | * @base_id: The starting SW channel ID, based on the Intel | ||
220 | * PTI arch. | ||
221 | * | ||
222 | * Returns: | ||
223 | * pti_masterchannel struct with master, channel ID address | ||
224 | * 0 for error | ||
225 | * | ||
226 | * Each bit in the arrays ia_app and ia_os correspond to a master and | ||
227 | * channel id. The bit is one if the id is taken and 0 if free. For | ||
228 | * every master there are 128 channel id's. | ||
229 | */ | ||
230 | static struct pti_masterchannel *get_id(u8 *id_array, int max_ids, int base_id) | ||
231 | { | ||
232 | struct pti_masterchannel *mc; | ||
233 | int i, j, mask; | ||
234 | |||
235 | mc = kmalloc(sizeof(struct pti_masterchannel), GFP_KERNEL); | ||
236 | if (mc == NULL) | ||
237 | return NULL; | ||
238 | |||
239 | /* look for a byte with a free bit */ | ||
240 | for (i = 0; i < max_ids; i++) | ||
241 | if (id_array[i] != 0xff) | ||
242 | break; | ||
243 | if (i == max_ids) { | ||
244 | kfree(mc); | ||
245 | return NULL; | ||
246 | } | ||
247 | /* find the bit in the 128 possible channel opportunities */ | ||
248 | mask = 0x80; | ||
249 | for (j = 0; j < 8; j++) { | ||
250 | if ((id_array[i] & mask) == 0) | ||
251 | break; | ||
252 | mask >>= 1; | ||
253 | } | ||
254 | |||
255 | /* grab it */ | ||
256 | id_array[i] |= mask; | ||
257 | mc->master = base_id; | ||
258 | mc->channel = ((i & 0xf)<<3) + j; | ||
259 | /* write new master Id / channel Id allocation to channel control */ | ||
260 | pti_control_frame_built_and_sent(mc); | ||
261 | return mc; | ||
262 | } | ||
263 | |||
264 | /* | ||
265 | * The following three functions: | ||
266 | * pti_request_mastercahannel(), mipi_release_masterchannel() | ||
267 | * and pti_writedata() are an API for other kernel drivers to | ||
268 | * access PTI. | ||
269 | */ | ||
270 | |||
271 | /** | ||
272 | * pti_request_masterchannel()- Kernel API function used to allocate | ||
273 | * a master, channel ID address | ||
274 | * to write to PTI HW. | ||
275 | * | ||
276 | * @type: 0- request Application master, channel aperture ID write address. | ||
277 | * 1- request OS master, channel aperture ID write | ||
278 | * address. | ||
279 | * 2- request Modem master, channel aperture ID | ||
280 | * write address. | ||
281 | * Other values, error. | ||
282 | * | ||
283 | * Returns: | ||
284 | * pti_masterchannel struct | ||
285 | * 0 for error | ||
286 | */ | ||
287 | struct pti_masterchannel *pti_request_masterchannel(u8 type) | ||
288 | { | ||
289 | struct pti_masterchannel *mc; | ||
290 | |||
291 | mutex_lock(&alloclock); | ||
292 | |||
293 | switch (type) { | ||
294 | |||
295 | case 0: | ||
296 | mc = get_id(drv_data->ia_app, MAX_APP_IDS, APP_BASE_ID); | ||
297 | break; | ||
298 | |||
299 | case 1: | ||
300 | mc = get_id(drv_data->ia_os, MAX_OS_IDS, OS_BASE_ID); | ||
301 | break; | ||
302 | |||
303 | case 2: | ||
304 | mc = get_id(drv_data->ia_modem, MAX_MODEM_IDS, MODEM_BASE_ID); | ||
305 | break; | ||
306 | default: | ||
307 | mc = NULL; | ||
308 | } | ||
309 | |||
310 | mutex_unlock(&alloclock); | ||
311 | return mc; | ||
312 | } | ||
313 | EXPORT_SYMBOL_GPL(pti_request_masterchannel); | ||
314 | |||
315 | /** | ||
316 | * pti_release_masterchannel()- Kernel API function used to release | ||
317 | * a master, channel ID address | ||
318 | * used to write to PTI HW. | ||
319 | * | ||
320 | * @mc: master, channel apeture ID address to be released. This | ||
321 | * will de-allocate the structure via kfree(). | ||
322 | */ | ||
323 | void pti_release_masterchannel(struct pti_masterchannel *mc) | ||
324 | { | ||
325 | u8 master, channel, i; | ||
326 | |||
327 | mutex_lock(&alloclock); | ||
328 | |||
329 | if (mc) { | ||
330 | master = mc->master; | ||
331 | channel = mc->channel; | ||
332 | |||
333 | if (master == APP_BASE_ID) { | ||
334 | i = channel >> 3; | ||
335 | drv_data->ia_app[i] &= ~(0x80>>(channel & 0x7)); | ||
336 | } else if (master == OS_BASE_ID) { | ||
337 | i = channel >> 3; | ||
338 | drv_data->ia_os[i] &= ~(0x80>>(channel & 0x7)); | ||
339 | } else { | ||
340 | i = channel >> 3; | ||
341 | drv_data->ia_modem[i] &= ~(0x80>>(channel & 0x7)); | ||
342 | } | ||
343 | |||
344 | kfree(mc); | ||
345 | } | ||
346 | |||
347 | mutex_unlock(&alloclock); | ||
348 | } | ||
349 | EXPORT_SYMBOL_GPL(pti_release_masterchannel); | ||
350 | |||
351 | /** | ||
352 | * pti_writedata()- Kernel API function used to write trace | ||
353 | * debugging data to PTI HW. | ||
354 | * | ||
355 | * @mc: Master, channel aperture ID address to write to. | ||
356 | * Null value will return with no write occurring. | ||
357 | * @buf: Trace debuging data to write to the PTI HW. | ||
358 | * Null value will return with no write occurring. | ||
359 | * @count: Size of buf. Value of 0 or a negative number will | ||
360 | * return with no write occuring. | ||
361 | */ | ||
362 | void pti_writedata(struct pti_masterchannel *mc, u8 *buf, int count) | ||
363 | { | ||
364 | /* | ||
365 | * since this function is exported, this is treated like an | ||
366 | * API function, thus, all parameters should | ||
367 | * be checked for validity. | ||
368 | */ | ||
369 | if ((mc != NULL) && (buf != NULL) && (count > 0)) | ||
370 | pti_write_to_aperture(mc, buf, count); | ||
371 | return; | ||
372 | } | ||
373 | EXPORT_SYMBOL_GPL(pti_writedata); | ||
374 | |||
375 | /** | ||
376 | * pti_pci_remove()- Driver exit method to remove PTI from | ||
377 | * PCI bus. | ||
378 | * @pdev: variable containing pci info of PTI. | ||
379 | */ | ||
380 | static void __devexit pti_pci_remove(struct pci_dev *pdev) | ||
381 | { | ||
382 | struct pti_dev *drv_data; | ||
383 | |||
384 | drv_data = pci_get_drvdata(pdev); | ||
385 | if (drv_data != NULL) { | ||
386 | pci_iounmap(pdev, drv_data->pti_ioaddr); | ||
387 | pci_set_drvdata(pdev, NULL); | ||
388 | kfree(drv_data); | ||
389 | pci_release_region(pdev, 1); | ||
390 | pci_disable_device(pdev); | ||
391 | } | ||
392 | } | ||
393 | |||
394 | /* | ||
395 | * for the tty_driver_*() basic function descriptions, see tty_driver.h. | ||
396 | * Specific header comments made for PTI-related specifics. | ||
397 | */ | ||
398 | |||
399 | /** | ||
400 | * pti_tty_driver_open()- Open an Application master, channel aperture | ||
401 | * ID to the PTI device via tty device. | ||
402 | * | ||
403 | * @tty: tty interface. | ||
404 | * @filp: filp interface pased to tty_port_open() call. | ||
405 | * | ||
406 | * Returns: | ||
407 | * int, 0 for success | ||
408 | * otherwise, fail value | ||
409 | * | ||
410 | * The main purpose of using the tty device interface is for | ||
411 | * each tty port to have a unique PTI write aperture. In an | ||
412 | * example use case, ttyPTI0 gets syslogd and an APP aperture | ||
413 | * ID and ttyPTI1 is where the n_tracesink ldisc hooks to route | ||
414 | * modem messages into PTI. Modem trace data does not have to | ||
415 | * go to ttyPTI1, but ttyPTI0 and ttyPTI1 do need to be distinct | ||
416 | * master IDs. These messages go through the PTI HW and out of | ||
417 | * the handheld platform and to the Fido/Lauterbach device. | ||
418 | */ | ||
419 | static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp) | ||
420 | { | ||
421 | /* | ||
422 | * we actually want to allocate a new channel per open, per | ||
423 | * system arch. HW gives more than plenty channels for a single | ||
424 | * system task to have its own channel to write trace data. This | ||
425 | * also removes a locking requirement for the actual write | ||
426 | * procedure. | ||
427 | */ | ||
428 | return tty_port_open(&drv_data->port, tty, filp); | ||
429 | } | ||
430 | |||
431 | /** | ||
432 | * pti_tty_driver_close()- close tty device and release Application | ||
433 | * master, channel aperture ID to the PTI device via tty device. | ||
434 | * | ||
435 | * @tty: tty interface. | ||
436 | * @filp: filp interface pased to tty_port_close() call. | ||
437 | * | ||
438 | * The main purpose of using the tty device interface is to route | ||
439 | * syslog daemon messages to the PTI HW and out of the handheld platform | ||
440 | * and to the Fido/Lauterbach device. | ||
441 | */ | ||
442 | static void pti_tty_driver_close(struct tty_struct *tty, struct file *filp) | ||
443 | { | ||
444 | tty_port_close(&drv_data->port, tty, filp); | ||
445 | } | ||
446 | |||
447 | /** | ||
448 | * pti_tty_intstall()- Used to set up specific master-channels | ||
449 | * to tty ports for organizational purposes when | ||
450 | * tracing viewed from debuging tools. | ||
451 | * | ||
452 | * @driver: tty driver information. | ||
453 | * @tty: tty struct containing pti information. | ||
454 | * | ||
455 | * Returns: | ||
456 | * 0 for success | ||
457 | * otherwise, error | ||
458 | */ | ||
459 | static int pti_tty_install(struct tty_driver *driver, struct tty_struct *tty) | ||
460 | { | ||
461 | int idx = tty->index; | ||
462 | struct pti_tty *pti_tty_data; | ||
463 | int ret = tty_init_termios(tty); | ||
464 | |||
465 | if (ret == 0) { | ||
466 | tty_driver_kref_get(driver); | ||
467 | tty->count++; | ||
468 | driver->ttys[idx] = tty; | ||
469 | |||
470 | pti_tty_data = kmalloc(sizeof(struct pti_tty), GFP_KERNEL); | ||
471 | if (pti_tty_data == NULL) | ||
472 | return -ENOMEM; | ||
473 | |||
474 | if (idx == PTITTY_MINOR_START) | ||
475 | pti_tty_data->mc = pti_request_masterchannel(0); | ||
476 | else | ||
477 | pti_tty_data->mc = pti_request_masterchannel(2); | ||
478 | |||
479 | if (pti_tty_data->mc == NULL) { | ||
480 | kfree(pti_tty_data); | ||
481 | return -ENXIO; | ||
482 | } | ||
483 | tty->driver_data = pti_tty_data; | ||
484 | } | ||
485 | |||
486 | return ret; | ||
487 | } | ||
488 | |||
489 | /** | ||
490 | * pti_tty_cleanup()- Used to de-allocate master-channel resources | ||
491 | * tied to tty's of this driver. | ||
492 | * | ||
493 | * @tty: tty struct containing pti information. | ||
494 | */ | ||
495 | static void pti_tty_cleanup(struct tty_struct *tty) | ||
496 | { | ||
497 | struct pti_tty *pti_tty_data = tty->driver_data; | ||
498 | if (pti_tty_data == NULL) | ||
499 | return; | ||
500 | pti_release_masterchannel(pti_tty_data->mc); | ||
501 | kfree(pti_tty_data); | ||
502 | tty->driver_data = NULL; | ||
503 | } | ||
504 | |||
505 | /** | ||
506 | * pti_tty_driver_write()- Write trace debugging data through the char | ||
507 | * interface to the PTI HW. Part of the misc device implementation. | ||
508 | * | ||
509 | * @filp: Contains private data which is used to obtain | ||
510 | * master, channel write ID. | ||
511 | * @data: trace data to be written. | ||
512 | * @len: # of byte to write. | ||
513 | * | ||
514 | * Returns: | ||
515 | * int, # of bytes written | ||
516 | * otherwise, error | ||
517 | */ | ||
518 | static int pti_tty_driver_write(struct tty_struct *tty, | ||
519 | const unsigned char *buf, int len) | ||
520 | { | ||
521 | struct pti_tty *pti_tty_data = tty->driver_data; | ||
522 | if ((pti_tty_data != NULL) && (pti_tty_data->mc != NULL)) { | ||
523 | pti_write_to_aperture(pti_tty_data->mc, (u8 *)buf, len); | ||
524 | return len; | ||
525 | } | ||
526 | /* | ||
527 | * we can't write to the pti hardware if the private driver_data | ||
528 | * and the mc address is not there. | ||
529 | */ | ||
530 | else | ||
531 | return -EFAULT; | ||
532 | } | ||
533 | |||
534 | /** | ||
535 | * pti_tty_write_room()- Always returns 2048. | ||
536 | * | ||
537 | * @tty: contains tty info of the pti driver. | ||
538 | */ | ||
539 | static int pti_tty_write_room(struct tty_struct *tty) | ||
540 | { | ||
541 | return 2048; | ||
542 | } | ||
543 | |||
544 | /** | ||
545 | * pti_char_open()- Open an Application master, channel aperture | ||
546 | * ID to the PTI device. Part of the misc device implementation. | ||
547 | * | ||
548 | * @inode: not used. | ||
549 | * @filp: Output- will have a masterchannel struct set containing | ||
550 | * the allocated application PTI aperture write address. | ||
551 | * | ||
552 | * Returns: | ||
553 | * int, 0 for success | ||
554 | * otherwise, a fail value | ||
555 | */ | ||
556 | static int pti_char_open(struct inode *inode, struct file *filp) | ||
557 | { | ||
558 | struct pti_masterchannel *mc; | ||
559 | |||
560 | /* | ||
561 | * We really do want to fail immediately if | ||
562 | * pti_request_masterchannel() fails, | ||
563 | * before assigning the value to filp->private_data. | ||
564 | * Slightly easier to debug if this driver needs debugging. | ||
565 | */ | ||
566 | mc = pti_request_masterchannel(0); | ||
567 | if (mc == NULL) | ||
568 | return -ENOMEM; | ||
569 | filp->private_data = mc; | ||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | /** | ||
574 | * pti_char_release()- Close a char channel to the PTI device. Part | ||
575 | * of the misc device implementation. | ||
576 | * | ||
577 | * @inode: Not used in this implementaiton. | ||
578 | * @filp: Contains private_data that contains the master, channel | ||
579 | * ID to be released by the PTI device. | ||
580 | * | ||
581 | * Returns: | ||
582 | * always 0 | ||
583 | */ | ||
584 | static int pti_char_release(struct inode *inode, struct file *filp) | ||
585 | { | ||
586 | pti_release_masterchannel(filp->private_data); | ||
587 | filp->private_data = NULL; | ||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | /** | ||
592 | * pti_char_write()- Write trace debugging data through the char | ||
593 | * interface to the PTI HW. Part of the misc device implementation. | ||
594 | * | ||
595 | * @filp: Contains private data which is used to obtain | ||
596 | * master, channel write ID. | ||
597 | * @data: trace data to be written. | ||
598 | * @len: # of byte to write. | ||
599 | * @ppose: Not used in this function implementation. | ||
600 | * | ||
601 | * Returns: | ||
602 | * int, # of bytes written | ||
603 | * otherwise, error value | ||
604 | * | ||
605 | * Notes: From side discussions with Alan Cox and experimenting | ||
606 | * with PTI debug HW like Nokia's Fido box and Lauterbach | ||
607 | * devices, 8192 byte write buffer used by USER_COPY_SIZE was | ||
608 | * deemed an appropriate size for this type of usage with | ||
609 | * debugging HW. | ||
610 | */ | ||
611 | static ssize_t pti_char_write(struct file *filp, const char __user *data, | ||
612 | size_t len, loff_t *ppose) | ||
613 | { | ||
614 | struct pti_masterchannel *mc; | ||
615 | void *kbuf; | ||
616 | const char __user *tmp; | ||
617 | size_t size = USER_COPY_SIZE; | ||
618 | size_t n = 0; | ||
619 | |||
620 | tmp = data; | ||
621 | mc = filp->private_data; | ||
622 | |||
623 | kbuf = kmalloc(size, GFP_KERNEL); | ||
624 | if (kbuf == NULL) { | ||
625 | pr_err("%s(%d): buf allocation failed\n", | ||
626 | __func__, __LINE__); | ||
627 | return -ENOMEM; | ||
628 | } | ||
629 | |||
630 | do { | ||
631 | if (len - n > USER_COPY_SIZE) | ||
632 | size = USER_COPY_SIZE; | ||
633 | else | ||
634 | size = len - n; | ||
635 | |||
636 | if (copy_from_user(kbuf, tmp, size)) { | ||
637 | kfree(kbuf); | ||
638 | return n ? n : -EFAULT; | ||
639 | } | ||
640 | |||
641 | pti_write_to_aperture(mc, kbuf, size); | ||
642 | n += size; | ||
643 | tmp += size; | ||
644 | |||
645 | } while (len > n); | ||
646 | |||
647 | kfree(kbuf); | ||
648 | return len; | ||
649 | } | ||
650 | |||
651 | static const struct tty_operations pti_tty_driver_ops = { | ||
652 | .open = pti_tty_driver_open, | ||
653 | .close = pti_tty_driver_close, | ||
654 | .write = pti_tty_driver_write, | ||
655 | .write_room = pti_tty_write_room, | ||
656 | .install = pti_tty_install, | ||
657 | .cleanup = pti_tty_cleanup | ||
658 | }; | ||
659 | |||
660 | static const struct file_operations pti_char_driver_ops = { | ||
661 | .owner = THIS_MODULE, | ||
662 | .write = pti_char_write, | ||
663 | .open = pti_char_open, | ||
664 | .release = pti_char_release, | ||
665 | }; | ||
666 | |||
667 | static struct miscdevice pti_char_driver = { | ||
668 | .minor = MISC_DYNAMIC_MINOR, | ||
669 | .name = CHARNAME, | ||
670 | .fops = &pti_char_driver_ops | ||
671 | }; | ||
672 | |||
673 | /** | ||
674 | * pti_console_write()- Write to the console that has been acquired. | ||
675 | * | ||
676 | * @c: Not used in this implementaiton. | ||
677 | * @buf: Data to be written. | ||
678 | * @len: Length of buf. | ||
679 | */ | ||
680 | static void pti_console_write(struct console *c, const char *buf, unsigned len) | ||
681 | { | ||
682 | static struct pti_masterchannel mc = {.master = CONSOLE_ID, | ||
683 | .channel = 0}; | ||
684 | |||
685 | mc.channel = pti_console_channel; | ||
686 | pti_console_channel = (pti_console_channel + 1) & 0x7f; | ||
687 | |||
688 | pti_write_full_frame_to_aperture(&mc, buf, len); | ||
689 | } | ||
690 | |||
691 | /** | ||
692 | * pti_console_device()- Return the driver tty structure and set the | ||
693 | * associated index implementation. | ||
694 | * | ||
695 | * @c: Console device of the driver. | ||
696 | * @index: index associated with c. | ||
697 | * | ||
698 | * Returns: | ||
699 | * always value of pti_tty_driver structure when this function | ||
700 | * is called. | ||
701 | */ | ||
702 | static struct tty_driver *pti_console_device(struct console *c, int *index) | ||
703 | { | ||
704 | *index = c->index; | ||
705 | return pti_tty_driver; | ||
706 | } | ||
707 | |||
708 | /** | ||
709 | * pti_console_setup()- Initialize console variables used by the driver. | ||
710 | * | ||
711 | * @c: Not used. | ||
712 | * @opts: Not used. | ||
713 | * | ||
714 | * Returns: | ||
715 | * always 0. | ||
716 | */ | ||
717 | static int pti_console_setup(struct console *c, char *opts) | ||
718 | { | ||
719 | pti_console_channel = 0; | ||
720 | pti_control_channel = 0; | ||
721 | return 0; | ||
722 | } | ||
723 | |||
724 | /* | ||
725 | * pti_console struct, used to capture OS printk()'s and shift | ||
726 | * out to the PTI device for debugging. This cannot be | ||
727 | * enabled upon boot because of the possibility of eating | ||
728 | * any serial console printk's (race condition discovered). | ||
729 | * The console should be enabled upon when the tty port is | ||
730 | * used for the first time. Since the primary purpose for | ||
731 | * the tty port is to hook up syslog to it, the tty port | ||
732 | * will be open for a really long time. | ||
733 | */ | ||
734 | static struct console pti_console = { | ||
735 | .name = TTYNAME, | ||
736 | .write = pti_console_write, | ||
737 | .device = pti_console_device, | ||
738 | .setup = pti_console_setup, | ||
739 | .flags = CON_PRINTBUFFER, | ||
740 | .index = 0, | ||
741 | }; | ||
742 | |||
743 | /** | ||
744 | * pti_port_activate()- Used to start/initialize any items upon | ||
745 | * first opening of tty_port(). | ||
746 | * | ||
747 | * @port- The tty port number of the PTI device. | ||
748 | * @tty- The tty struct associated with this device. | ||
749 | * | ||
750 | * Returns: | ||
751 | * always returns 0 | ||
752 | * | ||
753 | * Notes: The primary purpose of the PTI tty port 0 is to hook | ||
754 | * the syslog daemon to it; thus this port will be open for a | ||
755 | * very long time. | ||
756 | */ | ||
757 | static int pti_port_activate(struct tty_port *port, struct tty_struct *tty) | ||
758 | { | ||
759 | if (port->tty->index == PTITTY_MINOR_START) | ||
760 | console_start(&pti_console); | ||
761 | return 0; | ||
762 | } | ||
763 | |||
764 | /** | ||
765 | * pti_port_shutdown()- Used to stop/shutdown any items upon the | ||
766 | * last tty port close. | ||
767 | * | ||
768 | * @port- The tty port number of the PTI device. | ||
769 | * | ||
770 | * Notes: The primary purpose of the PTI tty port 0 is to hook | ||
771 | * the syslog daemon to it; thus this port will be open for a | ||
772 | * very long time. | ||
773 | */ | ||
774 | static void pti_port_shutdown(struct tty_port *port) | ||
775 | { | ||
776 | if (port->tty->index == PTITTY_MINOR_START) | ||
777 | console_stop(&pti_console); | ||
778 | } | ||
779 | |||
780 | static const struct tty_port_operations tty_port_ops = { | ||
781 | .activate = pti_port_activate, | ||
782 | .shutdown = pti_port_shutdown, | ||
783 | }; | ||
784 | |||
785 | /* | ||
786 | * Note the _probe() call sets everything up and ties the char and tty | ||
787 | * to successfully detecting the PTI device on the pci bus. | ||
788 | */ | ||
789 | |||
790 | /** | ||
791 | * pti_pci_probe()- Used to detect pti on the pci bus and set | ||
792 | * things up in the driver. | ||
793 | * | ||
794 | * @pdev- pci_dev struct values for pti. | ||
795 | * @ent- pci_device_id struct for pti driver. | ||
796 | * | ||
797 | * Returns: | ||
798 | * 0 for success | ||
799 | * otherwise, error | ||
800 | */ | ||
801 | static int __devinit pti_pci_probe(struct pci_dev *pdev, | ||
802 | const struct pci_device_id *ent) | ||
803 | { | ||
804 | int retval = -EINVAL; | ||
805 | int pci_bar = 1; | ||
806 | |||
807 | dev_dbg(&pdev->dev, "%s %s(%d): PTI PCI ID %04x:%04x\n", __FILE__, | ||
808 | __func__, __LINE__, pdev->vendor, pdev->device); | ||
809 | |||
810 | retval = misc_register(&pti_char_driver); | ||
811 | if (retval) { | ||
812 | pr_err("%s(%d): CHAR registration failed of pti driver\n", | ||
813 | __func__, __LINE__); | ||
814 | pr_err("%s(%d): Error value returned: %d\n", | ||
815 | __func__, __LINE__, retval); | ||
816 | return retval; | ||
817 | } | ||
818 | |||
819 | retval = pci_enable_device(pdev); | ||
820 | if (retval != 0) { | ||
821 | dev_err(&pdev->dev, | ||
822 | "%s: pci_enable_device() returned error %d\n", | ||
823 | __func__, retval); | ||
824 | return retval; | ||
825 | } | ||
826 | |||
827 | drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); | ||
828 | |||
829 | if (drv_data == NULL) { | ||
830 | retval = -ENOMEM; | ||
831 | dev_err(&pdev->dev, | ||
832 | "%s(%d): kmalloc() returned NULL memory.\n", | ||
833 | __func__, __LINE__); | ||
834 | return retval; | ||
835 | } | ||
836 | drv_data->pti_addr = pci_resource_start(pdev, pci_bar); | ||
837 | |||
838 | retval = pci_request_region(pdev, pci_bar, dev_name(&pdev->dev)); | ||
839 | if (retval != 0) { | ||
840 | dev_err(&pdev->dev, | ||
841 | "%s(%d): pci_request_region() returned error %d\n", | ||
842 | __func__, __LINE__, retval); | ||
843 | kfree(drv_data); | ||
844 | return retval; | ||
845 | } | ||
846 | drv_data->aperture_base = drv_data->pti_addr+APERTURE_14; | ||
847 | drv_data->pti_ioaddr = | ||
848 | ioremap_nocache((u32)drv_data->aperture_base, | ||
849 | APERTURE_LEN); | ||
850 | if (!drv_data->pti_ioaddr) { | ||
851 | pci_release_region(pdev, pci_bar); | ||
852 | retval = -ENOMEM; | ||
853 | kfree(drv_data); | ||
854 | return retval; | ||
855 | } | ||
856 | |||
857 | pci_set_drvdata(pdev, drv_data); | ||
858 | |||
859 | tty_port_init(&drv_data->port); | ||
860 | drv_data->port.ops = &tty_port_ops; | ||
861 | |||
862 | tty_register_device(pti_tty_driver, 0, &pdev->dev); | ||
863 | tty_register_device(pti_tty_driver, 1, &pdev->dev); | ||
864 | |||
865 | register_console(&pti_console); | ||
866 | |||
867 | return retval; | ||
868 | } | ||
869 | |||
870 | static struct pci_driver pti_pci_driver = { | ||
871 | .name = PCINAME, | ||
872 | .id_table = pci_ids, | ||
873 | .probe = pti_pci_probe, | ||
874 | .remove = pti_pci_remove, | ||
875 | }; | ||
876 | |||
877 | /** | ||
878 | * | ||
879 | * pti_init()- Overall entry/init call to the pti driver. | ||
880 | * It starts the registration process with the kernel. | ||
881 | * | ||
882 | * Returns: | ||
883 | * int __init, 0 for success | ||
884 | * otherwise value is an error | ||
885 | * | ||
886 | */ | ||
887 | static int __init pti_init(void) | ||
888 | { | ||
889 | int retval = -EINVAL; | ||
890 | |||
891 | /* First register module as tty device */ | ||
892 | |||
893 | pti_tty_driver = alloc_tty_driver(1); | ||
894 | if (pti_tty_driver == NULL) { | ||
895 | pr_err("%s(%d): Memory allocation failed for ptiTTY driver\n", | ||
896 | __func__, __LINE__); | ||
897 | return -ENOMEM; | ||
898 | } | ||
899 | |||
900 | pti_tty_driver->owner = THIS_MODULE; | ||
901 | pti_tty_driver->magic = TTY_DRIVER_MAGIC; | ||
902 | pti_tty_driver->driver_name = DRIVERNAME; | ||
903 | pti_tty_driver->name = TTYNAME; | ||
904 | pti_tty_driver->major = 0; | ||
905 | pti_tty_driver->minor_start = PTITTY_MINOR_START; | ||
906 | pti_tty_driver->minor_num = PTITTY_MINOR_NUM; | ||
907 | pti_tty_driver->num = PTITTY_MINOR_NUM; | ||
908 | pti_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; | ||
909 | pti_tty_driver->subtype = SYSTEM_TYPE_SYSCONS; | ||
910 | pti_tty_driver->flags = TTY_DRIVER_REAL_RAW | | ||
911 | TTY_DRIVER_DYNAMIC_DEV; | ||
912 | pti_tty_driver->init_termios = tty_std_termios; | ||
913 | |||
914 | tty_set_operations(pti_tty_driver, &pti_tty_driver_ops); | ||
915 | |||
916 | retval = tty_register_driver(pti_tty_driver); | ||
917 | if (retval) { | ||
918 | pr_err("%s(%d): TTY registration failed of pti driver\n", | ||
919 | __func__, __LINE__); | ||
920 | pr_err("%s(%d): Error value returned: %d\n", | ||
921 | __func__, __LINE__, retval); | ||
922 | |||
923 | pti_tty_driver = NULL; | ||
924 | return retval; | ||
925 | } | ||
926 | |||
927 | retval = pci_register_driver(&pti_pci_driver); | ||
928 | |||
929 | if (retval) { | ||
930 | pr_err("%s(%d): PCI registration failed of pti driver\n", | ||
931 | __func__, __LINE__); | ||
932 | pr_err("%s(%d): Error value returned: %d\n", | ||
933 | __func__, __LINE__, retval); | ||
934 | |||
935 | tty_unregister_driver(pti_tty_driver); | ||
936 | pr_err("%s(%d): Unregistering TTY part of pti driver\n", | ||
937 | __func__, __LINE__); | ||
938 | pti_tty_driver = NULL; | ||
939 | return retval; | ||
940 | } | ||
941 | |||
942 | return retval; | ||
943 | } | ||
944 | |||
945 | /** | ||
946 | * pti_exit()- Unregisters this module as a tty and pci driver. | ||
947 | */ | ||
948 | static void __exit pti_exit(void) | ||
949 | { | ||
950 | int retval; | ||
951 | |||
952 | tty_unregister_device(pti_tty_driver, 0); | ||
953 | tty_unregister_device(pti_tty_driver, 1); | ||
954 | |||
955 | retval = tty_unregister_driver(pti_tty_driver); | ||
956 | if (retval) { | ||
957 | pr_err("%s(%d): TTY unregistration failed of pti driver\n", | ||
958 | __func__, __LINE__); | ||
959 | pr_err("%s(%d): Error value returned: %d\n", | ||
960 | __func__, __LINE__, retval); | ||
961 | } | ||
962 | |||
963 | pci_unregister_driver(&pti_pci_driver); | ||
964 | |||
965 | retval = misc_deregister(&pti_char_driver); | ||
966 | if (retval) { | ||
967 | pr_err("%s(%d): CHAR unregistration failed of pti driver\n", | ||
968 | __func__, __LINE__); | ||
969 | pr_err("%s(%d): Error value returned: %d\n", | ||
970 | __func__, __LINE__, retval); | ||
971 | } | ||
972 | |||
973 | unregister_console(&pti_console); | ||
974 | return; | ||
975 | } | ||
976 | |||
977 | module_init(pti_init); | ||
978 | module_exit(pti_exit); | ||
979 | |||
980 | MODULE_LICENSE("GPL"); | ||
981 | MODULE_AUTHOR("Ken Mills, Jay Freyensee"); | ||
982 | MODULE_DESCRIPTION("PTI Driver"); | ||
983 | |||
diff --git a/drivers/misc/sgi-gru/Makefile b/drivers/misc/sgi-gru/Makefile index 7c4c306dfa8a..0003a1d56f7f 100644 --- a/drivers/misc/sgi-gru/Makefile +++ b/drivers/misc/sgi-gru/Makefile | |||
@@ -1,6 +1,4 @@ | |||
1 | ifdef CONFIG_SGI_GRU_DEBUG | 1 | ccflags-$(CONFIG_SGI_GRU_DEBUG) := -DDEBUG |
2 | EXTRA_CFLAGS += -DDEBUG | ||
3 | endif | ||
4 | 2 | ||
5 | obj-$(CONFIG_SGI_GRU) := gru.o | 3 | obj-$(CONFIG_SGI_GRU) := gru.o |
6 | gru-y := grufile.o grumain.o grufault.o grutlbpurge.o gruprocfs.o grukservices.o gruhandles.o grukdump.o | 4 | gru-y := grufile.o grumain.o grufault.o grutlbpurge.o gruprocfs.o grukservices.o gruhandles.o grukdump.o |
diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c index 38657cdaf54d..c4acac74725c 100644 --- a/drivers/misc/sgi-gru/grufault.c +++ b/drivers/misc/sgi-gru/grufault.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/io.h> | 33 | #include <linux/io.h> |
34 | #include <linux/uaccess.h> | 34 | #include <linux/uaccess.h> |
35 | #include <linux/security.h> | 35 | #include <linux/security.h> |
36 | #include <linux/prefetch.h> | ||
36 | #include <asm/pgtable.h> | 37 | #include <asm/pgtable.h> |
37 | #include "gru.h" | 38 | #include "gru.h" |
38 | #include "grutables.h" | 39 | #include "grutables.h" |
diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c index cb3b4d228475..ecafa4ba238b 100644 --- a/drivers/misc/sgi-gru/grufile.c +++ b/drivers/misc/sgi-gru/grufile.c | |||
@@ -348,15 +348,15 @@ static unsigned long gru_chiplet_cpu_to_mmr(int chiplet, int cpu, int *corep) | |||
348 | 348 | ||
349 | static int gru_irq_count[GRU_CHIPLETS_PER_BLADE]; | 349 | static int gru_irq_count[GRU_CHIPLETS_PER_BLADE]; |
350 | 350 | ||
351 | static void gru_noop(unsigned int irq) | 351 | static void gru_noop(struct irq_data *d) |
352 | { | 352 | { |
353 | } | 353 | } |
354 | 354 | ||
355 | static struct irq_chip gru_chip[GRU_CHIPLETS_PER_BLADE] = { | 355 | static struct irq_chip gru_chip[GRU_CHIPLETS_PER_BLADE] = { |
356 | [0 ... GRU_CHIPLETS_PER_BLADE - 1] { | 356 | [0 ... GRU_CHIPLETS_PER_BLADE - 1] { |
357 | .mask = gru_noop, | 357 | .irq_mask = gru_noop, |
358 | .unmask = gru_noop, | 358 | .irq_unmask = gru_noop, |
359 | .ack = gru_noop | 359 | .irq_ack = gru_noop |
360 | } | 360 | } |
361 | }; | 361 | }; |
362 | 362 | ||
@@ -373,7 +373,7 @@ static int gru_chiplet_setup_tlb_irq(int chiplet, char *irq_name, | |||
373 | 373 | ||
374 | if (gru_irq_count[chiplet] == 0) { | 374 | if (gru_irq_count[chiplet] == 0) { |
375 | gru_chip[chiplet].name = irq_name; | 375 | gru_chip[chiplet].name = irq_name; |
376 | ret = set_irq_chip(irq, &gru_chip[chiplet]); | 376 | ret = irq_set_chip(irq, &gru_chip[chiplet]); |
377 | if (ret) { | 377 | if (ret) { |
378 | printk(KERN_ERR "%s: set_irq_chip failed, errno=%d\n", | 378 | printk(KERN_ERR "%s: set_irq_chip failed, errno=%d\n", |
379 | GRU_DRIVER_ID_STR, -ret); | 379 | GRU_DRIVER_ID_STR, -ret); |
@@ -587,6 +587,7 @@ static const struct file_operations gru_fops = { | |||
587 | .owner = THIS_MODULE, | 587 | .owner = THIS_MODULE, |
588 | .unlocked_ioctl = gru_file_unlocked_ioctl, | 588 | .unlocked_ioctl = gru_file_unlocked_ioctl, |
589 | .mmap = gru_file_mmap, | 589 | .mmap = gru_file_mmap, |
590 | .llseek = noop_llseek, | ||
590 | }; | 591 | }; |
591 | 592 | ||
592 | static struct miscdevice gru_miscdev = { | 593 | static struct miscdevice gru_miscdev = { |
diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c index 34749ee88dfa..9e9bddaa95ae 100644 --- a/drivers/misc/sgi-gru/grukservices.c +++ b/drivers/misc/sgi-gru/grukservices.c | |||
@@ -229,7 +229,7 @@ again: | |||
229 | bid = blade_id < 0 ? uv_numa_blade_id() : blade_id; | 229 | bid = blade_id < 0 ? uv_numa_blade_id() : blade_id; |
230 | bs = gru_base[bid]; | 230 | bs = gru_base[bid]; |
231 | 231 | ||
232 | /* Handle the case where migration occured while waiting for the sema */ | 232 | /* Handle the case where migration occurred while waiting for the sema */ |
233 | down_read(&bs->bs_kgts_sema); | 233 | down_read(&bs->bs_kgts_sema); |
234 | if (blade_id < 0 && bid != uv_numa_blade_id()) { | 234 | if (blade_id < 0 && bid != uv_numa_blade_id()) { |
235 | up_read(&bs->bs_kgts_sema); | 235 | up_read(&bs->bs_kgts_sema); |
diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c index f8538bbd0bfa..ae16c8cb4f3e 100644 --- a/drivers/misc/sgi-gru/grumain.c +++ b/drivers/misc/sgi-gru/grumain.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/device.h> | 28 | #include <linux/device.h> |
29 | #include <linux/list.h> | 29 | #include <linux/list.h> |
30 | #include <linux/err.h> | 30 | #include <linux/err.h> |
31 | #include <linux/prefetch.h> | ||
31 | #include <asm/uv/uv_hub.h> | 32 | #include <asm/uv/uv_hub.h> |
32 | #include "gru.h" | 33 | #include "gru.h" |
33 | #include "grutables.h" | 34 | #include "grutables.h" |
diff --git a/drivers/misc/sgi-gru/grutables.h b/drivers/misc/sgi-gru/grutables.h index 7a8b9068ea03..5c3ce2459675 100644 --- a/drivers/misc/sgi-gru/grutables.h +++ b/drivers/misc/sgi-gru/grutables.h | |||
@@ -379,7 +379,7 @@ struct gru_thread_state { | |||
379 | required for contest */ | 379 | required for contest */ |
380 | char ts_cch_req_slice;/* CCH packet slice */ | 380 | char ts_cch_req_slice;/* CCH packet slice */ |
381 | char ts_blade; /* If >= 0, migrate context if | 381 | char ts_blade; /* If >= 0, migrate context if |
382 | ref from diferent blade */ | 382 | ref from different blade */ |
383 | char ts_force_cch_reload; | 383 | char ts_force_cch_reload; |
384 | char ts_cbr_idx[GRU_CBR_AU];/* CBR numbers of each | 384 | char ts_cbr_idx[GRU_CBR_AU];/* CBR numbers of each |
385 | allocated CB */ | 385 | allocated CB */ |
diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index d551f09ccb79..6956f7e7d439 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c | |||
@@ -439,18 +439,23 @@ xpc_discovery(void) | |||
439 | * nodes that can comprise an access protection grouping. The access | 439 | * nodes that can comprise an access protection grouping. The access |
440 | * protection is in regards to memory, IOI and IPI. | 440 | * protection is in regards to memory, IOI and IPI. |
441 | */ | 441 | */ |
442 | max_regions = 64; | ||
443 | region_size = xp_region_size; | 442 | region_size = xp_region_size; |
444 | 443 | ||
445 | switch (region_size) { | 444 | if (is_uv()) |
446 | case 128: | 445 | max_regions = 256; |
447 | max_regions *= 2; | 446 | else { |
448 | case 64: | 447 | max_regions = 64; |
449 | max_regions *= 2; | 448 | |
450 | case 32: | 449 | switch (region_size) { |
451 | max_regions *= 2; | 450 | case 128: |
452 | region_size = 16; | 451 | max_regions *= 2; |
453 | DBUG_ON(!is_shub2()); | 452 | case 64: |
453 | max_regions *= 2; | ||
454 | case 32: | ||
455 | max_regions *= 2; | ||
456 | region_size = 16; | ||
457 | DBUG_ON(!is_shub2()); | ||
458 | } | ||
454 | } | 459 | } |
455 | 460 | ||
456 | for (region = 0; region < max_regions; region++) { | 461 | for (region = 0; region < max_regions; region++) { |
diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c index 1f59ee2226ca..17bbacb1b4b1 100644 --- a/drivers/misc/sgi-xp/xpc_uv.c +++ b/drivers/misc/sgi-xp/xpc_uv.c | |||
@@ -417,6 +417,7 @@ xpc_process_activate_IRQ_rcvd_uv(void) | |||
417 | static void | 417 | static void |
418 | xpc_handle_activate_mq_msg_uv(struct xpc_partition *part, | 418 | xpc_handle_activate_mq_msg_uv(struct xpc_partition *part, |
419 | struct xpc_activate_mq_msghdr_uv *msg_hdr, | 419 | struct xpc_activate_mq_msghdr_uv *msg_hdr, |
420 | int part_setup, | ||
420 | int *wakeup_hb_checker) | 421 | int *wakeup_hb_checker) |
421 | { | 422 | { |
422 | unsigned long irq_flags; | 423 | unsigned long irq_flags; |
@@ -481,6 +482,9 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part, | |||
481 | case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV: { | 482 | case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREQUEST_UV: { |
482 | struct xpc_activate_mq_msg_chctl_closerequest_uv *msg; | 483 | struct xpc_activate_mq_msg_chctl_closerequest_uv *msg; |
483 | 484 | ||
485 | if (!part_setup) | ||
486 | break; | ||
487 | |||
484 | msg = container_of(msg_hdr, struct | 488 | msg = container_of(msg_hdr, struct |
485 | xpc_activate_mq_msg_chctl_closerequest_uv, | 489 | xpc_activate_mq_msg_chctl_closerequest_uv, |
486 | hdr); | 490 | hdr); |
@@ -497,6 +501,9 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part, | |||
497 | case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV: { | 501 | case XPC_ACTIVATE_MQ_MSG_CHCTL_CLOSEREPLY_UV: { |
498 | struct xpc_activate_mq_msg_chctl_closereply_uv *msg; | 502 | struct xpc_activate_mq_msg_chctl_closereply_uv *msg; |
499 | 503 | ||
504 | if (!part_setup) | ||
505 | break; | ||
506 | |||
500 | msg = container_of(msg_hdr, struct | 507 | msg = container_of(msg_hdr, struct |
501 | xpc_activate_mq_msg_chctl_closereply_uv, | 508 | xpc_activate_mq_msg_chctl_closereply_uv, |
502 | hdr); | 509 | hdr); |
@@ -511,6 +518,9 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part, | |||
511 | case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV: { | 518 | case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREQUEST_UV: { |
512 | struct xpc_activate_mq_msg_chctl_openrequest_uv *msg; | 519 | struct xpc_activate_mq_msg_chctl_openrequest_uv *msg; |
513 | 520 | ||
521 | if (!part_setup) | ||
522 | break; | ||
523 | |||
514 | msg = container_of(msg_hdr, struct | 524 | msg = container_of(msg_hdr, struct |
515 | xpc_activate_mq_msg_chctl_openrequest_uv, | 525 | xpc_activate_mq_msg_chctl_openrequest_uv, |
516 | hdr); | 526 | hdr); |
@@ -528,6 +538,9 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part, | |||
528 | case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV: { | 538 | case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENREPLY_UV: { |
529 | struct xpc_activate_mq_msg_chctl_openreply_uv *msg; | 539 | struct xpc_activate_mq_msg_chctl_openreply_uv *msg; |
530 | 540 | ||
541 | if (!part_setup) | ||
542 | break; | ||
543 | |||
531 | msg = container_of(msg_hdr, struct | 544 | msg = container_of(msg_hdr, struct |
532 | xpc_activate_mq_msg_chctl_openreply_uv, hdr); | 545 | xpc_activate_mq_msg_chctl_openreply_uv, hdr); |
533 | args = &part->remote_openclose_args[msg->ch_number]; | 546 | args = &part->remote_openclose_args[msg->ch_number]; |
@@ -545,6 +558,9 @@ xpc_handle_activate_mq_msg_uv(struct xpc_partition *part, | |||
545 | case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENCOMPLETE_UV: { | 558 | case XPC_ACTIVATE_MQ_MSG_CHCTL_OPENCOMPLETE_UV: { |
546 | struct xpc_activate_mq_msg_chctl_opencomplete_uv *msg; | 559 | struct xpc_activate_mq_msg_chctl_opencomplete_uv *msg; |
547 | 560 | ||
561 | if (!part_setup) | ||
562 | break; | ||
563 | |||
548 | msg = container_of(msg_hdr, struct | 564 | msg = container_of(msg_hdr, struct |
549 | xpc_activate_mq_msg_chctl_opencomplete_uv, hdr); | 565 | xpc_activate_mq_msg_chctl_opencomplete_uv, hdr); |
550 | spin_lock_irqsave(&part->chctl_lock, irq_flags); | 566 | spin_lock_irqsave(&part->chctl_lock, irq_flags); |
@@ -621,6 +637,7 @@ xpc_handle_activate_IRQ_uv(int irq, void *dev_id) | |||
621 | 637 | ||
622 | part_referenced = xpc_part_ref(part); | 638 | part_referenced = xpc_part_ref(part); |
623 | xpc_handle_activate_mq_msg_uv(part, msg_hdr, | 639 | xpc_handle_activate_mq_msg_uv(part, msg_hdr, |
640 | part_referenced, | ||
624 | &wakeup_hb_checker); | 641 | &wakeup_hb_checker); |
625 | if (part_referenced) | 642 | if (part_referenced) |
626 | xpc_part_deref(part); | 643 | xpc_part_deref(part); |
diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index ee5109a3cd98..42f067347bc7 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c | |||
@@ -495,14 +495,14 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
495 | } | 495 | } |
496 | } | 496 | } |
497 | 497 | ||
498 | dev->stats.tx_packets++; | ||
499 | dev->stats.tx_bytes += skb->len; | ||
500 | |||
498 | if (atomic_dec_return(&queued_msg->use_count) == 0) { | 501 | if (atomic_dec_return(&queued_msg->use_count) == 0) { |
499 | dev_kfree_skb(skb); | 502 | dev_kfree_skb(skb); |
500 | kfree(queued_msg); | 503 | kfree(queued_msg); |
501 | } | 504 | } |
502 | 505 | ||
503 | dev->stats.tx_packets++; | ||
504 | dev->stats.tx_bytes += skb->len; | ||
505 | |||
506 | return NETDEV_TX_OK; | 506 | return NETDEV_TX_OK; |
507 | } | 507 | } |
508 | 508 | ||
diff --git a/drivers/misc/spear13xx_pcie_gadget.c b/drivers/misc/spear13xx_pcie_gadget.c new file mode 100644 index 000000000000..cfbddbef11de --- /dev/null +++ b/drivers/misc/spear13xx_pcie_gadget.c | |||
@@ -0,0 +1,908 @@ | |||
1 | /* | ||
2 | * drivers/misc/spear13xx_pcie_gadget.c | ||
3 | * | ||
4 | * Copyright (C) 2010 ST Microelectronics | ||
5 | * Pratyush Anand<pratyush.anand@st.com> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/irq.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/pci_regs.h> | ||
22 | #include <linux/configfs.h> | ||
23 | #include <mach/pcie.h> | ||
24 | #include <mach/misc_regs.h> | ||
25 | |||
26 | #define IN0_MEM_SIZE (200 * 1024 * 1024 - 1) | ||
27 | /* In current implementation address translation is done using IN0 only. | ||
28 | * So IN1 start address and IN0 end address has been kept same | ||
29 | */ | ||
30 | #define IN1_MEM_SIZE (0 * 1024 * 1024 - 1) | ||
31 | #define IN_IO_SIZE (20 * 1024 * 1024 - 1) | ||
32 | #define IN_CFG0_SIZE (12 * 1024 * 1024 - 1) | ||
33 | #define IN_CFG1_SIZE (12 * 1024 * 1024 - 1) | ||
34 | #define IN_MSG_SIZE (12 * 1024 * 1024 - 1) | ||
35 | /* Keep default BAR size as 4K*/ | ||
36 | /* AORAM would be mapped by default*/ | ||
37 | #define INBOUND_ADDR_MASK (SPEAR13XX_SYSRAM1_SIZE - 1) | ||
38 | |||
39 | #define INT_TYPE_NO_INT 0 | ||
40 | #define INT_TYPE_INTX 1 | ||
41 | #define INT_TYPE_MSI 2 | ||
42 | struct spear_pcie_gadget_config { | ||
43 | void __iomem *base; | ||
44 | void __iomem *va_app_base; | ||
45 | void __iomem *va_dbi_base; | ||
46 | char int_type[10]; | ||
47 | ulong requested_msi; | ||
48 | ulong configured_msi; | ||
49 | ulong bar0_size; | ||
50 | ulong bar0_rw_offset; | ||
51 | void __iomem *va_bar0_address; | ||
52 | }; | ||
53 | |||
54 | struct pcie_gadget_target { | ||
55 | struct configfs_subsystem subsys; | ||
56 | struct spear_pcie_gadget_config config; | ||
57 | }; | ||
58 | |||
59 | struct pcie_gadget_target_attr { | ||
60 | struct configfs_attribute attr; | ||
61 | ssize_t (*show)(struct spear_pcie_gadget_config *config, | ||
62 | char *buf); | ||
63 | ssize_t (*store)(struct spear_pcie_gadget_config *config, | ||
64 | const char *buf, | ||
65 | size_t count); | ||
66 | }; | ||
67 | |||
68 | static void enable_dbi_access(struct pcie_app_reg __iomem *app_reg) | ||
69 | { | ||
70 | /* Enable DBI access */ | ||
71 | writel(readl(&app_reg->slv_armisc) | (1 << AXI_OP_DBI_ACCESS_ID), | ||
72 | &app_reg->slv_armisc); | ||
73 | writel(readl(&app_reg->slv_awmisc) | (1 << AXI_OP_DBI_ACCESS_ID), | ||
74 | &app_reg->slv_awmisc); | ||
75 | |||
76 | } | ||
77 | |||
78 | static void disable_dbi_access(struct pcie_app_reg __iomem *app_reg) | ||
79 | { | ||
80 | /* disable DBI access */ | ||
81 | writel(readl(&app_reg->slv_armisc) & ~(1 << AXI_OP_DBI_ACCESS_ID), | ||
82 | &app_reg->slv_armisc); | ||
83 | writel(readl(&app_reg->slv_awmisc) & ~(1 << AXI_OP_DBI_ACCESS_ID), | ||
84 | &app_reg->slv_awmisc); | ||
85 | |||
86 | } | ||
87 | |||
88 | static void spear_dbi_read_reg(struct spear_pcie_gadget_config *config, | ||
89 | int where, int size, u32 *val) | ||
90 | { | ||
91 | struct pcie_app_reg __iomem *app_reg = config->va_app_base; | ||
92 | ulong va_address; | ||
93 | |||
94 | /* Enable DBI access */ | ||
95 | enable_dbi_access(app_reg); | ||
96 | |||
97 | va_address = (ulong)config->va_dbi_base + (where & ~0x3); | ||
98 | |||
99 | *val = readl(va_address); | ||
100 | |||
101 | if (size == 1) | ||
102 | *val = (*val >> (8 * (where & 3))) & 0xff; | ||
103 | else if (size == 2) | ||
104 | *val = (*val >> (8 * (where & 3))) & 0xffff; | ||
105 | |||
106 | /* Disable DBI access */ | ||
107 | disable_dbi_access(app_reg); | ||
108 | } | ||
109 | |||
110 | static void spear_dbi_write_reg(struct spear_pcie_gadget_config *config, | ||
111 | int where, int size, u32 val) | ||
112 | { | ||
113 | struct pcie_app_reg __iomem *app_reg = config->va_app_base; | ||
114 | ulong va_address; | ||
115 | |||
116 | /* Enable DBI access */ | ||
117 | enable_dbi_access(app_reg); | ||
118 | |||
119 | va_address = (ulong)config->va_dbi_base + (where & ~0x3); | ||
120 | |||
121 | if (size == 4) | ||
122 | writel(val, va_address); | ||
123 | else if (size == 2) | ||
124 | writew(val, va_address + (where & 2)); | ||
125 | else if (size == 1) | ||
126 | writeb(val, va_address + (where & 3)); | ||
127 | |||
128 | /* Disable DBI access */ | ||
129 | disable_dbi_access(app_reg); | ||
130 | } | ||
131 | |||
132 | #define PCI_FIND_CAP_TTL 48 | ||
133 | |||
134 | static int pci_find_own_next_cap_ttl(struct spear_pcie_gadget_config *config, | ||
135 | u32 pos, int cap, int *ttl) | ||
136 | { | ||
137 | u32 id; | ||
138 | |||
139 | while ((*ttl)--) { | ||
140 | spear_dbi_read_reg(config, pos, 1, &pos); | ||
141 | if (pos < 0x40) | ||
142 | break; | ||
143 | pos &= ~3; | ||
144 | spear_dbi_read_reg(config, pos + PCI_CAP_LIST_ID, 1, &id); | ||
145 | if (id == 0xff) | ||
146 | break; | ||
147 | if (id == cap) | ||
148 | return pos; | ||
149 | pos += PCI_CAP_LIST_NEXT; | ||
150 | } | ||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int pci_find_own_next_cap(struct spear_pcie_gadget_config *config, | ||
155 | u32 pos, int cap) | ||
156 | { | ||
157 | int ttl = PCI_FIND_CAP_TTL; | ||
158 | |||
159 | return pci_find_own_next_cap_ttl(config, pos, cap, &ttl); | ||
160 | } | ||
161 | |||
162 | static int pci_find_own_cap_start(struct spear_pcie_gadget_config *config, | ||
163 | u8 hdr_type) | ||
164 | { | ||
165 | u32 status; | ||
166 | |||
167 | spear_dbi_read_reg(config, PCI_STATUS, 2, &status); | ||
168 | if (!(status & PCI_STATUS_CAP_LIST)) | ||
169 | return 0; | ||
170 | |||
171 | switch (hdr_type) { | ||
172 | case PCI_HEADER_TYPE_NORMAL: | ||
173 | case PCI_HEADER_TYPE_BRIDGE: | ||
174 | return PCI_CAPABILITY_LIST; | ||
175 | case PCI_HEADER_TYPE_CARDBUS: | ||
176 | return PCI_CB_CAPABILITY_LIST; | ||
177 | default: | ||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | * Tell if a device supports a given PCI capability. | ||
186 | * Returns the address of the requested capability structure within the | ||
187 | * device's PCI configuration space or 0 in case the device does not | ||
188 | * support it. Possible values for @cap: | ||
189 | * | ||
190 | * %PCI_CAP_ID_PM Power Management | ||
191 | * %PCI_CAP_ID_AGP Accelerated Graphics Port | ||
192 | * %PCI_CAP_ID_VPD Vital Product Data | ||
193 | * %PCI_CAP_ID_SLOTID Slot Identification | ||
194 | * %PCI_CAP_ID_MSI Message Signalled Interrupts | ||
195 | * %PCI_CAP_ID_CHSWP CompactPCI HotSwap | ||
196 | * %PCI_CAP_ID_PCIX PCI-X | ||
197 | * %PCI_CAP_ID_EXP PCI Express | ||
198 | */ | ||
199 | static int pci_find_own_capability(struct spear_pcie_gadget_config *config, | ||
200 | int cap) | ||
201 | { | ||
202 | u32 pos; | ||
203 | u32 hdr_type; | ||
204 | |||
205 | spear_dbi_read_reg(config, PCI_HEADER_TYPE, 1, &hdr_type); | ||
206 | |||
207 | pos = pci_find_own_cap_start(config, hdr_type); | ||
208 | if (pos) | ||
209 | pos = pci_find_own_next_cap(config, pos, cap); | ||
210 | |||
211 | return pos; | ||
212 | } | ||
213 | |||
214 | static irqreturn_t spear_pcie_gadget_irq(int irq, void *dev_id) | ||
215 | { | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | /* | ||
220 | * configfs interfaces show/store functions | ||
221 | */ | ||
222 | static ssize_t pcie_gadget_show_link( | ||
223 | struct spear_pcie_gadget_config *config, | ||
224 | char *buf) | ||
225 | { | ||
226 | struct pcie_app_reg __iomem *app_reg = config->va_app_base; | ||
227 | |||
228 | if (readl(&app_reg->app_status_1) & ((u32)1 << XMLH_LINK_UP_ID)) | ||
229 | return sprintf(buf, "UP"); | ||
230 | else | ||
231 | return sprintf(buf, "DOWN"); | ||
232 | } | ||
233 | |||
234 | static ssize_t pcie_gadget_store_link( | ||
235 | struct spear_pcie_gadget_config *config, | ||
236 | const char *buf, size_t count) | ||
237 | { | ||
238 | struct pcie_app_reg __iomem *app_reg = config->va_app_base; | ||
239 | |||
240 | if (sysfs_streq(buf, "UP")) | ||
241 | writel(readl(&app_reg->app_ctrl_0) | (1 << APP_LTSSM_ENABLE_ID), | ||
242 | &app_reg->app_ctrl_0); | ||
243 | else if (sysfs_streq(buf, "DOWN")) | ||
244 | writel(readl(&app_reg->app_ctrl_0) | ||
245 | & ~(1 << APP_LTSSM_ENABLE_ID), | ||
246 | &app_reg->app_ctrl_0); | ||
247 | else | ||
248 | return -EINVAL; | ||
249 | return count; | ||
250 | } | ||
251 | |||
252 | static ssize_t pcie_gadget_show_int_type( | ||
253 | struct spear_pcie_gadget_config *config, | ||
254 | char *buf) | ||
255 | { | ||
256 | return sprintf(buf, "%s", config->int_type); | ||
257 | } | ||
258 | |||
259 | static ssize_t pcie_gadget_store_int_type( | ||
260 | struct spear_pcie_gadget_config *config, | ||
261 | const char *buf, size_t count) | ||
262 | { | ||
263 | u32 cap, vec, flags; | ||
264 | ulong vector; | ||
265 | |||
266 | if (sysfs_streq(buf, "INTA")) | ||
267 | spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 1); | ||
268 | |||
269 | else if (sysfs_streq(buf, "MSI")) { | ||
270 | vector = config->requested_msi; | ||
271 | vec = 0; | ||
272 | while (vector > 1) { | ||
273 | vector /= 2; | ||
274 | vec++; | ||
275 | } | ||
276 | spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 0); | ||
277 | cap = pci_find_own_capability(config, PCI_CAP_ID_MSI); | ||
278 | spear_dbi_read_reg(config, cap + PCI_MSI_FLAGS, 1, &flags); | ||
279 | flags &= ~PCI_MSI_FLAGS_QMASK; | ||
280 | flags |= vec << 1; | ||
281 | spear_dbi_write_reg(config, cap + PCI_MSI_FLAGS, 1, flags); | ||
282 | } else | ||
283 | return -EINVAL; | ||
284 | |||
285 | strcpy(config->int_type, buf); | ||
286 | |||
287 | return count; | ||
288 | } | ||
289 | |||
290 | static ssize_t pcie_gadget_show_no_of_msi( | ||
291 | struct spear_pcie_gadget_config *config, | ||
292 | char *buf) | ||
293 | { | ||
294 | struct pcie_app_reg __iomem *app_reg = config->va_app_base; | ||
295 | u32 cap, vec, flags; | ||
296 | ulong vector; | ||
297 | |||
298 | if ((readl(&app_reg->msg_status) & (1 << CFG_MSI_EN_ID)) | ||
299 | != (1 << CFG_MSI_EN_ID)) | ||
300 | vector = 0; | ||
301 | else { | ||
302 | cap = pci_find_own_capability(config, PCI_CAP_ID_MSI); | ||
303 | spear_dbi_read_reg(config, cap + PCI_MSI_FLAGS, 1, &flags); | ||
304 | flags &= ~PCI_MSI_FLAGS_QSIZE; | ||
305 | vec = flags >> 4; | ||
306 | vector = 1; | ||
307 | while (vec--) | ||
308 | vector *= 2; | ||
309 | } | ||
310 | config->configured_msi = vector; | ||
311 | |||
312 | return sprintf(buf, "%lu", vector); | ||
313 | } | ||
314 | |||
315 | static ssize_t pcie_gadget_store_no_of_msi( | ||
316 | struct spear_pcie_gadget_config *config, | ||
317 | const char *buf, size_t count) | ||
318 | { | ||
319 | if (strict_strtoul(buf, 0, &config->requested_msi)) | ||
320 | return -EINVAL; | ||
321 | if (config->requested_msi > 32) | ||
322 | config->requested_msi = 32; | ||
323 | |||
324 | return count; | ||
325 | } | ||
326 | |||
327 | static ssize_t pcie_gadget_store_inta( | ||
328 | struct spear_pcie_gadget_config *config, | ||
329 | const char *buf, size_t count) | ||
330 | { | ||
331 | struct pcie_app_reg __iomem *app_reg = config->va_app_base; | ||
332 | ulong en; | ||
333 | |||
334 | if (strict_strtoul(buf, 0, &en)) | ||
335 | return -EINVAL; | ||
336 | |||
337 | if (en) | ||
338 | writel(readl(&app_reg->app_ctrl_0) | (1 << SYS_INT_ID), | ||
339 | &app_reg->app_ctrl_0); | ||
340 | else | ||
341 | writel(readl(&app_reg->app_ctrl_0) & ~(1 << SYS_INT_ID), | ||
342 | &app_reg->app_ctrl_0); | ||
343 | |||
344 | return count; | ||
345 | } | ||
346 | |||
347 | static ssize_t pcie_gadget_store_send_msi( | ||
348 | struct spear_pcie_gadget_config *config, | ||
349 | const char *buf, size_t count) | ||
350 | { | ||
351 | struct pcie_app_reg __iomem *app_reg = config->va_app_base; | ||
352 | ulong vector; | ||
353 | u32 ven_msi; | ||
354 | |||
355 | if (strict_strtoul(buf, 0, &vector)) | ||
356 | return -EINVAL; | ||
357 | |||
358 | if (!config->configured_msi) | ||
359 | return -EINVAL; | ||
360 | |||
361 | if (vector >= config->configured_msi) | ||
362 | return -EINVAL; | ||
363 | |||
364 | ven_msi = readl(&app_reg->ven_msi_1); | ||
365 | ven_msi &= ~VEN_MSI_FUN_NUM_MASK; | ||
366 | ven_msi |= 0 << VEN_MSI_FUN_NUM_ID; | ||
367 | ven_msi &= ~VEN_MSI_TC_MASK; | ||
368 | ven_msi |= 0 << VEN_MSI_TC_ID; | ||
369 | ven_msi &= ~VEN_MSI_VECTOR_MASK; | ||
370 | ven_msi |= vector << VEN_MSI_VECTOR_ID; | ||
371 | |||
372 | /* generating interrupt for msi vector */ | ||
373 | ven_msi |= VEN_MSI_REQ_EN; | ||
374 | writel(ven_msi, &app_reg->ven_msi_1); | ||
375 | udelay(1); | ||
376 | ven_msi &= ~VEN_MSI_REQ_EN; | ||
377 | writel(ven_msi, &app_reg->ven_msi_1); | ||
378 | |||
379 | return count; | ||
380 | } | ||
381 | |||
382 | static ssize_t pcie_gadget_show_vendor_id( | ||
383 | struct spear_pcie_gadget_config *config, | ||
384 | char *buf) | ||
385 | { | ||
386 | u32 id; | ||
387 | |||
388 | spear_dbi_read_reg(config, PCI_VENDOR_ID, 2, &id); | ||
389 | |||
390 | return sprintf(buf, "%x", id); | ||
391 | } | ||
392 | |||
393 | static ssize_t pcie_gadget_store_vendor_id( | ||
394 | struct spear_pcie_gadget_config *config, | ||
395 | const char *buf, size_t count) | ||
396 | { | ||
397 | ulong id; | ||
398 | |||
399 | if (strict_strtoul(buf, 0, &id)) | ||
400 | return -EINVAL; | ||
401 | |||
402 | spear_dbi_write_reg(config, PCI_VENDOR_ID, 2, id); | ||
403 | |||
404 | return count; | ||
405 | } | ||
406 | |||
407 | static ssize_t pcie_gadget_show_device_id( | ||
408 | struct spear_pcie_gadget_config *config, | ||
409 | char *buf) | ||
410 | { | ||
411 | u32 id; | ||
412 | |||
413 | spear_dbi_read_reg(config, PCI_DEVICE_ID, 2, &id); | ||
414 | |||
415 | return sprintf(buf, "%x", id); | ||
416 | } | ||
417 | |||
418 | static ssize_t pcie_gadget_store_device_id( | ||
419 | struct spear_pcie_gadget_config *config, | ||
420 | const char *buf, size_t count) | ||
421 | { | ||
422 | ulong id; | ||
423 | |||
424 | if (strict_strtoul(buf, 0, &id)) | ||
425 | return -EINVAL; | ||
426 | |||
427 | spear_dbi_write_reg(config, PCI_DEVICE_ID, 2, id); | ||
428 | |||
429 | return count; | ||
430 | } | ||
431 | |||
432 | static ssize_t pcie_gadget_show_bar0_size( | ||
433 | struct spear_pcie_gadget_config *config, | ||
434 | char *buf) | ||
435 | { | ||
436 | return sprintf(buf, "%lx", config->bar0_size); | ||
437 | } | ||
438 | |||
439 | static ssize_t pcie_gadget_store_bar0_size( | ||
440 | struct spear_pcie_gadget_config *config, | ||
441 | const char *buf, size_t count) | ||
442 | { | ||
443 | ulong size; | ||
444 | u32 pos, pos1; | ||
445 | u32 no_of_bit = 0; | ||
446 | |||
447 | if (strict_strtoul(buf, 0, &size)) | ||
448 | return -EINVAL; | ||
449 | /* min bar size is 256 */ | ||
450 | if (size <= 0x100) | ||
451 | size = 0x100; | ||
452 | /* max bar size is 1MB*/ | ||
453 | else if (size >= 0x100000) | ||
454 | size = 0x100000; | ||
455 | else { | ||
456 | pos = 0; | ||
457 | pos1 = 0; | ||
458 | while (pos < 21) { | ||
459 | pos = find_next_bit((ulong *)&size, 21, pos); | ||
460 | if (pos != 21) | ||
461 | pos1 = pos + 1; | ||
462 | pos++; | ||
463 | no_of_bit++; | ||
464 | } | ||
465 | if (no_of_bit == 2) | ||
466 | pos1--; | ||
467 | |||
468 | size = 1 << pos1; | ||
469 | } | ||
470 | config->bar0_size = size; | ||
471 | spear_dbi_write_reg(config, PCIE_BAR0_MASK_REG, 4, size - 1); | ||
472 | |||
473 | return count; | ||
474 | } | ||
475 | |||
476 | static ssize_t pcie_gadget_show_bar0_address( | ||
477 | struct spear_pcie_gadget_config *config, | ||
478 | char *buf) | ||
479 | { | ||
480 | struct pcie_app_reg __iomem *app_reg = config->va_app_base; | ||
481 | |||
482 | u32 address = readl(&app_reg->pim0_mem_addr_start); | ||
483 | |||
484 | return sprintf(buf, "%x", address); | ||
485 | } | ||
486 | |||
487 | static ssize_t pcie_gadget_store_bar0_address( | ||
488 | struct spear_pcie_gadget_config *config, | ||
489 | const char *buf, size_t count) | ||
490 | { | ||
491 | struct pcie_app_reg __iomem *app_reg = config->va_app_base; | ||
492 | ulong address; | ||
493 | |||
494 | if (strict_strtoul(buf, 0, &address)) | ||
495 | return -EINVAL; | ||
496 | |||
497 | address &= ~(config->bar0_size - 1); | ||
498 | if (config->va_bar0_address) | ||
499 | iounmap(config->va_bar0_address); | ||
500 | config->va_bar0_address = ioremap(address, config->bar0_size); | ||
501 | if (!config->va_bar0_address) | ||
502 | return -ENOMEM; | ||
503 | |||
504 | writel(address, &app_reg->pim0_mem_addr_start); | ||
505 | |||
506 | return count; | ||
507 | } | ||
508 | |||
509 | static ssize_t pcie_gadget_show_bar0_rw_offset( | ||
510 | struct spear_pcie_gadget_config *config, | ||
511 | char *buf) | ||
512 | { | ||
513 | return sprintf(buf, "%lx", config->bar0_rw_offset); | ||
514 | } | ||
515 | |||
516 | static ssize_t pcie_gadget_store_bar0_rw_offset( | ||
517 | struct spear_pcie_gadget_config *config, | ||
518 | const char *buf, size_t count) | ||
519 | { | ||
520 | ulong offset; | ||
521 | |||
522 | if (strict_strtoul(buf, 0, &offset)) | ||
523 | return -EINVAL; | ||
524 | |||
525 | if (offset % 4) | ||
526 | return -EINVAL; | ||
527 | |||
528 | config->bar0_rw_offset = offset; | ||
529 | |||
530 | return count; | ||
531 | } | ||
532 | |||
533 | static ssize_t pcie_gadget_show_bar0_data( | ||
534 | struct spear_pcie_gadget_config *config, | ||
535 | char *buf) | ||
536 | { | ||
537 | ulong data; | ||
538 | |||
539 | if (!config->va_bar0_address) | ||
540 | return -ENOMEM; | ||
541 | |||
542 | data = readl((ulong)config->va_bar0_address + config->bar0_rw_offset); | ||
543 | |||
544 | return sprintf(buf, "%lx", data); | ||
545 | } | ||
546 | |||
547 | static ssize_t pcie_gadget_store_bar0_data( | ||
548 | struct spear_pcie_gadget_config *config, | ||
549 | const char *buf, size_t count) | ||
550 | { | ||
551 | ulong data; | ||
552 | |||
553 | if (strict_strtoul(buf, 0, &data)) | ||
554 | return -EINVAL; | ||
555 | |||
556 | if (!config->va_bar0_address) | ||
557 | return -ENOMEM; | ||
558 | |||
559 | writel(data, (ulong)config->va_bar0_address + config->bar0_rw_offset); | ||
560 | |||
561 | return count; | ||
562 | } | ||
563 | |||
564 | /* | ||
565 | * Attribute definitions. | ||
566 | */ | ||
567 | |||
568 | #define PCIE_GADGET_TARGET_ATTR_RO(_name) \ | ||
569 | static struct pcie_gadget_target_attr pcie_gadget_target_##_name = \ | ||
570 | __CONFIGFS_ATTR(_name, S_IRUGO, pcie_gadget_show_##_name, NULL) | ||
571 | |||
572 | #define PCIE_GADGET_TARGET_ATTR_WO(_name) \ | ||
573 | static struct pcie_gadget_target_attr pcie_gadget_target_##_name = \ | ||
574 | __CONFIGFS_ATTR(_name, S_IWUSR, NULL, pcie_gadget_store_##_name) | ||
575 | |||
576 | #define PCIE_GADGET_TARGET_ATTR_RW(_name) \ | ||
577 | static struct pcie_gadget_target_attr pcie_gadget_target_##_name = \ | ||
578 | __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, pcie_gadget_show_##_name, \ | ||
579 | pcie_gadget_store_##_name) | ||
580 | PCIE_GADGET_TARGET_ATTR_RW(link); | ||
581 | PCIE_GADGET_TARGET_ATTR_RW(int_type); | ||
582 | PCIE_GADGET_TARGET_ATTR_RW(no_of_msi); | ||
583 | PCIE_GADGET_TARGET_ATTR_WO(inta); | ||
584 | PCIE_GADGET_TARGET_ATTR_WO(send_msi); | ||
585 | PCIE_GADGET_TARGET_ATTR_RW(vendor_id); | ||
586 | PCIE_GADGET_TARGET_ATTR_RW(device_id); | ||
587 | PCIE_GADGET_TARGET_ATTR_RW(bar0_size); | ||
588 | PCIE_GADGET_TARGET_ATTR_RW(bar0_address); | ||
589 | PCIE_GADGET_TARGET_ATTR_RW(bar0_rw_offset); | ||
590 | PCIE_GADGET_TARGET_ATTR_RW(bar0_data); | ||
591 | |||
592 | static struct configfs_attribute *pcie_gadget_target_attrs[] = { | ||
593 | &pcie_gadget_target_link.attr, | ||
594 | &pcie_gadget_target_int_type.attr, | ||
595 | &pcie_gadget_target_no_of_msi.attr, | ||
596 | &pcie_gadget_target_inta.attr, | ||
597 | &pcie_gadget_target_send_msi.attr, | ||
598 | &pcie_gadget_target_vendor_id.attr, | ||
599 | &pcie_gadget_target_device_id.attr, | ||
600 | &pcie_gadget_target_bar0_size.attr, | ||
601 | &pcie_gadget_target_bar0_address.attr, | ||
602 | &pcie_gadget_target_bar0_rw_offset.attr, | ||
603 | &pcie_gadget_target_bar0_data.attr, | ||
604 | NULL, | ||
605 | }; | ||
606 | |||
607 | static struct pcie_gadget_target *to_target(struct config_item *item) | ||
608 | { | ||
609 | return item ? | ||
610 | container_of(to_configfs_subsystem(to_config_group(item)), | ||
611 | struct pcie_gadget_target, subsys) : NULL; | ||
612 | } | ||
613 | |||
614 | /* | ||
615 | * Item operations and type for pcie_gadget_target. | ||
616 | */ | ||
617 | |||
618 | static ssize_t pcie_gadget_target_attr_show(struct config_item *item, | ||
619 | struct configfs_attribute *attr, | ||
620 | char *buf) | ||
621 | { | ||
622 | ssize_t ret = -EINVAL; | ||
623 | struct pcie_gadget_target *target = to_target(item); | ||
624 | struct pcie_gadget_target_attr *t_attr = | ||
625 | container_of(attr, struct pcie_gadget_target_attr, attr); | ||
626 | |||
627 | if (t_attr->show) | ||
628 | ret = t_attr->show(&target->config, buf); | ||
629 | return ret; | ||
630 | } | ||
631 | |||
632 | static ssize_t pcie_gadget_target_attr_store(struct config_item *item, | ||
633 | struct configfs_attribute *attr, | ||
634 | const char *buf, | ||
635 | size_t count) | ||
636 | { | ||
637 | ssize_t ret = -EINVAL; | ||
638 | struct pcie_gadget_target *target = to_target(item); | ||
639 | struct pcie_gadget_target_attr *t_attr = | ||
640 | container_of(attr, struct pcie_gadget_target_attr, attr); | ||
641 | |||
642 | if (t_attr->store) | ||
643 | ret = t_attr->store(&target->config, buf, count); | ||
644 | return ret; | ||
645 | } | ||
646 | |||
647 | static struct configfs_item_operations pcie_gadget_target_item_ops = { | ||
648 | .show_attribute = pcie_gadget_target_attr_show, | ||
649 | .store_attribute = pcie_gadget_target_attr_store, | ||
650 | }; | ||
651 | |||
652 | static struct config_item_type pcie_gadget_target_type = { | ||
653 | .ct_attrs = pcie_gadget_target_attrs, | ||
654 | .ct_item_ops = &pcie_gadget_target_item_ops, | ||
655 | .ct_owner = THIS_MODULE, | ||
656 | }; | ||
657 | |||
658 | static void spear13xx_pcie_device_init(struct spear_pcie_gadget_config *config) | ||
659 | { | ||
660 | struct pcie_app_reg __iomem *app_reg = config->va_app_base; | ||
661 | |||
662 | /*setup registers for outbound translation */ | ||
663 | |||
664 | writel(config->base, &app_reg->in0_mem_addr_start); | ||
665 | writel(app_reg->in0_mem_addr_start + IN0_MEM_SIZE, | ||
666 | &app_reg->in0_mem_addr_limit); | ||
667 | writel(app_reg->in0_mem_addr_limit + 1, &app_reg->in1_mem_addr_start); | ||
668 | writel(app_reg->in1_mem_addr_start + IN1_MEM_SIZE, | ||
669 | &app_reg->in1_mem_addr_limit); | ||
670 | writel(app_reg->in1_mem_addr_limit + 1, &app_reg->in_io_addr_start); | ||
671 | writel(app_reg->in_io_addr_start + IN_IO_SIZE, | ||
672 | &app_reg->in_io_addr_limit); | ||
673 | writel(app_reg->in_io_addr_limit + 1, &app_reg->in_cfg0_addr_start); | ||
674 | writel(app_reg->in_cfg0_addr_start + IN_CFG0_SIZE, | ||
675 | &app_reg->in_cfg0_addr_limit); | ||
676 | writel(app_reg->in_cfg0_addr_limit + 1, &app_reg->in_cfg1_addr_start); | ||
677 | writel(app_reg->in_cfg1_addr_start + IN_CFG1_SIZE, | ||
678 | &app_reg->in_cfg1_addr_limit); | ||
679 | writel(app_reg->in_cfg1_addr_limit + 1, &app_reg->in_msg_addr_start); | ||
680 | writel(app_reg->in_msg_addr_start + IN_MSG_SIZE, | ||
681 | &app_reg->in_msg_addr_limit); | ||
682 | |||
683 | writel(app_reg->in0_mem_addr_start, &app_reg->pom0_mem_addr_start); | ||
684 | writel(app_reg->in1_mem_addr_start, &app_reg->pom1_mem_addr_start); | ||
685 | writel(app_reg->in_io_addr_start, &app_reg->pom_io_addr_start); | ||
686 | |||
687 | /*setup registers for inbound translation */ | ||
688 | |||
689 | /* Keep AORAM mapped at BAR0 as default */ | ||
690 | config->bar0_size = INBOUND_ADDR_MASK + 1; | ||
691 | spear_dbi_write_reg(config, PCIE_BAR0_MASK_REG, 4, INBOUND_ADDR_MASK); | ||
692 | spear_dbi_write_reg(config, PCI_BASE_ADDRESS_0, 4, 0xC); | ||
693 | config->va_bar0_address = ioremap(SPEAR13XX_SYSRAM1_BASE, | ||
694 | config->bar0_size); | ||
695 | |||
696 | writel(SPEAR13XX_SYSRAM1_BASE, &app_reg->pim0_mem_addr_start); | ||
697 | writel(0, &app_reg->pim1_mem_addr_start); | ||
698 | writel(INBOUND_ADDR_MASK + 1, &app_reg->mem0_addr_offset_limit); | ||
699 | |||
700 | writel(0x0, &app_reg->pim_io_addr_start); | ||
701 | writel(0x0, &app_reg->pim_io_addr_start); | ||
702 | writel(0x0, &app_reg->pim_rom_addr_start); | ||
703 | |||
704 | writel(DEVICE_TYPE_EP | (1 << MISCTRL_EN_ID) | ||
705 | | ((u32)1 << REG_TRANSLATION_ENABLE), | ||
706 | &app_reg->app_ctrl_0); | ||
707 | /* disable all rx interrupts */ | ||
708 | writel(0, &app_reg->int_mask); | ||
709 | |||
710 | /* Select INTA as default*/ | ||
711 | spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 1); | ||
712 | } | ||
713 | |||
714 | static int __devinit spear_pcie_gadget_probe(struct platform_device *pdev) | ||
715 | { | ||
716 | struct resource *res0, *res1; | ||
717 | unsigned int status = 0; | ||
718 | int irq; | ||
719 | struct clk *clk; | ||
720 | static struct pcie_gadget_target *target; | ||
721 | struct spear_pcie_gadget_config *config; | ||
722 | struct config_item *cg_item; | ||
723 | struct configfs_subsystem *subsys; | ||
724 | |||
725 | /* get resource for application registers*/ | ||
726 | |||
727 | res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
728 | if (!res0) { | ||
729 | dev_err(&pdev->dev, "no resource defined\n"); | ||
730 | return -EBUSY; | ||
731 | } | ||
732 | if (!request_mem_region(res0->start, resource_size(res0), | ||
733 | pdev->name)) { | ||
734 | dev_err(&pdev->dev, "pcie gadget region already claimed\n"); | ||
735 | return -EBUSY; | ||
736 | } | ||
737 | /* get resource for dbi registers*/ | ||
738 | |||
739 | res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
740 | if (!res1) { | ||
741 | dev_err(&pdev->dev, "no resource defined\n"); | ||
742 | goto err_rel_res0; | ||
743 | } | ||
744 | if (!request_mem_region(res1->start, resource_size(res1), | ||
745 | pdev->name)) { | ||
746 | dev_err(&pdev->dev, "pcie gadget region already claimed\n"); | ||
747 | goto err_rel_res0; | ||
748 | } | ||
749 | |||
750 | target = kzalloc(sizeof(*target), GFP_KERNEL); | ||
751 | if (!target) { | ||
752 | dev_err(&pdev->dev, "out of memory\n"); | ||
753 | status = -ENOMEM; | ||
754 | goto err_rel_res; | ||
755 | } | ||
756 | |||
757 | cg_item = &target->subsys.su_group.cg_item; | ||
758 | sprintf(cg_item->ci_namebuf, "pcie_gadget.%d", pdev->id); | ||
759 | cg_item->ci_type = &pcie_gadget_target_type; | ||
760 | config = &target->config; | ||
761 | config->va_app_base = (void __iomem *)ioremap(res0->start, | ||
762 | resource_size(res0)); | ||
763 | if (!config->va_app_base) { | ||
764 | dev_err(&pdev->dev, "ioremap fail\n"); | ||
765 | status = -ENOMEM; | ||
766 | goto err_kzalloc; | ||
767 | } | ||
768 | |||
769 | config->base = (void __iomem *)res1->start; | ||
770 | |||
771 | config->va_dbi_base = (void __iomem *)ioremap(res1->start, | ||
772 | resource_size(res1)); | ||
773 | if (!config->va_dbi_base) { | ||
774 | dev_err(&pdev->dev, "ioremap fail\n"); | ||
775 | status = -ENOMEM; | ||
776 | goto err_iounmap_app; | ||
777 | } | ||
778 | |||
779 | dev_set_drvdata(&pdev->dev, target); | ||
780 | |||
781 | irq = platform_get_irq(pdev, 0); | ||
782 | if (irq < 0) { | ||
783 | dev_err(&pdev->dev, "no update irq?\n"); | ||
784 | status = irq; | ||
785 | goto err_iounmap; | ||
786 | } | ||
787 | |||
788 | status = request_irq(irq, spear_pcie_gadget_irq, 0, pdev->name, NULL); | ||
789 | if (status) { | ||
790 | dev_err(&pdev->dev, | ||
791 | "pcie gadget interrupt IRQ%d already claimed\n", irq); | ||
792 | goto err_iounmap; | ||
793 | } | ||
794 | |||
795 | /* Register configfs hooks */ | ||
796 | subsys = &target->subsys; | ||
797 | config_group_init(&subsys->su_group); | ||
798 | mutex_init(&subsys->su_mutex); | ||
799 | status = configfs_register_subsystem(subsys); | ||
800 | if (status) | ||
801 | goto err_irq; | ||
802 | |||
803 | /* | ||
804 | * init basic pcie application registers | ||
805 | * do not enable clock if it is PCIE0.Ideally , all controller should | ||
806 | * have been independent from others with respect to clock. But PCIE1 | ||
807 | * and 2 depends on PCIE0.So PCIE0 clk is provided during board init. | ||
808 | */ | ||
809 | if (pdev->id == 1) { | ||
810 | /* | ||
811 | * Ideally CFG Clock should have been also enabled here. But | ||
812 | * it is done currently during board init routne | ||
813 | */ | ||
814 | clk = clk_get_sys("pcie1", NULL); | ||
815 | if (IS_ERR(clk)) { | ||
816 | pr_err("%s:couldn't get clk for pcie1\n", __func__); | ||
817 | goto err_irq; | ||
818 | } | ||
819 | if (clk_enable(clk)) { | ||
820 | pr_err("%s:couldn't enable clk for pcie1\n", __func__); | ||
821 | goto err_irq; | ||
822 | } | ||
823 | } else if (pdev->id == 2) { | ||
824 | /* | ||
825 | * Ideally CFG Clock should have been also enabled here. But | ||
826 | * it is done currently during board init routne | ||
827 | */ | ||
828 | clk = clk_get_sys("pcie2", NULL); | ||
829 | if (IS_ERR(clk)) { | ||
830 | pr_err("%s:couldn't get clk for pcie2\n", __func__); | ||
831 | goto err_irq; | ||
832 | } | ||
833 | if (clk_enable(clk)) { | ||
834 | pr_err("%s:couldn't enable clk for pcie2\n", __func__); | ||
835 | goto err_irq; | ||
836 | } | ||
837 | } | ||
838 | spear13xx_pcie_device_init(config); | ||
839 | |||
840 | return 0; | ||
841 | err_irq: | ||
842 | free_irq(irq, NULL); | ||
843 | err_iounmap: | ||
844 | iounmap(config->va_dbi_base); | ||
845 | err_iounmap_app: | ||
846 | iounmap(config->va_app_base); | ||
847 | err_kzalloc: | ||
848 | kfree(target); | ||
849 | err_rel_res: | ||
850 | release_mem_region(res1->start, resource_size(res1)); | ||
851 | err_rel_res0: | ||
852 | release_mem_region(res0->start, resource_size(res0)); | ||
853 | return status; | ||
854 | } | ||
855 | |||
856 | static int __devexit spear_pcie_gadget_remove(struct platform_device *pdev) | ||
857 | { | ||
858 | struct resource *res0, *res1; | ||
859 | static struct pcie_gadget_target *target; | ||
860 | struct spear_pcie_gadget_config *config; | ||
861 | int irq; | ||
862 | |||
863 | res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
864 | res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
865 | irq = platform_get_irq(pdev, 0); | ||
866 | target = dev_get_drvdata(&pdev->dev); | ||
867 | config = &target->config; | ||
868 | |||
869 | free_irq(irq, NULL); | ||
870 | iounmap(config->va_dbi_base); | ||
871 | iounmap(config->va_app_base); | ||
872 | release_mem_region(res1->start, resource_size(res1)); | ||
873 | release_mem_region(res0->start, resource_size(res0)); | ||
874 | configfs_unregister_subsystem(&target->subsys); | ||
875 | kfree(target); | ||
876 | |||
877 | return 0; | ||
878 | } | ||
879 | |||
880 | static void spear_pcie_gadget_shutdown(struct platform_device *pdev) | ||
881 | { | ||
882 | } | ||
883 | |||
884 | static struct platform_driver spear_pcie_gadget_driver = { | ||
885 | .probe = spear_pcie_gadget_probe, | ||
886 | .remove = spear_pcie_gadget_remove, | ||
887 | .shutdown = spear_pcie_gadget_shutdown, | ||
888 | .driver = { | ||
889 | .name = "pcie-gadget-spear", | ||
890 | .bus = &platform_bus_type | ||
891 | }, | ||
892 | }; | ||
893 | |||
894 | static int __init spear_pcie_gadget_init(void) | ||
895 | { | ||
896 | return platform_driver_register(&spear_pcie_gadget_driver); | ||
897 | } | ||
898 | module_init(spear_pcie_gadget_init); | ||
899 | |||
900 | static void __exit spear_pcie_gadget_exit(void) | ||
901 | { | ||
902 | platform_driver_unregister(&spear_pcie_gadget_driver); | ||
903 | } | ||
904 | module_exit(spear_pcie_gadget_exit); | ||
905 | |||
906 | MODULE_ALIAS("pcie-gadget-spear"); | ||
907 | MODULE_AUTHOR("Pratyush Anand"); | ||
908 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/misc/ti-st/Kconfig b/drivers/misc/ti-st/Kconfig new file mode 100644 index 000000000000..abb5de1afce3 --- /dev/null +++ b/drivers/misc/ti-st/Kconfig | |||
@@ -0,0 +1,17 @@ | |||
1 | # | ||
2 | # TI's shared transport line discipline and the protocol | ||
3 | # drivers (BT, FM and GPS) | ||
4 | # | ||
5 | menu "Texas Instruments shared transport line discipline" | ||
6 | config TI_ST | ||
7 | tristate "Shared transport core driver" | ||
8 | depends on NET && GPIOLIB | ||
9 | select FW_LOADER | ||
10 | help | ||
11 | This enables the shared transport core driver for TI | ||
12 | BT / FM and GPS combo chips. This enables protocol drivers | ||
13 | to register themselves with core and send data, the responses | ||
14 | are returned to relevant protocol drivers based on their | ||
15 | packet types. | ||
16 | |||
17 | endmenu | ||
diff --git a/drivers/misc/ti-st/Makefile b/drivers/misc/ti-st/Makefile new file mode 100644 index 000000000000..78d7ebb14749 --- /dev/null +++ b/drivers/misc/ti-st/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for TI's shared transport line discipline | ||
3 | # and its protocol drivers (BT, FM, GPS) | ||
4 | # | ||
5 | obj-$(CONFIG_TI_ST) += st_drv.o | ||
6 | st_drv-objs := st_core.o st_kim.o st_ll.o | ||
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c new file mode 100644 index 000000000000..54c91ffe4a91 --- /dev/null +++ b/drivers/misc/ti-st/st_core.c | |||
@@ -0,0 +1,872 @@ | |||
1 | /* | ||
2 | * Shared Transport Line discipline driver Core | ||
3 | * This hooks up ST KIM driver and ST LL driver | ||
4 | * Copyright (C) 2009-2010 Texas Instruments | ||
5 | * Author: Pavan Savoy <pavan_savoy@ti.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #define pr_fmt(fmt) "(stc): " fmt | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/tty.h> | ||
27 | |||
28 | #include <linux/seq_file.h> | ||
29 | #include <linux/skbuff.h> | ||
30 | |||
31 | #include <linux/ti_wilink_st.h> | ||
32 | |||
33 | /* function pointer pointing to either, | ||
34 | * st_kim_recv during registration to receive fw download responses | ||
35 | * st_int_recv after registration to receive proto stack responses | ||
36 | */ | ||
37 | void (*st_recv) (void*, const unsigned char*, long); | ||
38 | |||
39 | /********************************************************************/ | ||
40 | static void add_channel_to_table(struct st_data_s *st_gdata, | ||
41 | struct st_proto_s *new_proto) | ||
42 | { | ||
43 | pr_info("%s: id %d\n", __func__, new_proto->chnl_id); | ||
44 | /* list now has the channel id as index itself */ | ||
45 | st_gdata->list[new_proto->chnl_id] = new_proto; | ||
46 | st_gdata->is_registered[new_proto->chnl_id] = true; | ||
47 | } | ||
48 | |||
49 | static void remove_channel_from_table(struct st_data_s *st_gdata, | ||
50 | struct st_proto_s *proto) | ||
51 | { | ||
52 | pr_info("%s: id %d\n", __func__, proto->chnl_id); | ||
53 | /* st_gdata->list[proto->chnl_id] = NULL; */ | ||
54 | st_gdata->is_registered[proto->chnl_id] = false; | ||
55 | } | ||
56 | |||
57 | /* | ||
58 | * called from KIM during firmware download. | ||
59 | * | ||
60 | * This is a wrapper function to tty->ops->write_room. | ||
61 | * It returns number of free space available in | ||
62 | * uart tx buffer. | ||
63 | */ | ||
64 | int st_get_uart_wr_room(struct st_data_s *st_gdata) | ||
65 | { | ||
66 | struct tty_struct *tty; | ||
67 | if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) { | ||
68 | pr_err("tty unavailable to perform write"); | ||
69 | return -1; | ||
70 | } | ||
71 | tty = st_gdata->tty; | ||
72 | return tty->ops->write_room(tty); | ||
73 | } | ||
74 | |||
75 | /* can be called in from | ||
76 | * -- KIM (during fw download) | ||
77 | * -- ST Core (during st_write) | ||
78 | * | ||
79 | * This is the internal write function - a wrapper | ||
80 | * to tty->ops->write | ||
81 | */ | ||
82 | int st_int_write(struct st_data_s *st_gdata, | ||
83 | const unsigned char *data, int count) | ||
84 | { | ||
85 | struct tty_struct *tty; | ||
86 | if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) { | ||
87 | pr_err("tty unavailable to perform write"); | ||
88 | return -EINVAL; | ||
89 | } | ||
90 | tty = st_gdata->tty; | ||
91 | #ifdef VERBOSE | ||
92 | print_hex_dump(KERN_DEBUG, "<out<", DUMP_PREFIX_NONE, | ||
93 | 16, 1, data, count, 0); | ||
94 | #endif | ||
95 | return tty->ops->write(tty, data, count); | ||
96 | |||
97 | } | ||
98 | |||
99 | /* | ||
100 | * push the skb received to relevant | ||
101 | * protocol stacks | ||
102 | */ | ||
103 | void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata) | ||
104 | { | ||
105 | pr_debug(" %s(prot:%d) ", __func__, chnl_id); | ||
106 | |||
107 | if (unlikely | ||
108 | (st_gdata == NULL || st_gdata->rx_skb == NULL | ||
109 | || st_gdata->is_registered[chnl_id] == false)) { | ||
110 | pr_err("chnl_id %d not registered, no data to send?", | ||
111 | chnl_id); | ||
112 | kfree_skb(st_gdata->rx_skb); | ||
113 | return; | ||
114 | } | ||
115 | /* this cannot fail | ||
116 | * this shouldn't take long | ||
117 | * - should be just skb_queue_tail for the | ||
118 | * protocol stack driver | ||
119 | */ | ||
120 | if (likely(st_gdata->list[chnl_id]->recv != NULL)) { | ||
121 | if (unlikely | ||
122 | (st_gdata->list[chnl_id]->recv | ||
123 | (st_gdata->list[chnl_id]->priv_data, st_gdata->rx_skb) | ||
124 | != 0)) { | ||
125 | pr_err(" proto stack %d's ->recv failed", chnl_id); | ||
126 | kfree_skb(st_gdata->rx_skb); | ||
127 | return; | ||
128 | } | ||
129 | } else { | ||
130 | pr_err(" proto stack %d's ->recv null", chnl_id); | ||
131 | kfree_skb(st_gdata->rx_skb); | ||
132 | } | ||
133 | return; | ||
134 | } | ||
135 | |||
136 | /** | ||
137 | * st_reg_complete - | ||
138 | * to call registration complete callbacks | ||
139 | * of all protocol stack drivers | ||
140 | */ | ||
141 | void st_reg_complete(struct st_data_s *st_gdata, char err) | ||
142 | { | ||
143 | unsigned char i = 0; | ||
144 | pr_info(" %s ", __func__); | ||
145 | for (i = 0; i < ST_MAX_CHANNELS; i++) { | ||
146 | if (likely(st_gdata != NULL && | ||
147 | st_gdata->is_registered[i] == true && | ||
148 | st_gdata->list[i]->reg_complete_cb != NULL)) { | ||
149 | st_gdata->list[i]->reg_complete_cb | ||
150 | (st_gdata->list[i]->priv_data, err); | ||
151 | pr_info("protocol %d's cb sent %d\n", i, err); | ||
152 | if (err) { /* cleanup registered protocol */ | ||
153 | st_gdata->protos_registered--; | ||
154 | st_gdata->is_registered[i] = false; | ||
155 | } | ||
156 | } | ||
157 | } | ||
158 | } | ||
159 | |||
160 | static inline int st_check_data_len(struct st_data_s *st_gdata, | ||
161 | unsigned char chnl_id, int len) | ||
162 | { | ||
163 | int room = skb_tailroom(st_gdata->rx_skb); | ||
164 | |||
165 | pr_debug("len %d room %d", len, room); | ||
166 | |||
167 | if (!len) { | ||
168 | /* Received packet has only packet header and | ||
169 | * has zero length payload. So, ask ST CORE to | ||
170 | * forward the packet to protocol driver (BT/FM/GPS) | ||
171 | */ | ||
172 | st_send_frame(chnl_id, st_gdata); | ||
173 | |||
174 | } else if (len > room) { | ||
175 | /* Received packet's payload length is larger. | ||
176 | * We can't accommodate it in created skb. | ||
177 | */ | ||
178 | pr_err("Data length is too large len %d room %d", len, | ||
179 | room); | ||
180 | kfree_skb(st_gdata->rx_skb); | ||
181 | } else { | ||
182 | /* Packet header has non-zero payload length and | ||
183 | * we have enough space in created skb. Lets read | ||
184 | * payload data */ | ||
185 | st_gdata->rx_state = ST_W4_DATA; | ||
186 | st_gdata->rx_count = len; | ||
187 | return len; | ||
188 | } | ||
189 | |||
190 | /* Change ST state to continue to process next | ||
191 | * packet */ | ||
192 | st_gdata->rx_state = ST_W4_PACKET_TYPE; | ||
193 | st_gdata->rx_skb = NULL; | ||
194 | st_gdata->rx_count = 0; | ||
195 | st_gdata->rx_chnl = 0; | ||
196 | |||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | /** | ||
201 | * st_wakeup_ack - internal function for action when wake-up ack | ||
202 | * received | ||
203 | */ | ||
204 | static inline void st_wakeup_ack(struct st_data_s *st_gdata, | ||
205 | unsigned char cmd) | ||
206 | { | ||
207 | struct sk_buff *waiting_skb; | ||
208 | unsigned long flags = 0; | ||
209 | |||
210 | spin_lock_irqsave(&st_gdata->lock, flags); | ||
211 | /* de-Q from waitQ and Q in txQ now that the | ||
212 | * chip is awake | ||
213 | */ | ||
214 | while ((waiting_skb = skb_dequeue(&st_gdata->tx_waitq))) | ||
215 | skb_queue_tail(&st_gdata->txq, waiting_skb); | ||
216 | |||
217 | /* state forwarded to ST LL */ | ||
218 | st_ll_sleep_state(st_gdata, (unsigned long)cmd); | ||
219 | spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
220 | |||
221 | /* wake up to send the recently copied skbs from waitQ */ | ||
222 | st_tx_wakeup(st_gdata); | ||
223 | } | ||
224 | |||
225 | /** | ||
226 | * st_int_recv - ST's internal receive function. | ||
227 | * Decodes received RAW data and forwards to corresponding | ||
228 | * client drivers (Bluetooth,FM,GPS..etc). | ||
229 | * This can receive various types of packets, | ||
230 | * HCI-Events, ACL, SCO, 4 types of HCI-LL PM packets | ||
231 | * CH-8 packets from FM, CH-9 packets from GPS cores. | ||
232 | */ | ||
233 | void st_int_recv(void *disc_data, | ||
234 | const unsigned char *data, long count) | ||
235 | { | ||
236 | char *ptr; | ||
237 | struct st_proto_s *proto; | ||
238 | unsigned short payload_len = 0; | ||
239 | int len = 0, type = 0; | ||
240 | unsigned char *plen; | ||
241 | struct st_data_s *st_gdata = (struct st_data_s *)disc_data; | ||
242 | unsigned long flags; | ||
243 | |||
244 | ptr = (char *)data; | ||
245 | /* tty_receive sent null ? */ | ||
246 | if (unlikely(ptr == NULL) || (st_gdata == NULL)) { | ||
247 | pr_err(" received null from TTY "); | ||
248 | return; | ||
249 | } | ||
250 | |||
251 | pr_debug("count %ld rx_state %ld" | ||
252 | "rx_count %ld", count, st_gdata->rx_state, | ||
253 | st_gdata->rx_count); | ||
254 | |||
255 | spin_lock_irqsave(&st_gdata->lock, flags); | ||
256 | /* Decode received bytes here */ | ||
257 | while (count) { | ||
258 | if (st_gdata->rx_count) { | ||
259 | len = min_t(unsigned int, st_gdata->rx_count, count); | ||
260 | memcpy(skb_put(st_gdata->rx_skb, len), ptr, len); | ||
261 | st_gdata->rx_count -= len; | ||
262 | count -= len; | ||
263 | ptr += len; | ||
264 | |||
265 | if (st_gdata->rx_count) | ||
266 | continue; | ||
267 | |||
268 | /* Check ST RX state machine , where are we? */ | ||
269 | switch (st_gdata->rx_state) { | ||
270 | /* Waiting for complete packet ? */ | ||
271 | case ST_W4_DATA: | ||
272 | pr_debug("Complete pkt received"); | ||
273 | /* Ask ST CORE to forward | ||
274 | * the packet to protocol driver */ | ||
275 | st_send_frame(st_gdata->rx_chnl, st_gdata); | ||
276 | |||
277 | st_gdata->rx_state = ST_W4_PACKET_TYPE; | ||
278 | st_gdata->rx_skb = NULL; | ||
279 | continue; | ||
280 | /* parse the header to know details */ | ||
281 | case ST_W4_HEADER: | ||
282 | proto = st_gdata->list[st_gdata->rx_chnl]; | ||
283 | plen = | ||
284 | &st_gdata->rx_skb->data | ||
285 | [proto->offset_len_in_hdr]; | ||
286 | pr_debug("plen pointing to %x\n", *plen); | ||
287 | if (proto->len_size == 1)/* 1 byte len field */ | ||
288 | payload_len = *(unsigned char *)plen; | ||
289 | else if (proto->len_size == 2) | ||
290 | payload_len = | ||
291 | __le16_to_cpu(*(unsigned short *)plen); | ||
292 | else | ||
293 | pr_info("%s: invalid length " | ||
294 | "for id %d\n", | ||
295 | __func__, proto->chnl_id); | ||
296 | st_check_data_len(st_gdata, proto->chnl_id, | ||
297 | payload_len); | ||
298 | pr_debug("off %d, pay len %d\n", | ||
299 | proto->offset_len_in_hdr, payload_len); | ||
300 | continue; | ||
301 | } /* end of switch rx_state */ | ||
302 | } | ||
303 | |||
304 | /* end of if rx_count */ | ||
305 | /* Check first byte of packet and identify module | ||
306 | * owner (BT/FM/GPS) */ | ||
307 | switch (*ptr) { | ||
308 | case LL_SLEEP_IND: | ||
309 | case LL_SLEEP_ACK: | ||
310 | case LL_WAKE_UP_IND: | ||
311 | pr_debug("PM packet"); | ||
312 | /* this takes appropriate action based on | ||
313 | * sleep state received -- | ||
314 | */ | ||
315 | st_ll_sleep_state(st_gdata, *ptr); | ||
316 | /* if WAKEUP_IND collides copy from waitq to txq | ||
317 | * and assume chip awake | ||
318 | */ | ||
319 | spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
320 | if (st_ll_getstate(st_gdata) == ST_LL_AWAKE) | ||
321 | st_wakeup_ack(st_gdata, LL_WAKE_UP_ACK); | ||
322 | spin_lock_irqsave(&st_gdata->lock, flags); | ||
323 | |||
324 | ptr++; | ||
325 | count--; | ||
326 | continue; | ||
327 | case LL_WAKE_UP_ACK: | ||
328 | pr_debug("PM packet"); | ||
329 | |||
330 | spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
331 | /* wake up ack received */ | ||
332 | st_wakeup_ack(st_gdata, *ptr); | ||
333 | spin_lock_irqsave(&st_gdata->lock, flags); | ||
334 | |||
335 | ptr++; | ||
336 | count--; | ||
337 | continue; | ||
338 | /* Unknow packet? */ | ||
339 | default: | ||
340 | type = *ptr; | ||
341 | st_gdata->rx_skb = alloc_skb( | ||
342 | st_gdata->list[type]->max_frame_size, | ||
343 | GFP_ATOMIC); | ||
344 | skb_reserve(st_gdata->rx_skb, | ||
345 | st_gdata->list[type]->reserve); | ||
346 | /* next 2 required for BT only */ | ||
347 | st_gdata->rx_skb->cb[0] = type; /*pkt_type*/ | ||
348 | st_gdata->rx_skb->cb[1] = 0; /*incoming*/ | ||
349 | st_gdata->rx_chnl = *ptr; | ||
350 | st_gdata->rx_state = ST_W4_HEADER; | ||
351 | st_gdata->rx_count = st_gdata->list[type]->hdr_len; | ||
352 | pr_debug("rx_count %ld\n", st_gdata->rx_count); | ||
353 | }; | ||
354 | ptr++; | ||
355 | count--; | ||
356 | } | ||
357 | spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
358 | pr_debug("done %s", __func__); | ||
359 | return; | ||
360 | } | ||
361 | |||
362 | /** | ||
363 | * st_int_dequeue - internal de-Q function. | ||
364 | * If the previous data set was not written | ||
365 | * completely, return that skb which has the pending data. | ||
366 | * In normal cases, return top of txq. | ||
367 | */ | ||
368 | struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata) | ||
369 | { | ||
370 | struct sk_buff *returning_skb; | ||
371 | |||
372 | pr_debug("%s", __func__); | ||
373 | if (st_gdata->tx_skb != NULL) { | ||
374 | returning_skb = st_gdata->tx_skb; | ||
375 | st_gdata->tx_skb = NULL; | ||
376 | return returning_skb; | ||
377 | } | ||
378 | return skb_dequeue(&st_gdata->txq); | ||
379 | } | ||
380 | |||
381 | /** | ||
382 | * st_int_enqueue - internal Q-ing function. | ||
383 | * Will either Q the skb to txq or the tx_waitq | ||
384 | * depending on the ST LL state. | ||
385 | * If the chip is asleep, then Q it onto waitq and | ||
386 | * wakeup the chip. | ||
387 | * txq and waitq needs protection since the other contexts | ||
388 | * may be sending data, waking up chip. | ||
389 | */ | ||
390 | void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb) | ||
391 | { | ||
392 | unsigned long flags = 0; | ||
393 | |||
394 | pr_debug("%s", __func__); | ||
395 | spin_lock_irqsave(&st_gdata->lock, flags); | ||
396 | |||
397 | switch (st_ll_getstate(st_gdata)) { | ||
398 | case ST_LL_AWAKE: | ||
399 | pr_debug("ST LL is AWAKE, sending normally"); | ||
400 | skb_queue_tail(&st_gdata->txq, skb); | ||
401 | break; | ||
402 | case ST_LL_ASLEEP_TO_AWAKE: | ||
403 | skb_queue_tail(&st_gdata->tx_waitq, skb); | ||
404 | break; | ||
405 | case ST_LL_AWAKE_TO_ASLEEP: | ||
406 | pr_err("ST LL is illegal state(%ld)," | ||
407 | "purging received skb.", st_ll_getstate(st_gdata)); | ||
408 | kfree_skb(skb); | ||
409 | break; | ||
410 | case ST_LL_ASLEEP: | ||
411 | skb_queue_tail(&st_gdata->tx_waitq, skb); | ||
412 | st_ll_wakeup(st_gdata); | ||
413 | break; | ||
414 | default: | ||
415 | pr_err("ST LL is illegal state(%ld)," | ||
416 | "purging received skb.", st_ll_getstate(st_gdata)); | ||
417 | kfree_skb(skb); | ||
418 | break; | ||
419 | } | ||
420 | |||
421 | spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
422 | pr_debug("done %s", __func__); | ||
423 | return; | ||
424 | } | ||
425 | |||
426 | /* | ||
427 | * internal wakeup function | ||
428 | * called from either | ||
429 | * - TTY layer when write's finished | ||
430 | * - st_write (in context of the protocol stack) | ||
431 | */ | ||
432 | void st_tx_wakeup(struct st_data_s *st_data) | ||
433 | { | ||
434 | struct sk_buff *skb; | ||
435 | unsigned long flags; /* for irq save flags */ | ||
436 | pr_debug("%s", __func__); | ||
437 | /* check for sending & set flag sending here */ | ||
438 | if (test_and_set_bit(ST_TX_SENDING, &st_data->tx_state)) { | ||
439 | pr_debug("ST already sending"); | ||
440 | /* keep sending */ | ||
441 | set_bit(ST_TX_WAKEUP, &st_data->tx_state); | ||
442 | return; | ||
443 | /* TX_WAKEUP will be checked in another | ||
444 | * context | ||
445 | */ | ||
446 | } | ||
447 | do { /* come back if st_tx_wakeup is set */ | ||
448 | /* woke-up to write */ | ||
449 | clear_bit(ST_TX_WAKEUP, &st_data->tx_state); | ||
450 | while ((skb = st_int_dequeue(st_data))) { | ||
451 | int len; | ||
452 | spin_lock_irqsave(&st_data->lock, flags); | ||
453 | /* enable wake-up from TTY */ | ||
454 | set_bit(TTY_DO_WRITE_WAKEUP, &st_data->tty->flags); | ||
455 | len = st_int_write(st_data, skb->data, skb->len); | ||
456 | skb_pull(skb, len); | ||
457 | /* if skb->len = len as expected, skb->len=0 */ | ||
458 | if (skb->len) { | ||
459 | /* would be the next skb to be sent */ | ||
460 | st_data->tx_skb = skb; | ||
461 | spin_unlock_irqrestore(&st_data->lock, flags); | ||
462 | break; | ||
463 | } | ||
464 | kfree_skb(skb); | ||
465 | spin_unlock_irqrestore(&st_data->lock, flags); | ||
466 | } | ||
467 | /* if wake-up is set in another context- restart sending */ | ||
468 | } while (test_bit(ST_TX_WAKEUP, &st_data->tx_state)); | ||
469 | |||
470 | /* clear flag sending */ | ||
471 | clear_bit(ST_TX_SENDING, &st_data->tx_state); | ||
472 | } | ||
473 | |||
474 | /********************************************************************/ | ||
475 | /* functions called from ST KIM | ||
476 | */ | ||
477 | void kim_st_list_protocols(struct st_data_s *st_gdata, void *buf) | ||
478 | { | ||
479 | seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n", | ||
480 | st_gdata->protos_registered, | ||
481 | st_gdata->is_registered[0x04] == true ? 'R' : 'U', | ||
482 | st_gdata->is_registered[0x08] == true ? 'R' : 'U', | ||
483 | st_gdata->is_registered[0x09] == true ? 'R' : 'U'); | ||
484 | } | ||
485 | |||
486 | /********************************************************************/ | ||
487 | /* | ||
488 | * functions called from protocol stack drivers | ||
489 | * to be EXPORT-ed | ||
490 | */ | ||
491 | long st_register(struct st_proto_s *new_proto) | ||
492 | { | ||
493 | struct st_data_s *st_gdata; | ||
494 | long err = 0; | ||
495 | unsigned long flags = 0; | ||
496 | |||
497 | st_kim_ref(&st_gdata, 0); | ||
498 | pr_info("%s(%d) ", __func__, new_proto->chnl_id); | ||
499 | if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL | ||
500 | || new_proto->reg_complete_cb == NULL) { | ||
501 | pr_err("gdata/new_proto/recv or reg_complete_cb not ready"); | ||
502 | return -EINVAL; | ||
503 | } | ||
504 | |||
505 | if (new_proto->chnl_id >= ST_MAX_CHANNELS) { | ||
506 | pr_err("chnl_id %d not supported", new_proto->chnl_id); | ||
507 | return -EPROTONOSUPPORT; | ||
508 | } | ||
509 | |||
510 | if (st_gdata->is_registered[new_proto->chnl_id] == true) { | ||
511 | pr_err("chnl_id %d already registered", new_proto->chnl_id); | ||
512 | return -EALREADY; | ||
513 | } | ||
514 | |||
515 | /* can be from process context only */ | ||
516 | spin_lock_irqsave(&st_gdata->lock, flags); | ||
517 | |||
518 | if (test_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state)) { | ||
519 | pr_info(" ST_REG_IN_PROGRESS:%d ", new_proto->chnl_id); | ||
520 | /* fw download in progress */ | ||
521 | |||
522 | add_channel_to_table(st_gdata, new_proto); | ||
523 | st_gdata->protos_registered++; | ||
524 | new_proto->write = st_write; | ||
525 | |||
526 | set_bit(ST_REG_PENDING, &st_gdata->st_state); | ||
527 | spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
528 | return -EINPROGRESS; | ||
529 | } else if (st_gdata->protos_registered == ST_EMPTY) { | ||
530 | pr_info(" chnl_id list empty :%d ", new_proto->chnl_id); | ||
531 | set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); | ||
532 | st_recv = st_kim_recv; | ||
533 | |||
534 | /* release lock previously held - re-locked below */ | ||
535 | spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
536 | |||
537 | /* enable the ST LL - to set default chip state */ | ||
538 | st_ll_enable(st_gdata); | ||
539 | /* this may take a while to complete | ||
540 | * since it involves BT fw download | ||
541 | */ | ||
542 | err = st_kim_start(st_gdata->kim_data); | ||
543 | if (err != 0) { | ||
544 | clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); | ||
545 | if ((st_gdata->protos_registered != ST_EMPTY) && | ||
546 | (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { | ||
547 | pr_err(" KIM failure complete callback "); | ||
548 | st_reg_complete(st_gdata, err); | ||
549 | } | ||
550 | return -EINVAL; | ||
551 | } | ||
552 | |||
553 | clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); | ||
554 | st_recv = st_int_recv; | ||
555 | |||
556 | /* this is where all pending registration | ||
557 | * are signalled to be complete by calling callback functions | ||
558 | */ | ||
559 | if ((st_gdata->protos_registered != ST_EMPTY) && | ||
560 | (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { | ||
561 | pr_debug(" call reg complete callback "); | ||
562 | st_reg_complete(st_gdata, 0); | ||
563 | } | ||
564 | clear_bit(ST_REG_PENDING, &st_gdata->st_state); | ||
565 | |||
566 | /* check for already registered once more, | ||
567 | * since the above check is old | ||
568 | */ | ||
569 | if (st_gdata->is_registered[new_proto->chnl_id] == true) { | ||
570 | pr_err(" proto %d already registered ", | ||
571 | new_proto->chnl_id); | ||
572 | return -EALREADY; | ||
573 | } | ||
574 | |||
575 | spin_lock_irqsave(&st_gdata->lock, flags); | ||
576 | add_channel_to_table(st_gdata, new_proto); | ||
577 | st_gdata->protos_registered++; | ||
578 | new_proto->write = st_write; | ||
579 | spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
580 | return err; | ||
581 | } | ||
582 | /* if fw is already downloaded & new stack registers protocol */ | ||
583 | else { | ||
584 | add_channel_to_table(st_gdata, new_proto); | ||
585 | st_gdata->protos_registered++; | ||
586 | new_proto->write = st_write; | ||
587 | |||
588 | /* lock already held before entering else */ | ||
589 | spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
590 | return err; | ||
591 | } | ||
592 | pr_debug("done %s(%d) ", __func__, new_proto->chnl_id); | ||
593 | } | ||
594 | EXPORT_SYMBOL_GPL(st_register); | ||
595 | |||
596 | /* to unregister a protocol - | ||
597 | * to be called from protocol stack driver | ||
598 | */ | ||
599 | long st_unregister(struct st_proto_s *proto) | ||
600 | { | ||
601 | long err = 0; | ||
602 | unsigned long flags = 0; | ||
603 | struct st_data_s *st_gdata; | ||
604 | |||
605 | pr_debug("%s: %d ", __func__, proto->chnl_id); | ||
606 | |||
607 | st_kim_ref(&st_gdata, 0); | ||
608 | if (!st_gdata || proto->chnl_id >= ST_MAX_CHANNELS) { | ||
609 | pr_err(" chnl_id %d not supported", proto->chnl_id); | ||
610 | return -EPROTONOSUPPORT; | ||
611 | } | ||
612 | |||
613 | spin_lock_irqsave(&st_gdata->lock, flags); | ||
614 | |||
615 | if (st_gdata->list[proto->chnl_id] == NULL) { | ||
616 | pr_err(" chnl_id %d not registered", proto->chnl_id); | ||
617 | spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
618 | return -EPROTONOSUPPORT; | ||
619 | } | ||
620 | |||
621 | st_gdata->protos_registered--; | ||
622 | remove_channel_from_table(st_gdata, proto); | ||
623 | spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
624 | |||
625 | if ((st_gdata->protos_registered == ST_EMPTY) && | ||
626 | (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) { | ||
627 | pr_info(" all chnl_ids unregistered "); | ||
628 | |||
629 | /* stop traffic on tty */ | ||
630 | if (st_gdata->tty) { | ||
631 | tty_ldisc_flush(st_gdata->tty); | ||
632 | stop_tty(st_gdata->tty); | ||
633 | } | ||
634 | |||
635 | /* all chnl_ids now unregistered */ | ||
636 | st_kim_stop(st_gdata->kim_data); | ||
637 | /* disable ST LL */ | ||
638 | st_ll_disable(st_gdata); | ||
639 | } | ||
640 | return err; | ||
641 | } | ||
642 | |||
643 | /* | ||
644 | * called in protocol stack drivers | ||
645 | * via the write function pointer | ||
646 | */ | ||
647 | long st_write(struct sk_buff *skb) | ||
648 | { | ||
649 | struct st_data_s *st_gdata; | ||
650 | long len; | ||
651 | |||
652 | st_kim_ref(&st_gdata, 0); | ||
653 | if (unlikely(skb == NULL || st_gdata == NULL | ||
654 | || st_gdata->tty == NULL)) { | ||
655 | pr_err("data/tty unavailable to perform write"); | ||
656 | return -EINVAL; | ||
657 | } | ||
658 | |||
659 | pr_debug("%d to be written", skb->len); | ||
660 | len = skb->len; | ||
661 | |||
662 | /* st_ll to decide where to enqueue the skb */ | ||
663 | st_int_enqueue(st_gdata, skb); | ||
664 | /* wake up */ | ||
665 | st_tx_wakeup(st_gdata); | ||
666 | |||
667 | /* return number of bytes written */ | ||
668 | return len; | ||
669 | } | ||
670 | |||
671 | /* for protocols making use of shared transport */ | ||
672 | EXPORT_SYMBOL_GPL(st_unregister); | ||
673 | |||
674 | /********************************************************************/ | ||
675 | /* | ||
676 | * functions called from TTY layer | ||
677 | */ | ||
678 | static int st_tty_open(struct tty_struct *tty) | ||
679 | { | ||
680 | int err = 0; | ||
681 | struct st_data_s *st_gdata; | ||
682 | pr_info("%s ", __func__); | ||
683 | |||
684 | st_kim_ref(&st_gdata, 0); | ||
685 | st_gdata->tty = tty; | ||
686 | tty->disc_data = st_gdata; | ||
687 | |||
688 | /* don't do an wakeup for now */ | ||
689 | clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); | ||
690 | |||
691 | /* mem already allocated | ||
692 | */ | ||
693 | tty->receive_room = 65536; | ||
694 | /* Flush any pending characters in the driver and discipline. */ | ||
695 | tty_ldisc_flush(tty); | ||
696 | tty_driver_flush_buffer(tty); | ||
697 | /* | ||
698 | * signal to UIM via KIM that - | ||
699 | * installation of N_TI_WL ldisc is complete | ||
700 | */ | ||
701 | st_kim_complete(st_gdata->kim_data); | ||
702 | pr_debug("done %s", __func__); | ||
703 | return err; | ||
704 | } | ||
705 | |||
706 | static void st_tty_close(struct tty_struct *tty) | ||
707 | { | ||
708 | unsigned char i = ST_MAX_CHANNELS; | ||
709 | unsigned long flags = 0; | ||
710 | struct st_data_s *st_gdata = tty->disc_data; | ||
711 | |||
712 | pr_info("%s ", __func__); | ||
713 | |||
714 | /* TODO: | ||
715 | * if a protocol has been registered & line discipline | ||
716 | * un-installed for some reason - what should be done ? | ||
717 | */ | ||
718 | spin_lock_irqsave(&st_gdata->lock, flags); | ||
719 | for (i = ST_BT; i < ST_MAX_CHANNELS; i++) { | ||
720 | if (st_gdata->list[i] != NULL) | ||
721 | pr_err("%d not un-registered", i); | ||
722 | st_gdata->list[i] = NULL; | ||
723 | } | ||
724 | st_gdata->protos_registered = 0; | ||
725 | spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
726 | /* | ||
727 | * signal to UIM via KIM that - | ||
728 | * N_TI_WL ldisc is un-installed | ||
729 | */ | ||
730 | st_kim_complete(st_gdata->kim_data); | ||
731 | st_gdata->tty = NULL; | ||
732 | /* Flush any pending characters in the driver and discipline. */ | ||
733 | tty_ldisc_flush(tty); | ||
734 | tty_driver_flush_buffer(tty); | ||
735 | |||
736 | spin_lock_irqsave(&st_gdata->lock, flags); | ||
737 | /* empty out txq and tx_waitq */ | ||
738 | skb_queue_purge(&st_gdata->txq); | ||
739 | skb_queue_purge(&st_gdata->tx_waitq); | ||
740 | /* reset the TTY Rx states of ST */ | ||
741 | st_gdata->rx_count = 0; | ||
742 | st_gdata->rx_state = ST_W4_PACKET_TYPE; | ||
743 | kfree_skb(st_gdata->rx_skb); | ||
744 | st_gdata->rx_skb = NULL; | ||
745 | spin_unlock_irqrestore(&st_gdata->lock, flags); | ||
746 | |||
747 | pr_debug("%s: done ", __func__); | ||
748 | } | ||
749 | |||
750 | static void st_tty_receive(struct tty_struct *tty, const unsigned char *data, | ||
751 | char *tty_flags, int count) | ||
752 | { | ||
753 | #ifdef VERBOSE | ||
754 | print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE, | ||
755 | 16, 1, data, count, 0); | ||
756 | #endif | ||
757 | |||
758 | /* | ||
759 | * if fw download is in progress then route incoming data | ||
760 | * to KIM for validation | ||
761 | */ | ||
762 | st_recv(tty->disc_data, data, count); | ||
763 | pr_debug("done %s", __func__); | ||
764 | } | ||
765 | |||
766 | /* wake-up function called in from the TTY layer | ||
767 | * inside the internal wakeup function will be called | ||
768 | */ | ||
769 | static void st_tty_wakeup(struct tty_struct *tty) | ||
770 | { | ||
771 | struct st_data_s *st_gdata = tty->disc_data; | ||
772 | pr_debug("%s ", __func__); | ||
773 | /* don't do an wakeup for now */ | ||
774 | clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); | ||
775 | |||
776 | /* call our internal wakeup */ | ||
777 | st_tx_wakeup((void *)st_gdata); | ||
778 | } | ||
779 | |||
780 | static void st_tty_flush_buffer(struct tty_struct *tty) | ||
781 | { | ||
782 | struct st_data_s *st_gdata = tty->disc_data; | ||
783 | pr_debug("%s ", __func__); | ||
784 | |||
785 | kfree_skb(st_gdata->tx_skb); | ||
786 | st_gdata->tx_skb = NULL; | ||
787 | |||
788 | tty->ops->flush_buffer(tty); | ||
789 | return; | ||
790 | } | ||
791 | |||
792 | static struct tty_ldisc_ops st_ldisc_ops = { | ||
793 | .magic = TTY_LDISC_MAGIC, | ||
794 | .name = "n_st", | ||
795 | .open = st_tty_open, | ||
796 | .close = st_tty_close, | ||
797 | .receive_buf = st_tty_receive, | ||
798 | .write_wakeup = st_tty_wakeup, | ||
799 | .flush_buffer = st_tty_flush_buffer, | ||
800 | .owner = THIS_MODULE | ||
801 | }; | ||
802 | |||
803 | /********************************************************************/ | ||
804 | int st_core_init(struct st_data_s **core_data) | ||
805 | { | ||
806 | struct st_data_s *st_gdata; | ||
807 | long err; | ||
808 | |||
809 | err = tty_register_ldisc(N_TI_WL, &st_ldisc_ops); | ||
810 | if (err) { | ||
811 | pr_err("error registering %d line discipline %ld", | ||
812 | N_TI_WL, err); | ||
813 | return err; | ||
814 | } | ||
815 | pr_debug("registered n_shared line discipline"); | ||
816 | |||
817 | st_gdata = kzalloc(sizeof(struct st_data_s), GFP_KERNEL); | ||
818 | if (!st_gdata) { | ||
819 | pr_err("memory allocation failed"); | ||
820 | err = tty_unregister_ldisc(N_TI_WL); | ||
821 | if (err) | ||
822 | pr_err("unable to un-register ldisc %ld", err); | ||
823 | err = -ENOMEM; | ||
824 | return err; | ||
825 | } | ||
826 | |||
827 | /* Initialize ST TxQ and Tx waitQ queue head. All BT/FM/GPS module skb's | ||
828 | * will be pushed in this queue for actual transmission. | ||
829 | */ | ||
830 | skb_queue_head_init(&st_gdata->txq); | ||
831 | skb_queue_head_init(&st_gdata->tx_waitq); | ||
832 | |||
833 | /* Locking used in st_int_enqueue() to avoid multiple execution */ | ||
834 | spin_lock_init(&st_gdata->lock); | ||
835 | |||
836 | err = st_ll_init(st_gdata); | ||
837 | if (err) { | ||
838 | pr_err("error during st_ll initialization(%ld)", err); | ||
839 | kfree(st_gdata); | ||
840 | err = tty_unregister_ldisc(N_TI_WL); | ||
841 | if (err) | ||
842 | pr_err("unable to un-register ldisc"); | ||
843 | return err; | ||
844 | } | ||
845 | *core_data = st_gdata; | ||
846 | return 0; | ||
847 | } | ||
848 | |||
849 | void st_core_exit(struct st_data_s *st_gdata) | ||
850 | { | ||
851 | long err; | ||
852 | /* internal module cleanup */ | ||
853 | err = st_ll_deinit(st_gdata); | ||
854 | if (err) | ||
855 | pr_err("error during deinit of ST LL %ld", err); | ||
856 | |||
857 | if (st_gdata != NULL) { | ||
858 | /* Free ST Tx Qs and skbs */ | ||
859 | skb_queue_purge(&st_gdata->txq); | ||
860 | skb_queue_purge(&st_gdata->tx_waitq); | ||
861 | kfree_skb(st_gdata->rx_skb); | ||
862 | kfree_skb(st_gdata->tx_skb); | ||
863 | /* TTY ldisc cleanup */ | ||
864 | err = tty_unregister_ldisc(N_TI_WL); | ||
865 | if (err) | ||
866 | pr_err("unable to un-register ldisc %ld", err); | ||
867 | /* free the global data pointer */ | ||
868 | kfree(st_gdata); | ||
869 | } | ||
870 | } | ||
871 | |||
872 | |||
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c new file mode 100644 index 000000000000..38fd2f04c07e --- /dev/null +++ b/drivers/misc/ti-st/st_kim.c | |||
@@ -0,0 +1,797 @@ | |||
1 | /* | ||
2 | * Shared Transport Line discipline driver Core | ||
3 | * Init Manager module responsible for GPIO control | ||
4 | * and firmware download | ||
5 | * Copyright (C) 2009-2010 Texas Instruments | ||
6 | * Author: Pavan Savoy <pavan_savoy@ti.com> | ||
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 version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #define pr_fmt(fmt) "(stk) :" fmt | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/jiffies.h> | ||
26 | #include <linux/firmware.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/wait.h> | ||
29 | #include <linux/gpio.h> | ||
30 | #include <linux/debugfs.h> | ||
31 | #include <linux/seq_file.h> | ||
32 | #include <linux/sched.h> | ||
33 | #include <linux/sysfs.h> | ||
34 | #include <linux/tty.h> | ||
35 | |||
36 | #include <linux/skbuff.h> | ||
37 | #include <linux/ti_wilink_st.h> | ||
38 | |||
39 | |||
40 | #define MAX_ST_DEVICES 3 /* Imagine 1 on each UART for now */ | ||
41 | static struct platform_device *st_kim_devices[MAX_ST_DEVICES]; | ||
42 | |||
43 | /**********************************************************************/ | ||
44 | /* internal functions */ | ||
45 | |||
46 | /** | ||
47 | * st_get_plat_device - | ||
48 | * function which returns the reference to the platform device | ||
49 | * requested by id. As of now only 1 such device exists (id=0) | ||
50 | * the context requesting for reference can get the id to be | ||
51 | * requested by a. The protocol driver which is registering or | ||
52 | * b. the tty device which is opened. | ||
53 | */ | ||
54 | static struct platform_device *st_get_plat_device(int id) | ||
55 | { | ||
56 | return st_kim_devices[id]; | ||
57 | } | ||
58 | |||
59 | /** | ||
60 | * validate_firmware_response - | ||
61 | * function to return whether the firmware response was proper | ||
62 | * in case of error don't complete so that waiting for proper | ||
63 | * response times out | ||
64 | */ | ||
65 | void validate_firmware_response(struct kim_data_s *kim_gdata) | ||
66 | { | ||
67 | struct sk_buff *skb = kim_gdata->rx_skb; | ||
68 | if (unlikely(skb->data[5] != 0)) { | ||
69 | pr_err("no proper response during fw download"); | ||
70 | pr_err("data6 %x", skb->data[5]); | ||
71 | return; /* keep waiting for the proper response */ | ||
72 | } | ||
73 | /* becos of all the script being downloaded */ | ||
74 | complete_all(&kim_gdata->kim_rcvd); | ||
75 | kfree_skb(skb); | ||
76 | } | ||
77 | |||
78 | /* check for data len received inside kim_int_recv | ||
79 | * most often hit the last case to update state to waiting for data | ||
80 | */ | ||
81 | static inline int kim_check_data_len(struct kim_data_s *kim_gdata, int len) | ||
82 | { | ||
83 | register int room = skb_tailroom(kim_gdata->rx_skb); | ||
84 | |||
85 | pr_debug("len %d room %d", len, room); | ||
86 | |||
87 | if (!len) { | ||
88 | validate_firmware_response(kim_gdata); | ||
89 | } else if (len > room) { | ||
90 | /* Received packet's payload length is larger. | ||
91 | * We can't accommodate it in created skb. | ||
92 | */ | ||
93 | pr_err("Data length is too large len %d room %d", len, | ||
94 | room); | ||
95 | kfree_skb(kim_gdata->rx_skb); | ||
96 | } else { | ||
97 | /* Packet header has non-zero payload length and | ||
98 | * we have enough space in created skb. Lets read | ||
99 | * payload data */ | ||
100 | kim_gdata->rx_state = ST_W4_DATA; | ||
101 | kim_gdata->rx_count = len; | ||
102 | return len; | ||
103 | } | ||
104 | |||
105 | /* Change ST LL state to continue to process next | ||
106 | * packet */ | ||
107 | kim_gdata->rx_state = ST_W4_PACKET_TYPE; | ||
108 | kim_gdata->rx_skb = NULL; | ||
109 | kim_gdata->rx_count = 0; | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * kim_int_recv - receive function called during firmware download | ||
116 | * firmware download responses on different UART drivers | ||
117 | * have been observed to come in bursts of different | ||
118 | * tty_receive and hence the logic | ||
119 | */ | ||
120 | void kim_int_recv(struct kim_data_s *kim_gdata, | ||
121 | const unsigned char *data, long count) | ||
122 | { | ||
123 | const unsigned char *ptr; | ||
124 | int len = 0, type = 0; | ||
125 | unsigned char *plen; | ||
126 | |||
127 | pr_debug("%s", __func__); | ||
128 | /* Decode received bytes here */ | ||
129 | ptr = data; | ||
130 | if (unlikely(ptr == NULL)) { | ||
131 | pr_err(" received null from TTY "); | ||
132 | return; | ||
133 | } | ||
134 | |||
135 | while (count) { | ||
136 | if (kim_gdata->rx_count) { | ||
137 | len = min_t(unsigned int, kim_gdata->rx_count, count); | ||
138 | memcpy(skb_put(kim_gdata->rx_skb, len), ptr, len); | ||
139 | kim_gdata->rx_count -= len; | ||
140 | count -= len; | ||
141 | ptr += len; | ||
142 | |||
143 | if (kim_gdata->rx_count) | ||
144 | continue; | ||
145 | |||
146 | /* Check ST RX state machine , where are we? */ | ||
147 | switch (kim_gdata->rx_state) { | ||
148 | /* Waiting for complete packet ? */ | ||
149 | case ST_W4_DATA: | ||
150 | pr_debug("Complete pkt received"); | ||
151 | validate_firmware_response(kim_gdata); | ||
152 | kim_gdata->rx_state = ST_W4_PACKET_TYPE; | ||
153 | kim_gdata->rx_skb = NULL; | ||
154 | continue; | ||
155 | /* Waiting for Bluetooth event header ? */ | ||
156 | case ST_W4_HEADER: | ||
157 | plen = | ||
158 | (unsigned char *)&kim_gdata->rx_skb->data[1]; | ||
159 | pr_debug("event hdr: plen 0x%02x\n", *plen); | ||
160 | kim_check_data_len(kim_gdata, *plen); | ||
161 | continue; | ||
162 | } /* end of switch */ | ||
163 | } /* end of if rx_state */ | ||
164 | switch (*ptr) { | ||
165 | /* Bluetooth event packet? */ | ||
166 | case 0x04: | ||
167 | kim_gdata->rx_state = ST_W4_HEADER; | ||
168 | kim_gdata->rx_count = 2; | ||
169 | type = *ptr; | ||
170 | break; | ||
171 | default: | ||
172 | pr_info("unknown packet"); | ||
173 | ptr++; | ||
174 | count--; | ||
175 | continue; | ||
176 | } | ||
177 | ptr++; | ||
178 | count--; | ||
179 | kim_gdata->rx_skb = | ||
180 | alloc_skb(1024+8, GFP_ATOMIC); | ||
181 | if (!kim_gdata->rx_skb) { | ||
182 | pr_err("can't allocate mem for new packet"); | ||
183 | kim_gdata->rx_state = ST_W4_PACKET_TYPE; | ||
184 | kim_gdata->rx_count = 0; | ||
185 | return; | ||
186 | } | ||
187 | skb_reserve(kim_gdata->rx_skb, 8); | ||
188 | kim_gdata->rx_skb->cb[0] = 4; | ||
189 | kim_gdata->rx_skb->cb[1] = 0; | ||
190 | |||
191 | } | ||
192 | return; | ||
193 | } | ||
194 | |||
195 | static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name) | ||
196 | { | ||
197 | unsigned short version = 0, chip = 0, min_ver = 0, maj_ver = 0; | ||
198 | const char read_ver_cmd[] = { 0x01, 0x01, 0x10, 0x00 }; | ||
199 | |||
200 | pr_debug("%s", __func__); | ||
201 | |||
202 | INIT_COMPLETION(kim_gdata->kim_rcvd); | ||
203 | if (4 != st_int_write(kim_gdata->core_data, read_ver_cmd, 4)) { | ||
204 | pr_err("kim: couldn't write 4 bytes"); | ||
205 | return -EIO; | ||
206 | } | ||
207 | |||
208 | if (!wait_for_completion_timeout | ||
209 | (&kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) { | ||
210 | pr_err(" waiting for ver info- timed out "); | ||
211 | return -ETIMEDOUT; | ||
212 | } | ||
213 | |||
214 | version = | ||
215 | MAKEWORD(kim_gdata->resp_buffer[13], | ||
216 | kim_gdata->resp_buffer[14]); | ||
217 | chip = (version & 0x7C00) >> 10; | ||
218 | min_ver = (version & 0x007F); | ||
219 | maj_ver = (version & 0x0380) >> 7; | ||
220 | |||
221 | if (version & 0x8000) | ||
222 | maj_ver |= 0x0008; | ||
223 | |||
224 | sprintf(bts_scr_name, "TIInit_%d.%d.%d.bts", chip, maj_ver, min_ver); | ||
225 | |||
226 | /* to be accessed later via sysfs entry */ | ||
227 | kim_gdata->version.full = version; | ||
228 | kim_gdata->version.chip = chip; | ||
229 | kim_gdata->version.maj_ver = maj_ver; | ||
230 | kim_gdata->version.min_ver = min_ver; | ||
231 | |||
232 | pr_info("%s", bts_scr_name); | ||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | void skip_change_remote_baud(unsigned char **ptr, long *len) | ||
237 | { | ||
238 | unsigned char *nxt_action, *cur_action; | ||
239 | cur_action = *ptr; | ||
240 | |||
241 | nxt_action = cur_action + sizeof(struct bts_action) + | ||
242 | ((struct bts_action *) cur_action)->size; | ||
243 | |||
244 | if (((struct bts_action *) nxt_action)->type != ACTION_WAIT_EVENT) { | ||
245 | pr_err("invalid action after change remote baud command"); | ||
246 | } else { | ||
247 | *ptr = *ptr + sizeof(struct bts_action) + | ||
248 | ((struct bts_action *)cur_action)->size; | ||
249 | *len = *len - (sizeof(struct bts_action) + | ||
250 | ((struct bts_action *)cur_action)->size); | ||
251 | /* warn user on not commenting these in firmware */ | ||
252 | pr_warn("skipping the wait event of change remote baud"); | ||
253 | } | ||
254 | } | ||
255 | |||
256 | /** | ||
257 | * download_firmware - | ||
258 | * internal function which parses through the .bts firmware | ||
259 | * script file intreprets SEND, DELAY actions only as of now | ||
260 | */ | ||
261 | static long download_firmware(struct kim_data_s *kim_gdata) | ||
262 | { | ||
263 | long err = 0; | ||
264 | long len = 0; | ||
265 | unsigned char *ptr = NULL; | ||
266 | unsigned char *action_ptr = NULL; | ||
267 | unsigned char bts_scr_name[30] = { 0 }; /* 30 char long bts scr name? */ | ||
268 | int wr_room_space; | ||
269 | int cmd_size; | ||
270 | unsigned long timeout; | ||
271 | |||
272 | err = read_local_version(kim_gdata, bts_scr_name); | ||
273 | if (err != 0) { | ||
274 | pr_err("kim: failed to read local ver"); | ||
275 | return err; | ||
276 | } | ||
277 | err = | ||
278 | request_firmware(&kim_gdata->fw_entry, bts_scr_name, | ||
279 | &kim_gdata->kim_pdev->dev); | ||
280 | if (unlikely((err != 0) || (kim_gdata->fw_entry->data == NULL) || | ||
281 | (kim_gdata->fw_entry->size == 0))) { | ||
282 | pr_err(" request_firmware failed(errno %ld) for %s", err, | ||
283 | bts_scr_name); | ||
284 | return -EINVAL; | ||
285 | } | ||
286 | ptr = (void *)kim_gdata->fw_entry->data; | ||
287 | len = kim_gdata->fw_entry->size; | ||
288 | /* bts_header to remove out magic number and | ||
289 | * version | ||
290 | */ | ||
291 | ptr += sizeof(struct bts_header); | ||
292 | len -= sizeof(struct bts_header); | ||
293 | |||
294 | while (len > 0 && ptr) { | ||
295 | pr_debug(" action size %d, type %d ", | ||
296 | ((struct bts_action *)ptr)->size, | ||
297 | ((struct bts_action *)ptr)->type); | ||
298 | |||
299 | switch (((struct bts_action *)ptr)->type) { | ||
300 | case ACTION_SEND_COMMAND: /* action send */ | ||
301 | action_ptr = &(((struct bts_action *)ptr)->data[0]); | ||
302 | if (unlikely | ||
303 | (((struct hci_command *)action_ptr)->opcode == | ||
304 | 0xFF36)) { | ||
305 | /* ignore remote change | ||
306 | * baud rate HCI VS command */ | ||
307 | pr_warn("change remote baud" | ||
308 | " rate command in firmware"); | ||
309 | skip_change_remote_baud(&ptr, &len); | ||
310 | break; | ||
311 | } | ||
312 | /* | ||
313 | * Make sure we have enough free space in uart | ||
314 | * tx buffer to write current firmware command | ||
315 | */ | ||
316 | cmd_size = ((struct bts_action *)ptr)->size; | ||
317 | timeout = jiffies + msecs_to_jiffies(CMD_WR_TIME); | ||
318 | do { | ||
319 | wr_room_space = | ||
320 | st_get_uart_wr_room(kim_gdata->core_data); | ||
321 | if (wr_room_space < 0) { | ||
322 | pr_err("Unable to get free " | ||
323 | "space info from uart tx buffer"); | ||
324 | release_firmware(kim_gdata->fw_entry); | ||
325 | return wr_room_space; | ||
326 | } | ||
327 | mdelay(1); /* wait 1ms before checking room */ | ||
328 | } while ((wr_room_space < cmd_size) && | ||
329 | time_before(jiffies, timeout)); | ||
330 | |||
331 | /* Timeout happened ? */ | ||
332 | if (time_after_eq(jiffies, timeout)) { | ||
333 | pr_err("Timeout while waiting for free " | ||
334 | "free space in uart tx buffer"); | ||
335 | release_firmware(kim_gdata->fw_entry); | ||
336 | return -ETIMEDOUT; | ||
337 | } | ||
338 | |||
339 | /* | ||
340 | * Free space found in uart buffer, call st_int_write | ||
341 | * to send current firmware command to the uart tx | ||
342 | * buffer. | ||
343 | */ | ||
344 | err = st_int_write(kim_gdata->core_data, | ||
345 | ((struct bts_action_send *)action_ptr)->data, | ||
346 | ((struct bts_action *)ptr)->size); | ||
347 | if (unlikely(err < 0)) { | ||
348 | release_firmware(kim_gdata->fw_entry); | ||
349 | return err; | ||
350 | } | ||
351 | /* | ||
352 | * Check number of bytes written to the uart tx buffer | ||
353 | * and requested command write size | ||
354 | */ | ||
355 | if (err != cmd_size) { | ||
356 | pr_err("Number of bytes written to uart " | ||
357 | "tx buffer are not matching with " | ||
358 | "requested cmd write size"); | ||
359 | release_firmware(kim_gdata->fw_entry); | ||
360 | return -EIO; | ||
361 | } | ||
362 | break; | ||
363 | case ACTION_WAIT_EVENT: /* wait */ | ||
364 | if (!wait_for_completion_timeout | ||
365 | (&kim_gdata->kim_rcvd, | ||
366 | msecs_to_jiffies(CMD_RESP_TIME))) { | ||
367 | pr_err("response timeout during fw download "); | ||
368 | /* timed out */ | ||
369 | release_firmware(kim_gdata->fw_entry); | ||
370 | return -ETIMEDOUT; | ||
371 | } | ||
372 | INIT_COMPLETION(kim_gdata->kim_rcvd); | ||
373 | break; | ||
374 | case ACTION_DELAY: /* sleep */ | ||
375 | pr_info("sleep command in scr"); | ||
376 | action_ptr = &(((struct bts_action *)ptr)->data[0]); | ||
377 | mdelay(((struct bts_action_delay *)action_ptr)->msec); | ||
378 | break; | ||
379 | } | ||
380 | len = | ||
381 | len - (sizeof(struct bts_action) + | ||
382 | ((struct bts_action *)ptr)->size); | ||
383 | ptr = | ||
384 | ptr + sizeof(struct bts_action) + | ||
385 | ((struct bts_action *)ptr)->size; | ||
386 | } | ||
387 | /* fw download complete */ | ||
388 | release_firmware(kim_gdata->fw_entry); | ||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | /**********************************************************************/ | ||
393 | /* functions called from ST core */ | ||
394 | /* called from ST Core, when REG_IN_PROGRESS (registration in progress) | ||
395 | * can be because of | ||
396 | * 1. response to read local version | ||
397 | * 2. during send/recv's of firmware download | ||
398 | */ | ||
399 | void st_kim_recv(void *disc_data, const unsigned char *data, long count) | ||
400 | { | ||
401 | struct st_data_s *st_gdata = (struct st_data_s *)disc_data; | ||
402 | struct kim_data_s *kim_gdata = st_gdata->kim_data; | ||
403 | |||
404 | /* copy to local buffer */ | ||
405 | if (unlikely(data[4] == 0x01 && data[5] == 0x10 && data[0] == 0x04)) { | ||
406 | /* must be the read_ver_cmd */ | ||
407 | memcpy(kim_gdata->resp_buffer, data, count); | ||
408 | complete_all(&kim_gdata->kim_rcvd); | ||
409 | return; | ||
410 | } else { | ||
411 | kim_int_recv(kim_gdata, data, count); | ||
412 | /* either completes or times out */ | ||
413 | } | ||
414 | return; | ||
415 | } | ||
416 | |||
417 | /* to signal completion of line discipline installation | ||
418 | * called from ST Core, upon tty_open | ||
419 | */ | ||
420 | void st_kim_complete(void *kim_data) | ||
421 | { | ||
422 | struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data; | ||
423 | complete(&kim_gdata->ldisc_installed); | ||
424 | } | ||
425 | |||
426 | /** | ||
427 | * st_kim_start - called from ST Core upon 1st registration | ||
428 | * This involves toggling the chip enable gpio, reading | ||
429 | * the firmware version from chip, forming the fw file name | ||
430 | * based on the chip version, requesting the fw, parsing it | ||
431 | * and perform download(send/recv). | ||
432 | */ | ||
433 | long st_kim_start(void *kim_data) | ||
434 | { | ||
435 | long err = 0; | ||
436 | long retry = POR_RETRY_COUNT; | ||
437 | struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data; | ||
438 | |||
439 | pr_info(" %s", __func__); | ||
440 | |||
441 | do { | ||
442 | /* Configure BT nShutdown to HIGH state */ | ||
443 | gpio_set_value(kim_gdata->nshutdown, GPIO_LOW); | ||
444 | mdelay(5); /* FIXME: a proper toggle */ | ||
445 | gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH); | ||
446 | mdelay(100); | ||
447 | /* re-initialize the completion */ | ||
448 | INIT_COMPLETION(kim_gdata->ldisc_installed); | ||
449 | /* send notification to UIM */ | ||
450 | kim_gdata->ldisc_install = 1; | ||
451 | pr_info("ldisc_install = 1"); | ||
452 | sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, | ||
453 | NULL, "install"); | ||
454 | /* wait for ldisc to be installed */ | ||
455 | err = wait_for_completion_timeout(&kim_gdata->ldisc_installed, | ||
456 | msecs_to_jiffies(LDISC_TIME)); | ||
457 | if (!err) { /* timeout */ | ||
458 | pr_err("line disc installation timed out "); | ||
459 | kim_gdata->ldisc_install = 0; | ||
460 | pr_info("ldisc_install = 0"); | ||
461 | sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, | ||
462 | NULL, "install"); | ||
463 | err = -ETIMEDOUT; | ||
464 | continue; | ||
465 | } else { | ||
466 | /* ldisc installed now */ | ||
467 | pr_info(" line discipline installed "); | ||
468 | err = download_firmware(kim_gdata); | ||
469 | if (err != 0) { | ||
470 | pr_err("download firmware failed"); | ||
471 | kim_gdata->ldisc_install = 0; | ||
472 | pr_info("ldisc_install = 0"); | ||
473 | sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, | ||
474 | NULL, "install"); | ||
475 | continue; | ||
476 | } else { /* on success don't retry */ | ||
477 | break; | ||
478 | } | ||
479 | } | ||
480 | } while (retry--); | ||
481 | return err; | ||
482 | } | ||
483 | |||
484 | /** | ||
485 | * st_kim_stop - called from ST Core, on the last un-registration | ||
486 | * toggle low the chip enable gpio | ||
487 | */ | ||
488 | long st_kim_stop(void *kim_data) | ||
489 | { | ||
490 | long err = 0; | ||
491 | struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data; | ||
492 | |||
493 | INIT_COMPLETION(kim_gdata->ldisc_installed); | ||
494 | |||
495 | /* Flush any pending characters in the driver and discipline. */ | ||
496 | tty_ldisc_flush(kim_gdata->core_data->tty); | ||
497 | tty_driver_flush_buffer(kim_gdata->core_data->tty); | ||
498 | |||
499 | /* send uninstall notification to UIM */ | ||
500 | pr_info("ldisc_install = 0"); | ||
501 | kim_gdata->ldisc_install = 0; | ||
502 | sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, NULL, "install"); | ||
503 | |||
504 | /* wait for ldisc to be un-installed */ | ||
505 | err = wait_for_completion_timeout(&kim_gdata->ldisc_installed, | ||
506 | msecs_to_jiffies(LDISC_TIME)); | ||
507 | if (!err) { /* timeout */ | ||
508 | pr_err(" timed out waiting for ldisc to be un-installed"); | ||
509 | return -ETIMEDOUT; | ||
510 | } | ||
511 | |||
512 | /* By default configure BT nShutdown to LOW state */ | ||
513 | gpio_set_value(kim_gdata->nshutdown, GPIO_LOW); | ||
514 | mdelay(1); | ||
515 | gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH); | ||
516 | mdelay(1); | ||
517 | gpio_set_value(kim_gdata->nshutdown, GPIO_LOW); | ||
518 | return err; | ||
519 | } | ||
520 | |||
521 | /**********************************************************************/ | ||
522 | /* functions called from subsystems */ | ||
523 | /* called when debugfs entry is read from */ | ||
524 | |||
525 | static int show_version(struct seq_file *s, void *unused) | ||
526 | { | ||
527 | struct kim_data_s *kim_gdata = (struct kim_data_s *)s->private; | ||
528 | seq_printf(s, "%04X %d.%d.%d\n", kim_gdata->version.full, | ||
529 | kim_gdata->version.chip, kim_gdata->version.maj_ver, | ||
530 | kim_gdata->version.min_ver); | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | static int show_list(struct seq_file *s, void *unused) | ||
535 | { | ||
536 | struct kim_data_s *kim_gdata = (struct kim_data_s *)s->private; | ||
537 | kim_st_list_protocols(kim_gdata->core_data, s); | ||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | static ssize_t show_install(struct device *dev, | ||
542 | struct device_attribute *attr, char *buf) | ||
543 | { | ||
544 | struct kim_data_s *kim_data = dev_get_drvdata(dev); | ||
545 | return sprintf(buf, "%d\n", kim_data->ldisc_install); | ||
546 | } | ||
547 | |||
548 | static ssize_t show_dev_name(struct device *dev, | ||
549 | struct device_attribute *attr, char *buf) | ||
550 | { | ||
551 | struct kim_data_s *kim_data = dev_get_drvdata(dev); | ||
552 | return sprintf(buf, "%s\n", kim_data->dev_name); | ||
553 | } | ||
554 | |||
555 | static ssize_t show_baud_rate(struct device *dev, | ||
556 | struct device_attribute *attr, char *buf) | ||
557 | { | ||
558 | struct kim_data_s *kim_data = dev_get_drvdata(dev); | ||
559 | return sprintf(buf, "%ld\n", kim_data->baud_rate); | ||
560 | } | ||
561 | |||
562 | static ssize_t show_flow_cntrl(struct device *dev, | ||
563 | struct device_attribute *attr, char *buf) | ||
564 | { | ||
565 | struct kim_data_s *kim_data = dev_get_drvdata(dev); | ||
566 | return sprintf(buf, "%d\n", kim_data->flow_cntrl); | ||
567 | } | ||
568 | |||
569 | /* structures specific for sysfs entries */ | ||
570 | static struct kobj_attribute ldisc_install = | ||
571 | __ATTR(install, 0444, (void *)show_install, NULL); | ||
572 | |||
573 | static struct kobj_attribute uart_dev_name = | ||
574 | __ATTR(dev_name, 0444, (void *)show_dev_name, NULL); | ||
575 | |||
576 | static struct kobj_attribute uart_baud_rate = | ||
577 | __ATTR(baud_rate, 0444, (void *)show_baud_rate, NULL); | ||
578 | |||
579 | static struct kobj_attribute uart_flow_cntrl = | ||
580 | __ATTR(flow_cntrl, 0444, (void *)show_flow_cntrl, NULL); | ||
581 | |||
582 | static struct attribute *uim_attrs[] = { | ||
583 | &ldisc_install.attr, | ||
584 | &uart_dev_name.attr, | ||
585 | &uart_baud_rate.attr, | ||
586 | &uart_flow_cntrl.attr, | ||
587 | NULL, | ||
588 | }; | ||
589 | |||
590 | static struct attribute_group uim_attr_grp = { | ||
591 | .attrs = uim_attrs, | ||
592 | }; | ||
593 | |||
594 | /** | ||
595 | * st_kim_ref - reference the core's data | ||
596 | * This references the per-ST platform device in the arch/xx/ | ||
597 | * board-xx.c file. | ||
598 | * This would enable multiple such platform devices to exist | ||
599 | * on a given platform | ||
600 | */ | ||
601 | void st_kim_ref(struct st_data_s **core_data, int id) | ||
602 | { | ||
603 | struct platform_device *pdev; | ||
604 | struct kim_data_s *kim_gdata; | ||
605 | /* get kim_gdata reference from platform device */ | ||
606 | pdev = st_get_plat_device(id); | ||
607 | if (!pdev) { | ||
608 | *core_data = NULL; | ||
609 | return; | ||
610 | } | ||
611 | kim_gdata = dev_get_drvdata(&pdev->dev); | ||
612 | *core_data = kim_gdata->core_data; | ||
613 | } | ||
614 | |||
615 | static int kim_version_open(struct inode *i, struct file *f) | ||
616 | { | ||
617 | return single_open(f, show_version, i->i_private); | ||
618 | } | ||
619 | |||
620 | static int kim_list_open(struct inode *i, struct file *f) | ||
621 | { | ||
622 | return single_open(f, show_list, i->i_private); | ||
623 | } | ||
624 | |||
625 | static const struct file_operations version_debugfs_fops = { | ||
626 | /* version info */ | ||
627 | .open = kim_version_open, | ||
628 | .read = seq_read, | ||
629 | .llseek = seq_lseek, | ||
630 | .release = single_release, | ||
631 | }; | ||
632 | static const struct file_operations list_debugfs_fops = { | ||
633 | /* protocols info */ | ||
634 | .open = kim_list_open, | ||
635 | .read = seq_read, | ||
636 | .llseek = seq_lseek, | ||
637 | .release = single_release, | ||
638 | }; | ||
639 | |||
640 | /**********************************************************************/ | ||
641 | /* functions called from platform device driver subsystem | ||
642 | * need to have a relevant platform device entry in the platform's | ||
643 | * board-*.c file | ||
644 | */ | ||
645 | |||
646 | struct dentry *kim_debugfs_dir; | ||
647 | static int kim_probe(struct platform_device *pdev) | ||
648 | { | ||
649 | long status; | ||
650 | struct kim_data_s *kim_gdata; | ||
651 | struct ti_st_plat_data *pdata = pdev->dev.platform_data; | ||
652 | |||
653 | if ((pdev->id != -1) && (pdev->id < MAX_ST_DEVICES)) { | ||
654 | /* multiple devices could exist */ | ||
655 | st_kim_devices[pdev->id] = pdev; | ||
656 | } else { | ||
657 | /* platform's sure about existence of 1 device */ | ||
658 | st_kim_devices[0] = pdev; | ||
659 | } | ||
660 | |||
661 | kim_gdata = kzalloc(sizeof(struct kim_data_s), GFP_ATOMIC); | ||
662 | if (!kim_gdata) { | ||
663 | pr_err("no mem to allocate"); | ||
664 | return -ENOMEM; | ||
665 | } | ||
666 | dev_set_drvdata(&pdev->dev, kim_gdata); | ||
667 | |||
668 | status = st_core_init(&kim_gdata->core_data); | ||
669 | if (status != 0) { | ||
670 | pr_err(" ST core init failed"); | ||
671 | return -EIO; | ||
672 | } | ||
673 | /* refer to itself */ | ||
674 | kim_gdata->core_data->kim_data = kim_gdata; | ||
675 | |||
676 | /* Claim the chip enable nShutdown gpio from the system */ | ||
677 | kim_gdata->nshutdown = pdata->nshutdown_gpio; | ||
678 | status = gpio_request(kim_gdata->nshutdown, "kim"); | ||
679 | if (unlikely(status)) { | ||
680 | pr_err(" gpio %ld request failed ", kim_gdata->nshutdown); | ||
681 | return status; | ||
682 | } | ||
683 | |||
684 | /* Configure nShutdown GPIO as output=0 */ | ||
685 | status = gpio_direction_output(kim_gdata->nshutdown, 0); | ||
686 | if (unlikely(status)) { | ||
687 | pr_err(" unable to configure gpio %ld", kim_gdata->nshutdown); | ||
688 | return status; | ||
689 | } | ||
690 | /* get reference of pdev for request_firmware | ||
691 | */ | ||
692 | kim_gdata->kim_pdev = pdev; | ||
693 | init_completion(&kim_gdata->kim_rcvd); | ||
694 | init_completion(&kim_gdata->ldisc_installed); | ||
695 | |||
696 | status = sysfs_create_group(&pdev->dev.kobj, &uim_attr_grp); | ||
697 | if (status) { | ||
698 | pr_err("failed to create sysfs entries"); | ||
699 | return status; | ||
700 | } | ||
701 | |||
702 | /* copying platform data */ | ||
703 | strncpy(kim_gdata->dev_name, pdata->dev_name, UART_DEV_NAME_LEN); | ||
704 | kim_gdata->flow_cntrl = pdata->flow_cntrl; | ||
705 | kim_gdata->baud_rate = pdata->baud_rate; | ||
706 | pr_info("sysfs entries created\n"); | ||
707 | |||
708 | kim_debugfs_dir = debugfs_create_dir("ti-st", NULL); | ||
709 | if (IS_ERR(kim_debugfs_dir)) { | ||
710 | pr_err(" debugfs entries creation failed "); | ||
711 | kim_debugfs_dir = NULL; | ||
712 | return -EIO; | ||
713 | } | ||
714 | |||
715 | debugfs_create_file("version", S_IRUGO, kim_debugfs_dir, | ||
716 | kim_gdata, &version_debugfs_fops); | ||
717 | debugfs_create_file("protocols", S_IRUGO, kim_debugfs_dir, | ||
718 | kim_gdata, &list_debugfs_fops); | ||
719 | pr_info(" debugfs entries created "); | ||
720 | return 0; | ||
721 | } | ||
722 | |||
723 | static int kim_remove(struct platform_device *pdev) | ||
724 | { | ||
725 | /* free the GPIOs requested */ | ||
726 | struct ti_st_plat_data *pdata = pdev->dev.platform_data; | ||
727 | struct kim_data_s *kim_gdata; | ||
728 | |||
729 | kim_gdata = dev_get_drvdata(&pdev->dev); | ||
730 | |||
731 | /* Free the Bluetooth/FM/GPIO | ||
732 | * nShutdown gpio from the system | ||
733 | */ | ||
734 | gpio_free(pdata->nshutdown_gpio); | ||
735 | pr_info("nshutdown GPIO Freed"); | ||
736 | |||
737 | debugfs_remove_recursive(kim_debugfs_dir); | ||
738 | sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp); | ||
739 | pr_info("sysfs entries removed"); | ||
740 | |||
741 | kim_gdata->kim_pdev = NULL; | ||
742 | st_core_exit(kim_gdata->core_data); | ||
743 | |||
744 | kfree(kim_gdata); | ||
745 | kim_gdata = NULL; | ||
746 | return 0; | ||
747 | } | ||
748 | |||
749 | int kim_suspend(struct platform_device *pdev, pm_message_t state) | ||
750 | { | ||
751 | struct ti_st_plat_data *pdata = pdev->dev.platform_data; | ||
752 | |||
753 | if (pdata->suspend) | ||
754 | return pdata->suspend(pdev, state); | ||
755 | |||
756 | return -EOPNOTSUPP; | ||
757 | } | ||
758 | |||
759 | int kim_resume(struct platform_device *pdev) | ||
760 | { | ||
761 | struct ti_st_plat_data *pdata = pdev->dev.platform_data; | ||
762 | |||
763 | if (pdata->resume) | ||
764 | return pdata->resume(pdev); | ||
765 | |||
766 | return -EOPNOTSUPP; | ||
767 | } | ||
768 | |||
769 | /**********************************************************************/ | ||
770 | /* entry point for ST KIM module, called in from ST Core */ | ||
771 | static struct platform_driver kim_platform_driver = { | ||
772 | .probe = kim_probe, | ||
773 | .remove = kim_remove, | ||
774 | .suspend = kim_suspend, | ||
775 | .resume = kim_resume, | ||
776 | .driver = { | ||
777 | .name = "kim", | ||
778 | .owner = THIS_MODULE, | ||
779 | }, | ||
780 | }; | ||
781 | |||
782 | static int __init st_kim_init(void) | ||
783 | { | ||
784 | return platform_driver_register(&kim_platform_driver); | ||
785 | } | ||
786 | |||
787 | static void __exit st_kim_deinit(void) | ||
788 | { | ||
789 | platform_driver_unregister(&kim_platform_driver); | ||
790 | } | ||
791 | |||
792 | |||
793 | module_init(st_kim_init); | ||
794 | module_exit(st_kim_deinit); | ||
795 | MODULE_AUTHOR("Pavan Savoy <pavan_savoy@ti.com>"); | ||
796 | MODULE_DESCRIPTION("Shared Transport Driver for TI BT/FM/GPS combo chips "); | ||
797 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/misc/ti-st/st_ll.c b/drivers/misc/ti-st/st_ll.c new file mode 100644 index 000000000000..3f2495138855 --- /dev/null +++ b/drivers/misc/ti-st/st_ll.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * Shared Transport driver | ||
3 | * HCI-LL module responsible for TI proprietary HCI_LL protocol | ||
4 | * Copyright (C) 2009-2010 Texas Instruments | ||
5 | * Author: Pavan Savoy <pavan_savoy@ti.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #define pr_fmt(fmt) "(stll) :" fmt | ||
23 | #include <linux/skbuff.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/ti_wilink_st.h> | ||
26 | |||
27 | /**********************************************************************/ | ||
28 | /* internal functions */ | ||
29 | static void send_ll_cmd(struct st_data_s *st_data, | ||
30 | unsigned char cmd) | ||
31 | { | ||
32 | |||
33 | pr_debug("%s: writing %x", __func__, cmd); | ||
34 | st_int_write(st_data, &cmd, 1); | ||
35 | return; | ||
36 | } | ||
37 | |||
38 | static void ll_device_want_to_sleep(struct st_data_s *st_data) | ||
39 | { | ||
40 | pr_debug("%s", __func__); | ||
41 | /* sanity check */ | ||
42 | if (st_data->ll_state != ST_LL_AWAKE) | ||
43 | pr_err("ERR hcill: ST_LL_GO_TO_SLEEP_IND" | ||
44 | "in state %ld", st_data->ll_state); | ||
45 | |||
46 | send_ll_cmd(st_data, LL_SLEEP_ACK); | ||
47 | /* update state */ | ||
48 | st_data->ll_state = ST_LL_ASLEEP; | ||
49 | } | ||
50 | |||
51 | static void ll_device_want_to_wakeup(struct st_data_s *st_data) | ||
52 | { | ||
53 | /* diff actions in diff states */ | ||
54 | switch (st_data->ll_state) { | ||
55 | case ST_LL_ASLEEP: | ||
56 | send_ll_cmd(st_data, LL_WAKE_UP_ACK); /* send wake_ack */ | ||
57 | break; | ||
58 | case ST_LL_ASLEEP_TO_AWAKE: | ||
59 | /* duplicate wake_ind */ | ||
60 | pr_err("duplicate wake_ind while waiting for Wake ack"); | ||
61 | break; | ||
62 | case ST_LL_AWAKE: | ||
63 | /* duplicate wake_ind */ | ||
64 | pr_err("duplicate wake_ind already AWAKE"); | ||
65 | break; | ||
66 | case ST_LL_AWAKE_TO_ASLEEP: | ||
67 | /* duplicate wake_ind */ | ||
68 | pr_err("duplicate wake_ind"); | ||
69 | break; | ||
70 | } | ||
71 | /* update state */ | ||
72 | st_data->ll_state = ST_LL_AWAKE; | ||
73 | } | ||
74 | |||
75 | /**********************************************************************/ | ||
76 | /* functions invoked by ST Core */ | ||
77 | |||
78 | /* called when ST Core wants to | ||
79 | * enable ST LL */ | ||
80 | void st_ll_enable(struct st_data_s *ll) | ||
81 | { | ||
82 | ll->ll_state = ST_LL_AWAKE; | ||
83 | } | ||
84 | |||
85 | /* called when ST Core /local module wants to | ||
86 | * disable ST LL */ | ||
87 | void st_ll_disable(struct st_data_s *ll) | ||
88 | { | ||
89 | ll->ll_state = ST_LL_INVALID; | ||
90 | } | ||
91 | |||
92 | /* called when ST Core wants to update the state */ | ||
93 | void st_ll_wakeup(struct st_data_s *ll) | ||
94 | { | ||
95 | if (likely(ll->ll_state != ST_LL_AWAKE)) { | ||
96 | send_ll_cmd(ll, LL_WAKE_UP_IND); /* WAKE_IND */ | ||
97 | ll->ll_state = ST_LL_ASLEEP_TO_AWAKE; | ||
98 | } else { | ||
99 | /* don't send the duplicate wake_indication */ | ||
100 | pr_err(" Chip already AWAKE "); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | /* called when ST Core wants the state */ | ||
105 | unsigned long st_ll_getstate(struct st_data_s *ll) | ||
106 | { | ||
107 | pr_debug(" returning state %ld", ll->ll_state); | ||
108 | return ll->ll_state; | ||
109 | } | ||
110 | |||
111 | /* called from ST Core, when a PM related packet arrives */ | ||
112 | unsigned long st_ll_sleep_state(struct st_data_s *st_data, | ||
113 | unsigned char cmd) | ||
114 | { | ||
115 | switch (cmd) { | ||
116 | case LL_SLEEP_IND: /* sleep ind */ | ||
117 | pr_debug("sleep indication recvd"); | ||
118 | ll_device_want_to_sleep(st_data); | ||
119 | break; | ||
120 | case LL_SLEEP_ACK: /* sleep ack */ | ||
121 | pr_err("sleep ack rcvd: host shouldn't"); | ||
122 | break; | ||
123 | case LL_WAKE_UP_IND: /* wake ind */ | ||
124 | pr_debug("wake indication recvd"); | ||
125 | ll_device_want_to_wakeup(st_data); | ||
126 | break; | ||
127 | case LL_WAKE_UP_ACK: /* wake ack */ | ||
128 | pr_debug("wake ack rcvd"); | ||
129 | st_data->ll_state = ST_LL_AWAKE; | ||
130 | break; | ||
131 | default: | ||
132 | pr_err(" unknown input/state "); | ||
133 | return -EINVAL; | ||
134 | } | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | /* Called from ST CORE to initialize ST LL */ | ||
139 | long st_ll_init(struct st_data_s *ll) | ||
140 | { | ||
141 | /* set state to invalid */ | ||
142 | ll->ll_state = ST_LL_INVALID; | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | /* Called from ST CORE to de-initialize ST LL */ | ||
147 | long st_ll_deinit(struct st_data_s *ll) | ||
148 | { | ||
149 | return 0; | ||
150 | } | ||
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c index 5f6852dff40b..44d4475a09dd 100644 --- a/drivers/misc/tifm_core.c +++ b/drivers/misc/tifm_core.c | |||
@@ -329,7 +329,7 @@ static int __init tifm_init(void) | |||
329 | { | 329 | { |
330 | int rc; | 330 | int rc; |
331 | 331 | ||
332 | workqueue = create_freezeable_workqueue("tifm"); | 332 | workqueue = create_freezable_workqueue("tifm"); |
333 | if (!workqueue) | 333 | if (!workqueue) |
334 | return -ENOMEM; | 334 | return -ENOMEM; |
335 | 335 | ||
diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 2a1e804a71aa..6df5a55da110 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c | |||
@@ -45,7 +45,7 @@ | |||
45 | 45 | ||
46 | MODULE_AUTHOR("VMware, Inc."); | 46 | MODULE_AUTHOR("VMware, Inc."); |
47 | MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver"); | 47 | MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver"); |
48 | MODULE_VERSION("1.2.1.1-k"); | 48 | MODULE_VERSION("1.2.1.2-k"); |
49 | MODULE_ALIAS("dmi:*:svnVMware*:*"); | 49 | MODULE_ALIAS("dmi:*:svnVMware*:*"); |
50 | MODULE_ALIAS("vmware_vmmemctl"); | 50 | MODULE_ALIAS("vmware_vmmemctl"); |
51 | MODULE_LICENSE("GPL"); | 51 | MODULE_LICENSE("GPL"); |
@@ -315,7 +315,8 @@ static bool vmballoon_send_get_target(struct vmballoon *b, u32 *new_target) | |||
315 | * fear that guest will need it. Host may reject some pages, we need to | 315 | * fear that guest will need it. Host may reject some pages, we need to |
316 | * check the return value and maybe submit a different page. | 316 | * check the return value and maybe submit a different page. |
317 | */ | 317 | */ |
318 | static bool vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn) | 318 | static bool vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn, |
319 | unsigned int *hv_status) | ||
319 | { | 320 | { |
320 | unsigned long status, dummy; | 321 | unsigned long status, dummy; |
321 | u32 pfn32; | 322 | u32 pfn32; |
@@ -326,7 +327,7 @@ static bool vmballoon_send_lock_page(struct vmballoon *b, unsigned long pfn) | |||
326 | 327 | ||
327 | STATS_INC(b->stats.lock); | 328 | STATS_INC(b->stats.lock); |
328 | 329 | ||
329 | status = VMWARE_BALLOON_CMD(LOCK, pfn, dummy); | 330 | *hv_status = status = VMWARE_BALLOON_CMD(LOCK, pfn, dummy); |
330 | if (vmballoon_check_status(b, status)) | 331 | if (vmballoon_check_status(b, status)) |
331 | return true; | 332 | return true; |
332 | 333 | ||
@@ -410,6 +411,7 @@ static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep) | |||
410 | { | 411 | { |
411 | struct page *page; | 412 | struct page *page; |
412 | gfp_t flags; | 413 | gfp_t flags; |
414 | unsigned int hv_status; | ||
413 | bool locked = false; | 415 | bool locked = false; |
414 | 416 | ||
415 | do { | 417 | do { |
@@ -429,11 +431,12 @@ static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep) | |||
429 | } | 431 | } |
430 | 432 | ||
431 | /* inform monitor */ | 433 | /* inform monitor */ |
432 | locked = vmballoon_send_lock_page(b, page_to_pfn(page)); | 434 | locked = vmballoon_send_lock_page(b, page_to_pfn(page), &hv_status); |
433 | if (!locked) { | 435 | if (!locked) { |
434 | STATS_INC(b->stats.refused_alloc); | 436 | STATS_INC(b->stats.refused_alloc); |
435 | 437 | ||
436 | if (b->reset_required) { | 438 | if (hv_status == VMW_BALLOON_ERROR_RESET || |
439 | hv_status == VMW_BALLOON_ERROR_PPN_NOTNEEDED) { | ||
437 | __free_page(page); | 440 | __free_page(page); |
438 | return -EIO; | 441 | return -EIO; |
439 | } | 442 | } |
@@ -782,7 +785,7 @@ static int __init vmballoon_init(void) | |||
782 | if (x86_hyper != &x86_hyper_vmware) | 785 | if (x86_hyper != &x86_hyper_vmware) |
783 | return -ENODEV; | 786 | return -ENODEV; |
784 | 787 | ||
785 | vmballoon_wq = create_freezeable_workqueue("vmmemctl"); | 788 | vmballoon_wq = create_freezable_workqueue("vmmemctl"); |
786 | if (!vmballoon_wq) { | 789 | if (!vmballoon_wq) { |
787 | pr_err("failed to create workqueue\n"); | 790 | pr_err("failed to create workqueue\n"); |
788 | return -ENOMEM; | 791 | return -ENOMEM; |