aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/Kconfig59
-rw-r--r--drivers/misc/Makefile5
-rw-r--r--drivers/misc/ad525x_dpot.c666
-rw-r--r--drivers/misc/cs5535-mfgpt.c370
-rw-r--r--drivers/misc/ds1682.c267
-rw-r--r--drivers/misc/eeprom/eeprom.c8
-rw-r--r--drivers/misc/hpilo.h13
-rw-r--r--drivers/misc/ics932s401.c48
-rw-r--r--drivers/misc/ioc4.c16
-rw-r--r--drivers/misc/iwmc3200top/Kconfig20
-rw-r--r--drivers/misc/iwmc3200top/Makefile29
-rw-r--r--drivers/misc/iwmc3200top/debugfs.c133
-rw-r--r--drivers/misc/iwmc3200top/debugfs.h58
-rw-r--r--drivers/misc/iwmc3200top/fw-download.c355
-rw-r--r--drivers/misc/iwmc3200top/fw-msg.h113
-rw-r--r--drivers/misc/iwmc3200top/iwmc3200top.h209
-rw-r--r--drivers/misc/iwmc3200top/log.c347
-rw-r--r--drivers/misc/iwmc3200top/log.h158
-rw-r--r--drivers/misc/iwmc3200top/main.c678
-rw-r--r--drivers/misc/kgdbts.c14
-rw-r--r--drivers/misc/sgi-gru/grufile.c2
-rw-r--r--drivers/misc/sgi-xp/xpc_main.c14
-rw-r--r--drivers/misc/sgi-xp/xpc_uv.c5
-rw-r--r--drivers/misc/ti_dac7512.c101
24 files changed, 3626 insertions, 62 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index ba137c8b263e..1a7a9fc50ea1 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -13,6 +13,20 @@ menuconfig MISC_DEVICES
13 13
14if MISC_DEVICES 14if MISC_DEVICES
15 15
16config AD525X_DPOT
17 tristate "Analog Devices AD525x Digital Potentiometers"
18 depends on I2C && SYSFS
19 help
20 If you say yes here, you get support for the Analog Devices
21 AD5258, AD5259, AD5251, AD5252, AD5253, AD5254 and AD5255
22 digital potentiometer chips.
23
24 See Documentation/misc-devices/ad525x_dpot.txt for the
25 userspace interface.
26
27 This driver can also be built as a module. If so, the module
28 will be called ad525x_dpot.
29
16config ATMEL_PWM 30config ATMEL_PWM
17 tristate "Atmel AT32/AT91 PWM support" 31 tristate "Atmel AT32/AT91 PWM support"
18 depends on AVR32 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 32 depends on AVR32 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9
@@ -173,6 +187,30 @@ config SGI_XP
173 this feature will allow for direct communication between SSIs 187 this feature will allow for direct communication between SSIs
174 based on a network adapter and DMA messaging. 188 based on a network adapter and DMA messaging.
175 189
190config CS5535_MFGPT
191 tristate "CS5535/CS5536 Geode Multi-Function General Purpose Timer (MFGPT) support"
192 depends on PCI
193 depends on X86
194 default n
195 help
196 This driver provides access to MFGPT functionality for other
197 drivers that need timers. MFGPTs are available in the CS5535 and
198 CS5536 companion chips that are found in AMD Geode and several
199 other platforms. They have a better resolution and max interval
200 than the generic PIT, and are suitable for use as high-res timers.
201 You probably don't want to enable this manually; other drivers that
202 make use of it should enable it.
203
204config CS5535_MFGPT_DEFAULT_IRQ
205 int
206 default 7
207 help
208 MFGPTs on the CS5535 require an interrupt. The selected IRQ
209 can be overridden as a module option as well as by driver that
210 use the cs5535_mfgpt_ API; however, different architectures might
211 want to use a different IRQ by default. This is here for
212 architectures to set as necessary.
213
176config HP_ILO 214config HP_ILO
177 tristate "Channel interface driver for HP iLO/iLO2 processor" 215 tristate "Channel interface driver for HP iLO/iLO2 processor"
178 depends on PCI 216 depends on PCI
@@ -233,8 +271,29 @@ config EP93XX_PWM
233 To compile this driver as a module, choose M here: the module will 271 To compile this driver as a module, choose M here: the module will
234 be called ep93xx_pwm. 272 be called ep93xx_pwm.
235 273
274config DS1682
275 tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm"
276 depends on I2C && EXPERIMENTAL
277 help
278 If you say yes here you get support for Dallas Semiconductor
279 DS1682 Total Elapsed Time Recorder.
280
281 This driver can also be built as a module. If so, the module
282 will be called ds1682.
283
284config TI_DAC7512
285 tristate "Texas Instruments DAC7512"
286 depends on SPI && SYSFS
287 help
288 If you say yes here you get support for the Texas Instruments
289 DAC7512 16-bit digital-to-analog converter.
290
291 This driver can also be built as a module. If so, the module
292 will be calles ti_dac7512.
293
236source "drivers/misc/c2port/Kconfig" 294source "drivers/misc/c2port/Kconfig"
237source "drivers/misc/eeprom/Kconfig" 295source "drivers/misc/eeprom/Kconfig"
238source "drivers/misc/cb710/Kconfig" 296source "drivers/misc/cb710/Kconfig"
297source "drivers/misc/iwmc3200top/Kconfig"
239 298
240endif # MISC_DEVICES 299endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index f982d2ecfde7..049ff2482f30 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -4,6 +4,7 @@
4 4
5obj-$(CONFIG_IBM_ASM) += ibmasm/ 5obj-$(CONFIG_IBM_ASM) += ibmasm/
6obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ 6obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
7obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o
7obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o 8obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
8obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o 9obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
9obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o 10obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
@@ -17,9 +18,13 @@ obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
17obj-$(CONFIG_KGDB_TESTS) += kgdbts.o 18obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
18obj-$(CONFIG_SGI_XP) += sgi-xp/ 19obj-$(CONFIG_SGI_XP) += sgi-xp/
19obj-$(CONFIG_SGI_GRU) += sgi-gru/ 20obj-$(CONFIG_SGI_GRU) += sgi-gru/
21obj-$(CONFIG_CS5535_MFGPT) += cs5535-mfgpt.o
20obj-$(CONFIG_HP_ILO) += hpilo.o 22obj-$(CONFIG_HP_ILO) += hpilo.o
21obj-$(CONFIG_ISL29003) += isl29003.o 23obj-$(CONFIG_ISL29003) += isl29003.o
22obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o 24obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o
25obj-$(CONFIG_DS1682) += ds1682.o
26obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o
23obj-$(CONFIG_C2PORT) += c2port/ 27obj-$(CONFIG_C2PORT) += c2port/
28obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/
24obj-y += eeprom/ 29obj-y += eeprom/
25obj-y += cb710/ 30obj-y += cb710/
diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c
new file mode 100644
index 000000000000..30a59f2bacd2
--- /dev/null
+++ b/drivers/misc/ad525x_dpot.c
@@ -0,0 +1,666 @@
1/*
2 * ad525x_dpot: Driver for the Analog Devices AD525x digital potentiometers
3 * Copyright (c) 2009 Analog Devices, Inc.
4 * Author: Michael Hennerich <hennerich@blackfin.uclinux.org>
5 *
6 * DEVID #Wipers #Positions Resistor Options (kOhm)
7 * AD5258 1 64 1, 10, 50, 100
8 * AD5259 1 256 5, 10, 50, 100
9 * AD5251 2 64 1, 10, 50, 100
10 * AD5252 2 256 1, 10, 50, 100
11 * AD5255 3 512 25, 250
12 * AD5253 4 64 1, 10, 50, 100
13 * AD5254 4 256 1, 10, 50, 100
14 *
15 * See Documentation/misc-devices/ad525x_dpot.txt for more info.
16 *
17 * derived from ad5258.c
18 * Copyright (c) 2009 Cyber Switching, Inc.
19 * Author: Chris Verges <chrisv@cyberswitching.com>
20 *
21 * derived from ad5252.c
22 * Copyright (c) 2006 Michael Hennerich <hennerich@blackfin.uclinux.org>
23 *
24 * Licensed under the GPL-2 or later.
25 */
26
27#include <linux/module.h>
28#include <linux/device.h>
29#include <linux/kernel.h>
30#include <linux/init.h>
31#include <linux/slab.h>
32#include <linux/i2c.h>
33#include <linux/delay.h>
34
35#define DRIVER_NAME "ad525x_dpot"
36#define DRIVER_VERSION "0.1"
37
38enum dpot_devid {
39 AD5258_ID,
40 AD5259_ID,
41 AD5251_ID,
42 AD5252_ID,
43 AD5253_ID,
44 AD5254_ID,
45 AD5255_ID,
46};
47
48#define AD5258_MAX_POSITION 64
49#define AD5259_MAX_POSITION 256
50#define AD5251_MAX_POSITION 64
51#define AD5252_MAX_POSITION 256
52#define AD5253_MAX_POSITION 64
53#define AD5254_MAX_POSITION 256
54#define AD5255_MAX_POSITION 512
55
56#define AD525X_RDAC0 0
57#define AD525X_RDAC1 1
58#define AD525X_RDAC2 2
59#define AD525X_RDAC3 3
60
61#define AD525X_REG_TOL 0x18
62#define AD525X_TOL_RDAC0 (AD525X_REG_TOL | AD525X_RDAC0)
63#define AD525X_TOL_RDAC1 (AD525X_REG_TOL | AD525X_RDAC1)
64#define AD525X_TOL_RDAC2 (AD525X_REG_TOL | AD525X_RDAC2)
65#define AD525X_TOL_RDAC3 (AD525X_REG_TOL | AD525X_RDAC3)
66
67/* RDAC-to-EEPROM Interface Commands */
68#define AD525X_I2C_RDAC (0x00 << 5)
69#define AD525X_I2C_EEPROM (0x01 << 5)
70#define AD525X_I2C_CMD (0x80)
71
72#define AD525X_DEC_ALL_6DB (AD525X_I2C_CMD | (0x4 << 3))
73#define AD525X_INC_ALL_6DB (AD525X_I2C_CMD | (0x9 << 3))
74#define AD525X_DEC_ALL (AD525X_I2C_CMD | (0x6 << 3))
75#define AD525X_INC_ALL (AD525X_I2C_CMD | (0xB << 3))
76
77static s32 ad525x_read(struct i2c_client *client, u8 reg);
78static s32 ad525x_write(struct i2c_client *client, u8 reg, u8 value);
79
80/*
81 * Client data (each client gets its own)
82 */
83
84struct dpot_data {
85 struct mutex update_lock;
86 unsigned rdac_mask;
87 unsigned max_pos;
88 unsigned devid;
89};
90
91/* sysfs functions */
92
93static ssize_t sysfs_show_reg(struct device *dev,
94 struct device_attribute *attr, char *buf, u32 reg)
95{
96 struct i2c_client *client = to_i2c_client(dev);
97 struct dpot_data *data = i2c_get_clientdata(client);
98 s32 value;
99
100 mutex_lock(&data->update_lock);
101 value = ad525x_read(client, reg);
102 mutex_unlock(&data->update_lock);
103
104 if (value < 0)
105 return -EINVAL;
106 /*
107 * Let someone else deal with converting this ...
108 * the tolerance is a two-byte value where the MSB
109 * is a sign + integer value, and the LSB is a
110 * decimal value. See page 18 of the AD5258
111 * datasheet (Rev. A) for more details.
112 */
113
114 if (reg & AD525X_REG_TOL)
115 return sprintf(buf, "0x%04x\n", value & 0xFFFF);
116 else
117 return sprintf(buf, "%u\n", value & data->rdac_mask);
118}
119
120static ssize_t sysfs_set_reg(struct device *dev,
121 struct device_attribute *attr,
122 const char *buf, size_t count, u32 reg)
123{
124 struct i2c_client *client = to_i2c_client(dev);
125 struct dpot_data *data = i2c_get_clientdata(client);
126 unsigned long value;
127 int err;
128
129 err = strict_strtoul(buf, 10, &value);
130 if (err)
131 return err;
132
133 if (value > data->rdac_mask)
134 value = data->rdac_mask;
135
136 mutex_lock(&data->update_lock);
137 ad525x_write(client, reg, value);
138 if (reg & AD525X_I2C_EEPROM)
139 msleep(26); /* Sleep while the EEPROM updates */
140 mutex_unlock(&data->update_lock);
141
142 return count;
143}
144
145static ssize_t sysfs_do_cmd(struct device *dev,
146 struct device_attribute *attr,
147 const char *buf, size_t count, u32 reg)
148{
149 struct i2c_client *client = to_i2c_client(dev);
150 struct dpot_data *data = i2c_get_clientdata(client);
151
152 mutex_lock(&data->update_lock);
153 ad525x_write(client, reg, 0);
154 mutex_unlock(&data->update_lock);
155
156 return count;
157}
158
159/* ------------------------------------------------------------------------- */
160
161static ssize_t show_rdac0(struct device *dev,
162 struct device_attribute *attr, char *buf)
163{
164 return sysfs_show_reg(dev, attr, buf, AD525X_I2C_RDAC | AD525X_RDAC0);
165}
166
167static ssize_t set_rdac0(struct device *dev,
168 struct device_attribute *attr,
169 const char *buf, size_t count)
170{
171 return sysfs_set_reg(dev, attr, buf, count,
172 AD525X_I2C_RDAC | AD525X_RDAC0);
173}
174
175static DEVICE_ATTR(rdac0, S_IWUSR | S_IRUGO, show_rdac0, set_rdac0);
176
177static ssize_t show_eeprom0(struct device *dev,
178 struct device_attribute *attr, char *buf)
179{
180 return sysfs_show_reg(dev, attr, buf, AD525X_I2C_EEPROM | AD525X_RDAC0);
181}
182
183static ssize_t set_eeprom0(struct device *dev,
184 struct device_attribute *attr,
185 const char *buf, size_t count)
186{
187 return sysfs_set_reg(dev, attr, buf, count,
188 AD525X_I2C_EEPROM | AD525X_RDAC0);
189}
190
191static DEVICE_ATTR(eeprom0, S_IWUSR | S_IRUGO, show_eeprom0, set_eeprom0);
192
193static ssize_t show_tolerance0(struct device *dev,
194 struct device_attribute *attr, char *buf)
195{
196 return sysfs_show_reg(dev, attr, buf,
197 AD525X_I2C_EEPROM | AD525X_TOL_RDAC0);
198}
199
200static DEVICE_ATTR(tolerance0, S_IRUGO, show_tolerance0, NULL);
201
202/* ------------------------------------------------------------------------- */
203
204static ssize_t show_rdac1(struct device *dev,
205 struct device_attribute *attr, char *buf)
206{
207 return sysfs_show_reg(dev, attr, buf, AD525X_I2C_RDAC | AD525X_RDAC1);
208}
209
210static ssize_t set_rdac1(struct device *dev,
211 struct device_attribute *attr,
212 const char *buf, size_t count)
213{
214 return sysfs_set_reg(dev, attr, buf, count,
215 AD525X_I2C_RDAC | AD525X_RDAC1);
216}
217
218static DEVICE_ATTR(rdac1, S_IWUSR | S_IRUGO, show_rdac1, set_rdac1);
219
220static ssize_t show_eeprom1(struct device *dev,
221 struct device_attribute *attr, char *buf)
222{
223 return sysfs_show_reg(dev, attr, buf, AD525X_I2C_EEPROM | AD525X_RDAC1);
224}
225
226static ssize_t set_eeprom1(struct device *dev,
227 struct device_attribute *attr,
228 const char *buf, size_t count)
229{
230 return sysfs_set_reg(dev, attr, buf, count,
231 AD525X_I2C_EEPROM | AD525X_RDAC1);
232}
233
234static DEVICE_ATTR(eeprom1, S_IWUSR | S_IRUGO, show_eeprom1, set_eeprom1);
235
236static ssize_t show_tolerance1(struct device *dev,
237 struct device_attribute *attr, char *buf)
238{
239 return sysfs_show_reg(dev, attr, buf,
240 AD525X_I2C_EEPROM | AD525X_TOL_RDAC1);
241}
242
243static DEVICE_ATTR(tolerance1, S_IRUGO, show_tolerance1, NULL);
244
245/* ------------------------------------------------------------------------- */
246
247static ssize_t show_rdac2(struct device *dev,
248 struct device_attribute *attr, char *buf)
249{
250 return sysfs_show_reg(dev, attr, buf, AD525X_I2C_RDAC | AD525X_RDAC2);
251}
252
253static ssize_t set_rdac2(struct device *dev,
254 struct device_attribute *attr,
255 const char *buf, size_t count)
256{
257 return sysfs_set_reg(dev, attr, buf, count,
258 AD525X_I2C_RDAC | AD525X_RDAC2);
259}
260
261static DEVICE_ATTR(rdac2, S_IWUSR | S_IRUGO, show_rdac2, set_rdac2);
262
263static ssize_t show_eeprom2(struct device *dev,
264 struct device_attribute *attr, char *buf)
265{
266 return sysfs_show_reg(dev, attr, buf, AD525X_I2C_EEPROM | AD525X_RDAC2);
267}
268
269static ssize_t set_eeprom2(struct device *dev,
270 struct device_attribute *attr,
271 const char *buf, size_t count)
272{
273 return sysfs_set_reg(dev, attr, buf, count,
274 AD525X_I2C_EEPROM | AD525X_RDAC2);
275}
276
277static DEVICE_ATTR(eeprom2, S_IWUSR | S_IRUGO, show_eeprom2, set_eeprom2);
278
279static ssize_t show_tolerance2(struct device *dev,
280 struct device_attribute *attr, char *buf)
281{
282 return sysfs_show_reg(dev, attr, buf,
283 AD525X_I2C_EEPROM | AD525X_TOL_RDAC2);
284}
285
286static DEVICE_ATTR(tolerance2, S_IRUGO, show_tolerance2, NULL);
287
288/* ------------------------------------------------------------------------- */
289
290static ssize_t show_rdac3(struct device *dev,
291 struct device_attribute *attr, char *buf)
292{
293 return sysfs_show_reg(dev, attr, buf, AD525X_I2C_RDAC | AD525X_RDAC3);
294}
295
296static ssize_t set_rdac3(struct device *dev,
297 struct device_attribute *attr,
298 const char *buf, size_t count)
299{
300 return sysfs_set_reg(dev, attr, buf, count,
301 AD525X_I2C_RDAC | AD525X_RDAC3);
302}
303
304static DEVICE_ATTR(rdac3, S_IWUSR | S_IRUGO, show_rdac3, set_rdac3);
305
306static ssize_t show_eeprom3(struct device *dev,
307 struct device_attribute *attr, char *buf)
308{
309 return sysfs_show_reg(dev, attr, buf, AD525X_I2C_EEPROM | AD525X_RDAC3);
310}
311
312static ssize_t set_eeprom3(struct device *dev,
313 struct device_attribute *attr,
314 const char *buf, size_t count)
315{
316 return sysfs_set_reg(dev, attr, buf, count,
317 AD525X_I2C_EEPROM | AD525X_RDAC3);
318}
319
320static DEVICE_ATTR(eeprom3, S_IWUSR | S_IRUGO, show_eeprom3, set_eeprom3);
321
322static ssize_t show_tolerance3(struct device *dev,
323 struct device_attribute *attr, char *buf)
324{
325 return sysfs_show_reg(dev, attr, buf,
326 AD525X_I2C_EEPROM | AD525X_TOL_RDAC3);
327}
328
329static DEVICE_ATTR(tolerance3, S_IRUGO, show_tolerance3, NULL);
330
331static struct attribute *ad525x_attributes_wipers[4][4] = {
332 {
333 &dev_attr_rdac0.attr,
334 &dev_attr_eeprom0.attr,
335 &dev_attr_tolerance0.attr,
336 NULL
337 }, {
338 &dev_attr_rdac1.attr,
339 &dev_attr_eeprom1.attr,
340 &dev_attr_tolerance1.attr,
341 NULL
342 }, {
343 &dev_attr_rdac2.attr,
344 &dev_attr_eeprom2.attr,
345 &dev_attr_tolerance2.attr,
346 NULL
347 }, {
348 &dev_attr_rdac3.attr,
349 &dev_attr_eeprom3.attr,
350 &dev_attr_tolerance3.attr,
351 NULL
352 }
353};
354
355static const struct attribute_group ad525x_group_wipers[] = {
356 {.attrs = ad525x_attributes_wipers[AD525X_RDAC0]},
357 {.attrs = ad525x_attributes_wipers[AD525X_RDAC1]},
358 {.attrs = ad525x_attributes_wipers[AD525X_RDAC2]},
359 {.attrs = ad525x_attributes_wipers[AD525X_RDAC3]},
360};
361
362/* ------------------------------------------------------------------------- */
363
364static ssize_t set_inc_all(struct device *dev,
365 struct device_attribute *attr,
366 const char *buf, size_t count)
367{
368 return sysfs_do_cmd(dev, attr, buf, count, AD525X_INC_ALL);
369}
370
371static DEVICE_ATTR(inc_all, S_IWUSR, NULL, set_inc_all);
372
373static ssize_t set_dec_all(struct device *dev,
374 struct device_attribute *attr,
375 const char *buf, size_t count)
376{
377 return sysfs_do_cmd(dev, attr, buf, count, AD525X_DEC_ALL);
378}
379
380static DEVICE_ATTR(dec_all, S_IWUSR, NULL, set_dec_all);
381
382static ssize_t set_inc_all_6db(struct device *dev,
383 struct device_attribute *attr,
384 const char *buf, size_t count)
385{
386 return sysfs_do_cmd(dev, attr, buf, count, AD525X_INC_ALL_6DB);
387}
388
389static DEVICE_ATTR(inc_all_6db, S_IWUSR, NULL, set_inc_all_6db);
390
391static ssize_t set_dec_all_6db(struct device *dev,
392 struct device_attribute *attr,
393 const char *buf, size_t count)
394{
395 return sysfs_do_cmd(dev, attr, buf, count, AD525X_DEC_ALL_6DB);
396}
397
398static DEVICE_ATTR(dec_all_6db, S_IWUSR, NULL, set_dec_all_6db);
399
400static struct attribute *ad525x_attributes_commands[] = {
401 &dev_attr_inc_all.attr,
402 &dev_attr_dec_all.attr,
403 &dev_attr_inc_all_6db.attr,
404 &dev_attr_dec_all_6db.attr,
405 NULL
406};
407
408static const struct attribute_group ad525x_group_commands = {
409 .attrs = ad525x_attributes_commands,
410};
411
412/* ------------------------------------------------------------------------- */
413
414/* i2c device functions */
415
416/**
417 * ad525x_read - return the value contained in the specified register
418 * on the AD5258 device.
419 * @client: value returned from i2c_new_device()
420 * @reg: the register to read
421 *
422 * If the tolerance register is specified, 2 bytes are returned.
423 * Otherwise, 1 byte is returned. A negative value indicates an error
424 * occurred while reading the register.
425 */
426static s32 ad525x_read(struct i2c_client *client, u8 reg)
427{
428 struct dpot_data *data = i2c_get_clientdata(client);
429
430 if ((reg & AD525X_REG_TOL) || (data->max_pos > 256))
431 return i2c_smbus_read_word_data(client, (reg & 0xF8) |
432 ((reg & 0x7) << 1));
433 else
434 return i2c_smbus_read_byte_data(client, reg);
435}
436
437/**
438 * ad525x_write - store the given value in the specified register on
439 * the AD5258 device.
440 * @client: value returned from i2c_new_device()
441 * @reg: the register to write
442 * @value: the byte to store in the register
443 *
444 * For certain instructions that do not require a data byte, "NULL"
445 * should be specified for the "value" parameter. These instructions
446 * include NOP, RESTORE_FROM_EEPROM, and STORE_TO_EEPROM.
447 *
448 * A negative return value indicates an error occurred while reading
449 * the register.
450 */
451static s32 ad525x_write(struct i2c_client *client, u8 reg, u8 value)
452{
453 struct dpot_data *data = i2c_get_clientdata(client);
454
455 /* Only write the instruction byte for certain commands */
456 if (reg & AD525X_I2C_CMD)
457 return i2c_smbus_write_byte(client, reg);
458
459 if (data->max_pos > 256)
460 return i2c_smbus_write_word_data(client, (reg & 0xF8) |
461 ((reg & 0x7) << 1), value);
462 else
463 /* All other registers require instruction + data bytes */
464 return i2c_smbus_write_byte_data(client, reg, value);
465}
466
467static int ad525x_probe(struct i2c_client *client,
468 const struct i2c_device_id *id)
469{
470 struct device *dev = &client->dev;
471 struct dpot_data *data;
472 int err = 0;
473
474 dev_dbg(dev, "%s\n", __func__);
475
476 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
477 dev_err(dev, "missing I2C functionality for this driver\n");
478 goto exit;
479 }
480
481 data = kzalloc(sizeof(struct dpot_data), GFP_KERNEL);
482 if (!data) {
483 err = -ENOMEM;
484 goto exit;
485 }
486
487 i2c_set_clientdata(client, data);
488 mutex_init(&data->update_lock);
489
490 switch (id->driver_data) {
491 case AD5258_ID:
492 data->max_pos = AD5258_MAX_POSITION;
493 err = sysfs_create_group(&dev->kobj,
494 &ad525x_group_wipers[AD525X_RDAC0]);
495 break;
496 case AD5259_ID:
497 data->max_pos = AD5259_MAX_POSITION;
498 err = sysfs_create_group(&dev->kobj,
499 &ad525x_group_wipers[AD525X_RDAC0]);
500 break;
501 case AD5251_ID:
502 data->max_pos = AD5251_MAX_POSITION;
503 err = sysfs_create_group(&dev->kobj,
504 &ad525x_group_wipers[AD525X_RDAC1]);
505 err |= sysfs_create_group(&dev->kobj,
506 &ad525x_group_wipers[AD525X_RDAC3]);
507 err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
508 break;
509 case AD5252_ID:
510 data->max_pos = AD5252_MAX_POSITION;
511 err = sysfs_create_group(&dev->kobj,
512 &ad525x_group_wipers[AD525X_RDAC1]);
513 err |= sysfs_create_group(&dev->kobj,
514 &ad525x_group_wipers[AD525X_RDAC3]);
515 err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
516 break;
517 case AD5253_ID:
518 data->max_pos = AD5253_MAX_POSITION;
519 err = sysfs_create_group(&dev->kobj,
520 &ad525x_group_wipers[AD525X_RDAC0]);
521 err |= sysfs_create_group(&dev->kobj,
522 &ad525x_group_wipers[AD525X_RDAC1]);
523 err |= sysfs_create_group(&dev->kobj,
524 &ad525x_group_wipers[AD525X_RDAC2]);
525 err |= sysfs_create_group(&dev->kobj,
526 &ad525x_group_wipers[AD525X_RDAC3]);
527 err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
528 break;
529 case AD5254_ID:
530 data->max_pos = AD5254_MAX_POSITION;
531 err = sysfs_create_group(&dev->kobj,
532 &ad525x_group_wipers[AD525X_RDAC0]);
533 err |= sysfs_create_group(&dev->kobj,
534 &ad525x_group_wipers[AD525X_RDAC1]);
535 err |= sysfs_create_group(&dev->kobj,
536 &ad525x_group_wipers[AD525X_RDAC2]);
537 err |= sysfs_create_group(&dev->kobj,
538 &ad525x_group_wipers[AD525X_RDAC3]);
539 err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
540 break;
541 case AD5255_ID:
542 data->max_pos = AD5255_MAX_POSITION;
543 err = sysfs_create_group(&dev->kobj,
544 &ad525x_group_wipers[AD525X_RDAC0]);
545 err |= sysfs_create_group(&dev->kobj,
546 &ad525x_group_wipers[AD525X_RDAC1]);
547 err |= sysfs_create_group(&dev->kobj,
548 &ad525x_group_wipers[AD525X_RDAC2]);
549 err |= sysfs_create_group(&dev->kobj, &ad525x_group_commands);
550 break;
551 default:
552 err = -ENODEV;
553 goto exit_free;
554 }
555
556 if (err) {
557 dev_err(dev, "failed to register sysfs hooks\n");
558 goto exit_free;
559 }
560
561 data->devid = id->driver_data;
562 data->rdac_mask = data->max_pos - 1;
563
564 dev_info(dev, "%s %d-Position Digital Potentiometer registered\n",
565 id->name, data->max_pos);
566
567 return 0;
568
569exit_free:
570 kfree(data);
571 i2c_set_clientdata(client, NULL);
572exit:
573 dev_err(dev, "failed to create client\n");
574 return err;
575}
576
577static int __devexit ad525x_remove(struct i2c_client *client)
578{
579 struct dpot_data *data = i2c_get_clientdata(client);
580 struct device *dev = &client->dev;
581
582 switch (data->devid) {
583 case AD5258_ID:
584 case AD5259_ID:
585 sysfs_remove_group(&dev->kobj,
586 &ad525x_group_wipers[AD525X_RDAC0]);
587 break;
588 case AD5251_ID:
589 case AD5252_ID:
590 sysfs_remove_group(&dev->kobj,
591 &ad525x_group_wipers[AD525X_RDAC1]);
592 sysfs_remove_group(&dev->kobj,
593 &ad525x_group_wipers[AD525X_RDAC3]);
594 sysfs_remove_group(&dev->kobj, &ad525x_group_commands);
595 break;
596 case AD5253_ID:
597 case AD5254_ID:
598 sysfs_remove_group(&dev->kobj,
599 &ad525x_group_wipers[AD525X_RDAC0]);
600 sysfs_remove_group(&dev->kobj,
601 &ad525x_group_wipers[AD525X_RDAC1]);
602 sysfs_remove_group(&dev->kobj,
603 &ad525x_group_wipers[AD525X_RDAC2]);
604 sysfs_remove_group(&dev->kobj,
605 &ad525x_group_wipers[AD525X_RDAC3]);
606 sysfs_remove_group(&dev->kobj, &ad525x_group_commands);
607 break;
608 case AD5255_ID:
609 sysfs_remove_group(&dev->kobj,
610 &ad525x_group_wipers[AD525X_RDAC0]);
611 sysfs_remove_group(&dev->kobj,
612 &ad525x_group_wipers[AD525X_RDAC1]);
613 sysfs_remove_group(&dev->kobj,
614 &ad525x_group_wipers[AD525X_RDAC2]);
615 sysfs_remove_group(&dev->kobj, &ad525x_group_commands);
616 break;
617 }
618
619 i2c_set_clientdata(client, NULL);
620 kfree(data);
621
622 return 0;
623}
624
625static const struct i2c_device_id ad525x_idtable[] = {
626 {"ad5258", AD5258_ID},
627 {"ad5259", AD5259_ID},
628 {"ad5251", AD5251_ID},
629 {"ad5252", AD5252_ID},
630 {"ad5253", AD5253_ID},
631 {"ad5254", AD5254_ID},
632 {"ad5255", AD5255_ID},
633 {}
634};
635
636MODULE_DEVICE_TABLE(i2c, ad525x_idtable);
637
638static struct i2c_driver ad525x_driver = {
639 .driver = {
640 .owner = THIS_MODULE,
641 .name = DRIVER_NAME,
642 },
643 .id_table = ad525x_idtable,
644 .probe = ad525x_probe,
645 .remove = __devexit_p(ad525x_remove),
646};
647
648static int __init ad525x_init(void)
649{
650 return i2c_add_driver(&ad525x_driver);
651}
652
653module_init(ad525x_init);
654
655static void __exit ad525x_exit(void)
656{
657 i2c_del_driver(&ad525x_driver);
658}
659
660module_exit(ad525x_exit);
661
662MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>, "
663 "Michael Hennerich <hennerich@blackfin.uclinux.org>, ");
664MODULE_DESCRIPTION("AD5258/9 digital potentiometer driver");
665MODULE_LICENSE("GPL");
666MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c
new file mode 100644
index 000000000000..8110460558ff
--- /dev/null
+++ b/drivers/misc/cs5535-mfgpt.c
@@ -0,0 +1,370 @@
1/*
2 * Driver for the CS5535/CS5536 Multi-Function General Purpose Timers (MFGPT)
3 *
4 * Copyright (C) 2006, Advanced Micro Devices, Inc.
5 * Copyright (C) 2007 Andres Salomon <dilinger@debian.org>
6 * Copyright (C) 2009 Andres Salomon <dilinger@collabora.co.uk>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of version 2 of the GNU General Public License
10 * as published by the Free Software Foundation.
11 *
12 * The MFGPTs are documented in AMD Geode CS5536 Companion Device Data Book.
13 */
14
15#include <linux/kernel.h>
16#include <linux/spinlock.h>
17#include <linux/interrupt.h>
18#include <linux/module.h>
19#include <linux/pci.h>
20#include <linux/cs5535.h>
21
22#define DRV_NAME "cs5535-mfgpt"
23#define MFGPT_BAR 2
24
25static int mfgpt_reset_timers;
26module_param_named(mfgptfix, mfgpt_reset_timers, int, 0644);
27MODULE_PARM_DESC(mfgptfix, "Reset the MFGPT timers during init; "
28 "required by some broken BIOSes (ie, TinyBIOS < 0.99).");
29
30struct cs5535_mfgpt_timer {
31 struct cs5535_mfgpt_chip *chip;
32 int nr;
33};
34
35static struct cs5535_mfgpt_chip {
36 DECLARE_BITMAP(avail, MFGPT_MAX_TIMERS);
37 resource_size_t base;
38
39 struct pci_dev *pdev;
40 spinlock_t lock;
41 int initialized;
42} cs5535_mfgpt_chip;
43
44int cs5535_mfgpt_toggle_event(struct cs5535_mfgpt_timer *timer, int cmp,
45 int event, int enable)
46{
47 uint32_t msr, mask, value, dummy;
48 int shift = (cmp == MFGPT_CMP1) ? 0 : 8;
49
50 if (!timer) {
51 WARN_ON(1);
52 return -EIO;
53 }
54
55 /*
56 * The register maps for these are described in sections 6.17.1.x of
57 * the AMD Geode CS5536 Companion Device Data Book.
58 */
59 switch (event) {
60 case MFGPT_EVENT_RESET:
61 /*
62 * XXX: According to the docs, we cannot reset timers above
63 * 6; that is, resets for 7 and 8 will be ignored. Is this
64 * a problem? -dilinger
65 */
66 msr = MSR_MFGPT_NR;
67 mask = 1 << (timer->nr + 24);
68 break;
69
70 case MFGPT_EVENT_NMI:
71 msr = MSR_MFGPT_NR;
72 mask = 1 << (timer->nr + shift);
73 break;
74
75 case MFGPT_EVENT_IRQ:
76 msr = MSR_MFGPT_IRQ;
77 mask = 1 << (timer->nr + shift);
78 break;
79
80 default:
81 return -EIO;
82 }
83
84 rdmsr(msr, value, dummy);
85
86 if (enable)
87 value |= mask;
88 else
89 value &= ~mask;
90
91 wrmsr(msr, value, dummy);
92 return 0;
93}
94EXPORT_SYMBOL_GPL(cs5535_mfgpt_toggle_event);
95
96int cs5535_mfgpt_set_irq(struct cs5535_mfgpt_timer *timer, int cmp, int *irq,
97 int enable)
98{
99 uint32_t zsel, lpc, dummy;
100 int shift;
101
102 if (!timer) {
103 WARN_ON(1);
104 return -EIO;
105 }
106
107 /*
108 * Unfortunately, MFGPTs come in pairs sharing their IRQ lines. If VSA
109 * is using the same CMP of the timer's Siamese twin, the IRQ is set to
110 * 2, and we mustn't use nor change it.
111 * XXX: Likewise, 2 Linux drivers might clash if the 2nd overwrites the
112 * IRQ of the 1st. This can only happen if forcing an IRQ, calling this
113 * with *irq==0 is safe. Currently there _are_ no 2 drivers.
114 */
115 rdmsr(MSR_PIC_ZSEL_LOW, zsel, dummy);
116 shift = ((cmp == MFGPT_CMP1 ? 0 : 4) + timer->nr % 4) * 4;
117 if (((zsel >> shift) & 0xF) == 2)
118 return -EIO;
119
120 /* Choose IRQ: if none supplied, keep IRQ already set or use default */
121 if (!*irq)
122 *irq = (zsel >> shift) & 0xF;
123 if (!*irq)
124 *irq = CONFIG_CS5535_MFGPT_DEFAULT_IRQ;
125
126 /* Can't use IRQ if it's 0 (=disabled), 2, or routed to LPC */
127 if (*irq < 1 || *irq == 2 || *irq > 15)
128 return -EIO;
129 rdmsr(MSR_PIC_IRQM_LPC, lpc, dummy);
130 if (lpc & (1 << *irq))
131 return -EIO;
132
133 /* All chosen and checked - go for it */
134 if (cs5535_mfgpt_toggle_event(timer, cmp, MFGPT_EVENT_IRQ, enable))
135 return -EIO;
136 if (enable) {
137 zsel = (zsel & ~(0xF << shift)) | (*irq << shift);
138 wrmsr(MSR_PIC_ZSEL_LOW, zsel, dummy);
139 }
140
141 return 0;
142}
143EXPORT_SYMBOL_GPL(cs5535_mfgpt_set_irq);
144
145struct cs5535_mfgpt_timer *cs5535_mfgpt_alloc_timer(int timer_nr, int domain)
146{
147 struct cs5535_mfgpt_chip *mfgpt = &cs5535_mfgpt_chip;
148 struct cs5535_mfgpt_timer *timer = NULL;
149 unsigned long flags;
150 int max;
151
152 if (!mfgpt->initialized)
153 goto done;
154
155 /* only allocate timers from the working domain if requested */
156 if (domain == MFGPT_DOMAIN_WORKING)
157 max = 6;
158 else
159 max = MFGPT_MAX_TIMERS;
160
161 if (timer_nr >= max) {
162 /* programmer error. silly programmers! */
163 WARN_ON(1);
164 goto done;
165 }
166
167 spin_lock_irqsave(&mfgpt->lock, flags);
168 if (timer_nr < 0) {
169 unsigned long t;
170
171 /* try to find any available timer */
172 t = find_first_bit(mfgpt->avail, max);
173 /* set timer_nr to -1 if no timers available */
174 timer_nr = t < max ? (int) t : -1;
175 } else {
176 /* check if the requested timer's available */
177 if (test_bit(timer_nr, mfgpt->avail))
178 timer_nr = -1;
179 }
180
181 if (timer_nr >= 0)
182 /* if timer_nr is not -1, it's an available timer */
183 __clear_bit(timer_nr, mfgpt->avail);
184 spin_unlock_irqrestore(&mfgpt->lock, flags);
185
186 if (timer_nr < 0)
187 goto done;
188
189 timer = kmalloc(sizeof(*timer), GFP_KERNEL);
190 if (!timer) {
191 /* aw hell */
192 spin_lock_irqsave(&mfgpt->lock, flags);
193 __set_bit(timer_nr, mfgpt->avail);
194 spin_unlock_irqrestore(&mfgpt->lock, flags);
195 goto done;
196 }
197 timer->chip = mfgpt;
198 timer->nr = timer_nr;
199 dev_info(&mfgpt->pdev->dev, "registered timer %d\n", timer_nr);
200
201done:
202 return timer;
203}
204EXPORT_SYMBOL_GPL(cs5535_mfgpt_alloc_timer);
205
206/*
207 * XXX: This frees the timer memory, but never resets the actual hardware
208 * timer. The old geode_mfgpt code did this; it would be good to figure
209 * out a way to actually release the hardware timer. See comments below.
210 */
211void cs5535_mfgpt_free_timer(struct cs5535_mfgpt_timer *timer)
212{
213 kfree(timer);
214}
215EXPORT_SYMBOL_GPL(cs5535_mfgpt_free_timer);
216
217uint16_t cs5535_mfgpt_read(struct cs5535_mfgpt_timer *timer, uint16_t reg)
218{
219 return inw(timer->chip->base + reg + (timer->nr * 8));
220}
221EXPORT_SYMBOL_GPL(cs5535_mfgpt_read);
222
223void cs5535_mfgpt_write(struct cs5535_mfgpt_timer *timer, uint16_t reg,
224 uint16_t value)
225{
226 outw(value, timer->chip->base + reg + (timer->nr * 8));
227}
228EXPORT_SYMBOL_GPL(cs5535_mfgpt_write);
229
230/*
231 * This is a sledgehammer that resets all MFGPT timers. This is required by
232 * some broken BIOSes which leave the system in an unstable state
233 * (TinyBIOS 0.98, for example; fixed in 0.99). It's uncertain as to
234 * whether or not this secret MSR can be used to release individual timers.
235 * Jordan tells me that he and Mitch once played w/ it, but it's unclear
236 * what the results of that were (and they experienced some instability).
237 */
238static void __init reset_all_timers(void)
239{
240 uint32_t val, dummy;
241
242 /* The following undocumented bit resets the MFGPT timers */
243 val = 0xFF; dummy = 0;
244 wrmsr(MSR_MFGPT_SETUP, val, dummy);
245}
246
247/*
248 * Check whether any MFGPTs are available for the kernel to use. In most
249 * cases, firmware that uses AMD's VSA code will claim all timers during
250 * bootup; we certainly don't want to take them if they're already in use.
251 * In other cases (such as with VSAless OpenFirmware), the system firmware
252 * leaves timers available for us to use.
253 */
254static int __init scan_timers(struct cs5535_mfgpt_chip *mfgpt)
255{
256 struct cs5535_mfgpt_timer timer = { .chip = mfgpt };
257 unsigned long flags;
258 int timers = 0;
259 uint16_t val;
260 int i;
261
262 /* bios workaround */
263 if (mfgpt_reset_timers)
264 reset_all_timers();
265
266 /* just to be safe, protect this section w/ lock */
267 spin_lock_irqsave(&mfgpt->lock, flags);
268 for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
269 timer.nr = i;
270 val = cs5535_mfgpt_read(&timer, MFGPT_REG_SETUP);
271 if (!(val & MFGPT_SETUP_SETUP)) {
272 __set_bit(i, mfgpt->avail);
273 timers++;
274 }
275 }
276 spin_unlock_irqrestore(&mfgpt->lock, flags);
277
278 return timers;
279}
280
281static int __init cs5535_mfgpt_probe(struct pci_dev *pdev,
282 const struct pci_device_id *pci_id)
283{
284 int err, t;
285
286 /* There are two ways to get the MFGPT base address; one is by
287 * fetching it from MSR_LBAR_MFGPT, the other is by reading the
288 * PCI BAR info. The latter method is easier (especially across
289 * different architectures), so we'll stick with that for now. If
290 * it turns out to be unreliable in the face of crappy BIOSes, we
291 * can always go back to using MSRs.. */
292
293 err = pci_enable_device_io(pdev);
294 if (err) {
295 dev_err(&pdev->dev, "can't enable device IO\n");
296 goto done;
297 }
298
299 err = pci_request_region(pdev, MFGPT_BAR, DRV_NAME);
300 if (err) {
301 dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", MFGPT_BAR);
302 goto done;
303 }
304
305 /* set up the driver-specific struct */
306 cs5535_mfgpt_chip.base = pci_resource_start(pdev, MFGPT_BAR);
307 cs5535_mfgpt_chip.pdev = pdev;
308 spin_lock_init(&cs5535_mfgpt_chip.lock);
309
310 dev_info(&pdev->dev, "allocated PCI BAR #%d: base 0x%llx\n", MFGPT_BAR,
311 (unsigned long long) cs5535_mfgpt_chip.base);
312
313 /* detect the available timers */
314 t = scan_timers(&cs5535_mfgpt_chip);
315 dev_info(&pdev->dev, DRV_NAME ": %d MFGPT timers available\n", t);
316 cs5535_mfgpt_chip.initialized = 1;
317 return 0;
318
319done:
320 return err;
321}
322
323static struct pci_device_id cs5535_mfgpt_pci_tbl[] = {
324 { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
325 { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
326 { 0, },
327};
328MODULE_DEVICE_TABLE(pci, cs5535_mfgpt_pci_tbl);
329
330/*
331 * Just like with the cs5535-gpio driver, we can't use the standard PCI driver
332 * registration stuff. It only allows only one driver to bind to each PCI
333 * device, and we want the GPIO and MFGPT drivers to be able to share a PCI
334 * device. Instead, we manually scan for the PCI device, request a single
335 * region, and keep track of the devices that we're using.
336 */
337
338static int __init cs5535_mfgpt_scan_pci(void)
339{
340 struct pci_dev *pdev;
341 int err = -ENODEV;
342 int i;
343
344 for (i = 0; i < ARRAY_SIZE(cs5535_mfgpt_pci_tbl); i++) {
345 pdev = pci_get_device(cs5535_mfgpt_pci_tbl[i].vendor,
346 cs5535_mfgpt_pci_tbl[i].device, NULL);
347 if (pdev) {
348 err = cs5535_mfgpt_probe(pdev,
349 &cs5535_mfgpt_pci_tbl[i]);
350 if (err)
351 pci_dev_put(pdev);
352
353 /* we only support a single CS5535/6 southbridge */
354 break;
355 }
356 }
357
358 return err;
359}
360
361static int __init cs5535_mfgpt_init(void)
362{
363 return cs5535_mfgpt_scan_pci();
364}
365
366module_init(cs5535_mfgpt_init);
367
368MODULE_AUTHOR("Andres Salomon <dilinger@collabora.co.uk>");
369MODULE_DESCRIPTION("CS5535/CS5536 MFGPT timer driver");
370MODULE_LICENSE("GPL");
diff --git a/drivers/misc/ds1682.c b/drivers/misc/ds1682.c
new file mode 100644
index 000000000000..f3ee4a1abb77
--- /dev/null
+++ b/drivers/misc/ds1682.c
@@ -0,0 +1,267 @@
1/*
2 * Dallas Semiconductor DS1682 Elapsed Time Recorder device driver
3 *
4 * Written by: Grant Likely <grant.likely@secretlab.ca>
5 *
6 * Copyright (C) 2007 Secret Lab Technologies Ltd.
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
13/*
14 * The DS1682 elapsed timer recorder is a simple device that implements
15 * one elapsed time counter, one event counter, an alarm signal and 10
16 * bytes of general purpose EEPROM.
17 *
18 * This driver provides access to the DS1682 counters and user data via
19 * the sysfs. The following attributes are added to the device node:
20 * elapsed_time (u32): Total elapsed event time in ms resolution
21 * alarm_time (u32): When elapsed time exceeds the value in alarm_time,
22 * then the alarm pin is asserted.
23 * event_count (u16): number of times the event pin has gone low.
24 * eeprom (u8[10]): general purpose EEPROM
25 *
26 * Counter registers and user data are both read/write unless the device
27 * has been write protected. This driver does not support turning off write
28 * protection. Once write protection is turned on, it is impossible to
29 * turn it off again, so I have left the feature out of this driver to avoid
30 * accidental enabling, but it is trivial to add write protect support.
31 *
32 */
33
34#include <linux/module.h>
35#include <linux/init.h>
36#include <linux/slab.h>
37#include <linux/i2c.h>
38#include <linux/string.h>
39#include <linux/list.h>
40#include <linux/sysfs.h>
41#include <linux/ctype.h>
42#include <linux/hwmon-sysfs.h>
43
44/* Device registers */
45#define DS1682_REG_CONFIG 0x00
46#define DS1682_REG_ALARM 0x01
47#define DS1682_REG_ELAPSED 0x05
48#define DS1682_REG_EVT_CNTR 0x09
49#define DS1682_REG_EEPROM 0x0b
50#define DS1682_REG_RESET 0x1d
51#define DS1682_REG_WRITE_DISABLE 0x1e
52#define DS1682_REG_WRITE_MEM_DISABLE 0x1f
53
54#define DS1682_EEPROM_SIZE 10
55
56/*
57 * Generic counter attributes
58 */
59static ssize_t ds1682_show(struct device *dev, struct device_attribute *attr,
60 char *buf)
61{
62 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
63 struct i2c_client *client = to_i2c_client(dev);
64 __le32 val = 0;
65 int rc;
66
67 dev_dbg(dev, "ds1682_show() called on %s\n", attr->attr.name);
68
69 /* Read the register */
70 rc = i2c_smbus_read_i2c_block_data(client, sattr->index, sattr->nr,
71 (u8 *) & val);
72 if (rc < 0)
73 return -EIO;
74
75 /* Special case: the 32 bit regs are time values with 1/4s
76 * resolution, scale them up to milliseconds */
77 if (sattr->nr == 4)
78 return sprintf(buf, "%llu\n",
79 ((unsigned long long)le32_to_cpu(val)) * 250);
80
81 /* Format the output string and return # of bytes */
82 return sprintf(buf, "%li\n", (long)le32_to_cpu(val));
83}
84
85static ssize_t ds1682_store(struct device *dev, struct device_attribute *attr,
86 const char *buf, size_t count)
87{
88 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
89 struct i2c_client *client = to_i2c_client(dev);
90 char *endp;
91 u64 val;
92 __le32 val_le;
93 int rc;
94
95 dev_dbg(dev, "ds1682_store() called on %s\n", attr->attr.name);
96
97 /* Decode input */
98 val = simple_strtoull(buf, &endp, 0);
99 if (buf == endp) {
100 dev_dbg(dev, "input string not a number\n");
101 return -EINVAL;
102 }
103
104 /* Special case: the 32 bit regs are time values with 1/4s
105 * resolution, scale input down to quarter-seconds */
106 if (sattr->nr == 4)
107 do_div(val, 250);
108
109 /* write out the value */
110 val_le = cpu_to_le32(val);
111 rc = i2c_smbus_write_i2c_block_data(client, sattr->index, sattr->nr,
112 (u8 *) & val_le);
113 if (rc < 0) {
114 dev_err(dev, "register write failed; reg=0x%x, size=%i\n",
115 sattr->index, sattr->nr);
116 return -EIO;
117 }
118
119 return count;
120}
121
122/*
123 * Simple register attributes
124 */
125static SENSOR_DEVICE_ATTR_2(elapsed_time, S_IRUGO | S_IWUSR, ds1682_show,
126 ds1682_store, 4, DS1682_REG_ELAPSED);
127static SENSOR_DEVICE_ATTR_2(alarm_time, S_IRUGO | S_IWUSR, ds1682_show,
128 ds1682_store, 4, DS1682_REG_ALARM);
129static SENSOR_DEVICE_ATTR_2(event_count, S_IRUGO | S_IWUSR, ds1682_show,
130 ds1682_store, 2, DS1682_REG_EVT_CNTR);
131
132static const struct attribute_group ds1682_group = {
133 .attrs = (struct attribute *[]) {
134 &sensor_dev_attr_elapsed_time.dev_attr.attr,
135 &sensor_dev_attr_alarm_time.dev_attr.attr,
136 &sensor_dev_attr_event_count.dev_attr.attr,
137 NULL,
138 },
139};
140
141/*
142 * User data attribute
143 */
144static ssize_t ds1682_eeprom_read(struct kobject *kobj, struct bin_attribute *attr,
145 char *buf, loff_t off, size_t count)
146{
147 struct i2c_client *client = kobj_to_i2c_client(kobj);
148 int rc;
149
150 dev_dbg(&client->dev, "ds1682_eeprom_read(p=%p, off=%lli, c=%zi)\n",
151 buf, off, count);
152
153 if (off >= DS1682_EEPROM_SIZE)
154 return 0;
155
156 if (off + count > DS1682_EEPROM_SIZE)
157 count = DS1682_EEPROM_SIZE - off;
158
159 rc = i2c_smbus_read_i2c_block_data(client, DS1682_REG_EEPROM + off,
160 count, buf);
161 if (rc < 0)
162 return -EIO;
163
164 return count;
165}
166
167static ssize_t ds1682_eeprom_write(struct kobject *kobj, struct bin_attribute *attr,
168 char *buf, loff_t off, size_t count)
169{
170 struct i2c_client *client = kobj_to_i2c_client(kobj);
171
172 dev_dbg(&client->dev, "ds1682_eeprom_write(p=%p, off=%lli, c=%zi)\n",
173 buf, off, count);
174
175 if (off >= DS1682_EEPROM_SIZE)
176 return -ENOSPC;
177
178 if (off + count > DS1682_EEPROM_SIZE)
179 count = DS1682_EEPROM_SIZE - off;
180
181 /* Write out to the device */
182 if (i2c_smbus_write_i2c_block_data(client, DS1682_REG_EEPROM + off,
183 count, buf) < 0)
184 return -EIO;
185
186 return count;
187}
188
189static struct bin_attribute ds1682_eeprom_attr = {
190 .attr = {
191 .name = "eeprom",
192 .mode = S_IRUGO | S_IWUSR,
193 },
194 .size = DS1682_EEPROM_SIZE,
195 .read = ds1682_eeprom_read,
196 .write = ds1682_eeprom_write,
197};
198
199/*
200 * Called when a ds1682 device is matched with this driver
201 */
202static int ds1682_probe(struct i2c_client *client,
203 const struct i2c_device_id *id)
204{
205 int rc;
206
207 if (!i2c_check_functionality(client->adapter,
208 I2C_FUNC_SMBUS_I2C_BLOCK)) {
209 dev_err(&client->dev, "i2c bus does not support the ds1682\n");
210 rc = -ENODEV;
211 goto exit;
212 }
213
214 rc = sysfs_create_group(&client->dev.kobj, &ds1682_group);
215 if (rc)
216 goto exit;
217
218 rc = sysfs_create_bin_file(&client->dev.kobj, &ds1682_eeprom_attr);
219 if (rc)
220 goto exit_bin_attr;
221
222 return 0;
223
224 exit_bin_attr:
225 sysfs_remove_group(&client->dev.kobj, &ds1682_group);
226 exit:
227 return rc;
228}
229
230static int ds1682_remove(struct i2c_client *client)
231{
232 sysfs_remove_bin_file(&client->dev.kobj, &ds1682_eeprom_attr);
233 sysfs_remove_group(&client->dev.kobj, &ds1682_group);
234 return 0;
235}
236
237static const struct i2c_device_id ds1682_id[] = {
238 { "ds1682", 0 },
239 { }
240};
241MODULE_DEVICE_TABLE(i2c, ds1682_id);
242
243static struct i2c_driver ds1682_driver = {
244 .driver = {
245 .name = "ds1682",
246 },
247 .probe = ds1682_probe,
248 .remove = ds1682_remove,
249 .id_table = ds1682_id,
250};
251
252static int __init ds1682_init(void)
253{
254 return i2c_add_driver(&ds1682_driver);
255}
256
257static void __exit ds1682_exit(void)
258{
259 i2c_del_driver(&ds1682_driver);
260}
261
262MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
263MODULE_DESCRIPTION("DS1682 Elapsed Time Indicator driver");
264MODULE_LICENSE("GPL");
265
266module_init(ds1682_init);
267module_exit(ds1682_exit);
diff --git a/drivers/misc/eeprom/eeprom.c b/drivers/misc/eeprom/eeprom.c
index 2c27193aeaa0..f939ebc2507c 100644
--- a/drivers/misc/eeprom/eeprom.c
+++ b/drivers/misc/eeprom/eeprom.c
@@ -32,9 +32,6 @@
32static const unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54, 32static const unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,
33 0x55, 0x56, 0x57, I2C_CLIENT_END }; 33 0x55, 0x56, 0x57, I2C_CLIENT_END };
34 34
35/* Insmod parameters */
36I2C_CLIENT_INSMOD_1(eeprom);
37
38 35
39/* Size of EEPROM in bytes */ 36/* Size of EEPROM in bytes */
40#define EEPROM_SIZE 256 37#define EEPROM_SIZE 256
@@ -135,8 +132,7 @@ static struct bin_attribute eeprom_attr = {
135}; 132};
136 133
137/* Return 0 if detection is successful, -ENODEV otherwise */ 134/* Return 0 if detection is successful, -ENODEV otherwise */
138static int eeprom_detect(struct i2c_client *client, int kind, 135static int eeprom_detect(struct i2c_client *client, struct i2c_board_info *info)
139 struct i2c_board_info *info)
140{ 136{
141 struct i2c_adapter *adapter = client->adapter; 137 struct i2c_adapter *adapter = client->adapter;
142 138
@@ -233,7 +229,7 @@ static struct i2c_driver eeprom_driver = {
233 229
234 .class = I2C_CLASS_DDC | I2C_CLASS_SPD, 230 .class = I2C_CLASS_DDC | I2C_CLASS_SPD,
235 .detect = eeprom_detect, 231 .detect = eeprom_detect,
236 .address_data = &addr_data, 232 .address_list = normal_i2c,
237}; 233};
238 234
239static int __init eeprom_init(void) 235static int __init eeprom_init(void)
diff --git a/drivers/misc/hpilo.h b/drivers/misc/hpilo.h
index 38576050776a..247eb386a973 100644
--- a/drivers/misc/hpilo.h
+++ b/drivers/misc/hpilo.h
@@ -44,9 +44,20 @@ struct ilo_hwinfo {
44 44
45 struct pci_dev *ilo_dev; 45 struct pci_dev *ilo_dev;
46 46
47 /*
48 * open_lock serializes ccb_cnt during open and close
49 * [ irq disabled ]
50 * -> alloc_lock used when adding/removing/searching ccb_alloc,
51 * which represents all ccbs open on the device
52 * --> fifo_lock controls access to fifo queues shared with hw
53 *
54 * Locks must be taken in this order, but open_lock and alloc_lock
55 * are optional, they do not need to be held in order to take a
56 * lower level lock.
57 */
58 spinlock_t open_lock;
47 spinlock_t alloc_lock; 59 spinlock_t alloc_lock;
48 spinlock_t fifo_lock; 60 spinlock_t fifo_lock;
49 spinlock_t open_lock;
50 61
51 struct cdev cdev; 62 struct cdev cdev;
52}; 63};
diff --git a/drivers/misc/ics932s401.c b/drivers/misc/ics932s401.c
index 6e43ab4231ae..395a4ea64e9c 100644
--- a/drivers/misc/ics932s401.c
+++ b/drivers/misc/ics932s401.c
@@ -30,9 +30,6 @@
30/* Addresses to scan */ 30/* Addresses to scan */
31static const unsigned short normal_i2c[] = { 0x69, I2C_CLIENT_END }; 31static const unsigned short normal_i2c[] = { 0x69, I2C_CLIENT_END };
32 32
33/* Insmod parameters */
34I2C_CLIENT_INSMOD_1(ics932s401);
35
36/* ICS932S401 registers */ 33/* ICS932S401 registers */
37#define ICS932S401_REG_CFG2 0x01 34#define ICS932S401_REG_CFG2 0x01
38#define ICS932S401_CFG1_SPREAD 0x01 35#define ICS932S401_CFG1_SPREAD 0x01
@@ -106,12 +103,12 @@ struct ics932s401_data {
106 103
107static int ics932s401_probe(struct i2c_client *client, 104static int ics932s401_probe(struct i2c_client *client,
108 const struct i2c_device_id *id); 105 const struct i2c_device_id *id);
109static int ics932s401_detect(struct i2c_client *client, int kind, 106static int ics932s401_detect(struct i2c_client *client,
110 struct i2c_board_info *info); 107 struct i2c_board_info *info);
111static int ics932s401_remove(struct i2c_client *client); 108static int ics932s401_remove(struct i2c_client *client);
112 109
113static const struct i2c_device_id ics932s401_id[] = { 110static const struct i2c_device_id ics932s401_id[] = {
114 { "ics932s401", ics932s401 }, 111 { "ics932s401", 0 },
115 { } 112 { }
116}; 113};
117MODULE_DEVICE_TABLE(i2c, ics932s401_id); 114MODULE_DEVICE_TABLE(i2c, ics932s401_id);
@@ -125,7 +122,7 @@ static struct i2c_driver ics932s401_driver = {
125 .remove = ics932s401_remove, 122 .remove = ics932s401_remove,
126 .id_table = ics932s401_id, 123 .id_table = ics932s401_id,
127 .detect = ics932s401_detect, 124 .detect = ics932s401_detect,
128 .address_data = &addr_data, 125 .address_list = normal_i2c,
129}; 126};
130 127
131static struct ics932s401_data *ics932s401_update_device(struct device *dev) 128static struct ics932s401_data *ics932s401_update_device(struct device *dev)
@@ -413,36 +410,29 @@ static ssize_t show_spread(struct device *dev,
413} 410}
414 411
415/* Return 0 if detection is successful, -ENODEV otherwise */ 412/* Return 0 if detection is successful, -ENODEV otherwise */
416static int ics932s401_detect(struct i2c_client *client, int kind, 413static int ics932s401_detect(struct i2c_client *client,
417 struct i2c_board_info *info) 414 struct i2c_board_info *info)
418{ 415{
419 struct i2c_adapter *adapter = client->adapter; 416 struct i2c_adapter *adapter = client->adapter;
417 int vendor, device, revision;
420 418
421 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 419 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
422 return -ENODEV; 420 return -ENODEV;
423 421
424 if (kind <= 0) { 422 vendor = i2c_smbus_read_word_data(client, ICS932S401_REG_VENDOR_REV);
425 int vendor, device, revision; 423 vendor >>= 8;
426 424 revision = vendor >> ICS932S401_REV_SHIFT;
427 vendor = i2c_smbus_read_word_data(client, 425 vendor &= ICS932S401_VENDOR_MASK;
428 ICS932S401_REG_VENDOR_REV); 426 if (vendor != ICS932S401_VENDOR)
429 vendor >>= 8; 427 return -ENODEV;
430 revision = vendor >> ICS932S401_REV_SHIFT; 428
431 vendor &= ICS932S401_VENDOR_MASK; 429 device = i2c_smbus_read_word_data(client, ICS932S401_REG_DEVICE);
432 if (vendor != ICS932S401_VENDOR) 430 device >>= 8;
433 return -ENODEV; 431 if (device != ICS932S401_DEVICE)
434 432 return -ENODEV;
435 device = i2c_smbus_read_word_data(client, 433
436 ICS932S401_REG_DEVICE); 434 if (revision != ICS932S401_REV)
437 device >>= 8; 435 dev_info(&adapter->dev, "Unknown revision %d\n", revision);
438 if (device != ICS932S401_DEVICE)
439 return -ENODEV;
440
441 if (revision != ICS932S401_REV)
442 dev_info(&adapter->dev, "Unknown revision %d\n",
443 revision);
444 } else
445 dev_dbg(&adapter->dev, "detection forced\n");
446 436
447 strlcpy(info->type, "ics932s401", I2C_NAME_SIZE); 437 strlcpy(info->type, "ics932s401", I2C_NAME_SIZE);
448 438
diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c
index 60b0b1a4fb3a..09dcb699e667 100644
--- a/drivers/misc/ioc4.c
+++ b/drivers/misc/ioc4.c
@@ -138,7 +138,7 @@ ioc4_unregister_submodule(struct ioc4_submodule *is)
138 * even though the following code utilizes external interrupt registers 138 * even though the following code utilizes external interrupt registers
139 * to perform the speed calculation. 139 * to perform the speed calculation.
140 */ 140 */
141static void 141static void __devinit
142ioc4_clock_calibrate(struct ioc4_driver_data *idd) 142ioc4_clock_calibrate(struct ioc4_driver_data *idd)
143{ 143{
144 union ioc4_int_out int_out; 144 union ioc4_int_out int_out;
@@ -230,7 +230,7 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd)
230 * on the same PCI bus at slot number 3 to differentiate IO9 from IO10. 230 * on the same PCI bus at slot number 3 to differentiate IO9 from IO10.
231 * If neither is present, it's a PCI-RT. 231 * If neither is present, it's a PCI-RT.
232 */ 232 */
233static unsigned int 233static unsigned int __devinit
234ioc4_variant(struct ioc4_driver_data *idd) 234ioc4_variant(struct ioc4_driver_data *idd)
235{ 235{
236 struct pci_dev *pdev = NULL; 236 struct pci_dev *pdev = NULL;
@@ -269,7 +269,7 @@ ioc4_variant(struct ioc4_driver_data *idd)
269 return IOC4_VARIANT_PCI_RT; 269 return IOC4_VARIANT_PCI_RT;
270} 270}
271 271
272static void 272static void __devinit
273ioc4_load_modules(struct work_struct *work) 273ioc4_load_modules(struct work_struct *work)
274{ 274{
275 /* arg just has to be freed */ 275 /* arg just has to be freed */
@@ -280,7 +280,7 @@ ioc4_load_modules(struct work_struct *work)
280} 280}
281 281
282/* Adds a new instance of an IOC4 card */ 282/* Adds a new instance of an IOC4 card */
283static int 283static int __devinit
284ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) 284ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
285{ 285{
286 struct ioc4_driver_data *idd; 286 struct ioc4_driver_data *idd;
@@ -425,7 +425,7 @@ out:
425} 425}
426 426
427/* Removes a particular instance of an IOC4 card. */ 427/* Removes a particular instance of an IOC4 card. */
428static void 428static void __devexit
429ioc4_remove(struct pci_dev *pdev) 429ioc4_remove(struct pci_dev *pdev)
430{ 430{
431 struct ioc4_submodule *is; 431 struct ioc4_submodule *is;
@@ -476,7 +476,7 @@ static struct pci_driver ioc4_driver = {
476 .name = "IOC4", 476 .name = "IOC4",
477 .id_table = ioc4_id_table, 477 .id_table = ioc4_id_table,
478 .probe = ioc4_probe, 478 .probe = ioc4_probe,
479 .remove = ioc4_remove, 479 .remove = __devexit_p(ioc4_remove),
480}; 480};
481 481
482MODULE_DEVICE_TABLE(pci, ioc4_id_table); 482MODULE_DEVICE_TABLE(pci, ioc4_id_table);
@@ -486,14 +486,14 @@ MODULE_DEVICE_TABLE(pci, ioc4_id_table);
486 *********************/ 486 *********************/
487 487
488/* Module load */ 488/* Module load */
489static int __devinit 489static int __init
490ioc4_init(void) 490ioc4_init(void)
491{ 491{
492 return pci_register_driver(&ioc4_driver); 492 return pci_register_driver(&ioc4_driver);
493} 493}
494 494
495/* Module unload */ 495/* Module unload */
496static void __devexit 496static void __exit
497ioc4_exit(void) 497ioc4_exit(void)
498{ 498{
499 /* Ensure ioc4_load_modules() has completed before exiting */ 499 /* Ensure ioc4_load_modules() has completed before exiting */
diff --git a/drivers/misc/iwmc3200top/Kconfig b/drivers/misc/iwmc3200top/Kconfig
new file mode 100644
index 000000000000..9e4b88fb57f1
--- /dev/null
+++ b/drivers/misc/iwmc3200top/Kconfig
@@ -0,0 +1,20 @@
1config IWMC3200TOP
2 tristate "Intel Wireless MultiCom Top Driver"
3 depends on MMC && EXPERIMENTAL
4 select FW_LOADER
5 ---help---
6 Intel Wireless MultiCom 3200 Top driver is responsible for
7 for firmware load and enabled coms enumeration
8
9config IWMC3200TOP_DEBUG
10 bool "Enable full debug output of iwmc3200top Driver"
11 depends on IWMC3200TOP
12 ---help---
13 Enable full debug output of iwmc3200top Driver
14
15config IWMC3200TOP_DEBUGFS
16 bool "Enable Debugfs debugging interface for iwmc3200top"
17 depends on IWMC3200TOP
18 ---help---
19 Enable creation of debugfs files for iwmc3200top
20
diff --git a/drivers/misc/iwmc3200top/Makefile b/drivers/misc/iwmc3200top/Makefile
new file mode 100644
index 000000000000..fbf53fb4634e
--- /dev/null
+++ b/drivers/misc/iwmc3200top/Makefile
@@ -0,0 +1,29 @@
1# iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
2# drivers/misc/iwmc3200top/Makefile
3#
4# Copyright (C) 2009 Intel Corporation. All rights reserved.
5#
6# This program is free software; you can redistribute it and/or
7# modify it under the terms of the GNU General Public License version
8# 2 as 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# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18# 02110-1301, USA.
19#
20#
21# Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
22# -
23#
24#
25
26obj-$(CONFIG_IWMC3200TOP) += iwmc3200top.o
27iwmc3200top-objs := main.o fw-download.o
28iwmc3200top-$(CONFIG_IWMC3200TOP_DEBUG) += log.o
29iwmc3200top-$(CONFIG_IWMC3200TOP_DEBUGFS) += debugfs.o
diff --git a/drivers/misc/iwmc3200top/debugfs.c b/drivers/misc/iwmc3200top/debugfs.c
new file mode 100644
index 000000000000..0c8ea0a1c8a3
--- /dev/null
+++ b/drivers/misc/iwmc3200top/debugfs.c
@@ -0,0 +1,133 @@
1/*
2 * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
3 * drivers/misc/iwmc3200top/debufs.c
4 *
5 * Copyright (C) 2009 Intel Corporation. All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version
9 * 2 as 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., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
20 *
21 *
22 * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
23 * -
24 *
25 */
26
27#include <linux/kernel.h>
28#include <linux/string.h>
29#include <linux/ctype.h>
30#include <linux/mmc/sdio_func.h>
31#include <linux/mmc/sdio.h>
32#include <linux/debugfs.h>
33
34#include "iwmc3200top.h"
35#include "fw-msg.h"
36#include "log.h"
37#include "debugfs.h"
38
39
40
41/* Constants definition */
42#define HEXADECIMAL_RADIX 16
43
44/* Functions definition */
45
46
47#define DEBUGFS_ADD(name, parent) do { \
48 dbgfs->dbgfs_##parent##_files.file_##name = \
49 debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \
50 &iwmct_dbgfs_##name##_ops); \
51} while (0)
52
53#define DEBUGFS_RM(name) do { \
54 debugfs_remove(name); \
55 name = NULL; \
56} while (0)
57
58#define DEBUGFS_READ_FUNC(name) \
59ssize_t iwmct_dbgfs_##name##_read(struct file *file, \
60 char __user *user_buf, \
61 size_t count, loff_t *ppos);
62
63#define DEBUGFS_WRITE_FUNC(name) \
64ssize_t iwmct_dbgfs_##name##_write(struct file *file, \
65 const char __user *user_buf, \
66 size_t count, loff_t *ppos);
67
68#define DEBUGFS_READ_FILE_OPS(name) \
69 DEBUGFS_READ_FUNC(name) \
70 static const struct file_operations iwmct_dbgfs_##name##_ops = { \
71 .read = iwmct_dbgfs_##name##_read, \
72 .open = iwmct_dbgfs_open_file_generic, \
73 };
74
75#define DEBUGFS_WRITE_FILE_OPS(name) \
76 DEBUGFS_WRITE_FUNC(name) \
77 static const struct file_operations iwmct_dbgfs_##name##_ops = { \
78 .write = iwmct_dbgfs_##name##_write, \
79 .open = iwmct_dbgfs_open_file_generic, \
80 };
81
82#define DEBUGFS_READ_WRITE_FILE_OPS(name) \
83 DEBUGFS_READ_FUNC(name) \
84 DEBUGFS_WRITE_FUNC(name) \
85 static const struct file_operations iwmct_dbgfs_##name##_ops = {\
86 .write = iwmct_dbgfs_##name##_write, \
87 .read = iwmct_dbgfs_##name##_read, \
88 .open = iwmct_dbgfs_open_file_generic, \
89 };
90
91
92/* Debugfs file ops definitions */
93
94/*
95 * Create the debugfs files and directories
96 *
97 */
98void iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name)
99{
100 struct iwmct_debugfs *dbgfs;
101
102 dbgfs = kzalloc(sizeof(struct iwmct_debugfs), GFP_KERNEL);
103 if (!dbgfs) {
104 LOG_ERROR(priv, DEBUGFS, "failed to allocate %zd bytes\n",
105 sizeof(struct iwmct_debugfs));
106 return;
107 }
108
109 priv->dbgfs = dbgfs;
110 dbgfs->name = name;
111 dbgfs->dir_drv = debugfs_create_dir(name, NULL);
112 if (!dbgfs->dir_drv) {
113 LOG_ERROR(priv, DEBUGFS, "failed to create debugfs dir\n");
114 return;
115 }
116
117 return;
118}
119
120/**
121 * Remove the debugfs files and directories
122 *
123 */
124void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs)
125{
126 if (!dbgfs)
127 return;
128
129 DEBUGFS_RM(dbgfs->dir_drv);
130 kfree(dbgfs);
131 dbgfs = NULL;
132}
133
diff --git a/drivers/misc/iwmc3200top/debugfs.h b/drivers/misc/iwmc3200top/debugfs.h
new file mode 100644
index 000000000000..71d45759b40f
--- /dev/null
+++ b/drivers/misc/iwmc3200top/debugfs.h
@@ -0,0 +1,58 @@
1/*
2 * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
3 * drivers/misc/iwmc3200top/debufs.h
4 *
5 * Copyright (C) 2009 Intel Corporation. All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version
9 * 2 as 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., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
20 *
21 *
22 * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
23 * -
24 *
25 */
26
27#ifndef __DEBUGFS_H__
28#define __DEBUGFS_H__
29
30
31#ifdef CONFIG_IWMC3200TOP_DEBUGFS
32
33struct iwmct_debugfs {
34 const char *name;
35 struct dentry *dir_drv;
36 struct dir_drv_files {
37 } dbgfs_drv_files;
38};
39
40void iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name);
41void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs);
42
43#else /* CONFIG_IWMC3200TOP_DEBUGFS */
44
45struct iwmct_debugfs;
46
47static inline void
48iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name)
49{}
50
51static inline void
52iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs)
53{}
54
55#endif /* CONFIG_IWMC3200TOP_DEBUGFS */
56
57#endif /* __DEBUGFS_H__ */
58
diff --git a/drivers/misc/iwmc3200top/fw-download.c b/drivers/misc/iwmc3200top/fw-download.c
new file mode 100644
index 000000000000..50d431e469f5
--- /dev/null
+++ b/drivers/misc/iwmc3200top/fw-download.c
@@ -0,0 +1,355 @@
1/*
2 * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
3 * drivers/misc/iwmc3200top/fw-download.c
4 *
5 * Copyright (C) 2009 Intel Corporation. All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version
9 * 2 as 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., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
20 *
21 *
22 * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
23 * -
24 *
25 */
26
27#include <linux/firmware.h>
28#include <linux/mmc/sdio_func.h>
29#include <asm/unaligned.h>
30
31#include "iwmc3200top.h"
32#include "log.h"
33#include "fw-msg.h"
34
35#define CHECKSUM_BYTES_NUM sizeof(u32)
36
37/**
38 init parser struct with file
39 */
40static int iwmct_fw_parser_init(struct iwmct_priv *priv, const u8 *file,
41 size_t file_size, size_t block_size)
42{
43 struct iwmct_parser *parser = &priv->parser;
44 struct iwmct_fw_hdr *fw_hdr = &parser->versions;
45
46 LOG_INFOEX(priv, INIT, "-->\n");
47
48 LOG_INFO(priv, FW_DOWNLOAD, "file_size=%zd\n", file_size);
49
50 parser->file = file;
51 parser->file_size = file_size;
52 parser->cur_pos = 0;
53 parser->buf = NULL;
54
55 parser->buf = kzalloc(block_size, GFP_KERNEL);
56 if (!parser->buf) {
57 LOG_ERROR(priv, FW_DOWNLOAD, "kzalloc error\n");
58 return -ENOMEM;
59 }
60 parser->buf_size = block_size;
61
62 /* extract fw versions */
63 memcpy(fw_hdr, parser->file, sizeof(struct iwmct_fw_hdr));
64 LOG_INFO(priv, FW_DOWNLOAD, "fw versions are:\n"
65 "top %u.%u.%u gps %u.%u.%u bt %u.%u.%u tic %s\n",
66 fw_hdr->top_major, fw_hdr->top_minor, fw_hdr->top_revision,
67 fw_hdr->gps_major, fw_hdr->gps_minor, fw_hdr->gps_revision,
68 fw_hdr->bt_major, fw_hdr->bt_minor, fw_hdr->bt_revision,
69 fw_hdr->tic_name);
70
71 parser->cur_pos += sizeof(struct iwmct_fw_hdr);
72
73 LOG_INFOEX(priv, INIT, "<--\n");
74 return 0;
75}
76
77static bool iwmct_checksum(struct iwmct_priv *priv)
78{
79 struct iwmct_parser *parser = &priv->parser;
80 __le32 *file = (__le32 *)parser->file;
81 int i, pad, steps;
82 u32 accum = 0;
83 u32 checksum;
84 u32 mask = 0xffffffff;
85
86 pad = (parser->file_size - CHECKSUM_BYTES_NUM) % 4;
87 steps = (parser->file_size - CHECKSUM_BYTES_NUM) / 4;
88
89 LOG_INFO(priv, FW_DOWNLOAD, "pad=%d steps=%d\n", pad, steps);
90
91 for (i = 0; i < steps; i++)
92 accum += le32_to_cpu(file[i]);
93
94 if (pad) {
95 mask <<= 8 * (4 - pad);
96 accum += le32_to_cpu(file[steps]) & mask;
97 }
98
99 checksum = get_unaligned_le32((__le32 *)(parser->file +
100 parser->file_size - CHECKSUM_BYTES_NUM));
101
102 LOG_INFO(priv, FW_DOWNLOAD,
103 "compare checksum accum=0x%x to checksum=0x%x\n",
104 accum, checksum);
105
106 return checksum == accum;
107}
108
109static int iwmct_parse_next_section(struct iwmct_priv *priv, const u8 **p_sec,
110 size_t *sec_size, __le32 *sec_addr)
111{
112 struct iwmct_parser *parser = &priv->parser;
113 struct iwmct_dbg *dbg = &priv->dbg;
114 struct iwmct_fw_sec_hdr *sec_hdr;
115
116 LOG_INFOEX(priv, INIT, "-->\n");
117
118 while (parser->cur_pos + sizeof(struct iwmct_fw_sec_hdr)
119 <= parser->file_size) {
120
121 sec_hdr = (struct iwmct_fw_sec_hdr *)
122 (parser->file + parser->cur_pos);
123 parser->cur_pos += sizeof(struct iwmct_fw_sec_hdr);
124
125 LOG_INFO(priv, FW_DOWNLOAD,
126 "sec hdr: type=%s addr=0x%x size=%d\n",
127 sec_hdr->type, sec_hdr->target_addr,
128 sec_hdr->data_size);
129
130 if (strcmp(sec_hdr->type, "ENT") == 0)
131 parser->entry_point = le32_to_cpu(sec_hdr->target_addr);
132 else if (strcmp(sec_hdr->type, "LBL") == 0)
133 strcpy(dbg->label_fw, parser->file + parser->cur_pos);
134 else if (((strcmp(sec_hdr->type, "TOP") == 0) &&
135 (priv->barker & BARKER_DNLOAD_TOP_MSK)) ||
136 ((strcmp(sec_hdr->type, "GPS") == 0) &&
137 (priv->barker & BARKER_DNLOAD_GPS_MSK)) ||
138 ((strcmp(sec_hdr->type, "BTH") == 0) &&
139 (priv->barker & BARKER_DNLOAD_BT_MSK))) {
140 *sec_addr = sec_hdr->target_addr;
141 *sec_size = le32_to_cpu(sec_hdr->data_size);
142 *p_sec = parser->file + parser->cur_pos;
143 parser->cur_pos += le32_to_cpu(sec_hdr->data_size);
144 return 1;
145 } else if (strcmp(sec_hdr->type, "LOG") != 0)
146 LOG_WARNING(priv, FW_DOWNLOAD,
147 "skipping section type %s\n",
148 sec_hdr->type);
149
150 parser->cur_pos += le32_to_cpu(sec_hdr->data_size);
151 LOG_INFO(priv, FW_DOWNLOAD,
152 "finished with section cur_pos=%zd\n", parser->cur_pos);
153 }
154
155 LOG_INFOEX(priv, INIT, "<--\n");
156 return 0;
157}
158
159static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec,
160 size_t sec_size, __le32 addr)
161{
162 struct iwmct_parser *parser = &priv->parser;
163 struct iwmct_fw_load_hdr *hdr = (struct iwmct_fw_load_hdr *)parser->buf;
164 const u8 *cur_block = p_sec;
165 size_t sent = 0;
166 int cnt = 0;
167 int ret = 0;
168 u32 cmd = 0;
169
170 LOG_INFOEX(priv, INIT, "-->\n");
171 LOG_INFO(priv, FW_DOWNLOAD, "Download address 0x%x size 0x%zx\n",
172 addr, sec_size);
173
174 while (sent < sec_size) {
175 int i;
176 u32 chksm = 0;
177 u32 reset = atomic_read(&priv->reset);
178 /* actual FW data */
179 u32 data_size = min(parser->buf_size - sizeof(*hdr),
180 sec_size - sent);
181 /* Pad to block size */
182 u32 trans_size = (data_size + sizeof(*hdr) +
183 IWMC_SDIO_BLK_SIZE - 1) &
184 ~(IWMC_SDIO_BLK_SIZE - 1);
185 ++cnt;
186
187 /* in case of reset, interrupt FW DOWNLAOD */
188 if (reset) {
189 LOG_INFO(priv, FW_DOWNLOAD,
190 "Reset detected. Abort FW download!!!");
191 ret = -ECANCELED;
192 goto exit;
193 }
194
195 memset(parser->buf, 0, parser->buf_size);
196 cmd |= IWMC_OPCODE_WRITE << CMD_HDR_OPCODE_POS;
197 cmd |= IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS;
198 cmd |= (priv->dbg.direct ? 1 : 0) << CMD_HDR_DIRECT_ACCESS_POS;
199 cmd |= (priv->dbg.checksum ? 1 : 0) << CMD_HDR_USE_CHECKSUM_POS;
200 hdr->data_size = cpu_to_le32(data_size);
201 hdr->target_addr = addr;
202
203 /* checksum is allowed for sizes divisible by 4 */
204 if (data_size & 0x3)
205 cmd &= ~CMD_HDR_USE_CHECKSUM_MSK;
206
207 memcpy(hdr->data, cur_block, data_size);
208
209
210 if (cmd & CMD_HDR_USE_CHECKSUM_MSK) {
211
212 chksm = data_size + le32_to_cpu(addr) + cmd;
213 for (i = 0; i < data_size >> 2; i++)
214 chksm += ((u32 *)cur_block)[i];
215
216 hdr->block_chksm = cpu_to_le32(chksm);
217 LOG_INFO(priv, FW_DOWNLOAD, "Checksum = 0x%X\n",
218 hdr->block_chksm);
219 }
220
221 LOG_INFO(priv, FW_DOWNLOAD, "trans#%d, len=%d, sent=%zd, "
222 "sec_size=%zd, startAddress 0x%X\n",
223 cnt, trans_size, sent, sec_size, addr);
224
225 if (priv->dbg.dump)
226 LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, trans_size);
227
228
229 hdr->cmd = cpu_to_le32(cmd);
230 /* send it down */
231 /* TODO: add more proper sending and error checking */
232 ret = iwmct_tx(priv, 0, parser->buf, trans_size);
233 if (ret != 0) {
234 LOG_INFO(priv, FW_DOWNLOAD,
235 "iwmct_tx returned %d\n", ret);
236 goto exit;
237 }
238
239 addr = cpu_to_le32(le32_to_cpu(addr) + data_size);
240 sent += data_size;
241 cur_block = p_sec + sent;
242
243 if (priv->dbg.blocks && (cnt + 1) >= priv->dbg.blocks) {
244 LOG_INFO(priv, FW_DOWNLOAD,
245 "Block number limit is reached [%d]\n",
246 priv->dbg.blocks);
247 break;
248 }
249 }
250
251 if (sent < sec_size)
252 ret = -EINVAL;
253exit:
254 LOG_INFOEX(priv, INIT, "<--\n");
255 return ret;
256}
257
258static int iwmct_kick_fw(struct iwmct_priv *priv, bool jump)
259{
260 struct iwmct_parser *parser = &priv->parser;
261 struct iwmct_fw_load_hdr *hdr = (struct iwmct_fw_load_hdr *)parser->buf;
262 int ret;
263 u32 cmd;
264
265 LOG_INFOEX(priv, INIT, "-->\n");
266
267 memset(parser->buf, 0, parser->buf_size);
268 cmd = IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS;
269 if (jump) {
270 cmd |= IWMC_OPCODE_JUMP << CMD_HDR_OPCODE_POS;
271 hdr->target_addr = cpu_to_le32(parser->entry_point);
272 LOG_INFO(priv, FW_DOWNLOAD, "jump address 0x%x\n",
273 parser->entry_point);
274 } else {
275 cmd |= IWMC_OPCODE_LAST_COMMAND << CMD_HDR_OPCODE_POS;
276 LOG_INFO(priv, FW_DOWNLOAD, "last command\n");
277 }
278
279 hdr->cmd = cpu_to_le32(cmd);
280
281 LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, sizeof(*hdr));
282 /* send it down */
283 /* TODO: add more proper sending and error checking */
284 ret = iwmct_tx(priv, 0, parser->buf, IWMC_SDIO_BLK_SIZE);
285 if (ret)
286 LOG_INFO(priv, FW_DOWNLOAD, "iwmct_tx returned %d", ret);
287
288 LOG_INFOEX(priv, INIT, "<--\n");
289 return 0;
290}
291
292int iwmct_fw_load(struct iwmct_priv *priv)
293{
294 const u8 *fw_name = FW_NAME(FW_API_VER);
295 const struct firmware *raw;
296 const u8 *pdata;
297 size_t len;
298 __le32 addr;
299 int ret;
300
301 /* clear parser struct */
302 memset(&priv->parser, 0, sizeof(struct iwmct_parser));
303
304 /* get the firmware */
305 ret = request_firmware(&raw, fw_name, &priv->func->dev);
306 if (ret < 0) {
307 LOG_ERROR(priv, FW_DOWNLOAD, "%s request_firmware failed %d\n",
308 fw_name, ret);
309 goto exit;
310 }
311
312 if (raw->size < sizeof(struct iwmct_fw_sec_hdr)) {
313 LOG_ERROR(priv, FW_DOWNLOAD, "%s smaller then (%zd) (%zd)\n",
314 fw_name, sizeof(struct iwmct_fw_sec_hdr), raw->size);
315 goto exit;
316 }
317
318 LOG_INFO(priv, FW_DOWNLOAD, "Read firmware '%s'\n", fw_name);
319
320 ret = iwmct_fw_parser_init(priv, raw->data, raw->size, priv->trans_len);
321 if (ret < 0) {
322 LOG_ERROR(priv, FW_DOWNLOAD,
323 "iwmct_parser_init failed: Reason %d\n", ret);
324 goto exit;
325 }
326
327 /* checksum */
328 if (!iwmct_checksum(priv)) {
329 LOG_ERROR(priv, FW_DOWNLOAD, "checksum error\n");
330 ret = -EINVAL;
331 goto exit;
332 }
333
334 /* download firmware to device */
335 while (iwmct_parse_next_section(priv, &pdata, &len, &addr)) {
336 if (iwmct_download_section(priv, pdata, len, addr)) {
337 LOG_ERROR(priv, FW_DOWNLOAD,
338 "%s download section failed\n", fw_name);
339 ret = -EIO;
340 goto exit;
341 }
342 }
343
344 iwmct_kick_fw(priv, !!(priv->barker & BARKER_DNLOAD_JUMP_MSK));
345
346exit:
347 kfree(priv->parser.buf);
348
349 if (raw)
350 release_firmware(raw);
351
352 raw = NULL;
353
354 return ret;
355}
diff --git a/drivers/misc/iwmc3200top/fw-msg.h b/drivers/misc/iwmc3200top/fw-msg.h
new file mode 100644
index 000000000000..9e26b75bd482
--- /dev/null
+++ b/drivers/misc/iwmc3200top/fw-msg.h
@@ -0,0 +1,113 @@
1/*
2 * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
3 * drivers/misc/iwmc3200top/fw-msg.h
4 *
5 * Copyright (C) 2009 Intel Corporation. All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version
9 * 2 as 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., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
20 *
21 *
22 * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
23 * -
24 *
25 */
26
27#ifndef __FWMSG_H__
28#define __FWMSG_H__
29
30#define COMM_TYPE_D2H 0xFF
31#define COMM_TYPE_H2D 0xEE
32
33#define COMM_CATEGORY_OPERATIONAL 0x00
34#define COMM_CATEGORY_DEBUG 0x01
35#define COMM_CATEGORY_TESTABILITY 0x02
36#define COMM_CATEGORY_DIAGNOSTICS 0x03
37
38#define OP_DBG_ZSTR_MSG cpu_to_le16(0x1A)
39
40#define FW_LOG_SRC_MAX 32
41#define FW_LOG_SRC_ALL 255
42
43#define FW_STRING_TABLE_ADDR cpu_to_le32(0x0C000000)
44
45#define CMD_DBG_LOG_LEVEL cpu_to_le16(0x0001)
46#define CMD_TST_DEV_RESET cpu_to_le16(0x0060)
47#define CMD_TST_FUNC_RESET cpu_to_le16(0x0062)
48#define CMD_TST_IFACE_RESET cpu_to_le16(0x0064)
49#define CMD_TST_CPU_UTILIZATION cpu_to_le16(0x0065)
50#define CMD_TST_TOP_DEEP_SLEEP cpu_to_le16(0x0080)
51#define CMD_TST_WAKEUP cpu_to_le16(0x0081)
52#define CMD_TST_FUNC_WAKEUP cpu_to_le16(0x0082)
53#define CMD_TST_FUNC_DEEP_SLEEP_REQUEST cpu_to_le16(0x0083)
54#define CMD_TST_GET_MEM_DUMP cpu_to_le16(0x0096)
55
56#define OP_OPR_ALIVE cpu_to_le16(0x0010)
57#define OP_OPR_CMD_ACK cpu_to_le16(0x001F)
58#define OP_OPR_CMD_NACK cpu_to_le16(0x0020)
59#define OP_TST_MEM_DUMP cpu_to_le16(0x0043)
60
61#define CMD_FLAG_PADDING_256 0x80
62
63#define FW_HCMD_BLOCK_SIZE 256
64
65struct msg_hdr {
66 u8 type;
67 u8 category;
68 __le16 opcode;
69 u8 seqnum;
70 u8 flags;
71 __le16 length;
72} __attribute__((__packed__));
73
74struct log_hdr {
75 __le32 timestamp;
76 u8 severity;
77 u8 logsource;
78 __le16 reserved;
79} __attribute__((__packed__));
80
81struct mdump_hdr {
82 u8 dmpid;
83 u8 frag;
84 __le16 size;
85 __le32 addr;
86} __attribute__((__packed__));
87
88struct top_msg {
89 struct msg_hdr hdr;
90 union {
91 /* D2H messages */
92 struct {
93 struct log_hdr log_hdr;
94 u8 data[1];
95 } __attribute__((__packed__)) log;
96
97 struct {
98 struct log_hdr log_hdr;
99 struct mdump_hdr md_hdr;
100 u8 data[1];
101 } __attribute__((__packed__)) mdump;
102
103 /* H2D messages */
104 struct {
105 u8 logsource;
106 u8 sevmask;
107 } __attribute__((__packed__)) logdefs[FW_LOG_SRC_MAX];
108 struct mdump_hdr mdump_req;
109 } u;
110} __attribute__((__packed__));
111
112
113#endif /* __FWMSG_H__ */
diff --git a/drivers/misc/iwmc3200top/iwmc3200top.h b/drivers/misc/iwmc3200top/iwmc3200top.h
new file mode 100644
index 000000000000..43bd510e1872
--- /dev/null
+++ b/drivers/misc/iwmc3200top/iwmc3200top.h
@@ -0,0 +1,209 @@
1/*
2 * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
3 * drivers/misc/iwmc3200top/iwmc3200top.h
4 *
5 * Copyright (C) 2009 Intel Corporation. All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version
9 * 2 as 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., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
20 *
21 *
22 * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
23 * -
24 *
25 */
26
27#ifndef __IWMC3200TOP_H__
28#define __IWMC3200TOP_H__
29
30#include <linux/workqueue.h>
31
32#define DRV_NAME "iwmc3200top"
33#define FW_API_VER 1
34#define _FW_NAME(api) DRV_NAME "." #api ".fw"
35#define FW_NAME(api) _FW_NAME(api)
36
37#define IWMC_SDIO_BLK_SIZE 256
38#define IWMC_DEFAULT_TR_BLK 64
39#define IWMC_SDIO_DATA_ADDR 0x0
40#define IWMC_SDIO_INTR_ENABLE_ADDR 0x14
41#define IWMC_SDIO_INTR_STATUS_ADDR 0x13
42#define IWMC_SDIO_INTR_CLEAR_ADDR 0x13
43#define IWMC_SDIO_INTR_GET_SIZE_ADDR 0x2C
44
45#define COMM_HUB_HEADER_LENGTH 16
46#define LOGGER_HEADER_LENGTH 10
47
48
49#define BARKER_DNLOAD_BT_POS 0
50#define BARKER_DNLOAD_BT_MSK BIT(BARKER_DNLOAD_BT_POS)
51#define BARKER_DNLOAD_GPS_POS 1
52#define BARKER_DNLOAD_GPS_MSK BIT(BARKER_DNLOAD_GPS_POS)
53#define BARKER_DNLOAD_TOP_POS 2
54#define BARKER_DNLOAD_TOP_MSK BIT(BARKER_DNLOAD_TOP_POS)
55#define BARKER_DNLOAD_RESERVED1_POS 3
56#define BARKER_DNLOAD_RESERVED1_MSK BIT(BARKER_DNLOAD_RESERVED1_POS)
57#define BARKER_DNLOAD_JUMP_POS 4
58#define BARKER_DNLOAD_JUMP_MSK BIT(BARKER_DNLOAD_JUMP_POS)
59#define BARKER_DNLOAD_SYNC_POS 5
60#define BARKER_DNLOAD_SYNC_MSK BIT(BARKER_DNLOAD_SYNC_POS)
61#define BARKER_DNLOAD_RESERVED2_POS 6
62#define BARKER_DNLOAD_RESERVED2_MSK (0x3 << BARKER_DNLOAD_RESERVED2_POS)
63#define BARKER_DNLOAD_BARKER_POS 8
64#define BARKER_DNLOAD_BARKER_MSK (0xffffff << BARKER_DNLOAD_BARKER_POS)
65
66#define IWMC_BARKER_REBOOT (0xdeadbe << BARKER_DNLOAD_BARKER_POS)
67/* whole field barker */
68#define IWMC_BARKER_ACK 0xfeedbabe
69
70#define IWMC_CMD_SIGNATURE 0xcbbc
71
72#define CMD_HDR_OPCODE_POS 0
73#define CMD_HDR_OPCODE_MSK_MSK (0xf << CMD_HDR_OPCODE_MSK_POS)
74#define CMD_HDR_RESPONSE_CODE_POS 4
75#define CMD_HDR_RESPONSE_CODE_MSK (0xf << CMD_HDR_RESPONSE_CODE_POS)
76#define CMD_HDR_USE_CHECKSUM_POS 8
77#define CMD_HDR_USE_CHECKSUM_MSK BIT(CMD_HDR_USE_CHECKSUM_POS)
78#define CMD_HDR_RESPONSE_REQUIRED_POS 9
79#define CMD_HDR_RESPONSE_REQUIRED_MSK BIT(CMD_HDR_RESPONSE_REQUIRED_POS)
80#define CMD_HDR_DIRECT_ACCESS_POS 10
81#define CMD_HDR_DIRECT_ACCESS_MSK BIT(CMD_HDR_DIRECT_ACCESS_POS)
82#define CMD_HDR_RESERVED_POS 11
83#define CMD_HDR_RESERVED_MSK BIT(0x1f << CMD_HDR_RESERVED_POS)
84#define CMD_HDR_SIGNATURE_POS 16
85#define CMD_HDR_SIGNATURE_MSK BIT(0xffff << CMD_HDR_SIGNATURE_POS)
86
87enum {
88 IWMC_OPCODE_PING = 0,
89 IWMC_OPCODE_READ = 1,
90 IWMC_OPCODE_WRITE = 2,
91 IWMC_OPCODE_JUMP = 3,
92 IWMC_OPCODE_REBOOT = 4,
93 IWMC_OPCODE_PERSISTENT_WRITE = 5,
94 IWMC_OPCODE_PERSISTENT_READ = 6,
95 IWMC_OPCODE_READ_MODIFY_WRITE = 7,
96 IWMC_OPCODE_LAST_COMMAND = 15
97};
98
99struct iwmct_fw_load_hdr {
100 __le32 cmd;
101 __le32 target_addr;
102 __le32 data_size;
103 __le32 block_chksm;
104 u8 data[0];
105};
106
107/**
108 * struct iwmct_fw_hdr
109 * holds all sw components versions
110 */
111struct iwmct_fw_hdr {
112 u8 top_major;
113 u8 top_minor;
114 u8 top_revision;
115 u8 gps_major;
116 u8 gps_minor;
117 u8 gps_revision;
118 u8 bt_major;
119 u8 bt_minor;
120 u8 bt_revision;
121 u8 tic_name[31];
122};
123
124/**
125 * struct iwmct_fw_sec_hdr
126 * @type: function type
127 * @data_size: section's data size
128 * @target_addr: download address
129 */
130struct iwmct_fw_sec_hdr {
131 u8 type[4];
132 __le32 data_size;
133 __le32 target_addr;
134};
135
136/**
137 * struct iwmct_parser
138 * @file: fw image
139 * @file_size: fw size
140 * @cur_pos: position in file
141 * @buf: temp buf for download
142 * @buf_size: size of buf
143 * @entry_point: address to jump in fw kick-off
144 */
145struct iwmct_parser {
146 const u8 *file;
147 size_t file_size;
148 size_t cur_pos;
149 u8 *buf;
150 size_t buf_size;
151 u32 entry_point;
152 struct iwmct_fw_hdr versions;
153};
154
155
156struct iwmct_work_struct {
157 struct list_head list;
158 ssize_t iosize;
159};
160
161struct iwmct_dbg {
162 int blocks;
163 bool dump;
164 bool jump;
165 bool direct;
166 bool checksum;
167 bool fw_download;
168 int block_size;
169 int download_trans_blks;
170
171 char label_fw[256];
172};
173
174struct iwmct_debugfs;
175
176struct iwmct_priv {
177 struct sdio_func *func;
178 struct iwmct_debugfs *dbgfs;
179 struct iwmct_parser parser;
180 atomic_t reset;
181 atomic_t dev_sync;
182 u32 trans_len;
183 u32 barker;
184 struct iwmct_dbg dbg;
185
186 /* drivers work queue */
187 struct workqueue_struct *wq;
188 struct workqueue_struct *bus_rescan_wq;
189 struct work_struct bus_rescan_worker;
190 struct work_struct isr_worker;
191
192 /* drivers wait queue */
193 wait_queue_head_t wait_q;
194
195 /* rx request list */
196 struct list_head read_req_list;
197};
198
199extern int iwmct_tx(struct iwmct_priv *priv, unsigned int addr,
200 void *src, int count);
201
202extern int iwmct_fw_load(struct iwmct_priv *priv);
203
204extern void iwmct_dbg_init_params(struct iwmct_priv *drv);
205extern void iwmct_dbg_init_drv_attrs(struct device_driver *drv);
206extern void iwmct_dbg_remove_drv_attrs(struct device_driver *drv);
207extern int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len);
208
209#endif /* __IWMC3200TOP_H__ */
diff --git a/drivers/misc/iwmc3200top/log.c b/drivers/misc/iwmc3200top/log.c
new file mode 100644
index 000000000000..d569279698f6
--- /dev/null
+++ b/drivers/misc/iwmc3200top/log.c
@@ -0,0 +1,347 @@
1/*
2 * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
3 * drivers/misc/iwmc3200top/log.c
4 *
5 * Copyright (C) 2009 Intel Corporation. All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version
9 * 2 as 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., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
20 *
21 *
22 * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
23 * -
24 *
25 */
26
27#include <linux/kernel.h>
28#include <linux/mmc/sdio_func.h>
29#include <linux/ctype.h>
30#include "fw-msg.h"
31#include "iwmc3200top.h"
32#include "log.h"
33
34/* Maximal hexadecimal string size of the FW memdump message */
35#define LOG_MSG_SIZE_MAX 12400
36
37/* iwmct_logdefs is a global used by log macros */
38u8 iwmct_logdefs[LOG_SRC_MAX];
39static u8 iwmct_fw_logdefs[FW_LOG_SRC_MAX];
40
41
42static int _log_set_log_filter(u8 *logdefs, int size, u8 src, u8 logmask)
43{
44 int i;
45
46 if (src < size)
47 logdefs[src] = logmask;
48 else if (src == LOG_SRC_ALL)
49 for (i = 0; i < size; i++)
50 logdefs[i] = logmask;
51 else
52 return -1;
53
54 return 0;
55}
56
57
58int iwmct_log_set_filter(u8 src, u8 logmask)
59{
60 return _log_set_log_filter(iwmct_logdefs, LOG_SRC_MAX, src, logmask);
61}
62
63
64int iwmct_log_set_fw_filter(u8 src, u8 logmask)
65{
66 return _log_set_log_filter(iwmct_fw_logdefs,
67 FW_LOG_SRC_MAX, src, logmask);
68}
69
70
71static int log_msg_format_hex(char *str, int slen, u8 *ibuf,
72 int ilen, char *pref)
73{
74 int pos = 0;
75 int i;
76 int len;
77
78 for (pos = 0, i = 0; pos < slen - 2 && pref[i] != '\0'; i++, pos++)
79 str[pos] = pref[i];
80
81 for (i = 0; pos < slen - 2 && i < ilen; pos += len, i++)
82 len = snprintf(&str[pos], slen - pos - 1, " %2.2X", ibuf[i]);
83
84 if (i < ilen)
85 return -1;
86
87 return 0;
88}
89
90/* NOTE: This function is not thread safe.
91 Currently it's called only from sdio rx worker - no race there
92*/
93void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len)
94{
95 struct top_msg *msg;
96 static char logbuf[LOG_MSG_SIZE_MAX];
97
98 msg = (struct top_msg *)buf;
99
100 if (len < sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr)) {
101 LOG_ERROR(priv, FW_MSG, "Log message from TOP "
102 "is too short %d (expected %zd)\n",
103 len, sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr));
104 return;
105 }
106
107 if (!(iwmct_fw_logdefs[msg->u.log.log_hdr.logsource] &
108 BIT(msg->u.log.log_hdr.severity)) ||
109 !(iwmct_logdefs[LOG_SRC_FW_MSG] & BIT(msg->u.log.log_hdr.severity)))
110 return;
111
112 switch (msg->hdr.category) {
113 case COMM_CATEGORY_TESTABILITY:
114 if (!(iwmct_logdefs[LOG_SRC_TST] &
115 BIT(msg->u.log.log_hdr.severity)))
116 return;
117 if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf,
118 le16_to_cpu(msg->hdr.length) +
119 sizeof(msg->hdr), "<TST>"))
120 LOG_WARNING(priv, TST,
121 "TOP TST message is too long, truncating...");
122 LOG_WARNING(priv, TST, "%s\n", logbuf);
123 break;
124 case COMM_CATEGORY_DEBUG:
125 if (msg->hdr.opcode == OP_DBG_ZSTR_MSG)
126 LOG_INFO(priv, FW_MSG, "%s %s", "<DBG>",
127 ((u8 *)msg) + sizeof(msg->hdr)
128 + sizeof(msg->u.log.log_hdr));
129 else {
130 if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf,
131 le16_to_cpu(msg->hdr.length)
132 + sizeof(msg->hdr),
133 "<DBG>"))
134 LOG_WARNING(priv, FW_MSG,
135 "TOP DBG message is too long,"
136 "truncating...");
137 LOG_WARNING(priv, FW_MSG, "%s\n", logbuf);
138 }
139 break;
140 default:
141 break;
142 }
143}
144
145static int _log_get_filter_str(u8 *logdefs, int logdefsz, char *buf, int size)
146{
147 int i, pos, len;
148 for (i = 0, pos = 0; (pos < size-1) && (i < logdefsz); i++) {
149 len = snprintf(&buf[pos], size - pos - 1, "0x%02X%02X,",
150 i, logdefs[i]);
151 pos += len;
152 }
153 buf[pos-1] = '\n';
154 buf[pos] = '\0';
155
156 if (i < logdefsz)
157 return -1;
158 return 0;
159}
160
161int log_get_filter_str(char *buf, int size)
162{
163 return _log_get_filter_str(iwmct_logdefs, LOG_SRC_MAX, buf, size);
164}
165
166int log_get_fw_filter_str(char *buf, int size)
167{
168 return _log_get_filter_str(iwmct_fw_logdefs, FW_LOG_SRC_MAX, buf, size);
169}
170
171#define HEXADECIMAL_RADIX 16
172#define LOG_SRC_FORMAT 7 /* log level is in format of "0xXXXX," */
173
174ssize_t show_iwmct_log_level(struct device *d,
175 struct device_attribute *attr, char *buf)
176{
177 struct iwmct_priv *priv = dev_get_drvdata(d);
178 char *str_buf;
179 int buf_size;
180 ssize_t ret;
181
182 buf_size = (LOG_SRC_FORMAT * LOG_SRC_MAX) + 1;
183 str_buf = kzalloc(buf_size, GFP_KERNEL);
184 if (!str_buf) {
185 LOG_ERROR(priv, DEBUGFS,
186 "failed to allocate %d bytes\n", buf_size);
187 ret = -ENOMEM;
188 goto exit;
189 }
190
191 if (log_get_filter_str(str_buf, buf_size) < 0) {
192 ret = -EINVAL;
193 goto exit;
194 }
195
196 ret = sprintf(buf, "%s", str_buf);
197
198exit:
199 kfree(str_buf);
200 return ret;
201}
202
203ssize_t store_iwmct_log_level(struct device *d,
204 struct device_attribute *attr,
205 const char *buf, size_t count)
206{
207 struct iwmct_priv *priv = dev_get_drvdata(d);
208 char *token, *str_buf = NULL;
209 long val;
210 ssize_t ret = count;
211 u8 src, mask;
212
213 if (!count)
214 goto exit;
215
216 str_buf = kzalloc(count, GFP_KERNEL);
217 if (!str_buf) {
218 LOG_ERROR(priv, DEBUGFS,
219 "failed to allocate %zd bytes\n", count);
220 ret = -ENOMEM;
221 goto exit;
222 }
223
224 memcpy(str_buf, buf, count);
225
226 while ((token = strsep(&str_buf, ",")) != NULL) {
227 while (isspace(*token))
228 ++token;
229 if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) {
230 LOG_ERROR(priv, DEBUGFS,
231 "failed to convert string to long %s\n",
232 token);
233 ret = -EINVAL;
234 goto exit;
235 }
236
237 mask = val & 0xFF;
238 src = (val & 0XFF00) >> 8;
239 iwmct_log_set_filter(src, mask);
240 }
241
242exit:
243 kfree(str_buf);
244 return ret;
245}
246
247ssize_t show_iwmct_log_level_fw(struct device *d,
248 struct device_attribute *attr, char *buf)
249{
250 struct iwmct_priv *priv = dev_get_drvdata(d);
251 char *str_buf;
252 int buf_size;
253 ssize_t ret;
254
255 buf_size = (LOG_SRC_FORMAT * FW_LOG_SRC_MAX) + 2;
256
257 str_buf = kzalloc(buf_size, GFP_KERNEL);
258 if (!str_buf) {
259 LOG_ERROR(priv, DEBUGFS,
260 "failed to allocate %d bytes\n", buf_size);
261 ret = -ENOMEM;
262 goto exit;
263 }
264
265 if (log_get_fw_filter_str(str_buf, buf_size) < 0) {
266 ret = -EINVAL;
267 goto exit;
268 }
269
270 ret = sprintf(buf, "%s", str_buf);
271
272exit:
273 kfree(str_buf);
274 return ret;
275}
276
277ssize_t store_iwmct_log_level_fw(struct device *d,
278 struct device_attribute *attr,
279 const char *buf, size_t count)
280{
281 struct iwmct_priv *priv = dev_get_drvdata(d);
282 struct top_msg cmd;
283 char *token, *str_buf = NULL;
284 ssize_t ret = count;
285 u16 cmdlen = 0;
286 int i;
287 long val;
288 u8 src, mask;
289
290 if (!count)
291 goto exit;
292
293 str_buf = kzalloc(count, GFP_KERNEL);
294 if (!str_buf) {
295 LOG_ERROR(priv, DEBUGFS,
296 "failed to allocate %zd bytes\n", count);
297 ret = -ENOMEM;
298 goto exit;
299 }
300
301 memcpy(str_buf, buf, count);
302
303 cmd.hdr.type = COMM_TYPE_H2D;
304 cmd.hdr.category = COMM_CATEGORY_DEBUG;
305 cmd.hdr.opcode = CMD_DBG_LOG_LEVEL;
306
307 for (i = 0; ((token = strsep(&str_buf, ",")) != NULL) &&
308 (i < FW_LOG_SRC_MAX); i++) {
309
310 while (isspace(*token))
311 ++token;
312
313 if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) {
314 LOG_ERROR(priv, DEBUGFS,
315 "failed to convert string to long %s\n",
316 token);
317 ret = -EINVAL;
318 goto exit;
319 }
320
321 mask = val & 0xFF; /* LSB */
322 src = (val & 0XFF00) >> 8; /* 2nd least significant byte. */
323 iwmct_log_set_fw_filter(src, mask);
324
325 cmd.u.logdefs[i].logsource = src;
326 cmd.u.logdefs[i].sevmask = mask;
327 }
328
329 cmd.hdr.length = cpu_to_le16(i * sizeof(cmd.u.logdefs[0]));
330 cmdlen = (i * sizeof(cmd.u.logdefs[0]) + sizeof(cmd.hdr));
331
332 ret = iwmct_send_hcmd(priv, (u8 *)&cmd, cmdlen);
333 if (ret) {
334 LOG_ERROR(priv, DEBUGFS,
335 "Failed to send %d bytes of fwcmd, ret=%zd\n",
336 cmdlen, ret);
337 goto exit;
338 } else
339 LOG_INFO(priv, DEBUGFS, "fwcmd sent (%d bytes)\n", cmdlen);
340
341 ret = count;
342
343exit:
344 kfree(str_buf);
345 return ret;
346}
347
diff --git a/drivers/misc/iwmc3200top/log.h b/drivers/misc/iwmc3200top/log.h
new file mode 100644
index 000000000000..aba8121f978c
--- /dev/null
+++ b/drivers/misc/iwmc3200top/log.h
@@ -0,0 +1,158 @@
1/*
2 * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
3 * drivers/misc/iwmc3200top/log.h
4 *
5 * Copyright (C) 2009 Intel Corporation. All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version
9 * 2 as 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., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
20 *
21 *
22 * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
23 * -
24 *
25 */
26
27#ifndef __LOG_H__
28#define __LOG_H__
29
30
31/* log severity:
32 * The log levels here match FW log levels
33 * so values need to stay as is */
34#define LOG_SEV_CRITICAL 0
35#define LOG_SEV_ERROR 1
36#define LOG_SEV_WARNING 2
37#define LOG_SEV_INFO 3
38#define LOG_SEV_INFOEX 4
39
40#define LOG_SEV_FILTER_ALL \
41 (BIT(LOG_SEV_CRITICAL) | \
42 BIT(LOG_SEV_ERROR) | \
43 BIT(LOG_SEV_WARNING) | \
44 BIT(LOG_SEV_INFO) | \
45 BIT(LOG_SEV_INFOEX))
46
47/* log source */
48#define LOG_SRC_INIT 0
49#define LOG_SRC_DEBUGFS 1
50#define LOG_SRC_FW_DOWNLOAD 2
51#define LOG_SRC_FW_MSG 3
52#define LOG_SRC_TST 4
53#define LOG_SRC_IRQ 5
54
55#define LOG_SRC_MAX 6
56#define LOG_SRC_ALL 0xFF
57
58/**
59 * Default intitialization runtime log level
60 */
61#ifndef LOG_SEV_FILTER_RUNTIME
62#define LOG_SEV_FILTER_RUNTIME \
63 (BIT(LOG_SEV_CRITICAL) | \
64 BIT(LOG_SEV_ERROR) | \
65 BIT(LOG_SEV_WARNING))
66#endif
67
68#ifndef FW_LOG_SEV_FILTER_RUNTIME
69#define FW_LOG_SEV_FILTER_RUNTIME LOG_SEV_FILTER_ALL
70#endif
71
72#ifdef CONFIG_IWMC3200TOP_DEBUG
73/**
74 * Log macros
75 */
76
77#define priv2dev(priv) (&(priv->func)->dev)
78
79#define LOG_CRITICAL(priv, src, fmt, args...) \
80do { \
81 if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_CRITICAL)) \
82 dev_crit(priv2dev(priv), "%s %d: " fmt, \
83 __func__, __LINE__, ##args); \
84} while (0)
85
86#define LOG_ERROR(priv, src, fmt, args...) \
87do { \
88 if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_ERROR)) \
89 dev_err(priv2dev(priv), "%s %d: " fmt, \
90 __func__, __LINE__, ##args); \
91} while (0)
92
93#define LOG_WARNING(priv, src, fmt, args...) \
94do { \
95 if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_WARNING)) \
96 dev_warn(priv2dev(priv), "%s %d: " fmt, \
97 __func__, __LINE__, ##args); \
98} while (0)
99
100#define LOG_INFO(priv, src, fmt, args...) \
101do { \
102 if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFO)) \
103 dev_info(priv2dev(priv), "%s %d: " fmt, \
104 __func__, __LINE__, ##args); \
105} while (0)
106
107#define LOG_INFOEX(priv, src, fmt, args...) \
108do { \
109 if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFOEX)) \
110 dev_dbg(priv2dev(priv), "%s %d: " fmt, \
111 __func__, __LINE__, ##args); \
112} while (0)
113
114#define LOG_HEXDUMP(src, ptr, len) \
115do { \
116 if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFOEX)) \
117 print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, \
118 16, 1, ptr, len, false); \
119} while (0)
120
121void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len);
122
123extern u8 iwmct_logdefs[];
124
125int iwmct_log_set_filter(u8 src, u8 logmask);
126int iwmct_log_set_fw_filter(u8 src, u8 logmask);
127
128ssize_t show_iwmct_log_level(struct device *d,
129 struct device_attribute *attr, char *buf);
130ssize_t store_iwmct_log_level(struct device *d,
131 struct device_attribute *attr,
132 const char *buf, size_t count);
133ssize_t show_iwmct_log_level_fw(struct device *d,
134 struct device_attribute *attr, char *buf);
135ssize_t store_iwmct_log_level_fw(struct device *d,
136 struct device_attribute *attr,
137 const char *buf, size_t count);
138
139#else
140
141#define LOG_CRITICAL(priv, src, fmt, args...)
142#define LOG_ERROR(priv, src, fmt, args...)
143#define LOG_WARNING(priv, src, fmt, args...)
144#define LOG_INFO(priv, src, fmt, args...)
145#define LOG_INFOEX(priv, src, fmt, args...)
146#define LOG_HEXDUMP(src, ptr, len)
147
148static inline void iwmct_log_top_message(struct iwmct_priv *priv,
149 u8 *buf, int len) {}
150static inline int iwmct_log_set_filter(u8 src, u8 logmask) { return 0; }
151static inline int iwmct_log_set_fw_filter(u8 src, u8 logmask) { return 0; }
152
153#endif /* CONFIG_IWMC3200TOP_DEBUG */
154
155int log_get_filter_str(char *buf, int size);
156int log_get_fw_filter_str(char *buf, int size);
157
158#endif /* __LOG_H__ */
diff --git a/drivers/misc/iwmc3200top/main.c b/drivers/misc/iwmc3200top/main.c
new file mode 100644
index 000000000000..fafcaa481d74
--- /dev/null
+++ b/drivers/misc/iwmc3200top/main.c
@@ -0,0 +1,678 @@
1/*
2 * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
3 * drivers/misc/iwmc3200top/main.c
4 *
5 * Copyright (C) 2009 Intel Corporation. All rights reserved.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License version
9 * 2 as 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., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
20 *
21 *
22 * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
23 * -
24 *
25 */
26
27#include <linux/module.h>
28#include <linux/init.h>
29#include <linux/kernel.h>
30#include <linux/debugfs.h>
31#include <linux/mmc/sdio_ids.h>
32#include <linux/mmc/sdio_func.h>
33#include <linux/mmc/sdio.h>
34
35#include "iwmc3200top.h"
36#include "log.h"
37#include "fw-msg.h"
38#include "debugfs.h"
39
40
41#define DRIVER_DESCRIPTION "Intel(R) IWMC 3200 Top Driver"
42#define DRIVER_COPYRIGHT "Copyright (c) 2008 Intel Corporation."
43
44#define DRIVER_VERSION "0.1.62"
45
46MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
47MODULE_VERSION(DRIVER_VERSION);
48MODULE_LICENSE("GPL");
49MODULE_AUTHOR(DRIVER_COPYRIGHT);
50MODULE_FIRMWARE(FW_NAME(FW_API_VER));
51
52/*
53 * This workers main task is to wait for OP_OPR_ALIVE
54 * from TOP FW until ALIVE_MSG_TIMOUT timeout is elapsed.
55 * When OP_OPR_ALIVE received it will issue
56 * a call to "bus_rescan_devices".
57 */
58static void iwmct_rescan_worker(struct work_struct *ws)
59{
60 struct iwmct_priv *priv;
61 int ret;
62
63 priv = container_of(ws, struct iwmct_priv, bus_rescan_worker);
64
65 LOG_INFO(priv, FW_MSG, "Calling bus_rescan\n");
66
67 ret = bus_rescan_devices(priv->func->dev.bus);
68 if (ret < 0)
69 LOG_INFO(priv, FW_DOWNLOAD, "bus_rescan_devices FAILED!!!\n");
70}
71
72static void op_top_message(struct iwmct_priv *priv, struct top_msg *msg)
73{
74 switch (msg->hdr.opcode) {
75 case OP_OPR_ALIVE:
76 LOG_INFO(priv, FW_MSG, "Got ALIVE from device, wake rescan\n");
77 queue_work(priv->bus_rescan_wq, &priv->bus_rescan_worker);
78 break;
79 default:
80 LOG_INFO(priv, FW_MSG, "Received msg opcode 0x%X\n",
81 msg->hdr.opcode);
82 break;
83 }
84}
85
86
87static void handle_top_message(struct iwmct_priv *priv, u8 *buf, int len)
88{
89 struct top_msg *msg;
90
91 msg = (struct top_msg *)buf;
92
93 if (msg->hdr.type != COMM_TYPE_D2H) {
94 LOG_ERROR(priv, FW_MSG,
95 "Message from TOP with invalid message type 0x%X\n",
96 msg->hdr.type);
97 return;
98 }
99
100 if (len < sizeof(msg->hdr)) {
101 LOG_ERROR(priv, FW_MSG,
102 "Message from TOP is too short for message header "
103 "received %d bytes, expected at least %zd bytes\n",
104 len, sizeof(msg->hdr));
105 return;
106 }
107
108 if (len < le16_to_cpu(msg->hdr.length) + sizeof(msg->hdr)) {
109 LOG_ERROR(priv, FW_MSG,
110 "Message length (%d bytes) is shorter than "
111 "in header (%d bytes)\n",
112 len, le16_to_cpu(msg->hdr.length));
113 return;
114 }
115
116 switch (msg->hdr.category) {
117 case COMM_CATEGORY_OPERATIONAL:
118 op_top_message(priv, (struct top_msg *)buf);
119 break;
120
121 case COMM_CATEGORY_DEBUG:
122 case COMM_CATEGORY_TESTABILITY:
123 case COMM_CATEGORY_DIAGNOSTICS:
124 iwmct_log_top_message(priv, buf, len);
125 break;
126
127 default:
128 LOG_ERROR(priv, FW_MSG,
129 "Message from TOP with unknown category 0x%X\n",
130 msg->hdr.category);
131 break;
132 }
133}
134
135int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len)
136{
137 int ret;
138 u8 *buf;
139
140 LOG_INFOEX(priv, FW_MSG, "Sending hcmd:\n");
141
142 /* add padding to 256 for IWMC */
143 ((struct top_msg *)cmd)->hdr.flags |= CMD_FLAG_PADDING_256;
144
145 LOG_HEXDUMP(FW_MSG, cmd, len);
146
147 if (len > FW_HCMD_BLOCK_SIZE) {
148 LOG_ERROR(priv, FW_MSG, "size %d exceeded hcmd max size %d\n",
149 len, FW_HCMD_BLOCK_SIZE);
150 return -1;
151 }
152
153 buf = kzalloc(FW_HCMD_BLOCK_SIZE, GFP_KERNEL);
154 if (!buf) {
155 LOG_ERROR(priv, FW_MSG, "kzalloc error, buf size %d\n",
156 FW_HCMD_BLOCK_SIZE);
157 return -1;
158 }
159
160 memcpy(buf, cmd, len);
161
162 sdio_claim_host(priv->func);
163 ret = sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR, buf,
164 FW_HCMD_BLOCK_SIZE);
165 sdio_release_host(priv->func);
166
167 kfree(buf);
168 return ret;
169}
170
171int iwmct_tx(struct iwmct_priv *priv, unsigned int addr,
172 void *src, int count)
173{
174 int ret;
175
176 sdio_claim_host(priv->func);
177 ret = sdio_memcpy_toio(priv->func, addr, src, count);
178 sdio_release_host(priv->func);
179
180 return ret;
181}
182
183static void iwmct_irq_read_worker(struct work_struct *ws)
184{
185 struct iwmct_priv *priv;
186 struct iwmct_work_struct *read_req;
187 __le32 *buf = NULL;
188 int ret;
189 int iosize;
190 u32 barker;
191 bool is_barker;
192
193 priv = container_of(ws, struct iwmct_priv, isr_worker);
194
195 LOG_INFO(priv, IRQ, "enter iwmct_irq_read_worker %p\n", ws);
196
197 /* --------------------- Handshake with device -------------------- */
198 sdio_claim_host(priv->func);
199
200 /* all list manipulations have to be protected by
201 * sdio_claim_host/sdio_release_host */
202 if (list_empty(&priv->read_req_list)) {
203 LOG_ERROR(priv, IRQ, "read_req_list empty in read worker\n");
204 goto exit_release;
205 }
206
207 read_req = list_entry(priv->read_req_list.next,
208 struct iwmct_work_struct, list);
209
210 list_del(&read_req->list);
211 iosize = read_req->iosize;
212 kfree(read_req);
213
214 buf = kzalloc(iosize, GFP_KERNEL);
215 if (!buf) {
216 LOG_ERROR(priv, IRQ, "kzalloc error, buf size %d\n", iosize);
217 goto exit_release;
218 }
219
220 LOG_INFO(priv, IRQ, "iosize=%d, buf=%p, func=%d\n",
221 iosize, buf, priv->func->num);
222
223 /* read from device */
224 ret = sdio_memcpy_fromio(priv->func, buf, IWMC_SDIO_DATA_ADDR, iosize);
225 if (ret) {
226 LOG_ERROR(priv, IRQ, "error %d reading buffer\n", ret);
227 goto exit_release;
228 }
229
230 LOG_HEXDUMP(IRQ, (u8 *)buf, iosize);
231
232 barker = le32_to_cpu(buf[0]);
233
234 /* Verify whether it's a barker and if not - treat as regular Rx */
235 if (barker == IWMC_BARKER_ACK ||
236 (barker & BARKER_DNLOAD_BARKER_MSK) == IWMC_BARKER_REBOOT) {
237
238 /* Valid Barker is equal on first 4 dwords */
239 is_barker = (buf[1] == buf[0]) &&
240 (buf[2] == buf[0]) &&
241 (buf[3] == buf[0]);
242
243 if (!is_barker) {
244 LOG_WARNING(priv, IRQ,
245 "Potentially inconsistent barker "
246 "%08X_%08X_%08X_%08X\n",
247 le32_to_cpu(buf[0]), le32_to_cpu(buf[1]),
248 le32_to_cpu(buf[2]), le32_to_cpu(buf[3]));
249 }
250 } else {
251 is_barker = false;
252 }
253
254 /* Handle Top CommHub message */
255 if (!is_barker) {
256 sdio_release_host(priv->func);
257 handle_top_message(priv, (u8 *)buf, iosize);
258 goto exit;
259 } else if (barker == IWMC_BARKER_ACK) { /* Handle barkers */
260 if (atomic_read(&priv->dev_sync) == 0) {
261 LOG_ERROR(priv, IRQ,
262 "ACK barker arrived out-of-sync\n");
263 goto exit_release;
264 }
265
266 /* Continuing to FW download (after Sync is completed)*/
267 atomic_set(&priv->dev_sync, 0);
268 LOG_INFO(priv, IRQ, "ACK barker arrived "
269 "- starting FW download\n");
270 } else { /* REBOOT barker */
271 LOG_INFO(priv, IRQ, "Recieved reboot barker: %x\n", barker);
272 priv->barker = barker;
273
274 if (barker & BARKER_DNLOAD_SYNC_MSK) {
275 /* Send the same barker back */
276 ret = sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR,
277 buf, iosize);
278 if (ret) {
279 LOG_ERROR(priv, IRQ,
280 "error %d echoing barker\n", ret);
281 goto exit_release;
282 }
283 LOG_INFO(priv, IRQ, "Echoing barker to device\n");
284 atomic_set(&priv->dev_sync, 1);
285 goto exit_release;
286 }
287
288 /* Continuing to FW download (without Sync) */
289 LOG_INFO(priv, IRQ, "No sync requested "
290 "- starting FW download\n");
291 }
292
293 sdio_release_host(priv->func);
294
295
296 LOG_INFO(priv, IRQ, "barker download request 0x%x is:\n", priv->barker);
297 LOG_INFO(priv, IRQ, "******* Top FW %s requested ********\n",
298 (priv->barker & BARKER_DNLOAD_TOP_MSK) ? "was" : "not");
299 LOG_INFO(priv, IRQ, "******* GPS FW %s requested ********\n",
300 (priv->barker & BARKER_DNLOAD_GPS_MSK) ? "was" : "not");
301 LOG_INFO(priv, IRQ, "******* BT FW %s requested ********\n",
302 (priv->barker & BARKER_DNLOAD_BT_MSK) ? "was" : "not");
303
304 if (priv->dbg.fw_download)
305 iwmct_fw_load(priv);
306 else
307 LOG_ERROR(priv, IRQ, "FW download not allowed\n");
308
309 goto exit;
310
311exit_release:
312 sdio_release_host(priv->func);
313exit:
314 kfree(buf);
315 LOG_INFO(priv, IRQ, "exit iwmct_irq_read_worker\n");
316}
317
318static void iwmct_irq(struct sdio_func *func)
319{
320 struct iwmct_priv *priv;
321 int val, ret;
322 int iosize;
323 int addr = IWMC_SDIO_INTR_GET_SIZE_ADDR;
324 struct iwmct_work_struct *read_req;
325
326 priv = sdio_get_drvdata(func);
327
328 LOG_INFO(priv, IRQ, "enter iwmct_irq\n");
329
330 /* read the function's status register */
331 val = sdio_readb(func, IWMC_SDIO_INTR_STATUS_ADDR, &ret);
332
333 LOG_INFO(priv, IRQ, "iir value = %d, ret=%d\n", val, ret);
334
335 if (!val) {
336 LOG_ERROR(priv, IRQ, "iir = 0, exiting ISR\n");
337 goto exit_clear_intr;
338 }
339
340
341 /*
342 * read 2 bytes of the transaction size
343 * IMPORTANT: sdio transaction size has to be read before clearing
344 * sdio interrupt!!!
345 */
346 val = sdio_readb(priv->func, addr++, &ret);
347 iosize = val;
348 val = sdio_readb(priv->func, addr++, &ret);
349 iosize += val << 8;
350
351 LOG_INFO(priv, IRQ, "READ size %d\n", iosize);
352
353 if (iosize == 0) {
354 LOG_ERROR(priv, IRQ, "READ size %d, exiting ISR\n", iosize);
355 goto exit_clear_intr;
356 }
357
358 /* allocate a work structure to pass iosize to the worker */
359 read_req = kzalloc(sizeof(struct iwmct_work_struct), GFP_KERNEL);
360 if (!read_req) {
361 LOG_ERROR(priv, IRQ, "failed to allocate read_req, exit ISR\n");
362 goto exit_clear_intr;
363 }
364
365 INIT_LIST_HEAD(&read_req->list);
366 read_req->iosize = iosize;
367
368 list_add_tail(&priv->read_req_list, &read_req->list);
369
370 /* clear the function's interrupt request bit (write 1 to clear) */
371 sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret);
372
373 queue_work(priv->wq, &priv->isr_worker);
374
375 LOG_INFO(priv, IRQ, "exit iwmct_irq\n");
376
377 return;
378
379exit_clear_intr:
380 /* clear the function's interrupt request bit (write 1 to clear) */
381 sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret);
382}
383
384
385static int blocks;
386module_param(blocks, int, 0604);
387MODULE_PARM_DESC(blocks, "max_blocks_to_send");
388
389static int dump;
390module_param(dump, bool, 0604);
391MODULE_PARM_DESC(dump, "dump_hex_content");
392
393static int jump = 1;
394module_param(jump, bool, 0604);
395
396static int direct = 1;
397module_param(direct, bool, 0604);
398
399static int checksum = 1;
400module_param(checksum, bool, 0604);
401
402static int fw_download = 1;
403module_param(fw_download, bool, 0604);
404
405static int block_size = IWMC_SDIO_BLK_SIZE;
406module_param(block_size, int, 0404);
407
408static int download_trans_blks = IWMC_DEFAULT_TR_BLK;
409module_param(download_trans_blks, int, 0604);
410
411static int rubbish_barker;
412module_param(rubbish_barker, bool, 0604);
413
414#ifdef CONFIG_IWMC3200TOP_DEBUG
415static int log_level[LOG_SRC_MAX];
416static unsigned int log_level_argc;
417module_param_array(log_level, int, &log_level_argc, 0604);
418MODULE_PARM_DESC(log_level, "log_level");
419
420static int log_level_fw[FW_LOG_SRC_MAX];
421static unsigned int log_level_fw_argc;
422module_param_array(log_level_fw, int, &log_level_fw_argc, 0604);
423MODULE_PARM_DESC(log_level_fw, "log_level_fw");
424#endif
425
426void iwmct_dbg_init_params(struct iwmct_priv *priv)
427{
428#ifdef CONFIG_IWMC3200TOP_DEBUG
429 int i;
430
431 for (i = 0; i < log_level_argc; i++) {
432 dev_notice(&priv->func->dev, "log_level[%d]=0x%X\n",
433 i, log_level[i]);
434 iwmct_log_set_filter((log_level[i] >> 8) & 0xFF,
435 log_level[i] & 0xFF);
436 }
437 for (i = 0; i < log_level_fw_argc; i++) {
438 dev_notice(&priv->func->dev, "log_level_fw[%d]=0x%X\n",
439 i, log_level_fw[i]);
440 iwmct_log_set_fw_filter((log_level_fw[i] >> 8) & 0xFF,
441 log_level_fw[i] & 0xFF);
442 }
443#endif
444
445 priv->dbg.blocks = blocks;
446 LOG_INFO(priv, INIT, "blocks=%d\n", blocks);
447 priv->dbg.dump = (bool)dump;
448 LOG_INFO(priv, INIT, "dump=%d\n", dump);
449 priv->dbg.jump = (bool)jump;
450 LOG_INFO(priv, INIT, "jump=%d\n", jump);
451 priv->dbg.direct = (bool)direct;
452 LOG_INFO(priv, INIT, "direct=%d\n", direct);
453 priv->dbg.checksum = (bool)checksum;
454 LOG_INFO(priv, INIT, "checksum=%d\n", checksum);
455 priv->dbg.fw_download = (bool)fw_download;
456 LOG_INFO(priv, INIT, "fw_download=%d\n", fw_download);
457 priv->dbg.block_size = block_size;
458 LOG_INFO(priv, INIT, "block_size=%d\n", block_size);
459 priv->dbg.download_trans_blks = download_trans_blks;
460 LOG_INFO(priv, INIT, "download_trans_blks=%d\n", download_trans_blks);
461}
462
463/*****************************************************************************
464 *
465 * sysfs attributes
466 *
467 *****************************************************************************/
468static ssize_t show_iwmct_fw_version(struct device *d,
469 struct device_attribute *attr, char *buf)
470{
471 struct iwmct_priv *priv = dev_get_drvdata(d);
472 return sprintf(buf, "%s\n", priv->dbg.label_fw);
473}
474static DEVICE_ATTR(cc_label_fw, S_IRUGO, show_iwmct_fw_version, NULL);
475
476#ifdef CONFIG_IWMC3200TOP_DEBUG
477static DEVICE_ATTR(log_level, S_IWUSR | S_IRUGO,
478 show_iwmct_log_level, store_iwmct_log_level);
479static DEVICE_ATTR(log_level_fw, S_IWUSR | S_IRUGO,
480 show_iwmct_log_level_fw, store_iwmct_log_level_fw);
481#endif
482
483static struct attribute *iwmct_sysfs_entries[] = {
484 &dev_attr_cc_label_fw.attr,
485#ifdef CONFIG_IWMC3200TOP_DEBUG
486 &dev_attr_log_level.attr,
487 &dev_attr_log_level_fw.attr,
488#endif
489 NULL
490};
491
492static struct attribute_group iwmct_attribute_group = {
493 .name = NULL, /* put in device directory */
494 .attrs = iwmct_sysfs_entries,
495};
496
497
498static int iwmct_probe(struct sdio_func *func,
499 const struct sdio_device_id *id)
500{
501 struct iwmct_priv *priv;
502 int ret;
503 int val = 1;
504 int addr = IWMC_SDIO_INTR_ENABLE_ADDR;
505
506 dev_dbg(&func->dev, "enter iwmct_probe\n");
507
508 dev_dbg(&func->dev, "IRQ polling period id %u msecs, HZ is %d\n",
509 jiffies_to_msecs(2147483647), HZ);
510
511 priv = kzalloc(sizeof(struct iwmct_priv), GFP_KERNEL);
512 if (!priv) {
513 dev_err(&func->dev, "kzalloc error\n");
514 return -ENOMEM;
515 }
516 priv->func = func;
517 sdio_set_drvdata(func, priv);
518
519
520 /* create drivers work queue */
521 priv->wq = create_workqueue(DRV_NAME "_wq");
522 priv->bus_rescan_wq = create_workqueue(DRV_NAME "_rescan_wq");
523 INIT_WORK(&priv->bus_rescan_worker, iwmct_rescan_worker);
524 INIT_WORK(&priv->isr_worker, iwmct_irq_read_worker);
525
526 init_waitqueue_head(&priv->wait_q);
527
528 sdio_claim_host(func);
529 /* FIXME: Remove after it is fixed in the Boot ROM upgrade */
530 func->enable_timeout = 10;
531
532 /* In our HW, setting the block size also wakes up the boot rom. */
533 ret = sdio_set_block_size(func, priv->dbg.block_size);
534 if (ret) {
535 LOG_ERROR(priv, INIT,
536 "sdio_set_block_size() failure: %d\n", ret);
537 goto error_sdio_enable;
538 }
539
540 ret = sdio_enable_func(func);
541 if (ret) {
542 LOG_ERROR(priv, INIT, "sdio_enable_func() failure: %d\n", ret);
543 goto error_sdio_enable;
544 }
545
546 /* init reset and dev_sync states */
547 atomic_set(&priv->reset, 0);
548 atomic_set(&priv->dev_sync, 0);
549
550 /* init read req queue */
551 INIT_LIST_HEAD(&priv->read_req_list);
552
553 /* process configurable parameters */
554 iwmct_dbg_init_params(priv);
555 ret = sysfs_create_group(&func->dev.kobj, &iwmct_attribute_group);
556 if (ret) {
557 LOG_ERROR(priv, INIT, "Failed to register attributes and "
558 "initialize module_params\n");
559 goto error_dev_attrs;
560 }
561
562 iwmct_dbgfs_register(priv, DRV_NAME);
563
564 if (!priv->dbg.direct && priv->dbg.download_trans_blks > 8) {
565 LOG_INFO(priv, INIT,
566 "Reducing transaction to 8 blocks = 2K (from %d)\n",
567 priv->dbg.download_trans_blks);
568 priv->dbg.download_trans_blks = 8;
569 }
570 priv->trans_len = priv->dbg.download_trans_blks * priv->dbg.block_size;
571 LOG_INFO(priv, INIT, "Transaction length = %d\n", priv->trans_len);
572
573 ret = sdio_claim_irq(func, iwmct_irq);
574 if (ret) {
575 LOG_ERROR(priv, INIT, "sdio_claim_irq() failure: %d\n", ret);
576 goto error_claim_irq;
577 }
578
579
580 /* Enable function's interrupt */
581 sdio_writeb(priv->func, val, addr, &ret);
582 if (ret) {
583 LOG_ERROR(priv, INIT, "Failure writing to "
584 "Interrupt Enable Register (%d): %d\n", addr, ret);
585 goto error_enable_int;
586 }
587
588 sdio_release_host(func);
589
590 LOG_INFO(priv, INIT, "exit iwmct_probe\n");
591
592 return ret;
593
594error_enable_int:
595 sdio_release_irq(func);
596error_claim_irq:
597 sdio_disable_func(func);
598error_dev_attrs:
599 iwmct_dbgfs_unregister(priv->dbgfs);
600 sysfs_remove_group(&func->dev.kobj, &iwmct_attribute_group);
601error_sdio_enable:
602 sdio_release_host(func);
603 return ret;
604}
605
606static void iwmct_remove(struct sdio_func *func)
607{
608 struct iwmct_work_struct *read_req;
609 struct iwmct_priv *priv = sdio_get_drvdata(func);
610
611 priv = sdio_get_drvdata(func);
612
613 LOG_INFO(priv, INIT, "enter\n");
614
615 sdio_claim_host(func);
616 sdio_release_irq(func);
617 sdio_release_host(func);
618
619 /* Safely destroy osc workqueue */
620 destroy_workqueue(priv->bus_rescan_wq);
621 destroy_workqueue(priv->wq);
622
623 sdio_claim_host(func);
624 sdio_disable_func(func);
625 sysfs_remove_group(&func->dev.kobj, &iwmct_attribute_group);
626 iwmct_dbgfs_unregister(priv->dbgfs);
627 sdio_release_host(func);
628
629 /* free read requests */
630 while (!list_empty(&priv->read_req_list)) {
631 read_req = list_entry(priv->read_req_list.next,
632 struct iwmct_work_struct, list);
633
634 list_del(&read_req->list);
635 kfree(read_req);
636 }
637
638 kfree(priv);
639}
640
641
642static const struct sdio_device_id iwmct_ids[] = {
643 /* Intel Wireless MultiCom 3200 Top Driver */
644 { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1404)},
645 { }, /* Terminating entry */
646};
647
648MODULE_DEVICE_TABLE(sdio, iwmct_ids);
649
650static struct sdio_driver iwmct_driver = {
651 .probe = iwmct_probe,
652 .remove = iwmct_remove,
653 .name = DRV_NAME,
654 .id_table = iwmct_ids,
655};
656
657static int __init iwmct_init(void)
658{
659 int rc;
660
661 /* Default log filter settings */
662 iwmct_log_set_filter(LOG_SRC_ALL, LOG_SEV_FILTER_RUNTIME);
663 iwmct_log_set_filter(LOG_SRC_FW_MSG, LOG_SEV_FILTER_ALL);
664 iwmct_log_set_fw_filter(LOG_SRC_ALL, FW_LOG_SEV_FILTER_RUNTIME);
665
666 rc = sdio_register_driver(&iwmct_driver);
667
668 return rc;
669}
670
671static void __exit iwmct_exit(void)
672{
673 sdio_unregister_driver(&iwmct_driver);
674}
675
676module_init(iwmct_init);
677module_exit(iwmct_exit);
678
diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c
index e4ff50b95a5e..fcb6ec1af173 100644
--- a/drivers/misc/kgdbts.c
+++ b/drivers/misc/kgdbts.c
@@ -712,6 +712,12 @@ static int run_simple_test(int is_get_char, int chr)
712 712
713 /* End of packet == #XX so look for the '#' */ 713 /* End of packet == #XX so look for the '#' */
714 if (put_buf_cnt > 3 && put_buf[put_buf_cnt - 3] == '#') { 714 if (put_buf_cnt > 3 && put_buf[put_buf_cnt - 3] == '#') {
715 if (put_buf_cnt >= BUFMAX) {
716 eprintk("kgdbts: ERROR: put buffer overflow on"
717 " '%s' line %i\n", ts.name, ts.idx);
718 put_buf_cnt = 0;
719 return 0;
720 }
715 put_buf[put_buf_cnt] = '\0'; 721 put_buf[put_buf_cnt] = '\0';
716 v2printk("put%i: %s\n", ts.idx, put_buf); 722 v2printk("put%i: %s\n", ts.idx, put_buf);
717 /* Trigger check here */ 723 /* Trigger check here */
@@ -885,16 +891,16 @@ static void kgdbts_run_tests(void)
885 int nmi_sleep = 0; 891 int nmi_sleep = 0;
886 int i; 892 int i;
887 893
888 ptr = strstr(config, "F"); 894 ptr = strchr(config, 'F');
889 if (ptr) 895 if (ptr)
890 fork_test = simple_strtol(ptr + 1, NULL, 10); 896 fork_test = simple_strtol(ptr + 1, NULL, 10);
891 ptr = strstr(config, "S"); 897 ptr = strchr(config, 'S');
892 if (ptr) 898 if (ptr)
893 do_sys_open_test = simple_strtol(ptr + 1, NULL, 10); 899 do_sys_open_test = simple_strtol(ptr + 1, NULL, 10);
894 ptr = strstr(config, "N"); 900 ptr = strchr(config, 'N');
895 if (ptr) 901 if (ptr)
896 nmi_sleep = simple_strtol(ptr+1, NULL, 10); 902 nmi_sleep = simple_strtol(ptr+1, NULL, 10);
897 ptr = strstr(config, "I"); 903 ptr = strchr(config, 'I');
898 if (ptr) 904 if (ptr)
899 sstep_test = simple_strtol(ptr+1, NULL, 10); 905 sstep_test = simple_strtol(ptr+1, NULL, 10);
900 906
diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c
index 41c8fe2a928c..ce5eda985ab0 100644
--- a/drivers/misc/sgi-gru/grufile.c
+++ b/drivers/misc/sgi-gru/grufile.c
@@ -92,7 +92,7 @@ static void gru_vma_close(struct vm_area_struct *vma)
92/* 92/*
93 * gru_file_mmap 93 * gru_file_mmap
94 * 94 *
95 * Called when mmaping the device. Initializes the vma with a fault handler 95 * Called when mmapping the device. Initializes the vma with a fault handler
96 * and private data structure necessary to allocate, track, and free the 96 * and private data structure necessary to allocate, track, and free the
97 * underlying pages. 97 * underlying pages.
98 */ 98 */
diff --git a/drivers/misc/sgi-xp/xpc_main.c b/drivers/misc/sgi-xp/xpc_main.c
index fd3688a3e23f..832ed4c88cf7 100644
--- a/drivers/misc/sgi-xp/xpc_main.c
+++ b/drivers/misc/sgi-xp/xpc_main.c
@@ -89,48 +89,40 @@ static int xpc_disengage_max_timelimit = 120;
89 89
90static ctl_table xpc_sys_xpc_hb_dir[] = { 90static ctl_table xpc_sys_xpc_hb_dir[] = {
91 { 91 {
92 .ctl_name = CTL_UNNUMBERED,
93 .procname = "hb_interval", 92 .procname = "hb_interval",
94 .data = &xpc_hb_interval, 93 .data = &xpc_hb_interval,
95 .maxlen = sizeof(int), 94 .maxlen = sizeof(int),
96 .mode = 0644, 95 .mode = 0644,
97 .proc_handler = &proc_dointvec_minmax, 96 .proc_handler = proc_dointvec_minmax,
98 .strategy = &sysctl_intvec,
99 .extra1 = &xpc_hb_min_interval, 97 .extra1 = &xpc_hb_min_interval,
100 .extra2 = &xpc_hb_max_interval}, 98 .extra2 = &xpc_hb_max_interval},
101 { 99 {
102 .ctl_name = CTL_UNNUMBERED,
103 .procname = "hb_check_interval", 100 .procname = "hb_check_interval",
104 .data = &xpc_hb_check_interval, 101 .data = &xpc_hb_check_interval,
105 .maxlen = sizeof(int), 102 .maxlen = sizeof(int),
106 .mode = 0644, 103 .mode = 0644,
107 .proc_handler = &proc_dointvec_minmax, 104 .proc_handler = proc_dointvec_minmax,
108 .strategy = &sysctl_intvec,
109 .extra1 = &xpc_hb_check_min_interval, 105 .extra1 = &xpc_hb_check_min_interval,
110 .extra2 = &xpc_hb_check_max_interval}, 106 .extra2 = &xpc_hb_check_max_interval},
111 {} 107 {}
112}; 108};
113static ctl_table xpc_sys_xpc_dir[] = { 109static ctl_table xpc_sys_xpc_dir[] = {
114 { 110 {
115 .ctl_name = CTL_UNNUMBERED,
116 .procname = "hb", 111 .procname = "hb",
117 .mode = 0555, 112 .mode = 0555,
118 .child = xpc_sys_xpc_hb_dir}, 113 .child = xpc_sys_xpc_hb_dir},
119 { 114 {
120 .ctl_name = CTL_UNNUMBERED,
121 .procname = "disengage_timelimit", 115 .procname = "disengage_timelimit",
122 .data = &xpc_disengage_timelimit, 116 .data = &xpc_disengage_timelimit,
123 .maxlen = sizeof(int), 117 .maxlen = sizeof(int),
124 .mode = 0644, 118 .mode = 0644,
125 .proc_handler = &proc_dointvec_minmax, 119 .proc_handler = proc_dointvec_minmax,
126 .strategy = &sysctl_intvec,
127 .extra1 = &xpc_disengage_min_timelimit, 120 .extra1 = &xpc_disengage_min_timelimit,
128 .extra2 = &xpc_disengage_max_timelimit}, 121 .extra2 = &xpc_disengage_max_timelimit},
129 {} 122 {}
130}; 123};
131static ctl_table xpc_sys_dir[] = { 124static ctl_table xpc_sys_dir[] = {
132 { 125 {
133 .ctl_name = CTL_UNNUMBERED,
134 .procname = "xpc", 126 .procname = "xpc",
135 .mode = 0555, 127 .mode = 0555,
136 .child = xpc_sys_xpc_dir}, 128 .child = xpc_sys_xpc_dir},
diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c
index c76677afda1b..b5bbe59f9c57 100644
--- a/drivers/misc/sgi-xp/xpc_uv.c
+++ b/drivers/misc/sgi-xp/xpc_uv.c
@@ -106,7 +106,8 @@ xpc_get_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq, int cpu, char *irq_name)
106 int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade); 106 int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade);
107 107
108#if defined CONFIG_X86_64 108#if defined CONFIG_X86_64
109 mq->irq = uv_setup_irq(irq_name, cpu, mq->mmr_blade, mq->mmr_offset); 109 mq->irq = uv_setup_irq(irq_name, cpu, mq->mmr_blade, mq->mmr_offset,
110 UV_AFFINITY_CPU);
110 if (mq->irq < 0) { 111 if (mq->irq < 0) {
111 dev_err(xpc_part, "uv_setup_irq() returned error=%d\n", 112 dev_err(xpc_part, "uv_setup_irq() returned error=%d\n",
112 -mq->irq); 113 -mq->irq);
@@ -136,7 +137,7 @@ static void
136xpc_release_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq) 137xpc_release_gru_mq_irq_uv(struct xpc_gru_mq_uv *mq)
137{ 138{
138#if defined CONFIG_X86_64 139#if defined CONFIG_X86_64
139 uv_teardown_irq(mq->irq, mq->mmr_blade, mq->mmr_offset); 140 uv_teardown_irq(mq->irq);
140 141
141#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV 142#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV
142 int mmr_pnode; 143 int mmr_pnode;
diff --git a/drivers/misc/ti_dac7512.c b/drivers/misc/ti_dac7512.c
new file mode 100644
index 000000000000..d3f229a3a77e
--- /dev/null
+++ b/drivers/misc/ti_dac7512.c
@@ -0,0 +1,101 @@
1/*
2 * dac7512.c - Linux kernel module for
3 * Texas Instruments DAC7512
4 *
5 * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
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., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <linux/module.h>
23#include <linux/init.h>
24#include <linux/spi/spi.h>
25
26#define DAC7512_DRV_NAME "dac7512"
27#define DRIVER_VERSION "1.0"
28
29static ssize_t dac7512_store_val(struct device *dev,
30 struct device_attribute *attr,
31 const char *buf, size_t count)
32{
33 struct spi_device *spi = to_spi_device(dev);
34 unsigned char tmp[2];
35 unsigned long val;
36
37 if (strict_strtoul(buf, 10, &val) < 0)
38 return -EINVAL;
39
40 tmp[0] = val >> 8;
41 tmp[1] = val & 0xff;
42 spi_write(spi, tmp, sizeof(tmp));
43 return count;
44}
45
46static DEVICE_ATTR(value, S_IWUSR, NULL, dac7512_store_val);
47
48static struct attribute *dac7512_attributes[] = {
49 &dev_attr_value.attr,
50 NULL
51};
52
53static const struct attribute_group dac7512_attr_group = {
54 .attrs = dac7512_attributes,
55};
56
57static int __devinit dac7512_probe(struct spi_device *spi)
58{
59 int ret;
60
61 spi->bits_per_word = 8;
62 spi->mode = SPI_MODE_0;
63 ret = spi_setup(spi);
64 if (ret < 0)
65 return ret;
66
67 return sysfs_create_group(&spi->dev.kobj, &dac7512_attr_group);
68}
69
70static int __devexit dac7512_remove(struct spi_device *spi)
71{
72 sysfs_remove_group(&spi->dev.kobj, &dac7512_attr_group);
73 return 0;
74}
75
76static struct spi_driver dac7512_driver = {
77 .driver = {
78 .name = DAC7512_DRV_NAME,
79 .owner = THIS_MODULE,
80 },
81 .probe = dac7512_probe,
82 .remove = __devexit_p(dac7512_remove),
83};
84
85static int __init dac7512_init(void)
86{
87 return spi_register_driver(&dac7512_driver);
88}
89
90static void __exit dac7512_exit(void)
91{
92 spi_unregister_driver(&dac7512_driver);
93}
94
95MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
96MODULE_DESCRIPTION("DAC7512 16-bit DAC");
97MODULE_LICENSE("GPL v2");
98MODULE_VERSION(DRIVER_VERSION);
99
100module_init(dac7512_init);
101module_exit(dac7512_exit);