summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/cpufreq/cpufreq.c55
-rw-r--r--drivers/hid/Kconfig70
-rw-r--r--drivers/hid/Makefile5
-rw-r--r--drivers/hid/hid-bright.c71
-rw-r--r--drivers/hid/hid-core.c120
-rw-r--r--drivers/hid/hid-dell.c76
-rw-r--r--drivers/hid/hid-dummy.c6
-rw-r--r--drivers/hid/hid-gaff.c185
-rw-r--r--drivers/hid/hid-ids.h21
-rw-r--r--drivers/hid/hid-lg.c7
-rw-r--r--drivers/hid/hid-ntrig.c82
-rw-r--r--drivers/hid/hid-sony.c2
-rw-r--r--drivers/hid/hid-topseed.c77
-rw-r--r--drivers/hid/hidraw.c32
-rw-r--r--drivers/hid/usbhid/Kconfig2
-rw-r--r--drivers/hid/usbhid/hid-core.c34
-rw-r--r--drivers/hid/usbhid/hid-quirks.c1
-rw-r--r--drivers/hid/usbhid/hiddev.c135
-rw-r--r--drivers/hid/usbhid/usbhid.h10
-rw-r--r--drivers/i2c/busses/i2c-omap.c420
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c185
-rw-r--r--drivers/i2c/chips/Kconfig23
-rw-r--r--drivers/i2c/chips/Makefile2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_fs.c3
-rw-r--r--drivers/isdn/capi/capidrv.c4
-rw-r--r--drivers/isdn/capi/capifs.c2
-rw-r--r--drivers/md/Makefile5
-rw-r--r--drivers/md/dm-crypt.c6
-rw-r--r--drivers/md/dm-delay.c6
-rw-r--r--drivers/md/dm-exception-store.c749
-rw-r--r--drivers/md/dm-exception-store.h148
-rw-r--r--drivers/md/dm-ioctl.c16
-rw-r--r--drivers/md/dm-linear.c6
-rw-r--r--drivers/md/dm-log.c40
-rw-r--r--drivers/md/dm-mpath.c14
-rw-r--r--drivers/md/dm-raid1.c24
-rw-r--r--drivers/md/dm-snap-persistent.c704
-rw-r--r--drivers/md/dm-snap-transient.c98
-rw-r--r--drivers/md/dm-snap.c48
-rw-r--r--drivers/md/dm-snap.h129
-rw-r--r--drivers/md/dm-stripe.c4
-rw-r--r--drivers/md/dm-sysfs.c99
-rw-r--r--drivers/md/dm-table.c47
-rw-r--r--drivers/md/dm-target.c15
-rw-r--r--drivers/md/dm-zero.c5
-rw-r--r--drivers/md/dm.c101
-rw-r--r--drivers/md/dm.h10
-rw-r--r--drivers/message/i2o/exec-osm.c2
-rw-r--r--drivers/message/i2o/i2o_config.c2
-rw-r--r--drivers/message/i2o/iop.c2
-rw-r--r--drivers/message/i2o/pci.c2
-rw-r--r--drivers/mfd/Kconfig66
-rw-r--r--drivers/mfd/Makefile7
-rw-r--r--drivers/mfd/da903x.c16
-rw-r--r--drivers/mfd/dm355evm_msp.c420
-rw-r--r--drivers/mfd/menelaus.c (renamed from drivers/i2c/chips/menelaus.c)0
-rw-r--r--drivers/mfd/mfd-core.c1
-rw-r--r--drivers/mfd/tps65010.c (renamed from drivers/i2c/chips/tps65010.c)0
-rw-r--r--drivers/mfd/twl4030-core.c472
-rw-r--r--drivers/mfd/twl4030-irq.c30
-rw-r--r--drivers/mfd/wm8350-core.c266
-rw-r--r--drivers/mfd/wm8350-i2c.c4
-rw-r--r--drivers/mfd/wm8350-regmap.c2100
-rw-r--r--drivers/mfd/wm8400-core.c31
-rw-r--r--drivers/misc/ibmasm/ibmasmfs.c2
-rw-r--r--drivers/net/acenic.c117
-rw-r--r--drivers/net/acenic.h4
-rw-r--r--drivers/net/e100.c268
-rw-r--r--drivers/net/ehea/ehea.h3
-rw-r--r--drivers/net/ehea/ehea_main.c2
-rw-r--r--drivers/net/enc28j60.c4
-rw-r--r--drivers/net/igb/igb_main.c4
-rw-r--r--drivers/net/myri10ge/myri10ge.c6
-rw-r--r--drivers/net/qlge/qlge.h57
-rw-r--r--drivers/net/qlge/qlge_dbg.c13
-rw-r--r--drivers/net/qlge/qlge_ethtool.c8
-rw-r--r--drivers/net/qlge/qlge_main.c116
-rw-r--r--drivers/net/starfire.c54
-rw-r--r--drivers/net/starfire_firmware.h346
-rw-r--r--drivers/net/starfire_firmware.pl31
-rw-r--r--drivers/net/tg3.c792
-rw-r--r--drivers/net/tg3.h4
-rw-r--r--drivers/net/tun.c2
-rw-r--r--drivers/oprofile/oprofilefs.c3
-rw-r--r--drivers/power/Kconfig14
-rw-r--r--drivers/power/Makefile2
-rw-r--r--drivers/power/da9030_battery.c600
-rw-r--r--drivers/power/power_supply_sysfs.c2
-rw-r--r--drivers/power/wm8350_power.c532
-rw-r--r--drivers/regulator/wm8350-regulator.c7
-rw-r--r--drivers/rtc/Kconfig6
-rw-r--r--drivers/rtc/interface.c54
-rw-r--r--drivers/rtc/rtc-dev.c51
-rw-r--r--drivers/s390/net/qeth_core.h1
-rw-r--r--drivers/s390/net/qeth_core_main.c57
-rw-r--r--drivers/s390/net/qeth_l2_main.c8
-rw-r--r--drivers/s390/net/qeth_l3_main.c26
-rw-r--r--drivers/usb/core/inode.c1
-rw-r--r--drivers/usb/gadget/file_storage.c18
-rw-r--r--drivers/usb/gadget/inode.c1
-rw-r--r--drivers/video/via/viafbdev.c248
101 files changed, 7439 insertions, 3350 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 31d6f535a79d..01dde80597f7 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -754,6 +754,11 @@ static struct kobj_type ktype_cpufreq = {
.release = cpufreq_sysfs_release,
};
+static struct kobj_type ktype_empty_cpufreq = {
+ .sysfs_ops = &sysfs_ops,
+ .release = cpufreq_sysfs_release,
+};
+
/**
* cpufreq_add_dev - add a CPU device
@@ -822,8 +827,8 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
dprintk("initialization failed\n");
goto err_out;
}
- policy->user_policy.min = policy->cpuinfo.min_freq;
- policy->user_policy.max = policy->cpuinfo.max_freq;
+ policy->user_policy.min = policy->min;
+ policy->user_policy.max = policy->max;
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_START, policy);
@@ -876,26 +881,36 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
/* prepare interface data */
- ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &sys_dev->kobj,
- "cpufreq");
- if (ret)
- goto err_out_driver_exit;
-
- /* set up files for this cpu device */
- drv_attr = cpufreq_driver->attr;
- while ((drv_attr) && (*drv_attr)) {
- ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
+ if (!cpufreq_driver->hide_interface) {
+ ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
+ &sys_dev->kobj, "cpufreq");
if (ret)
goto err_out_driver_exit;
- drv_attr++;
- }
- if (cpufreq_driver->get) {
- ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
- if (ret)
- goto err_out_driver_exit;
- }
- if (cpufreq_driver->target) {
- ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
+
+ /* set up files for this cpu device */
+ drv_attr = cpufreq_driver->attr;
+ while ((drv_attr) && (*drv_attr)) {
+ ret = sysfs_create_file(&policy->kobj,
+ &((*drv_attr)->attr));
+ if (ret)
+ goto err_out_driver_exit;
+ drv_attr++;
+ }
+ if (cpufreq_driver->get) {
+ ret = sysfs_create_file(&policy->kobj,
+ &cpuinfo_cur_freq.attr);
+ if (ret)
+ goto err_out_driver_exit;
+ }
+ if (cpufreq_driver->target) {
+ ret = sysfs_create_file(&policy->kobj,
+ &scaling_cur_freq.attr);
+ if (ret)
+ goto err_out_driver_exit;
+ }
+ } else {
+ ret = kobject_init_and_add(&policy->kobj, &ktype_empty_cpufreq,
+ &sys_dev->kobj, "cpufreq");
if (ret)
goto err_out_driver_exit;
}
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index b4fd8ca701a4..e85c8fe9ffcf 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -85,14 +85,14 @@ config HID_COMPAT
config HID_A4TECH
tristate "A4 tech" if EMBEDDED
depends on USB_HID
- default y
+ default !EMBEDDED
---help---
Support for A4 tech X5 and WOP-35 / Trust 450L mice.
config HID_APPLE
tristate "Apple" if EMBEDDED
depends on (USB_HID || BT_HIDP)
- default y
+ default !EMBEDDED
---help---
Support for some Apple devices which less or more break
HID specification.
@@ -103,64 +103,49 @@ config HID_APPLE
config HID_BELKIN
tristate "Belkin" if EMBEDDED
depends on USB_HID
- default y
+ default !EMBEDDED
---help---
Support for Belkin Flip KVM and Wireless keyboard.
-config HID_BRIGHT
- tristate "Bright" if EMBEDDED
- depends on USB_HID
- default y
- ---help---
- Support for Bright ABNT-2 keyboard.
-
config HID_CHERRY
tristate "Cherry" if EMBEDDED
depends on USB_HID
- default y
+ default !EMBEDDED
---help---
Support for Cherry Cymotion keyboard.
config HID_CHICONY
tristate "Chicony" if EMBEDDED
depends on USB_HID
- default y
+ default !EMBEDDED
---help---
Support for Chicony Tactical pad.
config HID_CYPRESS
tristate "Cypress" if EMBEDDED
depends on USB_HID
- default y
+ default !EMBEDDED
---help---
Support for cypress mouse and barcode readers.
-config HID_DELL
- tristate "Dell" if EMBEDDED
- depends on USB_HID
- default y
- ---help---
- Support for quirky Dell HID hardware that require
- special LED handling (W7658 and SK8115 models)
-
config HID_EZKEY
tristate "Ezkey" if EMBEDDED
depends on USB_HID
- default y
+ default !EMBEDDED
---help---
Support for Ezkey BTC 8193 keyboard.
config HID_GYRATION
tristate "Gyration" if EMBEDDED
depends on USB_HID
- default y
+ default !EMBEDDED
---help---
Support for Gyration remote control.
config HID_LOGITECH
tristate "Logitech" if EMBEDDED
depends on USB_HID
- default y
+ default !EMBEDDED
---help---
Support for Logitech devices that are not fully compliant with HID standard.
@@ -191,21 +176,28 @@ config LOGIRUMBLEPAD2_FF
config HID_MICROSOFT
tristate "Microsoft" if EMBEDDED
depends on USB_HID
- default y
+ default !EMBEDDED
---help---
Support for Microsoft devices that are not fully compliant with HID standard.
config HID_MONTEREY
tristate "Monterey" if EMBEDDED
depends on USB_HID
- default y
+ default !EMBEDDED
---help---
Support for Monterey Genius KB29E.
+config HID_NTRIG
+ tristate "NTrig" if EMBEDDED
+ depends on USB_HID
+ default !EMBEDDED
+ ---help---
+ Support for N-Trig touch screen.
+
config HID_PANTHERLORD
tristate "Pantherlord devices support" if EMBEDDED
depends on USB_HID
- default y
+ default !EMBEDDED
---help---
Support for PantherLord/GreenAsia based device support.
@@ -220,31 +212,47 @@ config PANTHERLORD_FF
config HID_PETALYNX
tristate "Petalynx" if EMBEDDED
depends on USB_HID
- default y
+ default !EMBEDDED
---help---
Support for Petalynx Maxter remote control.
config HID_SAMSUNG
tristate "Samsung" if EMBEDDED
depends on USB_HID
- default y
+ default !EMBEDDED
---help---
Support for Samsung InfraRed remote control.
config HID_SONY
tristate "Sony" if EMBEDDED
depends on USB_HID
- default y
+ default !EMBEDDED
---help---
Support for Sony PS3 controller.
config HID_SUNPLUS
tristate "Sunplus" if EMBEDDED
depends on USB_HID
- default y
+ default !EMBEDDED
---help---
Support for Sunplus wireless desktop.
+config GREENASIA_FF
+ tristate "GreenAsia (Product ID 0x12) force feedback support"
+ depends on USB_HID
+ select INPUT_FF_MEMLESS
+ ---help---
+ Say Y here if you have a GreenAsia (Product ID 0x12) based game controller
+ (like MANTA Warior MM816 and SpeedLink Strike2 SL-6635) or adapter
+ and want to enable force feedback support for it.
+
+config HID_TOPSEED
+ tristate "TopSeed Cyberlink remote control support" if EMBEDDED
+ depends on USB_HID
+ default !EMBEDDED
+ ---help---
+ Say Y if you have a TopSeed Cyberlink remote control.
+
config THRUSTMASTER_FF
tristate "ThrustMaster devices support"
depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index b09e43e7413e..fbd021f153f1 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -23,22 +23,23 @@ endif
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
obj-$(CONFIG_HID_APPLE) += hid-apple.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
-obj-$(CONFIG_HID_BRIGHT) += hid-bright.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
-obj-$(CONFIG_HID_DELL) += hid-dell.o
obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o
obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
+obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o
obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o
obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SONY) += hid-sony.o
obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o
+obj-$(CONFIG_GREENASIA_FF) += hid-gaff.o
obj-$(CONFIG_THRUSTMASTER_FF) += hid-tmff.o
+obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o
obj-$(CONFIG_ZEROPLUS_FF) += hid-zpff.o
obj-$(CONFIG_USB_HID) += usbhid/
diff --git a/drivers/hid/hid-bright.c b/drivers/hid/hid-bright.c
deleted file mode 100644
index 38517a117dfd..000000000000
--- a/drivers/hid/hid-bright.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * HID driver for some bright "special" devices
- *
- * Copyright (c) 2008 Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * Based on hid-dell driver
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- */
-
-#include <linux/device.h>
-#include <linux/hid.h>
-#include <linux/module.h>
-
-#include "hid-ids.h"
-
-static int bright_probe(struct hid_device *hdev, const struct hid_device_id *id)
-{
- int ret;
-
- ret = hid_parse(hdev);
- if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
- goto err_free;
- }
-
- ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
- if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
- goto err_free;
- }
-
- usbhid_set_leds(hdev);
-
- return 0;
-err_free:
- return ret;
-}
-
-static const struct hid_device_id bright_devices[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_BRIGHT, USB_DEVICE_ID_BRIGHT_ABNT2) },
- { }
-};
-MODULE_DEVICE_TABLE(hid, bright_devices);
-
-static struct hid_driver bright_driver = {
- .name = "bright",
- .id_table = bright_devices,
- .probe = bright_probe,
-};
-
-static int bright_init(void)
-{
- return hid_register_driver(&bright_driver);
-}
-
-static void bright_exit(void)
-{
- hid_unregister_driver(&bright_driver);
-}
-
-module_init(bright_init);
-module_exit(bright_exit);
-MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(bright);
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 40df3e1b4bd1..5d7640e49dc5 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1256,19 +1256,16 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
- { HID_USB_DEVICE(USB_VENDOR_ID_BRIGHT, USB_DEVICE_ID_BRIGHT_ABNT2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_SK8115) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
- { HID_USB_DEVICE(USB_VENDOR_ID_GENERIC_13BA, USB_DEVICE_ID_GENERIC_13BA_KBD_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
@@ -1279,7 +1276,6 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI) },
- { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) },
@@ -1297,23 +1293,105 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
{ }
};
+struct hid_dynid {
+ struct list_head list;
+ struct hid_device_id id;
+};
+
+/**
+ * store_new_id - add a new HID device ID to this driver and re-probe devices
+ * @driver: target device driver
+ * @buf: buffer for scanning device ID data
+ * @count: input size
+ *
+ * Adds a new dynamic hid device ID to this driver,
+ * and causes the driver to probe for all devices again.
+ */
+static ssize_t store_new_id(struct device_driver *drv, const char *buf,
+ size_t count)
+{
+ struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
+ struct hid_dynid *dynid;
+ __u32 bus, vendor, product;
+ unsigned long driver_data = 0;
+ int ret;
+
+ ret = sscanf(buf, "%x %x %x %lx",
+ &bus, &vendor, &product, &driver_data);
+ if (ret < 3)
+ return -EINVAL;
+
+ dynid = kzalloc(sizeof(*dynid), GFP_KERNEL);
+ if (!dynid)
+ return -ENOMEM;
+
+ dynid->id.bus = bus;
+ dynid->id.vendor = vendor;
+ dynid->id.product = product;
+ dynid->id.driver_data = driver_data;
+
+ spin_lock(&hdrv->dyn_lock);
+ list_add_tail(&dynid->list, &hdrv->dyn_list);
+ spin_unlock(&hdrv->dyn_lock);
+
+ ret = 0;
+ if (get_driver(&hdrv->driver)) {
+ ret = driver_attach(&hdrv->driver);
+ put_driver(&hdrv->driver);
+ }
+
+ return ret ? : count;
+}
+static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
+
+static void hid_free_dynids(struct hid_driver *hdrv)
+{
+ struct hid_dynid *dynid, *n;
+
+ spin_lock(&hdrv->dyn_lock);
+ list_for_each_entry_safe(dynid, n, &hdrv->dyn_list, list) {
+ list_del(&dynid->list);
+ kfree(dynid);
+ }
+ spin_unlock(&hdrv->dyn_lock);
+}
+
+static const struct hid_device_id *hid_match_device(struct hid_device *hdev,
+ struct hid_driver *hdrv)
+{
+ struct hid_dynid *dynid;
+
+ spin_lock(&hdrv->dyn_lock);
+ list_for_each_entry(dynid, &hdrv->dyn_list, list) {
+ if (hid_match_one_id(hdev, &dynid->id)) {
+ spin_unlock(&hdrv->dyn_lock);
+ return &dynid->id;
+ }
+ }
+ spin_unlock(&hdrv->dyn_lock);
+
+ return hid_match_id(hdev, hdrv->id_table);
+}
+
static int hid_bus_match(struct device *dev, struct device_driver *drv)
{
struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
- if (!hid_match_id(hdev, hdrv->id_table))
+ if (!hid_match_device(hdev, hdrv))
return 0;
/* generic wants all non-blacklisted */
@@ -1332,7 +1410,7 @@ static int hid_device_probe(struct device *dev)
int ret = 0;
if (!hdev->driver) {
- id = hid_match_id(hdev, hdrv->id_table);
+ id = hid_match_device(hdev, hdrv);
if (id == NULL)
return -ENODEV;
@@ -1420,6 +1498,7 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DEALEXTREAME, USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
@@ -1577,6 +1656,9 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ }
@@ -1618,9 +1700,10 @@ int hid_add_device(struct hid_device *hdev)
if (hid_ignore(hdev))
return -ENODEV;
- /* XXX hack, any other cleaner solution < 20 bus_id bytes? */
- sprintf(hdev->dev.bus_id, "%04X:%04X:%04X.%04X", hdev->bus,
- hdev->vendor, hdev->product, atomic_inc_return(&id));
+ /* XXX hack, any other cleaner solution after the driver core
+ * is converted to allow more than 20 bytes as the device name? */
+ dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus,
+ hdev->vendor, hdev->product, atomic_inc_return(&id));
ret = device_add(&hdev->dev);
if (!ret)
@@ -1695,18 +1778,33 @@ EXPORT_SYMBOL_GPL(hid_destroy_device);
int __hid_register_driver(struct hid_driver *hdrv, struct module *owner,
const char *mod_name)
{
+ int ret;
+
hdrv->driver.name = hdrv->name;
hdrv->driver.bus = &hid_bus_type;
hdrv->driver.owner = owner;
hdrv->driver.mod_name = mod_name;
- return driver_register(&hdrv->driver);
+ INIT_LIST_HEAD(&hdrv->dyn_list);
+ spin_lock_init(&hdrv->dyn_lock);
+
+ ret = driver_register(&hdrv->driver);
+ if (ret)
+ return ret;
+
+ ret = driver_create_file(&hdrv->driver, &driver_attr_new_id);
+ if (ret)
+ driver_unregister(&hdrv->driver);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(__hid_register_driver);
void hid_unregister_driver(struct hid_driver *hdrv)
{
+ driver_remove_file(&hdrv->driver, &driver_attr_new_id);
driver_unregister(&hdrv->driver);
+ hid_free_dynids(hdrv);
}
EXPORT_SYMBOL_GPL(hid_unregister_driver);
diff --git a/drivers/hid/hid-dell.c b/drivers/hid/hid-dell.c
deleted file mode 100644
index f5474300b83a..000000000000
--- a/drivers/hid/hid-dell.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * HID driver for some dell "special" devices
- *
- * Copyright (c) 1999 Andreas Gal
- * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
- * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
- * Copyright (c) 2006-2007 Jiri Kosina
- * Copyright (c) 2007 Paul Walmsley
- * Copyright (c) 2008 Jiri Slaby
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- */
-
-#include <linux/device.h>
-#include <linux/hid.h>
-#include <linux/module.h>
-
-#include "hid-ids.h"
-
-static int dell_probe(struct hid_device *hdev, const struct hid_device_id *id)
-{
- int ret;
-
- ret = hid_parse(hdev);
- if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
- goto err_free;
- }
-
- ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
- if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
- goto err_free;
- }
-
- usbhid_set_leds(hdev);
-
- return 0;
-err_free:
- return ret;
-}
-
-static const struct hid_device_id dell_devices[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_SK8115) },
- { HID_USB_DEVICE(USB_VENDOR_ID_GENERIC_13BA, USB_DEVICE_ID_GENERIC_13BA_KBD_MOUSE) },
- { }
-};
-MODULE_DEVICE_TABLE(hid, dell_devices);
-
-static struct hid_driver dell_driver = {
- .name = "dell",
- .id_table = dell_devices,
- .probe = dell_probe,
-};
-
-static int dell_init(void)
-{
- return hid_register_driver(&dell_driver);
-}
-
-static void dell_exit(void)
-{
- hid_unregister_driver(&dell_driver);
-}
-
-module_init(dell_init);
-module_exit(dell_exit);
-MODULE_LICENSE("GPL");
-
-HID_COMPAT_LOAD_DRIVER(dell);
diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c
index e148f86fb58e..b4cc0f743d63 100644
--- a/drivers/hid/hid-dummy.c
+++ b/drivers/hid/hid-dummy.c
@@ -43,6 +43,9 @@ static int __init hid_dummy_init(void)
#ifdef CONFIG_HID_MONTEREY_MODULE
HID_COMPAT_CALL_DRIVER(monterey);
#endif
+#ifdef CONFIG_HID_NTRIG_MODULE
+ HID_COMPAT_CALL_DRIVER(ntrig);
+#endif
#ifdef CONFIG_HID_PANTHERLORD_MODULE
HID_COMPAT_CALL_DRIVER(pantherlord);
#endif
@@ -58,6 +61,9 @@ static int __init hid_dummy_init(void)
#ifdef CONFIG_HID_SUNPLUS_MODULE
HID_COMPAT_CALL_DRIVER(sunplus);
#endif
+#ifdef CONFIG_GREENASIA_FF_MODULE
+ HID_COMPAT_CALL_DRIVER(greenasia);
+#endif
#ifdef CONFIG_THRUSTMASTER_FF_MODULE
HID_COMPAT_CALL_DRIVER(thrustmaster);
#endif
diff --git a/drivers/hid/hid-gaff.c b/drivers/hid/hid-gaff.c
new file mode 100644
index 000000000000..71211f6a4f02
--- /dev/null
+++ b/drivers/hid/hid-gaff.c
@@ -0,0 +1,185 @@
+/*
+ * Force feedback support for GreenAsia (Product ID 0x12) based devices
+ *
+ * The devices are distributed under various names and the same USB device ID
+ * can be used in many game controllers.
+ *
+ *
+ * 0e8f:0012 "GreenAsia Inc. USB Joystick "
+ * - tested with MANTA Warior MM816 and SpeedLink Strike2 SL-6635.
+ *
+ * Copyright (c) 2008 Lukasz Lubojanski <lukasz@lubojanski.info>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include "hid-ids.h"
+#include "usbhid/usbhid.h"
+
+struct gaff_device {
+ struct hid_report *report;
+};
+
+static int hid_gaff_play(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct hid_device *hid = input_get_drvdata(dev);
+ struct gaff_device *gaff = data;
+ int left, right;
+
+ left = effect->u.rumble.strong_magnitude;
+ right = effect->u.rumble.weak_magnitude;
+
+ dbg_hid("called with 0x%04x 0x%04x", left, right);
+
+ left = left * 0xfe / 0xffff;
+ right = right * 0xfe / 0xffff;
+
+ gaff->report->field[0]->value[0] = 0x51;
+ gaff->report->field[0]->value[1] = 0x0;
+ gaff->report->field[0]->value[2] = right;
+ gaff->report->field[0]->value[3] = 0;
+ gaff->report->field[0]->value[4] = left;
+ gaff->report->field[0]->value[5] = 0;
+ dbg_hid("running with 0x%02x 0x%02x", left, right);
+ usbhid_submit_report(hid, gaff->report, USB_DIR_OUT);
+
+ gaff->report->field[0]->value[0] = 0xfa;
+ gaff->report->field[0]->value[1] = 0xfe;
+ gaff->report->field[0]->value[2] = 0x0;
+ gaff->report->field[0]->value[4] = 0x0;
+
+ usbhid_submit_report(hid, gaff->report, USB_DIR_OUT);
+
+ return 0;
+}
+
+static int gaff_init(struct hid_device *hid)
+{
+ struct gaff_device *gaff;
+ struct hid_report *report;
+ struct hid_input *hidinput = list_entry(hid->inputs.next,
+ struct hid_input, list);
+ struct list_head *report_list =
+ &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct list_head *report_ptr = report_list;
+ struct input_dev *dev = hidinput->input;
+ int error;
+
+ if (list_empty(report_list)) {
+ dev_err(&hid->dev, "no output reports found\n");
+ return -ENODEV;
+ }
+
+ report_ptr = report_ptr->next;
+
+ report = list_entry(report_ptr, struct hid_report, list);
+ if (report->maxfield < 1) {
+ dev_err(&hid->dev, "no fields in the report\n");
+ return -ENODEV;
+ }
+
+ if (report->field[0]->report_count < 6) {
+ dev_err(&hid->dev, "not enough values in the field\n");
+ return -ENODEV;
+ }
+
+ gaff = kzalloc(sizeof(struct gaff_device), GFP_KERNEL);
+ if (!gaff)
+ return -ENOMEM;
+
+ set_bit(FF_RUMBLE, dev->ffbit);
+
+ error = input_ff_create_memless(dev, gaff, hid_gaff_play);
+ if (error) {
+ kfree(gaff);
+ return error;
+ }
+
+ gaff->report = report;
+ gaff->report->field[0]->value[0] = 0x51;
+ gaff->report->field[0]->value[1] = 0x00;
+ gaff->report->field[0]->value[2] = 0x00;
+ gaff->report->field[0]->value[3] = 0x00;
+ usbhid_submit_report(hid, gaff->report, USB_DIR_OUT);
+
+ gaff->report->field[0]->value[0] = 0xfa;
+ gaff->report->field[0]->value[1] = 0xfe;
+
+ usbhid_submit_report(hid, gaff->report, USB_DIR_OUT);
+
+ dev_info(&hid->dev, "Force Feedback for GreenAsia 0x12"
+ " devices by Lukasz Lubojanski <lukasz@lubojanski.info>\n");
+
+ return 0;
+}
+
+static int ga_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+
+ dev_dbg(&hdev->dev, "Greenasia HID hardware probe...");
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err;
+ }
+
+ gaff_init(hdev);
+
+ return 0;
+err:
+ return ret;
+}
+
+static const struct hid_device_id ga_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012), },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, ga_devices);
+
+static struct hid_driver ga_driver = {
+ .name = "greenasia",
+ .id_table = ga_devices,
+ .probe = ga_probe,
+};
+
+static int __init ga_init(void)
+{
+ return hid_register_driver(&ga_driver);
+}
+
+static void __exit ga_exit(void)
+{
+ hid_unregister_driver(&ga_driver);
+}
+
+module_init(ga_init);
+module_exit(ga_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(greenasia);
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 39289699c32f..acc1abc834a4 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -107,9 +107,6 @@
#define USB_VENDOR_ID_BELKIN 0x050d
#define USB_DEVICE_ID_FLIP_KVM 0x3201
-#define USB_VENDOR_ID_BRIGHT 0x1241
-#define USB_DEVICE_ID_BRIGHT_ABNT2 0x1503
-
#define USB_VENDOR_ID_BERKSHIRE 0x0c98
#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140
@@ -141,9 +138,8 @@
#define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61
#define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64
-#define USB_VENDOR_ID_DELL 0x413c
-#define USB_DEVICE_ID_DELL_W7658 0x2005
-#define USB_DEVICE_ID_DELL_SK8115 0x2105
+#define USB_VENDOR_ID_DEALEXTREAME 0x10c5
+#define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701 0x819a
#define USB_VENDOR_ID_DELORME 0x1163
#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
@@ -167,9 +163,6 @@
#define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc
-#define USB_VENDOR_ID_GENERIC_13BA 0x13ba
-#define USB_DEVICE_ID_GENERIC_13BA_KBD_MOUSE 0x0017
-
#define USB_VENDOR_ID_GLAB 0x06c2
#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038
#define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039
@@ -292,7 +285,6 @@
#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295
#define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a
-#define USB_DEVICE_ID_LOGITECH_KBD 0xc311
#define USB_DEVICE_ID_S510_RECEIVER 0xc50c
#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517
#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512
@@ -339,6 +331,9 @@
#define USB_VENDOR_ID_NEC 0x073e
#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301
+#define USB_VENDOR_ID_NTRIG 0x1b96
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001
+
#define USB_VENDOR_ID_ONTRAK 0x0a07
#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064
@@ -383,9 +378,15 @@
#define USB_VENDOR_ID_TOPMAX 0x0663
#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103
+#define USB_VENDOR_ID_TOPSEED 0x0766
+#define USB_DEVICE_ID_TOPSEED_CYBERLINK 0x0204
+
#define USB_VENDOR_ID_TURBOX 0x062a
#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201
+#define USB_VENDOR_ID_UCLOGIC 0x5543
+#define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 0x0042
+
#define USB_VENDOR_ID_VERNIER 0x08f7
#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001
#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index 2bae340eafe2..83e07c9f4144 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -26,7 +26,6 @@
#define LG_RDESC 0x001
#define LG_BAD_RELATIVE_KEYS 0x002
#define LG_DUPLICATE_USAGES 0x004
-#define LG_RESET_LEDS 0x008
#define LG_EXPANDED_KEYMAP 0x010
#define LG_IGNORE_DOUBLED_WHEEL 0x020
#define LG_WIRELESS 0x040
@@ -248,9 +247,6 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_free;
}
- if (quirks & LG_RESET_LEDS)
- usbhid_set_leds(hdev);
-
if (quirks & LG_FF)
lgff_init(hdev);
if (quirks & LG_FF2)
@@ -279,9 +275,6 @@ static const struct hid_device_id lg_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
.driver_data = LG_DUPLICATE_USAGES },
- { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD),
- .driver_data = LG_RESET_LEDS },
-
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
.driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
new file mode 100644
index 000000000000..db44fbd7bdf6
--- /dev/null
+++ b/drivers/hid/hid-ntrig.c
@@ -0,0 +1,82 @@
+/*
+ * HID driver for some ntrig "special" devices
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby
+ * Copyright (c) 2008 Rafi Rubin
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define NTRIG_DUPLICATE_USAGES 0x001
+
+#define nt_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
+ EV_KEY, (c))
+
+static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_DIGITIZER &&
+ (usage->hid & 0xff) == 0x47) {
+ nt_map_key_clear(BTN_TOOL_DOUBLETAP);
+ return 1;
+ }
+ return 0;
+}
+
+static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if (usage->type == EV_KEY || usage->type == EV_REL
+ || usage->type == EV_ABS)
+ clear_bit(usage->code, *bit);
+
+ return 0;
+}
+static const struct hid_device_id ntrig_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN),
+ .driver_data = NTRIG_DUPLICATE_USAGES },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, ntrig_devices);
+
+static struct hid_driver ntrig_driver = {
+ .name = "ntrig",
+ .id_table = ntrig_devices,
+ .input_mapping = ntrig_input_mapping,
+ .input_mapped = ntrig_input_mapped,
+};
+
+static int ntrig_init(void)
+{
+ return hid_register_driver(&ntrig_driver);
+}
+
+static void ntrig_exit(void)
+{
+ hid_unregister_driver(&ntrig_driver);
+}
+
+module_init(ntrig_init);
+module_exit(ntrig_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(ntrig);
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 86e563b8d644..dd5a3979a4de 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -102,7 +102,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
ret = sony_set_operational(hdev);
- if (ret)
+ if (ret < 0)
goto err_stop;
return 0;
diff --git a/drivers/hid/hid-topseed.c b/drivers/hid/hid-topseed.c
new file mode 100644
index 000000000000..cca64a0564a9
--- /dev/null
+++ b/drivers/hid/hid-topseed.c
@@ -0,0 +1,77 @@
+/*
+ * HID driver for TopSeed Cyberlink remote
+ *
+ * Copyright (c) 2008 Lev Babiev
+ * based on hid-cherry driver
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define ts_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
+ EV_KEY, (c))
+static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) != 0x0ffbc0000)
+ return 0;
+
+ switch (usage->hid & HID_USAGE) {
+ case 0x00d: ts_map_key_clear(KEY_HOME); break;
+ case 0x024: ts_map_key_clear(KEY_MENU); break;
+ case 0x025: ts_map_key_clear(KEY_TV); break;
+ case 0x048: ts_map_key_clear(KEY_RED); break;
+ case 0x047: ts_map_key_clear(KEY_GREEN); break;
+ case 0x049: ts_map_key_clear(KEY_YELLOW); break;
+ case 0x04a: ts_map_key_clear(KEY_BLUE); break;
+ case 0x04b: ts_map_key_clear(KEY_ANGLE); break;
+ case 0x04c: ts_map_key_clear(KEY_LANGUAGE); break;
+ case 0x04d: ts_map_key_clear(KEY_SUBTITLE); break;
+ case 0x031: ts_map_key_clear(KEY_AUDIO); break;
+ case 0x032: ts_map_key_clear(KEY_TEXT); break;
+ case 0x033: ts_map_key_clear(KEY_CHANNEL); break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static const struct hid_device_id ts_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, ts_devices);
+
+static struct hid_driver ts_driver = {
+ .name = "topseed",
+ .id_table = ts_devices,
+ .input_mapping = ts_input_mapping,
+};
+
+static int ts_init(void)
+{
+ return hid_register_driver(&ts_driver);
+}
+
+static void ts_exit(void)
+{
+ hid_unregister_driver(&ts_driver);
+}
+
+module_init(ts_init);
+module_exit(ts_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(topseed);
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 7685ae6808c4..732449628971 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -208,7 +208,7 @@ static int hidraw_release(struct inode * inode, struct file * file)
list_del(&list->node);
dev = hidraw_table[minor];
- if (!dev->open--) {
+ if (!--dev->open) {
if (list->hidraw->exist)
dev->hid->ll_driver->close(dev->hid);
else
@@ -265,6 +265,34 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
break;
}
default:
+ {
+ struct hid_device *hid = dev->hid;
+ if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ)
+ return -EINVAL;
+
+ if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWNAME(0))) {
+ int len;
+ if (!hid->name)
+ return 0;
+ len = strlen(hid->name) + 1;
+ if (len > _IOC_SIZE(cmd))
+ len = _IOC_SIZE(cmd);
+ return copy_to_user(user_arg, hid->name, len) ?
+ -EFAULT : len;
+ }
+
+ if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWPHYS(0))) {
+ int len;
+ if (!hid->phys)
+ return 0;
+ len = strlen(hid->phys) + 1;
+ if (len > _IOC_SIZE(cmd))
+ len = _IOC_SIZE(cmd);
+ return copy_to_user(user_arg, hid->phys, len) ?
+ -EFAULT : len;
+ }
+ }
+
ret = -ENOTTY;
}
unlock_kernel();
@@ -329,7 +357,7 @@ int hidraw_connect(struct hid_device *hid)
goto out;
}
- dev->dev = device_create(hidraw_class, NULL, MKDEV(hidraw_major, minor),
+ dev->dev = device_create(hidraw_class, &hid->dev, MKDEV(hidraw_major, minor),
NULL, "%s%d", "hidraw", minor);
if (IS_ERR(dev->dev)) {
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig
index 5d9aa95fc3ef..4edb3bef94a6 100644
--- a/drivers/hid/usbhid/Kconfig
+++ b/drivers/hid/usbhid/Kconfig
@@ -45,7 +45,7 @@ config USB_HIDDEV
If unsure, say Y.
menu "USB HID Boot Protocol drivers"
- depends on USB!=n && USB_HID!=y
+ depends on USB!=n && USB_HID!=y && EMBEDDED
config USB_KBD
tristate "USB HIDBP Keyboard (simple Boot) support"
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 606369ea24ca..03cb494af1c5 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -4,7 +4,7 @@
* Copyright (c) 1999 Andreas Gal
* Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
- * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2006-2008 Jiri Kosina
*/
/*
@@ -641,9 +641,7 @@ static void hid_find_max_report(struct hid_device *hid, unsigned int type,
unsigned int size;
list_for_each_entry(report, &hid->report_enum[type].report_list, list) {
- size = ((report->size - 1) >> 3) + 1;
- if (type == HID_INPUT_REPORT && hid->report_enum[type].numbered)
- size++;
+ size = ((report->size - 1) >> 3) + 1 + hid->report_enum[type].numbered;
if (*max < size)
*max = size;
}
@@ -653,13 +651,16 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
- if (!(usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->inbuf_dma)))
- return -1;
- if (!(usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->outbuf_dma)))
- return -1;
- if (!(usbhid->cr = usb_buffer_alloc(dev, sizeof(*(usbhid->cr)), GFP_ATOMIC, &usbhid->cr_dma)))
- return -1;
- if (!(usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->ctrlbuf_dma)))
+ usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_KERNEL,
+ &usbhid->inbuf_dma);
+ usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_KERNEL,
+ &usbhid->outbuf_dma);
+ usbhid->cr = usb_buffer_alloc(dev, sizeof(*usbhid->cr), GFP_KERNEL,
+ &usbhid->cr_dma);
+ usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_KERNEL,
+ &usbhid->ctrlbuf_dma);
+ if (!usbhid->inbuf || !usbhid->outbuf || !usbhid->cr ||
+ !usbhid->ctrlbuf)
return -1;
return 0;
@@ -807,7 +808,7 @@ static int usbhid_start(struct hid_device *hid)
int interval;
endpoint = &interface->endpoint[n].desc;
- if ((endpoint->bmAttributes & 3) != 3) /* Not an interrupt endpoint */
+ if (!usb_endpoint_xfer_int(endpoint))
continue;
interval = endpoint->bInterval;
@@ -876,6 +877,15 @@ static int usbhid_start(struct hid_device *hid)
set_bit(HID_STARTED, &usbhid->iofl);
+ /* Some keyboards don't work until their LEDs have been set.
+ * Since BIOSes do set the LEDs, it must be safe for any device
+ * that supports the keyboard boot protocol.
+ */
+ if (interface->desc.bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT &&
+ interface->desc.bInterfaceProtocol ==
+ USB_INTERFACE_PROTOCOL_KEYBOARD)
+ usbhid_set_leds(hid);
+
return 0;
fail:
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 47ebe045f9b5..4391717d2519 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -54,6 +54,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index 83e851a5ed30..6a98f9f572b0 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -49,6 +49,7 @@
struct hiddev {
int exist;
int open;
+ struct mutex existancelock;
wait_queue_head_t wait;
struct hid_device *hid;
struct list_head list;
@@ -63,6 +64,7 @@ struct hiddev_list {
struct fasync_struct *fasync;
struct hiddev *hiddev;
struct list_head node;
+ struct mutex thread_lock;
};
static struct hiddev *hiddev_table[HIDDEV_MINORS];
@@ -264,29 +266,48 @@ static int hiddev_release(struct inode * inode, struct file * file)
static int hiddev_open(struct inode *inode, struct file *file)
{
struct hiddev_list *list;
- unsigned long flags;
+ int res;
int i = iminor(inode) - HIDDEV_MINOR_BASE;
- if (i >= HIDDEV_MINORS || !hiddev_table[i])
+ if (i >= HIDDEV_MINORS || i < 0 || !hiddev_table[i])
return -ENODEV;
if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
return -ENOMEM;
+ mutex_init(&list->thread_lock);
list->hiddev = hiddev_table[i];
- spin_lock_irqsave(&list->hiddev->list_lock, flags);
- list_add_tail(&list->node, &hiddev_table[i]->list);
- spin_unlock_irqrestore(&list->hiddev->list_lock, flags);
file->private_data = list;
- if (!list->hiddev->open++)
- if (list->hiddev->exist)
- usbhid_open(hiddev_table[i]->hid);
+ /*
+ * no need for locking because the USB major number
+ * is shared which usbcore guards against disconnect
+ */
+ if (list->hiddev->exist) {
+ if (!list->hiddev->open++) {
+ res = usbhid_open(hiddev_table[i]->hid);
+ if (res < 0) {
+ res = -EIO;
+ goto bail;
+ }
+ }
+ } else {
+ res = -ENODEV;
+ goto bail;
+ }
+
+ spin_lock_irq(&list->hiddev->list_lock);
+ list_add_tail(&list->node, &hiddev_table[i]->list);
+ spin_unlock_irq(&list->hiddev->list_lock);
return 0;
+bail:
+ file->private_data = NULL;
+ kfree(list->hiddev);
+ return res;
}
/*
@@ -305,7 +326,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
DECLARE_WAITQUEUE(wait, current);
struct hiddev_list *list = file->private_data;
int event_size;
- int retval = 0;
+ int retval;
event_size = ((list->flags & HIDDEV_FLAG_UREF) != 0) ?
sizeof(struct hiddev_usage_ref) : sizeof(struct hiddev_event);
@@ -313,10 +334,14 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
if (count < event_size)
return 0;
+ /* lock against other threads */
+ retval = mutex_lock_interruptible(&list->thread_lock);
+ if (retval)
+ return -ERESTARTSYS;
+
while (retval == 0) {
if (list->head == list->tail) {
- add_wait_queue(&list->hiddev->wait, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
+ prepare_to_wait(&list->hiddev->wait, &wait, TASK_INTERRUPTIBLE);
while (list->head == list->tail) {
if (file->f_flags & O_NONBLOCK) {
@@ -332,35 +357,45 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
break;
}
+ /* let O_NONBLOCK tasks run */
+ mutex_unlock(&list->thread_lock);
schedule();
+ if (mutex_lock_interruptible(&list->thread_lock))
+ return -EINTR;
set_current_state(TASK_INTERRUPTIBLE);
}
+ finish_wait(&list->hiddev->wait, &wait);
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&list->hiddev->wait, &wait);
}
- if (retval)
+ if (retval) {
+ mutex_unlock(&list->thread_lock);
return retval;
+ }
while (list->head != list->tail &&
retval + event_size <= count) {
if ((list->flags & HIDDEV_FLAG_UREF) == 0) {
- if (list->buffer[list->tail].field_index !=
- HID_FIELD_INDEX_NONE) {
+ if (list->buffer[list->tail].field_index != HID_FIELD_INDEX_NONE) {
struct hiddev_event event;
+
event.hid = list->buffer[list->tail].usage_code;
event.value = list->buffer[list->tail].value;
- if (copy_to_user(buffer + retval, &event, sizeof(struct hiddev_event)))
+ if (copy_to_user(buffer + retval, &event, sizeof(struct hiddev_event))) {
+ mutex_unlock(&list->thread_lock);
return -EFAULT;
+ }
retval += sizeof(struct hiddev_event);
}
} else {
if (list->buffer[list->tail].field_index != HID_FIELD_INDEX_NONE ||
(list->flags & HIDDEV_FLAG_REPORT) != 0) {
- if (copy_to_user(buffer + retval, list->buffer + list->tail, sizeof(struct hiddev_usage_ref)))
+
+ if (copy_to_user(buffer + retval, list->buffer + list->tail, sizeof(struct hiddev_usage_ref))) {
+ mutex_unlock(&list->thread_lock);
return -EFAULT;
+ }
retval += sizeof(struct hiddev_usage_ref);
}
}
@@ -368,6 +403,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
}
}
+ mutex_unlock(&list->thread_lock);
return retval;
}
@@ -555,7 +591,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct hid_field *field;
struct usbhid_device *usbhid = hid->driver_data;
void __user *user_arg = (void __user *)arg;
- int i;
+ int i, r;
/* Called without BKL by compat methods so no BKL taken */
@@ -619,10 +655,22 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
case HIDIOCGSTRING:
- return hiddev_ioctl_string(hiddev, cmd, user_arg);
+ mutex_lock(&hiddev->existancelock);
+ if (!hiddev->exist)
+ r = hiddev_ioctl_string(hiddev, cmd, user_arg);
+ else
+ r = -ENODEV;
+ mutex_unlock(&hiddev->existancelock);
+ return r;
case HIDIOCINITREPORT:
+ mutex_lock(&hiddev->existancelock);
+ if (!hiddev->exist) {
+ mutex_unlock(&hiddev->existancelock);
+ return -ENODEV;
+ }
usbhid_init_reports(hid);
+ mutex_unlock(&hiddev->existancelock);
return 0;
@@ -636,8 +684,12 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
return -EINVAL;
- usbhid_submit_report(hid, report, USB_DIR_IN);
- usbhid_wait_io(hid);
+ mutex_lock(&hiddev->existancelock);
+ if (hiddev->exist) {
+ usbhid_submit_report(hid, report, USB_DIR_IN);
+ usbhid_wait_io(hid);
+ }
+ mutex_unlock(&hiddev->existancelock);
return 0;
@@ -651,8 +703,12 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
return -EINVAL;
- usbhid_submit_report(hid, report, USB_DIR_OUT);
- usbhid_wait_io(hid);
+ mutex_lock(&hiddev->existancelock);
+ if (hiddev->exist) {
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
+ usbhid_wait_io(hid);
+ }
+ mutex_unlock(&hiddev->existancelock);
return 0;
@@ -710,7 +766,13 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case HIDIOCGUSAGES:
case HIDIOCSUSAGES:
case HIDIOCGCOLLECTIONINDEX:
- return hiddev_ioctl_usage(hiddev, cmd, user_arg);
+ mutex_lock(&hiddev->existancelock);
+ if (hiddev->exist)
+ r = hiddev_ioctl_usage(hiddev, cmd, user_arg);
+ else
+ r = -ENODEV;
+ mutex_unlock(&hiddev->existancelock);
+ return r;
case HIDIOCGCOLLECTIONINFO:
if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))
@@ -808,23 +870,22 @@ int hiddev_connect(struct hid_device *hid, unsigned int force)
if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL)))
return -1;
- retval = usb_register_dev(usbhid->intf, &hiddev_class);
- if (retval) {
- err_hid("Not able to get a minor for this device.");
- kfree(hiddev);
- return -1;
- }
-
init_waitqueue_head(&hiddev->wait);
INIT_LIST_HEAD(&hiddev->list);
spin_lock_init(&hiddev->list_lock);
+ mutex_init(&hiddev->existancelock);
hiddev->hid = hid;
hiddev->exist = 1;
- hid->minor = usbhid->intf->minor;
- hid->hiddev = hiddev;
-
- hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
+ retval = usb_register_dev(usbhid->intf, &hiddev_class);
+ if (retval) {
+ err_hid("Not able to get a minor for this device.");
+ kfree(hiddev);
+ return -1;
+ } else {
+ hid->minor = usbhid->intf->minor;
+ hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
+ }
return 0;
}
@@ -839,7 +900,9 @@ void hiddev_disconnect(struct hid_device *hid)
struct hiddev *hiddev = hid->hiddev;
struct usbhid_device *usbhid = hid->driver_data;
+ mutex_lock(&hiddev->existancelock);
hiddev->exist = 0;
+ mutex_unlock(&hiddev->existancelock);
hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL;
usb_deregister_dev(usbhid->intf, &hiddev_class);
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index 332abcdf9956..9eb30564be9c 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -40,6 +40,16 @@ int usbhid_open(struct hid_device *hid);
void usbhid_init_reports(struct hid_device *hid);
void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir);
+/* iofl flags */
+#define HID_CTRL_RUNNING 1
+#define HID_OUT_RUNNING 2
+#define HID_IN_RUNNING 3
+#define HID_RESET_PENDING 4
+#define HID_SUSPENDED 5
+#define HID_CLEAR_HALT 6
+#define HID_DISCONNECTED 7
+#define HID_STARTED 8
+
/*
* USB-specific HID struct, to be pointed to
* from struct hid_device->driver_data
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 608038d64f81..be8ee2cac8bb 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -2,13 +2,16 @@
* TI OMAP I2C master mode driver
*
* Copyright (C) 2003 MontaVista Software, Inc.
- * Copyright (C) 2004 Texas Instruments.
- *
- * Updated to work with multiple I2C interfaces on 24xx by
- * Tony Lindgren <tony@atomide.com> and Imre Deak <imre.deak@nokia.com>
* Copyright (C) 2005 Nokia Corporation
+ * Copyright (C) 2004 - 2007 Texas Instruments.
*
- * Cleaned up by Juha Yrjölä <juha.yrjola@nokia.com>
+ * Originally written by MontaVista Software, Inc.
+ * Additional contributions by:
+ * Tony Lindgren <tony@atomide.com>
+ * Imre Deak <imre.deak@nokia.com>
+ * Juha Yrjölä <juha.yrjola@solidboot.com>
+ * Syed Khasim <x0khasim@ti.com>
+ * Nishant Menon <nm@ti.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -33,8 +36,14 @@
#include <linux/completion.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/io.h>
+
+/* I2C controller revisions */
+#define OMAP_I2C_REV_2 0x20
-#include <asm/io.h>
+/* I2C controller revisions present on specific hardware */
+#define OMAP_I2C_REV_ON_2430 0x36
+#define OMAP_I2C_REV_ON_3430 0x3C
/* timeout waiting for the controller to respond */
#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
@@ -43,6 +52,8 @@
#define OMAP_I2C_IE_REG 0x04
#define OMAP_I2C_STAT_REG 0x08
#define OMAP_I2C_IV_REG 0x0c
+/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */
+#define OMAP_I2C_WE_REG 0x0c
#define OMAP_I2C_SYSS_REG 0x10
#define OMAP_I2C_BUF_REG 0x14
#define OMAP_I2C_CNT_REG 0x18
@@ -55,8 +66,11 @@
#define OMAP_I2C_SCLL_REG 0x34
#define OMAP_I2C_SCLH_REG 0x38
#define OMAP_I2C_SYSTEST_REG 0x3c
+#define OMAP_I2C_BUFSTAT_REG 0x40
/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
+#define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drain int enable */
+#define OMAP_I2C_IE_RDR (1 << 13) /* RX Buffer drain int enable */
#define OMAP_I2C_IE_XRDY (1 << 4) /* TX data ready int enable */
#define OMAP_I2C_IE_RRDY (1 << 3) /* RX data ready int enable */
#define OMAP_I2C_IE_ARDY (1 << 2) /* Access ready int enable */
@@ -64,7 +78,8 @@
#define OMAP_I2C_IE_AL (1 << 0) /* Arbitration lost int ena */
/* I2C Status Register (OMAP_I2C_STAT): */
-#define OMAP_I2C_STAT_SBD (1 << 15) /* Single byte data */
+#define OMAP_I2C_STAT_XDR (1 << 14) /* TX Buffer draining */
+#define OMAP_I2C_STAT_RDR (1 << 13) /* RX Buffer draining */
#define OMAP_I2C_STAT_BB (1 << 12) /* Bus busy */
#define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */
#define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
@@ -76,13 +91,34 @@
#define OMAP_I2C_STAT_NACK (1 << 1) /* No ack interrupt enable */
#define OMAP_I2C_STAT_AL (1 << 0) /* Arbitration lost int ena */
+/* I2C WE wakeup enable register */
+#define OMAP_I2C_WE_XDR_WE (1 << 14) /* TX drain wakup */
+#define OMAP_I2C_WE_RDR_WE (1 << 13) /* RX drain wakeup */
+#define OMAP_I2C_WE_AAS_WE (1 << 9) /* Address as slave wakeup*/
+#define OMAP_I2C_WE_BF_WE (1 << 8) /* Bus free wakeup */
+#define OMAP_I2C_WE_STC_WE (1 << 6) /* Start condition wakeup */
+#define OMAP_I2C_WE_GC_WE (1 << 5) /* General call wakeup */
+#define OMAP_I2C_WE_DRDY_WE (1 << 3) /* TX/RX data ready wakeup */
+#define OMAP_I2C_WE_ARDY_WE (1 << 2) /* Reg access ready wakeup */
+#define OMAP_I2C_WE_NACK_WE (1 << 1) /* No acknowledgment wakeup */
+#define OMAP_I2C_WE_AL_WE (1 << 0) /* Arbitration lost wakeup */
+
+#define OMAP_I2C_WE_ALL (OMAP_I2C_WE_XDR_WE | OMAP_I2C_WE_RDR_WE | \
+ OMAP_I2C_WE_AAS_WE | OMAP_I2C_WE_BF_WE | \
+ OMAP_I2C_WE_STC_WE | OMAP_I2C_WE_GC_WE | \
+ OMAP_I2C_WE_DRDY_WE | OMAP_I2C_WE_ARDY_WE | \
+ OMAP_I2C_WE_NACK_WE | OMAP_I2C_WE_AL_WE)
+
/* I2C Buffer Configuration Register (OMAP_I2C_BUF): */
#define OMAP_I2C_BUF_RDMA_EN (1 << 15) /* RX DMA channel enable */
+#define OMAP_I2C_BUF_RXFIF_CLR (1 << 14) /* RX FIFO Clear */
#define OMAP_I2C_BUF_XDMA_EN (1 << 7) /* TX DMA channel enable */
+#define OMAP_I2C_BUF_TXFIF_CLR (1 << 6) /* TX FIFO Clear */
/* I2C Configuration Register (OMAP_I2C_CON): */
#define OMAP_I2C_CON_EN (1 << 15) /* I2C module enable */
#define OMAP_I2C_CON_BE (1 << 14) /* Big endian mode */
+#define OMAP_I2C_CON_OPMODE_HS (1 << 12) /* High Speed support */
#define OMAP_I2C_CON_STB (1 << 11) /* Start byte mode (master) */
#define OMAP_I2C_CON_MST (1 << 10) /* Master/slave mode */
#define OMAP_I2C_CON_TRX (1 << 9) /* TX/RX mode (master only) */
@@ -91,6 +127,10 @@
#define OMAP_I2C_CON_STP (1 << 1) /* Stop cond (master only) */
#define OMAP_I2C_CON_STT (1 << 0) /* Start condition (master) */
+/* I2C SCL time value when Master */
+#define OMAP_I2C_SCLL_HSSCLL 8
+#define OMAP_I2C_SCLH_HSSCLH 8
+
/* I2C System Test Register (OMAP_I2C_SYSTEST): */
#ifdef DEBUG
#define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */
@@ -103,17 +143,19 @@
#define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive out */
#endif
-/* I2C System Status register (OMAP_I2C_SYSS): */
-#define OMAP_I2C_SYSS_RDONE (1 << 0) /* Reset Done */
+/* OCP_SYSSTATUS bit definitions */
+#define SYSS_RESETDONE_MASK (1 << 0)
+
+/* OCP_SYSCONFIG bit definitions */
+#define SYSC_CLOCKACTIVITY_MASK (0x3 << 8)
+#define SYSC_SIDLEMODE_MASK (0x3 << 3)
+#define SYSC_ENAWAKEUP_MASK (1 << 2)
+#define SYSC_SOFTRESET_MASK (1 << 1)
+#define SYSC_AUTOIDLE_MASK (1 << 0)
-/* I2C System Configuration Register (OMAP_I2C_SYSC): */
-#define OMAP_I2C_SYSC_SRST (1 << 1) /* Soft Reset */
+#define SYSC_IDLEMODE_SMART 0x2
+#define SYSC_CLOCKACTIVITY_FCLK 0x2
-/* REVISIT: Use platform_data instead of module parameters */
-/* Fast Mode = 400 kHz, Standard = 100 kHz */
-static int clock = 100; /* Default: 100 kHz */
-module_param(clock, int, 0);
-MODULE_PARM_DESC(clock, "Set I2C clock in kHz: 400=fast mode (default == 100)");
struct omap_i2c_dev {
struct device *dev;
@@ -123,11 +165,17 @@ struct omap_i2c_dev {
struct clk *fclk; /* Functional clock */
struct completion cmd_complete;
struct resource *ioarea;
+ u32 speed; /* Speed of bus in Khz */
u16 cmd_err;
u8 *buf;
size_t buf_len;
struct i2c_adapter adapter;
- unsigned rev1:1;
+ u8 fifo_size; /* use as flag and value
+ * fifo_size==0 implies no fifo
+ * if set, should be trsh+1
+ */
+ u8 rev;
+ unsigned b_hw:1; /* bad h/w fixes */
unsigned idle:1;
u16 iestate; /* Saved interrupt register */
};
@@ -143,9 +191,9 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
return __raw_readw(i2c_dev->base + reg);
}
-static int omap_i2c_get_clocks(struct omap_i2c_dev *dev)
+static int __init omap_i2c_get_clocks(struct omap_i2c_dev *dev)
{
- if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
+ if (cpu_is_omap16xx() || cpu_class_is_omap2()) {
dev->iclk = clk_get(dev->dev, "i2c_ick");
if (IS_ERR(dev->iclk)) {
dev->iclk = NULL;
@@ -178,25 +226,33 @@ static void omap_i2c_put_clocks(struct omap_i2c_dev *dev)
static void omap_i2c_unidle(struct omap_i2c_dev *dev)
{
+ WARN_ON(!dev->idle);
+
if (dev->iclk != NULL)
clk_enable(dev->iclk);
clk_enable(dev->fclk);
+ dev->idle = 0;
if (dev->iestate)
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
- dev->idle = 0;
}
static void omap_i2c_idle(struct omap_i2c_dev *dev)
{
u16 iv;
- dev->idle = 1;
+ WARN_ON(dev->idle);
+
dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0);
- if (dev->rev1)
- iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
- else
+ if (dev->rev < OMAP_I2C_REV_2) {
+ iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */
+ } else {
omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate);
+
+ /* Flush posted write before the dev->idle store occurs */
+ omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+ }
+ dev->idle = 1;
clk_disable(dev->fclk);
if (dev->iclk != NULL)
clk_disable(dev->iclk);
@@ -204,18 +260,20 @@ static void omap_i2c_idle(struct omap_i2c_dev *dev)
static int omap_i2c_init(struct omap_i2c_dev *dev)
{
- u16 psc = 0;
+ u16 psc = 0, scll = 0, sclh = 0;
+ u16 fsscll = 0, fssclh = 0, hsscll = 0, hssclh = 0;
unsigned long fclk_rate = 12000000;
unsigned long timeout;
+ unsigned long internal_clk = 0;
- if (!dev->rev1) {
- omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, OMAP_I2C_SYSC_SRST);
+ if (dev->rev >= OMAP_I2C_REV_2) {
+ omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, SYSC_SOFTRESET_MASK);
/* For some reason we need to set the EN bit before the
* reset done bit gets set. */
timeout = jiffies + OMAP_I2C_TIMEOUT;
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
while (!(omap_i2c_read_reg(dev, OMAP_I2C_SYSS_REG) &
- OMAP_I2C_SYSS_RDONE)) {
+ SYSS_RESETDONE_MASK)) {
if (time_after(jiffies, timeout)) {
dev_warn(dev->dev, "timeout waiting "
"for controller reset\n");
@@ -223,6 +281,33 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
}
msleep(1);
}
+
+ /* SYSC register is cleared by the reset; rewrite it */
+ if (dev->rev == OMAP_I2C_REV_ON_2430) {
+
+ omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG,
+ SYSC_AUTOIDLE_MASK);
+
+ } else if (dev->rev >= OMAP_I2C_REV_ON_3430) {
+ u32 v;
+
+ v = SYSC_AUTOIDLE_MASK;
+ v |= SYSC_ENAWAKEUP_MASK;
+ v |= (SYSC_IDLEMODE_SMART <<
+ __ffs(SYSC_SIDLEMODE_MASK));
+ v |= (SYSC_CLOCKACTIVITY_FCLK <<
+ __ffs(SYSC_CLOCKACTIVITY_MASK));
+
+ omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, v);
+ /*
+ * Enabling all wakup sources to stop I2C freezing on
+ * WFI instruction.
+ * REVISIT: Some wkup sources might not be needed.
+ */
+ omap_i2c_write_reg(dev, OMAP_I2C_WE_REG,
+ OMAP_I2C_WE_ALL);
+
+ }
}
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
@@ -249,27 +334,65 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)
psc = fclk_rate / 12000000;
}
+ if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+
+ /* HSI2C controller internal clk rate should be 19.2 Mhz */
+ internal_clk = 19200;
+ fclk_rate = clk_get_rate(dev->fclk) / 1000;
+
+ /* Compute prescaler divisor */
+ psc = fclk_rate / internal_clk;
+ psc = psc - 1;
+
+ /* If configured for High Speed */
+ if (dev->speed > 400) {
+ /* For first phase of HS mode */
+ fsscll = internal_clk / (400 * 2) - 6;
+ fssclh = internal_clk / (400 * 2) - 6;
+
+ /* For second phase of HS mode */
+ hsscll = fclk_rate / (dev->speed * 2) - 6;
+ hssclh = fclk_rate / (dev->speed * 2) - 6;
+ } else {
+ /* To handle F/S modes */
+ fsscll = internal_clk / (dev->speed * 2) - 6;
+ fssclh = internal_clk / (dev->speed * 2) - 6;
+ }
+ scll = (hsscll << OMAP_I2C_SCLL_HSSCLL) | fsscll;
+ sclh = (hssclh << OMAP_I2C_SCLH_HSSCLH) | fssclh;
+ } else {
+ /* Program desired operating rate */
+ fclk_rate /= (psc + 1) * 1000;
+ if (psc > 2)
+ psc = 2;
+ scll = fclk_rate / (dev->speed * 2) - 7 + psc;
+ sclh = fclk_rate / (dev->speed * 2) - 7 + psc;
+ }
+
/* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc);
- /* Program desired operating rate */
- fclk_rate /= (psc + 1) * 1000;
- if (psc > 2)
- psc = 2;
+ /* SCL low and high time values */
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll);
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh);
- omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG,
- fclk_rate / (clock * 2) - 7 + psc);
- omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG,
- fclk_rate / (clock * 2) - 7 + psc);
+ if (dev->fifo_size)
+ /* Note: setup required fifo size - 1 */
+ omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG,
+ (dev->fifo_size - 1) << 8 | /* RTRSH */
+ OMAP_I2C_BUF_RXFIF_CLR |
+ (dev->fifo_size - 1) | /* XTRSH */
+ OMAP_I2C_BUF_TXFIF_CLR);
/* Take the I2C module out of reset: */
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
/* Enable interrupts */
omap_i2c_write_reg(dev, OMAP_I2C_IE_REG,
- (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
- OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
- OMAP_I2C_IE_AL));
+ (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
+ OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
+ OMAP_I2C_IE_AL) | ((dev->fifo_size) ?
+ (OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0));
return 0;
}
@@ -316,20 +439,59 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);
+ /* Clear the FIFO Buffers */
+ w = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG);
+ w |= OMAP_I2C_BUF_RXFIF_CLR | OMAP_I2C_BUF_TXFIF_CLR;
+ omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, w);
+
init_completion(&dev->cmd_complete);
dev->cmd_err = 0;
w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
+
+ /* High speed configuration */
+ if (dev->speed > 400)
+ w |= OMAP_I2C_CON_OPMODE_HS;
+
if (msg->flags & I2C_M_TEN)
w |= OMAP_I2C_CON_XA;
if (!(msg->flags & I2C_M_RD))
w |= OMAP_I2C_CON_TRX;
- if (stop)
+
+ if (!dev->b_hw && stop)
w |= OMAP_I2C_CON_STP;
+
omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
- r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
- OMAP_I2C_TIMEOUT);
+ /*
+ * Don't write stt and stp together on some hardware.
+ */
+ if (dev->b_hw && stop) {
+ unsigned long delay = jiffies + OMAP_I2C_TIMEOUT;
+ u16 con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+ while (con & OMAP_I2C_CON_STT) {
+ con = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+
+ /* Let the user know if i2c is in a bad state */
+ if (time_after(jiffies, delay)) {
+ dev_err(dev->dev, "controller timed out "
+ "waiting for start condition to finish\n");
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+ }
+
+ w |= OMAP_I2C_CON_STP;
+ w &= ~OMAP_I2C_CON_STT;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+ }
+
+ /*
+ * REVISIT: We should abort the transfer on signals, but the bus goes
+ * into arbitration and we're currently unable to recover from it.
+ */
+ r = wait_for_completion_timeout(&dev->cmd_complete,
+ OMAP_I2C_TIMEOUT);
dev->buf_len = 0;
if (r < 0)
return r;
@@ -376,7 +538,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
omap_i2c_unidle(dev);
- if ((r = omap_i2c_wait_for_bb(dev)) < 0)
+ r = omap_i2c_wait_for_bb(dev);
+ if (r < 0)
goto out;
for (i = 0; i < num; i++) {
@@ -411,6 +574,9 @@ omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat)
omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
}
+/* rev1 devices are apparently only on some 15xx */
+#ifdef CONFIG_ARCH_OMAP15XX
+
static irqreturn_t
omap_i2c_rev1_isr(int this_irq, void *dev_id)
{
@@ -465,6 +631,9 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id)
return IRQ_HANDLED;
}
+#else
+#define omap_i2c_rev1_isr NULL
+#endif
static irqreturn_t
omap_i2c_isr(int this_irq, void *dev_id)
@@ -472,7 +641,7 @@ omap_i2c_isr(int this_irq, void *dev_id)
struct omap_i2c_dev *dev = dev_id;
u16 bits;
u16 stat, w;
- int count = 0;
+ int err, count = 0;
if (dev->idle)
return IRQ_NONE;
@@ -487,39 +656,96 @@ omap_i2c_isr(int this_irq, void *dev_id)
omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
- if (stat & OMAP_I2C_STAT_ARDY) {
- omap_i2c_complete_cmd(dev, 0);
- continue;
+ err = 0;
+ if (stat & OMAP_I2C_STAT_NACK) {
+ err |= OMAP_I2C_STAT_NACK;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
+ OMAP_I2C_CON_STP);
}
- if (stat & OMAP_I2C_STAT_RRDY) {
- w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
- if (dev->buf_len) {
- *dev->buf++ = w;
- dev->buf_len--;
+ if (stat & OMAP_I2C_STAT_AL) {
+ dev_err(dev->dev, "Arbitration lost\n");
+ err |= OMAP_I2C_STAT_AL;
+ }
+ if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
+ OMAP_I2C_STAT_AL))
+ omap_i2c_complete_cmd(dev, err);
+ if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
+ u8 num_bytes = 1;
+ if (dev->fifo_size) {
+ if (stat & OMAP_I2C_STAT_RRDY)
+ num_bytes = dev->fifo_size;
+ else
+ num_bytes = omap_i2c_read_reg(dev,
+ OMAP_I2C_BUFSTAT_REG);
+ }
+ while (num_bytes) {
+ num_bytes--;
+ w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
if (dev->buf_len) {
- *dev->buf++ = w >> 8;
+ *dev->buf++ = w;
dev->buf_len--;
+ /* Data reg from 2430 is 8 bit wide */
+ if (!cpu_is_omap2430() &&
+ !cpu_is_omap34xx()) {
+ if (dev->buf_len) {
+ *dev->buf++ = w >> 8;
+ dev->buf_len--;
+ }
+ }
+ } else {
+ if (stat & OMAP_I2C_STAT_RRDY)
+ dev_err(dev->dev,
+ "RRDY IRQ while no data"
+ " requested\n");
+ if (stat & OMAP_I2C_STAT_RDR)
+ dev_err(dev->dev,
+ "RDR IRQ while no data"
+ " requested\n");
+ break;
}
- } else
- dev_err(dev->dev, "RRDY IRQ while no data "
- "requested\n");
- omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY);
+ }
+ omap_i2c_ack_stat(dev,
+ stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR));
continue;
}
- if (stat & OMAP_I2C_STAT_XRDY) {
- w = 0;
- if (dev->buf_len) {
- w = *dev->buf++;
- dev->buf_len--;
+ if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) {
+ u8 num_bytes = 1;
+ if (dev->fifo_size) {
+ if (stat & OMAP_I2C_STAT_XRDY)
+ num_bytes = dev->fifo_size;
+ else
+ num_bytes = omap_i2c_read_reg(dev,
+ OMAP_I2C_BUFSTAT_REG);
+ }
+ while (num_bytes) {
+ num_bytes--;
+ w = 0;
if (dev->buf_len) {
- w |= *dev->buf++ << 8;
+ w = *dev->buf++;
dev->buf_len--;
+ /* Data reg from 2430 is 8 bit wide */
+ if (!cpu_is_omap2430() &&
+ !cpu_is_omap34xx()) {
+ if (dev->buf_len) {
+ w |= *dev->buf++ << 8;
+ dev->buf_len--;
+ }
+ }
+ } else {
+ if (stat & OMAP_I2C_STAT_XRDY)
+ dev_err(dev->dev,
+ "XRDY IRQ while no "
+ "data to send\n");
+ if (stat & OMAP_I2C_STAT_XDR)
+ dev_err(dev->dev,
+ "XDR IRQ while no "
+ "data to send\n");
+ break;
}
- } else
- dev_err(dev->dev, "XRDY IRQ while no "
- "data to send\n");
- omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
- omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY);
+ omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+ }
+ omap_i2c_ack_stat(dev,
+ stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
continue;
}
if (stat & OMAP_I2C_STAT_ROVR) {
@@ -527,18 +753,9 @@ omap_i2c_isr(int this_irq, void *dev_id)
dev->cmd_err |= OMAP_I2C_STAT_ROVR;
}
if (stat & OMAP_I2C_STAT_XUDF) {
- dev_err(dev->dev, "Transmit overflow\n");
+ dev_err(dev->dev, "Transmit underflow\n");
dev->cmd_err |= OMAP_I2C_STAT_XUDF;
}
- if (stat & OMAP_I2C_STAT_NACK) {
- omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
- omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
- OMAP_I2C_CON_STP);
- }
- if (stat & OMAP_I2C_STAT_AL) {
- dev_err(dev->dev, "Arbitration lost\n");
- omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
- }
}
return count ? IRQ_HANDLED : IRQ_NONE;
@@ -549,13 +766,15 @@ static const struct i2c_algorithm omap_i2c_algo = {
.functionality = omap_i2c_func,
};
-static int
+static int __init
omap_i2c_probe(struct platform_device *pdev)
{
struct omap_i2c_dev *dev;
struct i2c_adapter *adap;
struct resource *mem, *irq, *ioarea;
+ irq_handler_t isr;
int r;
+ u32 speed = 0;
/* NOTE: driver uses the static register mapping */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -576,17 +795,19 @@ omap_i2c_probe(struct platform_device *pdev)
return -EBUSY;
}
- if (clock > 200)
- clock = 400; /* Fast mode */
- else
- clock = 100; /* Standard mode */
-
dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL);
if (!dev) {
r = -ENOMEM;
goto err_release_region;
}
+ if (pdev->dev.platform_data != NULL)
+ speed = *(u32 *)pdev->dev.platform_data;
+ else
+ speed = 100; /* Defualt speed */
+
+ dev->speed = speed;
+ dev->idle = 1;
dev->dev = &pdev->dev;
dev->irq = irq->start;
dev->base = ioremap(mem->start, mem->end - mem->start + 1);
@@ -602,22 +823,39 @@ omap_i2c_probe(struct platform_device *pdev)
omap_i2c_unidle(dev);
- if (cpu_is_omap15xx())
- dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20;
+ dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
+
+ if (cpu_is_omap2430() || cpu_is_omap34xx()) {
+ u16 s;
+
+ /* Set up the fifo size - Get total size */
+ s = (omap_i2c_read_reg(dev, OMAP_I2C_BUFSTAT_REG) >> 14) & 0x3;
+ dev->fifo_size = 0x8 << s;
+
+ /*
+ * Set up notification threshold as half the total available
+ * size. This is to ensure that we can handle the status on int
+ * call back latencies.
+ */
+ dev->fifo_size = (dev->fifo_size / 2);
+ dev->b_hw = 1; /* Enable hardware fixes */
+ }
/* reset ASAP, clearing any IRQs */
omap_i2c_init(dev);
- r = request_irq(dev->irq, dev->rev1 ? omap_i2c_rev1_isr : omap_i2c_isr,
- 0, pdev->name, dev);
+ isr = (dev->rev < OMAP_I2C_REV_2) ? omap_i2c_rev1_isr : omap_i2c_isr;
+ r = request_irq(dev->irq, isr, 0, pdev->name, dev);
if (r) {
dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
goto err_unuse_clocks;
}
- r = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
+
dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n",
- pdev->id, r >> 4, r & 0xf, clock);
+ pdev->id, dev->rev >> 4, dev->rev & 0xf, dev->speed);
+
+ omap_i2c_idle(dev);
adap = &dev->adapter;
i2c_set_adapdata(adap, dev);
@@ -635,8 +873,6 @@ omap_i2c_probe(struct platform_device *pdev)
goto err_free_irq;
}
- omap_i2c_idle(dev);
-
return 0;
err_free_irq:
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index c39079f9c73f..f69f91ffb469 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -35,11 +35,9 @@
#include <linux/clk.h>
#include <linux/cpufreq.h>
-#include <mach/hardware.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <mach/regs-gpio.h>
#include <plat/regs-iic.h>
#include <plat/iic.h>
@@ -64,6 +62,7 @@ struct s3c24xx_i2c {
unsigned int msg_ptr;
unsigned int tx_setup;
+ unsigned int irq;
enum s3c24xx_i2c_state state;
unsigned long clkrate;
@@ -71,7 +70,6 @@ struct s3c24xx_i2c {
void __iomem *regs;
struct clk *clk;
struct device *dev;
- struct resource *irq;
struct resource *ioarea;
struct i2c_adapter adap;
@@ -80,16 +78,7 @@ struct s3c24xx_i2c {
#endif
};
-/* default platform data to use if not supplied in the platform_device
-*/
-
-static struct s3c2410_platform_i2c s3c24xx_i2c_default_platform = {
- .flags = 0,
- .slave_addr = 0x10,
- .bus_freq = 100*1000,
- .max_freq = 400*1000,
- .sda_delay = S3C2410_IICLC_SDA_DELAY5 | S3C2410_IICLC_FILTER_ON,
-};
+/* default platform data removed, dev should always carry data. */
/* s3c24xx_i2c_is2440()
*
@@ -103,21 +92,6 @@ static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c)
return !strcmp(pdev->name, "s3c2440-i2c");
}
-
-/* s3c24xx_i2c_get_platformdata
- *
- * get the platform data associated with the given device, or return
- * the default if there is none
-*/
-
-static inline struct s3c2410_platform_i2c *s3c24xx_i2c_get_platformdata(struct device *dev)
-{
- if (dev->platform_data != NULL)
- return (struct s3c2410_platform_i2c *)dev->platform_data;
-
- return &s3c24xx_i2c_default_platform;
-}
-
/* s3c24xx_i2c_master_complete
*
* complete the message and wake up the caller, using the given return code,
@@ -130,7 +104,7 @@ static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret)
i2c->msg_ptr = 0;
i2c->msg = NULL;
- i2c->msg_idx ++;
+ i2c->msg_idx++;
i2c->msg_num = 0;
if (ret)
i2c->msg_idx = ret;
@@ -141,19 +115,17 @@ static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret)
static inline void s3c24xx_i2c_disable_ack(struct s3c24xx_i2c *i2c)
{
unsigned long tmp;
-
+
tmp = readl(i2c->regs + S3C2410_IICCON);
writel(tmp & ~S3C2410_IICCON_ACKEN, i2c->regs + S3C2410_IICCON);
-
}
static inline void s3c24xx_i2c_enable_ack(struct s3c24xx_i2c *i2c)
{
unsigned long tmp;
-
+
tmp = readl(i2c->regs + S3C2410_IICCON);
writel(tmp | S3C2410_IICCON_ACKEN, i2c->regs + S3C2410_IICCON);
-
}
/* irq enable/disable functions */
@@ -161,7 +133,7 @@ static inline void s3c24xx_i2c_enable_ack(struct s3c24xx_i2c *i2c)
static inline void s3c24xx_i2c_disable_irq(struct s3c24xx_i2c *i2c)
{
unsigned long tmp;
-
+
tmp = readl(i2c->regs + S3C2410_IICCON);
writel(tmp & ~S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON);
}
@@ -169,7 +141,7 @@ static inline void s3c24xx_i2c_disable_irq(struct s3c24xx_i2c *i2c)
static inline void s3c24xx_i2c_enable_irq(struct s3c24xx_i2c *i2c)
{
unsigned long tmp;
-
+
tmp = readl(i2c->regs + S3C2410_IICCON);
writel(tmp | S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON);
}
@@ -177,10 +149,10 @@ static inline void s3c24xx_i2c_enable_irq(struct s3c24xx_i2c *i2c)
/* s3c24xx_i2c_message_start
*
- * put the start of a message onto the bus
+ * put the start of a message onto the bus
*/
-static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
+static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
struct i2c_msg *msg)
{
unsigned int addr = (msg->addr & 0x7f) << 1;
@@ -199,15 +171,15 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
if (msg->flags & I2C_M_REV_DIR_ADDR)
addr ^= 1;
- // todo - check for wether ack wanted or not
+ /* todo - check for wether ack wanted or not */
s3c24xx_i2c_enable_ack(i2c);
iiccon = readl(i2c->regs + S3C2410_IICCON);
writel(stat, i2c->regs + S3C2410_IICSTAT);
-
+
dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr);
writeb(addr, i2c->regs + S3C2410_IICDS);
-
+
/* delay here to ensure the data byte has gotten onto the bus
* before the transaction is started */
@@ -215,8 +187,8 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon);
writel(iiccon, i2c->regs + S3C2410_IICCON);
-
- stat |= S3C2410_IICSTAT_START;
+
+ stat |= S3C2410_IICSTAT_START;
writel(stat, i2c->regs + S3C2410_IICSTAT);
}
@@ -227,11 +199,11 @@ static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
dev_dbg(i2c->dev, "STOP\n");
/* stop the transfer */
- iicstat &= ~ S3C2410_IICSTAT_START;
+ iicstat &= ~S3C2410_IICSTAT_START;
writel(iicstat, i2c->regs + S3C2410_IICSTAT);
-
+
i2c->state = STATE_STOP;
-
+
s3c24xx_i2c_master_complete(i2c, ret);
s3c24xx_i2c_disable_irq(i2c);
}
@@ -241,7 +213,7 @@ static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
/* is_lastmsg()
*
- * returns TRUE if the current message is the last in the set
+ * returns TRUE if the current message is the last in the set
*/
static inline int is_lastmsg(struct s3c24xx_i2c *i2c)
@@ -289,14 +261,14 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
case STATE_STOP:
dev_err(i2c->dev, "%s: called in STATE_STOP\n", __func__);
- s3c24xx_i2c_disable_irq(i2c);
+ s3c24xx_i2c_disable_irq(i2c);
goto out_ack;
case STATE_START:
/* last thing we did was send a start condition on the
* bus, or started a new i2c message
*/
-
+
if (iicstat & S3C2410_IICSTAT_LASTBIT &&
!(i2c->msg->flags & I2C_M_IGNORE_NAK)) {
/* ack was not received... */
@@ -322,7 +294,7 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
if (i2c->state == STATE_READ)
goto prepare_read;
- /* fall through to the write state, as we will need to
+ /* fall through to the write state, as we will need to
* send a byte as well */
case STATE_WRITE:
@@ -339,7 +311,7 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
}
}
- retry_write:
+ retry_write:
if (!is_msgend(i2c)) {
byte = i2c->msg->buf[i2c->msg_ptr++];
@@ -359,9 +331,9 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
dev_dbg(i2c->dev, "WRITE: Next Message\n");
i2c->msg_ptr = 0;
- i2c->msg_idx ++;
+ i2c->msg_idx++;
i2c->msg++;
-
+
/* check to see if we need to do another message */
if (i2c->msg->flags & I2C_M_NOSTART) {
@@ -375,7 +347,6 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
goto retry_write;
} else {
-
/* send the new start */
s3c24xx_i2c_message_start(i2c, i2c->msg);
i2c->state = STATE_START;
@@ -389,7 +360,7 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
break;
case STATE_READ:
- /* we have a byte of data in the data register, do
+ /* we have a byte of data in the data register, do
* something with it, and then work out wether we are
* going to do any more read/write
*/
@@ -397,13 +368,13 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
byte = readb(i2c->regs + S3C2410_IICDS);
i2c->msg->buf[i2c->msg_ptr++] = byte;
- prepare_read:
+ prepare_read:
if (is_msglast(i2c)) {
/* last byte of buffer */
if (is_lastmsg(i2c))
s3c24xx_i2c_disable_ack(i2c);
-
+
} else if (is_msgend(i2c)) {
/* ok, we've read the entire buffer, see if there
* is anything else we need to do */
@@ -429,7 +400,7 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
/* acknowlegde the IRQ and get back on with the work */
out_ack:
- tmp = readl(i2c->regs + S3C2410_IICCON);
+ tmp = readl(i2c->regs + S3C2410_IICCON);
tmp &= ~S3C2410_IICCON_IRQPEND;
writel(tmp, i2c->regs + S3C2410_IICCON);
out:
@@ -450,19 +421,19 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
status = readl(i2c->regs + S3C2410_IICSTAT);
if (status & S3C2410_IICSTAT_ARBITR) {
- // deal with arbitration loss
+ /* deal with arbitration loss */
dev_err(i2c->dev, "deal with arbitration loss\n");
}
if (i2c->state == STATE_IDLE) {
dev_dbg(i2c->dev, "IRQ: error i2c->state == IDLE\n");
- tmp = readl(i2c->regs + S3C2410_IICCON);
+ tmp = readl(i2c->regs + S3C2410_IICCON);
tmp &= ~S3C2410_IICCON_IRQPEND;
writel(tmp, i2c->regs + S3C2410_IICCON);
goto out;
}
-
+
/* pretty much this leaves us with the fact that we've
* transmitted or received whatever byte we last sent */
@@ -485,16 +456,13 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
while (timeout-- > 0) {
iicstat = readl(i2c->regs + S3C2410_IICSTAT);
-
+
if (!(iicstat & S3C2410_IICSTAT_BUSBUSY))
return 0;
msleep(1);
}
- dev_dbg(i2c->dev, "timeout: GPEDAT is %08x\n",
- __raw_readl(S3C2410_GPEDAT));
-
return -ETIMEDOUT;
}
@@ -503,7 +471,8 @@ static int s3c24xx_i2c_set_master(struct s3c24xx_i2c *i2c)
* this starts an i2c transfer
*/
-static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int num)
+static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
+ struct i2c_msg *msgs, int num)
{
unsigned long timeout;
int ret;
@@ -529,12 +498,12 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int
s3c24xx_i2c_enable_irq(i2c);
s3c24xx_i2c_message_start(i2c, msgs);
spin_unlock_irq(&i2c->lock);
-
+
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
ret = i2c->msg_idx;
- /* having these next two as dev_err() makes life very
+ /* having these next two as dev_err() makes life very
* noisy when doing an i2cdetect */
if (timeout == 0)
@@ -591,19 +560,6 @@ static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
.functionality = s3c24xx_i2c_func,
};
-static struct s3c24xx_i2c s3c24xx_i2c = {
- .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_i2c.lock),
- .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait),
- .tx_setup = 50,
- .adap = {
- .name = "s3c2410-i2c",
- .owner = THIS_MODULE,
- .algo = &s3c24xx_i2c_algorithm,
- .retries = 2,
- .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
- },
-};
-
/* s3c24xx_i2c_calcdivisor
*
* return the divisor settings for a given frequency
@@ -643,7 +599,7 @@ static inline int freq_acceptable(unsigned int freq, unsigned int wanted)
{
int diff = freq - wanted;
- return (diff >= -2 && diff <= 2);
+ return diff >= -2 && diff <= 2;
}
/* s3c24xx_i2c_clockrate
@@ -655,7 +611,7 @@ static inline int freq_acceptable(unsigned int freq, unsigned int wanted)
static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
{
- struct s3c2410_platform_i2c *pdata;
+ struct s3c2410_platform_i2c *pdata = i2c->dev->platform_data;
unsigned long clkin = clk_get_rate(i2c->clk);
unsigned int divs, div1;
u32 iiccon;
@@ -663,10 +619,8 @@ static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
int start, end;
i2c->clkrate = clkin;
-
- pdata = s3c24xx_i2c_get_platformdata(i2c->adap.dev.parent);
clkin /= 1000; /* clkin now in KHz */
-
+
dev_dbg(i2c->dev, "pdata %p, freq %lu %lu..%lu\n",
pdata, pdata->bus_freq, pdata->min_freq, pdata->max_freq);
@@ -774,7 +728,7 @@ static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c)
/* s3c24xx_i2c_init
*
- * initialise the controller, set the IO lines and frequency
+ * initialise the controller, set the IO lines and frequency
*/
static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
@@ -785,15 +739,15 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
/* get the plafrom data */
- pdata = s3c24xx_i2c_get_platformdata(i2c->adap.dev.parent);
+ pdata = i2c->dev->platform_data;
/* inititalise the gpio */
- s3c2410_gpio_cfgpin(S3C2410_GPE15, S3C2410_GPE15_IICSDA);
- s3c2410_gpio_cfgpin(S3C2410_GPE14, S3C2410_GPE14_IICSCL);
+ if (pdata->cfg_gpio)
+ pdata->cfg_gpio(to_platform_device(i2c->dev));
/* write slave address */
-
+
writeb(pdata->slave_addr, i2c->regs + S3C2410_IICADD);
dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);
@@ -831,12 +785,32 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
static int s3c24xx_i2c_probe(struct platform_device *pdev)
{
- struct s3c24xx_i2c *i2c = &s3c24xx_i2c;
+ struct s3c24xx_i2c *i2c;
struct s3c2410_platform_i2c *pdata;
struct resource *res;
int ret;
- pdata = s3c24xx_i2c_get_platformdata(&pdev->dev);
+ pdata = pdev->dev.platform_data;
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -EINVAL;
+ }
+
+ i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL);
+ if (!i2c) {
+ dev_err(&pdev->dev, "no memory for state\n");
+ return -ENOMEM;
+ }
+
+ strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name));
+ i2c->adap.owner = THIS_MODULE;
+ i2c->adap.algo = &s3c24xx_i2c_algorithm;
+ i2c->adap.retries = 2;
+ i2c->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+ i2c->tx_setup = 50;
+
+ spin_lock_init(&i2c->lock);
+ init_waitqueue_head(&i2c->wait);
/* find the clock and enable it */
@@ -878,7 +852,8 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
goto err_ioarea;
}
- dev_dbg(&pdev->dev, "registers %p (%p, %p)\n", i2c->regs, i2c->ioarea, res);
+ dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",
+ i2c->regs, i2c->ioarea, res);
/* setup info block for the i2c core */
@@ -892,29 +867,23 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
goto err_iomap;
/* find the IRQ for this unit (note, this relies on the init call to
- * ensure no current IRQs pending
+ * ensure no current IRQs pending
*/
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (res == NULL) {
+ i2c->irq = ret = platform_get_irq(pdev, 0);
+ if (ret <= 0) {
dev_err(&pdev->dev, "cannot find IRQ\n");
- ret = -ENOENT;
goto err_iomap;
}
- ret = request_irq(res->start, s3c24xx_i2c_irq, IRQF_DISABLED,
- pdev->name, i2c);
+ ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED,
+ dev_name(&pdev->dev), i2c);
if (ret != 0) {
- dev_err(&pdev->dev, "cannot claim IRQ\n");
+ dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
goto err_iomap;
}
- i2c->irq = res;
-
- dev_dbg(&pdev->dev, "irq resource %p (%lu)\n", res,
- (unsigned long)res->start);
-
ret = s3c24xx_i2c_register_cpufreq(i2c);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
@@ -944,7 +913,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
s3c24xx_i2c_deregister_cpufreq(i2c);
err_irq:
- free_irq(i2c->irq->start, i2c);
+ free_irq(i2c->irq, i2c);
err_iomap:
iounmap(i2c->regs);
@@ -958,6 +927,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
clk_put(i2c->clk);
err_noclk:
+ kfree(i2c);
return ret;
}
@@ -973,7 +943,7 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
s3c24xx_i2c_deregister_cpufreq(i2c);
i2c_del_adapter(&i2c->adap);
- free_irq(i2c->irq->start, i2c);
+ free_irq(i2c->irq, i2c);
clk_disable(i2c->clk);
clk_put(i2c->clk);
@@ -982,6 +952,7 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
release_resource(i2c->ioarea);
kfree(i2c->ioarea);
+ kfree(i2c);
return 0;
}
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index 4c35702830ce..864ac561fdbb 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -126,19 +126,6 @@ config ISP1301_OMAP
This driver can also be built as a module. If so, the module
will be called isp1301_omap.
-config TPS65010
- tristate "TPS6501x Power Management chips"
- depends on GPIOLIB
- default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK
- help
- If you say yes here you get support for the TPS6501x series of
- Power Management chips. These include voltage regulators,
- lithium ion/polymer battery charging, and other features that
- are often used in portable devices like cell phones and cameras.
-
- This driver can also be built as a module. If so, the module
- will be called tps65010.
-
config SENSORS_MAX6875
tristate "Maxim MAX6875 Power supply supervisor"
depends on EXPERIMENTAL
@@ -164,16 +151,6 @@ config SENSORS_TSL2550
This driver can also be built as a module. If so, the module
will be called tsl2550.
-config MENELAUS
- bool "TWL92330/Menelaus PM chip"
- depends on I2C=y && ARCH_OMAP24XX
- help
- If you say yes here you get support for the Texas Instruments
- TWL92330/Menelaus Power Management chip. This include voltage
- regulators, Dual slot memory card tranceivers, real-time clock
- and other features that are often used in portable devices like
- cell phones and PDAs.
-
config MCU_MPC8349EMITX
tristate "MPC8349E-mITX MCU driver"
depends on I2C && PPC_83xx
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
index 23d2a31b0a64..8b95f41a5001 100644
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -19,8 +19,6 @@ obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
obj-$(CONFIG_PCF8575) += pcf8575.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
-obj-$(CONFIG_TPS65010) += tps65010.o
-obj-$(CONFIG_MENELAUS) += menelaus.o
obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
obj-$(CONFIG_MCU_MPC8349EMITX) += mcu_mpc8349emitx.o
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index 53912c327bfe..8dc2bb781605 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -57,9 +57,6 @@ static int ipathfs_mknod(struct inode *dir, struct dentry *dentry,
}
inode->i_mode = mode;
- inode->i_uid = 0;
- inode->i_gid = 0;
- inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_private = data;
if ((mode & S_IFMT) == S_IFDIR) {
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index d5b4cc357a3c..650120261abf 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -1519,7 +1519,7 @@ static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep)
int digit2 = 0;
if (!isdigit(*s)) return -3;
while (isdigit(*s)) { digit1 = digit1*10 + (*s - '0'); s++; }
- if (digit1 <= 0 && digit1 > 30) return -4;
+ if (digit1 <= 0 || digit1 > 30) return -4;
if (*s == 0 || *s == ',' || *s == ' ') {
bmask |= (1 << digit1);
digit1 = 0;
@@ -1530,7 +1530,7 @@ static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep)
s++;
if (!isdigit(*s)) return -3;
while (isdigit(*s)) { digit2 = digit2*10 + (*s - '0'); s++; }
- if (digit2 <= 0 && digit2 > 30) return -4;
+ if (digit2 <= 0 || digit2 > 30) return -4;
if (*s == 0 || *s == ',' || *s == ' ') {
if (digit1 > digit2)
for (i = digit2; i <= digit1 ; i++)
diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c
index 0aa66ec4cbdd..b129409925af 100644
--- a/drivers/isdn/capi/capifs.c
+++ b/drivers/isdn/capi/capifs.c
@@ -111,8 +111,6 @@ capifs_fill_super(struct super_block *s, void *data, int silent)
goto fail;
inode->i_ino = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->i_blocks = 0;
- inode->i_uid = inode->i_gid = 0;
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index 1c615804ea76..72880b7e28d9 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -3,9 +3,10 @@
#
dm-mod-objs := dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \
- dm-ioctl.o dm-io.o dm-kcopyd.o
+ dm-ioctl.o dm-io.o dm-kcopyd.o dm-sysfs.o
dm-multipath-objs := dm-path-selector.o dm-mpath.o
-dm-snapshot-objs := dm-snap.o dm-exception-store.o
+dm-snapshot-objs := dm-snap.o dm-exception-store.o dm-snap-transient.o \
+ dm-snap-persistent.o
dm-mirror-objs := dm-raid1.o
md-mod-objs := md.o bitmap.o
raid456-objs := raid5.o raid6algos.o raid6recov.o raid6tables.o \
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 3326750ec02c..35bda49796fb 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -1322,11 +1322,7 @@ static int __init dm_crypt_init(void)
static void __exit dm_crypt_exit(void)
{
- int r = dm_unregister_target(&crypt_target);
-
- if (r < 0)
- DMERR("unregister failed %d", r);
-
+ dm_unregister_target(&crypt_target);
kmem_cache_destroy(_crypt_io_pool);
}
diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c
index 848b381f1173..59ee1b015d2d 100644
--- a/drivers/md/dm-delay.c
+++ b/drivers/md/dm-delay.c
@@ -364,11 +364,7 @@ bad_queue:
static void __exit dm_delay_exit(void)
{
- int r = dm_unregister_target(&delay_target);
-
- if (r < 0)
- DMERR("unregister failed %d", r);
-
+ dm_unregister_target(&delay_target);
kmem_cache_destroy(delayed_cache);
destroy_workqueue(kdelayd_wq);
}
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 01590f3e0009..dccbfb0e010f 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -1,756 +1,45 @@
/*
- * dm-exception-store.c
- *
* Copyright (C) 2001-2002 Sistina Software (UK) Limited.
- * Copyright (C) 2006 Red Hat GmbH
+ * Copyright (C) 2006-2008 Red Hat GmbH
*
* This file is released under the GPL.
*/
-#include "dm-snap.h"
+#include "dm-exception-store.h"
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
-#include <linux/dm-io.h>
-#include <linux/dm-kcopyd.h>
-
-#define DM_MSG_PREFIX "snapshots"
-#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32 /* 16KB */
-
-/*-----------------------------------------------------------------
- * Persistent snapshots, by persistent we mean that the snapshot
- * will survive a reboot.
- *---------------------------------------------------------------*/
-
-/*
- * We need to store a record of which parts of the origin have
- * been copied to the snapshot device. The snapshot code
- * requires that we copy exception chunks to chunk aligned areas
- * of the COW store. It makes sense therefore, to store the
- * metadata in chunk size blocks.
- *
- * There is no backward or forward compatibility implemented,
- * snapshots with different disk versions than the kernel will
- * not be usable. It is expected that "lvcreate" will blank out
- * the start of a fresh COW device before calling the snapshot
- * constructor.
- *
- * The first chunk of the COW device just contains the header.
- * After this there is a chunk filled with exception metadata,
- * followed by as many exception chunks as can fit in the
- * metadata areas.
- *
- * All on disk structures are in little-endian format. The end
- * of the exceptions info is indicated by an exception with a
- * new_chunk of 0, which is invalid since it would point to the
- * header chunk.
- */
-
-/*
- * Magic for persistent snapshots: "SnAp" - Feeble isn't it.
- */
-#define SNAP_MAGIC 0x70416e53
-
-/*
- * The on-disk version of the metadata.
- */
-#define SNAPSHOT_DISK_VERSION 1
-
-struct disk_header {
- uint32_t magic;
-
- /*
- * Is this snapshot valid. There is no way of recovering
- * an invalid snapshot.
- */
- uint32_t valid;
-
- /*
- * Simple, incrementing version. no backward
- * compatibility.
- */
- uint32_t version;
-
- /* In sectors */
- uint32_t chunk_size;
-};
-
-struct disk_exception {
- uint64_t old_chunk;
- uint64_t new_chunk;
-};
-
-struct commit_callback {
- void (*callback)(void *, int success);
- void *context;
-};
-
-/*
- * The top level structure for a persistent exception store.
- */
-struct pstore {
- struct dm_snapshot *snap; /* up pointer to my snapshot */
- int version;
- int valid;
- uint32_t exceptions_per_area;
-
- /*
- * Now that we have an asynchronous kcopyd there is no
- * need for large chunk sizes, so it wont hurt to have a
- * whole chunks worth of metadata in memory at once.
- */
- void *area;
-
- /*
- * An area of zeros used to clear the next area.
- */
- void *zero_area;
-
- /*
- * Used to keep track of which metadata area the data in
- * 'chunk' refers to.
- */
- chunk_t current_area;
-
- /*
- * The next free chunk for an exception.
- */
- chunk_t next_free;
-
- /*
- * The index of next free exception in the current
- * metadata area.
- */
- uint32_t current_committed;
-
- atomic_t pending_count;
- uint32_t callback_count;
- struct commit_callback *callbacks;
- struct dm_io_client *io_client;
-
- struct workqueue_struct *metadata_wq;
-};
-
-static unsigned sectors_to_pages(unsigned sectors)
-{
- return DIV_ROUND_UP(sectors, PAGE_SIZE >> 9);
-}
-
-static int alloc_area(struct pstore *ps)
-{
- int r = -ENOMEM;
- size_t len;
-
- len = ps->snap->chunk_size << SECTOR_SHIFT;
-
- /*
- * Allocate the chunk_size block of memory that will hold
- * a single metadata area.
- */
- ps->area = vmalloc(len);
- if (!ps->area)
- return r;
-
- ps->zero_area = vmalloc(len);
- if (!ps->zero_area) {
- vfree(ps->area);
- return r;
- }
- memset(ps->zero_area, 0, len);
-
- return 0;
-}
-
-static void free_area(struct pstore *ps)
-{
- vfree(ps->area);
- ps->area = NULL;
- vfree(ps->zero_area);
- ps->zero_area = NULL;
-}
-
-struct mdata_req {
- struct dm_io_region *where;
- struct dm_io_request *io_req;
- struct work_struct work;
- int result;
-};
-
-static void do_metadata(struct work_struct *work)
-{
- struct mdata_req *req = container_of(work, struct mdata_req, work);
-
- req->result = dm_io(req->io_req, 1, req->where, NULL);
-}
-
-/*
- * Read or write a chunk aligned and sized block of data from a device.
- */
-static int chunk_io(struct pstore *ps, chunk_t chunk, int rw, int metadata)
-{
- struct dm_io_region where = {
- .bdev = ps->snap->cow->bdev,
- .sector = ps->snap->chunk_size * chunk,
- .count = ps->snap->chunk_size,
- };
- struct dm_io_request io_req = {
- .bi_rw = rw,
- .mem.type = DM_IO_VMA,
- .mem.ptr.vma = ps->area,
- .client = ps->io_client,
- .notify.fn = NULL,
- };
- struct mdata_req req;
-
- if (!metadata)
- return dm_io(&io_req, 1, &where, NULL);
-
- req.where = &where;
- req.io_req = &io_req;
-
- /*
- * Issue the synchronous I/O from a different thread
- * to avoid generic_make_request recursion.
- */
- INIT_WORK(&req.work, do_metadata);
- queue_work(ps->metadata_wq, &req.work);
- flush_workqueue(ps->metadata_wq);
-
- return req.result;
-}
-
-/*
- * Convert a metadata area index to a chunk index.
- */
-static chunk_t area_location(struct pstore *ps, chunk_t area)
-{
- return 1 + ((ps->exceptions_per_area + 1) * area);
-}
-
-/*
- * Read or write a metadata area. Remembering to skip the first
- * chunk which holds the header.
- */
-static int area_io(struct pstore *ps, int rw)
-{
- int r;
- chunk_t chunk;
-
- chunk = area_location(ps, ps->current_area);
-
- r = chunk_io(ps, chunk, rw, 0);
- if (r)
- return r;
-
- return 0;
-}
-
-static void zero_memory_area(struct pstore *ps)
-{
- memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);
-}
-
-static int zero_disk_area(struct pstore *ps, chunk_t area)
-{
- struct dm_io_region where = {
- .bdev = ps->snap->cow->bdev,
- .sector = ps->snap->chunk_size * area_location(ps, area),
- .count = ps->snap->chunk_size,
- };
- struct dm_io_request io_req = {
- .bi_rw = WRITE,
- .mem.type = DM_IO_VMA,
- .mem.ptr.vma = ps->zero_area,
- .client = ps->io_client,
- .notify.fn = NULL,
- };
-
- return dm_io(&io_req, 1, &where, NULL);
-}
-
-static int read_header(struct pstore *ps, int *new_snapshot)
-{
- int r;
- struct disk_header *dh;
- chunk_t chunk_size;
- int chunk_size_supplied = 1;
-
- /*
- * Use default chunk size (or hardsect_size, if larger) if none supplied
- */
- if (!ps->snap->chunk_size) {
- ps->snap->chunk_size = max(DM_CHUNK_SIZE_DEFAULT_SECTORS,
- bdev_hardsect_size(ps->snap->cow->bdev) >> 9);
- ps->snap->chunk_mask = ps->snap->chunk_size - 1;
- ps->snap->chunk_shift = ffs(ps->snap->chunk_size) - 1;
- chunk_size_supplied = 0;
- }
-
- ps->io_client = dm_io_client_create(sectors_to_pages(ps->snap->
- chunk_size));
- if (IS_ERR(ps->io_client))
- return PTR_ERR(ps->io_client);
-
- r = alloc_area(ps);
- if (r)
- return r;
-
- r = chunk_io(ps, 0, READ, 1);
- if (r)
- goto bad;
-
- dh = (struct disk_header *) ps->area;
-
- if (le32_to_cpu(dh->magic) == 0) {
- *new_snapshot = 1;
- return 0;
- }
-
- if (le32_to_cpu(dh->magic) != SNAP_MAGIC) {
- DMWARN("Invalid or corrupt snapshot");
- r = -ENXIO;
- goto bad;
- }
-
- *new_snapshot = 0;
- ps->valid = le32_to_cpu(dh->valid);
- ps->version = le32_to_cpu(dh->version);
- chunk_size = le32_to_cpu(dh->chunk_size);
-
- if (!chunk_size_supplied || ps->snap->chunk_size == chunk_size)
- return 0;
-
- DMWARN("chunk size %llu in device metadata overrides "
- "table chunk size of %llu.",
- (unsigned long long)chunk_size,
- (unsigned long long)ps->snap->chunk_size);
-
- /* We had a bogus chunk_size. Fix stuff up. */
- free_area(ps);
-
- ps->snap->chunk_size = chunk_size;
- ps->snap->chunk_mask = chunk_size - 1;
- ps->snap->chunk_shift = ffs(chunk_size) - 1;
-
- r = dm_io_client_resize(sectors_to_pages(ps->snap->chunk_size),
- ps->io_client);
- if (r)
- return r;
-
- r = alloc_area(ps);
- return r;
-
-bad:
- free_area(ps);
- return r;
-}
-
-static int write_header(struct pstore *ps)
-{
- struct disk_header *dh;
-
- memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);
-
- dh = (struct disk_header *) ps->area;
- dh->magic = cpu_to_le32(SNAP_MAGIC);
- dh->valid = cpu_to_le32(ps->valid);
- dh->version = cpu_to_le32(ps->version);
- dh->chunk_size = cpu_to_le32(ps->snap->chunk_size);
-
- return chunk_io(ps, 0, WRITE, 1);
-}
-
-/*
- * Access functions for the disk exceptions, these do the endian conversions.
- */
-static struct disk_exception *get_exception(struct pstore *ps, uint32_t index)
-{
- BUG_ON(index >= ps->exceptions_per_area);
-
- return ((struct disk_exception *) ps->area) + index;
-}
-static void read_exception(struct pstore *ps,
- uint32_t index, struct disk_exception *result)
-{
- struct disk_exception *e = get_exception(ps, index);
-
- /* copy it */
- result->old_chunk = le64_to_cpu(e->old_chunk);
- result->new_chunk = le64_to_cpu(e->new_chunk);
-}
-
-static void write_exception(struct pstore *ps,
- uint32_t index, struct disk_exception *de)
-{
- struct disk_exception *e = get_exception(ps, index);
-
- /* copy it */
- e->old_chunk = cpu_to_le64(de->old_chunk);
- e->new_chunk = cpu_to_le64(de->new_chunk);
-}
+#define DM_MSG_PREFIX "snapshot exception stores"
-/*
- * Registers the exceptions that are present in the current area.
- * 'full' is filled in to indicate if the area has been
- * filled.
- */
-static int insert_exceptions(struct pstore *ps, int *full)
+int dm_exception_store_init(void)
{
int r;
- unsigned int i;
- struct disk_exception de;
-
- /* presume the area is full */
- *full = 1;
-
- for (i = 0; i < ps->exceptions_per_area; i++) {
- read_exception(ps, i, &de);
-
- /*
- * If the new_chunk is pointing at the start of
- * the COW device, where the first metadata area
- * is we know that we've hit the end of the
- * exceptions. Therefore the area is not full.
- */
- if (de.new_chunk == 0LL) {
- ps->current_committed = i;
- *full = 0;
- break;
- }
-
- /*
- * Keep track of the start of the free chunks.
- */
- if (ps->next_free <= de.new_chunk)
- ps->next_free = de.new_chunk + 1;
-
- /*
- * Otherwise we add the exception to the snapshot.
- */
- r = dm_add_exception(ps->snap, de.old_chunk, de.new_chunk);
- if (r)
- return r;
- }
-
- return 0;
-}
-
-static int read_exceptions(struct pstore *ps)
-{
- int r, full = 1;
-
- /*
- * Keeping reading chunks and inserting exceptions until
- * we find a partially full area.
- */
- for (ps->current_area = 0; full; ps->current_area++) {
- r = area_io(ps, READ);
- if (r)
- return r;
- r = insert_exceptions(ps, &full);
- if (r)
- return r;
+ r = dm_transient_snapshot_init();
+ if (r) {
+ DMERR("Unable to register transient exception store type.");
+ goto transient_fail;
}
- ps->current_area--;
-
- return 0;
-}
-
-static struct pstore *get_info(struct exception_store *store)
-{
- return (struct pstore *) store->context;
-}
-
-static void persistent_fraction_full(struct exception_store *store,
- sector_t *numerator, sector_t *denominator)
-{
- *numerator = get_info(store)->next_free * store->snap->chunk_size;
- *denominator = get_dev_size(store->snap->cow->bdev);
-}
-
-static void persistent_destroy(struct exception_store *store)
-{
- struct pstore *ps = get_info(store);
-
- destroy_workqueue(ps->metadata_wq);
- dm_io_client_destroy(ps->io_client);
- vfree(ps->callbacks);
- free_area(ps);
- kfree(ps);
-}
-
-static int persistent_read_metadata(struct exception_store *store)
-{
- int r, uninitialized_var(new_snapshot);
- struct pstore *ps = get_info(store);
-
- /*
- * Read the snapshot header.
- */
- r = read_header(ps, &new_snapshot);
- if (r)
- return r;
-
- /*
- * Now we know correct chunk_size, complete the initialisation.
- */
- ps->exceptions_per_area = (ps->snap->chunk_size << SECTOR_SHIFT) /
- sizeof(struct disk_exception);
- ps->callbacks = dm_vcalloc(ps->exceptions_per_area,
- sizeof(*ps->callbacks));
- if (!ps->callbacks)
- return -ENOMEM;
-
- /*
- * Do we need to setup a new snapshot ?
- */
- if (new_snapshot) {
- r = write_header(ps);
- if (r) {
- DMWARN("write_header failed");
- return r;
- }
-
- ps->current_area = 0;
- zero_memory_area(ps);
- r = zero_disk_area(ps, 0);
- if (r) {
- DMWARN("zero_disk_area(0) failed");
- return r;
- }
- } else {
- /*
- * Sanity checks.
- */
- if (ps->version != SNAPSHOT_DISK_VERSION) {
- DMWARN("unable to handle snapshot disk version %d",
- ps->version);
- return -EINVAL;
- }
-
- /*
- * Metadata are valid, but snapshot is invalidated
- */
- if (!ps->valid)
- return 1;
-
- /*
- * Read the metadata.
- */
- r = read_exceptions(ps);
- if (r)
- return r;
+ r = dm_persistent_snapshot_init();
+ if (r) {
+ DMERR("Unable to register persistent exception store type");
+ goto persistent_fail;
}
return 0;
-}
-
-static int persistent_prepare(struct exception_store *store,
- struct dm_snap_exception *e)
-{
- struct pstore *ps = get_info(store);
- uint32_t stride;
- chunk_t next_free;
- sector_t size = get_dev_size(store->snap->cow->bdev);
-
- /* Is there enough room ? */
- if (size < ((ps->next_free + 1) * store->snap->chunk_size))
- return -ENOSPC;
- e->new_chunk = ps->next_free;
-
- /*
- * Move onto the next free pending, making sure to take
- * into account the location of the metadata chunks.
- */
- stride = (ps->exceptions_per_area + 1);
- next_free = ++ps->next_free;
- if (sector_div(next_free, stride) == 1)
- ps->next_free++;
-
- atomic_inc(&ps->pending_count);
- return 0;
-}
-
-static void persistent_commit(struct exception_store *store,
- struct dm_snap_exception *e,
- void (*callback) (void *, int success),
- void *callback_context)
-{
- unsigned int i;
- struct pstore *ps = get_info(store);
- struct disk_exception de;
- struct commit_callback *cb;
-
- de.old_chunk = e->old_chunk;
- de.new_chunk = e->new_chunk;
- write_exception(ps, ps->current_committed++, &de);
-
- /*
- * Add the callback to the back of the array. This code
- * is the only place where the callback array is
- * manipulated, and we know that it will never be called
- * multiple times concurrently.
- */
- cb = ps->callbacks + ps->callback_count++;
- cb->callback = callback;
- cb->context = callback_context;
-
- /*
- * If there are exceptions in flight and we have not yet
- * filled this metadata area there's nothing more to do.
- */
- if (!atomic_dec_and_test(&ps->pending_count) &&
- (ps->current_committed != ps->exceptions_per_area))
- return;
-
- /*
- * If we completely filled the current area, then wipe the next one.
- */
- if ((ps->current_committed == ps->exceptions_per_area) &&
- zero_disk_area(ps, ps->current_area + 1))
- ps->valid = 0;
-
- /*
- * Commit exceptions to disk.
- */
- if (ps->valid && area_io(ps, WRITE))
- ps->valid = 0;
-
- /*
- * Advance to the next area if this one is full.
- */
- if (ps->current_committed == ps->exceptions_per_area) {
- ps->current_committed = 0;
- ps->current_area++;
- zero_memory_area(ps);
- }
-
- for (i = 0; i < ps->callback_count; i++) {
- cb = ps->callbacks + i;
- cb->callback(cb->context, ps->valid);
- }
-
- ps->callback_count = 0;
-}
-
-static void persistent_drop(struct exception_store *store)
-{
- struct pstore *ps = get_info(store);
-
- ps->valid = 0;
- if (write_header(ps))
- DMWARN("write header failed");
-}
-
-int dm_create_persistent(struct exception_store *store)
-{
- struct pstore *ps;
-
- /* allocate the pstore */
- ps = kmalloc(sizeof(*ps), GFP_KERNEL);
- if (!ps)
- return -ENOMEM;
-
- ps->snap = store->snap;
- ps->valid = 1;
- ps->version = SNAPSHOT_DISK_VERSION;
- ps->area = NULL;
- ps->next_free = 2; /* skipping the header and first area */
- ps->current_committed = 0;
-
- ps->callback_count = 0;
- atomic_set(&ps->pending_count, 0);
- ps->callbacks = NULL;
-
- ps->metadata_wq = create_singlethread_workqueue("ksnaphd");
- if (!ps->metadata_wq) {
- kfree(ps);
- DMERR("couldn't start header metadata update thread");
- return -ENOMEM;
- }
-
- store->destroy = persistent_destroy;
- store->read_metadata = persistent_read_metadata;
- store->prepare_exception = persistent_prepare;
- store->commit_exception = persistent_commit;
- store->drop_snapshot = persistent_drop;
- store->fraction_full = persistent_fraction_full;
- store->context = ps;
-
- return 0;
-}
-
-/*-----------------------------------------------------------------
- * Implementation of the store for non-persistent snapshots.
- *---------------------------------------------------------------*/
-struct transient_c {
- sector_t next_free;
-};
-
-static void transient_destroy(struct exception_store *store)
-{
- kfree(store->context);
-}
-
-static int transient_read_metadata(struct exception_store *store)
-{
- return 0;
-}
-
-static int transient_prepare(struct exception_store *store,
- struct dm_snap_exception *e)
-{
- struct transient_c *tc = (struct transient_c *) store->context;
- sector_t size = get_dev_size(store->snap->cow->bdev);
-
- if (size < (tc->next_free + store->snap->chunk_size))
- return -1;
-
- e->new_chunk = sector_to_chunk(store->snap, tc->next_free);
- tc->next_free += store->snap->chunk_size;
-
- return 0;
-}
-
-static void transient_commit(struct exception_store *store,
- struct dm_snap_exception *e,
- void (*callback) (void *, int success),
- void *callback_context)
-{
- /* Just succeed */
- callback(callback_context, 1);
-}
-
-static void transient_fraction_full(struct exception_store *store,
- sector_t *numerator, sector_t *denominator)
-{
- *numerator = ((struct transient_c *) store->context)->next_free;
- *denominator = get_dev_size(store->snap->cow->bdev);
+persistent_fail:
+ dm_persistent_snapshot_exit();
+transient_fail:
+ return r;
}
-int dm_create_transient(struct exception_store *store)
+void dm_exception_store_exit(void)
{
- struct transient_c *tc;
-
- store->destroy = transient_destroy;
- store->read_metadata = transient_read_metadata;
- store->prepare_exception = transient_prepare;
- store->commit_exception = transient_commit;
- store->drop_snapshot = NULL;
- store->fraction_full = transient_fraction_full;
-
- tc = kmalloc(sizeof(struct transient_c), GFP_KERNEL);
- if (!tc)
- return -ENOMEM;
-
- tc->next_free = 0;
- store->context = tc;
-
- return 0;
+ dm_persistent_snapshot_exit();
+ dm_transient_snapshot_exit();
}
diff --git a/drivers/md/dm-exception-store.h b/drivers/md/dm-exception-store.h
new file mode 100644
index 000000000000..bb9f33d5daa2
--- /dev/null
+++ b/drivers/md/dm-exception-store.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2001-2002 Sistina Software (UK) Limited.
+ * Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+ *
+ * Device-mapper snapshot exception store.
+ *
+ * This file is released under the GPL.
+ */
+
+#ifndef _LINUX_DM_EXCEPTION_STORE
+#define _LINUX_DM_EXCEPTION_STORE
+
+#include <linux/blkdev.h>
+#include <linux/device-mapper.h>
+
+/*
+ * The snapshot code deals with largish chunks of the disk at a
+ * time. Typically 32k - 512k.
+ */
+typedef sector_t chunk_t;
+
+/*
+ * An exception is used where an old chunk of data has been
+ * replaced by a new one.
+ * If chunk_t is 64 bits in size, the top 8 bits of new_chunk hold the number
+ * of chunks that follow contiguously. Remaining bits hold the number of the
+ * chunk within the device.
+ */
+struct dm_snap_exception {
+ struct list_head hash_list;
+
+ chunk_t old_chunk;
+ chunk_t new_chunk;
+};
+
+/*
+ * Abstraction to handle the meta/layout of exception stores (the
+ * COW device).
+ */
+struct dm_exception_store {
+ /*
+ * Destroys this object when you've finished with it.
+ */
+ void (*destroy) (struct dm_exception_store *store);
+
+ /*
+ * The target shouldn't read the COW device until this is
+ * called. As exceptions are read from the COW, they are
+ * reported back via the callback.
+ */
+ int (*read_metadata) (struct dm_exception_store *store,
+ int (*callback)(void *callback_context,
+ chunk_t old, chunk_t new),
+ void *callback_context);
+
+ /*
+ * Find somewhere to store the next exception.
+ */
+ int (*prepare_exception) (struct dm_exception_store *store,
+ struct dm_snap_exception *e);
+
+ /*
+ * Update the metadata with this exception.
+ */
+ void (*commit_exception) (struct dm_exception_store *store,
+ struct dm_snap_exception *e,
+ void (*callback) (void *, int success),
+ void *callback_context);
+
+ /*
+ * The snapshot is invalid, note this in the metadata.
+ */
+ void (*drop_snapshot) (struct dm_exception_store *store);
+
+ int (*status) (struct dm_exception_store *store, status_type_t status,
+ char *result, unsigned int maxlen);
+
+ /*
+ * Return how full the snapshot is.
+ */
+ void (*fraction_full) (struct dm_exception_store *store,
+ sector_t *numerator,
+ sector_t *denominator);
+
+ struct dm_snapshot *snap;
+ void *context;
+};
+
+/*
+ * Funtions to manipulate consecutive chunks
+ */
+# if defined(CONFIG_LBD) || (BITS_PER_LONG == 64)
+# define DM_CHUNK_CONSECUTIVE_BITS 8
+# define DM_CHUNK_NUMBER_BITS 56
+
+static inline chunk_t dm_chunk_number(chunk_t chunk)
+{
+ return chunk & (chunk_t)((1ULL << DM_CHUNK_NUMBER_BITS) - 1ULL);
+}
+
+static inline unsigned dm_consecutive_chunk_count(struct dm_snap_exception *e)
+{
+ return e->new_chunk >> DM_CHUNK_NUMBER_BITS;
+}
+
+static inline void dm_consecutive_chunk_count_inc(struct dm_snap_exception *e)
+{
+ e->new_chunk += (1ULL << DM_CHUNK_NUMBER_BITS);
+
+ BUG_ON(!dm_consecutive_chunk_count(e));
+}
+
+# else
+# define DM_CHUNK_CONSECUTIVE_BITS 0
+
+static inline chunk_t dm_chunk_number(chunk_t chunk)
+{
+ return chunk;
+}
+
+static inline unsigned dm_consecutive_chunk_count(struct dm_snap_exception *e)
+{
+ return 0;
+}
+
+static inline void dm_consecutive_chunk_count_inc(struct dm_snap_exception *e)
+{
+}
+
+# endif
+
+int dm_exception_store_init(void);
+void dm_exception_store_exit(void);
+
+/*
+ * Two exception store implementations.
+ */
+int dm_persistent_snapshot_init(void);
+void dm_persistent_snapshot_exit(void);
+
+int dm_transient_snapshot_init(void);
+void dm_transient_snapshot_exit(void);
+
+int dm_create_persistent(struct dm_exception_store *store);
+
+int dm_create_transient(struct dm_exception_store *store);
+
+#endif /* _LINUX_DM_EXCEPTION_STORE */
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 777c948180f9..54d0588fc1f6 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -233,7 +233,7 @@ static void __hash_remove(struct hash_cell *hc)
}
if (hc->new_map)
- dm_table_put(hc->new_map);
+ dm_table_destroy(hc->new_map);
dm_put(hc->md);
free_cell(hc);
}
@@ -827,8 +827,8 @@ static int do_resume(struct dm_ioctl *param)
r = dm_swap_table(md, new_map);
if (r) {
+ dm_table_destroy(new_map);
dm_put(md);
- dm_table_put(new_map);
return r;
}
@@ -836,8 +836,6 @@ static int do_resume(struct dm_ioctl *param)
set_disk_ro(dm_disk(md), 0);
else
set_disk_ro(dm_disk(md), 1);
-
- dm_table_put(new_map);
}
if (dm_suspended(md))
@@ -1080,7 +1078,7 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
}
if (hc->new_map)
- dm_table_put(hc->new_map);
+ dm_table_destroy(hc->new_map);
hc->new_map = t;
up_write(&_hash_lock);
@@ -1109,7 +1107,7 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
}
if (hc->new_map) {
- dm_table_put(hc->new_map);
+ dm_table_destroy(hc->new_map);
hc->new_map = NULL;
}
@@ -1550,8 +1548,10 @@ int dm_copy_name_and_uuid(struct mapped_device *md, char *name, char *uuid)
goto out;
}
- strcpy(name, hc->name);
- strcpy(uuid, hc->uuid ? : "");
+ if (name)
+ strcpy(name, hc->name);
+ if (uuid)
+ strcpy(uuid, hc->uuid ? : "");
out:
up_read(&_hash_lock);
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index 44042becad8a..bfa107f59d96 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -142,6 +142,7 @@ static struct target_type linear_target = {
.status = linear_status,
.ioctl = linear_ioctl,
.merge = linear_merge,
+ .features = DM_TARGET_SUPPORTS_BARRIERS,
};
int __init dm_linear_init(void)
@@ -156,8 +157,5 @@ int __init dm_linear_init(void)
void dm_linear_exit(void)
{
- int r = dm_unregister_target(&linear_target);
-
- if (r < 0)
- DMERR("unregister failed %d", r);
+ dm_unregister_target(&linear_target);
}
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index a8c0fc79ca78..737961f275c1 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -326,8 +326,6 @@ static void header_from_disk(struct log_header *core, struct log_header *disk)
static int rw_header(struct log_c *lc, int rw)
{
lc->io_req.bi_rw = rw;
- lc->io_req.mem.ptr.vma = lc->disk_header;
- lc->io_req.notify.fn = NULL;
return dm_io(&lc->io_req, 1, &lc->header_location, NULL);
}
@@ -362,10 +360,15 @@ static int read_header(struct log_c *log)
return 0;
}
-static inline int write_header(struct log_c *log)
+static int _check_region_size(struct dm_target *ti, uint32_t region_size)
{
- header_to_disk(&log->header, log->disk_header);
- return rw_header(log, WRITE);
+ if (region_size < 2 || region_size > ti->len)
+ return 0;
+
+ if (!is_power_of_2(region_size))
+ return 0;
+
+ return 1;
}
/*----------------------------------------------------------------
@@ -403,8 +406,9 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
}
}
- if (sscanf(argv[0], "%u", &region_size) != 1) {
- DMWARN("invalid region size string");
+ if (sscanf(argv[0], "%u", &region_size) != 1 ||
+ !_check_region_size(ti, region_size)) {
+ DMWARN("invalid region size %s", argv[0]);
return -EINVAL;
}
@@ -453,8 +457,18 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
*/
buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) +
bitset_size, ti->limits.hardsect_size);
+
+ if (buf_size > dev->bdev->bd_inode->i_size) {
+ DMWARN("log device %s too small: need %llu bytes",
+ dev->name, (unsigned long long)buf_size);
+ kfree(lc);
+ return -EINVAL;
+ }
+
lc->header_location.count = buf_size >> SECTOR_SHIFT;
+
lc->io_req.mem.type = DM_IO_VMA;
+ lc->io_req.notify.fn = NULL;
lc->io_req.client = dm_io_client_create(dm_div_up(buf_size,
PAGE_SIZE));
if (IS_ERR(lc->io_req.client)) {
@@ -467,10 +481,12 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
lc->disk_header = vmalloc(buf_size);
if (!lc->disk_header) {
DMWARN("couldn't allocate disk log buffer");
+ dm_io_client_destroy(lc->io_req.client);
kfree(lc);
return -ENOMEM;
}
+ lc->io_req.mem.ptr.vma = lc->disk_header;
lc->clean_bits = (void *)lc->disk_header +
(LOG_OFFSET << SECTOR_SHIFT);
}
@@ -482,6 +498,8 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
DMWARN("couldn't allocate sync bitset");
if (!dev)
vfree(lc->clean_bits);
+ else
+ dm_io_client_destroy(lc->io_req.client);
vfree(lc->disk_header);
kfree(lc);
return -ENOMEM;
@@ -495,6 +513,8 @@ static int create_log_context(struct dm_dirty_log *log, struct dm_target *ti,
vfree(lc->sync_bits);
if (!dev)
vfree(lc->clean_bits);
+ else
+ dm_io_client_destroy(lc->io_req.client);
vfree(lc->disk_header);
kfree(lc);
return -ENOMEM;
@@ -631,8 +651,10 @@ static int disk_resume(struct dm_dirty_log *log)
/* set the correct number of regions in the header */
lc->header.nr_regions = lc->region_count;
+ header_to_disk(&lc->header, lc->disk_header);
+
/* write the new header */
- r = write_header(lc);
+ r = rw_header(lc, WRITE);
if (r) {
DMWARN("%s: Failed to write header on dirty region log device",
lc->log_dev->name);
@@ -682,7 +704,7 @@ static int disk_flush(struct dm_dirty_log *log)
if (!lc->touched)
return 0;
- r = write_header(lc);
+ r = rw_header(lc, WRITE);
if (r)
fail_log_device(lc);
else
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 3d7f4923cd13..095f77bf9681 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -889,7 +889,7 @@ static int fail_path(struct pgpath *pgpath)
dm_path_uevent(DM_UEVENT_PATH_FAILED, m->ti,
pgpath->path.dev->name, m->nr_valid_paths);
- queue_work(kmultipathd, &m->trigger_event);
+ schedule_work(&m->trigger_event);
queue_work(kmultipathd, &pgpath->deactivate_path);
out:
@@ -932,7 +932,7 @@ static int reinstate_path(struct pgpath *pgpath)
dm_path_uevent(DM_UEVENT_PATH_REINSTATED, m->ti,
pgpath->path.dev->name, m->nr_valid_paths);
- queue_work(kmultipathd, &m->trigger_event);
+ schedule_work(&m->trigger_event);
out:
spin_unlock_irqrestore(&m->lock, flags);
@@ -976,7 +976,7 @@ static void bypass_pg(struct multipath *m, struct priority_group *pg,
spin_unlock_irqrestore(&m->lock, flags);
- queue_work(kmultipathd, &m->trigger_event);
+ schedule_work(&m->trigger_event);
}
/*
@@ -1006,7 +1006,7 @@ static int switch_pg_num(struct multipath *m, const char *pgstr)
}
spin_unlock_irqrestore(&m->lock, flags);
- queue_work(kmultipathd, &m->trigger_event);
+ schedule_work(&m->trigger_event);
return 0;
}
@@ -1495,14 +1495,10 @@ static int __init dm_multipath_init(void)
static void __exit dm_multipath_exit(void)
{
- int r;
-
destroy_workqueue(kmpath_handlerd);
destroy_workqueue(kmultipathd);
- r = dm_unregister_target(&multipath_target);
- if (r < 0)
- DMERR("target unregister failed %d", r);
+ dm_unregister_target(&multipath_target);
kmem_cache_destroy(_mpio_cache);
}
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index ec43f9fa4b2a..4d6bc101962e 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -197,9 +197,6 @@ static void fail_mirror(struct mirror *m, enum dm_raid1_error error_type)
struct mirror_set *ms = m->ms;
struct mirror *new;
- if (!errors_handled(ms))
- return;
-
/*
* error_count is used for nothing more than a
* simple way to tell if a device has encountered
@@ -210,6 +207,9 @@ static void fail_mirror(struct mirror *m, enum dm_raid1_error error_type)
if (test_and_set_bit(error_type, &m->error_type))
return;
+ if (!errors_handled(ms))
+ return;
+
if (m != get_default_mirror(ms))
goto out;
@@ -808,12 +808,6 @@ static void free_context(struct mirror_set *ms, struct dm_target *ti,
kfree(ms);
}
-static inline int _check_region_size(struct dm_target *ti, uint32_t size)
-{
- return !(size % (PAGE_SIZE >> 9) || !is_power_of_2(size) ||
- size > ti->len);
-}
-
static int get_mirror(struct mirror_set *ms, struct dm_target *ti,
unsigned int mirror, char **argv)
{
@@ -872,12 +866,6 @@ static struct dm_dirty_log *create_dirty_log(struct dm_target *ti,
return NULL;
}
- if (!_check_region_size(ti, dl->type->get_region_size(dl))) {
- ti->error = "Invalid region size";
- dm_dirty_log_destroy(dl);
- return NULL;
- }
-
return dl;
}
@@ -1300,11 +1288,7 @@ static int __init dm_mirror_init(void)
static void __exit dm_mirror_exit(void)
{
- int r;
-
- r = dm_unregister_target(&mirror_target);
- if (r < 0)
- DMERR("unregister failed %d", r);
+ dm_unregister_target(&mirror_target);
}
/* Module hooks */
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c
new file mode 100644
index 000000000000..936b34e0959f
--- /dev/null
+++ b/drivers/md/dm-snap-persistent.c
@@ -0,0 +1,704 @@
+/*
+ * Copyright (C) 2001-2002 Sistina Software (UK) Limited.
+ * Copyright (C) 2006-2008 Red Hat GmbH
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm-exception-store.h"
+#include "dm-snap.h"
+
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/dm-io.h>
+
+#define DM_MSG_PREFIX "persistent snapshot"
+#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32 /* 16KB */
+
+/*-----------------------------------------------------------------
+ * Persistent snapshots, by persistent we mean that the snapshot
+ * will survive a reboot.
+ *---------------------------------------------------------------*/
+
+/*
+ * We need to store a record of which parts of the origin have
+ * been copied to the snapshot device. The snapshot code
+ * requires that we copy exception chunks to chunk aligned areas
+ * of the COW store. It makes sense therefore, to store the
+ * metadata in chunk size blocks.
+ *
+ * There is no backward or forward compatibility implemented,
+ * snapshots with different disk versions than the kernel will
+ * not be usable. It is expected that "lvcreate" will blank out
+ * the start of a fresh COW device before calling the snapshot
+ * constructor.
+ *
+ * The first chunk of the COW device just contains the header.
+ * After this there is a chunk filled with exception metadata,
+ * followed by as many exception chunks as can fit in the
+ * metadata areas.
+ *
+ * All on disk structures are in little-endian format. The end
+ * of the exceptions info is indicated by an exception with a
+ * new_chunk of 0, which is invalid since it would point to the
+ * header chunk.
+ */
+
+/*
+ * Magic for persistent snapshots: "SnAp" - Feeble isn't it.
+ */
+#define SNAP_MAGIC 0x70416e53
+
+/*
+ * The on-disk version of the metadata.
+ */
+#define SNAPSHOT_DISK_VERSION 1
+
+struct disk_header {
+ uint32_t magic;
+
+ /*
+ * Is this snapshot valid. There is no way of recovering
+ * an invalid snapshot.
+ */
+ uint32_t valid;
+
+ /*
+ * Simple, incrementing version. no backward
+ * compatibility.
+ */
+ uint32_t version;
+
+ /* In sectors */
+ uint32_t chunk_size;
+};
+
+struct disk_exception {
+ uint64_t old_chunk;
+ uint64_t new_chunk;
+};
+
+struct commit_callback {
+ void (*callback)(void *, int success);
+ void *context;
+};
+
+/*
+ * The top level structure for a persistent exception store.
+ */
+struct pstore {
+ struct dm_snapshot *snap; /* up pointer to my snapshot */
+ int version;
+ int valid;
+ uint32_t exceptions_per_area;
+
+ /*
+ * Now that we have an asynchronous kcopyd there is no
+ * need for large chunk sizes, so it wont hurt to have a
+ * whole chunks worth of metadata in memory at once.
+ */
+ void *area;
+
+ /*
+ * An area of zeros used to clear the next area.
+ */
+ void *zero_area;
+
+ /*
+ * Used to keep track of which metadata area the data in
+ * 'chunk' refers to.
+ */
+ chunk_t current_area;
+
+ /*
+ * The next free chunk for an exception.
+ */
+ chunk_t next_free;
+
+ /*
+ * The index of next free exception in the current
+ * metadata area.
+ */
+ uint32_t current_committed;
+
+ atomic_t pending_count;
+ uint32_t callback_count;
+ struct commit_callback *callbacks;
+ struct dm_io_client *io_client;
+
+ struct workqueue_struct *metadata_wq;
+};
+
+static unsigned sectors_to_pages(unsigned sectors)
+{
+ return DIV_ROUND_UP(sectors, PAGE_SIZE >> 9);
+}
+
+static int alloc_area(struct pstore *ps)
+{
+ int r = -ENOMEM;
+ size_t len;
+
+ len = ps->snap->chunk_size << SECTOR_SHIFT;
+
+ /*
+ * Allocate the chunk_size block of memory that will hold
+ * a single metadata area.
+ */
+ ps->area = vmalloc(len);
+ if (!ps->area)
+ return r;
+
+ ps->zero_area = vmalloc(len);
+ if (!ps->zero_area) {
+ vfree(ps->area);
+ return r;
+ }
+ memset(ps->zero_area, 0, len);
+
+ return 0;
+}
+
+static void free_area(struct pstore *ps)
+{
+ vfree(ps->area);
+ ps->area = NULL;
+ vfree(ps->zero_area);
+ ps->zero_area = NULL;
+}
+
+struct mdata_req {
+ struct dm_io_region *where;
+ struct dm_io_request *io_req;
+ struct work_struct work;
+ int result;
+};
+
+static void do_metadata(struct work_struct *work)
+{
+ struct mdata_req *req = container_of(work, struct mdata_req, work);
+
+ req->result = dm_io(req->io_req, 1, req->where, NULL);
+}
+
+/*
+ * Read or write a chunk aligned and sized block of data from a device.
+ */
+static int chunk_io(struct pstore *ps, chunk_t chunk, int rw, int metadata)
+{
+ struct dm_io_region where = {
+ .bdev = ps->snap->cow->bdev,
+ .sector = ps->snap->chunk_size * chunk,
+ .count = ps->snap->chunk_size,
+ };
+ struct dm_io_request io_req = {
+ .bi_rw = rw,
+ .mem.type = DM_IO_VMA,
+ .mem.ptr.vma = ps->area,
+ .client = ps->io_client,
+ .notify.fn = NULL,
+ };
+ struct mdata_req req;
+
+ if (!metadata)
+ return dm_io(&io_req, 1, &where, NULL);
+
+ req.where = &where;
+ req.io_req = &io_req;
+
+ /*
+ * Issue the synchronous I/O from a different thread
+ * to avoid generic_make_request recursion.
+ */
+ INIT_WORK(&req.work, do_metadata);
+ queue_work(ps->metadata_wq, &req.work);
+ flush_workqueue(ps->metadata_wq);
+
+ return req.result;
+}
+
+/*
+ * Convert a metadata area index to a chunk index.
+ */
+static chunk_t area_location(struct pstore *ps, chunk_t area)
+{
+ return 1 + ((ps->exceptions_per_area + 1) * area);
+}
+
+/*
+ * Read or write a metadata area. Remembering to skip the first
+ * chunk which holds the header.
+ */
+static int area_io(struct pstore *ps, int rw)
+{
+ int r;
+ chunk_t chunk;
+
+ chunk = area_location(ps, ps->current_area);
+
+ r = chunk_io(ps, chunk, rw, 0);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static void zero_memory_area(struct pstore *ps)
+{
+ memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);
+}
+
+static int zero_disk_area(struct pstore *ps, chunk_t area)
+{
+ struct dm_io_region where = {
+ .bdev = ps->snap->cow->bdev,
+ .sector = ps->snap->chunk_size * area_location(ps, area),
+ .count = ps->snap->chunk_size,
+ };
+ struct dm_io_request io_req = {
+ .bi_rw = WRITE,
+ .mem.type = DM_IO_VMA,
+ .mem.ptr.vma = ps->zero_area,
+ .client = ps->io_client,
+ .notify.fn = NULL,
+ };
+
+ return dm_io(&io_req, 1, &where, NULL);
+}
+
+static int read_header(struct pstore *ps, int *new_snapshot)
+{
+ int r;
+ struct disk_header *dh;
+ chunk_t chunk_size;
+ int chunk_size_supplied = 1;
+
+ /*
+ * Use default chunk size (or hardsect_size, if larger) if none supplied
+ */
+ if (!ps->snap->chunk_size) {
+ ps->snap->chunk_size = max(DM_CHUNK_SIZE_DEFAULT_SECTORS,
+ bdev_hardsect_size(ps->snap->cow->bdev) >> 9);
+ ps->snap->chunk_mask = ps->snap->chunk_size - 1;
+ ps->snap->chunk_shift = ffs(ps->snap->chunk_size) - 1;
+ chunk_size_supplied = 0;
+ }
+
+ ps->io_client = dm_io_client_create(sectors_to_pages(ps->snap->
+ chunk_size));
+ if (IS_ERR(ps->io_client))
+ return PTR_ERR(ps->io_client);
+
+ r = alloc_area(ps);
+ if (r)
+ return r;
+
+ r = chunk_io(ps, 0, READ, 1);
+ if (r)
+ goto bad;
+
+ dh = (struct disk_header *) ps->area;
+
+ if (le32_to_cpu(dh->magic) == 0) {
+ *new_snapshot = 1;
+ return 0;
+ }
+
+ if (le32_to_cpu(dh->magic) != SNAP_MAGIC) {
+ DMWARN("Invalid or corrupt snapshot");
+ r = -ENXIO;
+ goto bad;
+ }
+
+ *new_snapshot = 0;
+ ps->valid = le32_to_cpu(dh->valid);
+ ps->version = le32_to_cpu(dh->version);
+ chunk_size = le32_to_cpu(dh->chunk_size);
+
+ if (!chunk_size_supplied || ps->snap->chunk_size == chunk_size)
+ return 0;
+
+ DMWARN("chunk size %llu in device metadata overrides "
+ "table chunk size of %llu.",
+ (unsigned long long)chunk_size,
+ (unsigned long long)ps->snap->chunk_size);
+
+ /* We had a bogus chunk_size. Fix stuff up. */
+ free_area(ps);
+
+ ps->snap->chunk_size = chunk_size;
+ ps->snap->chunk_mask = chunk_size - 1;
+ ps->snap->chunk_shift = ffs(chunk_size) - 1;
+
+ r = dm_io_client_resize(sectors_to_pages(ps->snap->chunk_size),
+ ps->io_client);
+ if (r)
+ return r;
+
+ r = alloc_area(ps);
+ return r;
+
+bad:
+ free_area(ps);
+ return r;
+}
+
+static int write_header(struct pstore *ps)
+{
+ struct disk_header *dh;
+
+ memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);
+
+ dh = (struct disk_header *) ps->area;
+ dh->magic = cpu_to_le32(SNAP_MAGIC);
+ dh->valid = cpu_to_le32(ps->valid);
+ dh->version = cpu_to_le32(ps->version);
+ dh->chunk_size = cpu_to_le32(ps->snap->chunk_size);
+
+ return chunk_io(ps, 0, WRITE, 1);
+}
+
+/*
+ * Access functions for the disk exceptions, these do the endian conversions.
+ */
+static struct disk_exception *get_exception(struct pstore *ps, uint32_t index)
+{
+ BUG_ON(index >= ps->exceptions_per_area);
+
+ return ((struct disk_exception *) ps->area) + index;
+}
+
+static void read_exception(struct pstore *ps,
+ uint32_t index, struct disk_exception *result)
+{
+ struct disk_exception *e = get_exception(ps, index);
+
+ /* copy it */
+ result->old_chunk = le64_to_cpu(e->old_chunk);
+ result->new_chunk = le64_to_cpu(e->new_chunk);
+}
+
+static void write_exception(struct pstore *ps,
+ uint32_t index, struct disk_exception *de)
+{
+ struct disk_exception *e = get_exception(ps, index);
+
+ /* copy it */
+ e->old_chunk = cpu_to_le64(de->old_chunk);
+ e->new_chunk = cpu_to_le64(de->new_chunk);
+}
+
+/*
+ * Registers the exceptions that are present in the current area.
+ * 'full' is filled in to indicate if the area has been
+ * filled.
+ */
+static int insert_exceptions(struct pstore *ps,
+ int (*callback)(void *callback_context,
+ chunk_t old, chunk_t new),
+ void *callback_context,
+ int *full)
+{
+ int r;
+ unsigned int i;
+ struct disk_exception de;
+
+ /* presume the area is full */
+ *full = 1;
+
+ for (i = 0; i < ps->exceptions_per_area; i++) {
+ read_exception(ps, i, &de);
+
+ /*
+ * If the new_chunk is pointing at the start of
+ * the COW device, where the first metadata area
+ * is we know that we've hit the end of the
+ * exceptions. Therefore the area is not full.
+ */
+ if (de.new_chunk == 0LL) {
+ ps->current_committed = i;
+ *full = 0;
+ break;
+ }
+
+ /*
+ * Keep track of the start of the free chunks.
+ */
+ if (ps->next_free <= de.new_chunk)
+ ps->next_free = de.new_chunk + 1;
+
+ /*
+ * Otherwise we add the exception to the snapshot.
+ */
+ r = callback(callback_context, de.old_chunk, de.new_chunk);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
+static int read_exceptions(struct pstore *ps,
+ int (*callback)(void *callback_context, chunk_t old,
+ chunk_t new),
+ void *callback_context)
+{
+ int r, full = 1;
+
+ /*
+ * Keeping reading chunks and inserting exceptions until
+ * we find a partially full area.
+ */
+ for (ps->current_area = 0; full; ps->current_area++) {
+ r = area_io(ps, READ);
+ if (r)
+ return r;
+
+ r = insert_exceptions(ps, callback, callback_context, &full);
+ if (r)
+ return r;
+ }
+
+ ps->current_area--;
+
+ return 0;
+}
+
+static struct pstore *get_info(struct dm_exception_store *store)
+{
+ return (struct pstore *) store->context;
+}
+
+static void persistent_fraction_full(struct dm_exception_store *store,
+ sector_t *numerator, sector_t *denominator)
+{
+ *numerator = get_info(store)->next_free * store->snap->chunk_size;
+ *denominator = get_dev_size(store->snap->cow->bdev);
+}
+
+static void persistent_destroy(struct dm_exception_store *store)
+{
+ struct pstore *ps = get_info(store);
+
+ destroy_workqueue(ps->metadata_wq);
+ dm_io_client_destroy(ps->io_client);
+ vfree(ps->callbacks);
+ free_area(ps);
+ kfree(ps);
+}
+
+static int persistent_read_metadata(struct dm_exception_store *store,
+ int (*callback)(void *callback_context,
+ chunk_t old, chunk_t new),
+ void *callback_context)
+{
+ int r, uninitialized_var(new_snapshot);
+ struct pstore *ps = get_info(store);
+
+ /*
+ * Read the snapshot header.
+ */
+ r = read_header(ps, &new_snapshot);
+ if (r)
+ return r;
+
+ /*
+ * Now we know correct chunk_size, complete the initialisation.
+ */
+ ps->exceptions_per_area = (ps->snap->chunk_size << SECTOR_SHIFT) /
+ sizeof(struct disk_exception);
+ ps->callbacks = dm_vcalloc(ps->exceptions_per_area,
+ sizeof(*ps->callbacks));
+ if (!ps->callbacks)
+ return -ENOMEM;
+
+ /*
+ * Do we need to setup a new snapshot ?
+ */
+ if (new_snapshot) {
+ r = write_header(ps);
+ if (r) {
+ DMWARN("write_header failed");
+ return r;
+ }
+
+ ps->current_area = 0;
+ zero_memory_area(ps);
+ r = zero_disk_area(ps, 0);
+ if (r) {
+ DMWARN("zero_disk_area(0) failed");
+ return r;
+ }
+ } else {
+ /*
+ * Sanity checks.
+ */
+ if (ps->version != SNAPSHOT_DISK_VERSION) {
+ DMWARN("unable to handle snapshot disk version %d",
+ ps->version);
+ return -EINVAL;
+ }
+
+ /*
+ * Metadata are valid, but snapshot is invalidated
+ */
+ if (!ps->valid)
+ return 1;
+
+ /*
+ * Read the metadata.
+ */
+ r = read_exceptions(ps, callback, callback_context);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
+static int persistent_prepare_exception(struct dm_exception_store *store,
+ struct dm_snap_exception *e)
+{
+ struct pstore *ps = get_info(store);
+ uint32_t stride;
+ chunk_t next_free;
+ sector_t size = get_dev_size(store->snap->cow->bdev);
+
+ /* Is there enough room ? */
+ if (size < ((ps->next_free + 1) * store->snap->chunk_size))
+ return -ENOSPC;
+
+ e->new_chunk = ps->next_free;
+
+ /*
+ * Move onto the next free pending, making sure to take
+ * into account the location of the metadata chunks.
+ */
+ stride = (ps->exceptions_per_area + 1);
+ next_free = ++ps->next_free;
+ if (sector_div(next_free, stride) == 1)
+ ps->next_free++;
+
+ atomic_inc(&ps->pending_count);
+ return 0;
+}
+
+static void persistent_commit_exception(struct dm_exception_store *store,
+ struct dm_snap_exception *e,
+ void (*callback) (void *, int success),
+ void *callback_context)
+{
+ unsigned int i;
+ struct pstore *ps = get_info(store);
+ struct disk_exception de;
+ struct commit_callback *cb;
+
+ de.old_chunk = e->old_chunk;
+ de.new_chunk = e->new_chunk;
+ write_exception(ps, ps->current_committed++, &de);
+
+ /*
+ * Add the callback to the back of the array. This code
+ * is the only place where the callback array is
+ * manipulated, and we know that it will never be called
+ * multiple times concurrently.
+ */
+ cb = ps->callbacks + ps->callback_count++;
+ cb->callback = callback;
+ cb->context = callback_context;
+
+ /*
+ * If there are exceptions in flight and we have not yet
+ * filled this metadata area there's nothing more to do.
+ */
+ if (!atomic_dec_and_test(&ps->pending_count) &&
+ (ps->current_committed != ps->exceptions_per_area))
+ return;
+
+ /*
+ * If we completely filled the current area, then wipe the next one.
+ */
+ if ((ps->current_committed == ps->exceptions_per_area) &&
+ zero_disk_area(ps, ps->current_area + 1))
+ ps->valid = 0;
+
+ /*
+ * Commit exceptions to disk.
+ */
+ if (ps->valid && area_io(ps, WRITE))
+ ps->valid = 0;
+
+ /*
+ * Advance to the next area if this one is full.
+ */
+ if (ps->current_committed == ps->exceptions_per_area) {
+ ps->current_committed = 0;
+ ps->current_area++;
+ zero_memory_area(ps);
+ }
+
+ for (i = 0; i < ps->callback_count; i++) {
+ cb = ps->callbacks + i;
+ cb->callback(cb->context, ps->valid);
+ }
+
+ ps->callback_count = 0;
+}
+
+static void persistent_drop_snapshot(struct dm_exception_store *store)
+{
+ struct pstore *ps = get_info(store);
+
+ ps->valid = 0;
+ if (write_header(ps))
+ DMWARN("write header failed");
+}
+
+int dm_create_persistent(struct dm_exception_store *store)
+{
+ struct pstore *ps;
+
+ /* allocate the pstore */
+ ps = kmalloc(sizeof(*ps), GFP_KERNEL);
+ if (!ps)
+ return -ENOMEM;
+
+ ps->snap = store->snap;
+ ps->valid = 1;
+ ps->version = SNAPSHOT_DISK_VERSION;
+ ps->area = NULL;
+ ps->next_free = 2; /* skipping the header and first area */
+ ps->current_committed = 0;
+
+ ps->callback_count = 0;
+ atomic_set(&ps->pending_count, 0);
+ ps->callbacks = NULL;
+
+ ps->metadata_wq = create_singlethread_workqueue("ksnaphd");
+ if (!ps->metadata_wq) {
+ kfree(ps);
+ DMERR("couldn't start header metadata update thread");
+ return -ENOMEM;
+ }
+
+ store->destroy = persistent_destroy;
+ store->read_metadata = persistent_read_metadata;
+ store->prepare_exception = persistent_prepare_exception;
+ store->commit_exception = persistent_commit_exception;
+ store->drop_snapshot = persistent_drop_snapshot;
+ store->fraction_full = persistent_fraction_full;
+ store->context = ps;
+
+ return 0;
+}
+
+int dm_persistent_snapshot_init(void)
+{
+ return 0;
+}
+
+void dm_persistent_snapshot_exit(void)
+{
+}
diff --git a/drivers/md/dm-snap-transient.c b/drivers/md/dm-snap-transient.c
new file mode 100644
index 000000000000..7f6e2e6dcb0d
--- /dev/null
+++ b/drivers/md/dm-snap-transient.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2001-2002 Sistina Software (UK) Limited.
+ * Copyright (C) 2006-2008 Red Hat GmbH
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm-exception-store.h"
+#include "dm-snap.h"
+
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/dm-io.h>
+
+#define DM_MSG_PREFIX "transient snapshot"
+
+/*-----------------------------------------------------------------
+ * Implementation of the store for non-persistent snapshots.
+ *---------------------------------------------------------------*/
+struct transient_c {
+ sector_t next_free;
+};
+
+static void transient_destroy(struct dm_exception_store *store)
+{
+ kfree(store->context);
+}
+
+static int transient_read_metadata(struct dm_exception_store *store,
+ int (*callback)(void *callback_context,
+ chunk_t old, chunk_t new),
+ void *callback_context)
+{
+ return 0;
+}
+
+static int transient_prepare_exception(struct dm_exception_store *store,
+ struct dm_snap_exception *e)
+{
+ struct transient_c *tc = (struct transient_c *) store->context;
+ sector_t size = get_dev_size(store->snap->cow->bdev);
+
+ if (size < (tc->next_free + store->snap->chunk_size))
+ return -1;
+
+ e->new_chunk = sector_to_chunk(store->snap, tc->next_free);
+ tc->next_free += store->snap->chunk_size;
+
+ return 0;
+}
+
+static void transient_commit_exception(struct dm_exception_store *store,
+ struct dm_snap_exception *e,
+ void (*callback) (void *, int success),
+ void *callback_context)
+{
+ /* Just succeed */
+ callback(callback_context, 1);
+}
+
+static void transient_fraction_full(struct dm_exception_store *store,
+ sector_t *numerator, sector_t *denominator)
+{
+ *numerator = ((struct transient_c *) store->context)->next_free;
+ *denominator = get_dev_size(store->snap->cow->bdev);
+}
+
+int dm_create_transient(struct dm_exception_store *store)
+{
+ struct transient_c *tc;
+
+ store->destroy = transient_destroy;
+ store->read_metadata = transient_read_metadata;
+ store->prepare_exception = transient_prepare_exception;
+ store->commit_exception = transient_commit_exception;
+ store->drop_snapshot = NULL;
+ store->fraction_full = transient_fraction_full;
+
+ tc = kmalloc(sizeof(struct transient_c), GFP_KERNEL);
+ if (!tc)
+ return -ENOMEM;
+
+ tc->next_free = 0;
+ store->context = tc;
+
+ return 0;
+}
+
+int dm_transient_snapshot_init(void)
+{
+ return 0;
+}
+
+void dm_transient_snapshot_exit(void)
+{
+}
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 6c96db26b87c..65ff82ff124e 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -9,6 +9,7 @@
#include <linux/blkdev.h>
#include <linux/ctype.h>
#include <linux/device-mapper.h>
+#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kdev_t.h>
@@ -20,6 +21,7 @@
#include <linux/log2.h>
#include <linux/dm-kcopyd.h>
+#include "dm-exception-store.h"
#include "dm-snap.h"
#include "dm-bio-list.h"
@@ -428,8 +430,13 @@ out:
list_add(&new_e->hash_list, e ? &e->hash_list : l);
}
-int dm_add_exception(struct dm_snapshot *s, chunk_t old, chunk_t new)
+/*
+ * Callback used by the exception stores to load exceptions when
+ * initialising.
+ */
+static int dm_add_exception(void *context, chunk_t old, chunk_t new)
{
+ struct dm_snapshot *s = context;
struct dm_snap_exception *e;
e = alloc_exception();
@@ -658,7 +665,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
spin_lock_init(&s->tracked_chunk_lock);
/* Metadata must only be loaded into one table at once */
- r = s->store.read_metadata(&s->store);
+ r = s->store.read_metadata(&s->store, dm_add_exception, (void *)s);
if (r < 0) {
ti->error = "Failed to read snapshot metadata";
goto bad_load_and_register;
@@ -735,7 +742,7 @@ static void snapshot_dtr(struct dm_target *ti)
unregister_snapshot(s);
while (atomic_read(&s->pending_exceptions_count))
- yield();
+ msleep(1);
/*
* Ensure instructions in mempool_destroy aren't reordered
* before atomic_read.
@@ -888,10 +895,10 @@ static void pending_complete(struct dm_snap_pending_exception *pe, int success)
/*
* Check for conflicting reads. This is extremely improbable,
- * so yield() is sufficient and there is no need for a wait queue.
+ * so msleep(1) is sufficient and there is no need for a wait queue.
*/
while (__chunk_is_tracked(s, pe->e.old_chunk))
- yield();
+ msleep(1);
/*
* Add a proper exception, and remove the
@@ -1404,6 +1411,12 @@ static int __init dm_snapshot_init(void)
{
int r;
+ r = dm_exception_store_init();
+ if (r) {
+ DMERR("Failed to initialize exception stores");
+ return r;
+ }
+
r = dm_register_target(&snapshot_target);
if (r) {
DMERR("snapshot target register failed %d", r);
@@ -1452,39 +1465,34 @@ static int __init dm_snapshot_init(void)
return 0;
- bad_pending_pool:
+bad_pending_pool:
kmem_cache_destroy(tracked_chunk_cache);
- bad5:
+bad5:
kmem_cache_destroy(pending_cache);
- bad4:
+bad4:
kmem_cache_destroy(exception_cache);
- bad3:
+bad3:
exit_origin_hash();
- bad2:
+bad2:
dm_unregister_target(&origin_target);
- bad1:
+bad1:
dm_unregister_target(&snapshot_target);
return r;
}
static void __exit dm_snapshot_exit(void)
{
- int r;
-
destroy_workqueue(ksnapd);
- r = dm_unregister_target(&snapshot_target);
- if (r)
- DMERR("snapshot unregister failed %d", r);
-
- r = dm_unregister_target(&origin_target);
- if (r)
- DMERR("origin unregister failed %d", r);
+ dm_unregister_target(&snapshot_target);
+ dm_unregister_target(&origin_target);
exit_origin_hash();
kmem_cache_destroy(pending_cache);
kmem_cache_destroy(exception_cache);
kmem_cache_destroy(tracked_chunk_cache);
+
+ dm_exception_store_exit();
}
/* Module hooks */
diff --git a/drivers/md/dm-snap.h b/drivers/md/dm-snap.h
index 99c0106ede2d..d9e62b43cf85 100644
--- a/drivers/md/dm-snap.h
+++ b/drivers/md/dm-snap.h
@@ -1,6 +1,4 @@
/*
- * dm-snapshot.c
- *
* Copyright (C) 2001-2002 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
@@ -10,6 +8,7 @@
#define DM_SNAPSHOT_H
#include <linux/device-mapper.h>
+#include "dm-exception-store.h"
#include "dm-bio-list.h"
#include <linux/blkdev.h>
#include <linux/workqueue.h>
@@ -20,116 +19,6 @@ struct exception_table {
struct list_head *table;
};
-/*
- * The snapshot code deals with largish chunks of the disk at a
- * time. Typically 32k - 512k.
- */
-typedef sector_t chunk_t;
-
-/*
- * An exception is used where an old chunk of data has been
- * replaced by a new one.
- * If chunk_t is 64 bits in size, the top 8 bits of new_chunk hold the number
- * of chunks that follow contiguously. Remaining bits hold the number of the
- * chunk within the device.
- */
-struct dm_snap_exception {
- struct list_head hash_list;
-
- chunk_t old_chunk;
- chunk_t new_chunk;
-};
-
-/*
- * Funtions to manipulate consecutive chunks
- */
-# if defined(CONFIG_LBD) || (BITS_PER_LONG == 64)
-# define DM_CHUNK_CONSECUTIVE_BITS 8
-# define DM_CHUNK_NUMBER_BITS 56
-
-static inline chunk_t dm_chunk_number(chunk_t chunk)
-{
- return chunk & (chunk_t)((1ULL << DM_CHUNK_NUMBER_BITS) - 1ULL);
-}
-
-static inline unsigned dm_consecutive_chunk_count(struct dm_snap_exception *e)
-{
- return e->new_chunk >> DM_CHUNK_NUMBER_BITS;
-}
-
-static inline void dm_consecutive_chunk_count_inc(struct dm_snap_exception *e)
-{
- e->new_chunk += (1ULL << DM_CHUNK_NUMBER_BITS);
-
- BUG_ON(!dm_consecutive_chunk_count(e));
-}
-
-# else
-# define DM_CHUNK_CONSECUTIVE_BITS 0
-
-static inline chunk_t dm_chunk_number(chunk_t chunk)
-{
- return chunk;
-}
-
-static inline unsigned dm_consecutive_chunk_count(struct dm_snap_exception *e)
-{
- return 0;
-}
-
-static inline void dm_consecutive_chunk_count_inc(struct dm_snap_exception *e)
-{
-}
-
-# endif
-
-/*
- * Abstraction to handle the meta/layout of exception stores (the
- * COW device).
- */
-struct exception_store {
-
- /*
- * Destroys this object when you've finished with it.
- */
- void (*destroy) (struct exception_store *store);
-
- /*
- * The target shouldn't read the COW device until this is
- * called.
- */
- int (*read_metadata) (struct exception_store *store);
-
- /*
- * Find somewhere to store the next exception.
- */
- int (*prepare_exception) (struct exception_store *store,
- struct dm_snap_exception *e);
-
- /*
- * Update the metadata with this exception.
- */
- void (*commit_exception) (struct exception_store *store,
- struct dm_snap_exception *e,
- void (*callback) (void *, int success),
- void *callback_context);
-
- /*
- * The snapshot is invalid, note this in the metadata.
- */
- void (*drop_snapshot) (struct exception_store *store);
-
- /*
- * Return how full the snapshot is.
- */
- void (*fraction_full) (struct exception_store *store,
- sector_t *numerator,
- sector_t *denominator);
-
- struct dm_snapshot *snap;
- void *context;
-};
-
#define DM_TRACKED_CHUNK_HASH_SIZE 16
#define DM_TRACKED_CHUNK_HASH(x) ((unsigned long)(x) & \
(DM_TRACKED_CHUNK_HASH_SIZE - 1))
@@ -172,7 +61,7 @@ struct dm_snapshot {
spinlock_t pe_lock;
/* The on disk metadata handler */
- struct exception_store store;
+ struct dm_exception_store store;
struct dm_kcopyd_client *kcopyd_client;
@@ -187,20 +76,6 @@ struct dm_snapshot {
};
/*
- * Used by the exception stores to load exceptions hen
- * initialising.
- */
-int dm_add_exception(struct dm_snapshot *s, chunk_t old, chunk_t new);
-
-/*
- * Constructor and destructor for the default persistent
- * store.
- */
-int dm_create_persistent(struct exception_store *store);
-
-int dm_create_transient(struct exception_store *store);
-
-/*
* Return the number of sectors in the device.
*/
static inline sector_t get_dev_size(struct block_device *bdev)
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index 9e4ef88d421e..41569bc60abc 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -337,9 +337,7 @@ int __init dm_stripe_init(void)
void dm_stripe_exit(void)
{
- if (dm_unregister_target(&stripe_target))
- DMWARN("target unregistration failed");
-
+ dm_unregister_target(&stripe_target);
destroy_workqueue(kstriped);
return;
diff --git a/drivers/md/dm-sysfs.c b/drivers/md/dm-sysfs.c
new file mode 100644
index 000000000000..a2a45e6c7c8b
--- /dev/null
+++ b/drivers/md/dm-sysfs.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/sysfs.h>
+#include <linux/dm-ioctl.h>
+#include "dm.h"
+
+struct dm_sysfs_attr {
+ struct attribute attr;
+ ssize_t (*show)(struct mapped_device *, char *);
+ ssize_t (*store)(struct mapped_device *, char *);
+};
+
+#define DM_ATTR_RO(_name) \
+struct dm_sysfs_attr dm_attr_##_name = \
+ __ATTR(_name, S_IRUGO, dm_attr_##_name##_show, NULL)
+
+static ssize_t dm_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *page)
+{
+ struct dm_sysfs_attr *dm_attr;
+ struct mapped_device *md;
+ ssize_t ret;
+
+ dm_attr = container_of(attr, struct dm_sysfs_attr, attr);
+ if (!dm_attr->show)
+ return -EIO;
+
+ md = dm_get_from_kobject(kobj);
+ if (!md)
+ return -EINVAL;
+
+ ret = dm_attr->show(md, page);
+ dm_put(md);
+
+ return ret;
+}
+
+static ssize_t dm_attr_name_show(struct mapped_device *md, char *buf)
+{
+ if (dm_copy_name_and_uuid(md, buf, NULL))
+ return -EIO;
+
+ strcat(buf, "\n");
+ return strlen(buf);
+}
+
+static ssize_t dm_attr_uuid_show(struct mapped_device *md, char *buf)
+{
+ if (dm_copy_name_and_uuid(md, NULL, buf))
+ return -EIO;
+
+ strcat(buf, "\n");
+ return strlen(buf);
+}
+
+static DM_ATTR_RO(name);
+static DM_ATTR_RO(uuid);
+
+static struct attribute *dm_attrs[] = {
+ &dm_attr_name.attr,
+ &dm_attr_uuid.attr,
+ NULL,
+};
+
+static struct sysfs_ops dm_sysfs_ops = {
+ .show = dm_attr_show,
+};
+
+/*
+ * dm kobject is embedded in mapped_device structure
+ * no need to define release function here
+ */
+static struct kobj_type dm_ktype = {
+ .sysfs_ops = &dm_sysfs_ops,
+ .default_attrs = dm_attrs,
+};
+
+/*
+ * Initialize kobj
+ * because nobody using md yet, no need to call explicit dm_get/put
+ */
+int dm_sysfs_init(struct mapped_device *md)
+{
+ return kobject_init_and_add(dm_kobject(md), &dm_ktype,
+ &disk_to_dev(dm_disk(md))->kobj,
+ "%s", "dm");
+}
+
+/*
+ * Remove kobj, called after all references removed
+ */
+void dm_sysfs_exit(struct mapped_device *md)
+{
+ kobject_put(dm_kobject(md));
+}
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 04e5fd742c2c..2fd66c30f7f8 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
*
* This file is released under the GPL.
*/
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
+#include <linux/delay.h>
#include <asm/atomic.h>
#define DM_MSG_PREFIX "table"
@@ -24,6 +25,19 @@
#define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t))
#define CHILDREN_PER_NODE (KEYS_PER_NODE + 1)
+/*
+ * The table has always exactly one reference from either mapped_device->map
+ * or hash_cell->new_map. This reference is not counted in table->holders.
+ * A pair of dm_create_table/dm_destroy_table functions is used for table
+ * creation/destruction.
+ *
+ * Temporary references from the other code increase table->holders. A pair
+ * of dm_table_get/dm_table_put functions is used to manipulate it.
+ *
+ * When the table is about to be destroyed, we wait for table->holders to
+ * drop to zero.
+ */
+
struct dm_table {
struct mapped_device *md;
atomic_t holders;
@@ -38,6 +52,8 @@ struct dm_table {
sector_t *highs;
struct dm_target *targets;
+ unsigned barriers_supported:1;
+
/*
* Indicates the rw permissions for the new logical
* device. This should be a combination of FMODE_READ
@@ -226,7 +242,8 @@ int dm_table_create(struct dm_table **result, fmode_t mode,
return -ENOMEM;
INIT_LIST_HEAD(&t->devices);
- atomic_set(&t->holders, 1);
+ atomic_set(&t->holders, 0);
+ t->barriers_supported = 1;
if (!num_targets)
num_targets = KEYS_PER_NODE;
@@ -256,10 +273,14 @@ static void free_devices(struct list_head *devices)
}
}
-static void table_destroy(struct dm_table *t)
+void dm_table_destroy(struct dm_table *t)
{
unsigned int i;
+ while (atomic_read(&t->holders))
+ msleep(1);
+ smp_mb();
+
/* free the indexes (see dm_table_complete) */
if (t->depth >= 2)
vfree(t->index[t->depth - 2]);
@@ -297,8 +318,8 @@ void dm_table_put(struct dm_table *t)
if (!t)
return;
- if (atomic_dec_and_test(&t->holders))
- table_destroy(t);
+ smp_mb__before_atomic_dec();
+ atomic_dec(&t->holders);
}
/*
@@ -728,6 +749,10 @@ int dm_table_add_target(struct dm_table *t, const char *type,
/* FIXME: the plan is to combine high here and then have
* the merge fn apply the target level restrictions. */
combine_restrictions_low(&t->limits, &tgt->limits);
+
+ if (!(tgt->type->features & DM_TARGET_SUPPORTS_BARRIERS))
+ t->barriers_supported = 0;
+
return 0;
bad:
@@ -772,6 +797,12 @@ int dm_table_complete(struct dm_table *t)
check_for_valid_limits(&t->limits);
+ /*
+ * We only support barriers if there is exactly one underlying device.
+ */
+ if (!list_is_singular(&t->devices))
+ t->barriers_supported = 0;
+
/* how many indexes will the btree have ? */
leaf_nodes = dm_div_up(t->num_targets, KEYS_PER_NODE);
t->depth = 1 + int_log(leaf_nodes, CHILDREN_PER_NODE);
@@ -986,6 +1017,12 @@ struct mapped_device *dm_table_get_md(struct dm_table *t)
return t->md;
}
+int dm_table_barrier_ok(struct dm_table *t)
+{
+ return t->barriers_supported;
+}
+EXPORT_SYMBOL(dm_table_barrier_ok);
+
EXPORT_SYMBOL(dm_vcalloc);
EXPORT_SYMBOL(dm_get_device);
EXPORT_SYMBOL(dm_put_device);
diff --git a/drivers/md/dm-target.c b/drivers/md/dm-target.c
index 835cf95b857f..7decf10006e4 100644
--- a/drivers/md/dm-target.c
+++ b/drivers/md/dm-target.c
@@ -130,26 +130,26 @@ int dm_register_target(struct target_type *t)
return rv;
}
-int dm_unregister_target(struct target_type *t)
+void dm_unregister_target(struct target_type *t)
{
struct tt_internal *ti;
down_write(&_lock);
if (!(ti = __find_target_type(t->name))) {
- up_write(&_lock);
- return -EINVAL;
+ DMCRIT("Unregistering unrecognised target: %s", t->name);
+ BUG();
}
if (ti->use) {
- up_write(&_lock);
- return -ETXTBSY;
+ DMCRIT("Attempt to unregister target still in use: %s",
+ t->name);
+ BUG();
}
list_del(&ti->list);
kfree(ti);
up_write(&_lock);
- return 0;
}
/*
@@ -187,8 +187,7 @@ int __init dm_target_init(void)
void dm_target_exit(void)
{
- if (dm_unregister_target(&error_target))
- DMWARN("error target unregistration failed");
+ dm_unregister_target(&error_target);
}
EXPORT_SYMBOL(dm_register_target);
diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c
index cdbf126ec106..bbc97030c0c2 100644
--- a/drivers/md/dm-zero.c
+++ b/drivers/md/dm-zero.c
@@ -69,10 +69,7 @@ static int __init dm_zero_init(void)
static void __exit dm_zero_exit(void)
{
- int r = dm_unregister_target(&zero_target);
-
- if (r < 0)
- DMERR("unregister failed %d", r);
+ dm_unregister_target(&zero_target);
}
module_init(dm_zero_init)
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 421c9f02d8ca..51ba1db4b3e7 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
- * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2008 Red Hat, Inc. All rights reserved.
*
* This file is released under the GPL.
*/
@@ -32,6 +32,7 @@ static unsigned int _major = 0;
static DEFINE_SPINLOCK(_minor_lock);
/*
+ * For bio-based dm.
* One of these is allocated per bio.
*/
struct dm_io {
@@ -43,6 +44,7 @@ struct dm_io {
};
/*
+ * For bio-based dm.
* One of these is allocated per target within a bio. Hopefully
* this will be simplified out one day.
*/
@@ -54,6 +56,27 @@ struct dm_target_io {
DEFINE_TRACE(block_bio_complete);
+/*
+ * For request-based dm.
+ * One of these is allocated per request.
+ */
+struct dm_rq_target_io {
+ struct mapped_device *md;
+ struct dm_target *ti;
+ struct request *orig, clone;
+ int error;
+ union map_info info;
+};
+
+/*
+ * For request-based dm.
+ * One of these is allocated per bio.
+ */
+struct dm_rq_clone_bio_info {
+ struct bio *orig;
+ struct request *rq;
+};
+
union map_info *dm_get_mapinfo(struct bio *bio)
{
if (bio && bio->bi_private)
@@ -144,11 +167,16 @@ struct mapped_device {
/* forced geometry settings */
struct hd_geometry geometry;
+
+ /* sysfs handle */
+ struct kobject kobj;
};
#define MIN_IOS 256
static struct kmem_cache *_io_cache;
static struct kmem_cache *_tio_cache;
+static struct kmem_cache *_rq_tio_cache;
+static struct kmem_cache *_rq_bio_info_cache;
static int __init local_init(void)
{
@@ -164,9 +192,17 @@ static int __init local_init(void)
if (!_tio_cache)
goto out_free_io_cache;
+ _rq_tio_cache = KMEM_CACHE(dm_rq_target_io, 0);
+ if (!_rq_tio_cache)
+ goto out_free_tio_cache;
+
+ _rq_bio_info_cache = KMEM_CACHE(dm_rq_clone_bio_info, 0);
+ if (!_rq_bio_info_cache)
+ goto out_free_rq_tio_cache;
+
r = dm_uevent_init();
if (r)
- goto out_free_tio_cache;
+ goto out_free_rq_bio_info_cache;
_major = major;
r = register_blkdev(_major, _name);
@@ -180,6 +216,10 @@ static int __init local_init(void)
out_uevent_exit:
dm_uevent_exit();
+out_free_rq_bio_info_cache:
+ kmem_cache_destroy(_rq_bio_info_cache);
+out_free_rq_tio_cache:
+ kmem_cache_destroy(_rq_tio_cache);
out_free_tio_cache:
kmem_cache_destroy(_tio_cache);
out_free_io_cache:
@@ -190,6 +230,8 @@ out_free_io_cache:
static void local_exit(void)
{
+ kmem_cache_destroy(_rq_bio_info_cache);
+ kmem_cache_destroy(_rq_tio_cache);
kmem_cache_destroy(_tio_cache);
kmem_cache_destroy(_io_cache);
unregister_blkdev(_major, _name);
@@ -796,7 +838,11 @@ static int __split_bio(struct mapped_device *md, struct bio *bio)
ci.map = dm_get_table(md);
if (unlikely(!ci.map))
return -EIO;
-
+ if (unlikely(bio_barrier(bio) && !dm_table_barrier_ok(ci.map))) {
+ dm_table_put(ci.map);
+ bio_endio(bio, -EOPNOTSUPP);
+ return 0;
+ }
ci.md = md;
ci.bio = bio;
ci.io = alloc_io(md);
@@ -880,15 +926,6 @@ static int dm_request(struct request_queue *q, struct bio *bio)
struct mapped_device *md = q->queuedata;
int cpu;
- /*
- * There is no use in forwarding any barrier request since we can't
- * guarantee it is (or can be) handled by the targets correctly.
- */
- if (unlikely(bio_barrier(bio))) {
- bio_endio(bio, -EOPNOTSUPP);
- return 0;
- }
-
down_read(&md->io_lock);
cpu = part_stat_lock();
@@ -943,8 +980,6 @@ static int dm_any_congested(void *congested_data, int bdi_bits)
struct mapped_device *md = congested_data;
struct dm_table *map;
- atomic_inc(&md->pending);
-
if (!test_bit(DMF_BLOCK_IO, &md->flags)) {
map = dm_get_table(md);
if (map) {
@@ -953,10 +988,6 @@ static int dm_any_congested(void *congested_data, int bdi_bits)
}
}
- if (!atomic_dec_return(&md->pending))
- /* nudge anyone waiting on suspend queue */
- wake_up(&md->wait);
-
return r;
}
@@ -1216,10 +1247,12 @@ static int __bind(struct mapped_device *md, struct dm_table *t)
if (md->suspended_bdev)
__set_size(md, size);
- if (size == 0)
+
+ if (!size) {
+ dm_table_destroy(t);
return 0;
+ }
- dm_table_get(t);
dm_table_event_callback(t, event_callback, md);
write_lock(&md->map_lock);
@@ -1241,7 +1274,7 @@ static void __unbind(struct mapped_device *md)
write_lock(&md->map_lock);
md->map = NULL;
write_unlock(&md->map_lock);
- dm_table_put(map);
+ dm_table_destroy(map);
}
/*
@@ -1255,6 +1288,8 @@ int dm_create(int minor, struct mapped_device **result)
if (!md)
return -ENXIO;
+ dm_sysfs_init(md);
+
*result = md;
return 0;
}
@@ -1330,8 +1365,9 @@ void dm_put(struct mapped_device *md)
dm_table_presuspend_targets(map);
dm_table_postsuspend_targets(map);
}
- __unbind(md);
+ dm_sysfs_exit(md);
dm_table_put(map);
+ __unbind(md);
free_dev(md);
}
}
@@ -1669,6 +1705,27 @@ struct gendisk *dm_disk(struct mapped_device *md)
return md->disk;
}
+struct kobject *dm_kobject(struct mapped_device *md)
+{
+ return &md->kobj;
+}
+
+/*
+ * struct mapped_device should not be exported outside of dm.c
+ * so use this check to verify that kobj is part of md structure
+ */
+struct mapped_device *dm_get_from_kobject(struct kobject *kobj)
+{
+ struct mapped_device *md;
+
+ md = container_of(kobj, struct mapped_device, kobj);
+ if (&md->kobj != kobj)
+ return NULL;
+
+ dm_get(md);
+ return md;
+}
+
int dm_suspended(struct mapped_device *md)
{
return test_bit(DMF_SUSPENDED, &md->flags);
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 0ade60cdef42..20194e000c5a 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -36,6 +36,7 @@ struct dm_table;
/*-----------------------------------------------------------------
* Internal table functions.
*---------------------------------------------------------------*/
+void dm_table_destroy(struct dm_table *t);
void dm_table_event_callback(struct dm_table *t,
void (*fn)(void *), void *context);
struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index);
@@ -51,6 +52,7 @@ int dm_table_any_congested(struct dm_table *t, int bdi_bits);
* To check the return value from dm_table_find_target().
*/
#define dm_target_is_valid(t) ((t)->table)
+int dm_table_barrier_ok(struct dm_table *t);
/*-----------------------------------------------------------------
* A registry of target types.
@@ -72,6 +74,14 @@ int dm_interface_init(void);
void dm_interface_exit(void);
/*
+ * sysfs interface
+ */
+int dm_sysfs_init(struct mapped_device *md);
+void dm_sysfs_exit(struct mapped_device *md);
+struct kobject *dm_kobject(struct mapped_device *md);
+struct mapped_device *dm_get_from_kobject(struct kobject *kobj);
+
+/*
* Targets for linear and striped mappings
*/
int dm_linear_init(void);
diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c
index 56faef1a1d55..06c655c55587 100644
--- a/drivers/message/i2o/exec-osm.c
+++ b/drivers/message/i2o/exec-osm.c
@@ -19,7 +19,7 @@
* Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
* Deepak Saxena <deepak@plexity.net>
* Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
- * Alan Cox <alan@redhat.com>:
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>:
* Ported to Linux 2.5.
* Markus Lidel <Markus.Lidel@shadowconnect.com>:
* Minor fixes for 2.6.
diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c
index f3384c32b9a1..efba7021948a 100644
--- a/drivers/message/i2o/i2o_config.c
+++ b/drivers/message/i2o/i2o_config.c
@@ -19,7 +19,7 @@
* Changed ioctl_swdl(), implemented ioctl_swul() and ioctl_swdel()
* Deepak Saxena (11/18/1999):
* Added event managmenet support
- * Alan Cox <alan@redhat.com>:
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>:
* 2.4 rewrite ported to 2.5
* Markus Lidel <Markus.Lidel@shadowconnect.com>:
* Added pass-thru support for Adaptec's raidutils
diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c
index 6e53a30bfd38..35c67d1f255e 100644
--- a/drivers/message/i2o/iop.c
+++ b/drivers/message/i2o/iop.c
@@ -19,7 +19,7 @@
* Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
* Deepak Saxena <deepak@plexity.net>
* Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
- * Alan Cox <alan@redhat.com>:
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>:
* Ported to Linux 2.5.
* Markus Lidel <Markus.Lidel@shadowconnect.com>:
* Minor fixes for 2.6.
diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c
index 610ef1204e68..25d6f2341983 100644
--- a/drivers/message/i2o/pci.c
+++ b/drivers/message/i2o/pci.c
@@ -19,7 +19,7 @@
* Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
* Deepak Saxena <deepak@plexity.net>
* Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
- * Alan Cox <alan@redhat.com>:
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>:
* Ported to Linux 2.5.
* Markus Lidel <Markus.Lidel@shadowconnect.com>:
* Minor fixes for 2.6.
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 257277394f8c..416f9e7286ba 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -34,6 +34,14 @@ config MFD_ASIC3
This driver supports the ASIC3 multifunction chip found on many
PDAs (mainly iPAQ and HTC based ones)
+config MFD_DM355EVM_MSP
+ bool "DaVinci DM355 EVM microcontroller"
+ depends on I2C && MACH_DAVINCI_DM355_EVM
+ help
+ This driver supports the MSP430 microcontroller used on these
+ boards. MSP430 firmware manages resets and power sequencing,
+ inputs from buttons and the IR remote, LEDs, an RTC, and more.
+
config HTC_EGPIO
bool "HTC EGPIO support"
depends on GENERIC_HARDIRQS && GPIOLIB && ARM
@@ -61,9 +69,32 @@ config UCB1400_CORE
To compile this driver as a module, choose M here: the
module will be called ucb1400_core.
+config TPS65010
+ tristate "TPS6501x Power Management chips"
+ depends on I2C && GPIOLIB
+ default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK
+ help
+ If you say yes here you get support for the TPS6501x series of
+ Power Management chips. These include voltage regulators,
+ lithium ion/polymer battery charging, and other features that
+ are often used in portable devices like cell phones and cameras.
+
+ This driver can also be built as a module. If so, the module
+ will be called tps65010.
+
+config MENELAUS
+ bool "Texas Instruments TWL92330/Menelaus PM chip"
+ depends on I2C=y && ARCH_OMAP24XX
+ help
+ If you say yes here you get support for the Texas Instruments
+ TWL92330/Menelaus Power Management chip. This include voltage
+ regulators, Dual slot memory card tranceivers, real-time clock
+ and other features that are often used in portable devices like
+ cell phones and PDAs.
+
config TWL4030_CORE
bool "Texas Instruments TWL4030/TPS659x0 Support"
- depends on I2C=y && GENERIC_HARDIRQS && (ARCH_OMAP2 || ARCH_OMAP3)
+ depends on I2C=y && GENERIC_HARDIRQS
help
Say yes here if you have TWL4030 family chip on your board.
This core driver provides register access and IRQ handling
@@ -116,6 +147,7 @@ config PMIC_DA903X
config MFD_WM8400
tristate "Support Wolfson Microelectronics WM8400"
+ select MFD_CORE
depends on I2C
help
Support for the Wolfson Microelecronics WM8400 PMIC and audio
@@ -142,6 +174,38 @@ config MFD_WM8350_CONFIG_MODE_3
bool
depends on MFD_WM8350
+config MFD_WM8351_CONFIG_MODE_0
+ bool
+ depends on MFD_WM8350
+
+config MFD_WM8351_CONFIG_MODE_1
+ bool
+ depends on MFD_WM8350
+
+config MFD_WM8351_CONFIG_MODE_2
+ bool
+ depends on MFD_WM8350
+
+config MFD_WM8351_CONFIG_MODE_3
+ bool
+ depends on MFD_WM8350
+
+config MFD_WM8352_CONFIG_MODE_0
+ bool
+ depends on MFD_WM8350
+
+config MFD_WM8352_CONFIG_MODE_1
+ bool
+ depends on MFD_WM8350
+
+config MFD_WM8352_CONFIG_MODE_2
+ bool
+ depends on MFD_WM8350
+
+config MFD_WM8352_CONFIG_MODE_3
+ bool
+ depends on MFD_WM8350
+
config MFD_WM8350_I2C
tristate "Support Wolfson Microelectronics WM8350 with I2C"
select MFD_WM8350
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 9a5ad8af9116..0c9418b36c26 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -8,6 +8,8 @@ obj-$(CONFIG_MFD_ASIC3) += asic3.o
obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o
obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o
+obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
+
obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o
obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o
obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o
@@ -17,6 +19,9 @@ wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
obj-$(CONFIG_MFD_WM8350) += wm8350.o
obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
+obj-$(CONFIG_TPS65010) += tps65010.o
+obj-$(CONFIG_MENELAUS) += menelaus.o
+
obj-$(CONFIG_TWL4030_CORE) += twl4030-core.o twl4030-irq.o
obj-$(CONFIG_MFD_CORE) += mfd-core.o
@@ -31,4 +36,4 @@ obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o
endif
obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o
-obj-$(CONFIG_PMIC_DA903X) += da903x.o \ No newline at end of file
+obj-$(CONFIG_PMIC_DA903X) += da903x.o
diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c
index 0b5bd85dfcec..99f8dcfe3d98 100644
--- a/drivers/mfd/da903x.c
+++ b/drivers/mfd/da903x.c
@@ -151,12 +151,24 @@ int da903x_write(struct device *dev, int reg, uint8_t val)
}
EXPORT_SYMBOL_GPL(da903x_write);
+int da903x_writes(struct device *dev, int reg, int len, uint8_t *val)
+{
+ return __da903x_writes(to_i2c_client(dev), reg, len, val);
+}
+EXPORT_SYMBOL_GPL(da903x_writes);
+
int da903x_read(struct device *dev, int reg, uint8_t *val)
{
return __da903x_read(to_i2c_client(dev), reg, val);
}
EXPORT_SYMBOL_GPL(da903x_read);
+int da903x_reads(struct device *dev, int reg, int len, uint8_t *val)
+{
+ return __da903x_reads(to_i2c_client(dev), reg, len, val);
+}
+EXPORT_SYMBOL_GPL(da903x_reads);
+
int da903x_set_bits(struct device *dev, int reg, uint8_t bit_mask)
{
struct da903x_chip *chip = dev_get_drvdata(dev);
@@ -435,13 +447,13 @@ static const struct i2c_device_id da903x_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, da903x_id_table);
-static int __devexit __remove_subdev(struct device *dev, void *unused)
+static int __remove_subdev(struct device *dev, void *unused)
{
platform_device_unregister(to_platform_device(dev));
return 0;
}
-static int __devexit da903x_remove_subdevs(struct da903x_chip *chip)
+static int da903x_remove_subdevs(struct da903x_chip *chip)
{
return device_for_each_child(chip->dev, NULL, __remove_subdev);
}
diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c
new file mode 100644
index 000000000000..4214b3f72426
--- /dev/null
+++ b/drivers/mfd/dm355evm_msp.c
@@ -0,0 +1,420 @@
+/*
+ * dm355evm_msp.c - driver for MSP430 firmware on DM355EVM board
+ *
+ * Copyright (C) 2008 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/i2c.h>
+#include <linux/i2c/dm355evm_msp.h>
+
+
+/*
+ * The DM355 is a DaVinci chip with video support but no C64+ DSP. Its
+ * EVM board has an MSP430 programmed with firmware for various board
+ * support functions. This driver exposes some of them directly, and
+ * supports other drivers (e.g. RTC, input) for more complex access.
+ *
+ * Because this firmware is entirely board-specific, this file embeds
+ * knowledge that would be passed as platform_data in a generic driver.
+ *
+ * This driver was tested with firmware revision A4.
+ */
+
+#if defined(CONFIG_KEYBOARD_DM355EVM) \
+ || defined(CONFIG_KEYBOARD_DM355EVM_MODULE)
+#define msp_has_keyboard() true
+#else
+#define msp_has_keyboard() false
+#endif
+
+#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+#define msp_has_leds() true
+#else
+#define msp_has_leds() false
+#endif
+
+#if defined(CONFIG_RTC_DRV_DM355EVM) || defined(CONFIG_RTC_DRV_DM355EVM_MODULE)
+#define msp_has_rtc() true
+#else
+#define msp_has_rtc() false
+#endif
+
+#if defined(CONFIG_VIDEO_TVP514X) || defined(CONFIG_VIDEO_TVP514X_MODULE)
+#define msp_has_tvp() true
+#else
+#define msp_has_tvp() false
+#endif
+
+
+/*----------------------------------------------------------------------*/
+
+/* REVISIT for paranoia's sake, retry reads/writes on error */
+
+static struct i2c_client *msp430;
+
+/**
+ * dm355evm_msp_write - Writes a register in dm355evm_msp
+ * @value: the value to be written
+ * @reg: register address
+ *
+ * Returns result of operation - 0 is success, else negative errno
+ */
+int dm355evm_msp_write(u8 value, u8 reg)
+{
+ return i2c_smbus_write_byte_data(msp430, reg, value);
+}
+EXPORT_SYMBOL(dm355evm_msp_write);
+
+/**
+ * dm355evm_msp_read - Reads a register from dm355evm_msp
+ * @reg: register address
+ *
+ * Returns result of operation - value, or negative errno
+ */
+int dm355evm_msp_read(u8 reg)
+{
+ return i2c_smbus_read_byte_data(msp430, reg);
+}
+EXPORT_SYMBOL(dm355evm_msp_read);
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Many of the msp430 pins are just used as fixed-direction GPIOs.
+ * We could export a few more of them this way, if we wanted.
+ */
+#define MSP_GPIO(bit,reg) ((DM355EVM_MSP_ ## reg) << 3 | (bit))
+
+static const u8 msp_gpios[] = {
+ /* eight leds */
+ MSP_GPIO(0, LED), MSP_GPIO(1, LED),
+ MSP_GPIO(2, LED), MSP_GPIO(3, LED),
+ MSP_GPIO(4, LED), MSP_GPIO(5, LED),
+ MSP_GPIO(6, LED), MSP_GPIO(7, LED),
+ /* SW6 and the NTSC/nPAL jumper */
+ MSP_GPIO(0, SWITCH1), MSP_GPIO(1, SWITCH1),
+ MSP_GPIO(2, SWITCH1), MSP_GPIO(3, SWITCH1),
+ MSP_GPIO(4, SWITCH1),
+};
+
+#define MSP_GPIO_REG(offset) (msp_gpios[(offset)] >> 3)
+#define MSP_GPIO_MASK(offset) BIT(msp_gpios[(offset)] & 0x07)
+
+static int msp_gpio_in(struct gpio_chip *chip, unsigned offset)
+{
+ switch (MSP_GPIO_REG(offset)) {
+ case DM355EVM_MSP_SWITCH1:
+ case DM355EVM_MSP_SWITCH2:
+ case DM355EVM_MSP_SDMMC:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static u8 msp_led_cache;
+
+static int msp_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ int reg, status;
+
+ reg = MSP_GPIO_REG(offset);
+ status = dm355evm_msp_read(reg);
+ if (status < 0)
+ return status;
+ if (reg == DM355EVM_MSP_LED)
+ msp_led_cache = status;
+ return status & MSP_GPIO_MASK(offset);
+}
+
+static int msp_gpio_out(struct gpio_chip *chip, unsigned offset, int value)
+{
+ int mask, bits;
+
+ /* NOTE: there are some other signals that could be
+ * packaged as output GPIOs, but they aren't as useful
+ * as the LEDs ... so for now we don't.
+ */
+ if (MSP_GPIO_REG(offset) != DM355EVM_MSP_LED)
+ return -EINVAL;
+
+ mask = MSP_GPIO_MASK(offset);
+ bits = msp_led_cache;
+
+ bits &= ~mask;
+ if (value)
+ bits |= mask;
+ msp_led_cache = bits;
+
+ return dm355evm_msp_write(bits, DM355EVM_MSP_LED);
+}
+
+static void msp_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ msp_gpio_out(chip, offset, value);
+}
+
+static struct gpio_chip dm355evm_msp_gpio = {
+ .label = "dm355evm_msp",
+ .owner = THIS_MODULE,
+ .direction_input = msp_gpio_in,
+ .get = msp_gpio_get,
+ .direction_output = msp_gpio_out,
+ .set = msp_gpio_set,
+ .base = -EINVAL, /* dynamic assignment */
+ .ngpio = ARRAY_SIZE(msp_gpios),
+ .can_sleep = true,
+};
+
+/*----------------------------------------------------------------------*/
+
+static struct device *add_child(struct i2c_client *client, const char *name,
+ void *pdata, unsigned pdata_len,
+ bool can_wakeup, int irq)
+{
+ struct platform_device *pdev;
+ int status;
+
+ pdev = platform_device_alloc(name, -1);
+ if (!pdev) {
+ dev_dbg(&client->dev, "can't alloc dev\n");
+ status = -ENOMEM;
+ goto err;
+ }
+
+ device_init_wakeup(&pdev->dev, can_wakeup);
+ pdev->dev.parent = &client->dev;
+
+ if (pdata) {
+ status = platform_device_add_data(pdev, pdata, pdata_len);
+ if (status < 0) {
+ dev_dbg(&pdev->dev, "can't add platform_data\n");
+ goto err;
+ }
+ }
+
+ if (irq) {
+ struct resource r = {
+ .start = irq,
+ .flags = IORESOURCE_IRQ,
+ };
+
+ status = platform_device_add_resources(pdev, &r, 1);
+ if (status < 0) {
+ dev_dbg(&pdev->dev, "can't add irq\n");
+ goto err;
+ }
+ }
+
+ status = platform_device_add(pdev);
+
+err:
+ if (status < 0) {
+ platform_device_put(pdev);
+ dev_err(&client->dev, "can't add %s dev\n", name);
+ return ERR_PTR(status);
+ }
+ return &pdev->dev;
+}
+
+static int add_children(struct i2c_client *client)
+{
+ static const struct {
+ int offset;
+ char *label;
+ } config_inputs[] = {
+ /* 8 == right after the LEDs */
+ { 8 + 0, "sw6_1", },
+ { 8 + 1, "sw6_2", },
+ { 8 + 2, "sw6_3", },
+ { 8 + 3, "sw6_4", },
+ { 8 + 4, "NTSC/nPAL", },
+ };
+
+ struct device *child;
+ int status;
+ int i;
+
+ /* GPIO-ish stuff */
+ dm355evm_msp_gpio.dev = &client->dev;
+ status = gpiochip_add(&dm355evm_msp_gpio);
+ if (status < 0)
+ return status;
+
+ /* LED output */
+ if (msp_has_leds()) {
+#define GPIO_LED(l) .name = l, .active_low = true
+ static struct gpio_led evm_leds[] = {
+ { GPIO_LED("dm355evm::ds14"),
+ .default_trigger = "heartbeat", },
+ { GPIO_LED("dm355evm::ds15"),
+ .default_trigger = "mmc0", },
+ { GPIO_LED("dm355evm::ds16"),
+ /* could also be a CE-ATA drive */
+ .default_trigger = "mmc1", },
+ { GPIO_LED("dm355evm::ds17"),
+ .default_trigger = "nand-disk", },
+ { GPIO_LED("dm355evm::ds18"), },
+ { GPIO_LED("dm355evm::ds19"), },
+ { GPIO_LED("dm355evm::ds20"), },
+ { GPIO_LED("dm355evm::ds21"), },
+ };
+#undef GPIO_LED
+
+ struct gpio_led_platform_data evm_led_data = {
+ .num_leds = ARRAY_SIZE(evm_leds),
+ .leds = evm_leds,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(evm_leds); i++)
+ evm_leds[i].gpio = i + dm355evm_msp_gpio.base;
+
+ /* NOTE: these are the only fully programmable LEDs
+ * on the board, since GPIO-61/ds22 (and many signals
+ * going to DC7) must be used for AEMIF address lines
+ * unless the top 1 GB of NAND is unused...
+ */
+ child = add_child(client, "leds-gpio",
+ &evm_led_data, sizeof(evm_led_data),
+ false, 0);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ }
+
+ /* configuration inputs */
+ for (i = 0; i < ARRAY_SIZE(config_inputs); i++) {
+ int gpio = dm355evm_msp_gpio.base + config_inputs[i].offset;
+
+ gpio_request(gpio, config_inputs[i].label);
+ gpio_direction_input(gpio);
+
+ /* make it easy for userspace to see these */
+ gpio_export(gpio, false);
+ }
+
+ /* RTC is a 32 bit counter, no alarm */
+ if (msp_has_rtc()) {
+ child = add_child(client, "rtc-dm355evm",
+ NULL, 0, false, 0);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ }
+
+ /* input from buttons and IR remote (uses the IRQ) */
+ if (msp_has_keyboard()) {
+ child = add_child(client, "dm355evm_keys",
+ NULL, 0, true, client->irq);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ }
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------*/
+
+static void dm355evm_command(unsigned command)
+{
+ int status;
+
+ status = dm355evm_msp_write(command, DM355EVM_MSP_COMMAND);
+ if (status < 0)
+ dev_err(&msp430->dev, "command %d failure %d\n",
+ command, status);
+}
+
+static void dm355evm_power_off(void)
+{
+ dm355evm_command(MSP_COMMAND_POWEROFF);
+}
+
+static int dm355evm_msp_remove(struct i2c_client *client)
+{
+ pm_power_off = NULL;
+ msp430 = NULL;
+ return 0;
+}
+
+static int
+dm355evm_msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ int status;
+ const char *video = msp_has_tvp() ? "TVP5146" : "imager";
+
+ if (msp430)
+ return -EBUSY;
+ msp430 = client;
+
+ /* display revision status; doubles as sanity check */
+ status = dm355evm_msp_read(DM355EVM_MSP_FIRMREV);
+ if (status < 0)
+ goto fail;
+ dev_info(&client->dev, "firmware v.%02X, %s as video-in\n",
+ status, video);
+
+ /* mux video input: either tvp5146 or some external imager */
+ status = dm355evm_msp_write(msp_has_tvp() ? 0 : MSP_VIDEO_IMAGER,
+ DM355EVM_MSP_VIDEO_IN);
+ if (status < 0)
+ dev_warn(&client->dev, "error %d muxing %s as video-in\n",
+ status, video);
+
+ /* init LED cache, and turn off the LEDs */
+ msp_led_cache = 0xff;
+ dm355evm_msp_write(msp_led_cache, DM355EVM_MSP_LED);
+
+ /* export capabilities we support */
+ status = add_children(client);
+ if (status < 0)
+ goto fail;
+
+ /* PM hookup */
+ pm_power_off = dm355evm_power_off;
+
+ return 0;
+
+fail:
+ /* FIXME remove children ... */
+ dm355evm_msp_remove(client);
+ return status;
+}
+
+static const struct i2c_device_id dm355evm_msp_ids[] = {
+ { "dm355evm_msp", 0 },
+ { /* end of list */ },
+};
+MODULE_DEVICE_TABLE(i2c, dm355evm_msp_ids);
+
+static struct i2c_driver dm355evm_msp_driver = {
+ .driver.name = "dm355evm_msp",
+ .id_table = dm355evm_msp_ids,
+ .probe = dm355evm_msp_probe,
+ .remove = dm355evm_msp_remove,
+};
+
+static int __init dm355evm_msp_init(void)
+{
+ return i2c_add_driver(&dm355evm_msp_driver);
+}
+subsys_initcall(dm355evm_msp_init);
+
+static void __exit dm355evm_msp_exit(void)
+{
+ i2c_del_driver(&dm355evm_msp_driver);
+}
+module_exit(dm355evm_msp_exit);
+
+MODULE_DESCRIPTION("Interface to MSP430 firmware on DM355EVM");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/chips/menelaus.c b/drivers/mfd/menelaus.c
index 4b364bae6b3e..4b364bae6b3e 100644
--- a/drivers/i2c/chips/menelaus.c
+++ b/drivers/mfd/menelaus.c
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index 6c0d1bec4b76..54ddf3772e0c 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -34,6 +34,7 @@ static int mfd_add_device(struct device *parent, int id,
goto fail_device;
pdev->dev.parent = parent;
+ platform_set_drvdata(pdev, cell->driver_data);
ret = platform_device_add_data(pdev,
cell->platform_data, cell->data_size);
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/mfd/tps65010.c
index acf8b9d5f575..acf8b9d5f575 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/mfd/tps65010.c
diff --git a/drivers/mfd/twl4030-core.c b/drivers/mfd/twl4030-core.c
index dd843c4fbcc7..b59c385cbc12 100644
--- a/drivers/mfd/twl4030-core.c
+++ b/drivers/mfd/twl4030-core.c
@@ -33,6 +33,8 @@
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/regulator/machine.h>
+
#include <linux/i2c.h>
#include <linux/i2c/twl4030.h>
@@ -71,6 +73,13 @@
#define twl_has_gpio() false
#endif
+#if defined(CONFIG_REGULATOR_TWL4030) \
+ || defined(CONFIG_REGULATOR_TWL4030_MODULE)
+#define twl_has_regulator() true
+#else
+#define twl_has_regulator() false
+#endif
+
#if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE)
#define twl_has_madc() true
#else
@@ -149,6 +158,10 @@
#define HIGH_PERF_SQ (1 << 3)
+/* chip-specific feature flags, for i2c_device_id.driver_data */
+#define TWL4030_VAUX2 BIT(0) /* pre-5030 voltage ranges */
+#define TPS_SUBSET BIT(1) /* tps659[23]0 have fewer LDOs */
+
/*----------------------------------------------------------------------*/
/* is driver active, bound to a chip? */
@@ -225,7 +238,7 @@ static struct twl4030mapping twl4030_map[TWL4030_MODULE_LAST + 1] = {
*
* Returns the result of operation - 0 is success
*/
-int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, u8 num_bytes)
+int twl4030_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
{
int ret;
int sid;
@@ -274,7 +287,7 @@ EXPORT_SYMBOL(twl4030_i2c_write);
*
* Returns result of operation - num_bytes is success else failure.
*/
-int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, u8 num_bytes)
+int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
{
int ret;
u8 val;
@@ -352,258 +365,258 @@ EXPORT_SYMBOL(twl4030_i2c_read_u8);
/*----------------------------------------------------------------------*/
-/*
- * NOTE: We know the first 8 IRQs after pdata->base_irq are
- * for the PIH, and the next are for the PWR_INT SIH, since
- * that's how twl_init_irq() sets things up.
- */
-
-static int add_children(struct twl4030_platform_data *pdata)
+static struct device *
+add_numbered_child(unsigned chip, const char *name, int num,
+ void *pdata, unsigned pdata_len,
+ bool can_wakeup, int irq0, int irq1)
{
- struct platform_device *pdev = NULL;
- struct twl4030_client *twl = NULL;
- int status = 0;
+ struct platform_device *pdev;
+ struct twl4030_client *twl = &twl4030_modules[chip];
+ int status;
+
+ pdev = platform_device_alloc(name, num);
+ if (!pdev) {
+ dev_dbg(&twl->client->dev, "can't alloc dev\n");
+ status = -ENOMEM;
+ goto err;
+ }
- if (twl_has_bci() && pdata->bci) {
- twl = &twl4030_modules[3];
+ device_init_wakeup(&pdev->dev, can_wakeup);
+ pdev->dev.parent = &twl->client->dev;
- pdev = platform_device_alloc("twl4030_bci", -1);
- if (!pdev) {
- pr_debug("%s: can't alloc bci dev\n", DRIVER_NAME);
- status = -ENOMEM;
+ if (pdata) {
+ status = platform_device_add_data(pdev, pdata, pdata_len);
+ if (status < 0) {
+ dev_dbg(&pdev->dev, "can't add platform_data\n");
goto err;
}
+ }
- if (status == 0) {
- pdev->dev.parent = &twl->client->dev;
- status = platform_device_add_data(pdev, pdata->bci,
- sizeof(*pdata->bci));
- if (status < 0) {
- dev_dbg(&twl->client->dev,
- "can't add bci data, %d\n",
- status);
- goto err;
- }
- }
-
- if (status == 0) {
- struct resource r = {
- .start = pdata->irq_base + 8 + 1,
- .flags = IORESOURCE_IRQ,
- };
-
- status = platform_device_add_resources(pdev, &r, 1);
- }
-
- if (status == 0)
- status = platform_device_add(pdev);
+ if (irq0) {
+ struct resource r[2] = {
+ { .start = irq0, .flags = IORESOURCE_IRQ, },
+ { .start = irq1, .flags = IORESOURCE_IRQ, },
+ };
+ status = platform_device_add_resources(pdev, r, irq1 ? 2 : 1);
if (status < 0) {
- platform_device_put(pdev);
- dev_dbg(&twl->client->dev,
- "can't create bci dev, %d\n",
- status);
+ dev_dbg(&pdev->dev, "can't add irqs\n");
goto err;
}
}
- if (twl_has_gpio() && pdata->gpio) {
- twl = &twl4030_modules[1];
+ status = platform_device_add(pdev);
- pdev = platform_device_alloc("twl4030_gpio", -1);
- if (!pdev) {
- pr_debug("%s: can't alloc gpio dev\n", DRIVER_NAME);
- status = -ENOMEM;
- goto err;
- }
+err:
+ if (status < 0) {
+ platform_device_put(pdev);
+ dev_err(&twl->client->dev, "can't add %s dev\n", name);
+ return ERR_PTR(status);
+ }
+ return &pdev->dev;
+}
- /* more driver model init */
- if (status == 0) {
- pdev->dev.parent = &twl->client->dev;
- /* device_init_wakeup(&pdev->dev, 1); */
-
- status = platform_device_add_data(pdev, pdata->gpio,
- sizeof(*pdata->gpio));
- if (status < 0) {
- dev_dbg(&twl->client->dev,
- "can't add gpio data, %d\n",
- status);
- goto err;
- }
- }
+static inline struct device *add_child(unsigned chip, const char *name,
+ void *pdata, unsigned pdata_len,
+ bool can_wakeup, int irq0, int irq1)
+{
+ return add_numbered_child(chip, name, -1, pdata, pdata_len,
+ can_wakeup, irq0, irq1);
+}
- /* GPIO module IRQ */
- if (status == 0) {
- struct resource r = {
- .start = pdata->irq_base + 0,
- .flags = IORESOURCE_IRQ,
- };
+static struct device *
+add_regulator_linked(int num, struct regulator_init_data *pdata,
+ struct regulator_consumer_supply *consumers,
+ unsigned num_consumers)
+{
+ /* regulator framework demands init_data ... */
+ if (!pdata)
+ return NULL;
- status = platform_device_add_resources(pdev, &r, 1);
- }
+ if (consumers) {
+ pdata->consumer_supplies = consumers;
+ pdata->num_consumer_supplies = num_consumers;
+ }
- if (status == 0)
- status = platform_device_add(pdev);
+ /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */
+ return add_numbered_child(3, "twl4030_reg", num,
+ pdata, sizeof(*pdata), false, 0, 0);
+}
- if (status < 0) {
- platform_device_put(pdev);
- dev_dbg(&twl->client->dev,
- "can't create gpio dev, %d\n",
- status);
- goto err;
- }
+static struct device *
+add_regulator(int num, struct regulator_init_data *pdata)
+{
+ return add_regulator_linked(num, pdata, NULL, 0);
+}
+
+/*
+ * NOTE: We know the first 8 IRQs after pdata->base_irq are
+ * for the PIH, and the next are for the PWR_INT SIH, since
+ * that's how twl_init_irq() sets things up.
+ */
+
+static int
+add_children(struct twl4030_platform_data *pdata, unsigned long features)
+{
+ struct device *child;
+ struct device *usb_transceiver = NULL;
+
+ if (twl_has_bci() && pdata->bci && !(features & TPS_SUBSET)) {
+ child = add_child(3, "twl4030_bci",
+ pdata->bci, sizeof(*pdata->bci),
+ false,
+ /* irq0 = CHG_PRES, irq1 = BCI */
+ pdata->irq_base + 8 + 1, pdata->irq_base + 2);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ }
+
+ if (twl_has_gpio() && pdata->gpio) {
+ child = add_child(1, "twl4030_gpio",
+ pdata->gpio, sizeof(*pdata->gpio),
+ false, pdata->irq_base + 0, 0);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
}
if (twl_has_keypad() && pdata->keypad) {
- pdev = platform_device_alloc("twl4030_keypad", -1);
- if (pdev) {
- twl = &twl4030_modules[2];
- pdev->dev.parent = &twl->client->dev;
- device_init_wakeup(&pdev->dev, 1);
- status = platform_device_add_data(pdev, pdata->keypad,
- sizeof(*pdata->keypad));
- if (status < 0) {
- dev_dbg(&twl->client->dev,
- "can't add keypad data, %d\n",
- status);
- platform_device_put(pdev);
- goto err;
- }
- status = platform_device_add(pdev);
- if (status < 0) {
- platform_device_put(pdev);
- dev_dbg(&twl->client->dev,
- "can't create keypad dev, %d\n",
- status);
- goto err;
- }
- } else {
- pr_debug("%s: can't alloc keypad dev\n", DRIVER_NAME);
- status = -ENOMEM;
- goto err;
- }
+ child = add_child(2, "twl4030_keypad",
+ pdata->keypad, sizeof(*pdata->keypad),
+ true, pdata->irq_base + 1, 0);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
}
if (twl_has_madc() && pdata->madc) {
- pdev = platform_device_alloc("twl4030_madc", -1);
- if (pdev) {
- twl = &twl4030_modules[2];
- pdev->dev.parent = &twl->client->dev;
- device_init_wakeup(&pdev->dev, 1);
- status = platform_device_add_data(pdev, pdata->madc,
- sizeof(*pdata->madc));
- if (status < 0) {
- platform_device_put(pdev);
- dev_dbg(&twl->client->dev,
- "can't add madc data, %d\n",
- status);
- goto err;
- }
- status = platform_device_add(pdev);
- if (status < 0) {
- platform_device_put(pdev);
- dev_dbg(&twl->client->dev,
- "can't create madc dev, %d\n",
- status);
- goto err;
- }
- } else {
- pr_debug("%s: can't alloc madc dev\n", DRIVER_NAME);
- status = -ENOMEM;
- goto err;
- }
+ child = add_child(2, "twl4030_madc",
+ pdata->madc, sizeof(*pdata->madc),
+ true, pdata->irq_base + 3, 0);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
}
if (twl_has_rtc()) {
- twl = &twl4030_modules[3];
-
- pdev = platform_device_alloc("twl4030_rtc", -1);
- if (!pdev) {
- pr_debug("%s: can't alloc rtc dev\n", DRIVER_NAME);
- status = -ENOMEM;
- } else {
- pdev->dev.parent = &twl->client->dev;
- device_init_wakeup(&pdev->dev, 1);
- }
-
/*
- * REVISIT platform_data here currently might use of
+ * REVISIT platform_data here currently might expose the
* "msecure" line ... but for now we just expect board
- * setup to tell the chip "we are secure" at all times.
+ * setup to tell the chip "it's always ok to SET_TIME".
* Eventually, Linux might become more aware of such
* HW security concerns, and "least privilege".
*/
-
- /* RTC module IRQ */
- if (status == 0) {
- struct resource r = {
- .start = pdata->irq_base + 8 + 3,
- .flags = IORESOURCE_IRQ,
- };
-
- status = platform_device_add_resources(pdev, &r, 1);
- }
-
- if (status == 0)
- status = platform_device_add(pdev);
-
- if (status < 0) {
- platform_device_put(pdev);
- dev_dbg(&twl->client->dev,
- "can't create rtc dev, %d\n",
- status);
- goto err;
- }
+ child = add_child(3, "twl4030_rtc",
+ NULL, 0,
+ true, pdata->irq_base + 8 + 3, 0);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
}
if (twl_has_usb() && pdata->usb) {
- twl = &twl4030_modules[0];
-
- pdev = platform_device_alloc("twl4030_usb", -1);
- if (!pdev) {
- pr_debug("%s: can't alloc usb dev\n", DRIVER_NAME);
- status = -ENOMEM;
- goto err;
- }
-
- if (status == 0) {
- pdev->dev.parent = &twl->client->dev;
- device_init_wakeup(&pdev->dev, 1);
- status = platform_device_add_data(pdev, pdata->usb,
- sizeof(*pdata->usb));
- if (status < 0) {
- platform_device_put(pdev);
- dev_dbg(&twl->client->dev,
- "can't add usb data, %d\n",
- status);
- goto err;
- }
- }
-
- if (status == 0) {
- struct resource r = {
- .start = pdata->irq_base + 8 + 2,
- .flags = IORESOURCE_IRQ,
- };
+ child = add_child(0, "twl4030_usb",
+ pdata->usb, sizeof(*pdata->usb),
+ true,
+ /* irq0 = USB_PRES, irq1 = USB */
+ pdata->irq_base + 8 + 2, pdata->irq_base + 4);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ /* we need to connect regulators to this transceiver */
+ usb_transceiver = child;
+ }
- status = platform_device_add_resources(pdev, &r, 1);
- }
+ if (twl_has_regulator()) {
+ /*
+ child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ */
+
+ child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL4030_REG_VDAC, pdata->vdac);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator((features & TWL4030_VAUX2)
+ ? TWL4030_REG_VAUX2_4030
+ : TWL4030_REG_VAUX2,
+ pdata->vaux2);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ }
- if (status == 0)
- status = platform_device_add(pdev);
+ if (twl_has_regulator() && usb_transceiver) {
+ static struct regulator_consumer_supply usb1v5 = {
+ .supply = "usb1v5",
+ };
+ static struct regulator_consumer_supply usb1v8 = {
+ .supply = "usb1v8",
+ };
+ static struct regulator_consumer_supply usb3v1 = {
+ .supply = "usb3v1",
+ };
+
+ /* this is a template that gets copied */
+ struct regulator_init_data usb_fixed = {
+ .constraints.valid_modes_mask =
+ REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .constraints.valid_ops_mask =
+ REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ };
+
+ usb1v5.dev = usb_transceiver;
+ usb1v8.dev = usb_transceiver;
+ usb3v1.dev = usb_transceiver;
+
+ child = add_regulator_linked(TWL4030_REG_VUSB1V5, &usb_fixed,
+ &usb1v5, 1);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator_linked(TWL4030_REG_VUSB1V8, &usb_fixed,
+ &usb1v8, 1);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator_linked(TWL4030_REG_VUSB3V1, &usb_fixed,
+ &usb3v1, 1);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ }
- if (status < 0) {
- platform_device_put(pdev);
- dev_dbg(&twl->client->dev,
- "can't create usb dev, %d\n",
- status);
- }
+ /* maybe add LDOs that are omitted on cost-reduced parts */
+ if (twl_has_regulator() && !(features & TPS_SUBSET)) {
+ /*
+ child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ */
+
+ child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL4030_REG_VSIM, pdata->vsim);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
}
-err:
- if (status)
- pr_err("failed to add twl4030's children (status %d)\n", status);
- return status;
+ return 0;
}
/*----------------------------------------------------------------------*/
@@ -645,12 +658,7 @@ static void __init clocks_init(void)
osc = clk_get(NULL, "osc_ck");
else
osc = clk_get(NULL, "osc_sys_ck");
-#else
- /* REVISIT for non-OMAP systems, pass the clock rate from
- * board init code, using platform_data.
- */
- osc = ERR_PTR(-EIO);
-#endif
+
if (IS_ERR(osc)) {
printk(KERN_WARNING "Skipping twl4030 internal clock init and "
"using bootloader value (unknown osc rate)\n");
@@ -660,6 +668,18 @@ static void __init clocks_init(void)
rate = clk_get_rate(osc);
clk_put(osc);
+#else
+ /* REVISIT for non-OMAP systems, pass the clock rate from
+ * board init code, using platform_data.
+ */
+ osc = ERR_PTR(-EIO);
+
+ printk(KERN_WARNING "Skipping twl4030 internal clock init and "
+ "using bootloader value (unknown osc rate)\n");
+
+ return;
+#endif
+
switch (rate) {
case 19200000:
ctrl = HFCLK_FREQ_19p2_MHZ;
@@ -764,7 +784,7 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id)
goto fail;
}
- status = add_children(pdata);
+ status = add_children(pdata, id->driver_data);
fail:
if (status < 0)
twl4030_remove(client);
@@ -772,11 +792,11 @@ fail:
}
static const struct i2c_device_id twl4030_ids[] = {
- { "twl4030", 0 }, /* "Triton 2" */
- { "tps65950", 0 }, /* catalog version of twl4030 */
- { "tps65930", 0 }, /* fewer LDOs and DACs; no charger */
- { "tps65920", 0 }, /* fewer LDOs; no codec or charger */
- { "twl5030", 0 }, /* T2 updated */
+ { "twl4030", TWL4030_VAUX2 }, /* "Triton 2" */
+ { "twl5030", 0 }, /* T2 updated */
+ { "tps65950", 0 }, /* catalog version of twl5030 */
+ { "tps65930", TPS_SUBSET }, /* fewer LDOs and DACs; no charger */
+ { "tps65920", TPS_SUBSET }, /* fewer LDOs; no codec or charger */
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(i2c, twl4030_ids);
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
index fae868a8d499..b10876036983 100644
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -180,10 +180,15 @@ static struct completion irq_event;
static int twl4030_irq_thread(void *data)
{
long irq = (long)data;
- irq_desc_t *desc = irq_desc + irq;
+ struct irq_desc *desc = irq_to_desc(irq);
static unsigned i2c_errors;
const static unsigned max_i2c_errors = 100;
+ if (!desc) {
+ pr_err("twl4030: Invalid IRQ: %ld\n", irq);
+ return -EINVAL;
+ }
+
current->flags |= PF_NOFREEZE;
while (!kthread_should_stop()) {
@@ -215,7 +220,13 @@ static int twl4030_irq_thread(void *data)
pih_isr;
pih_isr >>= 1, module_irq++) {
if (pih_isr & 0x1) {
- irq_desc_t *d = irq_desc + module_irq;
+ struct irq_desc *d = irq_to_desc(module_irq);
+
+ if (!d) {
+ pr_err("twl4030: Invalid SIH IRQ: %d\n",
+ module_irq);
+ return -EINVAL;
+ }
/* These can't be masked ... always warn
* if we get any surprises.
@@ -452,10 +463,16 @@ static void twl4030_sih_do_edge(struct work_struct *work)
/* Modify only the bits we know must change */
while (edge_change) {
int i = fls(edge_change) - 1;
- struct irq_desc *d = irq_desc + i + agent->irq_base;
+ struct irq_desc *d = irq_to_desc(i + agent->irq_base);
int byte = 1 + (i >> 2);
int off = (i & 0x3) * 2;
+ if (!d) {
+ pr_err("twl4030: Invalid IRQ: %d\n",
+ i + agent->irq_base);
+ return;
+ }
+
bytes[byte] &= ~(0x03 << off);
spin_lock_irq(&d->lock);
@@ -512,9 +529,14 @@ static void twl4030_sih_unmask(unsigned irq)
static int twl4030_sih_set_type(unsigned irq, unsigned trigger)
{
struct sih_agent *sih = get_irq_chip_data(irq);
- struct irq_desc *desc = irq_desc + irq;
+ struct irq_desc *desc = irq_to_desc(irq);
unsigned long flags;
+ if (!desc) {
+ pr_err("twl4030: Invalid IRQ: %d\n", irq);
+ return -EINVAL;
+ }
+
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
return -EINVAL;
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c
index 0d47fb9e4b3b..3a273ccef3f2 100644
--- a/drivers/mfd/wm8350-core.c
+++ b/drivers/mfd/wm8350-core.c
@@ -63,7 +63,6 @@
*/
static DEFINE_MUTEX(io_mutex);
static DEFINE_MUTEX(reg_lock_mutex);
-static DEFINE_MUTEX(auxadc_mutex);
/* Perform a physical read from the device.
*/
@@ -299,6 +298,13 @@ int wm8350_block_write(struct wm8350 *wm8350, int start_reg, int regs,
}
EXPORT_SYMBOL_GPL(wm8350_block_write);
+/**
+ * wm8350_reg_lock()
+ *
+ * The WM8350 has a hardware lock which can be used to prevent writes to
+ * some registers (generally those which can cause particularly serious
+ * problems if misused). This function enables that lock.
+ */
int wm8350_reg_lock(struct wm8350 *wm8350)
{
u16 key = WM8350_LOCK_KEY;
@@ -314,6 +320,15 @@ int wm8350_reg_lock(struct wm8350 *wm8350)
}
EXPORT_SYMBOL_GPL(wm8350_reg_lock);
+/**
+ * wm8350_reg_unlock()
+ *
+ * The WM8350 has a hardware lock which can be used to prevent writes to
+ * some registers (generally those which can cause particularly serious
+ * problems if misused). This function disables that lock so updates
+ * can be performed. For maximum safety this should be done only when
+ * required.
+ */
int wm8350_reg_unlock(struct wm8350 *wm8350)
{
u16 key = WM8350_UNLOCK_KEY;
@@ -1066,38 +1081,158 @@ int wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
}
EXPORT_SYMBOL_GPL(wm8350_unmask_irq);
+int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref)
+{
+ u16 reg, result = 0;
+ int tries = 5;
+
+ if (channel < WM8350_AUXADC_AUX1 || channel > WM8350_AUXADC_TEMP)
+ return -EINVAL;
+ if (channel >= WM8350_AUXADC_USB && channel <= WM8350_AUXADC_TEMP
+ && (scale != 0 || vref != 0))
+ return -EINVAL;
+
+ mutex_lock(&wm8350->auxadc_mutex);
+
+ /* Turn on the ADC */
+ reg = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5);
+ wm8350_reg_write(wm8350, WM8350_POWER_MGMT_5, reg | WM8350_AUXADC_ENA);
+
+ if (scale || vref) {
+ reg = scale << 13;
+ reg |= vref << 12;
+ wm8350_reg_write(wm8350, WM8350_AUX1_READBACK + channel, reg);
+ }
+
+ reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1);
+ reg |= 1 << channel | WM8350_AUXADC_POLL;
+ wm8350_reg_write(wm8350, WM8350_DIGITISER_CONTROL_1, reg);
+
+ do {
+ schedule_timeout_interruptible(1);
+ reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1);
+ } while (tries-- && (reg & WM8350_AUXADC_POLL));
+
+ if (!tries)
+ dev_err(wm8350->dev, "adc chn %d read timeout\n", channel);
+ else
+ result = wm8350_reg_read(wm8350,
+ WM8350_AUX1_READBACK + channel);
+
+ /* Turn off the ADC */
+ reg = wm8350_reg_read(wm8350, WM8350_POWER_MGMT_5);
+ wm8350_reg_write(wm8350, WM8350_POWER_MGMT_5,
+ reg & ~WM8350_AUXADC_ENA);
+
+ mutex_unlock(&wm8350->auxadc_mutex);
+
+ return result & WM8350_AUXADC_DATA1_MASK;
+}
+EXPORT_SYMBOL_GPL(wm8350_read_auxadc);
+
/*
* Cache is always host endian.
*/
-static int wm8350_create_cache(struct wm8350 *wm8350, int mode)
+static int wm8350_create_cache(struct wm8350 *wm8350, int type, int mode)
{
int i, ret = 0;
u16 value;
const u16 *reg_map;
- switch (mode) {
-#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0
+ switch (type) {
case 0:
- reg_map = wm8350_mode0_defaults;
- break;
+ switch (mode) {
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0
+ case 0:
+ reg_map = wm8350_mode0_defaults;
+ break;
#endif
#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1
- case 1:
- reg_map = wm8350_mode1_defaults;
- break;
+ case 1:
+ reg_map = wm8350_mode1_defaults;
+ break;
#endif
#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2
- case 2:
- reg_map = wm8350_mode2_defaults;
- break;
+ case 2:
+ reg_map = wm8350_mode2_defaults;
+ break;
#endif
#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3
- case 3:
- reg_map = wm8350_mode3_defaults;
+ case 3:
+ reg_map = wm8350_mode3_defaults;
+ break;
+#endif
+ default:
+ dev_err(wm8350->dev,
+ "WM8350 configuration mode %d not supported\n",
+ mode);
+ return -EINVAL;
+ }
+ break;
+
+ case 1:
+ switch (mode) {
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_0
+ case 0:
+ reg_map = wm8351_mode0_defaults;
+ break;
+#endif
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_1
+ case 1:
+ reg_map = wm8351_mode1_defaults;
+ break;
+#endif
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_2
+ case 2:
+ reg_map = wm8351_mode2_defaults;
+ break;
+#endif
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_3
+ case 3:
+ reg_map = wm8351_mode3_defaults;
+ break;
+#endif
+ default:
+ dev_err(wm8350->dev,
+ "WM8351 configuration mode %d not supported\n",
+ mode);
+ return -EINVAL;
+ }
break;
+
+ case 2:
+ switch (mode) {
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_0
+ case 0:
+ reg_map = wm8352_mode0_defaults;
+ break;
+#endif
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_1
+ case 1:
+ reg_map = wm8352_mode1_defaults;
+ break;
#endif
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_2
+ case 2:
+ reg_map = wm8352_mode2_defaults;
+ break;
+#endif
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_3
+ case 3:
+ reg_map = wm8352_mode3_defaults;
+ break;
+#endif
+ default:
+ dev_err(wm8350->dev,
+ "WM8352 configuration mode %d not supported\n",
+ mode);
+ return -EINVAL;
+ }
+ break;
+
default:
- dev_err(wm8350->dev, "Configuration mode %d not supported\n",
+ dev_err(wm8350->dev,
+ "WM835x configuration mode %d not supported\n",
mode);
return -EINVAL;
}
@@ -1163,53 +1298,113 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
struct wm8350_platform_data *pdata)
{
int ret = -EINVAL;
- u16 id1, id2, mask, mode;
+ u16 id1, id2, mask_rev;
+ u16 cust_id, mode, chip_rev;
/* get WM8350 revision and config mode */
wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1);
wm8350->read_dev(wm8350, WM8350_ID, sizeof(id2), &id2);
+ wm8350->read_dev(wm8350, WM8350_REVISION, sizeof(mask_rev), &mask_rev);
id1 = be16_to_cpu(id1);
id2 = be16_to_cpu(id2);
+ mask_rev = be16_to_cpu(mask_rev);
- if (id1 == 0x6143) {
- switch ((id2 & WM8350_CHIP_REV_MASK) >> 12) {
+ if (id1 != 0x6143) {
+ dev_err(wm8350->dev,
+ "Device with ID %x is not a WM8350\n", id1);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ mode = id2 & WM8350_CONF_STS_MASK >> 10;
+ cust_id = id2 & WM8350_CUST_ID_MASK;
+ chip_rev = (id2 & WM8350_CHIP_REV_MASK) >> 12;
+ dev_info(wm8350->dev,
+ "CONF_STS %d, CUST_ID %d, MASK_REV %d, CHIP_REV %d\n",
+ mode, cust_id, mask_rev, chip_rev);
+
+ if (cust_id != 0) {
+ dev_err(wm8350->dev, "Unsupported CUST_ID\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ switch (mask_rev) {
+ case 0:
+ wm8350->pmic.max_dcdc = WM8350_DCDC_6;
+ wm8350->pmic.max_isink = WM8350_ISINK_B;
+
+ switch (chip_rev) {
case WM8350_REV_E:
- dev_info(wm8350->dev, "Found Rev E device\n");
- wm8350->rev = WM8350_REV_E;
+ dev_info(wm8350->dev, "WM8350 Rev E\n");
break;
case WM8350_REV_F:
- dev_info(wm8350->dev, "Found Rev F device\n");
- wm8350->rev = WM8350_REV_F;
+ dev_info(wm8350->dev, "WM8350 Rev F\n");
break;
case WM8350_REV_G:
- dev_info(wm8350->dev, "Found Rev G device\n");
- wm8350->rev = WM8350_REV_G;
+ dev_info(wm8350->dev, "WM8350 Rev G\n");
+ wm8350->power.rev_g_coeff = 1;
+ break;
+ case WM8350_REV_H:
+ dev_info(wm8350->dev, "WM8350 Rev H\n");
+ wm8350->power.rev_g_coeff = 1;
break;
default:
/* For safety we refuse to run on unknown hardware */
- dev_info(wm8350->dev, "Found unknown rev\n");
+ dev_err(wm8350->dev, "Unknown WM8350 CHIP_REV\n");
ret = -ENODEV;
goto err;
}
- } else {
- dev_info(wm8350->dev, "Device with ID %x is not a WM8350\n",
- id1);
+ break;
+
+ case 1:
+ wm8350->pmic.max_dcdc = WM8350_DCDC_4;
+ wm8350->pmic.max_isink = WM8350_ISINK_A;
+
+ switch (chip_rev) {
+ case 0:
+ dev_info(wm8350->dev, "WM8351 Rev A\n");
+ wm8350->power.rev_g_coeff = 1;
+ break;
+
+ default:
+ dev_err(wm8350->dev, "Unknown WM8351 CHIP_REV\n");
+ ret = -ENODEV;
+ goto err;
+ }
+ break;
+
+ case 2:
+ wm8350->pmic.max_dcdc = WM8350_DCDC_6;
+ wm8350->pmic.max_isink = WM8350_ISINK_B;
+
+ switch (chip_rev) {
+ case 0:
+ dev_info(wm8350->dev, "WM8352 Rev A\n");
+ wm8350->power.rev_g_coeff = 1;
+ break;
+
+ default:
+ dev_err(wm8350->dev, "Unknown WM8352 CHIP_REV\n");
+ ret = -ENODEV;
+ goto err;
+ }
+ break;
+
+ default:
+ dev_err(wm8350->dev, "Unknown MASK_REV\n");
ret = -ENODEV;
goto err;
}
- mode = id2 & WM8350_CONF_STS_MASK >> 10;
- mask = id2 & WM8350_CUST_ID_MASK;
- dev_info(wm8350->dev, "Config mode %d, ROM mask %d\n", mode, mask);
-
- ret = wm8350_create_cache(wm8350, mode);
+ ret = wm8350_create_cache(wm8350, mask_rev, mode);
if (ret < 0) {
- printk(KERN_ERR "wm8350: failed to create register cache\n");
+ dev_err(wm8350->dev, "Failed to create register cache\n");
return ret;
}
- if (pdata->init) {
+ if (pdata && pdata->init) {
ret = pdata->init(wm8350);
if (ret != 0) {
dev_err(wm8350->dev, "Platform init() failed: %d\n",
@@ -1218,6 +1413,7 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
}
}
+ mutex_init(&wm8350->auxadc_mutex);
mutex_init(&wm8350->irq_mutex);
INIT_WORK(&wm8350->irq_work, wm8350_irq_worker);
if (irq) {
diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c
index 3e0ce0e50ea2..8d8c93217572 100644
--- a/drivers/mfd/wm8350-i2c.c
+++ b/drivers/mfd/wm8350-i2c.c
@@ -1,8 +1,6 @@
/*
* wm8350-i2c.c -- Generic I2C driver for Wolfson WM8350 PMIC
*
- * This driver defines and configures the WM8350 for the Freescale i.MX32ADS.
- *
* Copyright 2007, 2008 Wolfson Microelectronics PLC.
*
* Author: Liam Girdwood
@@ -99,6 +97,8 @@ static int wm8350_i2c_remove(struct i2c_client *i2c)
static const struct i2c_device_id wm8350_i2c_id[] = {
{ "wm8350", 0 },
+ { "wm8351", 0 },
+ { "wm8352", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8350_i2c_id);
diff --git a/drivers/mfd/wm8350-regmap.c b/drivers/mfd/wm8350-regmap.c
index 974678db22cd..68887b817d17 100644
--- a/drivers/mfd/wm8350-regmap.c
+++ b/drivers/mfd/wm8350-regmap.c
@@ -1074,6 +1074,2102 @@ const u16 wm8350_mode3_defaults[] = {
};
#endif
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_0
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8351_mode0_defaults[] = {
+ 0x6143, /* R0 - Reset/ID */
+ 0x0000, /* R1 - ID */
+ 0x0001, /* R2 - Revision */
+ 0x1C02, /* R3 - System Control 1 */
+ 0x0004, /* R4 - System Control 2 */
+ 0x0000, /* R5 - System Hibernate */
+ 0x8A00, /* R6 - Interface Control */
+ 0x0000, /* R7 */
+ 0x8000, /* R8 - Power mgmt (1) */
+ 0x0000, /* R9 - Power mgmt (2) */
+ 0x0000, /* R10 - Power mgmt (3) */
+ 0x2000, /* R11 - Power mgmt (4) */
+ 0x0E00, /* R12 - Power mgmt (5) */
+ 0x0000, /* R13 - Power mgmt (6) */
+ 0x0000, /* R14 - Power mgmt (7) */
+ 0x0000, /* R15 */
+ 0x0000, /* R16 - RTC Seconds/Minutes */
+ 0x0100, /* R17 - RTC Hours/Day */
+ 0x0101, /* R18 - RTC Date/Month */
+ 0x1400, /* R19 - RTC Year */
+ 0x0000, /* R20 - Alarm Seconds/Minutes */
+ 0x0000, /* R21 - Alarm Hours/Day */
+ 0x0000, /* R22 - Alarm Date/Month */
+ 0x0320, /* R23 - RTC Time Control */
+ 0x0000, /* R24 - System Interrupts */
+ 0x0000, /* R25 - Interrupt Status 1 */
+ 0x0000, /* R26 - Interrupt Status 2 */
+ 0x0000, /* R27 */
+ 0x0000, /* R28 - Under Voltage Interrupt status */
+ 0x0000, /* R29 - Over Current Interrupt status */
+ 0x0000, /* R30 - GPIO Interrupt Status */
+ 0x0000, /* R31 - Comparator Interrupt Status */
+ 0x3FFF, /* R32 - System Interrupts Mask */
+ 0x0000, /* R33 - Interrupt Status 1 Mask */
+ 0x0000, /* R34 - Interrupt Status 2 Mask */
+ 0x0000, /* R35 */
+ 0x0000, /* R36 - Under Voltage Interrupt status Mask */
+ 0x0000, /* R37 - Over Current Interrupt status Mask */
+ 0x0000, /* R38 - GPIO Interrupt Status Mask */
+ 0x0000, /* R39 - Comparator Interrupt Status Mask */
+ 0x0040, /* R40 - Clock Control 1 */
+ 0x0000, /* R41 - Clock Control 2 */
+ 0x3A00, /* R42 - FLL Control 1 */
+ 0x7086, /* R43 - FLL Control 2 */
+ 0xC226, /* R44 - FLL Control 3 */
+ 0x0000, /* R45 - FLL Control 4 */
+ 0x0000, /* R46 */
+ 0x0000, /* R47 */
+ 0x0000, /* R48 - DAC Control */
+ 0x0000, /* R49 */
+ 0x00C0, /* R50 - DAC Digital Volume L */
+ 0x00C0, /* R51 - DAC Digital Volume R */
+ 0x0000, /* R52 */
+ 0x0040, /* R53 - DAC LR Rate */
+ 0x0000, /* R54 - DAC Clock Control */
+ 0x0000, /* R55 */
+ 0x0000, /* R56 */
+ 0x0000, /* R57 */
+ 0x4000, /* R58 - DAC Mute */
+ 0x0000, /* R59 - DAC Mute Volume */
+ 0x0000, /* R60 - DAC Side */
+ 0x0000, /* R61 */
+ 0x0000, /* R62 */
+ 0x0000, /* R63 */
+ 0x8000, /* R64 - ADC Control */
+ 0x0000, /* R65 */
+ 0x00C0, /* R66 - ADC Digital Volume L */
+ 0x00C0, /* R67 - ADC Digital Volume R */
+ 0x0000, /* R68 - ADC Divider */
+ 0x0000, /* R69 */
+ 0x0040, /* R70 - ADC LR Rate */
+ 0x0000, /* R71 */
+ 0x0303, /* R72 - Input Control */
+ 0x0000, /* R73 - IN3 Input Control */
+ 0x0000, /* R74 - Mic Bias Control */
+ 0x0000, /* R75 */
+ 0x0000, /* R76 - Output Control */
+ 0x0000, /* R77 - Jack Detect */
+ 0x0000, /* R78 - Anti Pop Control */
+ 0x0000, /* R79 */
+ 0x0040, /* R80 - Left Input Volume */
+ 0x0040, /* R81 - Right Input Volume */
+ 0x0000, /* R82 */
+ 0x0000, /* R83 */
+ 0x0000, /* R84 */
+ 0x0000, /* R85 */
+ 0x0000, /* R86 */
+ 0x0000, /* R87 */
+ 0x0800, /* R88 - Left Mixer Control */
+ 0x1000, /* R89 - Right Mixer Control */
+ 0x0000, /* R90 */
+ 0x0000, /* R91 */
+ 0x0000, /* R92 - OUT3 Mixer Control */
+ 0x0000, /* R93 - OUT4 Mixer Control */
+ 0x0000, /* R94 */
+ 0x0000, /* R95 */
+ 0x0000, /* R96 - Output Left Mixer Volume */
+ 0x0000, /* R97 - Output Right Mixer Volume */
+ 0x0000, /* R98 - Input Mixer Volume L */
+ 0x0000, /* R99 - Input Mixer Volume R */
+ 0x0000, /* R100 - Input Mixer Volume */
+ 0x0000, /* R101 */
+ 0x0000, /* R102 */
+ 0x0000, /* R103 */
+ 0x00E4, /* R104 - OUT1L Volume */
+ 0x00E4, /* R105 - OUT1R Volume */
+ 0x00E4, /* R106 - OUT2L Volume */
+ 0x02E4, /* R107 - OUT2R Volume */
+ 0x0000, /* R108 */
+ 0x0000, /* R109 */
+ 0x0000, /* R110 */
+ 0x0000, /* R111 - BEEP Volume */
+ 0x0A00, /* R112 - AI Formating */
+ 0x0000, /* R113 - ADC DAC COMP */
+ 0x0020, /* R114 - AI ADC Control */
+ 0x0020, /* R115 - AI DAC Control */
+ 0x0000, /* R116 */
+ 0x0000, /* R117 */
+ 0x0000, /* R118 */
+ 0x0000, /* R119 */
+ 0x0000, /* R120 */
+ 0x0000, /* R121 */
+ 0x0000, /* R122 */
+ 0x0000, /* R123 */
+ 0x0000, /* R124 */
+ 0x0000, /* R125 */
+ 0x0000, /* R126 */
+ 0x0000, /* R127 */
+ 0x1FFF, /* R128 - GPIO Debounce */
+ 0x0000, /* R129 - GPIO Pin pull up Control */
+ 0x0000, /* R130 - GPIO Pull down Control */
+ 0x0000, /* R131 - GPIO Interrupt Mode */
+ 0x0000, /* R132 */
+ 0x0000, /* R133 - GPIO Control */
+ 0x0FFC, /* R134 - GPIO Configuration (i/o) */
+ 0x0FFC, /* R135 - GPIO Pin Polarity / Type */
+ 0x0000, /* R136 */
+ 0x0000, /* R137 */
+ 0x0000, /* R138 */
+ 0x0000, /* R139 */
+ 0x0013, /* R140 - GPIO Function Select 1 */
+ 0x0000, /* R141 - GPIO Function Select 2 */
+ 0x0000, /* R142 - GPIO Function Select 3 */
+ 0x0003, /* R143 - GPIO Function Select 4 */
+ 0x0000, /* R144 - Digitiser Control (1) */
+ 0x0002, /* R145 - Digitiser Control (2) */
+ 0x0000, /* R146 */
+ 0x0000, /* R147 */
+ 0x0000, /* R148 */
+ 0x0000, /* R149 */
+ 0x0000, /* R150 */
+ 0x0000, /* R151 */
+ 0x7000, /* R152 - AUX1 Readback */
+ 0x7000, /* R153 - AUX2 Readback */
+ 0x7000, /* R154 - AUX3 Readback */
+ 0x7000, /* R155 - AUX4 Readback */
+ 0x0000, /* R156 - USB Voltage Readback */
+ 0x0000, /* R157 - LINE Voltage Readback */
+ 0x0000, /* R158 - BATT Voltage Readback */
+ 0x0000, /* R159 - Chip Temp Readback */
+ 0x0000, /* R160 */
+ 0x0000, /* R161 */
+ 0x0000, /* R162 */
+ 0x0000, /* R163 - Generic Comparator Control */
+ 0x0000, /* R164 - Generic comparator 1 */
+ 0x0000, /* R165 - Generic comparator 2 */
+ 0x0000, /* R166 - Generic comparator 3 */
+ 0x0000, /* R167 - Generic comparator 4 */
+ 0xA00F, /* R168 - Battery Charger Control 1 */
+ 0x0B06, /* R169 - Battery Charger Control 2 */
+ 0x0000, /* R170 - Battery Charger Control 3 */
+ 0x0000, /* R171 */
+ 0x0000, /* R172 - Current Sink Driver A */
+ 0x0000, /* R173 - CSA Flash control */
+ 0x0000, /* R174 */
+ 0x0000, /* R175 */
+ 0x0000, /* R176 - DCDC/LDO requested */
+ 0x032D, /* R177 - DCDC Active options */
+ 0x0000, /* R178 - DCDC Sleep options */
+ 0x0025, /* R179 - Power-check comparator */
+ 0x000E, /* R180 - DCDC1 Control */
+ 0x0000, /* R181 - DCDC1 Timeouts */
+ 0x1006, /* R182 - DCDC1 Low Power */
+ 0x0018, /* R183 - DCDC2 Control */
+ 0x0000, /* R184 - DCDC2 Timeouts */
+ 0x0000, /* R185 */
+ 0x0000, /* R186 - DCDC3 Control */
+ 0x0000, /* R187 - DCDC3 Timeouts */
+ 0x0006, /* R188 - DCDC3 Low Power */
+ 0x0000, /* R189 - DCDC4 Control */
+ 0x0000, /* R190 - DCDC4 Timeouts */
+ 0x0006, /* R191 - DCDC4 Low Power */
+ 0x0008, /* R192 */
+ 0x0000, /* R193 */
+ 0x0000, /* R194 */
+ 0x0000, /* R195 */
+ 0x0000, /* R196 */
+ 0x0006, /* R197 */
+ 0x0000, /* R198 */
+ 0x0003, /* R199 - Limit Switch Control */
+ 0x001C, /* R200 - LDO1 Control */
+ 0x0000, /* R201 - LDO1 Timeouts */
+ 0x001C, /* R202 - LDO1 Low Power */
+ 0x001B, /* R203 - LDO2 Control */
+ 0x0000, /* R204 - LDO2 Timeouts */
+ 0x001C, /* R205 - LDO2 Low Power */
+ 0x001B, /* R206 - LDO3 Control */
+ 0x0000, /* R207 - LDO3 Timeouts */
+ 0x001C, /* R208 - LDO3 Low Power */
+ 0x001B, /* R209 - LDO4 Control */
+ 0x0000, /* R210 - LDO4 Timeouts */
+ 0x001C, /* R211 - LDO4 Low Power */
+ 0x0000, /* R212 */
+ 0x0000, /* R213 */
+ 0x0000, /* R214 */
+ 0x0000, /* R215 - VCC_FAULT Masks */
+ 0x001F, /* R216 - Main Bandgap Control */
+ 0x0000, /* R217 - OSC Control */
+ 0x9000, /* R218 - RTC Tick Control */
+ 0x0000, /* R219 - Security1 */
+ 0x4000, /* R220 */
+ 0x0000, /* R221 */
+ 0x0000, /* R222 */
+ 0x0000, /* R223 */
+ 0x0000, /* R224 - Signal overrides */
+ 0x0000, /* R225 - DCDC/LDO status */
+ 0x0000, /* R226 - Charger Overides/status */
+ 0x0000, /* R227 - misc overrides */
+ 0x0000, /* R228 - Supply overrides/status 1 */
+ 0x0000, /* R229 - Supply overrides/status 2 */
+ 0xE000, /* R230 - GPIO Pin Status */
+ 0x0000, /* R231 - comparotor overrides */
+ 0x0000, /* R232 */
+ 0x0000, /* R233 - State Machine status */
+ 0x1200, /* R234 - FLL Test 1 */
+ 0x0000, /* R235 */
+ 0x8000, /* R236 */
+ 0x0000, /* R237 */
+ 0x0000, /* R238 */
+ 0x0000, /* R239 */
+ 0x0003, /* R240 */
+ 0x0000, /* R241 */
+ 0x0000, /* R242 */
+ 0x0004, /* R243 */
+ 0x0300, /* R244 */
+ 0x0000, /* R245 */
+ 0x0200, /* R246 */
+ 0x0000, /* R247 */
+ 0x1000, /* R248 - DCDC1 Test Controls */
+ 0x1000, /* R249 */
+ 0x1000, /* R250 - DCDC3 Test Controls */
+ 0x1000, /* R251 - DCDC4 Test Controls */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_1
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8351_mode1_defaults[] = {
+ 0x6143, /* R0 - Reset/ID */
+ 0x0000, /* R1 - ID */
+ 0x0001, /* R2 - Revision */
+ 0x1C02, /* R3 - System Control 1 */
+ 0x0204, /* R4 - System Control 2 */
+ 0x0000, /* R5 - System Hibernate */
+ 0x8A00, /* R6 - Interface Control */
+ 0x0000, /* R7 */
+ 0x8000, /* R8 - Power mgmt (1) */
+ 0x0000, /* R9 - Power mgmt (2) */
+ 0x0000, /* R10 - Power mgmt (3) */
+ 0x2000, /* R11 - Power mgmt (4) */
+ 0x0E00, /* R12 - Power mgmt (5) */
+ 0x0000, /* R13 - Power mgmt (6) */
+ 0x0000, /* R14 - Power mgmt (7) */
+ 0x0000, /* R15 */
+ 0x0000, /* R16 - RTC Seconds/Minutes */
+ 0x0100, /* R17 - RTC Hours/Day */
+ 0x0101, /* R18 - RTC Date/Month */
+ 0x1400, /* R19 - RTC Year */
+ 0x0000, /* R20 - Alarm Seconds/Minutes */
+ 0x0000, /* R21 - Alarm Hours/Day */
+ 0x0000, /* R22 - Alarm Date/Month */
+ 0x0320, /* R23 - RTC Time Control */
+ 0x0000, /* R24 - System Interrupts */
+ 0x0000, /* R25 - Interrupt Status 1 */
+ 0x0000, /* R26 - Interrupt Status 2 */
+ 0x0000, /* R27 */
+ 0x0000, /* R28 - Under Voltage Interrupt status */
+ 0x0000, /* R29 - Over Current Interrupt status */
+ 0x0000, /* R30 - GPIO Interrupt Status */
+ 0x0000, /* R31 - Comparator Interrupt Status */
+ 0x3FFF, /* R32 - System Interrupts Mask */
+ 0x0000, /* R33 - Interrupt Status 1 Mask */
+ 0x0000, /* R34 - Interrupt Status 2 Mask */
+ 0x0000, /* R35 */
+ 0x0000, /* R36 - Under Voltage Interrupt status Mask */
+ 0x0000, /* R37 - Over Current Interrupt status Mask */
+ 0x0000, /* R38 - GPIO Interrupt Status Mask */
+ 0x0000, /* R39 - Comparator Interrupt Status Mask */
+ 0x0040, /* R40 - Clock Control 1 */
+ 0x0000, /* R41 - Clock Control 2 */
+ 0x3A00, /* R42 - FLL Control 1 */
+ 0x7086, /* R43 - FLL Control 2 */
+ 0xC226, /* R44 - FLL Control 3 */
+ 0x0000, /* R45 - FLL Control 4 */
+ 0x0000, /* R46 */
+ 0x0000, /* R47 */
+ 0x0000, /* R48 - DAC Control */
+ 0x0000, /* R49 */
+ 0x00C0, /* R50 - DAC Digital Volume L */
+ 0x00C0, /* R51 - DAC Digital Volume R */
+ 0x0000, /* R52 */
+ 0x0040, /* R53 - DAC LR Rate */
+ 0x0000, /* R54 - DAC Clock Control */
+ 0x0000, /* R55 */
+ 0x0000, /* R56 */
+ 0x0000, /* R57 */
+ 0x4000, /* R58 - DAC Mute */
+ 0x0000, /* R59 - DAC Mute Volume */
+ 0x0000, /* R60 - DAC Side */
+ 0x0000, /* R61 */
+ 0x0000, /* R62 */
+ 0x0000, /* R63 */
+ 0x8000, /* R64 - ADC Control */
+ 0x0000, /* R65 */
+ 0x00C0, /* R66 - ADC Digital Volume L */
+ 0x00C0, /* R67 - ADC Digital Volume R */
+ 0x0000, /* R68 - ADC Divider */
+ 0x0000, /* R69 */
+ 0x0040, /* R70 - ADC LR Rate */
+ 0x0000, /* R71 */
+ 0x0303, /* R72 - Input Control */
+ 0x0000, /* R73 - IN3 Input Control */
+ 0x0000, /* R74 - Mic Bias Control */
+ 0x0000, /* R75 */
+ 0x0000, /* R76 - Output Control */
+ 0x0000, /* R77 - Jack Detect */
+ 0x0000, /* R78 - Anti Pop Control */
+ 0x0000, /* R79 */
+ 0x0040, /* R80 - Left Input Volume */
+ 0x0040, /* R81 - Right Input Volume */
+ 0x0000, /* R82 */
+ 0x0000, /* R83 */
+ 0x0000, /* R84 */
+ 0x0000, /* R85 */
+ 0x0000, /* R86 */
+ 0x0000, /* R87 */
+ 0x0800, /* R88 - Left Mixer Control */
+ 0x1000, /* R89 - Right Mixer Control */
+ 0x0000, /* R90 */
+ 0x0000, /* R91 */
+ 0x0000, /* R92 - OUT3 Mixer Control */
+ 0x0000, /* R93 - OUT4 Mixer Control */
+ 0x0000, /* R94 */
+ 0x0000, /* R95 */
+ 0x0000, /* R96 - Output Left Mixer Volume */
+ 0x0000, /* R97 - Output Right Mixer Volume */
+ 0x0000, /* R98 - Input Mixer Volume L */
+ 0x0000, /* R99 - Input Mixer Volume R */
+ 0x0000, /* R100 - Input Mixer Volume */
+ 0x0000, /* R101 */
+ 0x0000, /* R102 */
+ 0x0000, /* R103 */
+ 0x00E4, /* R104 - OUT1L Volume */
+ 0x00E4, /* R105 - OUT1R Volume */
+ 0x00E4, /* R106 - OUT2L Volume */
+ 0x02E4, /* R107 - OUT2R Volume */
+ 0x0000, /* R108 */
+ 0x0000, /* R109 */
+ 0x0000, /* R110 */
+ 0x0000, /* R111 - BEEP Volume */
+ 0x0A00, /* R112 - AI Formating */
+ 0x0000, /* R113 - ADC DAC COMP */
+ 0x0020, /* R114 - AI ADC Control */
+ 0x0020, /* R115 - AI DAC Control */
+ 0x0000, /* R116 */
+ 0x0000, /* R117 */
+ 0x0000, /* R118 */
+ 0x0000, /* R119 */
+ 0x0000, /* R120 */
+ 0x0000, /* R121 */
+ 0x0000, /* R122 */
+ 0x0000, /* R123 */
+ 0x0000, /* R124 */
+ 0x0000, /* R125 */
+ 0x0000, /* R126 */
+ 0x0000, /* R127 */
+ 0x1FFF, /* R128 - GPIO Debounce */
+ 0x0000, /* R129 - GPIO Pin pull up Control */
+ 0x0000, /* R130 - GPIO Pull down Control */
+ 0x0000, /* R131 - GPIO Interrupt Mode */
+ 0x0000, /* R132 */
+ 0x0000, /* R133 - GPIO Control */
+ 0x0CFB, /* R134 - GPIO Configuration (i/o) */
+ 0x0C1F, /* R135 - GPIO Pin Polarity / Type */
+ 0x0000, /* R136 */
+ 0x0000, /* R137 */
+ 0x0000, /* R138 */
+ 0x0000, /* R139 */
+ 0x0300, /* R140 - GPIO Function Select 1 */
+ 0x1110, /* R141 - GPIO Function Select 2 */
+ 0x0013, /* R142 - GPIO Function Select 3 */
+ 0x0003, /* R143 - GPIO Function Select 4 */
+ 0x0000, /* R144 - Digitiser Control (1) */
+ 0x0002, /* R145 - Digitiser Control (2) */
+ 0x0000, /* R146 */
+ 0x0000, /* R147 */
+ 0x0000, /* R148 */
+ 0x0000, /* R149 */
+ 0x0000, /* R150 */
+ 0x0000, /* R151 */
+ 0x7000, /* R152 - AUX1 Readback */
+ 0x7000, /* R153 - AUX2 Readback */
+ 0x7000, /* R154 - AUX3 Readback */
+ 0x7000, /* R155 - AUX4 Readback */
+ 0x0000, /* R156 - USB Voltage Readback */
+ 0x0000, /* R157 - LINE Voltage Readback */
+ 0x0000, /* R158 - BATT Voltage Readback */
+ 0x0000, /* R159 - Chip Temp Readback */
+ 0x0000, /* R160 */
+ 0x0000, /* R161 */
+ 0x0000, /* R162 */
+ 0x0000, /* R163 - Generic Comparator Control */
+ 0x0000, /* R164 - Generic comparator 1 */
+ 0x0000, /* R165 - Generic comparator 2 */
+ 0x0000, /* R166 - Generic comparator 3 */
+ 0x0000, /* R167 - Generic comparator 4 */
+ 0xA00F, /* R168 - Battery Charger Control 1 */
+ 0x0B06, /* R169 - Battery Charger Control 2 */
+ 0x0000, /* R170 - Battery Charger Control 3 */
+ 0x0000, /* R171 */
+ 0x0000, /* R172 - Current Sink Driver A */
+ 0x0000, /* R173 - CSA Flash control */
+ 0x0000, /* R174 */
+ 0x0000, /* R175 */
+ 0x0000, /* R176 - DCDC/LDO requested */
+ 0x032D, /* R177 - DCDC Active options */
+ 0x0000, /* R178 - DCDC Sleep options */
+ 0x0025, /* R179 - Power-check comparator */
+ 0x000E, /* R180 - DCDC1 Control */
+ 0x0C00, /* R181 - DCDC1 Timeouts */
+ 0x1006, /* R182 - DCDC1 Low Power */
+ 0x0018, /* R183 - DCDC2 Control */
+ 0x0000, /* R184 - DCDC2 Timeouts */
+ 0x0000, /* R185 */
+ 0x0026, /* R186 - DCDC3 Control */
+ 0x0400, /* R187 - DCDC3 Timeouts */
+ 0x0006, /* R188 - DCDC3 Low Power */
+ 0x0062, /* R189 - DCDC4 Control */
+ 0x0800, /* R190 - DCDC4 Timeouts */
+ 0x0006, /* R191 - DCDC4 Low Power */
+ 0x0008, /* R192 */
+ 0x0000, /* R193 */
+ 0x0000, /* R194 */
+ 0x000A, /* R195 */
+ 0x1000, /* R196 */
+ 0x0006, /* R197 */
+ 0x0000, /* R198 */
+ 0x0003, /* R199 - Limit Switch Control */
+ 0x0006, /* R200 - LDO1 Control */
+ 0x0000, /* R201 - LDO1 Timeouts */
+ 0x001C, /* R202 - LDO1 Low Power */
+ 0x0010, /* R203 - LDO2 Control */
+ 0x0C00, /* R204 - LDO2 Timeouts */
+ 0x001C, /* R205 - LDO2 Low Power */
+ 0x001F, /* R206 - LDO3 Control */
+ 0x0800, /* R207 - LDO3 Timeouts */
+ 0x001C, /* R208 - LDO3 Low Power */
+ 0x000A, /* R209 - LDO4 Control */
+ 0x0800, /* R210 - LDO4 Timeouts */
+ 0x001C, /* R211 - LDO4 Low Power */
+ 0x0000, /* R212 */
+ 0x0000, /* R213 */
+ 0x0000, /* R214 */
+ 0x0000, /* R215 - VCC_FAULT Masks */
+ 0x001F, /* R216 - Main Bandgap Control */
+ 0x0000, /* R217 - OSC Control */
+ 0x9000, /* R218 - RTC Tick Control */
+ 0x0000, /* R219 - Security1 */
+ 0x4000, /* R220 */
+ 0x0000, /* R221 */
+ 0x0000, /* R222 */
+ 0x0000, /* R223 */
+ 0x0000, /* R224 - Signal overrides */
+ 0x0000, /* R225 - DCDC/LDO status */
+ 0x0000, /* R226 - Charger Overides/status */
+ 0x0000, /* R227 - misc overrides */
+ 0x0000, /* R228 - Supply overrides/status 1 */
+ 0x0000, /* R229 - Supply overrides/status 2 */
+ 0xE000, /* R230 - GPIO Pin Status */
+ 0x0000, /* R231 - comparotor overrides */
+ 0x0000, /* R232 */
+ 0x0000, /* R233 - State Machine status */
+ 0x1200, /* R234 - FLL Test 1 */
+ 0x0000, /* R235 */
+ 0x8000, /* R236 */
+ 0x0000, /* R237 */
+ 0x0000, /* R238 */
+ 0x0000, /* R239 */
+ 0x0003, /* R240 */
+ 0x0000, /* R241 */
+ 0x0000, /* R242 */
+ 0x0004, /* R243 */
+ 0x0300, /* R244 */
+ 0x0000, /* R245 */
+ 0x0200, /* R246 */
+ 0x1000, /* R247 */
+ 0x1000, /* R248 - DCDC1 Test Controls */
+ 0x1000, /* R249 */
+ 0x1000, /* R250 - DCDC3 Test Controls */
+ 0x1000, /* R251 - DCDC4 Test Controls */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_2
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8351_mode2_defaults[] = {
+ 0x6143, /* R0 - Reset/ID */
+ 0x0000, /* R1 - ID */
+ 0x0001, /* R2 - Revision */
+ 0x1C02, /* R3 - System Control 1 */
+ 0x0214, /* R4 - System Control 2 */
+ 0x0000, /* R5 - System Hibernate */
+ 0x8A00, /* R6 - Interface Control */
+ 0x0000, /* R7 */
+ 0x8000, /* R8 - Power mgmt (1) */
+ 0x0000, /* R9 - Power mgmt (2) */
+ 0x0000, /* R10 - Power mgmt (3) */
+ 0x2000, /* R11 - Power mgmt (4) */
+ 0x0E00, /* R12 - Power mgmt (5) */
+ 0x0000, /* R13 - Power mgmt (6) */
+ 0x0000, /* R14 - Power mgmt (7) */
+ 0x0000, /* R15 */
+ 0x0000, /* R16 - RTC Seconds/Minutes */
+ 0x0100, /* R17 - RTC Hours/Day */
+ 0x0101, /* R18 - RTC Date/Month */
+ 0x1400, /* R19 - RTC Year */
+ 0x0000, /* R20 - Alarm Seconds/Minutes */
+ 0x0000, /* R21 - Alarm Hours/Day */
+ 0x0000, /* R22 - Alarm Date/Month */
+ 0x0320, /* R23 - RTC Time Control */
+ 0x0000, /* R24 - System Interrupts */
+ 0x0000, /* R25 - Interrupt Status 1 */
+ 0x0000, /* R26 - Interrupt Status 2 */
+ 0x0000, /* R27 */
+ 0x0000, /* R28 - Under Voltage Interrupt status */
+ 0x0000, /* R29 - Over Current Interrupt status */
+ 0x0000, /* R30 - GPIO Interrupt Status */
+ 0x0000, /* R31 - Comparator Interrupt Status */
+ 0x3FFF, /* R32 - System Interrupts Mask */
+ 0x0000, /* R33 - Interrupt Status 1 Mask */
+ 0x0000, /* R34 - Interrupt Status 2 Mask */
+ 0x0000, /* R35 */
+ 0x0000, /* R36 - Under Voltage Interrupt status Mask */
+ 0x0000, /* R37 - Over Current Interrupt status Mask */
+ 0x0000, /* R38 - GPIO Interrupt Status Mask */
+ 0x0000, /* R39 - Comparator Interrupt Status Mask */
+ 0x0040, /* R40 - Clock Control 1 */
+ 0x0000, /* R41 - Clock Control 2 */
+ 0x3A00, /* R42 - FLL Control 1 */
+ 0x7086, /* R43 - FLL Control 2 */
+ 0xC226, /* R44 - FLL Control 3 */
+ 0x0000, /* R45 - FLL Control 4 */
+ 0x0000, /* R46 */
+ 0x0000, /* R47 */
+ 0x0000, /* R48 - DAC Control */
+ 0x0000, /* R49 */
+ 0x00C0, /* R50 - DAC Digital Volume L */
+ 0x00C0, /* R51 - DAC Digital Volume R */
+ 0x0000, /* R52 */
+ 0x0040, /* R53 - DAC LR Rate */
+ 0x0000, /* R54 - DAC Clock Control */
+ 0x0000, /* R55 */
+ 0x0000, /* R56 */
+ 0x0000, /* R57 */
+ 0x4000, /* R58 - DAC Mute */
+ 0x0000, /* R59 - DAC Mute Volume */
+ 0x0000, /* R60 - DAC Side */
+ 0x0000, /* R61 */
+ 0x0000, /* R62 */
+ 0x0000, /* R63 */
+ 0x8000, /* R64 - ADC Control */
+ 0x0000, /* R65 */
+ 0x00C0, /* R66 - ADC Digital Volume L */
+ 0x00C0, /* R67 - ADC Digital Volume R */
+ 0x0000, /* R68 - ADC Divider */
+ 0x0000, /* R69 */
+ 0x0040, /* R70 - ADC LR Rate */
+ 0x0000, /* R71 */
+ 0x0303, /* R72 - Input Control */
+ 0x0000, /* R73 - IN3 Input Control */
+ 0x0000, /* R74 - Mic Bias Control */
+ 0x0000, /* R75 */
+ 0x0000, /* R76 - Output Control */
+ 0x0000, /* R77 - Jack Detect */
+ 0x0000, /* R78 - Anti Pop Control */
+ 0x0000, /* R79 */
+ 0x0040, /* R80 - Left Input Volume */
+ 0x0040, /* R81 - Right Input Volume */
+ 0x0000, /* R82 */
+ 0x0000, /* R83 */
+ 0x0000, /* R84 */
+ 0x0000, /* R85 */
+ 0x0000, /* R86 */
+ 0x0000, /* R87 */
+ 0x0800, /* R88 - Left Mixer Control */
+ 0x1000, /* R89 - Right Mixer Control */
+ 0x0000, /* R90 */
+ 0x0000, /* R91 */
+ 0x0000, /* R92 - OUT3 Mixer Control */
+ 0x0000, /* R93 - OUT4 Mixer Control */
+ 0x0000, /* R94 */
+ 0x0000, /* R95 */
+ 0x0000, /* R96 - Output Left Mixer Volume */
+ 0x0000, /* R97 - Output Right Mixer Volume */
+ 0x0000, /* R98 - Input Mixer Volume L */
+ 0x0000, /* R99 - Input Mixer Volume R */
+ 0x0000, /* R100 - Input Mixer Volume */
+ 0x0000, /* R101 */
+ 0x0000, /* R102 */
+ 0x0000, /* R103 */
+ 0x00E4, /* R104 - OUT1L Volume */
+ 0x00E4, /* R105 - OUT1R Volume */
+ 0x00E4, /* R106 - OUT2L Volume */
+ 0x02E4, /* R107 - OUT2R Volume */
+ 0x0000, /* R108 */
+ 0x0000, /* R109 */
+ 0x0000, /* R110 */
+ 0x0000, /* R111 - BEEP Volume */
+ 0x0A00, /* R112 - AI Formating */
+ 0x0000, /* R113 - ADC DAC COMP */
+ 0x0020, /* R114 - AI ADC Control */
+ 0x0020, /* R115 - AI DAC Control */
+ 0x0000, /* R116 */
+ 0x0000, /* R117 */
+ 0x0000, /* R118 */
+ 0x0000, /* R119 */
+ 0x0000, /* R120 */
+ 0x0000, /* R121 */
+ 0x0000, /* R122 */
+ 0x0000, /* R123 */
+ 0x0000, /* R124 */
+ 0x0000, /* R125 */
+ 0x0000, /* R126 */
+ 0x0000, /* R127 */
+ 0x1FFF, /* R128 - GPIO Debounce */
+ 0x0000, /* R129 - GPIO Pin pull up Control */
+ 0x0110, /* R130 - GPIO Pull down Control */
+ 0x0000, /* R131 - GPIO Interrupt Mode */
+ 0x0000, /* R132 */
+ 0x0000, /* R133 - GPIO Control */
+ 0x09FA, /* R134 - GPIO Configuration (i/o) */
+ 0x0DF6, /* R135 - GPIO Pin Polarity / Type */
+ 0x0000, /* R136 */
+ 0x0000, /* R137 */
+ 0x0000, /* R138 */
+ 0x0000, /* R139 */
+ 0x1310, /* R140 - GPIO Function Select 1 */
+ 0x0003, /* R141 - GPIO Function Select 2 */
+ 0x2000, /* R142 - GPIO Function Select 3 */
+ 0x0000, /* R143 - GPIO Function Select 4 */
+ 0x0000, /* R144 - Digitiser Control (1) */
+ 0x0002, /* R145 - Digitiser Control (2) */
+ 0x0000, /* R146 */
+ 0x0000, /* R147 */
+ 0x0000, /* R148 */
+ 0x0000, /* R149 */
+ 0x0000, /* R150 */
+ 0x0000, /* R151 */
+ 0x7000, /* R152 - AUX1 Readback */
+ 0x7000, /* R153 - AUX2 Readback */
+ 0x7000, /* R154 - AUX3 Readback */
+ 0x7000, /* R155 - AUX4 Readback */
+ 0x0000, /* R156 - USB Voltage Readback */
+ 0x0000, /* R157 - LINE Voltage Readback */
+ 0x0000, /* R158 - BATT Voltage Readback */
+ 0x0000, /* R159 - Chip Temp Readback */
+ 0x0000, /* R160 */
+ 0x0000, /* R161 */
+ 0x0000, /* R162 */
+ 0x0000, /* R163 - Generic Comparator Control */
+ 0x0000, /* R164 - Generic comparator 1 */
+ 0x0000, /* R165 - Generic comparator 2 */
+ 0x0000, /* R166 - Generic comparator 3 */
+ 0x0000, /* R167 - Generic comparator 4 */
+ 0xA00F, /* R168 - Battery Charger Control 1 */
+ 0x0B06, /* R169 - Battery Charger Control 2 */
+ 0x0000, /* R170 - Battery Charger Control 3 */
+ 0x0000, /* R171 */
+ 0x0000, /* R172 - Current Sink Driver A */
+ 0x0000, /* R173 - CSA Flash control */
+ 0x0000, /* R174 */
+ 0x0000, /* R175 */
+ 0x0000, /* R176 - DCDC/LDO requested */
+ 0x032D, /* R177 - DCDC Active options */
+ 0x0000, /* R178 - DCDC Sleep options */
+ 0x0025, /* R179 - Power-check comparator */
+ 0x001A, /* R180 - DCDC1 Control */
+ 0x0800, /* R181 - DCDC1 Timeouts */
+ 0x1006, /* R182 - DCDC1 Low Power */
+ 0x0018, /* R183 - DCDC2 Control */
+ 0x0000, /* R184 - DCDC2 Timeouts */
+ 0x0000, /* R185 */
+ 0x0056, /* R186 - DCDC3 Control */
+ 0x0400, /* R187 - DCDC3 Timeouts */
+ 0x0006, /* R188 - DCDC3 Low Power */
+ 0x0026, /* R189 - DCDC4 Control */
+ 0x0C00, /* R190 - DCDC4 Timeouts */
+ 0x0006, /* R191 - DCDC4 Low Power */
+ 0x0008, /* R192 */
+ 0x0000, /* R193 */
+ 0x0000, /* R194 */
+ 0x0026, /* R195 */
+ 0x0C00, /* R196 */
+ 0x0006, /* R197 */
+ 0x0000, /* R198 */
+ 0x0003, /* R199 - Limit Switch Control */
+ 0x001C, /* R200 - LDO1 Control */
+ 0x0400, /* R201 - LDO1 Timeouts */
+ 0x001C, /* R202 - LDO1 Low Power */
+ 0x0010, /* R203 - LDO2 Control */
+ 0x0C00, /* R204 - LDO2 Timeouts */
+ 0x001C, /* R205 - LDO2 Low Power */
+ 0x0015, /* R206 - LDO3 Control */
+ 0x0000, /* R207 - LDO3 Timeouts */
+ 0x001C, /* R208 - LDO3 Low Power */
+ 0x001A, /* R209 - LDO4 Control */
+ 0x0000, /* R210 - LDO4 Timeouts */
+ 0x001C, /* R211 - LDO4 Low Power */
+ 0x0000, /* R212 */
+ 0x0000, /* R213 */
+ 0x0000, /* R214 */
+ 0x0000, /* R215 - VCC_FAULT Masks */
+ 0x001F, /* R216 - Main Bandgap Control */
+ 0x0000, /* R217 - OSC Control */
+ 0x9000, /* R218 - RTC Tick Control */
+ 0x0000, /* R219 - Security1 */
+ 0x4000, /* R220 */
+ 0x0000, /* R221 */
+ 0x0000, /* R222 */
+ 0x0000, /* R223 */
+ 0x0000, /* R224 - Signal overrides */
+ 0x0000, /* R225 - DCDC/LDO status */
+ 0x0000, /* R226 - Charger Overides/status */
+ 0x0000, /* R227 - misc overrides */
+ 0x0000, /* R228 - Supply overrides/status 1 */
+ 0x0000, /* R229 - Supply overrides/status 2 */
+ 0xE000, /* R230 - GPIO Pin Status */
+ 0x0000, /* R231 - comparotor overrides */
+ 0x0000, /* R232 */
+ 0x0000, /* R233 - State Machine status */
+ 0x1200, /* R234 - FLL Test 1 */
+ 0x0000, /* R235 */
+ 0x8000, /* R236 */
+ 0x0000, /* R237 */
+ 0x0000, /* R238 */
+ 0x0000, /* R239 */
+ 0x0003, /* R240 */
+ 0x0000, /* R241 */
+ 0x0000, /* R242 */
+ 0x0004, /* R243 */
+ 0x0300, /* R244 */
+ 0x0000, /* R245 */
+ 0x0200, /* R246 */
+ 0x0000, /* R247 */
+ 0x1000, /* R248 - DCDC1 Test Controls */
+ 0x1000, /* R249 */
+ 0x1000, /* R250 - DCDC3 Test Controls */
+ 0x1000, /* R251 - DCDC4 Test Controls */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8351_CONFIG_MODE_3
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8351_mode3_defaults[] = {
+ 0x6143, /* R0 - Reset/ID */
+ 0x0000, /* R1 - ID */
+ 0x0001, /* R2 - Revision */
+ 0x1C02, /* R3 - System Control 1 */
+ 0x0204, /* R4 - System Control 2 */
+ 0x0000, /* R5 - System Hibernate */
+ 0x8A00, /* R6 - Interface Control */
+ 0x0000, /* R7 */
+ 0x8000, /* R8 - Power mgmt (1) */
+ 0x0000, /* R9 - Power mgmt (2) */
+ 0x0000, /* R10 - Power mgmt (3) */
+ 0x2000, /* R11 - Power mgmt (4) */
+ 0x0E00, /* R12 - Power mgmt (5) */
+ 0x0000, /* R13 - Power mgmt (6) */
+ 0x0000, /* R14 - Power mgmt (7) */
+ 0x0000, /* R15 */
+ 0x0000, /* R16 - RTC Seconds/Minutes */
+ 0x0100, /* R17 - RTC Hours/Day */
+ 0x0101, /* R18 - RTC Date/Month */
+ 0x1400, /* R19 - RTC Year */
+ 0x0000, /* R20 - Alarm Seconds/Minutes */
+ 0x0000, /* R21 - Alarm Hours/Day */
+ 0x0000, /* R22 - Alarm Date/Month */
+ 0x0320, /* R23 - RTC Time Control */
+ 0x0000, /* R24 - System Interrupts */
+ 0x0000, /* R25 - Interrupt Status 1 */
+ 0x0000, /* R26 - Interrupt Status 2 */
+ 0x0000, /* R27 */
+ 0x0000, /* R28 - Under Voltage Interrupt status */
+ 0x0000, /* R29 - Over Current Interrupt status */
+ 0x0000, /* R30 - GPIO Interrupt Status */
+ 0x0000, /* R31 - Comparator Interrupt Status */
+ 0x3FFF, /* R32 - System Interrupts Mask */
+ 0x0000, /* R33 - Interrupt Status 1 Mask */
+ 0x0000, /* R34 - Interrupt Status 2 Mask */
+ 0x0000, /* R35 */
+ 0x0000, /* R36 - Under Voltage Interrupt status Mask */
+ 0x0000, /* R37 - Over Current Interrupt status Mask */
+ 0x0000, /* R38 - GPIO Interrupt Status Mask */
+ 0x0000, /* R39 - Comparator Interrupt Status Mask */
+ 0x0040, /* R40 - Clock Control 1 */
+ 0x0000, /* R41 - Clock Control 2 */
+ 0x3A00, /* R42 - FLL Control 1 */
+ 0x7086, /* R43 - FLL Control 2 */
+ 0xC226, /* R44 - FLL Control 3 */
+ 0x0000, /* R45 - FLL Control 4 */
+ 0x0000, /* R46 */
+ 0x0000, /* R47 */
+ 0x0000, /* R48 - DAC Control */
+ 0x0000, /* R49 */
+ 0x00C0, /* R50 - DAC Digital Volume L */
+ 0x00C0, /* R51 - DAC Digital Volume R */
+ 0x0000, /* R52 */
+ 0x0040, /* R53 - DAC LR Rate */
+ 0x0000, /* R54 - DAC Clock Control */
+ 0x0000, /* R55 */
+ 0x0000, /* R56 */
+ 0x0000, /* R57 */
+ 0x4000, /* R58 - DAC Mute */
+ 0x0000, /* R59 - DAC Mute Volume */
+ 0x0000, /* R60 - DAC Side */
+ 0x0000, /* R61 */
+ 0x0000, /* R62 */
+ 0x0000, /* R63 */
+ 0x8000, /* R64 - ADC Control */
+ 0x0000, /* R65 */
+ 0x00C0, /* R66 - ADC Digital Volume L */
+ 0x00C0, /* R67 - ADC Digital Volume R */
+ 0x0000, /* R68 - ADC Divider */
+ 0x0000, /* R69 */
+ 0x0040, /* R70 - ADC LR Rate */
+ 0x0000, /* R71 */
+ 0x0303, /* R72 - Input Control */
+ 0x0000, /* R73 - IN3 Input Control */
+ 0x0000, /* R74 - Mic Bias Control */
+ 0x0000, /* R75 */
+ 0x0000, /* R76 - Output Control */
+ 0x0000, /* R77 - Jack Detect */
+ 0x0000, /* R78 - Anti Pop Control */
+ 0x0000, /* R79 */
+ 0x0040, /* R80 - Left Input Volume */
+ 0x0040, /* R81 - Right Input Volume */
+ 0x0000, /* R82 */
+ 0x0000, /* R83 */
+ 0x0000, /* R84 */
+ 0x0000, /* R85 */
+ 0x0000, /* R86 */
+ 0x0000, /* R87 */
+ 0x0800, /* R88 - Left Mixer Control */
+ 0x1000, /* R89 - Right Mixer Control */
+ 0x0000, /* R90 */
+ 0x0000, /* R91 */
+ 0x0000, /* R92 - OUT3 Mixer Control */
+ 0x0000, /* R93 - OUT4 Mixer Control */
+ 0x0000, /* R94 */
+ 0x0000, /* R95 */
+ 0x0000, /* R96 - Output Left Mixer Volume */
+ 0x0000, /* R97 - Output Right Mixer Volume */
+ 0x0000, /* R98 - Input Mixer Volume L */
+ 0x0000, /* R99 - Input Mixer Volume R */
+ 0x0000, /* R100 - Input Mixer Volume */
+ 0x0000, /* R101 */
+ 0x0000, /* R102 */
+ 0x0000, /* R103 */
+ 0x00E4, /* R104 - OUT1L Volume */
+ 0x00E4, /* R105 - OUT1R Volume */
+ 0x00E4, /* R106 - OUT2L Volume */
+ 0x02E4, /* R107 - OUT2R Volume */
+ 0x0000, /* R108 */
+ 0x0000, /* R109 */
+ 0x0000, /* R110 */
+ 0x0000, /* R111 - BEEP Volume */
+ 0x0A00, /* R112 - AI Formating */
+ 0x0000, /* R113 - ADC DAC COMP */
+ 0x0020, /* R114 - AI ADC Control */
+ 0x0020, /* R115 - AI DAC Control */
+ 0x0000, /* R116 */
+ 0x0000, /* R117 */
+ 0x0000, /* R118 */
+ 0x0000, /* R119 */
+ 0x0000, /* R120 */
+ 0x0000, /* R121 */
+ 0x0000, /* R122 */
+ 0x0000, /* R123 */
+ 0x0000, /* R124 */
+ 0x0000, /* R125 */
+ 0x0000, /* R126 */
+ 0x0000, /* R127 */
+ 0x1FFF, /* R128 - GPIO Debounce */
+ 0x0010, /* R129 - GPIO Pin pull up Control */
+ 0x0000, /* R130 - GPIO Pull down Control */
+ 0x0000, /* R131 - GPIO Interrupt Mode */
+ 0x0000, /* R132 */
+ 0x0000, /* R133 - GPIO Control */
+ 0x0BFB, /* R134 - GPIO Configuration (i/o) */
+ 0x0FFD, /* R135 - GPIO Pin Polarity / Type */
+ 0x0000, /* R136 */
+ 0x0000, /* R137 */
+ 0x0000, /* R138 */
+ 0x0000, /* R139 */
+ 0x0310, /* R140 - GPIO Function Select 1 */
+ 0x0001, /* R141 - GPIO Function Select 2 */
+ 0x2300, /* R142 - GPIO Function Select 3 */
+ 0x0003, /* R143 - GPIO Function Select 4 */
+ 0x0000, /* R144 - Digitiser Control (1) */
+ 0x0002, /* R145 - Digitiser Control (2) */
+ 0x0000, /* R146 */
+ 0x0000, /* R147 */
+ 0x0000, /* R148 */
+ 0x0000, /* R149 */
+ 0x0000, /* R150 */
+ 0x0000, /* R151 */
+ 0x7000, /* R152 - AUX1 Readback */
+ 0x7000, /* R153 - AUX2 Readback */
+ 0x7000, /* R154 - AUX3 Readback */
+ 0x7000, /* R155 - AUX4 Readback */
+ 0x0000, /* R156 - USB Voltage Readback */
+ 0x0000, /* R157 - LINE Voltage Readback */
+ 0x0000, /* R158 - BATT Voltage Readback */
+ 0x0000, /* R159 - Chip Temp Readback */
+ 0x0000, /* R160 */
+ 0x0000, /* R161 */
+ 0x0000, /* R162 */
+ 0x0000, /* R163 - Generic Comparator Control */
+ 0x0000, /* R164 - Generic comparator 1 */
+ 0x0000, /* R165 - Generic comparator 2 */
+ 0x0000, /* R166 - Generic comparator 3 */
+ 0x0000, /* R167 - Generic comparator 4 */
+ 0xA00F, /* R168 - Battery Charger Control 1 */
+ 0x0B06, /* R169 - Battery Charger Control 2 */
+ 0x0000, /* R170 - Battery Charger Control 3 */
+ 0x0000, /* R171 */
+ 0x0000, /* R172 - Current Sink Driver A */
+ 0x0000, /* R173 - CSA Flash control */
+ 0x0000, /* R174 */
+ 0x0000, /* R175 */
+ 0x0000, /* R176 - DCDC/LDO requested */
+ 0x032D, /* R177 - DCDC Active options */
+ 0x0000, /* R178 - DCDC Sleep options */
+ 0x0025, /* R179 - Power-check comparator */
+ 0x000E, /* R180 - DCDC1 Control */
+ 0x0400, /* R181 - DCDC1 Timeouts */
+ 0x1006, /* R182 - DCDC1 Low Power */
+ 0x0018, /* R183 - DCDC2 Control */
+ 0x0000, /* R184 - DCDC2 Timeouts */
+ 0x0000, /* R185 */
+ 0x0026, /* R186 - DCDC3 Control */
+ 0x0800, /* R187 - DCDC3 Timeouts */
+ 0x0006, /* R188 - DCDC3 Low Power */
+ 0x0062, /* R189 - DCDC4 Control */
+ 0x1400, /* R190 - DCDC4 Timeouts */
+ 0x0006, /* R191 - DCDC4 Low Power */
+ 0x0008, /* R192 */
+ 0x0000, /* R193 */
+ 0x0000, /* R194 */
+ 0x0026, /* R195 */
+ 0x0400, /* R196 */
+ 0x0006, /* R197 */
+ 0x0000, /* R198 */
+ 0x0003, /* R199 - Limit Switch Control */
+ 0x0006, /* R200 - LDO1 Control */
+ 0x0C00, /* R201 - LDO1 Timeouts */
+ 0x001C, /* R202 - LDO1 Low Power */
+ 0x0016, /* R203 - LDO2 Control */
+ 0x0000, /* R204 - LDO2 Timeouts */
+ 0x001C, /* R205 - LDO2 Low Power */
+ 0x0019, /* R206 - LDO3 Control */
+ 0x0000, /* R207 - LDO3 Timeouts */
+ 0x001C, /* R208 - LDO3 Low Power */
+ 0x001A, /* R209 - LDO4 Control */
+ 0x1000, /* R210 - LDO4 Timeouts */
+ 0x001C, /* R211 - LDO4 Low Power */
+ 0x0000, /* R212 */
+ 0x0000, /* R213 */
+ 0x0000, /* R214 */
+ 0x0000, /* R215 - VCC_FAULT Masks */
+ 0x001F, /* R216 - Main Bandgap Control */
+ 0x0000, /* R217 - OSC Control */
+ 0x9000, /* R218 - RTC Tick Control */
+ 0x0000, /* R219 - Security1 */
+ 0x4000, /* R220 */
+ 0x0000, /* R221 */
+ 0x0000, /* R222 */
+ 0x0000, /* R223 */
+ 0x0000, /* R224 - Signal overrides */
+ 0x0000, /* R225 - DCDC/LDO status */
+ 0x0000, /* R226 - Charger Overides/status */
+ 0x0000, /* R227 - misc overrides */
+ 0x0000, /* R228 - Supply overrides/status 1 */
+ 0x0000, /* R229 - Supply overrides/status 2 */
+ 0xE000, /* R230 - GPIO Pin Status */
+ 0x0000, /* R231 - comparotor overrides */
+ 0x0000, /* R232 */
+ 0x0000, /* R233 - State Machine status */
+ 0x1200, /* R234 - FLL Test 1 */
+ 0x0000, /* R235 */
+ 0x8000, /* R236 */
+ 0x0000, /* R237 */
+ 0x0000, /* R238 */
+ 0x0000, /* R239 */
+ 0x0003, /* R240 */
+ 0x0000, /* R241 */
+ 0x0000, /* R242 */
+ 0x0004, /* R243 */
+ 0x0300, /* R244 */
+ 0x0000, /* R245 */
+ 0x0200, /* R246 */
+ 0x0000, /* R247 */
+ 0x1000, /* R248 - DCDC1 Test Controls */
+ 0x1000, /* R249 */
+ 0x1000, /* R250 - DCDC3 Test Controls */
+ 0x1000, /* R251 - DCDC4 Test Controls */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_0
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8352_mode0_defaults[] = {
+ 0x6143, /* R0 - Reset/ID */
+ 0x0000, /* R1 - ID */
+ 0x0002, /* R2 - Revision */
+ 0x1C02, /* R3 - System Control 1 */
+ 0x0004, /* R4 - System Control 2 */
+ 0x0000, /* R5 - System Hibernate */
+ 0x8A00, /* R6 - Interface Control */
+ 0x0000, /* R7 */
+ 0x8000, /* R8 - Power mgmt (1) */
+ 0x0000, /* R9 - Power mgmt (2) */
+ 0x0000, /* R10 - Power mgmt (3) */
+ 0x2000, /* R11 - Power mgmt (4) */
+ 0x0E00, /* R12 - Power mgmt (5) */
+ 0x0000, /* R13 - Power mgmt (6) */
+ 0x0000, /* R14 - Power mgmt (7) */
+ 0x0000, /* R15 */
+ 0x0000, /* R16 - RTC Seconds/Minutes */
+ 0x0100, /* R17 - RTC Hours/Day */
+ 0x0101, /* R18 - RTC Date/Month */
+ 0x1400, /* R19 - RTC Year */
+ 0x0000, /* R20 - Alarm Seconds/Minutes */
+ 0x0000, /* R21 - Alarm Hours/Day */
+ 0x0000, /* R22 - Alarm Date/Month */
+ 0x0320, /* R23 - RTC Time Control */
+ 0x0000, /* R24 - System Interrupts */
+ 0x0000, /* R25 - Interrupt Status 1 */
+ 0x0000, /* R26 - Interrupt Status 2 */
+ 0x0000, /* R27 */
+ 0x0000, /* R28 - Under Voltage Interrupt status */
+ 0x0000, /* R29 - Over Current Interrupt status */
+ 0x0000, /* R30 - GPIO Interrupt Status */
+ 0x0000, /* R31 - Comparator Interrupt Status */
+ 0x3FFF, /* R32 - System Interrupts Mask */
+ 0x0000, /* R33 - Interrupt Status 1 Mask */
+ 0x0000, /* R34 - Interrupt Status 2 Mask */
+ 0x0000, /* R35 */
+ 0x0000, /* R36 - Under Voltage Interrupt status Mask */
+ 0x0000, /* R37 - Over Current Interrupt status Mask */
+ 0x0000, /* R38 - GPIO Interrupt Status Mask */
+ 0x0000, /* R39 - Comparator Interrupt Status Mask */
+ 0x0040, /* R40 - Clock Control 1 */
+ 0x0000, /* R41 - Clock Control 2 */
+ 0x3A00, /* R42 - FLL Control 1 */
+ 0x7086, /* R43 - FLL Control 2 */
+ 0xC226, /* R44 - FLL Control 3 */
+ 0x0000, /* R45 - FLL Control 4 */
+ 0x0000, /* R46 */
+ 0x0000, /* R47 */
+ 0x0000, /* R48 - DAC Control */
+ 0x0000, /* R49 */
+ 0x00C0, /* R50 - DAC Digital Volume L */
+ 0x00C0, /* R51 - DAC Digital Volume R */
+ 0x0000, /* R52 */
+ 0x0040, /* R53 - DAC LR Rate */
+ 0x0000, /* R54 - DAC Clock Control */
+ 0x0000, /* R55 */
+ 0x0000, /* R56 */
+ 0x0000, /* R57 */
+ 0x4000, /* R58 - DAC Mute */
+ 0x0000, /* R59 - DAC Mute Volume */
+ 0x0000, /* R60 - DAC Side */
+ 0x0000, /* R61 */
+ 0x0000, /* R62 */
+ 0x0000, /* R63 */
+ 0x8000, /* R64 - ADC Control */
+ 0x0000, /* R65 */
+ 0x00C0, /* R66 - ADC Digital Volume L */
+ 0x00C0, /* R67 - ADC Digital Volume R */
+ 0x0000, /* R68 - ADC Divider */
+ 0x0000, /* R69 */
+ 0x0040, /* R70 - ADC LR Rate */
+ 0x0000, /* R71 */
+ 0x0303, /* R72 - Input Control */
+ 0x0000, /* R73 - IN3 Input Control */
+ 0x0000, /* R74 - Mic Bias Control */
+ 0x0000, /* R75 */
+ 0x0000, /* R76 - Output Control */
+ 0x0000, /* R77 - Jack Detect */
+ 0x0000, /* R78 - Anti Pop Control */
+ 0x0000, /* R79 */
+ 0x0040, /* R80 - Left Input Volume */
+ 0x0040, /* R81 - Right Input Volume */
+ 0x0000, /* R82 */
+ 0x0000, /* R83 */
+ 0x0000, /* R84 */
+ 0x0000, /* R85 */
+ 0x0000, /* R86 */
+ 0x0000, /* R87 */
+ 0x0800, /* R88 - Left Mixer Control */
+ 0x1000, /* R89 - Right Mixer Control */
+ 0x0000, /* R90 */
+ 0x0000, /* R91 */
+ 0x0000, /* R92 - OUT3 Mixer Control */
+ 0x0000, /* R93 - OUT4 Mixer Control */
+ 0x0000, /* R94 */
+ 0x0000, /* R95 */
+ 0x0000, /* R96 - Output Left Mixer Volume */
+ 0x0000, /* R97 - Output Right Mixer Volume */
+ 0x0000, /* R98 - Input Mixer Volume L */
+ 0x0000, /* R99 - Input Mixer Volume R */
+ 0x0000, /* R100 - Input Mixer Volume */
+ 0x0000, /* R101 */
+ 0x0000, /* R102 */
+ 0x0000, /* R103 */
+ 0x00E4, /* R104 - OUT1L Volume */
+ 0x00E4, /* R105 - OUT1R Volume */
+ 0x00E4, /* R106 - OUT2L Volume */
+ 0x02E4, /* R107 - OUT2R Volume */
+ 0x0000, /* R108 */
+ 0x0000, /* R109 */
+ 0x0000, /* R110 */
+ 0x0000, /* R111 - BEEP Volume */
+ 0x0A00, /* R112 - AI Formating */
+ 0x0000, /* R113 - ADC DAC COMP */
+ 0x0020, /* R114 - AI ADC Control */
+ 0x0020, /* R115 - AI DAC Control */
+ 0x0000, /* R116 */
+ 0x0000, /* R117 */
+ 0x0000, /* R118 */
+ 0x0000, /* R119 */
+ 0x0000, /* R120 */
+ 0x0000, /* R121 */
+ 0x0000, /* R122 */
+ 0x0000, /* R123 */
+ 0x0000, /* R124 */
+ 0x0000, /* R125 */
+ 0x0000, /* R126 */
+ 0x0000, /* R127 */
+ 0x1FFF, /* R128 - GPIO Debounce */
+ 0x0000, /* R129 - GPIO Pin pull up Control */
+ 0x0000, /* R130 - GPIO Pull down Control */
+ 0x0000, /* R131 - GPIO Interrupt Mode */
+ 0x0000, /* R132 */
+ 0x0000, /* R133 - GPIO Control */
+ 0x0FFC, /* R134 - GPIO Configuration (i/o) */
+ 0x0FFC, /* R135 - GPIO Pin Polarity / Type */
+ 0x0000, /* R136 */
+ 0x0000, /* R137 */
+ 0x0000, /* R138 */
+ 0x0000, /* R139 */
+ 0x0013, /* R140 - GPIO Function Select 1 */
+ 0x0000, /* R141 - GPIO Function Select 2 */
+ 0x0000, /* R142 - GPIO Function Select 3 */
+ 0x0003, /* R143 - GPIO Function Select 4 */
+ 0x0000, /* R144 - Digitiser Control (1) */
+ 0x0002, /* R145 - Digitiser Control (2) */
+ 0x0000, /* R146 */
+ 0x0000, /* R147 */
+ 0x0000, /* R148 */
+ 0x0000, /* R149 */
+ 0x0000, /* R150 */
+ 0x0000, /* R151 */
+ 0x7000, /* R152 - AUX1 Readback */
+ 0x7000, /* R153 - AUX2 Readback */
+ 0x7000, /* R154 - AUX3 Readback */
+ 0x7000, /* R155 - AUX4 Readback */
+ 0x0000, /* R156 - USB Voltage Readback */
+ 0x0000, /* R157 - LINE Voltage Readback */
+ 0x0000, /* R158 - BATT Voltage Readback */
+ 0x0000, /* R159 - Chip Temp Readback */
+ 0x0000, /* R160 */
+ 0x0000, /* R161 */
+ 0x0000, /* R162 */
+ 0x0000, /* R163 - Generic Comparator Control */
+ 0x0000, /* R164 - Generic comparator 1 */
+ 0x0000, /* R165 - Generic comparator 2 */
+ 0x0000, /* R166 - Generic comparator 3 */
+ 0x0000, /* R167 - Generic comparator 4 */
+ 0xA00F, /* R168 - Battery Charger Control 1 */
+ 0x0B06, /* R169 - Battery Charger Control 2 */
+ 0x0000, /* R170 - Battery Charger Control 3 */
+ 0x0000, /* R171 */
+ 0x0000, /* R172 - Current Sink Driver A */
+ 0x0000, /* R173 - CSA Flash control */
+ 0x0000, /* R174 - Current Sink Driver B */
+ 0x0000, /* R175 - CSB Flash control */
+ 0x0000, /* R176 - DCDC/LDO requested */
+ 0x032D, /* R177 - DCDC Active options */
+ 0x0000, /* R178 - DCDC Sleep options */
+ 0x0025, /* R179 - Power-check comparator */
+ 0x000E, /* R180 - DCDC1 Control */
+ 0x0000, /* R181 - DCDC1 Timeouts */
+ 0x1006, /* R182 - DCDC1 Low Power */
+ 0x0018, /* R183 - DCDC2 Control */
+ 0x0000, /* R184 - DCDC2 Timeouts */
+ 0x0000, /* R185 */
+ 0x0000, /* R186 - DCDC3 Control */
+ 0x0000, /* R187 - DCDC3 Timeouts */
+ 0x0006, /* R188 - DCDC3 Low Power */
+ 0x0000, /* R189 - DCDC4 Control */
+ 0x0000, /* R190 - DCDC4 Timeouts */
+ 0x0006, /* R191 - DCDC4 Low Power */
+ 0x0008, /* R192 - DCDC5 Control */
+ 0x0000, /* R193 - DCDC5 Timeouts */
+ 0x0000, /* R194 */
+ 0x0000, /* R195 - DCDC6 Control */
+ 0x0000, /* R196 - DCDC6 Timeouts */
+ 0x0006, /* R197 - DCDC6 Low Power */
+ 0x0000, /* R198 */
+ 0x0003, /* R199 - Limit Switch Control */
+ 0x001C, /* R200 - LDO1 Control */
+ 0x0000, /* R201 - LDO1 Timeouts */
+ 0x001C, /* R202 - LDO1 Low Power */
+ 0x001B, /* R203 - LDO2 Control */
+ 0x0000, /* R204 - LDO2 Timeouts */
+ 0x001C, /* R205 - LDO2 Low Power */
+ 0x001B, /* R206 - LDO3 Control */
+ 0x0000, /* R207 - LDO3 Timeouts */
+ 0x001C, /* R208 - LDO3 Low Power */
+ 0x001B, /* R209 - LDO4 Control */
+ 0x0000, /* R210 - LDO4 Timeouts */
+ 0x001C, /* R211 - LDO4 Low Power */
+ 0x0000, /* R212 */
+ 0x0000, /* R213 */
+ 0x0000, /* R214 */
+ 0x0000, /* R215 - VCC_FAULT Masks */
+ 0x001F, /* R216 - Main Bandgap Control */
+ 0x0000, /* R217 - OSC Control */
+ 0x9000, /* R218 - RTC Tick Control */
+ 0x0000, /* R219 - Security1 */
+ 0x4000, /* R220 */
+ 0x0000, /* R221 */
+ 0x0000, /* R222 */
+ 0x0000, /* R223 */
+ 0x0000, /* R224 - Signal overrides */
+ 0x0000, /* R225 - DCDC/LDO status */
+ 0x0000, /* R226 - Charger Overides/status */
+ 0x0000, /* R227 - misc overrides */
+ 0x0000, /* R228 - Supply overrides/status 1 */
+ 0x0000, /* R229 - Supply overrides/status 2 */
+ 0xE000, /* R230 - GPIO Pin Status */
+ 0x0000, /* R231 - comparotor overrides */
+ 0x0000, /* R232 */
+ 0x0000, /* R233 - State Machine status */
+ 0x1200, /* R234 */
+ 0x0000, /* R235 */
+ 0x8000, /* R236 */
+ 0x0000, /* R237 */
+ 0x0000, /* R238 */
+ 0x0000, /* R239 */
+ 0x0003, /* R240 */
+ 0x0000, /* R241 */
+ 0x0000, /* R242 */
+ 0x0004, /* R243 */
+ 0x0300, /* R244 */
+ 0x0000, /* R245 */
+ 0x0200, /* R246 */
+ 0x0000, /* R247 */
+ 0x1000, /* R248 - DCDC1 Test Controls */
+ 0x5000, /* R249 */
+ 0x1000, /* R250 - DCDC3 Test Controls */
+ 0x1000, /* R251 - DCDC4 Test Controls */
+ 0x5100, /* R252 */
+ 0x1000, /* R253 - DCDC6 Test Controls */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_1
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8352_mode1_defaults[] = {
+ 0x6143, /* R0 - Reset/ID */
+ 0x0000, /* R1 - ID */
+ 0x0002, /* R2 - Revision */
+ 0x1C02, /* R3 - System Control 1 */
+ 0x0204, /* R4 - System Control 2 */
+ 0x0000, /* R5 - System Hibernate */
+ 0x8A00, /* R6 - Interface Control */
+ 0x0000, /* R7 */
+ 0x8000, /* R8 - Power mgmt (1) */
+ 0x0000, /* R9 - Power mgmt (2) */
+ 0x0000, /* R10 - Power mgmt (3) */
+ 0x2000, /* R11 - Power mgmt (4) */
+ 0x0E00, /* R12 - Power mgmt (5) */
+ 0x0000, /* R13 - Power mgmt (6) */
+ 0x0000, /* R14 - Power mgmt (7) */
+ 0x0000, /* R15 */
+ 0x0000, /* R16 - RTC Seconds/Minutes */
+ 0x0100, /* R17 - RTC Hours/Day */
+ 0x0101, /* R18 - RTC Date/Month */
+ 0x1400, /* R19 - RTC Year */
+ 0x0000, /* R20 - Alarm Seconds/Minutes */
+ 0x0000, /* R21 - Alarm Hours/Day */
+ 0x0000, /* R22 - Alarm Date/Month */
+ 0x0320, /* R23 - RTC Time Control */
+ 0x0000, /* R24 - System Interrupts */
+ 0x0000, /* R25 - Interrupt Status 1 */
+ 0x0000, /* R26 - Interrupt Status 2 */
+ 0x0000, /* R27 */
+ 0x0000, /* R28 - Under Voltage Interrupt status */
+ 0x0000, /* R29 - Over Current Interrupt status */
+ 0x0000, /* R30 - GPIO Interrupt Status */
+ 0x0000, /* R31 - Comparator Interrupt Status */
+ 0x3FFF, /* R32 - System Interrupts Mask */
+ 0x0000, /* R33 - Interrupt Status 1 Mask */
+ 0x0000, /* R34 - Interrupt Status 2 Mask */
+ 0x0000, /* R35 */
+ 0x0000, /* R36 - Under Voltage Interrupt status Mask */
+ 0x0000, /* R37 - Over Current Interrupt status Mask */
+ 0x0000, /* R38 - GPIO Interrupt Status Mask */
+ 0x0000, /* R39 - Comparator Interrupt Status Mask */
+ 0x0040, /* R40 - Clock Control 1 */
+ 0x0000, /* R41 - Clock Control 2 */
+ 0x3A00, /* R42 - FLL Control 1 */
+ 0x7086, /* R43 - FLL Control 2 */
+ 0xC226, /* R44 - FLL Control 3 */
+ 0x0000, /* R45 - FLL Control 4 */
+ 0x0000, /* R46 */
+ 0x0000, /* R47 */
+ 0x0000, /* R48 - DAC Control */
+ 0x0000, /* R49 */
+ 0x00C0, /* R50 - DAC Digital Volume L */
+ 0x00C0, /* R51 - DAC Digital Volume R */
+ 0x0000, /* R52 */
+ 0x0040, /* R53 - DAC LR Rate */
+ 0x0000, /* R54 - DAC Clock Control */
+ 0x0000, /* R55 */
+ 0x0000, /* R56 */
+ 0x0000, /* R57 */
+ 0x4000, /* R58 - DAC Mute */
+ 0x0000, /* R59 - DAC Mute Volume */
+ 0x0000, /* R60 - DAC Side */
+ 0x0000, /* R61 */
+ 0x0000, /* R62 */
+ 0x0000, /* R63 */
+ 0x8000, /* R64 - ADC Control */
+ 0x0000, /* R65 */
+ 0x00C0, /* R66 - ADC Digital Volume L */
+ 0x00C0, /* R67 - ADC Digital Volume R */
+ 0x0000, /* R68 - ADC Divider */
+ 0x0000, /* R69 */
+ 0x0040, /* R70 - ADC LR Rate */
+ 0x0000, /* R71 */
+ 0x0303, /* R72 - Input Control */
+ 0x0000, /* R73 - IN3 Input Control */
+ 0x0000, /* R74 - Mic Bias Control */
+ 0x0000, /* R75 */
+ 0x0000, /* R76 - Output Control */
+ 0x0000, /* R77 - Jack Detect */
+ 0x0000, /* R78 - Anti Pop Control */
+ 0x0000, /* R79 */
+ 0x0040, /* R80 - Left Input Volume */
+ 0x0040, /* R81 - Right Input Volume */
+ 0x0000, /* R82 */
+ 0x0000, /* R83 */
+ 0x0000, /* R84 */
+ 0x0000, /* R85 */
+ 0x0000, /* R86 */
+ 0x0000, /* R87 */
+ 0x0800, /* R88 - Left Mixer Control */
+ 0x1000, /* R89 - Right Mixer Control */
+ 0x0000, /* R90 */
+ 0x0000, /* R91 */
+ 0x0000, /* R92 - OUT3 Mixer Control */
+ 0x0000, /* R93 - OUT4 Mixer Control */
+ 0x0000, /* R94 */
+ 0x0000, /* R95 */
+ 0x0000, /* R96 - Output Left Mixer Volume */
+ 0x0000, /* R97 - Output Right Mixer Volume */
+ 0x0000, /* R98 - Input Mixer Volume L */
+ 0x0000, /* R99 - Input Mixer Volume R */
+ 0x0000, /* R100 - Input Mixer Volume */
+ 0x0000, /* R101 */
+ 0x0000, /* R102 */
+ 0x0000, /* R103 */
+ 0x00E4, /* R104 - OUT1L Volume */
+ 0x00E4, /* R105 - OUT1R Volume */
+ 0x00E4, /* R106 - OUT2L Volume */
+ 0x02E4, /* R107 - OUT2R Volume */
+ 0x0000, /* R108 */
+ 0x0000, /* R109 */
+ 0x0000, /* R110 */
+ 0x0000, /* R111 - BEEP Volume */
+ 0x0A00, /* R112 - AI Formating */
+ 0x0000, /* R113 - ADC DAC COMP */
+ 0x0020, /* R114 - AI ADC Control */
+ 0x0020, /* R115 - AI DAC Control */
+ 0x0000, /* R116 */
+ 0x0000, /* R117 */
+ 0x0000, /* R118 */
+ 0x0000, /* R119 */
+ 0x0000, /* R120 */
+ 0x0000, /* R121 */
+ 0x0000, /* R122 */
+ 0x0000, /* R123 */
+ 0x0000, /* R124 */
+ 0x0000, /* R125 */
+ 0x0000, /* R126 */
+ 0x0000, /* R127 */
+ 0x1FFF, /* R128 - GPIO Debounce */
+ 0x0000, /* R129 - GPIO Pin pull up Control */
+ 0x0000, /* R130 - GPIO Pull down Control */
+ 0x0000, /* R131 - GPIO Interrupt Mode */
+ 0x0000, /* R132 */
+ 0x0000, /* R133 - GPIO Control */
+ 0x0BFB, /* R134 - GPIO Configuration (i/o) */
+ 0x0FFF, /* R135 - GPIO Pin Polarity / Type */
+ 0x0000, /* R136 */
+ 0x0000, /* R137 */
+ 0x0000, /* R138 */
+ 0x0000, /* R139 */
+ 0x0300, /* R140 - GPIO Function Select 1 */
+ 0x0000, /* R141 - GPIO Function Select 2 */
+ 0x2300, /* R142 - GPIO Function Select 3 */
+ 0x0003, /* R143 - GPIO Function Select 4 */
+ 0x0000, /* R144 - Digitiser Control (1) */
+ 0x0002, /* R145 - Digitiser Control (2) */
+ 0x0000, /* R146 */
+ 0x0000, /* R147 */
+ 0x0000, /* R148 */
+ 0x0000, /* R149 */
+ 0x0000, /* R150 */
+ 0x0000, /* R151 */
+ 0x7000, /* R152 - AUX1 Readback */
+ 0x7000, /* R153 - AUX2 Readback */
+ 0x7000, /* R154 - AUX3 Readback */
+ 0x7000, /* R155 - AUX4 Readback */
+ 0x0000, /* R156 - USB Voltage Readback */
+ 0x0000, /* R157 - LINE Voltage Readback */
+ 0x0000, /* R158 - BATT Voltage Readback */
+ 0x0000, /* R159 - Chip Temp Readback */
+ 0x0000, /* R160 */
+ 0x0000, /* R161 */
+ 0x0000, /* R162 */
+ 0x0000, /* R163 - Generic Comparator Control */
+ 0x0000, /* R164 - Generic comparator 1 */
+ 0x0000, /* R165 - Generic comparator 2 */
+ 0x0000, /* R166 - Generic comparator 3 */
+ 0x0000, /* R167 - Generic comparator 4 */
+ 0xA00F, /* R168 - Battery Charger Control 1 */
+ 0x0B06, /* R169 - Battery Charger Control 2 */
+ 0x0000, /* R170 - Battery Charger Control 3 */
+ 0x0000, /* R171 */
+ 0x0000, /* R172 - Current Sink Driver A */
+ 0x0000, /* R173 - CSA Flash control */
+ 0x0000, /* R174 - Current Sink Driver B */
+ 0x0000, /* R175 - CSB Flash control */
+ 0x0000, /* R176 - DCDC/LDO requested */
+ 0x032D, /* R177 - DCDC Active options */
+ 0x0000, /* R178 - DCDC Sleep options */
+ 0x0025, /* R179 - Power-check comparator */
+ 0x0062, /* R180 - DCDC1 Control */
+ 0x0400, /* R181 - DCDC1 Timeouts */
+ 0x1006, /* R182 - DCDC1 Low Power */
+ 0x0018, /* R183 - DCDC2 Control */
+ 0x0000, /* R184 - DCDC2 Timeouts */
+ 0x0000, /* R185 */
+ 0x0006, /* R186 - DCDC3 Control */
+ 0x0800, /* R187 - DCDC3 Timeouts */
+ 0x0006, /* R188 - DCDC3 Low Power */
+ 0x0006, /* R189 - DCDC4 Control */
+ 0x0C00, /* R190 - DCDC4 Timeouts */
+ 0x0006, /* R191 - DCDC4 Low Power */
+ 0x0008, /* R192 - DCDC5 Control */
+ 0x0000, /* R193 - DCDC5 Timeouts */
+ 0x0000, /* R194 */
+ 0x0026, /* R195 - DCDC6 Control */
+ 0x1000, /* R196 - DCDC6 Timeouts */
+ 0x0006, /* R197 - DCDC6 Low Power */
+ 0x0000, /* R198 */
+ 0x0003, /* R199 - Limit Switch Control */
+ 0x0002, /* R200 - LDO1 Control */
+ 0x0000, /* R201 - LDO1 Timeouts */
+ 0x001C, /* R202 - LDO1 Low Power */
+ 0x001A, /* R203 - LDO2 Control */
+ 0x0000, /* R204 - LDO2 Timeouts */
+ 0x001C, /* R205 - LDO2 Low Power */
+ 0x001F, /* R206 - LDO3 Control */
+ 0x0000, /* R207 - LDO3 Timeouts */
+ 0x001C, /* R208 - LDO3 Low Power */
+ 0x001F, /* R209 - LDO4 Control */
+ 0x0000, /* R210 - LDO4 Timeouts */
+ 0x001C, /* R211 - LDO4 Low Power */
+ 0x0000, /* R212 */
+ 0x0000, /* R213 */
+ 0x0000, /* R214 */
+ 0x0000, /* R215 - VCC_FAULT Masks */
+ 0x001F, /* R216 - Main Bandgap Control */
+ 0x0000, /* R217 - OSC Control */
+ 0x9000, /* R218 - RTC Tick Control */
+ 0x0000, /* R219 - Security1 */
+ 0x4000, /* R220 */
+ 0x0000, /* R221 */
+ 0x0000, /* R222 */
+ 0x0000, /* R223 */
+ 0x0000, /* R224 - Signal overrides */
+ 0x0000, /* R225 - DCDC/LDO status */
+ 0x0000, /* R226 - Charger Overides/status */
+ 0x0000, /* R227 - misc overrides */
+ 0x0000, /* R228 - Supply overrides/status 1 */
+ 0x0000, /* R229 - Supply overrides/status 2 */
+ 0xE000, /* R230 - GPIO Pin Status */
+ 0x0000, /* R231 - comparotor overrides */
+ 0x0000, /* R232 */
+ 0x0000, /* R233 - State Machine status */
+ 0x1200, /* R234 */
+ 0x0000, /* R235 */
+ 0x8000, /* R236 */
+ 0x0000, /* R237 */
+ 0x0000, /* R238 */
+ 0x0000, /* R239 */
+ 0x0003, /* R240 */
+ 0x0000, /* R241 */
+ 0x0000, /* R242 */
+ 0x0004, /* R243 */
+ 0x0300, /* R244 */
+ 0x0000, /* R245 */
+ 0x0200, /* R246 */
+ 0x0000, /* R247 */
+ 0x1000, /* R248 - DCDC1 Test Controls */
+ 0x5000, /* R249 */
+ 0x1000, /* R250 - DCDC3 Test Controls */
+ 0x1000, /* R251 - DCDC4 Test Controls */
+ 0x5100, /* R252 */
+ 0x1000, /* R253 - DCDC6 Test Controls */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_2
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8352_mode2_defaults[] = {
+ 0x6143, /* R0 - Reset/ID */
+ 0x0000, /* R1 - ID */
+ 0x0002, /* R2 - Revision */
+ 0x1C02, /* R3 - System Control 1 */
+ 0x0204, /* R4 - System Control 2 */
+ 0x0000, /* R5 - System Hibernate */
+ 0x8A00, /* R6 - Interface Control */
+ 0x0000, /* R7 */
+ 0x8000, /* R8 - Power mgmt (1) */
+ 0x0000, /* R9 - Power mgmt (2) */
+ 0x0000, /* R10 - Power mgmt (3) */
+ 0x2000, /* R11 - Power mgmt (4) */
+ 0x0E00, /* R12 - Power mgmt (5) */
+ 0x0000, /* R13 - Power mgmt (6) */
+ 0x0000, /* R14 - Power mgmt (7) */
+ 0x0000, /* R15 */
+ 0x0000, /* R16 - RTC Seconds/Minutes */
+ 0x0100, /* R17 - RTC Hours/Day */
+ 0x0101, /* R18 - RTC Date/Month */
+ 0x1400, /* R19 - RTC Year */
+ 0x0000, /* R20 - Alarm Seconds/Minutes */
+ 0x0000, /* R21 - Alarm Hours/Day */
+ 0x0000, /* R22 - Alarm Date/Month */
+ 0x0320, /* R23 - RTC Time Control */
+ 0x0000, /* R24 - System Interrupts */
+ 0x0000, /* R25 - Interrupt Status 1 */
+ 0x0000, /* R26 - Interrupt Status 2 */
+ 0x0000, /* R27 */
+ 0x0000, /* R28 - Under Voltage Interrupt status */
+ 0x0000, /* R29 - Over Current Interrupt status */
+ 0x0000, /* R30 - GPIO Interrupt Status */
+ 0x0000, /* R31 - Comparator Interrupt Status */
+ 0x3FFF, /* R32 - System Interrupts Mask */
+ 0x0000, /* R33 - Interrupt Status 1 Mask */
+ 0x0000, /* R34 - Interrupt Status 2 Mask */
+ 0x0000, /* R35 */
+ 0x0000, /* R36 - Under Voltage Interrupt status Mask */
+ 0x0000, /* R37 - Over Current Interrupt status Mask */
+ 0x0000, /* R38 - GPIO Interrupt Status Mask */
+ 0x0000, /* R39 - Comparator Interrupt Status Mask */
+ 0x0040, /* R40 - Clock Control 1 */
+ 0x0000, /* R41 - Clock Control 2 */
+ 0x3A00, /* R42 - FLL Control 1 */
+ 0x7086, /* R43 - FLL Control 2 */
+ 0xC226, /* R44 - FLL Control 3 */
+ 0x0000, /* R45 - FLL Control 4 */
+ 0x0000, /* R46 */
+ 0x0000, /* R47 */
+ 0x0000, /* R48 - DAC Control */
+ 0x0000, /* R49 */
+ 0x00C0, /* R50 - DAC Digital Volume L */
+ 0x00C0, /* R51 - DAC Digital Volume R */
+ 0x0000, /* R52 */
+ 0x0040, /* R53 - DAC LR Rate */
+ 0x0000, /* R54 - DAC Clock Control */
+ 0x0000, /* R55 */
+ 0x0000, /* R56 */
+ 0x0000, /* R57 */
+ 0x4000, /* R58 - DAC Mute */
+ 0x0000, /* R59 - DAC Mute Volume */
+ 0x0000, /* R60 - DAC Side */
+ 0x0000, /* R61 */
+ 0x0000, /* R62 */
+ 0x0000, /* R63 */
+ 0x8000, /* R64 - ADC Control */
+ 0x0000, /* R65 */
+ 0x00C0, /* R66 - ADC Digital Volume L */
+ 0x00C0, /* R67 - ADC Digital Volume R */
+ 0x0000, /* R68 - ADC Divider */
+ 0x0000, /* R69 */
+ 0x0040, /* R70 - ADC LR Rate */
+ 0x0000, /* R71 */
+ 0x0303, /* R72 - Input Control */
+ 0x0000, /* R73 - IN3 Input Control */
+ 0x0000, /* R74 - Mic Bias Control */
+ 0x0000, /* R75 */
+ 0x0000, /* R76 - Output Control */
+ 0x0000, /* R77 - Jack Detect */
+ 0x0000, /* R78 - Anti Pop Control */
+ 0x0000, /* R79 */
+ 0x0040, /* R80 - Left Input Volume */
+ 0x0040, /* R81 - Right Input Volume */
+ 0x0000, /* R82 */
+ 0x0000, /* R83 */
+ 0x0000, /* R84 */
+ 0x0000, /* R85 */
+ 0x0000, /* R86 */
+ 0x0000, /* R87 */
+ 0x0800, /* R88 - Left Mixer Control */
+ 0x1000, /* R89 - Right Mixer Control */
+ 0x0000, /* R90 */
+ 0x0000, /* R91 */
+ 0x0000, /* R92 - OUT3 Mixer Control */
+ 0x0000, /* R93 - OUT4 Mixer Control */
+ 0x0000, /* R94 */
+ 0x0000, /* R95 */
+ 0x0000, /* R96 - Output Left Mixer Volume */
+ 0x0000, /* R97 - Output Right Mixer Volume */
+ 0x0000, /* R98 - Input Mixer Volume L */
+ 0x0000, /* R99 - Input Mixer Volume R */
+ 0x0000, /* R100 - Input Mixer Volume */
+ 0x0000, /* R101 */
+ 0x0000, /* R102 */
+ 0x0000, /* R103 */
+ 0x00E4, /* R104 - OUT1L Volume */
+ 0x00E4, /* R105 - OUT1R Volume */
+ 0x00E4, /* R106 - OUT2L Volume */
+ 0x02E4, /* R107 - OUT2R Volume */
+ 0x0000, /* R108 */
+ 0x0000, /* R109 */
+ 0x0000, /* R110 */
+ 0x0000, /* R111 - BEEP Volume */
+ 0x0A00, /* R112 - AI Formating */
+ 0x0000, /* R113 - ADC DAC COMP */
+ 0x0020, /* R114 - AI ADC Control */
+ 0x0020, /* R115 - AI DAC Control */
+ 0x0000, /* R116 */
+ 0x0000, /* R117 */
+ 0x0000, /* R118 */
+ 0x0000, /* R119 */
+ 0x0000, /* R120 */
+ 0x0000, /* R121 */
+ 0x0000, /* R122 */
+ 0x0000, /* R123 */
+ 0x0000, /* R124 */
+ 0x0000, /* R125 */
+ 0x0000, /* R126 */
+ 0x0000, /* R127 */
+ 0x1FFF, /* R128 - GPIO Debounce */
+ 0x0000, /* R129 - GPIO Pin pull up Control */
+ 0x0110, /* R130 - GPIO Pull down Control */
+ 0x0000, /* R131 - GPIO Interrupt Mode */
+ 0x0000, /* R132 */
+ 0x0000, /* R133 - GPIO Control */
+ 0x09DA, /* R134 - GPIO Configuration (i/o) */
+ 0x0DD6, /* R135 - GPIO Pin Polarity / Type */
+ 0x0000, /* R136 */
+ 0x0000, /* R137 */
+ 0x0000, /* R138 */
+ 0x0000, /* R139 */
+ 0x1310, /* R140 - GPIO Function Select 1 */
+ 0x0033, /* R141 - GPIO Function Select 2 */
+ 0x2000, /* R142 - GPIO Function Select 3 */
+ 0x0000, /* R143 - GPIO Function Select 4 */
+ 0x0000, /* R144 - Digitiser Control (1) */
+ 0x0002, /* R145 - Digitiser Control (2) */
+ 0x0000, /* R146 */
+ 0x0000, /* R147 */
+ 0x0000, /* R148 */
+ 0x0000, /* R149 */
+ 0x0000, /* R150 */
+ 0x0000, /* R151 */
+ 0x7000, /* R152 - AUX1 Readback */
+ 0x7000, /* R153 - AUX2 Readback */
+ 0x7000, /* R154 - AUX3 Readback */
+ 0x7000, /* R155 - AUX4 Readback */
+ 0x0000, /* R156 - USB Voltage Readback */
+ 0x0000, /* R157 - LINE Voltage Readback */
+ 0x0000, /* R158 - BATT Voltage Readback */
+ 0x0000, /* R159 - Chip Temp Readback */
+ 0x0000, /* R160 */
+ 0x0000, /* R161 */
+ 0x0000, /* R162 */
+ 0x0000, /* R163 - Generic Comparator Control */
+ 0x0000, /* R164 - Generic comparator 1 */
+ 0x0000, /* R165 - Generic comparator 2 */
+ 0x0000, /* R166 - Generic comparator 3 */
+ 0x0000, /* R167 - Generic comparator 4 */
+ 0xA00F, /* R168 - Battery Charger Control 1 */
+ 0x0B06, /* R169 - Battery Charger Control 2 */
+ 0x0000, /* R170 - Battery Charger Control 3 */
+ 0x0000, /* R171 */
+ 0x0000, /* R172 - Current Sink Driver A */
+ 0x0000, /* R173 - CSA Flash control */
+ 0x0000, /* R174 - Current Sink Driver B */
+ 0x0000, /* R175 - CSB Flash control */
+ 0x0000, /* R176 - DCDC/LDO requested */
+ 0x032D, /* R177 - DCDC Active options */
+ 0x0000, /* R178 - DCDC Sleep options */
+ 0x0025, /* R179 - Power-check comparator */
+ 0x000E, /* R180 - DCDC1 Control */
+ 0x0800, /* R181 - DCDC1 Timeouts */
+ 0x1006, /* R182 - DCDC1 Low Power */
+ 0x0018, /* R183 - DCDC2 Control */
+ 0x0000, /* R184 - DCDC2 Timeouts */
+ 0x0000, /* R185 */
+ 0x0056, /* R186 - DCDC3 Control */
+ 0x1800, /* R187 - DCDC3 Timeouts */
+ 0x0006, /* R188 - DCDC3 Low Power */
+ 0x000E, /* R189 - DCDC4 Control */
+ 0x1000, /* R190 - DCDC4 Timeouts */
+ 0x0006, /* R191 - DCDC4 Low Power */
+ 0x0008, /* R192 - DCDC5 Control */
+ 0x0000, /* R193 - DCDC5 Timeouts */
+ 0x0000, /* R194 */
+ 0x0026, /* R195 - DCDC6 Control */
+ 0x0C00, /* R196 - DCDC6 Timeouts */
+ 0x0006, /* R197 - DCDC6 Low Power */
+ 0x0000, /* R198 */
+ 0x0003, /* R199 - Limit Switch Control */
+ 0x001C, /* R200 - LDO1 Control */
+ 0x0000, /* R201 - LDO1 Timeouts */
+ 0x001C, /* R202 - LDO1 Low Power */
+ 0x0006, /* R203 - LDO2 Control */
+ 0x0400, /* R204 - LDO2 Timeouts */
+ 0x001C, /* R205 - LDO2 Low Power */
+ 0x001C, /* R206 - LDO3 Control */
+ 0x1400, /* R207 - LDO3 Timeouts */
+ 0x001C, /* R208 - LDO3 Low Power */
+ 0x001A, /* R209 - LDO4 Control */
+ 0x0000, /* R210 - LDO4 Timeouts */
+ 0x001C, /* R211 - LDO4 Low Power */
+ 0x0000, /* R212 */
+ 0x0000, /* R213 */
+ 0x0000, /* R214 */
+ 0x0000, /* R215 - VCC_FAULT Masks */
+ 0x001F, /* R216 - Main Bandgap Control */
+ 0x0000, /* R217 - OSC Control */
+ 0x9000, /* R218 - RTC Tick Control */
+ 0x0000, /* R219 - Security1 */
+ 0x4000, /* R220 */
+ 0x0000, /* R221 */
+ 0x0000, /* R222 */
+ 0x0000, /* R223 */
+ 0x0000, /* R224 - Signal overrides */
+ 0x0000, /* R225 - DCDC/LDO status */
+ 0x0000, /* R226 - Charger Overides/status */
+ 0x0000, /* R227 - misc overrides */
+ 0x0000, /* R228 - Supply overrides/status 1 */
+ 0x0000, /* R229 - Supply overrides/status 2 */
+ 0xE000, /* R230 - GPIO Pin Status */
+ 0x0000, /* R231 - comparotor overrides */
+ 0x0000, /* R232 */
+ 0x0000, /* R233 - State Machine status */
+ 0x1200, /* R234 */
+ 0x0000, /* R235 */
+ 0x8000, /* R236 */
+ 0x0000, /* R237 */
+ 0x0000, /* R238 */
+ 0x0000, /* R239 */
+ 0x0003, /* R240 */
+ 0x0000, /* R241 */
+ 0x0000, /* R242 */
+ 0x0004, /* R243 */
+ 0x0300, /* R244 */
+ 0x0000, /* R245 */
+ 0x0200, /* R246 */
+ 0x0000, /* R247 */
+ 0x1000, /* R248 - DCDC1 Test Controls */
+ 0x5000, /* R249 */
+ 0x1000, /* R250 - DCDC3 Test Controls */
+ 0x1000, /* R251 - DCDC4 Test Controls */
+ 0x5100, /* R252 */
+ 0x1000, /* R253 - DCDC6 Test Controls */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8352_CONFIG_MODE_3
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8352_mode3_defaults[] = {
+ 0x6143, /* R0 - Reset/ID */
+ 0x0000, /* R1 - ID */
+ 0x0002, /* R2 - Revision */
+ 0x1C02, /* R3 - System Control 1 */
+ 0x0204, /* R4 - System Control 2 */
+ 0x0000, /* R5 - System Hibernate */
+ 0x8A00, /* R6 - Interface Control */
+ 0x0000, /* R7 */
+ 0x8000, /* R8 - Power mgmt (1) */
+ 0x0000, /* R9 - Power mgmt (2) */
+ 0x0000, /* R10 - Power mgmt (3) */
+ 0x2000, /* R11 - Power mgmt (4) */
+ 0x0E00, /* R12 - Power mgmt (5) */
+ 0x0000, /* R13 - Power mgmt (6) */
+ 0x0000, /* R14 - Power mgmt (7) */
+ 0x0000, /* R15 */
+ 0x0000, /* R16 - RTC Seconds/Minutes */
+ 0x0100, /* R17 - RTC Hours/Day */
+ 0x0101, /* R18 - RTC Date/Month */
+ 0x1400, /* R19 - RTC Year */
+ 0x0000, /* R20 - Alarm Seconds/Minutes */
+ 0x0000, /* R21 - Alarm Hours/Day */
+ 0x0000, /* R22 - Alarm Date/Month */
+ 0x0320, /* R23 - RTC Time Control */
+ 0x0000, /* R24 - System Interrupts */
+ 0x0000, /* R25 - Interrupt Status 1 */
+ 0x0000, /* R26 - Interrupt Status 2 */
+ 0x0000, /* R27 */
+ 0x0000, /* R28 - Under Voltage Interrupt status */
+ 0x0000, /* R29 - Over Current Interrupt status */
+ 0x0000, /* R30 - GPIO Interrupt Status */
+ 0x0000, /* R31 - Comparator Interrupt Status */
+ 0x3FFF, /* R32 - System Interrupts Mask */
+ 0x0000, /* R33 - Interrupt Status 1 Mask */
+ 0x0000, /* R34 - Interrupt Status 2 Mask */
+ 0x0000, /* R35 */
+ 0x0000, /* R36 - Under Voltage Interrupt status Mask */
+ 0x0000, /* R37 - Over Current Interrupt status Mask */
+ 0x0000, /* R38 - GPIO Interrupt Status Mask */
+ 0x0000, /* R39 - Comparator Interrupt Status Mask */
+ 0x0040, /* R40 - Clock Control 1 */
+ 0x0000, /* R41 - Clock Control 2 */
+ 0x3A00, /* R42 - FLL Control 1 */
+ 0x7086, /* R43 - FLL Control 2 */
+ 0xC226, /* R44 - FLL Control 3 */
+ 0x0000, /* R45 - FLL Control 4 */
+ 0x0000, /* R46 */
+ 0x0000, /* R47 */
+ 0x0000, /* R48 - DAC Control */
+ 0x0000, /* R49 */
+ 0x00C0, /* R50 - DAC Digital Volume L */
+ 0x00C0, /* R51 - DAC Digital Volume R */
+ 0x0000, /* R52 */
+ 0x0040, /* R53 - DAC LR Rate */
+ 0x0000, /* R54 - DAC Clock Control */
+ 0x0000, /* R55 */
+ 0x0000, /* R56 */
+ 0x0000, /* R57 */
+ 0x4000, /* R58 - DAC Mute */
+ 0x0000, /* R59 - DAC Mute Volume */
+ 0x0000, /* R60 - DAC Side */
+ 0x0000, /* R61 */
+ 0x0000, /* R62 */
+ 0x0000, /* R63 */
+ 0x8000, /* R64 - ADC Control */
+ 0x0000, /* R65 */
+ 0x00C0, /* R66 - ADC Digital Volume L */
+ 0x00C0, /* R67 - ADC Digital Volume R */
+ 0x0000, /* R68 - ADC Divider */
+ 0x0000, /* R69 */
+ 0x0040, /* R70 - ADC LR Rate */
+ 0x0000, /* R71 */
+ 0x0303, /* R72 - Input Control */
+ 0x0000, /* R73 - IN3 Input Control */
+ 0x0000, /* R74 - Mic Bias Control */
+ 0x0000, /* R75 */
+ 0x0000, /* R76 - Output Control */
+ 0x0000, /* R77 - Jack Detect */
+ 0x0000, /* R78 - Anti Pop Control */
+ 0x0000, /* R79 */
+ 0x0040, /* R80 - Left Input Volume */
+ 0x0040, /* R81 - Right Input Volume */
+ 0x0000, /* R82 */
+ 0x0000, /* R83 */
+ 0x0000, /* R84 */
+ 0x0000, /* R85 */
+ 0x0000, /* R86 */
+ 0x0000, /* R87 */
+ 0x0800, /* R88 - Left Mixer Control */
+ 0x1000, /* R89 - Right Mixer Control */
+ 0x0000, /* R90 */
+ 0x0000, /* R91 */
+ 0x0000, /* R92 - OUT3 Mixer Control */
+ 0x0000, /* R93 - OUT4 Mixer Control */
+ 0x0000, /* R94 */
+ 0x0000, /* R95 */
+ 0x0000, /* R96 - Output Left Mixer Volume */
+ 0x0000, /* R97 - Output Right Mixer Volume */
+ 0x0000, /* R98 - Input Mixer Volume L */
+ 0x0000, /* R99 - Input Mixer Volume R */
+ 0x0000, /* R100 - Input Mixer Volume */
+ 0x0000, /* R101 */
+ 0x0000, /* R102 */
+ 0x0000, /* R103 */
+ 0x00E4, /* R104 - OUT1L Volume */
+ 0x00E4, /* R105 - OUT1R Volume */
+ 0x00E4, /* R106 - OUT2L Volume */
+ 0x02E4, /* R107 - OUT2R Volume */
+ 0x0000, /* R108 */
+ 0x0000, /* R109 */
+ 0x0000, /* R110 */
+ 0x0000, /* R111 - BEEP Volume */
+ 0x0A00, /* R112 - AI Formating */
+ 0x0000, /* R113 - ADC DAC COMP */
+ 0x0020, /* R114 - AI ADC Control */
+ 0x0020, /* R115 - AI DAC Control */
+ 0x0000, /* R116 */
+ 0x0000, /* R117 */
+ 0x0000, /* R118 */
+ 0x0000, /* R119 */
+ 0x0000, /* R120 */
+ 0x0000, /* R121 */
+ 0x0000, /* R122 */
+ 0x0000, /* R123 */
+ 0x0000, /* R124 */
+ 0x0000, /* R125 */
+ 0x0000, /* R126 */
+ 0x0000, /* R127 */
+ 0x1FFF, /* R128 - GPIO Debounce */
+ 0x0010, /* R129 - GPIO Pin pull up Control */
+ 0x0000, /* R130 - GPIO Pull down Control */
+ 0x0000, /* R131 - GPIO Interrupt Mode */
+ 0x0000, /* R132 */
+ 0x0000, /* R133 - GPIO Control */
+ 0x0BFB, /* R134 - GPIO Configuration (i/o) */
+ 0x0FFD, /* R135 - GPIO Pin Polarity / Type */
+ 0x0000, /* R136 */
+ 0x0000, /* R137 */
+ 0x0000, /* R138 */
+ 0x0000, /* R139 */
+ 0x0310, /* R140 - GPIO Function Select 1 */
+ 0x0001, /* R141 - GPIO Function Select 2 */
+ 0x2300, /* R142 - GPIO Function Select 3 */
+ 0x0003, /* R143 - GPIO Function Select 4 */
+ 0x0000, /* R144 - Digitiser Control (1) */
+ 0x0002, /* R145 - Digitiser Control (2) */
+ 0x0000, /* R146 */
+ 0x0000, /* R147 */
+ 0x0000, /* R148 */
+ 0x0000, /* R149 */
+ 0x0000, /* R150 */
+ 0x0000, /* R151 */
+ 0x7000, /* R152 - AUX1 Readback */
+ 0x7000, /* R153 - AUX2 Readback */
+ 0x7000, /* R154 - AUX3 Readback */
+ 0x7000, /* R155 - AUX4 Readback */
+ 0x0000, /* R156 - USB Voltage Readback */
+ 0x0000, /* R157 - LINE Voltage Readback */
+ 0x0000, /* R158 - BATT Voltage Readback */
+ 0x0000, /* R159 - Chip Temp Readback */
+ 0x0000, /* R160 */
+ 0x0000, /* R161 */
+ 0x0000, /* R162 */
+ 0x0000, /* R163 - Generic Comparator Control */
+ 0x0000, /* R164 - Generic comparator 1 */
+ 0x0000, /* R165 - Generic comparator 2 */
+ 0x0000, /* R166 - Generic comparator 3 */
+ 0x0000, /* R167 - Generic comparator 4 */
+ 0xA00F, /* R168 - Battery Charger Control 1 */
+ 0x0B06, /* R169 - Battery Charger Control 2 */
+ 0x0000, /* R170 - Battery Charger Control 3 */
+ 0x0000, /* R171 */
+ 0x0000, /* R172 - Current Sink Driver A */
+ 0x0000, /* R173 - CSA Flash control */
+ 0x0000, /* R174 - Current Sink Driver B */
+ 0x0000, /* R175 - CSB Flash control */
+ 0x0000, /* R176 - DCDC/LDO requested */
+ 0x032D, /* R177 - DCDC Active options */
+ 0x0000, /* R178 - DCDC Sleep options */
+ 0x0025, /* R179 - Power-check comparator */
+ 0x0006, /* R180 - DCDC1 Control */
+ 0x0400, /* R181 - DCDC1 Timeouts */
+ 0x1006, /* R182 - DCDC1 Low Power */
+ 0x0018, /* R183 - DCDC2 Control */
+ 0x0000, /* R184 - DCDC2 Timeouts */
+ 0x0000, /* R185 */
+ 0x0050, /* R186 - DCDC3 Control */
+ 0x0C00, /* R187 - DCDC3 Timeouts */
+ 0x0006, /* R188 - DCDC3 Low Power */
+ 0x000E, /* R189 - DCDC4 Control */
+ 0x0400, /* R190 - DCDC4 Timeouts */
+ 0x0006, /* R191 - DCDC4 Low Power */
+ 0x0008, /* R192 - DCDC5 Control */
+ 0x0000, /* R193 - DCDC5 Timeouts */
+ 0x0000, /* R194 */
+ 0x0029, /* R195 - DCDC6 Control */
+ 0x0800, /* R196 - DCDC6 Timeouts */
+ 0x0006, /* R197 - DCDC6 Low Power */
+ 0x0000, /* R198 */
+ 0x0003, /* R199 - Limit Switch Control */
+ 0x001D, /* R200 - LDO1 Control */
+ 0x1000, /* R201 - LDO1 Timeouts */
+ 0x001C, /* R202 - LDO1 Low Power */
+ 0x0017, /* R203 - LDO2 Control */
+ 0x1000, /* R204 - LDO2 Timeouts */
+ 0x001C, /* R205 - LDO2 Low Power */
+ 0x0006, /* R206 - LDO3 Control */
+ 0x1000, /* R207 - LDO3 Timeouts */
+ 0x001C, /* R208 - LDO3 Low Power */
+ 0x0010, /* R209 - LDO4 Control */
+ 0x1000, /* R210 - LDO4 Timeouts */
+ 0x001C, /* R211 - LDO4 Low Power */
+ 0x0000, /* R212 */
+ 0x0000, /* R213 */
+ 0x0000, /* R214 */
+ 0x0000, /* R215 - VCC_FAULT Masks */
+ 0x001F, /* R216 - Main Bandgap Control */
+ 0x0000, /* R217 - OSC Control */
+ 0x9000, /* R218 - RTC Tick Control */
+ 0x0000, /* R219 - Security1 */
+ 0x4000, /* R220 */
+ 0x0000, /* R221 */
+ 0x0000, /* R222 */
+ 0x0000, /* R223 */
+ 0x0000, /* R224 - Signal overrides */
+ 0x0000, /* R225 - DCDC/LDO status */
+ 0x0000, /* R226 - Charger Overides/status */
+ 0x0000, /* R227 - misc overrides */
+ 0x0000, /* R228 - Supply overrides/status 1 */
+ 0x0000, /* R229 - Supply overrides/status 2 */
+ 0xE000, /* R230 - GPIO Pin Status */
+ 0x0000, /* R231 - comparotor overrides */
+ 0x0000, /* R232 */
+ 0x0000, /* R233 - State Machine status */
+ 0x1200, /* R234 */
+ 0x0000, /* R235 */
+ 0x8000, /* R236 */
+ 0x0000, /* R237 */
+ 0x0000, /* R238 */
+ 0x0000, /* R239 */
+ 0x0003, /* R240 */
+ 0x0000, /* R241 */
+ 0x0000, /* R242 */
+ 0x0004, /* R243 */
+ 0x0300, /* R244 */
+ 0x0000, /* R245 */
+ 0x0200, /* R246 */
+ 0x0000, /* R247 */
+ 0x1000, /* R248 - DCDC1 Test Controls */
+ 0x5000, /* R249 */
+ 0x1000, /* R250 - DCDC3 Test Controls */
+ 0x1000, /* R251 - DCDC4 Test Controls */
+ 0x5100, /* R252 */
+ 0x1000, /* R253 - DCDC6 Test Controls */
+};
+#endif
+
/* The register defaults for the config mode used must be compiled in but
* due to the impact on kernel size it is possible to disable
*/
@@ -1307,14 +3403,14 @@ const struct wm8350_reg_access wm8350_reg_io_map[] = {
{ 0xFF3F, 0xE03F, 0x0000 }, /* R216 - Main Bandgap Control */
{ 0xEF2F, 0xE02F, 0x0000 }, /* R217 - OSC Control */
{ 0xF3FF, 0xB3FF, 0xc000 }, /* R218 - RTC Tick Control */
- { 0xFFFF, 0xFFFF, 0xFFFF }, /* R219 */
+ { 0xFFFF, 0xFFFF, 0x0000 }, /* R219 - Security */
{ 0x09FF, 0x01FF, 0x0000 }, /* R220 - RAM BIST 1 */
{ 0x0000, 0x0000, 0x0000 }, /* R221 */
{ 0xFFFF, 0xFFFF, 0xFFFF }, /* R222 */
{ 0xFFFF, 0xFFFF, 0xFFFF }, /* R223 */
{ 0x0000, 0x0000, 0x0000 }, /* R224 */
{ 0x8F3F, 0x0000, 0xFFFF }, /* R225 - DCDC/LDO status */
- { 0x0000, 0x0000, 0x0000 }, /* R226 */
+ { 0x0000, 0x0000, 0xFFFF }, /* R226 - Charger status */
{ 0x0000, 0x0000, 0xFFFF }, /* R227 */
{ 0x0000, 0x0000, 0x0000 }, /* R228 */
{ 0x0000, 0x0000, 0x0000 }, /* R229 */
diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c
index 6a0cedb5bb8a..cf30d06a0104 100644
--- a/drivers/mfd/wm8400-core.c
+++ b/drivers/mfd/wm8400-core.c
@@ -15,6 +15,7 @@
#include <linux/bug.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
+#include <linux/mfd/core.h>
#include <linux/mfd/wm8400-private.h>
#include <linux/mfd/wm8400-audio.h>
@@ -239,6 +240,16 @@ void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400)
}
EXPORT_SYMBOL_GPL(wm8400_reset_codec_reg_cache);
+static int wm8400_register_codec(struct wm8400 *wm8400)
+{
+ struct mfd_cell cell = {
+ .name = "wm8400-codec",
+ .driver_data = wm8400,
+ };
+
+ return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0);
+}
+
/*
* wm8400_init - Generic initialisation
*
@@ -296,24 +307,32 @@ static int wm8400_init(struct wm8400 *wm8400,
reg = (reg & WM8400_CHIP_REV_MASK) >> WM8400_CHIP_REV_SHIFT;
dev_info(wm8400->dev, "WM8400 revision %x\n", reg);
+ ret = wm8400_register_codec(wm8400);
+ if (ret != 0) {
+ dev_err(wm8400->dev, "Failed to register codec\n");
+ goto err_children;
+ }
+
if (pdata && pdata->platform_init) {
ret = pdata->platform_init(wm8400->dev);
- if (ret != 0)
+ if (ret != 0) {
dev_err(wm8400->dev, "Platform init failed: %d\n",
ret);
+ goto err_children;
+ }
} else
dev_warn(wm8400->dev, "No platform initialisation supplied\n");
+ return 0;
+
+err_children:
+ mfd_remove_devices(wm8400->dev);
return ret;
}
static void wm8400_release(struct wm8400 *wm8400)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(wm8400->regulators); i++)
- if (wm8400->regulators[i].name)
- platform_device_unregister(&wm8400->regulators[i]);
+ mfd_remove_devices(wm8400->dev);
}
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c
index 22a7e8ba211d..de966a6fb7e6 100644
--- a/drivers/misc/ibmasm/ibmasmfs.c
+++ b/drivers/misc/ibmasm/ibmasmfs.c
@@ -146,8 +146,6 @@ static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode)
if (ret) {
ret->i_mode = mode;
- ret->i_uid = ret->i_gid = 0;
- ret->i_blocks = 0;
ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
}
return ret;
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index 517fce48d94a..5b396ff6c83f 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -66,6 +66,7 @@
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/sockios.h>
+#include <linux/firmware.h>
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#include <linux/if_vlan.h>
@@ -186,8 +187,6 @@ MODULE_DEVICE_TABLE(pci, acenic_pci_tbl);
#define MAX_RODATA_LEN 8*1024
#define MAX_DATA_LEN 2*1024
-#include "acenic_firmware.h"
-
#ifndef tigon2FwReleaseLocal
#define tigon2FwReleaseLocal 0
#endif
@@ -417,6 +416,10 @@ static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};
MODULE_AUTHOR("Jes Sorensen <jes@trained-monkey.org>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver");
+#ifndef CONFIG_ACENIC_OMIT_TIGON_I
+MODULE_FIRMWARE("acenic/tg1.bin");
+#endif
+MODULE_FIRMWARE("acenic/tg2.bin");
module_param_array_named(link, link_state, int, NULL, 0);
module_param_array(trace, int, NULL, 0);
@@ -943,8 +946,8 @@ static int __devinit ace_init(struct net_device *dev)
case 4:
case 5:
printk(KERN_INFO " Tigon I (Rev. %i), Firmware: %i.%i.%i, ",
- tig_ver, tigonFwReleaseMajor, tigonFwReleaseMinor,
- tigonFwReleaseFix);
+ tig_ver, ap->firmware_major, ap->firmware_minor,
+ ap->firmware_fix);
writel(0, &regs->LocalCtrl);
ap->version = 1;
ap->tx_ring_entries = TIGON_I_TX_RING_ENTRIES;
@@ -952,8 +955,8 @@ static int __devinit ace_init(struct net_device *dev)
#endif
case 6:
printk(KERN_INFO " Tigon II (Rev. %i), Firmware: %i.%i.%i, ",
- tig_ver, tigon2FwReleaseMajor, tigon2FwReleaseMinor,
- tigon2FwReleaseFix);
+ tig_ver, ap->firmware_major, ap->firmware_minor,
+ ap->firmware_fix);
writel(readl(&regs->CpuBCtrl) | CPU_HALT, &regs->CpuBCtrl);
readl(&regs->CpuBCtrl); /* PCI write posting */
/*
@@ -1205,7 +1208,9 @@ static int __devinit ace_init(struct net_device *dev)
memset(ap->info, 0, sizeof(struct ace_info));
memset(ap->skb, 0, sizeof(struct ace_skb));
- ace_load_firmware(dev);
+ if (ace_load_firmware(dev))
+ goto init_error;
+
ap->fw_running = 0;
tmp_ptr = ap->info_dma;
@@ -1441,10 +1446,7 @@ static int __devinit ace_init(struct net_device *dev)
if (ap->version >= 2)
writel(tmp, &regs->TuneFastLink);
- if (ACE_IS_TIGON_I(ap))
- writel(tigonFwStartAddr, &regs->Pc);
- if (ap->version == 2)
- writel(tigon2FwStartAddr, &regs->Pc);
+ writel(ap->firmware_start, &regs->Pc);
writel(0, &regs->Mb0Lo);
@@ -2761,8 +2763,8 @@ static void ace_get_drvinfo(struct net_device *dev,
strlcpy(info->driver, "acenic", sizeof(info->driver));
snprintf(info->version, sizeof(info->version), "%i.%i.%i",
- tigonFwReleaseMajor, tigonFwReleaseMinor,
- tigonFwReleaseFix);
+ ap->firmware_major, ap->firmware_minor,
+ ap->firmware_fix);
if (ap->pdev)
strlcpy(info->bus_info, pci_name(ap->pdev),
@@ -2869,11 +2871,10 @@ static struct net_device_stats *ace_get_stats(struct net_device *dev)
}
-static void __devinit ace_copy(struct ace_regs __iomem *regs, void *src,
- u32 dest, int size)
+static void __devinit ace_copy(struct ace_regs __iomem *regs, const __be32 *src,
+ u32 dest, int size)
{
void __iomem *tdest;
- u32 *wsrc;
short tsize, i;
if (size <= 0)
@@ -2885,20 +2886,15 @@ static void __devinit ace_copy(struct ace_regs __iomem *regs, void *src,
tdest = (void __iomem *) &regs->Window +
(dest & (ACE_WINDOW_SIZE - 1));
writel(dest & ~(ACE_WINDOW_SIZE - 1), &regs->WinBase);
- /*
- * This requires byte swapping on big endian, however
- * writel does that for us
- */
- wsrc = src;
for (i = 0; i < (tsize / 4); i++) {
- writel(wsrc[i], tdest + i*4);
+ /* Firmware is big-endian */
+ writel(be32_to_cpup(src), tdest);
+ src++;
+ tdest += 4;
+ dest += 4;
+ size -= 4;
}
- dest += tsize;
- src += tsize;
- size -= tsize;
}
-
- return;
}
@@ -2937,8 +2933,13 @@ static void __devinit ace_clear(struct ace_regs __iomem *regs, u32 dest, int siz
*/
static int __devinit ace_load_firmware(struct net_device *dev)
{
+ const struct firmware *fw;
+ const char *fw_name = "acenic/tg2.bin";
struct ace_private *ap = netdev_priv(dev);
struct ace_regs __iomem *regs = ap->regs;
+ const __be32 *fw_data;
+ u32 load_addr;
+ int ret;
if (!(readl(&regs->CpuCtrl) & CPU_HALTED)) {
printk(KERN_ERR "%s: trying to download firmware while the "
@@ -2946,28 +2947,52 @@ static int __devinit ace_load_firmware(struct net_device *dev)
return -EFAULT;
}
+ if (ACE_IS_TIGON_I(ap))
+ fw_name = "acenic/tg1.bin";
+
+ ret = request_firmware(&fw, fw_name, &ap->pdev->dev);
+ if (ret) {
+ printk(KERN_ERR "%s: Failed to load firmware \"%s\"\n",
+ ap->name, fw_name);
+ return ret;
+ }
+
+ fw_data = (void *)fw->data;
+
+ /* Firmware blob starts with version numbers, followed by
+ load and start address. Remainder is the blob to be loaded
+ contiguously from load address. We don't bother to represent
+ the BSS/SBSS sections any more, since we were clearing the
+ whole thing anyway. */
+ ap->firmware_major = fw->data[0];
+ ap->firmware_minor = fw->data[1];
+ ap->firmware_fix = fw->data[2];
+
+ ap->firmware_start = be32_to_cpu(fw_data[1]);
+ if (ap->firmware_start < 0x4000 || ap->firmware_start >= 0x80000) {
+ printk(KERN_ERR "%s: bogus load address %08x in \"%s\"\n",
+ ap->name, ap->firmware_start, fw_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ load_addr = be32_to_cpu(fw_data[2]);
+ if (load_addr < 0x4000 || load_addr >= 0x80000) {
+ printk(KERN_ERR "%s: bogus load address %08x in \"%s\"\n",
+ ap->name, load_addr, fw_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
/*
- * Do not try to clear more than 512KB or we end up seeing
- * funny things on NICs with only 512KB SRAM
+ * Do not try to clear more than 512KiB or we end up seeing
+ * funny things on NICs with only 512KiB SRAM
*/
ace_clear(regs, 0x2000, 0x80000-0x2000);
- if (ACE_IS_TIGON_I(ap)) {
- ace_copy(regs, tigonFwText, tigonFwTextAddr, tigonFwTextLen);
- ace_copy(regs, tigonFwData, tigonFwDataAddr, tigonFwDataLen);
- ace_copy(regs, tigonFwRodata, tigonFwRodataAddr,
- tigonFwRodataLen);
- ace_clear(regs, tigonFwBssAddr, tigonFwBssLen);
- ace_clear(regs, tigonFwSbssAddr, tigonFwSbssLen);
- }else if (ap->version == 2) {
- ace_clear(regs, tigon2FwBssAddr, tigon2FwBssLen);
- ace_clear(regs, tigon2FwSbssAddr, tigon2FwSbssLen);
- ace_copy(regs, tigon2FwText, tigon2FwTextAddr,tigon2FwTextLen);
- ace_copy(regs, tigon2FwRodata, tigon2FwRodataAddr,
- tigon2FwRodataLen);
- ace_copy(regs, tigon2FwData, tigon2FwDataAddr,tigon2FwDataLen);
- }
-
- return 0;
+ ace_copy(regs, &fw_data[3], load_addr, fw->size-12);
+ out:
+ release_firmware(fw);
+ return ret;
}
diff --git a/drivers/net/acenic.h b/drivers/net/acenic.h
index 4487f32759a4..c987c9b5a137 100644
--- a/drivers/net/acenic.h
+++ b/drivers/net/acenic.h
@@ -694,6 +694,10 @@ struct ace_private
u32 last_tx, last_std_rx, last_mini_rx;
#endif
int pci_using_dac;
+ u8 firmware_major;
+ u8 firmware_minor;
+ u8 firmware_fix;
+ u32 firmware_start;
};
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 9f38b16ccbbd..134b2d60b479 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -658,12 +658,12 @@ static int e100_self_test(struct nic *nic)
e100_disable_irq(nic);
/* Check results of self-test */
- if(nic->mem->selftest.result != 0) {
+ if (nic->mem->selftest.result != 0) {
DPRINTK(HW, ERR, "Self-test failed: result=0x%08X\n",
nic->mem->selftest.result);
return -ETIMEDOUT;
}
- if(nic->mem->selftest.signature == 0) {
+ if (nic->mem->selftest.signature == 0) {
DPRINTK(HW, ERR, "Self-test failed: timed out\n");
return -ETIMEDOUT;
}
@@ -684,13 +684,13 @@ static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, __le16 da
cmd_addr_data[2] = op_ewds << (addr_len - 2);
/* Bit-bang cmds to write word to eeprom */
- for(j = 0; j < 3; j++) {
+ for (j = 0; j < 3; j++) {
/* Chip select */
iowrite8(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
- for(i = 31; i >= 0; i--) {
+ for (i = 31; i >= 0; i--) {
ctrl = (cmd_addr_data[j] & (1 << i)) ?
eecs | eedi : eecs;
iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo);
@@ -723,7 +723,7 @@ static __le16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr)
e100_write_flush(nic); udelay(4);
/* Bit-bang to read word from eeprom */
- for(i = 31; i >= 0; i--) {
+ for (i = 31; i >= 0; i--) {
ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs;
iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo);
e100_write_flush(nic); udelay(4);
@@ -734,7 +734,7 @@ static __le16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr)
/* Eeprom drives a dummy zero to EEDO after receiving
* complete address. Use this to adjust addr_len. */
ctrl = ioread8(&nic->csr->eeprom_ctrl_lo);
- if(!(ctrl & eedo) && i > 16) {
+ if (!(ctrl & eedo) && i > 16) {
*addr_len -= (i - 16);
i = 17;
}
@@ -758,9 +758,9 @@ static int e100_eeprom_load(struct nic *nic)
e100_eeprom_read(nic, &addr_len, 0);
nic->eeprom_wc = 1 << addr_len;
- for(addr = 0; addr < nic->eeprom_wc; addr++) {
+ for (addr = 0; addr < nic->eeprom_wc; addr++) {
nic->eeprom[addr] = e100_eeprom_read(nic, &addr_len, addr);
- if(addr < nic->eeprom_wc - 1)
+ if (addr < nic->eeprom_wc - 1)
checksum += le16_to_cpu(nic->eeprom[addr]);
}
@@ -784,15 +784,15 @@ static int e100_eeprom_save(struct nic *nic, u16 start, u16 count)
e100_eeprom_read(nic, &addr_len, 0);
nic->eeprom_wc = 1 << addr_len;
- if(start + count >= nic->eeprom_wc)
+ if (start + count >= nic->eeprom_wc)
return -EINVAL;
- for(addr = start; addr < start + count; addr++)
+ for (addr = start; addr < start + count; addr++)
e100_eeprom_write(nic, addr_len, addr, nic->eeprom[addr]);
/* The checksum, stored in the last word, is calculated such that
* the sum of words should be 0xBABA */
- for(addr = 0; addr < nic->eeprom_wc - 1; addr++)
+ for (addr = 0; addr < nic->eeprom_wc - 1; addr++)
checksum += le16_to_cpu(nic->eeprom[addr]);
nic->eeprom[nic->eeprom_wc - 1] = cpu_to_le16(0xBABA - checksum);
e100_eeprom_write(nic, addr_len, nic->eeprom_wc - 1,
@@ -812,19 +812,19 @@ static int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr)
spin_lock_irqsave(&nic->cmd_lock, flags);
/* Previous command is accepted when SCB clears */
- for(i = 0; i < E100_WAIT_SCB_TIMEOUT; i++) {
- if(likely(!ioread8(&nic->csr->scb.cmd_lo)))
+ for (i = 0; i < E100_WAIT_SCB_TIMEOUT; i++) {
+ if (likely(!ioread8(&nic->csr->scb.cmd_lo)))
break;
cpu_relax();
- if(unlikely(i > E100_WAIT_SCB_FAST))
+ if (unlikely(i > E100_WAIT_SCB_FAST))
udelay(5);
}
- if(unlikely(i == E100_WAIT_SCB_TIMEOUT)) {
+ if (unlikely(i == E100_WAIT_SCB_TIMEOUT)) {
err = -EAGAIN;
goto err_unlock;
}
- if(unlikely(cmd != cuc_resume))
+ if (unlikely(cmd != cuc_resume))
iowrite32(dma_addr, &nic->csr->scb.gen_ptr);
iowrite8(cmd, &nic->csr->scb.cmd_lo);
@@ -843,7 +843,7 @@ static int e100_exec_cb(struct nic *nic, struct sk_buff *skb,
spin_lock_irqsave(&nic->cb_lock, flags);
- if(unlikely(!nic->cbs_avail)) {
+ if (unlikely(!nic->cbs_avail)) {
err = -ENOMEM;
goto err_unlock;
}
@@ -853,7 +853,7 @@ static int e100_exec_cb(struct nic *nic, struct sk_buff *skb,
nic->cbs_avail--;
cb->skb = skb;
- if(unlikely(!nic->cbs_avail))
+ if (unlikely(!nic->cbs_avail))
err = -ENOSPC;
cb_prepare(nic, cb, skb);
@@ -864,15 +864,15 @@ static int e100_exec_cb(struct nic *nic, struct sk_buff *skb,
wmb();
cb->prev->command &= cpu_to_le16(~cb_s);
- while(nic->cb_to_send != nic->cb_to_use) {
- if(unlikely(e100_exec_cmd(nic, nic->cuc_cmd,
+ while (nic->cb_to_send != nic->cb_to_use) {
+ if (unlikely(e100_exec_cmd(nic, nic->cuc_cmd,
nic->cb_to_send->dma_addr))) {
/* Ok, here's where things get sticky. It's
* possible that we can't schedule the command
* because the controller is too busy, so
* let's just queue the command and try again
* when another command is scheduled. */
- if(err == -ENOSPC) {
+ if (err == -ENOSPC) {
//request a reset
schedule_work(&nic->tx_timeout_task);
}
@@ -945,7 +945,7 @@ static void e100_get_defaults(struct nic *nic)
/* MAC type is encoded as rev ID; exception: ICH is treated as 82559 */
nic->mac = (nic->flags & ich) ? mac_82559_D101M : nic->pdev->revision;
- if(nic->mac == mac_unknown)
+ if (nic->mac == mac_unknown)
nic->mac = mac_82557_D100_A;
nic->params.rfds = rfds;
@@ -1008,23 +1008,23 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb)
config->adaptive_ifs = nic->adaptive_ifs;
config->loopback = nic->loopback;
- if(nic->mii.force_media && nic->mii.full_duplex)
+ if (nic->mii.force_media && nic->mii.full_duplex)
config->full_duplex_force = 0x1; /* 1=force, 0=auto */
- if(nic->flags & promiscuous || nic->loopback) {
+ if (nic->flags & promiscuous || nic->loopback) {
config->rx_save_bad_frames = 0x1; /* 1=save, 0=discard */
config->rx_discard_short_frames = 0x0; /* 1=discard, 0=save */
config->promiscuous_mode = 0x1; /* 1=on, 0=off */
}
- if(nic->flags & multicast_all)
+ if (nic->flags & multicast_all)
config->multicast_all = 0x1; /* 1=accept, 0=no */
/* disable WoL when up */
- if(netif_running(nic->netdev) || !(nic->flags & wol_magic))
+ if (netif_running(nic->netdev) || !(nic->flags & wol_magic))
config->magic_packet_disable = 0x1; /* 1=off, 0=on */
- if(nic->mac >= mac_82558_D101_A4) {
+ if (nic->mac >= mac_82558_D101_A4) {
config->fc_disable = 0x1; /* 1=Tx fc off, 0=Tx fc on */
config->mwi_enable = 0x1; /* 1=enable, 0=disable */
config->standard_tcb = 0x0; /* 1=standard, 0=extended */
@@ -1369,21 +1369,21 @@ static int e100_phy_init(struct nic *nic)
u16 bmcr, stat, id_lo, id_hi, cong;
/* Discover phy addr by searching addrs in order {1,0,2,..., 31} */
- for(addr = 0; addr < 32; addr++) {
+ for (addr = 0; addr < 32; addr++) {
nic->mii.phy_id = (addr == 0) ? 1 : (addr == 1) ? 0 : addr;
bmcr = mdio_read(netdev, nic->mii.phy_id, MII_BMCR);
stat = mdio_read(netdev, nic->mii.phy_id, MII_BMSR);
stat = mdio_read(netdev, nic->mii.phy_id, MII_BMSR);
- if(!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0))))
+ if (!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0))))
break;
}
DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id);
- if(addr == 32)
+ if (addr == 32)
return -EAGAIN;
/* Selected the phy and isolate the rest */
- for(addr = 0; addr < 32; addr++) {
- if(addr != nic->mii.phy_id) {
+ for (addr = 0; addr < 32; addr++) {
+ if (addr != nic->mii.phy_id) {
mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE);
} else {
bmcr = mdio_read(netdev, addr, MII_BMCR);
@@ -1400,7 +1400,7 @@ static int e100_phy_init(struct nic *nic)
/* Handle National tx phys */
#define NCS_PHY_MODEL_MASK 0xFFF0FFFF
- if((nic->phy & NCS_PHY_MODEL_MASK) == phy_nsc_tx) {
+ if ((nic->phy & NCS_PHY_MODEL_MASK) == phy_nsc_tx) {
/* Disable congestion control */
cong = mdio_read(netdev, nic->mii.phy_id, MII_NSC_CONG);
cong |= NSC_CONG_TXREADY;
@@ -1408,7 +1408,7 @@ static int e100_phy_init(struct nic *nic)
mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong);
}
- if((nic->mac >= mac_82550_D102) || ((nic->flags & ich) &&
+ if ((nic->mac >= mac_82550_D102) || ((nic->flags & ich) &&
(mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) &&
!(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) {
/* enable/disable MDI/MDI-X auto-switching. */
@@ -1426,25 +1426,25 @@ static int e100_hw_init(struct nic *nic)
e100_hw_reset(nic);
DPRINTK(HW, ERR, "e100_hw_init\n");
- if(!in_interrupt() && (err = e100_self_test(nic)))
+ if (!in_interrupt() && (err = e100_self_test(nic)))
return err;
- if((err = e100_phy_init(nic)))
+ if ((err = e100_phy_init(nic)))
return err;
- if((err = e100_exec_cmd(nic, cuc_load_base, 0)))
+ if ((err = e100_exec_cmd(nic, cuc_load_base, 0)))
return err;
- if((err = e100_exec_cmd(nic, ruc_load_base, 0)))
+ if ((err = e100_exec_cmd(nic, ruc_load_base, 0)))
return err;
if ((err = e100_exec_cb_wait(nic, NULL, e100_setup_ucode)))
return err;
- if((err = e100_exec_cb(nic, NULL, e100_configure)))
+ if ((err = e100_exec_cb(nic, NULL, e100_configure)))
return err;
- if((err = e100_exec_cb(nic, NULL, e100_setup_iaaddr)))
+ if ((err = e100_exec_cb(nic, NULL, e100_setup_iaaddr)))
return err;
- if((err = e100_exec_cmd(nic, cuc_dump_addr,
+ if ((err = e100_exec_cmd(nic, cuc_dump_addr,
nic->dma_addr + offsetof(struct mem, stats))))
return err;
- if((err = e100_exec_cmd(nic, cuc_dump_reset, 0)))
+ if ((err = e100_exec_cmd(nic, cuc_dump_reset, 0)))
return err;
e100_disable_irq(nic);
@@ -1460,7 +1460,7 @@ static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb)
cb->command = cpu_to_le16(cb_multi);
cb->u.multi.count = cpu_to_le16(count * ETH_ALEN);
- for(i = 0; list && i < count; i++, list = list->next)
+ for (i = 0; list && i < count; i++, list = list->next)
memcpy(&cb->u.multi.addr[i*ETH_ALEN], &list->dmi_addr,
ETH_ALEN);
}
@@ -1472,12 +1472,12 @@ static void e100_set_multicast_list(struct net_device *netdev)
DPRINTK(HW, DEBUG, "mc_count=%d, flags=0x%04X\n",
netdev->mc_count, netdev->flags);
- if(netdev->flags & IFF_PROMISC)
+ if (netdev->flags & IFF_PROMISC)
nic->flags |= promiscuous;
else
nic->flags &= ~promiscuous;
- if(netdev->flags & IFF_ALLMULTI ||
+ if (netdev->flags & IFF_ALLMULTI ||
netdev->mc_count > E100_MAX_MULTICAST_ADDRS)
nic->flags |= multicast_all;
else
@@ -1500,7 +1500,7 @@ static void e100_update_stats(struct nic *nic)
* complete, so we're always waiting for results of the
* previous command. */
- if(*complete == cpu_to_le32(cuc_dump_reset_complete)) {
+ if (*complete == cpu_to_le32(cuc_dump_reset_complete)) {
*complete = 0;
nic->tx_frames = le32_to_cpu(s->tx_good_frames);
nic->tx_collisions = le32_to_cpu(s->tx_total_collisions);
@@ -1527,12 +1527,12 @@ static void e100_update_stats(struct nic *nic)
le32_to_cpu(s->tx_single_collisions);
nic->tx_multiple_collisions +=
le32_to_cpu(s->tx_multiple_collisions);
- if(nic->mac >= mac_82558_D101_A4) {
+ if (nic->mac >= mac_82558_D101_A4) {
nic->tx_fc_pause += le32_to_cpu(s->fc_xmt_pause);
nic->rx_fc_pause += le32_to_cpu(s->fc_rcv_pause);
nic->rx_fc_unsupported +=
le32_to_cpu(s->fc_rcv_unsupported);
- if(nic->mac >= mac_82559_D101M) {
+ if (nic->mac >= mac_82559_D101M) {
nic->tx_tco_frames +=
le16_to_cpu(s->xmt_tco_frames);
nic->rx_tco_frames +=
@@ -1542,7 +1542,7 @@ static void e100_update_stats(struct nic *nic)
}
- if(e100_exec_cmd(nic, cuc_dump_reset, 0))
+ if (e100_exec_cmd(nic, cuc_dump_reset, 0))
DPRINTK(TX_ERR, DEBUG, "exec cuc_dump_reset failed\n");
}
@@ -1551,19 +1551,19 @@ static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex)
/* Adjust inter-frame-spacing (IFS) between two transmits if
* we're getting collisions on a half-duplex connection. */
- if(duplex == DUPLEX_HALF) {
+ if (duplex == DUPLEX_HALF) {
u32 prev = nic->adaptive_ifs;
u32 min_frames = (speed == SPEED_100) ? 1000 : 100;
- if((nic->tx_frames / 32 < nic->tx_collisions) &&
+ if ((nic->tx_frames / 32 < nic->tx_collisions) &&
(nic->tx_frames > min_frames)) {
- if(nic->adaptive_ifs < 60)
+ if (nic->adaptive_ifs < 60)
nic->adaptive_ifs += 5;
} else if (nic->tx_frames < min_frames) {
- if(nic->adaptive_ifs >= 5)
+ if (nic->adaptive_ifs >= 5)
nic->adaptive_ifs -= 5;
}
- if(nic->adaptive_ifs != prev)
+ if (nic->adaptive_ifs != prev)
e100_exec_cb(nic, NULL, e100_configure);
}
}
@@ -1579,12 +1579,12 @@ static void e100_watchdog(unsigned long data)
mii_ethtool_gset(&nic->mii, &cmd);
- if(mii_link_ok(&nic->mii) && !netif_carrier_ok(nic->netdev)) {
+ if (mii_link_ok(&nic->mii) && !netif_carrier_ok(nic->netdev)) {
printk(KERN_INFO "e100: %s NIC Link is Up %s Mbps %s Duplex\n",
nic->netdev->name,
cmd.speed == SPEED_100 ? "100" : "10",
cmd.duplex == DUPLEX_FULL ? "Full" : "Half");
- } else if(!mii_link_ok(&nic->mii) && netif_carrier_ok(nic->netdev)) {
+ } else if (!mii_link_ok(&nic->mii) && netif_carrier_ok(nic->netdev)) {
printk(KERN_INFO "e100: %s NIC Link is Down\n",
nic->netdev->name);
}
@@ -1604,11 +1604,11 @@ static void e100_watchdog(unsigned long data)
e100_update_stats(nic);
e100_adjust_adaptive_ifs(nic, cmd.speed, cmd.duplex);
- if(nic->mac <= mac_82557_D100_C)
+ if (nic->mac <= mac_82557_D100_C)
/* Issue a multicast command to workaround a 557 lock up */
e100_set_multicast_list(nic->netdev);
- if(nic->flags & ich && cmd.speed==SPEED_10 && cmd.duplex==DUPLEX_HALF)
+ if (nic->flags & ich && cmd.speed==SPEED_10 && cmd.duplex==DUPLEX_HALF)
/* Need SW workaround for ICH[x] 10Mbps/half duplex Tx hang. */
nic->flags |= ich_10h_workaround;
else
@@ -1623,7 +1623,7 @@ static void e100_xmit_prepare(struct nic *nic, struct cb *cb,
{
cb->command = nic->tx_command;
/* interrupt every 16 packets regardless of delay */
- if((nic->cbs_avail & ~15) == nic->cbs_avail)
+ if ((nic->cbs_avail & ~15) == nic->cbs_avail)
cb->command |= cpu_to_le16(cb_i);
cb->u.tcb.tbd_array = cb->dma_addr + offsetof(struct cb, u.tcb.tbd);
cb->u.tcb.tcb_byte_count = 0;
@@ -1640,18 +1640,18 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
struct nic *nic = netdev_priv(netdev);
int err;
- if(nic->flags & ich_10h_workaround) {
+ if (nic->flags & ich_10h_workaround) {
/* SW workaround for ICH[x] 10Mbps/half duplex Tx hang.
Issue a NOP command followed by a 1us delay before
issuing the Tx command. */
- if(e100_exec_cmd(nic, cuc_nop, 0))
+ if (e100_exec_cmd(nic, cuc_nop, 0))
DPRINTK(TX_ERR, DEBUG, "exec cuc_nop failed\n");
udelay(1);
}
err = e100_exec_cb(nic, skb, e100_xmit_prepare);
- switch(err) {
+ switch (err) {
case -ENOSPC:
/* We queued the skb, but now we're out of space. */
DPRINTK(TX_ERR, DEBUG, "No space for CB\n");
@@ -1677,14 +1677,14 @@ static int e100_tx_clean(struct nic *nic)
spin_lock(&nic->cb_lock);
/* Clean CBs marked complete */
- for(cb = nic->cb_to_clean;
+ for (cb = nic->cb_to_clean;
cb->status & cpu_to_le16(cb_complete);
cb = nic->cb_to_clean = cb->next) {
DPRINTK(TX_DONE, DEBUG, "cb[%d]->status = 0x%04X\n",
(int)(((void*)cb - (void*)nic->cbs)/sizeof(struct cb)),
cb->status);
- if(likely(cb->skb != NULL)) {
+ if (likely(cb->skb != NULL)) {
dev->stats.tx_packets++;
dev->stats.tx_bytes += cb->skb->len;
@@ -1703,7 +1703,7 @@ static int e100_tx_clean(struct nic *nic)
spin_unlock(&nic->cb_lock);
/* Recover from running out of Tx resources in xmit_frame */
- if(unlikely(tx_cleaned && netif_queue_stopped(nic->netdev)))
+ if (unlikely(tx_cleaned && netif_queue_stopped(nic->netdev)))
netif_wake_queue(nic->netdev);
return tx_cleaned;
@@ -1711,10 +1711,10 @@ static int e100_tx_clean(struct nic *nic)
static void e100_clean_cbs(struct nic *nic)
{
- if(nic->cbs) {
- while(nic->cbs_avail != nic->params.cbs.count) {
+ if (nic->cbs) {
+ while (nic->cbs_avail != nic->params.cbs.count) {
struct cb *cb = nic->cb_to_clean;
- if(cb->skb) {
+ if (cb->skb) {
pci_unmap_single(nic->pdev,
le32_to_cpu(cb->u.tcb.tbd.buf_addr),
le16_to_cpu(cb->u.tcb.tbd.size),
@@ -1746,10 +1746,10 @@ static int e100_alloc_cbs(struct nic *nic)
nic->cbs = pci_alloc_consistent(nic->pdev,
sizeof(struct cb) * count, &nic->cbs_dma_addr);
- if(!nic->cbs)
+ if (!nic->cbs)
return -ENOMEM;
- for(cb = nic->cbs, i = 0; i < count; cb++, i++) {
+ for (cb = nic->cbs, i = 0; i < count; cb++, i++) {
cb->next = (i + 1 < count) ? cb + 1 : nic->cbs;
cb->prev = (i == 0) ? nic->cbs + count - 1 : cb - 1;
@@ -1767,14 +1767,14 @@ static int e100_alloc_cbs(struct nic *nic)
static inline void e100_start_receiver(struct nic *nic, struct rx *rx)
{
- if(!nic->rxs) return;
- if(RU_SUSPENDED != nic->ru_running) return;
+ if (!nic->rxs) return;
+ if (RU_SUSPENDED != nic->ru_running) return;
/* handle init time starts */
- if(!rx) rx = nic->rxs;
+ if (!rx) rx = nic->rxs;
/* (Re)start RU if suspended or idle and RFA is non-NULL */
- if(rx->skb) {
+ if (rx->skb) {
e100_exec_cmd(nic, ruc_start, rx->dma_addr);
nic->ru_running = RU_RUNNING;
}
@@ -1783,7 +1783,7 @@ static inline void e100_start_receiver(struct nic *nic, struct rx *rx)
#define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)
static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
{
- if(!(rx->skb = netdev_alloc_skb(nic->netdev, RFD_BUF_LEN + NET_IP_ALIGN)))
+ if (!(rx->skb = netdev_alloc_skb(nic->netdev, RFD_BUF_LEN + NET_IP_ALIGN)))
return -ENOMEM;
/* Align, init, and map the RFD. */
@@ -1820,7 +1820,7 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx,
struct rfd *rfd = (struct rfd *)skb->data;
u16 rfd_status, actual_size;
- if(unlikely(work_done && *work_done >= work_to_do))
+ if (unlikely(work_done && *work_done >= work_to_do))
return -EAGAIN;
/* Need to sync before taking a peek at cb_complete bit */
@@ -1847,7 +1847,7 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx,
/* Get actual data size */
actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF;
- if(unlikely(actual_size > RFD_BUF_LEN - sizeof(struct rfd)))
+ if (unlikely(actual_size > RFD_BUF_LEN - sizeof(struct rfd)))
actual_size = RFD_BUF_LEN - sizeof(struct rfd);
/* Get data */
@@ -1872,10 +1872,10 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx,
skb_put(skb, actual_size);
skb->protocol = eth_type_trans(skb, nic->netdev);
- if(unlikely(!(rfd_status & cb_ok))) {
+ if (unlikely(!(rfd_status & cb_ok))) {
/* Don't indicate if hardware indicates errors */
dev_kfree_skb_any(skb);
- } else if(actual_size > ETH_DATA_LEN + VLAN_ETH_HLEN) {
+ } else if (actual_size > ETH_DATA_LEN + VLAN_ETH_HLEN) {
/* Don't indicate oversized frames */
nic->rx_over_length_errors++;
dev_kfree_skb_any(skb);
@@ -1883,7 +1883,7 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx,
dev->stats.rx_packets++;
dev->stats.rx_bytes += actual_size;
netif_receive_skb(skb);
- if(work_done)
+ if (work_done)
(*work_done)++;
}
@@ -1901,7 +1901,7 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done,
struct rfd *old_before_last_rfd, *new_before_last_rfd;
/* Indicate newly arrived packets */
- for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {
+ for (rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {
err = e100_rx_indicate(nic, rx, work_done, work_to_do);
/* Hit quota or no more to clean */
if (-EAGAIN == err || -ENODATA == err)
@@ -1922,8 +1922,8 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done,
old_before_last_rfd = (struct rfd *)old_before_last_rx->skb->data;
/* Alloc new skbs to refill list */
- for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {
- if(unlikely(e100_rx_alloc_skb(nic, rx)))
+ for (rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {
+ if (unlikely(e100_rx_alloc_skb(nic, rx)))
break; /* Better luck next time (see watchdog) */
}
@@ -1959,11 +1959,11 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done,
PCI_DMA_BIDIRECTIONAL);
}
- if(restart_required) {
+ if (restart_required) {
// ack the rnr?
iowrite8(stat_ack_rnr, &nic->csr->scb.stat_ack);
e100_start_receiver(nic, nic->rx_to_clean);
- if(work_done)
+ if (work_done)
(*work_done)++;
}
}
@@ -1975,9 +1975,9 @@ static void e100_rx_clean_list(struct nic *nic)
nic->ru_running = RU_UNINITIALIZED;
- if(nic->rxs) {
- for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
- if(rx->skb) {
+ if (nic->rxs) {
+ for (rx = nic->rxs, i = 0; i < count; rx++, i++) {
+ if (rx->skb) {
pci_unmap_single(nic->pdev, rx->dma_addr,
RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);
dev_kfree_skb(rx->skb);
@@ -1999,13 +1999,13 @@ static int e100_rx_alloc_list(struct nic *nic)
nic->rx_to_use = nic->rx_to_clean = NULL;
nic->ru_running = RU_UNINITIALIZED;
- if(!(nic->rxs = kcalloc(count, sizeof(struct rx), GFP_ATOMIC)))
+ if (!(nic->rxs = kcalloc(count, sizeof(struct rx), GFP_ATOMIC)))
return -ENOMEM;
- for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
+ for (rx = nic->rxs, i = 0; i < count; rx++, i++) {
rx->next = (i + 1 < count) ? rx + 1 : nic->rxs;
rx->prev = (i == 0) ? nic->rxs + count - 1 : rx - 1;
- if(e100_rx_alloc_skb(nic, rx)) {
+ if (e100_rx_alloc_skb(nic, rx)) {
e100_rx_clean_list(nic);
return -ENOMEM;
}
@@ -2038,7 +2038,7 @@ static irqreturn_t e100_intr(int irq, void *dev_id)
DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack);
- if(stat_ack == stat_ack_not_ours || /* Not our interrupt */
+ if (stat_ack == stat_ack_not_ours || /* Not our interrupt */
stat_ack == stat_ack_not_present) /* Hardware is ejected */
return IRQ_NONE;
@@ -2046,10 +2046,10 @@ static irqreturn_t e100_intr(int irq, void *dev_id)
iowrite8(stat_ack, &nic->csr->scb.stat_ack);
/* We hit Receive No Resource (RNR); restart RU after cleaning */
- if(stat_ack & stat_ack_rnr)
+ if (stat_ack & stat_ack_rnr)
nic->ru_running = RU_SUSPENDED;
- if(likely(netif_rx_schedule_prep(&nic->napi))) {
+ if (likely(netif_rx_schedule_prep(&nic->napi))) {
e100_disable_irq(nic);
__netif_rx_schedule(&nic->napi);
}
@@ -2102,7 +2102,7 @@ static int e100_set_mac_address(struct net_device *netdev, void *p)
static int e100_change_mtu(struct net_device *netdev, int new_mtu)
{
- if(new_mtu < ETH_ZLEN || new_mtu > ETH_DATA_LEN)
+ if (new_mtu < ETH_ZLEN || new_mtu > ETH_DATA_LEN)
return -EINVAL;
netdev->mtu = new_mtu;
return 0;
@@ -2121,16 +2121,16 @@ static int e100_up(struct nic *nic)
{
int err;
- if((err = e100_rx_alloc_list(nic)))
+ if ((err = e100_rx_alloc_list(nic)))
return err;
- if((err = e100_alloc_cbs(nic)))
+ if ((err = e100_alloc_cbs(nic)))
goto err_rx_clean_list;
- if((err = e100_hw_init(nic)))
+ if ((err = e100_hw_init(nic)))
goto err_clean_cbs;
e100_set_multicast_list(nic->netdev);
e100_start_receiver(nic, NULL);
mod_timer(&nic->watchdog, jiffies);
- if((err = request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED,
+ if ((err = request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED,
nic->netdev->name, nic->netdev)))
goto err_no_irq;
netif_wake_queue(nic->netdev);
@@ -2192,26 +2192,26 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
* in loopback mode, and the test passes if the received
* packet compares byte-for-byte to the transmitted packet. */
- if((err = e100_rx_alloc_list(nic)))
+ if ((err = e100_rx_alloc_list(nic)))
return err;
- if((err = e100_alloc_cbs(nic)))
+ if ((err = e100_alloc_cbs(nic)))
goto err_clean_rx;
/* ICH PHY loopback is broken so do MAC loopback instead */
- if(nic->flags & ich && loopback_mode == lb_phy)
+ if (nic->flags & ich && loopback_mode == lb_phy)
loopback_mode = lb_mac;
nic->loopback = loopback_mode;
- if((err = e100_hw_init(nic)))
+ if ((err = e100_hw_init(nic)))
goto err_loopback_none;
- if(loopback_mode == lb_phy)
+ if (loopback_mode == lb_phy)
mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR,
BMCR_LOOPBACK);
e100_start_receiver(nic, NULL);
- if(!(skb = netdev_alloc_skb(nic->netdev, ETH_DATA_LEN))) {
+ if (!(skb = netdev_alloc_skb(nic->netdev, ETH_DATA_LEN))) {
err = -ENOMEM;
goto err_loopback_none;
}
@@ -2224,7 +2224,7 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
pci_dma_sync_single_for_cpu(nic->pdev, nic->rx_to_clean->dma_addr,
RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);
- if(memcmp(nic->rx_to_clean->skb->data + sizeof(struct rfd),
+ if (memcmp(nic->rx_to_clean->skb->data + sizeof(struct rfd),
skb->data, ETH_DATA_LEN))
err = -EAGAIN;
@@ -2301,7 +2301,7 @@ static void e100_get_regs(struct net_device *netdev,
buff[0] = ioread8(&nic->csr->scb.cmd_hi) << 24 |
ioread8(&nic->csr->scb.cmd_lo) << 16 |
ioread16(&nic->csr->scb.status);
- for(i = E100_PHY_REGS; i >= 0; i--)
+ for (i = E100_PHY_REGS; i >= 0; i--)
buff[1 + E100_PHY_REGS - i] =
mdio_read(netdev, nic->mii.phy_id, i);
memset(nic->mem->dump_buf, 0, sizeof(nic->mem->dump_buf));
@@ -2326,7 +2326,7 @@ static int e100_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
!device_can_wakeup(&nic->pdev->dev))
return -EOPNOTSUPP;
- if(wol->wolopts)
+ if (wol->wolopts)
nic->flags |= wol_magic;
else
nic->flags &= ~wol_magic;
@@ -2385,7 +2385,7 @@ static int e100_set_eeprom(struct net_device *netdev,
{
struct nic *nic = netdev_priv(netdev);
- if(eeprom->magic != E100_EEPROM_MAGIC)
+ if (eeprom->magic != E100_EEPROM_MAGIC)
return -EINVAL;
memcpy(&((u8 *)nic->eeprom)[eeprom->offset], bytes, eeprom->len);
@@ -2421,7 +2421,7 @@ static int e100_set_ringparam(struct net_device *netdev,
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
return -EINVAL;
- if(netif_running(netdev))
+ if (netif_running(netdev))
e100_down(nic);
rfds->count = max(ring->rx_pending, rfds->min);
rfds->count = min(rfds->count, rfds->max);
@@ -2429,7 +2429,7 @@ static int e100_set_ringparam(struct net_device *netdev,
cbs->count = min(cbs->count, cbs->max);
DPRINTK(DRV, INFO, "Ring Param settings: rx: %d, tx %d\n",
rfds->count, cbs->count);
- if(netif_running(netdev))
+ if (netif_running(netdev))
e100_up(nic);
return 0;
@@ -2454,12 +2454,12 @@ static void e100_diag_test(struct net_device *netdev,
memset(data, 0, E100_TEST_LEN * sizeof(u64));
data[0] = !mii_link_ok(&nic->mii);
data[1] = e100_eeprom_load(nic);
- if(test->flags & ETH_TEST_FL_OFFLINE) {
+ if (test->flags & ETH_TEST_FL_OFFLINE) {
/* save speed, duplex & autoneg settings */
err = mii_ethtool_gset(&nic->mii, &cmd);
- if(netif_running(netdev))
+ if (netif_running(netdev))
e100_down(nic);
data[2] = e100_self_test(nic);
data[3] = e100_loopback_test(nic, lb_mac);
@@ -2468,10 +2468,10 @@ static void e100_diag_test(struct net_device *netdev,
/* restore speed, duplex & autoneg settings */
err = mii_ethtool_sset(&nic->mii, &cmd);
- if(netif_running(netdev))
+ if (netif_running(netdev))
e100_up(nic);
}
- for(i = 0; i < E100_TEST_LEN; i++)
+ for (i = 0; i < E100_TEST_LEN; i++)
test->flags |= data[i] ? ETH_TEST_FL_FAILED : 0;
msleep_interruptible(4 * 1000);
@@ -2481,7 +2481,7 @@ static int e100_phys_id(struct net_device *netdev, u32 data)
{
struct nic *nic = netdev_priv(netdev);
- if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
+ if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
mod_timer(&nic->blink_timer, jiffies);
msleep_interruptible(data * 1000);
@@ -2524,7 +2524,7 @@ static void e100_get_ethtool_stats(struct net_device *netdev,
struct nic *nic = netdev_priv(netdev);
int i;
- for(i = 0; i < E100_NET_STATS_LEN; i++)
+ for (i = 0; i < E100_NET_STATS_LEN; i++)
data[i] = ((unsigned long *)&netdev->stats)[i];
data[i++] = nic->tx_deferred;
@@ -2539,7 +2539,7 @@ static void e100_get_ethtool_stats(struct net_device *netdev,
static void e100_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
{
- switch(stringset) {
+ switch (stringset) {
case ETH_SS_TEST:
memcpy(data, *e100_gstrings_test, sizeof(e100_gstrings_test));
break;
@@ -2589,7 +2589,7 @@ static int e100_alloc(struct nic *nic)
static void e100_free(struct nic *nic)
{
- if(nic->mem) {
+ if (nic->mem) {
pci_free_consistent(nic->pdev, sizeof(struct mem),
nic->mem, nic->dma_addr);
nic->mem = NULL;
@@ -2602,7 +2602,7 @@ static int e100_open(struct net_device *netdev)
int err = 0;
netif_carrier_off(netdev);
- if((err = e100_up(nic)))
+ if ((err = e100_up(nic)))
DPRINTK(IFUP, ERR, "Cannot open interface, aborting.\n");
return err;
}
@@ -2635,8 +2635,8 @@ static int __devinit e100_probe(struct pci_dev *pdev,
struct nic *nic;
int err;
- if(!(netdev = alloc_etherdev(sizeof(struct nic)))) {
- if(((1 << debug) - 1) & NETIF_MSG_PROBE)
+ if (!(netdev = alloc_etherdev(sizeof(struct nic)))) {
+ if (((1 << debug) - 1) & NETIF_MSG_PROBE)
printk(KERN_ERR PFX "Etherdev alloc failed, abort.\n");
return -ENOMEM;
}
@@ -2653,24 +2653,24 @@ static int __devinit e100_probe(struct pci_dev *pdev,
nic->msg_enable = (1 << debug) - 1;
pci_set_drvdata(pdev, netdev);
- if((err = pci_enable_device(pdev))) {
+ if ((err = pci_enable_device(pdev))) {
DPRINTK(PROBE, ERR, "Cannot enable PCI device, aborting.\n");
goto err_out_free_dev;
}
- if(!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
DPRINTK(PROBE, ERR, "Cannot find proper PCI device "
"base address, aborting.\n");
err = -ENODEV;
goto err_out_disable_pdev;
}
- if((err = pci_request_regions(pdev, DRV_NAME))) {
+ if ((err = pci_request_regions(pdev, DRV_NAME))) {
DPRINTK(PROBE, ERR, "Cannot obtain PCI resources, aborting.\n");
goto err_out_disable_pdev;
}
- if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) {
+ if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) {
DPRINTK(PROBE, ERR, "No usable DMA configuration, aborting.\n");
goto err_out_free_res;
}
@@ -2681,13 +2681,13 @@ static int __devinit e100_probe(struct pci_dev *pdev,
DPRINTK(PROBE, INFO, "using i/o access mode\n");
nic->csr = pci_iomap(pdev, (use_io ? 1 : 0), sizeof(struct csr));
- if(!nic->csr) {
+ if (!nic->csr) {
DPRINTK(PROBE, ERR, "Cannot map device registers, aborting.\n");
err = -ENOMEM;
goto err_out_free_res;
}
- if(ent->driver_data)
+ if (ent->driver_data)
nic->flags |= ich;
else
nic->flags &= ~ich;
@@ -2715,12 +2715,12 @@ static int __devinit e100_probe(struct pci_dev *pdev,
INIT_WORK(&nic->tx_timeout_task, e100_tx_timeout_task);
- if((err = e100_alloc(nic))) {
+ if ((err = e100_alloc(nic))) {
DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n");
goto err_out_iounmap;
}
- if((err = e100_eeprom_load(nic)))
+ if ((err = e100_eeprom_load(nic)))
goto err_out_free;
e100_phy_init(nic);
@@ -2740,7 +2740,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
}
/* Wol magic packet can be enabled from eeprom */
- if((nic->mac >= mac_82558_D101_A4) &&
+ if ((nic->mac >= mac_82558_D101_A4) &&
(nic->eeprom[eeprom_id] & eeprom_id_wol)) {
nic->flags |= wol_magic;
device_set_wakeup_enable(&pdev->dev, true);
@@ -2750,7 +2750,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
pci_pme_active(pdev, false);
strcpy(netdev->name, "eth%d");
- if((err = register_netdev(netdev))) {
+ if ((err = register_netdev(netdev))) {
DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n");
goto err_out_free;
}
@@ -2779,7 +2779,7 @@ static void __devexit e100_remove(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
- if(netdev) {
+ if (netdev) {
struct nic *nic = netdev_priv(netdev);
unregister_netdev(netdev);
e100_free(nic);
@@ -2932,7 +2932,7 @@ static struct pci_driver e100_driver = {
static int __init e100_init_module(void)
{
- if(((1 << debug) - 1) & NETIF_MSG_DRV) {
+ if (((1 << debug) - 1) & NETIF_MSG_DRV) {
printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT);
}
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 9930d5f8b9e1..6271b9411ccf 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -478,7 +478,7 @@ struct ehea_port {
int num_add_tx_qps;
int num_mcs;
int resets;
- u64 flags;
+ unsigned long flags;
u64 mac_addr;
u32 logical_port_id;
u32 port_speed;
@@ -510,7 +510,6 @@ void ehea_set_ethtool_ops(struct net_device *netdev);
int ehea_sense_port_attr(struct ehea_port *port);
int ehea_set_portspeed(struct ehea_port *port, u32 port_speed);
-extern u64 ehea_driver_flags;
extern struct work_struct ehea_rereg_mr_task;
#endif /* __EHEA_H__ */
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index a2f1905a23df..e3131ea629cd 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -99,7 +99,7 @@ MODULE_PARM_DESC(use_lro, " Large Receive Offload, 1: enable, 0: disable, "
static int port_name_cnt;
static LIST_HEAD(adapter_list);
-u64 ehea_driver_flags;
+static unsigned long ehea_driver_flags;
struct work_struct ehea_rereg_mr_task;
static DEFINE_MUTEX(dlpar_mem_lock);
struct ehea_fw_handle_array ehea_fw_handles;
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index b0ef46c51a9d..cefe1d98f93e 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -944,7 +944,7 @@ static void enc28j60_hw_rx(struct net_device *ndev)
if (netif_msg_rx_status(priv))
enc28j60_dump_rsv(priv, __func__, next_packet, len, rxstat);
- if (!RSV_GETBIT(rxstat, RSV_RXOK)) {
+ if (!RSV_GETBIT(rxstat, RSV_RXOK) || len > MAX_FRAMELEN) {
if (netif_msg_rx_err(priv))
dev_err(&ndev->dev, "Rx Error (%04x)\n", rxstat);
ndev->stats.rx_errors++;
@@ -952,6 +952,8 @@ static void enc28j60_hw_rx(struct net_device *ndev)
ndev->stats.rx_crc_errors++;
if (RSV_GETBIT(rxstat, RSV_LENCHECKERR))
ndev->stats.rx_frame_errors++;
+ if (len > MAX_FRAMELEN)
+ ndev->stats.rx_over_errors++;
} else {
skb = dev_alloc_skb(len + NET_IP_ALIGN);
if (!skb) {
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index 022794e579c7..b82b0fb2056c 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -1457,8 +1457,8 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)
/* Number of supported queues. */
/* Having more queues than CPUs doesn't make sense. */
- adapter->num_rx_queues = min((u32)IGB_MAX_RX_QUEUES, (u32)num_online_cpus());
- adapter->num_tx_queues = min(IGB_MAX_TX_QUEUES, num_online_cpus());
+ adapter->num_rx_queues = min_t(u32, IGB_MAX_RX_QUEUES, num_online_cpus());
+ adapter->num_tx_queues = min_t(u32, IGB_MAX_TX_QUEUES, num_online_cpus());
/* This call may decrease the number of queues depending on
* interrupt mode. */
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 5e70180bf569..6bb71b687f7b 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -75,7 +75,7 @@
#include "myri10ge_mcp.h"
#include "myri10ge_mcp_gen_header.h"
-#define MYRI10GE_VERSION_STR "1.4.4-1.395"
+#define MYRI10GE_VERSION_STR "1.4.4-1.398"
MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
MODULE_AUTHOR("Maintainer: help@myri.com");
@@ -3929,6 +3929,10 @@ abort_with_firmware:
myri10ge_dummy_rdma(mgp, 0);
abort_with_ioremap:
+ if (mgp->mac_addr_string != NULL)
+ dev_err(&pdev->dev,
+ "myri10ge_probe() failed: MAC=%s, SN=%ld\n",
+ mgp->mac_addr_string, mgp->serial_number);
iounmap(mgp->sram);
abort_with_mtrr:
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index ba2e1c5b6bcf..459663a4023d 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -818,15 +818,6 @@ struct tx_doorbell_context {
};
/* DATA STRUCTURES SHARED WITH HARDWARE. */
-
-struct bq_element {
- u32 addr_lo;
-#define BQ_END 0x00000001
-#define BQ_CONT 0x00000002
-#define BQ_MASK 0x00000003
- u32 addr_hi;
-} __attribute((packed));
-
struct tx_buf_desc {
__le64 addr;
__le32 len;
@@ -860,8 +851,8 @@ struct ob_mac_iocb_req {
__le16 frame_len;
#define OB_MAC_IOCB_LEN_MASK 0x3ffff
__le16 reserved2;
- __le32 tid;
- __le32 txq_idx;
+ u32 tid;
+ u32 txq_idx;
__le32 reserved3;
__le16 vlan_tci;
__le16 reserved4;
@@ -880,8 +871,8 @@ struct ob_mac_iocb_rsp {
u8 flags2; /* */
u8 flags3; /* */
#define OB_MAC_IOCB_RSP_B 0x80 /* */
- __le32 tid;
- __le32 txq_idx;
+ u32 tid;
+ u32 txq_idx;
__le32 reserved[13];
} __attribute((packed));
@@ -903,8 +894,8 @@ struct ob_mac_tso_iocb_req {
#define OB_MAC_TSO_IOCB_V 0x04
__le32 reserved1[2];
__le32 frame_len;
- __le32 tid;
- __le32 txq_idx;
+ u32 tid;
+ u32 txq_idx;
__le16 total_hdrs_len;
__le16 net_trans_offset;
#define OB_MAC_TRANSPORT_HDR_SHIFT 6
@@ -925,8 +916,8 @@ struct ob_mac_tso_iocb_rsp {
u8 flags2; /* */
u8 flags3; /* */
#define OB_MAC_TSO_IOCB_RSP_B 0x8000
- __le32 tid;
- __le32 txq_idx;
+ u32 tid;
+ u32 txq_idx;
__le32 reserved2[13];
} __attribute((packed));
@@ -979,10 +970,11 @@ struct ib_mac_iocb_rsp {
__le16 reserved1;
__le32 reserved2[6];
- __le32 flags4;
-#define IB_MAC_IOCB_RSP_HV 0x20000000 /* */
-#define IB_MAC_IOCB_RSP_HS 0x40000000 /* */
-#define IB_MAC_IOCB_RSP_HL 0x80000000 /* */
+ u8 reserved3[3];
+ u8 flags4;
+#define IB_MAC_IOCB_RSP_HV 0x20
+#define IB_MAC_IOCB_RSP_HS 0x40
+#define IB_MAC_IOCB_RSP_HL 0x80
__le32 hdr_len; /* */
__le32 hdr_addr_lo; /* */
__le32 hdr_addr_hi; /* */
@@ -1126,7 +1118,7 @@ struct map_list {
struct tx_ring_desc {
struct sk_buff *skb;
struct ob_mac_iocb_req *queue_entry;
- int index;
+ u32 index;
struct oal oal;
struct map_list map[MAX_SKB_FRAGS + 1];
int map_cnt;
@@ -1138,8 +1130,8 @@ struct bq_desc {
struct page *lbq_page;
struct sk_buff *skb;
} p;
- struct bq_element *bq;
- int index;
+ __le64 *addr;
+ u32 index;
DECLARE_PCI_UNMAP_ADDR(mapaddr);
DECLARE_PCI_UNMAP_LEN(maplen);
};
@@ -1189,7 +1181,7 @@ struct rx_ring {
u32 cq_size;
u32 cq_len;
u16 cq_id;
- u32 *prod_idx_sh_reg; /* Shadowed producer register. */
+ volatile __le32 *prod_idx_sh_reg; /* Shadowed producer register. */
dma_addr_t prod_idx_sh_reg_dma;
void __iomem *cnsmr_idx_db_reg; /* PCI doorbell mem area + 0 */
u32 cnsmr_idx; /* current sw idx */
@@ -1467,21 +1459,6 @@ static inline void ql_write_db_reg(u32 val, void __iomem *addr)
mmiowb();
}
-/*
- * Shadow Registers:
- * Outbound queues have a consumer index that is maintained by the chip.
- * Inbound queues have a producer index that is maintained by the chip.
- * For lower overhead, these registers are "shadowed" to host memory
- * which allows the device driver to track the queue progress without
- * PCI reads. When an entry is placed on an inbound queue, the chip will
- * update the relevant index register and then copy the value to the
- * shadow register in host memory.
- */
-static inline unsigned int ql_read_sh_reg(const volatile void *addr)
-{
- return *(volatile unsigned int __force *)addr;
-}
-
extern char qlge_driver_name[];
extern const char qlge_driver_version[];
extern const struct ethtool_ops qlge_ethtool_ops;
diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c
index 47df304a02c8..3f5e02d2e4a9 100644
--- a/drivers/net/qlge/qlge_dbg.c
+++ b/drivers/net/qlge/qlge_dbg.c
@@ -821,14 +821,11 @@ void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp)
le16_to_cpu(ib_mac_rsp->vlan_id));
printk(KERN_ERR PFX "flags4 = %s%s%s.\n",
- le32_to_cpu(ib_mac_rsp->
- flags4) & IB_MAC_IOCB_RSP_HV ? "HV " : "",
- le32_to_cpu(ib_mac_rsp->
- flags4) & IB_MAC_IOCB_RSP_HS ? "HS " : "",
- le32_to_cpu(ib_mac_rsp->
- flags4) & IB_MAC_IOCB_RSP_HL ? "HL " : "");
-
- if (le32_to_cpu(ib_mac_rsp->flags4) & IB_MAC_IOCB_RSP_HV) {
+ ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV ? "HV " : "",
+ ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS ? "HS " : "",
+ ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HL ? "HL " : "");
+
+ if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV) {
printk(KERN_ERR PFX "hdr length = %d.\n",
le32_to_cpu(ib_mac_rsp->hdr_len));
printk(KERN_ERR PFX "hdr addr_hi = 0x%x.\n",
diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c
index eefb81b13758..9d922e2ff226 100644
--- a/drivers/net/qlge/qlge_ethtool.c
+++ b/drivers/net/qlge/qlge_ethtool.c
@@ -56,9 +56,9 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev)
for (i = 1; i < qdev->rss_ring_first_cq_id; i++, rx_ring++) {
rx_ring = &qdev->rx_ring[i];
cqicb = (struct cqicb *)rx_ring;
- cqicb->irq_delay = le16_to_cpu(qdev->tx_coalesce_usecs);
+ cqicb->irq_delay = cpu_to_le16(qdev->tx_coalesce_usecs);
cqicb->pkt_delay =
- le16_to_cpu(qdev->tx_max_coalesced_frames);
+ cpu_to_le16(qdev->tx_max_coalesced_frames);
cqicb->flags = FLAGS_LI;
status = ql_write_cfg(qdev, cqicb, sizeof(cqicb),
CFG_LCQ, rx_ring->cq_id);
@@ -79,9 +79,9 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev)
i++) {
rx_ring = &qdev->rx_ring[i];
cqicb = (struct cqicb *)rx_ring;
- cqicb->irq_delay = le16_to_cpu(qdev->rx_coalesce_usecs);
+ cqicb->irq_delay = cpu_to_le16(qdev->rx_coalesce_usecs);
cqicb->pkt_delay =
- le16_to_cpu(qdev->rx_max_coalesced_frames);
+ cpu_to_le16(qdev->rx_max_coalesced_frames);
cqicb->flags = FLAGS_LI;
status = ql_write_cfg(qdev, cqicb, sizeof(cqicb),
CFG_LCQ, rx_ring->cq_id);
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 718a7bd0cd1a..f4c016012f18 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -257,7 +257,7 @@ int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index,
{
status =
ql_wait_reg_rdy(qdev,
- MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+ MAC_ADDR_IDX, MAC_ADDR_MW, 0);
if (status)
goto exit;
ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */
@@ -265,13 +265,13 @@ int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index,
MAC_ADDR_ADR | MAC_ADDR_RS | type); /* type */
status =
ql_wait_reg_rdy(qdev,
- MAC_ADDR_IDX, MAC_ADDR_MR, MAC_ADDR_E);
+ MAC_ADDR_IDX, MAC_ADDR_MR, 0);
if (status)
goto exit;
*value++ = ql_read32(qdev, MAC_ADDR_DATA);
status =
ql_wait_reg_rdy(qdev,
- MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+ MAC_ADDR_IDX, MAC_ADDR_MW, 0);
if (status)
goto exit;
ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */
@@ -279,14 +279,14 @@ int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index,
MAC_ADDR_ADR | MAC_ADDR_RS | type); /* type */
status =
ql_wait_reg_rdy(qdev,
- MAC_ADDR_IDX, MAC_ADDR_MR, MAC_ADDR_E);
+ MAC_ADDR_IDX, MAC_ADDR_MR, 0);
if (status)
goto exit;
*value++ = ql_read32(qdev, MAC_ADDR_DATA);
if (type == MAC_ADDR_TYPE_CAM_MAC) {
status =
ql_wait_reg_rdy(qdev,
- MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+ MAC_ADDR_IDX, MAC_ADDR_MW, 0);
if (status)
goto exit;
ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */
@@ -294,7 +294,7 @@ int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index,
MAC_ADDR_ADR | MAC_ADDR_RS | type); /* type */
status =
ql_wait_reg_rdy(qdev, MAC_ADDR_IDX,
- MAC_ADDR_MR, MAC_ADDR_E);
+ MAC_ADDR_MR, 0);
if (status)
goto exit;
*value++ = ql_read32(qdev, MAC_ADDR_DATA);
@@ -344,7 +344,7 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
status =
ql_wait_reg_rdy(qdev,
- MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+ MAC_ADDR_IDX, MAC_ADDR_MW, 0);
if (status)
goto exit;
ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */
@@ -353,7 +353,7 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
ql_write32(qdev, MAC_ADDR_DATA, lower);
status =
ql_wait_reg_rdy(qdev,
- MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+ MAC_ADDR_IDX, MAC_ADDR_MW, 0);
if (status)
goto exit;
ql_write32(qdev, MAC_ADDR_IDX, (offset++) | /* offset */
@@ -362,7 +362,7 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
ql_write32(qdev, MAC_ADDR_DATA, upper);
status =
ql_wait_reg_rdy(qdev,
- MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+ MAC_ADDR_IDX, MAC_ADDR_MW, 0);
if (status)
goto exit;
ql_write32(qdev, MAC_ADDR_IDX, (offset) | /* offset */
@@ -400,7 +400,7 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
status =
ql_wait_reg_rdy(qdev,
- MAC_ADDR_IDX, MAC_ADDR_MW, MAC_ADDR_E);
+ MAC_ADDR_IDX, MAC_ADDR_MW, 0);
if (status)
goto exit;
ql_write32(qdev, MAC_ADDR_IDX, offset | /* offset */
@@ -431,13 +431,13 @@ int ql_get_routing_reg(struct ql_adapter *qdev, u32 index, u32 *value)
if (status)
goto exit;
- status = ql_wait_reg_rdy(qdev, RT_IDX, RT_IDX_MW, RT_IDX_E);
+ status = ql_wait_reg_rdy(qdev, RT_IDX, RT_IDX_MW, 0);
if (status)
goto exit;
ql_write32(qdev, RT_IDX,
RT_IDX_TYPE_NICQ | RT_IDX_RS | (index << RT_IDX_IDX_SHIFT));
- status = ql_wait_reg_rdy(qdev, RT_IDX, RT_IDX_MR, RT_IDX_E);
+ status = ql_wait_reg_rdy(qdev, RT_IDX, RT_IDX_MR, 0);
if (status)
goto exit;
*value = ql_read32(qdev, RT_DATA);
@@ -874,7 +874,6 @@ static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
{
int clean_idx = rx_ring->lbq_clean_idx;
struct bq_desc *lbq_desc;
- struct bq_element *bq;
u64 map;
int i;
@@ -884,7 +883,6 @@ static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
"lbq: try cleaning clean_idx = %d.\n",
clean_idx);
lbq_desc = &rx_ring->lbq[clean_idx];
- bq = lbq_desc->bq;
if (lbq_desc->p.lbq_page == NULL) {
QPRINTK(qdev, RX_STATUS, DEBUG,
"lbq: getting new page for index %d.\n",
@@ -906,10 +904,7 @@ static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
}
pci_unmap_addr_set(lbq_desc, mapaddr, map);
pci_unmap_len_set(lbq_desc, maplen, PAGE_SIZE);
- bq->addr_lo = /*lbq_desc->addr_lo = */
- cpu_to_le32(map);
- bq->addr_hi = /*lbq_desc->addr_hi = */
- cpu_to_le32(map >> 32);
+ *lbq_desc->addr = cpu_to_le64(map);
}
clean_idx++;
if (clean_idx == rx_ring->lbq_len)
@@ -934,7 +929,6 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
{
int clean_idx = rx_ring->sbq_clean_idx;
struct bq_desc *sbq_desc;
- struct bq_element *bq;
u64 map;
int i;
@@ -944,7 +938,6 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
QPRINTK(qdev, RX_STATUS, DEBUG,
"sbq: try cleaning clean_idx = %d.\n",
clean_idx);
- bq = sbq_desc->bq;
if (sbq_desc->p.skb == NULL) {
QPRINTK(qdev, RX_STATUS, DEBUG,
"sbq: getting new skb for index %d.\n",
@@ -963,11 +956,15 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
sbq_desc->p.skb->data,
rx_ring->sbq_buf_size /
2, PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(qdev->pdev, map)) {
+ QPRINTK(qdev, IFUP, ERR, "PCI mapping failed.\n");
+ rx_ring->sbq_clean_idx = clean_idx;
+ return;
+ }
pci_unmap_addr_set(sbq_desc, mapaddr, map);
pci_unmap_len_set(sbq_desc, maplen,
rx_ring->sbq_buf_size / 2);
- bq->addr_lo = cpu_to_le32(map);
- bq->addr_hi = cpu_to_le32(map >> 32);
+ *sbq_desc->addr = cpu_to_le64(map);
}
clean_idx++;
@@ -1303,6 +1300,11 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
"No skb available, drop the packet.\n");
return NULL;
}
+ pci_unmap_page(qdev->pdev,
+ pci_unmap_addr(lbq_desc,
+ mapaddr),
+ pci_unmap_len(lbq_desc, maplen),
+ PCI_DMA_FROMDEVICE);
skb_reserve(skb, NET_IP_ALIGN);
QPRINTK(qdev, RX_STATUS, DEBUG,
"%d bytes of headers and data in large. Chain page to new skb and pull tail.\n", length);
@@ -1330,7 +1332,7 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
* eventually be in trouble.
*/
int size, offset, i = 0;
- struct bq_element *bq, bq_array[8];
+ __le64 *bq, bq_array[8];
sbq_desc = ql_get_curr_sbuf(rx_ring);
pci_unmap_single(qdev->pdev,
pci_unmap_addr(sbq_desc, mapaddr),
@@ -1356,16 +1358,10 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev,
} else {
QPRINTK(qdev, RX_STATUS, DEBUG,
"Headers in small, %d bytes of data in chain of large.\n", length);
- bq = (struct bq_element *)sbq_desc->p.skb->data;
+ bq = (__le64 *)sbq_desc->p.skb->data;
}
while (length > 0) {
lbq_desc = ql_get_curr_lbuf(rx_ring);
- if ((bq->addr_lo & ~BQ_MASK) != lbq_desc->bq->addr_lo) {
- QPRINTK(qdev, RX_STATUS, ERR,
- "Panic!!! bad large buffer address, expected 0x%.08x, got 0x%.08x.\n",
- lbq_desc->bq->addr_lo, bq->addr_lo);
- return NULL;
- }
pci_unmap_page(qdev->pdev,
pci_unmap_addr(lbq_desc,
mapaddr),
@@ -1549,7 +1545,7 @@ static void ql_process_chip_ae_intr(struct ql_adapter *qdev,
static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring)
{
struct ql_adapter *qdev = rx_ring->qdev;
- u32 prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg);
+ u32 prod = le32_to_cpu(*rx_ring->prod_idx_sh_reg);
struct ob_mac_iocb_rsp *net_rsp = NULL;
int count = 0;
@@ -1575,7 +1571,7 @@ static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring)
}
count++;
ql_update_cq(rx_ring);
- prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg);
+ prod = le32_to_cpu(*rx_ring->prod_idx_sh_reg);
}
ql_write_cq_idx(rx_ring);
if (netif_queue_stopped(qdev->ndev) && net_rsp != NULL) {
@@ -1595,7 +1591,7 @@ static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring)
static int ql_clean_inbound_rx_ring(struct rx_ring *rx_ring, int budget)
{
struct ql_adapter *qdev = rx_ring->qdev;
- u32 prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg);
+ u32 prod = le32_to_cpu(*rx_ring->prod_idx_sh_reg);
struct ql_net_rsp_iocb *net_rsp;
int count = 0;
@@ -1628,7 +1624,7 @@ static int ql_clean_inbound_rx_ring(struct rx_ring *rx_ring, int budget)
}
count++;
ql_update_cq(rx_ring);
- prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg);
+ prod = le32_to_cpu(*rx_ring->prod_idx_sh_reg);
if (count == budget)
break;
}
@@ -1791,7 +1787,7 @@ static irqreturn_t qlge_isr(int irq, void *dev_id)
* Check the default queue and wake handler if active.
*/
rx_ring = &qdev->rx_ring[0];
- if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) != rx_ring->cnsmr_idx) {
+ if (le32_to_cpu(*rx_ring->prod_idx_sh_reg) != rx_ring->cnsmr_idx) {
QPRINTK(qdev, INTR, INFO, "Waking handler for rx_ring[0].\n");
ql_disable_completion_interrupt(qdev, intr_context->intr);
queue_delayed_work_on(smp_processor_id(), qdev->q_workqueue,
@@ -1805,7 +1801,7 @@ static irqreturn_t qlge_isr(int irq, void *dev_id)
*/
for (i = 1; i < qdev->rx_ring_count; i++) {
rx_ring = &qdev->rx_ring[i];
- if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) !=
+ if (le32_to_cpu(*rx_ring->prod_idx_sh_reg) !=
rx_ring->cnsmr_idx) {
QPRINTK(qdev, INTR, INFO,
"Waking handler for rx_ring[%d].\n", i);
@@ -1874,7 +1870,7 @@ static void ql_hw_csum_setup(struct sk_buff *skb,
{
int len;
struct iphdr *iph = ip_hdr(skb);
- u16 *check;
+ __sum16 *check;
mac_iocb_ptr->opcode = OPCODE_OB_MAC_TSO_IOCB;
mac_iocb_ptr->frame_len = cpu_to_le32((u32) skb->len);
mac_iocb_ptr->net_trans_offset =
@@ -2083,8 +2079,6 @@ static void ql_free_lbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring
put_page(lbq_desc->p.lbq_page);
lbq_desc->p.lbq_page = NULL;
}
- lbq_desc->bq->addr_lo = 0;
- lbq_desc->bq->addr_hi = 0;
}
}
@@ -2097,12 +2091,12 @@ static int ql_alloc_lbq_buffers(struct ql_adapter *qdev,
int i;
struct bq_desc *lbq_desc;
u64 map;
- struct bq_element *bq = rx_ring->lbq_base;
+ __le64 *bq = rx_ring->lbq_base;
for (i = 0; i < rx_ring->lbq_len; i++) {
lbq_desc = &rx_ring->lbq[i];
memset(lbq_desc, 0, sizeof(lbq_desc));
- lbq_desc->bq = bq;
+ lbq_desc->addr = bq;
lbq_desc->index = i;
lbq_desc->p.lbq_page = alloc_page(GFP_ATOMIC);
if (unlikely(!lbq_desc->p.lbq_page)) {
@@ -2119,8 +2113,7 @@ static int ql_alloc_lbq_buffers(struct ql_adapter *qdev,
}
pci_unmap_addr_set(lbq_desc, mapaddr, map);
pci_unmap_len_set(lbq_desc, maplen, PAGE_SIZE);
- bq->addr_lo = cpu_to_le32(map);
- bq->addr_hi = cpu_to_le32(map >> 32);
+ *lbq_desc->addr = cpu_to_le64(map);
}
bq++;
}
@@ -2149,13 +2142,6 @@ static void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring
dev_kfree_skb(sbq_desc->p.skb);
sbq_desc->p.skb = NULL;
}
- if (sbq_desc->bq == NULL) {
- QPRINTK(qdev, IFUP, ERR, "sbq_desc->bq %d is NULL.\n",
- i);
- return;
- }
- sbq_desc->bq->addr_lo = 0;
- sbq_desc->bq->addr_hi = 0;
}
}
@@ -2167,13 +2153,13 @@ static int ql_alloc_sbq_buffers(struct ql_adapter *qdev,
struct bq_desc *sbq_desc;
struct sk_buff *skb;
u64 map;
- struct bq_element *bq = rx_ring->sbq_base;
+ __le64 *bq = rx_ring->sbq_base;
for (i = 0; i < rx_ring->sbq_len; i++) {
sbq_desc = &rx_ring->sbq[i];
memset(sbq_desc, 0, sizeof(sbq_desc));
sbq_desc->index = i;
- sbq_desc->bq = bq;
+ sbq_desc->addr = bq;
skb = netdev_alloc_skb(qdev->ndev, rx_ring->sbq_buf_size);
if (unlikely(!skb)) {
/* Better luck next round */
@@ -2199,10 +2185,7 @@ static int ql_alloc_sbq_buffers(struct ql_adapter *qdev,
}
pci_unmap_addr_set(sbq_desc, mapaddr, map);
pci_unmap_len_set(sbq_desc, maplen, rx_ring->sbq_buf_size / 2);
- bq->addr_lo = /*sbq_desc->addr_lo = */
- cpu_to_le32(map);
- bq->addr_hi = /*sbq_desc->addr_hi = */
- cpu_to_le32(map >> 32);
+ *sbq_desc->addr = cpu_to_le64(map);
bq++;
}
return 0;
@@ -2481,7 +2464,8 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
memset((void *)cqicb, 0, sizeof(struct cqicb));
cqicb->msix_vect = rx_ring->irq;
- cqicb->len = cpu_to_le16(rx_ring->cq_len | LEN_V | LEN_CPP_CONT);
+ bq_len = (rx_ring->cq_len == 65536) ? 0 : (u16) rx_ring->cq_len;
+ cqicb->len = cpu_to_le16(bq_len | LEN_V | LEN_CPP_CONT);
cqicb->addr_lo = cpu_to_le32(rx_ring->cq_base_dma);
cqicb->addr_hi = cpu_to_le32((u64) rx_ring->cq_base_dma >> 32);
@@ -2503,8 +2487,11 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
cpu_to_le32(rx_ring->lbq_base_indirect_dma);
cqicb->lbq_addr_hi =
cpu_to_le32((u64) rx_ring->lbq_base_indirect_dma >> 32);
- cqicb->lbq_buf_size = cpu_to_le32(rx_ring->lbq_buf_size);
- bq_len = (u16) rx_ring->lbq_len;
+ bq_len = (rx_ring->lbq_buf_size == 65536) ? 0 :
+ (u16) rx_ring->lbq_buf_size;
+ cqicb->lbq_buf_size = cpu_to_le16(bq_len);
+ bq_len = (rx_ring->lbq_len == 65536) ? 0 :
+ (u16) rx_ring->lbq_len;
cqicb->lbq_len = cpu_to_le16(bq_len);
rx_ring->lbq_prod_idx = rx_ring->lbq_len - 16;
rx_ring->lbq_curr_idx = 0;
@@ -2520,7 +2507,8 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
cpu_to_le32((u64) rx_ring->sbq_base_indirect_dma >> 32);
cqicb->sbq_buf_size =
cpu_to_le16(((rx_ring->sbq_buf_size / 2) + 8) & 0xfffffff8);
- bq_len = (u16) rx_ring->sbq_len;
+ bq_len = (rx_ring->sbq_len == 65536) ? 0 :
+ (u16) rx_ring->sbq_len;
cqicb->sbq_len = cpu_to_le16(bq_len);
rx_ring->sbq_prod_idx = rx_ring->sbq_len - 16;
rx_ring->sbq_curr_idx = 0;
@@ -3341,11 +3329,11 @@ static int ql_configure_rings(struct ql_adapter *qdev)
rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb);
rx_ring->lbq_len = NUM_LARGE_BUFFERS;
rx_ring->lbq_size =
- rx_ring->lbq_len * sizeof(struct bq_element);
+ rx_ring->lbq_len * sizeof(__le64);
rx_ring->lbq_buf_size = LARGE_BUFFER_SIZE;
rx_ring->sbq_len = NUM_SMALL_BUFFERS;
rx_ring->sbq_size =
- rx_ring->sbq_len * sizeof(struct bq_element);
+ rx_ring->sbq_len * sizeof(__le64);
rx_ring->sbq_buf_size = SMALL_BUFFER_SIZE * 2;
rx_ring->type = DEFAULT_Q;
} else if (i < qdev->rss_ring_first_cq_id) {
@@ -3372,11 +3360,11 @@ static int ql_configure_rings(struct ql_adapter *qdev)
rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb);
rx_ring->lbq_len = NUM_LARGE_BUFFERS;
rx_ring->lbq_size =
- rx_ring->lbq_len * sizeof(struct bq_element);
+ rx_ring->lbq_len * sizeof(__le64);
rx_ring->lbq_buf_size = LARGE_BUFFER_SIZE;
rx_ring->sbq_len = NUM_SMALL_BUFFERS;
rx_ring->sbq_size =
- rx_ring->sbq_len * sizeof(struct bq_element);
+ rx_ring->sbq_len * sizeof(__le64);
rx_ring->sbq_buf_size = SMALL_BUFFER_SIZE * 2;
rx_ring->type = RX_Q;
}
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index f54ac2389da2..57fb1f71c47b 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -42,11 +42,11 @@
#include <linux/mii.h>
#include <linux/if_vlan.h>
#include <linux/mm.h>
+#include <linux/firmware.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/uaccess.h>
#include <asm/io.h>
-#include "starfire_firmware.h"
/*
* The current frame processor firmware fails to checksum a fragment
* of length 1. If and when this is fixed, the #define below can be removed.
@@ -173,6 +173,10 @@ static int full_duplex[MAX_UNITS] = {0, };
#define skb_first_frag_len(skb) skb_headlen(skb)
#define skb_num_frags(skb) (skb_shinfo(skb)->nr_frags + 1)
+/* Firmware names */
+#define FIRMWARE_RX "adaptec/starfire_rx.bin"
+#define FIRMWARE_TX "adaptec/starfire_tx.bin"
+
/* These identify the driver base version and may not be removed. */
static char version[] =
KERN_INFO "starfire.c:v1.03 7/26/2000 Written by Donald Becker <becker@scyld.com>\n"
@@ -182,6 +186,8 @@ MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+MODULE_FIRMWARE(FIRMWARE_RX);
+MODULE_FIRMWARE(FIRMWARE_TX);
module_param(max_interrupt_work, int, 0);
module_param(mtu, int, 0);
@@ -902,9 +908,12 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val
static int netdev_open(struct net_device *dev)
{
+ const struct firmware *fw_rx, *fw_tx;
+ const __be32 *fw_rx_data, *fw_tx_data;
struct netdev_private *np = netdev_priv(dev);
void __iomem *ioaddr = np->base;
int i, retval;
+ size_t tx_size, rx_size;
size_t tx_done_q_size, rx_done_q_size, tx_ring_size, rx_ring_size;
/* Do we ever need to reset the chip??? */
@@ -1040,11 +1049,40 @@ static int netdev_open(struct net_device *dev)
writel(ETH_P_8021Q, ioaddr + VlanType);
#endif /* VLAN_SUPPORT */
+ retval = request_firmware(&fw_rx, FIRMWARE_RX, &np->pci_dev->dev);
+ if (retval) {
+ printk(KERN_ERR "starfire: Failed to load firmware \"%s\"\n",
+ FIRMWARE_RX);
+ return retval;
+ }
+ if (fw_rx->size % 4) {
+ printk(KERN_ERR "starfire: bogus length %zu in \"%s\"\n",
+ fw_rx->size, FIRMWARE_RX);
+ retval = -EINVAL;
+ goto out_rx;
+ }
+ retval = request_firmware(&fw_tx, FIRMWARE_TX, &np->pci_dev->dev);
+ if (retval) {
+ printk(KERN_ERR "starfire: Failed to load firmware \"%s\"\n",
+ FIRMWARE_TX);
+ goto out_rx;
+ }
+ if (fw_tx->size % 4) {
+ printk(KERN_ERR "starfire: bogus length %zu in \"%s\"\n",
+ fw_tx->size, FIRMWARE_TX);
+ retval = -EINVAL;
+ goto out_tx;
+ }
+ fw_rx_data = (const __be32 *)&fw_rx->data[0];
+ fw_tx_data = (const __be32 *)&fw_tx->data[0];
+ rx_size = fw_rx->size / 4;
+ tx_size = fw_tx->size / 4;
+
/* Load Rx/Tx firmware into the frame processors */
- for (i = 0; i < FIRMWARE_RX_SIZE * 2; i++)
- writel(firmware_rx[i], ioaddr + RxGfpMem + i * 4);
- for (i = 0; i < FIRMWARE_TX_SIZE * 2; i++)
- writel(firmware_tx[i], ioaddr + TxGfpMem + i * 4);
+ for (i = 0; i < rx_size; i++)
+ writel(be32_to_cpup(&fw_rx_data[i]), ioaddr + RxGfpMem + i * 4);
+ for (i = 0; i < tx_size; i++)
+ writel(be32_to_cpup(&fw_tx_data[i]), ioaddr + TxGfpMem + i * 4);
if (enable_hw_cksum)
/* Enable the Rx and Tx units, and the Rx/Tx frame processors. */
writel(TxEnable|TxGFPEnable|RxEnable|RxGFPEnable, ioaddr + GenCtrl);
@@ -1056,7 +1094,11 @@ static int netdev_open(struct net_device *dev)
printk(KERN_DEBUG "%s: Done netdev_open().\n",
dev->name);
- return 0;
+out_tx:
+ release_firmware(fw_tx);
+out_rx:
+ release_firmware(fw_rx);
+ return retval;
}
diff --git a/drivers/net/starfire_firmware.h b/drivers/net/starfire_firmware.h
deleted file mode 100644
index 0a668528955d..000000000000
--- a/drivers/net/starfire_firmware.h
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * Copyright 2003 Adaptec, Inc.
- *
- * Please read the following license before using the Adaptec Software
- * ("Program"). If you do not agree to the license terms, do not use the
- * Program:
- *
- * You agree to be bound by version 2 of the General Public License ("GPL")
- * dated June 1991, which can be found at http://www.fsf.org/licenses/gpl.html.
- * If the link is broken, write to Free Software Foundation, 59 Temple Place,
- * Boston, Massachusetts 02111-1307.
- *
- * BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE IT IS LICENSED "AS IS" AND
- * THERE IS NO WARRANTY FOR THE PROGRAM, INCLUDING BUT NOT LIMITED TO THE
- * IMPLIED WARRANTIES OF MERCHANTIBILITY OR FITNESS FOR A PARTICULAR PURPOSE
- * (TO THE EXTENT PERMITTED BY APPLICABLE LAW). USE OF THE PROGRAM IS AT YOUR
- * OWN RISK. IN NO EVENT WILL ADAPTEC OR ITS LICENSORS BE LIABLE TO YOU FOR
- * DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM.
- *
- */
-
-static const u32 firmware_rx[] = {
- 0x010003dc, 0x00000000,
- 0x04000421, 0x00000086,
- 0x80000015, 0x0000180e,
- 0x81000015, 0x00006664,
- 0x1a0040ab, 0x00000b06,
- 0x14200011, 0x00000000,
- 0x14204022, 0x0000aaaa,
- 0x14204022, 0x00000300,
- 0x14204022, 0x00000000,
- 0x1a0040ab, 0x00000b14,
- 0x14200011, 0x00000000,
- 0x83000015, 0x00000002,
- 0x04000021, 0x00000000,
- 0x00000010, 0x00000000,
- 0x04000421, 0x00000087,
- 0x00000010, 0x00000000,
- 0x00000010, 0x00000000,
- 0x00008015, 0x00000000,
- 0x0000003e, 0x00000000,
- 0x00000010, 0x00000000,
- 0x82000015, 0x00004000,
- 0x009e8050, 0x00000000,
- 0x03008015, 0x00000000,
- 0x86008015, 0x00000000,
- 0x82000015, 0x00008000,
- 0x0100001c, 0x00000000,
- 0x000050a0, 0x0000010c,
- 0x4e20d011, 0x00006008,
- 0x1420d012, 0x00004008,
- 0x0000f090, 0x00007000,
- 0x0000c8b0, 0x00003000,
- 0x00004040, 0x00000000,
- 0x00108015, 0x00000000,
- 0x00a2c150, 0x00004000,
- 0x00a400b0, 0x00000014,
- 0x00000020, 0x00000000,
- 0x2500400d, 0x00002525,
- 0x00047220, 0x00003100,
- 0x00934070, 0x00000000,
- 0x00000020, 0x00000000,
- 0x00924460, 0x00000184,
- 0x2b20c011, 0x00000000,
- 0x0000c420, 0x00000540,
- 0x36014018, 0x0000422d,
- 0x14200011, 0x00000000,
- 0x00924460, 0x00000183,
- 0x3200001f, 0x00000034,
- 0x02ac0015, 0x00000002,
- 0x00a60110, 0x00000008,
- 0x42200011, 0x00000000,
- 0x00924060, 0x00000103,
- 0x0000001e, 0x00000000,
- 0x00000020, 0x00000100,
- 0x0000001e, 0x00000000,
- 0x00924460, 0x00000086,
- 0x00004080, 0x00000000,
- 0x0092c070, 0x00000000,
- 0x00924060, 0x00000100,
- 0x0000c890, 0x00005000,
- 0x00a6c110, 0x00000000,
- 0x00b0c090, 0x00000012,
- 0x021c0015, 0x00000000,
- 0x3200001f, 0x00000034,
- 0x00924460, 0x00000510,
- 0x44210011, 0x00000000,
- 0x42000011, 0x00000000,
- 0x83000015, 0x00000040,
- 0x00924460, 0x00000508,
- 0x45014018, 0x00004545,
- 0x00808050, 0x00000000,
- 0x62208012, 0x00000000,
- 0x82000015, 0x00000800,
- 0x15200011, 0x00000000,
- 0x00000010, 0x00000000,
- 0x00000010, 0x00000000,
- 0x00000010, 0x00000000,
- 0x00000010, 0x00000000,
- 0x00000010, 0x00000000,
- 0x80000015, 0x0000eea4,
- 0x81000015, 0x0000005f,
- 0x00000060, 0x00000000,
- 0x00004120, 0x00000000,
- 0x00004a00, 0x00004000,
- 0x00924460, 0x00000190,
- 0x5601401a, 0x00005956,
- 0x14000011, 0x00000000,
- 0x00934050, 0x00000018,
- 0x00930050, 0x00000018,
- 0x3601403a, 0x0000002d,
- 0x000643a9, 0x00000000,
- 0x0000c420, 0x00000140,
- 0x5601401a, 0x00005956,
- 0x14000011, 0x00000000,
- 0x00000010, 0x00000000,
- 0x00000010, 0x00000000,
- 0x000642a9, 0x00000000,
- 0x00024420, 0x00000183,
- 0x5601401a, 0x00005956,
- 0x82000015, 0x00002000,
- 0x15200011, 0x00000000,
- 0x82000015, 0x00000010,
- 0x15200011, 0x00000000,
- 0x82000015, 0x00000010,
- 0x15200011, 0x00000000,
-}; /* 104 Rx instructions */
-#define FIRMWARE_RX_SIZE 104
-
-static const u32 firmware_tx[] = {
- 0x010003dc, 0x00000000,
- 0x04000421, 0x00000086,
- 0x80000015, 0x0000180e,
- 0x81000015, 0x00006664,
- 0x1a0040ab, 0x00000b06,
- 0x14200011, 0x00000000,
- 0x14204022, 0x0000aaaa,
- 0x14204022, 0x00000300,
- 0x14204022, 0x00000000,
- 0x1a0040ab, 0x00000b14,
- 0x14200011, 0x00000000,
- 0x83000015, 0x00000002,
- 0x04000021, 0x00000000,
- 0x00000010, 0x00000000,
- 0x04000421, 0x00000087,
- 0x00000010, 0x00000000,
- 0x00000010, 0x00000000,
- 0x00008015, 0x00000000,
- 0x0000003e, 0x00000000,
- 0x00000010, 0x00000000,
- 0x82000015, 0x00004000,
- 0x009e8050, 0x00000000,
- 0x03008015, 0x00000000,
- 0x86008015, 0x00000000,
- 0x82000015, 0x00008000,
- 0x0100001c, 0x00000000,
- 0x000050a0, 0x0000010c,
- 0x4e20d011, 0x00006008,
- 0x1420d012, 0x00004008,
- 0x0000f090, 0x00007000,
- 0x0000c8b0, 0x00003000,
- 0x00004040, 0x00000000,
- 0x00108015, 0x00000000,
- 0x00a2c150, 0x00004000,
- 0x00a400b0, 0x00000014,
- 0x00000020, 0x00000000,
- 0x2500400d, 0x00002525,
- 0x00047220, 0x00003100,
- 0x00934070, 0x00000000,
- 0x00000020, 0x00000000,
- 0x00924460, 0x00000184,
- 0x2b20c011, 0x00000000,
- 0x0000c420, 0x00000540,
- 0x36014018, 0x0000422d,
- 0x14200011, 0x00000000,
- 0x00924460, 0x00000183,
- 0x3200001f, 0x00000034,
- 0x02ac0015, 0x00000002,
- 0x00a60110, 0x00000008,
- 0x42200011, 0x00000000,
- 0x00924060, 0x00000103,
- 0x0000001e, 0x00000000,
- 0x00000020, 0x00000100,
- 0x0000001e, 0x00000000,
- 0x00924460, 0x00000086,
- 0x00004080, 0x00000000,
- 0x0092c070, 0x00000000,
- 0x00924060, 0x00000100,
- 0x0000c890, 0x00005000,
- 0x00a6c110, 0x00000000,
- 0x00b0c090, 0x00000012,
- 0x021c0015, 0x00000000,
- 0x3200001f, 0x00000034,
- 0x00924460, 0x00000510,
- 0x44210011, 0x00000000,
- 0x42000011, 0x00000000,
- 0x83000015, 0x00000040,
- 0x00924460, 0x00000508,
- 0x45014018, 0x00004545,
- 0x00808050, 0x00000000,
- 0x62208012, 0x00000000,
- 0x82000015, 0x00000800,
- 0x15200011, 0x00000000,
- 0x00000010, 0x00000000,
- 0x00000010, 0x00000000,
- 0x00000010, 0x00000000,
- 0x00000010, 0x00000000,
- 0x00000010, 0x00000000,
- 0x80000015, 0x0000eea4,
- 0x81000015, 0x0000005f,
- 0x00000060, 0x00000000,
- 0x00004120, 0x00000000,
- 0x00004a00, 0x00004000,
- 0x00924460, 0x00000190,
- 0x5601401a, 0x00005956,
- 0x14000011, 0x00000000,
- 0x00934050, 0x00000018,
- 0x00930050, 0x00000018,
- 0x3601403a, 0x0000002d,
- 0x000643a9, 0x00000000,
- 0x0000c420, 0x00000140,
- 0x5601401a, 0x00005956,
- 0x14000011, 0x00000000,
- 0x00000010, 0x00000000,
- 0x00000010, 0x00000000,
- 0x000642a9, 0x00000000,
- 0x00024420, 0x00000183,
- 0x5601401a, 0x00005956,
- 0x82000015, 0x00002000,
- 0x15200011, 0x00000000,
- 0x82000015, 0x00000010,
- 0x15200011, 0x00000000,
- 0x82000015, 0x00000010,
- 0x15200011, 0x00000000,
-}; /* 104 Tx instructions */
-#define FIRMWARE_TX_SIZE 104
-#if 0
-static const u32 firmware_wol[] = {
- 0x010003dc, 0x00000000,
- 0x19000421, 0x00000087,
- 0x80000015, 0x00001a1a,
- 0x81000015, 0x00001a1a,
- 0x1a0040ab, 0x00000b06,
- 0x15200011, 0x00000000,
- 0x15204022, 0x0000aaaa,
- 0x15204022, 0x00000300,
- 0x15204022, 0x00000000,
- 0x1a0040ab, 0x00000b15,
- 0x15200011, 0x00000000,
- 0x83000015, 0x00000002,
- 0x04000021, 0x00000000,
- 0x00000010, 0x00000000,
- 0x04000421, 0x00000087,
- 0x00000010, 0x00000000,
- 0x00000010, 0x00000000,
- 0x00008015, 0x00000000,
- 0x0000003e, 0x00000000,
- 0x00000010, 0x00000000,
- 0x00000010, 0x00000000,
- 0x82000015, 0x00004000,
- 0x82000015, 0x00008000,
- 0x0000000c, 0x00000000,
- 0x00000010, 0x00000000,
- 0x00004080, 0x00000100,
- 0x1f20c011, 0x00001122,
- 0x2720f011, 0x00003011,
- 0x19200071, 0x00000000,
- 0x1a200051, 0x00000000,
- 0x00000010, 0x00000000,
- 0x00000010, 0x00000000,
- 0x1d2040a4, 0x00003344,
- 0x1d2040a2, 0x00005566,
- 0x000040a0, 0x00000100,
- 0x00108050, 0x00000001,
- 0x1a208012, 0x00000006,
- 0x82000015, 0x00008080,
- 0x010003dc, 0x00000000,
- 0x1d2040a4, 0x00002233,
- 0x1d2040a4, 0x00004455,
- 0x2d208011, 0x00000005,
- 0x1d2040a4, 0x00006611,
- 0x00108050, 0x00000001,
- 0x27200011, 0x00000000,
- 0x1d2050a4, 0x00006600,
- 0x82000015, 0x00008080,
- 0x010003dc, 0x00000000,
- 0x00000050, 0x00000000,
- 0x1b200031, 0x00000000,
- 0x0000001e, 0x00000000,
- 0x0000001e, 0x00000000,
- 0x0000001e, 0x00000000,
- 0x0000001e, 0x00000000,
- 0x00924460, 0x00000086,
- 0x00004080, 0x00000000,
- 0x0092c070, 0x00000000,
- 0x00924060, 0x00000100,
- 0x0000c890, 0x00005000,
- 0x00a6c110, 0x00000000,
- 0x00b0c090, 0x00000012,
- 0x021c0015, 0x00000000,
- 0x3200001f, 0x00000034,
- 0x00924460, 0x00000510,
- 0x44210011, 0x00000000,
- 0x42000011, 0x00000000,
- 0x83000015, 0x00000040,
- 0x00924460, 0x00000508,
- 0x476a0012, 0x00000100,
- 0x83000015, 0x00000008,
- 0x16200011, 0x00000000,
- 0x001e8050, 0x00000000,
- 0x001e8050, 0x00000000,
- 0x00808050, 0x00000000,
- 0x03008015, 0x00000000,
- 0x62208012, 0x00000000,
- 0x82000015, 0x00000800,
- 0x16200011, 0x00000000,
- 0x80000015, 0x0000eea4,
- 0x81000015, 0x0000005f,
- 0x00000020, 0x00000000,
- 0x00004120, 0x00000000,
- 0x00004a00, 0x00004000,
- 0x00924460, 0x00000190,
- 0x5c01401a, 0x0000595c,
- 0x15000011, 0x00000000,
- 0x00934050, 0x00000018,
- 0x00930050, 0x00000018,
- 0x3601403a, 0x0000002d,
- 0x00064029, 0x00000000,
- 0x0000c420, 0x00000140,
- 0x5c01401a, 0x0000595c,
- 0x15000011, 0x00000000,
- 0x00000010, 0x00000000,
- 0x00000010, 0x00000000,
- 0x00064029, 0x00000000,
- 0x00024420, 0x00000183,
- 0x5c01401a, 0x0000595c,
- 0x82000015, 0x00002000,
- 0x16200011, 0x00000000,
- 0x82000015, 0x00000010,
- 0x16200011, 0x00000000,
- 0x82000015, 0x00000010,
- 0x16200011, 0x00000000,
-}; /* 104 WoL instructions */
-#define FIRMWARE_WOL_SIZE 104
-#endif
diff --git a/drivers/net/starfire_firmware.pl b/drivers/net/starfire_firmware.pl
deleted file mode 100644
index 0c82b80e1074..000000000000
--- a/drivers/net/starfire_firmware.pl
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/perl
-
-# This script can be used to generate a new starfire_firmware.h
-# from GFP_RX.DAT and GFP_TX.DAT, files included with the DDK
-# and also with the Novell drivers.
-
-open FW, "GFP_RX.DAT" || die;
-open FWH, ">starfire_firmware.h" || die;
-
-printf(FWH "static u32 firmware_rx[] = {\n");
-$counter = 0;
-while ($foo = <FW>) {
- chomp;
- printf(FWH " 0x%s, 0x0000%s,\n", substr($foo, 4, 8), substr($foo, 0, 4));
- $counter++;
-}
-
-close FW;
-open FW, "GFP_TX.DAT" || die;
-
-printf(FWH "};\t/* %d Rx instructions */\n#define FIRMWARE_RX_SIZE %d\n\nstatic u32 firmware_tx[] = {\n", $counter, $counter);
-$counter = 0;
-while ($foo = <FW>) {
- chomp;
- printf(FWH " 0x%s, 0x0000%s,\n", substr($foo, 4, 8), substr($foo, 0, 4));
- $counter++;
-}
-
-close FW;
-printf(FWH "};\t/* %d Tx instructions */\n#define FIRMWARE_TX_SIZE %d\n", $counter, $counter);
-close(FWH);
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 04ae1e86aeaa..5e2dbaee125b 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -40,6 +40,7 @@
#include <linux/workqueue.h>
#include <linux/prefetch.h>
#include <linux/dma-mapping.h>
+#include <linux/firmware.h>
#include <net/checksum.h>
#include <net/ip.h>
@@ -137,6 +138,10 @@
#define TG3_NUM_TEST 6
+#define FIRMWARE_TG3 "tigon/tg3.bin"
+#define FIRMWARE_TG3TSO "tigon/tg3_tso.bin"
+#define FIRMWARE_TG3TSO5 "tigon/tg3_tso5.bin"
+
static char version[] __devinitdata =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -144,6 +149,10 @@ MODULE_AUTHOR("David S. Miller (davem@redhat.com) and Jeff Garzik (jgarzik@pobox
MODULE_DESCRIPTION("Broadcom Tigon3 ethernet driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
+MODULE_FIRMWARE(FIRMWARE_TG3);
+MODULE_FIRMWARE(FIRMWARE_TG3TSO);
+MODULE_FIRMWARE(FIRMWARE_TG3TSO5);
+
static int tg3_debug = -1; /* -1 == use TG3_DEF_MSG_ENABLE as value */
module_param(tg3_debug, int, 0);
@@ -6205,130 +6214,6 @@ static int tg3_halt(struct tg3 *tp, int kind, int silent)
return 0;
}
-#define TG3_FW_RELEASE_MAJOR 0x0
-#define TG3_FW_RELASE_MINOR 0x0
-#define TG3_FW_RELEASE_FIX 0x0
-#define TG3_FW_START_ADDR 0x08000000
-#define TG3_FW_TEXT_ADDR 0x08000000
-#define TG3_FW_TEXT_LEN 0x9c0
-#define TG3_FW_RODATA_ADDR 0x080009c0
-#define TG3_FW_RODATA_LEN 0x60
-#define TG3_FW_DATA_ADDR 0x08000a40
-#define TG3_FW_DATA_LEN 0x20
-#define TG3_FW_SBSS_ADDR 0x08000a60
-#define TG3_FW_SBSS_LEN 0xc
-#define TG3_FW_BSS_ADDR 0x08000a70
-#define TG3_FW_BSS_LEN 0x10
-
-static const u32 tg3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = {
- 0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c1d0800,
- 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100000, 0x0e000018, 0x00000000,
- 0x0000000d, 0x3c1d0800, 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100034,
- 0x0e00021c, 0x00000000, 0x0000000d, 0x00000000, 0x00000000, 0x00000000,
- 0x27bdffe0, 0x3c1cc000, 0xafbf0018, 0xaf80680c, 0x0e00004c, 0x241b2105,
- 0x97850000, 0x97870002, 0x9782002c, 0x9783002e, 0x3c040800, 0x248409c0,
- 0xafa00014, 0x00021400, 0x00621825, 0x00052c00, 0xafa30010, 0x8f860010,
- 0x00e52825, 0x0e000060, 0x24070102, 0x3c02ac00, 0x34420100, 0x3c03ac01,
- 0x34630100, 0xaf820490, 0x3c02ffff, 0xaf820494, 0xaf830498, 0xaf82049c,
- 0x24020001, 0xaf825ce0, 0x0e00003f, 0xaf825d00, 0x0e000140, 0x00000000,
- 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x2402ffff, 0xaf825404, 0x8f835400,
- 0x34630400, 0xaf835400, 0xaf825404, 0x3c020800, 0x24420034, 0xaf82541c,
- 0x03e00008, 0xaf805400, 0x00000000, 0x00000000, 0x3c020800, 0x34423000,
- 0x3c030800, 0x34633000, 0x3c040800, 0x348437ff, 0x3c010800, 0xac220a64,
- 0x24020040, 0x3c010800, 0xac220a68, 0x3c010800, 0xac200a60, 0xac600000,
- 0x24630004, 0x0083102b, 0x5040fffd, 0xac600000, 0x03e00008, 0x00000000,
- 0x00804821, 0x8faa0010, 0x3c020800, 0x8c420a60, 0x3c040800, 0x8c840a68,
- 0x8fab0014, 0x24430001, 0x0044102b, 0x3c010800, 0xac230a60, 0x14400003,
- 0x00004021, 0x3c010800, 0xac200a60, 0x3c020800, 0x8c420a60, 0x3c030800,
- 0x8c630a64, 0x91240000, 0x00021140, 0x00431021, 0x00481021, 0x25080001,
- 0xa0440000, 0x29020008, 0x1440fff4, 0x25290001, 0x3c020800, 0x8c420a60,
- 0x3c030800, 0x8c630a64, 0x8f84680c, 0x00021140, 0x00431021, 0xac440008,
- 0xac45000c, 0xac460010, 0xac470014, 0xac4a0018, 0x03e00008, 0xac4b001c,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,
- 0x02000008, 0x00000000, 0x0a0001e3, 0x3c0a0001, 0x0a0001e3, 0x3c0a0002,
- 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000,
- 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000,
- 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000,
- 0x0a0001e3, 0x3c0a0007, 0x0a0001e3, 0x3c0a0008, 0x0a0001e3, 0x3c0a0009,
- 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x3c0a000b,
- 0x0a0001e3, 0x3c0a000c, 0x0a0001e3, 0x3c0a000d, 0x0a0001e3, 0x00000000,
- 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x3c0a000e, 0x0a0001e3, 0x00000000,
- 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000,
- 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x00000000,
- 0x0a0001e3, 0x00000000, 0x0a0001e3, 0x3c0a0013, 0x0a0001e3, 0x3c0a0014,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0x27bdffe0, 0x00001821, 0x00001021, 0xafbf0018, 0xafb10014, 0xafb00010,
- 0x3c010800, 0x00220821, 0xac200a70, 0x3c010800, 0x00220821, 0xac200a74,
- 0x3c010800, 0x00220821, 0xac200a78, 0x24630001, 0x1860fff5, 0x2442000c,
- 0x24110001, 0x8f906810, 0x32020004, 0x14400005, 0x24040001, 0x3c020800,
- 0x8c420a78, 0x18400003, 0x00002021, 0x0e000182, 0x00000000, 0x32020001,
- 0x10400003, 0x00000000, 0x0e000169, 0x00000000, 0x0a000153, 0xaf915028,
- 0x8fbf0018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020, 0x3c050800,
- 0x8ca50a70, 0x3c060800, 0x8cc60a80, 0x3c070800, 0x8ce70a78, 0x27bdffe0,
- 0x3c040800, 0x248409d0, 0xafbf0018, 0xafa00010, 0x0e000060, 0xafa00014,
- 0x0e00017b, 0x00002021, 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x24020001,
- 0x8f836810, 0x00821004, 0x00021027, 0x00621824, 0x03e00008, 0xaf836810,
- 0x27bdffd8, 0xafbf0024, 0x1080002e, 0xafb00020, 0x8f825cec, 0xafa20018,
- 0x8f825cec, 0x3c100800, 0x26100a78, 0xafa2001c, 0x34028000, 0xaf825cec,
- 0x8e020000, 0x18400016, 0x00000000, 0x3c020800, 0x94420a74, 0x8fa3001c,
- 0x000221c0, 0xac830004, 0x8fa2001c, 0x3c010800, 0x0e000201, 0xac220a74,
- 0x10400005, 0x00000000, 0x8e020000, 0x24420001, 0x0a0001df, 0xae020000,
- 0x3c020800, 0x8c420a70, 0x00021c02, 0x000321c0, 0x0a0001c5, 0xafa2001c,
- 0x0e000201, 0x00000000, 0x1040001f, 0x00000000, 0x8e020000, 0x8fa3001c,
- 0x24420001, 0x3c010800, 0xac230a70, 0x3c010800, 0xac230a74, 0x0a0001df,
- 0xae020000, 0x3c100800, 0x26100a78, 0x8e020000, 0x18400028, 0x00000000,
- 0x0e000201, 0x00000000, 0x14400024, 0x00000000, 0x8e020000, 0x3c030800,
- 0x8c630a70, 0x2442ffff, 0xafa3001c, 0x18400006, 0xae020000, 0x00031402,
- 0x000221c0, 0x8c820004, 0x3c010800, 0xac220a70, 0x97a2001e, 0x2442ff00,
- 0x2c420300, 0x1440000b, 0x24024000, 0x3c040800, 0x248409dc, 0xafa00010,
- 0xafa00014, 0x8fa6001c, 0x24050008, 0x0e000060, 0x00003821, 0x0a0001df,
- 0x00000000, 0xaf825cf8, 0x3c020800, 0x8c420a40, 0x8fa3001c, 0x24420001,
- 0xaf835cf8, 0x3c010800, 0xac220a40, 0x8fbf0024, 0x8fb00020, 0x03e00008,
- 0x27bd0028, 0x27bdffe0, 0x3c040800, 0x248409e8, 0x00002821, 0x00003021,
- 0x00003821, 0xafbf0018, 0xafa00010, 0x0e000060, 0xafa00014, 0x8fbf0018,
- 0x03e00008, 0x27bd0020, 0x8f82680c, 0x8f85680c, 0x00021827, 0x0003182b,
- 0x00031823, 0x00431024, 0x00441021, 0x00a2282b, 0x10a00006, 0x00000000,
- 0x00401821, 0x8f82680c, 0x0043102b, 0x1440fffd, 0x00000000, 0x03e00008,
- 0x00000000, 0x3c040800, 0x8c840000, 0x3c030800, 0x8c630a40, 0x0064102b,
- 0x54400002, 0x00831023, 0x00641023, 0x2c420008, 0x03e00008, 0x38420001,
- 0x27bdffe0, 0x00802821, 0x3c040800, 0x24840a00, 0x00003021, 0x00003821,
- 0xafbf0018, 0xafa00010, 0x0e000060, 0xafa00014, 0x0a000216, 0x00000000,
- 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x00000000, 0x27bdffe0, 0x3c1cc000,
- 0xafbf0018, 0x0e00004c, 0xaf80680c, 0x3c040800, 0x24840a10, 0x03802821,
- 0x00003021, 0x00003821, 0xafa00010, 0x0e000060, 0xafa00014, 0x2402ffff,
- 0xaf825404, 0x3c0200aa, 0x0e000234, 0xaf825434, 0x8fbf0018, 0x03e00008,
- 0x27bd0020, 0x00000000, 0x00000000, 0x00000000, 0x27bdffe8, 0xafb00010,
- 0x24100001, 0xafbf0014, 0x3c01c003, 0xac200000, 0x8f826810, 0x30422000,
- 0x10400003, 0x00000000, 0x0e000246, 0x00000000, 0x0a00023a, 0xaf905428,
- 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x27bdfff8, 0x8f845d0c,
- 0x3c0200ff, 0x3c030800, 0x8c630a50, 0x3442fff8, 0x00821024, 0x1043001e,
- 0x3c0500ff, 0x34a5fff8, 0x3c06c003, 0x3c074000, 0x00851824, 0x8c620010,
- 0x3c010800, 0xac230a50, 0x30420008, 0x10400005, 0x00871025, 0x8cc20000,
- 0x24420001, 0xacc20000, 0x00871025, 0xaf825d0c, 0x8fa20000, 0x24420001,
- 0xafa20000, 0x8fa20000, 0x8fa20000, 0x24420001, 0xafa20000, 0x8fa20000,
- 0x8f845d0c, 0x3c030800, 0x8c630a50, 0x00851024, 0x1443ffe8, 0x00851824,
- 0x27bd0008, 0x03e00008, 0x00000000, 0x00000000, 0x00000000
-};
-
-static const u32 tg3FwRodata[(TG3_FW_RODATA_LEN / sizeof(u32)) + 1] = {
- 0x35373031, 0x726c7341, 0x00000000, 0x00000000, 0x53774576, 0x656e7430,
- 0x00000000, 0x726c7045, 0x76656e74, 0x31000000, 0x556e6b6e, 0x45766e74,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x66617461, 0x6c457272,
- 0x00000000, 0x00000000, 0x4d61696e, 0x43707542, 0x00000000, 0x00000000,
- 0x00000000
-};
-
-#if 0 /* All zeros, don't eat up space with it. */
-u32 tg3FwData[(TG3_FW_DATA_LEN / sizeof(u32)) + 1] = {
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000
-};
-#endif
-
#define RX_CPU_SCRATCH_BASE 0x30000
#define RX_CPU_SCRATCH_SIZE 0x04000
#define TX_CPU_SCRATCH_BASE 0x34000
@@ -6383,15 +6268,9 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
}
struct fw_info {
- unsigned int text_base;
- unsigned int text_len;
- const u32 *text_data;
- unsigned int rodata_base;
- unsigned int rodata_len;
- const u32 *rodata_data;
- unsigned int data_base;
- unsigned int data_len;
- const u32 *data_data;
+ unsigned int fw_base;
+ unsigned int fw_len;
+ const __be32 *fw_data;
};
/* tp->lock is held. */
@@ -6428,24 +6307,11 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_b
write_op(tp, cpu_scratch_base + i, 0);
tw32(cpu_base + CPU_STATE, 0xffffffff);
tw32(cpu_base + CPU_MODE, tr32(cpu_base+CPU_MODE)|CPU_MODE_HALT);
- for (i = 0; i < (info->text_len / sizeof(u32)); i++)
- write_op(tp, (cpu_scratch_base +
- (info->text_base & 0xffff) +
- (i * sizeof(u32))),
- (info->text_data ?
- info->text_data[i] : 0));
- for (i = 0; i < (info->rodata_len / sizeof(u32)); i++)
- write_op(tp, (cpu_scratch_base +
- (info->rodata_base & 0xffff) +
- (i * sizeof(u32))),
- (info->rodata_data ?
- info->rodata_data[i] : 0));
- for (i = 0; i < (info->data_len / sizeof(u32)); i++)
+ for (i = 0; i < (info->fw_len / sizeof(u32)); i++)
write_op(tp, (cpu_scratch_base +
- (info->data_base & 0xffff) +
+ (info->fw_base & 0xffff) +
(i * sizeof(u32))),
- (info->data_data ?
- info->data_data[i] : 0));
+ be32_to_cpu(info->fw_data[i]));
err = 0;
@@ -6457,17 +6323,20 @@ out:
static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
{
struct fw_info info;
+ const __be32 *fw_data;
int err, i;
- info.text_base = TG3_FW_TEXT_ADDR;
- info.text_len = TG3_FW_TEXT_LEN;
- info.text_data = &tg3FwText[0];
- info.rodata_base = TG3_FW_RODATA_ADDR;
- info.rodata_len = TG3_FW_RODATA_LEN;
- info.rodata_data = &tg3FwRodata[0];
- info.data_base = TG3_FW_DATA_ADDR;
- info.data_len = TG3_FW_DATA_LEN;
- info.data_data = NULL;
+ fw_data = (void *)tp->fw->data;
+
+ /* Firmware blob starts with version numbers, followed by
+ start address and length. We are setting complete length.
+ length = end_address_of_bss - start_address_of_text.
+ Remainder is the blob to be loaded contiguously
+ from start address. */
+
+ info.fw_base = be32_to_cpu(fw_data[1]);
+ info.fw_len = tp->fw->size - 12;
+ info.fw_data = &fw_data[3];
err = tg3_load_firmware_cpu(tp, RX_CPU_BASE,
RX_CPU_SCRATCH_BASE, RX_CPU_SCRATCH_SIZE,
@@ -6483,21 +6352,21 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
/* Now startup only the RX cpu. */
tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
- tw32_f(RX_CPU_BASE + CPU_PC, TG3_FW_TEXT_ADDR);
+ tw32_f(RX_CPU_BASE + CPU_PC, info.fw_base);
for (i = 0; i < 5; i++) {
- if (tr32(RX_CPU_BASE + CPU_PC) == TG3_FW_TEXT_ADDR)
+ if (tr32(RX_CPU_BASE + CPU_PC) == info.fw_base)
break;
tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
tw32(RX_CPU_BASE + CPU_MODE, CPU_MODE_HALT);
- tw32_f(RX_CPU_BASE + CPU_PC, TG3_FW_TEXT_ADDR);
+ tw32_f(RX_CPU_BASE + CPU_PC, info.fw_base);
udelay(1000);
}
if (i >= 5) {
printk(KERN_ERR PFX "tg3_load_firmware fails for %s "
"to set RX CPU PC, is %08x should be %08x\n",
tp->dev->name, tr32(RX_CPU_BASE + CPU_PC),
- TG3_FW_TEXT_ADDR);
+ info.fw_base);
return -ENODEV;
}
tw32(RX_CPU_BASE + CPU_STATE, 0xffffffff);
@@ -6506,547 +6375,36 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
return 0;
}
-
-#define TG3_TSO_FW_RELEASE_MAJOR 0x1
-#define TG3_TSO_FW_RELASE_MINOR 0x6
-#define TG3_TSO_FW_RELEASE_FIX 0x0
-#define TG3_TSO_FW_START_ADDR 0x08000000
-#define TG3_TSO_FW_TEXT_ADDR 0x08000000
-#define TG3_TSO_FW_TEXT_LEN 0x1aa0
-#define TG3_TSO_FW_RODATA_ADDR 0x08001aa0
-#define TG3_TSO_FW_RODATA_LEN 0x60
-#define TG3_TSO_FW_DATA_ADDR 0x08001b20
-#define TG3_TSO_FW_DATA_LEN 0x30
-#define TG3_TSO_FW_SBSS_ADDR 0x08001b50
-#define TG3_TSO_FW_SBSS_LEN 0x2c
-#define TG3_TSO_FW_BSS_ADDR 0x08001b80
-#define TG3_TSO_FW_BSS_LEN 0x894
-
-static const u32 tg3TsoFwText[(TG3_TSO_FW_TEXT_LEN / 4) + 1] = {
- 0x0e000003, 0x00000000, 0x08001b24, 0x00000000, 0x10000003, 0x00000000,
- 0x0000000d, 0x0000000d, 0x3c1d0800, 0x37bd4000, 0x03a0f021, 0x3c100800,
- 0x26100000, 0x0e000010, 0x00000000, 0x0000000d, 0x27bdffe0, 0x3c04fefe,
- 0xafbf0018, 0x0e0005d8, 0x34840002, 0x0e000668, 0x00000000, 0x3c030800,
- 0x90631b68, 0x24020002, 0x3c040800, 0x24841aac, 0x14620003, 0x24050001,
- 0x3c040800, 0x24841aa0, 0x24060006, 0x00003821, 0xafa00010, 0x0e00067c,
- 0xafa00014, 0x8f625c50, 0x34420001, 0xaf625c50, 0x8f625c90, 0x34420001,
- 0xaf625c90, 0x2402ffff, 0x0e000034, 0xaf625404, 0x8fbf0018, 0x03e00008,
- 0x27bd0020, 0x00000000, 0x00000000, 0x00000000, 0x27bdffe0, 0xafbf001c,
- 0xafb20018, 0xafb10014, 0x0e00005b, 0xafb00010, 0x24120002, 0x24110001,
- 0x8f706820, 0x32020100, 0x10400003, 0x00000000, 0x0e0000bb, 0x00000000,
- 0x8f706820, 0x32022000, 0x10400004, 0x32020001, 0x0e0001f0, 0x24040001,
- 0x32020001, 0x10400003, 0x00000000, 0x0e0000a3, 0x00000000, 0x3c020800,
- 0x90421b98, 0x14520003, 0x00000000, 0x0e0004c0, 0x00000000, 0x0a00003c,
- 0xaf715028, 0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x03e00008,
- 0x27bd0020, 0x27bdffe0, 0x3c040800, 0x24841ac0, 0x00002821, 0x00003021,
- 0x00003821, 0xafbf0018, 0xafa00010, 0x0e00067c, 0xafa00014, 0x3c040800,
- 0x248423d8, 0xa4800000, 0x3c010800, 0xa0201b98, 0x3c010800, 0xac201b9c,
- 0x3c010800, 0xac201ba0, 0x3c010800, 0xac201ba4, 0x3c010800, 0xac201bac,
- 0x3c010800, 0xac201bb8, 0x3c010800, 0xac201bbc, 0x8f624434, 0x3c010800,
- 0xac221b88, 0x8f624438, 0x3c010800, 0xac221b8c, 0x8f624410, 0xac80f7a8,
- 0x3c010800, 0xac201b84, 0x3c010800, 0xac2023e0, 0x3c010800, 0xac2023c8,
- 0x3c010800, 0xac2023cc, 0x3c010800, 0xac202400, 0x3c010800, 0xac221b90,
- 0x8f620068, 0x24030007, 0x00021702, 0x10430005, 0x00000000, 0x8f620068,
- 0x00021702, 0x14400004, 0x24020001, 0x3c010800, 0x0a000097, 0xac20240c,
- 0xac820034, 0x3c040800, 0x24841acc, 0x3c050800, 0x8ca5240c, 0x00003021,
- 0x00003821, 0xafa00010, 0x0e00067c, 0xafa00014, 0x8fbf0018, 0x03e00008,
- 0x27bd0020, 0x27bdffe0, 0x3c040800, 0x24841ad8, 0x00002821, 0x00003021,
- 0x00003821, 0xafbf0018, 0xafa00010, 0x0e00067c, 0xafa00014, 0x0e00005b,
- 0x00000000, 0x0e0000b4, 0x00002021, 0x8fbf0018, 0x03e00008, 0x27bd0020,
- 0x24020001, 0x8f636820, 0x00821004, 0x00021027, 0x00621824, 0x03e00008,
- 0xaf636820, 0x27bdffd0, 0xafbf002c, 0xafb60028, 0xafb50024, 0xafb40020,
- 0xafb3001c, 0xafb20018, 0xafb10014, 0xafb00010, 0x8f675c5c, 0x3c030800,
- 0x24631bbc, 0x8c620000, 0x14470005, 0x3c0200ff, 0x3c020800, 0x90421b98,
- 0x14400119, 0x3c0200ff, 0x3442fff8, 0x00e28824, 0xac670000, 0x00111902,
- 0x306300ff, 0x30e20003, 0x000211c0, 0x00622825, 0x00a04021, 0x00071602,
- 0x3c030800, 0x90631b98, 0x3044000f, 0x14600036, 0x00804821, 0x24020001,
- 0x3c010800, 0xa0221b98, 0x00051100, 0x00821025, 0x3c010800, 0xac201b9c,
- 0x3c010800, 0xac201ba0, 0x3c010800, 0xac201ba4, 0x3c010800, 0xac201bac,
- 0x3c010800, 0xac201bb8, 0x3c010800, 0xac201bb0, 0x3c010800, 0xac201bb4,
- 0x3c010800, 0xa42223d8, 0x9622000c, 0x30437fff, 0x3c010800, 0xa4222410,
- 0x30428000, 0x3c010800, 0xa4231bc6, 0x10400005, 0x24020001, 0x3c010800,
- 0xac2223f4, 0x0a000102, 0x2406003e, 0x24060036, 0x3c010800, 0xac2023f4,
- 0x9622000a, 0x3c030800, 0x94631bc6, 0x3c010800, 0xac2023f0, 0x3c010800,
- 0xac2023f8, 0x00021302, 0x00021080, 0x00c21021, 0x00621821, 0x3c010800,
- 0xa42223d0, 0x3c010800, 0x0a000115, 0xa4231b96, 0x9622000c, 0x3c010800,
- 0xa42223ec, 0x3c040800, 0x24841b9c, 0x8c820000, 0x00021100, 0x3c010800,
- 0x00220821, 0xac311bc8, 0x8c820000, 0x00021100, 0x3c010800, 0x00220821,
- 0xac271bcc, 0x8c820000, 0x25030001, 0x306601ff, 0x00021100, 0x3c010800,
- 0x00220821, 0xac261bd0, 0x8c820000, 0x00021100, 0x3c010800, 0x00220821,
- 0xac291bd4, 0x96230008, 0x3c020800, 0x8c421bac, 0x00432821, 0x3c010800,
- 0xac251bac, 0x9622000a, 0x30420004, 0x14400018, 0x00061100, 0x8f630c14,
- 0x3063000f, 0x2c620002, 0x1440000b, 0x3c02c000, 0x8f630c14, 0x3c020800,
- 0x8c421b40, 0x3063000f, 0x24420001, 0x3c010800, 0xac221b40, 0x2c620002,
- 0x1040fff7, 0x3c02c000, 0x00e21825, 0xaf635c5c, 0x8f625c50, 0x30420002,
- 0x10400014, 0x00000000, 0x0a000147, 0x00000000, 0x3c030800, 0x8c631b80,
- 0x3c040800, 0x94841b94, 0x01221025, 0x3c010800, 0xa42223da, 0x24020001,
- 0x3c010800, 0xac221bb8, 0x24630001, 0x0085202a, 0x3c010800, 0x10800003,
- 0xac231b80, 0x3c010800, 0xa4251b94, 0x3c060800, 0x24c61b9c, 0x8cc20000,
- 0x24420001, 0xacc20000, 0x28420080, 0x14400005, 0x00000000, 0x0e000656,
- 0x24040002, 0x0a0001e6, 0x00000000, 0x3c020800, 0x8c421bb8, 0x10400078,
- 0x24020001, 0x3c050800, 0x90a51b98, 0x14a20072, 0x00000000, 0x3c150800,
- 0x96b51b96, 0x3c040800, 0x8c841bac, 0x32a3ffff, 0x0083102a, 0x1440006c,
- 0x00000000, 0x14830003, 0x00000000, 0x3c010800, 0xac2523f0, 0x1060005c,
- 0x00009021, 0x24d60004, 0x0060a021, 0x24d30014, 0x8ec20000, 0x00028100,
- 0x3c110800, 0x02308821, 0x0e000625, 0x8e311bc8, 0x00402821, 0x10a00054,
- 0x00000000, 0x9628000a, 0x31020040, 0x10400005, 0x2407180c, 0x8e22000c,
- 0x2407188c, 0x00021400, 0xaca20018, 0x3c030800, 0x00701821, 0x8c631bd0,
- 0x3c020800, 0x00501021, 0x8c421bd4, 0x00031d00, 0x00021400, 0x00621825,
- 0xaca30014, 0x8ec30004, 0x96220008, 0x00432023, 0x3242ffff, 0x3083ffff,
- 0x00431021, 0x0282102a, 0x14400002, 0x02b23023, 0x00803021, 0x8e620000,
- 0x30c4ffff, 0x00441021, 0xae620000, 0x8e220000, 0xaca20000, 0x8e220004,
- 0x8e63fff4, 0x00431021, 0xaca20004, 0xa4a6000e, 0x8e62fff4, 0x00441021,
- 0xae62fff4, 0x96230008, 0x0043102a, 0x14400005, 0x02469021, 0x8e62fff0,
- 0xae60fff4, 0x24420001, 0xae62fff0, 0xaca00008, 0x3242ffff, 0x14540008,
- 0x24020305, 0x31020080, 0x54400001, 0x34e70010, 0x24020905, 0xa4a2000c,
- 0x0a0001cb, 0x34e70020, 0xa4a2000c, 0x3c020800, 0x8c4223f0, 0x10400003,
- 0x3c024b65, 0x0a0001d3, 0x34427654, 0x3c02b49a, 0x344289ab, 0xaca2001c,
- 0x30e2ffff, 0xaca20010, 0x0e0005a2, 0x00a02021, 0x3242ffff, 0x0054102b,
- 0x1440ffa9, 0x00000000, 0x24020002, 0x3c010800, 0x0a0001e6, 0xa0221b98,
- 0x8ec2083c, 0x24420001, 0x0a0001e6, 0xaec2083c, 0x0e0004c0, 0x00000000,
- 0x8fbf002c, 0x8fb60028, 0x8fb50024, 0x8fb40020, 0x8fb3001c, 0x8fb20018,
- 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0030, 0x27bdffd0, 0xafbf0028,
- 0xafb30024, 0xafb20020, 0xafb1001c, 0xafb00018, 0x8f725c9c, 0x3c0200ff,
- 0x3442fff8, 0x3c070800, 0x24e71bb4, 0x02428824, 0x9623000e, 0x8ce20000,
- 0x00431021, 0xace20000, 0x8e220010, 0x30420020, 0x14400011, 0x00809821,
- 0x0e00063b, 0x02202021, 0x3c02c000, 0x02421825, 0xaf635c9c, 0x8f625c90,
- 0x30420002, 0x1040011e, 0x00000000, 0xaf635c9c, 0x8f625c90, 0x30420002,
- 0x10400119, 0x00000000, 0x0a00020d, 0x00000000, 0x8e240008, 0x8e230014,
- 0x00041402, 0x000231c0, 0x00031502, 0x304201ff, 0x2442ffff, 0x3042007f,
- 0x00031942, 0x30637800, 0x00021100, 0x24424000, 0x00624821, 0x9522000a,
- 0x3084ffff, 0x30420008, 0x104000b0, 0x000429c0, 0x3c020800, 0x8c422400,
- 0x14400024, 0x24c50008, 0x94c20014, 0x3c010800, 0xa42223d0, 0x8cc40010,
- 0x00041402, 0x3c010800, 0xa42223d2, 0x3c010800, 0xa42423d4, 0x94c2000e,
- 0x3083ffff, 0x00431023, 0x3c010800, 0xac222408, 0x94c2001a, 0x3c010800,
- 0xac262400, 0x3c010800, 0xac322404, 0x3c010800, 0xac2223fc, 0x3c02c000,
- 0x02421825, 0xaf635c9c, 0x8f625c90, 0x30420002, 0x104000e5, 0x00000000,
- 0xaf635c9c, 0x8f625c90, 0x30420002, 0x104000e0, 0x00000000, 0x0a000246,
- 0x00000000, 0x94c2000e, 0x3c030800, 0x946323d4, 0x00434023, 0x3103ffff,
- 0x2c620008, 0x1040001c, 0x00000000, 0x94c20014, 0x24420028, 0x00a22821,
- 0x00031042, 0x1840000b, 0x00002021, 0x24e60848, 0x00403821, 0x94a30000,
- 0x8cc20000, 0x24840001, 0x00431021, 0xacc20000, 0x0087102a, 0x1440fff9,
- 0x24a50002, 0x31020001, 0x1040001f, 0x3c024000, 0x3c040800, 0x248423fc,
- 0xa0a00001, 0x94a30000, 0x8c820000, 0x00431021, 0x0a000285, 0xac820000,
- 0x8f626800, 0x3c030010, 0x00431024, 0x10400009, 0x00000000, 0x94c2001a,
- 0x3c030800, 0x8c6323fc, 0x00431021, 0x3c010800, 0xac2223fc, 0x0a000286,
- 0x3c024000, 0x94c2001a, 0x94c4001c, 0x3c030800, 0x8c6323fc, 0x00441023,
- 0x00621821, 0x3c010800, 0xac2323fc, 0x3c024000, 0x02421825, 0xaf635c9c,
- 0x8f625c90, 0x30420002, 0x1440fffc, 0x00000000, 0x9522000a, 0x30420010,
- 0x1040009b, 0x00000000, 0x3c030800, 0x946323d4, 0x3c070800, 0x24e72400,
- 0x8ce40000, 0x8f626800, 0x24630030, 0x00832821, 0x3c030010, 0x00431024,
- 0x1440000a, 0x00000000, 0x94a20004, 0x3c040800, 0x8c842408, 0x3c030800,
- 0x8c6323fc, 0x00441023, 0x00621821, 0x3c010800, 0xac2323fc, 0x3c040800,
- 0x8c8423fc, 0x00041c02, 0x3082ffff, 0x00622021, 0x00041402, 0x00822021,
- 0x00041027, 0xa4a20006, 0x3c030800, 0x8c632404, 0x3c0200ff, 0x3442fff8,
- 0x00628824, 0x96220008, 0x24050001, 0x24034000, 0x000231c0, 0x00801021,
- 0xa4c2001a, 0xa4c0001c, 0xace00000, 0x3c010800, 0xac251b60, 0xaf635cb8,
- 0x8f625cb0, 0x30420002, 0x10400003, 0x00000000, 0x3c010800, 0xac201b60,
- 0x8e220008, 0xaf625cb8, 0x8f625cb0, 0x30420002, 0x10400003, 0x00000000,
- 0x3c010800, 0xac201b60, 0x3c020800, 0x8c421b60, 0x1040ffec, 0x00000000,
- 0x3c040800, 0x0e00063b, 0x8c842404, 0x0a00032a, 0x00000000, 0x3c030800,
- 0x90631b98, 0x24020002, 0x14620003, 0x3c034b65, 0x0a0002e1, 0x00008021,
- 0x8e22001c, 0x34637654, 0x10430002, 0x24100002, 0x24100001, 0x00c02021,
- 0x0e000350, 0x02003021, 0x24020003, 0x3c010800, 0xa0221b98, 0x24020002,
- 0x1202000a, 0x24020001, 0x3c030800, 0x8c6323f0, 0x10620006, 0x00000000,
- 0x3c020800, 0x944223d8, 0x00021400, 0x0a00031f, 0xae220014, 0x3c040800,
- 0x248423da, 0x94820000, 0x00021400, 0xae220014, 0x3c020800, 0x8c421bbc,
- 0x3c03c000, 0x3c010800, 0xa0201b98, 0x00431025, 0xaf625c5c, 0x8f625c50,
- 0x30420002, 0x10400009, 0x00000000, 0x2484f7e2, 0x8c820000, 0x00431025,
- 0xaf625c5c, 0x8f625c50, 0x30420002, 0x1440fffa, 0x00000000, 0x3c020800,
- 0x24421b84, 0x8c430000, 0x24630001, 0xac430000, 0x8f630c14, 0x3063000f,
- 0x2c620002, 0x1440000c, 0x3c024000, 0x8f630c14, 0x3c020800, 0x8c421b40,
- 0x3063000f, 0x24420001, 0x3c010800, 0xac221b40, 0x2c620002, 0x1040fff7,
- 0x00000000, 0x3c024000, 0x02421825, 0xaf635c9c, 0x8f625c90, 0x30420002,
- 0x1440fffc, 0x00000000, 0x12600003, 0x00000000, 0x0e0004c0, 0x00000000,
- 0x8fbf0028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x03e00008,
- 0x27bd0030, 0x8f634450, 0x3c040800, 0x24841b88, 0x8c820000, 0x00031c02,
- 0x0043102b, 0x14400007, 0x3c038000, 0x8c840004, 0x8f624450, 0x00021c02,
- 0x0083102b, 0x1040fffc, 0x3c038000, 0xaf634444, 0x8f624444, 0x00431024,
- 0x1440fffd, 0x00000000, 0x8f624448, 0x03e00008, 0x3042ffff, 0x3c024000,
- 0x00822025, 0xaf645c38, 0x8f625c30, 0x30420002, 0x1440fffc, 0x00000000,
- 0x03e00008, 0x00000000, 0x27bdffe0, 0x00805821, 0x14c00011, 0x256e0008,
- 0x3c020800, 0x8c4223f4, 0x10400007, 0x24020016, 0x3c010800, 0xa42223d2,
- 0x2402002a, 0x3c010800, 0x0a000364, 0xa42223d4, 0x8d670010, 0x00071402,
- 0x3c010800, 0xa42223d2, 0x3c010800, 0xa42723d4, 0x3c040800, 0x948423d4,
- 0x3c030800, 0x946323d2, 0x95cf0006, 0x3c020800, 0x944223d0, 0x00832023,
- 0x01e2c023, 0x3065ffff, 0x24a20028, 0x01c24821, 0x3082ffff, 0x14c0001a,
- 0x01226021, 0x9582000c, 0x3042003f, 0x3c010800, 0xa42223d6, 0x95820004,
- 0x95830006, 0x3c010800, 0xac2023e4, 0x3c010800, 0xac2023e8, 0x00021400,
- 0x00431025, 0x3c010800, 0xac221bc0, 0x95220004, 0x3c010800, 0xa4221bc4,
- 0x95230002, 0x01e51023, 0x0043102a, 0x10400010, 0x24020001, 0x3c010800,
- 0x0a000398, 0xac2223f8, 0x3c030800, 0x8c6323e8, 0x3c020800, 0x94421bc4,
- 0x00431021, 0xa5220004, 0x3c020800, 0x94421bc0, 0xa5820004, 0x3c020800,
- 0x8c421bc0, 0xa5820006, 0x3c020800, 0x8c4223f0, 0x3c0d0800, 0x8dad23e4,
- 0x3c0a0800, 0x144000e5, 0x8d4a23e8, 0x3c020800, 0x94421bc4, 0x004a1821,
- 0x3063ffff, 0x0062182b, 0x24020002, 0x10c2000d, 0x01435023, 0x3c020800,
- 0x944223d6, 0x30420009, 0x10400008, 0x00000000, 0x9582000c, 0x3042fff6,
- 0xa582000c, 0x3c020800, 0x944223d6, 0x30420009, 0x01a26823, 0x3c020800,
- 0x8c4223f8, 0x1040004a, 0x01203821, 0x3c020800, 0x944223d2, 0x00004021,
- 0xa520000a, 0x01e21023, 0xa5220002, 0x3082ffff, 0x00021042, 0x18400008,
- 0x00003021, 0x00401821, 0x94e20000, 0x25080001, 0x00c23021, 0x0103102a,
- 0x1440fffb, 0x24e70002, 0x00061c02, 0x30c2ffff, 0x00623021, 0x00061402,
- 0x00c23021, 0x00c02821, 0x00061027, 0xa522000a, 0x00003021, 0x2527000c,
- 0x00004021, 0x94e20000, 0x25080001, 0x00c23021, 0x2d020004, 0x1440fffb,
- 0x24e70002, 0x95220002, 0x00004021, 0x91230009, 0x00442023, 0x01803821,
- 0x3082ffff, 0xa4e00010, 0x00621821, 0x00021042, 0x18400010, 0x00c33021,
- 0x00404821, 0x94e20000, 0x24e70002, 0x00c23021, 0x30e2007f, 0x14400006,
- 0x25080001, 0x8d630000, 0x3c02007f, 0x3442ff80, 0x00625824, 0x25670008,
- 0x0109102a, 0x1440fff3, 0x00000000, 0x30820001, 0x10400005, 0x00061c02,
- 0xa0e00001, 0x94e20000, 0x00c23021, 0x00061c02, 0x30c2ffff, 0x00623021,
- 0x00061402, 0x00c23021, 0x0a00047d, 0x30c6ffff, 0x24020002, 0x14c20081,
- 0x00000000, 0x3c020800, 0x8c42240c, 0x14400007, 0x00000000, 0x3c020800,
- 0x944223d2, 0x95230002, 0x01e21023, 0x10620077, 0x00000000, 0x3c020800,
- 0x944223d2, 0x01e21023, 0xa5220002, 0x3c020800, 0x8c42240c, 0x1040001a,
- 0x31e3ffff, 0x8dc70010, 0x3c020800, 0x94421b96, 0x00e04021, 0x00072c02,
- 0x00aa2021, 0x00431023, 0x00823823, 0x00072402, 0x30e2ffff, 0x00823821,
- 0x00071027, 0xa522000a, 0x3102ffff, 0x3c040800, 0x948423d4, 0x00453023,
- 0x00e02821, 0x00641823, 0x006d1821, 0x00c33021, 0x00061c02, 0x30c2ffff,
- 0x0a00047d, 0x00623021, 0x01203821, 0x00004021, 0x3082ffff, 0x00021042,
- 0x18400008, 0x00003021, 0x00401821, 0x94e20000, 0x25080001, 0x00c23021,
- 0x0103102a, 0x1440fffb, 0x24e70002, 0x00061c02, 0x30c2ffff, 0x00623021,
- 0x00061402, 0x00c23021, 0x00c02821, 0x00061027, 0xa522000a, 0x00003021,
- 0x2527000c, 0x00004021, 0x94e20000, 0x25080001, 0x00c23021, 0x2d020004,
- 0x1440fffb, 0x24e70002, 0x95220002, 0x00004021, 0x91230009, 0x00442023,
- 0x01803821, 0x3082ffff, 0xa4e00010, 0x3c040800, 0x948423d4, 0x00621821,
- 0x00c33021, 0x00061c02, 0x30c2ffff, 0x00623021, 0x00061c02, 0x3c020800,
- 0x944223d0, 0x00c34821, 0x00441023, 0x00021fc2, 0x00431021, 0x00021043,
- 0x18400010, 0x00003021, 0x00402021, 0x94e20000, 0x24e70002, 0x00c23021,
- 0x30e2007f, 0x14400006, 0x25080001, 0x8d630000, 0x3c02007f, 0x3442ff80,
- 0x00625824, 0x25670008, 0x0104102a, 0x1440fff3, 0x00000000, 0x3c020800,
- 0x944223ec, 0x00c23021, 0x3122ffff, 0x00c23021, 0x00061c02, 0x30c2ffff,
- 0x00623021, 0x00061402, 0x00c23021, 0x00c04021, 0x00061027, 0xa5820010,
- 0xadc00014, 0x0a00049d, 0xadc00000, 0x8dc70010, 0x00e04021, 0x11400007,
- 0x00072c02, 0x00aa3021, 0x00061402, 0x30c3ffff, 0x00433021, 0x00061402,
- 0x00c22821, 0x00051027, 0xa522000a, 0x3c030800, 0x946323d4, 0x3102ffff,
- 0x01e21021, 0x00433023, 0x00cd3021, 0x00061c02, 0x30c2ffff, 0x00623021,
- 0x00061402, 0x00c23021, 0x00c04021, 0x00061027, 0xa5820010, 0x3102ffff,
- 0x00051c00, 0x00431025, 0xadc20010, 0x3c020800, 0x8c4223f4, 0x10400005,
- 0x2de205eb, 0x14400002, 0x25e2fff2, 0x34028870, 0xa5c20034, 0x3c030800,
- 0x246323e8, 0x8c620000, 0x24420001, 0xac620000, 0x3c040800, 0x8c8423e4,
- 0x3c020800, 0x8c421bc0, 0x3303ffff, 0x00832021, 0x00431821, 0x0062102b,
- 0x3c010800, 0xac2423e4, 0x10400003, 0x2482ffff, 0x3c010800, 0xac2223e4,
- 0x3c010800, 0xac231bc0, 0x03e00008, 0x27bd0020, 0x27bdffb8, 0x3c050800,
- 0x24a51b96, 0xafbf0044, 0xafbe0040, 0xafb7003c, 0xafb60038, 0xafb50034,
- 0xafb40030, 0xafb3002c, 0xafb20028, 0xafb10024, 0xafb00020, 0x94a90000,
- 0x3c020800, 0x944223d0, 0x3c030800, 0x8c631bb0, 0x3c040800, 0x8c841bac,
- 0x01221023, 0x0064182a, 0xa7a9001e, 0x106000be, 0xa7a20016, 0x24be0022,
- 0x97b6001e, 0x24b3001a, 0x24b70016, 0x8fc20000, 0x14400008, 0x00000000,
- 0x8fc2fff8, 0x97a30016, 0x8fc4fff4, 0x00431021, 0x0082202a, 0x148000b0,
- 0x00000000, 0x97d50818, 0x32a2ffff, 0x104000a3, 0x00009021, 0x0040a021,
- 0x00008821, 0x0e000625, 0x00000000, 0x00403021, 0x14c00007, 0x00000000,
- 0x3c020800, 0x8c4223dc, 0x24420001, 0x3c010800, 0x0a000596, 0xac2223dc,
- 0x3c100800, 0x02118021, 0x8e101bc8, 0x9608000a, 0x31020040, 0x10400005,
- 0x2407180c, 0x8e02000c, 0x2407188c, 0x00021400, 0xacc20018, 0x31020080,
- 0x54400001, 0x34e70010, 0x3c020800, 0x00511021, 0x8c421bd0, 0x3c030800,
- 0x00711821, 0x8c631bd4, 0x00021500, 0x00031c00, 0x00431025, 0xacc20014,
- 0x96040008, 0x3242ffff, 0x00821021, 0x0282102a, 0x14400002, 0x02b22823,
- 0x00802821, 0x8e020000, 0x02459021, 0xacc20000, 0x8e020004, 0x00c02021,
- 0x26310010, 0xac820004, 0x30e2ffff, 0xac800008, 0xa485000e, 0xac820010,
- 0x24020305, 0x0e0005a2, 0xa482000c, 0x3242ffff, 0x0054102b, 0x1440ffc5,
- 0x3242ffff, 0x0a00058e, 0x00000000, 0x8e620000, 0x8e63fffc, 0x0043102a,
- 0x10400067, 0x00000000, 0x8e62fff0, 0x00028900, 0x3c100800, 0x02118021,
- 0x0e000625, 0x8e101bc8, 0x00403021, 0x14c00005, 0x00000000, 0x8e62082c,
- 0x24420001, 0x0a000596, 0xae62082c, 0x9608000a, 0x31020040, 0x10400005,
- 0x2407180c, 0x8e02000c, 0x2407188c, 0x00021400, 0xacc20018, 0x3c020800,
- 0x00511021, 0x8c421bd0, 0x3c030800, 0x00711821, 0x8c631bd4, 0x00021500,
- 0x00031c00, 0x00431025, 0xacc20014, 0x8e63fff4, 0x96020008, 0x00432023,
- 0x3242ffff, 0x3083ffff, 0x00431021, 0x02c2102a, 0x10400003, 0x00802821,
- 0x97a9001e, 0x01322823, 0x8e620000, 0x30a4ffff, 0x00441021, 0xae620000,
- 0xa4c5000e, 0x8e020000, 0xacc20000, 0x8e020004, 0x8e63fff4, 0x00431021,
- 0xacc20004, 0x8e63fff4, 0x96020008, 0x00641821, 0x0062102a, 0x14400006,
- 0x02459021, 0x8e62fff0, 0xae60fff4, 0x24420001, 0x0a000571, 0xae62fff0,
- 0xae63fff4, 0xacc00008, 0x3242ffff, 0x10560003, 0x31020004, 0x10400006,
- 0x24020305, 0x31020080, 0x54400001, 0x34e70010, 0x34e70020, 0x24020905,
- 0xa4c2000c, 0x8ee30000, 0x8ee20004, 0x14620007, 0x3c02b49a, 0x8ee20860,
- 0x54400001, 0x34e70400, 0x3c024b65, 0x0a000588, 0x34427654, 0x344289ab,
- 0xacc2001c, 0x30e2ffff, 0xacc20010, 0x0e0005a2, 0x00c02021, 0x3242ffff,
- 0x0056102b, 0x1440ff9b, 0x00000000, 0x8e620000, 0x8e63fffc, 0x0043102a,
- 0x1440ff48, 0x00000000, 0x8fbf0044, 0x8fbe0040, 0x8fb7003c, 0x8fb60038,
- 0x8fb50034, 0x8fb40030, 0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020,
- 0x03e00008, 0x27bd0048, 0x27bdffe8, 0xafbf0014, 0xafb00010, 0x8f624450,
- 0x8f634410, 0x0a0005b1, 0x00808021, 0x8f626820, 0x30422000, 0x10400003,
- 0x00000000, 0x0e0001f0, 0x00002021, 0x8f624450, 0x8f634410, 0x3042ffff,
- 0x0043102b, 0x1440fff5, 0x00000000, 0x8f630c14, 0x3063000f, 0x2c620002,
- 0x1440000b, 0x00000000, 0x8f630c14, 0x3c020800, 0x8c421b40, 0x3063000f,
- 0x24420001, 0x3c010800, 0xac221b40, 0x2c620002, 0x1040fff7, 0x00000000,
- 0xaf705c18, 0x8f625c10, 0x30420002, 0x10400009, 0x00000000, 0x8f626820,
- 0x30422000, 0x1040fff8, 0x00000000, 0x0e0001f0, 0x00002021, 0x0a0005c4,
- 0x00000000, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x00000000,
- 0x00000000, 0x00000000, 0x27bdffe8, 0x3c1bc000, 0xafbf0014, 0xafb00010,
- 0xaf60680c, 0x8f626804, 0x34420082, 0xaf626804, 0x8f634000, 0x24020b50,
- 0x3c010800, 0xac221b54, 0x24020b78, 0x3c010800, 0xac221b64, 0x34630002,
- 0xaf634000, 0x0e000605, 0x00808021, 0x3c010800, 0xa0221b68, 0x304200ff,
- 0x24030002, 0x14430005, 0x00000000, 0x3c020800, 0x8c421b54, 0x0a0005f8,
- 0xac5000c0, 0x3c020800, 0x8c421b54, 0xac5000bc, 0x8f624434, 0x8f634438,
- 0x8f644410, 0x3c010800, 0xac221b5c, 0x3c010800, 0xac231b6c, 0x3c010800,
- 0xac241b58, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x3c040800,
- 0x8c870000, 0x3c03aa55, 0x3463aa55, 0x3c06c003, 0xac830000, 0x8cc20000,
- 0x14430007, 0x24050002, 0x3c0355aa, 0x346355aa, 0xac830000, 0x8cc20000,
- 0x50430001, 0x24050001, 0x3c020800, 0xac470000, 0x03e00008, 0x00a01021,
- 0x27bdfff8, 0x18800009, 0x00002821, 0x8f63680c, 0x8f62680c, 0x1043fffe,
- 0x00000000, 0x24a50001, 0x00a4102a, 0x1440fff9, 0x00000000, 0x03e00008,
- 0x27bd0008, 0x8f634450, 0x3c020800, 0x8c421b5c, 0x00031c02, 0x0043102b,
- 0x14400008, 0x3c038000, 0x3c040800, 0x8c841b6c, 0x8f624450, 0x00021c02,
- 0x0083102b, 0x1040fffc, 0x3c038000, 0xaf634444, 0x8f624444, 0x00431024,
- 0x1440fffd, 0x00000000, 0x8f624448, 0x03e00008, 0x3042ffff, 0x3082ffff,
- 0x2442e000, 0x2c422001, 0x14400003, 0x3c024000, 0x0a000648, 0x2402ffff,
- 0x00822025, 0xaf645c38, 0x8f625c30, 0x30420002, 0x1440fffc, 0x00001021,
- 0x03e00008, 0x00000000, 0x8f624450, 0x3c030800, 0x8c631b58, 0x0a000651,
- 0x3042ffff, 0x8f624450, 0x3042ffff, 0x0043102b, 0x1440fffc, 0x00000000,
- 0x03e00008, 0x00000000, 0x27bdffe0, 0x00802821, 0x3c040800, 0x24841af0,
- 0x00003021, 0x00003821, 0xafbf0018, 0xafa00010, 0x0e00067c, 0xafa00014,
- 0x0a000660, 0x00000000, 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x00000000,
- 0x00000000, 0x00000000, 0x3c020800, 0x34423000, 0x3c030800, 0x34633000,
- 0x3c040800, 0x348437ff, 0x3c010800, 0xac221b74, 0x24020040, 0x3c010800,
- 0xac221b78, 0x3c010800, 0xac201b70, 0xac600000, 0x24630004, 0x0083102b,
- 0x5040fffd, 0xac600000, 0x03e00008, 0x00000000, 0x00804821, 0x8faa0010,
- 0x3c020800, 0x8c421b70, 0x3c040800, 0x8c841b78, 0x8fab0014, 0x24430001,
- 0x0044102b, 0x3c010800, 0xac231b70, 0x14400003, 0x00004021, 0x3c010800,
- 0xac201b70, 0x3c020800, 0x8c421b70, 0x3c030800, 0x8c631b74, 0x91240000,
- 0x00021140, 0x00431021, 0x00481021, 0x25080001, 0xa0440000, 0x29020008,
- 0x1440fff4, 0x25290001, 0x3c020800, 0x8c421b70, 0x3c030800, 0x8c631b74,
- 0x8f64680c, 0x00021140, 0x00431021, 0xac440008, 0xac45000c, 0xac460010,
- 0xac470014, 0xac4a0018, 0x03e00008, 0xac4b001c, 0x00000000, 0x00000000,
-};
-
-static const u32 tg3TsoFwRodata[] = {
- 0x4d61696e, 0x43707542, 0x00000000, 0x4d61696e, 0x43707541, 0x00000000,
- 0x00000000, 0x00000000, 0x73746b6f, 0x66666c64, 0x496e0000, 0x73746b6f,
- 0x66662a2a, 0x00000000, 0x53774576, 0x656e7430, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x66617461, 0x6c457272, 0x00000000, 0x00000000,
- 0x00000000,
-};
-
-static const u32 tg3TsoFwData[] = {
- 0x00000000, 0x73746b6f, 0x66666c64, 0x5f76312e, 0x362e3000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000,
-};
-
/* 5705 needs a special version of the TSO firmware. */
-#define TG3_TSO5_FW_RELEASE_MAJOR 0x1
-#define TG3_TSO5_FW_RELASE_MINOR 0x2
-#define TG3_TSO5_FW_RELEASE_FIX 0x0
-#define TG3_TSO5_FW_START_ADDR 0x00010000
-#define TG3_TSO5_FW_TEXT_ADDR 0x00010000
-#define TG3_TSO5_FW_TEXT_LEN 0xe90
-#define TG3_TSO5_FW_RODATA_ADDR 0x00010e90
-#define TG3_TSO5_FW_RODATA_LEN 0x50
-#define TG3_TSO5_FW_DATA_ADDR 0x00010f00
-#define TG3_TSO5_FW_DATA_LEN 0x20
-#define TG3_TSO5_FW_SBSS_ADDR 0x00010f20
-#define TG3_TSO5_FW_SBSS_LEN 0x28
-#define TG3_TSO5_FW_BSS_ADDR 0x00010f50
-#define TG3_TSO5_FW_BSS_LEN 0x88
-
-static const u32 tg3Tso5FwText[(TG3_TSO5_FW_TEXT_LEN / 4) + 1] = {
- 0x0c004003, 0x00000000, 0x00010f04, 0x00000000, 0x10000003, 0x00000000,
- 0x0000000d, 0x0000000d, 0x3c1d0001, 0x37bde000, 0x03a0f021, 0x3c100001,
- 0x26100000, 0x0c004010, 0x00000000, 0x0000000d, 0x27bdffe0, 0x3c04fefe,
- 0xafbf0018, 0x0c0042e8, 0x34840002, 0x0c004364, 0x00000000, 0x3c030001,
- 0x90630f34, 0x24020002, 0x3c040001, 0x24840e9c, 0x14620003, 0x24050001,
- 0x3c040001, 0x24840e90, 0x24060002, 0x00003821, 0xafa00010, 0x0c004378,
- 0xafa00014, 0x0c00402c, 0x00000000, 0x8fbf0018, 0x03e00008, 0x27bd0020,
- 0x00000000, 0x00000000, 0x27bdffe0, 0xafbf001c, 0xafb20018, 0xafb10014,
- 0x0c0042d4, 0xafb00010, 0x3c128000, 0x24110001, 0x8f706810, 0x32020400,
- 0x10400007, 0x00000000, 0x8f641008, 0x00921024, 0x14400003, 0x00000000,
- 0x0c004064, 0x00000000, 0x3c020001, 0x90420f56, 0x10510003, 0x32020200,
- 0x1040fff1, 0x00000000, 0x0c0041b4, 0x00000000, 0x08004034, 0x00000000,
- 0x8fbf001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x03e00008, 0x27bd0020,
- 0x27bdffe0, 0x3c040001, 0x24840eb0, 0x00002821, 0x00003021, 0x00003821,
- 0xafbf0018, 0xafa00010, 0x0c004378, 0xafa00014, 0x0000d021, 0x24020130,
- 0xaf625000, 0x3c010001, 0xa4200f50, 0x3c010001, 0xa0200f57, 0x8fbf0018,
- 0x03e00008, 0x27bd0020, 0x00000000, 0x00000000, 0x3c030001, 0x24630f60,
- 0x90620000, 0x27bdfff0, 0x14400003, 0x0080c021, 0x08004073, 0x00004821,
- 0x3c022000, 0x03021024, 0x10400003, 0x24090002, 0x08004073, 0xa0600000,
- 0x24090001, 0x00181040, 0x30431f80, 0x346f8008, 0x1520004b, 0x25eb0028,
- 0x3c040001, 0x00832021, 0x8c848010, 0x3c050001, 0x24a50f7a, 0x00041402,
- 0xa0a20000, 0x3c010001, 0xa0240f7b, 0x3c020001, 0x00431021, 0x94428014,
- 0x3c010001, 0xa0220f7c, 0x3c0c0001, 0x01836021, 0x8d8c8018, 0x304200ff,
- 0x24420008, 0x000220c3, 0x24020001, 0x3c010001, 0xa0220f60, 0x0124102b,
- 0x1040000c, 0x00003821, 0x24a6000e, 0x01602821, 0x8ca20000, 0x8ca30004,
- 0x24a50008, 0x24e70001, 0xacc20000, 0xacc30004, 0x00e4102b, 0x1440fff8,
- 0x24c60008, 0x00003821, 0x3c080001, 0x25080f7b, 0x91060000, 0x3c020001,
- 0x90420f7c, 0x2503000d, 0x00c32821, 0x00461023, 0x00021fc2, 0x00431021,
- 0x00021043, 0x1840000c, 0x00002021, 0x91020001, 0x00461023, 0x00021fc2,
- 0x00431021, 0x00021843, 0x94a20000, 0x24e70001, 0x00822021, 0x00e3102a,
- 0x1440fffb, 0x24a50002, 0x00041c02, 0x3082ffff, 0x00622021, 0x00041402,
- 0x00822021, 0x3c02ffff, 0x01821024, 0x3083ffff, 0x00431025, 0x3c010001,
- 0x080040fa, 0xac220f80, 0x3c050001, 0x24a50f7c, 0x90a20000, 0x3c0c0001,
- 0x01836021, 0x8d8c8018, 0x000220c2, 0x1080000e, 0x00003821, 0x01603021,
- 0x24a5000c, 0x8ca20000, 0x8ca30004, 0x24a50008, 0x24e70001, 0xacc20000,
- 0xacc30004, 0x00e4102b, 0x1440fff8, 0x24c60008, 0x3c050001, 0x24a50f7c,
- 0x90a20000, 0x30430007, 0x24020004, 0x10620011, 0x28620005, 0x10400005,
- 0x24020002, 0x10620008, 0x000710c0, 0x080040fa, 0x00000000, 0x24020006,
- 0x1062000e, 0x000710c0, 0x080040fa, 0x00000000, 0x00a21821, 0x9463000c,
- 0x004b1021, 0x080040fa, 0xa4430000, 0x000710c0, 0x00a21821, 0x8c63000c,
- 0x004b1021, 0x080040fa, 0xac430000, 0x00a21821, 0x8c63000c, 0x004b2021,
- 0x00a21021, 0xac830000, 0x94420010, 0xa4820004, 0x95e70006, 0x3c020001,
- 0x90420f7c, 0x3c030001, 0x90630f7a, 0x00e2c823, 0x3c020001, 0x90420f7b,
- 0x24630028, 0x01e34021, 0x24420028, 0x15200012, 0x01e23021, 0x94c2000c,
- 0x3c010001, 0xa4220f78, 0x94c20004, 0x94c30006, 0x3c010001, 0xa4200f76,
- 0x3c010001, 0xa4200f72, 0x00021400, 0x00431025, 0x3c010001, 0xac220f6c,
- 0x95020004, 0x3c010001, 0x08004124, 0xa4220f70, 0x3c020001, 0x94420f70,
- 0x3c030001, 0x94630f72, 0x00431021, 0xa5020004, 0x3c020001, 0x94420f6c,
- 0xa4c20004, 0x3c020001, 0x8c420f6c, 0xa4c20006, 0x3c040001, 0x94840f72,
- 0x3c020001, 0x94420f70, 0x3c0a0001, 0x954a0f76, 0x00441821, 0x3063ffff,
- 0x0062182a, 0x24020002, 0x1122000b, 0x00832023, 0x3c030001, 0x94630f78,
- 0x30620009, 0x10400006, 0x3062fff6, 0xa4c2000c, 0x3c020001, 0x94420f78,
- 0x30420009, 0x01425023, 0x24020001, 0x1122001b, 0x29220002, 0x50400005,
- 0x24020002, 0x11200007, 0x31a2ffff, 0x08004197, 0x00000000, 0x1122001d,
- 0x24020016, 0x08004197, 0x31a2ffff, 0x3c0e0001, 0x95ce0f80, 0x10800005,
- 0x01806821, 0x01c42021, 0x00041c02, 0x3082ffff, 0x00627021, 0x000e1027,
- 0xa502000a, 0x3c030001, 0x90630f7b, 0x31a2ffff, 0x00e21021, 0x0800418d,
- 0x00432023, 0x3c020001, 0x94420f80, 0x00442021, 0x00041c02, 0x3082ffff,
- 0x00622021, 0x00807021, 0x00041027, 0x08004185, 0xa502000a, 0x3c050001,
- 0x24a50f7a, 0x90a30000, 0x14620002, 0x24e2fff2, 0xa5e20034, 0x90a20000,
- 0x00e21023, 0xa5020002, 0x3c030001, 0x94630f80, 0x3c020001, 0x94420f5a,
- 0x30e5ffff, 0x00641821, 0x00451023, 0x00622023, 0x00041c02, 0x3082ffff,
- 0x00622021, 0x00041027, 0xa502000a, 0x3c030001, 0x90630f7c, 0x24620001,
- 0x14a20005, 0x00807021, 0x01631021, 0x90420000, 0x08004185, 0x00026200,
- 0x24620002, 0x14a20003, 0x306200fe, 0x004b1021, 0x944c0000, 0x3c020001,
- 0x94420f82, 0x3183ffff, 0x3c040001, 0x90840f7b, 0x00431021, 0x00e21021,
- 0x00442023, 0x008a2021, 0x00041c02, 0x3082ffff, 0x00622021, 0x00041402,
- 0x00822021, 0x00806821, 0x00041027, 0xa4c20010, 0x31a2ffff, 0x000e1c00,
- 0x00431025, 0x3c040001, 0x24840f72, 0xade20010, 0x94820000, 0x3c050001,
- 0x94a50f76, 0x3c030001, 0x8c630f6c, 0x24420001, 0x00b92821, 0xa4820000,
- 0x3322ffff, 0x00622021, 0x0083182b, 0x3c010001, 0xa4250f76, 0x10600003,
- 0x24a2ffff, 0x3c010001, 0xa4220f76, 0x3c024000, 0x03021025, 0x3c010001,
- 0xac240f6c, 0xaf621008, 0x03e00008, 0x27bd0010, 0x3c030001, 0x90630f56,
- 0x27bdffe8, 0x24020001, 0xafbf0014, 0x10620026, 0xafb00010, 0x8f620cf4,
- 0x2442ffff, 0x3042007f, 0x00021100, 0x8c434000, 0x3c010001, 0xac230f64,
- 0x8c434008, 0x24444000, 0x8c5c4004, 0x30620040, 0x14400002, 0x24020088,
- 0x24020008, 0x3c010001, 0xa4220f68, 0x30620004, 0x10400005, 0x24020001,
- 0x3c010001, 0xa0220f57, 0x080041d5, 0x00031402, 0x3c010001, 0xa0200f57,
- 0x00031402, 0x3c010001, 0xa4220f54, 0x9483000c, 0x24020001, 0x3c010001,
- 0xa4200f50, 0x3c010001, 0xa0220f56, 0x3c010001, 0xa4230f62, 0x24020001,
- 0x1342001e, 0x00000000, 0x13400005, 0x24020003, 0x13420067, 0x00000000,
- 0x080042cf, 0x00000000, 0x3c020001, 0x94420f62, 0x241a0001, 0x3c010001,
- 0xa4200f5e, 0x3c010001, 0xa4200f52, 0x304407ff, 0x00021bc2, 0x00031823,
- 0x3063003e, 0x34630036, 0x00021242, 0x3042003c, 0x00621821, 0x3c010001,
- 0xa4240f58, 0x00832021, 0x24630030, 0x3c010001, 0xa4240f5a, 0x3c010001,
- 0xa4230f5c, 0x3c060001, 0x24c60f52, 0x94c50000, 0x94c30002, 0x3c040001,
- 0x94840f5a, 0x00651021, 0x0044102a, 0x10400013, 0x3c108000, 0x00a31021,
- 0xa4c20000, 0x3c02a000, 0xaf620cf4, 0x3c010001, 0xa0200f56, 0x8f641008,
- 0x00901024, 0x14400003, 0x00000000, 0x0c004064, 0x00000000, 0x8f620cf4,
- 0x00501024, 0x104000b7, 0x00000000, 0x0800420f, 0x00000000, 0x3c030001,
- 0x94630f50, 0x00851023, 0xa4c40000, 0x00621821, 0x3042ffff, 0x3c010001,
- 0xa4230f50, 0xaf620ce8, 0x3c020001, 0x94420f68, 0x34420024, 0xaf620cec,
- 0x94c30002, 0x3c020001, 0x94420f50, 0x14620012, 0x3c028000, 0x3c108000,
- 0x3c02a000, 0xaf620cf4, 0x3c010001, 0xa0200f56, 0x8f641008, 0x00901024,
- 0x14400003, 0x00000000, 0x0c004064, 0x00000000, 0x8f620cf4, 0x00501024,
- 0x1440fff7, 0x00000000, 0x080042cf, 0x241a0003, 0xaf620cf4, 0x3c108000,
- 0x8f641008, 0x00901024, 0x14400003, 0x00000000, 0x0c004064, 0x00000000,
- 0x8f620cf4, 0x00501024, 0x1440fff7, 0x00000000, 0x080042cf, 0x241a0003,
- 0x3c070001, 0x24e70f50, 0x94e20000, 0x03821021, 0xaf620ce0, 0x3c020001,
- 0x8c420f64, 0xaf620ce4, 0x3c050001, 0x94a50f54, 0x94e30000, 0x3c040001,
- 0x94840f58, 0x3c020001, 0x94420f5e, 0x00a32823, 0x00822023, 0x30a6ffff,
- 0x3083ffff, 0x00c3102b, 0x14400043, 0x00000000, 0x3c020001, 0x94420f5c,
- 0x00021400, 0x00621025, 0xaf620ce8, 0x94e20000, 0x3c030001, 0x94630f54,
- 0x00441021, 0xa4e20000, 0x3042ffff, 0x14430021, 0x3c020008, 0x3c020001,
- 0x90420f57, 0x10400006, 0x3c03000c, 0x3c020001, 0x94420f68, 0x34630624,
- 0x0800427c, 0x0000d021, 0x3c020001, 0x94420f68, 0x3c030008, 0x34630624,
- 0x00431025, 0xaf620cec, 0x3c108000, 0x3c02a000, 0xaf620cf4, 0x3c010001,
- 0xa0200f56, 0x8f641008, 0x00901024, 0x14400003, 0x00000000, 0x0c004064,
- 0x00000000, 0x8f620cf4, 0x00501024, 0x10400015, 0x00000000, 0x08004283,
- 0x00000000, 0x3c030001, 0x94630f68, 0x34420624, 0x3c108000, 0x00621825,
- 0x3c028000, 0xaf630cec, 0xaf620cf4, 0x8f641008, 0x00901024, 0x14400003,
- 0x00000000, 0x0c004064, 0x00000000, 0x8f620cf4, 0x00501024, 0x1440fff7,
- 0x00000000, 0x3c010001, 0x080042cf, 0xa4200f5e, 0x3c020001, 0x94420f5c,
- 0x00021400, 0x00c21025, 0xaf620ce8, 0x3c020001, 0x90420f57, 0x10400009,
- 0x3c03000c, 0x3c020001, 0x94420f68, 0x34630624, 0x0000d021, 0x00431025,
- 0xaf620cec, 0x080042c1, 0x3c108000, 0x3c020001, 0x94420f68, 0x3c030008,
- 0x34630604, 0x00431025, 0xaf620cec, 0x3c020001, 0x94420f5e, 0x00451021,
- 0x3c010001, 0xa4220f5e, 0x3c108000, 0x3c02a000, 0xaf620cf4, 0x3c010001,
- 0xa0200f56, 0x8f641008, 0x00901024, 0x14400003, 0x00000000, 0x0c004064,
- 0x00000000, 0x8f620cf4, 0x00501024, 0x1440fff7, 0x00000000, 0x8fbf0014,
- 0x8fb00010, 0x03e00008, 0x27bd0018, 0x00000000, 0x27bdffe0, 0x3c040001,
- 0x24840ec0, 0x00002821, 0x00003021, 0x00003821, 0xafbf0018, 0xafa00010,
- 0x0c004378, 0xafa00014, 0x0000d021, 0x24020130, 0xaf625000, 0x3c010001,
- 0xa4200f50, 0x3c010001, 0xa0200f57, 0x8fbf0018, 0x03e00008, 0x27bd0020,
- 0x27bdffe8, 0x3c1bc000, 0xafbf0014, 0xafb00010, 0xaf60680c, 0x8f626804,
- 0x34420082, 0xaf626804, 0x8f634000, 0x24020b50, 0x3c010001, 0xac220f20,
- 0x24020b78, 0x3c010001, 0xac220f30, 0x34630002, 0xaf634000, 0x0c004315,
- 0x00808021, 0x3c010001, 0xa0220f34, 0x304200ff, 0x24030002, 0x14430005,
- 0x00000000, 0x3c020001, 0x8c420f20, 0x08004308, 0xac5000c0, 0x3c020001,
- 0x8c420f20, 0xac5000bc, 0x8f624434, 0x8f634438, 0x8f644410, 0x3c010001,
- 0xac220f28, 0x3c010001, 0xac230f38, 0x3c010001, 0xac240f24, 0x8fbf0014,
- 0x8fb00010, 0x03e00008, 0x27bd0018, 0x03e00008, 0x24020001, 0x27bdfff8,
- 0x18800009, 0x00002821, 0x8f63680c, 0x8f62680c, 0x1043fffe, 0x00000000,
- 0x24a50001, 0x00a4102a, 0x1440fff9, 0x00000000, 0x03e00008, 0x27bd0008,
- 0x8f634450, 0x3c020001, 0x8c420f28, 0x00031c02, 0x0043102b, 0x14400008,
- 0x3c038000, 0x3c040001, 0x8c840f38, 0x8f624450, 0x00021c02, 0x0083102b,
- 0x1040fffc, 0x3c038000, 0xaf634444, 0x8f624444, 0x00431024, 0x1440fffd,
- 0x00000000, 0x8f624448, 0x03e00008, 0x3042ffff, 0x3082ffff, 0x2442e000,
- 0x2c422001, 0x14400003, 0x3c024000, 0x08004347, 0x2402ffff, 0x00822025,
- 0xaf645c38, 0x8f625c30, 0x30420002, 0x1440fffc, 0x00001021, 0x03e00008,
- 0x00000000, 0x8f624450, 0x3c030001, 0x8c630f24, 0x08004350, 0x3042ffff,
- 0x8f624450, 0x3042ffff, 0x0043102b, 0x1440fffc, 0x00000000, 0x03e00008,
- 0x00000000, 0x27bdffe0, 0x00802821, 0x3c040001, 0x24840ed0, 0x00003021,
- 0x00003821, 0xafbf0018, 0xafa00010, 0x0c004378, 0xafa00014, 0x0800435f,
- 0x00000000, 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x3c020001, 0x3442d600,
- 0x3c030001, 0x3463d600, 0x3c040001, 0x3484ddff, 0x3c010001, 0xac220f40,
- 0x24020040, 0x3c010001, 0xac220f44, 0x3c010001, 0xac200f3c, 0xac600000,
- 0x24630004, 0x0083102b, 0x5040fffd, 0xac600000, 0x03e00008, 0x00000000,
- 0x00804821, 0x8faa0010, 0x3c020001, 0x8c420f3c, 0x3c040001, 0x8c840f44,
- 0x8fab0014, 0x24430001, 0x0044102b, 0x3c010001, 0xac230f3c, 0x14400003,
- 0x00004021, 0x3c010001, 0xac200f3c, 0x3c020001, 0x8c420f3c, 0x3c030001,
- 0x8c630f40, 0x91240000, 0x00021140, 0x00431021, 0x00481021, 0x25080001,
- 0xa0440000, 0x29020008, 0x1440fff4, 0x25290001, 0x3c020001, 0x8c420f3c,
- 0x3c030001, 0x8c630f40, 0x8f64680c, 0x00021140, 0x00431021, 0xac440008,
- 0xac45000c, 0xac460010, 0xac470014, 0xac4a0018, 0x03e00008, 0xac4b001c,
- 0x00000000, 0x00000000, 0x00000000,
-};
-
-static const u32 tg3Tso5FwRodata[(TG3_TSO5_FW_RODATA_LEN / 4) + 1] = {
- 0x4d61696e, 0x43707542, 0x00000000, 0x4d61696e, 0x43707541, 0x00000000,
- 0x00000000, 0x00000000, 0x73746b6f, 0x66666c64, 0x00000000, 0x00000000,
- 0x73746b6f, 0x66666c64, 0x00000000, 0x00000000, 0x66617461, 0x6c457272,
- 0x00000000, 0x00000000, 0x00000000,
-};
-
-static const u32 tg3Tso5FwData[(TG3_TSO5_FW_DATA_LEN / 4) + 1] = {
- 0x00000000, 0x73746b6f, 0x66666c64, 0x5f76312e, 0x322e3000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000,
-};
/* tp->lock is held. */
static int tg3_load_tso_firmware(struct tg3 *tp)
{
struct fw_info info;
+ const __be32 *fw_data;
unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
int err, i;
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
return 0;
+ fw_data = (void *)tp->fw->data;
+
+ /* Firmware blob starts with version numbers, followed by
+ start address and length. We are setting complete length.
+ length = end_address_of_bss - start_address_of_text.
+ Remainder is the blob to be loaded contiguously
+ from start address. */
+
+ info.fw_base = be32_to_cpu(fw_data[1]);
+ cpu_scratch_size = tp->fw_len;
+ info.fw_len = tp->fw->size - 12;
+ info.fw_data = &fw_data[3];
+
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
- info.text_base = TG3_TSO5_FW_TEXT_ADDR;
- info.text_len = TG3_TSO5_FW_TEXT_LEN;
- info.text_data = &tg3Tso5FwText[0];
- info.rodata_base = TG3_TSO5_FW_RODATA_ADDR;
- info.rodata_len = TG3_TSO5_FW_RODATA_LEN;
- info.rodata_data = &tg3Tso5FwRodata[0];
- info.data_base = TG3_TSO5_FW_DATA_ADDR;
- info.data_len = TG3_TSO5_FW_DATA_LEN;
- info.data_data = &tg3Tso5FwData[0];
cpu_base = RX_CPU_BASE;
cpu_scratch_base = NIC_SRAM_MBUF_POOL_BASE5705;
- cpu_scratch_size = (info.text_len +
- info.rodata_len +
- info.data_len +
- TG3_TSO5_FW_SBSS_LEN +
- TG3_TSO5_FW_BSS_LEN);
} else {
- info.text_base = TG3_TSO_FW_TEXT_ADDR;
- info.text_len = TG3_TSO_FW_TEXT_LEN;
- info.text_data = &tg3TsoFwText[0];
- info.rodata_base = TG3_TSO_FW_RODATA_ADDR;
- info.rodata_len = TG3_TSO_FW_RODATA_LEN;
- info.rodata_data = &tg3TsoFwRodata[0];
- info.data_base = TG3_TSO_FW_DATA_ADDR;
- info.data_len = TG3_TSO_FW_DATA_LEN;
- info.data_data = &tg3TsoFwData[0];
cpu_base = TX_CPU_BASE;
cpu_scratch_base = TX_CPU_SCRATCH_BASE;
cpu_scratch_size = TX_CPU_SCRATCH_SIZE;
@@ -7060,21 +6418,21 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
/* Now startup the cpu. */
tw32(cpu_base + CPU_STATE, 0xffffffff);
- tw32_f(cpu_base + CPU_PC, info.text_base);
+ tw32_f(cpu_base + CPU_PC, info.fw_base);
for (i = 0; i < 5; i++) {
- if (tr32(cpu_base + CPU_PC) == info.text_base)
+ if (tr32(cpu_base + CPU_PC) == info.fw_base)
break;
tw32(cpu_base + CPU_STATE, 0xffffffff);
tw32(cpu_base + CPU_MODE, CPU_MODE_HALT);
- tw32_f(cpu_base + CPU_PC, info.text_base);
+ tw32_f(cpu_base + CPU_PC, info.fw_base);
udelay(1000);
}
if (i >= 5) {
printk(KERN_ERR PFX "tg3_load_tso_firmware fails for %s "
"to set CPU PC, is %08x should be %08x\n",
tp->dev->name, tr32(cpu_base + CPU_PC),
- info.text_base);
+ info.fw_base);
return -ENODEV;
}
tw32(cpu_base + CPU_STATE, 0xffffffff);
@@ -7299,11 +6657,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
else if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
int fw_len;
- fw_len = (TG3_TSO5_FW_TEXT_LEN +
- TG3_TSO5_FW_RODATA_LEN +
- TG3_TSO5_FW_DATA_LEN +
- TG3_TSO5_FW_SBSS_LEN +
- TG3_TSO5_FW_BSS_LEN);
+ fw_len = tp->fw_len;
fw_len = (fw_len + (0x80 - 1)) & ~(0x80 - 1);
tw32(BUFMGR_MB_POOL_ADDR,
NIC_SRAM_MBUF_POOL_BASE5705 + fw_len);
@@ -13580,6 +12934,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
struct net_device *dev;
struct tg3 *tp;
int err, pm_cap;
+ const char *fw_name = NULL;
char str[40];
u64 dma_mask, persist_dma_mask;
@@ -13735,6 +13090,9 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
tg3_init_bufmgr_config(tp);
+ if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0)
+ fw_name = FIRMWARE_TG3;
+
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
}
@@ -13747,6 +13105,37 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
} else {
tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE | TG3_FLG2_TSO_BUG;
}
+ if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
+ fw_name = FIRMWARE_TG3TSO5;
+ else
+ fw_name = FIRMWARE_TG3TSO;
+ }
+
+ if (fw_name) {
+ const __be32 *fw_data;
+
+ err = request_firmware(&tp->fw, fw_name, &tp->pdev->dev);
+ if (err) {
+ printk(KERN_ERR "tg3: Failed to load firmware \"%s\"\n",
+ fw_name);
+ goto err_out_iounmap;
+ }
+
+ fw_data = (void *)tp->fw->data;
+
+ /* Firmware blob starts with version numbers, followed by
+ start address and _full_ length including BSS sections
+ (which must be longer than the actual data, of course */
+
+ tp->fw_len = be32_to_cpu(fw_data[2]); /* includes bss */
+ if (tp->fw_len < (tp->fw->size - 12)) {
+ printk(KERN_ERR "tg3: bogus length %d in \"%s\"\n",
+ tp->fw_len, fw_name);
+ err = -EINVAL;
+ goto err_out_fw;
+ }
+ }
/* TSO is on by default on chips that support hardware TSO.
* Firmware TSO on older chips gives lower performance, so it
@@ -13778,7 +13167,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
if (err) {
printk(KERN_ERR PFX "Could not obtain valid ethernet address, "
"aborting.\n");
- goto err_out_iounmap;
+ goto err_out_fw;
}
if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
@@ -13787,7 +13176,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
printk(KERN_ERR PFX "Cannot map APE registers, "
"aborting.\n");
err = -ENOMEM;
- goto err_out_iounmap;
+ goto err_out_fw;
}
tg3_ape_lock_init(tp);
@@ -13867,6 +13256,10 @@ err_out_apeunmap:
tp->aperegs = NULL;
}
+err_out_fw:
+ if (tp->fw)
+ release_firmware(tp->fw);
+
err_out_iounmap:
if (tp->regs) {
iounmap(tp->regs);
@@ -13892,6 +13285,9 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
if (dev) {
struct tg3 *tp = netdev_priv(dev);
+ if (tp->fw)
+ release_firmware(tp->fw);
+
flush_scheduled_work();
if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 8936edfb0438..ae5da603c6af 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2762,6 +2762,10 @@ struct tg3 {
#define SST_25VF0X0_PAGE_SIZE 4098
struct ethtool_coalesce coal;
+
+ /* firmware info */
+ const struct firmware *fw;
+ u32 fw_len; /* includes BSS */
};
#endif /* !(_T3_H) */
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 69f9a0ec764d..d7b81e4fdd56 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -213,7 +213,7 @@ static int check_filter(struct tap_filter *filter, const struct sk_buff *skb)
/* Network device part of the driver */
-static unsigned int tun_net_id;
+static int tun_net_id;
struct tun_net {
struct list_head dev_list;
};
diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c
index ddc4c59f02dc..b7e4cee24269 100644
--- a/drivers/oprofile/oprofilefs.c
+++ b/drivers/oprofile/oprofilefs.c
@@ -29,9 +29,6 @@ static struct inode *oprofilefs_get_inode(struct super_block *sb, int mode)
if (inode) {
inode->i_mode = mode;
- inode->i_uid = 0;
- inode->i_gid = 0;
- inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
}
return inode;
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 8e0c2b47803c..668472405a57 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -29,6 +29,13 @@ config APM_POWER
Say Y here to enable support APM status emulation using
battery class devices.
+config WM8350_POWER
+ tristate "WM8350 PMU support"
+ depends on MFD_WM8350
+ help
+ Say Y here to enable support for the power management unit
+ provided by the Wolfson Microelectronics WM8350 PMIC.
+
config BATTERY_DS2760
tristate "DS2760 battery driver (HP iPAQ & others)"
select W1
@@ -68,4 +75,11 @@ config BATTERY_BQ27x00
help
Say Y here to enable support for batteries with BQ27200(I2C) chip.
+config BATTERY_DA9030
+ tristate "DA9030 battery driver"
+ depends on PMIC_DA903X
+ help
+ Say Y here to enable support for batteries charger integrated into
+ DA9030 PMIC.
+
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index e8f1ecec5d8f..eebb15505a40 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_POWER_SUPPLY) += power_supply.o
obj-$(CONFIG_PDA_POWER) += pda_power.o
obj-$(CONFIG_APM_POWER) += apm_power.o
+obj-$(CONFIG_WM8350_POWER) += wm8350_power.o
obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
@@ -23,3 +24,4 @@ obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o
obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
+obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
diff --git a/drivers/power/da9030_battery.c b/drivers/power/da9030_battery.c
new file mode 100644
index 000000000000..1662bb0f23a5
--- /dev/null
+++ b/drivers/power/da9030_battery.c
@@ -0,0 +1,600 @@
+/*
+ * Battery charger driver for Dialog Semiconductor DA9030
+ *
+ * Copyright (C) 2008 Compulab, Ltd.
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/da903x.h>
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#define DA9030_STATUS_CHDET (1 << 3)
+
+#define DA9030_FAULT_LOG 0x0a
+#define DA9030_FAULT_LOG_OVER_TEMP (1 << 7)
+#define DA9030_FAULT_LOG_VBAT_OVER (1 << 4)
+
+#define DA9030_CHARGE_CONTROL 0x28
+#define DA9030_CHRG_CHARGER_ENABLE (1 << 7)
+
+#define DA9030_ADC_MAN_CONTROL 0x30
+#define DA9030_ADC_TBATREF_ENABLE (1 << 5)
+#define DA9030_ADC_LDO_INT_ENABLE (1 << 4)
+
+#define DA9030_ADC_AUTO_CONTROL 0x31
+#define DA9030_ADC_TBAT_ENABLE (1 << 5)
+#define DA9030_ADC_VBAT_IN_TXON (1 << 4)
+#define DA9030_ADC_VCH_ENABLE (1 << 3)
+#define DA9030_ADC_ICH_ENABLE (1 << 2)
+#define DA9030_ADC_VBAT_ENABLE (1 << 1)
+#define DA9030_ADC_AUTO_SLEEP_ENABLE (1 << 0)
+
+#define DA9030_VBATMON 0x32
+#define DA9030_VBATMONTXON 0x33
+#define DA9030_TBATHIGHP 0x34
+#define DA9030_TBATHIGHN 0x35
+#define DA9030_TBATLOW 0x36
+
+#define DA9030_VBAT_RES 0x41
+#define DA9030_VBATMIN_RES 0x42
+#define DA9030_VBATMINTXON_RES 0x43
+#define DA9030_ICHMAX_RES 0x44
+#define DA9030_ICHMIN_RES 0x45
+#define DA9030_ICHAVERAGE_RES 0x46
+#define DA9030_VCHMAX_RES 0x47
+#define DA9030_VCHMIN_RES 0x48
+#define DA9030_TBAT_RES 0x49
+
+struct da9030_adc_res {
+ uint8_t vbat_res;
+ uint8_t vbatmin_res;
+ uint8_t vbatmintxon;
+ uint8_t ichmax_res;
+ uint8_t ichmin_res;
+ uint8_t ichaverage_res;
+ uint8_t vchmax_res;
+ uint8_t vchmin_res;
+ uint8_t tbat_res;
+ uint8_t adc_in4_res;
+ uint8_t adc_in5_res;
+};
+
+struct da9030_battery_thresholds {
+ int tbat_low;
+ int tbat_high;
+ int tbat_restart;
+
+ int vbat_low;
+ int vbat_crit;
+ int vbat_charge_start;
+ int vbat_charge_stop;
+ int vbat_charge_restart;
+
+ int vcharge_min;
+ int vcharge_max;
+};
+
+struct da9030_charger {
+ struct power_supply psy;
+
+ struct device *master;
+
+ struct da9030_adc_res adc;
+ struct delayed_work work;
+ unsigned int interval;
+
+ struct power_supply_info *battery_info;
+
+ struct da9030_battery_thresholds thresholds;
+
+ unsigned int charge_milliamp;
+ unsigned int charge_millivolt;
+
+ /* charger status */
+ bool chdet;
+ uint8_t fault;
+ int mA;
+ int mV;
+ bool is_on;
+
+ struct notifier_block nb;
+
+ /* platform callbacks for battery low and critical events */
+ void (*battery_low)(void);
+ void (*battery_critical)(void);
+
+ struct dentry *debug_file;
+};
+
+static inline int da9030_reg_to_mV(int reg)
+{
+ return ((reg * 2650) >> 8) + 2650;
+}
+
+static inline int da9030_millivolt_to_reg(int mV)
+{
+ return ((mV - 2650) << 8) / 2650;
+}
+
+static inline int da9030_reg_to_mA(int reg)
+{
+ return ((reg * 24000) >> 8) / 15;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int bat_debug_show(struct seq_file *s, void *data)
+{
+ struct da9030_charger *charger = s->private;
+
+ seq_printf(s, "charger is %s\n", charger->is_on ? "on" : "off");
+ if (charger->chdet) {
+ seq_printf(s, "iset = %dmA, vset = %dmV\n",
+ charger->mA, charger->mV);
+ }
+
+ seq_printf(s, "vbat_res = %d (%dmV)\n",
+ charger->adc.vbat_res,
+ da9030_reg_to_mV(charger->adc.vbat_res));
+ seq_printf(s, "vbatmin_res = %d (%dmV)\n",
+ charger->adc.vbatmin_res,
+ da9030_reg_to_mV(charger->adc.vbatmin_res));
+ seq_printf(s, "vbatmintxon = %d (%dmV)\n",
+ charger->adc.vbatmintxon,
+ da9030_reg_to_mV(charger->adc.vbatmintxon));
+ seq_printf(s, "ichmax_res = %d (%dmA)\n",
+ charger->adc.ichmax_res,
+ da9030_reg_to_mV(charger->adc.ichmax_res));
+ seq_printf(s, "ichmin_res = %d (%dmA)\n",
+ charger->adc.ichmin_res,
+ da9030_reg_to_mA(charger->adc.ichmin_res));
+ seq_printf(s, "ichaverage_res = %d (%dmA)\n",
+ charger->adc.ichaverage_res,
+ da9030_reg_to_mA(charger->adc.ichaverage_res));
+ seq_printf(s, "vchmax_res = %d (%dmV)\n",
+ charger->adc.vchmax_res,
+ da9030_reg_to_mA(charger->adc.vchmax_res));
+ seq_printf(s, "vchmin_res = %d (%dmV)\n",
+ charger->adc.vchmin_res,
+ da9030_reg_to_mV(charger->adc.vchmin_res));
+
+ return 0;
+}
+
+static int debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, bat_debug_show, inode->i_private);
+}
+
+static const struct file_operations bat_debug_fops = {
+ .open = debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct dentry *da9030_bat_create_debugfs(struct da9030_charger *charger)
+{
+ charger->debug_file = debugfs_create_file("charger", 0666, 0, charger,
+ &bat_debug_fops);
+ return charger->debug_file;
+}
+
+static void da9030_bat_remove_debugfs(struct da9030_charger *charger)
+{
+ debugfs_remove(charger->debug_file);
+}
+#else
+static inline struct dentry *da9030_bat_create_debugfs(struct da9030_charger *charger)
+{
+ return NULL;
+}
+static inline void da9030_bat_remove_debugfs(struct da9030_charger *charger)
+{
+}
+#endif
+
+static inline void da9030_read_adc(struct da9030_charger *charger,
+ struct da9030_adc_res *adc)
+{
+ da903x_reads(charger->master, DA9030_VBAT_RES,
+ sizeof(*adc), (uint8_t *)adc);
+}
+
+static void da9030_charger_update_state(struct da9030_charger *charger)
+{
+ uint8_t val;
+
+ da903x_read(charger->master, DA9030_CHARGE_CONTROL, &val);
+ charger->is_on = (val & DA9030_CHRG_CHARGER_ENABLE) ? 1 : 0;
+ charger->mA = ((val >> 3) & 0xf) * 100;
+ charger->mV = (val & 0x7) * 50 + 4000;
+
+ da9030_read_adc(charger, &charger->adc);
+ da903x_read(charger->master, DA9030_FAULT_LOG, &charger->fault);
+ charger->chdet = da903x_query_status(charger->master,
+ DA9030_STATUS_CHDET);
+}
+
+static void da9030_set_charge(struct da9030_charger *charger, int on)
+{
+ uint8_t val;
+
+ if (on) {
+ val = DA9030_CHRG_CHARGER_ENABLE;
+ val |= (charger->charge_milliamp / 100) << 3;
+ val |= (charger->charge_millivolt - 4000) / 50;
+ charger->is_on = 1;
+ } else {
+ val = 0;
+ charger->is_on = 0;
+ }
+
+ da903x_write(charger->master, DA9030_CHARGE_CONTROL, val);
+}
+
+static void da9030_charger_check_state(struct da9030_charger *charger)
+{
+ da9030_charger_update_state(charger);
+
+ /* we wake or boot with external power on */
+ if (!charger->is_on) {
+ if ((charger->chdet) &&
+ (charger->adc.vbat_res <
+ charger->thresholds.vbat_charge_start)) {
+ da9030_set_charge(charger, 1);
+ }
+ } else {
+ if (charger->adc.vbat_res >=
+ charger->thresholds.vbat_charge_stop) {
+ da9030_set_charge(charger, 0);
+ da903x_write(charger->master, DA9030_VBATMON,
+ charger->thresholds.vbat_charge_restart);
+ } else if (charger->adc.vbat_res >
+ charger->thresholds.vbat_low) {
+ /* we are charging and passed LOW_THRESH,
+ so upate DA9030 VBAT threshold
+ */
+ da903x_write(charger->master, DA9030_VBATMON,
+ charger->thresholds.vbat_low);
+ }
+ if (charger->adc.vchmax_res > charger->thresholds.vcharge_max ||
+ charger->adc.vchmin_res < charger->thresholds.vcharge_min ||
+ /* Tempreture readings are negative */
+ charger->adc.tbat_res < charger->thresholds.tbat_high ||
+ charger->adc.tbat_res > charger->thresholds.tbat_low) {
+ /* disable charger */
+ da9030_set_charge(charger, 0);
+ }
+ }
+}
+
+static void da9030_charging_monitor(struct work_struct *work)
+{
+ struct da9030_charger *charger;
+
+ charger = container_of(work, struct da9030_charger, work.work);
+
+ da9030_charger_check_state(charger);
+
+ /* reschedule for the next time */
+ schedule_delayed_work(&charger->work, charger->interval);
+}
+
+static enum power_supply_property da9030_battery_props[] = {
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+};
+
+static void da9030_battery_check_status(struct da9030_charger *charger,
+ union power_supply_propval *val)
+{
+ if (charger->chdet) {
+ if (charger->is_on)
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ } else {
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ }
+}
+
+static void da9030_battery_check_health(struct da9030_charger *charger,
+ union power_supply_propval *val)
+{
+ if (charger->fault & DA9030_FAULT_LOG_OVER_TEMP)
+ val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+ else if (charger->fault & DA9030_FAULT_LOG_VBAT_OVER)
+ val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ else
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+}
+
+static int da9030_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct da9030_charger *charger;
+ charger = container_of(psy, struct da9030_charger, psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ da9030_battery_check_status(charger, val);
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ da9030_battery_check_health(charger, val);
+ break;
+ case POWER_SUPPLY_PROP_TECHNOLOGY:
+ val->intval = charger->battery_info->technology;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+ val->intval = charger->battery_info->voltage_max_design;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+ val->intval = charger->battery_info->voltage_min_design;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = da9030_reg_to_mV(charger->adc.vbat_res) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_AVG:
+ val->intval =
+ da9030_reg_to_mA(charger->adc.ichaverage_res) * 1000;
+ break;
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = charger->battery_info->name;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static void da9030_battery_vbat_event(struct da9030_charger *charger)
+{
+ da9030_read_adc(charger, &charger->adc);
+
+ if (charger->is_on)
+ return;
+
+ if (charger->adc.vbat_res < charger->thresholds.vbat_low) {
+ /* set VBAT threshold for critical */
+ da903x_write(charger->master, DA9030_VBATMON,
+ charger->thresholds.vbat_crit);
+ if (charger->battery_low)
+ charger->battery_low();
+ } else if (charger->adc.vbat_res <
+ charger->thresholds.vbat_crit) {
+ /* notify the system of battery critical */
+ if (charger->battery_critical)
+ charger->battery_critical();
+ }
+}
+
+static int da9030_battery_event(struct notifier_block *nb, unsigned long event,
+ void *data)
+{
+ struct da9030_charger *charger =
+ container_of(nb, struct da9030_charger, nb);
+ int status;
+
+ switch (event) {
+ case DA9030_EVENT_CHDET:
+ status = da903x_query_status(charger->master,
+ DA9030_STATUS_CHDET);
+ da9030_set_charge(charger, status);
+ break;
+ case DA9030_EVENT_VBATMON:
+ da9030_battery_vbat_event(charger);
+ break;
+ case DA9030_EVENT_CHIOVER:
+ case DA9030_EVENT_TBAT:
+ da9030_set_charge(charger, 0);
+ break;
+ }
+
+ return 0;
+}
+
+static void da9030_battery_convert_thresholds(struct da9030_charger *charger,
+ struct da9030_battery_info *pdata)
+{
+ charger->thresholds.tbat_low = pdata->tbat_low;
+ charger->thresholds.tbat_high = pdata->tbat_high;
+ charger->thresholds.tbat_restart = pdata->tbat_restart;
+
+ charger->thresholds.vbat_low =
+ da9030_millivolt_to_reg(pdata->vbat_low);
+ charger->thresholds.vbat_crit =
+ da9030_millivolt_to_reg(pdata->vbat_crit);
+ charger->thresholds.vbat_charge_start =
+ da9030_millivolt_to_reg(pdata->vbat_charge_start);
+ charger->thresholds.vbat_charge_stop =
+ da9030_millivolt_to_reg(pdata->vbat_charge_stop);
+ charger->thresholds.vbat_charge_restart =
+ da9030_millivolt_to_reg(pdata->vbat_charge_restart);
+
+ charger->thresholds.vcharge_min =
+ da9030_millivolt_to_reg(pdata->vcharge_min);
+ charger->thresholds.vcharge_max =
+ da9030_millivolt_to_reg(pdata->vcharge_max);
+}
+
+static void da9030_battery_setup_psy(struct da9030_charger *charger)
+{
+ struct power_supply *psy = &charger->psy;
+ struct power_supply_info *info = charger->battery_info;
+
+ psy->name = info->name;
+ psy->use_for_apm = info->use_for_apm;
+ psy->type = POWER_SUPPLY_TYPE_BATTERY;
+ psy->get_property = da9030_battery_get_property;
+
+ psy->properties = da9030_battery_props;
+ psy->num_properties = ARRAY_SIZE(da9030_battery_props);
+};
+
+static int da9030_battery_charger_init(struct da9030_charger *charger)
+{
+ char v[5];
+ int ret;
+
+ v[0] = v[1] = charger->thresholds.vbat_low;
+ v[2] = charger->thresholds.tbat_high;
+ v[3] = charger->thresholds.tbat_restart;
+ v[4] = charger->thresholds.tbat_low;
+
+ ret = da903x_writes(charger->master, DA9030_VBATMON, 5, v);
+ if (ret)
+ return ret;
+
+ /*
+ * Enable reference voltage supply for ADC from the LDO_INTERNAL
+ * regulator. Must be set before ADC measurements can be made.
+ */
+ ret = da903x_write(charger->master, DA9030_ADC_MAN_CONTROL,
+ DA9030_ADC_LDO_INT_ENABLE |
+ DA9030_ADC_TBATREF_ENABLE);
+ if (ret)
+ return ret;
+
+ /* enable auto ADC measuremnts */
+ return da903x_write(charger->master, DA9030_ADC_AUTO_CONTROL,
+ DA9030_ADC_TBAT_ENABLE | DA9030_ADC_VBAT_IN_TXON |
+ DA9030_ADC_VCH_ENABLE | DA9030_ADC_ICH_ENABLE |
+ DA9030_ADC_VBAT_ENABLE |
+ DA9030_ADC_AUTO_SLEEP_ENABLE);
+}
+
+static int da9030_battery_probe(struct platform_device *pdev)
+{
+ struct da9030_charger *charger;
+ struct da9030_battery_info *pdata = pdev->dev.platform_data;
+ int ret;
+
+ if (pdata == NULL)
+ return -EINVAL;
+
+ if (pdata->charge_milliamp >= 1500 ||
+ pdata->charge_millivolt < 4000 ||
+ pdata->charge_millivolt > 4350)
+ return -EINVAL;
+
+ charger = kzalloc(sizeof(*charger), GFP_KERNEL);
+ if (charger == NULL)
+ return -ENOMEM;
+
+ charger->master = pdev->dev.parent;
+
+ /* 10 seconds between monotor runs unless platfrom defines other
+ interval */
+ charger->interval = msecs_to_jiffies(
+ (pdata->batmon_interval ? : 10) * 1000);
+
+ charger->charge_milliamp = pdata->charge_milliamp;
+ charger->charge_millivolt = pdata->charge_millivolt;
+ charger->battery_info = pdata->battery_info;
+ charger->battery_low = pdata->battery_low;
+ charger->battery_critical = pdata->battery_critical;
+
+ da9030_battery_convert_thresholds(charger, pdata);
+
+ ret = da9030_battery_charger_init(charger);
+ if (ret)
+ goto err_charger_init;
+
+ INIT_DELAYED_WORK(&charger->work, da9030_charging_monitor);
+ schedule_delayed_work(&charger->work, charger->interval);
+
+ charger->nb.notifier_call = da9030_battery_event;
+ ret = da903x_register_notifier(charger->master, &charger->nb,
+ DA9030_EVENT_CHDET |
+ DA9030_EVENT_VBATMON |
+ DA9030_EVENT_CHIOVER |
+ DA9030_EVENT_TBAT);
+ if (ret)
+ goto err_notifier;
+
+ da9030_battery_setup_psy(charger);
+ ret = power_supply_register(&pdev->dev, &charger->psy);
+ if (ret)
+ goto err_ps_register;
+
+ charger->debug_file = da9030_bat_create_debugfs(charger);
+ platform_set_drvdata(pdev, charger);
+ return 0;
+
+err_ps_register:
+ da903x_unregister_notifier(charger->master, &charger->nb,
+ DA9030_EVENT_CHDET | DA9030_EVENT_VBATMON |
+ DA9030_EVENT_CHIOVER | DA9030_EVENT_TBAT);
+err_notifier:
+ cancel_delayed_work(&charger->work);
+
+err_charger_init:
+ kfree(charger);
+
+ return ret;
+}
+
+static int da9030_battery_remove(struct platform_device *dev)
+{
+ struct da9030_charger *charger = platform_get_drvdata(dev);
+
+ da9030_bat_remove_debugfs(charger);
+
+ da903x_unregister_notifier(charger->master, &charger->nb,
+ DA9030_EVENT_CHDET | DA9030_EVENT_VBATMON |
+ DA9030_EVENT_CHIOVER | DA9030_EVENT_TBAT);
+ cancel_delayed_work(&charger->work);
+ power_supply_unregister(&charger->psy);
+
+ kfree(charger);
+
+ return 0;
+}
+
+static struct platform_driver da903x_battery_driver = {
+ .driver = {
+ .name = "da903x-battery",
+ .owner = THIS_MODULE,
+ },
+ .probe = da9030_battery_probe,
+ .remove = da9030_battery_remove,
+};
+
+static int da903x_battery_init(void)
+{
+ return platform_driver_register(&da903x_battery_driver);
+}
+
+static void da903x_battery_exit(void)
+{
+ platform_driver_unregister(&da903x_battery_driver);
+}
+
+module_init(da903x_battery_init);
+module_exit(da903x_battery_exit);
+
+MODULE_DESCRIPTION("DA9030 battery charger driver");
+MODULE_AUTHOR("Mike Rapoport, CompuLab");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 23ae8460f5c1..ac01e06817fb 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -45,7 +45,7 @@ static ssize_t power_supply_show_property(struct device *dev,
};
static char *health_text[] = {
"Unknown", "Good", "Overheat", "Dead", "Over voltage",
- "Unspecified failure"
+ "Unspecified failure", "Cold",
};
static char *technology_text[] = {
"Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
diff --git a/drivers/power/wm8350_power.c b/drivers/power/wm8350_power.c
new file mode 100644
index 000000000000..1b16bf343f2f
--- /dev/null
+++ b/drivers/power/wm8350_power.c
@@ -0,0 +1,532 @@
+/*
+ * Battery driver for wm8350 PMIC
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Based on OLPC Battery Driver
+ *
+ * Copyright 2006 David Woodhouse <dwmw2@infradead.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/wm8350/supply.h>
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/comparator.h>
+
+static int wm8350_read_battery_uvolts(struct wm8350 *wm8350)
+{
+ return wm8350_read_auxadc(wm8350, WM8350_AUXADC_BATT, 0, 0)
+ * WM8350_AUX_COEFF;
+}
+
+static int wm8350_read_line_uvolts(struct wm8350 *wm8350)
+{
+ return wm8350_read_auxadc(wm8350, WM8350_AUXADC_LINE, 0, 0)
+ * WM8350_AUX_COEFF;
+}
+
+static int wm8350_read_usb_uvolts(struct wm8350 *wm8350)
+{
+ return wm8350_read_auxadc(wm8350, WM8350_AUXADC_USB, 0, 0)
+ * WM8350_AUX_COEFF;
+}
+
+#define WM8350_BATT_SUPPLY 1
+#define WM8350_USB_SUPPLY 2
+#define WM8350_LINE_SUPPLY 4
+
+static inline int wm8350_charge_time_min(struct wm8350 *wm8350, int min)
+{
+ if (!wm8350->power.rev_g_coeff)
+ return (((min - 30) / 15) & 0xf) << 8;
+ else
+ return (((min - 30) / 30) & 0xf) << 8;
+}
+
+static int wm8350_get_supplies(struct wm8350 *wm8350)
+{
+ u16 sm, ov, co, chrg;
+ int supplies = 0;
+
+ sm = wm8350_reg_read(wm8350, WM8350_STATE_MACHINE_STATUS);
+ ov = wm8350_reg_read(wm8350, WM8350_MISC_OVERRIDES);
+ co = wm8350_reg_read(wm8350, WM8350_COMPARATOR_OVERRIDES);
+ chrg = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2);
+
+ /* USB_SM */
+ sm = (sm & WM8350_USB_SM_MASK) >> WM8350_USB_SM_SHIFT;
+
+ /* CHG_ISEL */
+ chrg &= WM8350_CHG_ISEL_MASK;
+
+ /* If the USB state machine is active then we're using that with or
+ * without battery, otherwise check for wall supply */
+ if (((sm == WM8350_USB_SM_100_SLV) ||
+ (sm == WM8350_USB_SM_500_SLV) ||
+ (sm == WM8350_USB_SM_STDBY_SLV))
+ && !(ov & WM8350_USB_LIMIT_OVRDE))
+ supplies = WM8350_USB_SUPPLY;
+ else if (((sm == WM8350_USB_SM_100_SLV) ||
+ (sm == WM8350_USB_SM_500_SLV) ||
+ (sm == WM8350_USB_SM_STDBY_SLV))
+ && (ov & WM8350_USB_LIMIT_OVRDE) && (chrg == 0))
+ supplies = WM8350_USB_SUPPLY | WM8350_BATT_SUPPLY;
+ else if (co & WM8350_WALL_FB_OVRDE)
+ supplies = WM8350_LINE_SUPPLY;
+ else
+ supplies = WM8350_BATT_SUPPLY;
+
+ return supplies;
+}
+
+static int wm8350_charger_config(struct wm8350 *wm8350,
+ struct wm8350_charger_policy *policy)
+{
+ u16 reg, eoc_mA, fast_limit_mA;
+
+ if (!policy) {
+ dev_warn(wm8350->dev,
+ "No charger policy, charger not configured.\n");
+ return -EINVAL;
+ }
+
+ /* make sure USB fast charge current is not > 500mA */
+ if (policy->fast_limit_USB_mA > 500) {
+ dev_err(wm8350->dev, "USB fast charge > 500mA\n");
+ return -EINVAL;
+ }
+
+ eoc_mA = WM8350_CHG_EOC_mA(policy->eoc_mA);
+
+ wm8350_reg_unlock(wm8350);
+
+ reg = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1)
+ & WM8350_CHG_ENA_R168;
+ wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1,
+ reg | eoc_mA | policy->trickle_start_mV |
+ WM8350_CHG_TRICKLE_TEMP_CHOKE |
+ WM8350_CHG_TRICKLE_USB_CHOKE |
+ WM8350_CHG_FAST_USB_THROTTLE);
+
+ if (wm8350_get_supplies(wm8350) & WM8350_USB_SUPPLY) {
+ fast_limit_mA =
+ WM8350_CHG_FAST_LIMIT_mA(policy->fast_limit_USB_mA);
+ wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2,
+ policy->charge_mV | policy->trickle_charge_USB_mA |
+ fast_limit_mA | wm8350_charge_time_min(wm8350,
+ policy->charge_timeout));
+
+ } else {
+ fast_limit_mA =
+ WM8350_CHG_FAST_LIMIT_mA(policy->fast_limit_mA);
+ wm8350_reg_write(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2,
+ policy->charge_mV | policy->trickle_charge_mA |
+ fast_limit_mA | wm8350_charge_time_min(wm8350,
+ policy->charge_timeout));
+ }
+
+ wm8350_reg_lock(wm8350);
+ return 0;
+}
+
+static int wm8350_batt_status(struct wm8350 *wm8350)
+{
+ u16 state;
+
+ state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2);
+ state &= WM8350_CHG_STS_MASK;
+
+ switch (state) {
+ case WM8350_CHG_STS_OFF:
+ return POWER_SUPPLY_STATUS_DISCHARGING;
+
+ case WM8350_CHG_STS_TRICKLE:
+ case WM8350_CHG_STS_FAST:
+ return POWER_SUPPLY_STATUS_CHARGING;
+
+ default:
+ return POWER_SUPPLY_STATUS_UNKNOWN;
+ }
+}
+
+static ssize_t charger_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct wm8350 *wm8350 = dev_get_drvdata(dev);
+ char *charge;
+ int state;
+
+ state = wm8350_reg_read(wm8350, WM8350_BATTERY_CHARGER_CONTROL_2) &
+ WM8350_CHG_STS_MASK;
+ switch (state) {
+ case WM8350_CHG_STS_OFF:
+ charge = "Charger Off";
+ break;
+ case WM8350_CHG_STS_TRICKLE:
+ charge = "Trickle Charging";
+ break;
+ case WM8350_CHG_STS_FAST:
+ charge = "Fast Charging";
+ break;
+ default:
+ return 0;
+ }
+
+ return sprintf(buf, "%s\n", charge);
+}
+
+static DEVICE_ATTR(charger_state, 0444, charger_state_show, NULL);
+
+static void wm8350_charger_handler(struct wm8350 *wm8350, int irq, void *data)
+{
+ struct wm8350_power *power = &wm8350->power;
+ struct wm8350_charger_policy *policy = power->policy;
+
+ switch (irq) {
+ case WM8350_IRQ_CHG_BAT_FAIL:
+ dev_err(wm8350->dev, "battery failed\n");
+ break;
+ case WM8350_IRQ_CHG_TO:
+ dev_err(wm8350->dev, "charger timeout\n");
+ power_supply_changed(&power->battery);
+ break;
+
+ case WM8350_IRQ_CHG_BAT_HOT:
+ case WM8350_IRQ_CHG_BAT_COLD:
+ case WM8350_IRQ_CHG_START:
+ case WM8350_IRQ_CHG_END:
+ power_supply_changed(&power->battery);
+ break;
+
+ case WM8350_IRQ_CHG_FAST_RDY:
+ dev_dbg(wm8350->dev, "fast charger ready\n");
+ wm8350_charger_config(wm8350, policy);
+ wm8350_reg_unlock(wm8350);
+ wm8350_set_bits(wm8350, WM8350_BATTERY_CHARGER_CONTROL_1,
+ WM8350_CHG_FAST);
+ wm8350_reg_lock(wm8350);
+ break;
+
+ case WM8350_IRQ_CHG_VBATT_LT_3P9:
+ dev_warn(wm8350->dev, "battery < 3.9V\n");
+ break;
+ case WM8350_IRQ_CHG_VBATT_LT_3P1:
+ dev_warn(wm8350->dev, "battery < 3.1V\n");
+ break;
+ case WM8350_IRQ_CHG_VBATT_LT_2P85:
+ dev_warn(wm8350->dev, "battery < 2.85V\n");
+ break;
+
+ /* Supply change. We will overnotify but it should do
+ * no harm. */
+ case WM8350_IRQ_EXT_USB_FB:
+ case WM8350_IRQ_EXT_WALL_FB:
+ wm8350_charger_config(wm8350, policy);
+ case WM8350_IRQ_EXT_BAT_FB: /* Fall through */
+ power_supply_changed(&power->battery);
+ power_supply_changed(&power->usb);
+ power_supply_changed(&power->ac);
+ break;
+
+ default:
+ dev_err(wm8350->dev, "Unknown interrupt %d\n", irq);
+ }
+}
+
+/*********************************************************************
+ * AC Power
+ *********************************************************************/
+static int wm8350_ac_get_prop(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct wm8350 *wm8350 = dev_get_drvdata(psy->dev->parent);
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = !!(wm8350_get_supplies(wm8350) &
+ WM8350_LINE_SUPPLY);
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = wm8350_read_line_uvolts(wm8350);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static enum power_supply_property wm8350_ac_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+/*********************************************************************
+ * USB Power
+ *********************************************************************/
+static int wm8350_usb_get_prop(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct wm8350 *wm8350 = dev_get_drvdata(psy->dev->parent);
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = !!(wm8350_get_supplies(wm8350) &
+ WM8350_USB_SUPPLY);
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = wm8350_read_usb_uvolts(wm8350);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static enum power_supply_property wm8350_usb_props[] = {
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+};
+
+/*********************************************************************
+ * Battery properties
+ *********************************************************************/
+
+static int wm8350_bat_check_health(struct wm8350 *wm8350)
+{
+ u16 reg;
+
+ if (wm8350_read_battery_uvolts(wm8350) < 2850000)
+ return POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+
+ reg = wm8350_reg_read(wm8350, WM8350_CHARGER_OVERRIDES);
+ if (reg & WM8350_CHG_BATT_HOT_OVRDE)
+ return POWER_SUPPLY_HEALTH_OVERHEAT;
+
+ if (reg & WM8350_CHG_BATT_COLD_OVRDE)
+ return POWER_SUPPLY_HEALTH_COLD;
+
+ return POWER_SUPPLY_HEALTH_GOOD;
+}
+
+static int wm8350_bat_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct wm8350 *wm8350 = dev_get_drvdata(psy->dev->parent);
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = wm8350_batt_status(wm8350);
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = !!(wm8350_get_supplies(wm8350) &
+ WM8350_BATT_SUPPLY);
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ val->intval = wm8350_read_battery_uvolts(wm8350);
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ val->intval = wm8350_bat_check_health(wm8350);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static enum power_supply_property wm8350_bat_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_HEALTH,
+};
+
+/*********************************************************************
+ * Initialisation
+ *********************************************************************/
+
+static void wm8350_init_charger(struct wm8350 *wm8350)
+{
+ /* register our interest in charger events */
+ wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT,
+ wm8350_charger_handler, NULL);
+ wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT);
+ wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD,
+ wm8350_charger_handler, NULL);
+ wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD);
+ wm8350_register_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL,
+ wm8350_charger_handler, NULL);
+ wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL);
+ wm8350_register_irq(wm8350, WM8350_IRQ_CHG_TO,
+ wm8350_charger_handler, NULL);
+ wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_TO);
+ wm8350_register_irq(wm8350, WM8350_IRQ_CHG_END,
+ wm8350_charger_handler, NULL);
+ wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_END);
+ wm8350_register_irq(wm8350, WM8350_IRQ_CHG_START,
+ wm8350_charger_handler, NULL);
+ wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_START);
+ wm8350_register_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY,
+ wm8350_charger_handler, NULL);
+ wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_FAST_RDY);
+ wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9,
+ wm8350_charger_handler, NULL);
+ wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9);
+ wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1,
+ wm8350_charger_handler, NULL);
+ wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1);
+ wm8350_register_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85,
+ wm8350_charger_handler, NULL);
+ wm8350_unmask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85);
+
+ /* and supply change events */
+ wm8350_register_irq(wm8350, WM8350_IRQ_EXT_USB_FB,
+ wm8350_charger_handler, NULL);
+ wm8350_unmask_irq(wm8350, WM8350_IRQ_EXT_USB_FB);
+ wm8350_register_irq(wm8350, WM8350_IRQ_EXT_WALL_FB,
+ wm8350_charger_handler, NULL);
+ wm8350_unmask_irq(wm8350, WM8350_IRQ_EXT_WALL_FB);
+ wm8350_register_irq(wm8350, WM8350_IRQ_EXT_BAT_FB,
+ wm8350_charger_handler, NULL);
+ wm8350_unmask_irq(wm8350, WM8350_IRQ_EXT_BAT_FB);
+}
+
+static void free_charger_irq(struct wm8350 *wm8350)
+{
+ wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_HOT);
+ wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_COLD);
+ wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CHG_BAT_FAIL);
+ wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_TO);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CHG_TO);
+ wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_END);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CHG_END);
+ wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_START);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CHG_START);
+ wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P9);
+ wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_3P1);
+ wm8350_mask_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85);
+ wm8350_free_irq(wm8350, WM8350_IRQ_CHG_VBATT_LT_2P85);
+ wm8350_mask_irq(wm8350, WM8350_IRQ_EXT_USB_FB);
+ wm8350_free_irq(wm8350, WM8350_IRQ_EXT_USB_FB);
+ wm8350_mask_irq(wm8350, WM8350_IRQ_EXT_WALL_FB);
+ wm8350_free_irq(wm8350, WM8350_IRQ_EXT_WALL_FB);
+ wm8350_mask_irq(wm8350, WM8350_IRQ_EXT_BAT_FB);
+ wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB);
+}
+
+static __devinit int wm8350_power_probe(struct platform_device *pdev)
+{
+ struct wm8350 *wm8350 = platform_get_drvdata(pdev);
+ struct wm8350_power *power = &wm8350->power;
+ struct wm8350_charger_policy *policy = power->policy;
+ struct power_supply *usb = &power->usb;
+ struct power_supply *battery = &power->battery;
+ struct power_supply *ac = &power->ac;
+ int ret;
+
+ ac->name = "wm8350-ac";
+ ac->type = POWER_SUPPLY_TYPE_MAINS;
+ ac->properties = wm8350_ac_props;
+ ac->num_properties = ARRAY_SIZE(wm8350_ac_props);
+ ac->get_property = wm8350_ac_get_prop;
+ ret = power_supply_register(&pdev->dev, ac);
+ if (ret)
+ return ret;
+
+ battery->name = "wm8350-battery";
+ battery->properties = wm8350_bat_props;
+ battery->num_properties = ARRAY_SIZE(wm8350_bat_props);
+ battery->get_property = wm8350_bat_get_property;
+ battery->use_for_apm = 1;
+ ret = power_supply_register(&pdev->dev, battery);
+ if (ret)
+ goto battery_failed;
+
+ usb->name = "wm8350-usb",
+ usb->type = POWER_SUPPLY_TYPE_USB;
+ usb->properties = wm8350_usb_props;
+ usb->num_properties = ARRAY_SIZE(wm8350_usb_props);
+ usb->get_property = wm8350_usb_get_prop;
+ ret = power_supply_register(&pdev->dev, usb);
+ if (ret)
+ goto usb_failed;
+
+ ret = device_create_file(&pdev->dev, &dev_attr_charger_state);
+ if (ret < 0)
+ dev_warn(wm8350->dev, "failed to add charge sysfs: %d\n", ret);
+ ret = 0;
+
+ wm8350_init_charger(wm8350);
+ if (wm8350_charger_config(wm8350, policy) == 0) {
+ wm8350_reg_unlock(wm8350);
+ wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CHG_ENA);
+ wm8350_reg_lock(wm8350);
+ }
+
+ return ret;
+
+usb_failed:
+ power_supply_unregister(battery);
+battery_failed:
+ power_supply_unregister(ac);
+
+ return ret;
+}
+
+static __devexit int wm8350_power_remove(struct platform_device *pdev)
+{
+ struct wm8350 *wm8350 = platform_get_drvdata(pdev);
+ struct wm8350_power *power = &wm8350->power;
+
+ free_charger_irq(wm8350);
+ device_remove_file(&pdev->dev, &dev_attr_charger_state);
+ power_supply_unregister(&power->battery);
+ power_supply_unregister(&power->ac);
+ power_supply_unregister(&power->usb);
+ return 0;
+}
+
+static struct platform_driver wm8350_power_driver = {
+ .probe = wm8350_power_probe,
+ .remove = __devexit_p(wm8350_power_remove),
+ .driver = {
+ .name = "wm8350-power",
+ },
+};
+
+static int __init wm8350_power_init(void)
+{
+ return platform_driver_register(&wm8350_power_driver);
+}
+module_init(wm8350_power_init);
+
+static void __exit wm8350_power_exit(void)
+{
+ platform_driver_unregister(&wm8350_power_driver);
+}
+module_exit(wm8350_power_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Power supply driver for WM8350");
+MODULE_ALIAS("platform:wm8350-power");
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
index 1f44b17e23b1..c68c496b2c49 100644
--- a/drivers/regulator/wm8350-regulator.c
+++ b/drivers/regulator/wm8350-regulator.c
@@ -1380,6 +1380,13 @@ int wm8350_register_regulator(struct wm8350 *wm8350, int reg,
if (wm8350->pmic.pdev[reg])
return -EBUSY;
+ if (reg >= WM8350_DCDC_1 && reg <= WM8350_DCDC_6 &&
+ reg > wm8350->pmic.max_dcdc)
+ return -ENODEV;
+ if (reg >= WM8350_ISINK_A && reg <= WM8350_ISINK_B &&
+ reg > wm8350->pmic.max_isink)
+ return -ENODEV;
+
pdev = platform_device_alloc("wm8350-regulator", reg);
if (!pdev)
return -ENOMEM;
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 123092d8a984..165a81843357 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -102,9 +102,13 @@ config RTC_INTF_DEV_UIE_EMUL
depends on RTC_INTF_DEV
help
Provides an emulation for RTC_UIE if the underlying rtc chip
- driver does not expose RTC_UIE ioctls. Those requests generate
+ driver does not expose RTC_UIE ioctls. Those requests generate
once-per-second update interrupts, used for synchronization.
+ The emulation code will read the time from the hardware
+ clock several times per second, please enable this option
+ only if you know that you really need it.
+
config RTC_DRV_TEST
tristate "Test driver/device"
help
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index a04c1b6b1575..fd2c652504ff 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -307,6 +307,60 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
}
EXPORT_SYMBOL_GPL(rtc_set_alarm);
+int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
+{
+ int err = mutex_lock_interruptible(&rtc->ops_lock);
+ if (err)
+ return err;
+
+ if (!rtc->ops)
+ err = -ENODEV;
+ else if (!rtc->ops->alarm_irq_enable)
+ err = -EINVAL;
+ else
+ err = rtc->ops->alarm_irq_enable(rtc->dev.parent, enabled);
+
+ mutex_unlock(&rtc->ops_lock);
+ return err;
+}
+EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable);
+
+int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
+{
+ int err = mutex_lock_interruptible(&rtc->ops_lock);
+ if (err)
+ return err;
+
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+ if (enabled == 0 && rtc->uie_irq_active) {
+ mutex_unlock(&rtc->ops_lock);
+ return rtc_dev_update_irq_enable_emul(rtc, enabled);
+ }
+#endif
+
+ if (!rtc->ops)
+ err = -ENODEV;
+ else if (!rtc->ops->update_irq_enable)
+ err = -EINVAL;
+ else
+ err = rtc->ops->update_irq_enable(rtc->dev.parent, enabled);
+
+ mutex_unlock(&rtc->ops_lock);
+
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+ /*
+ * Enable emulation if the driver did not provide
+ * the update_irq_enable function pointer or if returned
+ * -EINVAL to signal that it has been configured without
+ * interrupts or that are not available at the moment.
+ */
+ if (err == -EINVAL)
+ err = rtc_dev_update_irq_enable_emul(rtc, enabled);
+#endif
+ return err;
+}
+EXPORT_SYMBOL_GPL(rtc_update_irq_enable);
+
/**
* rtc_update_irq - report RTC periodic, alarm, and/or update irqs
* @rtc: the rtc device
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index ecdea44ae4e5..45152f4952d6 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -92,10 +92,10 @@ static void rtc_uie_timer(unsigned long data)
spin_unlock_irqrestore(&rtc->irq_lock, flags);
}
-static void clear_uie(struct rtc_device *rtc)
+static int clear_uie(struct rtc_device *rtc)
{
spin_lock_irq(&rtc->irq_lock);
- if (rtc->irq_active) {
+ if (rtc->uie_irq_active) {
rtc->stop_uie_polling = 1;
if (rtc->uie_timer_active) {
spin_unlock_irq(&rtc->irq_lock);
@@ -108,9 +108,10 @@ static void clear_uie(struct rtc_device *rtc)
flush_scheduled_work();
spin_lock_irq(&rtc->irq_lock);
}
- rtc->irq_active = 0;
+ rtc->uie_irq_active = 0;
}
spin_unlock_irq(&rtc->irq_lock);
+ return 0;
}
static int set_uie(struct rtc_device *rtc)
@@ -122,8 +123,8 @@ static int set_uie(struct rtc_device *rtc)
if (err)
return err;
spin_lock_irq(&rtc->irq_lock);
- if (!rtc->irq_active) {
- rtc->irq_active = 1;
+ if (!rtc->uie_irq_active) {
+ rtc->uie_irq_active = 1;
rtc->stop_uie_polling = 0;
rtc->oldsecs = tm.tm_sec;
rtc->uie_task_active = 1;
@@ -134,6 +135,16 @@ static int set_uie(struct rtc_device *rtc)
spin_unlock_irq(&rtc->irq_lock);
return 0;
}
+
+int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled)
+{
+ if (enabled)
+ return set_uie(rtc);
+ else
+ return clear_uie(rtc);
+}
+EXPORT_SYMBOL(rtc_dev_update_irq_enable_emul);
+
#endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */
static ssize_t
@@ -357,6 +368,22 @@ static long rtc_dev_ioctl(struct file *file,
err = rtc_irq_set_state(rtc, NULL, 0);
break;
+ case RTC_AIE_ON:
+ mutex_unlock(&rtc->ops_lock);
+ return rtc_alarm_irq_enable(rtc, 1);
+
+ case RTC_AIE_OFF:
+ mutex_unlock(&rtc->ops_lock);
+ return rtc_alarm_irq_enable(rtc, 0);
+
+ case RTC_UIE_ON:
+ mutex_unlock(&rtc->ops_lock);
+ return rtc_update_irq_enable(rtc, 1);
+
+ case RTC_UIE_OFF:
+ mutex_unlock(&rtc->ops_lock);
+ return rtc_update_irq_enable(rtc, 0);
+
case RTC_IRQP_SET:
err = rtc_irq_set_freq(rtc, NULL, arg);
break;
@@ -401,17 +428,6 @@ static long rtc_dev_ioctl(struct file *file,
err = -EFAULT;
return err;
-#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
- case RTC_UIE_OFF:
- mutex_unlock(&rtc->ops_lock);
- clear_uie(rtc);
- return 0;
-
- case RTC_UIE_ON:
- mutex_unlock(&rtc->ops_lock);
- err = set_uie(rtc);
- return err;
-#endif
default:
err = -ENOTTY;
break;
@@ -440,7 +456,10 @@ static int rtc_dev_release(struct inode *inode, struct file *file)
* Leave the alarm alone; it may be set to trigger a system wakeup
* later, or be used by kernel code, and is a one-shot event anyway.
*/
+
+ /* Keep ioctl until all drivers are converted */
rtc_dev_ioctl(file, RTC_UIE_OFF, 0);
+ rtc_update_irq_enable(rtc, 0);
rtc_irq_set_state(rtc, NULL, 0);
if (rtc->ops->release)
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index d5ccce1643e4..e0c45574b0c8 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -643,7 +643,6 @@ struct qeth_card_options {
int macaddr_mode;
int fake_broadcast;
int add_hhlen;
- int fake_ll;
int layer2;
enum qeth_large_send_types large_send;
int performance_stats;
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index e783644a2105..6811dd529f48 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -287,8 +287,15 @@ int qeth_set_large_send(struct qeth_card *card,
card->options.large_send = type;
switch (card->options.large_send) {
case QETH_LARGE_SEND_EDDP:
- card->dev->features |= NETIF_F_TSO | NETIF_F_SG |
+ if (card->info.type != QETH_CARD_TYPE_IQD) {
+ card->dev->features |= NETIF_F_TSO | NETIF_F_SG |
NETIF_F_HW_CSUM;
+ } else {
+ card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
+ NETIF_F_HW_CSUM);
+ card->options.large_send = QETH_LARGE_SEND_NO;
+ rc = -EOPNOTSUPP;
+ }
break;
case QETH_LARGE_SEND_TSO:
if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
@@ -572,6 +579,10 @@ static void qeth_send_control_data_cb(struct qeth_channel *channel,
card = CARD_FROM_CDEV(channel->ccwdev);
if (qeth_check_idx_response(iob->data)) {
qeth_clear_ipacmd_list(card);
+ if (((iob->data[2] & 0xc0) == 0xc0) && iob->data[4] == 0xf6)
+ dev_err(&card->gdev->dev,
+ "The qeth device is not configured "
+ "for the OSI layer required by z/VM\n");
qeth_schedule_recovery(card);
goto out;
}
@@ -1072,7 +1083,6 @@ static void qeth_set_intial_options(struct qeth_card *card)
card->options.macaddr_mode = QETH_TR_MACADDR_NONCANONICAL;
card->options.fake_broadcast = 0;
card->options.add_hhlen = DEFAULT_ADD_HHLEN;
- card->options.fake_ll = 0;
card->options.performance_stats = 0;
card->options.rx_sg_cb = QETH_RX_SG_CB;
}
@@ -1682,6 +1692,7 @@ int qeth_send_control_data(struct qeth_card *card, int len,
unsigned long flags;
struct qeth_reply *reply = NULL;
unsigned long timeout;
+ struct qeth_ipa_cmd *cmd;
QETH_DBF_TEXT(TRACE, 2, "sendctl");
@@ -1728,17 +1739,34 @@ int qeth_send_control_data(struct qeth_card *card, int len,
wake_up(&card->wait_q);
return rc;
}
- while (!atomic_read(&reply->received)) {
- if (time_after(jiffies, timeout)) {
- spin_lock_irqsave(&reply->card->lock, flags);
- list_del_init(&reply->list);
- spin_unlock_irqrestore(&reply->card->lock, flags);
- reply->rc = -ETIME;
- atomic_inc(&reply->received);
- wake_up(&reply->wait_q);
- }
- cpu_relax();
- };
+
+ /* we have only one long running ipassist, since we can ensure
+ process context of this command we can sleep */
+ cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
+ if ((cmd->hdr.command == IPA_CMD_SETIP) &&
+ (cmd->hdr.prot_version == QETH_PROT_IPV4)) {
+ if (!wait_event_timeout(reply->wait_q,
+ atomic_read(&reply->received), timeout))
+ goto time_err;
+ } else {
+ while (!atomic_read(&reply->received)) {
+ if (time_after(jiffies, timeout))
+ goto time_err;
+ cpu_relax();
+ };
+ }
+
+ rc = reply->rc;
+ qeth_put_reply(reply);
+ return rc;
+
+time_err:
+ spin_lock_irqsave(&reply->card->lock, flags);
+ list_del_init(&reply->list);
+ spin_unlock_irqrestore(&reply->card->lock, flags);
+ reply->rc = -ETIME;
+ atomic_inc(&reply->received);
+ wake_up(&reply->wait_q);
rc = reply->rc;
qeth_put_reply(reply);
return rc;
@@ -2250,7 +2278,8 @@ void qeth_print_status_message(struct qeth_card *card)
}
/* fallthrough */
case QETH_CARD_TYPE_IQD:
- if (card->info.guestlan) {
+ if ((card->info.guestlan) ||
+ (card->info.mcl_level[0] & 0x80)) {
card->info.mcl_level[0] = (char) _ebcasc[(__u8)
card->info.mcl_level[0]];
card->info.mcl_level[1] = (char) _ebcasc[(__u8)
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 2c48591ced44..21627ba3093b 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -1126,9 +1126,11 @@ static int qeth_l2_recover(void *ptr)
dev_info(&card->gdev->dev,
"Device successfully recovered!\n");
else {
- rtnl_lock();
- dev_close(card->dev);
- rtnl_unlock();
+ if (card->dev) {
+ rtnl_lock();
+ dev_close(card->dev);
+ rtnl_unlock();
+ }
dev_warn(&card->gdev->dev, "The qeth device driver "
"failed to recover an error on the device\n");
}
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index c0b30b25a5f1..cfda1ecffdf2 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -1047,7 +1047,7 @@ static int qeth_l3_setadapter_parms(struct qeth_card *card)
rc = qeth_setadpparms_change_macaddr(card);
if (rc)
dev_warn(&card->gdev->dev, "Reading the adapter MAC"
- " address failed\n", rc);
+ " address failed\n");
}
if ((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
@@ -1207,12 +1207,9 @@ static int qeth_l3_start_ipa_source_mac(struct qeth_card *card)
QETH_DBF_TEXT(TRACE, 3, "stsrcmac");
- if (!card->options.fake_ll)
- return -EOPNOTSUPP;
-
if (!qeth_is_supported(card, IPA_SOURCE_MAC)) {
dev_info(&card->gdev->dev,
- "Inbound source address not supported on %s\n",
+ "Inbound source MAC-address not supported on %s\n",
QETH_CARD_IFNAME(card));
return -EOPNOTSUPP;
}
@@ -1221,7 +1218,7 @@ static int qeth_l3_start_ipa_source_mac(struct qeth_card *card)
IPA_CMD_ASS_START, 0);
if (rc)
dev_warn(&card->gdev->dev,
- "Starting proxy ARP support for %s failed\n",
+ "Starting source MAC-address support for %s failed\n",
QETH_CARD_IFNAME(card));
return rc;
}
@@ -1921,8 +1918,13 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card,
memcpy(tg_addr, card->dev->dev_addr,
card->dev->addr_len);
}
- card->dev->header_ops->create(skb, card->dev, prot, tg_addr,
- "FAKELL", card->dev->addr_len);
+ if (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR)
+ card->dev->header_ops->create(skb, card->dev, prot,
+ tg_addr, &hdr->hdr.l3.dest_addr[2],
+ card->dev->addr_len);
+ else
+ card->dev->header_ops->create(skb, card->dev, prot,
+ tg_addr, "FAKELL", card->dev->addr_len);
}
#ifdef CONFIG_TR
@@ -2080,9 +2082,11 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode)
if (recovery_mode)
qeth_l3_stop(card->dev);
else {
- rtnl_lock();
- dev_close(card->dev);
- rtnl_unlock();
+ if (card->dev) {
+ rtnl_lock();
+ dev_close(card->dev);
+ rtnl_unlock();
+ }
}
if (!card->use_hard_stop) {
rc = qeth_send_stoplan(card);
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 185be760833e..2a129cb7bb56 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -279,7 +279,6 @@ static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t de
inode->i_mode = mode;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
- inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
switch (mode & S_IFMT) {
default:
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index c4e62a6297d7..2e71368f45b4 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -1863,26 +1863,10 @@ static int do_write(struct fsg_dev *fsg)
static int fsync_sub(struct lun *curlun)
{
struct file *filp = curlun->filp;
- struct inode *inode;
- int rc, err;
if (curlun->ro || !filp)
return 0;
- if (!filp->f_op->fsync)
- return -EINVAL;
-
- inode = filp->f_path.dentry->d_inode;
- mutex_lock(&inode->i_mutex);
- rc = filemap_fdatawrite(inode->i_mapping);
- err = filp->f_op->fsync(filp, filp->f_path.dentry, 1);
- if (!rc)
- rc = err;
- err = filemap_fdatawait(inode->i_mapping);
- if (!rc)
- rc = err;
- mutex_unlock(&inode->i_mutex);
- VLDBG(curlun, "fdatasync -> %d\n", rc);
- return rc;
+ return vfs_fsync(filp, filp->f_path.dentry, 1);
}
static void fsync_all(struct fsg_dev *fsg)
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index eeb26c0f88e5..317b48fdbf01 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -2001,7 +2001,6 @@ gadgetfs_make_inode (struct super_block *sb,
inode->i_mode = mode;
inode->i_uid = default_uid;
inode->i_gid = default_gid;
- inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime
= CURRENT_TIME;
inode->i_private = data;
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index 73ac754ad801..e21fe5b6f9ff 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -546,23 +546,25 @@ static int viafb_blank(int blank_mode, struct fb_info *info)
static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
{
- struct viafb_ioctl_mode viamode;
- struct viafb_ioctl_samm viasamm;
- struct viafb_driver_version driver_version;
- struct fb_var_screeninfo sec_var;
- struct _panel_size_pos_info panel_pos_size_para;
+ union {
+ struct viafb_ioctl_mode viamode;
+ struct viafb_ioctl_samm viasamm;
+ struct viafb_driver_version driver_version;
+ struct fb_var_screeninfo sec_var;
+ struct _panel_size_pos_info panel_pos_size_para;
+ struct viafb_ioctl_setting viafb_setting;
+ struct device_t active_dev;
+ } u;
u32 state_info = 0;
- u32 viainfo_size = sizeof(struct viafb_ioctl_info);
u32 *viafb_gamma_table;
char driver_name[] = "viafb";
u32 __user *argp = (u32 __user *) arg;
u32 gpu32;
u32 video_dev_info = 0;
- struct viafb_ioctl_setting viafb_setting = {};
- struct device_t active_dev = {};
DEBUG_MSG(KERN_INFO "viafb_ioctl: 0x%X !!\n", cmd);
+ memset(&u, 0, sizeof(u));
switch (cmd) {
case VIAFB_GET_CHIP_INFO:
@@ -571,7 +573,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
return -EFAULT;
break;
case VIAFB_GET_INFO_SIZE:
- return put_user(viainfo_size, argp);
+ return put_user((u32)sizeof(struct viafb_ioctl_info), argp);
case VIAFB_GET_INFO:
return viafb_ioctl_get_viafb_info(arg);
case VIAFB_HOTPLUG:
@@ -584,60 +586,60 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
viafb_hotplug = (gpu32) ? 1 : 0;
break;
case VIAFB_GET_RESOLUTION:
- viamode.xres = (u32) viafb_hotplug_Xres;
- viamode.yres = (u32) viafb_hotplug_Yres;
- viamode.refresh = (u32) viafb_hotplug_refresh;
- viamode.bpp = (u32) viafb_hotplug_bpp;
+ u.viamode.xres = (u32) viafb_hotplug_Xres;
+ u.viamode.yres = (u32) viafb_hotplug_Yres;
+ u.viamode.refresh = (u32) viafb_hotplug_refresh;
+ u.viamode.bpp = (u32) viafb_hotplug_bpp;
if (viafb_SAMM_ON == 1) {
- viamode.xres_sec = viafb_second_xres;
- viamode.yres_sec = viafb_second_yres;
- viamode.virtual_xres_sec = viafb_second_virtual_xres;
- viamode.virtual_yres_sec = viafb_second_virtual_yres;
- viamode.refresh_sec = viafb_refresh1;
- viamode.bpp_sec = viafb_bpp1;
+ u.viamode.xres_sec = viafb_second_xres;
+ u.viamode.yres_sec = viafb_second_yres;
+ u.viamode.virtual_xres_sec = viafb_second_virtual_xres;
+ u.viamode.virtual_yres_sec = viafb_second_virtual_yres;
+ u.viamode.refresh_sec = viafb_refresh1;
+ u.viamode.bpp_sec = viafb_bpp1;
} else {
- viamode.xres_sec = 0;
- viamode.yres_sec = 0;
- viamode.virtual_xres_sec = 0;
- viamode.virtual_yres_sec = 0;
- viamode.refresh_sec = 0;
- viamode.bpp_sec = 0;
+ u.viamode.xres_sec = 0;
+ u.viamode.yres_sec = 0;
+ u.viamode.virtual_xres_sec = 0;
+ u.viamode.virtual_yres_sec = 0;
+ u.viamode.refresh_sec = 0;
+ u.viamode.bpp_sec = 0;
}
- if (copy_to_user(argp, &viamode, sizeof(viamode)))
+ if (copy_to_user(argp, &u.viamode, sizeof(u.viamode)))
return -EFAULT;
break;
case VIAFB_GET_SAMM_INFO:
- viasamm.samm_status = viafb_SAMM_ON;
+ u.viasamm.samm_status = viafb_SAMM_ON;
if (viafb_SAMM_ON == 1) {
if (viafb_dual_fb) {
- viasamm.size_prim = viaparinfo->fbmem_free;
- viasamm.size_sec = viaparinfo1->fbmem_free;
+ u.viasamm.size_prim = viaparinfo->fbmem_free;
+ u.viasamm.size_sec = viaparinfo1->fbmem_free;
} else {
if (viafb_second_size) {
- viasamm.size_prim =
+ u.viasamm.size_prim =
viaparinfo->fbmem_free -
viafb_second_size * 1024 * 1024;
- viasamm.size_sec =
+ u.viasamm.size_sec =
viafb_second_size * 1024 * 1024;
} else {
- viasamm.size_prim =
+ u.viasamm.size_prim =
viaparinfo->fbmem_free >> 1;
- viasamm.size_sec =
+ u.viasamm.size_sec =
(viaparinfo->fbmem_free >> 1);
}
}
- viasamm.mem_base = viaparinfo->fbmem;
- viasamm.offset_sec = viafb_second_offset;
+ u.viasamm.mem_base = viaparinfo->fbmem;
+ u.viasamm.offset_sec = viafb_second_offset;
} else {
- viasamm.size_prim =
+ u.viasamm.size_prim =
viaparinfo->memsize - viaparinfo->fbmem_used;
- viasamm.size_sec = 0;
- viasamm.mem_base = viaparinfo->fbmem;
- viasamm.offset_sec = 0;
+ u.viasamm.size_sec = 0;
+ u.viasamm.mem_base = viaparinfo->fbmem;
+ u.viasamm.offset_sec = 0;
}
- if (copy_to_user(argp, &viasamm, sizeof(viasamm)))
+ if (copy_to_user(argp, &u.viasamm, sizeof(u.viasamm)))
return -EFAULT;
break;
@@ -662,74 +664,75 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
viafb_lcd_disable();
break;
case VIAFB_SET_DEVICE:
- if (copy_from_user(&active_dev, (void *)argp,
- sizeof(active_dev)))
+ if (copy_from_user(&u.active_dev, (void *)argp,
+ sizeof(u.active_dev)))
return -EFAULT;
- viafb_set_device(active_dev);
+ viafb_set_device(u.active_dev);
viafb_set_par(info);
break;
case VIAFB_GET_DEVICE:
- active_dev.crt = viafb_CRT_ON;
- active_dev.dvi = viafb_DVI_ON;
- active_dev.lcd = viafb_LCD_ON;
- active_dev.samm = viafb_SAMM_ON;
- active_dev.primary_dev = viafb_primary_dev;
+ u.active_dev.crt = viafb_CRT_ON;
+ u.active_dev.dvi = viafb_DVI_ON;
+ u.active_dev.lcd = viafb_LCD_ON;
+ u.active_dev.samm = viafb_SAMM_ON;
+ u.active_dev.primary_dev = viafb_primary_dev;
- active_dev.lcd_dsp_cent = viafb_lcd_dsp_method;
- active_dev.lcd_panel_id = viafb_lcd_panel_id;
- active_dev.lcd_mode = viafb_lcd_mode;
+ u.active_dev.lcd_dsp_cent = viafb_lcd_dsp_method;
+ u.active_dev.lcd_panel_id = viafb_lcd_panel_id;
+ u.active_dev.lcd_mode = viafb_lcd_mode;
- active_dev.xres = viafb_hotplug_Xres;
- active_dev.yres = viafb_hotplug_Yres;
+ u.active_dev.xres = viafb_hotplug_Xres;
+ u.active_dev.yres = viafb_hotplug_Yres;
- active_dev.xres1 = viafb_second_xres;
- active_dev.yres1 = viafb_second_yres;
+ u.active_dev.xres1 = viafb_second_xres;
+ u.active_dev.yres1 = viafb_second_yres;
- active_dev.bpp = viafb_bpp;
- active_dev.bpp1 = viafb_bpp1;
- active_dev.refresh = viafb_refresh;
- active_dev.refresh1 = viafb_refresh1;
+ u.active_dev.bpp = viafb_bpp;
+ u.active_dev.bpp1 = viafb_bpp1;
+ u.active_dev.refresh = viafb_refresh;
+ u.active_dev.refresh1 = viafb_refresh1;
- active_dev.epia_dvi = viafb_platform_epia_dvi;
- active_dev.lcd_dual_edge = viafb_device_lcd_dualedge;
- active_dev.bus_width = viafb_bus_width;
+ u.active_dev.epia_dvi = viafb_platform_epia_dvi;
+ u.active_dev.lcd_dual_edge = viafb_device_lcd_dualedge;
+ u.active_dev.bus_width = viafb_bus_width;
- if (copy_to_user(argp, &active_dev, sizeof(active_dev)))
+ if (copy_to_user(argp, &u.active_dev, sizeof(u.active_dev)))
return -EFAULT;
break;
case VIAFB_GET_DRIVER_VERSION:
- driver_version.iMajorNum = VERSION_MAJOR;
- driver_version.iKernelNum = VERSION_KERNEL;
- driver_version.iOSNum = VERSION_OS;
- driver_version.iMinorNum = VERSION_MINOR;
+ u.driver_version.iMajorNum = VERSION_MAJOR;
+ u.driver_version.iKernelNum = VERSION_KERNEL;
+ u.driver_version.iOSNum = VERSION_OS;
+ u.driver_version.iMinorNum = VERSION_MINOR;
- if (copy_to_user(argp, &driver_version,
- sizeof(driver_version)))
+ if (copy_to_user(argp, &u.driver_version,
+ sizeof(u.driver_version)))
return -EFAULT;
break;
case VIAFB_SET_DEVICE_INFO:
- if (copy_from_user(&viafb_setting,
- argp, sizeof(viafb_setting)))
+ if (copy_from_user(&u.viafb_setting,
+ argp, sizeof(u.viafb_setting)))
return -EFAULT;
- if (apply_device_setting(viafb_setting, info) < 0)
+ if (apply_device_setting(u.viafb_setting, info) < 0)
return -EINVAL;
break;
case VIAFB_SET_SECOND_MODE:
- if (copy_from_user(&sec_var, argp, sizeof(sec_var)))
+ if (copy_from_user(&u.sec_var, argp, sizeof(u.sec_var)))
return -EFAULT;
- apply_second_mode_setting(&sec_var);
+ apply_second_mode_setting(&u.sec_var);
break;
case VIAFB_GET_DEVICE_INFO:
- retrieve_device_setting(&viafb_setting);
+ retrieve_device_setting(&u.viafb_setting);
- if (copy_to_user(argp, &viafb_setting, sizeof(viafb_setting)))
+ if (copy_to_user(argp, &u.viafb_setting,
+ sizeof(u.viafb_setting)))
return -EFAULT;
break;
@@ -806,51 +809,51 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
break;
case VIAFB_GET_PANEL_MAX_SIZE:
- if (copy_from_user
- (&panel_pos_size_para, argp, sizeof(panel_pos_size_para)))
+ if (copy_from_user(&u.panel_pos_size_para, argp,
+ sizeof(u.panel_pos_size_para)))
return -EFAULT;
- panel_pos_size_para.x = panel_pos_size_para.y = 0;
- if (copy_to_user(argp, &panel_pos_size_para,
- sizeof(panel_pos_size_para)))
+ u.panel_pos_size_para.x = u.panel_pos_size_para.y = 0;
+ if (copy_to_user(argp, &u.panel_pos_size_para,
+ sizeof(u.panel_pos_size_para)))
return -EFAULT;
break;
case VIAFB_GET_PANEL_MAX_POSITION:
- if (copy_from_user
- (&panel_pos_size_para, argp, sizeof(panel_pos_size_para)))
+ if (copy_from_user(&u.panel_pos_size_para, argp,
+ sizeof(u.panel_pos_size_para)))
return -EFAULT;
- panel_pos_size_para.x = panel_pos_size_para.y = 0;
- if (copy_to_user(argp, &panel_pos_size_para,
- sizeof(panel_pos_size_para)))
+ u.panel_pos_size_para.x = u.panel_pos_size_para.y = 0;
+ if (copy_to_user(argp, &u.panel_pos_size_para,
+ sizeof(u.panel_pos_size_para)))
return -EFAULT;
break;
case VIAFB_GET_PANEL_POSITION:
- if (copy_from_user
- (&panel_pos_size_para, argp, sizeof(panel_pos_size_para)))
+ if (copy_from_user(&u.panel_pos_size_para, argp,
+ sizeof(u.panel_pos_size_para)))
return -EFAULT;
- panel_pos_size_para.x = panel_pos_size_para.y = 0;
- if (copy_to_user(argp, &panel_pos_size_para,
- sizeof(panel_pos_size_para)))
+ u.panel_pos_size_para.x = u.panel_pos_size_para.y = 0;
+ if (copy_to_user(argp, &u.panel_pos_size_para,
+ sizeof(u.panel_pos_size_para)))
return -EFAULT;
break;
case VIAFB_GET_PANEL_SIZE:
- if (copy_from_user
- (&panel_pos_size_para, argp, sizeof(panel_pos_size_para)))
+ if (copy_from_user(&u.panel_pos_size_para, argp,
+ sizeof(u.panel_pos_size_para)))
return -EFAULT;
- panel_pos_size_para.x = panel_pos_size_para.y = 0;
- if (copy_to_user(argp, &panel_pos_size_para,
- sizeof(panel_pos_size_para)))
+ u.panel_pos_size_para.x = u.panel_pos_size_para.y = 0;
+ if (copy_to_user(argp, &u.panel_pos_size_para,
+ sizeof(u.panel_pos_size_para)))
return -EFAULT;
break;
case VIAFB_SET_PANEL_POSITION:
- if (copy_from_user
- (&panel_pos_size_para, argp, sizeof(panel_pos_size_para)))
+ if (copy_from_user(&u.panel_pos_size_para, argp,
+ sizeof(u.panel_pos_size_para)))
return -EFAULT;
break;
case VIAFB_SET_PANEL_SIZE:
- if (copy_from_user
- (&panel_pos_size_para, argp, sizeof(panel_pos_size_para)))
+ if (copy_from_user(&u.panel_pos_size_para, argp,
+ sizeof(u.panel_pos_size_para)))
return -EFAULT;
break;
@@ -1052,10 +1055,8 @@ static void viafb_imageblit(struct fb_info *info,
static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
- u8 data[CURSOR_SIZE / 8];
- u32 data_bak[CURSOR_SIZE / 32];
u32 temp, xx, yy, bg_col = 0, fg_col = 0;
- int size, i, j = 0;
+ int i, j = 0;
static int hw_cursor;
struct viafb_par *p_viafb_par;
@@ -1178,22 +1179,29 @@ static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
}
if (cursor->set & FB_CUR_SETSHAPE) {
- size =
+ struct {
+ u8 data[CURSOR_SIZE / 8];
+ u32 bak[CURSOR_SIZE / 32];
+ } *cr_data = kzalloc(sizeof(*cr_data), GFP_ATOMIC);
+ int size =
((viacursor.image.width + 7) >> 3) *
viacursor.image.height;
+ if (cr_data == NULL)
+ goto out;
+
if (MAX_CURS == 32) {
for (i = 0; i < (CURSOR_SIZE / 32); i++) {
- data_bak[i] = 0x0;
- data_bak[i + 1] = 0xFFFFFFFF;
+ cr_data->bak[i] = 0x0;
+ cr_data->bak[i + 1] = 0xFFFFFFFF;
i += 1;
}
} else if (MAX_CURS == 64) {
for (i = 0; i < (CURSOR_SIZE / 32); i++) {
- data_bak[i] = 0x0;
- data_bak[i + 1] = 0x0;
- data_bak[i + 2] = 0xFFFFFFFF;
- data_bak[i + 3] = 0xFFFFFFFF;
+ cr_data->bak[i] = 0x0;
+ cr_data->bak[i + 1] = 0x0;
+ cr_data->bak[i + 2] = 0xFFFFFFFF;
+ cr_data->bak[i + 3] = 0xFFFFFFFF;
i += 3;
}
}
@@ -1201,12 +1209,12 @@ static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
switch (viacursor.rop) {
case ROP_XOR:
for (i = 0; i < size; i++)
- data[i] = viacursor.mask[i];
+ cr_data->data[i] = viacursor.mask[i];
break;
case ROP_COPY:
for (i = 0; i < size; i++)
- data[i] = viacursor.mask[i];
+ cr_data->data[i] = viacursor.mask[i];
break;
default:
break;
@@ -1214,23 +1222,25 @@ static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
if (MAX_CURS == 32) {
for (i = 0; i < size; i++) {
- data_bak[j] = (u32) data[i];
- data_bak[j + 1] = ~data_bak[j];
+ cr_data->bak[j] = (u32) cr_data->data[i];
+ cr_data->bak[j + 1] = ~cr_data->bak[j];
j += 2;
}
} else if (MAX_CURS == 64) {
for (i = 0; i < size; i++) {
- data_bak[j] = (u32) data[i];
- data_bak[j + 1] = 0x0;
- data_bak[j + 2] = ~data_bak[j];
- data_bak[j + 3] = ~data_bak[j + 1];
+ cr_data->bak[j] = (u32) cr_data->data[i];
+ cr_data->bak[j + 1] = 0x0;
+ cr_data->bak[j + 2] = ~cr_data->bak[j];
+ cr_data->bak[j + 3] = ~cr_data->bak[j + 1];
j += 4;
}
}
memcpy(((struct viafb_par *)(info->par))->fbmem_virt +
((struct viafb_par *)(info->par))->cursor_start,
- data_bak, CURSOR_SIZE);
+ cr_data->bak, CURSOR_SIZE);
+out:
+ kfree(cr_data);
}
if (viacursor.enable)