diff options
Diffstat (limited to 'drivers')
1024 files changed, 28201 insertions, 11494 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 119d58db834..0300bf61294 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -181,6 +181,12 @@ config ACPI_DOCK This driver supports ACPI-controlled docking stations and removable drive bays such as the IBM Ultrabay and the Dell Module Bay. +config ACPI_I2C + def_tristate I2C + depends on I2C + help + ACPI I2C enumeration support. + config ACPI_PROCESSOR tristate "Processor" select THERMAL diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 82422fe90f8..2a4502becd1 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -21,9 +21,10 @@ obj-y += acpi.o \ acpi-y += osl.o utils.o reboot.o acpi-y += nvs.o -# sleep related files +# Power management related files acpi-y += wakeup.o acpi-y += sleep.o +acpi-$(CONFIG_PM) += device_pm.o acpi-$(CONFIG_ACPI_SLEEP) += proc.o @@ -32,10 +33,12 @@ acpi-$(CONFIG_ACPI_SLEEP) += proc.o # acpi-y += bus.o glue.o acpi-y += scan.o +acpi-y += resource.o acpi-y += processor_core.o acpi-y += ec.o acpi-$(CONFIG_ACPI_DOCK) += dock.o acpi-y += pci_root.o pci_link.o pci_irq.o pci_bind.o +acpi-y += acpi_platform.o acpi-y += power.o acpi-y += event.o acpi-y += sysfs.o @@ -67,6 +70,7 @@ obj-$(CONFIG_ACPI_HED) += hed.o obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o obj-$(CONFIG_ACPI_BGRT) += bgrt.o +obj-$(CONFIG_ACPI_I2C) += acpi_i2c.o # processor has its own "processor." module_param namespace processor-y := processor_driver.o processor_throttling.o diff --git a/drivers/acpi/acpi_i2c.c b/drivers/acpi/acpi_i2c.c new file mode 100644 index 00000000000..82045e3f5ca --- /dev/null +++ b/drivers/acpi/acpi_i2c.c @@ -0,0 +1,103 @@ +/* + * ACPI I2C enumeration support + * + * Copyright (C) 2012, Intel Corporation + * Author: Mika Westerberg <mika.westerberg@linux.intel.com> + * + * 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/acpi.h> +#include <linux/device.h> +#include <linux/export.h> +#include <linux/i2c.h> +#include <linux/ioport.h> + +ACPI_MODULE_NAME("i2c"); + +static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data) +{ + struct i2c_board_info *info = data; + + if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { + struct acpi_resource_i2c_serialbus *sb; + + sb = &ares->data.i2c_serial_bus; + if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) { + info->addr = sb->slave_address; + if (sb->access_mode == ACPI_I2C_10BIT_MODE) + info->flags |= I2C_CLIENT_TEN; + } + } else if (info->irq < 0) { + struct resource r; + + if (acpi_dev_resource_interrupt(ares, 0, &r)) + info->irq = r.start; + } + + /* Tell the ACPI core to skip this resource */ + return 1; +} + +static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, + void *data, void **return_value) +{ + struct i2c_adapter *adapter = data; + struct list_head resource_list; + struct i2c_board_info info; + struct acpi_device *adev; + int ret; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + if (acpi_bus_get_status(adev) || !adev->status.present) + return AE_OK; + + memset(&info, 0, sizeof(info)); + info.acpi_node.handle = handle; + info.irq = -1; + + INIT_LIST_HEAD(&resource_list); + ret = acpi_dev_get_resources(adev, &resource_list, + acpi_i2c_add_resource, &info); + acpi_dev_free_resource_list(&resource_list); + + if (ret < 0 || !info.addr) + return AE_OK; + + strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type)); + if (!i2c_new_device(adapter, &info)) { + dev_err(&adapter->dev, + "failed to add I2C device %s from ACPI\n", + dev_name(&adev->dev)); + } + + return AE_OK; +} + +/** + * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter + * @adapter: pointer to adapter + * + * Enumerate all I2C slave devices behind this adapter by walking the ACPI + * namespace. When a device is found it will be added to the Linux device + * model and bound to the corresponding ACPI handle. + */ +void acpi_i2c_register_devices(struct i2c_adapter *adapter) +{ + acpi_handle handle; + acpi_status status; + + handle = ACPI_HANDLE(&adapter->dev); + if (!handle) + return; + + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + acpi_i2c_add_device, NULL, + adapter, NULL); + if (ACPI_FAILURE(status)) + dev_warn(&adapter->dev, "failed to enumerate I2C slaves\n"); +} +EXPORT_SYMBOL_GPL(acpi_i2c_register_devices); diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index 24c807f9663..eb30e5ab4ca 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -31,6 +31,7 @@ #include <linux/types.h> #include <linux/memory_hotplug.h> #include <linux/slab.h> +#include <linux/acpi.h> #include <acpi/acpi_drivers.h> #define ACPI_MEMORY_DEVICE_CLASS "memory" @@ -78,6 +79,7 @@ struct acpi_memory_info { unsigned short caching; /* memory cache attribute */ unsigned short write_protect; /* memory read/write attribute */ unsigned int enabled:1; + unsigned int failed:1; }; struct acpi_memory_device { @@ -86,8 +88,6 @@ struct acpi_memory_device { struct list_head res_list; }; -static int acpi_hotmem_initialized; - static acpi_status acpi_memory_get_resource(struct acpi_resource *resource, void *context) { @@ -125,12 +125,20 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context) return AE_OK; } +static void +acpi_memory_free_device_resources(struct acpi_memory_device *mem_device) +{ + struct acpi_memory_info *info, *n; + + list_for_each_entry_safe(info, n, &mem_device->res_list, list) + kfree(info); + INIT_LIST_HEAD(&mem_device->res_list); +} + static int acpi_memory_get_device_resources(struct acpi_memory_device *mem_device) { acpi_status status; - struct acpi_memory_info *info, *n; - if (!list_empty(&mem_device->res_list)) return 0; @@ -138,9 +146,7 @@ acpi_memory_get_device_resources(struct acpi_memory_device *mem_device) status = acpi_walk_resources(mem_device->device->handle, METHOD_NAME__CRS, acpi_memory_get_resource, mem_device); if (ACPI_FAILURE(status)) { - list_for_each_entry_safe(info, n, &mem_device->res_list, list) - kfree(info); - INIT_LIST_HEAD(&mem_device->res_list); + acpi_memory_free_device_resources(mem_device); return -EINVAL; } @@ -170,7 +176,7 @@ acpi_memory_get_device(acpi_handle handle, /* Get the parent device */ result = acpi_bus_get_device(phandle, &pdevice); if (result) { - printk(KERN_WARNING PREFIX "Cannot get acpi bus device"); + acpi_handle_warn(phandle, "Cannot get acpi bus device\n"); return -EINVAL; } @@ -180,14 +186,14 @@ acpi_memory_get_device(acpi_handle handle, */ result = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE); if (result) { - printk(KERN_WARNING PREFIX "Cannot add acpi bus"); + acpi_handle_warn(handle, "Cannot add acpi bus\n"); return -EINVAL; } end: *mem_device = acpi_driver_data(device); if (!(*mem_device)) { - printk(KERN_ERR "\n driver data not found"); + dev_err(&device->dev, "driver data not found\n"); return -ENODEV; } @@ -224,7 +230,8 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) /* Get the range from the _CRS */ result = acpi_memory_get_device_resources(mem_device); if (result) { - printk(KERN_ERR PREFIX "get_device_resources failed\n"); + dev_err(&mem_device->device->dev, + "get_device_resources failed\n"); mem_device->state = MEMORY_INVALID_STATE; return result; } @@ -251,13 +258,27 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) node = memory_add_physaddr_to_nid(info->start_addr); result = add_memory(node, info->start_addr, info->length); - if (result) + + /* + * If the memory block has been used by the kernel, add_memory() + * returns -EEXIST. If add_memory() returns the other error, it + * means that this memory block is not used by the kernel. + */ + if (result && result != -EEXIST) { + info->failed = 1; continue; - info->enabled = 1; + } + + if (!result) + info->enabled = 1; + /* + * Add num_enable even if add_memory() returns -EEXIST, so the + * device is bound to this driver. + */ num_enabled++; } if (!num_enabled) { - printk(KERN_ERR PREFIX "add_memory failed\n"); + dev_err(&mem_device->device->dev, "add_memory failed\n"); mem_device->state = MEMORY_INVALID_STATE; return -EINVAL; } @@ -272,68 +293,31 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) return 0; } -static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device) +static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device) { - acpi_status status; - struct acpi_object_list arg_list; - union acpi_object arg; - unsigned long long current_status; - - - /* Issue the _EJ0 command */ - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; - status = acpi_evaluate_object(mem_device->device->handle, - "_EJ0", &arg_list, NULL); - /* Return on _EJ0 failure */ - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "_EJ0 failed")); - return -ENODEV; - } - - /* Evalute _STA to check if the device is disabled */ - status = acpi_evaluate_integer(mem_device->device->handle, "_STA", - NULL, ¤t_status); - if (ACPI_FAILURE(status)) - return -ENODEV; - - /* Check for device status. Device should be disabled */ - if (current_status & ACPI_STA_DEVICE_ENABLED) - return -EINVAL; + int result = 0; + struct acpi_memory_info *info, *n; - return 0; -} + list_for_each_entry_safe(info, n, &mem_device->res_list, list) { + if (info->failed) + /* The kernel does not use this memory block */ + continue; -static int acpi_memory_disable_device(struct acpi_memory_device *mem_device) -{ - int result; - struct acpi_memory_info *info, *n; + if (!info->enabled) + /* + * The kernel uses this memory block, but it may be not + * managed by us. + */ + return -EBUSY; + result = remove_memory(info->start_addr, info->length); + if (result) + return result; - /* - * Ask the VM to offline this memory range. - * Note: Assume that this function returns zero on success - */ - list_for_each_entry_safe(info, n, &mem_device->res_list, list) { - if (info->enabled) { - result = remove_memory(info->start_addr, info->length); - if (result) - return result; - } + list_del(&info->list); kfree(info); } - /* Power-off and eject the device */ - result = acpi_memory_powerdown_device(mem_device); - if (result) { - /* Set the status of the device to invalid */ - mem_device->state = MEMORY_INVALID_STATE; - return result; - } - - mem_device->state = MEMORY_POWER_OFF_STATE; return result; } @@ -341,6 +325,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) { struct acpi_memory_device *mem_device; struct acpi_device *device; + struct acpi_eject_event *ej_event = NULL; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ switch (event) { @@ -353,7 +338,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "\nReceived DEVICE CHECK notification for device\n")); if (acpi_memory_get_device(handle, &mem_device)) { - printk(KERN_ERR PREFIX "Cannot find driver data\n"); + acpi_handle_err(handle, "Cannot find driver data\n"); break; } @@ -361,7 +346,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) break; if (acpi_memory_enable_device(mem_device)) { - printk(KERN_ERR PREFIX "Cannot enable memory device\n"); + acpi_handle_err(handle,"Cannot enable memory device\n"); break; } @@ -373,40 +358,28 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) "\nReceived EJECT REQUEST notification for device\n")); if (acpi_bus_get_device(handle, &device)) { - printk(KERN_ERR PREFIX "Device doesn't exist\n"); + acpi_handle_err(handle, "Device doesn't exist\n"); break; } mem_device = acpi_driver_data(device); if (!mem_device) { - printk(KERN_ERR PREFIX "Driver Data is NULL\n"); + acpi_handle_err(handle, "Driver Data is NULL\n"); break; } - /* - * Currently disabling memory device from kernel mode - * TBD: Can also be disabled from user mode scripts - * TBD: Can also be disabled by Callback registration - * with generic sysfs driver - */ - if (acpi_memory_disable_device(mem_device)) { - printk(KERN_ERR PREFIX "Disable memory device\n"); - /* - * If _EJ0 was called but failed, _OST is not - * necessary. - */ - if (mem_device->state == MEMORY_INVALID_STATE) - return; - + ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); + if (!ej_event) { + pr_err(PREFIX "No memory, dropping EJECT\n"); break; } - /* - * TBD: Invoke acpi_bus_remove to cleanup data structures - */ + ej_event->handle = handle; + ej_event->event = ACPI_NOTIFY_EJECT_REQUEST; + acpi_os_hotplug_execute(acpi_bus_hot_remove_device, + (void *)ej_event); - /* _EJ0 succeeded; _OST is not necessary */ + /* eject is performed asynchronously */ return; - default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported event [0x%x]\n", event)); @@ -420,6 +393,15 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) return; } +static void acpi_memory_device_free(struct acpi_memory_device *mem_device) +{ + if (!mem_device) + return; + + acpi_memory_free_device_resources(mem_device); + kfree(mem_device); +} + static int acpi_memory_device_add(struct acpi_device *device) { int result; @@ -449,23 +431,16 @@ static int acpi_memory_device_add(struct acpi_device *device) /* Set the device state */ mem_device->state = MEMORY_POWER_ON_STATE; - printk(KERN_DEBUG "%s \n", acpi_device_name(device)); - - /* - * Early boot code has recognized memory area by EFI/E820. - * If DSDT shows these memory devices on boot, hotplug is not necessary - * for them. So, it just returns until completion of this driver's - * start up. - */ - if (!acpi_hotmem_initialized) - return 0; + pr_debug("%s\n", acpi_device_name(device)); if (!acpi_memory_check_device(mem_device)) { /* call add_memory func */ result = acpi_memory_enable_device(mem_device); - if (result) - printk(KERN_ERR PREFIX + if (result) { + dev_err(&device->dev, "Error in acpi_memory_enable_device\n"); + acpi_memory_device_free(mem_device); + } } return result; } @@ -473,13 +448,18 @@ static int acpi_memory_device_add(struct acpi_device *device) static int acpi_memory_device_remove(struct acpi_device *device, int type) { struct acpi_memory_device *mem_device = NULL; - + int result; if (!device || !acpi_driver_data(device)) return -EINVAL; mem_device = acpi_driver_data(device); - kfree(mem_device); + + result = acpi_memory_remove_memory(mem_device); + if (result) + return result; + + acpi_memory_device_free(mem_device); return 0; } @@ -568,7 +548,6 @@ static int __init acpi_memory_device_init(void) return -ENODEV; } - acpi_hotmem_initialized = 1; return 0; } diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index af4aad6ee2e..16fa979f718 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -286,7 +286,7 @@ static ssize_t acpi_pad_rrtime_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long num; - if (strict_strtoul(buf, 0, &num)) + if (kstrtoul(buf, 0, &num)) return -EINVAL; if (num < 1 || num >= 100) return -EINVAL; @@ -309,7 +309,7 @@ static ssize_t acpi_pad_idlepct_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long num; - if (strict_strtoul(buf, 0, &num)) + if (kstrtoul(buf, 0, &num)) return -EINVAL; if (num < 1 || num >= 100) return -EINVAL; @@ -332,7 +332,7 @@ static ssize_t acpi_pad_idlecpus_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned long num; - if (strict_strtoul(buf, 0, &num)) + if (kstrtoul(buf, 0, &num)) return -EINVAL; mutex_lock(&isolated_cpus_lock); acpi_pad_idle_cpus(num); @@ -457,7 +457,7 @@ static void acpi_pad_notify(acpi_handle handle, u32 event, dev_name(&device->dev), event, 0); break; default: - printk(KERN_WARNING "Unsupported event [0x%x]\n", event); + pr_warn("Unsupported event [0x%x]\n", event); break; } } diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c new file mode 100644 index 00000000000..db129b9f52c --- /dev/null +++ b/drivers/acpi/acpi_platform.c @@ -0,0 +1,104 @@ +/* + * ACPI support for platform bus type. + * + * Copyright (C) 2012, Intel Corporation + * Authors: Mika Westerberg <mika.westerberg@linux.intel.com> + * Mathias Nyman <mathias.nyman@linux.intel.com> + * Rafael J. Wysocki <rafael.j.wysocki@intel.com> + * + * 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/acpi.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include "internal.h" + +ACPI_MODULE_NAME("platform"); + +/** + * acpi_create_platform_device - Create platform device for ACPI device node + * @adev: ACPI device node to create a platform device for. + * + * Check if the given @adev can be represented as a platform device and, if + * that's the case, create and register a platform device, populate its common + * resources and returns a pointer to it. Otherwise, return %NULL. + * + * The platform device's name will be taken from the @adev's _HID and _UID. + */ +struct platform_device *acpi_create_platform_device(struct acpi_device *adev) +{ + struct platform_device *pdev = NULL; + struct acpi_device *acpi_parent; + struct platform_device_info pdevinfo; + struct resource_list_entry *rentry; + struct list_head resource_list; + struct resource *resources; + int count; + + /* If the ACPI node already has a physical device attached, skip it. */ + if (adev->physical_node_count) + return NULL; + + INIT_LIST_HEAD(&resource_list); + count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); + if (count <= 0) + return NULL; + + resources = kmalloc(count * sizeof(struct resource), GFP_KERNEL); + if (!resources) { + dev_err(&adev->dev, "No memory for resources\n"); + acpi_dev_free_resource_list(&resource_list); + return NULL; + } + count = 0; + list_for_each_entry(rentry, &resource_list, node) + resources[count++] = rentry->res; + + acpi_dev_free_resource_list(&resource_list); + + memset(&pdevinfo, 0, sizeof(pdevinfo)); + /* + * If the ACPI node has a parent and that parent has a physical device + * attached to it, that physical device should be the parent of the + * platform device we are about to create. + */ + pdevinfo.parent = NULL; + acpi_parent = adev->parent; + if (acpi_parent) { + struct acpi_device_physical_node *entry; + struct list_head *list; + + mutex_lock(&acpi_parent->physical_node_lock); + list = &acpi_parent->physical_node_list; + if (!list_empty(list)) { + entry = list_first_entry(list, + struct acpi_device_physical_node, + node); + pdevinfo.parent = entry->dev; + } + mutex_unlock(&acpi_parent->physical_node_lock); + } + pdevinfo.name = dev_name(&adev->dev); + pdevinfo.id = -1; + pdevinfo.res = resources; + pdevinfo.num_res = count; + pdevinfo.acpi_node.handle = adev->handle; + pdev = platform_device_register_full(&pdevinfo); + if (IS_ERR(pdev)) { + dev_err(&adev->dev, "platform device creation failed: %ld\n", + PTR_ERR(pdev)); + pdev = NULL; + } else { + dev_dbg(&adev->dev, "created platform device %s\n", + dev_name(&pdev->dev)); + } + + kfree(resources); + return pdev; +} diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index 7f1d40797e8..c8bc24bd1f7 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -161,3 +161,6 @@ acpi-y += \ utxfinit.o \ utxferror.o \ utxfmutex.o + +acpi-$(ACPI_FUTURE_USAGE) += uttrack.o utcache.o utclib.o + diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index 5e8abb07724..432a318c9ed 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -44,17 +44,28 @@ #ifndef __ACDEBUG_H__ #define __ACDEBUG_H__ -#define ACPI_DEBUG_BUFFER_SIZE 4196 +#define ACPI_DEBUG_BUFFER_SIZE 0x4000 /* 16K buffer for return objects */ -struct command_info { +struct acpi_db_command_info { char *name; /* Command Name */ u8 min_args; /* Minimum arguments required */ }; -struct argument_info { +struct acpi_db_command_help { + u8 line_count; /* Number of help lines */ + char *invocation; /* Command Invocation */ + char *description; /* Command Description */ +}; + +struct acpi_db_argument_info { char *name; /* Argument Name */ }; +struct acpi_db_execute_walk { + u32 count; + u32 max_count; +}; + #define PARAM_LIST(pl) pl #define DBTEST_OUTPUT_LEVEL(lvl) if (acpi_gbl_db_opt_verbose) #define VERBOSE_PRINT(fp) DBTEST_OUTPUT_LEVEL(lvl) {\ @@ -77,59 +88,71 @@ acpi_db_single_step(struct acpi_walk_state *walk_state, /* * dbcmds - debug commands and output routines */ -acpi_status acpi_db_disassemble_method(char *name); +struct acpi_namespace_node *acpi_db_convert_to_node(char *in_string); void acpi_db_display_table_info(char *table_arg); -void acpi_db_unload_acpi_table(char *table_arg, char *instance_arg); +void acpi_db_display_template(char *buffer_arg); -void -acpi_db_set_method_breakpoint(char *location, - struct acpi_walk_state *walk_state, - union acpi_parse_object *op); +void acpi_db_unload_acpi_table(char *name); -void acpi_db_set_method_call_breakpoint(union acpi_parse_object *op); +void acpi_db_send_notify(char *name, u32 value); -void acpi_db_get_bus_info(void); +void acpi_db_display_interfaces(char *action_arg, char *interface_name_arg); -void acpi_db_disassemble_aml(char *statements, union acpi_parse_object *op); +acpi_status acpi_db_sleep(char *object_arg); -void acpi_db_dump_namespace(char *start_arg, char *depth_arg); +void acpi_db_display_locks(void); -void acpi_db_dump_namespace_by_owner(char *owner_arg, char *depth_arg); +void acpi_db_display_resources(char *object_arg); -void acpi_db_send_notify(char *name, u32 value); +ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_db_display_gpes(void)) + +void acpi_db_display_handlers(void); + +ACPI_HW_DEPENDENT_RETURN_VOID(void + acpi_db_generate_gpe(char *gpe_arg, + char *block_arg)) + +/* + * dbmethod - control method commands + */ +void +acpi_db_set_method_breakpoint(char *location, + struct acpi_walk_state *walk_state, + union acpi_parse_object *op); + +void acpi_db_set_method_call_breakpoint(union acpi_parse_object *op); void acpi_db_set_method_data(char *type_arg, char *index_arg, char *value_arg); -acpi_status -acpi_db_display_objects(char *obj_type_arg, char *display_count_arg); +acpi_status acpi_db_disassemble_method(char *name); -void acpi_db_display_interfaces(char *action_arg, char *interface_name_arg); +void acpi_db_disassemble_aml(char *statements, union acpi_parse_object *op); -acpi_status acpi_db_find_name_in_namespace(char *name_arg); +void acpi_db_batch_execute(char *count_arg); +/* + * dbnames - namespace commands + */ void acpi_db_set_scope(char *name); -ACPI_HW_DEPENDENT_RETURN_OK(acpi_status acpi_db_sleep(char *object_arg)) +void acpi_db_dump_namespace(char *start_arg, char *depth_arg); -void acpi_db_find_references(char *object_arg); +void acpi_db_dump_namespace_by_owner(char *owner_arg, char *depth_arg); -void acpi_db_display_locks(void); +acpi_status acpi_db_find_name_in_namespace(char *name_arg); -void acpi_db_display_resources(char *object_arg); +void acpi_db_check_predefined_names(void); -ACPI_HW_DEPENDENT_RETURN_VOID(void acpi_db_display_gpes(void)) +acpi_status +acpi_db_display_objects(char *obj_type_arg, char *display_count_arg); void acpi_db_check_integrity(void); -ACPI_HW_DEPENDENT_RETURN_VOID(void - acpi_db_generate_gpe(char *gpe_arg, - char *block_arg)) - -void acpi_db_check_predefined_names(void); +void acpi_db_find_references(char *object_arg); -void acpi_db_batch_execute(void); +void acpi_db_get_bus_info(void); /* * dbdisply - debug display commands @@ -161,7 +184,8 @@ acpi_db_display_argument_object(union acpi_operand_object *obj_desc, /* * dbexec - debugger control method execution */ -void acpi_db_execute(char *name, char **args, u32 flags); +void +acpi_db_execute(char *name, char **args, acpi_object_type * types, u32 flags); void acpi_db_create_execution_threads(char *num_threads_arg, @@ -175,7 +199,8 @@ u32 acpi_db_get_cache_info(struct acpi_memory_list *cache); * dbfileio - Debugger file I/O commands */ acpi_object_type -acpi_db_match_argument(char *user_argument, struct argument_info *arguments); +acpi_db_match_argument(char *user_argument, + struct acpi_db_argument_info *arguments); void acpi_db_close_debug_file(void); @@ -208,6 +233,11 @@ acpi_db_command_dispatch(char *input_buffer, void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context); +acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op); + +char *acpi_db_get_next_token(char *string, + char **next, acpi_object_type * return_type); + /* * dbstats - Generation and display of ACPI table statistics */ diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h index 5935ba6707e..ed33ebcdaeb 100644 --- a/drivers/acpi/acpica/acdispat.h +++ b/drivers/acpi/acpica/acdispat.h @@ -309,10 +309,13 @@ acpi_ds_obj_stack_push(void *object, struct acpi_walk_state *walk_state); acpi_status acpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state *walk_state); -struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union acpi_parse_object - *origin, union acpi_operand_object - *mth_desc, struct acpi_thread_state - *thread); +struct acpi_walk_state * acpi_ds_create_walk_state(acpi_owner_id owner_id, + union acpi_parse_object + *origin, + union acpi_operand_object + *mth_desc, + struct acpi_thread_state + *thread); acpi_status acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state, diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index c0a43b38c6a..e975c672044 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -84,9 +84,11 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info); acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info); -acpi_status acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info); +acpi_status +acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info); -acpi_status acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info); +acpi_status +acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info); struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device, u32 gpe_number); diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index ce79100fb5e..64472e4ec32 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -70,7 +70,7 @@ /* * Enable "slack" in the AML interpreter? Default is FALSE, and the - * interpreter strictly follows the ACPI specification. Setting to TRUE + * interpreter strictly follows the ACPI specification. Setting to TRUE * allows the interpreter to ignore certain errors and/or bad AML constructs. * * Currently, these features are enabled by this flag: @@ -155,26 +155,6 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_no_resource_disassembly, FALSE); /***************************************************************************** * - * Debug support - * - ****************************************************************************/ - -/* Procedure nesting level for debug output */ - -extern u32 acpi_gbl_nesting_level; - -ACPI_EXTERN u32 acpi_gpe_count; -ACPI_EXTERN u32 acpi_fixed_event_count[ACPI_NUM_FIXED_EVENTS]; - -/* Support for dynamic control method tracing mechanism */ - -ACPI_EXTERN u32 acpi_gbl_original_dbg_level; -ACPI_EXTERN u32 acpi_gbl_original_dbg_layer; -ACPI_EXTERN u32 acpi_gbl_trace_dbg_level; -ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer; - -/***************************************************************************** - * * ACPI Table globals * ****************************************************************************/ @@ -259,15 +239,6 @@ ACPI_EXTERN acpi_spinlock acpi_gbl_hardware_lock; /* For ACPI H/W except GPE reg * ****************************************************************************/ -#ifdef ACPI_DBG_TRACK_ALLOCATIONS - -/* Lists for tracking memory allocations */ - -ACPI_EXTERN struct acpi_memory_list *acpi_gbl_global_list; -ACPI_EXTERN struct acpi_memory_list *acpi_gbl_ns_node_list; -ACPI_EXTERN u8 acpi_gbl_display_final_mem_stats; -#endif - /* Object caches */ ACPI_EXTERN acpi_cache_t *acpi_gbl_namespace_cache; @@ -326,6 +297,15 @@ extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS]; #endif +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + +/* Lists for tracking memory allocations */ + +ACPI_EXTERN struct acpi_memory_list *acpi_gbl_global_list; +ACPI_EXTERN struct acpi_memory_list *acpi_gbl_ns_node_list; +ACPI_EXTERN u8 acpi_gbl_display_final_mem_stats; +#endif + /***************************************************************************** * * Namespace globals @@ -396,13 +376,35 @@ ACPI_EXTERN struct acpi_gpe_block_info #if (!ACPI_REDUCED_HARDWARE) ACPI_EXTERN u8 acpi_gbl_all_gpes_initialized; -ACPI_EXTERN ACPI_GBL_EVENT_HANDLER acpi_gbl_global_event_handler; +ACPI_EXTERN acpi_gbl_event_handler acpi_gbl_global_event_handler; ACPI_EXTERN void *acpi_gbl_global_event_handler_context; #endif /* !ACPI_REDUCED_HARDWARE */ /***************************************************************************** * + * Debug support + * + ****************************************************************************/ + +/* Procedure nesting level for debug output */ + +extern u32 acpi_gbl_nesting_level; + +/* Event counters */ + +ACPI_EXTERN u32 acpi_gpe_count; +ACPI_EXTERN u32 acpi_fixed_event_count[ACPI_NUM_FIXED_EVENTS]; + +/* Support for dynamic control method tracing mechanism */ + +ACPI_EXTERN u32 acpi_gbl_original_dbg_level; +ACPI_EXTERN u32 acpi_gbl_original_dbg_layer; +ACPI_EXTERN u32 acpi_gbl_trace_dbg_level; +ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer; + +/***************************************************************************** + * * Debugger globals * ****************************************************************************/ @@ -426,10 +428,11 @@ ACPI_EXTERN u8 acpi_gbl_db_opt_stats; ACPI_EXTERN u8 acpi_gbl_db_opt_ini_methods; ACPI_EXTERN char *acpi_gbl_db_args[ACPI_DEBUGGER_MAX_ARGS]; -ACPI_EXTERN char acpi_gbl_db_line_buf[80]; -ACPI_EXTERN char acpi_gbl_db_parsed_buf[80]; -ACPI_EXTERN char acpi_gbl_db_scope_buf[40]; -ACPI_EXTERN char acpi_gbl_db_debug_filename[40]; +ACPI_EXTERN acpi_object_type acpi_gbl_db_arg_types[ACPI_DEBUGGER_MAX_ARGS]; +ACPI_EXTERN char acpi_gbl_db_line_buf[ACPI_DB_LINE_BUFFER_SIZE]; +ACPI_EXTERN char acpi_gbl_db_parsed_buf[ACPI_DB_LINE_BUFFER_SIZE]; +ACPI_EXTERN char acpi_gbl_db_scope_buf[80]; +ACPI_EXTERN char acpi_gbl_db_debug_filename[80]; ACPI_EXTERN u8 acpi_gbl_db_output_to_file; ACPI_EXTERN char *acpi_gbl_db_buffer; ACPI_EXTERN char *acpi_gbl_db_filename; diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index c816ee67509..ff8bd0061e8 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -262,10 +262,10 @@ struct acpi_create_field_info { }; typedef -acpi_status(*ACPI_INTERNAL_METHOD) (struct acpi_walk_state * walk_state); +acpi_status(*acpi_internal_method) (struct acpi_walk_state * walk_state); /* - * Bitmapped ACPI types. Used internally only + * Bitmapped ACPI types. Used internally only */ #define ACPI_BTYPE_ANY 0x00000000 #define ACPI_BTYPE_INTEGER 0x00000001 @@ -486,8 +486,10 @@ struct acpi_gpe_device_info { struct acpi_namespace_node *gpe_device; }; -typedef acpi_status(*acpi_gpe_callback) (struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block, void *context); +typedef acpi_status(*acpi_gpe_callback) (struct acpi_gpe_xrupt_info * + gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, + void *context); /* Information about each particular fixed event */ @@ -582,7 +584,7 @@ struct acpi_pscope_state { }; /* - * Thread state - one per thread across multiple walk states. Multiple walk + * Thread state - one per thread across multiple walk states. Multiple walk * states are created when there are nested control methods executing. */ struct acpi_thread_state { @@ -645,7 +647,7 @@ union acpi_generic_state { * ****************************************************************************/ -typedef acpi_status(*ACPI_EXECUTE_OP) (struct acpi_walk_state * walk_state); +typedef acpi_status(*acpi_execute_op) (struct acpi_walk_state * walk_state); /* Address Range info block */ @@ -1031,6 +1033,7 @@ struct acpi_db_method_info { acpi_handle method; acpi_handle main_thread_gate; acpi_handle thread_complete_gate; + acpi_handle info_gate; acpi_thread_id *threads; u32 num_threads; u32 num_created; @@ -1041,6 +1044,7 @@ struct acpi_db_method_info { u32 num_loops; char pathname[128]; char **args; + acpi_object_type *types; /* * Arguments to be passed to method for the command diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index a7f68c47f51..5efad99f216 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -84,29 +84,29 @@ /* These macros reverse the bytes during the move, converting little-endian to big endian */ - /* Big Endian <== Little Endian */ - /* Hi...Lo Lo...Hi */ + /* Big Endian <== Little Endian */ + /* Hi...Lo Lo...Hi */ /* 16-bit source, 16/32/64 destination */ #define ACPI_MOVE_16_TO_16(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[1];\ - (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[0];} + (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[0];} #define ACPI_MOVE_16_TO_32(d, s) {(*(u32 *)(void *)(d))=0;\ - ((u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\ - ((u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];} + ((u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\ + ((u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];} #define ACPI_MOVE_16_TO_64(d, s) {(*(u64 *)(void *)(d))=0;\ - ((u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[1];\ - ((u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[0];} + ((u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[1];\ + ((u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[0];} /* 32-bit source, 16/32/64 destination */ #define ACPI_MOVE_32_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ #define ACPI_MOVE_32_TO_32(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[3];\ - (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[2];\ - (( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\ - (( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];} + (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[2];\ + (( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\ + (( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];} #define ACPI_MOVE_32_TO_64(d, s) {(*(u64 *)(void *)(d))=0;\ ((u8 *)(void *)(d))[4] = ((u8 *)(void *)(s))[3];\ @@ -196,24 +196,12 @@ #endif #endif -/* Macros based on machine integer width */ - -#if ACPI_MACHINE_WIDTH == 32 -#define ACPI_MOVE_SIZE_TO_16(d, s) ACPI_MOVE_32_TO_16(d, s) - -#elif ACPI_MACHINE_WIDTH == 64 -#define ACPI_MOVE_SIZE_TO_16(d, s) ACPI_MOVE_64_TO_16(d, s) - -#else -#error unknown ACPI_MACHINE_WIDTH -#endif - /* * Fast power-of-two math macros for non-optimized compilers */ -#define _ACPI_DIV(value, power_of2) ((u32) ((value) >> (power_of2))) -#define _ACPI_MUL(value, power_of2) ((u32) ((value) << (power_of2))) -#define _ACPI_MOD(value, divisor) ((u32) ((value) & ((divisor) -1))) +#define _ACPI_DIV(value, power_of2) ((u32) ((value) >> (power_of2))) +#define _ACPI_MUL(value, power_of2) ((u32) ((value) << (power_of2))) +#define _ACPI_MOD(value, divisor) ((u32) ((value) & ((divisor) -1))) #define ACPI_DIV_2(a) _ACPI_DIV(a, 1) #define ACPI_MUL_2(a) _ACPI_MUL(a, 1) @@ -238,12 +226,12 @@ /* * Rounding macros (Power of two boundaries only) */ -#define ACPI_ROUND_DOWN(value, boundary) (((acpi_size)(value)) & \ - (~(((acpi_size) boundary)-1))) +#define ACPI_ROUND_DOWN(value, boundary) (((acpi_size)(value)) & \ + (~(((acpi_size) boundary)-1))) -#define ACPI_ROUND_UP(value, boundary) ((((acpi_size)(value)) + \ - (((acpi_size) boundary)-1)) & \ - (~(((acpi_size) boundary)-1))) +#define ACPI_ROUND_UP(value, boundary) ((((acpi_size)(value)) + \ + (((acpi_size) boundary)-1)) & \ + (~(((acpi_size) boundary)-1))) /* Note: sizeof(acpi_size) evaluates to either 4 or 8 (32- vs 64-bit mode) */ @@ -264,7 +252,7 @@ #define ACPI_ROUND_UP_TO(value, boundary) (((value) + ((boundary)-1)) / (boundary)) -#define ACPI_IS_MISALIGNED(value) (((acpi_size) value) & (sizeof(acpi_size)-1)) +#define ACPI_IS_MISALIGNED(value) (((acpi_size) value) & (sizeof(acpi_size)-1)) /* * Bitmask creation @@ -355,7 +343,6 @@ * Ascii error messages can be configured out */ #ifndef ACPI_NO_ERROR_MESSAGES - /* * Error reporting. Callers module and line number are inserted by AE_INFO, * the plist contains a set of parens to allow variable-length lists. @@ -375,18 +362,15 @@ #define ACPI_WARN_PREDEFINED(plist) #define ACPI_INFO_PREDEFINED(plist) -#endif /* ACPI_NO_ERROR_MESSAGES */ +#endif /* ACPI_NO_ERROR_MESSAGES */ /* * Debug macros that are conditionally compiled */ #ifdef ACPI_DEBUG_OUTPUT - /* * Function entry tracing */ -#ifdef CONFIG_ACPI_DEBUG_FUNC_TRACE - #define ACPI_FUNCTION_TRACE(a) ACPI_FUNCTION_NAME(a) \ acpi_ut_trace(ACPI_DEBUG_PARAMETERS) #define ACPI_FUNCTION_TRACE_PTR(a, b) ACPI_FUNCTION_NAME(a) \ @@ -464,45 +448,19 @@ #endif /* ACPI_SIMPLE_RETURN_MACROS */ -#else /* !CONFIG_ACPI_DEBUG_FUNC_TRACE */ - -#define ACPI_FUNCTION_TRACE(a) -#define ACPI_FUNCTION_TRACE_PTR(a,b) -#define ACPI_FUNCTION_TRACE_U32(a,b) -#define ACPI_FUNCTION_TRACE_STR(a,b) -#define ACPI_FUNCTION_EXIT -#define ACPI_FUNCTION_STATUS_EXIT(s) -#define ACPI_FUNCTION_VALUE_EXIT(s) -#define ACPI_FUNCTION_TRACE(a) -#define ACPI_FUNCTION_ENTRY() - -#define return_VOID return -#define return_ACPI_STATUS(s) return(s) -#define return_VALUE(s) return(s) -#define return_UINT8(s) return(s) -#define return_UINT32(s) return(s) -#define return_PTR(s) return(s) - -#endif /* CONFIG_ACPI_DEBUG_FUNC_TRACE */ - /* Conditional execution */ #define ACPI_DEBUG_EXEC(a) a -#define ACPI_NORMAL_EXEC(a) - -#define ACPI_DEBUG_DEFINE(a) a; #define ACPI_DEBUG_ONLY_MEMBERS(a) a; #define _VERBOSE_STRUCTURES -/* Stack and buffer dumping */ +/* Various object display routines for debug */ #define ACPI_DUMP_STACK_ENTRY(a) acpi_ex_dump_operand((a), 0) -#define ACPI_DUMP_OPERANDS(a, b, c) acpi_ex_dump_operands(a, b, c) - +#define ACPI_DUMP_OPERANDS(a, b ,c) acpi_ex_dump_operands(a, b, c) #define ACPI_DUMP_ENTRY(a, b) acpi_ns_dump_entry (a, b) #define ACPI_DUMP_PATHNAME(a, b, c, d) acpi_ns_dump_pathname(a, b, c, d) -#define ACPI_DUMP_RESOURCE_LIST(a) acpi_rs_dump_resource_list(a) -#define ACPI_DUMP_BUFFER(a, b) acpi_ut_dump_buffer((u8 *) a, b, DB_BYTE_DISPLAY, _COMPONENT) +#define ACPI_DUMP_BUFFER(a, b) acpi_ut_debug_dump_buffer((u8 *) a, b, DB_BYTE_DISPLAY, _COMPONENT) #else /* @@ -510,25 +468,23 @@ * leaving no executable debug code! */ #define ACPI_DEBUG_EXEC(a) -#define ACPI_NORMAL_EXEC(a) a; - -#define ACPI_DEBUG_DEFINE(a) do { } while(0) -#define ACPI_DEBUG_ONLY_MEMBERS(a) do { } while(0) -#define ACPI_FUNCTION_TRACE(a) do { } while(0) -#define ACPI_FUNCTION_TRACE_PTR(a, b) do { } while(0) -#define ACPI_FUNCTION_TRACE_U32(a, b) do { } while(0) -#define ACPI_FUNCTION_TRACE_STR(a, b) do { } while(0) -#define ACPI_FUNCTION_EXIT do { } while(0) -#define ACPI_FUNCTION_STATUS_EXIT(s) do { } while(0) -#define ACPI_FUNCTION_VALUE_EXIT(s) do { } while(0) -#define ACPI_FUNCTION_ENTRY() do { } while(0) -#define ACPI_DUMP_STACK_ENTRY(a) do { } while(0) -#define ACPI_DUMP_OPERANDS(a, b, c) do { } while(0) -#define ACPI_DUMP_ENTRY(a, b) do { } while(0) -#define ACPI_DUMP_TABLES(a, b) do { } while(0) -#define ACPI_DUMP_PATHNAME(a, b, c, d) do { } while(0) -#define ACPI_DUMP_RESOURCE_LIST(a) do { } while(0) -#define ACPI_DUMP_BUFFER(a, b) do { } while(0) +#define ACPI_DEBUG_ONLY_MEMBERS(a) +#define ACPI_FUNCTION_TRACE(a) +#define ACPI_FUNCTION_TRACE_PTR(a, b) +#define ACPI_FUNCTION_TRACE_U32(a, b) +#define ACPI_FUNCTION_TRACE_STR(a, b) +#define ACPI_FUNCTION_EXIT +#define ACPI_FUNCTION_STATUS_EXIT(s) +#define ACPI_FUNCTION_VALUE_EXIT(s) +#define ACPI_FUNCTION_ENTRY() +#define ACPI_DUMP_STACK_ENTRY(a) +#define ACPI_DUMP_OPERANDS(a, b, c) +#define ACPI_DUMP_ENTRY(a, b) +#define ACPI_DUMP_TABLES(a, b) +#define ACPI_DUMP_PATHNAME(a, b, c, d) +#define ACPI_DUMP_BUFFER(a, b) +#define ACPI_DEBUG_PRINT(pl) +#define ACPI_DEBUG_PRINT_RAW(pl) #define return_VOID return #define return_ACPI_STATUS(s) return(s) @@ -556,18 +512,6 @@ #define ACPI_DEBUGGER_EXEC(a) #endif -#ifdef ACPI_DEBUG_OUTPUT -/* - * 1) Set name to blanks - * 2) Copy the object name - */ -#define ACPI_ADD_OBJECT_NAME(a,b) ACPI_MEMSET (a->common.name, ' ', sizeof (a->common.name));\ - ACPI_STRNCPY (a->common.name, acpi_gbl_ns_type_names[b], sizeof (a->common.name)) -#else - -#define ACPI_ADD_OBJECT_NAME(a,b) -#endif - /* * Memory allocation tracking (DEBUG ONLY) */ @@ -578,13 +522,13 @@ /* Memory allocation */ #ifndef ACPI_ALLOCATE -#define ACPI_ALLOCATE(a) acpi_ut_allocate((acpi_size)(a), ACPI_MEM_PARAMETERS) +#define ACPI_ALLOCATE(a) acpi_ut_allocate((acpi_size) (a), ACPI_MEM_PARAMETERS) #endif #ifndef ACPI_ALLOCATE_ZEROED -#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_allocate_zeroed((acpi_size)(a), ACPI_MEM_PARAMETERS) +#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_allocate_zeroed((acpi_size) (a), ACPI_MEM_PARAMETERS) #endif #ifndef ACPI_FREE -#define ACPI_FREE(a) acpio_os_free(a) +#define ACPI_FREE(a) acpi_os_free(a) #endif #define ACPI_MEM_TRACKING(a) @@ -592,16 +536,25 @@ /* Memory allocation */ -#define ACPI_ALLOCATE(a) acpi_ut_allocate_and_track((acpi_size)(a), ACPI_MEM_PARAMETERS) -#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_allocate_zeroed_and_track((acpi_size)(a), ACPI_MEM_PARAMETERS) +#define ACPI_ALLOCATE(a) acpi_ut_allocate_and_track((acpi_size) (a), ACPI_MEM_PARAMETERS) +#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_allocate_zeroed_and_track((acpi_size) (a), ACPI_MEM_PARAMETERS) #define ACPI_FREE(a) acpi_ut_free_and_track(a, ACPI_MEM_PARAMETERS) #define ACPI_MEM_TRACKING(a) a #endif /* ACPI_DBG_TRACK_ALLOCATIONS */ -/* Preemption point */ -#ifndef ACPI_PREEMPTION_POINT -#define ACPI_PREEMPTION_POINT() /* no preemption */ -#endif +/* + * Macros used for ACPICA utilities only + */ + +/* Generate a UUID */ + +#define ACPI_INIT_UUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ + (a) & 0xFF, ((a) >> 8) & 0xFF, ((a) >> 16) & 0xFF, ((a) >> 24) & 0xFF, \ + (b) & 0xFF, ((b) >> 8) & 0xFF, \ + (c) & 0xFF, ((c) >> 8) & 0xFF, \ + (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) + +#define ACPI_IS_OCTAL_DIGIT(d) (((char)(d) >= '0') && ((char)(d) <= '7')) #endif /* ACMACROS_H */ diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index 364a1303fb8..24eb9eac951 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -1,4 +1,3 @@ - /****************************************************************************** * * Name: acobject.h - Definition of union acpi_operand_object (Internal object only) @@ -179,7 +178,7 @@ struct acpi_object_method { union acpi_operand_object *mutex; u8 *aml_start; union { - ACPI_INTERNAL_METHOD implementation; + acpi_internal_method implementation; union acpi_operand_object *handler; } dispatch; @@ -198,7 +197,7 @@ struct acpi_object_method { /****************************************************************************** * - * Objects that can be notified. All share a common notify_info area. + * Objects that can be notified. All share a common notify_info area. * *****************************************************************************/ @@ -235,7 +234,7 @@ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO}; /****************************************************************************** * - * Fields. All share a common header/info field. + * Fields. All share a common header/info field. * *****************************************************************************/ diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index 9440d053fbb..d786a5128b7 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -54,7 +54,7 @@ #define _UNK 0x6B /* - * Reserved ASCII characters. Do not use any of these for + * Reserved ASCII characters. Do not use any of these for * internal opcodes, since they are used to differentiate * name strings from AML opcodes */ @@ -63,7 +63,7 @@ #define _PFX 0x6D /* - * All AML opcodes and the parse-time arguments for each. Used by the AML + * All AML opcodes and the parse-time arguments for each. Used by the AML * parser Each list is compressed into a 32-bit number and stored in the * master opcode table (in psopcode.c). */ @@ -193,7 +193,7 @@ #define ARGP_ZERO_OP ARG_NONE /* - * All AML opcodes and the runtime arguments for each. Used by the AML + * All AML opcodes and the runtime arguments for each. Used by the AML * interpreter Each list is compressed into a 32-bit number and stored * in the master opcode table (in psopcode.c). * diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h index b725d780d34..eefcf47a61a 100644 --- a/drivers/acpi/acpica/acparser.h +++ b/drivers/acpi/acpica/acparser.h @@ -150,8 +150,7 @@ u8 acpi_ps_has_completed_scope(struct acpi_parse_state *parser_state); void acpi_ps_pop_scope(struct acpi_parse_state *parser_state, - union acpi_parse_object **op, - u32 * arg_list, u32 * arg_count); + union acpi_parse_object **op, u32 *arg_list, u32 *arg_count); acpi_status acpi_ps_push_scope(struct acpi_parse_state *parser_state, diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index 3080c017f5b..9dfa1c83bd4 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -150,8 +150,7 @@ enum acpi_return_package_types { * is saved here (rather than in a separate table) in order to minimize the * overall size of the stored data. */ -static const union acpi_predefined_info predefined_names[] = -{ +static const union acpi_predefined_info predefined_names[] = { {{"_AC0", 0, ACPI_RTYPE_INTEGER}}, {{"_AC1", 0, ACPI_RTYPE_INTEGER}}, {{"_AC2", 0, ACPI_RTYPE_INTEGER}}, @@ -538,7 +537,8 @@ static const union acpi_predefined_info predefined_names[] = /* Acpi 1.0 defined _WAK with no return value. Later, it was changed to return a package */ - {{"_WAK", 1, ACPI_RTYPE_NONE | ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE}}, + {{"_WAK", 1, + ACPI_RTYPE_NONE | ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE}}, {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2,0}, 0,0}}, /* Fixed-length (2 Int), but is optional */ /* _WDG/_WED are MS extensions defined by "Windows Instrumentation" */ @@ -551,11 +551,12 @@ static const union acpi_predefined_info predefined_names[] = }; #if 0 + /* This is an internally implemented control method, no need to check */ - {{"_OSI", 1, ACPI_RTYPE_INTEGER}}, +{ { +"_OSI", 1, ACPI_RTYPE_INTEGER}}, /* TBD: */ - _PRT - currently ignore reversed entries. attempt to fix here? think about possibly fixing package elements like _BIF, etc. #endif diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h index f196e2c9a71..937e66c65d1 100644 --- a/drivers/acpi/acpica/acstruct.h +++ b/drivers/acpi/acpica/acstruct.h @@ -53,7 +53,7 @@ ****************************************************************************/ /* - * Walk state - current state of a parse tree walk. Used for both a leisurely + * Walk state - current state of a parse tree walk. Used for both a leisurely * stroll through the tree (for whatever reason), and for control method * execution. */ diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 5035327ebcc..b0f5f92b674 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -69,6 +69,22 @@ extern const char *acpi_gbl_siz_decode[]; extern const char *acpi_gbl_trs_decode[]; extern const char *acpi_gbl_ttp_decode[]; extern const char *acpi_gbl_typ_decode[]; +extern const char *acpi_gbl_ppc_decode[]; +extern const char *acpi_gbl_ior_decode[]; +extern const char *acpi_gbl_dts_decode[]; +extern const char *acpi_gbl_ct_decode[]; +extern const char *acpi_gbl_sbt_decode[]; +extern const char *acpi_gbl_am_decode[]; +extern const char *acpi_gbl_sm_decode[]; +extern const char *acpi_gbl_wm_decode[]; +extern const char *acpi_gbl_cph_decode[]; +extern const char *acpi_gbl_cpo_decode[]; +extern const char *acpi_gbl_dp_decode[]; +extern const char *acpi_gbl_ed_decode[]; +extern const char *acpi_gbl_bpb_decode[]; +extern const char *acpi_gbl_sb_decode[]; +extern const char *acpi_gbl_fc_decode[]; +extern const char *acpi_gbl_pt_decode[]; #endif /* Types for Resource descriptor entries */ @@ -79,14 +95,14 @@ extern const char *acpi_gbl_typ_decode[]; #define ACPI_SMALL_VARIABLE_LENGTH 3 typedef -acpi_status(*acpi_walk_aml_callback) (u8 * aml, +acpi_status(*acpi_walk_aml_callback) (u8 *aml, u32 length, u32 offset, u8 resource_index, void **context); typedef acpi_status(*acpi_pkg_callback) (u8 object_type, - union acpi_operand_object * source_object, + union acpi_operand_object *source_object, union acpi_generic_state * state, void *context); @@ -202,7 +218,9 @@ extern const u8 _acpi_ctype[]; #define ACPI_IS_PRINT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP | _ACPI_DI | _ACPI_SP | _ACPI_PU)) #define ACPI_IS_ALPHA(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP)) -#endif /* ACPI_USE_SYSTEM_CLIBRARY */ +#endif /* !ACPI_USE_SYSTEM_CLIBRARY */ + +#define ACPI_IS_ASCII(c) ((c) < 0x80) /* * utcopy - Object construction and conversion interfaces @@ -210,11 +228,11 @@ extern const u8 _acpi_ctype[]; acpi_status acpi_ut_build_simple_object(union acpi_operand_object *obj, union acpi_object *user_obj, - u8 * data_space, u32 * buffer_space_used); + u8 *data_space, u32 *buffer_space_used); acpi_status acpi_ut_build_package_object(union acpi_operand_object *obj, - u8 * buffer, u32 * space_used); + u8 *buffer, u32 *space_used); acpi_status acpi_ut_copy_iobject_to_eobject(union acpi_operand_object *obj, @@ -287,9 +305,10 @@ acpi_ut_ptr_exit(u32 line_number, const char *function_name, const char *module_name, u32 component_id, u8 *ptr); -void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id); +void +acpi_ut_debug_dump_buffer(u8 *buffer, u32 count, u32 display, u32 component_id); -void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display); +void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 offset); void acpi_ut_report_error(char *module_name, u32 line_number); @@ -337,15 +356,19 @@ acpi_ut_execute_power_methods(struct acpi_namespace_node *device_node, */ acpi_status acpi_ut_execute_HID(struct acpi_namespace_node *device_node, - struct acpica_device_id **return_id); + struct acpi_pnp_device_id ** return_id); acpi_status acpi_ut_execute_UID(struct acpi_namespace_node *device_node, - struct acpica_device_id **return_id); + struct acpi_pnp_device_id ** return_id); + +acpi_status +acpi_ut_execute_SUB(struct acpi_namespace_node *device_node, + struct acpi_pnp_device_id **return_id); acpi_status acpi_ut_execute_CID(struct acpi_namespace_node *device_node, - struct acpica_device_id_list **return_cid_list); + struct acpi_pnp_device_id_list ** return_cid_list); /* * utlock - reader/writer locks @@ -479,15 +502,19 @@ acpi_ut_walk_package_tree(union acpi_operand_object *source_object, void acpi_ut_strupr(char *src_string); +void acpi_ut_strlwr(char *src_string); + +int acpi_ut_stricmp(char *string1, char *string2); + void acpi_ut_print_string(char *string, u8 max_length); u8 acpi_ut_valid_acpi_name(u32 name); -acpi_name acpi_ut_repair_name(char *name); +void acpi_ut_repair_name(char *name); u8 acpi_ut_valid_acpi_char(char character, u32 position); -acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 * ret_integer); +acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer); /* Values for Base above (16=Hex, 10=Decimal) */ @@ -508,12 +535,12 @@ acpi_ut_display_init_pathname(u8 type, * utresrc */ acpi_status -acpi_ut_walk_aml_resources(u8 * aml, +acpi_ut_walk_aml_resources(u8 *aml, acpi_size aml_length, acpi_walk_aml_callback user_function, void **context); -acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index); +acpi_status acpi_ut_validate_resource(void *aml, u8 *return_index); u32 acpi_ut_get_descriptor_length(void *aml); @@ -524,8 +551,7 @@ u8 acpi_ut_get_resource_header_length(void *aml); u8 acpi_ut_get_resource_type(void *aml); acpi_status -acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, - u8 ** end_tag); +acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, u8 **end_tag); /* * utmutex - mutex support diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h index af4947956ec..968449685e0 100644 --- a/drivers/acpi/acpica/amlresrc.h +++ b/drivers/acpi/acpica/amlresrc.h @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: amlresrc.h - AML resource descriptors diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c index 465f02134b8..57895db3231 100644 --- a/drivers/acpi/acpica/dscontrol.c +++ b/drivers/acpi/acpica/dscontrol.c @@ -280,7 +280,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, /* * Get the return value and save as the last result - * value. This is the only place where walk_state->return_desc + * value. This is the only place where walk_state->return_desc * is set to anything other than zero! */ walk_state->return_desc = walk_state->operands[0]; diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 3da6fd8530c..b5b904ee815 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -277,7 +277,7 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op, * * RETURN: Status * - * DESCRIPTION: Process all named fields in a field declaration. Names are + * DESCRIPTION: Process all named fields in a field declaration. Names are * entered into the namespace. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index aa9a5d4e405..52eb4e01622 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -170,7 +170,7 @@ acpi_ds_create_method_mutex(union acpi_operand_object *method_desc) * * RETURN: Status * - * DESCRIPTION: Prepare a method for execution. Parses the method if necessary, + * DESCRIPTION: Prepare a method for execution. Parses the method if necessary, * increments the thread count, and waits at the method semaphore * for clearance to execute. * @@ -444,7 +444,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, * RETURN: Status * * DESCRIPTION: Restart a method that was preempted by another (nested) method - * invocation. Handle the return value (if any) from the callee. + * invocation. Handle the return value (if any) from the callee. * ******************************************************************************/ @@ -530,7 +530,7 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, * * RETURN: None * - * DESCRIPTION: Terminate a control method. Delete everything that the method + * DESCRIPTION: Terminate a control method. Delete everything that the method * created, delete all locals and arguments, and delete the parse * tree if requested. * diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c index 8d55cebaa65..9a83b7e0f3b 100644 --- a/drivers/acpi/acpica/dsmthdat.c +++ b/drivers/acpi/acpica/dsmthdat.c @@ -76,7 +76,7 @@ acpi_ds_method_data_get_type(u16 opcode, * RETURN: Status * * DESCRIPTION: Initialize the data structures that hold the method's arguments - * and locals. The data struct is an array of namespace nodes for + * and locals. The data struct is an array of namespace nodes for * each - this allows ref_of and de_ref_of to work properly for these * special data types. * @@ -129,7 +129,7 @@ void acpi_ds_method_data_init(struct acpi_walk_state *walk_state) * * RETURN: None * - * DESCRIPTION: Delete method locals and arguments. Arguments are only + * DESCRIPTION: Delete method locals and arguments. Arguments are only * deleted if this method was called from another method. * ******************************************************************************/ @@ -183,7 +183,7 @@ void acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state) * * RETURN: Status * - * DESCRIPTION: Initialize arguments for a method. The parameter list is a list + * DESCRIPTION: Initialize arguments for a method. The parameter list is a list * of ACPI operand objects, either null terminated or whose length * is defined by max_param_count. * @@ -401,7 +401,7 @@ acpi_ds_method_data_get_value(u8 type, * This means that either 1) The expected argument was * not passed to the method, or 2) A local variable * was referenced by the method (via the ASL) - * before it was initialized. Either case is an error. + * before it was initialized. Either case is an error. */ /* If slack enabled, init the local_x/arg_x to an Integer of value zero */ @@ -465,7 +465,7 @@ acpi_ds_method_data_get_value(u8 type, * * RETURN: None * - * DESCRIPTION: Delete the entry at Opcode:Index. Inserts + * DESCRIPTION: Delete the entry at Opcode:Index. Inserts * a null into the stack slot after the object is deleted. * ******************************************************************************/ @@ -523,7 +523,7 @@ acpi_ds_method_data_delete_value(u8 type, * * RETURN: Status * - * DESCRIPTION: Store a value in an Arg or Local. The obj_desc is installed + * DESCRIPTION: Store a value in an Arg or Local. The obj_desc is installed * as the new value for the Arg or Local and the reference count * for obj_desc is incremented. * @@ -566,7 +566,7 @@ acpi_ds_store_object_to_local(u8 type, /* * If the reference count on the object is more than one, we must - * take a copy of the object before we store. A reference count + * take a copy of the object before we store. A reference count * of exactly 1 means that the object was just created during the * evaluation of an expression, and we can safely use it since it * is not used anywhere else. diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index 68592dd3496..c9f15d3a368 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -293,7 +293,7 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, /* * Second arg is the buffer data (optional) byte_list can be either - * individual bytes or a string initializer. In either case, a + * individual bytes or a string initializer. In either case, a * byte_list appears in the AML. */ arg = op->common.value.arg; /* skip first arg */ @@ -568,7 +568,7 @@ acpi_ds_create_node(struct acpi_walk_state *walk_state, /* * Because of the execution pass through the non-control-method - * parts of the table, we can arrive here twice. Only init + * parts of the table, we can arrive here twice. Only init * the named object node the first time through */ if (acpi_ns_get_attached_object(node)) { @@ -618,7 +618,7 @@ acpi_ds_create_node(struct acpi_walk_state *walk_state, * RETURN: Status * * DESCRIPTION: Initialize a namespace object from a parser Op and its - * associated arguments. The namespace object is a more compact + * associated arguments. The namespace object is a more compact * representation of the Op and its arguments. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index aa34d8984d3..0df024e5fb6 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -649,7 +649,8 @@ acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state, ((op->common.parent->common.aml_opcode != AML_PACKAGE_OP) && (op->common.parent->common.aml_opcode != AML_VAR_PACKAGE_OP) - && (op->common.parent->common.aml_opcode != AML_NAME_OP))) { + && (op->common.parent->common.aml_opcode != + AML_NAME_OP))) { walk_state->result_obj = obj_desc; } } diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index 73a5447475f..afeb99f4948 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -61,7 +61,7 @@ ACPI_MODULE_NAME("dsutils") * * RETURN: None. * - * DESCRIPTION: Clear and remove a reference on an implicit return value. Used + * DESCRIPTION: Clear and remove a reference on an implicit return value. Used * to delete "stale" return values (if enabled, the return value * from every operator is saved at least momentarily, in case the * parent method exits.) @@ -107,7 +107,7 @@ void acpi_ds_clear_implicit_return(struct acpi_walk_state *walk_state) * * DESCRIPTION: Implements the optional "implicit return". We save the result * of every ASL operator and control method invocation in case the - * parent method exit. Before storing a new return value, we + * parent method exit. Before storing a new return value, we * delete the previous return value. * ******************************************************************************/ @@ -198,7 +198,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op, * * If there is no parent, or the parent is a scope_op, we are executing * at the method level. An executing method typically has no parent, - * since each method is parsed separately. A method invoked externally + * since each method is parsed separately. A method invoked externally * via execute_control_method has a scope_op as the parent. */ if ((!op->common.parent) || @@ -223,7 +223,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op, } /* - * Decide what to do with the result based on the parent. If + * Decide what to do with the result based on the parent. If * the parent opcode will not use the result, delete the object. * Otherwise leave it as is, it will be deleted when it is used * as an operand later. @@ -266,7 +266,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op, /* * These opcodes allow term_arg(s) as operands and therefore - * the operands can be method calls. The result is used. + * the operands can be method calls. The result is used. */ goto result_used; @@ -284,7 +284,7 @@ acpi_ds_is_result_used(union acpi_parse_object * op, AML_BANK_FIELD_OP)) { /* * These opcodes allow term_arg(s) as operands and therefore - * the operands can be method calls. The result is used. + * the operands can be method calls. The result is used. */ goto result_used; } @@ -329,9 +329,9 @@ acpi_ds_is_result_used(union acpi_parse_object * op, * * RETURN: Status * - * DESCRIPTION: Used after interpretation of an opcode. If there is an internal + * DESCRIPTION: Used after interpretation of an opcode. If there is an internal * result descriptor, check if the parent opcode will actually use - * this result. If not, delete the result now so that it will + * this result. If not, delete the result now so that it will * not become orphaned. * ******************************************************************************/ @@ -376,7 +376,7 @@ acpi_ds_delete_result_if_not_used(union acpi_parse_object *op, * * RETURN: Status * - * DESCRIPTION: Resolve all operands to their values. Used to prepare + * DESCRIPTION: Resolve all operands to their values. Used to prepare * arguments to a control method invocation (a call from one * method to another.) * @@ -391,7 +391,7 @@ acpi_status acpi_ds_resolve_operands(struct acpi_walk_state *walk_state) /* * Attempt to resolve each of the valid operands - * Method arguments are passed by reference, not by value. This means + * Method arguments are passed by reference, not by value. This means * that the actual objects are passed, not copies of the objects. */ for (i = 0; i < walk_state->num_operands; i++) { @@ -451,7 +451,7 @@ void acpi_ds_clear_operands(struct acpi_walk_state *walk_state) * RETURN: Status * * DESCRIPTION: Translate a parse tree object that is an argument to an AML - * opcode to the equivalent interpreter object. This may include + * opcode to the equivalent interpreter object. This may include * looking up a name or entering a new name into the internal * namespace. * @@ -496,9 +496,9 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, /* * Special handling for buffer_field declarations. This is a deferred * opcode that unfortunately defines the field name as the last - * parameter instead of the first. We get here when we are performing + * parameter instead of the first. We get here when we are performing * the deferred execution, so the actual name of the field is already - * in the namespace. We don't want to attempt to look it up again + * in the namespace. We don't want to attempt to look it up again * because we may be executing in a different scope than where the * actual opcode exists. */ @@ -560,7 +560,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, * indicate this to the interpreter, set the * object to the root */ - obj_desc = ACPI_CAST_PTR(union + obj_desc = + ACPI_CAST_PTR(union acpi_operand_object, acpi_gbl_root_node); status = AE_OK; @@ -604,8 +605,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, /* * If the name is null, this means that this is an * optional result parameter that was not specified - * in the original ASL. Create a Zero Constant for a - * placeholder. (Store to a constant is a Noop.) + * in the original ASL. Create a Zero Constant for a + * placeholder. (Store to a constant is a Noop.) */ opcode = AML_ZERO_OP; /* Has no arguments! */ diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c index 642f3c053e8..58593931be9 100644 --- a/drivers/acpi/acpica/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -57,7 +57,7 @@ ACPI_MODULE_NAME("dswexec") /* * Dispatch table for opcode classes */ -static ACPI_EXECUTE_OP acpi_gbl_op_type_dispatch[] = { +static acpi_execute_op acpi_gbl_op_type_dispatch[] = { acpi_ex_opcode_0A_0T_1R, acpi_ex_opcode_1A_0T_0R, acpi_ex_opcode_1A_0T_1R, @@ -204,7 +204,7 @@ acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state, * RETURN: Status * * DESCRIPTION: Descending callback used during the execution of control - * methods. This is where most operators and operands are + * methods. This is where most operators and operands are * dispatched to the interpreter. * ****************************************************************************/ @@ -297,7 +297,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, if (walk_state->walk_type & ACPI_WALK_METHOD) { /* * Found a named object declaration during method execution; - * we must enter this object into the namespace. The created + * we must enter this object into the namespace. The created * object is temporary and will be deleted upon completion of * the execution of this method. * @@ -348,7 +348,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, * RETURN: Status * * DESCRIPTION: Ascending callback used during the execution of control - * methods. The only thing we really need to do here is to + * methods. The only thing we really need to do here is to * notice the beginning of IF, ELSE, and WHILE blocks. * ****************************************************************************/ @@ -432,7 +432,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) if (ACPI_SUCCESS(status)) { /* * Dispatch the request to the appropriate interpreter handler - * routine. There is one routine per opcode "type" based upon the + * routine. There is one routine per opcode "type" based upon the * number of opcode arguments and return type. */ status = diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c index 89c0114210c..37983574835 100644 --- a/drivers/acpi/acpica/dswload2.c +++ b/drivers/acpi/acpica/dswload2.c @@ -254,7 +254,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, acpi_ut_get_type_name(node->type), acpi_ut_get_node_name(node))); - return (AE_AML_OPERAND_TYPE); + return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } break; @@ -602,7 +602,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) region_space, walk_state); if (ACPI_FAILURE(status)) { - return (status); + return_ACPI_STATUS(status); } acpi_ex_exit_interpreter(); diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c index d0e6555061e..3e65a15a735 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -51,8 +51,9 @@ ACPI_MODULE_NAME("dswstate") /* Local prototypes */ -static acpi_status acpi_ds_result_stack_push(struct acpi_walk_state *ws); -static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *ws); +static acpi_status +acpi_ds_result_stack_push(struct acpi_walk_state *walk_state); +static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *walk_state); /******************************************************************************* * @@ -347,7 +348,7 @@ acpi_ds_obj_stack_push(void *object, struct acpi_walk_state * walk_state) * * RETURN: Status * - * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT + * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT * deleted by this routine. * ******************************************************************************/ @@ -491,7 +492,7 @@ acpi_ds_push_walk_state(struct acpi_walk_state *walk_state, * RETURN: A walk_state object popped from the thread's stack * * DESCRIPTION: Remove and return the walkstate object that is at the head of - * the walk stack for the given walk list. NULL indicates that + * the walk stack for the given walk list. NULL indicates that * the list is empty. * ******************************************************************************/ @@ -531,14 +532,17 @@ struct acpi_walk_state *acpi_ds_pop_walk_state(struct acpi_thread_state *thread) * * RETURN: Pointer to the new walk state. * - * DESCRIPTION: Allocate and initialize a new walk state. The current walk + * DESCRIPTION: Allocate and initialize a new walk state. The current walk * state is set to this new state. * ******************************************************************************/ -struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union acpi_parse_object - *origin, union acpi_operand_object - *method_desc, struct acpi_thread_state +struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, + union acpi_parse_object + *origin, + union acpi_operand_object + *method_desc, + struct acpi_thread_state *thread) { struct acpi_walk_state *walk_state; @@ -653,7 +657,7 @@ acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state, /* * Setup the current scope. * Find a Named Op that has a namespace node associated with it. - * search upwards from this Op. Current scope is the first + * search upwards from this Op. Current scope is the first * Op with a namespace node. */ extra_op = parser_state->start_op; @@ -704,13 +708,13 @@ void acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state) ACPI_FUNCTION_TRACE_PTR(ds_delete_walk_state, walk_state); if (!walk_state) { - return; + return_VOID; } if (walk_state->descriptor_type != ACPI_DESC_TYPE_WALK) { ACPI_ERROR((AE_INFO, "%p is not a valid walk state", walk_state)); - return; + return_VOID; } /* There should not be any open scopes */ diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index ef0193d74b5..36d12057442 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -89,7 +89,8 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info) /* Set the mask bit only if there are references to this GPE */ if (gpe_event_info->runtime_count) { - ACPI_SET_BIT(gpe_register_info->enable_for_run, (u8)register_bit); + ACPI_SET_BIT(gpe_register_info->enable_for_run, + (u8)register_bit); } return_ACPI_STATUS(AE_OK); @@ -106,8 +107,7 @@ acpi_ev_update_gpe_enable_mask(struct acpi_gpe_event_info *gpe_event_info) * DESCRIPTION: Clear a GPE of stale events and enable it. * ******************************************************************************/ -acpi_status -acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) +acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) { acpi_status status; @@ -131,8 +131,8 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) } /* Enable the requested GPE */ - status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE); + status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE); return_ACPI_STATUS(status); } @@ -150,7 +150,8 @@ acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info) * ******************************************************************************/ -acpi_status acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info) +acpi_status +acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info) { acpi_status status = AE_OK; @@ -191,7 +192,8 @@ acpi_status acpi_ev_add_gpe_reference(struct acpi_gpe_event_info *gpe_event_info * ******************************************************************************/ -acpi_status acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info) +acpi_status +acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info) { acpi_status status = AE_OK; @@ -208,7 +210,8 @@ acpi_status acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_i status = acpi_ev_update_gpe_enable_mask(gpe_event_info); if (ACPI_SUCCESS(status)) { - status = acpi_hw_low_set_gpe(gpe_event_info, + status = + acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); } @@ -306,7 +309,8 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device, /* A Non-NULL gpe_device means this is a GPE Block Device */ - obj_desc = acpi_ns_get_attached_object((struct acpi_namespace_node *) + obj_desc = + acpi_ns_get_attached_object((struct acpi_namespace_node *) gpe_device); if (!obj_desc || !obj_desc->device.gpe_block) { return (NULL); diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index 8cf4c104c7b..1571a61a783 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -486,7 +486,8 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not enable GPE 0x%02X", - gpe_index + gpe_block->block_base_number)); + gpe_index + + gpe_block->block_base_number)); continue; } diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c index cb50dd91bc1..228a0c3b1d4 100644 --- a/drivers/acpi/acpica/evgpeutil.c +++ b/drivers/acpi/acpica/evgpeutil.c @@ -374,7 +374,8 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, gpe_event_info->dispatch.handler = NULL; gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; - } else if ((gpe_event_info-> + } else + if ((gpe_event_info-> flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_NOTIFY) { diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 4c1c8261166..1474241bfc7 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -227,8 +227,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, /* Install a handler for this PCI root bridge */ - status = - acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); + status = acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); if (ACPI_FAILURE(status)) { if (status == AE_SAME_HANDLER) { /* @@ -350,8 +349,8 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) { acpi_status status; - struct acpica_device_id *hid; - struct acpica_device_id_list *cid; + struct acpi_pnp_device_id *hid; + struct acpi_pnp_device_id_list *cid; u32 i; u8 match; diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index 7587eb6c958..ae668f32cf1 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -398,7 +398,7 @@ ACPI_EXPORT_SYMBOL(acpi_install_exception_handler) * ******************************************************************************/ acpi_status -acpi_install_global_event_handler(ACPI_GBL_EVENT_HANDLER handler, void *context) +acpi_install_global_event_handler(acpi_gbl_event_handler handler, void *context) { acpi_status status; diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index 87c5f233226..3f30e753b65 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -221,7 +221,8 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device, if (wake_device == ACPI_ROOT_OBJECT) { device_node = acpi_gbl_root_node; } else { - device_node = ACPI_CAST_PTR(struct acpi_namespace_node, wake_device); + device_node = + ACPI_CAST_PTR(struct acpi_namespace_node, wake_device); } /* Validate WakeDevice is of type Device */ @@ -324,7 +325,8 @@ ACPI_EXPORT_SYMBOL(acpi_setup_gpe_for_wake) * ******************************************************************************/ -acpi_status acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 action) +acpi_status +acpi_set_gpe_wake_mask(acpi_handle gpe_device, u32 gpe_number, u8 action) { acpi_status status = AE_OK; struct acpi_gpe_event_info *gpe_event_info; @@ -567,7 +569,7 @@ acpi_install_gpe_block(acpi_handle gpe_device, status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { - return (status); + return_ACPI_STATUS(status); } node = acpi_ns_validate_handle(gpe_device); @@ -650,7 +652,7 @@ acpi_status acpi_remove_gpe_block(acpi_handle gpe_device) status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { - return (status); + return_ACPI_STATUS(status); } node = acpi_ns_validate_handle(gpe_device); @@ -694,8 +696,7 @@ ACPI_EXPORT_SYMBOL(acpi_remove_gpe_block) * the FADT-defined gpe blocks. Otherwise, the GPE block device. * ******************************************************************************/ -acpi_status -acpi_get_gpe_device(u32 index, acpi_handle *gpe_device) +acpi_status acpi_get_gpe_device(u32 index, acpi_handle * gpe_device) { struct acpi_gpe_device_info info; acpi_status status; diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index bfb062e4c4b..4492a4e0302 100644 --- a/drivers/acpi/acpica/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -516,8 +516,8 @@ acpi_ex_convert_to_string(union acpi_operand_object * obj_desc, string_length--; } - return_desc = acpi_ut_create_string_object((acpi_size) - string_length); + return_desc = + acpi_ut_create_string_object((acpi_size) string_length); if (!return_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index 691d4763102..66554bc6f9a 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -78,7 +78,7 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state) (target_node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) { /* * Dereference an existing alias so that we don't create a chain - * of aliases. With this code, we guarantee that an alias is + * of aliases. With this code, we guarantee that an alias is * always exactly one level of indirection away from the * actual aliased name. */ @@ -90,7 +90,7 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state) /* * For objects that can never change (i.e., the NS node will * permanently point to the same object), we can simply attach - * the object to the new NS node. For other objects (such as + * the object to the new NS node. For other objects (such as * Integers, buffers, etc.), we have to point the Alias node * to the original Node. */ @@ -139,7 +139,7 @@ acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state) /* * The new alias assumes the type of the target, and it points - * to the same object. The reference count of the object has an + * to the same object. The reference count of the object has an * additional reference to prevent deletion out from under either the * target node or the alias Node */ @@ -243,8 +243,7 @@ acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state) /* Init object and attach to NS node */ - obj_desc->mutex.sync_level = - (u8) walk_state->operands[1]->integer.value; + obj_desc->mutex.sync_level = (u8)walk_state->operands[1]->integer.value; obj_desc->mutex.node = (struct acpi_namespace_node *)walk_state->operands[0]; diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index bc5b9a6a131..d7c9f51608a 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -145,10 +145,10 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, case ACPI_TYPE_BUFFER: acpi_os_printf("[0x%.2X]\n", (u32)source_desc->buffer.length); - acpi_ut_dump_buffer2(source_desc->buffer.pointer, - (source_desc->buffer.length < 256) ? - source_desc->buffer.length : 256, - DB_BYTE_DISPLAY); + acpi_ut_dump_buffer(source_desc->buffer.pointer, + (source_desc->buffer.length < 256) ? + source_desc->buffer.length : 256, + DB_BYTE_DISPLAY, 0); break; case ACPI_TYPE_STRING: @@ -190,7 +190,7 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, acpi_os_printf("Table Index 0x%X\n", source_desc->reference.value); - return; + return_VOID; default: break; diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 213c081776f..858b43a7dcf 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -464,7 +464,8 @@ void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth) ACPI_FUNCTION_NAME(ex_dump_operand) - if (!((ACPI_LV_EXEC & acpi_dbg_level) + if (! + ((ACPI_LV_EXEC & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) { return; } @@ -777,7 +778,7 @@ acpi_ex_dump_operands(union acpi_operand_object **operands, * PARAMETERS: title - Descriptive text * value - Value to be displayed * - * DESCRIPTION: Object dump output formatting functions. These functions + * DESCRIPTION: Object dump output formatting functions. These functions * reduce the number of format strings required and keeps them * all in one place for easy modification. * @@ -810,7 +811,8 @@ void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags) ACPI_FUNCTION_ENTRY(); if (!flags) { - if (!((ACPI_LV_OBJECTS & acpi_dbg_level) + if (! + ((ACPI_LV_OBJECTS & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) { return; } @@ -940,10 +942,11 @@ acpi_ex_dump_package_obj(union acpi_operand_object *obj_desc, acpi_os_printf("[Buffer] Length %.2X = ", obj_desc->buffer.length); if (obj_desc->buffer.length) { - acpi_ut_dump_buffer(ACPI_CAST_PTR - (u8, obj_desc->buffer.pointer), - obj_desc->buffer.length, - DB_DWORD_DISPLAY, _COMPONENT); + acpi_ut_debug_dump_buffer(ACPI_CAST_PTR + (u8, + obj_desc->buffer.pointer), + obj_desc->buffer.length, + DB_DWORD_DISPLAY, _COMPONENT); } else { acpi_os_printf("\n"); } @@ -996,7 +999,8 @@ acpi_ex_dump_object_descriptor(union acpi_operand_object *obj_desc, u32 flags) } if (!flags) { - if (!((ACPI_LV_OBJECTS & acpi_dbg_level) + if (! + ((ACPI_LV_OBJECTS & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) { return_VOID; } diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index dc092f5b35d..ebc55fbf3ff 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -59,7 +59,7 @@ ACPI_MODULE_NAME("exfield") * * RETURN: Status * - * DESCRIPTION: Read from a named field. Returns either an Integer or a + * DESCRIPTION: Read from a named field. Returns either an Integer or a * Buffer, depending on the size of the field. * ******************************************************************************/ @@ -149,7 +149,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, * Allocate a buffer for the contents of the field. * * If the field is larger than the current integer width, create - * a BUFFER to hold it. Otherwise, use an INTEGER. This allows + * a BUFFER to hold it. Otherwise, use an INTEGER. This allows * the use of arithmetic operators on the returned value if the * field size is equal or smaller than an Integer. * diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index a7784152ed3..aa2ccfb7cb6 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -54,8 +54,7 @@ ACPI_MODULE_NAME("exfldio") /* Local prototypes */ static acpi_status acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, - u32 field_datum_byte_offset, - u64 *value, u32 read_write); + u32 field_datum_byte_offset, u64 *value, u32 read_write); static u8 acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value); @@ -155,7 +154,7 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, #endif /* - * Validate the request. The entire request from the byte offset for a + * Validate the request. The entire request from the byte offset for a * length of one field datum (access width) must fit within the region. * (Region length is specified in bytes) */ @@ -183,7 +182,7 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, obj_desc->common_field.access_byte_width) { /* * This is the case where the access_type (acc_word, etc.) is wider - * than the region itself. For example, a region of length one + * than the region itself. For example, a region of length one * byte, and a field with Dword access specified. */ ACPI_ERROR((AE_INFO, @@ -321,7 +320,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, * * DESCRIPTION: Check if a value is out of range of the field being written. * Used to check if the values written to Index and Bank registers - * are out of range. Normally, the value is simply truncated + * are out of range. Normally, the value is simply truncated * to fit the field, but this case is most likely a serious * coding error in the ASL. * @@ -370,7 +369,7 @@ acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value) * * RETURN: Status * - * DESCRIPTION: Read or Write a single datum of a field. The field_type is + * DESCRIPTION: Read or Write a single datum of a field. The field_type is * demultiplexed here to handle the different types of fields * (buffer_field, region_field, index_field, bank_field) * @@ -860,7 +859,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length); /* * We must have a buffer that is at least as long as the field - * we are writing to. This is because individual fields are + * we are writing to. This is because individual fields are * indivisible and partial writes are not supported -- as per * the ACPI specification. */ @@ -875,7 +874,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, /* * Copy the original data to the new buffer, starting - * at Byte zero. All unused (upper) bytes of the + * at Byte zero. All unused (upper) bytes of the * buffer will be 0. */ ACPI_MEMCPY((char *)new_buffer, (char *)buffer, buffer_length); diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index 271c0c57ea1..84058705ed1 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes @@ -254,7 +253,7 @@ acpi_ex_do_concatenate(union acpi_operand_object *operand0, ACPI_FUNCTION_TRACE(ex_do_concatenate); /* - * Convert the second operand if necessary. The first operand + * Convert the second operand if necessary. The first operand * determines the type of the second operand, (See the Data Types * section of the ACPI specification.) Both object types are * guaranteed to be either Integer/String/Buffer by the operand @@ -573,7 +572,7 @@ acpi_ex_do_logical_op(u16 opcode, ACPI_FUNCTION_TRACE(ex_do_logical_op); /* - * Convert the second operand if necessary. The first operand + * Convert the second operand if necessary. The first operand * determines the type of the second operand, (See the Data Types * section of the ACPI 3.0+ specification.) Both object types are * guaranteed to be either Integer/String/Buffer by the operand diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index bcceda5be9e..d1f449d93dc 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exmutex - ASL Mutex Acquire/Release functions @@ -305,7 +304,7 @@ acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc) ACPI_FUNCTION_TRACE(ex_release_mutex_object); if (obj_desc->mutex.acquisition_depth == 0) { - return (AE_NOT_ACQUIRED); + return_ACPI_STATUS(AE_NOT_ACQUIRED); } /* Match multiple Acquires with multiple Releases */ @@ -462,7 +461,7 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) union acpi_operand_object *next = thread->acquired_mutex_list; union acpi_operand_object *obj_desc; - ACPI_FUNCTION_ENTRY(); + ACPI_FUNCTION_NAME(ex_release_all_mutexes); /* Traverse the list of owned mutexes, releasing each one */ @@ -474,6 +473,10 @@ void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread) obj_desc->mutex.next = NULL; obj_desc->mutex.acquisition_depth = 0; + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Force-releasing held mutex: %p\n", + obj_desc)); + /* Release the mutex, special case for Global Lock */ if (obj_desc == acpi_gbl_global_lock_mutex) { diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c index fcc75fa27d3..2ff578a16ad 100644 --- a/drivers/acpi/acpica/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exnames - interpreter/scanner name load/execute @@ -53,8 +52,7 @@ ACPI_MODULE_NAME("exnames") /* Local prototypes */ static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs); -static acpi_status -acpi_ex_name_segment(u8 ** in_aml_address, char *name_string); +static acpi_status acpi_ex_name_segment(u8 **in_aml_address, char *name_string); /******************************************************************************* * @@ -64,7 +62,7 @@ acpi_ex_name_segment(u8 ** in_aml_address, char *name_string); * (-1)==root, 0==none * num_name_segs - count of 4-character name segments * - * RETURN: A pointer to the allocated string segment. This segment must + * RETURN: A pointer to the allocated string segment. This segment must * be deleted by the caller. * * DESCRIPTION: Allocate a buffer for a name string. Ensure allocated name @@ -178,7 +176,8 @@ static acpi_status acpi_ex_name_segment(u8 ** in_aml_address, char *name_string) ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Bytes from stream:\n")); - for (index = 0; (index < ACPI_NAME_SIZE) + for (index = 0; + (index < ACPI_NAME_SIZE) && (acpi_ut_valid_acpi_char(*aml_address, 0)); index++) { char_buf[index] = *aml_address++; ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "%c\n", char_buf[index])); diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index 9ba8c73cea1..bbf01e9bf05 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exoparg1 - AML execution - opcodes with 1 argument @@ -606,7 +605,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) } /* - * Set result to ONES (TRUE) if Value == 0. Note: + * Set result to ONES (TRUE) if Value == 0. Note: * return_desc->Integer.Value is initially == 0 (FALSE) from above. */ if (!operand[0]->integer.value) { @@ -618,7 +617,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) case AML_INCREMENT_OP: /* Increment (Operand) */ /* - * Create a new integer. Can't just get the base integer and + * Create a new integer. Can't just get the base integer and * increment it because it may be an Arg or Field. */ return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); @@ -686,7 +685,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) /* * Note: The operand is not resolved at this point because we want to - * get the associated object, not its value. For example, we don't + * get the associated object, not its value. For example, we don't * want to resolve a field_unit to its value, we want the actual * field_unit object. */ @@ -727,7 +726,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) /* * The type of the base object must be integer, buffer, string, or - * package. All others are not supported. + * package. All others are not supported. * * NOTE: Integer is not specifically supported by the ACPI spec, * but is supported implicitly via implicit operand conversion. @@ -965,7 +964,7 @@ acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) case ACPI_TYPE_PACKAGE: /* - * Return the referenced element of the package. We must + * Return the referenced element of the package. We must * add another reference to the referenced object, however. */ return_desc = diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index 879e8a277b9..ee5634a074c 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -123,7 +123,7 @@ acpi_status acpi_ex_opcode_2A_0T_0R(struct acpi_walk_state *walk_state) /* * Dispatch the notify to the appropriate handler * NOTE: the request is queued for execution after this method - * completes. The notify handlers are NOT invoked synchronously + * completes. The notify handlers are NOT invoked synchronously * from this thread -- because handlers may in turn run other * control methods. */ diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c index 71fcc65c9ff..2c89b4651f0 100644 --- a/drivers/acpi/acpica/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exoparg3 - AML execution - opcodes with 3 arguments @@ -158,7 +157,7 @@ acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state) case AML_MID_OP: /* Mid (Source[0], Index[1], Length[2], Result[3]) */ /* - * Create the return object. The Source operand is guaranteed to be + * Create the return object. The Source operand is guaranteed to be * either a String or a Buffer, so just use its type. */ return_desc = acpi_ut_create_internal_object((operand[0])-> diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c index 0786b865906..3e08695c3b3 100644 --- a/drivers/acpi/acpica/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exoparg6 - AML execution - opcodes with 6 arguments @@ -198,7 +197,7 @@ acpi_ex_do_match(u32 match_op, return (FALSE); } - return logical_result; + return (logical_result); } /******************************************************************************* @@ -269,7 +268,7 @@ acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state * walk_state) * and the next should be examined. * * Upon finding a match, the loop will terminate via "break" at - * the bottom. If it terminates "normally", match_value will be + * the bottom. If it terminates "normally", match_value will be * ACPI_UINT64_MAX (Ones) (its initial value) indicating that no * match was found. */ diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c index 81eca60d274..ba9db4de7c8 100644 --- a/drivers/acpi/acpica/exprep.c +++ b/drivers/acpi/acpica/exprep.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exprep - ACPI AML (p-code) execution - field prep utilities @@ -78,8 +77,8 @@ acpi_ex_generate_access(u32 field_bit_offset, * any_acc keyword. * * NOTE: Need to have the region_length in order to check for boundary - * conditions (end-of-region). However, the region_length is a deferred - * operation. Therefore, to complete this implementation, the generation + * conditions (end-of-region). However, the region_length is a deferred + * operation. Therefore, to complete this implementation, the generation * of this access width must be deferred until the region length has * been evaluated. * @@ -308,7 +307,7 @@ acpi_ex_decode_field_access(union acpi_operand_object *obj_desc, * RETURN: Status * * DESCRIPTION: Initialize the areas of the field object that are common - * to the various types of fields. Note: This is very "sensitive" + * to the various types of fields. Note: This is very "sensitive" * code because we are solving the general case for field * alignment. * @@ -336,13 +335,13 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc, obj_desc->common_field.bit_length = field_bit_length; /* - * Decode the access type so we can compute offsets. The access type gives + * Decode the access type so we can compute offsets. The access type gives * two pieces of information - the width of each field access and the * necessary byte_alignment (address granularity) of the access. * * For any_acc, the access_bit_width is the largest width that is both * necessary and possible in an attempt to access the whole field in one - * I/O operation. However, for any_acc, the byte_alignment is always one + * I/O operation. However, for any_acc, the byte_alignment is always one * byte. * * For all Buffer Fields, the byte_alignment is always one byte. @@ -363,7 +362,7 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc, /* * base_byte_offset is the address of the start of the field within the - * region. It is the byte address of the first *datum* (field-width data + * region. It is the byte address of the first *datum* (field-width data * unit) of the field. (i.e., the first datum that contains at least the * first *bit* of the field.) * diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index 1f1ce0c3d2f..1db2c0bfde0 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exregion - ACPI default op_region (address space) handlers @@ -202,7 +201,7 @@ acpi_ex_system_memory_space_handler(u32 function, * Perform the memory read or write * * Note: For machines that do not support non-aligned transfers, the target - * address was checked for alignment above. We do not attempt to break the + * address was checked for alignment above. We do not attempt to break the * transfer up into smaller (byte-size) chunks because the AML specifically * asked for a transfer width that the hardware may require. */ diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c index fa50e77e64a..6239956786e 100644 --- a/drivers/acpi/acpica/exresnte.c +++ b/drivers/acpi/acpica/exresnte.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exresnte - AML Interpreter object resolution @@ -58,8 +57,8 @@ ACPI_MODULE_NAME("exresnte") * PARAMETERS: object_ptr - Pointer to a location that contains * a pointer to a NS node, and will receive a * pointer to the resolved object. - * walk_state - Current state. Valid only if executing AML - * code. NULL if simply resolving an object + * walk_state - Current state. Valid only if executing AML + * code. NULL if simply resolving an object * * RETURN: Status * @@ -67,7 +66,7 @@ ACPI_MODULE_NAME("exresnte") * * Note: for some of the data types, the pointer attached to the Node * can be either a pointer to an actual internal object or a pointer into the - * AML stream itself. These types are currently: + * AML stream itself. These types are currently: * * ACPI_TYPE_INTEGER * ACPI_TYPE_STRING @@ -89,7 +88,7 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, ACPI_FUNCTION_TRACE(ex_resolve_node_to_value); /* - * The stack pointer points to a struct acpi_namespace_node (Node). Get the + * The stack pointer points to a struct acpi_namespace_node (Node). Get the * object that is attached to the Node. */ node = *object_ptr; diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c index bbf40ac2758..cc176b245e2 100644 --- a/drivers/acpi/acpica/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exresolv - AML Interpreter object resolution @@ -327,7 +326,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr, * * RETURN: Status * - * DESCRIPTION: Return the base object and type. Traverse a reference list if + * DESCRIPTION: Return the base object and type. Traverse a reference list if * necessary to get to the base object. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c index f232fbabdea..b9ebff2f6a0 100644 --- a/drivers/acpi/acpica/exresop.c +++ b/drivers/acpi/acpica/exresop.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exresop - AML Interpreter operand/object resolution @@ -87,7 +86,7 @@ acpi_ex_check_object_type(acpi_object_type type_needed, if (type_needed == ACPI_TYPE_LOCAL_REFERENCE) { /* * Allow the AML "Constant" opcodes (Zero, One, etc.) to be reference - * objects and thus allow them to be targets. (As per the ACPI + * objects and thus allow them to be targets. (As per the ACPI * specification, a store to a constant is a noop.) */ if ((this_type == ACPI_TYPE_INTEGER) && @@ -337,7 +336,8 @@ acpi_ex_resolve_operands(u16 opcode, if ((opcode == AML_STORE_OP) && ((*stack_ptr)->common.type == ACPI_TYPE_LOCAL_REFERENCE) - && ((*stack_ptr)->reference.class == ACPI_REFCLASS_INDEX)) { + && ((*stack_ptr)->reference.class == + ACPI_REFCLASS_INDEX)) { goto next_operand; } break; @@ -638,7 +638,7 @@ acpi_ex_resolve_operands(u16 opcode, if (acpi_gbl_enable_interpreter_slack) { /* * Enable original behavior of Store(), allowing any and all - * objects as the source operand. The ACPI spec does not + * objects as the source operand. The ACPI spec does not * allow this, however. */ break; diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c index 5fffe7ab5ec..90431f12f83 100644 --- a/drivers/acpi/acpica/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -374,7 +374,7 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc, * with the input value. * * When storing into an object the data is converted to the - * target object type then stored in the object. This means + * target object type then stored in the object. This means * that the target object type (for an initialized target) will * not be changed by a store operation. * @@ -491,7 +491,7 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, acpi_ut_get_object_type_name(source_desc), source_desc, node)); - /* No conversions for all other types. Just attach the source object */ + /* No conversions for all other types. Just attach the source object */ status = acpi_ns_attach_object(node, source_desc, source_desc->common.type); diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c index b35bed52e06..87153bbc4b4 100644 --- a/drivers/acpi/acpica/exstoren.c +++ b/drivers/acpi/acpica/exstoren.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exstoren - AML Interpreter object store support, @@ -61,7 +60,7 @@ ACPI_MODULE_NAME("exstoren") * * RETURN: Status, resolved object in source_desc_ptr. * - * DESCRIPTION: Resolve an object. If the object is a reference, dereference + * DESCRIPTION: Resolve an object. If the object is a reference, dereference * it and return the actual object in the source_desc_ptr. * ******************************************************************************/ @@ -93,7 +92,7 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr, /* * Stores into a Field/Region or into a Integer/Buffer/String - * are all essentially the same. This case handles the + * are all essentially the same. This case handles the * "interchangeable" types Integer, String, and Buffer. */ if (source_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE) { @@ -167,7 +166,7 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr, * * RETURN: Status * - * DESCRIPTION: "Store" an object to another object. This may include + * DESCRIPTION: "Store" an object to another object. This may include * converting the source type to the target type (implicit * conversion), and a copy of the value of the source to * the target. @@ -178,14 +177,14 @@ acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr, * with the input value. * * When storing into an object the data is converted to the - * target object type then stored in the object. This means + * target object type then stored in the object. This means * that the target object type (for an initialized target) will * not be changed by a store operation. * * This module allows destination types of Number, String, * Buffer, and Package. * - * Assumes parameters are already validated. NOTE: source_desc + * Assumes parameters are already validated. NOTE: source_desc * resolution (from a reference object) must be performed by * the caller if necessary. * diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c index 53c24847354..b5f339cb130 100644 --- a/drivers/acpi/acpica/exstorob.c +++ b/drivers/acpi/acpica/exstorob.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exstorob - AML Interpreter object store support, store to object @@ -108,7 +107,7 @@ acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc, #ifdef ACPI_OBSOLETE_BEHAVIOR /* * NOTE: ACPI versions up to 3.0 specified that the buffer must be - * truncated if the string is smaller than the buffer. However, "other" + * truncated if the string is smaller than the buffer. However, "other" * implementations of ACPI never did this and thus became the defacto * standard. ACPI 3.0A changes this behavior such that the buffer * is no longer truncated. @@ -117,7 +116,7 @@ acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc, /* * OBSOLETE BEHAVIOR: * If the original source was a string, we must truncate the buffer, - * according to the ACPI spec. Integer-to-Buffer and Buffer-to-Buffer + * according to the ACPI spec. Integer-to-Buffer and Buffer-to-Buffer * copy must not truncate the original buffer. */ if (original_src_type == ACPI_TYPE_STRING) { diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c index b760641e2fc..c8a0ad5c1f5 100644 --- a/drivers/acpi/acpica/exsystem.c +++ b/drivers/acpi/acpica/exsystem.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exsystem - Interface to OS services @@ -59,7 +58,7 @@ ACPI_MODULE_NAME("exsystem") * RETURN: Status * * DESCRIPTION: Implements a semaphore wait with a check to see if the - * semaphore is available immediately. If it is not, the + * semaphore is available immediately. If it is not, the * interpreter is released before waiting. * ******************************************************************************/ @@ -104,7 +103,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout) * RETURN: Status * * DESCRIPTION: Implements a mutex wait with a check to see if the - * mutex is available immediately. If it is not, the + * mutex is available immediately. If it is not, the * interpreter is released before waiting. * ******************************************************************************/ @@ -152,7 +151,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout) * DESCRIPTION: Suspend running thread for specified amount of time. * Note: ACPI specification requires that Stall() does not * relinquish the processor, and delays longer than 100 usec - * should use Sleep() instead. We allow stalls up to 255 usec + * should use Sleep() instead. We allow stalls up to 255 usec * for compatibility with other interpreters and existing BIOSs. * ******************************************************************************/ @@ -254,7 +253,7 @@ acpi_status acpi_ex_system_signal_event(union acpi_operand_object * obj_desc) * RETURN: Status * * DESCRIPTION: Provides an access point to perform synchronization operations - * within the AML. This operation is a request to wait for an + * within the AML. This operation is a request to wait for an * event. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c index d1ab7917eed..264d22d8018 100644 --- a/drivers/acpi/acpica/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: exutils - interpreter/scanner utilities @@ -45,12 +44,12 @@ /* * DEFINE_AML_GLOBALS is tested in amlcode.h * to determine whether certain global names should be "defined" or only - * "declared" in the current compilation. This enhances maintainability + * "declared" in the current compilation. This enhances maintainability * by enabling a single header file to embody all knowledge of the names * in question. * * Exactly one module of any executable should #define DEFINE_GLOBALS - * before #including the header files which use this convention. The + * before #including the header files which use this convention. The * names in question will be defined and initialized in that module, * and declared as extern in all other modules which #include those * header files. diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c index a1e71d0ef57..90a9aea1cee 100644 --- a/drivers/acpi/acpica/hwacpi.c +++ b/drivers/acpi/acpica/hwacpi.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: hwacpi - ACPI Hardware Initialization/Mode Interface @@ -136,7 +135,7 @@ acpi_status acpi_hw_set_mode(u32 mode) * * RETURN: SYS_MODE_ACPI or SYS_MODE_LEGACY * - * DESCRIPTION: Return current operating state of system. Determined by + * DESCRIPTION: Return current operating state of system. Determined by * querying the SCI_EN bit. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index db4076580e2..64560045052 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: hwgpe - Low level GPE enable/disable/clear functions @@ -339,7 +338,8 @@ acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, acpi_status acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block, void *context) + struct acpi_gpe_block_info * gpe_block, + void *context) { u32 i; acpi_status status; diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c index 1455ddcdc32..65bc3453a29 100644 --- a/drivers/acpi/acpica/hwpci.c +++ b/drivers/acpi/acpica/hwpci.c @@ -259,7 +259,7 @@ acpi_hw_process_pci_list(struct acpi_pci_id *pci_id, status = acpi_hw_get_pci_device_info(pci_id, info->device, &bus_number, &is_bridge); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + return (status); } info = info->next; @@ -271,7 +271,7 @@ acpi_hw_process_pci_list(struct acpi_pci_id *pci_id, pci_id->segment, pci_id->bus, pci_id->device, pci_id->function, status, bus_number, is_bridge)); - return_ACPI_STATUS(AE_OK); + return (AE_OK); } /******************************************************************************* diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 4af6d20ef07..f4e57503576 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -1,4 +1,3 @@ - /******************************************************************************* * * Module Name: hwregs - Read/write access functions for the various ACPI diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index b6411f16832..bfdce22f379 100644 --- a/drivers/acpi/acpica/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Name: hwtimer.c - ACPI Power Management Timer Interface @@ -101,8 +100,7 @@ acpi_status acpi_get_timer(u32 * ticks) return_ACPI_STATUS(AE_BAD_PARAMETER); } - status = - acpi_hw_read(ticks, &acpi_gbl_FADT.xpm_timer_block); + status = acpi_hw_read(ticks, &acpi_gbl_FADT.xpm_timer_block); return_ACPI_STATUS(status); } @@ -129,7 +127,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_timer) * a versatile and accurate timer. * * Note that this function accommodates only a single timer - * rollover. Thus for 24-bit timers, this function should only + * rollover. Thus for 24-bit timers, this function should only * be used for calculating durations less than ~4.6 seconds * (~20 minutes for 32-bit timers) -- calculations below: * diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c index c99d546b217..b6aae58299d 100644 --- a/drivers/acpi/acpica/hwvalid.c +++ b/drivers/acpi/acpica/hwvalid.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: hwvalid - I/O request validation diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index 7bfd649d199..05a154c3c9a 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -1,4 +1,3 @@ - /****************************************************************************** * * Module Name: hwxface - Public ACPICA hardware interfaces diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index 0ff1ecea5c3..ae443fe2ebf 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -49,8 +49,7 @@ ACPI_MODULE_NAME("hwxfsleep") /* Local prototypes */ -static acpi_status -acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id); +static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id); /* * Dispatch table used to efficiently branch to the various sleep @@ -234,8 +233,7 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios) * function. * ******************************************************************************/ -static acpi_status -acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id) +static acpi_status acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id) { acpi_status status; struct acpi_sleep_functions *sleep_functions = @@ -369,8 +367,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state) return_ACPI_STATUS(AE_AML_OPERAND_VALUE); } - status = - acpi_hw_sleep_dispatch(sleep_state, ACPI_SLEEP_FUNCTION_ID); + status = acpi_hw_sleep_dispatch(sleep_state, ACPI_SLEEP_FUNCTION_ID); return_ACPI_STATUS(status); } @@ -396,8 +393,7 @@ acpi_status acpi_leave_sleep_state_prep(u8 sleep_state) ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep); status = - acpi_hw_sleep_dispatch(sleep_state, - ACPI_WAKE_PREP_FUNCTION_ID); + acpi_hw_sleep_dispatch(sleep_state, ACPI_WAKE_PREP_FUNCTION_ID); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index 23db53ce229..d70eaf39dfd 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -110,11 +110,11 @@ acpi_status acpi_ns_root_initialize(void) status = acpi_ns_lookup(NULL, init_val->name, init_val->type, ACPI_IMODE_LOAD_PASS2, ACPI_NS_NO_UPSEARCH, NULL, &new_node); - - if (ACPI_FAILURE(status) || (!new_node)) { /* Must be on same line for code converter */ + if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not create predefined name %s", init_val->name)); + continue; } /* @@ -179,8 +179,7 @@ acpi_status acpi_ns_root_initialize(void) /* Build an object around the static string */ - obj_desc->string.length = - (u32) ACPI_STRLEN(val); + obj_desc->string.length = (u32)ACPI_STRLEN(val); obj_desc->string.pointer = val; obj_desc->common.flags |= AOPOBJ_STATIC_POINTER; break; diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index ac389e5bb59..15143c44f5e 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -332,7 +332,7 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent_node) * * RETURN: None. * - * DESCRIPTION: Delete a subtree of the namespace. This includes all objects + * DESCRIPTION: Delete a subtree of the namespace. This includes all objects * stored within the subtree. * ******************************************************************************/ @@ -418,7 +418,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) * RETURN: Status * * DESCRIPTION: Delete entries within the namespace that are owned by a - * specific ID. Used to delete entire ACPI tables. All + * specific ID. Used to delete entire ACPI tables. All * reference counts are updated. * * MUTEX: Locks namespace during deletion walk. diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index 2526aaf945e..924b3c71473 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -209,14 +209,6 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, "Invalid ACPI Object Type 0x%08X", type)); } - if (!acpi_ut_valid_acpi_name(this_node->name.integer)) { - this_node->name.integer = - acpi_ut_repair_name(this_node->name.ascii); - - ACPI_WARNING((AE_INFO, "Invalid ACPI Name %08X", - this_node->name.integer)); - } - acpi_os_printf("%4.4s", acpi_ut_get_node_name(this_node)); } @@ -700,7 +692,7 @@ void acpi_ns_dump_entry(acpi_handle handle, u32 debug_level) * * PARAMETERS: search_base - Root of subtree to be dumped, or * NS_ALL to dump the entire namespace - * max_depth - Maximum depth of dump. Use INT_MAX + * max_depth - Maximum depth of dump. Use INT_MAX * for an effectively unlimited depth. * * RETURN: None diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index 95ffe8dfa1f..4328e2adfeb 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -96,8 +96,8 @@ acpi_status acpi_ns_initialize_objects(void) /* Walk entire namespace from the supplied root */ status = acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, acpi_ns_init_one_object, NULL, - &info, NULL); + ACPI_UINT32_MAX, acpi_ns_init_one_object, + NULL, &info, NULL); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace")); } diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index 76935ff2928..911f99127b9 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -80,8 +80,8 @@ acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node) /* * Parse the table and load the namespace with all named - * objects found within. Control methods are NOT parsed - * at this time. In fact, the control methods cannot be + * objects found within. Control methods are NOT parsed + * at this time. In fact, the control methods cannot be * parsed until the entire namespace is loaded, because * if a control method makes a forward reference (call) * to another control method, we can't continue parsing @@ -122,7 +122,7 @@ acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node) } /* - * Now we can parse the control methods. We always parse + * Now we can parse the control methods. We always parse * them here for a sanity check, and if configured for * just-in-time parsing, we delete the control method * parse trees. @@ -166,7 +166,7 @@ acpi_status acpi_ns_load_namespace(void) } /* - * Load the namespace. The DSDT is required, + * Load the namespace. The DSDT is required, * but the SSDT and PSDT tables are optional. */ status = acpi_ns_load_table_by_type(ACPI_TABLE_ID_DSDT); @@ -283,7 +283,7 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle) * RETURN: Status * * DESCRIPTION: Shrinks the namespace, typically in response to an undocking - * event. Deletes an entire subtree starting from (and + * event. Deletes an entire subtree starting from (and * including) the given handle. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index 96e0eb609bb..55a175eadcc 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -195,7 +195,7 @@ acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node) ACPI_ERROR((AE_INFO, "Invalid Namespace Node (%p) while traversing namespace", next_node)); - return 0; + return (0); } size += ACPI_PATH_SEGMENT_LENGTH; next_node = next_node->parent; diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c index d6c9a3cc671..e69f7fa2579 100644 --- a/drivers/acpi/acpica/nsobject.c +++ b/drivers/acpi/acpica/nsobject.c @@ -61,7 +61,7 @@ ACPI_MODULE_NAME("nsobject") * RETURN: Status * * DESCRIPTION: Record the given object as the value associated with the - * name whose acpi_handle is passed. If Object is NULL + * name whose acpi_handle is passed. If Object is NULL * and Type is ACPI_TYPE_ANY, set the name as having no value. * Note: Future may require that the Node->Flags field be passed * as a parameter. @@ -133,7 +133,7 @@ acpi_ns_attach_object(struct acpi_namespace_node *node, ((struct acpi_namespace_node *)object)->object) { /* * Value passed is a name handle and that name has a - * non-null value. Use that name's value and type. + * non-null value. Use that name's value and type. */ obj_desc = ((struct acpi_namespace_node *)object)->object; object_type = ((struct acpi_namespace_node *)object)->type; @@ -321,7 +321,7 @@ union acpi_operand_object *acpi_ns_get_secondary_object(union * * RETURN: Status * - * DESCRIPTION: Low-level attach data. Create and attach a Data object. + * DESCRIPTION: Low-level attach data. Create and attach a Data object. * ******************************************************************************/ @@ -377,7 +377,7 @@ acpi_ns_attach_data(struct acpi_namespace_node *node, * * RETURN: Status * - * DESCRIPTION: Low-level detach data. Delete the data node, but the caller + * DESCRIPTION: Low-level detach data. Delete the data node, but the caller * is responsible for the actual data. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index ec7ba2d3463..233f756d5cf 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -168,11 +168,11 @@ acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node) /* * AML Parse, pass 1 * - * In this pass, we load most of the namespace. Control methods - * are not parsed until later. A parse tree is not created. Instead, - * each Parser Op subtree is deleted when it is finished. This saves + * In this pass, we load most of the namespace. Control methods + * are not parsed until later. A parse tree is not created. Instead, + * each Parser Op subtree is deleted when it is finished. This saves * a great deal of memory, and allows a small cache of parse objects - * to service the entire parse. The second pass of the parse then + * to service the entire parse. The second pass of the parse then * performs another complete parse of the AML. */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 1\n")); diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index 456cc859f86..1d2d8ffc1bc 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -314,22 +314,7 @@ acpi_ns_search_and_enter(u32 target_name, * this problem, and we want to be able to enable ACPI support for them, * even though there are a few bad names. */ - if (!acpi_ut_valid_acpi_name(target_name)) { - target_name = - acpi_ut_repair_name(ACPI_CAST_PTR(char, &target_name)); - - /* Report warning only if in strict mode or debug mode */ - - if (!acpi_gbl_enable_interpreter_slack) { - ACPI_WARNING((AE_INFO, - "Found bad character(s) in name, repaired: [%4.4s]\n", - ACPI_CAST_PTR(char, &target_name))); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Found bad character(s) in name, repaired: [%4.4s]\n", - ACPI_CAST_PTR(char, &target_name))); - } - } + acpi_ut_repair_name(ACPI_CAST_PTR(char, &target_name)); /* Try to find the name in the namespace level specified by the caller */ diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index ef753a41e08..b5b4cb72a8a 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -530,7 +530,7 @@ acpi_ns_externalize_name(u32 internal_name_length, ((num_segments > 0) ? (num_segments - 1) : 0) + 1; /* - * Check to see if we're still in bounds. If not, there's a problem + * Check to see if we're still in bounds. If not, there's a problem * with internal_name (invalid format). */ if (required_length > internal_name_length) { @@ -557,10 +557,14 @@ acpi_ns_externalize_name(u32 internal_name_length, (*converted_name)[j++] = '.'; } - (*converted_name)[j++] = internal_name[names_index++]; - (*converted_name)[j++] = internal_name[names_index++]; - (*converted_name)[j++] = internal_name[names_index++]; - (*converted_name)[j++] = internal_name[names_index++]; + /* Copy and validate the 4-char name segment */ + + ACPI_MOVE_NAME(&(*converted_name)[j], + &internal_name[names_index]); + acpi_ut_repair_name(&(*converted_name)[j]); + + j += ACPI_NAME_SIZE; + names_index += ACPI_NAME_SIZE; } } @@ -681,7 +685,7 @@ u32 acpi_ns_opens_scope(acpi_object_type type) * \ (backslash) and ^ (carat) prefixes, and the * . (period) to separate segments are supported. * prefix_node - Root of subtree to be searched, or NS_ALL for the - * root of the name space. If Name is fully + * root of the name space. If Name is fully * qualified (first s8 is '\'), the passed value * of Scope will not be accessed. * flags - Used to indicate whether to perform upsearch or @@ -689,7 +693,7 @@ u32 acpi_ns_opens_scope(acpi_object_type type) * return_node - Where the Node is returned * * DESCRIPTION: Look up a name relative to a given scope and return the - * corresponding Node. NOTE: Scope can be null. + * corresponding Node. NOTE: Scope can be null. * * MUTEX: Locks namespace * diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index 730bccc5e7f..0483877f26b 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -60,8 +60,8 @@ ACPI_MODULE_NAME("nswalk") * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if * none is found. * - * DESCRIPTION: Return the next peer node within the namespace. If Handle - * is valid, Scope is ignored. Otherwise, the first node + * DESCRIPTION: Return the next peer node within the namespace. If Handle + * is valid, Scope is ignored. Otherwise, the first node * within Scope is returned. * ******************************************************************************/ @@ -97,8 +97,8 @@ struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if * none is found. * - * DESCRIPTION: Return the next peer node within the namespace. If Handle - * is valid, Scope is ignored. Otherwise, the first node + * DESCRIPTION: Return the next peer node within the namespace. If Handle + * is valid, Scope is ignored. Otherwise, the first node * within Scope is returned. * ******************************************************************************/ @@ -305,7 +305,7 @@ acpi_ns_walk_namespace(acpi_object_type type, /* * Depth first search: Attempt to go down another level in the - * namespace if we are allowed to. Don't go any further if we have + * namespace if we are allowed to. Don't go any further if we have * reached the caller specified maximum depth or if the user * function has specified that the maximum depth has been reached. */ diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index 9692e670233..d6a9f77972b 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -61,16 +61,16 @@ static void acpi_ns_resolve_references(struct acpi_evaluate_info *info); * PARAMETERS: handle - Object handle (optional) * pathname - Object pathname (optional) * external_params - List of parameters to pass to method, - * terminated by NULL. May be NULL + * terminated by NULL. May be NULL * if no parameters are being passed. * return_buffer - Where to put method's return value (if - * any). If NULL, no value is returned. + * any). If NULL, no value is returned. * return_type - Expected type of return object * * RETURN: Status * * DESCRIPTION: Find and evaluate the given object, passing the given - * parameters if necessary. One of "Handle" or "Pathname" must + * parameters if necessary. One of "Handle" or "Pathname" must * be valid (non-null) * ******************************************************************************/ @@ -155,15 +155,15 @@ ACPI_EXPORT_SYMBOL(acpi_evaluate_object_typed) * PARAMETERS: handle - Object handle (optional) * pathname - Object pathname (optional) * external_params - List of parameters to pass to method, - * terminated by NULL. May be NULL + * terminated by NULL. May be NULL * if no parameters are being passed. * return_buffer - Where to put method's return value (if - * any). If NULL, no value is returned. + * any). If NULL, no value is returned. * * RETURN: Status * * DESCRIPTION: Find and evaluate the given object, passing the given - * parameters if necessary. One of "Handle" or "Pathname" must + * parameters if necessary. One of "Handle" or "Pathname" must * be valid (non-null) * ******************************************************************************/ @@ -542,15 +542,15 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, acpi_status status; struct acpi_namespace_node *node; u32 flags; - struct acpica_device_id *hid; - struct acpica_device_id_list *cid; + struct acpi_pnp_device_id *hid; + struct acpi_pnp_device_id_list *cid; u32 i; u8 found; int no_match; status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { - return (status); + return_ACPI_STATUS(status); } node = acpi_ns_validate_handle(obj_handle); @@ -656,7 +656,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, * DESCRIPTION: Performs a modified depth-first walk of the namespace tree, * starting (and ending) at the object specified by start_handle. * The user_function is called whenever an object of type - * Device is found. If the user function returns + * Device is found. If the user function returns * a non-zero value, the search is terminated immediately and this * value is returned to the caller. * diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 08e9610b34c..811c6f13f47 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -53,8 +53,8 @@ ACPI_MODULE_NAME("nsxfname") /* Local prototypes */ -static char *acpi_ns_copy_device_id(struct acpica_device_id *dest, - struct acpica_device_id *source, +static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, + struct acpi_pnp_device_id *source, char *string_area); /****************************************************************************** @@ -69,8 +69,8 @@ static char *acpi_ns_copy_device_id(struct acpica_device_id *dest, * RETURN: Status * * DESCRIPTION: This routine will search for a caller specified name in the - * name space. The caller can restrict the search region by - * specifying a non NULL parent. The parent value is itself a + * name space. The caller can restrict the search region by + * specifying a non NULL parent. The parent value is itself a * namespace handle. * ******************************************************************************/ @@ -149,7 +149,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_handle) * RETURN: Pointer to a string containing the fully qualified Name. * * DESCRIPTION: This routine returns the fully qualified name associated with - * the Handle parameter. This and the acpi_pathname_to_handle are + * the Handle parameter. This and the acpi_pathname_to_handle are * complementary functions. * ******************************************************************************/ @@ -202,8 +202,7 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) /* Just copy the ACPI name from the Node and zero terminate it */ - ACPI_STRNCPY(buffer->pointer, acpi_ut_get_node_name(node), - ACPI_NAME_SIZE); + ACPI_MOVE_NAME(buffer->pointer, acpi_ut_get_node_name(node)); ((char *)buffer->pointer)[ACPI_NAME_SIZE] = 0; status = AE_OK; @@ -219,20 +218,21 @@ ACPI_EXPORT_SYMBOL(acpi_get_name) * * FUNCTION: acpi_ns_copy_device_id * - * PARAMETERS: dest - Pointer to the destination DEVICE_ID - * source - Pointer to the source DEVICE_ID + * PARAMETERS: dest - Pointer to the destination PNP_DEVICE_ID + * source - Pointer to the source PNP_DEVICE_ID * string_area - Pointer to where to copy the dest string * * RETURN: Pointer to the next string area * - * DESCRIPTION: Copy a single DEVICE_ID, including the string data. + * DESCRIPTION: Copy a single PNP_DEVICE_ID, including the string data. * ******************************************************************************/ -static char *acpi_ns_copy_device_id(struct acpica_device_id *dest, - struct acpica_device_id *source, +static char *acpi_ns_copy_device_id(struct acpi_pnp_device_id *dest, + struct acpi_pnp_device_id *source, char *string_area) { - /* Create the destination DEVICE_ID */ + + /* Create the destination PNP_DEVICE_ID */ dest->string = string_area; dest->length = source->length; @@ -256,8 +256,8 @@ static char *acpi_ns_copy_device_id(struct acpica_device_id *dest, * namespace node and possibly by running several standard * control methods (Such as in the case of a device.) * - * For Device and Processor objects, run the Device _HID, _UID, _CID, _STA, - * _ADR, _sx_w, and _sx_d methods. + * For Device and Processor objects, run the Device _HID, _UID, _CID, _SUB, + * _STA, _ADR, _sx_w, and _sx_d methods. * * Note: Allocates the return buffer, must be freed by the caller. * @@ -269,9 +269,10 @@ acpi_get_object_info(acpi_handle handle, { struct acpi_namespace_node *node; struct acpi_device_info *info; - struct acpica_device_id_list *cid_list = NULL; - struct acpica_device_id *hid = NULL; - struct acpica_device_id *uid = NULL; + struct acpi_pnp_device_id_list *cid_list = NULL; + struct acpi_pnp_device_id *hid = NULL; + struct acpi_pnp_device_id *uid = NULL; + struct acpi_pnp_device_id *sub = NULL; char *next_id_string; acpi_object_type type; acpi_name name; @@ -316,7 +317,7 @@ acpi_get_object_info(acpi_handle handle, if ((type == ACPI_TYPE_DEVICE) || (type == ACPI_TYPE_PROCESSOR)) { /* * Get extra info for ACPI Device/Processor objects only: - * Run the Device _HID, _UID, and _CID methods. + * Run the Device _HID, _UID, _SUB, and _CID methods. * * Note: none of these methods are required, so they may or may * not be present for this device. The Info->Valid bitfield is used @@ -339,6 +340,14 @@ acpi_get_object_info(acpi_handle handle, valid |= ACPI_VALID_UID; } + /* Execute the Device._SUB method */ + + status = acpi_ut_execute_SUB(node, &sub); + if (ACPI_SUCCESS(status)) { + info_size += sub->length; + valid |= ACPI_VALID_SUB; + } + /* Execute the Device._CID method */ status = acpi_ut_execute_CID(node, &cid_list); @@ -348,7 +357,7 @@ acpi_get_object_info(acpi_handle handle, info_size += (cid_list->list_size - - sizeof(struct acpica_device_id_list)); + sizeof(struct acpi_pnp_device_id_list)); valid |= ACPI_VALID_CID; } } @@ -418,16 +427,17 @@ acpi_get_object_info(acpi_handle handle, next_id_string = ACPI_CAST_PTR(char, info->compatible_id_list.ids); if (cid_list) { - /* Point past the CID DEVICE_ID array */ + /* Point past the CID PNP_DEVICE_ID array */ next_id_string += ((acpi_size) cid_list->count * - sizeof(struct acpica_device_id)); + sizeof(struct acpi_pnp_device_id)); } /* - * Copy the HID, UID, and CIDs to the return buffer. The variable-length - * strings are copied to the reserved area at the end of the buffer. + * Copy the HID, UID, SUB, and CIDs to the return buffer. + * The variable-length strings are copied to the reserved area + * at the end of the buffer. * * For HID and CID, check if the ID is a PCI Root Bridge. */ @@ -445,6 +455,11 @@ acpi_get_object_info(acpi_handle handle, uid, next_id_string); } + if (sub) { + next_id_string = acpi_ns_copy_device_id(&info->subsystem_id, + sub, next_id_string); + } + if (cid_list) { info->compatible_id_list.count = cid_list->count; info->compatible_id_list.list_size = cid_list->list_size; @@ -481,6 +496,9 @@ acpi_get_object_info(acpi_handle handle, if (uid) { ACPI_FREE(uid); } + if (sub) { + ACPI_FREE(sub); + } if (cid_list) { ACPI_FREE(cid_list); } diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index 6766fc4f088..9d029dac6b6 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -220,8 +220,8 @@ ACPI_EXPORT_SYMBOL(acpi_get_parent) * * RETURN: Status * - * DESCRIPTION: Return the next peer object within the namespace. If Handle is - * valid, Scope is ignored. Otherwise, the first object within + * DESCRIPTION: Return the next peer object within the namespace. If Handle is + * valid, Scope is ignored. Otherwise, the first object within * Scope is returned. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index 844464c4f90..cb79e2d4d74 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -120,7 +120,7 @@ acpi_ps_get_next_package_length(struct acpi_parse_state *parser_state) * RETURN: Pointer to end-of-package +1 * * DESCRIPTION: Get next package length and return a pointer past the end of - * the package. Consumes the package length field + * the package. Consumes the package length field * ******************************************************************************/ @@ -147,8 +147,8 @@ u8 *acpi_ps_get_next_package_end(struct acpi_parse_state *parser_state) * RETURN: Pointer to the start of the name string (pointer points into * the AML. * - * DESCRIPTION: Get next raw namestring within the AML stream. Handles all name - * prefix characters. Set parser state to point past the string. + * DESCRIPTION: Get next raw namestring within the AML stream. Handles all name + * prefix characters. Set parser state to point past the string. * (Name is consumed from the AML.) * ******************************************************************************/ @@ -220,7 +220,7 @@ char *acpi_ps_get_next_namestring(struct acpi_parse_state *parser_state) * * DESCRIPTION: Get next name (if method call, return # of required args). * Names are looked up in the internal namespace to determine - * if the name represents a control method. If a method + * if the name represents a control method. If a method * is found, the number of arguments to the method is returned. * This information is critical for parsing to continue correctly. * diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 799162c1b6d..5607805aab2 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -133,18 +133,46 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) case AML_CLASS_UNKNOWN: - /* The opcode is unrecognized. Just skip unknown opcodes */ + /* The opcode is unrecognized. Complain and skip unknown opcodes */ - ACPI_ERROR((AE_INFO, - "Found unknown opcode 0x%X at AML address %p offset 0x%X, ignoring", - walk_state->opcode, walk_state->parser_state.aml, - walk_state->aml_offset)); + if (walk_state->pass_number == 2) { + ACPI_ERROR((AE_INFO, + "Unknown opcode 0x%.2X at table offset 0x%.4X, ignoring", + walk_state->opcode, + (u32)(walk_state->aml_offset + + sizeof(struct acpi_table_header)))); - ACPI_DUMP_BUFFER(walk_state->parser_state.aml, 128); + ACPI_DUMP_BUFFER(walk_state->parser_state.aml - 16, 48); - /* Assume one-byte bad opcode */ +#ifdef ACPI_ASL_COMPILER + /* + * This is executed for the disassembler only. Output goes + * to the disassembled ASL output file. + */ + acpi_os_printf + ("/*\nError: Unknown opcode 0x%.2X at table offset 0x%.4X, context:\n", + walk_state->opcode, + (u32)(walk_state->aml_offset + + sizeof(struct acpi_table_header))); + + /* Dump the context surrounding the invalid opcode */ + + acpi_ut_dump_buffer(((u8 *)walk_state->parser_state. + aml - 16), 48, DB_BYTE_DISPLAY, + walk_state->aml_offset + + sizeof(struct acpi_table_header) - + 16); + acpi_os_printf(" */\n"); +#endif + } + + /* Increment past one-byte or two-byte opcode */ walk_state->parser_state.aml++; + if (walk_state->opcode > 0xFF) { /* Can only happen if first byte is 0x5B */ + walk_state->parser_state.aml++; + } + return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); default: @@ -519,11 +547,18 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, if ((op_info->class == AML_CLASS_EXECUTE) && (!arg)) { ACPI_WARNING((AE_INFO, - "Detected an unsupported executable opcode " - "at module-level: [0x%.4X] at table offset 0x%.4X", - op->common.aml_opcode, - (u32)((aml_op_start - walk_state->parser_state.aml_start) - + sizeof(struct acpi_table_header)))); + "Unsupported module-level executable opcode " + "0x%.2X at table offset 0x%.4X", + op->common. + aml_opcode, + (u32) + (ACPI_PTR_DIFF + (aml_op_start, + walk_state-> + parser_state. + aml_start) + + sizeof(struct + acpi_table_header)))); } } break; @@ -843,8 +878,6 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state, *op = NULL; } - ACPI_PREEMPTION_POINT(); - return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c index ed1d457bd5c..1793d934aa3 100644 --- a/drivers/acpi/acpica/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -59,7 +59,7 @@ static const u8 acpi_gbl_argument_count[] = * * DESCRIPTION: Opcode table. Each entry contains <opcode, type, name, operands> * The name is a simple ascii string, the operand specifier is an - * ascii string with one letter per operand. The letter specifies + * ascii string with one letter per operand. The letter specifies * the operand type. * ******************************************************************************/ @@ -183,7 +183,7 @@ static const u8 acpi_gbl_argument_count[] = ******************************************************************************/ /* - * Master Opcode information table. A summary of everything we know about each + * Master Opcode information table. A summary of everything we know about each * opcode, all in one place. */ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { @@ -392,10 +392,12 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE), /* 38 */ ACPI_OP("LAnd", ARGP_LAND_OP, ARGI_LAND_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, - AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | AML_CONSTANT), + AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | + AML_CONSTANT), /* 39 */ ACPI_OP("LOr", ARGP_LOR_OP, ARGI_LOR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, - AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | AML_CONSTANT), + AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | + AML_CONSTANT), /* 3A */ ACPI_OP("LNot", ARGP_LNOT_OP, ARGI_LNOT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT), @@ -495,7 +497,8 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { AML_NSNODE | AML_NAMED | AML_DEFER), /* 59 */ ACPI_OP("Field", ARGP_FIELD_OP, ARGI_FIELD_OP, ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD), + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_FIELD), /* 5A */ ACPI_OP("Device", ARGP_DEVICE_OP, ARGI_DEVICE_OP, ACPI_TYPE_DEVICE, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, @@ -519,12 +522,13 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { /* 5E */ ACPI_OP("IndexField", ARGP_INDEX_FIELD_OP, ARGI_INDEX_FIELD_OP, ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD), + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_FIELD), /* 5F */ ACPI_OP("BankField", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP, - ACPI_TYPE_LOCAL_BANK_FIELD, AML_CLASS_NAMED_OBJECT, - AML_TYPE_NAMED_FIELD, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD | - AML_DEFER), + ACPI_TYPE_LOCAL_BANK_FIELD, + AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_FIELD | AML_DEFER), /* Internal opcodes that map to invalid AML opcodes */ @@ -632,7 +636,8 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { /* 7D */ ACPI_OP("[EvalSubTree]", ARGP_SCOPE_OP, ARGI_SCOPE_OP, ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, - AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE), + AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | + AML_NSNODE), /* ACPI 3.0 opcodes */ @@ -695,7 +700,7 @@ static const u8 acpi_gbl_short_op_index[256] = { /* * This table is indexed by the second opcode of the extended opcode - * pair. It returns an index into the opcode table (acpi_gbl_aml_op_info) + * pair. It returns an index into the opcode table (acpi_gbl_aml_op_info) */ static const u8 acpi_gbl_long_op_index[NUM_EXTENDED_OPCODE] = { /* 0 1 2 3 4 5 6 7 */ diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index 01985703bb9..2494caf4775 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -43,9 +43,9 @@ /* * Parse the AML and build an operation tree as most interpreters, - * like Perl, do. Parsing is done by hand rather than with a YACC + * like Perl, do. Parsing is done by hand rather than with a YACC * generated parser to tightly constrain stack and dynamic memory - * usage. At the same time, parsing is kept flexible and the code + * usage. At the same time, parsing is kept flexible and the code * fairly compact by parsing based on a list of AML opcode * templates in aml_op_info[] */ @@ -379,7 +379,7 @@ acpi_ps_next_parse_state(struct acpi_walk_state *walk_state, case AE_CTRL_FALSE: /* * Either an IF/WHILE Predicate was false or we encountered a BREAK - * opcode. In both cases, we do not execute the rest of the + * opcode. In both cases, we do not execute the rest of the * package; We simply close out the parent (finishing the walk of * this branch of the tree) and continue execution at the parent * level. @@ -459,8 +459,9 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) /* Executing a control method - additional cleanup */ - acpi_ds_terminate_control_method( - walk_state->method_desc, walk_state); + acpi_ds_terminate_control_method(walk_state-> + method_desc, + walk_state); } acpi_ds_delete_walk_state(walk_state); @@ -487,7 +488,7 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) acpi_gbl_current_walk_list = thread; /* - * Execute the walk loop as long as there is a valid Walk State. This + * Execute the walk loop as long as there is a valid Walk State. This * handles nested control method invocations without recursion. */ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "State=%p\n", walk_state)); diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c index 8736ad5f04d..4137dcb352d 100644 --- a/drivers/acpi/acpica/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -108,7 +108,7 @@ void acpi_ps_init_op(union acpi_parse_object *op, u16 opcode) * RETURN: Pointer to the new Op, null on failure * * DESCRIPTION: Allocate an acpi_op, choose op type (and thus size) based on - * opcode. A cache of opcodes is available for the pure + * opcode. A cache of opcodes is available for the pure * GENERIC_OP, since this is by far the most commonly used. * ******************************************************************************/ @@ -164,7 +164,7 @@ union acpi_parse_object *acpi_ps_alloc_op(u16 opcode) * * RETURN: None. * - * DESCRIPTION: Free an Op object. Either put it on the GENERIC_OP cache list + * DESCRIPTION: Free an Op object. Either put it on the GENERIC_OP cache list * or actually free it. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index de12469d1c9..147feb6aa2a 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -457,6 +457,15 @@ acpi_rs_get_list_length(u8 * aml_buffer, * Get the number of vendor data bytes */ extra_struct_bytes = resource_length; + + /* + * There is already one byte included in the minimum + * descriptor size. If there are extra struct bytes, + * subtract one from the count. + */ + if (extra_struct_bytes) { + extra_struct_bytes--; + } break; case ACPI_RESOURCE_NAME_END_TAG: @@ -601,7 +610,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, /* * Calculate the size of the return buffer. * The base size is the number of elements * the sizes of the - * structures. Additional space for the strings is added below. + * structures. Additional space for the strings is added below. * The minus one is to subtract the size of the u8 Source[1] * member because it is added below. * @@ -664,8 +673,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, (*sub_object_list)->string. length + 1); } else { - temp_size_needed += - acpi_ns_get_pathname_length((*sub_object_list)->reference.node); + temp_size_needed += acpi_ns_get_pathname_length((*sub_object_list)->reference.node); } } else { /* diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c index 46b5324b22d..8b64db9a3fd 100644 --- a/drivers/acpi/acpica/rslist.c +++ b/drivers/acpi/acpica/rslist.c @@ -109,7 +109,7 @@ acpi_rs_convert_aml_to_resources(u8 * aml, ACPI_ERROR((AE_INFO, "Invalid/unsupported resource descriptor: Type 0x%2.2X", resource_index)); - return (AE_AML_INVALID_RESOURCE_TYPE); + return_ACPI_STATUS(AE_AML_INVALID_RESOURCE_TYPE); } /* Convert the AML byte stream resource to a local resource struct */ @@ -200,7 +200,7 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, ACPI_ERROR((AE_INFO, "Invalid/unsupported resource descriptor: Type 0x%2.2X", resource->type)); - return (AE_AML_INVALID_RESOURCE_TYPE); + return_ACPI_STATUS(AE_AML_INVALID_RESOURCE_TYPE); } status = acpi_rs_convert_resource_to_aml(resource, diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c index 57deae16657..77d1db29a72 100644 --- a/drivers/acpi/acpica/tbfind.c +++ b/drivers/acpi/acpica/tbfind.c @@ -77,7 +77,7 @@ acpi_tb_find_table(char *signature, /* Normalize the input strings */ ACPI_MEMSET(&header, 0, sizeof(struct acpi_table_header)); - ACPI_STRNCPY(header.signature, signature, ACPI_NAME_SIZE); + ACPI_MOVE_NAME(header.signature, signature); ACPI_STRNCPY(header.oem_id, oem_id, ACPI_OEM_ID_SIZE); ACPI_STRNCPY(header.oem_table_id, oem_table_id, ACPI_OEM_TABLE_ID_SIZE); diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 70f9d787c82..f540ae46292 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -526,6 +526,8 @@ void acpi_tb_terminate(void) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n")); (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + + return_VOID; } /******************************************************************************* diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index b6cea30da63..285e24b9738 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -354,7 +354,7 @@ u8 acpi_tb_checksum(u8 *buffer, u32 length) sum = (u8) (sum + *(buffer++)); } - return sum; + return (sum); } /******************************************************************************* diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 21101262e47..f5632780421 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -236,7 +236,7 @@ acpi_get_table_header(char *signature, sizeof(struct acpi_table_header)); if (!header) { - return AE_NO_MEMORY; + return (AE_NO_MEMORY); } ACPI_MEMCPY(out_table_header, header, sizeof(struct acpi_table_header)); @@ -244,7 +244,7 @@ acpi_get_table_header(char *signature, sizeof(struct acpi_table_header)); } else { - return AE_NOT_FOUND; + return (AE_NOT_FOUND); } } else { ACPI_MEMCPY(out_table_header, diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index f87cc63e69a..a5e1e4e4709 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -211,7 +211,7 @@ static acpi_status acpi_tb_load_namespace(void) * DESCRIPTION: Dynamically load an ACPI table from the caller's buffer. Must * be a valid ACPI table with a valid ACPI table header. * Note1: Mainly intended to support hotplug addition of SSDTs. - * Note2: Does not copy the incoming table. User is reponsible + * Note2: Does not copy the incoming table. User is responsible * to ensure that the table is not deleted or unmapped. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c index 74e72080003..28f330230f9 100644 --- a/drivers/acpi/acpica/tbxfroot.c +++ b/drivers/acpi/acpica/tbxfroot.c @@ -67,7 +67,6 @@ static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp); static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp) { - ACPI_FUNCTION_ENTRY(); /* * The signature and checksum must both be correct @@ -108,7 +107,7 @@ static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp) * RETURN: Status, RSDP physical address * * DESCRIPTION: Search lower 1Mbyte of memory for the root system descriptor - * pointer structure. If it is found, set *RSDP to point to it. + * pointer structure. If it is found, set *RSDP to point to it. * * NOTE1: The RSDP must be either in the first 1K of the Extended * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.) diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c new file mode 100644 index 00000000000..e1d40ed2639 --- /dev/null +++ b/drivers/acpi/acpica/utcache.c @@ -0,0 +1,323 @@ +/****************************************************************************** + * + * Module Name: utcache - local cache allocation routines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include <acpi/acpi.h> +#include "accommon.h" + +#define _COMPONENT ACPI_UTILITIES +ACPI_MODULE_NAME("utcache") + +#ifdef ACPI_USE_LOCAL_CACHE +/******************************************************************************* + * + * FUNCTION: acpi_os_create_cache + * + * PARAMETERS: cache_name - Ascii name for the cache + * object_size - Size of each cached object + * max_depth - Maximum depth of the cache (in objects) + * return_cache - Where the new cache object is returned + * + * RETURN: Status + * + * DESCRIPTION: Create a cache object + * + ******************************************************************************/ +acpi_status +acpi_os_create_cache(char *cache_name, + u16 object_size, + u16 max_depth, struct acpi_memory_list ** return_cache) +{ + struct acpi_memory_list *cache; + + ACPI_FUNCTION_ENTRY(); + + if (!cache_name || !return_cache || (object_size < 16)) { + return (AE_BAD_PARAMETER); + } + + /* Create the cache object */ + + cache = acpi_os_allocate(sizeof(struct acpi_memory_list)); + if (!cache) { + return (AE_NO_MEMORY); + } + + /* Populate the cache object and return it */ + + ACPI_MEMSET(cache, 0, sizeof(struct acpi_memory_list)); + cache->link_offset = 8; + cache->list_name = cache_name; + cache->object_size = object_size; + cache->max_depth = max_depth; + + *return_cache = cache; + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_os_purge_cache + * + * PARAMETERS: cache - Handle to cache object + * + * RETURN: Status + * + * DESCRIPTION: Free all objects within the requested cache. + * + ******************************************************************************/ + +acpi_status acpi_os_purge_cache(struct acpi_memory_list * cache) +{ + char *next; + acpi_status status; + + ACPI_FUNCTION_ENTRY(); + + if (!cache) { + return (AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Walk the list of objects in this cache */ + + while (cache->list_head) { + + /* Delete and unlink one cached state object */ + + next = *(ACPI_CAST_INDIRECT_PTR(char, + &(((char *)cache-> + list_head)[cache-> + link_offset]))); + ACPI_FREE(cache->list_head); + + cache->list_head = next; + cache->current_depth--; + } + + (void)acpi_ut_release_mutex(ACPI_MTX_CACHES); + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_os_delete_cache + * + * PARAMETERS: cache - Handle to cache object + * + * RETURN: Status + * + * DESCRIPTION: Free all objects within the requested cache and delete the + * cache object. + * + ******************************************************************************/ + +acpi_status acpi_os_delete_cache(struct acpi_memory_list * cache) +{ + acpi_status status; + + ACPI_FUNCTION_ENTRY(); + + /* Purge all objects in the cache */ + + status = acpi_os_purge_cache(cache); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Now we can delete the cache object */ + + acpi_os_free(cache); + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_os_release_object + * + * PARAMETERS: cache - Handle to cache object + * object - The object to be released + * + * RETURN: None + * + * DESCRIPTION: Release an object to the specified cache. If cache is full, + * the object is deleted. + * + ******************************************************************************/ + +acpi_status +acpi_os_release_object(struct acpi_memory_list * cache, void *object) +{ + acpi_status status; + + ACPI_FUNCTION_ENTRY(); + + if (!cache || !object) { + return (AE_BAD_PARAMETER); + } + + /* If cache is full, just free this object */ + + if (cache->current_depth >= cache->max_depth) { + ACPI_FREE(object); + ACPI_MEM_TRACKING(cache->total_freed++); + } + + /* Otherwise put this object back into the cache */ + + else { + status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Mark the object as cached */ + + ACPI_MEMSET(object, 0xCA, cache->object_size); + ACPI_SET_DESCRIPTOR_TYPE(object, ACPI_DESC_TYPE_CACHED); + + /* Put the object at the head of the cache list */ + + *(ACPI_CAST_INDIRECT_PTR(char, + &(((char *)object)[cache-> + link_offset]))) = + cache->list_head; + cache->list_head = object; + cache->current_depth++; + + (void)acpi_ut_release_mutex(ACPI_MTX_CACHES); + } + + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_os_acquire_object + * + * PARAMETERS: cache - Handle to cache object + * + * RETURN: the acquired object. NULL on error + * + * DESCRIPTION: Get an object from the specified cache. If cache is empty, + * the object is allocated. + * + ******************************************************************************/ + +void *acpi_os_acquire_object(struct acpi_memory_list *cache) +{ + acpi_status status; + void *object; + + ACPI_FUNCTION_NAME(os_acquire_object); + + if (!cache) { + return (NULL); + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); + if (ACPI_FAILURE(status)) { + return (NULL); + } + + ACPI_MEM_TRACKING(cache->requests++); + + /* Check the cache first */ + + if (cache->list_head) { + + /* There is an object available, use it */ + + object = cache->list_head; + cache->list_head = *(ACPI_CAST_INDIRECT_PTR(char, + &(((char *) + object)[cache-> + link_offset]))); + + cache->current_depth--; + + ACPI_MEM_TRACKING(cache->hits++); + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "Object %p from %s cache\n", object, + cache->list_name)); + + status = acpi_ut_release_mutex(ACPI_MTX_CACHES); + if (ACPI_FAILURE(status)) { + return (NULL); + } + + /* Clear (zero) the previously used Object */ + + ACPI_MEMSET(object, 0, cache->object_size); + } else { + /* The cache is empty, create a new object */ + + ACPI_MEM_TRACKING(cache->total_allocated++); + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + if ((cache->total_allocated - cache->total_freed) > + cache->max_occupied) { + cache->max_occupied = + cache->total_allocated - cache->total_freed; + } +#endif + + /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */ + + status = acpi_ut_release_mutex(ACPI_MTX_CACHES); + if (ACPI_FAILURE(status)) { + return (NULL); + } + + object = ACPI_ALLOCATE_ZEROED(cache->object_size); + if (!object) { + return (NULL); + } + } + + return (object); +} +#endif /* ACPI_USE_LOCAL_CACHE */ diff --git a/drivers/acpi/acpica/utclib.c b/drivers/acpi/acpica/utclib.c new file mode 100644 index 00000000000..19ea4755aa7 --- /dev/null +++ b/drivers/acpi/acpica/utclib.c @@ -0,0 +1,749 @@ +/****************************************************************************** + * + * Module Name: cmclib - Local implementation of C library functions + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include <acpi/acpi.h> +#include "accommon.h" + +/* + * These implementations of standard C Library routines can optionally be + * used if a C library is not available. In general, they are less efficient + * than an inline or assembly implementation + */ + +#define _COMPONENT ACPI_UTILITIES +ACPI_MODULE_NAME("cmclib") + +#ifndef ACPI_USE_SYSTEM_CLIBRARY +#define NEGATIVE 1 +#define POSITIVE 0 +/******************************************************************************* + * + * FUNCTION: acpi_ut_memcmp (memcmp) + * + * PARAMETERS: buffer1 - First Buffer + * buffer2 - Second Buffer + * count - Maximum # of bytes to compare + * + * RETURN: Index where Buffers mismatched, or 0 if Buffers matched + * + * DESCRIPTION: Compare two Buffers, with a maximum length + * + ******************************************************************************/ +int acpi_ut_memcmp(const char *buffer1, const char *buffer2, acpi_size count) +{ + + return ((count == ACPI_SIZE_MAX) ? 0 : ((unsigned char)*buffer1 - + (unsigned char)*buffer2)); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_memcpy (memcpy) + * + * PARAMETERS: dest - Target of the copy + * src - Source buffer to copy + * count - Number of bytes to copy + * + * RETURN: Dest + * + * DESCRIPTION: Copy arbitrary bytes of memory + * + ******************************************************************************/ + +void *acpi_ut_memcpy(void *dest, const void *src, acpi_size count) +{ + char *new = (char *)dest; + char *old = (char *)src; + + while (count) { + *new = *old; + new++; + old++; + count--; + } + + return (dest); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_memset (memset) + * + * PARAMETERS: dest - Buffer to set + * value - Value to set each byte of memory + * count - Number of bytes to set + * + * RETURN: Dest + * + * DESCRIPTION: Initialize a buffer to a known value. + * + ******************************************************************************/ + +void *acpi_ut_memset(void *dest, u8 value, acpi_size count) +{ + char *new = (char *)dest; + + while (count) { + *new = (char)value; + new++; + count--; + } + + return (dest); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strlen (strlen) + * + * PARAMETERS: string - Null terminated string + * + * RETURN: Length + * + * DESCRIPTION: Returns the length of the input string + * + ******************************************************************************/ + +acpi_size acpi_ut_strlen(const char *string) +{ + u32 length = 0; + + /* Count the string until a null is encountered */ + + while (*string) { + length++; + string++; + } + + return (length); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strcpy (strcpy) + * + * PARAMETERS: dst_string - Target of the copy + * src_string - The source string to copy + * + * RETURN: dst_string + * + * DESCRIPTION: Copy a null terminated string + * + ******************************************************************************/ + +char *acpi_ut_strcpy(char *dst_string, const char *src_string) +{ + char *string = dst_string; + + /* Move bytes brute force */ + + while (*src_string) { + *string = *src_string; + + string++; + src_string++; + } + + /* Null terminate */ + + *string = 0; + return (dst_string); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strncpy (strncpy) + * + * PARAMETERS: dst_string - Target of the copy + * src_string - The source string to copy + * count - Maximum # of bytes to copy + * + * RETURN: dst_string + * + * DESCRIPTION: Copy a null terminated string, with a maximum length + * + ******************************************************************************/ + +char *acpi_ut_strncpy(char *dst_string, const char *src_string, acpi_size count) +{ + char *string = dst_string; + + /* Copy the string */ + + for (string = dst_string; + count && (count--, (*string++ = *src_string++));) {; + } + + /* Pad with nulls if necessary */ + + while (count--) { + *string = 0; + string++; + } + + /* Return original pointer */ + + return (dst_string); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strcmp (strcmp) + * + * PARAMETERS: string1 - First string + * string2 - Second string + * + * RETURN: Index where strings mismatched, or 0 if strings matched + * + * DESCRIPTION: Compare two null terminated strings + * + ******************************************************************************/ + +int acpi_ut_strcmp(const char *string1, const char *string2) +{ + + for (; (*string1 == *string2); string2++) { + if (!*string1++) { + return (0); + } + } + + return ((unsigned char)*string1 - (unsigned char)*string2); +} + +#ifdef ACPI_FUTURE_IMPLEMENTATION +/* Not used at this time */ +/******************************************************************************* + * + * FUNCTION: acpi_ut_strchr (strchr) + * + * PARAMETERS: string - Search string + * ch - character to search for + * + * RETURN: Ptr to char or NULL if not found + * + * DESCRIPTION: Search a string for a character + * + ******************************************************************************/ + +char *acpi_ut_strchr(const char *string, int ch) +{ + + for (; (*string); string++) { + if ((*string) == (char)ch) { + return ((char *)string); + } + } + + return (NULL); +} +#endif + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strncmp (strncmp) + * + * PARAMETERS: string1 - First string + * string2 - Second string + * count - Maximum # of bytes to compare + * + * RETURN: Index where strings mismatched, or 0 if strings matched + * + * DESCRIPTION: Compare two null terminated strings, with a maximum length + * + ******************************************************************************/ + +int acpi_ut_strncmp(const char *string1, const char *string2, acpi_size count) +{ + + for (; count-- && (*string1 == *string2); string2++) { + if (!*string1++) { + return (0); + } + } + + return ((count == ACPI_SIZE_MAX) ? 0 : ((unsigned char)*string1 - + (unsigned char)*string2)); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strcat (Strcat) + * + * PARAMETERS: dst_string - Target of the copy + * src_string - The source string to copy + * + * RETURN: dst_string + * + * DESCRIPTION: Append a null terminated string to a null terminated string + * + ******************************************************************************/ + +char *acpi_ut_strcat(char *dst_string, const char *src_string) +{ + char *string; + + /* Find end of the destination string */ + + for (string = dst_string; *string++;) {; + } + + /* Concatenate the string */ + + for (--string; (*string++ = *src_string++);) {; + } + + return (dst_string); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strncat (strncat) + * + * PARAMETERS: dst_string - Target of the copy + * src_string - The source string to copy + * count - Maximum # of bytes to copy + * + * RETURN: dst_string + * + * DESCRIPTION: Append a null terminated string to a null terminated string, + * with a maximum count. + * + ******************************************************************************/ + +char *acpi_ut_strncat(char *dst_string, const char *src_string, acpi_size count) +{ + char *string; + + if (count) { + + /* Find end of the destination string */ + + for (string = dst_string; *string++;) {; + } + + /* Concatenate the string */ + + for (--string; (*string++ = *src_string++) && --count;) {; + } + + /* Null terminate if necessary */ + + if (!count) { + *string = 0; + } + } + + return (dst_string); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strstr (strstr) + * + * PARAMETERS: string1 - Target string + * string2 - Substring to search for + * + * RETURN: Where substring match starts, Null if no match found + * + * DESCRIPTION: Checks if String2 occurs in String1. This is not really a + * full implementation of strstr, only sufficient for command + * matching + * + ******************************************************************************/ + +char *acpi_ut_strstr(char *string1, char *string2) +{ + char *string; + + if (acpi_ut_strlen(string2) > acpi_ut_strlen(string1)) { + return (NULL); + } + + /* Walk entire string, comparing the letters */ + + for (string = string1; *string2;) { + if (*string2 != *string) { + return (NULL); + } + + string2++; + string++; + } + + return (string1); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strtoul (strtoul) + * + * PARAMETERS: string - Null terminated string + * terminater - Where a pointer to the terminating byte is + * returned + * base - Radix of the string + * + * RETURN: Converted value + * + * DESCRIPTION: Convert a string into a 32-bit unsigned value. + * Note: use acpi_ut_strtoul64 for 64-bit integers. + * + ******************************************************************************/ + +u32 acpi_ut_strtoul(const char *string, char **terminator, u32 base) +{ + u32 converted = 0; + u32 index; + u32 sign; + const char *string_start; + u32 return_value = 0; + acpi_status status = AE_OK; + + /* + * Save the value of the pointer to the buffer's first + * character, save the current errno value, and then + * skip over any white space in the buffer: + */ + string_start = string; + while (ACPI_IS_SPACE(*string) || *string == '\t') { + ++string; + } + + /* + * The buffer may contain an optional plus or minus sign. + * If it does, then skip over it but remember what is was: + */ + if (*string == '-') { + sign = NEGATIVE; + ++string; + } else if (*string == '+') { + ++string; + sign = POSITIVE; + } else { + sign = POSITIVE; + } + + /* + * If the input parameter Base is zero, then we need to + * determine if it is octal, decimal, or hexadecimal: + */ + if (base == 0) { + if (*string == '0') { + if (acpi_ut_to_lower(*(++string)) == 'x') { + base = 16; + ++string; + } else { + base = 8; + } + } else { + base = 10; + } + } else if (base < 2 || base > 36) { + /* + * The specified Base parameter is not in the domain of + * this function: + */ + goto done; + } + + /* + * For octal and hexadecimal bases, skip over the leading + * 0 or 0x, if they are present. + */ + if (base == 8 && *string == '0') { + string++; + } + + if (base == 16 && + *string == '0' && acpi_ut_to_lower(*(++string)) == 'x') { + string++; + } + + /* + * Main loop: convert the string to an unsigned long: + */ + while (*string) { + if (ACPI_IS_DIGIT(*string)) { + index = (u32)((u8)*string - '0'); + } else { + index = (u32)acpi_ut_to_upper(*string); + if (ACPI_IS_UPPER(index)) { + index = index - 'A' + 10; + } else { + goto done; + } + } + + if (index >= base) { + goto done; + } + + /* + * Check to see if value is out of range: + */ + + if (return_value > ((ACPI_UINT32_MAX - (u32)index) / (u32)base)) { + status = AE_ERROR; + return_value = 0; /* reset */ + } else { + return_value *= base; + return_value += index; + converted = 1; + } + + ++string; + } + + done: + /* + * If appropriate, update the caller's pointer to the next + * unconverted character in the buffer. + */ + if (terminator) { + if (converted == 0 && return_value == 0 && string != NULL) { + *terminator = (char *)string_start; + } else { + *terminator = (char *)string; + } + } + + if (status == AE_ERROR) { + return_value = ACPI_UINT32_MAX; + } + + /* + * If a minus sign was present, then "the conversion is negated": + */ + if (sign == NEGATIVE) { + return_value = (ACPI_UINT32_MAX - return_value) + 1; + } + + return (return_value); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_to_upper (TOUPPER) + * + * PARAMETERS: c - Character to convert + * + * RETURN: Converted character as an int + * + * DESCRIPTION: Convert character to uppercase + * + ******************************************************************************/ + +int acpi_ut_to_upper(int c) +{ + + return (ACPI_IS_LOWER(c) ? ((c) - 0x20) : (c)); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_to_lower (TOLOWER) + * + * PARAMETERS: c - Character to convert + * + * RETURN: Converted character as an int + * + * DESCRIPTION: Convert character to lowercase + * + ******************************************************************************/ + +int acpi_ut_to_lower(int c) +{ + + return (ACPI_IS_UPPER(c) ? ((c) + 0x20) : (c)); +} + +/******************************************************************************* + * + * FUNCTION: is* functions + * + * DESCRIPTION: is* functions use the ctype table below + * + ******************************************************************************/ + +const u8 _acpi_ctype[257] = { + _ACPI_CN, /* 0x00 0 NUL */ + _ACPI_CN, /* 0x01 1 SOH */ + _ACPI_CN, /* 0x02 2 STX */ + _ACPI_CN, /* 0x03 3 ETX */ + _ACPI_CN, /* 0x04 4 EOT */ + _ACPI_CN, /* 0x05 5 ENQ */ + _ACPI_CN, /* 0x06 6 ACK */ + _ACPI_CN, /* 0x07 7 BEL */ + _ACPI_CN, /* 0x08 8 BS */ + _ACPI_CN | _ACPI_SP, /* 0x09 9 TAB */ + _ACPI_CN | _ACPI_SP, /* 0x0A 10 LF */ + _ACPI_CN | _ACPI_SP, /* 0x0B 11 VT */ + _ACPI_CN | _ACPI_SP, /* 0x0C 12 FF */ + _ACPI_CN | _ACPI_SP, /* 0x0D 13 CR */ + _ACPI_CN, /* 0x0E 14 SO */ + _ACPI_CN, /* 0x0F 15 SI */ + _ACPI_CN, /* 0x10 16 DLE */ + _ACPI_CN, /* 0x11 17 DC1 */ + _ACPI_CN, /* 0x12 18 DC2 */ + _ACPI_CN, /* 0x13 19 DC3 */ + _ACPI_CN, /* 0x14 20 DC4 */ + _ACPI_CN, /* 0x15 21 NAK */ + _ACPI_CN, /* 0x16 22 SYN */ + _ACPI_CN, /* 0x17 23 ETB */ + _ACPI_CN, /* 0x18 24 CAN */ + _ACPI_CN, /* 0x19 25 EM */ + _ACPI_CN, /* 0x1A 26 SUB */ + _ACPI_CN, /* 0x1B 27 ESC */ + _ACPI_CN, /* 0x1C 28 FS */ + _ACPI_CN, /* 0x1D 29 GS */ + _ACPI_CN, /* 0x1E 30 RS */ + _ACPI_CN, /* 0x1F 31 US */ + _ACPI_XS | _ACPI_SP, /* 0x20 32 ' ' */ + _ACPI_PU, /* 0x21 33 '!' */ + _ACPI_PU, /* 0x22 34 '"' */ + _ACPI_PU, /* 0x23 35 '#' */ + _ACPI_PU, /* 0x24 36 '$' */ + _ACPI_PU, /* 0x25 37 '%' */ + _ACPI_PU, /* 0x26 38 '&' */ + _ACPI_PU, /* 0x27 39 ''' */ + _ACPI_PU, /* 0x28 40 '(' */ + _ACPI_PU, /* 0x29 41 ')' */ + _ACPI_PU, /* 0x2A 42 '*' */ + _ACPI_PU, /* 0x2B 43 '+' */ + _ACPI_PU, /* 0x2C 44 ',' */ + _ACPI_PU, /* 0x2D 45 '-' */ + _ACPI_PU, /* 0x2E 46 '.' */ + _ACPI_PU, /* 0x2F 47 '/' */ + _ACPI_XD | _ACPI_DI, /* 0x30 48 '0' */ + _ACPI_XD | _ACPI_DI, /* 0x31 49 '1' */ + _ACPI_XD | _ACPI_DI, /* 0x32 50 '2' */ + _ACPI_XD | _ACPI_DI, /* 0x33 51 '3' */ + _ACPI_XD | _ACPI_DI, /* 0x34 52 '4' */ + _ACPI_XD | _ACPI_DI, /* 0x35 53 '5' */ + _ACPI_XD | _ACPI_DI, /* 0x36 54 '6' */ + _ACPI_XD | _ACPI_DI, /* 0x37 55 '7' */ + _ACPI_XD | _ACPI_DI, /* 0x38 56 '8' */ + _ACPI_XD | _ACPI_DI, /* 0x39 57 '9' */ + _ACPI_PU, /* 0x3A 58 ':' */ + _ACPI_PU, /* 0x3B 59 ';' */ + _ACPI_PU, /* 0x3C 60 '<' */ + _ACPI_PU, /* 0x3D 61 '=' */ + _ACPI_PU, /* 0x3E 62 '>' */ + _ACPI_PU, /* 0x3F 63 '?' */ + _ACPI_PU, /* 0x40 64 '@' */ + _ACPI_XD | _ACPI_UP, /* 0x41 65 'A' */ + _ACPI_XD | _ACPI_UP, /* 0x42 66 'B' */ + _ACPI_XD | _ACPI_UP, /* 0x43 67 'C' */ + _ACPI_XD | _ACPI_UP, /* 0x44 68 'D' */ + _ACPI_XD | _ACPI_UP, /* 0x45 69 'E' */ + _ACPI_XD | _ACPI_UP, /* 0x46 70 'F' */ + _ACPI_UP, /* 0x47 71 'G' */ + _ACPI_UP, /* 0x48 72 'H' */ + _ACPI_UP, /* 0x49 73 'I' */ + _ACPI_UP, /* 0x4A 74 'J' */ + _ACPI_UP, /* 0x4B 75 'K' */ + _ACPI_UP, /* 0x4C 76 'L' */ + _ACPI_UP, /* 0x4D 77 'M' */ + _ACPI_UP, /* 0x4E 78 'N' */ + _ACPI_UP, /* 0x4F 79 'O' */ + _ACPI_UP, /* 0x50 80 'P' */ + _ACPI_UP, /* 0x51 81 'Q' */ + _ACPI_UP, /* 0x52 82 'R' */ + _ACPI_UP, /* 0x53 83 'S' */ + _ACPI_UP, /* 0x54 84 'T' */ + _ACPI_UP, /* 0x55 85 'U' */ + _ACPI_UP, /* 0x56 86 'V' */ + _ACPI_UP, /* 0x57 87 'W' */ + _ACPI_UP, /* 0x58 88 'X' */ + _ACPI_UP, /* 0x59 89 'Y' */ + _ACPI_UP, /* 0x5A 90 'Z' */ + _ACPI_PU, /* 0x5B 91 '[' */ + _ACPI_PU, /* 0x5C 92 '\' */ + _ACPI_PU, /* 0x5D 93 ']' */ + _ACPI_PU, /* 0x5E 94 '^' */ + _ACPI_PU, /* 0x5F 95 '_' */ + _ACPI_PU, /* 0x60 96 '`' */ + _ACPI_XD | _ACPI_LO, /* 0x61 97 'a' */ + _ACPI_XD | _ACPI_LO, /* 0x62 98 'b' */ + _ACPI_XD | _ACPI_LO, /* 0x63 99 'c' */ + _ACPI_XD | _ACPI_LO, /* 0x64 100 'd' */ + _ACPI_XD | _ACPI_LO, /* 0x65 101 'e' */ + _ACPI_XD | _ACPI_LO, /* 0x66 102 'f' */ + _ACPI_LO, /* 0x67 103 'g' */ + _ACPI_LO, /* 0x68 104 'h' */ + _ACPI_LO, /* 0x69 105 'i' */ + _ACPI_LO, /* 0x6A 106 'j' */ + _ACPI_LO, /* 0x6B 107 'k' */ + _ACPI_LO, /* 0x6C 108 'l' */ + _ACPI_LO, /* 0x6D 109 'm' */ + _ACPI_LO, /* 0x6E 110 'n' */ + _ACPI_LO, /* 0x6F 111 'o' */ + _ACPI_LO, /* 0x70 112 'p' */ + _ACPI_LO, /* 0x71 113 'q' */ + _ACPI_LO, /* 0x72 114 'r' */ + _ACPI_LO, /* 0x73 115 's' */ + _ACPI_LO, /* 0x74 116 't' */ + _ACPI_LO, /* 0x75 117 'u' */ + _ACPI_LO, /* 0x76 118 'v' */ + _ACPI_LO, /* 0x77 119 'w' */ + _ACPI_LO, /* 0x78 120 'x' */ + _ACPI_LO, /* 0x79 121 'y' */ + _ACPI_LO, /* 0x7A 122 'z' */ + _ACPI_PU, /* 0x7B 123 '{' */ + _ACPI_PU, /* 0x7C 124 '|' */ + _ACPI_PU, /* 0x7D 125 '}' */ + _ACPI_PU, /* 0x7E 126 '~' */ + _ACPI_CN, /* 0x7F 127 DEL */ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 to 0x8F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 to 0x9F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 to 0xAF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xB0 to 0xBF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC0 to 0xCF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0 to 0xDF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0 to 0xEF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xF0 to 0xFF */ + 0 /* 0x100 */ +}; + +#endif /* ACPI_USE_SYSTEM_CLIBRARY */ diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index e810894149a..5d95166245a 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -47,8 +47,9 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utdebug") + #ifdef ACPI_DEBUG_OUTPUT -static acpi_thread_id acpi_gbl_prev_thread_id; +static acpi_thread_id acpi_gbl_prev_thread_id = (acpi_thread_id) 0xFFFFFFFF; static char *acpi_gbl_fn_entry_str = "----Entry"; static char *acpi_gbl_fn_exit_str = "----Exit-"; @@ -109,7 +110,7 @@ void acpi_ut_track_stack_ptr(void) * RETURN: Updated pointer to the function name * * DESCRIPTION: Remove the "Acpi" prefix from the function name, if present. - * This allows compiler macros such as __func__ to be used + * This allows compiler macros such as __FUNCTION__ to be used * with no change to the debug output. * ******************************************************************************/ @@ -222,7 +223,7 @@ ACPI_EXPORT_SYMBOL(acpi_debug_print) * * RETURN: None * - * DESCRIPTION: Print message with no headers. Has same interface as + * DESCRIPTION: Print message with no headers. Has same interface as * debug_print so that the same macros can be used. * ******************************************************************************/ @@ -258,7 +259,7 @@ ACPI_EXPORT_SYMBOL(acpi_debug_print_raw) * * RETURN: None * - * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is + * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * ******************************************************************************/ @@ -290,7 +291,7 @@ ACPI_EXPORT_SYMBOL(acpi_ut_trace) * * RETURN: None * - * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is + * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * ******************************************************************************/ @@ -299,6 +300,7 @@ acpi_ut_trace_ptr(u32 line_number, const char *function_name, const char *module_name, u32 component_id, void *pointer) { + acpi_gbl_nesting_level++; acpi_ut_track_stack_ptr(); @@ -319,7 +321,7 @@ acpi_ut_trace_ptr(u32 line_number, * * RETURN: None * - * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is + * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * ******************************************************************************/ @@ -350,7 +352,7 @@ acpi_ut_trace_str(u32 line_number, * * RETURN: None * - * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is + * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * ******************************************************************************/ @@ -380,7 +382,7 @@ acpi_ut_trace_u32(u32 line_number, * * RETURN: None * - * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is + * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level * ******************************************************************************/ @@ -412,7 +414,7 @@ ACPI_EXPORT_SYMBOL(acpi_ut_exit) * * RETURN: None * - * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is + * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level. Prints exit status also. * ******************************************************************************/ @@ -453,7 +455,7 @@ ACPI_EXPORT_SYMBOL(acpi_ut_status_exit) * * RETURN: None * - * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is + * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level. Prints exit value also. * ******************************************************************************/ @@ -485,7 +487,7 @@ ACPI_EXPORT_SYMBOL(acpi_ut_value_exit) * * RETURN: None * - * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is + * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is * set in debug_level. Prints exit value also. * ******************************************************************************/ @@ -511,7 +513,7 @@ acpi_ut_ptr_exit(u32 line_number, * PARAMETERS: buffer - Buffer to dump * count - Amount to dump, in bytes * display - BYTE, WORD, DWORD, or QWORD display - * component_ID - Caller's component ID + * offset - Beginning buffer offset (display only) * * RETURN: None * @@ -519,7 +521,7 @@ acpi_ut_ptr_exit(u32 line_number, * ******************************************************************************/ -void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display) +void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 base_offset) { u32 i = 0; u32 j; @@ -541,7 +543,7 @@ void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display) /* Print current offset */ - acpi_os_printf("%6.4X: ", i); + acpi_os_printf("%6.4X: ", (base_offset + i)); /* Print 16 hex chars */ @@ -623,7 +625,7 @@ void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display) /******************************************************************************* * - * FUNCTION: acpi_ut_dump_buffer + * FUNCTION: acpi_ut_debug_dump_buffer * * PARAMETERS: buffer - Buffer to dump * count - Amount to dump, in bytes @@ -636,7 +638,8 @@ void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display) * ******************************************************************************/ -void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id) +void +acpi_ut_debug_dump_buffer(u8 *buffer, u32 count, u32 display, u32 component_id) { /* Only dump the buffer if tracing is enabled */ @@ -646,5 +649,5 @@ void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id) return; } - acpi_ut_dump_buffer2(buffer, count, display); + acpi_ut_dump_buffer(buffer, count, display, 0); } diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c index 5d84e195457..774c3aefbf5 100644 --- a/drivers/acpi/acpica/utids.c +++ b/drivers/acpi/acpica/utids.c @@ -67,10 +67,10 @@ ACPI_MODULE_NAME("utids") ******************************************************************************/ acpi_status acpi_ut_execute_HID(struct acpi_namespace_node *device_node, - struct acpica_device_id **return_id) + struct acpi_pnp_device_id **return_id) { union acpi_operand_object *obj_desc; - struct acpica_device_id *hid; + struct acpi_pnp_device_id *hid; u32 length; acpi_status status; @@ -94,16 +94,17 @@ acpi_ut_execute_HID(struct acpi_namespace_node *device_node, /* Allocate a buffer for the HID */ hid = - ACPI_ALLOCATE_ZEROED(sizeof(struct acpica_device_id) + + ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) + (acpi_size) length); if (!hid) { status = AE_NO_MEMORY; goto cleanup; } - /* Area for the string starts after DEVICE_ID struct */ + /* Area for the string starts after PNP_DEVICE_ID struct */ - hid->string = ACPI_ADD_PTR(char, hid, sizeof(struct acpica_device_id)); + hid->string = + ACPI_ADD_PTR(char, hid, sizeof(struct acpi_pnp_device_id)); /* Convert EISAID to a string or simply copy existing string */ @@ -126,6 +127,73 @@ cleanup: /******************************************************************************* * + * FUNCTION: acpi_ut_execute_SUB + * + * PARAMETERS: device_node - Node for the device + * return_id - Where the _SUB is returned + * + * RETURN: Status + * + * DESCRIPTION: Executes the _SUB control method that returns the subsystem + * ID of the device. The _SUB value is always a string containing + * either a valid PNP or ACPI ID. + * + * NOTE: Internal function, no parameter validation + * + ******************************************************************************/ + +acpi_status +acpi_ut_execute_SUB(struct acpi_namespace_node *device_node, + struct acpi_pnp_device_id **return_id) +{ + union acpi_operand_object *obj_desc; + struct acpi_pnp_device_id *sub; + u32 length; + acpi_status status; + + ACPI_FUNCTION_TRACE(ut_execute_SUB); + + status = acpi_ut_evaluate_object(device_node, METHOD_NAME__SUB, + ACPI_BTYPE_STRING, &obj_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Get the size of the String to be returned, includes null terminator */ + + length = obj_desc->string.length + 1; + + /* Allocate a buffer for the SUB */ + + sub = + ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) + + (acpi_size) length); + if (!sub) { + status = AE_NO_MEMORY; + goto cleanup; + } + + /* Area for the string starts after PNP_DEVICE_ID struct */ + + sub->string = + ACPI_ADD_PTR(char, sub, sizeof(struct acpi_pnp_device_id)); + + /* Simply copy existing string */ + + ACPI_STRCPY(sub->string, obj_desc->string.pointer); + sub->length = length; + *return_id = sub; + + cleanup: + + /* On exit, we must delete the return object */ + + acpi_ut_remove_reference(obj_desc); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * * FUNCTION: acpi_ut_execute_UID * * PARAMETERS: device_node - Node for the device @@ -144,10 +212,10 @@ cleanup: acpi_status acpi_ut_execute_UID(struct acpi_namespace_node *device_node, - struct acpica_device_id **return_id) + struct acpi_pnp_device_id **return_id) { union acpi_operand_object *obj_desc; - struct acpica_device_id *uid; + struct acpi_pnp_device_id *uid; u32 length; acpi_status status; @@ -171,16 +239,17 @@ acpi_ut_execute_UID(struct acpi_namespace_node *device_node, /* Allocate a buffer for the UID */ uid = - ACPI_ALLOCATE_ZEROED(sizeof(struct acpica_device_id) + + ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pnp_device_id) + (acpi_size) length); if (!uid) { status = AE_NO_MEMORY; goto cleanup; } - /* Area for the string starts after DEVICE_ID struct */ + /* Area for the string starts after PNP_DEVICE_ID struct */ - uid->string = ACPI_ADD_PTR(char, uid, sizeof(struct acpica_device_id)); + uid->string = + ACPI_ADD_PTR(char, uid, sizeof(struct acpi_pnp_device_id)); /* Convert an Integer to string, or just copy an existing string */ @@ -226,11 +295,11 @@ cleanup: acpi_status acpi_ut_execute_CID(struct acpi_namespace_node *device_node, - struct acpica_device_id_list **return_cid_list) + struct acpi_pnp_device_id_list **return_cid_list) { union acpi_operand_object **cid_objects; union acpi_operand_object *obj_desc; - struct acpica_device_id_list *cid_list; + struct acpi_pnp_device_id_list *cid_list; char *next_id_string; u32 string_area_size; u32 length; @@ -288,11 +357,12 @@ acpi_ut_execute_CID(struct acpi_namespace_node *device_node, /* * Now that we know the length of the CIDs, allocate return buffer: * 1) Size of the base structure + - * 2) Size of the CID DEVICE_ID array + + * 2) Size of the CID PNP_DEVICE_ID array + * 3) Size of the actual CID strings */ - cid_list_size = sizeof(struct acpica_device_id_list) + - ((count - 1) * sizeof(struct acpica_device_id)) + string_area_size; + cid_list_size = sizeof(struct acpi_pnp_device_id_list) + + ((count - 1) * sizeof(struct acpi_pnp_device_id)) + + string_area_size; cid_list = ACPI_ALLOCATE_ZEROED(cid_list_size); if (!cid_list) { @@ -300,10 +370,10 @@ acpi_ut_execute_CID(struct acpi_namespace_node *device_node, goto cleanup; } - /* Area for CID strings starts after the CID DEVICE_ID array */ + /* Area for CID strings starts after the CID PNP_DEVICE_ID array */ next_id_string = ACPI_CAST_PTR(char, cid_list->ids) + - ((acpi_size) count * sizeof(struct acpica_device_id)); + ((acpi_size) count * sizeof(struct acpi_pnp_device_id)); /* Copy/convert the CIDs to the return buffer */ diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c index d88a8aaab2a..49563674833 100644 --- a/drivers/acpi/acpica/utmath.c +++ b/drivers/acpi/acpica/utmath.c @@ -81,7 +81,7 @@ typedef union uint64_overlay { * RETURN: Status (Checks for divide-by-zero) * * DESCRIPTION: Perform a short (maximum 64 bits divided by 32 bits) - * divide and modulo. The result is a 64-bit quotient and a + * divide and modulo. The result is a 64-bit quotient and a * 32-bit remainder. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 33c6cf7ff46..9286a69eb9a 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -41,8 +41,6 @@ * POSSIBILITY OF SUCH DAMAGES. */ -#include <linux/module.h> - #include <acpi/acpi.h> #include "accommon.h" #include "acnamesp.h" @@ -201,8 +199,8 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id) */ acpi_gbl_owner_id_mask[j] |= (1 << k); - acpi_gbl_last_owner_id_index = (u8) j; - acpi_gbl_next_owner_id_offset = (u8) (k + 1); + acpi_gbl_last_owner_id_index = (u8)j; + acpi_gbl_next_owner_id_offset = (u8)(k + 1); /* * Construct encoded ID from the index and bit position @@ -252,7 +250,7 @@ acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id) * control method or unloading a table. Either way, we would * ignore any error anyway. * - * DESCRIPTION: Release a table or method owner ID. Valid IDs are 1 - 255 + * DESCRIPTION: Release a table or method owner ID. Valid IDs are 1 - 255 * ******************************************************************************/ @@ -339,6 +337,73 @@ void acpi_ut_strupr(char *src_string) return; } +#ifdef ACPI_ASL_COMPILER +/******************************************************************************* + * + * FUNCTION: acpi_ut_strlwr (strlwr) + * + * PARAMETERS: src_string - The source string to convert + * + * RETURN: None + * + * DESCRIPTION: Convert string to lowercase + * + * NOTE: This is not a POSIX function, so it appears here, not in utclib.c + * + ******************************************************************************/ + +void acpi_ut_strlwr(char *src_string) +{ + char *string; + + ACPI_FUNCTION_ENTRY(); + + if (!src_string) { + return; + } + + /* Walk entire string, lowercasing the letters */ + + for (string = src_string; *string; string++) { + *string = (char)ACPI_TOLOWER(*string); + } + + return; +} + +/****************************************************************************** + * + * FUNCTION: acpi_ut_stricmp + * + * PARAMETERS: string1 - first string to compare + * string2 - second string to compare + * + * RETURN: int that signifies string relationship. Zero means strings + * are equal. + * + * DESCRIPTION: Implementation of the non-ANSI stricmp function (compare + * strings with no case sensitivity) + * + ******************************************************************************/ + +int acpi_ut_stricmp(char *string1, char *string2) +{ + int c1; + int c2; + + do { + c1 = tolower((int)*string1); + c2 = tolower((int)*string2); + + string1++; + string2++; + } + while ((c1 == c2) && (c1)); + + return (c1 - c2); +} +#endif + /******************************************************************************* * * FUNCTION: acpi_ut_print_string @@ -469,8 +534,8 @@ u32 acpi_ut_dword_byte_swap(u32 value) * RETURN: None * * DESCRIPTION: Set the global integer bit width based upon the revision - * of the DSDT. For Revision 1 and 0, Integers are 32 bits. - * For Revision 2 and above, Integers are 64 bits. Yes, this + * of the DSDT. For Revision 1 and 0, Integers are 32 bits. + * For Revision 2 and above, Integers are 64 bits. Yes, this * makes a difference. * ******************************************************************************/ @@ -606,7 +671,7 @@ u8 acpi_ut_valid_acpi_char(char character, u32 position) * * RETURN: TRUE if the name is valid, FALSE otherwise * - * DESCRIPTION: Check for a valid ACPI name. Each character must be one of: + * DESCRIPTION: Check for a valid ACPI name. Each character must be one of: * 1) Upper case alpha * 2) numeric * 3) underscore @@ -638,29 +703,59 @@ u8 acpi_ut_valid_acpi_name(u32 name) * RETURN: Repaired version of the name * * DESCRIPTION: Repair an ACPI name: Change invalid characters to '*' and - * return the new name. + * return the new name. NOTE: the Name parameter must reside in + * read/write memory, cannot be a const. + * + * An ACPI Name must consist of valid ACPI characters. We will repair the name + * if necessary because we don't want to abort because of this, but we want + * all namespace names to be printable. A warning message is appropriate. + * + * This issue came up because there are in fact machines that exhibit + * this problem, and we want to be able to enable ACPI support for them, + * even though there are a few bad names. * ******************************************************************************/ -acpi_name acpi_ut_repair_name(char *name) +void acpi_ut_repair_name(char *name) { - u32 i; - char new_name[ACPI_NAME_SIZE]; + u32 i; + u8 found_bad_char = FALSE; + u32 original_name; + + ACPI_FUNCTION_NAME(ut_repair_name); + + ACPI_MOVE_NAME(&original_name, name); + + /* Check each character in the name */ for (i = 0; i < ACPI_NAME_SIZE; i++) { - new_name[i] = name[i]; + if (acpi_ut_valid_acpi_char(name[i], i)) { + continue; + } /* * Replace a bad character with something printable, yet technically * still invalid. This prevents any collisions with existing "good" * names in the namespace. */ - if (!acpi_ut_valid_acpi_char(name[i], i)) { - new_name[i] = '*'; - } + name[i] = '*'; + found_bad_char = TRUE; } - return (*(u32 *) new_name); + if (found_bad_char) { + + /* Report warning only if in strict mode or debug mode */ + + if (!acpi_gbl_enable_interpreter_slack) { + ACPI_WARNING((AE_INFO, + "Found bad character(s) in name, repaired: [%4.4s]\n", + name)); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Found bad character(s) in name, repaired: [%4.4s]\n", + name)); + } + } } /******************************************************************************* @@ -681,7 +776,7 @@ acpi_name acpi_ut_repair_name(char *name) * ******************************************************************************/ -acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 * ret_integer) +acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) { u32 this_digit = 0; u64 return_value = 0; @@ -754,14 +849,14 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 * ret_integer) /* Convert ASCII 0-9 to Decimal value */ - this_digit = ((u8) * string) - '0'; + this_digit = ((u8)*string) - '0'; } else if (base == 10) { /* Digit is out of range; possible in to_integer case only */ term = 1; } else { - this_digit = (u8) ACPI_TOUPPER(*string); + this_digit = (u8)ACPI_TOUPPER(*string); if (ACPI_IS_XDIGIT((char)this_digit)) { /* Convert ASCII Hex char to value */ @@ -788,8 +883,9 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 * ret_integer) valid_digits++; - if (sign_of0x && ((valid_digits > 16) - || ((valid_digits > 8) && mode32))) { + if (sign_of0x + && ((valid_digits > 16) + || ((valid_digits > 8) && mode32))) { /* * This is to_integer operation case. * No any restrictions for string-to-integer conversion, @@ -800,7 +896,7 @@ acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 * ret_integer) /* Divide the digit into the correct position */ - (void)acpi_ut_short_divide((dividend - (u64) this_digit), + (void)acpi_ut_short_divide((dividend - (u64)this_digit), base, "ient, NULL); if (return_value > quotient) { @@ -890,7 +986,7 @@ acpi_ut_create_update_state_and_push(union acpi_operand_object *object, ******************************************************************************/ acpi_status -acpi_ut_walk_package_tree(union acpi_operand_object * source_object, +acpi_ut_walk_package_tree(union acpi_operand_object *source_object, void *target_object, acpi_pkg_callback walk_callback, void *context) { @@ -917,10 +1013,10 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object, /* * Check for: - * 1) An uninitialized package element. It is completely + * 1) An uninitialized package element. It is completely * legal to declare a package and leave it uninitialized * 2) Not an internal object - can be a namespace node instead - * 3) Any type other than a package. Packages are handled in else + * 3) Any type other than a package. Packages are handled in else * case below. */ if ((!this_source_obj) || @@ -939,7 +1035,7 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object, state->pkg.source_object->package.count) { /* * We've handled all of the objects at this level, This means - * that we have just completed a package. That package may + * that we have just completed a package. That package may * have contained one or more packages itself. * * Delete this state and pop the previous state (package). diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index 296baa676bc..5ccf57c0d87 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -193,6 +193,8 @@ static void acpi_ut_delete_mutex(acpi_mutex_handle mutex_id) acpi_gbl_mutex_info[mutex_id].mutex = NULL; acpi_gbl_mutex_info[mutex_id].thread_id = ACPI_MUTEX_NOT_ACQUIRED; + + return_VOID; } /******************************************************************************* @@ -226,9 +228,9 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) /* * Mutex debug code, for internal debugging only. * - * Deadlock prevention. Check if this thread owns any mutexes of value - * greater than or equal to this one. If so, the thread has violated - * the mutex ordering rule. This indicates a coding error somewhere in + * Deadlock prevention. Check if this thread owns any mutexes of value + * greater than or equal to this one. If so, the thread has violated + * the mutex ordering rule. This indicates a coding error somewhere in * the ACPI subsystem code. */ for (i = mutex_id; i < ACPI_NUM_MUTEX; i++) { @@ -319,9 +321,9 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) /* * Mutex debug code, for internal debugging only. * - * Deadlock prevention. Check if this thread owns any mutexes of value - * greater than this one. If so, the thread has violated the mutex - * ordering rule. This indicates a coding error somewhere in + * Deadlock prevention. Check if this thread owns any mutexes of value + * greater than this one. If so, the thread has violated the mutex + * ordering rule. This indicates a coding error somewhere in * the ACPI subsystem code. */ for (i = mutex_id; i < ACPI_NUM_MUTEX; i++) { diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c index 655f0799a39..5c52ca78f6f 100644 --- a/drivers/acpi/acpica/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -77,7 +77,7 @@ acpi_ut_get_element_length(u8 object_type, * * NOTE: We always allocate the worst-case object descriptor because * these objects are cached, and we want them to be - * one-size-satisifies-any-request. This in itself may not be + * one-size-satisifies-any-request. This in itself may not be * the most memory efficient, but the efficiency of the object * cache should more than make up for this! * @@ -370,9 +370,9 @@ u8 acpi_ut_valid_internal_object(void *object) * line_number - Caller's line number (for error output) * component_id - Caller's component ID (for error output) * - * RETURN: Pointer to newly allocated object descriptor. Null on error + * RETURN: Pointer to newly allocated object descriptor. Null on error * - * DESCRIPTION: Allocate a new object descriptor. Gracefully handle + * DESCRIPTION: Allocate a new object descriptor. Gracefully handle * error conditions. * ******************************************************************************/ @@ -554,7 +554,7 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object, /* * Account for the space required by the object rounded up to the next - * multiple of the machine word size. This keeps each object aligned + * multiple of the machine word size. This keeps each object aligned * on a machine word boundary. (preventing alignment faults on some * machines.) */ diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c index a1c98826007..cee0473ba81 100644 --- a/drivers/acpi/acpica/utstate.c +++ b/drivers/acpi/acpica/utstate.c @@ -147,7 +147,7 @@ union acpi_generic_state *acpi_ut_pop_generic_state(union acpi_generic_state * * RETURN: The new state object. NULL on failure. * - * DESCRIPTION: Create a generic state object. Attempt to obtain one from + * DESCRIPTION: Create a generic state object. Attempt to obtain one from * the global state cache; If none available, create a new one. * ******************************************************************************/ diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c new file mode 100644 index 00000000000..a424a9e3fea --- /dev/null +++ b/drivers/acpi/acpica/uttrack.c @@ -0,0 +1,692 @@ +/****************************************************************************** + * + * Module Name: uttrack - Memory allocation tracking routines (debug only) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +/* + * These procedures are used for tracking memory leaks in the subsystem, and + * they get compiled out when the ACPI_DBG_TRACK_ALLOCATIONS is not set. + * + * Each memory allocation is tracked via a doubly linked list. Each + * element contains the caller's component, module name, function name, and + * line number. acpi_ut_allocate and acpi_ut_allocate_zeroed call + * acpi_ut_track_allocation to add an element to the list; deletion + * occurs in the body of acpi_ut_free. + */ + +#include <acpi/acpi.h> +#include "accommon.h" + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + +#define _COMPONENT ACPI_UTILITIES +ACPI_MODULE_NAME("uttrack") + +/* Local prototypes */ +static struct acpi_debug_mem_block *acpi_ut_find_allocation(struct + acpi_debug_mem_block + *allocation); + +static acpi_status +acpi_ut_track_allocation(struct acpi_debug_mem_block *address, + acpi_size size, + u8 alloc_type, + u32 component, const char *module, u32 line); + +static acpi_status +acpi_ut_remove_allocation(struct acpi_debug_mem_block *address, + u32 component, const char *module, u32 line); + +/******************************************************************************* + * + * FUNCTION: acpi_ut_create_list + * + * PARAMETERS: cache_name - Ascii name for the cache + * object_size - Size of each cached object + * return_cache - Where the new cache object is returned + * + * RETURN: Status + * + * DESCRIPTION: Create a local memory list for tracking purposed + * + ******************************************************************************/ + +acpi_status +acpi_ut_create_list(char *list_name, + u16 object_size, struct acpi_memory_list **return_cache) +{ + struct acpi_memory_list *cache; + + cache = acpi_os_allocate(sizeof(struct acpi_memory_list)); + if (!cache) { + return (AE_NO_MEMORY); + } + + ACPI_MEMSET(cache, 0, sizeof(struct acpi_memory_list)); + + cache->list_name = list_name; + cache->object_size = object_size; + + *return_cache = cache; + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_allocate_and_track + * + * PARAMETERS: size - Size of the allocation + * component - Component type of caller + * module - Source file name of caller + * line - Line number of caller + * + * RETURN: Address of the allocated memory on success, NULL on failure. + * + * DESCRIPTION: The subsystem's equivalent of malloc. + * + ******************************************************************************/ + +void *acpi_ut_allocate_and_track(acpi_size size, + u32 component, const char *module, u32 line) +{ + struct acpi_debug_mem_block *allocation; + acpi_status status; + + allocation = + acpi_ut_allocate(size + sizeof(struct acpi_debug_mem_header), + component, module, line); + if (!allocation) { + return (NULL); + } + + status = acpi_ut_track_allocation(allocation, size, + ACPI_MEM_MALLOC, component, module, + line); + if (ACPI_FAILURE(status)) { + acpi_os_free(allocation); + return (NULL); + } + + acpi_gbl_global_list->total_allocated++; + acpi_gbl_global_list->total_size += (u32)size; + acpi_gbl_global_list->current_total_size += (u32)size; + if (acpi_gbl_global_list->current_total_size > + acpi_gbl_global_list->max_occupied) { + acpi_gbl_global_list->max_occupied = + acpi_gbl_global_list->current_total_size; + } + + return ((void *)&allocation->user_space); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_allocate_zeroed_and_track + * + * PARAMETERS: size - Size of the allocation + * component - Component type of caller + * module - Source file name of caller + * line - Line number of caller + * + * RETURN: Address of the allocated memory on success, NULL on failure. + * + * DESCRIPTION: Subsystem equivalent of calloc. + * + ******************************************************************************/ + +void *acpi_ut_allocate_zeroed_and_track(acpi_size size, + u32 component, + const char *module, u32 line) +{ + struct acpi_debug_mem_block *allocation; + acpi_status status; + + allocation = + acpi_ut_allocate_zeroed(size + sizeof(struct acpi_debug_mem_header), + component, module, line); + if (!allocation) { + + /* Report allocation error */ + + ACPI_ERROR((module, line, + "Could not allocate size %u", (u32)size)); + return (NULL); + } + + status = acpi_ut_track_allocation(allocation, size, + ACPI_MEM_CALLOC, component, module, + line); + if (ACPI_FAILURE(status)) { + acpi_os_free(allocation); + return (NULL); + } + + acpi_gbl_global_list->total_allocated++; + acpi_gbl_global_list->total_size += (u32)size; + acpi_gbl_global_list->current_total_size += (u32)size; + if (acpi_gbl_global_list->current_total_size > + acpi_gbl_global_list->max_occupied) { + acpi_gbl_global_list->max_occupied = + acpi_gbl_global_list->current_total_size; + } + + return ((void *)&allocation->user_space); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_free_and_track + * + * PARAMETERS: allocation - Address of the memory to deallocate + * component - Component type of caller + * module - Source file name of caller + * line - Line number of caller + * + * RETURN: None + * + * DESCRIPTION: Frees the memory at Allocation + * + ******************************************************************************/ + +void +acpi_ut_free_and_track(void *allocation, + u32 component, const char *module, u32 line) +{ + struct acpi_debug_mem_block *debug_block; + acpi_status status; + + ACPI_FUNCTION_TRACE_PTR(ut_free, allocation); + + if (NULL == allocation) { + ACPI_ERROR((module, line, "Attempt to delete a NULL address")); + + return_VOID; + } + + debug_block = ACPI_CAST_PTR(struct acpi_debug_mem_block, + (((char *)allocation) - + sizeof(struct acpi_debug_mem_header))); + + acpi_gbl_global_list->total_freed++; + acpi_gbl_global_list->current_total_size -= debug_block->size; + + status = acpi_ut_remove_allocation(debug_block, + component, module, line); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, "Could not free memory")); + } + + acpi_os_free(debug_block); + ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "%p freed\n", allocation)); + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_find_allocation + * + * PARAMETERS: allocation - Address of allocated memory + * + * RETURN: Three cases: + * 1) List is empty, NULL is returned. + * 2) Element was found. Returns Allocation parameter. + * 3) Element was not found. Returns position where it should be + * inserted into the list. + * + * DESCRIPTION: Searches for an element in the global allocation tracking list. + * If the element is not found, returns the location within the + * list where the element should be inserted. + * + * Note: The list is ordered by larger-to-smaller addresses. + * + * This global list is used to detect memory leaks in ACPICA as + * well as other issues such as an attempt to release the same + * internal object more than once. Although expensive as far + * as cpu time, this list is much more helpful for finding these + * types of issues than using memory leak detectors outside of + * the ACPICA code. + * + ******************************************************************************/ + +static struct acpi_debug_mem_block *acpi_ut_find_allocation(struct + acpi_debug_mem_block + *allocation) +{ + struct acpi_debug_mem_block *element; + + element = acpi_gbl_global_list->list_head; + if (!element) { + return (NULL); + } + + /* + * Search for the address. + * + * Note: List is ordered by larger-to-smaller addresses, on the + * assumption that a new allocation usually has a larger address + * than previous allocations. + */ + while (element > allocation) { + + /* Check for end-of-list */ + + if (!element->next) { + return (element); + } + + element = element->next; + } + + if (element == allocation) { + return (element); + } + + return (element->previous); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_track_allocation + * + * PARAMETERS: allocation - Address of allocated memory + * size - Size of the allocation + * alloc_type - MEM_MALLOC or MEM_CALLOC + * component - Component type of caller + * module - Source file name of caller + * line - Line number of caller + * + * RETURN: Status + * + * DESCRIPTION: Inserts an element into the global allocation tracking list. + * + ******************************************************************************/ + +static acpi_status +acpi_ut_track_allocation(struct acpi_debug_mem_block *allocation, + acpi_size size, + u8 alloc_type, + u32 component, const char *module, u32 line) +{ + struct acpi_memory_list *mem_list; + struct acpi_debug_mem_block *element; + acpi_status status = AE_OK; + + ACPI_FUNCTION_TRACE_PTR(ut_track_allocation, allocation); + + if (acpi_gbl_disable_mem_tracking) { + return_ACPI_STATUS(AE_OK); + } + + mem_list = acpi_gbl_global_list; + status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* + * Search the global list for this address to make sure it is not + * already present. This will catch several kinds of problems. + */ + element = acpi_ut_find_allocation(allocation); + if (element == allocation) { + ACPI_ERROR((AE_INFO, + "UtTrackAllocation: Allocation (%p) already present in global list!", + allocation)); + goto unlock_and_exit; + } + + /* Fill in the instance data */ + + allocation->size = (u32)size; + allocation->alloc_type = alloc_type; + allocation->component = component; + allocation->line = line; + + ACPI_STRNCPY(allocation->module, module, ACPI_MAX_MODULE_NAME); + allocation->module[ACPI_MAX_MODULE_NAME - 1] = 0; + + if (!element) { + + /* Insert at list head */ + + if (mem_list->list_head) { + ((struct acpi_debug_mem_block *)(mem_list->list_head))-> + previous = allocation; + } + + allocation->next = mem_list->list_head; + allocation->previous = NULL; + + mem_list->list_head = allocation; + } else { + /* Insert after element */ + + allocation->next = element->next; + allocation->previous = element; + + if (element->next) { + (element->next)->previous = allocation; + } + + element->next = allocation; + } + + unlock_and_exit: + status = acpi_ut_release_mutex(ACPI_MTX_MEMORY); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_remove_allocation + * + * PARAMETERS: allocation - Address of allocated memory + * component - Component type of caller + * module - Source file name of caller + * line - Line number of caller + * + * RETURN: Status + * + * DESCRIPTION: Deletes an element from the global allocation tracking list. + * + ******************************************************************************/ + +static acpi_status +acpi_ut_remove_allocation(struct acpi_debug_mem_block *allocation, + u32 component, const char *module, u32 line) +{ + struct acpi_memory_list *mem_list; + acpi_status status; + + ACPI_FUNCTION_TRACE(ut_remove_allocation); + + if (acpi_gbl_disable_mem_tracking) { + return_ACPI_STATUS(AE_OK); + } + + mem_list = acpi_gbl_global_list; + if (NULL == mem_list->list_head) { + + /* No allocations! */ + + ACPI_ERROR((module, line, + "Empty allocation list, nothing to free!")); + + return_ACPI_STATUS(AE_OK); + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_MEMORY); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Unlink */ + + if (allocation->previous) { + (allocation->previous)->next = allocation->next; + } else { + mem_list->list_head = allocation->next; + } + + if (allocation->next) { + (allocation->next)->previous = allocation->previous; + } + + /* Mark the segment as deleted */ + + ACPI_MEMSET(&allocation->user_space, 0xEA, allocation->size); + + ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "Freeing size 0%X\n", + allocation->size)); + + status = acpi_ut_release_mutex(ACPI_MTX_MEMORY); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_dump_allocation_info + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Print some info about the outstanding allocations. + * + ******************************************************************************/ + +void acpi_ut_dump_allocation_info(void) +{ +/* + struct acpi_memory_list *mem_list; +*/ + + ACPI_FUNCTION_TRACE(ut_dump_allocation_info); + +/* + ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, + ("%30s: %4d (%3d Kb)\n", "Current allocations", + mem_list->current_count, + ROUND_UP_TO_1K (mem_list->current_size))); + + ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, + ("%30s: %4d (%3d Kb)\n", "Max concurrent allocations", + mem_list->max_concurrent_count, + ROUND_UP_TO_1K (mem_list->max_concurrent_size))); + + ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, + ("%30s: %4d (%3d Kb)\n", "Total (all) internal objects", + running_object_count, + ROUND_UP_TO_1K (running_object_size))); + + ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, + ("%30s: %4d (%3d Kb)\n", "Total (all) allocations", + running_alloc_count, + ROUND_UP_TO_1K (running_alloc_size))); + + ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, + ("%30s: %4d (%3d Kb)\n", "Current Nodes", + acpi_gbl_current_node_count, + ROUND_UP_TO_1K (acpi_gbl_current_node_size))); + + ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES, + ("%30s: %4d (%3d Kb)\n", "Max Nodes", + acpi_gbl_max_concurrent_node_count, + ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count * + sizeof (struct acpi_namespace_node))))); +*/ + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_dump_allocations + * + * PARAMETERS: component - Component(s) to dump info for. + * module - Module to dump info for. NULL means all. + * + * RETURN: None + * + * DESCRIPTION: Print a list of all outstanding allocations. + * + ******************************************************************************/ + +void acpi_ut_dump_allocations(u32 component, const char *module) +{ + struct acpi_debug_mem_block *element; + union acpi_descriptor *descriptor; + u32 num_outstanding = 0; + u8 descriptor_type; + + ACPI_FUNCTION_TRACE(ut_dump_allocations); + + if (acpi_gbl_disable_mem_tracking) { + return_VOID; + } + + /* + * Walk the allocation list. + */ + if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_MEMORY))) { + return_VOID; + } + + element = acpi_gbl_global_list->list_head; + while (element) { + if ((element->component & component) && + ((module == NULL) + || (0 == ACPI_STRCMP(module, element->module)))) { + descriptor = + ACPI_CAST_PTR(union acpi_descriptor, + &element->user_space); + + if (element->size < + sizeof(struct acpi_common_descriptor)) { + acpi_os_printf("%p Length 0x%04X %9.9s-%u " + "[Not a Descriptor - too small]\n", + descriptor, element->size, + element->module, element->line); + } else { + /* Ignore allocated objects that are in a cache */ + + if (ACPI_GET_DESCRIPTOR_TYPE(descriptor) != + ACPI_DESC_TYPE_CACHED) { + acpi_os_printf + ("%p Length 0x%04X %9.9s-%u [%s] ", + descriptor, element->size, + element->module, element->line, + acpi_ut_get_descriptor_name + (descriptor)); + + /* Validate the descriptor type using Type field and length */ + + descriptor_type = 0; /* Not a valid descriptor type */ + + switch (ACPI_GET_DESCRIPTOR_TYPE + (descriptor)) { + case ACPI_DESC_TYPE_OPERAND: + if (element->size == + sizeof(union + acpi_operand_object)) + { + descriptor_type = + ACPI_DESC_TYPE_OPERAND; + } + break; + + case ACPI_DESC_TYPE_PARSER: + if (element->size == + sizeof(union + acpi_parse_object)) { + descriptor_type = + ACPI_DESC_TYPE_PARSER; + } + break; + + case ACPI_DESC_TYPE_NAMED: + if (element->size == + sizeof(struct + acpi_namespace_node)) + { + descriptor_type = + ACPI_DESC_TYPE_NAMED; + } + break; + + default: + break; + } + + /* Display additional info for the major descriptor types */ + + switch (descriptor_type) { + case ACPI_DESC_TYPE_OPERAND: + acpi_os_printf + ("%12.12s RefCount 0x%04X\n", + acpi_ut_get_type_name + (descriptor->object.common. + type), + descriptor->object.common. + reference_count); + break; + + case ACPI_DESC_TYPE_PARSER: + acpi_os_printf + ("AmlOpcode 0x%04hX\n", + descriptor->op.asl. + aml_opcode); + break; + + case ACPI_DESC_TYPE_NAMED: + acpi_os_printf("%4.4s\n", + acpi_ut_get_node_name + (&descriptor-> + node)); + break; + + default: + acpi_os_printf("\n"); + break; + } + } + } + + num_outstanding++; + } + + element = element->next; + } + + (void)acpi_ut_release_mutex(ACPI_MTX_MEMORY); + + /* Print summary */ + + if (!num_outstanding) { + ACPI_INFO((AE_INFO, "No outstanding allocations")); + } else { + ACPI_ERROR((AE_INFO, "%u(0x%X) Outstanding allocations", + num_outstanding, num_outstanding)); + } + + return_VOID; +} + +#endif /* ACPI_DBG_TRACK_ALLOCATIONS */ diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index b09632b4f5b..390db0ca5e2 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -147,7 +147,7 @@ ACPI_EXPORT_SYMBOL(acpi_subsystem_status) * RETURN: status - the status of the call * * DESCRIPTION: This function is called to get information about the current - * state of the ACPI subsystem. It will return system information + * state of the ACPI subsystem. It will return system information * in the out_buffer. * * If the function fails an appropriate status will be returned @@ -238,7 +238,7 @@ acpi_install_initialization_handler(acpi_init_handler handler, u32 function) } acpi_gbl_init_handler = handler; - return AE_OK; + return (AE_OK); } ACPI_EXPORT_SYMBOL(acpi_install_initialization_handler) @@ -263,6 +263,7 @@ acpi_status acpi_purge_cached_objects(void) (void)acpi_os_purge_cache(acpi_gbl_operand_cache); (void)acpi_os_purge_cache(acpi_gbl_ps_node_cache); (void)acpi_os_purge_cache(acpi_gbl_ps_node_ext_cache); + return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c index 6d63cc39b9a..d4d3826140d 100644 --- a/drivers/acpi/acpica/utxferror.c +++ b/drivers/acpi/acpica/utxferror.c @@ -408,7 +408,7 @@ acpi_ut_namespace_error(const char *module_name, ACPI_MOVE_32_TO_32(&bad_name, ACPI_CAST_PTR(u32, internal_name)); - acpi_os_printf("[0x%4.4X] (NON-ASCII)", bad_name); + acpi_os_printf("[0x%.8X] (NON-ASCII)", bad_name); } else { /* Convert path to external format */ diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 1599566ed1f..7ae2750bb45 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -901,7 +901,7 @@ static unsigned long ghes_esource_prealloc_size( return prealloc_size; } -static int __devinit ghes_probe(struct platform_device *ghes_dev) +static int ghes_probe(struct platform_device *ghes_dev) { struct acpi_hest_generic *generic; struct ghes *ghes = NULL; @@ -994,7 +994,7 @@ err: return rc; } -static int __devexit ghes_remove(struct platform_device *ghes_dev) +static int ghes_remove(struct platform_device *ghes_dev) { struct ghes *ghes; struct acpi_hest_generic *generic; diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 45e3e1759fb..7efaeaa53b8 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -34,6 +34,7 @@ #include <linux/dmi.h> #include <linux/slab.h> #include <linux/suspend.h> +#include <asm/unaligned.h> #ifdef CONFIG_ACPI_PROCFS_POWER #include <linux/proc_fs.h> @@ -95,6 +96,18 @@ enum { ACPI_BATTERY_ALARM_PRESENT, ACPI_BATTERY_XINFO_PRESENT, ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, + /* On Lenovo Thinkpad models from 2010 and 2011, the power unit + switches between mWh and mAh depending on whether the system + is running on battery or not. When mAh is the unit, most + reported values are incorrect and need to be adjusted by + 10000/design_voltage. Verified on x201, t410, t410s, and x220. + Pre-2010 and 2012 models appear to always report in mWh and + are thus unaffected (tested with t42, t61, t500, x200, x300, + and x230). Also, in mid-2012 Lenovo issued a BIOS update for + the 2011 models that fixes the issue (tested on x220 with a + post-1.29 BIOS), but as of Nov. 2012, no such update is + available for the 2010 models. */ + ACPI_BATTERY_QUIRK_THINKPAD_MAH, }; struct acpi_battery { @@ -438,6 +451,21 @@ static int acpi_battery_get_info(struct acpi_battery *battery) kfree(buffer.pointer); if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)) battery->full_charge_capacity = battery->design_capacity; + if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) && + battery->power_unit && battery->design_voltage) { + battery->design_capacity = battery->design_capacity * + 10000 / battery->design_voltage; + battery->full_charge_capacity = battery->full_charge_capacity * + 10000 / battery->design_voltage; + battery->design_capacity_warning = + battery->design_capacity_warning * + 10000 / battery->design_voltage; + /* Curiously, design_capacity_low, unlike the rest of them, + is correct. */ + /* capacity_granularity_* equal 1 on the systems tested, so + it's impossible to tell if they would need an adjustment + or not if their values were higher. */ + } return result; } @@ -486,6 +514,11 @@ static int acpi_battery_get_state(struct acpi_battery *battery) && battery->capacity_now >= 0 && battery->capacity_now <= 100) battery->capacity_now = (battery->capacity_now * battery->full_charge_capacity) / 100; + if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) && + battery->power_unit && battery->design_voltage) { + battery->capacity_now = battery->capacity_now * + 10000 / battery->design_voltage; + } return result; } @@ -595,6 +628,24 @@ static void sysfs_remove_battery(struct acpi_battery *battery) mutex_unlock(&battery->sysfs_lock); } +static void find_battery(const struct dmi_header *dm, void *private) +{ + struct acpi_battery *battery = (struct acpi_battery *)private; + /* Note: the hardcoded offsets below have been extracted from + the source code of dmidecode. */ + if (dm->type == DMI_ENTRY_PORTABLE_BATTERY && dm->length >= 8) { + const u8 *dmi_data = (const u8 *)(dm + 1); + int dmi_capacity = get_unaligned((const u16 *)(dmi_data + 6)); + if (dm->length >= 18) + dmi_capacity *= dmi_data[17]; + if (battery->design_capacity * battery->design_voltage / 1000 + != dmi_capacity && + battery->design_capacity * 10 == dmi_capacity) + set_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, + &battery->flags); + } +} + /* * According to the ACPI spec, some kinds of primary batteries can * report percentage battery remaining capacity directly to OS. @@ -620,6 +671,32 @@ static void acpi_battery_quirks(struct acpi_battery *battery) battery->capacity_now = (battery->capacity_now * battery->full_charge_capacity) / 100; } + + if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags)) + return ; + + if (battery->power_unit && dmi_name_in_vendors("LENOVO")) { + const char *s; + s = dmi_get_system_info(DMI_PRODUCT_VERSION); + if (s && !strnicmp(s, "ThinkPad", 8)) { + dmi_walk(find_battery, battery); + if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, + &battery->flags) && + battery->design_voltage) { + battery->design_capacity = + battery->design_capacity * + 10000 / battery->design_voltage; + battery->full_charge_capacity = + battery->full_charge_capacity * + 10000 / battery->design_voltage; + battery->design_capacity_warning = + battery->design_capacity_warning * + 10000 / battery->design_voltage; + battery->capacity_now = battery->capacity_now * + 10000 / battery->design_voltage; + } + } + } } static int acpi_battery_update(struct acpi_battery *battery) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index d59175efc42..1f0d457ecbc 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -257,7 +257,15 @@ static int __acpi_bus_get_power(struct acpi_device *device, int *state) } -static int __acpi_bus_set_power(struct acpi_device *device, int state) +/** + * acpi_device_set_power - Set power state of an ACPI device. + * @device: Device to set the power state of. + * @state: New power state to set. + * + * Callers must ensure that the device is power manageable before using this + * function. + */ +int acpi_device_set_power(struct acpi_device *device, int state) { int result = 0; acpi_status status = AE_OK; @@ -298,6 +306,12 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state) * a lower-powered state. */ if (state < device->power.state) { + if (device->power.state >= ACPI_STATE_D3_HOT && + state != ACPI_STATE_D0) { + printk(KERN_WARNING PREFIX + "Cannot transition to non-D0 state from D3\n"); + return -ENODEV; + } if (device->power.flags.power_resources) { result = acpi_power_transition(device, state); if (result) @@ -341,6 +355,7 @@ static int __acpi_bus_set_power(struct acpi_device *device, int state) return result; } +EXPORT_SYMBOL(acpi_device_set_power); int acpi_bus_set_power(acpi_handle handle, int state) @@ -359,7 +374,7 @@ int acpi_bus_set_power(acpi_handle handle, int state) return -ENODEV; } - return __acpi_bus_set_power(device, state); + return acpi_device_set_power(device, state); } EXPORT_SYMBOL(acpi_bus_set_power); @@ -402,7 +417,7 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p) if (result) return result; - result = __acpi_bus_set_power(device, state); + result = acpi_device_set_power(device, state); if (!result && state_p) *state_p = state; diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 1f9f7d7d7bc..811910b50b7 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -92,17 +92,24 @@ static int is_device_present(acpi_handle handle) return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT); } +static bool is_container_device(const char *hid) +{ + const struct acpi_device_id *container_id; + + for (container_id = container_device_ids; + container_id->id[0]; container_id++) { + if (!strcmp((char *)container_id->id, hid)) + return true; + } + + return false; +} + /*******************************************************************/ static int acpi_container_add(struct acpi_device *device) { struct acpi_container *container; - - if (!device) { - printk(KERN_ERR PREFIX "device is NULL\n"); - return -EINVAL; - } - container = kzalloc(sizeof(struct acpi_container), GFP_KERNEL); if (!container) return -ENOMEM; @@ -164,7 +171,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context) case ACPI_NOTIFY_BUS_CHECK: /* Fall through */ case ACPI_NOTIFY_DEVICE_CHECK: - printk(KERN_WARNING "Container driver received %s event\n", + pr_debug("Container driver received %s event\n", (type == ACPI_NOTIFY_BUS_CHECK) ? "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK"); @@ -185,7 +192,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context) result = container_device_add(&device, handle); if (result) { - printk(KERN_WARNING "Failed to add container\n"); + acpi_handle_warn(handle, "Failed to add container\n"); break; } @@ -232,10 +239,8 @@ container_walk_namespace_cb(acpi_handle handle, goto end; } - if (strcmp(hid, "ACPI0004") && strcmp(hid, "PNP0A05") && - strcmp(hid, "PNP0A06")) { + if (!is_container_device(hid)) goto end; - } switch (*action) { case INSTALL_NOTIFY_HANDLER: diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c new file mode 100644 index 00000000000..f09dc987cf1 --- /dev/null +++ b/drivers/acpi/device_pm.c @@ -0,0 +1,668 @@ +/* + * drivers/acpi/device_pm.c - ACPI device power management routines. + * + * Copyright (C) 2012, Intel Corp. + * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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. + * + * 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/device.h> +#include <linux/export.h> +#include <linux/mutex.h> +#include <linux/pm_qos.h> +#include <linux/pm_runtime.h> + +#include <acpi/acpi.h> +#include <acpi/acpi_bus.h> + +static DEFINE_MUTEX(acpi_pm_notifier_lock); + +/** + * acpi_add_pm_notifier - Register PM notifier for given ACPI device. + * @adev: ACPI device to add the notifier for. + * @context: Context information to pass to the notifier routine. + * + * NOTE: @adev need not be a run-wake or wakeup device to be a valid source of + * PM wakeup events. For example, wakeup events may be generated for bridges + * if one of the devices below the bridge is signaling wakeup, even if the + * bridge itself doesn't have a wakeup GPE associated with it. + */ +acpi_status acpi_add_pm_notifier(struct acpi_device *adev, + acpi_notify_handler handler, void *context) +{ + acpi_status status = AE_ALREADY_EXISTS; + + mutex_lock(&acpi_pm_notifier_lock); + + if (adev->wakeup.flags.notifier_present) + goto out; + + status = acpi_install_notify_handler(adev->handle, + ACPI_SYSTEM_NOTIFY, + handler, context); + if (ACPI_FAILURE(status)) + goto out; + + adev->wakeup.flags.notifier_present = true; + + out: + mutex_unlock(&acpi_pm_notifier_lock); + return status; +} + +/** + * acpi_remove_pm_notifier - Unregister PM notifier from given ACPI device. + * @adev: ACPI device to remove the notifier from. + */ +acpi_status acpi_remove_pm_notifier(struct acpi_device *adev, + acpi_notify_handler handler) +{ + acpi_status status = AE_BAD_PARAMETER; + + mutex_lock(&acpi_pm_notifier_lock); + + if (!adev->wakeup.flags.notifier_present) + goto out; + + status = acpi_remove_notify_handler(adev->handle, + ACPI_SYSTEM_NOTIFY, + handler); + if (ACPI_FAILURE(status)) + goto out; + + adev->wakeup.flags.notifier_present = false; + + out: + mutex_unlock(&acpi_pm_notifier_lock); + return status; +} + +/** + * acpi_device_power_state - Get preferred power state of ACPI device. + * @dev: Device whose preferred target power state to return. + * @adev: ACPI device node corresponding to @dev. + * @target_state: System state to match the resultant device state. + * @d_max_in: Deepest low-power state to take into consideration. + * @d_min_p: Location to store the upper limit of the allowed states range. + * Return value: Preferred power state of the device on success, -ENODEV + * (if there's no 'struct acpi_device' for @dev) or -EINVAL on failure + * + * Find the lowest power (highest number) ACPI device power state that the + * device can be in while the system is in the state represented by + * @target_state. If @d_min_p is set, the highest power (lowest number) device + * power state that @dev can be in for the given system sleep state is stored + * at the location pointed to by it. + * + * Callers must ensure that @dev and @adev are valid pointers and that @adev + * actually corresponds to @dev before using this function. + */ +int acpi_device_power_state(struct device *dev, struct acpi_device *adev, + u32 target_state, int d_max_in, int *d_min_p) +{ + char acpi_method[] = "_SxD"; + unsigned long long d_min, d_max; + bool wakeup = false; + + if (d_max_in < ACPI_STATE_D0 || d_max_in > ACPI_STATE_D3) + return -EINVAL; + + if (d_max_in > ACPI_STATE_D3_HOT) { + enum pm_qos_flags_status stat; + + stat = dev_pm_qos_flags(dev, PM_QOS_FLAG_NO_POWER_OFF); + if (stat == PM_QOS_FLAGS_ALL) + d_max_in = ACPI_STATE_D3_HOT; + } + + acpi_method[2] = '0' + target_state; + /* + * If the sleep state is S0, the lowest limit from ACPI is D3, + * but if the device has _S0W, we will use the value from _S0W + * as the lowest limit from ACPI. Finally, we will constrain + * the lowest limit with the specified one. + */ + d_min = ACPI_STATE_D0; + d_max = ACPI_STATE_D3; + + /* + * If present, _SxD methods return the minimum D-state (highest power + * state) we can use for the corresponding S-states. Otherwise, the + * minimum D-state is D0 (ACPI 3.x). + * + * NOTE: We rely on acpi_evaluate_integer() not clobbering the integer + * provided -- that's our fault recovery, we ignore retval. + */ + if (target_state > ACPI_STATE_S0) { + acpi_evaluate_integer(adev->handle, acpi_method, NULL, &d_min); + wakeup = device_may_wakeup(dev) && adev->wakeup.flags.valid + && adev->wakeup.sleep_state >= target_state; + } else if (dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) != + PM_QOS_FLAGS_NONE) { + wakeup = adev->wakeup.flags.valid; + } + + /* + * If _PRW says we can wake up the system from the target sleep state, + * the D-state returned by _SxD is sufficient for that (we assume a + * wakeup-aware driver if wake is set). Still, if _SxW exists + * (ACPI 3.x), it should return the maximum (lowest power) D-state that + * can wake the system. _S0W may be valid, too. + */ + if (wakeup) { + acpi_status status; + + acpi_method[3] = 'W'; + status = acpi_evaluate_integer(adev->handle, acpi_method, NULL, + &d_max); + if (ACPI_FAILURE(status)) { + if (target_state != ACPI_STATE_S0 || + status != AE_NOT_FOUND) + d_max = d_min; + } else if (d_max < d_min) { + /* Warn the user of the broken DSDT */ + printk(KERN_WARNING "ACPI: Wrong value from %s\n", + acpi_method); + /* Sanitize it */ + d_min = d_max; + } + } + + if (d_max_in < d_min) + return -EINVAL; + if (d_min_p) + *d_min_p = d_min; + /* constrain d_max with specified lowest limit (max number) */ + if (d_max > d_max_in) { + for (d_max = d_max_in; d_max > d_min; d_max--) { + if (adev->power.states[d_max].flags.valid) + break; + } + } + return d_max; +} +EXPORT_SYMBOL_GPL(acpi_device_power_state); + +/** + * acpi_pm_device_sleep_state - Get preferred power state of ACPI device. + * @dev: Device whose preferred target power state to return. + * @d_min_p: Location to store the upper limit of the allowed states range. + * @d_max_in: Deepest low-power state to take into consideration. + * Return value: Preferred power state of the device on success, -ENODEV + * (if there's no 'struct acpi_device' for @dev) or -EINVAL on failure + * + * The caller must ensure that @dev is valid before using this function. + */ +int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) +{ + acpi_handle handle = DEVICE_ACPI_HANDLE(dev); + struct acpi_device *adev; + + if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { + dev_dbg(dev, "ACPI handle without context in %s!\n", __func__); + return -ENODEV; + } + + return acpi_device_power_state(dev, adev, acpi_target_system_state(), + d_max_in, d_min_p); +} +EXPORT_SYMBOL(acpi_pm_device_sleep_state); + +#ifdef CONFIG_PM_RUNTIME +/** + * acpi_wakeup_device - Wakeup notification handler for ACPI devices. + * @handle: ACPI handle of the device the notification is for. + * @event: Type of the signaled event. + * @context: Device corresponding to @handle. + */ +static void acpi_wakeup_device(acpi_handle handle, u32 event, void *context) +{ + struct device *dev = context; + + if (event == ACPI_NOTIFY_DEVICE_WAKE && dev) { + pm_wakeup_event(dev, 0); + pm_runtime_resume(dev); + } +} + +/** + * __acpi_device_run_wake - Enable/disable runtime remote wakeup for device. + * @adev: ACPI device to enable/disable the remote wakeup for. + * @enable: Whether to enable or disable the wakeup functionality. + * + * Enable/disable the GPE associated with @adev so that it can generate + * wakeup signals for the device in response to external (remote) events and + * enable/disable device wakeup power. + * + * Callers must ensure that @adev is a valid ACPI device node before executing + * this function. + */ +int __acpi_device_run_wake(struct acpi_device *adev, bool enable) +{ + struct acpi_device_wakeup *wakeup = &adev->wakeup; + + if (enable) { + acpi_status res; + int error; + + error = acpi_enable_wakeup_device_power(adev, ACPI_STATE_S0); + if (error) + return error; + + res = acpi_enable_gpe(wakeup->gpe_device, wakeup->gpe_number); + if (ACPI_FAILURE(res)) { + acpi_disable_wakeup_device_power(adev); + return -EIO; + } + } else { + acpi_disable_gpe(wakeup->gpe_device, wakeup->gpe_number); + acpi_disable_wakeup_device_power(adev); + } + return 0; +} + +/** + * acpi_pm_device_run_wake - Enable/disable remote wakeup for given device. + * @dev: Device to enable/disable the platform to wake up. + * @enable: Whether to enable or disable the wakeup functionality. + */ +int acpi_pm_device_run_wake(struct device *phys_dev, bool enable) +{ + struct acpi_device *adev; + acpi_handle handle; + + if (!device_run_wake(phys_dev)) + return -EINVAL; + + handle = DEVICE_ACPI_HANDLE(phys_dev); + if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { + dev_dbg(phys_dev, "ACPI handle without context in %s!\n", + __func__); + return -ENODEV; + } + + return __acpi_device_run_wake(adev, enable); +} +EXPORT_SYMBOL(acpi_pm_device_run_wake); +#else +static inline void acpi_wakeup_device(acpi_handle handle, u32 event, + void *context) {} +#endif /* CONFIG_PM_RUNTIME */ + + #ifdef CONFIG_PM_SLEEP +/** + * __acpi_device_sleep_wake - Enable or disable device to wake up the system. + * @dev: Device to enable/desible to wake up the system. + * @target_state: System state the device is supposed to wake up from. + * @enable: Whether to enable or disable @dev to wake up the system. + */ +int __acpi_device_sleep_wake(struct acpi_device *adev, u32 target_state, + bool enable) +{ + return enable ? + acpi_enable_wakeup_device_power(adev, target_state) : + acpi_disable_wakeup_device_power(adev); +} + +/** + * acpi_pm_device_sleep_wake - Enable or disable device to wake up the system. + * @dev: Device to enable/desible to wake up the system from sleep states. + * @enable: Whether to enable or disable @dev to wake up the system. + */ +int acpi_pm_device_sleep_wake(struct device *dev, bool enable) +{ + acpi_handle handle; + struct acpi_device *adev; + int error; + + if (!device_can_wakeup(dev)) + return -EINVAL; + + handle = DEVICE_ACPI_HANDLE(dev); + if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { + dev_dbg(dev, "ACPI handle without context in %s!\n", __func__); + return -ENODEV; + } + + error = __acpi_device_sleep_wake(adev, acpi_target_system_state(), + enable); + if (!error) + dev_info(dev, "System wakeup %s by ACPI\n", + enable ? "enabled" : "disabled"); + + return error; +} +#endif /* CONFIG_PM_SLEEP */ + +/** + * acpi_dev_pm_get_node - Get ACPI device node for the given physical device. + * @dev: Device to get the ACPI node for. + */ +static struct acpi_device *acpi_dev_pm_get_node(struct device *dev) +{ + acpi_handle handle = DEVICE_ACPI_HANDLE(dev); + struct acpi_device *adev; + + return handle && ACPI_SUCCESS(acpi_bus_get_device(handle, &adev)) ? + adev : NULL; +} + +/** + * acpi_dev_pm_low_power - Put ACPI device into a low-power state. + * @dev: Device to put into a low-power state. + * @adev: ACPI device node corresponding to @dev. + * @system_state: System state to choose the device state for. + */ +static int acpi_dev_pm_low_power(struct device *dev, struct acpi_device *adev, + u32 system_state) +{ + int power_state; + + if (!acpi_device_power_manageable(adev)) + return 0; + + power_state = acpi_device_power_state(dev, adev, system_state, + ACPI_STATE_D3, NULL); + if (power_state < ACPI_STATE_D0 || power_state > ACPI_STATE_D3) + return -EIO; + + return acpi_device_set_power(adev, power_state); +} + +/** + * acpi_dev_pm_full_power - Put ACPI device into the full-power state. + * @adev: ACPI device node to put into the full-power state. + */ +static int acpi_dev_pm_full_power(struct acpi_device *adev) +{ + return acpi_device_power_manageable(adev) ? + acpi_device_set_power(adev, ACPI_STATE_D0) : 0; +} + +#ifdef CONFIG_PM_RUNTIME +/** + * acpi_dev_runtime_suspend - Put device into a low-power state using ACPI. + * @dev: Device to put into a low-power state. + * + * Put the given device into a runtime low-power state using the standard ACPI + * mechanism. Set up remote wakeup if desired, choose the state to put the + * device into (this checks if remote wakeup is expected to work too), and set + * the power state of the device. + */ +int acpi_dev_runtime_suspend(struct device *dev) +{ + struct acpi_device *adev = acpi_dev_pm_get_node(dev); + bool remote_wakeup; + int error; + + if (!adev) + return 0; + + remote_wakeup = dev_pm_qos_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP) > + PM_QOS_FLAGS_NONE; + error = __acpi_device_run_wake(adev, remote_wakeup); + if (remote_wakeup && error) + return -EAGAIN; + + error = acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0); + if (error) + __acpi_device_run_wake(adev, false); + + return error; +} +EXPORT_SYMBOL_GPL(acpi_dev_runtime_suspend); + +/** + * acpi_dev_runtime_resume - Put device into the full-power state using ACPI. + * @dev: Device to put into the full-power state. + * + * Put the given device into the full-power state using the standard ACPI + * mechanism at run time. Set the power state of the device to ACPI D0 and + * disable remote wakeup. + */ +int acpi_dev_runtime_resume(struct device *dev) +{ + struct acpi_device *adev = acpi_dev_pm_get_node(dev); + int error; + + if (!adev) + return 0; + + error = acpi_dev_pm_full_power(adev); + __acpi_device_run_wake(adev, false); + return error; +} +EXPORT_SYMBOL_GPL(acpi_dev_runtime_resume); + +/** + * acpi_subsys_runtime_suspend - Suspend device using ACPI. + * @dev: Device to suspend. + * + * Carry out the generic runtime suspend procedure for @dev and use ACPI to put + * it into a runtime low-power state. + */ +int acpi_subsys_runtime_suspend(struct device *dev) +{ + int ret = pm_generic_runtime_suspend(dev); + return ret ? ret : acpi_dev_runtime_suspend(dev); +} +EXPORT_SYMBOL_GPL(acpi_subsys_runtime_suspend); + +/** + * acpi_subsys_runtime_resume - Resume device using ACPI. + * @dev: Device to Resume. + * + * Use ACPI to put the given device into the full-power state and carry out the + * generic runtime resume procedure for it. + */ +int acpi_subsys_runtime_resume(struct device *dev) +{ + int ret = acpi_dev_runtime_resume(dev); + return ret ? ret : pm_generic_runtime_resume(dev); +} +EXPORT_SYMBOL_GPL(acpi_subsys_runtime_resume); +#endif /* CONFIG_PM_RUNTIME */ + +#ifdef CONFIG_PM_SLEEP +/** + * acpi_dev_suspend_late - Put device into a low-power state using ACPI. + * @dev: Device to put into a low-power state. + * + * Put the given device into a low-power state during system transition to a + * sleep state using the standard ACPI mechanism. Set up system wakeup if + * desired, choose the state to put the device into (this checks if system + * wakeup is expected to work too), and set the power state of the device. + */ +int acpi_dev_suspend_late(struct device *dev) +{ + struct acpi_device *adev = acpi_dev_pm_get_node(dev); + u32 target_state; + bool wakeup; + int error; + + if (!adev) + return 0; + + target_state = acpi_target_system_state(); + wakeup = device_may_wakeup(dev); + error = __acpi_device_sleep_wake(adev, target_state, wakeup); + if (wakeup && error) + return error; + + error = acpi_dev_pm_low_power(dev, adev, target_state); + if (error) + __acpi_device_sleep_wake(adev, ACPI_STATE_UNKNOWN, false); + + return error; +} +EXPORT_SYMBOL_GPL(acpi_dev_suspend_late); + +/** + * acpi_dev_resume_early - Put device into the full-power state using ACPI. + * @dev: Device to put into the full-power state. + * + * Put the given device into the full-power state using the standard ACPI + * mechanism during system transition to the working state. Set the power + * state of the device to ACPI D0 and disable remote wakeup. + */ +int acpi_dev_resume_early(struct device *dev) +{ + struct acpi_device *adev = acpi_dev_pm_get_node(dev); + int error; + + if (!adev) + return 0; + + error = acpi_dev_pm_full_power(adev); + __acpi_device_sleep_wake(adev, ACPI_STATE_UNKNOWN, false); + return error; +} +EXPORT_SYMBOL_GPL(acpi_dev_resume_early); + +/** + * acpi_subsys_prepare - Prepare device for system transition to a sleep state. + * @dev: Device to prepare. + */ +int acpi_subsys_prepare(struct device *dev) +{ + /* + * Follow PCI and resume devices suspended at run time before running + * their system suspend callbacks. + */ + pm_runtime_resume(dev); + return pm_generic_prepare(dev); +} +EXPORT_SYMBOL_GPL(acpi_subsys_prepare); + +/** + * acpi_subsys_suspend_late - Suspend device using ACPI. + * @dev: Device to suspend. + * + * Carry out the generic late suspend procedure for @dev and use ACPI to put + * it into a low-power state during system transition into a sleep state. + */ +int acpi_subsys_suspend_late(struct device *dev) +{ + int ret = pm_generic_suspend_late(dev); + return ret ? ret : acpi_dev_suspend_late(dev); +} +EXPORT_SYMBOL_GPL(acpi_subsys_suspend_late); + +/** + * acpi_subsys_resume_early - Resume device using ACPI. + * @dev: Device to Resume. + * + * Use ACPI to put the given device into the full-power state and carry out the + * generic early resume procedure for it during system transition into the + * working state. + */ +int acpi_subsys_resume_early(struct device *dev) +{ + int ret = acpi_dev_resume_early(dev); + return ret ? ret : pm_generic_resume_early(dev); +} +EXPORT_SYMBOL_GPL(acpi_subsys_resume_early); +#endif /* CONFIG_PM_SLEEP */ + +static struct dev_pm_domain acpi_general_pm_domain = { + .ops = { +#ifdef CONFIG_PM_RUNTIME + .runtime_suspend = acpi_subsys_runtime_suspend, + .runtime_resume = acpi_subsys_runtime_resume, + .runtime_idle = pm_generic_runtime_idle, +#endif +#ifdef CONFIG_PM_SLEEP + .prepare = acpi_subsys_prepare, + .suspend_late = acpi_subsys_suspend_late, + .resume_early = acpi_subsys_resume_early, + .poweroff_late = acpi_subsys_suspend_late, + .restore_early = acpi_subsys_resume_early, +#endif + }, +}; + +/** + * acpi_dev_pm_attach - Prepare device for ACPI power management. + * @dev: Device to prepare. + * @power_on: Whether or not to power on the device. + * + * If @dev has a valid ACPI handle that has a valid struct acpi_device object + * attached to it, install a wakeup notification handler for the device and + * add it to the general ACPI PM domain. If @power_on is set, the device will + * be put into the ACPI D0 state before the function returns. + * + * This assumes that the @dev's bus type uses generic power management callbacks + * (or doesn't use any power management callbacks at all). + * + * Callers must ensure proper synchronization of this function with power + * management callbacks. + */ +int acpi_dev_pm_attach(struct device *dev, bool power_on) +{ + struct acpi_device *adev = acpi_dev_pm_get_node(dev); + + if (!adev) + return -ENODEV; + + if (dev->pm_domain) + return -EEXIST; + + acpi_add_pm_notifier(adev, acpi_wakeup_device, dev); + dev->pm_domain = &acpi_general_pm_domain; + if (power_on) { + acpi_dev_pm_full_power(adev); + __acpi_device_run_wake(adev, false); + } + return 0; +} +EXPORT_SYMBOL_GPL(acpi_dev_pm_attach); + +/** + * acpi_dev_pm_detach - Remove ACPI power management from the device. + * @dev: Device to take care of. + * @power_off: Whether or not to try to remove power from the device. + * + * Remove the device from the general ACPI PM domain and remove its wakeup + * notifier. If @power_off is set, additionally remove power from the device if + * possible. + * + * Callers must ensure proper synchronization of this function with power + * management callbacks. + */ +void acpi_dev_pm_detach(struct device *dev, bool power_off) +{ + struct acpi_device *adev = acpi_dev_pm_get_node(dev); + + if (adev && dev->pm_domain == &acpi_general_pm_domain) { + dev->pm_domain = NULL; + acpi_remove_pm_notifier(adev, acpi_wakeup_device); + if (power_off) { + /* + * If the device's PM QoS resume latency limit or flags + * have been exposed to user space, they have to be + * hidden at this point, so that they don't affect the + * choice of the low-power state to put the device into. + */ + dev_pm_qos_hide_latency_limit(dev); + dev_pm_qos_hide_flags(dev); + __acpi_device_run_wake(adev, false); + acpi_dev_pm_low_power(dev, adev, ACPI_STATE_S0); + } + } +} +EXPORT_SYMBOL_GPL(acpi_dev_pm_detach); diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 88eb1430466..f32bd47b35e 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -31,6 +31,7 @@ #include <linux/platform_device.h> #include <linux/jiffies.h> #include <linux/stddef.h> +#include <linux/acpi.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> @@ -460,12 +461,8 @@ static void handle_dock(struct dock_station *ds, int dock) struct acpi_object_list arg_list; union acpi_object arg; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer); - - printk(KERN_INFO PREFIX "%s - %s\n", - (char *)name_buffer.pointer, dock ? "docking" : "undocking"); + acpi_handle_info(ds->handle, "%s\n", dock ? "docking" : "undocking"); /* _DCK method has one argument */ arg_list.count = 1; @@ -474,11 +471,10 @@ static void handle_dock(struct dock_station *ds, int dock) arg.integer.value = dock; status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer); if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) - ACPI_EXCEPTION((AE_INFO, status, "%s - failed to execute" - " _DCK\n", (char *)name_buffer.pointer)); + acpi_handle_err(ds->handle, "Failed to execute _DCK (0x%x)\n", + status); kfree(buffer.pointer); - kfree(name_buffer.pointer); } static inline void dock(struct dock_station *ds) @@ -525,9 +521,11 @@ static void dock_lock(struct dock_station *ds, int lock) status = acpi_evaluate_object(ds->handle, "_LCK", &arg_list, NULL); if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { if (lock) - printk(KERN_WARNING PREFIX "Locking device failed\n"); + acpi_handle_warn(ds->handle, + "Locking device failed (0x%x)\n", status); else - printk(KERN_WARNING PREFIX "Unlocking device failed\n"); + acpi_handle_warn(ds->handle, + "Unlocking device failed (0x%x)\n", status); } } @@ -667,7 +665,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event) dock_lock(ds, 0); eject_dock(ds); if (dock_present(ds)) { - printk(KERN_ERR PREFIX "Unable to undock!\n"); + acpi_handle_err(ds->handle, "Unable to undock!\n"); return -EBUSY; } complete_undock(ds); @@ -715,7 +713,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) begin_dock(ds); dock(ds); if (!dock_present(ds)) { - printk(KERN_ERR PREFIX "Unable to dock!\n"); + acpi_handle_err(handle, "Unable to dock!\n"); complete_dock(ds); break; } @@ -743,7 +741,7 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) dock_event(ds, event, UNDOCK_EVENT); break; default: - printk(KERN_ERR PREFIX "Unknown dock event %d\n", event); + acpi_handle_err(handle, "Unknown dock event %d\n", event); } } @@ -987,7 +985,7 @@ err_rmgroup: sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group); err_unregister: platform_device_unregister(dd); - printk(KERN_ERR "%s encountered error %d\n", __func__, ret); + acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret); return ret; } @@ -1016,51 +1014,39 @@ static int dock_remove(struct dock_station *ds) } /** - * find_dock - look for a dock station + * find_dock_and_bay - look for dock stations and bays * @handle: acpi handle of a device * @lvl: unused - * @context: counter of dock stations found + * @context: unused * @rv: unused * - * This is called by acpi_walk_namespace to look for dock stations. + * This is called by acpi_walk_namespace to look for dock stations and bays. */ static __init acpi_status -find_dock(acpi_handle handle, u32 lvl, void *context, void **rv) +find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv) { - if (is_dock(handle)) + if (is_dock(handle) || is_ejectable_bay(handle)) dock_add(handle); return AE_OK; } -static __init acpi_status -find_bay(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - /* If bay is a dock, it's already handled */ - if (is_ejectable_bay(handle) && !is_dock(handle)) - dock_add(handle); - return AE_OK; -} - static int __init dock_init(void) { if (acpi_disabled) return 0; - /* look for a dock station */ + /* look for dock stations and bays */ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_dock, NULL, NULL, NULL); + ACPI_UINT32_MAX, find_dock_and_bay, NULL, NULL, NULL); - /* look for bay */ - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_bay, NULL, NULL, NULL); if (!dock_station_count) { - printk(KERN_INFO PREFIX "No dock devices found.\n"); + pr_info(PREFIX "No dock devices found.\n"); return 0; } register_acpi_bus_notifier(&dock_acpi_notifier); - printk(KERN_INFO PREFIX "%s: %d docks/bays found\n", + pr_info(PREFIX "%s: %d docks/bays found\n", ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); return 0; } diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index a51df968131..354007d490d 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -158,10 +158,10 @@ static int ec_transaction_done(struct acpi_ec *ec) { unsigned long flags; int ret = 0; - spin_lock_irqsave(&ec->curr_lock, flags); + spin_lock_irqsave(&ec->lock, flags); if (!ec->curr || ec->curr->done) ret = 1; - spin_unlock_irqrestore(&ec->curr_lock, flags); + spin_unlock_irqrestore(&ec->lock, flags); return ret; } @@ -175,32 +175,38 @@ static void start_transaction(struct acpi_ec *ec) static void advance_transaction(struct acpi_ec *ec, u8 status) { unsigned long flags; - spin_lock_irqsave(&ec->curr_lock, flags); - if (!ec->curr) + struct transaction *t = ec->curr; + + spin_lock_irqsave(&ec->lock, flags); + if (!t) goto unlock; - if (ec->curr->wlen > ec->curr->wi) { + if (t->wlen > t->wi) { if ((status & ACPI_EC_FLAG_IBF) == 0) acpi_ec_write_data(ec, - ec->curr->wdata[ec->curr->wi++]); + t->wdata[t->wi++]); else goto err; - } else if (ec->curr->rlen > ec->curr->ri) { + } else if (t->rlen > t->ri) { if ((status & ACPI_EC_FLAG_OBF) == 1) { - ec->curr->rdata[ec->curr->ri++] = acpi_ec_read_data(ec); - if (ec->curr->rlen == ec->curr->ri) - ec->curr->done = true; + t->rdata[t->ri++] = acpi_ec_read_data(ec); + if (t->rlen == t->ri) + t->done = true; } else goto err; - } else if (ec->curr->wlen == ec->curr->wi && + } else if (t->wlen == t->wi && (status & ACPI_EC_FLAG_IBF) == 0) - ec->curr->done = true; + t->done = true; goto unlock; err: - /* false interrupt, state didn't change */ - if (in_interrupt()) - ++ec->curr->irq_count; + /* + * If SCI bit is set, then don't think it's a false IRQ + * otherwise will take a not handled IRQ as a false one. + */ + if (in_interrupt() && !(status & ACPI_EC_FLAG_SCI)) + ++t->irq_count; + unlock: - spin_unlock_irqrestore(&ec->curr_lock, flags); + spin_unlock_irqrestore(&ec->lock, flags); } static int acpi_ec_sync_query(struct acpi_ec *ec); @@ -238,9 +244,9 @@ static int ec_poll(struct acpi_ec *ec) if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) break; pr_debug(PREFIX "controller reset, restart transaction\n"); - spin_lock_irqsave(&ec->curr_lock, flags); + spin_lock_irqsave(&ec->lock, flags); start_transaction(ec); - spin_unlock_irqrestore(&ec->curr_lock, flags); + spin_unlock_irqrestore(&ec->lock, flags); } return -ETIME; } @@ -253,17 +259,17 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, if (EC_FLAGS_MSI) udelay(ACPI_EC_MSI_UDELAY); /* start transaction */ - spin_lock_irqsave(&ec->curr_lock, tmp); + spin_lock_irqsave(&ec->lock, tmp); /* following two actions should be kept atomic */ ec->curr = t; start_transaction(ec); if (ec->curr->command == ACPI_EC_COMMAND_QUERY) clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags); - spin_unlock_irqrestore(&ec->curr_lock, tmp); + spin_unlock_irqrestore(&ec->lock, tmp); ret = ec_poll(ec); - spin_lock_irqsave(&ec->curr_lock, tmp); + spin_lock_irqsave(&ec->lock, tmp); ec->curr = NULL; - spin_unlock_irqrestore(&ec->curr_lock, tmp); + spin_unlock_irqrestore(&ec->lock, tmp); return ret; } @@ -292,7 +298,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) return -EINVAL; if (t->rdata) memset(t->rdata, 0, t->rlen); - mutex_lock(&ec->lock); + mutex_lock(&ec->mutex); if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) { status = -EINVAL; goto unlock; @@ -310,7 +316,8 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) status = -ETIME; goto end; } - pr_debug(PREFIX "transaction start\n"); + pr_debug(PREFIX "transaction start (cmd=0x%02x, addr=0x%02x)\n", + t->command, t->wdata ? t->wdata[0] : 0); /* disable GPE during transaction if storm is detected */ if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) { /* It has to be disabled, so that it doesn't trigger. */ @@ -326,8 +333,9 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t) /* It is safe to enable the GPE outside of the transaction. */ acpi_enable_gpe(NULL, ec->gpe); } else if (t->irq_count > ec_storm_threshold) { - pr_info(PREFIX "GPE storm detected, " - "transactions will use polling mode\n"); + pr_info(PREFIX "GPE storm detected(%d GPEs), " + "transactions will use polling mode\n", + t->irq_count); set_bit(EC_FLAGS_GPE_STORM, &ec->flags); } pr_debug(PREFIX "transaction end\n"); @@ -335,7 +343,7 @@ end: if (ec->global_lock) acpi_release_global_lock(glk); unlock: - mutex_unlock(&ec->lock); + mutex_unlock(&ec->mutex); return status; } @@ -403,7 +411,7 @@ int ec_burst_disable(void) EXPORT_SYMBOL(ec_burst_disable); -int ec_read(u8 addr, u8 * val) +int ec_read(u8 addr, u8 *val) { int err; u8 temp_data; @@ -468,10 +476,10 @@ void acpi_ec_block_transactions(void) if (!ec) return; - mutex_lock(&ec->lock); + mutex_lock(&ec->mutex); /* Prevent transactions from being carried out */ set_bit(EC_FLAGS_BLOCKED, &ec->flags); - mutex_unlock(&ec->lock); + mutex_unlock(&ec->mutex); } void acpi_ec_unblock_transactions(void) @@ -481,10 +489,10 @@ void acpi_ec_unblock_transactions(void) if (!ec) return; - mutex_lock(&ec->lock); + mutex_lock(&ec->mutex); /* Allow transactions to be carried out again */ clear_bit(EC_FLAGS_BLOCKED, &ec->flags); - mutex_unlock(&ec->lock); + mutex_unlock(&ec->mutex); } void acpi_ec_unblock_transactions_early(void) @@ -536,9 +544,9 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, handler->handle = handle; handler->func = func; handler->data = data; - mutex_lock(&ec->lock); + mutex_lock(&ec->mutex); list_add(&handler->node, &ec->list); - mutex_unlock(&ec->lock); + mutex_unlock(&ec->mutex); return 0; } @@ -547,14 +555,14 @@ EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler); void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) { struct acpi_ec_query_handler *handler, *tmp; - mutex_lock(&ec->lock); + mutex_lock(&ec->mutex); list_for_each_entry_safe(handler, tmp, &ec->list, node) { if (query_bit == handler->query_bit) { list_del(&handler->node); kfree(handler); } } - mutex_unlock(&ec->lock); + mutex_unlock(&ec->mutex); } EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); @@ -601,9 +609,9 @@ static void acpi_ec_gpe_query(void *ec_cxt) struct acpi_ec *ec = ec_cxt; if (!ec) return; - mutex_lock(&ec->lock); + mutex_lock(&ec->mutex); acpi_ec_sync_query(ec); - mutex_unlock(&ec->lock); + mutex_unlock(&ec->mutex); } static int ec_check_sci(struct acpi_ec *ec, u8 state) @@ -622,10 +630,11 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device, u32 gpe_number, void *data) { struct acpi_ec *ec = data; + u8 status = acpi_ec_read_status(ec); - pr_debug(PREFIX "~~~> interrupt\n"); + pr_debug(PREFIX "~~~> interrupt, status:0x%02x\n", status); - advance_transaction(ec, acpi_ec_read_status(ec)); + advance_transaction(ec, status); if (ec_transaction_done(ec) && (acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) == 0) { wake_up(&ec->wait); @@ -691,10 +700,10 @@ static struct acpi_ec *make_acpi_ec(void) if (!ec) return NULL; ec->flags = 1 << EC_FLAGS_QUERY_PENDING; - mutex_init(&ec->lock); + mutex_init(&ec->mutex); init_waitqueue_head(&ec->wait); INIT_LIST_HEAD(&ec->list); - spin_lock_init(&ec->curr_lock); + spin_lock_init(&ec->lock); return ec; } @@ -853,12 +862,12 @@ static int acpi_ec_remove(struct acpi_device *device, int type) ec = acpi_driver_data(device); ec_remove_handlers(ec); - mutex_lock(&ec->lock); + mutex_lock(&ec->mutex); list_for_each_entry_safe(handler, tmp, &ec->list, node) { list_del(&handler->node); kfree(handler); } - mutex_unlock(&ec->lock); + mutex_unlock(&ec->mutex); release_region(ec->data_addr, 1); release_region(ec->command_addr, 1); device->driver_data = NULL; diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 08373086cd7..01551840d23 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -130,46 +130,59 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle) { struct acpi_device *acpi_dev; acpi_status status; - struct acpi_device_physical_node *physical_node; + struct acpi_device_physical_node *physical_node, *pn; char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2]; int retval = -EINVAL; - if (dev->archdata.acpi_handle) { - dev_warn(dev, "Drivers changed 'acpi_handle'\n"); - return -EINVAL; + if (ACPI_HANDLE(dev)) { + if (handle) { + dev_warn(dev, "ACPI handle is already set\n"); + return -EINVAL; + } else { + handle = ACPI_HANDLE(dev); + } } + if (!handle) + return -EINVAL; get_device(dev); status = acpi_bus_get_device(handle, &acpi_dev); if (ACPI_FAILURE(status)) goto err; - physical_node = kzalloc(sizeof(struct acpi_device_physical_node), - GFP_KERNEL); + physical_node = kzalloc(sizeof(*physical_node), GFP_KERNEL); if (!physical_node) { retval = -ENOMEM; goto err; } mutex_lock(&acpi_dev->physical_node_lock); + + /* Sanity check. */ + list_for_each_entry(pn, &acpi_dev->physical_node_list, node) + if (pn->dev == dev) { + dev_warn(dev, "Already associated with ACPI node\n"); + goto err_free; + } + /* allocate physical node id according to physical_node_id_bitmap */ physical_node->node_id = find_first_zero_bit(acpi_dev->physical_node_id_bitmap, ACPI_MAX_PHYSICAL_NODE); if (physical_node->node_id >= ACPI_MAX_PHYSICAL_NODE) { retval = -ENOSPC; - mutex_unlock(&acpi_dev->physical_node_lock); - kfree(physical_node); - goto err; + goto err_free; } set_bit(physical_node->node_id, acpi_dev->physical_node_id_bitmap); physical_node->dev = dev; list_add_tail(&physical_node->node, &acpi_dev->physical_node_list); acpi_dev->physical_node_count++; + mutex_unlock(&acpi_dev->physical_node_lock); - dev->archdata.acpi_handle = handle; + if (!ACPI_HANDLE(dev)) + ACPI_HANDLE_SET(dev, acpi_dev->handle); if (!physical_node->node_id) strcpy(physical_node_name, PHYSICAL_NODE_STRING); @@ -187,8 +200,14 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle) return 0; err: + ACPI_HANDLE_SET(dev, NULL); put_device(dev); return retval; + + err_free: + mutex_unlock(&acpi_dev->physical_node_lock); + kfree(physical_node); + goto err; } static int acpi_unbind_one(struct device *dev) @@ -198,11 +217,10 @@ static int acpi_unbind_one(struct device *dev) acpi_status status; struct list_head *node, *next; - if (!dev->archdata.acpi_handle) + if (!ACPI_HANDLE(dev)) return 0; - status = acpi_bus_get_device(dev->archdata.acpi_handle, - &acpi_dev); + status = acpi_bus_get_device(ACPI_HANDLE(dev), &acpi_dev); if (ACPI_FAILURE(status)) goto err; @@ -228,7 +246,7 @@ static int acpi_unbind_one(struct device *dev) sysfs_remove_link(&acpi_dev->dev.kobj, physical_node_name); sysfs_remove_link(&dev->kobj, "firmware_node"); - dev->archdata.acpi_handle = NULL; + ACPI_HANDLE_SET(dev, NULL); /* acpi_bind_one increase refcnt by one */ put_device(dev); kfree(entry); @@ -248,6 +266,10 @@ static int acpi_platform_notify(struct device *dev) acpi_handle handle; int ret = -EINVAL; + ret = acpi_bind_one(dev, NULL); + if (!ret) + goto out; + if (!dev->bus || !dev->parent) { /* bridge devices genernally haven't bus or parent */ ret = acpi_find_bridge_device(dev, &handle); @@ -261,16 +283,16 @@ static int acpi_platform_notify(struct device *dev) } if ((ret = type->find_device(dev, &handle)) != 0) DBG("Can't get handler for %s\n", dev_name(dev)); - end: + end: if (!ret) acpi_bind_one(dev, handle); + out: #if ACPI_GLUE_DEBUG if (!ret) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - acpi_get_name(dev->archdata.acpi_handle, - ACPI_FULL_PATHNAME, &buffer); + acpi_get_name(dev->acpi_handle, ACPI_FULL_PATHNAME, &buffer); DBG("Device %s -> %s\n", dev_name(dev), (char *)buffer.pointer); kfree(buffer.pointer); } else diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c index 20a0f2c3ca3..a0cc796932f 100644 --- a/drivers/acpi/hed.c +++ b/drivers/acpi/hed.c @@ -61,7 +61,7 @@ static void acpi_hed_notify(struct acpi_device *device, u32 event) blocking_notifier_call_chain(&acpi_hed_notify_list, 0, NULL); } -static int __devinit acpi_hed_add(struct acpi_device *device) +static int acpi_hed_add(struct acpi_device *device) { /* Only one hardware error device */ if (hed_handle) @@ -70,7 +70,7 @@ static int __devinit acpi_hed_add(struct acpi_device *device) return 0; } -static int __devexit acpi_hed_remove(struct acpi_device *device, int type) +static int acpi_hed_remove(struct acpi_device *device, int type) { hed_handle = NULL; return 0; diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index ca75b9ce048..3c407cdc1ec 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -58,11 +58,11 @@ struct acpi_ec { unsigned long data_addr; unsigned long global_lock; unsigned long flags; - struct mutex lock; + struct mutex mutex; wait_queue_head_t wait; struct list_head list; struct transaction *curr; - spinlock_t curr_lock; + spinlock_t lock; }; extern struct acpi_ec *first_ec; @@ -93,4 +93,11 @@ static inline int suspend_nvs_save(void) { return 0; } static inline void suspend_nvs_restore(void) {} #endif +/*-------------------------------------------------------------------------- + Platform bus support + -------------------------------------------------------------------------- */ +struct platform_device; + +struct platform_device *acpi_create_platform_device(struct acpi_device *adev); + #endif /* _ACPI_INTERNAL_H_ */ diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 9eaf708f588..6dc4a2b1e95 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -932,7 +932,7 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, * having a static work_struct. */ - dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC); + dpc = kzalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC); if (!dpc) return AE_NO_MEMORY; @@ -944,17 +944,22 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, * because the hotplug code may call driver .remove() functions, * which invoke flush_scheduled_work/acpi_os_wait_events_complete * to flush these workqueues. + * + * To prevent lockdep from complaining unnecessarily, make sure that + * there is a different static lockdep key for each workqueue by using + * INIT_WORK() for each of them separately. */ - queue = hp ? kacpi_hotplug_wq : - (type == OSL_NOTIFY_HANDLER ? kacpi_notify_wq : kacpid_wq); - dpc->wait = hp ? 1 : 0; - - if (queue == kacpi_hotplug_wq) + if (hp) { + queue = kacpi_hotplug_wq; + dpc->wait = 1; INIT_WORK(&dpc->work, acpi_os_execute_deferred); - else if (queue == kacpi_notify_wq) + } else if (type == OSL_NOTIFY_HANDLER) { + queue = kacpi_notify_wq; INIT_WORK(&dpc->work, acpi_os_execute_deferred); - else + } else { + queue = kacpid_wq; INIT_WORK(&dpc->work, acpi_os_execute_deferred); + } /* * On some machines, a software-initiated SMI causes corruption unless @@ -986,6 +991,7 @@ acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function, { return __acpi_os_execute(0, function, context, 1); } +EXPORT_SYMBOL(acpi_os_hotplug_execute); void acpi_os_wait_events_complete(void) { diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 0eefa12e648..23a03249013 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -459,19 +459,19 @@ int acpi_pci_irq_enable(struct pci_dev *dev) */ if (gsi < 0) { u32 dev_gsi; - dev_warn(&dev->dev, "PCI INT %c: no GSI", pin_name(pin)); /* Interrupt Line values above 0xF are forbidden */ if (dev->irq > 0 && (dev->irq <= 0xF) && (acpi_isa_irq_to_gsi(dev->irq, &dev_gsi) == 0)) { - printk(" - using ISA IRQ %d\n", dev->irq); + dev_warn(&dev->dev, "PCI INT %c: no GSI - using ISA IRQ %d\n", + pin_name(pin), dev->irq); acpi_register_gsi(&dev->dev, dev_gsi, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW); - return 0; } else { - printk("\n"); - return 0; + dev_warn(&dev->dev, "PCI INT %c: no GSI\n", + pin_name(pin)); } + return 0; } rc = acpi_register_gsi(&dev->dev, gsi, triggering, polarity); @@ -495,11 +495,6 @@ int acpi_pci_irq_enable(struct pci_dev *dev) return 0; } -/* FIXME: implement x86/x86_64 version */ -void __attribute__ ((weak)) acpi_unregister_gsi(u32 i) -{ -} - void acpi_pci_irq_disable(struct pci_dev *dev) { struct acpi_prt_entry *entry; diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index bce469c0b48..f70b9e5fc1b 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -445,7 +445,7 @@ out: } EXPORT_SYMBOL(acpi_pci_osc_control_set); -static int __devinit acpi_pci_root_add(struct acpi_device *device) +static int acpi_pci_root_add(struct acpi_device *device) { unsigned long long segment, bus; acpi_status status; diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 40e38a06ba8..7db61b8fa11 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -473,7 +473,7 @@ int acpi_power_resource_register_device(struct device *dev, acpi_handle handle) return ret; no_power_resource: - printk(KERN_DEBUG PREFIX "Invalid Power Resource to register!"); + printk(KERN_DEBUG PREFIX "Invalid Power Resource to register!\n"); return -ENODEV; } EXPORT_SYMBOL_GPL(acpi_power_resource_register_device); diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c index 27adb090bb3..ef98796b382 100644 --- a/drivers/acpi/proc.c +++ b/drivers/acpi/proc.c @@ -362,16 +362,13 @@ acpi_system_write_wakeup_device(struct file *file, struct list_head *node, *next; char strbuf[5]; char str[5] = ""; - unsigned int len = count; - if (len > 4) - len = 4; - if (len < 0) - return -EFAULT; + if (count > 4) + count = 4; - if (copy_from_user(strbuf, buffer, len)) + if (copy_from_user(strbuf, buffer, count)) return -EFAULT; - strbuf[len] = '\0'; + strbuf[count] = '\0'; sscanf(strbuf, "%s", str); mutex_lock(&acpi_device_lock); diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index bd4e5dca3ff..e83311bf1eb 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -44,6 +44,7 @@ #include <linux/moduleparam.h> #include <linux/cpuidle.h> #include <linux/slab.h> +#include <linux/acpi.h> #include <asm/io.h> #include <asm/cpu.h> @@ -282,7 +283,9 @@ static int acpi_processor_get_info(struct acpi_device *device) /* Declared with "Processor" statement; match ProcessorID */ status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "Evaluating processor object\n"); + dev_err(&device->dev, + "Failed to evaluate processor object (0x%x)\n", + status); return -ENODEV; } @@ -301,8 +304,9 @@ static int acpi_processor_get_info(struct acpi_device *device) status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID, NULL, &value); if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX - "Evaluating processor _UID [%#x]\n", status); + dev_err(&device->dev, + "Failed to evaluate processor _UID (0x%x)\n", + status); return -ENODEV; } device_declaration = 1; @@ -345,7 +349,7 @@ static int acpi_processor_get_info(struct acpi_device *device) if (!object.processor.pblk_address) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n")); else if (object.processor.pblk_length != 6) - printk(KERN_ERR PREFIX "Invalid PBLK length [%d]\n", + dev_err(&device->dev, "Invalid PBLK length [%d]\n", object.processor.pblk_length); else { pr->throttling.address = object.processor.pblk_address; @@ -430,8 +434,8 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb, * Initialize missing things */ if (pr->flags.need_hotplug_init) { - printk(KERN_INFO "Will online and init hotplugged " - "CPU: %d\n", pr->id); + pr_info("Will online and init hotplugged CPU: %d\n", + pr->id); WARN(acpi_processor_start(pr), "Failed to start CPU:" " %d\n", pr->id); pr->flags.need_hotplug_init = 0; @@ -492,14 +496,16 @@ static __ref int acpi_processor_start(struct acpi_processor *pr) &pr->cdev->device.kobj, "thermal_cooling"); if (result) { - printk(KERN_ERR PREFIX "Create sysfs link\n"); + dev_err(&device->dev, + "Failed to create sysfs link 'thermal_cooling'\n"); goto err_thermal_unregister; } result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj, "device"); if (result) { - printk(KERN_ERR PREFIX "Create sysfs link\n"); + dev_err(&pr->cdev->device, + "Failed to create sysfs link 'device'\n"); goto err_remove_sysfs_thermal; } @@ -561,8 +567,9 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) */ if (per_cpu(processor_device_array, pr->id) != NULL && per_cpu(processor_device_array, pr->id) != device) { - printk(KERN_WARNING "BIOS reported wrong ACPI id " - "for the processor\n"); + dev_warn(&device->dev, + "BIOS reported wrong ACPI id %d for the processor\n", + pr->id); result = -ENODEV; goto err_free_cpumask; } @@ -695,8 +702,8 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device) static void acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data) { - struct acpi_processor *pr; struct acpi_device *device = NULL; + struct acpi_eject_event *ej_event = NULL; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ int result; @@ -716,7 +723,7 @@ static void acpi_processor_hotplug_notify(acpi_handle handle, result = acpi_processor_device_add(handle, &device); if (result) { - printk(KERN_ERR PREFIX "Unable to add the device\n"); + acpi_handle_err(handle, "Unable to add the device\n"); break; } @@ -728,20 +735,29 @@ static void acpi_processor_hotplug_notify(acpi_handle handle, "received ACPI_NOTIFY_EJECT_REQUEST\n")); if (acpi_bus_get_device(handle, &device)) { - printk(KERN_ERR PREFIX - "Device don't exist, dropping EJECT\n"); + acpi_handle_err(handle, + "Device don't exist, dropping EJECT\n"); break; } - pr = acpi_driver_data(device); - if (!pr) { - printk(KERN_ERR PREFIX - "Driver data is NULL, dropping EJECT\n"); + if (!acpi_driver_data(device)) { + acpi_handle_err(handle, + "Driver data is NULL, dropping EJECT\n"); break; } - /* REVISIT: update when eject is supported */ - ost_code = ACPI_OST_SC_EJECT_NOT_SUPPORTED; - break; + ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); + if (!ej_event) { + acpi_handle_err(handle, "No memory, dropping EJECT\n"); + break; + } + + ej_event->handle = handle; + ej_event->event = ACPI_NOTIFY_EJECT_REQUEST; + acpi_os_hotplug_execute(acpi_bus_hot_remove_device, + (void *)ej_event); + + /* eject is performed asynchronously */ + return; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -841,7 +857,7 @@ static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr) * and do it when the CPU gets online the first time * TBD: Cleanup above functions and try to do this more elegant. */ - printk(KERN_INFO "CPU %d got hotplugged\n", pr->id); + pr_info("CPU %d got hotplugged\n", pr->id); pr->flags.need_hotplug_init = 1; return AE_OK; @@ -852,8 +868,22 @@ static int acpi_processor_handle_eject(struct acpi_processor *pr) if (cpu_online(pr->id)) cpu_down(pr->id); + get_online_cpus(); + /* + * The cpu might become online again at this point. So we check whether + * the cpu has been onlined or not. If the cpu became online, it means + * that someone wants to use the cpu. So acpi_processor_handle_eject() + * returns -EAGAIN. + */ + if (unlikely(cpu_online(pr->id))) { + put_online_cpus(); + pr_warn("Failed to remove CPU %d, because other task " + "brought the CPU back online\n", pr->id); + return -EAGAIN; + } arch_unregister_cpu(pr->id); acpi_unmap_lsapic(pr->id); + put_online_cpus(); return (0); } #else diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index e8086c72530..f1a5da44591 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -735,31 +735,18 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) static int acpi_idle_enter_c1(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - ktime_t kt1, kt2; - s64 idle_time; struct acpi_processor *pr; struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); pr = __this_cpu_read(processors); - dev->last_residency = 0; if (unlikely(!pr)) return -EINVAL; - local_irq_disable(); - - lapic_timer_state_broadcast(pr, cx, 1); - kt1 = ktime_get_real(); acpi_idle_do_entry(cx); - kt2 = ktime_get_real(); - idle_time = ktime_to_us(ktime_sub(kt2, kt1)); - - /* Update device last_residency*/ - dev->last_residency = (int)idle_time; - local_irq_enable(); lapic_timer_state_broadcast(pr, cx, 0); return index; @@ -806,19 +793,12 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, struct acpi_processor *pr; struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); - ktime_t kt1, kt2; - s64 idle_time_ns; - s64 idle_time; pr = __this_cpu_read(processors); - dev->last_residency = 0; if (unlikely(!pr)) return -EINVAL; - local_irq_disable(); - - if (cx->entry_method != ACPI_CSTATE_FFH) { current_thread_info()->status &= ~TS_POLLING; /* @@ -829,7 +809,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, if (unlikely(need_resched())) { current_thread_info()->status |= TS_POLLING; - local_irq_enable(); return -EINVAL; } } @@ -843,22 +822,12 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, if (cx->type == ACPI_STATE_C3) ACPI_FLUSH_CPU_CACHE(); - kt1 = ktime_get_real(); /* Tell the scheduler that we are going deep-idle: */ sched_clock_idle_sleep_event(); acpi_idle_do_entry(cx); - kt2 = ktime_get_real(); - idle_time_ns = ktime_to_ns(ktime_sub(kt2, kt1)); - idle_time = idle_time_ns; - do_div(idle_time, NSEC_PER_USEC); - /* Update device last_residency*/ - dev->last_residency = (int)idle_time; + sched_clock_idle_wakeup_event(0); - /* Tell the scheduler how much we idled: */ - sched_clock_idle_wakeup_event(idle_time_ns); - - local_irq_enable(); if (cx->entry_method != ACPI_CSTATE_FFH) current_thread_info()->status |= TS_POLLING; @@ -883,13 +852,8 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, struct acpi_processor *pr; struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); - ktime_t kt1, kt2; - s64 idle_time_ns; - s64 idle_time; - pr = __this_cpu_read(processors); - dev->last_residency = 0; if (unlikely(!pr)) return -EINVAL; @@ -899,16 +863,11 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, return drv->states[drv->safe_state_index].enter(dev, drv, drv->safe_state_index); } else { - local_irq_disable(); acpi_safe_halt(); - local_irq_enable(); return -EBUSY; } } - local_irq_disable(); - - if (cx->entry_method != ACPI_CSTATE_FFH) { current_thread_info()->status &= ~TS_POLLING; /* @@ -919,7 +878,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, if (unlikely(need_resched())) { current_thread_info()->status |= TS_POLLING; - local_irq_enable(); return -EINVAL; } } @@ -934,7 +892,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, */ lapic_timer_state_broadcast(pr, cx, 1); - kt1 = ktime_get_real(); /* * disable bus master * bm_check implies we need ARB_DIS @@ -965,18 +922,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, c3_cpu_count--; raw_spin_unlock(&c3_lock); } - kt2 = ktime_get_real(); - idle_time_ns = ktime_to_ns(ktime_sub(kt2, kt1)); - idle_time = idle_time_ns; - do_div(idle_time, NSEC_PER_USEC); - - /* Update device last_residency*/ - dev->last_residency = (int)idle_time; - /* Tell the scheduler how much we idled: */ - sched_clock_idle_wakeup_event(idle_time_ns); + sched_clock_idle_wakeup_event(0); - local_irq_enable(); if (cx->entry_method != ACPI_CSTATE_FFH) current_thread_info()->status |= TS_POLLING; @@ -987,6 +935,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, struct cpuidle_driver acpi_idle_driver = { .name = "acpi_idle", .owner = THIS_MODULE, + .en_core_tk_irqen = 1, }; /** diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c new file mode 100644 index 00000000000..a3868f6c222 --- /dev/null +++ b/drivers/acpi/resource.c @@ -0,0 +1,526 @@ +/* + * drivers/acpi/resource.c - ACPI device resources interpretation. + * + * Copyright (C) 2012, Intel Corp. + * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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. + * + * 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/acpi.h> +#include <linux/device.h> +#include <linux/export.h> +#include <linux/ioport.h> +#include <linux/slab.h> + +#ifdef CONFIG_X86 +#define valid_IRQ(i) (((i) != 0) && ((i) != 2)) +#else +#define valid_IRQ(i) (true) +#endif + +static unsigned long acpi_dev_memresource_flags(u64 len, u8 write_protect, + bool window) +{ + unsigned long flags = IORESOURCE_MEM; + + if (len == 0) + flags |= IORESOURCE_DISABLED; + + if (write_protect == ACPI_READ_WRITE_MEMORY) + flags |= IORESOURCE_MEM_WRITEABLE; + + if (window) + flags |= IORESOURCE_WINDOW; + + return flags; +} + +static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len, + u8 write_protect) +{ + res->start = start; + res->end = start + len - 1; + res->flags = acpi_dev_memresource_flags(len, write_protect, false); +} + +/** + * acpi_dev_resource_memory - Extract ACPI memory resource information. + * @ares: Input ACPI resource object. + * @res: Output generic resource object. + * + * Check if the given ACPI resource object represents a memory resource and + * if that's the case, use the information in it to populate the generic + * resource object pointed to by @res. + */ +bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res) +{ + struct acpi_resource_memory24 *memory24; + struct acpi_resource_memory32 *memory32; + struct acpi_resource_fixed_memory32 *fixed_memory32; + + switch (ares->type) { + case ACPI_RESOURCE_TYPE_MEMORY24: + memory24 = &ares->data.memory24; + acpi_dev_get_memresource(res, memory24->minimum, + memory24->address_length, + memory24->write_protect); + break; + case ACPI_RESOURCE_TYPE_MEMORY32: + memory32 = &ares->data.memory32; + acpi_dev_get_memresource(res, memory32->minimum, + memory32->address_length, + memory32->write_protect); + break; + case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: + fixed_memory32 = &ares->data.fixed_memory32; + acpi_dev_get_memresource(res, fixed_memory32->address, + fixed_memory32->address_length, + fixed_memory32->write_protect); + break; + default: + return false; + } + return true; +} +EXPORT_SYMBOL_GPL(acpi_dev_resource_memory); + +static unsigned int acpi_dev_ioresource_flags(u64 start, u64 end, u8 io_decode, + bool window) +{ + int flags = IORESOURCE_IO; + + if (io_decode == ACPI_DECODE_16) + flags |= IORESOURCE_IO_16BIT_ADDR; + + if (start > end || end >= 0x10003) + flags |= IORESOURCE_DISABLED; + + if (window) + flags |= IORESOURCE_WINDOW; + + return flags; +} + +static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len, + u8 io_decode) +{ + u64 end = start + len - 1; + + res->start = start; + res->end = end; + res->flags = acpi_dev_ioresource_flags(start, end, io_decode, false); +} + +/** + * acpi_dev_resource_io - Extract ACPI I/O resource information. + * @ares: Input ACPI resource object. + * @res: Output generic resource object. + * + * Check if the given ACPI resource object represents an I/O resource and + * if that's the case, use the information in it to populate the generic + * resource object pointed to by @res. + */ +bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res) +{ + struct acpi_resource_io *io; + struct acpi_resource_fixed_io *fixed_io; + + switch (ares->type) { + case ACPI_RESOURCE_TYPE_IO: + io = &ares->data.io; + acpi_dev_get_ioresource(res, io->minimum, + io->address_length, + io->io_decode); + break; + case ACPI_RESOURCE_TYPE_FIXED_IO: + fixed_io = &ares->data.fixed_io; + acpi_dev_get_ioresource(res, fixed_io->address, + fixed_io->address_length, + ACPI_DECODE_10); + break; + default: + return false; + } + return true; +} +EXPORT_SYMBOL_GPL(acpi_dev_resource_io); + +/** + * acpi_dev_resource_address_space - Extract ACPI address space information. + * @ares: Input ACPI resource object. + * @res: Output generic resource object. + * + * Check if the given ACPI resource object represents an address space resource + * and if that's the case, use the information in it to populate the generic + * resource object pointed to by @res. + */ +bool acpi_dev_resource_address_space(struct acpi_resource *ares, + struct resource *res) +{ + acpi_status status; + struct acpi_resource_address64 addr; + bool window; + u64 len; + u8 io_decode; + + switch (ares->type) { + case ACPI_RESOURCE_TYPE_ADDRESS16: + case ACPI_RESOURCE_TYPE_ADDRESS32: + case ACPI_RESOURCE_TYPE_ADDRESS64: + break; + default: + return false; + } + + status = acpi_resource_to_address64(ares, &addr); + if (ACPI_FAILURE(status)) + return true; + + res->start = addr.minimum; + res->end = addr.maximum; + window = addr.producer_consumer == ACPI_PRODUCER; + + switch(addr.resource_type) { + case ACPI_MEMORY_RANGE: + len = addr.maximum - addr.minimum + 1; + res->flags = acpi_dev_memresource_flags(len, + addr.info.mem.write_protect, + window); + break; + case ACPI_IO_RANGE: + io_decode = addr.granularity == 0xfff ? + ACPI_DECODE_10 : ACPI_DECODE_16; + res->flags = acpi_dev_ioresource_flags(addr.minimum, + addr.maximum, + io_decode, window); + break; + case ACPI_BUS_NUMBER_RANGE: + res->flags = IORESOURCE_BUS; + break; + default: + res->flags = 0; + } + + return true; +} +EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space); + +/** + * acpi_dev_resource_ext_address_space - Extract ACPI address space information. + * @ares: Input ACPI resource object. + * @res: Output generic resource object. + * + * Check if the given ACPI resource object represents an extended address space + * resource and if that's the case, use the information in it to populate the + * generic resource object pointed to by @res. + */ +bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, + struct resource *res) +{ + struct acpi_resource_extended_address64 *ext_addr; + bool window; + u64 len; + u8 io_decode; + + if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64) + return false; + + ext_addr = &ares->data.ext_address64; + + res->start = ext_addr->minimum; + res->end = ext_addr->maximum; + window = ext_addr->producer_consumer == ACPI_PRODUCER; + + switch(ext_addr->resource_type) { + case ACPI_MEMORY_RANGE: + len = ext_addr->maximum - ext_addr->minimum + 1; + res->flags = acpi_dev_memresource_flags(len, + ext_addr->info.mem.write_protect, + window); + break; + case ACPI_IO_RANGE: + io_decode = ext_addr->granularity == 0xfff ? + ACPI_DECODE_10 : ACPI_DECODE_16; + res->flags = acpi_dev_ioresource_flags(ext_addr->minimum, + ext_addr->maximum, + io_decode, window); + break; + case ACPI_BUS_NUMBER_RANGE: + res->flags = IORESOURCE_BUS; + break; + default: + res->flags = 0; + } + + return true; +} +EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space); + +/** + * acpi_dev_irq_flags - Determine IRQ resource flags. + * @triggering: Triggering type as provided by ACPI. + * @polarity: Interrupt polarity as provided by ACPI. + * @shareable: Whether or not the interrupt is shareable. + */ +unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable) +{ + unsigned long flags; + + if (triggering == ACPI_LEVEL_SENSITIVE) + flags = polarity == ACPI_ACTIVE_LOW ? + IORESOURCE_IRQ_LOWLEVEL : IORESOURCE_IRQ_HIGHLEVEL; + else + flags = polarity == ACPI_ACTIVE_LOW ? + IORESOURCE_IRQ_LOWEDGE : IORESOURCE_IRQ_HIGHEDGE; + + if (shareable == ACPI_SHARED) + flags |= IORESOURCE_IRQ_SHAREABLE; + + return flags | IORESOURCE_IRQ; +} +EXPORT_SYMBOL_GPL(acpi_dev_irq_flags); + +static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi) +{ + res->start = gsi; + res->end = gsi; + res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED; +} + +static void acpi_dev_get_irqresource(struct resource *res, u32 gsi, + u8 triggering, u8 polarity, u8 shareable) +{ + int irq, p, t; + + if (!valid_IRQ(gsi)) { + acpi_dev_irqresource_disabled(res, gsi); + return; + } + + /* + * In IO-APIC mode, use overrided attribute. Two reasons: + * 1. BIOS bug in DSDT + * 2. BIOS uses IO-APIC mode Interrupt Source Override + */ + if (!acpi_get_override_irq(gsi, &t, &p)) { + u8 trig = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE; + u8 pol = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; + + if (triggering != trig || polarity != pol) { + pr_warning("ACPI: IRQ %d override to %s, %s\n", gsi, + t ? "edge" : "level", p ? "low" : "high"); + triggering = trig; + polarity = pol; + } + } + + res->flags = acpi_dev_irq_flags(triggering, polarity, shareable); + irq = acpi_register_gsi(NULL, gsi, triggering, polarity); + if (irq >= 0) { + res->start = irq; + res->end = irq; + } else { + acpi_dev_irqresource_disabled(res, gsi); + } +} + +/** + * acpi_dev_resource_interrupt - Extract ACPI interrupt resource information. + * @ares: Input ACPI resource object. + * @index: Index into the array of GSIs represented by the resource. + * @res: Output generic resource object. + * + * Check if the given ACPI resource object represents an interrupt resource + * and @index does not exceed the resource's interrupt count (true is returned + * in that case regardless of the results of the other checks)). If that's the + * case, register the GSI corresponding to @index from the array of interrupts + * represented by the resource and populate the generic resource object pointed + * to by @res accordingly. If the registration of the GSI is not successful, + * IORESOURCE_DISABLED will be set it that object's flags. + */ +bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, + struct resource *res) +{ + struct acpi_resource_irq *irq; + struct acpi_resource_extended_irq *ext_irq; + + switch (ares->type) { + case ACPI_RESOURCE_TYPE_IRQ: + /* + * Per spec, only one interrupt per descriptor is allowed in + * _CRS, but some firmware violates this, so parse them all. + */ + irq = &ares->data.irq; + if (index >= irq->interrupt_count) { + acpi_dev_irqresource_disabled(res, 0); + return false; + } + acpi_dev_get_irqresource(res, irq->interrupts[index], + irq->triggering, irq->polarity, + irq->sharable); + break; + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + ext_irq = &ares->data.extended_irq; + if (index >= ext_irq->interrupt_count) { + acpi_dev_irqresource_disabled(res, 0); + return false; + } + acpi_dev_get_irqresource(res, ext_irq->interrupts[index], + ext_irq->triggering, ext_irq->polarity, + ext_irq->sharable); + break; + default: + return false; + } + + return true; +} +EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt); + +/** + * acpi_dev_free_resource_list - Free resource from %acpi_dev_get_resources(). + * @list: The head of the resource list to free. + */ +void acpi_dev_free_resource_list(struct list_head *list) +{ + struct resource_list_entry *rentry, *re; + + list_for_each_entry_safe(rentry, re, list, node) { + list_del(&rentry->node); + kfree(rentry); + } +} +EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list); + +struct res_proc_context { + struct list_head *list; + int (*preproc)(struct acpi_resource *, void *); + void *preproc_data; + int count; + int error; +}; + +static acpi_status acpi_dev_new_resource_entry(struct resource *r, + struct res_proc_context *c) +{ + struct resource_list_entry *rentry; + + rentry = kmalloc(sizeof(*rentry), GFP_KERNEL); + if (!rentry) { + c->error = -ENOMEM; + return AE_NO_MEMORY; + } + rentry->res = *r; + list_add_tail(&rentry->node, c->list); + c->count++; + return AE_OK; +} + +static acpi_status acpi_dev_process_resource(struct acpi_resource *ares, + void *context) +{ + struct res_proc_context *c = context; + struct resource r; + int i; + + if (c->preproc) { + int ret; + + ret = c->preproc(ares, c->preproc_data); + if (ret < 0) { + c->error = ret; + return AE_CTRL_TERMINATE; + } else if (ret > 0) { + return AE_OK; + } + } + + memset(&r, 0, sizeof(r)); + + if (acpi_dev_resource_memory(ares, &r) + || acpi_dev_resource_io(ares, &r) + || acpi_dev_resource_address_space(ares, &r) + || acpi_dev_resource_ext_address_space(ares, &r)) + return acpi_dev_new_resource_entry(&r, c); + + for (i = 0; acpi_dev_resource_interrupt(ares, i, &r); i++) { + acpi_status status; + + status = acpi_dev_new_resource_entry(&r, c); + if (ACPI_FAILURE(status)) + return status; + } + + return AE_OK; +} + +/** + * acpi_dev_get_resources - Get current resources of a device. + * @adev: ACPI device node to get the resources for. + * @list: Head of the resultant list of resources (must be empty). + * @preproc: The caller's preprocessing routine. + * @preproc_data: Pointer passed to the caller's preprocessing routine. + * + * Evaluate the _CRS method for the given device node and process its output by + * (1) executing the @preproc() rountine provided by the caller, passing the + * resource pointer and @preproc_data to it as arguments, for each ACPI resource + * returned and (2) converting all of the returned ACPI resources into struct + * resource objects if possible. If the return value of @preproc() in step (1) + * is different from 0, step (2) is not applied to the given ACPI resource and + * if that value is negative, the whole processing is aborted and that value is + * returned as the final error code. + * + * The resultant struct resource objects are put on the list pointed to by + * @list, that must be empty initially, as members of struct resource_list_entry + * objects. Callers of this routine should use %acpi_dev_free_resource_list() to + * free that list. + * + * The number of resources in the output list is returned on success, an error + * code reflecting the error condition is returned otherwise. + */ +int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, + int (*preproc)(struct acpi_resource *, void *), + void *preproc_data) +{ + struct res_proc_context c; + acpi_handle not_used; + acpi_status status; + + if (!adev || !adev->handle || !list_empty(list)) + return -EINVAL; + + status = acpi_get_handle(adev->handle, METHOD_NAME__CRS, ¬_used); + if (ACPI_FAILURE(status)) + return 0; + + c.list = list; + c.preproc = preproc; + c.preproc_data = preproc_data; + c.count = 0; + c.error = 0; + status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS, + acpi_dev_process_resource, &c); + if (ACPI_FAILURE(status)) { + acpi_dev_free_resource_list(list); + return c.error ? c.error : -EIO; + } + + return c.count; +} +EXPORT_SYMBOL_GPL(acpi_dev_get_resources); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 1fcb8678665..53502d1bbf2 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -29,6 +29,27 @@ extern struct acpi_device *acpi_root; static const char *dummy_hid = "device"; +/* + * The following ACPI IDs are known to be suitable for representing as + * platform devices. + */ +static const struct acpi_device_id acpi_platform_device_ids[] = { + + { "PNP0D40" }, + + /* Haswell LPSS devices */ + { "INT33C0", 0 }, + { "INT33C1", 0 }, + { "INT33C2", 0 }, + { "INT33C3", 0 }, + { "INT33C4", 0 }, + { "INT33C5", 0 }, + { "INT33C6", 0 }, + { "INT33C7", 0 }, + + { } +}; + static LIST_HEAD(acpi_device_list); static LIST_HEAD(acpi_bus_id_list); DEFINE_MUTEX(acpi_device_lock); @@ -97,6 +118,7 @@ void acpi_bus_hot_remove_device(void *context) struct acpi_eject_event *ej_event = (struct acpi_eject_event *) context; struct acpi_device *device; acpi_handle handle = ej_event->handle; + acpi_handle temp; struct acpi_object_list arg_list; union acpi_object arg; acpi_status status = AE_OK; @@ -117,13 +139,16 @@ void acpi_bus_hot_remove_device(void *context) goto err_out; } + /* device has been freed */ + device = NULL; + /* power off device */ status = acpi_evaluate_object(handle, "_PS3", NULL, NULL); if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) printk(KERN_WARNING PREFIX "Power-off device failed\n"); - if (device->flags.lockable) { + if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) { arg_list.count = 1; arg_list.pointer = &arg; arg.type = ACPI_TYPE_INTEGER; @@ -157,6 +182,7 @@ err_out: kfree(context); return; } +EXPORT_SYMBOL(acpi_bus_hot_remove_device); static ssize_t acpi_eject_store(struct device *d, struct device_attribute *attr, @@ -216,6 +242,25 @@ acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *bu } static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL); +static ssize_t acpi_device_uid_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + + return sprintf(buf, "%s\n", acpi_dev->pnp.unique_id); +} +static DEVICE_ATTR(uid, 0444, acpi_device_uid_show, NULL); + +static ssize_t acpi_device_adr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + + return sprintf(buf, "0x%08x\n", + (unsigned int)(acpi_dev->pnp.bus_address)); +} +static DEVICE_ATTR(adr, 0444, acpi_device_adr_show, NULL); + static ssize_t acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) { struct acpi_device *acpi_dev = to_acpi_device(dev); @@ -259,11 +304,21 @@ static ssize_t description_show(struct device *dev, } static DEVICE_ATTR(description, 0444, description_show, NULL); +static ssize_t +acpi_device_sun_show(struct device *dev, struct device_attribute *attr, + char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); + + return sprintf(buf, "%lu\n", acpi_dev->pnp.sun); +} +static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL); + static int acpi_device_setup_files(struct acpi_device *dev) { struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; acpi_status status; acpi_handle temp; + unsigned long long sun; int result = 0; /* @@ -300,6 +355,21 @@ static int acpi_device_setup_files(struct acpi_device *dev) goto end; } + if (dev->flags.bus_address) + result = device_create_file(&dev->dev, &dev_attr_adr); + if (dev->pnp.unique_id) + result = device_create_file(&dev->dev, &dev_attr_uid); + + status = acpi_evaluate_integer(dev->handle, "_SUN", NULL, &sun); + if (ACPI_SUCCESS(status)) { + dev->pnp.sun = (unsigned long)sun; + result = device_create_file(&dev->dev, &dev_attr_sun); + if (result) + goto end; + } else { + dev->pnp.sun = (unsigned long)-1; + } + /* * If device has _EJ0, 'eject' file is created that is used to trigger * hot-removal function from userland. @@ -331,6 +401,14 @@ static void acpi_device_remove_files(struct acpi_device *dev) if (ACPI_SUCCESS(status)) device_remove_file(&dev->dev, &dev_attr_eject); + status = acpi_get_handle(dev->handle, "_SUN", &temp); + if (ACPI_SUCCESS(status)) + device_remove_file(&dev->dev, &dev_attr_sun); + + if (dev->pnp.unique_id) + device_remove_file(&dev->dev, &dev_attr_uid); + if (dev->flags.bus_address) + device_remove_file(&dev->dev, &dev_attr_adr); device_remove_file(&dev->dev, &dev_attr_modalias); device_remove_file(&dev->dev, &dev_attr_hid); if (dev->handle) @@ -340,8 +418,8 @@ static void acpi_device_remove_files(struct acpi_device *dev) ACPI Bus operations -------------------------------------------------------------------------- */ -int acpi_match_device_ids(struct acpi_device *device, - const struct acpi_device_id *ids) +static const struct acpi_device_id *__acpi_match_device( + struct acpi_device *device, const struct acpi_device_id *ids) { const struct acpi_device_id *id; struct acpi_hardware_id *hwid; @@ -351,14 +429,44 @@ int acpi_match_device_ids(struct acpi_device *device, * driver for it. */ if (!device->status.present) - return -ENODEV; + return NULL; for (id = ids; id->id[0]; id++) list_for_each_entry(hwid, &device->pnp.ids, list) if (!strcmp((char *) id->id, hwid->id)) - return 0; + return id; - return -ENOENT; + return NULL; +} + +/** + * acpi_match_device - Match a struct device against a given list of ACPI IDs + * @ids: Array of struct acpi_device_id object to match against. + * @dev: The device structure to match. + * + * Check if @dev has a valid ACPI handle and if there is a struct acpi_device + * object for that handle and use that object to match against a given list of + * device IDs. + * + * Return a pointer to the first matching ID on success or %NULL on failure. + */ +const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, + const struct device *dev) +{ + struct acpi_device *adev; + + if (!ids || !ACPI_HANDLE(dev) + || ACPI_FAILURE(acpi_bus_get_device(ACPI_HANDLE(dev), &adev))) + return NULL; + + return __acpi_match_device(adev, ids); +} +EXPORT_SYMBOL_GPL(acpi_match_device); + +int acpi_match_device_ids(struct acpi_device *device, + const struct acpi_device_id *ids) +{ + return __acpi_match_device(device, ids) ? 0 : -ENOENT; } EXPORT_SYMBOL(acpi_match_device_ids); @@ -377,6 +485,7 @@ static void acpi_device_release(struct device *dev) struct acpi_device *acpi_dev = to_acpi_device(dev); acpi_free_ids(acpi_dev); + kfree(acpi_dev->pnp.unique_id); kfree(acpi_dev); } @@ -859,8 +968,8 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, static void acpi_bus_set_run_wake_flags(struct acpi_device *device) { struct acpi_device_id button_device_ids[] = { - {"PNP0C0D", 0}, {"PNP0C0C", 0}, + {"PNP0C0D", 0}, {"PNP0C0E", 0}, {"", 0}, }; @@ -872,6 +981,11 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device) /* Power button, Lid switch always enable wakeup */ if (!acpi_match_device_ids(device, button_device_ids)) { device->wakeup.flags.run_wake = 1; + if (!acpi_match_device_ids(device, &button_device_ids[1])) { + /* Do not use Lid/sleep button for S5 wakeup */ + if (device->wakeup.sleep_state == ACPI_STATE_S5) + device->wakeup.sleep_state = ACPI_STATE_S4; + } device_set_wakeup_capable(&device->dev, true); return; } @@ -965,8 +1079,10 @@ static int acpi_bus_get_power_flags(struct acpi_device *device) * D3hot is only valid if _PR3 present. */ if (ps->resources.count || - (ps->flags.explicit_set && i < ACPI_STATE_D3_HOT)) + (ps->flags.explicit_set && i < ACPI_STATE_D3_HOT)) { ps->flags.valid = 1; + ps->flags.os_accessible = 1; + } ps->power = -1; /* Unknown - driver assigned */ ps->latency = -1; /* Unknown - driver assigned */ @@ -982,6 +1098,11 @@ static int acpi_bus_get_power_flags(struct acpi_device *device) if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set) device->power.states[ACPI_STATE_D3_COLD].flags.explicit_set = 1; + /* Presence of _PS3 or _PRx means we can put the device into D3 cold */ + if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set || + device->power.flags.power_resources) + device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible = 1; + acpi_bus_init_power(device); return 0; @@ -1013,11 +1134,6 @@ static int acpi_bus_get_flags(struct acpi_device *device) device->flags.ejectable = 1; } - /* Presence of _LCK indicates 'lockable' */ - status = acpi_get_handle(device->handle, "_LCK", &temp); - if (ACPI_SUCCESS(status)) - device->flags.lockable = 1; - /* Power resources cannot be power manageable. */ if (device->device_type == ACPI_BUS_TYPE_POWER) return 0; @@ -1185,7 +1301,7 @@ static void acpi_device_set_id(struct acpi_device *device) { acpi_status status; struct acpi_device_info *info; - struct acpica_device_id_list *cid_list; + struct acpi_pnp_device_id_list *cid_list; int i; switch (device->device_type) { @@ -1212,6 +1328,9 @@ static void acpi_device_set_id(struct acpi_device *device) device->pnp.bus_address = info->address; device->flags.bus_address = 1; } + if (info->valid & ACPI_VALID_UID) + device->pnp.unique_id = kstrdup(info->unique_id.string, + GFP_KERNEL); kfree(info); @@ -1483,8 +1602,13 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, */ device = NULL; acpi_bus_get_device(handle, &device); - if (ops->acpi_op_add && !device) + if (ops->acpi_op_add && !device) { acpi_add_single_object(&device, handle, type, sta, ops); + /* Is the device a known good platform device? */ + if (device + && !acpi_match_device_ids(device, acpi_platform_device_ids)) + acpi_create_platform_device(device); + } if (!device) return AE_CTRL_DEPTH; diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index fdcdbb65291..2fcc67d34b1 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -18,7 +18,6 @@ #include <linux/reboot.h> #include <linux/acpi.h> #include <linux/module.h> -#include <linux/pm_runtime.h> #include <asm/io.h> @@ -81,6 +80,12 @@ static int acpi_sleep_prepare(u32 acpi_state) #ifdef CONFIG_ACPI_SLEEP static u32 acpi_target_sleep_state = ACPI_STATE_S0; + +u32 acpi_target_system_state(void) +{ + return acpi_target_sleep_state; +} + static bool pwr_btn_event_pending; /* @@ -98,6 +103,21 @@ void __init acpi_nvs_nosave(void) } /* + * The ACPI specification wants us to save NVS memory regions during hibernation + * but says nothing about saving NVS during S3. Not all versions of Windows + * save NVS on S3 suspend either, and it is clear that not all systems need + * NVS to be saved at S3 time. To improve suspend/resume time, allow the + * user to disable saving NVS on S3 if their system does not require it, but + * continue to save/restore NVS for S4 as specified. + */ +static bool nvs_nosave_s3; + +void __init acpi_nvs_nosave_s3(void) +{ + nvs_nosave_s3 = true; +} + +/* * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the * user to request that behavior by using the 'acpi_old_suspend_ordering' * kernel command line option that causes the following variable to be set. @@ -109,6 +129,180 @@ void __init acpi_old_suspend_ordering(void) old_suspend_ordering = true; } +static int __init init_old_suspend_ordering(const struct dmi_system_id *d) +{ + acpi_old_suspend_ordering(); + return 0; +} + +static int __init init_nvs_nosave(const struct dmi_system_id *d) +{ + acpi_nvs_nosave(); + return 0; +} + +static struct dmi_system_id __initdata acpisleep_dmi_table[] = { + { + .callback = init_old_suspend_ordering, + .ident = "Abit KN9 (nForce4 variant)", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "http://www.abit.com.tw/"), + DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"), + }, + }, + { + .callback = init_old_suspend_ordering, + .ident = "HP xw4600 Workstation", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP xw4600 Workstation"), + }, + }, + { + .callback = init_old_suspend_ordering, + .ident = "Asus Pundit P1-AH2 (M2N8L motherboard)", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "M2N8L"), + }, + }, + { + .callback = init_old_suspend_ordering, + .ident = "Panasonic CF51-2L", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, + "Matsushita Electric Industrial Co.,Ltd."), + DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-FW21E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21E"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VPCEB17FX", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB17FX"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-SR11M", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR11M"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Everex StepNote Series", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Everex Systems, Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Everex StepNote Series"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VPCEB1Z1E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1Z1E"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-NW130D", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NW130D"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VPCCW29FX", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VPCCW29FX"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Averatec AV1020-ED2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AVERATEC"), + DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"), + }, + }, + { + .callback = init_old_suspend_ordering, + .ident = "Asus A8N-SLI DELUXE", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI DELUXE"), + }, + }, + { + .callback = init_old_suspend_ordering, + .ident = "Asus A8N-SLI Premium", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI Premium"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-SR26GN_P", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR26GN_P"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VPCEB1S1E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1S1E"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Sony Vaio VGN-FW520F", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW520F"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Asus K54C", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "K54C"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Asus K54HR", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "K54HR"), + }, + }, + {}, +}; + +static void acpi_sleep_dmi_check(void) +{ + dmi_check_system(acpisleep_dmi_table); +} + /** * acpi_pm_freeze - Disable the GPEs and suspend EC transactions. */ @@ -224,6 +418,7 @@ static void acpi_pm_end(void) } #else /* !CONFIG_ACPI_SLEEP */ #define acpi_target_sleep_state ACPI_STATE_S0 +static inline void acpi_sleep_dmi_check(void) {} #endif /* CONFIG_ACPI_SLEEP */ #ifdef CONFIG_SUSPEND @@ -243,7 +438,7 @@ static int acpi_suspend_begin(suspend_state_t pm_state) u32 acpi_state = acpi_suspend_states[pm_state]; int error = 0; - error = nvs_nosave ? 0 : suspend_nvs_alloc(); + error = (nvs_nosave || nvs_nosave_s3) ? 0 : suspend_nvs_alloc(); if (error) return error; @@ -382,167 +577,6 @@ static const struct platform_suspend_ops acpi_suspend_ops_old = { .end = acpi_pm_end, .recover = acpi_pm_finish, }; - -static int __init init_old_suspend_ordering(const struct dmi_system_id *d) -{ - old_suspend_ordering = true; - return 0; -} - -static int __init init_nvs_nosave(const struct dmi_system_id *d) -{ - acpi_nvs_nosave(); - return 0; -} - -static struct dmi_system_id __initdata acpisleep_dmi_table[] = { - { - .callback = init_old_suspend_ordering, - .ident = "Abit KN9 (nForce4 variant)", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "http://www.abit.com.tw/"), - DMI_MATCH(DMI_BOARD_NAME, "KN9 Series(NF-CK804)"), - }, - }, - { - .callback = init_old_suspend_ordering, - .ident = "HP xw4600 Workstation", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP xw4600 Workstation"), - }, - }, - { - .callback = init_old_suspend_ordering, - .ident = "Asus Pundit P1-AH2 (M2N8L motherboard)", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek Computer INC."), - DMI_MATCH(DMI_BOARD_NAME, "M2N8L"), - }, - }, - { - .callback = init_old_suspend_ordering, - .ident = "Panasonic CF51-2L", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, - "Matsushita Electric Industrial Co.,Ltd."), - DMI_MATCH(DMI_BOARD_NAME, "CF51-2L"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VGN-FW21E", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21E"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VPCEB17FX", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB17FX"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VGN-SR11M", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR11M"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Everex StepNote Series", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Everex Systems, Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Everex StepNote Series"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VPCEB1Z1E", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VPCEB1Z1E"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VGN-NW130D", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NW130D"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VPCCW29FX", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VPCCW29FX"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Averatec AV1020-ED2", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "AVERATEC"), - DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"), - }, - }, - { - .callback = init_old_suspend_ordering, - .ident = "Asus A8N-SLI DELUXE", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), - DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI DELUXE"), - }, - }, - { - .callback = init_old_suspend_ordering, - .ident = "Asus A8N-SLI Premium", - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), - DMI_MATCH(DMI_BOARD_NAME, "A8N-SLI Premium"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VGN-SR26GN_P", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR26GN_P"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Sony Vaio VGN-FW520F", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW520F"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Asus K54C", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "K54C"), - }, - }, - { - .callback = init_nvs_nosave, - .ident = "Asus K54HR", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "K54HR"), - }, - }, - {}, -}; #endif /* CONFIG_SUSPEND */ #ifdef CONFIG_HIBERNATION @@ -681,177 +715,6 @@ int acpi_suspend(u32 acpi_state) return -EINVAL; } -#ifdef CONFIG_PM -/** - * acpi_pm_device_sleep_state - return preferred power state of ACPI device - * in the system sleep state given by %acpi_target_sleep_state - * @dev: device to examine; its driver model wakeup flags control - * whether it should be able to wake up the system - * @d_min_p: used to store the upper limit of allowed states range - * @d_max_in: specify the lowest allowed states - * Return value: preferred power state of the device on success, -ENODEV - * (ie. if there's no 'struct acpi_device' for @dev) or -EINVAL on failure - * - * Find the lowest power (highest number) ACPI device power state that - * device @dev can be in while the system is in the sleep state represented - * by %acpi_target_sleep_state. If @wake is nonzero, the device should be - * able to wake up the system from this sleep state. If @d_min_p is set, - * the highest power (lowest number) device power state of @dev allowed - * in this system sleep state is stored at the location pointed to by it. - * - * The caller must ensure that @dev is valid before using this function. - * The caller is also responsible for figuring out if the device is - * supposed to be able to wake up the system and passing this information - * via @wake. - */ - -int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in) -{ - acpi_handle handle = DEVICE_ACPI_HANDLE(dev); - struct acpi_device *adev; - char acpi_method[] = "_SxD"; - unsigned long long d_min, d_max; - - if (d_max_in < ACPI_STATE_D0 || d_max_in > ACPI_STATE_D3) - return -EINVAL; - if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { - printk(KERN_DEBUG "ACPI handle has no context!\n"); - return -ENODEV; - } - - acpi_method[2] = '0' + acpi_target_sleep_state; - /* - * If the sleep state is S0, the lowest limit from ACPI is D3, - * but if the device has _S0W, we will use the value from _S0W - * as the lowest limit from ACPI. Finally, we will constrain - * the lowest limit with the specified one. - */ - d_min = ACPI_STATE_D0; - d_max = ACPI_STATE_D3; - - /* - * If present, _SxD methods return the minimum D-state (highest power - * state) we can use for the corresponding S-states. Otherwise, the - * minimum D-state is D0 (ACPI 3.x). - * - * NOTE: We rely on acpi_evaluate_integer() not clobbering the integer - * provided -- that's our fault recovery, we ignore retval. - */ - if (acpi_target_sleep_state > ACPI_STATE_S0) - acpi_evaluate_integer(handle, acpi_method, NULL, &d_min); - - /* - * If _PRW says we can wake up the system from the target sleep state, - * the D-state returned by _SxD is sufficient for that (we assume a - * wakeup-aware driver if wake is set). Still, if _SxW exists - * (ACPI 3.x), it should return the maximum (lowest power) D-state that - * can wake the system. _S0W may be valid, too. - */ - if (acpi_target_sleep_state == ACPI_STATE_S0 || - (device_may_wakeup(dev) && adev->wakeup.flags.valid && - adev->wakeup.sleep_state >= acpi_target_sleep_state)) { - acpi_status status; - - acpi_method[3] = 'W'; - status = acpi_evaluate_integer(handle, acpi_method, NULL, - &d_max); - if (ACPI_FAILURE(status)) { - if (acpi_target_sleep_state != ACPI_STATE_S0 || - status != AE_NOT_FOUND) - d_max = d_min; - } else if (d_max < d_min) { - /* Warn the user of the broken DSDT */ - printk(KERN_WARNING "ACPI: Wrong value from %s\n", - acpi_method); - /* Sanitize it */ - d_min = d_max; - } - } - - if (d_max_in < d_min) - return -EINVAL; - if (d_min_p) - *d_min_p = d_min; - /* constrain d_max with specified lowest limit (max number) */ - if (d_max > d_max_in) { - for (d_max = d_max_in; d_max > d_min; d_max--) { - if (adev->power.states[d_max].flags.valid) - break; - } - } - return d_max; -} -EXPORT_SYMBOL(acpi_pm_device_sleep_state); -#endif /* CONFIG_PM */ - -#ifdef CONFIG_PM_SLEEP -/** - * acpi_pm_device_run_wake - Enable/disable wake-up for given device. - * @phys_dev: Device to enable/disable the platform to wake-up the system for. - * @enable: Whether enable or disable the wake-up functionality. - * - * Find the ACPI device object corresponding to @pci_dev and try to - * enable/disable the GPE associated with it. - */ -int acpi_pm_device_run_wake(struct device *phys_dev, bool enable) -{ - struct acpi_device *dev; - acpi_handle handle; - - if (!device_run_wake(phys_dev)) - return -EINVAL; - - handle = DEVICE_ACPI_HANDLE(phys_dev); - if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &dev))) { - dev_dbg(phys_dev, "ACPI handle has no context in %s!\n", - __func__); - return -ENODEV; - } - - if (enable) { - acpi_enable_wakeup_device_power(dev, ACPI_STATE_S0); - acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); - } else { - acpi_disable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number); - acpi_disable_wakeup_device_power(dev); - } - - return 0; -} -EXPORT_SYMBOL(acpi_pm_device_run_wake); - -/** - * acpi_pm_device_sleep_wake - enable or disable the system wake-up - * capability of given device - * @dev: device to handle - * @enable: 'true' - enable, 'false' - disable the wake-up capability - */ -int acpi_pm_device_sleep_wake(struct device *dev, bool enable) -{ - acpi_handle handle; - struct acpi_device *adev; - int error; - - if (!device_can_wakeup(dev)) - return -EINVAL; - - handle = DEVICE_ACPI_HANDLE(dev); - if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) { - dev_dbg(dev, "ACPI handle has no context in %s!\n", __func__); - return -ENODEV; - } - - error = enable ? - acpi_enable_wakeup_device_power(adev, acpi_target_sleep_state) : - acpi_disable_wakeup_device_power(adev); - if (!error) - dev_info(dev, "wake-up capability %s by ACPI\n", - enable ? "enabled" : "disabled"); - - return error; -} -#endif /* CONFIG_PM_SLEEP */ - static void acpi_power_off_prepare(void) { /* Prepare to power off the system */ @@ -873,13 +736,13 @@ int __init acpi_sleep_init(void) u8 type_a, type_b; #ifdef CONFIG_SUSPEND int i = 0; - - dmi_check_system(acpisleep_dmi_table); #endif if (acpi_disabled) return 0; + acpi_sleep_dmi_check(); + sleep_states[ACPI_STATE_S0] = 1; printk(KERN_INFO PREFIX "(supports S0"); diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 7c3f98ba4af..ea61ca9129c 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -476,7 +476,7 @@ static void fixed_event_count(u32 event_number) return; } -static void acpi_gbl_event_handler(u32 event_type, acpi_handle device, +static void acpi_global_event_handler(u32 event_type, acpi_handle device, u32 event_number, void *context) { if (event_type == ACPI_EVENT_TYPE_GPE) @@ -638,7 +638,7 @@ void acpi_irq_stats_init(void) if (all_counters == NULL) goto fail; - status = acpi_install_global_event_handler(acpi_gbl_event_handler, NULL); + status = acpi_install_global_event_handler(acpi_global_event_handler, NULL); if (ACPI_FAILURE(status)) goto fail; diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 804204d4199..6e8cc16b54c 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -984,6 +984,38 @@ static void acpi_thermal_notify(struct acpi_device *device, u32 event) } } +/* + * On some platforms, the AML code has dependency about + * the evaluating order of _TMP and _CRT/_HOT/_PSV/_ACx. + * 1. On HP Pavilion G4-1016tx, _TMP must be invoked after + * /_CRT/_HOT/_PSV/_ACx, or else system will be power off. + * 2. On HP Compaq 6715b/6715s, the return value of _PSV is 0 + * if _TMP has never been evaluated. + * + * As this dependency is totally transparent to OS, evaluate + * all of them once, in the order of _CRT/_HOT/_PSV/_ACx, + * _TMP, before they are actually used. + */ +static void acpi_thermal_aml_dependency_fix(struct acpi_thermal *tz) +{ + acpi_handle handle = tz->device->handle; + unsigned long long value; + int i; + + acpi_evaluate_integer(handle, "_CRT", NULL, &value); + acpi_evaluate_integer(handle, "_HOT", NULL, &value); + acpi_evaluate_integer(handle, "_PSV", NULL, &value); + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { + char name[5] = { '_', 'A', 'C', ('0' + i), '\0' }; + acpi_status status; + + status = acpi_evaluate_integer(handle, name, NULL, &value); + if (status == AE_NOT_FOUND) + break; + } + acpi_evaluate_integer(handle, "_TMP", NULL, &value); +} + static int acpi_thermal_get_info(struct acpi_thermal *tz) { int result = 0; @@ -992,6 +1024,8 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz) if (!tz) return -EINVAL; + acpi_thermal_aml_dependency_fix(tz); + /* Get trip points [_CRT, _PSV, etc.] (required) */ result = acpi_thermal_get_trip_points(tz); if (result) diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 462f7e30036..74437130431 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -28,6 +28,8 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/types.h> +#include <linux/hardirq.h> +#include <linux/acpi.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> @@ -457,3 +459,39 @@ acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event, #endif } EXPORT_SYMBOL(acpi_evaluate_hotplug_ost); + +/** + * acpi_handle_printk: Print message with ACPI prefix and object path + * + * This function is called through acpi_handle_<level> macros and prints + * a message with ACPI prefix and object path. This function acquires + * the global namespace mutex to obtain an object path. In interrupt + * context, it shows the object path as <n/a>. + */ +void +acpi_handle_printk(const char *level, acpi_handle handle, const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + struct acpi_buffer buffer = { + .length = ACPI_ALLOCATE_BUFFER, + .pointer = NULL + }; + const char *path; + + va_start(args, fmt); + vaf.fmt = fmt; + vaf.va = &args; + + if (in_interrupt() || + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer) != AE_OK) + path = "<n/a>"; + else + path = buffer.pointer; + + printk("%sACPI: %s: %pV", level, path, &vaf); + + va_end(args); + kfree(buffer.pointer); +} +EXPORT_SYMBOL(acpi_handle_printk); diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 0230cb6cbb3..ac9a69cd45f 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -389,6 +389,12 @@ static int __init video_set_bqc_offset(const struct dmi_system_id *d) return 0; } +static int video_ignore_initial_backlight(const struct dmi_system_id *d) +{ + use_bios_initial_backlight = 0; + return 0; +} + static struct dmi_system_id video_dmi_table[] __initdata = { /* * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121 @@ -433,6 +439,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720"), }, }, + { + .callback = video_ignore_initial_backlight, + .ident = "HP Folio 13-2000", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Folio 13 - 2000 Notebook PC"), + }, + }, {} }; diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index b728880ef10..4ac2593234e 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -156,6 +156,14 @@ static struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "X360"), }, }, + { + .callback = video_detect_force_vendor, + .ident = "Asus UL30VT", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "UL30VT"), + }, + }, { }, }; diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index b1ae48054dc..b7078afddb7 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -238,7 +238,7 @@ static int __devexit ahci_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int ahci_suspend(struct device *dev) { struct ahci_platform_data *pdata = dev_get_platdata(dev); diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index fd9ecf74e63..5b0ba3f20ed 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -1105,10 +1105,15 @@ static int ata_acpi_bind_device(struct ata_port *ap, struct scsi_device *sdev, struct acpi_device *acpi_dev; struct acpi_device_power_state *states; - if (ap->flags & ATA_FLAG_ACPI_SATA) - ata_dev = &ap->link.device[sdev->channel]; - else + if (ap->flags & ATA_FLAG_ACPI_SATA) { + if (!sata_pmp_attached(ap)) + ata_dev = &ap->link.device[sdev->id]; + else + ata_dev = &ap->pmp_link[sdev->channel].device[sdev->id]; + } + else { ata_dev = &ap->link.device[sdev->id]; + } *handle = ata_dev_acpi_handle(ata_dev); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 3cc7096cfda..f46fbd3bd3f 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2942,6 +2942,10 @@ const struct ata_timing *ata_timing_find_mode(u8 xfer_mode) if (xfer_mode == t->mode) return t; + + WARN_ONCE(true, "%s: unable to find timing for xfer_mode 0x%x\n", + __func__, xfer_mode); + return NULL; } diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e3bda074fa1..a6df6a351d6 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1052,6 +1052,8 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev) { sdev->use_10_for_rw = 1; sdev->use_10_for_ms = 1; + sdev->no_report_opcodes = 1; + sdev->no_write_same = 1; /* Schedule policy is determined by ->qc_defer() callback and * it needs to see every deferred qc. Set dev_blocked to 1 to diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index 26201ebef3c..371fd2c698b 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -317,6 +317,12 @@ static int cf_init(struct arasan_cf_dev *acdev) return ret; } + ret = clk_set_rate(acdev->clk, 166000000); + if (ret) { + dev_warn(acdev->host->dev, "clock set rate failed"); + return ret; + } + spin_lock_irqsave(&acdev->host->lock, flags); /* configure CF interface clock */ writel((pdata->cf_if_clk <= CF_IF_CLK_200M) ? pdata->cf_if_clk : @@ -908,7 +914,7 @@ static int __devexit arasan_cf_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int arasan_cf_suspend(struct device *dev) { struct ata_host *host = dev_get_drvdata(dev); diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c index 0d7c4c2cd26..400bf1c3e98 100644 --- a/drivers/ata/sata_highbank.c +++ b/drivers/ata/sata_highbank.c @@ -260,7 +260,7 @@ static const struct of_device_id ahci_of_match[] = { }; MODULE_DEVICE_TABLE(of, ahci_of_match); -static int __init ahci_highbank_probe(struct platform_device *pdev) +static int __devinit ahci_highbank_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ahci_host_priv *hpriv; @@ -378,7 +378,7 @@ static int __devexit ahci_highbank_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int ahci_highbank_suspend(struct device *dev) { struct ata_host *host = dev_get_drvdata(dev); diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c index 44a4256533e..08608de87e4 100644 --- a/drivers/ata/sata_svw.c +++ b/drivers/ata/sata_svw.c @@ -142,6 +142,39 @@ static int k2_sata_scr_write(struct ata_link *link, return 0; } +static int k2_sata_softreset(struct ata_link *link, + unsigned int *class, unsigned long deadline) +{ + u8 dmactl; + void __iomem *mmio = link->ap->ioaddr.bmdma_addr; + + dmactl = readb(mmio + ATA_DMA_CMD); + + /* Clear the start bit */ + if (dmactl & ATA_DMA_START) { + dmactl &= ~ATA_DMA_START; + writeb(dmactl, mmio + ATA_DMA_CMD); + } + + return ata_sff_softreset(link, class, deadline); +} + +static int k2_sata_hardreset(struct ata_link *link, + unsigned int *class, unsigned long deadline) +{ + u8 dmactl; + void __iomem *mmio = link->ap->ioaddr.bmdma_addr; + + dmactl = readb(mmio + ATA_DMA_CMD); + + /* Clear the start bit */ + if (dmactl & ATA_DMA_START) { + dmactl &= ~ATA_DMA_START; + writeb(dmactl, mmio + ATA_DMA_CMD); + } + + return sata_sff_hardreset(link, class, deadline); +} static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { @@ -346,6 +379,8 @@ static struct scsi_host_template k2_sata_sht = { static struct ata_port_operations k2_sata_ops = { .inherits = &ata_bmdma_port_ops, + .softreset = k2_sata_softreset, + .hardreset = k2_sata_hardreset, .sff_tf_load = k2_sata_tf_load, .sff_tf_read = k2_sata_tf_read, .sff_check_status = k2_stat_check_status, diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index 89b30f32ba6..ff7bb8a42ed 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -1961,6 +1961,7 @@ static int __devinit ucode_init (loader_block * lb, amb_dev * dev) { res = loader_verify(lb, dev, rec); if (res) break; + rec = ihex_next_binrec(rec); } release_firmware(fw); if (!res) diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index b34b5cda5ae..c8b453939da 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -57,7 +57,7 @@ config DEVTMPFS_MOUNT on the rootfs is completely empty. config STANDALONE - bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL + bool "Select only drivers that don't need compile-time external firmware" default y help Select this option if you don't have magic firmware for drivers that @@ -185,7 +185,6 @@ config DMA_SHARED_BUFFER bool default n select ANON_INODES - depends on EXPERIMENTAL help This option enables the framework for buffer-sharing between multiple drivers. A buffer is associated with a file using driver @@ -193,8 +192,8 @@ config DMA_SHARED_BUFFER driver. config CMA - bool "Contiguous Memory Allocator (EXPERIMENTAL)" - depends on HAVE_DMA_CONTIGUOUS && HAVE_MEMBLOCK && EXPERIMENTAL + bool "Contiguous Memory Allocator" + depends on HAVE_DMA_CONTIGUOUS && HAVE_MEMBLOCK select MIGRATION select MEMORY_ISOLATION help diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index 8fc200b2e2c..d78b204e65c 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -158,7 +158,7 @@ attribute_container_add_device(struct device *dev, ic = kzalloc(sizeof(*ic), GFP_KERNEL); if (!ic) { - dev_printk(KERN_ERR, dev, "failed to allocate class container\n"); + dev_err(dev, "failed to allocate class container\n"); continue; } diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 181ed2660b3..24eb0786834 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -164,8 +164,6 @@ static const struct kset_uevent_ops bus_uevent_ops = { static struct kset *bus_kset; - -#ifdef CONFIG_HOTPLUG /* Manually detach a device from its associated driver. */ static ssize_t driver_unbind(struct device_driver *drv, const char *buf, size_t count) @@ -252,7 +250,6 @@ static ssize_t store_drivers_probe(struct bus_type *bus, return -EINVAL; return count; } -#endif static struct device *next_device(struct klist_iter *i) { @@ -618,11 +615,6 @@ static void driver_remove_attrs(struct bus_type *bus, } } -#ifdef CONFIG_HOTPLUG -/* - * Thanks to drivers making their tables __devinit, we can't allow manual - * bind and unbind from userspace unless CONFIG_HOTPLUG is enabled. - */ static int __must_check add_bind_files(struct device_driver *drv) { int ret; @@ -666,12 +658,6 @@ static void remove_probe_files(struct bus_type *bus) bus_remove_file(bus, &bus_attr_drivers_autoprobe); bus_remove_file(bus, &bus_attr_drivers_probe); } -#else -static inline int add_bind_files(struct device_driver *drv) { return 0; } -static inline void remove_bind_files(struct device_driver *drv) {} -static inline int add_probe_files(struct bus_type *bus) { return 0; } -static inline void remove_probe_files(struct bus_type *bus) {} -#endif static ssize_t driver_uevent_store(struct device_driver *drv, const char *buf, size_t count) diff --git a/drivers/base/core.c b/drivers/base/core.c index abea76c36a4..417913974df 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1180,7 +1180,6 @@ void device_del(struct device *dev) if (dev->bus) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_DEL_DEVICE, dev); - device_pm_remove(dev); dpm_sysfs_remove(dev); if (parent) klist_del(&dev->p->knode_parent); @@ -1205,6 +1204,7 @@ void device_del(struct device *dev) device_remove_file(dev, &uevent_attr); device_remove_attrs(dev); bus_remove_device(dev); + device_pm_remove(dev); driver_deferred_probe_del(dev); /* Notify the platform of the removal, in case they @@ -1399,7 +1399,7 @@ struct root_device { struct module *owner; }; -inline struct root_device *to_root_device(struct device *d) +static inline struct root_device *to_root_device(struct device *d) { return container_of(d, struct root_device, dev); } @@ -1840,10 +1840,12 @@ void device_shutdown(void) pm_runtime_barrier(dev); if (dev->bus && dev->bus->shutdown) { - dev_dbg(dev, "shutdown\n"); + if (initcall_debug) + dev_info(dev, "shutdown\n"); dev->bus->shutdown(dev); } else if (dev->driver && dev->driver->shutdown) { - dev_dbg(dev, "shutdown\n"); + if (initcall_debug) + dev_info(dev, "shutdown\n"); dev->driver->shutdown(dev); } diff --git a/drivers/base/devres.c b/drivers/base/devres.c index 8731979d668..66839066476 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -50,8 +50,8 @@ static void devres_log(struct device *dev, struct devres_node *node, const char *op) { if (unlikely(log_devres)) - dev_printk(KERN_ERR, dev, "DEVRES %3s %p %s (%lu bytes)\n", - op, node, node->name, (unsigned long)node->size); + dev_err(dev, "DEVRES %3s %p %s (%lu bytes)\n", + op, node, node->name, (unsigned long)node->size); } #else /* CONFIG_DEBUG_DEVRES */ #define set_node_dbginfo(node, n, s) do {} while (0) diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c index 612afcc5a93..0ca54421ce9 100644 --- a/drivers/base/dma-contiguous.c +++ b/drivers/base/dma-contiguous.c @@ -57,8 +57,8 @@ struct cma *dma_contiguous_default_area; * Users, who want to set the size of global CMA area for their system * should use cma= kernel parameter. */ -static const unsigned long size_bytes = CMA_SIZE_MBYTES * SZ_1M; -static long size_cmdline = -1; +static const phys_addr_t size_bytes = CMA_SIZE_MBYTES * SZ_1M; +static phys_addr_t size_cmdline = -1; static int __init early_cma(char *p) { @@ -70,7 +70,7 @@ early_param("cma", early_cma); #ifdef CONFIG_CMA_SIZE_PERCENTAGE -static unsigned long __init __maybe_unused cma_early_percent_memory(void) +static phys_addr_t __init __maybe_unused cma_early_percent_memory(void) { struct memblock_region *reg; unsigned long total_pages = 0; @@ -88,7 +88,7 @@ static unsigned long __init __maybe_unused cma_early_percent_memory(void) #else -static inline __maybe_unused unsigned long cma_early_percent_memory(void) +static inline __maybe_unused phys_addr_t cma_early_percent_memory(void) { return 0; } @@ -106,7 +106,7 @@ static inline __maybe_unused unsigned long cma_early_percent_memory(void) */ void __init dma_contiguous_reserve(phys_addr_t limit) { - unsigned long selected_size = 0; + phys_addr_t selected_size = 0; pr_debug("%s(limit %08lx)\n", __func__, (unsigned long)limit); @@ -126,7 +126,7 @@ void __init dma_contiguous_reserve(phys_addr_t limit) if (selected_size) { pr_debug("%s: reserving %ld MiB for global area\n", __func__, - selected_size / SZ_1M); + (unsigned long)selected_size / SZ_1M); dma_declare_contiguous(NULL, selected_size, 0, limit); } @@ -227,11 +227,11 @@ core_initcall(cma_init_reserved_areas); * called by board specific code when early allocator (memblock or bootmem) * is still activate. */ -int __init dma_declare_contiguous(struct device *dev, unsigned long size, +int __init dma_declare_contiguous(struct device *dev, phys_addr_t size, phys_addr_t base, phys_addr_t limit) { struct cma_reserved *r = &cma_reserved[cma_reserved_count]; - unsigned long alignment; + phys_addr_t alignment; pr_debug("%s(size %lx, base %08lx, limit %08lx)\n", __func__, (unsigned long)size, (unsigned long)base, @@ -268,10 +268,6 @@ int __init dma_declare_contiguous(struct device *dev, unsigned long size, if (!addr) { base = -ENOMEM; goto err; - } else if (addr + size > ~(unsigned long)0) { - memblock_free(addr, size); - base = -EINVAL; - goto err; } else { base = addr; } @@ -285,14 +281,14 @@ int __init dma_declare_contiguous(struct device *dev, unsigned long size, r->size = size; r->dev = dev; cma_reserved_count++; - pr_info("CMA: reserved %ld MiB at %08lx\n", size / SZ_1M, + pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M, (unsigned long)base); /* Architecture specific contiguous memory fixup. */ dma_contiguous_early_fixup(base, size); return 0; err: - pr_err("CMA: failed to reserve %ld MiB\n", size / SZ_1M); + pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M); return base; } diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 8945f4e489e..d8146030918 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -143,7 +143,7 @@ struct fw_cache_entry { }; struct firmware_priv { - struct timer_list timeout; + struct delayed_work timeout_work; bool nowait; struct device dev; struct firmware_buf *buf; @@ -246,7 +246,6 @@ static void __fw_free_buf(struct kref *ref) __func__, buf->fw_id, buf, buf->data, (unsigned int)buf->size); - spin_lock(&fwc->lock); list_del(&buf->list); spin_unlock(&fwc->lock); @@ -263,19 +262,32 @@ static void __fw_free_buf(struct kref *ref) static void fw_free_buf(struct firmware_buf *buf) { - kref_put(&buf->ref, __fw_free_buf); + struct firmware_cache *fwc = buf->fwc; + spin_lock(&fwc->lock); + if (!kref_put(&buf->ref, __fw_free_buf)) + spin_unlock(&fwc->lock); } /* direct firmware loading support */ -static const char *fw_path[] = { +static char fw_path_para[256]; +static const char * const fw_path[] = { + fw_path_para, "/lib/firmware/updates/" UTS_RELEASE, "/lib/firmware/updates", "/lib/firmware/" UTS_RELEASE, "/lib/firmware" }; +/* + * Typical usage is that passing 'firmware_class.path=$CUSTOMIZED_PATH' + * from kernel command line because firmware_class is generally built in + * kernel instead of module. + */ +module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644); +MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path"); + /* Don't inline this: 'struct kstat' is biggish */ -static noinline long fw_file_size(struct file *file) +static noinline_for_stack long fw_file_size(struct file *file) { struct kstat st; if (vfs_getattr(file->f_path.mnt, file->f_path.dentry, &st)) @@ -315,6 +327,11 @@ static bool fw_get_filesystem_firmware(struct firmware_buf *buf) for (i = 0; i < ARRAY_SIZE(fw_path); i++) { struct file *file; + + /* skip the unset customized path */ + if (!fw_path[i][0]) + continue; + snprintf(path, PATH_MAX, "%s/%s", fw_path[i], buf->fw_id); file = filp_open(path, O_RDONLY, 0); @@ -667,11 +684,18 @@ static struct bin_attribute firmware_attr_data = { .write = firmware_data_write, }; -static void firmware_class_timeout(u_long data) +static void firmware_class_timeout_work(struct work_struct *work) { - struct firmware_priv *fw_priv = (struct firmware_priv *) data; + struct firmware_priv *fw_priv = container_of(work, + struct firmware_priv, timeout_work.work); + mutex_lock(&fw_lock); + if (test_bit(FW_STATUS_DONE, &(fw_priv->buf->status))) { + mutex_unlock(&fw_lock); + return; + } fw_load_abort(fw_priv); + mutex_unlock(&fw_lock); } static struct firmware_priv * @@ -690,8 +714,8 @@ fw_create_instance(struct firmware *firmware, const char *fw_name, fw_priv->nowait = nowait; fw_priv->fw = firmware; - setup_timer(&fw_priv->timeout, - firmware_class_timeout, (u_long) fw_priv); + INIT_DELAYED_WORK(&fw_priv->timeout_work, + firmware_class_timeout_work); f_dev = &fw_priv->dev; @@ -858,7 +882,9 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, dev_dbg(f_dev->parent, "firmware: direct-loading" " firmware %s\n", buf->fw_id); + mutex_lock(&fw_lock); set_bit(FW_STATUS_DONE, &buf->status); + mutex_unlock(&fw_lock); complete_all(&buf->completion); direct_load = 1; goto handle_fw; @@ -894,15 +920,14 @@ static int _request_firmware_load(struct firmware_priv *fw_priv, bool uevent, dev_set_uevent_suppress(f_dev, false); dev_dbg(f_dev, "firmware: requesting %s\n", buf->fw_id); if (timeout != MAX_SCHEDULE_TIMEOUT) - mod_timer(&fw_priv->timeout, - round_jiffies_up(jiffies + timeout)); + schedule_delayed_work(&fw_priv->timeout_work, timeout); kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD); } wait_for_completion(&buf->completion); - del_timer_sync(&fw_priv->timeout); + cancel_delayed_work_sync(&fw_priv->timeout_work); handle_fw: mutex_lock(&fw_lock); @@ -963,6 +988,9 @@ err_put_dev: * firmware image for this or any other device. * * Caller must hold the reference count of @device. + * + * The function can be called safely inside device's suspend and + * resume callback. **/ int request_firmware(const struct firmware **firmware_p, const char *name, diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 72c776f2a1f..c0b8df38402 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -21,6 +21,7 @@ #include <linux/slab.h> #include <linux/pm_runtime.h> #include <linux/idr.h> +#include <linux/acpi.h> #include "base.h" #include "power/power.h" @@ -44,7 +45,7 @@ EXPORT_SYMBOL_GPL(platform_bus); * be setup before the platform_notifier is called. So if a user needs to * manipulate any relevant information in the pdev_archdata they can do: * - * platform_devic_alloc() + * platform_device_alloc() * ... manipulate ... * platform_device_add() * @@ -122,7 +123,7 @@ struct resource *platform_get_resource_byname(struct platform_device *dev, EXPORT_SYMBOL_GPL(platform_get_resource_byname); /** - * platform_get_irq - get an IRQ for a device + * platform_get_irq_byname - get an IRQ for a device by name * @dev: platform device * @name: IRQ name */ @@ -436,6 +437,7 @@ struct platform_device *platform_device_register_full( goto err_alloc; pdev->dev.parent = pdevinfo->parent; + ACPI_HANDLE_SET(&pdev->dev, pdevinfo->acpi_node.handle); if (pdevinfo->dma_mask) { /* @@ -466,6 +468,7 @@ struct platform_device *platform_device_register_full( ret = platform_device_add(pdev); if (ret) { err: + ACPI_HANDLE_SET(&pdev->dev, NULL); kfree(pdev->dev.dma_mask); err_alloc: @@ -481,8 +484,16 @@ static int platform_drv_probe(struct device *_dev) { struct platform_driver *drv = to_platform_driver(_dev->driver); struct platform_device *dev = to_platform_device(_dev); + int ret; + + if (ACPI_HANDLE(_dev)) + acpi_dev_pm_attach(_dev, true); - return drv->probe(dev); + ret = drv->probe(dev); + if (ret && ACPI_HANDLE(_dev)) + acpi_dev_pm_detach(_dev, true); + + return ret; } static int platform_drv_probe_fail(struct device *_dev) @@ -494,8 +505,13 @@ static int platform_drv_remove(struct device *_dev) { struct platform_driver *drv = to_platform_driver(_dev->driver); struct platform_device *dev = to_platform_device(_dev); + int ret; - return drv->remove(dev); + ret = drv->remove(dev); + if (ACPI_HANDLE(_dev)) + acpi_dev_pm_detach(_dev, true); + + return ret; } static void platform_drv_shutdown(struct device *_dev) @@ -504,6 +520,8 @@ static void platform_drv_shutdown(struct device *_dev) struct platform_device *dev = to_platform_device(_dev); drv->shutdown(dev); + if (ACPI_HANDLE(_dev)) + acpi_dev_pm_detach(_dev, true); } /** @@ -709,6 +727,10 @@ static int platform_match(struct device *dev, struct device_driver *drv) if (of_driver_match_device(dev, drv)) return 1; + /* Then try ACPI style match */ + if (acpi_driver_match_device(dev, drv)) + return 1; + /* Then try to match against the id table */ if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL; diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index eb78e9640c4..9d8fde70939 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -99,7 +99,7 @@ static void __pm_clk_remove(struct pm_clock_entry *ce) if (ce->status < PCE_STATUS_ERROR) { if (ce->status == PCE_STATUS_ENABLED) - clk_disable(ce->clk); + clk_disable_unprepare(ce->clk); if (ce->status >= PCE_STATUS_ACQUIRED) clk_put(ce->clk); @@ -396,7 +396,7 @@ static void enable_clock(struct device *dev, const char *con_id) clk = clk_get(dev, con_id); if (!IS_ERR(clk)) { - clk_enable(clk); + clk_prepare_enable(clk); clk_put(clk); dev_info(dev, "Runtime PM disabled, clock forced on.\n"); } @@ -413,7 +413,7 @@ static void disable_clock(struct device *dev, const char *con_id) clk = clk_get(dev, con_id); if (!IS_ERR(clk)) { - clk_disable(clk); + clk_disable_unprepare(clk); clk_put(clk); dev_info(dev, "Runtime PM disabled, clock forced off.\n"); } diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 96b71b6536d..acc3a8ded29 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -470,10 +470,19 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd) return -EBUSY; not_suspended = 0; - list_for_each_entry(pdd, &genpd->dev_list, list_node) + list_for_each_entry(pdd, &genpd->dev_list, list_node) { + enum pm_qos_flags_status stat; + + stat = dev_pm_qos_flags(pdd->dev, + PM_QOS_FLAG_NO_POWER_OFF + | PM_QOS_FLAG_REMOTE_WAKEUP); + if (stat > PM_QOS_FLAGS_NONE) + return -EBUSY; + if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev) || pdd->dev->power.irq_safe)) not_suspended++; + } if (not_suspended > genpd->in_progress) return -EBUSY; diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index d9468642fc4..50b2831e027 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -23,6 +23,7 @@ #include <linux/rcupdate.h> #include <linux/opp.h> #include <linux/of.h> +#include <linux/export.h> /* * Internal data structure organization with the OPP layer library is as @@ -65,6 +66,7 @@ struct opp { unsigned long u_volt; struct device_opp *dev_opp; + struct rcu_head head; }; /** @@ -160,6 +162,7 @@ unsigned long opp_get_voltage(struct opp *opp) return v; } +EXPORT_SYMBOL(opp_get_voltage); /** * opp_get_freq() - Gets the frequency corresponding to an available opp @@ -189,6 +192,7 @@ unsigned long opp_get_freq(struct opp *opp) return f; } +EXPORT_SYMBOL(opp_get_freq); /** * opp_get_opp_count() - Get number of opps available in the opp list @@ -221,6 +225,7 @@ int opp_get_opp_count(struct device *dev) return count; } +EXPORT_SYMBOL(opp_get_opp_count); /** * opp_find_freq_exact() - search for an exact frequency @@ -230,7 +235,10 @@ int opp_get_opp_count(struct device *dev) * * Searches for exact match in the opp list and returns pointer to the matching * opp if found, else returns ERR_PTR in case of error and should be handled - * using IS_ERR. + * using IS_ERR. Error return values can be: + * EINVAL: for bad pointer + * ERANGE: no match found for search + * ENODEV: if device not found in list of registered devices * * Note: available is a modifier for the search. if available=true, then the * match is for exact matching frequency and is available in the stored OPP @@ -249,7 +257,7 @@ struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq, bool available) { struct device_opp *dev_opp; - struct opp *temp_opp, *opp = ERR_PTR(-ENODEV); + struct opp *temp_opp, *opp = ERR_PTR(-ERANGE); dev_opp = find_device_opp(dev); if (IS_ERR(dev_opp)) { @@ -268,6 +276,7 @@ struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq, return opp; } +EXPORT_SYMBOL(opp_find_freq_exact); /** * opp_find_freq_ceil() - Search for an rounded ceil freq @@ -278,7 +287,11 @@ struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq, * for a device. * * Returns matching *opp and refreshes *freq accordingly, else returns - * ERR_PTR in case of error and should be handled using IS_ERR. + * ERR_PTR in case of error and should be handled using IS_ERR. Error return + * values can be: + * EINVAL: for bad pointer + * ERANGE: no match found for search + * ENODEV: if device not found in list of registered devices * * Locking: This function must be called under rcu_read_lock(). opp is a rcu * protected pointer. The reason for the same is that the opp pointer which is @@ -289,7 +302,7 @@ struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq, struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq) { struct device_opp *dev_opp; - struct opp *temp_opp, *opp = ERR_PTR(-ENODEV); + struct opp *temp_opp, *opp = ERR_PTR(-ERANGE); if (!dev || !freq) { dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq); @@ -298,7 +311,7 @@ struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq) dev_opp = find_device_opp(dev); if (IS_ERR(dev_opp)) - return opp; + return ERR_CAST(dev_opp); list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) { if (temp_opp->available && temp_opp->rate >= *freq) { @@ -310,6 +323,7 @@ struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq) return opp; } +EXPORT_SYMBOL(opp_find_freq_ceil); /** * opp_find_freq_floor() - Search for a rounded floor freq @@ -320,7 +334,11 @@ struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq) * for a device. * * Returns matching *opp and refreshes *freq accordingly, else returns - * ERR_PTR in case of error and should be handled using IS_ERR. + * ERR_PTR in case of error and should be handled using IS_ERR. Error return + * values can be: + * EINVAL: for bad pointer + * ERANGE: no match found for search + * ENODEV: if device not found in list of registered devices * * Locking: This function must be called under rcu_read_lock(). opp is a rcu * protected pointer. The reason for the same is that the opp pointer which is @@ -331,7 +349,7 @@ struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq) struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq) { struct device_opp *dev_opp; - struct opp *temp_opp, *opp = ERR_PTR(-ENODEV); + struct opp *temp_opp, *opp = ERR_PTR(-ERANGE); if (!dev || !freq) { dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq); @@ -340,7 +358,7 @@ struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq) dev_opp = find_device_opp(dev); if (IS_ERR(dev_opp)) - return opp; + return ERR_CAST(dev_opp); list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) { if (temp_opp->available) { @@ -356,6 +374,7 @@ struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq) return opp; } +EXPORT_SYMBOL(opp_find_freq_floor); /** * opp_add() - Add an OPP table from a table definitions @@ -512,7 +531,7 @@ static int opp_set_availability(struct device *dev, unsigned long freq, list_replace_rcu(&opp->node, &new_opp->node); mutex_unlock(&dev_opp_list_lock); - synchronize_rcu(); + kfree_rcu(opp, head); /* Notify the change of the OPP availability */ if (availability_req) @@ -522,13 +541,10 @@ static int opp_set_availability(struct device *dev, unsigned long freq, srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_DISABLE, new_opp); - /* clean up old opp */ - new_opp = opp; - goto out; + return 0; unlock: mutex_unlock(&dev_opp_list_lock); -out: kfree(new_opp); return r; } @@ -552,6 +568,7 @@ int opp_enable(struct device *dev, unsigned long freq) { return opp_set_availability(dev, freq, true); } +EXPORT_SYMBOL(opp_enable); /** * opp_disable() - Disable a specific OPP @@ -573,6 +590,7 @@ int opp_disable(struct device *dev, unsigned long freq) { return opp_set_availability(dev, freq, false); } +EXPORT_SYMBOL(opp_disable); #ifdef CONFIG_CPU_FREQ /** diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index 0dbfdf4419a..b16686a0a5a 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -93,8 +93,10 @@ extern void dpm_sysfs_remove(struct device *dev); extern void rpm_sysfs_remove(struct device *dev); extern int wakeup_sysfs_add(struct device *dev); extern void wakeup_sysfs_remove(struct device *dev); -extern int pm_qos_sysfs_add(struct device *dev); -extern void pm_qos_sysfs_remove(struct device *dev); +extern int pm_qos_sysfs_add_latency(struct device *dev); +extern void pm_qos_sysfs_remove_latency(struct device *dev); +extern int pm_qos_sysfs_add_flags(struct device *dev); +extern void pm_qos_sysfs_remove_flags(struct device *dev); #else /* CONFIG_PM */ diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 74a67e0019a..ff46387f530 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -40,6 +40,7 @@ #include <linux/device.h> #include <linux/mutex.h> #include <linux/export.h> +#include <linux/pm_runtime.h> #include "power.h" @@ -48,6 +49,50 @@ static DEFINE_MUTEX(dev_pm_qos_mtx); static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers); /** + * __dev_pm_qos_flags - Check PM QoS flags for a given device. + * @dev: Device to check the PM QoS flags for. + * @mask: Flags to check against. + * + * This routine must be called with dev->power.lock held. + */ +enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask) +{ + struct dev_pm_qos *qos = dev->power.qos; + struct pm_qos_flags *pqf; + s32 val; + + if (!qos) + return PM_QOS_FLAGS_UNDEFINED; + + pqf = &qos->flags; + if (list_empty(&pqf->list)) + return PM_QOS_FLAGS_UNDEFINED; + + val = pqf->effective_flags & mask; + if (val) + return (val == mask) ? PM_QOS_FLAGS_ALL : PM_QOS_FLAGS_SOME; + + return PM_QOS_FLAGS_NONE; +} + +/** + * dev_pm_qos_flags - Check PM QoS flags for a given device (locked). + * @dev: Device to check the PM QoS flags for. + * @mask: Flags to check against. + */ +enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask) +{ + unsigned long irqflags; + enum pm_qos_flags_status ret; + + spin_lock_irqsave(&dev->power.lock, irqflags); + ret = __dev_pm_qos_flags(dev, mask); + spin_unlock_irqrestore(&dev->power.lock, irqflags); + + return ret; +} + +/** * __dev_pm_qos_read_value - Get PM QoS constraint for a given device. * @dev: Device to get the PM QoS constraint value for. * @@ -55,9 +100,7 @@ static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers); */ s32 __dev_pm_qos_read_value(struct device *dev) { - struct pm_qos_constraints *c = dev->power.constraints; - - return c ? pm_qos_read_value(c) : 0; + return dev->power.qos ? pm_qos_read_value(&dev->power.qos->latency) : 0; } /** @@ -76,30 +119,39 @@ s32 dev_pm_qos_read_value(struct device *dev) return ret; } -/* - * apply_constraint - * @req: constraint request to apply - * @action: action to perform add/update/remove, of type enum pm_qos_req_action - * @value: defines the qos request +/** + * apply_constraint - Add/modify/remove device PM QoS request. + * @req: Constraint request to apply + * @action: Action to perform (add/update/remove). + * @value: Value to assign to the QoS request. * * Internal function to update the constraints list using the PM QoS core * code and if needed call the per-device and the global notification * callbacks */ static int apply_constraint(struct dev_pm_qos_request *req, - enum pm_qos_req_action action, int value) + enum pm_qos_req_action action, s32 value) { - int ret, curr_value; - - ret = pm_qos_update_target(req->dev->power.constraints, - &req->node, action, value); + struct dev_pm_qos *qos = req->dev->power.qos; + int ret; - if (ret) { - /* Call the global callbacks if needed */ - curr_value = pm_qos_read_value(req->dev->power.constraints); - blocking_notifier_call_chain(&dev_pm_notifiers, - (unsigned long)curr_value, - req); + switch(req->type) { + case DEV_PM_QOS_LATENCY: + ret = pm_qos_update_target(&qos->latency, &req->data.pnode, + action, value); + if (ret) { + value = pm_qos_read_value(&qos->latency); + blocking_notifier_call_chain(&dev_pm_notifiers, + (unsigned long)value, + req); + } + break; + case DEV_PM_QOS_FLAGS: + ret = pm_qos_update_flags(&qos->flags, &req->data.flr, + action, value); + break; + default: + ret = -EINVAL; } return ret; @@ -114,28 +166,32 @@ static int apply_constraint(struct dev_pm_qos_request *req, */ static int dev_pm_qos_constraints_allocate(struct device *dev) { + struct dev_pm_qos *qos; struct pm_qos_constraints *c; struct blocking_notifier_head *n; - c = kzalloc(sizeof(*c), GFP_KERNEL); - if (!c) + qos = kzalloc(sizeof(*qos), GFP_KERNEL); + if (!qos) return -ENOMEM; n = kzalloc(sizeof(*n), GFP_KERNEL); if (!n) { - kfree(c); + kfree(qos); return -ENOMEM; } BLOCKING_INIT_NOTIFIER_HEAD(n); + c = &qos->latency; plist_head_init(&c->list); c->target_value = PM_QOS_DEV_LAT_DEFAULT_VALUE; c->default_value = PM_QOS_DEV_LAT_DEFAULT_VALUE; c->type = PM_QOS_MIN; c->notifiers = n; + INIT_LIST_HEAD(&qos->flags.list); + spin_lock_irq(&dev->power.lock); - dev->power.constraints = c; + dev->power.qos = qos; spin_unlock_irq(&dev->power.lock); return 0; @@ -151,7 +207,7 @@ static int dev_pm_qos_constraints_allocate(struct device *dev) void dev_pm_qos_constraints_init(struct device *dev) { mutex_lock(&dev_pm_qos_mtx); - dev->power.constraints = NULL; + dev->power.qos = NULL; dev->power.power_state = PMSG_ON; mutex_unlock(&dev_pm_qos_mtx); } @@ -164,24 +220,28 @@ void dev_pm_qos_constraints_init(struct device *dev) */ void dev_pm_qos_constraints_destroy(struct device *dev) { + struct dev_pm_qos *qos; struct dev_pm_qos_request *req, *tmp; struct pm_qos_constraints *c; + struct pm_qos_flags *f; /* - * If the device's PM QoS resume latency limit has been exposed to user - * space, it has to be hidden at this point. + * If the device's PM QoS resume latency limit or PM QoS flags have been + * exposed to user space, they have to be hidden at this point. */ dev_pm_qos_hide_latency_limit(dev); + dev_pm_qos_hide_flags(dev); mutex_lock(&dev_pm_qos_mtx); dev->power.power_state = PMSG_INVALID; - c = dev->power.constraints; - if (!c) + qos = dev->power.qos; + if (!qos) goto out; - /* Flush the constraints list for the device */ - plist_for_each_entry_safe(req, tmp, &c->list, node) { + /* Flush the constraints lists for the device. */ + c = &qos->latency; + plist_for_each_entry_safe(req, tmp, &c->list, data.pnode) { /* * Update constraints list and call the notification * callbacks if needed @@ -189,13 +249,18 @@ void dev_pm_qos_constraints_destroy(struct device *dev) apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); memset(req, 0, sizeof(*req)); } + f = &qos->flags; + list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) { + apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); + memset(req, 0, sizeof(*req)); + } spin_lock_irq(&dev->power.lock); - dev->power.constraints = NULL; + dev->power.qos = NULL; spin_unlock_irq(&dev->power.lock); kfree(c->notifiers); - kfree(c); + kfree(qos); out: mutex_unlock(&dev_pm_qos_mtx); @@ -205,6 +270,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev) * dev_pm_qos_add_request - inserts new qos request into the list * @dev: target device for the constraint * @req: pointer to a preallocated handle + * @type: type of the request * @value: defines the qos request * * This function inserts a new entry in the device constraints list of @@ -218,9 +284,12 @@ void dev_pm_qos_constraints_destroy(struct device *dev) * -EINVAL in case of wrong parameters, -ENOMEM if there's not enough memory * to allocate for data structures, -ENODEV if the device has just been removed * from the system. + * + * Callers should ensure that the target device is not RPM_SUSPENDED before + * using this function for requests of type DEV_PM_QOS_FLAGS. */ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, - s32 value) + enum dev_pm_qos_req_type type, s32 value) { int ret = 0; @@ -235,7 +304,7 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, mutex_lock(&dev_pm_qos_mtx); - if (!dev->power.constraints) { + if (!dev->power.qos) { if (dev->power.power_state.event == PM_EVENT_INVALID) { /* The device has been removed from the system. */ req->dev = NULL; @@ -251,8 +320,10 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, } } - if (!ret) + if (!ret) { + req->type = type; ret = apply_constraint(req, PM_QOS_ADD_REQ, value); + } out: mutex_unlock(&dev_pm_qos_mtx); @@ -262,6 +333,37 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, EXPORT_SYMBOL_GPL(dev_pm_qos_add_request); /** + * __dev_pm_qos_update_request - Modify an existing device PM QoS request. + * @req : PM QoS request to modify. + * @new_value: New value to request. + */ +static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req, + s32 new_value) +{ + s32 curr_value; + int ret = 0; + + if (!req->dev->power.qos) + return -ENODEV; + + switch(req->type) { + case DEV_PM_QOS_LATENCY: + curr_value = req->data.pnode.prio; + break; + case DEV_PM_QOS_FLAGS: + curr_value = req->data.flr.flags; + break; + default: + return -EINVAL; + } + + if (curr_value != new_value) + ret = apply_constraint(req, PM_QOS_UPDATE_REQ, new_value); + + return ret; +} + +/** * dev_pm_qos_update_request - modifies an existing qos request * @req : handle to list element holding a dev_pm_qos request to use * @new_value: defines the qos request @@ -275,11 +377,13 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_add_request); * 0 if the aggregated constraint value has not changed, * -EINVAL in case of wrong parameters, -ENODEV if the device has been * removed from the system + * + * Callers should ensure that the target device is not RPM_SUSPENDED before + * using this function for requests of type DEV_PM_QOS_FLAGS. */ -int dev_pm_qos_update_request(struct dev_pm_qos_request *req, - s32 new_value) +int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value) { - int ret = 0; + int ret; if (!req) /*guard against callers passing in null */ return -EINVAL; @@ -289,17 +393,9 @@ int dev_pm_qos_update_request(struct dev_pm_qos_request *req, return -EINVAL; mutex_lock(&dev_pm_qos_mtx); - - if (req->dev->power.constraints) { - if (new_value != req->node.prio) - ret = apply_constraint(req, PM_QOS_UPDATE_REQ, - new_value); - } else { - /* Return if the device has been removed */ - ret = -ENODEV; - } - + ret = __dev_pm_qos_update_request(req, new_value); mutex_unlock(&dev_pm_qos_mtx); + return ret; } EXPORT_SYMBOL_GPL(dev_pm_qos_update_request); @@ -315,6 +411,9 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_update_request); * 0 if the aggregated constraint value has not changed, * -EINVAL in case of wrong parameters, -ENODEV if the device has been * removed from the system + * + * Callers should ensure that the target device is not RPM_SUSPENDED before + * using this function for requests of type DEV_PM_QOS_FLAGS. */ int dev_pm_qos_remove_request(struct dev_pm_qos_request *req) { @@ -329,7 +428,7 @@ int dev_pm_qos_remove_request(struct dev_pm_qos_request *req) mutex_lock(&dev_pm_qos_mtx); - if (req->dev->power.constraints) { + if (req->dev->power.qos) { ret = apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE); memset(req, 0, sizeof(*req)); @@ -362,13 +461,13 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier) mutex_lock(&dev_pm_qos_mtx); - if (!dev->power.constraints) + if (!dev->power.qos) ret = dev->power.power_state.event != PM_EVENT_INVALID ? dev_pm_qos_constraints_allocate(dev) : -ENODEV; if (!ret) ret = blocking_notifier_chain_register( - dev->power.constraints->notifiers, notifier); + dev->power.qos->latency.notifiers, notifier); mutex_unlock(&dev_pm_qos_mtx); return ret; @@ -393,9 +492,9 @@ int dev_pm_qos_remove_notifier(struct device *dev, mutex_lock(&dev_pm_qos_mtx); /* Silently return if the constraints object is not present. */ - if (dev->power.constraints) + if (dev->power.qos) retval = blocking_notifier_chain_unregister( - dev->power.constraints->notifiers, + dev->power.qos->latency.notifiers, notifier); mutex_unlock(&dev_pm_qos_mtx); @@ -449,9 +548,10 @@ int dev_pm_qos_add_ancestor_request(struct device *dev, ancestor = ancestor->parent; if (ancestor) - error = dev_pm_qos_add_request(ancestor, req, value); + error = dev_pm_qos_add_request(ancestor, req, + DEV_PM_QOS_LATENCY, value); - if (error) + if (error < 0) req->dev = NULL; return error; @@ -459,10 +559,19 @@ int dev_pm_qos_add_ancestor_request(struct device *dev, EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request); #ifdef CONFIG_PM_RUNTIME -static void __dev_pm_qos_drop_user_request(struct device *dev) +static void __dev_pm_qos_drop_user_request(struct device *dev, + enum dev_pm_qos_req_type type) { - dev_pm_qos_remove_request(dev->power.pq_req); - dev->power.pq_req = NULL; + switch(type) { + case DEV_PM_QOS_LATENCY: + dev_pm_qos_remove_request(dev->power.qos->latency_req); + dev->power.qos->latency_req = NULL; + break; + case DEV_PM_QOS_FLAGS: + dev_pm_qos_remove_request(dev->power.qos->flags_req); + dev->power.qos->flags_req = NULL; + break; + } } /** @@ -478,21 +587,21 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value) if (!device_is_registered(dev) || value < 0) return -EINVAL; - if (dev->power.pq_req) + if (dev->power.qos && dev->power.qos->latency_req) return -EEXIST; req = kzalloc(sizeof(*req), GFP_KERNEL); if (!req) return -ENOMEM; - ret = dev_pm_qos_add_request(dev, req, value); + ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_LATENCY, value); if (ret < 0) return ret; - dev->power.pq_req = req; - ret = pm_qos_sysfs_add(dev); + dev->power.qos->latency_req = req; + ret = pm_qos_sysfs_add_latency(dev); if (ret) - __dev_pm_qos_drop_user_request(dev); + __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY); return ret; } @@ -504,10 +613,92 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit); */ void dev_pm_qos_hide_latency_limit(struct device *dev) { - if (dev->power.pq_req) { - pm_qos_sysfs_remove(dev); - __dev_pm_qos_drop_user_request(dev); + if (dev->power.qos && dev->power.qos->latency_req) { + pm_qos_sysfs_remove_latency(dev); + __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY); } } EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit); + +/** + * dev_pm_qos_expose_flags - Expose PM QoS flags of a device to user space. + * @dev: Device whose PM QoS flags are to be exposed to user space. + * @val: Initial values of the flags. + */ +int dev_pm_qos_expose_flags(struct device *dev, s32 val) +{ + struct dev_pm_qos_request *req; + int ret; + + if (!device_is_registered(dev)) + return -EINVAL; + + if (dev->power.qos && dev->power.qos->flags_req) + return -EEXIST; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + pm_runtime_get_sync(dev); + ret = dev_pm_qos_add_request(dev, req, DEV_PM_QOS_FLAGS, val); + if (ret < 0) + goto fail; + + dev->power.qos->flags_req = req; + ret = pm_qos_sysfs_add_flags(dev); + if (ret) + __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS); + +fail: + pm_runtime_put(dev); + return ret; +} +EXPORT_SYMBOL_GPL(dev_pm_qos_expose_flags); + +/** + * dev_pm_qos_hide_flags - Hide PM QoS flags of a device from user space. + * @dev: Device whose PM QoS flags are to be hidden from user space. + */ +void dev_pm_qos_hide_flags(struct device *dev) +{ + if (dev->power.qos && dev->power.qos->flags_req) { + pm_qos_sysfs_remove_flags(dev); + pm_runtime_get_sync(dev); + __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS); + pm_runtime_put(dev); + } +} +EXPORT_SYMBOL_GPL(dev_pm_qos_hide_flags); + +/** + * dev_pm_qos_update_flags - Update PM QoS flags request owned by user space. + * @dev: Device to update the PM QoS flags request for. + * @mask: Flags to set/clear. + * @set: Whether to set or clear the flags (true means set). + */ +int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set) +{ + s32 value; + int ret; + + if (!dev->power.qos || !dev->power.qos->flags_req) + return -EINVAL; + + pm_runtime_get_sync(dev); + mutex_lock(&dev_pm_qos_mtx); + + value = dev_pm_qos_requested_flags(dev); + if (set) + value |= mask; + else + value &= ~mask; + + ret = __dev_pm_qos_update_request(dev->power.qos->flags_req, value); + + mutex_unlock(&dev_pm_qos_mtx); + pm_runtime_put(dev); + + return ret; +} #endif /* CONFIG_PM_RUNTIME */ diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index b91dc6f1e91..50d16e3cb0a 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -221,7 +221,7 @@ static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show, static ssize_t pm_qos_latency_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", dev->power.pq_req->node.prio); + return sprintf(buf, "%d\n", dev_pm_qos_requested_latency(dev)); } static ssize_t pm_qos_latency_store(struct device *dev, @@ -237,12 +237,66 @@ static ssize_t pm_qos_latency_store(struct device *dev, if (value < 0) return -EINVAL; - ret = dev_pm_qos_update_request(dev->power.pq_req, value); + ret = dev_pm_qos_update_request(dev->power.qos->latency_req, value); return ret < 0 ? ret : n; } static DEVICE_ATTR(pm_qos_resume_latency_us, 0644, pm_qos_latency_show, pm_qos_latency_store); + +static ssize_t pm_qos_no_power_off_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", !!(dev_pm_qos_requested_flags(dev) + & PM_QOS_FLAG_NO_POWER_OFF)); +} + +static ssize_t pm_qos_no_power_off_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t n) +{ + int ret; + + if (kstrtoint(buf, 0, &ret)) + return -EINVAL; + + if (ret != 0 && ret != 1) + return -EINVAL; + + ret = dev_pm_qos_update_flags(dev, PM_QOS_FLAG_NO_POWER_OFF, ret); + return ret < 0 ? ret : n; +} + +static DEVICE_ATTR(pm_qos_no_power_off, 0644, + pm_qos_no_power_off_show, pm_qos_no_power_off_store); + +static ssize_t pm_qos_remote_wakeup_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", !!(dev_pm_qos_requested_flags(dev) + & PM_QOS_FLAG_REMOTE_WAKEUP)); +} + +static ssize_t pm_qos_remote_wakeup_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t n) +{ + int ret; + + if (kstrtoint(buf, 0, &ret)) + return -EINVAL; + + if (ret != 0 && ret != 1) + return -EINVAL; + + ret = dev_pm_qos_update_flags(dev, PM_QOS_FLAG_REMOTE_WAKEUP, ret); + return ret < 0 ? ret : n; +} + +static DEVICE_ATTR(pm_qos_remote_wakeup, 0644, + pm_qos_remote_wakeup_show, pm_qos_remote_wakeup_store); #endif /* CONFIG_PM_RUNTIME */ #ifdef CONFIG_PM_SLEEP @@ -564,15 +618,27 @@ static struct attribute_group pm_runtime_attr_group = { .attrs = runtime_attrs, }; -static struct attribute *pm_qos_attrs[] = { +static struct attribute *pm_qos_latency_attrs[] = { #ifdef CONFIG_PM_RUNTIME &dev_attr_pm_qos_resume_latency_us.attr, #endif /* CONFIG_PM_RUNTIME */ NULL, }; -static struct attribute_group pm_qos_attr_group = { +static struct attribute_group pm_qos_latency_attr_group = { .name = power_group_name, - .attrs = pm_qos_attrs, + .attrs = pm_qos_latency_attrs, +}; + +static struct attribute *pm_qos_flags_attrs[] = { +#ifdef CONFIG_PM_RUNTIME + &dev_attr_pm_qos_no_power_off.attr, + &dev_attr_pm_qos_remote_wakeup.attr, +#endif /* CONFIG_PM_RUNTIME */ + NULL, +}; +static struct attribute_group pm_qos_flags_attr_group = { + .name = power_group_name, + .attrs = pm_qos_flags_attrs, }; int dpm_sysfs_add(struct device *dev) @@ -615,14 +681,24 @@ void wakeup_sysfs_remove(struct device *dev) sysfs_unmerge_group(&dev->kobj, &pm_wakeup_attr_group); } -int pm_qos_sysfs_add(struct device *dev) +int pm_qos_sysfs_add_latency(struct device *dev) +{ + return sysfs_merge_group(&dev->kobj, &pm_qos_latency_attr_group); +} + +void pm_qos_sysfs_remove_latency(struct device *dev) +{ + sysfs_unmerge_group(&dev->kobj, &pm_qos_latency_attr_group); +} + +int pm_qos_sysfs_add_flags(struct device *dev) { - return sysfs_merge_group(&dev->kobj, &pm_qos_attr_group); + return sysfs_merge_group(&dev->kobj, &pm_qos_flags_attr_group); } -void pm_qos_sysfs_remove(struct device *dev) +void pm_qos_sysfs_remove_flags(struct device *dev) { - sysfs_unmerge_group(&dev->kobj, &pm_qos_attr_group); + sysfs_unmerge_group(&dev->kobj, &pm_qos_flags_attr_group); } void rpm_sysfs_remove(struct device *dev) diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 3804a0af3ef..9fe4f186555 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -935,7 +935,7 @@ aoe_end_request(struct aoedev *d, struct request *rq, int fastfail) /* cf. http://lkml.org/lkml/2006/10/31/28 */ if (!fastfail) - q->request_fn(q); + __blk_run_queue(q); } static void diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 1c49d717396..2ddd64a9ffd 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4330,6 +4330,7 @@ out_unreg_region: out_unreg_blkdev: unregister_blkdev(FLOPPY_MAJOR, "fd"); out_put_disk: + destroy_workqueue(floppy_wq); for (drive = 0; drive < N_DRIVE; drive++) { if (!disks[drive]) break; @@ -4340,7 +4341,6 @@ out_put_disk: } put_disk(disks[drive]); } - destroy_workqueue(floppy_wq); return err; } @@ -4555,6 +4555,8 @@ static void __exit floppy_module_exit(void) unregister_blkdev(FLOPPY_MAJOR, "fd"); platform_driver_unregister(&floppy_driver); + destroy_workqueue(floppy_wq); + for (drive = 0; drive < N_DRIVE; drive++) { del_timer_sync(&motor_off_timer[drive]); @@ -4578,7 +4580,6 @@ static void __exit floppy_module_exit(void) cancel_delayed_work_sync(&fd_timeout); cancel_delayed_work_sync(&fd_timer); - destroy_workqueue(floppy_wq); if (atomic_read(&usage_count)) floppy_release_irq_and_dma(); diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index adc6f36564c..9694dd99bbb 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -559,7 +559,7 @@ static void mtip_timeout_function(unsigned long int data) struct mtip_cmd *command; int tag, cmdto_cnt = 0; unsigned int bit, group; - unsigned int num_command_slots = port->dd->slot_groups * 32; + unsigned int num_command_slots; unsigned long to, tagaccum[SLOTBITS_IN_LONGS]; if (unlikely(!port)) @@ -572,6 +572,7 @@ static void mtip_timeout_function(unsigned long int data) } /* clear the tag accumulator */ memset(tagaccum, 0, SLOTBITS_IN_LONGS * sizeof(long)); + num_command_slots = port->dd->slot_groups * 32; for (tag = 0; tag < num_command_slots; tag++) { /* @@ -2218,8 +2219,8 @@ static int exec_drive_taskfile(struct driver_data *dd, fis.device); /* check for erase mode support during secure erase.*/ - if ((fis.command == ATA_CMD_SEC_ERASE_UNIT) - && (outbuf[0] & MTIP_SEC_ERASE_MODE)) { + if ((fis.command == ATA_CMD_SEC_ERASE_UNIT) && outbuf && + (outbuf[0] & MTIP_SEC_ERASE_MODE)) { erasemode = 1; } @@ -2439,7 +2440,7 @@ static int mtip_hw_ioctl(struct driver_data *dd, unsigned int cmd, * return value * None */ -static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, +static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector, int nsect, int nents, int tag, void *callback, void *data, int dir) { @@ -2447,6 +2448,7 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, struct mtip_port *port = dd->port; struct mtip_cmd *command = &port->commands[tag]; int dma_dir = (dir == READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + u64 start = sector; /* Map the scatter list for DMA access */ nents = dma_map_sg(&dd->pdev->dev, command->sg, nents, dma_dir); @@ -2465,8 +2467,12 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t start, fis->opts = 1 << 7; fis->command = (dir == READ ? ATA_CMD_FPDMA_READ : ATA_CMD_FPDMA_WRITE); - *((unsigned int *) &fis->lba_low) = (start & 0xFFFFFF); - *((unsigned int *) &fis->lba_low_ex) = ((start >> 24) & 0xFFFFFF); + fis->lba_low = start & 0xFF; + fis->lba_mid = (start >> 8) & 0xFF; + fis->lba_hi = (start >> 16) & 0xFF; + fis->lba_low_ex = (start >> 24) & 0xFF; + fis->lba_mid_ex = (start >> 32) & 0xFF; + fis->lba_hi_ex = (start >> 40) & 0xFF; fis->device = 1 << 6; fis->features = nsect & 0xFF; fis->features_ex = (nsect >> 8) & 0xFF; diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h index 5f4a917bd8b..b1742640556 100644 --- a/drivers/block/mtip32xx/mtip32xx.h +++ b/drivers/block/mtip32xx/mtip32xx.h @@ -34,7 +34,7 @@ #define PCIE_CONFIG_EXT_DEVICE_CONTROL_OFFSET 0x48 /* check for erase mode support during secure erase */ -#define MTIP_SEC_ERASE_MODE 0x3 +#define MTIP_SEC_ERASE_MODE 0x2 /* # of times to retry timed out/failed IOs */ #define MTIP_MAX_RETRIES 2 @@ -155,14 +155,14 @@ enum { MTIP_DDF_REBUILD_FAILED_BIT = 8, }; -__packed struct smart_attr{ +struct smart_attr { u8 attr_id; u16 flags; u8 cur; u8 worst; u32 data; u8 res[3]; -}; +} __packed; /* Register Frame Information Structure (FIS), host to device. */ struct host_to_dev_fis { diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index fd793519ea2..478493543b3 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -249,7 +249,7 @@ static const struct agp_bridge_driver ali_m1541_bridge = { }; -static struct agp_device_ids ali_agp_device_ids[] __devinitdata = +static struct agp_device_ids ali_agp_device_ids[] = { { .device_id = PCI_DEVICE_ID_AL_M1541, @@ -374,7 +374,7 @@ found: return agp_add_bridge(bridge); } -static void __devexit agp_ali_remove(struct pci_dev *pdev) +static void agp_ali_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index f7e88787af9..1b2101160e9 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -388,7 +388,7 @@ static const struct agp_bridge_driver amd_irongate_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_device_ids amd_agp_device_ids[] __devinitdata = +static struct agp_device_ids amd_agp_device_ids[] = { { .device_id = PCI_DEVICE_ID_AMD_FE_GATE_7006, @@ -480,7 +480,7 @@ static int __devinit agp_amdk7_probe(struct pci_dev *pdev, return agp_add_bridge(bridge); } -static void __devexit agp_amdk7_remove(struct pci_dev *pdev) +static void agp_amdk7_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 444f8b6ab41..061d46209b1 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -579,7 +579,7 @@ static int __devinit agp_amd64_probe(struct pci_dev *pdev, return 0; } -static void __devexit agp_amd64_remove(struct pci_dev *pdev) +static void agp_amd64_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index dc30e224349..ed0433576e7 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -445,7 +445,7 @@ static const struct agp_bridge_driver ati_generic_bridge = { }; -static struct agp_device_ids ati_agp_device_ids[] __devinitdata = +static struct agp_device_ids ati_agp_device_ids[] = { { .device_id = PCI_DEVICE_ID_ATI_RS100, @@ -533,7 +533,7 @@ found: return agp_add_bridge(bridge); } -static void __devexit agp_ati_remove(struct pci_dev *pdev) +static void agp_ati_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index d607f53d8af..55f3e33a309 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -407,7 +407,7 @@ static int __devinit agp_efficeon_probe(struct pci_dev *pdev, return agp_add_bridge(bridge); } -static void __devexit agp_efficeon_remove(struct pci_dev *pdev) +static void agp_efficeon_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index 75b763cb3ea..d328b662e50 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c @@ -611,7 +611,7 @@ static int __devinit agp_intel_i460_probe(struct pci_dev *pdev, return agp_add_bridge(bridge); } -static void __devexit agp_intel_i460_remove(struct pci_dev *pdev) +static void agp_intel_i460_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index b130df0a195..f3a8f52b5a0 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -819,7 +819,7 @@ found_gmch: return err; } -static void __devexit agp_intel_remove(struct pci_dev *pdev) +static void agp_intel_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index b9734a97818..66e0868000f 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -388,7 +388,7 @@ static int __devinit agp_nvidia_probe(struct pci_dev *pdev, return agp_add_bridge(bridge); } -static void __devexit agp_nvidia_remove(struct pci_dev *pdev) +static void agp_nvidia_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index 3a5af2f9b01..a18791d7718 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -327,7 +327,7 @@ static int __devinit agp_sgi_init(void) return 0; } -static void __devexit agp_sgi_cleanup(void) +static void agp_sgi_cleanup(void) { kfree(sgi_tioca_agp_bridges); sgi_tioca_agp_bridges = NULL; diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c index 08704ae5395..93d1d31f9d0 100644 --- a/drivers/char/agp/sis-agp.c +++ b/drivers/char/agp/sis-agp.c @@ -17,8 +17,8 @@ #define PCI_DEVICE_ID_SI_662 0x0662 #define PCI_DEVICE_ID_SI_671 0x0671 -static bool __devinitdata agp_sis_force_delay = 0; -static int __devinitdata agp_sis_agp_spec = -1; +static bool agp_sis_force_delay = 0; +static int agp_sis_agp_spec = -1; static int sis_fetch_size(void) { @@ -148,7 +148,7 @@ static struct agp_bridge_driver sis_driver = { }; // chipsets that require the 'delay hack' -static int sis_broken_chipsets[] __devinitdata = { +static int sis_broken_chipsets[] = { PCI_DEVICE_ID_SI_648, PCI_DEVICE_ID_SI_746, 0 // terminator @@ -211,7 +211,7 @@ static int __devinit agp_sis_probe(struct pci_dev *pdev, return agp_add_bridge(bridge); } -static void __devexit agp_sis_remove(struct pci_dev *pdev) +static void agp_sis_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index f02f9b07fd4..26020fb8d7a 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -518,7 +518,7 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, return agp_add_bridge(bridge); } -static void __devexit agp_serverworks_remove(struct pci_dev *pdev) +static void agp_serverworks_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index a32c492baf5..011967ad3ee 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -557,7 +557,7 @@ const struct agp_bridge_driver u3_agp_driver = { .needs_scratch_page = true, }; -static struct agp_device_ids uninorth_agp_device_ids[] __devinitdata = { +static struct agp_device_ids uninorth_agp_device_ids[] = { { .device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP, .chipset_name = "UniNorth", @@ -663,7 +663,7 @@ static int __devinit agp_uninorth_probe(struct pci_dev *pdev, return agp_add_bridge(bridge); } -static void __devexit agp_uninorth_remove(struct pci_dev *pdev) +static void agp_uninorth_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index 8bc38493740..6818595bb86 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -224,7 +224,7 @@ static const struct agp_bridge_driver via_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_device_ids via_agp_device_ids[] __devinitdata = +static struct agp_device_ids via_agp_device_ids[] = { { .device_id = PCI_DEVICE_ID_VIA_82C597_0, @@ -485,7 +485,7 @@ static int __devinit agp_via_probe(struct pci_dev *pdev, return agp_add_bridge(bridge); } -static void __devexit agp_via_remove(struct pci_dev *pdev) +static void agp_via_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index dfd7876f127..fe6d4be4829 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -816,7 +816,7 @@ static unsigned long __hpet_calibrate(struct hpets *hpetp) static unsigned long hpet_calibrate(struct hpets *hpetp) { - unsigned long ret = -1; + unsigned long ret = ~0UL; unsigned long tmp; /* @@ -1001,6 +1001,9 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) irqp = &res->data.extended_irq; for (i = 0; i < irqp->interrupt_count; i++) { + if (hdp->hd_nirqs >= HPET_MAX_TIMERS) + break; + irq = acpi_register_gsi(NULL, irqp->interrupts[i], irqp->triggering, irqp->polarity); if (irq < 0) diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index fbd9b2b850e..c58ea9b80b1 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -127,12 +127,12 @@ config HW_RANDOM_VIA If unsure, say Y. config HW_RANDOM_IXP4XX - tristate "Intel IXP4xx NPU HW Random Number Generator support" + tristate "Intel IXP4xx NPU HW Pseudo-Random Number Generator support" depends on HW_RANDOM && ARCH_IXP4XX default HW_RANDOM ---help--- - This driver provides kernel-side support for the Random - Number Generator hardware found on the Intel IXP4xx NPU. + This driver provides kernel-side support for the Pseudo-Random + Number Generator hardware found on the Intel IXP45x/46x NPU. To compile this driver as a module, choose M here: the module will be called ixp4xx-rng. diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c index 731c9046cf7..5a4a6e70478 100644 --- a/drivers/char/hw_random/atmel-rng.c +++ b/drivers/char/hw_random/atmel-rng.c @@ -98,7 +98,7 @@ err_enable: return ret; } -static int __devexit atmel_trng_remove(struct platform_device *pdev) +static int atmel_trng_remove(struct platform_device *pdev) { struct atmel_trng *trng = platform_get_drvdata(pdev); diff --git a/drivers/char/hw_random/bcm63xx-rng.c b/drivers/char/hw_random/bcm63xx-rng.c index aec6a4277ca..ae95bcb18d4 100644 --- a/drivers/char/hw_random/bcm63xx-rng.c +++ b/drivers/char/hw_random/bcm63xx-rng.c @@ -145,7 +145,7 @@ out: return ret; } -static int __devexit bcm63xx_rng_remove(struct platform_device *pdev) +static int bcm63xx_rng_remove(struct platform_device *pdev) { struct hwrng *rng = platform_get_drvdata(pdev); struct bcm63xx_rng_priv *priv = to_rng_priv(rng); diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c index 232ba9ce579..bdc852ea763 100644 --- a/drivers/char/hw_random/exynos-rng.c +++ b/drivers/char/hw_random/exynos-rng.c @@ -134,7 +134,7 @@ static int __devinit exynos_rng_probe(struct platform_device *pdev) return hwrng_register(&exynos_rng->rng); } -static int __devexit exynos_rng_remove(struct platform_device *pdev) +static int exynos_rng_remove(struct platform_device *pdev) { struct exynos_rng *exynos_rng = platform_get_drvdata(pdev); diff --git a/drivers/char/hw_random/ixp4xx-rng.c b/drivers/char/hw_random/ixp4xx-rng.c index 263567f5f39..beec1627db3 100644 --- a/drivers/char/hw_random/ixp4xx-rng.c +++ b/drivers/char/hw_random/ixp4xx-rng.c @@ -45,6 +45,9 @@ static int __init ixp4xx_rng_init(void) void __iomem * rng_base; int err; + if (!cpu_is_ixp46x()) /* includes IXP455 */ + return -ENOSYS; + rng_base = ioremap(0x70002100, 4); if (!rng_base) return -ENOMEM; @@ -68,5 +71,5 @@ module_init(ixp4xx_rng_init); module_exit(ixp4xx_rng_exit); MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>"); -MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver for IXP4xx"); +MODULE_DESCRIPTION("H/W Pseudo-Random Number Generator (RNG) driver for IXP45x/46x"); MODULE_LICENSE("GPL"); diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index ebd48f0135d..d68a72a08b5 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c @@ -25,7 +25,7 @@ #define DRV_MODULE_VERSION "0.2" #define DRV_MODULE_RELDATE "July 27, 2011" -static char version[] __devinitdata = +static char version[] = DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); @@ -719,7 +719,7 @@ out: return err; } -static int __devexit n2rng_remove(struct platform_device *op) +static int n2rng_remove(struct platform_device *op) { struct n2rng *np = dev_get_drvdata(&op->dev); diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c index 3a632673aed..a1f70407cc9 100644 --- a/drivers/char/hw_random/pasemi-rng.c +++ b/drivers/char/hw_random/pasemi-rng.c @@ -122,7 +122,7 @@ static int __devinit rng_probe(struct platform_device *ofdev) return err; } -static int __devexit rng_remove(struct platform_device *dev) +static int rng_remove(struct platform_device *dev) { void __iomem *rng_regs = (void __iomem *)pasemi_rng.priv; diff --git a/drivers/char/hw_random/picoxcell-rng.c b/drivers/char/hw_random/picoxcell-rng.c index 97bd891422c..d4b24c1dd48 100644 --- a/drivers/char/hw_random/picoxcell-rng.c +++ b/drivers/char/hw_random/picoxcell-rng.c @@ -151,7 +151,7 @@ err_enable: return ret; } -static int __devexit picoxcell_trng_remove(struct platform_device *pdev) +static int picoxcell_trng_remove(struct platform_device *pdev) { hwrng_unregister(&picoxcell_trng); clk_disable(rng_clk); diff --git a/drivers/char/hw_random/ppc4xx-rng.c b/drivers/char/hw_random/ppc4xx-rng.c index c51762c1303..af6506a69cd 100644 --- a/drivers/char/hw_random/ppc4xx-rng.c +++ b/drivers/char/hw_random/ppc4xx-rng.c @@ -111,7 +111,7 @@ static int __devinit ppc4xx_rng_probe(struct platform_device *dev) return err; } -static int __devexit ppc4xx_rng_remove(struct platform_device *dev) +static int ppc4xx_rng_remove(struct platform_device *dev) { void __iomem *rng_regs = (void __iomem *) ppc4xx_rng.priv; diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c index f1a1618db1f..3a1abc9417e 100644 --- a/drivers/char/hw_random/timeriomem-rng.c +++ b/drivers/char/hw_random/timeriomem-rng.c @@ -130,7 +130,7 @@ failed: return ret; } -static int __devexit timeriomem_rng_remove(struct platform_device *pdev) +static int timeriomem_rng_remove(struct platform_device *pdev) { del_timer_sync(&timeriomem_rng_timer); hwrng_unregister(&timeriomem_rng_ops); diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index 5708299507d..621f595f1a9 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c @@ -119,7 +119,7 @@ static int virtrng_probe(struct virtio_device *vdev) return probe_common(vdev); } -static void __devexit virtrng_remove(struct virtio_device *vdev) +static void virtrng_remove(struct virtio_device *vdev) { remove_common(vdev); } diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 32a6c7e256b..20ab5b3a891 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1836,7 +1836,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) return rv; } -static int __devinit hardcode_find_bmc(void) +static int hardcode_find_bmc(void) { int ret = -ENODEV; int i; @@ -2023,7 +2023,7 @@ struct SPMITable { s8 spmi_id[1]; /* A '\0' terminated array starts here. */ }; -static int __devinit try_init_spmi(struct SPMITable *spmi) +static int try_init_spmi(struct SPMITable *spmi) { struct smi_info *info; @@ -2106,7 +2106,7 @@ static int __devinit try_init_spmi(struct SPMITable *spmi) return 0; } -static void __devinit spmi_find_bmc(void) +static void spmi_find_bmc(void) { acpi_status status; struct SPMITable *spmi; @@ -2128,7 +2128,7 @@ static void __devinit spmi_find_bmc(void) } } -static int __devinit ipmi_pnp_probe(struct pnp_dev *dev, +static int ipmi_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) { struct acpi_device *acpi_dev; @@ -2228,7 +2228,7 @@ err_free: return -EINVAL; } -static void __devexit ipmi_pnp_remove(struct pnp_dev *dev) +static void ipmi_pnp_remove(struct pnp_dev *dev) { struct smi_info *info = pnp_get_drvdata(dev); @@ -2258,7 +2258,7 @@ struct dmi_ipmi_data { u8 slave_addr; }; -static int __devinit decode_dmi(const struct dmi_header *dm, +static int decode_dmi(const struct dmi_header *dm, struct dmi_ipmi_data *dmi) { const u8 *data = (const u8 *)dm; @@ -2320,7 +2320,7 @@ static int __devinit decode_dmi(const struct dmi_header *dm, return 0; } -static void __devinit try_init_dmi(struct dmi_ipmi_data *ipmi_data) +static void try_init_dmi(struct dmi_ipmi_data *ipmi_data) { struct smi_info *info; @@ -2388,7 +2388,7 @@ static void __devinit try_init_dmi(struct dmi_ipmi_data *ipmi_data) kfree(info); } -static void __devinit dmi_find_bmc(void) +static void dmi_find_bmc(void) { const struct dmi_device *dev = NULL; struct dmi_ipmi_data data; @@ -2424,7 +2424,7 @@ static void ipmi_pci_cleanup(struct smi_info *info) pci_disable_device(pdev); } -static int __devinit ipmi_pci_probe_regspacing(struct smi_info *info) +static int ipmi_pci_probe_regspacing(struct smi_info *info) { if (info->si_type == SI_KCS) { unsigned char status; @@ -2456,7 +2456,7 @@ static int __devinit ipmi_pci_probe_regspacing(struct smi_info *info) return DEFAULT_REGSPACING; } -static int __devinit ipmi_pci_probe(struct pci_dev *pdev, +static int ipmi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int rv; @@ -2529,7 +2529,7 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, return 0; } -static void __devexit ipmi_pci_remove(struct pci_dev *pdev) +static void ipmi_pci_remove(struct pci_dev *pdev) { struct smi_info *info = pci_get_drvdata(pdev); cleanup_one_si(info); @@ -2551,7 +2551,7 @@ static struct pci_driver ipmi_pci_driver = { #endif /* CONFIG_PCI */ static struct of_device_id ipmi_match[]; -static int __devinit ipmi_probe(struct platform_device *dev) +static int ipmi_probe(struct platform_device *dev) { #ifdef CONFIG_OF const struct of_device_id *match; @@ -2635,7 +2635,7 @@ static int __devinit ipmi_probe(struct platform_device *dev) return 0; } -static int __devexit ipmi_remove(struct platform_device *dev) +static int ipmi_remove(struct platform_device *dev) { #ifdef CONFIG_OF cleanup_one_si(dev_get_drvdata(&dev->dev)); @@ -3047,7 +3047,7 @@ static inline void wait_for_timer_and_thread(struct smi_info *smi_info) } } -static __devinitdata struct ipmi_default_vals +static struct ipmi_default_vals { int type; int port; @@ -3059,7 +3059,7 @@ static __devinitdata struct ipmi_default_vals { .port = 0 } }; -static void __devinit default_find_bmc(void) +static void default_find_bmc(void) { struct smi_info *info; int i; @@ -3359,7 +3359,7 @@ static int try_smi_init(struct smi_info *new_smi) return rv; } -static int __devinit init_ipmi_si(void) +static int init_ipmi_si(void) { int i; char *str; diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c index f74e892711d..e5d3e3f7a49 100644 --- a/drivers/char/mbcs.c +++ b/drivers/char/mbcs.c @@ -799,7 +799,7 @@ static int mbcs_remove(struct cx_dev *dev) return 0; } -static const struct cx_device_id __devinitconst mbcs_id_table[] = { +static const struct cx_device_id mbcs_id_table[] = { { .part_num = MBCS_PART_NUM, .mfg_num = MBCS_MFG_NUM, diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 0537903c985..c6fa3bc2baa 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -48,7 +48,7 @@ static inline unsigned long size_inside_page(unsigned long start, } #ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE -static inline int valid_phys_addr_range(unsigned long addr, size_t count) +static inline int valid_phys_addr_range(phys_addr_t addr, size_t count) { return addr + count <= __pa(high_memory); } @@ -96,7 +96,7 @@ void __weak unxlate_dev_mem_ptr(unsigned long phys, void *addr) static ssize_t read_mem(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - unsigned long p = *ppos; + phys_addr_t p = *ppos; ssize_t read, sz; char *ptr; @@ -153,7 +153,7 @@ static ssize_t read_mem(struct file *file, char __user *buf, static ssize_t write_mem(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - unsigned long p = *ppos; + phys_addr_t p = *ppos; ssize_t written, sz; unsigned long copied; void *ptr; @@ -226,7 +226,7 @@ int __weak phys_mem_access_prot_allowed(struct file *file, * */ #ifdef pgprot_noncached -static int uncached_access(struct file *file, unsigned long addr) +static int uncached_access(struct file *file, phys_addr_t addr) { #if defined(CONFIG_IA64) /* @@ -258,7 +258,7 @@ static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, unsigned long size, pgprot_t vma_prot) { #ifdef pgprot_noncached - unsigned long offset = pfn << PAGE_SHIFT; + phys_addr_t offset = pfn << PAGE_SHIFT; if (uncached_access(file, offset)) return pgprot_noncached(vma_prot); diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c index b304ec05250..3f79a9fb6b1 100644 --- a/drivers/char/pc8736x_gpio.c +++ b/drivers/char/pc8736x_gpio.c @@ -345,8 +345,7 @@ static void __exit pc8736x_gpio_cleanup(void) unregister_chrdev_region(MKDEV(major,0), PC8736X_GPIO_CT); release_region(pc8736x_gpio_base, PC8736X_GPIO_RANGE); - platform_device_del(pdev); - platform_device_put(pdev); + platform_device_unregister(pdev); } module_init(pc8736x_gpio_init); diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c index 6abdde4da2b..588063ac951 100644 --- a/drivers/char/ps3flash.c +++ b/drivers/char/ps3flash.c @@ -363,7 +363,7 @@ static struct miscdevice ps3flash_misc = { .fops = &ps3flash_fops, }; -static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev) +static int ps3flash_probe(struct ps3_system_bus_device *_dev) { struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); struct ps3flash_private *priv; diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 0bb207eaef2..54a3a6d0981 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -285,7 +285,7 @@ static long raw_ctl_compat_ioctl(struct file *file, unsigned int cmd, static const struct file_operations raw_fops = { .read = do_sync_read, - .aio_read = blkdev_aio_read, + .aio_read = generic_file_aio_read, .write = do_sync_write, .aio_write = blkdev_aio_write, .fsync = blkdev_fsync, diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 9b4f0116ff2..d780295a147 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -1164,7 +1164,7 @@ static struct acpi_driver sonypi_acpi_driver = { }; #endif -static int __devinit sonypi_create_input_devices(struct platform_device *pdev) +static int sonypi_create_input_devices(struct platform_device *pdev) { struct input_dev *jog_dev; struct input_dev *key_dev; @@ -1225,7 +1225,7 @@ static int __devinit sonypi_create_input_devices(struct platform_device *pdev) return error; } -static int __devinit sonypi_setup_ioports(struct sonypi_device *dev, +static int sonypi_setup_ioports(struct sonypi_device *dev, const struct sonypi_ioport_list *ioport_list) { /* try to detect if sony-laptop is being used and thus @@ -1265,7 +1265,7 @@ static int __devinit sonypi_setup_ioports(struct sonypi_device *dev, return -EBUSY; } -static int __devinit sonypi_setup_irq(struct sonypi_device *dev, +static int sonypi_setup_irq(struct sonypi_device *dev, const struct sonypi_irq_list *irq_list) { while (irq_list->irq) { @@ -1282,7 +1282,7 @@ static int __devinit sonypi_setup_irq(struct sonypi_device *dev, return -EBUSY; } -static void __devinit sonypi_display_info(void) +static void sonypi_display_info(void) { printk(KERN_INFO "sonypi: detected type%d model, " "verbose = %d, fnkeyinit = %s, camera = %s, " @@ -1304,7 +1304,7 @@ static void __devinit sonypi_display_info(void) sonypi_misc_device.minor); } -static int __devinit sonypi_probe(struct platform_device *dev) +static int sonypi_probe(struct platform_device *dev) { const struct sonypi_ioport_list *ioport_list; const struct sonypi_irq_list *irq_list; @@ -1428,7 +1428,7 @@ static int __devinit sonypi_probe(struct platform_device *dev) return error; } -static int __devexit sonypi_remove(struct platform_device *dev) +static int sonypi_remove(struct platform_device *dev) { sonypi_disable(); @@ -1491,7 +1491,7 @@ static struct platform_driver sonypi_driver = { .pm = SONYPI_PM, }, .probe = sonypi_probe, - .remove = __devexit_p(sonypi_remove), + .remove = sonypi_remove, .shutdown = sonypi_shutdown, }; diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c index ad264185eb1..34c63f85104 100644 --- a/drivers/char/tb0219.c +++ b/drivers/char/tb0219.c @@ -284,7 +284,7 @@ static void tb0219_pci_irq_init(void) vr41xx_set_irq_level(TB0219_PCI_SLOT3_PIN, IRQ_LEVEL_LOW); } -static int __devinit tb0219_probe(struct platform_device *dev) +static int tb0219_probe(struct platform_device *dev) { int retval; @@ -318,7 +318,7 @@ static int __devinit tb0219_probe(struct platform_device *dev) return 0; } -static int __devexit tb0219_remove(struct platform_device *dev) +static int tb0219_remove(struct platform_device *dev) { _machine_restart = old_machine_restart; @@ -334,7 +334,7 @@ static struct platform_device *tb0219_platform_device; static struct platform_driver tb0219_device_driver = { .probe = tb0219_probe, - .remove = __devexit_p(tb0219_remove), + .remove = tb0219_remove, .driver = { .name = "TB0219", .owner = THIS_MODULE, diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index 5a831aec9d4..fb447bd0cb6 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -555,7 +555,7 @@ static struct tpm_vendor_specific tpm_tis_i2c = { .miscdev.fops = &tis_ops, }; -static int __devinit tpm_tis_i2c_init(struct device *dev) +static int tpm_tis_i2c_init(struct device *dev) { u32 vendor; int rc = 0; @@ -632,7 +632,7 @@ static const struct i2c_device_id tpm_tis_i2c_table[] = { MODULE_DEVICE_TABLE(i2c, tpm_tis_i2c_table); static SIMPLE_DEV_PM_OPS(tpm_tis_i2c_ops, tpm_pm_suspend, tpm_pm_resume); -static int __devinit tpm_tis_i2c_probe(struct i2c_client *client, +static int tpm_tis_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int rc; @@ -656,7 +656,7 @@ static int __devinit tpm_tis_i2c_probe(struct i2c_client *client, return rc; } -static int __devexit tpm_tis_i2c_remove(struct i2c_client *client) +static int tpm_tis_i2c_remove(struct i2c_client *client) { struct tpm_chip *chip = tpm_dev.chip; release_locality(chip, chip->vendor.locality, 1); diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index efc4ab36a9d..7da840d487d 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -32,7 +32,7 @@ static const char tpm_ibmvtpm_driver_name[] = "tpm_ibmvtpm"; -static struct vio_device_id tpm_ibmvtpm_device_table[] __devinitdata = { +static struct vio_device_id tpm_ibmvtpm_device_table[] = { { "IBM,vtpm", "IBM,vtpm"}, { "", "" } }; @@ -267,7 +267,7 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm) * Return value: * 0 */ -static int __devexit tpm_ibmvtpm_remove(struct vio_dev *vdev) +static int tpm_ibmvtpm_remove(struct vio_dev *vdev) { struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev); int rc = 0; @@ -602,7 +602,7 @@ static void ibmvtpm_tasklet(void *data) * 0 - Success * Non-zero - Failure */ -static int __devinit tpm_ibmvtpm_probe(struct vio_dev *vio_dev, +static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev, const struct vio_device_id *id) { struct ibmvtpm_dev *ibmvtpm; diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index 3251a44e8ce..2b480c2960b 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -415,7 +415,7 @@ static const struct pnp_device_id tpm_inf_pnp_tbl[] = { MODULE_DEVICE_TABLE(pnp, tpm_inf_pnp_tbl); -static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, +static int tpm_inf_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) { int rc = 0; @@ -594,7 +594,7 @@ err_last: return rc; } -static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev) +static void tpm_inf_pnp_remove(struct pnp_dev *dev) { struct tpm_chip *chip = pnp_get_drvdata(dev); @@ -655,7 +655,7 @@ static struct pnp_driver tpm_inf_pnp_driver = { .probe = tpm_inf_pnp_probe, .suspend = tpm_inf_pnp_suspend, .resume = tpm_inf_pnp_resume, - .remove = __devexit_p(tpm_inf_pnp_remove) + .remove = tpm_inf_pnp_remove }; static int __init init_inf(void) diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 6bdf2671254..ea31dafbcac 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -729,7 +729,7 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) #endif #ifdef CONFIG_PNP -static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, +static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev, const struct pnp_device_id *pnp_id) { resource_size_t start, len; @@ -769,7 +769,7 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev) return ret; } -static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = { +static struct pnp_device_id tpm_pnp_tbl[] = { {"PNP0C31", 0}, /* TPM */ {"ATM1200", 0}, /* Atmel */ {"IFX0102", 0}, /* Infineon */ @@ -783,7 +783,7 @@ static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = { }; MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl); -static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev) +static void tpm_tis_pnp_remove(struct pnp_dev *dev) { struct tpm_chip *chip = pnp_get_drvdata(dev); diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 8ab9c3d4bf1..90493d4ead1 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1846,7 +1846,7 @@ static void remove_controlq_data(struct ports_device *portdev) * config space to see how many ports the host has spawned. We * initialize each port found. */ -static int __devinit virtcons_probe(struct virtio_device *vdev) +static int virtcons_probe(struct virtio_device *vdev) { struct ports_device *portdev; int err; diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index 2c5d15beea3..5224da5202d 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -595,7 +595,7 @@ static const struct file_operations hwicap_fops = { .llseek = noop_llseek, }; -static int __devinit hwicap_setup(struct device *dev, int id, +static int hwicap_setup(struct device *dev, int id, const struct resource *regs_res, const struct hwicap_driver_config *config, const struct config_registers *config_regs) @@ -717,7 +717,7 @@ static struct hwicap_driver_config fifo_icap_config = { .reset = fifo_icap_reset, }; -static int __devexit hwicap_remove(struct device *dev) +static int hwicap_remove(struct device *dev) { struct hwicap_drvdata *drvdata; @@ -740,7 +740,7 @@ static int __devexit hwicap_remove(struct device *dev) } #ifdef CONFIG_OF -static int __devinit hwicap_of_probe(struct platform_device *op, +static int hwicap_of_probe(struct platform_device *op, const struct hwicap_driver_config *config) { struct resource res; @@ -785,8 +785,8 @@ static inline int hwicap_of_probe(struct platform_device *op, } #endif /* CONFIG_OF */ -static const struct of_device_id __devinitconst hwicap_of_match[]; -static int __devinit hwicap_drv_probe(struct platform_device *pdev) +static const struct of_device_id hwicap_of_match[]; +static int hwicap_drv_probe(struct platform_device *pdev) { const struct of_device_id *match; struct resource *res; @@ -822,14 +822,14 @@ static int __devinit hwicap_drv_probe(struct platform_device *pdev) &buffer_icap_config, regs); } -static int __devexit hwicap_drv_remove(struct platform_device *pdev) +static int hwicap_drv_remove(struct platform_device *pdev) { return hwicap_remove(&pdev->dev); } #ifdef CONFIG_OF /* Match table for device tree binding */ -static const struct of_device_id __devinitconst hwicap_of_match[] = { +static const struct of_device_id hwicap_of_match[] = { { .compatible = "xlnx,opb-hwicap-1.00.b", .data = &buffer_icap_config}, { .compatible = "xlnx,xps-hwicap-1.00.a", .data = &fifo_icap_config}, {}, diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index bace9e98f75..823f62d900b 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -42,10 +42,12 @@ config COMMON_CLK_WM831X config COMMON_CLK_VERSATILE bool "Clock driver for ARM Reference designs" - depends on ARCH_INTEGRATOR || ARCH_REALVIEW + depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS ---help--- - Supports clocking on ARM Reference designs Integrator/AP, - Integrator/CP, RealView PB1176, EB, PB11MP and PBX. + Supports clocking on ARM Reference designs: + - Integrator/AP and Integrator/CP + - RealView PB1176, EB, PB11MP and PBX + - Versatile Express config COMMON_CLK_MAX77686 tristate "Clock driver for Maxim 77686 MFD" @@ -53,4 +55,12 @@ config COMMON_CLK_MAX77686 ---help--- This driver supports Maxim 77686 crystal oscillator clock. +config CLK_TWL6040 + tristate "External McPDM functional clock from twl6040" + depends on TWL6040_CORE + ---help--- + Enable the external functional clock support on OMAP4+ platforms for + McPDM. McPDM module is using the external bit clock on the McPDM bus + as functional clock. + endmenu diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 71a25b91de0..2701235d575 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -23,3 +23,4 @@ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o # Chip specific obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o +obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o diff --git a/drivers/clk/clk-bcm2835.c b/drivers/clk/clk-bcm2835.c index 67ad16b20b8..b61ee2c5af8 100644 --- a/drivers/clk/clk-bcm2835.c +++ b/drivers/clk/clk-bcm2835.c @@ -33,17 +33,17 @@ void __init bcm2835_init_clocks(void) clk = clk_register_fixed_rate(NULL, "sys_pclk", NULL, CLK_IS_ROOT, 250000000); - if (!clk) + if (IS_ERR(clk)) pr_err("sys_pclk not registered\n"); clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 126000000); - if (!clk) + if (IS_ERR(clk)) pr_err("apb_pclk not registered\n"); clk = clk_register_fixed_rate(NULL, "uart0_pclk", NULL, CLK_IS_ROOT, 3000000); - if (!clk) + if (IS_ERR(clk)) pr_err("uart0_pclk not registered\n"); ret = clk_register_clkdev(clk, NULL, "20201000.uart"); if (ret) @@ -51,7 +51,7 @@ void __init bcm2835_init_clocks(void) clk = clk_register_fixed_rate(NULL, "uart1_pclk", NULL, CLK_IS_ROOT, 125000000); - if (!clk) + if (IS_ERR(clk)) pr_err("uart1_pclk not registered\n"); ret = clk_register_clkdev(clk, NULL, "20215000.uart"); if (ret) diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c index f5ec0eebd4d..af78ed6b67e 100644 --- a/drivers/clk/clk-fixed-rate.c +++ b/drivers/clk/clk-fixed-rate.c @@ -97,7 +97,7 @@ void __init of_fixed_clk_setup(struct device_node *node) of_property_read_string(node, "clock-output-names", &clk_name); clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, rate); - if (clk) + if (!IS_ERR(clk)) of_clk_add_provider(node, of_clk_src_simple_get, clk); } EXPORT_SYMBOL_GPL(of_fixed_clk_setup); diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c index ac5f5434cb9..d098f72e1d5 100644 --- a/drivers/clk/clk-max77686.c +++ b/drivers/clk/clk-max77686.c @@ -143,7 +143,7 @@ static int max77686_clk_register(struct device *dev, return 0; } -static __devinit int max77686_clk_probe(struct platform_device *pdev) +static int max77686_clk_probe(struct platform_device *pdev) { struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max77686_clk **max77686_clks; @@ -199,7 +199,7 @@ out: return ret; } -static int __devexit max77686_clk_remove(struct platform_device *pdev) +static int max77686_clk_remove(struct platform_device *pdev) { struct max77686_clk **max77686_clks = platform_get_drvdata(pdev); int i; @@ -223,7 +223,7 @@ static struct platform_driver max77686_clk_driver = { .owner = THIS_MODULE, }, .probe = max77686_clk_probe, - .remove = __devexit_p(max77686_clk_remove), + .remove = max77686_clk_remove, .id_table = max77686_clk_id, }; diff --git a/drivers/clk/clk-prima2.c b/drivers/clk/clk-prima2.c index 517874fa685..a203ecccdc4 100644 --- a/drivers/clk/clk-prima2.c +++ b/drivers/clk/clk-prima2.c @@ -1054,118 +1054,118 @@ void __init sirfsoc_of_clk_init(void) /* These are always available (RTC and 26MHz OSC)*/ clk = clk_register_fixed_rate(NULL, "rtc", NULL, CLK_IS_ROOT, 32768); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk = clk_register_fixed_rate(NULL, "osc", NULL, CLK_IS_ROOT, 26000000); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk = clk_register(NULL, &clk_pll1.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk = clk_register(NULL, &clk_pll2.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk = clk_register(NULL, &clk_pll3.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk = clk_register(NULL, &clk_mem.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk = clk_register(NULL, &clk_sys.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk = clk_register(NULL, &clk_security.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b8030000.security"); clk = clk_register(NULL, &clk_dsp.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk = clk_register(NULL, &clk_gps.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "a8010000.gps"); clk = clk_register(NULL, &clk_mf.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk = clk_register(NULL, &clk_io.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "io"); clk = clk_register(NULL, &clk_cpu.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "cpu"); clk = clk_register(NULL, &clk_uart0.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b0050000.uart"); clk = clk_register(NULL, &clk_uart1.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b0060000.uart"); clk = clk_register(NULL, &clk_uart2.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b0070000.uart"); clk = clk_register(NULL, &clk_tsc.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b0110000.tsc"); clk = clk_register(NULL, &clk_i2c0.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b00e0000.i2c"); clk = clk_register(NULL, &clk_i2c1.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b00f0000.i2c"); clk = clk_register(NULL, &clk_spi0.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b00d0000.spi"); clk = clk_register(NULL, &clk_spi1.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b0170000.spi"); clk = clk_register(NULL, &clk_pwmc.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b0130000.pwm"); clk = clk_register(NULL, &clk_efuse.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b0140000.efusesys"); clk = clk_register(NULL, &clk_pulse.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b0150000.pulsec"); clk = clk_register(NULL, &clk_dmac0.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b00b0000.dma-controller"); clk = clk_register(NULL, &clk_dmac1.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b0160000.dma-controller"); clk = clk_register(NULL, &clk_nand.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b0030000.nand"); clk = clk_register(NULL, &clk_audio.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b0040000.audio"); clk = clk_register(NULL, &clk_usp0.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b0080000.usp"); clk = clk_register(NULL, &clk_usp1.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b0090000.usp"); clk = clk_register(NULL, &clk_usp2.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b00a0000.usp"); clk = clk_register(NULL, &clk_vip.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b00c0000.vip"); clk = clk_register(NULL, &clk_gfx.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "98000000.graphics"); clk = clk_register(NULL, &clk_mm.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "a0000000.multimedia"); clk = clk_register(NULL, &clk_lcd.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "90010000.display"); clk = clk_register(NULL, &clk_vpp.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "90020000.vpp"); clk = clk_register(NULL, &clk_mmc01.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk = clk_register(NULL, &clk_mmc23.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk = clk_register(NULL, &clk_mmc45.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk = clk_register(NULL, &usb_pll_clk_hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk = clk_register(NULL, &clk_usb0.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b00e0000.usb"); clk = clk_register(NULL, &clk_usb1.hw); - BUG_ON(!clk); + BUG_ON(IS_ERR(clk)); clk_register_clkdev(clk, NULL, "b00f0000.usb"); } diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c new file mode 100644 index 00000000000..bc1e713e7b9 --- /dev/null +++ b/drivers/clk/clk-twl6040.c @@ -0,0 +1,126 @@ +/* +* TWL6040 clock module driver for OMAP4 McPDM functional clock +* +* Copyright (C) 2012 Texas Instruments Inc. +* Peter Ujfalusi <peter.ujfalusi@ti.com> +* +* 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. +* +* 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., 51 Franklin St, Fifth Floor, Boston, MA +* 02110-1301 USA +* +*/ + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/mfd/twl6040.h> +#include <linux/clk-provider.h> + +struct twl6040_clk { + struct twl6040 *twl6040; + struct device *dev; + struct clk_hw mcpdm_fclk; + struct clk *clk; + int enabled; +}; + +static int twl6040_bitclk_is_enabled(struct clk_hw *hw) +{ + struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk, + mcpdm_fclk); + return twl6040_clk->enabled; +} + +static int twl6040_bitclk_prepare(struct clk_hw *hw) +{ + struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk, + mcpdm_fclk); + int ret; + + ret = twl6040_power(twl6040_clk->twl6040, 1); + if (!ret) + twl6040_clk->enabled = 1; + + return ret; +} + +static void twl6040_bitclk_unprepare(struct clk_hw *hw) +{ + struct twl6040_clk *twl6040_clk = container_of(hw, struct twl6040_clk, + mcpdm_fclk); + int ret; + + ret = twl6040_power(twl6040_clk->twl6040, 0); + if (!ret) + twl6040_clk->enabled = 0; +} + +static const struct clk_ops twl6040_mcpdm_ops = { + .is_enabled = twl6040_bitclk_is_enabled, + .prepare = twl6040_bitclk_prepare, + .unprepare = twl6040_bitclk_unprepare, +}; + +static struct clk_init_data wm831x_clkout_init = { + .name = "mcpdm_fclk", + .ops = &twl6040_mcpdm_ops, + .flags = CLK_IS_ROOT, +}; + +static int __devinit twl6040_clk_probe(struct platform_device *pdev) +{ + struct twl6040 *twl6040 = dev_get_drvdata(pdev->dev.parent); + struct twl6040_clk *clkdata; + + clkdata = devm_kzalloc(&pdev->dev, sizeof(*clkdata), GFP_KERNEL); + if (!clkdata) + return -ENOMEM; + + clkdata->dev = &pdev->dev; + clkdata->twl6040 = twl6040; + + clkdata->mcpdm_fclk.init = &wm831x_clkout_init; + clkdata->clk = clk_register(&pdev->dev, &clkdata->mcpdm_fclk); + if (IS_ERR(clkdata->clk)) + return PTR_ERR(clkdata->clk); + + dev_set_drvdata(&pdev->dev, clkdata); + + return 0; +} + +static int __devexit twl6040_clk_remove(struct platform_device *pdev) +{ + struct twl6040_clk *clkdata = dev_get_drvdata(&pdev->dev); + + clk_unregister(clkdata->clk); + + return 0; +} + +static struct platform_driver twl6040_clk_driver = { + .driver = { + .name = "twl6040-clk", + .owner = THIS_MODULE, + }, + .probe = twl6040_clk_probe, + .remove = __devexit_p(twl6040_clk_remove), +}; + +module_platform_driver(twl6040_clk_driver); + +MODULE_DESCRIPTION("TWL6040 clock driver for McPDM functional clock"); +MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>"); +MODULE_ALIAS("platform:twl6040-clk"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c index a885600f527..fe25570874d 100644 --- a/drivers/clk/clk-vt8500.c +++ b/drivers/clk/clk-vt8500.c @@ -120,8 +120,17 @@ static unsigned long vt8500_dclk_recalc_rate(struct clk_hw *hw, static long vt8500_dclk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) { + struct clk_device *cdev = to_clk_device(hw); u32 divisor = *prate / rate; + /* + * If this is a request for SDMMC we have to adjust the divisor + * when >31 to use the fixed predivisor + */ + if ((cdev->div_mask == 0x3F) && (divisor > 31)) { + divisor = 64 * ((divisor / 64) + 1); + } + return *prate / divisor; } @@ -135,6 +144,15 @@ static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate, if (divisor == cdev->div_mask + 1) divisor = 0; + /* SDMMC mask may need to be corrected before testing if its valid */ + if ((cdev->div_mask == 0x3F) && (divisor > 31)) { + /* + * Bit 5 is a fixed /64 predivisor. If the requested divisor + * is >31 then correct for the fixed divisor being required. + */ + divisor = 0x20 + (divisor / 64); + } + if (divisor > cdev->div_mask) { pr_err("%s: invalid divisor for clock\n", __func__); return -EINVAL; diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c index e7b7765e85f..16ed0680855 100644 --- a/drivers/clk/clk-wm831x.c +++ b/drivers/clk/clk-wm831x.c @@ -350,7 +350,7 @@ static struct clk_init_data wm831x_clkout_init = { .flags = CLK_SET_RATE_PARENT, }; -static __devinit int wm831x_clk_probe(struct platform_device *pdev) +static int wm831x_clk_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_clk *clkdata; @@ -370,49 +370,33 @@ static __devinit int wm831x_clk_probe(struct platform_device *pdev) clkdata->xtal_ena = ret & WM831X_XTAL_ENA; clkdata->xtal_hw.init = &wm831x_xtal_init; - clkdata->xtal = clk_register(&pdev->dev, &clkdata->xtal_hw); - if (!clkdata->xtal) - return -EINVAL; + clkdata->xtal = devm_clk_register(&pdev->dev, &clkdata->xtal_hw); + if (IS_ERR(clkdata->xtal)) + return PTR_ERR(clkdata->xtal); clkdata->fll_hw.init = &wm831x_fll_init; - clkdata->fll = clk_register(&pdev->dev, &clkdata->fll_hw); - if (!clkdata->fll) { - ret = -EINVAL; - goto err_xtal; - } + clkdata->fll = devm_clk_register(&pdev->dev, &clkdata->fll_hw); + if (IS_ERR(clkdata->fll)) + return PTR_ERR(clkdata->fll); clkdata->clkout_hw.init = &wm831x_clkout_init; - clkdata->clkout = clk_register(&pdev->dev, &clkdata->clkout_hw); - if (!clkdata->clkout) { - ret = -EINVAL; - goto err_fll; - } + clkdata->clkout = devm_clk_register(&pdev->dev, &clkdata->clkout_hw); + if (IS_ERR(clkdata->clkout)) + return PTR_ERR(clkdata->clkout); dev_set_drvdata(&pdev->dev, clkdata); return 0; - -err_fll: - clk_unregister(clkdata->fll); -err_xtal: - clk_unregister(clkdata->xtal); - return ret; } -static int __devexit wm831x_clk_remove(struct platform_device *pdev) +static int wm831x_clk_remove(struct platform_device *pdev) { - struct wm831x_clk *clkdata = dev_get_drvdata(&pdev->dev); - - clk_unregister(clkdata->clkout); - clk_unregister(clkdata->fll); - clk_unregister(clkdata->xtal); - return 0; } static struct platform_driver wm831x_clk_driver = { .probe = wm831x_clk_probe, - .remove = __devexit_p(wm831x_clk_remove), + .remove = wm831x_clk_remove, .driver = { .name = "wm831x-clk", .owner = THIS_MODULE, diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 56e4495ebeb..251e45d6024 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -17,6 +17,7 @@ #include <linux/list.h> #include <linux/slab.h> #include <linux/of.h> +#include <linux/device.h> static DEFINE_SPINLOCK(enable_lock); static DEFINE_MUTEX(prepare_lock); @@ -218,8 +219,17 @@ static void clk_disable_unused_subtree(struct clk *clk) if (clk->flags & CLK_IGNORE_UNUSED) goto unlock_out; - if (__clk_is_enabled(clk) && clk->ops->disable) - clk->ops->disable(clk->hw); + /* + * some gate clocks have special needs during the disable-unused + * sequence. call .disable_unused if available, otherwise fall + * back to .disable + */ + if (__clk_is_enabled(clk)) { + if (clk->ops->disable_unused) + clk->ops->disable_unused(clk->hw); + else if (clk->ops->disable) + clk->ops->disable(clk->hw); + } unlock_out: spin_unlock_irqrestore(&enable_lock, flags); @@ -261,7 +271,7 @@ inline struct clk_hw *__clk_get_hw(struct clk *clk) inline u8 __clk_get_num_parents(struct clk *clk) { - return !clk ? -EINVAL : clk->num_parents; + return !clk ? 0 : clk->num_parents; } inline struct clk *__clk_get_parent(struct clk *clk) @@ -269,14 +279,14 @@ inline struct clk *__clk_get_parent(struct clk *clk) return !clk ? NULL : clk->parent; } -inline int __clk_get_enable_count(struct clk *clk) +inline unsigned int __clk_get_enable_count(struct clk *clk) { - return !clk ? -EINVAL : clk->enable_count; + return !clk ? 0 : clk->enable_count; } -inline int __clk_get_prepare_count(struct clk *clk) +inline unsigned int __clk_get_prepare_count(struct clk *clk) { - return !clk ? -EINVAL : clk->prepare_count; + return !clk ? 0 : clk->prepare_count; } unsigned long __clk_get_rate(struct clk *clk) @@ -302,15 +312,15 @@ out: inline unsigned long __clk_get_flags(struct clk *clk) { - return !clk ? -EINVAL : clk->flags; + return !clk ? 0 : clk->flags; } -int __clk_is_enabled(struct clk *clk) +bool __clk_is_enabled(struct clk *clk) { int ret; if (!clk) - return -EINVAL; + return false; /* * .is_enabled is only mandatory for clocks that gate @@ -323,7 +333,7 @@ int __clk_is_enabled(struct clk *clk) ret = clk->ops->is_enabled(clk->hw); out: - return ret; + return !!ret; } static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk) @@ -568,7 +578,7 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) unsigned long parent_rate = 0; if (!clk) - return -EINVAL; + return 0; if (!clk->ops->round_rate) { if (clk->flags & CLK_SET_RATE_PARENT) @@ -1297,12 +1307,20 @@ int __clk_init(struct device *dev, struct clk *clk) * walk the list of orphan clocks and reparent any that are children of * this clock */ - hlist_for_each_entry_safe(orphan, tmp, tmp2, &clk_orphan_list, child_node) + hlist_for_each_entry_safe(orphan, tmp, tmp2, &clk_orphan_list, child_node) { + if (orphan->ops->get_parent) { + i = orphan->ops->get_parent(orphan->hw); + if (!strcmp(clk->name, orphan->parent_names[i])) + __clk_reparent(orphan, clk); + continue; + } + for (i = 0; i < orphan->num_parents; i++) if (!strcmp(clk->name, orphan->parent_names[i])) { __clk_reparent(orphan, clk); break; } + } /* * optional platform-specific magic @@ -1361,28 +1379,9 @@ struct clk *__clk_register(struct device *dev, struct clk_hw *hw) } EXPORT_SYMBOL_GPL(__clk_register); -/** - * clk_register - allocate a new clock, register it and return an opaque cookie - * @dev: device that is registering this clock - * @hw: link to hardware-specific clock data - * - * clk_register is the primary interface for populating the clock tree with new - * clock nodes. It returns a pointer to the newly allocated struct clk which - * cannot be dereferenced by driver code but may be used in conjuction with the - * rest of the clock API. In the event of an error clk_register will return an - * error code; drivers must test for an error code after calling clk_register. - */ -struct clk *clk_register(struct device *dev, struct clk_hw *hw) +static int _clk_register(struct device *dev, struct clk_hw *hw, struct clk *clk) { int i, ret; - struct clk *clk; - - clk = kzalloc(sizeof(*clk), GFP_KERNEL); - if (!clk) { - pr_err("%s: could not allocate clk\n", __func__); - ret = -ENOMEM; - goto fail_out; - } clk->name = kstrdup(hw->init->name, GFP_KERNEL); if (!clk->name) { @@ -1420,7 +1419,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) ret = __clk_init(dev, clk); if (!ret) - return clk; + return 0; fail_parent_names_copy: while (--i >= 0) @@ -1429,6 +1428,36 @@ fail_parent_names_copy: fail_parent_names: kfree(clk->name); fail_name: + return ret; +} + +/** + * clk_register - allocate a new clock, register it and return an opaque cookie + * @dev: device that is registering this clock + * @hw: link to hardware-specific clock data + * + * clk_register is the primary interface for populating the clock tree with new + * clock nodes. It returns a pointer to the newly allocated struct clk which + * cannot be dereferenced by driver code but may be used in conjuction with the + * rest of the clock API. In the event of an error clk_register will return an + * error code; drivers must test for an error code after calling clk_register. + */ +struct clk *clk_register(struct device *dev, struct clk_hw *hw) +{ + int ret; + struct clk *clk; + + clk = kzalloc(sizeof(*clk), GFP_KERNEL); + if (!clk) { + pr_err("%s: could not allocate clk\n", __func__); + ret = -ENOMEM; + goto fail_out; + } + + ret = _clk_register(dev, hw, clk); + if (!ret) + return clk; + kfree(clk); fail_out: return ERR_PTR(ret); @@ -1444,6 +1473,63 @@ EXPORT_SYMBOL_GPL(clk_register); void clk_unregister(struct clk *clk) {} EXPORT_SYMBOL_GPL(clk_unregister); +static void devm_clk_release(struct device *dev, void *res) +{ + clk_unregister(res); +} + +/** + * devm_clk_register - resource managed clk_register() + * @dev: device that is registering this clock + * @hw: link to hardware-specific clock data + * + * Managed clk_register(). Clocks returned from this function are + * automatically clk_unregister()ed on driver detach. See clk_register() for + * more information. + */ +struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw) +{ + struct clk *clk; + int ret; + + clk = devres_alloc(devm_clk_release, sizeof(*clk), GFP_KERNEL); + if (!clk) + return ERR_PTR(-ENOMEM); + + ret = _clk_register(dev, hw, clk); + if (!ret) { + devres_add(dev, clk); + } else { + devres_free(clk); + clk = ERR_PTR(ret); + } + + return clk; +} +EXPORT_SYMBOL_GPL(devm_clk_register); + +static int devm_clk_match(struct device *dev, void *res, void *data) +{ + struct clk *c = res; + if (WARN_ON(!c)) + return 0; + return c == data; +} + +/** + * devm_clk_unregister - resource managed clk_unregister() + * @clk: clock to unregister + * + * Deallocate a clock allocated with devm_clk_register(). Normally + * this function will not need to be called and the resource management + * code will ensure that the resource is freed. + */ +void devm_clk_unregister(struct device *dev, struct clk *clk) +{ + WARN_ON(devres_release(dev, devm_clk_release, devm_clk_match, clk)); +} +EXPORT_SYMBOL_GPL(devm_clk_unregister); + /*** clk rate change notifiers ***/ /** diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c index f00dffb9ad6..8dd476e2a9c 100644 --- a/drivers/clk/mxs/clk-imx23.c +++ b/drivers/clk/mxs/clk-imx23.c @@ -85,7 +85,7 @@ enum imx23_clk { cpu_xtal, hbus, xbus, lcdif_div, ssp_div, gpmi_div, emi_pll, emi_xtal, etm_div, saif_div, clk32k_div, rtc, adc, spdif_div, clk32k, dri, pwm, filt, uart, ssp, gpmi, spdif, emi, saif, - lcdif, etm, usb, usb_pwr, + lcdif, etm, usb, usb_phy, clk_max }; @@ -143,8 +143,8 @@ int __init mx23_clocks_init(void) clks[saif] = mxs_clk_gate("saif", "saif_div", SAIF, 31); clks[lcdif] = mxs_clk_gate("lcdif", "lcdif_div", PIX, 31); clks[etm] = mxs_clk_gate("etm", "etm_div", ETM, 31); - clks[usb] = mxs_clk_gate("usb", "usb_pwr", DIGCTRL, 2); - clks[usb_pwr] = clk_register_gate(NULL, "usb_pwr", "pll", 0, PLLCTRL0, 18, 0, &mxs_lock); + clks[usb] = mxs_clk_gate("usb", "usb_phy", DIGCTRL, 2); + clks[usb_phy] = clk_register_gate(NULL, "usb_phy", "pll", 0, PLLCTRL0, 18, 0, &mxs_lock); for (i = 0; i < ARRAY_SIZE(clks); i++) if (IS_ERR(clks[i])) { diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c index 42978f1b4bd..db3af087412 100644 --- a/drivers/clk/mxs/clk-imx28.c +++ b/drivers/clk/mxs/clk-imx28.c @@ -140,7 +140,7 @@ enum imx28_clk { emi_xtal, lcdif_div, etm_div, ptp, saif0_div, saif1_div, clk32k_div, rtc, lradc, spdif_div, clk32k, pwm, uart, ssp0, ssp1, ssp2, ssp3, gpmi, spdif, emi, saif0, saif1, lcdif, etm, - fec, can0, can1, usb0, usb1, usb0_pwr, usb1_pwr, enet_out, + fec, can0, can1, usb0, usb1, usb0_phy, usb1_phy, enet_out, clk_max }; @@ -218,10 +218,10 @@ int __init mx28_clocks_init(void) clks[fec] = mxs_clk_gate("fec", "hbus", ENET, 30); clks[can0] = mxs_clk_gate("can0", "ref_xtal", FLEXCAN, 30); clks[can1] = mxs_clk_gate("can1", "ref_xtal", FLEXCAN, 28); - clks[usb0] = mxs_clk_gate("usb0", "usb0_pwr", DIGCTRL, 2); - clks[usb1] = mxs_clk_gate("usb1", "usb1_pwr", DIGCTRL, 16); - clks[usb0_pwr] = clk_register_gate(NULL, "usb0_pwr", "pll0", 0, PLL0CTRL0, 18, 0, &mxs_lock); - clks[usb1_pwr] = clk_register_gate(NULL, "usb1_pwr", "pll1", 0, PLL1CTRL0, 18, 0, &mxs_lock); + clks[usb0] = mxs_clk_gate("usb0", "usb0_phy", DIGCTRL, 2); + clks[usb1] = mxs_clk_gate("usb1", "usb1_phy", DIGCTRL, 16); + clks[usb0_phy] = clk_register_gate(NULL, "usb0_phy", "pll0", 0, PLL0CTRL0, 18, 0, &mxs_lock); + clks[usb1_phy] = clk_register_gate(NULL, "usb1_phy", "pll1", 0, PLL1CTRL0, 18, 0, &mxs_lock); clks[enet_out] = clk_register_gate(NULL, "enet_out", "pll2", 0, ENET, 18, 0, &mxs_lock); for (i = 0; i < ARRAY_SIZE(clks); i++) diff --git a/drivers/clk/spear/clk-aux-synth.c b/drivers/clk/spear/clk-aux-synth.c index 6756e7c3bc0..bdfb4421c64 100644 --- a/drivers/clk/spear/clk-aux-synth.c +++ b/drivers/clk/spear/clk-aux-synth.c @@ -179,7 +179,8 @@ struct clk *clk_register_aux(const char *aux_name, const char *gate_name, if (gate_name) { struct clk *tgate_clk; - tgate_clk = clk_register_gate(NULL, gate_name, aux_name, 0, reg, + tgate_clk = clk_register_gate(NULL, gate_name, aux_name, + CLK_SET_RATE_PARENT, reg, aux->masks->enable_bit, 0, lock); if (IS_ERR_OR_NULL(tgate_clk)) goto free_aux; diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c index 5f1b6badeb1..1b9b65bca51 100644 --- a/drivers/clk/spear/clk-vco-pll.c +++ b/drivers/clk/spear/clk-vco-pll.c @@ -147,7 +147,7 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long drate, struct clk_pll *pll = to_clk_pll(hw); struct pll_rate_tbl *rtbl = pll->vco->rtbl; unsigned long flags = 0, val; - int i; + int uninitialized_var(i); clk_pll_round_rate_index(hw, drate, NULL, &i); diff --git a/drivers/clk/spear/clk.c b/drivers/clk/spear/clk.c index 7cd63788d54..628b6d5ed3d 100644 --- a/drivers/clk/spear/clk.c +++ b/drivers/clk/spear/clk.c @@ -32,5 +32,8 @@ long clk_round_rate_index(struct clk_hw *hw, unsigned long drate, } } + if ((*index) == rtbl_cnt) + (*index)--; + return rate; } diff --git a/drivers/clk/spear/spear1310_clock.c b/drivers/clk/spear/spear1310_clock.c index 0fcec2aae19..147e25f0040 100644 --- a/drivers/clk/spear/spear1310_clock.c +++ b/drivers/clk/spear/spear1310_clock.c @@ -313,6 +313,20 @@ static struct aux_clk_masks i2s_sclk_masks = { /* i2s prs1 aux rate configuration table, in ascending order of rates */ static struct aux_rate_tbl i2s_prs1_rtbl[] = { /* For parent clk = 49.152 MHz */ + {.xscale = 1, .yscale = 12, .eq = 0}, /* 2.048 MHz, smp freq = 8Khz */ + {.xscale = 11, .yscale = 96, .eq = 0}, /* 2.816 MHz, smp freq = 11Khz */ + {.xscale = 1, .yscale = 6, .eq = 0}, /* 4.096 MHz, smp freq = 16Khz */ + {.xscale = 11, .yscale = 48, .eq = 0}, /* 5.632 MHz, smp freq = 22Khz */ + + /* + * with parent clk = 49.152, freq gen is 8.192 MHz, smp freq = 32Khz + * with parent clk = 12.288, freq gen is 2.048 MHz, smp freq = 8Khz + */ + {.xscale = 1, .yscale = 3, .eq = 0}, + + /* For parent clk = 49.152 MHz */ + {.xscale = 17, .yscale = 37, .eq = 0}, /* 11.289 MHz, smp freq = 44Khz*/ + {.xscale = 1, .yscale = 2, .eq = 0}, /* 12.288 MHz */ }; @@ -374,9 +388,6 @@ void __init spear1310_clk_init(void) { struct clk *clk, *clk1; - clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); - clk_register_clkdev(clk, "apb_pclk", NULL); - clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT, 32000); clk_register_clkdev(clk, "osc_32k_clk", NULL); @@ -401,7 +412,7 @@ void __init spear1310_clk_init(void) clk = clk_register_gate(NULL, "rtc-spear", "osc_32k_clk", 0, SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_RTC_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, NULL, "fc900000.rtc"); + clk_register_clkdev(clk, NULL, "e0580000.rtc"); /* clock derived from 24 or 25 MHz osc clk */ /* vco-pll */ @@ -483,13 +494,18 @@ void __init spear1310_clk_init(void) clk_register_clkdev(clk, "ddr_clk", NULL); /* clock derived from pll1 clk */ - clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", 0, 1, 2); + clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", + CLK_SET_RATE_PARENT, 1, 2); clk_register_clkdev(clk, "cpu_clk", NULL); clk = clk_register_fixed_factor(NULL, "wdt_clk", "cpu_clk", 0, 1, 2); clk_register_clkdev(clk, NULL, "ec800620.wdt"); + clk = clk_register_fixed_factor(NULL, "smp_twd_clk", "cpu_clk", 0, 1, + 2); + clk_register_clkdev(clk, NULL, "smp_twd"); + clk = clk_register_fixed_factor(NULL, "ahb_clk", "pll1_clk", 0, 1, 6); clk_register_clkdev(clk, "ahb_clk", NULL); @@ -547,14 +563,14 @@ void __init spear1310_clk_init(void) clk_register_clkdev(clk1, "uart_syn_gclk", NULL); clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents, - ARRAY_SIZE(uart0_parents), 0, SPEAR1310_PERIP_CLK_CFG, - SPEAR1310_UART_CLK_SHIFT, SPEAR1310_UART_CLK_MASK, 0, - &_lock); + ARRAY_SIZE(uart0_parents), CLK_SET_RATE_PARENT, + SPEAR1310_PERIP_CLK_CFG, SPEAR1310_UART_CLK_SHIFT, + SPEAR1310_UART_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, "uart0_mclk", NULL); - clk = clk_register_gate(NULL, "uart0_clk", "uart0_mclk", 0, - SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_UART_CLK_ENB, 0, - &_lock); + clk = clk_register_gate(NULL, "uart0_clk", "uart0_mclk", + CLK_SET_RATE_PARENT, SPEAR1310_PERIP1_CLK_ENB, + SPEAR1310_UART_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "e0000000.serial"); clk = clk_register_aux("sdhci_syn_clk", "sdhci_syn_gclk", @@ -563,9 +579,9 @@ void __init spear1310_clk_init(void) clk_register_clkdev(clk, "sdhci_syn_clk", NULL); clk_register_clkdev(clk1, "sdhci_syn_gclk", NULL); - clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_syn_gclk", 0, - SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_SDHCI_CLK_ENB, 0, - &_lock); + clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_syn_gclk", + CLK_SET_RATE_PARENT, SPEAR1310_PERIP1_CLK_ENB, + SPEAR1310_SDHCI_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "b3000000.sdhci"); clk = clk_register_aux("cfxd_syn_clk", "cfxd_syn_gclk", "vco1div2_clk", @@ -574,9 +590,9 @@ void __init spear1310_clk_init(void) clk_register_clkdev(clk, "cfxd_syn_clk", NULL); clk_register_clkdev(clk1, "cfxd_syn_gclk", NULL); - clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_syn_gclk", 0, - SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_CFXD_CLK_ENB, 0, - &_lock); + clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_syn_gclk", + CLK_SET_RATE_PARENT, SPEAR1310_PERIP1_CLK_ENB, + SPEAR1310_CFXD_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "b2800000.cf"); clk_register_clkdev(clk, NULL, "arasan_xd"); @@ -587,9 +603,9 @@ void __init spear1310_clk_init(void) clk_register_clkdev(clk1, "c3_syn_gclk", NULL); clk = clk_register_mux(NULL, "c3_mclk", c3_parents, - ARRAY_SIZE(c3_parents), 0, SPEAR1310_PERIP_CLK_CFG, - SPEAR1310_C3_CLK_SHIFT, SPEAR1310_C3_CLK_MASK, 0, - &_lock); + ARRAY_SIZE(c3_parents), CLK_SET_RATE_PARENT, + SPEAR1310_PERIP_CLK_CFG, SPEAR1310_C3_CLK_SHIFT, + SPEAR1310_C3_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, "c3_mclk", NULL); clk = clk_register_gate(NULL, "c3_clk", "c3_mclk", 0, @@ -615,7 +631,7 @@ void __init spear1310_clk_init(void) ARRAY_SIZE(gmac_phy_parents), 0, SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GMAC_PHY_CLK_SHIFT, SPEAR1310_GMAC_PHY_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, NULL, "stmmacphy.0"); + clk_register_clkdev(clk, "stmmacphy.0", NULL); /* clcd */ clk = clk_register_mux(NULL, "clcd_syn_mclk", clcd_synth_parents, @@ -630,22 +646,22 @@ void __init spear1310_clk_init(void) clk_register_clkdev(clk, "clcd_syn_clk", NULL); clk = clk_register_mux(NULL, "clcd_pixel_mclk", clcd_pixel_parents, - ARRAY_SIZE(clcd_pixel_parents), 0, + ARRAY_SIZE(clcd_pixel_parents), CLK_SET_RATE_PARENT, SPEAR1310_PERIP_CLK_CFG, SPEAR1310_CLCD_CLK_SHIFT, SPEAR1310_CLCD_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "clcd_pixel_clk", NULL); + clk_register_clkdev(clk, "clcd_pixel_mclk", NULL); clk = clk_register_gate(NULL, "clcd_clk", "clcd_pixel_mclk", 0, SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_CLCD_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, "clcd_clk", NULL); + clk_register_clkdev(clk, NULL, "e1000000.clcd"); /* i2s */ clk = clk_register_mux(NULL, "i2s_src_mclk", i2s_src_parents, ARRAY_SIZE(i2s_src_parents), 0, SPEAR1310_I2S_CLK_CFG, SPEAR1310_I2S_SRC_CLK_SHIFT, SPEAR1310_I2S_SRC_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "i2s_src_clk", NULL); + clk_register_clkdev(clk, "i2s_src_mclk", NULL); clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mclk", 0, SPEAR1310_I2S_CLK_CFG, &i2s_prs1_masks, i2s_prs1_rtbl, @@ -653,10 +669,10 @@ void __init spear1310_clk_init(void) clk_register_clkdev(clk, "i2s_prs1_clk", NULL); clk = clk_register_mux(NULL, "i2s_ref_mclk", i2s_ref_parents, - ARRAY_SIZE(i2s_ref_parents), 0, SPEAR1310_I2S_CLK_CFG, - SPEAR1310_I2S_REF_SHIFT, SPEAR1310_I2S_REF_SEL_MASK, 0, - &_lock); - clk_register_clkdev(clk, "i2s_ref_clk", NULL); + ARRAY_SIZE(i2s_ref_parents), CLK_SET_RATE_PARENT, + SPEAR1310_I2S_CLK_CFG, SPEAR1310_I2S_REF_SHIFT, + SPEAR1310_I2S_REF_SEL_MASK, 0, &_lock); + clk_register_clkdev(clk, "i2s_ref_mclk", NULL); clk = clk_register_gate(NULL, "i2s_ref_pad_clk", "i2s_ref_mclk", 0, SPEAR1310_PERIP2_CLK_ENB, SPEAR1310_I2S_REF_PAD_CLK_ENB, @@ -664,7 +680,7 @@ void __init spear1310_clk_init(void) clk_register_clkdev(clk, "i2s_ref_pad_clk", NULL); clk = clk_register_aux("i2s_sclk_clk", "i2s_sclk_gclk", - "i2s_ref_pad_clk", 0, SPEAR1310_I2S_CLK_CFG, + "i2s_ref_mclk", 0, SPEAR1310_I2S_CLK_CFG, &i2s_sclk_masks, i2s_sclk_rtbl, ARRAY_SIZE(i2s_sclk_rtbl), &_lock, &clk1); clk_register_clkdev(clk, "i2s_sclk_clk", NULL); @@ -705,35 +721,37 @@ void __init spear1310_clk_init(void) clk = clk_register_gate(NULL, "usbh0_clk", "ahb_clk", 0, SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_UHC0_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, "usbh.0_clk", NULL); + clk_register_clkdev(clk, NULL, "e4000000.ohci"); + clk_register_clkdev(clk, NULL, "e4800000.ehci"); clk = clk_register_gate(NULL, "usbh1_clk", "ahb_clk", 0, SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_UHC1_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, "usbh.1_clk", NULL); + clk_register_clkdev(clk, NULL, "e5000000.ohci"); + clk_register_clkdev(clk, NULL, "e5800000.ehci"); clk = clk_register_gate(NULL, "uoc_clk", "ahb_clk", 0, SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_UOC_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, NULL, "uoc"); + clk_register_clkdev(clk, NULL, "e3800000.otg"); clk = clk_register_gate(NULL, "pcie_sata_0_clk", "ahb_clk", 0, SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_PCIE_SATA_0_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "dw_pcie.0"); - clk_register_clkdev(clk, NULL, "ahci.0"); + clk_register_clkdev(clk, NULL, "b1000000.ahci"); clk = clk_register_gate(NULL, "pcie_sata_1_clk", "ahb_clk", 0, SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_PCIE_SATA_1_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "dw_pcie.1"); - clk_register_clkdev(clk, NULL, "ahci.1"); + clk_register_clkdev(clk, NULL, "b1800000.ahci"); clk = clk_register_gate(NULL, "pcie_sata_2_clk", "ahb_clk", 0, SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_PCIE_SATA_2_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "dw_pcie.2"); - clk_register_clkdev(clk, NULL, "ahci.2"); + clk_register_clkdev(clk, NULL, "b4000000.ahci"); clk = clk_register_gate(NULL, "sysram0_clk", "ahb_clk", 0, SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_SYSRAM0_CLK_ENB, 0, @@ -751,10 +769,10 @@ void __init spear1310_clk_init(void) clk_register_clkdev(clk, "adc_syn_clk", NULL); clk_register_clkdev(clk1, "adc_syn_gclk", NULL); - clk = clk_register_gate(NULL, "adc_clk", "adc_syn_gclk", 0, - SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_ADC_CLK_ENB, 0, - &_lock); - clk_register_clkdev(clk, NULL, "adc_clk"); + clk = clk_register_gate(NULL, "adc_clk", "adc_syn_gclk", + CLK_SET_RATE_PARENT, SPEAR1310_PERIP1_CLK_ENB, + SPEAR1310_ADC_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "e0080000.adc"); /* clock derived from apb clk */ clk = clk_register_gate(NULL, "ssp0_clk", "apb_clk", 0, @@ -916,15 +934,15 @@ void __init spear1310_clk_init(void) SPEAR1310_RAS_CTRL_REG1, SPEAR1310_SMII_RGMII_PHY_CLK_SHIFT, SPEAR1310_PHY_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, NULL, "stmmacphy.1"); - clk_register_clkdev(clk, NULL, "stmmacphy.2"); - clk_register_clkdev(clk, NULL, "stmmacphy.4"); + clk_register_clkdev(clk, "stmmacphy.1", NULL); + clk_register_clkdev(clk, "stmmacphy.2", NULL); + clk_register_clkdev(clk, "stmmacphy.4", NULL); clk = clk_register_mux(NULL, "rmii_phy_mclk", rmii_phy_parents, ARRAY_SIZE(rmii_phy_parents), 0, SPEAR1310_RAS_CTRL_REG1, SPEAR1310_RMII_PHY_CLK_SHIFT, SPEAR1310_PHY_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, NULL, "stmmacphy.3"); + clk_register_clkdev(clk, "stmmacphy.3", NULL); clk = clk_register_mux(NULL, "uart1_mclk", uart_parents, ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0, diff --git a/drivers/clk/spear/spear1340_clock.c b/drivers/clk/spear/spear1340_clock.c index 2352cee7f64..82abea366b7 100644 --- a/drivers/clk/spear/spear1340_clock.c +++ b/drivers/clk/spear/spear1340_clock.c @@ -190,6 +190,7 @@ static struct pll_rate_tbl pll4_rtbl[] = { * different values of vco1div2 */ static struct frac_rate_tbl amba_synth_rtbl[] = { + {.div = 0x073A8}, /* for vco1div2 = 600 MHz */ {.div = 0x06062}, /* for vco1div2 = 500 MHz */ {.div = 0x04D1B}, /* for vco1div2 = 400 MHz */ {.div = 0x04000}, /* for vco1div2 = 332 MHz */ @@ -220,6 +221,12 @@ static struct frac_rate_tbl amba_synth_rtbl[] = { * 500 400 200 0x02800 * 500 500 250 0x02000 * -------------------------------------------------------------------- + * 600 200 100 0x06000 + * 600 250 125 0x04CCE + * 600 332 166 0x039D5 + * 600 400 200 0x03000 + * 600 500 250 0x02666 + * -------------------------------------------------------------------- * 664 200 100 0x06a38 * 664 250 125 0x054FD * 664 332 166 0x04000 @@ -238,28 +245,50 @@ static struct frac_rate_tbl sys_synth_rtbl[] = { {.div = 0x08000}, {.div = 0x06a38}, {.div = 0x06666}, + {.div = 0x06000}, {.div = 0x054FD}, {.div = 0x05000}, {.div = 0x04D18}, + {.div = 0x04CCE}, {.div = 0x04000}, + {.div = 0x039D5}, {.div = 0x0351E}, {.div = 0x03333}, {.div = 0x03031}, + {.div = 0x03000}, {.div = 0x02A7E}, {.div = 0x02800}, {.div = 0x0268D}, + {.div = 0x02666}, {.div = 0x02000}, }; /* aux rate configuration table, in ascending order of rates */ static struct aux_rate_tbl aux_rtbl[] = { - /* For VCO1div2 = 500 MHz */ - {.xscale = 10, .yscale = 204, .eq = 0}, /* 12.29 MHz */ - {.xscale = 4, .yscale = 21, .eq = 0}, /* 48 MHz */ - {.xscale = 2, .yscale = 6, .eq = 0}, /* 83 MHz */ - {.xscale = 2, .yscale = 4, .eq = 0}, /* 125 MHz */ - {.xscale = 1, .yscale = 3, .eq = 1}, /* 166 MHz */ - {.xscale = 1, .yscale = 2, .eq = 1}, /* 250 MHz */ + /* 12.29MHz for vic1div2=600MHz and 10.24MHz for VCO1div2=500MHz */ + {.xscale = 5, .yscale = 122, .eq = 0}, + /* 14.70MHz for vic1div2=600MHz and 12.29MHz for VCO1div2=500MHz */ + {.xscale = 10, .yscale = 204, .eq = 0}, + /* 48MHz for vic1div2=600MHz and 40 MHz for VCO1div2=500MHz */ + {.xscale = 4, .yscale = 25, .eq = 0}, + /* 57.14MHz for vic1div2=600MHz and 48 MHz for VCO1div2=500MHz */ + {.xscale = 4, .yscale = 21, .eq = 0}, + /* 83.33MHz for vic1div2=600MHz and 69.44MHz for VCO1div2=500MHz */ + {.xscale = 5, .yscale = 18, .eq = 0}, + /* 100MHz for vic1div2=600MHz and 83.33 MHz for VCO1div2=500MHz */ + {.xscale = 2, .yscale = 6, .eq = 0}, + /* 125MHz for vic1div2=600MHz and 104.1MHz for VCO1div2=500MHz */ + {.xscale = 5, .yscale = 12, .eq = 0}, + /* 150MHz for vic1div2=600MHz and 125MHz for VCO1div2=500MHz */ + {.xscale = 2, .yscale = 4, .eq = 0}, + /* 166MHz for vic1div2=600MHz and 138.88MHz for VCO1div2=500MHz */ + {.xscale = 5, .yscale = 18, .eq = 1}, + /* 200MHz for vic1div2=600MHz and 166MHz for VCO1div2=500MHz */ + {.xscale = 1, .yscale = 3, .eq = 1}, + /* 250MHz for vic1div2=600MHz and 208.33MHz for VCO1div2=500MHz */ + {.xscale = 5, .yscale = 12, .eq = 1}, + /* 300MHz for vic1div2=600MHz and 250MHz for VCO1div2=500MHz */ + {.xscale = 1, .yscale = 2, .eq = 1}, }; /* gmac rate configuration table, in ascending order of rates */ @@ -273,16 +302,23 @@ static struct aux_rate_tbl gmac_rtbl[] = { /* clcd rate configuration table, in ascending order of rates */ static struct frac_rate_tbl clcd_rtbl[] = { + {.div = 0x18000}, /* 25 Mhz , for vc01div4 = 300 MHz*/ + {.div = 0x1638E}, /* 27 Mhz , for vc01div4 = 300 MHz*/ {.div = 0x14000}, /* 25 Mhz , for vc01div4 = 250 MHz*/ {.div = 0x1284B}, /* 27 Mhz , for vc01div4 = 250 MHz*/ {.div = 0x0D8D3}, /* 58 Mhz , for vco1div4 = 393 MHz */ {.div = 0x0B72C}, /* 58 Mhz , for vco1div4 = 332 MHz */ + {.div = 0x0A584}, /* 58 Mhz , for vco1div4 = 300 MHz */ + {.div = 0x093B1}, /* 65 Mhz , for vc01div4 = 300 MHz*/ {.div = 0x089EE}, /* 58 Mhz , for vc01div4 = 250 MHz*/ + {.div = 0x081BA}, /* 74 Mhz , for vc01div4 = 300 MHz*/ {.div = 0x07BA0}, /* 65 Mhz , for vc01div4 = 250 MHz*/ {.div = 0x06f1C}, /* 72 Mhz , for vc01div4 = 250 MHz*/ {.div = 0x06E58}, /* 58 Mhz , for vco1div4 = 200 MHz */ {.div = 0x06c1B}, /* 74 Mhz , for vc01div4 = 250 MHz*/ + {.div = 0x058E3}, /* 108 Mhz , for vc01div4 = 300 MHz*/ {.div = 0x04A12}, /* 108 Mhz , for vc01div4 = 250 MHz*/ + {.div = 0x040A5}, /* 148.5 Mhz , for vc01div4 = 300 MHz*/ {.div = 0x0378E}, /* 144 Mhz , for vc01div4 = 250 MHz*/ {.div = 0x0360D}, /* 148 Mhz , for vc01div4 = 250 MHz*/ {.div = 0x035E0}, /* 148.5 MHz, for vc01div4 = 250 MHz*/ @@ -351,26 +387,37 @@ static struct aux_rate_tbl adc_rtbl[] = { /* General synth rate configuration table, in ascending order of rates */ static struct frac_rate_tbl gen_rtbl[] = { - /* For vco1div4 = 250 MHz */ - {.div = 0x1624E}, /* 22.5792 MHz */ - {.div = 0x14585}, /* 24.576 MHz */ - {.div = 0x14000}, /* 25 MHz */ - {.div = 0x0B127}, /* 45.1584 MHz */ - {.div = 0x0A000}, /* 50 MHz */ - {.div = 0x061A8}, /* 81.92 MHz */ - {.div = 0x05000}, /* 100 MHz */ - {.div = 0x02800}, /* 200 MHz */ - {.div = 0x02620}, /* 210 MHz */ - {.div = 0x02460}, /* 220 MHz */ - {.div = 0x022C0}, /* 230 MHz */ - {.div = 0x02160}, /* 240 MHz */ - {.div = 0x02000}, /* 250 MHz */ + {.div = 0x1A92B}, /* 22.5792 MHz for vco1div4=300 MHz*/ + {.div = 0x186A0}, /* 24.576 MHz for vco1div4=300 MHz*/ + {.div = 0x18000}, /* 25 MHz for vco1div4=300 MHz*/ + {.div = 0x1624E}, /* 22.5792 MHz for vco1div4=250 MHz*/ + {.div = 0x14585}, /* 24.576 MHz for vco1div4=250 MHz*/ + {.div = 0x14000}, /* 25 MHz for vco1div4=250 MHz*/ + {.div = 0x0D495}, /* 45.1584 MHz for vco1div4=300 MHz*/ + {.div = 0x0C000}, /* 50 MHz for vco1div4=300 MHz*/ + {.div = 0x0B127}, /* 45.1584 MHz for vco1div4=250 MHz*/ + {.div = 0x0A000}, /* 50 MHz for vco1div4=250 MHz*/ + {.div = 0x07530}, /* 81.92 MHz for vco1div4=300 MHz*/ + {.div = 0x061A8}, /* 81.92 MHz for vco1div4=250 MHz*/ + {.div = 0x06000}, /* 100 MHz for vco1div4=300 MHz*/ + {.div = 0x05000}, /* 100 MHz for vco1div4=250 MHz*/ + {.div = 0x03000}, /* 200 MHz for vco1div4=300 MHz*/ + {.div = 0x02DB6}, /* 210 MHz for vco1div4=300 MHz*/ + {.div = 0x02BA2}, /* 220 MHz for vco1div4=300 MHz*/ + {.div = 0x029BD}, /* 230 MHz for vco1div4=300 MHz*/ + {.div = 0x02800}, /* 200 MHz for vco1div4=250 MHz*/ + {.div = 0x02666}, /* 250 MHz for vco1div4=300 MHz*/ + {.div = 0x02620}, /* 210 MHz for vco1div4=250 MHz*/ + {.div = 0x02460}, /* 220 MHz for vco1div4=250 MHz*/ + {.div = 0x022C0}, /* 230 MHz for vco1div4=250 MHz*/ + {.div = 0x02160}, /* 240 MHz for vco1div4=250 MHz*/ + {.div = 0x02000}, /* 250 MHz for vco1div4=250 MHz*/ }; /* clock parents */ static const char *vco_parents[] = { "osc_24m_clk", "osc_25m_clk", }; static const char *sys_parents[] = { "pll1_clk", "pll1_clk", "pll1_clk", - "pll1_clk", "sys_synth_clk", "sys_synth_clk", "pll2_clk", "pll3_clk", }; + "pll1_clk", "sys_syn_clk", "sys_syn_clk", "pll2_clk", "pll3_clk", }; static const char *ahb_parents[] = { "cpu_div3_clk", "amba_syn_clk", }; static const char *gpt_parents[] = { "osc_24m_clk", "apb_clk", }; static const char *uart0_parents[] = { "pll5_clk", "osc_24m_clk", @@ -391,16 +438,13 @@ static const char *spdif_in_parents[] = { "pll2_clk", "gen_syn3_clk", }; static const char *gen_synth0_1_parents[] = { "vco1div4_clk", "vco3div2_clk", "pll3_clk", }; -static const char *gen_synth2_3_parents[] = { "vco1div4_clk", "vco3div2_clk", +static const char *gen_synth2_3_parents[] = { "vco1div4_clk", "vco2div2_clk", "pll2_clk", }; void __init spear1340_clk_init(void) { struct clk *clk, *clk1; - clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); - clk_register_clkdev(clk, "apb_pclk", NULL); - clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT, 32000); clk_register_clkdev(clk, "osc_32k_clk", NULL); @@ -425,7 +469,7 @@ void __init spear1340_clk_init(void) clk = clk_register_gate(NULL, "rtc-spear", "osc_32k_clk", 0, SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_RTC_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, NULL, "fc900000.rtc"); + clk_register_clkdev(clk, NULL, "e0580000.rtc"); /* clock derived from 24 or 25 MHz osc clk */ /* vco-pll */ @@ -499,7 +543,7 @@ void __init spear1340_clk_init(void) clk = clk_register_gate(NULL, "thermal_gclk", "thermal_clk", 0, SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_THSENS_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, NULL, "spear_thermal"); + clk_register_clkdev(clk, NULL, "e07008c4.thermal"); /* clock derived from pll4 clk */ clk = clk_register_fixed_factor(NULL, "ddr_clk", "pll4_clk", 0, 1, @@ -521,7 +565,7 @@ void __init spear1340_clk_init(void) ARRAY_SIZE(sys_parents), 0, SPEAR1340_SYS_CLK_CTRL, SPEAR1340_SCLK_SRC_SEL_SHIFT, SPEAR1340_SCLK_SRC_SEL_MASK, 0, &_lock); - clk_register_clkdev(clk, "sys_clk", NULL); + clk_register_clkdev(clk, "sys_mclk", NULL); clk = clk_register_fixed_factor(NULL, "cpu_clk", "sys_mclk", 0, 1, 2); @@ -535,6 +579,10 @@ void __init spear1340_clk_init(void) 2); clk_register_clkdev(clk, NULL, "ec800620.wdt"); + clk = clk_register_fixed_factor(NULL, "smp_twd_clk", "cpu_clk", 0, 1, + 2); + clk_register_clkdev(clk, NULL, "smp_twd"); + clk = clk_register_mux(NULL, "ahb_clk", ahb_parents, ARRAY_SIZE(ahb_parents), 0, SPEAR1340_SYS_CLK_CTRL, SPEAR1340_HCLK_SRC_SEL_SHIFT, @@ -594,14 +642,14 @@ void __init spear1340_clk_init(void) clk_register_clkdev(clk1, "uart0_syn_gclk", NULL); clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents, - ARRAY_SIZE(uart0_parents), 0, SPEAR1340_PERIP_CLK_CFG, - SPEAR1340_UART0_CLK_SHIFT, SPEAR1340_UART_CLK_MASK, 0, - &_lock); + ARRAY_SIZE(uart0_parents), CLK_SET_RATE_PARENT, + SPEAR1340_PERIP_CLK_CFG, SPEAR1340_UART0_CLK_SHIFT, + SPEAR1340_UART_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, "uart0_mclk", NULL); - clk = clk_register_gate(NULL, "uart0_clk", "uart0_mclk", 0, - SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_UART0_CLK_ENB, 0, - &_lock); + clk = clk_register_gate(NULL, "uart0_clk", "uart0_mclk", + CLK_SET_RATE_PARENT, SPEAR1340_PERIP1_CLK_ENB, + SPEAR1340_UART0_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "e0000000.serial"); clk = clk_register_aux("uart1_syn_clk", "uart1_syn_gclk", @@ -627,9 +675,9 @@ void __init spear1340_clk_init(void) clk_register_clkdev(clk, "sdhci_syn_clk", NULL); clk_register_clkdev(clk1, "sdhci_syn_gclk", NULL); - clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_syn_gclk", 0, - SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_SDHCI_CLK_ENB, 0, - &_lock); + clk = clk_register_gate(NULL, "sdhci_clk", "sdhci_syn_gclk", + CLK_SET_RATE_PARENT, SPEAR1340_PERIP1_CLK_ENB, + SPEAR1340_SDHCI_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "b3000000.sdhci"); clk = clk_register_aux("cfxd_syn_clk", "cfxd_syn_gclk", "vco1div2_clk", @@ -638,9 +686,9 @@ void __init spear1340_clk_init(void) clk_register_clkdev(clk, "cfxd_syn_clk", NULL); clk_register_clkdev(clk1, "cfxd_syn_gclk", NULL); - clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_syn_gclk", 0, - SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_CFXD_CLK_ENB, 0, - &_lock); + clk = clk_register_gate(NULL, "cfxd_clk", "cfxd_syn_gclk", + CLK_SET_RATE_PARENT, SPEAR1340_PERIP1_CLK_ENB, + SPEAR1340_CFXD_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "b2800000.cf"); clk_register_clkdev(clk, NULL, "arasan_xd"); @@ -651,15 +699,15 @@ void __init spear1340_clk_init(void) clk_register_clkdev(clk1, "c3_syn_gclk", NULL); clk = clk_register_mux(NULL, "c3_mclk", c3_parents, - ARRAY_SIZE(c3_parents), 0, SPEAR1340_PERIP_CLK_CFG, - SPEAR1340_C3_CLK_SHIFT, SPEAR1340_C3_CLK_MASK, 0, - &_lock); + ARRAY_SIZE(c3_parents), CLK_SET_RATE_PARENT, + SPEAR1340_PERIP_CLK_CFG, SPEAR1340_C3_CLK_SHIFT, + SPEAR1340_C3_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, "c3_mclk", NULL); - clk = clk_register_gate(NULL, "c3_clk", "c3_mclk", 0, + clk = clk_register_gate(NULL, "c3_clk", "c3_mclk", CLK_SET_RATE_PARENT, SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_C3_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, NULL, "c3"); + clk_register_clkdev(clk, NULL, "e1800000.c3"); /* gmac */ clk = clk_register_mux(NULL, "phy_input_mclk", gmac_phy_input_parents, @@ -679,7 +727,7 @@ void __init spear1340_clk_init(void) ARRAY_SIZE(gmac_phy_parents), 0, SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GMAC_PHY_CLK_SHIFT, SPEAR1340_GMAC_PHY_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, NULL, "stmmacphy.0"); + clk_register_clkdev(clk, "stmmacphy.0", NULL); /* clcd */ clk = clk_register_mux(NULL, "clcd_syn_mclk", clcd_synth_parents, @@ -694,33 +742,34 @@ void __init spear1340_clk_init(void) clk_register_clkdev(clk, "clcd_syn_clk", NULL); clk = clk_register_mux(NULL, "clcd_pixel_mclk", clcd_pixel_parents, - ARRAY_SIZE(clcd_pixel_parents), 0, + ARRAY_SIZE(clcd_pixel_parents), CLK_SET_RATE_PARENT, SPEAR1340_PERIP_CLK_CFG, SPEAR1340_CLCD_CLK_SHIFT, SPEAR1340_CLCD_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "clcd_pixel_clk", NULL); + clk_register_clkdev(clk, "clcd_pixel_mclk", NULL); clk = clk_register_gate(NULL, "clcd_clk", "clcd_pixel_mclk", 0, SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_CLCD_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, "clcd_clk", NULL); + clk_register_clkdev(clk, NULL, "e1000000.clcd"); /* i2s */ clk = clk_register_mux(NULL, "i2s_src_mclk", i2s_src_parents, ARRAY_SIZE(i2s_src_parents), 0, SPEAR1340_I2S_CLK_CFG, SPEAR1340_I2S_SRC_CLK_SHIFT, SPEAR1340_I2S_SRC_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "i2s_src_clk", NULL); + clk_register_clkdev(clk, "i2s_src_mclk", NULL); - clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mclk", 0, - SPEAR1340_I2S_CLK_CFG, &i2s_prs1_masks, i2s_prs1_rtbl, + clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mclk", + CLK_SET_RATE_PARENT, SPEAR1340_I2S_CLK_CFG, + &i2s_prs1_masks, i2s_prs1_rtbl, ARRAY_SIZE(i2s_prs1_rtbl), &_lock, NULL); clk_register_clkdev(clk, "i2s_prs1_clk", NULL); clk = clk_register_mux(NULL, "i2s_ref_mclk", i2s_ref_parents, - ARRAY_SIZE(i2s_ref_parents), 0, SPEAR1340_I2S_CLK_CFG, - SPEAR1340_I2S_REF_SHIFT, SPEAR1340_I2S_REF_SEL_MASK, 0, - &_lock); - clk_register_clkdev(clk, "i2s_ref_clk", NULL); + ARRAY_SIZE(i2s_ref_parents), CLK_SET_RATE_PARENT, + SPEAR1340_I2S_CLK_CFG, SPEAR1340_I2S_REF_SHIFT, + SPEAR1340_I2S_REF_SEL_MASK, 0, &_lock); + clk_register_clkdev(clk, "i2s_ref_mclk", NULL); clk = clk_register_gate(NULL, "i2s_ref_pad_clk", "i2s_ref_mclk", 0, SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_I2S_REF_PAD_CLK_ENB, @@ -769,23 +818,25 @@ void __init spear1340_clk_init(void) clk = clk_register_gate(NULL, "usbh0_clk", "ahb_clk", 0, SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_UHC0_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, "usbh.0_clk", NULL); + clk_register_clkdev(clk, NULL, "e4000000.ohci"); + clk_register_clkdev(clk, NULL, "e4800000.ehci"); clk = clk_register_gate(NULL, "usbh1_clk", "ahb_clk", 0, SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_UHC1_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, "usbh.1_clk", NULL); + clk_register_clkdev(clk, NULL, "e5000000.ohci"); + clk_register_clkdev(clk, NULL, "e5800000.ehci"); clk = clk_register_gate(NULL, "uoc_clk", "ahb_clk", 0, SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_UOC_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, NULL, "uoc"); + clk_register_clkdev(clk, NULL, "e3800000.otg"); clk = clk_register_gate(NULL, "pcie_sata_clk", "ahb_clk", 0, SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_PCIE_SATA_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "dw_pcie"); - clk_register_clkdev(clk, NULL, "ahci"); + clk_register_clkdev(clk, NULL, "b1000000.ahci"); clk = clk_register_gate(NULL, "sysram0_clk", "ahb_clk", 0, SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_SYSRAM0_CLK_ENB, 0, @@ -803,10 +854,10 @@ void __init spear1340_clk_init(void) clk_register_clkdev(clk, "adc_syn_clk", NULL); clk_register_clkdev(clk1, "adc_syn_gclk", NULL); - clk = clk_register_gate(NULL, "adc_clk", "adc_syn_gclk", 0, - SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_ADC_CLK_ENB, 0, - &_lock); - clk_register_clkdev(clk, NULL, "adc_clk"); + clk = clk_register_gate(NULL, "adc_clk", "adc_syn_gclk", + CLK_SET_RATE_PARENT, SPEAR1340_PERIP1_CLK_ENB, + SPEAR1340_ADC_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "e0080000.adc"); /* clock derived from apb clk */ clk = clk_register_gate(NULL, "ssp_clk", "apb_clk", 0, @@ -827,12 +878,12 @@ void __init spear1340_clk_init(void) clk = clk_register_gate(NULL, "i2s_play_clk", "apb_clk", 0, SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_I2S_PLAY_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, NULL, "b2400000.i2s"); + clk_register_clkdev(clk, NULL, "b2400000.i2s-play"); clk = clk_register_gate(NULL, "i2s_rec_clk", "apb_clk", 0, SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_I2S_REC_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, NULL, "b2000000.i2s"); + clk_register_clkdev(clk, NULL, "b2000000.i2s-rec"); clk = clk_register_gate(NULL, "kbd_clk", "apb_clk", 0, SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_KBD_CLK_ENB, 0, @@ -844,37 +895,37 @@ void __init spear1340_clk_init(void) ARRAY_SIZE(gen_synth0_1_parents), 0, SPEAR1340_PLL_CFG, SPEAR1340_GEN_SYNT0_1_CLK_SHIFT, SPEAR1340_GEN_SYNT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gen_syn0_1_clk", NULL); + clk_register_clkdev(clk, "gen_syn0_1_mclk", NULL); clk = clk_register_mux(NULL, "gen_syn2_3_mclk", gen_synth2_3_parents, ARRAY_SIZE(gen_synth2_3_parents), 0, SPEAR1340_PLL_CFG, SPEAR1340_GEN_SYNT2_3_CLK_SHIFT, SPEAR1340_GEN_SYNT_CLK_MASK, 0, &_lock); - clk_register_clkdev(clk, "gen_syn2_3_clk", NULL); + clk_register_clkdev(clk, "gen_syn2_3_mclk", NULL); - clk = clk_register_frac("gen_syn0_clk", "gen_syn0_1_clk", 0, + clk = clk_register_frac("gen_syn0_clk", "gen_syn0_1_mclk", 0, SPEAR1340_GEN_CLK_SYNT0, gen_rtbl, ARRAY_SIZE(gen_rtbl), &_lock); clk_register_clkdev(clk, "gen_syn0_clk", NULL); - clk = clk_register_frac("gen_syn1_clk", "gen_syn0_1_clk", 0, + clk = clk_register_frac("gen_syn1_clk", "gen_syn0_1_mclk", 0, SPEAR1340_GEN_CLK_SYNT1, gen_rtbl, ARRAY_SIZE(gen_rtbl), &_lock); clk_register_clkdev(clk, "gen_syn1_clk", NULL); - clk = clk_register_frac("gen_syn2_clk", "gen_syn2_3_clk", 0, + clk = clk_register_frac("gen_syn2_clk", "gen_syn2_3_mclk", 0, SPEAR1340_GEN_CLK_SYNT2, gen_rtbl, ARRAY_SIZE(gen_rtbl), &_lock); clk_register_clkdev(clk, "gen_syn2_clk", NULL); - clk = clk_register_frac("gen_syn3_clk", "gen_syn2_3_clk", 0, + clk = clk_register_frac("gen_syn3_clk", "gen_syn2_3_mclk", 0, SPEAR1340_GEN_CLK_SYNT3, gen_rtbl, ARRAY_SIZE(gen_rtbl), &_lock); clk_register_clkdev(clk, "gen_syn3_clk", NULL); - clk = clk_register_gate(NULL, "mali_clk", "gen_syn3_clk", 0, - SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_MALI_CLK_ENB, 0, - &_lock); + clk = clk_register_gate(NULL, "mali_clk", "gen_syn3_clk", + CLK_SET_RATE_PARENT, SPEAR1340_PERIP3_CLK_ENB, + SPEAR1340_MALI_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, NULL, "mali"); clk = clk_register_gate(NULL, "cec0_clk", "ahb_clk", 0, @@ -888,26 +939,26 @@ void __init spear1340_clk_init(void) clk_register_clkdev(clk, NULL, "spear_cec.1"); clk = clk_register_mux(NULL, "spdif_out_mclk", spdif_out_parents, - ARRAY_SIZE(spdif_out_parents), 0, + ARRAY_SIZE(spdif_out_parents), CLK_SET_RATE_PARENT, SPEAR1340_PERIP_CLK_CFG, SPEAR1340_SPDIF_OUT_CLK_SHIFT, SPEAR1340_SPDIF_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, "spdif_out_mclk", NULL); - clk = clk_register_gate(NULL, "spdif_out_clk", "spdif_out_mclk", 0, - SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_SPDIF_OUT_CLK_ENB, - 0, &_lock); - clk_register_clkdev(clk, NULL, "spdif-out"); + clk = clk_register_gate(NULL, "spdif_out_clk", "spdif_out_mclk", + CLK_SET_RATE_PARENT, SPEAR1340_PERIP3_CLK_ENB, + SPEAR1340_SPDIF_OUT_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "d0000000.spdif-out"); clk = clk_register_mux(NULL, "spdif_in_mclk", spdif_in_parents, - ARRAY_SIZE(spdif_in_parents), 0, + ARRAY_SIZE(spdif_in_parents), CLK_SET_RATE_PARENT, SPEAR1340_PERIP_CLK_CFG, SPEAR1340_SPDIF_IN_CLK_SHIFT, SPEAR1340_SPDIF_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, "spdif_in_mclk", NULL); - clk = clk_register_gate(NULL, "spdif_in_clk", "spdif_in_mclk", 0, - SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_SPDIF_IN_CLK_ENB, 0, - &_lock); - clk_register_clkdev(clk, NULL, "spdif-in"); + clk = clk_register_gate(NULL, "spdif_in_clk", "spdif_in_mclk", + CLK_SET_RATE_PARENT, SPEAR1340_PERIP3_CLK_ENB, + SPEAR1340_SPDIF_IN_CLK_ENB, 0, &_lock); + clk_register_clkdev(clk, NULL, "d0100000.spdif-in"); clk = clk_register_gate(NULL, "acp_clk", "acp_mclk", 0, SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_ACP_CLK_ENB, 0, @@ -917,7 +968,7 @@ void __init spear1340_clk_init(void) clk = clk_register_gate(NULL, "plgpio_clk", "plgpio_mclk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_PLGPIO_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, NULL, "plgpio"); + clk_register_clkdev(clk, NULL, "e2800000.gpio"); clk = clk_register_gate(NULL, "video_dec_clk", "video_dec_mclk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_VIDEO_DEC_CLK_ENB, @@ -937,25 +988,25 @@ void __init spear1340_clk_init(void) clk = clk_register_gate(NULL, "cam0_clk", "cam0_mclk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM0_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, NULL, "spear_camif.0"); + clk_register_clkdev(clk, NULL, "d0200000.cam0"); clk = clk_register_gate(NULL, "cam1_clk", "cam1_mclk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM1_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, NULL, "spear_camif.1"); + clk_register_clkdev(clk, NULL, "d0300000.cam1"); clk = clk_register_gate(NULL, "cam2_clk", "cam2_mclk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM2_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, NULL, "spear_camif.2"); + clk_register_clkdev(clk, NULL, "d0400000.cam2"); clk = clk_register_gate(NULL, "cam3_clk", "cam3_mclk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_CAM3_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, NULL, "spear_camif.3"); + clk_register_clkdev(clk, NULL, "d0500000.cam3"); - clk = clk_register_gate(NULL, "pwm_clk", "pwm_mclk", 0, + clk = clk_register_gate(NULL, "pwm_clk", "ahb_clk", 0, SPEAR1340_PERIP3_CLK_ENB, SPEAR1340_PWM_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, NULL, "pwm"); + clk_register_clkdev(clk, NULL, "e0180000.pwm"); } diff --git a/drivers/clk/spear/spear3xx_clock.c b/drivers/clk/spear/spear3xx_clock.c index c3157454bb3..33d3ac588da 100644 --- a/drivers/clk/spear/spear3xx_clock.c +++ b/drivers/clk/spear/spear3xx_clock.c @@ -107,6 +107,12 @@ static struct pll_rate_tbl pll_rtbl[] = { /* aux rate configuration table, in ascending order of rates */ static struct aux_rate_tbl aux_rtbl[] = { /* For PLL1 = 332 MHz */ + {.xscale = 1, .yscale = 81, .eq = 0}, /* 2.049 MHz */ + {.xscale = 1, .yscale = 59, .eq = 0}, /* 2.822 MHz */ + {.xscale = 2, .yscale = 81, .eq = 0}, /* 4.098 MHz */ + {.xscale = 3, .yscale = 89, .eq = 0}, /* 5.644 MHz */ + {.xscale = 4, .yscale = 81, .eq = 0}, /* 8.197 MHz */ + {.xscale = 4, .yscale = 59, .eq = 0}, /* 11.254 MHz */ {.xscale = 2, .yscale = 27, .eq = 0}, /* 12.296 MHz */ {.xscale = 2, .yscale = 8, .eq = 0}, /* 41.5 MHz */ {.xscale = 2, .yscale = 4, .eq = 0}, /* 83 MHz */ @@ -157,6 +163,8 @@ static void __init spear300_clk_init(void) 1); clk_register_clkdev(clk, NULL, "a0000000.kbd"); } +#else +static inline void spear300_clk_init(void) { } #endif /* array of all spear 310 clock lookups */ @@ -197,6 +205,8 @@ static void __init spear310_clk_init(void) 1); clk_register_clkdev(clk, NULL, "b2200000.serial"); } +#else +static inline void spear310_clk_init(void) { } #endif /* array of all spear 320 clock lookups */ @@ -251,7 +261,7 @@ static void __init spear320_clk_init(void) clk = clk_register_fixed_factor(NULL, "pwm_clk", "ras_ahb_clk", 0, 1, 1); - clk_register_clkdev(clk, "pwm", NULL); + clk_register_clkdev(clk, NULL, "a8000000.pwm"); clk = clk_register_fixed_factor(NULL, "ssp1_clk", "ras_ahb_clk", 0, 1, 1); @@ -271,26 +281,37 @@ static void __init spear320_clk_init(void) clk = clk_register_fixed_factor(NULL, "i2s_clk", "ras_apb_clk", 0, 1, 1); - clk_register_clkdev(clk, NULL, "i2s"); + clk_register_clkdev(clk, NULL, "a9400000.i2s"); clk = clk_register_mux(NULL, "i2s_ref_clk", i2s_ref_parents, - ARRAY_SIZE(i2s_ref_parents), 0, SPEAR320_CONTROL_REG, - I2S_REF_PCLK_SHIFT, I2S_REF_PCLK_MASK, 0, &_lock); + ARRAY_SIZE(i2s_ref_parents), CLK_SET_RATE_PARENT, + SPEAR320_CONTROL_REG, I2S_REF_PCLK_SHIFT, + I2S_REF_PCLK_MASK, 0, &_lock); clk_register_clkdev(clk, "i2s_ref_clk", NULL); - clk = clk_register_fixed_factor(NULL, "i2s_sclk", "i2s_ref_clk", 0, 1, + clk = clk_register_fixed_factor(NULL, "i2s_sclk", "i2s_ref_clk", + CLK_SET_RATE_PARENT, 1, 4); clk_register_clkdev(clk, "i2s_sclk", NULL); + clk = clk_register_fixed_factor(NULL, "macb1_clk", "ras_apb_clk", 0, 1, + 1); + clk_register_clkdev(clk, "hclk", "aa000000.eth"); + + clk = clk_register_fixed_factor(NULL, "macb2_clk", "ras_apb_clk", 0, 1, + 1); + clk_register_clkdev(clk, "hclk", "ab000000.eth"); + clk = clk_register_mux(NULL, "rs485_clk", uartx_parents, - ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, - SPEAR320_RS485_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, - &_lock); + ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT, + SPEAR320_EXT_CTRL_REG, SPEAR320_RS485_PCLK_SHIFT, + SPEAR320_UARTX_PCLK_MASK, 0, &_lock); clk_register_clkdev(clk, NULL, "a9300000.serial"); clk = clk_register_mux(NULL, "sdhci_clk", sdhci_parents, - ARRAY_SIZE(sdhci_parents), 0, SPEAR320_CONTROL_REG, - SDHCI_PCLK_SHIFT, SDHCI_PCLK_MASK, 0, &_lock); + ARRAY_SIZE(sdhci_parents), CLK_SET_RATE_PARENT, + SPEAR320_CONTROL_REG, SDHCI_PCLK_SHIFT, SDHCI_PCLK_MASK, + 0, &_lock); clk_register_clkdev(clk, NULL, "70000000.sdhci"); clk = clk_register_mux(NULL, "smii_pclk", smii0_parents, @@ -302,49 +323,49 @@ static void __init spear320_clk_init(void) clk_register_clkdev(clk, NULL, "smii"); clk = clk_register_mux(NULL, "uart1_clk", uartx_parents, - ARRAY_SIZE(uartx_parents), 0, SPEAR320_CONTROL_REG, - UART1_PCLK_SHIFT, UART1_PCLK_MASK, 0, &_lock); + ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT, + SPEAR320_CONTROL_REG, UART1_PCLK_SHIFT, UART1_PCLK_MASK, + 0, &_lock); clk_register_clkdev(clk, NULL, "a3000000.serial"); clk = clk_register_mux(NULL, "uart2_clk", uartx_parents, - ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, - SPEAR320_UART2_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, - &_lock); + ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT, + SPEAR320_EXT_CTRL_REG, SPEAR320_UART2_PCLK_SHIFT, + SPEAR320_UARTX_PCLK_MASK, 0, &_lock); clk_register_clkdev(clk, NULL, "a4000000.serial"); clk = clk_register_mux(NULL, "uart3_clk", uartx_parents, - ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, - SPEAR320_UART3_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, - &_lock); + ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT, + SPEAR320_EXT_CTRL_REG, SPEAR320_UART3_PCLK_SHIFT, + SPEAR320_UARTX_PCLK_MASK, 0, &_lock); clk_register_clkdev(clk, NULL, "a9100000.serial"); clk = clk_register_mux(NULL, "uart4_clk", uartx_parents, - ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, - SPEAR320_UART4_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, - &_lock); + ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT, + SPEAR320_EXT_CTRL_REG, SPEAR320_UART4_PCLK_SHIFT, + SPEAR320_UARTX_PCLK_MASK, 0, &_lock); clk_register_clkdev(clk, NULL, "a9200000.serial"); clk = clk_register_mux(NULL, "uart5_clk", uartx_parents, - ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, - SPEAR320_UART5_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, - &_lock); + ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT, + SPEAR320_EXT_CTRL_REG, SPEAR320_UART5_PCLK_SHIFT, + SPEAR320_UARTX_PCLK_MASK, 0, &_lock); clk_register_clkdev(clk, NULL, "60000000.serial"); clk = clk_register_mux(NULL, "uart6_clk", uartx_parents, - ARRAY_SIZE(uartx_parents), 0, SPEAR320_EXT_CTRL_REG, - SPEAR320_UART6_PCLK_SHIFT, SPEAR320_UARTX_PCLK_MASK, 0, - &_lock); + ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT, + SPEAR320_EXT_CTRL_REG, SPEAR320_UART6_PCLK_SHIFT, + SPEAR320_UARTX_PCLK_MASK, 0, &_lock); clk_register_clkdev(clk, NULL, "60100000.serial"); } +#else +static inline void spear320_clk_init(void) { } #endif void __init spear3xx_clk_init(void) { struct clk *clk, *clk1; - clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); - clk_register_clkdev(clk, "apb_pclk", NULL); - clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT, 32000); clk_register_clkdev(clk, "osc_32k_clk", NULL); @@ -380,7 +401,8 @@ void __init spear3xx_clk_init(void) clk_register_clkdev(clk1, "pll2_clk", NULL); /* clock derived from pll1 clk */ - clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", 0, 1, 1); + clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", + CLK_SET_RATE_PARENT, 1, 1); clk_register_clkdev(clk, "cpu_clk", NULL); clk = clk_register_divider(NULL, "ahb_clk", "pll1_clk", @@ -395,12 +417,14 @@ void __init spear3xx_clk_init(void) clk_register_clkdev(clk1, "uart_syn_gclk", NULL); clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents, - ARRAY_SIZE(uart0_parents), 0, PERIP_CLK_CFG, - UART_CLK_SHIFT, UART_CLK_MASK, 0, &_lock); + ARRAY_SIZE(uart0_parents), CLK_SET_RATE_PARENT, + PERIP_CLK_CFG, UART_CLK_SHIFT, UART_CLK_MASK, 0, + &_lock); clk_register_clkdev(clk, "uart0_mclk", NULL); - clk = clk_register_gate(NULL, "uart0", "uart0_mclk", 0, PERIP1_CLK_ENB, - UART_CLK_ENB, 0, &_lock); + clk = clk_register_gate(NULL, "uart0", "uart0_mclk", + CLK_SET_RATE_PARENT, PERIP1_CLK_ENB, UART_CLK_ENB, 0, + &_lock); clk_register_clkdev(clk, NULL, "d0000000.serial"); clk = clk_register_aux("firda_syn_clk", "firda_syn_gclk", "pll1_clk", 0, @@ -410,40 +434,44 @@ void __init spear3xx_clk_init(void) clk_register_clkdev(clk1, "firda_syn_gclk", NULL); clk = clk_register_mux(NULL, "firda_mclk", firda_parents, - ARRAY_SIZE(firda_parents), 0, PERIP_CLK_CFG, - FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0, &_lock); + ARRAY_SIZE(firda_parents), CLK_SET_RATE_PARENT, + PERIP_CLK_CFG, FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0, + &_lock); clk_register_clkdev(clk, "firda_mclk", NULL); - clk = clk_register_gate(NULL, "firda_clk", "firda_mclk", 0, - PERIP1_CLK_ENB, FIRDA_CLK_ENB, 0, &_lock); + clk = clk_register_gate(NULL, "firda_clk", "firda_mclk", + CLK_SET_RATE_PARENT, PERIP1_CLK_ENB, FIRDA_CLK_ENB, 0, + &_lock); clk_register_clkdev(clk, NULL, "firda"); /* gpt clocks */ clk_register_gpt("gpt0_syn_clk", "pll1_clk", 0, PRSC0_CLK_CFG, gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); clk = clk_register_mux(NULL, "gpt0_clk", gpt0_parents, - ARRAY_SIZE(gpt0_parents), 0, PERIP_CLK_CFG, - GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); + ARRAY_SIZE(gpt0_parents), CLK_SET_RATE_PARENT, + PERIP_CLK_CFG, GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, NULL, "gpt0"); clk_register_gpt("gpt1_syn_clk", "pll1_clk", 0, PRSC1_CLK_CFG, gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); clk = clk_register_mux(NULL, "gpt1_mclk", gpt1_parents, - ARRAY_SIZE(gpt1_parents), 0, PERIP_CLK_CFG, - GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); + ARRAY_SIZE(gpt1_parents), CLK_SET_RATE_PARENT, + PERIP_CLK_CFG, GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, "gpt1_mclk", NULL); - clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk", 0, - PERIP1_CLK_ENB, GPT1_CLK_ENB, 0, &_lock); + clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk", + CLK_SET_RATE_PARENT, PERIP1_CLK_ENB, GPT1_CLK_ENB, 0, + &_lock); clk_register_clkdev(clk, NULL, "gpt1"); clk_register_gpt("gpt2_syn_clk", "pll1_clk", 0, PRSC2_CLK_CFG, gpt_rtbl, ARRAY_SIZE(gpt_rtbl), &_lock); clk = clk_register_mux(NULL, "gpt2_mclk", gpt2_parents, - ARRAY_SIZE(gpt2_parents), 0, PERIP_CLK_CFG, - GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); + ARRAY_SIZE(gpt2_parents), CLK_SET_RATE_PARENT, + PERIP_CLK_CFG, GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock); clk_register_clkdev(clk, "gpt2_mclk", NULL); - clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk", 0, - PERIP1_CLK_ENB, GPT2_CLK_ENB, 0, &_lock); + clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk", + CLK_SET_RATE_PARENT, PERIP1_CLK_ENB, GPT2_CLK_ENB, 0, + &_lock); clk_register_clkdev(clk, NULL, "gpt2"); /* general synths clocks */ @@ -480,7 +508,9 @@ void __init spear3xx_clk_init(void) /* clock derived from pll3 clk */ clk = clk_register_gate(NULL, "usbh_clk", "pll3_clk", 0, PERIP1_CLK_ENB, USBH_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, "usbh_clk", NULL); + clk_register_clkdev(clk, NULL, "e1800000.ehci"); + clk_register_clkdev(clk, NULL, "e1900000.ohci"); + clk_register_clkdev(clk, NULL, "e2100000.ohci"); clk = clk_register_fixed_factor(NULL, "usbh.0_clk", "usbh_clk", 0, 1, 1); @@ -492,7 +522,7 @@ void __init spear3xx_clk_init(void) clk = clk_register_gate(NULL, "usbd_clk", "pll3_clk", 0, PERIP1_CLK_ENB, USBD_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, NULL, "designware_udc"); + clk_register_clkdev(clk, NULL, "e1100000.usbd"); /* clock derived from ahb clk */ clk = clk_register_fixed_factor(NULL, "ahbmult2_clk", "ahb_clk", 0, 2, @@ -540,7 +570,7 @@ void __init spear3xx_clk_init(void) /* clock derived from apb clk */ clk = clk_register_gate(NULL, "adc_clk", "apb_clk", 0, PERIP1_CLK_ENB, ADC_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, NULL, "adc"); + clk_register_clkdev(clk, NULL, "d0080000.adc"); clk = clk_register_gate(NULL, "gpio0_clk", "apb_clk", 0, PERIP1_CLK_ENB, GPIO_CLK_ENB, 0, &_lock); @@ -579,20 +609,24 @@ void __init spear3xx_clk_init(void) RAS_CLK_ENB, RAS_48M_CLK_ENB, 0, &_lock); clk_register_clkdev(clk, "ras_pll3_clk", NULL); - clk = clk_register_gate(NULL, "ras_syn0_gclk", "gen0_syn_gclk", 0, - RAS_CLK_ENB, RAS_SYNT0_CLK_ENB, 0, &_lock); + clk = clk_register_gate(NULL, "ras_syn0_gclk", "gen0_syn_gclk", + CLK_SET_RATE_PARENT, RAS_CLK_ENB, RAS_SYNT0_CLK_ENB, 0, + &_lock); clk_register_clkdev(clk, "ras_syn0_gclk", NULL); - clk = clk_register_gate(NULL, "ras_syn1_gclk", "gen1_syn_gclk", 0, - RAS_CLK_ENB, RAS_SYNT1_CLK_ENB, 0, &_lock); + clk = clk_register_gate(NULL, "ras_syn1_gclk", "gen1_syn_gclk", + CLK_SET_RATE_PARENT, RAS_CLK_ENB, RAS_SYNT1_CLK_ENB, 0, + &_lock); clk_register_clkdev(clk, "ras_syn1_gclk", NULL); - clk = clk_register_gate(NULL, "ras_syn2_gclk", "gen2_syn_gclk", 0, - RAS_CLK_ENB, RAS_SYNT2_CLK_ENB, 0, &_lock); + clk = clk_register_gate(NULL, "ras_syn2_gclk", "gen2_syn_gclk", + CLK_SET_RATE_PARENT, RAS_CLK_ENB, RAS_SYNT2_CLK_ENB, 0, + &_lock); clk_register_clkdev(clk, "ras_syn2_gclk", NULL); - clk = clk_register_gate(NULL, "ras_syn3_gclk", "gen3_syn_gclk", 0, - RAS_CLK_ENB, RAS_SYNT3_CLK_ENB, 0, &_lock); + clk = clk_register_gate(NULL, "ras_syn3_gclk", "gen3_syn_gclk", + CLK_SET_RATE_PARENT, RAS_CLK_ENB, RAS_SYNT3_CLK_ENB, 0, + &_lock); clk_register_clkdev(clk, "ras_syn3_gclk", NULL); if (of_machine_is_compatible("st,spear300")) diff --git a/drivers/clk/spear/spear6xx_clock.c b/drivers/clk/spear/spear6xx_clock.c index a98d0866f54..e862a333ad3 100644 --- a/drivers/clk/spear/spear6xx_clock.c +++ b/drivers/clk/spear/spear6xx_clock.c @@ -92,6 +92,7 @@ static struct pll_rate_tbl pll_rtbl[] = { /* aux rate configuration table, in ascending order of rates */ static struct aux_rate_tbl aux_rtbl[] = { /* For PLL1 = 332 MHz */ + {.xscale = 2, .yscale = 27, .eq = 0}, /* 12.296 MHz */ {.xscale = 2, .yscale = 8, .eq = 0}, /* 41.5 MHz */ {.xscale = 2, .yscale = 4, .eq = 0}, /* 83 MHz */ {.xscale = 1, .yscale = 2, .eq = 1}, /* 166 MHz */ @@ -118,9 +119,6 @@ void __init spear6xx_clk_init(void) { struct clk *clk, *clk1; - clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); - clk_register_clkdev(clk, "apb_pclk", NULL); - clk = clk_register_fixed_rate(NULL, "osc_32k_clk", NULL, CLK_IS_ROOT, 32000); clk_register_clkdev(clk, "osc_32k_clk", NULL); @@ -156,7 +154,8 @@ void __init spear6xx_clk_init(void) clk_register_clkdev(clk, NULL, "wdt"); /* clock derived from pll1 clk */ - clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", 0, 1, 1); + clk = clk_register_fixed_factor(NULL, "cpu_clk", "pll1_clk", + CLK_SET_RATE_PARENT, 1, 1); clk_register_clkdev(clk, "cpu_clk", NULL); clk = clk_register_divider(NULL, "ahb_clk", "pll1_clk", @@ -261,11 +260,13 @@ void __init spear6xx_clk_init(void) /* clock derived from pll3 clk */ clk = clk_register_gate(NULL, "usbh0_clk", "pll3_clk", 0, PERIP1_CLK_ENB, USBH0_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, NULL, "usbh.0_clk"); + clk_register_clkdev(clk, NULL, "e1800000.ehci"); + clk_register_clkdev(clk, NULL, "e1900000.ohci"); clk = clk_register_gate(NULL, "usbh1_clk", "pll3_clk", 0, PERIP1_CLK_ENB, USBH1_CLK_ENB, 0, &_lock); - clk_register_clkdev(clk, NULL, "usbh.1_clk"); + clk_register_clkdev(clk, NULL, "e2000000.ehci"); + clk_register_clkdev(clk, NULL, "e2100000.ohci"); clk = clk_register_gate(NULL, "usbd_clk", "pll3_clk", 0, PERIP1_CLK_ENB, USBD_CLK_ENB, 0, &_lock); diff --git a/drivers/clk/ux500/Makefile b/drivers/clk/ux500/Makefile index 858fbfe6628..bcc0c11a507 100644 --- a/drivers/clk/ux500/Makefile +++ b/drivers/clk/ux500/Makefile @@ -10,3 +10,6 @@ obj-y += clk-prcmu.o obj-y += u8500_clk.o obj-y += u9540_clk.o obj-y += u8540_clk.o + +# ABX500 clock driver +obj-y += abx500-clk.o diff --git a/drivers/clk/ux500/abx500-clk.c b/drivers/clk/ux500/abx500-clk.c new file mode 100644 index 00000000000..e27c52317ff --- /dev/null +++ b/drivers/clk/ux500/abx500-clk.c @@ -0,0 +1,73 @@ +/* + * abx500 clock implementation for ux500 platform. + * + * Copyright (C) 2012 ST-Ericsson SA + * Author: Ulf Hansson <ulf.hansson@linaro.org> + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include <linux/err.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/mfd/abx500/ab8500.h> + +/* TODO: Add clock implementations here */ + + +/* Clock definitions for ab8500 */ +static int ab8500_reg_clks(struct device *dev) +{ + return 0; +} + +/* Clock definitions for ab8540 */ +static int ab8540_reg_clks(struct device *dev) +{ + return 0; +} + +/* Clock definitions for ab9540 */ +static int ab9540_reg_clks(struct device *dev) +{ + return 0; +} + +static int __devinit abx500_clk_probe(struct platform_device *pdev) +{ + struct ab8500 *parent = dev_get_drvdata(pdev->dev.parent); + int ret; + + if (is_ab8500(parent) || is_ab8505(parent)) { + ret = ab8500_reg_clks(&pdev->dev); + } else if (is_ab8540(parent)) { + ret = ab8540_reg_clks(&pdev->dev); + } else if (is_ab9540(parent)) { + ret = ab9540_reg_clks(&pdev->dev); + } else { + dev_err(&pdev->dev, "non supported plf id\n"); + return -ENODEV; + } + + return ret; +} + +static struct platform_driver abx500_clk_driver = { + .driver = { + .name = "abx500-clk", + .owner = THIS_MODULE, + }, + .probe = abx500_clk_probe, +}; + +static int __init abx500_clk_init(void) +{ + return platform_driver_register(&abx500_clk_driver); +} + +arch_initcall(abx500_clk_init); + +MODULE_AUTHOR("Ulf Hansson <ulf.hansson@linaro.org"); +MODULE_DESCRIPTION("ABX500 clk driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c index 930cdfeb47a..74faa7e3cf5 100644 --- a/drivers/clk/ux500/clk-prcmu.c +++ b/drivers/clk/ux500/clk-prcmu.c @@ -133,6 +133,40 @@ out_error: hw->init->name); } +static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw) +{ + int err; + struct clk_prcmu *clk = to_clk_prcmu(hw); + + err = prcmu_request_ape_opp_100_voltage(true); + if (err) { + pr_err("clk_prcmu: %s failed to request APE OPP VOLT for %s.\n", + __func__, hw->init->name); + return err; + } + + err = prcmu_request_clock(clk->cg_sel, true); + if (err) + prcmu_request_ape_opp_100_voltage(false); + + return err; +} + +static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw) +{ + struct clk_prcmu *clk = to_clk_prcmu(hw); + + if (prcmu_request_clock(clk->cg_sel, false)) + goto out_error; + if (prcmu_request_ape_opp_100_voltage(false)) + goto out_error; + return; + +out_error: + pr_err("clk_prcmu: %s failed to disable %s.\n", __func__, + hw->init->name); +} + static struct clk_ops clk_prcmu_scalable_ops = { .prepare = clk_prcmu_prepare, .unprepare = clk_prcmu_unprepare, @@ -153,6 +187,13 @@ static struct clk_ops clk_prcmu_gate_ops = { .recalc_rate = clk_prcmu_recalc_rate, }; +static struct clk_ops clk_prcmu_scalable_rate_ops = { + .is_enabled = clk_prcmu_is_enabled, + .recalc_rate = clk_prcmu_recalc_rate, + .round_rate = clk_prcmu_round_rate, + .set_rate = clk_prcmu_set_rate, +}; + static struct clk_ops clk_prcmu_rate_ops = { .is_enabled = clk_prcmu_is_enabled, .recalc_rate = clk_prcmu_recalc_rate, @@ -167,6 +208,17 @@ static struct clk_ops clk_prcmu_opp_gate_ops = { .recalc_rate = clk_prcmu_recalc_rate, }; +static struct clk_ops clk_prcmu_opp_volt_scalable_ops = { + .prepare = clk_prcmu_opp_volt_prepare, + .unprepare = clk_prcmu_opp_volt_unprepare, + .enable = clk_prcmu_enable, + .disable = clk_prcmu_disable, + .is_enabled = clk_prcmu_is_enabled, + .recalc_rate = clk_prcmu_recalc_rate, + .round_rate = clk_prcmu_round_rate, + .set_rate = clk_prcmu_set_rate, +}; + static struct clk *clk_reg_prcmu(const char *name, const char *parent_name, u8 cg_sel, @@ -233,6 +285,16 @@ struct clk *clk_reg_prcmu_gate(const char *name, &clk_prcmu_gate_ops); } +struct clk *clk_reg_prcmu_scalable_rate(const char *name, + const char *parent_name, + u8 cg_sel, + unsigned long rate, + unsigned long flags) +{ + return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags, + &clk_prcmu_scalable_rate_ops); +} + struct clk *clk_reg_prcmu_rate(const char *name, const char *parent_name, u8 cg_sel, @@ -250,3 +312,13 @@ struct clk *clk_reg_prcmu_opp_gate(const char *name, return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags, &clk_prcmu_opp_gate_ops); } + +struct clk *clk_reg_prcmu_opp_volt_scalable(const char *name, + const char *parent_name, + u8 cg_sel, + unsigned long rate, + unsigned long flags) +{ + return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags, + &clk_prcmu_opp_volt_scalable_ops); +} diff --git a/drivers/clk/ux500/clk.h b/drivers/clk/ux500/clk.h index 836d7d16751..c3e449169a8 100644 --- a/drivers/clk/ux500/clk.h +++ b/drivers/clk/ux500/clk.h @@ -35,6 +35,12 @@ struct clk *clk_reg_prcmu_gate(const char *name, u8 cg_sel, unsigned long flags); +struct clk *clk_reg_prcmu_scalable_rate(const char *name, + const char *parent_name, + u8 cg_sel, + unsigned long rate, + unsigned long flags); + struct clk *clk_reg_prcmu_rate(const char *name, const char *parent_name, u8 cg_sel, @@ -45,4 +51,10 @@ struct clk *clk_reg_prcmu_opp_gate(const char *name, u8 cg_sel, unsigned long flags); +struct clk *clk_reg_prcmu_opp_volt_scalable(const char *name, + const char *parent_name, + u8 cg_sel, + unsigned long rate, + unsigned long flags); + #endif /* __UX500_CLK_H */ diff --git a/drivers/clk/ux500/u8500_clk.c b/drivers/clk/ux500/u8500_clk.c index e2c17d187d9..7d0e0258f20 100644 --- a/drivers/clk/ux500/u8500_clk.c +++ b/drivers/clk/ux500/u8500_clk.c @@ -170,10 +170,11 @@ void u8500_clk_init(void) clk_register_clkdev(clk, NULL, "mtu0"); clk_register_clkdev(clk, NULL, "mtu1"); - clk = clk_reg_prcmu_gate("sdmmcclk", NULL, PRCMU_SDMMCCLK, CLK_IS_ROOT); + clk = clk_reg_prcmu_opp_volt_scalable("sdmmcclk", NULL, PRCMU_SDMMCCLK, + 100000000, + CLK_IS_ROOT|CLK_SET_RATE_GATE); clk_register_clkdev(clk, NULL, "sdmmc"); - clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk", PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE); clk_register_clkdev(clk, "dsihs2", "mcde"); @@ -205,16 +206,18 @@ void u8500_clk_init(void) clk_register_clkdev(clk, "dsilp2", "dsilink.2"); clk_register_clkdev(clk, "dsilp2", "mcde"); - clk = clk_reg_prcmu_rate("smp_twd", NULL, PRCMU_ARMSS, - CLK_IS_ROOT|CLK_GET_RATE_NOCACHE| - CLK_IGNORE_UNUSED); + clk = clk_reg_prcmu_scalable_rate("armss", NULL, + PRCMU_ARMSS, 0, CLK_IS_ROOT|CLK_IGNORE_UNUSED); + clk_register_clkdev(clk, "armss", NULL); + + clk = clk_register_fixed_factor(NULL, "smp_twd", "armss", + CLK_IGNORE_UNUSED, 1, 2); clk_register_clkdev(clk, NULL, "smp_twd"); /* * FIXME: Add special handled PRCMU clocks here: - * 1. clk_arm, use PRCMU_ARMCLK. - * 2. clkout0yuv, use PRCMU as parent + need regulator + pinctrl. - * 3. ab9540_clkout1yuv, see clkout0yuv + * 1. clkout0yuv, use PRCMU as parent + need regulator + pinctrl. + * 2. ab9540_clkout1yuv, see clkout0yuv */ /* PRCC P-clocks */ @@ -323,7 +326,7 @@ void u8500_clk_init(void) clk_register_clkdev(clk, NULL, "gpioblock1"); clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", U8500_CLKRST2_BASE, - BIT(11), 0); + BIT(12), 0); clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", U8500_CLKRST3_BASE, BIT(0), 0); @@ -347,6 +350,8 @@ void u8500_clk_init(void) clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", U8500_CLKRST3_BASE, BIT(5), 0); + clk_register_clkdev(clk, "apb_pclk", "ske"); + clk_register_clkdev(clk, "apb_pclk", "nmk-ske-keypad"); clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", U8500_CLKRST3_BASE, BIT(6), 0); @@ -375,6 +380,7 @@ void u8500_clk_init(void) clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", U8500_CLKRST6_BASE, BIT(0), 0); + clk_register_clkdev(clk, "apb_pclk", "rng"); clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", U8500_CLKRST6_BASE, BIT(1), 0); @@ -503,6 +509,8 @@ void u8500_clk_init(void) clk = clk_reg_prcc_kclk("p3_ske_kclk", "rtc32k", U8500_CLKRST3_BASE, BIT(5), CLK_SET_RATE_GATE); + clk_register_clkdev(clk, NULL, "ske"); + clk_register_clkdev(clk, NULL, "nmk-ske-keypad"); clk = clk_reg_prcc_kclk("p3_uart2_kclk", "uartclk", U8500_CLKRST3_BASE, BIT(6), CLK_SET_RATE_GATE); @@ -515,5 +523,5 @@ void u8500_clk_init(void) /* Periph6 */ clk = clk_reg_prcc_kclk("p3_rng_kclk", "rngclk", U8500_CLKRST6_BASE, BIT(0), CLK_SET_RATE_GATE); - + clk_register_clkdev(clk, NULL, "rng"); } diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile index c0a0f647879..ec3b88fe3e6 100644 --- a/drivers/clk/versatile/Makefile +++ b/drivers/clk/versatile/Makefile @@ -1,4 +1,7 @@ # Makefile for Versatile-specific clocks obj-$(CONFIG_ICST) += clk-icst.o obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o +obj-$(CONFIG_INTEGRATOR_IMPD1) += clk-impd1.o obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o +obj-$(CONFIG_ARCH_VEXPRESS) += clk-vexpress.o +obj-$(CONFIG_VEXPRESS_CONFIG) += clk-vexpress-osc.o diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index f555b50a5fa..67ccf4aa727 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c @@ -3,6 +3,12 @@ * We wrap the custom interface from <asm/hardware/icst.h> into the generic * clock framework. * + * Copyright (C) 2012 Linus Walleij + * + * 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. + * * TODO: when all ARM reference designs are migrated to generic clocks, the * ICST clock code from the ARM tree should probably be merged into this * file. @@ -11,33 +17,74 @@ #include <linux/clkdev.h> #include <linux/err.h> #include <linux/clk-provider.h> +#include <linux/io.h> #include "clk-icst.h" /** * struct clk_icst - ICST VCO clock wrapper * @hw: corresponding clock hardware entry + * @vcoreg: VCO register address + * @lockreg: VCO lock register address * @params: parameters for this ICST instance * @rate: current rate - * @setvco: function to commit ICST settings to hardware */ struct clk_icst { struct clk_hw hw; + void __iomem *vcoreg; + void __iomem *lockreg; const struct icst_params *params; unsigned long rate; - struct icst_vco (*getvco)(void); - void (*setvco)(struct icst_vco); }; #define to_icst(_hw) container_of(_hw, struct clk_icst, hw) +/** + * vco_get() - get ICST VCO settings from a certain register + * @vcoreg: register containing the VCO settings + */ +static struct icst_vco vco_get(void __iomem *vcoreg) +{ + u32 val; + struct icst_vco vco; + + val = readl(vcoreg); + vco.v = val & 0x1ff; + vco.r = (val >> 9) & 0x7f; + vco.s = (val >> 16) & 03; + return vco; +} + +/** + * vco_set() - commit changes to an ICST VCO + * @locreg: register to poke to unlock the VCO for writing + * @vcoreg: register containing the VCO settings + * @vco: ICST VCO parameters to commit + */ +static void vco_set(void __iomem *lockreg, + void __iomem *vcoreg, + struct icst_vco vco) +{ + u32 val; + + val = readl(vcoreg) & ~0x7ffff; + val |= vco.v | (vco.r << 9) | (vco.s << 16); + + /* This magic unlocks the VCO so it can be controlled */ + writel(0xa05f, lockreg); + writel(val, vcoreg); + /* This locks the VCO again */ + writel(0, lockreg); +} + + static unsigned long icst_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_icst *icst = to_icst(hw); struct icst_vco vco; - vco = icst->getvco(); + vco = vco_get(icst->vcoreg); icst->rate = icst_hz(icst->params, vco); return icst->rate; } @@ -60,7 +107,7 @@ static int icst_set_rate(struct clk_hw *hw, unsigned long rate, vco = icst_hz_to_vco(icst->params, rate); icst->rate = icst_hz(icst->params, vco); - icst->setvco(vco); + vco_set(icst->vcoreg, icst->lockreg, vco); return 0; } @@ -70,8 +117,9 @@ static const struct clk_ops icst_ops = { .set_rate = icst_set_rate, }; -struct clk * __init icst_clk_register(struct device *dev, - const struct clk_icst_desc *desc) +struct clk *icst_clk_register(struct device *dev, + const struct clk_icst_desc *desc, + void __iomem *base) { struct clk *clk; struct clk_icst *icst; @@ -89,8 +137,8 @@ struct clk * __init icst_clk_register(struct device *dev, init.num_parents = 0; icst->hw.init = &init; icst->params = desc->params; - icst->getvco = desc->getvco; - icst->setvco = desc->setvco; + icst->vcoreg = base + desc->vco_offset; + icst->lockreg = base + desc->lock_offset; clk = clk_register(dev, &icst->hw); if (IS_ERR(clk)) diff --git a/drivers/clk/versatile/clk-icst.h b/drivers/clk/versatile/clk-icst.h index 71b4c56c141..dad51b6ffd0 100644 --- a/drivers/clk/versatile/clk-icst.h +++ b/drivers/clk/versatile/clk-icst.h @@ -1,10 +1,18 @@ #include <asm/hardware/icst.h> +/** + * struct clk_icst_desc - descriptor for the ICST VCO + * @params: ICST parameters + * @vco_offset: offset to the ICST VCO from the provided memory base + * @lock_offset: offset to the ICST VCO locking register from the provided + * memory base + */ struct clk_icst_desc { const struct icst_params *params; - struct icst_vco (*getvco)(void); - void (*setvco)(struct icst_vco); + u32 vco_offset; + u32 lock_offset; }; struct clk *icst_clk_register(struct device *dev, - const struct clk_icst_desc *desc); + const struct clk_icst_desc *desc, + void __iomem *base); diff --git a/drivers/clk/versatile/clk-impd1.c b/drivers/clk/versatile/clk-impd1.c new file mode 100644 index 00000000000..369139af2a3 --- /dev/null +++ b/drivers/clk/versatile/clk-impd1.c @@ -0,0 +1,97 @@ +/* + * Clock driver for the ARM Integrator/IM-PD1 board + * Copyright (C) 2012 Linus Walleij + * + * 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/clk-provider.h> +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/platform_data/clk-integrator.h> + +#include <mach/impd1.h> + +#include "clk-icst.h" + +struct impd1_clk { + struct clk *vcoclk; + struct clk *uartclk; + struct clk_lookup *clks[3]; +}; + +static struct impd1_clk impd1_clks[4]; + +/* + * There are two VCO's on the IM-PD1 but only one is used by the + * kernel, that is why we are only implementing the control of + * IMPD1_OSC1 here. + */ + +static const struct icst_params impd1_vco_params = { + .ref = 24000000, /* 24 MHz */ + .vco_max = ICST525_VCO_MAX_3V, + .vco_min = ICST525_VCO_MIN, + .vd_min = 12, + .vd_max = 519, + .rd_min = 3, + .rd_max = 120, + .s2div = icst525_s2div, + .idx2s = icst525_idx2s, +}; + +static const struct clk_icst_desc impd1_icst1_desc = { + .params = &impd1_vco_params, + .vco_offset = IMPD1_OSC1, + .lock_offset = IMPD1_LOCK, +}; + +/** + * integrator_impd1_clk_init() - set up the integrator clock tree + * @base: base address of the logic module (LM) + * @id: the ID of this LM + */ +void integrator_impd1_clk_init(void __iomem *base, unsigned int id) +{ + struct impd1_clk *imc; + struct clk *clk; + int i; + + if (id > 3) { + pr_crit("no more than 4 LMs can be attached\n"); + return; + } + imc = &impd1_clks[id]; + + clk = icst_clk_register(NULL, &impd1_icst1_desc, base); + imc->vcoclk = clk; + imc->clks[0] = clkdev_alloc(clk, NULL, "lm%x:01000", id); + + /* UART reference clock */ + clk = clk_register_fixed_rate(NULL, "uartclk", NULL, CLK_IS_ROOT, + 14745600); + imc->uartclk = clk; + imc->clks[1] = clkdev_alloc(clk, NULL, "lm%x:00100", id); + imc->clks[2] = clkdev_alloc(clk, NULL, "lm%x:00200", id); + + for (i = 0; i < ARRAY_SIZE(imc->clks); i++) + clkdev_add(imc->clks[i]); +} + +void integrator_impd1_clk_exit(unsigned int id) +{ + int i; + struct impd1_clk *imc; + + if (id > 3) + return; + imc = &impd1_clks[id]; + + for (i = 0; i < ARRAY_SIZE(imc->clks); i++) + clkdev_drop(imc->clks[i]); + clk_unregister(imc->uartclk); + clk_unregister(imc->vcoclk); +} diff --git a/drivers/clk/versatile/clk-integrator.c b/drivers/clk/versatile/clk-integrator.c index a5053921bf7..08593b4ee2c 100644 --- a/drivers/clk/versatile/clk-integrator.c +++ b/drivers/clk/versatile/clk-integrator.c @@ -1,8 +1,16 @@ +/* + * Clock driver for the ARM Integrator/AP and Integrator/CP boards + * Copyright (C) 2012 Linus Walleij + * + * 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/clk-provider.h> #include <linux/clk.h> #include <linux/clkdev.h> #include <linux/err.h> -#include <linux/io.h> -#include <linux/clk-provider.h> +#include <linux/platform_data/clk-integrator.h> #include <mach/hardware.h> #include <mach/platform.h> @@ -14,42 +22,6 @@ * Inspired by portions of: * plat-versatile/clock.c and plat-versatile/include/plat/clock.h */ -#define CM_LOCK (__io_address(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET) -#define CM_AUXOSC (__io_address(INTEGRATOR_HDR_BASE)+0x1c) - -/** - * cp_auxvco_get() - get ICST VCO settings for the Integrator/CP - * @vco: ICST VCO parameters to update with hardware status - */ -static struct icst_vco cp_auxvco_get(void) -{ - u32 val; - struct icst_vco vco; - - val = readl(CM_AUXOSC); - vco.v = val & 0x1ff; - vco.r = (val >> 9) & 0x7f; - vco.s = (val >> 16) & 03; - return vco; -} - -/** - * cp_auxvco_set() - commit changes to Integrator/CP ICST VCO - * @vco: ICST VCO parameters to commit - */ -static void cp_auxvco_set(struct icst_vco vco) -{ - u32 val; - - val = readl(CM_AUXOSC) & ~0x7ffff; - val |= vco.v | (vco.r << 9) | (vco.s << 16); - - /* This magic unlocks the CM VCO so it can be controlled */ - writel(0xa05f, CM_LOCK); - writel(val, CM_AUXOSC); - /* This locks the CM again */ - writel(0, CM_LOCK); -} static const struct icst_params cp_auxvco_params = { .ref = 24000000, @@ -65,8 +37,8 @@ static const struct icst_params cp_auxvco_params = { static const struct clk_icst_desc __initdata cp_icst_desc = { .params = &cp_auxvco_params, - .getvco = cp_auxvco_get, - .setvco = cp_auxvco_set, + .vco_offset = 0x1c, + .lock_offset = INTEGRATOR_HDR_LOCK_OFFSET, }; /* @@ -106,6 +78,7 @@ void __init integrator_clk_init(bool is_cp) clk_register_clkdev(clk, NULL, "sp804"); /* ICST VCO clock used on the Integrator/CP CLCD */ - clk = icst_clk_register(NULL, &cp_icst_desc); + clk = icst_clk_register(NULL, &cp_icst_desc, + __io_address(INTEGRATOR_HDR_BASE)); clk_register_clkdev(clk, NULL, "clcd"); } diff --git a/drivers/clk/versatile/clk-realview.c b/drivers/clk/versatile/clk-realview.c index e21a99cef37..cda07e70a40 100644 --- a/drivers/clk/versatile/clk-realview.c +++ b/drivers/clk/versatile/clk-realview.c @@ -1,3 +1,11 @@ +/* + * Clock driver for the ARM RealView boards + * Copyright (C) 2012 Linus Walleij + * + * 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/clk.h> #include <linux/clkdev.h> #include <linux/err.h> @@ -13,38 +21,6 @@ * Implementation of the ARM RealView clock trees. */ -static void __iomem *sys_lock; -static void __iomem *sys_vcoreg; - -/** - * realview_oscvco_get() - get ICST OSC settings for the RealView - */ -static struct icst_vco realview_oscvco_get(void) -{ - u32 val; - struct icst_vco vco; - - val = readl(sys_vcoreg); - vco.v = val & 0x1ff; - vco.r = (val >> 9) & 0x7f; - vco.s = (val >> 16) & 03; - return vco; -} - -static void realview_oscvco_set(struct icst_vco vco) -{ - u32 val; - - val = readl(sys_vcoreg) & ~0x7ffff; - val |= vco.v | (vco.r << 9) | (vco.s << 16); - - /* This magic unlocks the CM VCO so it can be controlled */ - writel(0xa05f, sys_lock); - writel(val, sys_vcoreg); - /* This locks the CM again */ - writel(0, sys_lock); -} - static const struct icst_params realview_oscvco_params = { .ref = 24000000, .vco_max = ICST307_VCO_MAX, @@ -57,10 +33,16 @@ static const struct icst_params realview_oscvco_params = { .idx2s = icst307_idx2s, }; -static const struct clk_icst_desc __initdata realview_icst_desc = { +static const struct clk_icst_desc __initdata realview_osc0_desc = { + .params = &realview_oscvco_params, + .vco_offset = REALVIEW_SYS_OSC0_OFFSET, + .lock_offset = REALVIEW_SYS_LOCK_OFFSET, +}; + +static const struct clk_icst_desc __initdata realview_osc4_desc = { .params = &realview_oscvco_params, - .getvco = realview_oscvco_get, - .setvco = realview_oscvco_set, + .vco_offset = REALVIEW_SYS_OSC4_OFFSET, + .lock_offset = REALVIEW_SYS_LOCK_OFFSET, }; /* @@ -70,13 +52,6 @@ void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176) { struct clk *clk; - sys_lock = sysbase + REALVIEW_SYS_LOCK_OFFSET; - if (is_pb1176) - sys_vcoreg = sysbase + REALVIEW_SYS_OSC0_OFFSET; - else - sys_vcoreg = sysbase + REALVIEW_SYS_OSC4_OFFSET; - - /* APB clock dummy */ clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); clk_register_clkdev(clk, "apb_pclk", NULL); @@ -108,7 +83,11 @@ void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176) clk_register_clkdev(clk, NULL, "sp804"); /* ICST VCO clock */ - clk = icst_clk_register(NULL, &realview_icst_desc); + if (is_pb1176) + clk = icst_clk_register(NULL, &realview_osc0_desc, sysbase); + else + clk = icst_clk_register(NULL, &realview_osc4_desc, sysbase); + clk_register_clkdev(clk, NULL, "dev:clcd"); clk_register_clkdev(clk, NULL, "issp:clcd"); } diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c new file mode 100644 index 00000000000..dcb6ae0a042 --- /dev/null +++ b/drivers/clk/versatile/clk-vexpress-osc.c @@ -0,0 +1,146 @@ +/* + * 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. + * + * 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. + * + * Copyright (C) 2012 ARM Limited + */ + +#define pr_fmt(fmt) "vexpress-osc: " fmt + +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/vexpress.h> + +struct vexpress_osc { + struct vexpress_config_func *func; + struct clk_hw hw; + unsigned long rate_min; + unsigned long rate_max; +}; + +#define to_vexpress_osc(osc) container_of(osc, struct vexpress_osc, hw) + +static unsigned long vexpress_osc_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct vexpress_osc *osc = to_vexpress_osc(hw); + u32 rate; + + vexpress_config_read(osc->func, 0, &rate); + + return rate; +} + +static long vexpress_osc_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct vexpress_osc *osc = to_vexpress_osc(hw); + + if (WARN_ON(osc->rate_min && rate < osc->rate_min)) + rate = osc->rate_min; + + if (WARN_ON(osc->rate_max && rate > osc->rate_max)) + rate = osc->rate_max; + + return rate; +} + +static int vexpress_osc_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct vexpress_osc *osc = to_vexpress_osc(hw); + + return vexpress_config_write(osc->func, 0, rate); +} + +static struct clk_ops vexpress_osc_ops = { + .recalc_rate = vexpress_osc_recalc_rate, + .round_rate = vexpress_osc_round_rate, + .set_rate = vexpress_osc_set_rate, +}; + + +struct clk * __init vexpress_osc_setup(struct device *dev) +{ + struct clk_init_data init; + struct vexpress_osc *osc = kzalloc(sizeof(*osc), GFP_KERNEL); + + if (!osc) + return NULL; + + osc->func = vexpress_config_func_get_by_dev(dev); + if (!osc->func) { + kfree(osc); + return NULL; + } + + init.name = dev_name(dev); + init.ops = &vexpress_osc_ops; + init.flags = CLK_IS_ROOT; + init.num_parents = 0; + osc->hw.init = &init; + + return clk_register(NULL, &osc->hw); +} + +void __init vexpress_osc_of_setup(struct device_node *node) +{ + struct clk_init_data init; + struct vexpress_osc *osc; + struct clk *clk; + u32 range[2]; + + osc = kzalloc(sizeof(*osc), GFP_KERNEL); + if (!osc) + goto error; + + osc->func = vexpress_config_func_get_by_node(node); + if (!osc->func) { + pr_err("Failed to obtain config func for node '%s'!\n", + node->name); + goto error; + } + + if (of_property_read_u32_array(node, "freq-range", range, + ARRAY_SIZE(range)) == 0) { + osc->rate_min = range[0]; + osc->rate_max = range[1]; + } + + of_property_read_string(node, "clock-output-names", &init.name); + if (!init.name) + init.name = node->name; + + init.ops = &vexpress_osc_ops; + init.flags = CLK_IS_ROOT; + init.num_parents = 0; + + osc->hw.init = &init; + + clk = clk_register(NULL, &osc->hw); + if (IS_ERR(clk)) { + pr_err("Failed to register clock '%s'!\n", init.name); + goto error; + } + + of_clk_add_provider(node, of_clk_src_simple_get, clk); + + pr_debug("Registered clock '%s'\n", init.name); + + return; + +error: + if (osc->func) + vexpress_config_func_put(osc->func); + kfree(osc); +} diff --git a/drivers/clk/versatile/clk-vexpress.c b/drivers/clk/versatile/clk-vexpress.c new file mode 100644 index 00000000000..c742ac7c60b --- /dev/null +++ b/drivers/clk/versatile/clk-vexpress.c @@ -0,0 +1,142 @@ +/* + * 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. + * + * 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. + * + * Copyright (C) 2012 ARM Limited + */ + +#include <linux/clkdev.h> +#include <linux/clk-provider.h> +#include <linux/err.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/vexpress.h> + +#include <asm/hardware/sp810.h> + +static struct clk *vexpress_sp810_timerclken[4]; +static DEFINE_SPINLOCK(vexpress_sp810_lock); + +static void __init vexpress_sp810_init(void __iomem *base) +{ + int i; + + if (WARN_ON(!base)) + return; + + for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++) { + char name[12]; + const char *parents[] = { + "v2m:refclk32khz", /* REFCLK */ + "v2m:refclk1mhz" /* TIMCLK */ + }; + + snprintf(name, ARRAY_SIZE(name), "timerclken%d", i); + + vexpress_sp810_timerclken[i] = clk_register_mux(NULL, name, + parents, 2, 0, base + SCCTRL, + SCCTRL_TIMERENnSEL_SHIFT(i), 1, + 0, &vexpress_sp810_lock); + + if (WARN_ON(IS_ERR(vexpress_sp810_timerclken[i]))) + break; + } +} + + +static const char * const vexpress_clk_24mhz_periphs[] __initconst = { + "mb:uart0", "mb:uart1", "mb:uart2", "mb:uart3", + "mb:mmci", "mb:kmi0", "mb:kmi1" +}; + +void __init vexpress_clk_init(void __iomem *sp810_base) +{ + struct clk *clk; + int i; + + clk = clk_register_fixed_rate(NULL, "dummy_apb_pclk", NULL, + CLK_IS_ROOT, 0); + WARN_ON(clk_register_clkdev(clk, "apb_pclk", NULL)); + + clk = clk_register_fixed_rate(NULL, "v2m:clk_24mhz", NULL, + CLK_IS_ROOT, 24000000); + for (i = 0; i < ARRAY_SIZE(vexpress_clk_24mhz_periphs); i++) + WARN_ON(clk_register_clkdev(clk, NULL, + vexpress_clk_24mhz_periphs[i])); + + clk = clk_register_fixed_rate(NULL, "v2m:refclk32khz", NULL, + CLK_IS_ROOT, 32768); + WARN_ON(clk_register_clkdev(clk, NULL, "v2m:wdt")); + + clk = clk_register_fixed_rate(NULL, "v2m:refclk1mhz", NULL, + CLK_IS_ROOT, 1000000); + + vexpress_sp810_init(sp810_base); + + for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++) + WARN_ON(clk_set_parent(vexpress_sp810_timerclken[i], clk)); + + WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[0], + "v2m-timer0", "sp804")); + WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[1], + "v2m-timer1", "sp804")); +} + +#if defined(CONFIG_OF) + +struct clk *vexpress_sp810_of_get(struct of_phandle_args *clkspec, void *data) +{ + if (WARN_ON(clkspec->args_count != 1 || clkspec->args[0] > + ARRAY_SIZE(vexpress_sp810_timerclken))) + return NULL; + + return vexpress_sp810_timerclken[clkspec->args[0]]; +} + +static const __initconst struct of_device_id vexpress_fixed_clk_match[] = { + { .compatible = "fixed-clock", .data = of_fixed_clk_setup, }, + { .compatible = "arm,vexpress-osc", .data = vexpress_osc_of_setup, }, + {} +}; + +void __init vexpress_clk_of_init(void) +{ + struct device_node *node; + struct clk *clk; + struct clk *refclk, *timclk; + + of_clk_init(vexpress_fixed_clk_match); + + node = of_find_compatible_node(NULL, NULL, "arm,sp810"); + vexpress_sp810_init(of_iomap(node, 0)); + of_clk_add_provider(node, vexpress_sp810_of_get, NULL); + + /* Select "better" (faster) parent for SP804 timers */ + refclk = of_clk_get_by_name(node, "refclk"); + timclk = of_clk_get_by_name(node, "timclk"); + if (!WARN_ON(IS_ERR(refclk) || IS_ERR(timclk))) { + int i = 0; + + if (clk_get_rate(refclk) > clk_get_rate(timclk)) + clk = refclk; + else + clk = timclk; + + for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++) + WARN_ON(clk_set_parent(vexpress_sp810_timerclken[i], + clk)); + } + + WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[0], + "v2m-timer0", "sp804")); + WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[1], + "v2m-timer1", "sp804")); +} + +#endif diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 5961e6415f0..a0b3661d90b 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -76,3 +76,10 @@ config ARM_EXYNOS5250_CPUFREQ help This adds the CPUFreq driver for Samsung EXYNOS5250 SoC. + +config ARM_SPEAR_CPUFREQ + bool "SPEAr CPUFreq support" + depends on PLAT_SPEAR + default y + help + This adds the CPUFreq driver support for SPEAr SOCs. diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 1bc90e1306d..1f254ec087c 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -7,8 +7,8 @@ obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o -obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o -obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o +obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o cpufreq_governor.o +obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o cpufreq_governor.o # CPUfreq cross-arch helpers obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o @@ -50,6 +50,7 @@ obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ) += exynos4x12-cpufreq.o obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o +obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o ################################################################################## # PowerPC platform drivers diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c index e9158278c71..52bf36d599f 100644 --- a/drivers/cpufreq/cpufreq-cpu0.c +++ b/drivers/cpufreq/cpufreq-cpu0.c @@ -174,7 +174,7 @@ static struct cpufreq_driver cpu0_cpufreq_driver = { .attr = cpu0_cpufreq_attr, }; -static int __devinit cpu0_cpufreq_driver_init(void) +static int cpu0_cpufreq_driver_init(void) { struct device_node *np; int ret; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index fb8a5279c5d..1f93dbd7235 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -15,6 +15,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -127,7 +129,7 @@ static int __init init_cpufreq_transition_notifier_list(void) pure_initcall(init_cpufreq_transition_notifier_list); static int off __read_mostly; -int cpufreq_disabled(void) +static int cpufreq_disabled(void) { return off; } @@ -402,7 +404,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, static ssize_t store_##file_name \ (struct cpufreq_policy *policy, const char *buf, size_t count) \ { \ - unsigned int ret = -EINVAL; \ + unsigned int ret; \ struct cpufreq_policy new_policy; \ \ ret = cpufreq_get_policy(&new_policy, policy->cpu); \ @@ -445,7 +447,7 @@ static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf) else if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) return sprintf(buf, "performance\n"); else if (policy->governor) - return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n", + return scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n", policy->governor->name); return -EINVAL; } @@ -457,7 +459,7 @@ static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf) static ssize_t store_scaling_governor(struct cpufreq_policy *policy, const char *buf, size_t count) { - unsigned int ret = -EINVAL; + unsigned int ret; char str_governor[16]; struct cpufreq_policy new_policy; @@ -491,7 +493,7 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy, */ static ssize_t show_scaling_driver(struct cpufreq_policy *policy, char *buf) { - return scnprintf(buf, CPUFREQ_NAME_LEN, "%s\n", cpufreq_driver->name); + return scnprintf(buf, CPUFREQ_NAME_PLEN, "%s\n", cpufreq_driver->name); } /** @@ -512,7 +514,7 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy, if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char)) - (CPUFREQ_NAME_LEN + 2))) goto out; - i += scnprintf(&buf[i], CPUFREQ_NAME_LEN, "%s ", t->name); + i += scnprintf(&buf[i], CPUFREQ_NAME_PLEN, "%s ", t->name); } out: i += sprintf(&buf[i], "\n"); @@ -581,7 +583,7 @@ static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf) } /** - * show_scaling_driver - show the current cpufreq HW/BIOS limitation + * show_bios_limit - show the current cpufreq HW/BIOS limitation */ static ssize_t show_bios_limit(struct cpufreq_policy *policy, char *buf) { @@ -1468,12 +1470,23 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int relation) { int retval = -EINVAL; + unsigned int old_target_freq = target_freq; if (cpufreq_disabled()) return -ENODEV; - pr_debug("target for CPU %u: %u kHz, relation %u\n", policy->cpu, - target_freq, relation); + /* Make sure that target_freq is within supported range */ + if (target_freq > policy->max) + target_freq = policy->max; + if (target_freq < policy->min) + target_freq = policy->min; + + pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n", + policy->cpu, target_freq, relation, old_target_freq); + + if (target_freq == policy->cur) + return 0; + if (cpu_online(policy->cpu) && cpufreq_driver->target) retval = cpufreq_driver->target(policy, target_freq, relation); @@ -1509,12 +1522,14 @@ int __cpufreq_driver_getavg(struct cpufreq_policy *policy, unsigned int cpu) { int ret = 0; + if (!(cpu_online(cpu) && cpufreq_driver->getavg)) + return 0; + policy = cpufreq_cpu_get(policy->cpu); if (!policy) return -EINVAL; - if (cpu_online(cpu) && cpufreq_driver->getavg) - ret = cpufreq_driver->getavg(policy, cpu); + ret = cpufreq_driver->getavg(policy, cpu); cpufreq_cpu_put(policy); return ret; diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index a152af7e199..64ef737e7e7 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -11,83 +11,30 @@ * published by the Free Software Foundation. */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> #include <linux/cpufreq.h> -#include <linux/cpu.h> -#include <linux/jiffies.h> +#include <linux/init.h> +#include <linux/kernel.h> #include <linux/kernel_stat.h> +#include <linux/kobject.h> +#include <linux/module.h> #include <linux/mutex.h> -#include <linux/hrtimer.h> -#include <linux/tick.h> -#include <linux/ktime.h> -#include <linux/sched.h> +#include <linux/notifier.h> +#include <linux/percpu-defs.h> +#include <linux/sysfs.h> +#include <linux/types.h> -/* - * dbs is used in this file as a shortform for demandbased switching - * It helps to keep variable names smaller, simpler - */ +#include "cpufreq_governor.h" +/* Conservative governor macors */ #define DEF_FREQUENCY_UP_THRESHOLD (80) #define DEF_FREQUENCY_DOWN_THRESHOLD (20) - -/* - * The polling frequency of this governor depends on the capability of - * the processor. Default polling frequency is 1000 times the transition - * latency of the processor. The governor will work on any processor with - * transition latency <= 10mS, using appropriate sampling - * rate. - * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL) - * this governor will not work. - * All times here are in uS. - */ -#define MIN_SAMPLING_RATE_RATIO (2) - -static unsigned int min_sampling_rate; - -#define LATENCY_MULTIPLIER (1000) -#define MIN_LATENCY_MULTIPLIER (100) #define DEF_SAMPLING_DOWN_FACTOR (1) #define MAX_SAMPLING_DOWN_FACTOR (10) -#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) - -static void do_dbs_timer(struct work_struct *work); - -struct cpu_dbs_info_s { - cputime64_t prev_cpu_idle; - cputime64_t prev_cpu_wall; - cputime64_t prev_cpu_nice; - struct cpufreq_policy *cur_policy; - struct delayed_work work; - unsigned int down_skip; - unsigned int requested_freq; - int cpu; - unsigned int enable:1; - /* - * percpu mutex that serializes governor limit change with - * do_dbs_timer invocation. We do not want do_dbs_timer to run - * when user is changing the governor or limits. - */ - struct mutex timer_mutex; -}; -static DEFINE_PER_CPU(struct cpu_dbs_info_s, cs_cpu_dbs_info); -static unsigned int dbs_enable; /* number of CPUs using this policy */ +static struct dbs_data cs_dbs_data; +static DEFINE_PER_CPU(struct cs_cpu_dbs_info_s, cs_cpu_dbs_info); -/* - * dbs_mutex protects dbs_enable in governor start/stop. - */ -static DEFINE_MUTEX(dbs_mutex); - -static struct dbs_tuners { - unsigned int sampling_rate; - unsigned int sampling_down_factor; - unsigned int up_threshold; - unsigned int down_threshold; - unsigned int ignore_nice; - unsigned int freq_step; -} dbs_tuners_ins = { +static struct cs_dbs_tuners cs_tuners = { .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, .down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD, .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR, @@ -95,95 +42,121 @@ static struct dbs_tuners { .freq_step = 5, }; -static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) +/* + * Every sampling_rate, we check, if current idle time is less than 20% + * (default), then we try to increase frequency Every sampling_rate * + * sampling_down_factor, we check, if current idle time is more than 80%, then + * we try to decrease frequency + * + * Any frequency increase takes it to the maximum frequency. Frequency reduction + * happens at minimum steps of 5% (default) of maximum frequency + */ +static void cs_check_cpu(int cpu, unsigned int load) { - u64 idle_time; - u64 cur_wall_time; - u64 busy_time; + struct cs_cpu_dbs_info_s *dbs_info = &per_cpu(cs_cpu_dbs_info, cpu); + struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy; + unsigned int freq_target; + + /* + * break out if we 'cannot' reduce the speed as the user might + * want freq_step to be zero + */ + if (cs_tuners.freq_step == 0) + return; - cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); + /* Check for frequency increase */ + if (load > cs_tuners.up_threshold) { + dbs_info->down_skip = 0; - busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE]; + /* if we are already at full speed then break out early */ + if (dbs_info->requested_freq == policy->max) + return; - idle_time = cur_wall_time - busy_time; - if (wall) - *wall = jiffies_to_usecs(cur_wall_time); + freq_target = (cs_tuners.freq_step * policy->max) / 100; - return jiffies_to_usecs(idle_time); + /* max freq cannot be less than 100. But who knows.... */ + if (unlikely(freq_target == 0)) + freq_target = 5; + + dbs_info->requested_freq += freq_target; + if (dbs_info->requested_freq > policy->max) + dbs_info->requested_freq = policy->max; + + __cpufreq_driver_target(policy, dbs_info->requested_freq, + CPUFREQ_RELATION_H); + return; + } + + /* + * The optimal frequency is the frequency that is the lowest that can + * support the current CPU usage without triggering the up policy. To be + * safe, we focus 10 points under the threshold. + */ + if (load < (cs_tuners.down_threshold - 10)) { + freq_target = (cs_tuners.freq_step * policy->max) / 100; + + dbs_info->requested_freq -= freq_target; + if (dbs_info->requested_freq < policy->min) + dbs_info->requested_freq = policy->min; + + /* + * if we cannot reduce the frequency anymore, break out early + */ + if (policy->cur == policy->min) + return; + + __cpufreq_driver_target(policy, dbs_info->requested_freq, + CPUFREQ_RELATION_H); + return; + } } -static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) +static void cs_dbs_timer(struct work_struct *work) { - u64 idle_time = get_cpu_idle_time_us(cpu, NULL); + struct cs_cpu_dbs_info_s *dbs_info = container_of(work, + struct cs_cpu_dbs_info_s, cdbs.work.work); + unsigned int cpu = dbs_info->cdbs.cpu; + int delay = delay_for_sampling_rate(cs_tuners.sampling_rate); - if (idle_time == -1ULL) - return get_cpu_idle_time_jiffy(cpu, wall); - else - idle_time += get_cpu_iowait_time_us(cpu, wall); + mutex_lock(&dbs_info->cdbs.timer_mutex); - return idle_time; + dbs_check_cpu(&cs_dbs_data, cpu); + + schedule_delayed_work_on(cpu, &dbs_info->cdbs.work, delay); + mutex_unlock(&dbs_info->cdbs.timer_mutex); } -/* keep track of frequency transitions */ -static int -dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val, - void *data) +static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val, + void *data) { struct cpufreq_freqs *freq = data; - struct cpu_dbs_info_s *this_dbs_info = &per_cpu(cs_cpu_dbs_info, - freq->cpu); - + struct cs_cpu_dbs_info_s *dbs_info = + &per_cpu(cs_cpu_dbs_info, freq->cpu); struct cpufreq_policy *policy; - if (!this_dbs_info->enable) + if (!dbs_info->enable) return 0; - policy = this_dbs_info->cur_policy; + policy = dbs_info->cdbs.cur_policy; /* - * we only care if our internally tracked freq moves outside - * the 'valid' ranges of freqency available to us otherwise - * we do not change it + * we only care if our internally tracked freq moves outside the 'valid' + * ranges of freqency available to us otherwise we do not change it */ - if (this_dbs_info->requested_freq > policy->max - || this_dbs_info->requested_freq < policy->min) - this_dbs_info->requested_freq = freq->new; + if (dbs_info->requested_freq > policy->max + || dbs_info->requested_freq < policy->min) + dbs_info->requested_freq = freq->new; return 0; } -static struct notifier_block dbs_cpufreq_notifier_block = { - .notifier_call = dbs_cpufreq_notifier -}; - /************************** sysfs interface ************************/ static ssize_t show_sampling_rate_min(struct kobject *kobj, struct attribute *attr, char *buf) { - return sprintf(buf, "%u\n", min_sampling_rate); + return sprintf(buf, "%u\n", cs_dbs_data.min_sampling_rate); } -define_one_global_ro(sampling_rate_min); - -/* cpufreq_conservative Governor Tunables */ -#define show_one(file_name, object) \ -static ssize_t show_##file_name \ -(struct kobject *kobj, struct attribute *attr, char *buf) \ -{ \ - return sprintf(buf, "%u\n", dbs_tuners_ins.object); \ -} -show_one(sampling_rate, sampling_rate); -show_one(sampling_down_factor, sampling_down_factor); -show_one(up_threshold, up_threshold); -show_one(down_threshold, down_threshold); -show_one(ignore_nice_load, ignore_nice); -show_one(freq_step, freq_step); - static ssize_t store_sampling_down_factor(struct kobject *a, struct attribute *b, const char *buf, size_t count) @@ -195,7 +168,7 @@ static ssize_t store_sampling_down_factor(struct kobject *a, if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1) return -EINVAL; - dbs_tuners_ins.sampling_down_factor = input; + cs_tuners.sampling_down_factor = input; return count; } @@ -209,7 +182,7 @@ static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b, if (ret != 1) return -EINVAL; - dbs_tuners_ins.sampling_rate = max(input, min_sampling_rate); + cs_tuners.sampling_rate = max(input, cs_dbs_data.min_sampling_rate); return count; } @@ -220,11 +193,10 @@ static ssize_t store_up_threshold(struct kobject *a, struct attribute *b, int ret; ret = sscanf(buf, "%u", &input); - if (ret != 1 || input > 100 || - input <= dbs_tuners_ins.down_threshold) + if (ret != 1 || input > 100 || input <= cs_tuners.down_threshold) return -EINVAL; - dbs_tuners_ins.up_threshold = input; + cs_tuners.up_threshold = input; return count; } @@ -237,21 +209,19 @@ static ssize_t store_down_threshold(struct kobject *a, struct attribute *b, /* cannot be lower than 11 otherwise freq will not fall */ if (ret != 1 || input < 11 || input > 100 || - input >= dbs_tuners_ins.up_threshold) + input >= cs_tuners.up_threshold) return -EINVAL; - dbs_tuners_ins.down_threshold = input; + cs_tuners.down_threshold = input; return count; } static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b, const char *buf, size_t count) { - unsigned int input; + unsigned int input, j; int ret; - unsigned int j; - ret = sscanf(buf, "%u", &input); if (ret != 1) return -EINVAL; @@ -259,19 +229,20 @@ static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b, if (input > 1) input = 1; - if (input == dbs_tuners_ins.ignore_nice) /* nothing to do */ + if (input == cs_tuners.ignore_nice) /* nothing to do */ return count; - dbs_tuners_ins.ignore_nice = input; + cs_tuners.ignore_nice = input; /* we need to re-evaluate prev_cpu_idle */ for_each_online_cpu(j) { - struct cpu_dbs_info_s *dbs_info; + struct cs_cpu_dbs_info_s *dbs_info; dbs_info = &per_cpu(cs_cpu_dbs_info, j); - dbs_info->prev_cpu_idle = get_cpu_idle_time(j, - &dbs_info->prev_cpu_wall); - if (dbs_tuners_ins.ignore_nice) - dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j, + &dbs_info->cdbs.prev_cpu_wall); + if (cs_tuners.ignore_nice) + dbs_info->cdbs.prev_cpu_nice = + kcpustat_cpu(j).cpustat[CPUTIME_NICE]; } return count; } @@ -289,18 +260,28 @@ static ssize_t store_freq_step(struct kobject *a, struct attribute *b, if (input > 100) input = 100; - /* no need to test here if freq_step is zero as the user might actually - * want this, they would be crazy though :) */ - dbs_tuners_ins.freq_step = input; + /* + * no need to test here if freq_step is zero as the user might actually + * want this, they would be crazy though :) + */ + cs_tuners.freq_step = input; return count; } +show_one(cs, sampling_rate, sampling_rate); +show_one(cs, sampling_down_factor, sampling_down_factor); +show_one(cs, up_threshold, up_threshold); +show_one(cs, down_threshold, down_threshold); +show_one(cs, ignore_nice_load, ignore_nice); +show_one(cs, freq_step, freq_step); + define_one_global_rw(sampling_rate); define_one_global_rw(sampling_down_factor); define_one_global_rw(up_threshold); define_one_global_rw(down_threshold); define_one_global_rw(ignore_nice_load); define_one_global_rw(freq_step); +define_one_global_ro(sampling_rate_min); static struct attribute *dbs_attributes[] = { &sampling_rate_min.attr, @@ -313,283 +294,38 @@ static struct attribute *dbs_attributes[] = { NULL }; -static struct attribute_group dbs_attr_group = { +static struct attribute_group cs_attr_group = { .attrs = dbs_attributes, .name = "conservative", }; /************************** sysfs end ************************/ -static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) -{ - unsigned int load = 0; - unsigned int max_load = 0; - unsigned int freq_target; - - struct cpufreq_policy *policy; - unsigned int j; - - policy = this_dbs_info->cur_policy; - - /* - * Every sampling_rate, we check, if current idle time is less - * than 20% (default), then we try to increase frequency - * Every sampling_rate*sampling_down_factor, we check, if current - * idle time is more than 80%, then we try to decrease frequency - * - * Any frequency increase takes it to the maximum frequency. - * Frequency reduction happens at minimum steps of - * 5% (default) of maximum frequency - */ - - /* Get Absolute Load */ - for_each_cpu(j, policy->cpus) { - struct cpu_dbs_info_s *j_dbs_info; - cputime64_t cur_wall_time, cur_idle_time; - unsigned int idle_time, wall_time; - - j_dbs_info = &per_cpu(cs_cpu_dbs_info, j); - - cur_idle_time = get_cpu_idle_time(j, &cur_wall_time); - - wall_time = (unsigned int) - (cur_wall_time - j_dbs_info->prev_cpu_wall); - j_dbs_info->prev_cpu_wall = cur_wall_time; - - idle_time = (unsigned int) - (cur_idle_time - j_dbs_info->prev_cpu_idle); - j_dbs_info->prev_cpu_idle = cur_idle_time; - - if (dbs_tuners_ins.ignore_nice) { - u64 cur_nice; - unsigned long cur_nice_jiffies; - - cur_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE] - - j_dbs_info->prev_cpu_nice; - /* - * Assumption: nice time between sampling periods will - * be less than 2^32 jiffies for 32 bit sys - */ - cur_nice_jiffies = (unsigned long) - cputime64_to_jiffies64(cur_nice); - - j_dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; - idle_time += jiffies_to_usecs(cur_nice_jiffies); - } +define_get_cpu_dbs_routines(cs_cpu_dbs_info); - if (unlikely(!wall_time || wall_time < idle_time)) - continue; - - load = 100 * (wall_time - idle_time) / wall_time; - - if (load > max_load) - max_load = load; - } - - /* - * break out if we 'cannot' reduce the speed as the user might - * want freq_step to be zero - */ - if (dbs_tuners_ins.freq_step == 0) - return; - - /* Check for frequency increase */ - if (max_load > dbs_tuners_ins.up_threshold) { - this_dbs_info->down_skip = 0; - - /* if we are already at full speed then break out early */ - if (this_dbs_info->requested_freq == policy->max) - return; - - freq_target = (dbs_tuners_ins.freq_step * policy->max) / 100; - - /* max freq cannot be less than 100. But who knows.... */ - if (unlikely(freq_target == 0)) - freq_target = 5; - - this_dbs_info->requested_freq += freq_target; - if (this_dbs_info->requested_freq > policy->max) - this_dbs_info->requested_freq = policy->max; - - __cpufreq_driver_target(policy, this_dbs_info->requested_freq, - CPUFREQ_RELATION_H); - return; - } - - /* - * The optimal frequency is the frequency that is the lowest that - * can support the current CPU usage without triggering the up - * policy. To be safe, we focus 10 points under the threshold. - */ - if (max_load < (dbs_tuners_ins.down_threshold - 10)) { - freq_target = (dbs_tuners_ins.freq_step * policy->max) / 100; - - this_dbs_info->requested_freq -= freq_target; - if (this_dbs_info->requested_freq < policy->min) - this_dbs_info->requested_freq = policy->min; - - /* - * if we cannot reduce the frequency anymore, break out early - */ - if (policy->cur == policy->min) - return; - - __cpufreq_driver_target(policy, this_dbs_info->requested_freq, - CPUFREQ_RELATION_H); - return; - } -} - -static void do_dbs_timer(struct work_struct *work) -{ - struct cpu_dbs_info_s *dbs_info = - container_of(work, struct cpu_dbs_info_s, work.work); - unsigned int cpu = dbs_info->cpu; - - /* We want all CPUs to do sampling nearly on same jiffy */ - int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); - - delay -= jiffies % delay; - - mutex_lock(&dbs_info->timer_mutex); - - dbs_check_cpu(dbs_info); - - schedule_delayed_work_on(cpu, &dbs_info->work, delay); - mutex_unlock(&dbs_info->timer_mutex); -} - -static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) -{ - /* We want all CPUs to do sampling nearly on same jiffy */ - int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); - delay -= jiffies % delay; +static struct notifier_block cs_cpufreq_notifier_block = { + .notifier_call = dbs_cpufreq_notifier, +}; - dbs_info->enable = 1; - INIT_DEFERRABLE_WORK(&dbs_info->work, do_dbs_timer); - schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work, delay); -} +static struct cs_ops cs_ops = { + .notifier_block = &cs_cpufreq_notifier_block, +}; -static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) -{ - dbs_info->enable = 0; - cancel_delayed_work_sync(&dbs_info->work); -} +static struct dbs_data cs_dbs_data = { + .governor = GOV_CONSERVATIVE, + .attr_group = &cs_attr_group, + .tuners = &cs_tuners, + .get_cpu_cdbs = get_cpu_cdbs, + .get_cpu_dbs_info_s = get_cpu_dbs_info_s, + .gov_dbs_timer = cs_dbs_timer, + .gov_check_cpu = cs_check_cpu, + .gov_ops = &cs_ops, +}; -static int cpufreq_governor_dbs(struct cpufreq_policy *policy, +static int cs_cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event) { - unsigned int cpu = policy->cpu; - struct cpu_dbs_info_s *this_dbs_info; - unsigned int j; - int rc; - - this_dbs_info = &per_cpu(cs_cpu_dbs_info, cpu); - - switch (event) { - case CPUFREQ_GOV_START: - if ((!cpu_online(cpu)) || (!policy->cur)) - return -EINVAL; - - mutex_lock(&dbs_mutex); - - for_each_cpu(j, policy->cpus) { - struct cpu_dbs_info_s *j_dbs_info; - j_dbs_info = &per_cpu(cs_cpu_dbs_info, j); - j_dbs_info->cur_policy = policy; - - j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j, - &j_dbs_info->prev_cpu_wall); - if (dbs_tuners_ins.ignore_nice) - j_dbs_info->prev_cpu_nice = - kcpustat_cpu(j).cpustat[CPUTIME_NICE]; - } - this_dbs_info->cpu = cpu; - this_dbs_info->down_skip = 0; - this_dbs_info->requested_freq = policy->cur; - - mutex_init(&this_dbs_info->timer_mutex); - dbs_enable++; - /* - * Start the timerschedule work, when this governor - * is used for first time - */ - if (dbs_enable == 1) { - unsigned int latency; - /* policy latency is in nS. Convert it to uS first */ - latency = policy->cpuinfo.transition_latency / 1000; - if (latency == 0) - latency = 1; - - rc = sysfs_create_group(cpufreq_global_kobject, - &dbs_attr_group); - if (rc) { - mutex_unlock(&dbs_mutex); - return rc; - } - - /* - * conservative does not implement micro like ondemand - * governor, thus we are bound to jiffes/HZ - */ - min_sampling_rate = - MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10); - /* Bring kernel and HW constraints together */ - min_sampling_rate = max(min_sampling_rate, - MIN_LATENCY_MULTIPLIER * latency); - dbs_tuners_ins.sampling_rate = - max(min_sampling_rate, - latency * LATENCY_MULTIPLIER); - - cpufreq_register_notifier( - &dbs_cpufreq_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); - } - mutex_unlock(&dbs_mutex); - - dbs_timer_init(this_dbs_info); - - break; - - case CPUFREQ_GOV_STOP: - dbs_timer_exit(this_dbs_info); - - mutex_lock(&dbs_mutex); - dbs_enable--; - mutex_destroy(&this_dbs_info->timer_mutex); - - /* - * Stop the timerschedule work, when this governor - * is used for first time - */ - if (dbs_enable == 0) - cpufreq_unregister_notifier( - &dbs_cpufreq_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); - - mutex_unlock(&dbs_mutex); - if (!dbs_enable) - sysfs_remove_group(cpufreq_global_kobject, - &dbs_attr_group); - - break; - - case CPUFREQ_GOV_LIMITS: - mutex_lock(&this_dbs_info->timer_mutex); - if (policy->max < this_dbs_info->cur_policy->cur) - __cpufreq_driver_target( - this_dbs_info->cur_policy, - policy->max, CPUFREQ_RELATION_H); - else if (policy->min > this_dbs_info->cur_policy->cur) - __cpufreq_driver_target( - this_dbs_info->cur_policy, - policy->min, CPUFREQ_RELATION_L); - dbs_check_cpu(this_dbs_info); - mutex_unlock(&this_dbs_info->timer_mutex); - - break; - } - return 0; + return cpufreq_governor_dbs(&cs_dbs_data, policy, event); } #ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE @@ -597,13 +333,14 @@ static #endif struct cpufreq_governor cpufreq_gov_conservative = { .name = "conservative", - .governor = cpufreq_governor_dbs, + .governor = cs_cpufreq_governor_dbs, .max_transition_latency = TRANSITION_LATENCY_LIMIT, .owner = THIS_MODULE, }; static int __init cpufreq_gov_dbs_init(void) { + mutex_init(&cs_dbs_data.mutex); return cpufreq_register_governor(&cpufreq_gov_conservative); } @@ -612,7 +349,6 @@ static void __exit cpufreq_gov_dbs_exit(void) cpufreq_unregister_governor(&cpufreq_gov_conservative); } - MODULE_AUTHOR("Alexander Clouter <alex@digriz.org.uk>"); MODULE_DESCRIPTION("'cpufreq_conservative' - A dynamic cpufreq governor for " "Low Latency Frequency Transition capable processors " diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c new file mode 100644 index 00000000000..6c5f1d383cd --- /dev/null +++ b/drivers/cpufreq/cpufreq_governor.c @@ -0,0 +1,318 @@ +/* + * drivers/cpufreq/cpufreq_governor.c + * + * CPUFREQ governors common code + * + * Copyright (C) 2001 Russell King + * (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>. + * (C) 2003 Jun Nakajima <jun.nakajima@intel.com> + * (C) 2009 Alexander Clouter <alex@digriz.org.uk> + * (c) 2012 Viresh Kumar <viresh.kumar@linaro.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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <asm/cputime.h> +#include <linux/cpufreq.h> +#include <linux/cpumask.h> +#include <linux/export.h> +#include <linux/kernel_stat.h> +#include <linux/mutex.h> +#include <linux/tick.h> +#include <linux/types.h> +#include <linux/workqueue.h> + +#include "cpufreq_governor.h" + +static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) +{ + u64 idle_time; + u64 cur_wall_time; + u64 busy_time; + + cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); + + busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL]; + busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE]; + + idle_time = cur_wall_time - busy_time; + if (wall) + *wall = cputime_to_usecs(cur_wall_time); + + return cputime_to_usecs(idle_time); +} + +u64 get_cpu_idle_time(unsigned int cpu, u64 *wall) +{ + u64 idle_time = get_cpu_idle_time_us(cpu, NULL); + + if (idle_time == -1ULL) + return get_cpu_idle_time_jiffy(cpu, wall); + else + idle_time += get_cpu_iowait_time_us(cpu, wall); + + return idle_time; +} +EXPORT_SYMBOL_GPL(get_cpu_idle_time); + +void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) +{ + struct cpu_dbs_common_info *cdbs = dbs_data->get_cpu_cdbs(cpu); + struct od_dbs_tuners *od_tuners = dbs_data->tuners; + struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; + struct cpufreq_policy *policy; + unsigned int max_load = 0; + unsigned int ignore_nice; + unsigned int j; + + if (dbs_data->governor == GOV_ONDEMAND) + ignore_nice = od_tuners->ignore_nice; + else + ignore_nice = cs_tuners->ignore_nice; + + policy = cdbs->cur_policy; + + /* Get Absolute Load (in terms of freq for ondemand gov) */ + for_each_cpu(j, policy->cpus) { + struct cpu_dbs_common_info *j_cdbs; + u64 cur_wall_time, cur_idle_time, cur_iowait_time; + unsigned int idle_time, wall_time, iowait_time; + unsigned int load; + + j_cdbs = dbs_data->get_cpu_cdbs(j); + + cur_idle_time = get_cpu_idle_time(j, &cur_wall_time); + + wall_time = (unsigned int) + (cur_wall_time - j_cdbs->prev_cpu_wall); + j_cdbs->prev_cpu_wall = cur_wall_time; + + idle_time = (unsigned int) + (cur_idle_time - j_cdbs->prev_cpu_idle); + j_cdbs->prev_cpu_idle = cur_idle_time; + + if (ignore_nice) { + u64 cur_nice; + unsigned long cur_nice_jiffies; + + cur_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE] - + cdbs->prev_cpu_nice; + /* + * Assumption: nice time between sampling periods will + * be less than 2^32 jiffies for 32 bit sys + */ + cur_nice_jiffies = (unsigned long) + cputime64_to_jiffies64(cur_nice); + + cdbs->prev_cpu_nice = + kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + idle_time += jiffies_to_usecs(cur_nice_jiffies); + } + + if (dbs_data->governor == GOV_ONDEMAND) { + struct od_cpu_dbs_info_s *od_j_dbs_info = + dbs_data->get_cpu_dbs_info_s(cpu); + + cur_iowait_time = get_cpu_iowait_time_us(j, + &cur_wall_time); + if (cur_iowait_time == -1ULL) + cur_iowait_time = 0; + + iowait_time = (unsigned int) (cur_iowait_time - + od_j_dbs_info->prev_cpu_iowait); + od_j_dbs_info->prev_cpu_iowait = cur_iowait_time; + + /* + * For the purpose of ondemand, waiting for disk IO is + * an indication that you're performance critical, and + * not that the system is actually idle. So subtract the + * iowait time from the cpu idle time. + */ + if (od_tuners->io_is_busy && idle_time >= iowait_time) + idle_time -= iowait_time; + } + + if (unlikely(!wall_time || wall_time < idle_time)) + continue; + + load = 100 * (wall_time - idle_time) / wall_time; + + if (dbs_data->governor == GOV_ONDEMAND) { + int freq_avg = __cpufreq_driver_getavg(policy, j); + if (freq_avg <= 0) + freq_avg = policy->cur; + + load *= freq_avg; + } + + if (load > max_load) + max_load = load; + } + + dbs_data->gov_check_cpu(cpu, max_load); +} +EXPORT_SYMBOL_GPL(dbs_check_cpu); + +static inline void dbs_timer_init(struct dbs_data *dbs_data, + struct cpu_dbs_common_info *cdbs, unsigned int sampling_rate) +{ + int delay = delay_for_sampling_rate(sampling_rate); + + INIT_DEFERRABLE_WORK(&cdbs->work, dbs_data->gov_dbs_timer); + schedule_delayed_work_on(cdbs->cpu, &cdbs->work, delay); +} + +static inline void dbs_timer_exit(struct cpu_dbs_common_info *cdbs) +{ + cancel_delayed_work_sync(&cdbs->work); +} + +int cpufreq_governor_dbs(struct dbs_data *dbs_data, + struct cpufreq_policy *policy, unsigned int event) +{ + struct od_cpu_dbs_info_s *od_dbs_info = NULL; + struct cs_cpu_dbs_info_s *cs_dbs_info = NULL; + struct od_dbs_tuners *od_tuners = dbs_data->tuners; + struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; + struct cpu_dbs_common_info *cpu_cdbs; + unsigned int *sampling_rate, latency, ignore_nice, j, cpu = policy->cpu; + int rc; + + cpu_cdbs = dbs_data->get_cpu_cdbs(cpu); + + if (dbs_data->governor == GOV_CONSERVATIVE) { + cs_dbs_info = dbs_data->get_cpu_dbs_info_s(cpu); + sampling_rate = &cs_tuners->sampling_rate; + ignore_nice = cs_tuners->ignore_nice; + } else { + od_dbs_info = dbs_data->get_cpu_dbs_info_s(cpu); + sampling_rate = &od_tuners->sampling_rate; + ignore_nice = od_tuners->ignore_nice; + } + + switch (event) { + case CPUFREQ_GOV_START: + if ((!cpu_online(cpu)) || (!policy->cur)) + return -EINVAL; + + mutex_lock(&dbs_data->mutex); + + dbs_data->enable++; + cpu_cdbs->cpu = cpu; + for_each_cpu(j, policy->cpus) { + struct cpu_dbs_common_info *j_cdbs; + j_cdbs = dbs_data->get_cpu_cdbs(j); + + j_cdbs->cur_policy = policy; + j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, + &j_cdbs->prev_cpu_wall); + if (ignore_nice) + j_cdbs->prev_cpu_nice = + kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + } + + /* + * Start the timerschedule work, when this governor is used for + * first time + */ + if (dbs_data->enable != 1) + goto second_time; + + rc = sysfs_create_group(cpufreq_global_kobject, + dbs_data->attr_group); + if (rc) { + mutex_unlock(&dbs_data->mutex); + return rc; + } + + /* policy latency is in nS. Convert it to uS first */ + latency = policy->cpuinfo.transition_latency / 1000; + if (latency == 0) + latency = 1; + + /* + * conservative does not implement micro like ondemand + * governor, thus we are bound to jiffes/HZ + */ + if (dbs_data->governor == GOV_CONSERVATIVE) { + struct cs_ops *ops = dbs_data->gov_ops; + + cpufreq_register_notifier(ops->notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); + + dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO * + jiffies_to_usecs(10); + } else { + struct od_ops *ops = dbs_data->gov_ops; + + od_tuners->io_is_busy = ops->io_busy(); + } + + /* Bring kernel and HW constraints together */ + dbs_data->min_sampling_rate = max(dbs_data->min_sampling_rate, + MIN_LATENCY_MULTIPLIER * latency); + *sampling_rate = max(dbs_data->min_sampling_rate, latency * + LATENCY_MULTIPLIER); + +second_time: + if (dbs_data->governor == GOV_CONSERVATIVE) { + cs_dbs_info->down_skip = 0; + cs_dbs_info->enable = 1; + cs_dbs_info->requested_freq = policy->cur; + } else { + struct od_ops *ops = dbs_data->gov_ops; + od_dbs_info->rate_mult = 1; + od_dbs_info->sample_type = OD_NORMAL_SAMPLE; + ops->powersave_bias_init_cpu(cpu); + } + mutex_unlock(&dbs_data->mutex); + + mutex_init(&cpu_cdbs->timer_mutex); + dbs_timer_init(dbs_data, cpu_cdbs, *sampling_rate); + break; + + case CPUFREQ_GOV_STOP: + if (dbs_data->governor == GOV_CONSERVATIVE) + cs_dbs_info->enable = 0; + + dbs_timer_exit(cpu_cdbs); + + mutex_lock(&dbs_data->mutex); + mutex_destroy(&cpu_cdbs->timer_mutex); + dbs_data->enable--; + if (!dbs_data->enable) { + struct cs_ops *ops = dbs_data->gov_ops; + + sysfs_remove_group(cpufreq_global_kobject, + dbs_data->attr_group); + if (dbs_data->governor == GOV_CONSERVATIVE) + cpufreq_unregister_notifier(ops->notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); + } + mutex_unlock(&dbs_data->mutex); + + break; + + case CPUFREQ_GOV_LIMITS: + mutex_lock(&cpu_cdbs->timer_mutex); + if (policy->max < cpu_cdbs->cur_policy->cur) + __cpufreq_driver_target(cpu_cdbs->cur_policy, + policy->max, CPUFREQ_RELATION_H); + else if (policy->min > cpu_cdbs->cur_policy->cur) + __cpufreq_driver_target(cpu_cdbs->cur_policy, + policy->min, CPUFREQ_RELATION_L); + dbs_check_cpu(dbs_data, cpu); + mutex_unlock(&cpu_cdbs->timer_mutex); + break; + } + return 0; +} +EXPORT_SYMBOL_GPL(cpufreq_governor_dbs); diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h new file mode 100644 index 00000000000..f6616540c53 --- /dev/null +++ b/drivers/cpufreq/cpufreq_governor.h @@ -0,0 +1,176 @@ +/* + * drivers/cpufreq/cpufreq_governor.h + * + * Header file for CPUFreq governors common code + * + * Copyright (C) 2001 Russell King + * (C) 2003 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>. + * (C) 2003 Jun Nakajima <jun.nakajima@intel.com> + * (C) 2009 Alexander Clouter <alex@digriz.org.uk> + * (c) 2012 Viresh Kumar <viresh.kumar@linaro.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. + */ + +#ifndef _CPUFREQ_GOVERNER_H +#define _CPUFREQ_GOVERNER_H + +#include <linux/cpufreq.h> +#include <linux/kobject.h> +#include <linux/mutex.h> +#include <linux/workqueue.h> +#include <linux/sysfs.h> + +/* + * The polling frequency depends on the capability of the processor. Default + * polling frequency is 1000 times the transition latency of the processor. The + * governor will work on any processor with transition latency <= 10mS, using + * appropriate sampling rate. + * + * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL) + * this governor will not work. All times here are in uS. + */ +#define MIN_SAMPLING_RATE_RATIO (2) +#define LATENCY_MULTIPLIER (1000) +#define MIN_LATENCY_MULTIPLIER (100) +#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) + +/* Ondemand Sampling types */ +enum {OD_NORMAL_SAMPLE, OD_SUB_SAMPLE}; + +/* Macro creating sysfs show routines */ +#define show_one(_gov, file_name, object) \ +static ssize_t show_##file_name \ +(struct kobject *kobj, struct attribute *attr, char *buf) \ +{ \ + return sprintf(buf, "%u\n", _gov##_tuners.object); \ +} + +#define define_get_cpu_dbs_routines(_dbs_info) \ +static struct cpu_dbs_common_info *get_cpu_cdbs(int cpu) \ +{ \ + return &per_cpu(_dbs_info, cpu).cdbs; \ +} \ + \ +static void *get_cpu_dbs_info_s(int cpu) \ +{ \ + return &per_cpu(_dbs_info, cpu); \ +} + +/* + * Abbreviations: + * dbs: used as a shortform for demand based switching It helps to keep variable + * names smaller, simpler + * cdbs: common dbs + * on_*: On-demand governor + * cs_*: Conservative governor + */ + +/* Per cpu structures */ +struct cpu_dbs_common_info { + int cpu; + u64 prev_cpu_idle; + u64 prev_cpu_wall; + u64 prev_cpu_nice; + struct cpufreq_policy *cur_policy; + struct delayed_work work; + /* + * percpu mutex that serializes governor limit change with gov_dbs_timer + * invocation. We do not want gov_dbs_timer to run when user is changing + * the governor or limits. + */ + struct mutex timer_mutex; +}; + +struct od_cpu_dbs_info_s { + struct cpu_dbs_common_info cdbs; + u64 prev_cpu_iowait; + struct cpufreq_frequency_table *freq_table; + unsigned int freq_lo; + unsigned int freq_lo_jiffies; + unsigned int freq_hi_jiffies; + unsigned int rate_mult; + unsigned int sample_type:1; +}; + +struct cs_cpu_dbs_info_s { + struct cpu_dbs_common_info cdbs; + unsigned int down_skip; + unsigned int requested_freq; + unsigned int enable:1; +}; + +/* Governers sysfs tunables */ +struct od_dbs_tuners { + unsigned int ignore_nice; + unsigned int sampling_rate; + unsigned int sampling_down_factor; + unsigned int up_threshold; + unsigned int down_differential; + unsigned int powersave_bias; + unsigned int io_is_busy; +}; + +struct cs_dbs_tuners { + unsigned int ignore_nice; + unsigned int sampling_rate; + unsigned int sampling_down_factor; + unsigned int up_threshold; + unsigned int down_threshold; + unsigned int freq_step; +}; + +/* Per Governer data */ +struct dbs_data { + /* Common across governors */ + #define GOV_ONDEMAND 0 + #define GOV_CONSERVATIVE 1 + int governor; + unsigned int min_sampling_rate; + unsigned int enable; /* number of CPUs using this policy */ + struct attribute_group *attr_group; + void *tuners; + + /* dbs_mutex protects dbs_enable in governor start/stop */ + struct mutex mutex; + + struct cpu_dbs_common_info *(*get_cpu_cdbs)(int cpu); + void *(*get_cpu_dbs_info_s)(int cpu); + void (*gov_dbs_timer)(struct work_struct *work); + void (*gov_check_cpu)(int cpu, unsigned int load); + + /* Governor specific ops, see below */ + void *gov_ops; +}; + +/* Governor specific ops, will be passed to dbs_data->gov_ops */ +struct od_ops { + int (*io_busy)(void); + void (*powersave_bias_init_cpu)(int cpu); + unsigned int (*powersave_bias_target)(struct cpufreq_policy *policy, + unsigned int freq_next, unsigned int relation); + void (*freq_increase)(struct cpufreq_policy *p, unsigned int freq); +}; + +struct cs_ops { + struct notifier_block *notifier_block; +}; + +static inline int delay_for_sampling_rate(unsigned int sampling_rate) +{ + int delay = usecs_to_jiffies(sampling_rate); + + /* We want all CPUs to do sampling nearly on same jiffy */ + if (num_online_cpus() > 1) + delay -= jiffies % delay; + + return delay; +} + +u64 get_cpu_idle_time(unsigned int cpu, u64 *wall); +void dbs_check_cpu(struct dbs_data *dbs_data, int cpu); +int cpufreq_governor_dbs(struct dbs_data *dbs_data, + struct cpufreq_policy *policy, unsigned int event); +#endif /* _CPUFREQ_GOVERNER_H */ diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 396322f2a83..7731f7c7e79 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -10,24 +10,23 @@ * published by the Free Software Foundation. */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/cpufreq.h> -#include <linux/cpu.h> -#include <linux/jiffies.h> +#include <linux/init.h> +#include <linux/kernel.h> #include <linux/kernel_stat.h> +#include <linux/kobject.h> +#include <linux/module.h> #include <linux/mutex.h> -#include <linux/hrtimer.h> +#include <linux/percpu-defs.h> +#include <linux/sysfs.h> #include <linux/tick.h> -#include <linux/ktime.h> -#include <linux/sched.h> +#include <linux/types.h> -/* - * dbs is used in this file as a shortform for demandbased switching - * It helps to keep variable names smaller, simpler - */ +#include "cpufreq_governor.h" +/* On-demand governor macors */ #define DEF_FREQUENCY_DOWN_DIFFERENTIAL (10) #define DEF_FREQUENCY_UP_THRESHOLD (80) #define DEF_SAMPLING_DOWN_FACTOR (1) @@ -38,80 +37,14 @@ #define MIN_FREQUENCY_UP_THRESHOLD (11) #define MAX_FREQUENCY_UP_THRESHOLD (100) -/* - * The polling frequency of this governor depends on the capability of - * the processor. Default polling frequency is 1000 times the transition - * latency of the processor. The governor will work on any processor with - * transition latency <= 10mS, using appropriate sampling - * rate. - * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL) - * this governor will not work. - * All times here are in uS. - */ -#define MIN_SAMPLING_RATE_RATIO (2) - -static unsigned int min_sampling_rate; - -#define LATENCY_MULTIPLIER (1000) -#define MIN_LATENCY_MULTIPLIER (100) -#define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000) - -static void do_dbs_timer(struct work_struct *work); -static int cpufreq_governor_dbs(struct cpufreq_policy *policy, - unsigned int event); +static struct dbs_data od_dbs_data; +static DEFINE_PER_CPU(struct od_cpu_dbs_info_s, od_cpu_dbs_info); #ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND -static +static struct cpufreq_governor cpufreq_gov_ondemand; #endif -struct cpufreq_governor cpufreq_gov_ondemand = { - .name = "ondemand", - .governor = cpufreq_governor_dbs, - .max_transition_latency = TRANSITION_LATENCY_LIMIT, - .owner = THIS_MODULE, -}; -/* Sampling types */ -enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE}; - -struct cpu_dbs_info_s { - cputime64_t prev_cpu_idle; - cputime64_t prev_cpu_iowait; - cputime64_t prev_cpu_wall; - cputime64_t prev_cpu_nice; - struct cpufreq_policy *cur_policy; - struct delayed_work work; - struct cpufreq_frequency_table *freq_table; - unsigned int freq_lo; - unsigned int freq_lo_jiffies; - unsigned int freq_hi_jiffies; - unsigned int rate_mult; - int cpu; - unsigned int sample_type:1; - /* - * percpu mutex that serializes governor limit change with - * do_dbs_timer invocation. We do not want do_dbs_timer to run - * when user is changing the governor or limits. - */ - struct mutex timer_mutex; -}; -static DEFINE_PER_CPU(struct cpu_dbs_info_s, od_cpu_dbs_info); - -static unsigned int dbs_enable; /* number of CPUs using this policy */ - -/* - * dbs_mutex protects dbs_enable in governor start/stop. - */ -static DEFINE_MUTEX(dbs_mutex); - -static struct dbs_tuners { - unsigned int sampling_rate; - unsigned int up_threshold; - unsigned int down_differential; - unsigned int ignore_nice; - unsigned int sampling_down_factor; - unsigned int powersave_bias; - unsigned int io_is_busy; -} dbs_tuners_ins = { +static struct od_dbs_tuners od_tuners = { .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR, .down_differential = DEF_FREQUENCY_DOWN_DIFFERENTIAL, @@ -119,48 +52,35 @@ static struct dbs_tuners { .powersave_bias = 0, }; -static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) -{ - u64 idle_time; - u64 cur_wall_time; - u64 busy_time; - - cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); - - busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL]; - busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE]; - - idle_time = cur_wall_time - busy_time; - if (wall) - *wall = jiffies_to_usecs(cur_wall_time); - - return jiffies_to_usecs(idle_time); -} - -static inline cputime64_t get_cpu_idle_time(unsigned int cpu, cputime64_t *wall) +static void ondemand_powersave_bias_init_cpu(int cpu) { - u64 idle_time = get_cpu_idle_time_us(cpu, NULL); - - if (idle_time == -1ULL) - return get_cpu_idle_time_jiffy(cpu, wall); - else - idle_time += get_cpu_iowait_time_us(cpu, wall); + struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); - return idle_time; + dbs_info->freq_table = cpufreq_frequency_get_table(cpu); + dbs_info->freq_lo = 0; } -static inline cputime64_t get_cpu_iowait_time(unsigned int cpu, cputime64_t *wall) +/* + * Not all CPUs want IO time to be accounted as busy; this depends on how + * efficient idling at a higher frequency/voltage is. + * Pavel Machek says this is not so for various generations of AMD and old + * Intel systems. + * Mike Chan (androidlcom) calis this is also not true for ARM. + * Because of this, whitelist specific known (series) of CPUs by default, and + * leave all others up to the user. + */ +static int should_io_be_busy(void) { - u64 iowait_time = get_cpu_iowait_time_us(cpu, wall); - - if (iowait_time == -1ULL) - return 0; - - return iowait_time; +#if defined(CONFIG_X86) + /* + * For Intel, Core 2 (model 15) andl later have an efficient idle. + */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && + boot_cpu_data.x86 == 6 && + boot_cpu_data.x86_model >= 15) + return 1; +#endif + return 0; } /* @@ -169,14 +89,13 @@ static inline cputime64_t get_cpu_iowait_time(unsigned int cpu, cputime64_t *wal * freq_lo, and freq_lo_jiffies in percpu area for averaging freqs. */ static unsigned int powersave_bias_target(struct cpufreq_policy *policy, - unsigned int freq_next, - unsigned int relation) + unsigned int freq_next, unsigned int relation) { unsigned int freq_req, freq_reduc, freq_avg; unsigned int freq_hi, freq_lo; unsigned int index = 0; unsigned int jiffies_total, jiffies_hi, jiffies_lo; - struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, + struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, policy->cpu); if (!dbs_info->freq_table) { @@ -188,7 +107,7 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy, cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_next, relation, &index); freq_req = dbs_info->freq_table[index].frequency; - freq_reduc = freq_req * dbs_tuners_ins.powersave_bias / 1000; + freq_reduc = freq_req * od_tuners.powersave_bias / 1000; freq_avg = freq_req - freq_reduc; /* Find freq bounds for freq_avg in freq_table */ @@ -207,7 +126,7 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy, dbs_info->freq_lo_jiffies = 0; return freq_lo; } - jiffies_total = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + jiffies_total = usecs_to_jiffies(od_tuners.sampling_rate); jiffies_hi = (freq_avg - freq_lo) * jiffies_total; jiffies_hi += ((freq_hi - freq_lo) / 2); jiffies_hi /= (freq_hi - freq_lo); @@ -218,13 +137,6 @@ static unsigned int powersave_bias_target(struct cpufreq_policy *policy, return freq_hi; } -static void ondemand_powersave_bias_init_cpu(int cpu) -{ - struct cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); - dbs_info->freq_table = cpufreq_frequency_get_table(cpu); - dbs_info->freq_lo = 0; -} - static void ondemand_powersave_bias_init(void) { int i; @@ -233,83 +145,173 @@ static void ondemand_powersave_bias_init(void) } } -/************************** sysfs interface ************************/ +static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq) +{ + if (od_tuners.powersave_bias) + freq = powersave_bias_target(p, freq, CPUFREQ_RELATION_H); + else if (p->cur == p->max) + return; -static ssize_t show_sampling_rate_min(struct kobject *kobj, - struct attribute *attr, char *buf) + __cpufreq_driver_target(p, freq, od_tuners.powersave_bias ? + CPUFREQ_RELATION_L : CPUFREQ_RELATION_H); +} + +/* + * Every sampling_rate, we check, if current idle time is less than 20% + * (default), then we try to increase frequency Every sampling_rate, we look for + * a the lowest frequency which can sustain the load while keeping idle time + * over 30%. If such a frequency exist, we try to decrease to this frequency. + * + * Any frequency increase takes it to the maximum frequency. Frequency reduction + * happens at minimum steps of 5% (default) of current frequency + */ +static void od_check_cpu(int cpu, unsigned int load_freq) { - return sprintf(buf, "%u\n", min_sampling_rate); + struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); + struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy; + + dbs_info->freq_lo = 0; + + /* Check for frequency increase */ + if (load_freq > od_tuners.up_threshold * policy->cur) { + /* If switching to max speed, apply sampling_down_factor */ + if (policy->cur < policy->max) + dbs_info->rate_mult = + od_tuners.sampling_down_factor; + dbs_freq_increase(policy, policy->max); + return; + } + + /* Check for frequency decrease */ + /* if we cannot reduce the frequency anymore, break out early */ + if (policy->cur == policy->min) + return; + + /* + * The optimal frequency is the frequency that is the lowest that can + * support the current CPU usage without triggering the up policy. To be + * safe, we focus 10 points under the threshold. + */ + if (load_freq < (od_tuners.up_threshold - od_tuners.down_differential) * + policy->cur) { + unsigned int freq_next; + freq_next = load_freq / (od_tuners.up_threshold - + od_tuners.down_differential); + + /* No longer fully busy, reset rate_mult */ + dbs_info->rate_mult = 1; + + if (freq_next < policy->min) + freq_next = policy->min; + + if (!od_tuners.powersave_bias) { + __cpufreq_driver_target(policy, freq_next, + CPUFREQ_RELATION_L); + } else { + int freq = powersave_bias_target(policy, freq_next, + CPUFREQ_RELATION_L); + __cpufreq_driver_target(policy, freq, + CPUFREQ_RELATION_L); + } + } } -define_one_global_ro(sampling_rate_min); +static void od_dbs_timer(struct work_struct *work) +{ + struct od_cpu_dbs_info_s *dbs_info = + container_of(work, struct od_cpu_dbs_info_s, cdbs.work.work); + unsigned int cpu = dbs_info->cdbs.cpu; + int delay, sample_type = dbs_info->sample_type; + + mutex_lock(&dbs_info->cdbs.timer_mutex); + + /* Common NORMAL_SAMPLE setup */ + dbs_info->sample_type = OD_NORMAL_SAMPLE; + if (sample_type == OD_SUB_SAMPLE) { + delay = dbs_info->freq_lo_jiffies; + __cpufreq_driver_target(dbs_info->cdbs.cur_policy, + dbs_info->freq_lo, CPUFREQ_RELATION_H); + } else { + dbs_check_cpu(&od_dbs_data, cpu); + if (dbs_info->freq_lo) { + /* Setup timer for SUB_SAMPLE */ + dbs_info->sample_type = OD_SUB_SAMPLE; + delay = dbs_info->freq_hi_jiffies; + } else { + delay = delay_for_sampling_rate(od_tuners.sampling_rate + * dbs_info->rate_mult); + } + } + + schedule_delayed_work_on(cpu, &dbs_info->cdbs.work, delay); + mutex_unlock(&dbs_info->cdbs.timer_mutex); +} + +/************************** sysfs interface ************************/ -/* cpufreq_ondemand Governor Tunables */ -#define show_one(file_name, object) \ -static ssize_t show_##file_name \ -(struct kobject *kobj, struct attribute *attr, char *buf) \ -{ \ - return sprintf(buf, "%u\n", dbs_tuners_ins.object); \ +static ssize_t show_sampling_rate_min(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", od_dbs_data.min_sampling_rate); } -show_one(sampling_rate, sampling_rate); -show_one(io_is_busy, io_is_busy); -show_one(up_threshold, up_threshold); -show_one(sampling_down_factor, sampling_down_factor); -show_one(ignore_nice_load, ignore_nice); -show_one(powersave_bias, powersave_bias); /** * update_sampling_rate - update sampling rate effective immediately if needed. * @new_rate: new sampling rate * * If new rate is smaller than the old, simply updaing - * dbs_tuners_int.sampling_rate might not be appropriate. For example, - * if the original sampling_rate was 1 second and the requested new sampling - * rate is 10 ms because the user needs immediate reaction from ondemand - * governor, but not sure if higher frequency will be required or not, - * then, the governor may change the sampling rate too late; up to 1 second - * later. Thus, if we are reducing the sampling rate, we need to make the - * new value effective immediately. + * dbs_tuners_int.sampling_rate might not be appropriate. For example, if the + * original sampling_rate was 1 second and the requested new sampling rate is 10 + * ms because the user needs immediate reaction from ondemand governor, but not + * sure if higher frequency will be required or not, then, the governor may + * change the sampling rate too late; up to 1 second later. Thus, if we are + * reducing the sampling rate, we need to make the new value effective + * immediately. */ static void update_sampling_rate(unsigned int new_rate) { int cpu; - dbs_tuners_ins.sampling_rate = new_rate - = max(new_rate, min_sampling_rate); + od_tuners.sampling_rate = new_rate = max(new_rate, + od_dbs_data.min_sampling_rate); for_each_online_cpu(cpu) { struct cpufreq_policy *policy; - struct cpu_dbs_info_s *dbs_info; + struct od_cpu_dbs_info_s *dbs_info; unsigned long next_sampling, appointed_at; policy = cpufreq_cpu_get(cpu); if (!policy) continue; + if (policy->governor != &cpufreq_gov_ondemand) { + cpufreq_cpu_put(policy); + continue; + } dbs_info = &per_cpu(od_cpu_dbs_info, policy->cpu); cpufreq_cpu_put(policy); - mutex_lock(&dbs_info->timer_mutex); + mutex_lock(&dbs_info->cdbs.timer_mutex); - if (!delayed_work_pending(&dbs_info->work)) { - mutex_unlock(&dbs_info->timer_mutex); + if (!delayed_work_pending(&dbs_info->cdbs.work)) { + mutex_unlock(&dbs_info->cdbs.timer_mutex); continue; } - next_sampling = jiffies + usecs_to_jiffies(new_rate); - appointed_at = dbs_info->work.timer.expires; - + next_sampling = jiffies + usecs_to_jiffies(new_rate); + appointed_at = dbs_info->cdbs.work.timer.expires; if (time_before(next_sampling, appointed_at)) { - mutex_unlock(&dbs_info->timer_mutex); - cancel_delayed_work_sync(&dbs_info->work); - mutex_lock(&dbs_info->timer_mutex); + mutex_unlock(&dbs_info->cdbs.timer_mutex); + cancel_delayed_work_sync(&dbs_info->cdbs.work); + mutex_lock(&dbs_info->cdbs.timer_mutex); - schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work, - usecs_to_jiffies(new_rate)); + schedule_delayed_work_on(dbs_info->cdbs.cpu, + &dbs_info->cdbs.work, + usecs_to_jiffies(new_rate)); } - mutex_unlock(&dbs_info->timer_mutex); + mutex_unlock(&dbs_info->cdbs.timer_mutex); } } @@ -334,7 +336,7 @@ static ssize_t store_io_is_busy(struct kobject *a, struct attribute *b, ret = sscanf(buf, "%u", &input); if (ret != 1) return -EINVAL; - dbs_tuners_ins.io_is_busy = !!input; + od_tuners.io_is_busy = !!input; return count; } @@ -349,7 +351,7 @@ static ssize_t store_up_threshold(struct kobject *a, struct attribute *b, input < MIN_FREQUENCY_UP_THRESHOLD) { return -EINVAL; } - dbs_tuners_ins.up_threshold = input; + od_tuners.up_threshold = input; return count; } @@ -362,12 +364,12 @@ static ssize_t store_sampling_down_factor(struct kobject *a, if (ret != 1 || input > MAX_SAMPLING_DOWN_FACTOR || input < 1) return -EINVAL; - dbs_tuners_ins.sampling_down_factor = input; + od_tuners.sampling_down_factor = input; /* Reset down sampling multiplier in case it was active */ for_each_online_cpu(j) { - struct cpu_dbs_info_s *dbs_info; - dbs_info = &per_cpu(od_cpu_dbs_info, j); + struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, + j); dbs_info->rate_mult = 1; } return count; @@ -388,19 +390,20 @@ static ssize_t store_ignore_nice_load(struct kobject *a, struct attribute *b, if (input > 1) input = 1; - if (input == dbs_tuners_ins.ignore_nice) { /* nothing to do */ + if (input == od_tuners.ignore_nice) { /* nothing to do */ return count; } - dbs_tuners_ins.ignore_nice = input; + od_tuners.ignore_nice = input; /* we need to re-evaluate prev_cpu_idle */ for_each_online_cpu(j) { - struct cpu_dbs_info_s *dbs_info; + struct od_cpu_dbs_info_s *dbs_info; dbs_info = &per_cpu(od_cpu_dbs_info, j); - dbs_info->prev_cpu_idle = get_cpu_idle_time(j, - &dbs_info->prev_cpu_wall); - if (dbs_tuners_ins.ignore_nice) - dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; + dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j, + &dbs_info->cdbs.prev_cpu_wall); + if (od_tuners.ignore_nice) + dbs_info->cdbs.prev_cpu_nice = + kcpustat_cpu(j).cpustat[CPUTIME_NICE]; } return count; @@ -419,17 +422,25 @@ static ssize_t store_powersave_bias(struct kobject *a, struct attribute *b, if (input > 1000) input = 1000; - dbs_tuners_ins.powersave_bias = input; + od_tuners.powersave_bias = input; ondemand_powersave_bias_init(); return count; } +show_one(od, sampling_rate, sampling_rate); +show_one(od, io_is_busy, io_is_busy); +show_one(od, up_threshold, up_threshold); +show_one(od, sampling_down_factor, sampling_down_factor); +show_one(od, ignore_nice_load, ignore_nice); +show_one(od, powersave_bias, powersave_bias); + define_one_global_rw(sampling_rate); define_one_global_rw(io_is_busy); define_one_global_rw(up_threshold); define_one_global_rw(sampling_down_factor); define_one_global_rw(ignore_nice_load); define_one_global_rw(powersave_bias); +define_one_global_ro(sampling_rate_min); static struct attribute *dbs_attributes[] = { &sampling_rate_min.attr, @@ -442,354 +453,71 @@ static struct attribute *dbs_attributes[] = { NULL }; -static struct attribute_group dbs_attr_group = { +static struct attribute_group od_attr_group = { .attrs = dbs_attributes, .name = "ondemand", }; /************************** sysfs end ************************/ -static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq) -{ - if (dbs_tuners_ins.powersave_bias) - freq = powersave_bias_target(p, freq, CPUFREQ_RELATION_H); - else if (p->cur == p->max) - return; - - __cpufreq_driver_target(p, freq, dbs_tuners_ins.powersave_bias ? - CPUFREQ_RELATION_L : CPUFREQ_RELATION_H); -} - -static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) -{ - unsigned int max_load_freq; - - struct cpufreq_policy *policy; - unsigned int j; - - this_dbs_info->freq_lo = 0; - policy = this_dbs_info->cur_policy; - - /* - * Every sampling_rate, we check, if current idle time is less - * than 20% (default), then we try to increase frequency - * Every sampling_rate, we look for a the lowest - * frequency which can sustain the load while keeping idle time over - * 30%. If such a frequency exist, we try to decrease to this frequency. - * - * Any frequency increase takes it to the maximum frequency. - * Frequency reduction happens at minimum steps of - * 5% (default) of current frequency - */ - - /* Get Absolute Load - in terms of freq */ - max_load_freq = 0; - - for_each_cpu(j, policy->cpus) { - struct cpu_dbs_info_s *j_dbs_info; - cputime64_t cur_wall_time, cur_idle_time, cur_iowait_time; - unsigned int idle_time, wall_time, iowait_time; - unsigned int load, load_freq; - int freq_avg; - - j_dbs_info = &per_cpu(od_cpu_dbs_info, j); - - cur_idle_time = get_cpu_idle_time(j, &cur_wall_time); - cur_iowait_time = get_cpu_iowait_time(j, &cur_wall_time); - - wall_time = (unsigned int) - (cur_wall_time - j_dbs_info->prev_cpu_wall); - j_dbs_info->prev_cpu_wall = cur_wall_time; - - idle_time = (unsigned int) - (cur_idle_time - j_dbs_info->prev_cpu_idle); - j_dbs_info->prev_cpu_idle = cur_idle_time; - - iowait_time = (unsigned int) - (cur_iowait_time - j_dbs_info->prev_cpu_iowait); - j_dbs_info->prev_cpu_iowait = cur_iowait_time; - - if (dbs_tuners_ins.ignore_nice) { - u64 cur_nice; - unsigned long cur_nice_jiffies; - - cur_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE] - - j_dbs_info->prev_cpu_nice; - /* - * Assumption: nice time between sampling periods will - * be less than 2^32 jiffies for 32 bit sys - */ - cur_nice_jiffies = (unsigned long) - cputime64_to_jiffies64(cur_nice); - - j_dbs_info->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; - idle_time += jiffies_to_usecs(cur_nice_jiffies); - } - - /* - * For the purpose of ondemand, waiting for disk IO is an - * indication that you're performance critical, and not that - * the system is actually idle. So subtract the iowait time - * from the cpu idle time. - */ - - if (dbs_tuners_ins.io_is_busy && idle_time >= iowait_time) - idle_time -= iowait_time; - - if (unlikely(!wall_time || wall_time < idle_time)) - continue; - - load = 100 * (wall_time - idle_time) / wall_time; - - freq_avg = __cpufreq_driver_getavg(policy, j); - if (freq_avg <= 0) - freq_avg = policy->cur; - - load_freq = load * freq_avg; - if (load_freq > max_load_freq) - max_load_freq = load_freq; - } +define_get_cpu_dbs_routines(od_cpu_dbs_info); - /* Check for frequency increase */ - if (max_load_freq > dbs_tuners_ins.up_threshold * policy->cur) { - /* If switching to max speed, apply sampling_down_factor */ - if (policy->cur < policy->max) - this_dbs_info->rate_mult = - dbs_tuners_ins.sampling_down_factor; - dbs_freq_increase(policy, policy->max); - return; - } - - /* Check for frequency decrease */ - /* if we cannot reduce the frequency anymore, break out early */ - if (policy->cur == policy->min) - return; - - /* - * The optimal frequency is the frequency that is the lowest that - * can support the current CPU usage without triggering the up - * policy. To be safe, we focus 10 points under the threshold. - */ - if (max_load_freq < - (dbs_tuners_ins.up_threshold - dbs_tuners_ins.down_differential) * - policy->cur) { - unsigned int freq_next; - freq_next = max_load_freq / - (dbs_tuners_ins.up_threshold - - dbs_tuners_ins.down_differential); - - /* No longer fully busy, reset rate_mult */ - this_dbs_info->rate_mult = 1; - - if (freq_next < policy->min) - freq_next = policy->min; - - if (!dbs_tuners_ins.powersave_bias) { - __cpufreq_driver_target(policy, freq_next, - CPUFREQ_RELATION_L); - } else { - int freq = powersave_bias_target(policy, freq_next, - CPUFREQ_RELATION_L); - __cpufreq_driver_target(policy, freq, - CPUFREQ_RELATION_L); - } - } -} - -static void do_dbs_timer(struct work_struct *work) -{ - struct cpu_dbs_info_s *dbs_info = - container_of(work, struct cpu_dbs_info_s, work.work); - unsigned int cpu = dbs_info->cpu; - int sample_type = dbs_info->sample_type; - - int delay; - - mutex_lock(&dbs_info->timer_mutex); - - /* Common NORMAL_SAMPLE setup */ - dbs_info->sample_type = DBS_NORMAL_SAMPLE; - if (!dbs_tuners_ins.powersave_bias || - sample_type == DBS_NORMAL_SAMPLE) { - dbs_check_cpu(dbs_info); - if (dbs_info->freq_lo) { - /* Setup timer for SUB_SAMPLE */ - dbs_info->sample_type = DBS_SUB_SAMPLE; - delay = dbs_info->freq_hi_jiffies; - } else { - /* We want all CPUs to do sampling nearly on - * same jiffy - */ - delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate - * dbs_info->rate_mult); - - if (num_online_cpus() > 1) - delay -= jiffies % delay; - } - } else { - __cpufreq_driver_target(dbs_info->cur_policy, - dbs_info->freq_lo, CPUFREQ_RELATION_H); - delay = dbs_info->freq_lo_jiffies; - } - schedule_delayed_work_on(cpu, &dbs_info->work, delay); - mutex_unlock(&dbs_info->timer_mutex); -} - -static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) -{ - /* We want all CPUs to do sampling nearly on same jiffy */ - int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); - - if (num_online_cpus() > 1) - delay -= jiffies % delay; +static struct od_ops od_ops = { + .io_busy = should_io_be_busy, + .powersave_bias_init_cpu = ondemand_powersave_bias_init_cpu, + .powersave_bias_target = powersave_bias_target, + .freq_increase = dbs_freq_increase, +}; - dbs_info->sample_type = DBS_NORMAL_SAMPLE; - INIT_DEFERRABLE_WORK(&dbs_info->work, do_dbs_timer); - schedule_delayed_work_on(dbs_info->cpu, &dbs_info->work, delay); -} +static struct dbs_data od_dbs_data = { + .governor = GOV_ONDEMAND, + .attr_group = &od_attr_group, + .tuners = &od_tuners, + .get_cpu_cdbs = get_cpu_cdbs, + .get_cpu_dbs_info_s = get_cpu_dbs_info_s, + .gov_dbs_timer = od_dbs_timer, + .gov_check_cpu = od_check_cpu, + .gov_ops = &od_ops, +}; -static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) +static int od_cpufreq_governor_dbs(struct cpufreq_policy *policy, + unsigned int event) { - cancel_delayed_work_sync(&dbs_info->work); + return cpufreq_governor_dbs(&od_dbs_data, policy, event); } -/* - * Not all CPUs want IO time to be accounted as busy; this dependson how - * efficient idling at a higher frequency/voltage is. - * Pavel Machek says this is not so for various generations of AMD and old - * Intel systems. - * Mike Chan (androidlcom) calis this is also not true for ARM. - * Because of this, whitelist specific known (series) of CPUs by default, and - * leave all others up to the user. - */ -static int should_io_be_busy(void) -{ -#if defined(CONFIG_X86) - /* - * For Intel, Core 2 (model 15) andl later have an efficient idle. - */ - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && - boot_cpu_data.x86 == 6 && - boot_cpu_data.x86_model >= 15) - return 1; +#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND +static #endif - return 0; -} - -static int cpufreq_governor_dbs(struct cpufreq_policy *policy, - unsigned int event) -{ - unsigned int cpu = policy->cpu; - struct cpu_dbs_info_s *this_dbs_info; - unsigned int j; - int rc; - - this_dbs_info = &per_cpu(od_cpu_dbs_info, cpu); - - switch (event) { - case CPUFREQ_GOV_START: - if ((!cpu_online(cpu)) || (!policy->cur)) - return -EINVAL; - - mutex_lock(&dbs_mutex); - - dbs_enable++; - for_each_cpu(j, policy->cpus) { - struct cpu_dbs_info_s *j_dbs_info; - j_dbs_info = &per_cpu(od_cpu_dbs_info, j); - j_dbs_info->cur_policy = policy; - - j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j, - &j_dbs_info->prev_cpu_wall); - if (dbs_tuners_ins.ignore_nice) - j_dbs_info->prev_cpu_nice = - kcpustat_cpu(j).cpustat[CPUTIME_NICE]; - } - this_dbs_info->cpu = cpu; - this_dbs_info->rate_mult = 1; - ondemand_powersave_bias_init_cpu(cpu); - /* - * Start the timerschedule work, when this governor - * is used for first time - */ - if (dbs_enable == 1) { - unsigned int latency; - - rc = sysfs_create_group(cpufreq_global_kobject, - &dbs_attr_group); - if (rc) { - mutex_unlock(&dbs_mutex); - return rc; - } - - /* policy latency is in nS. Convert it to uS first */ - latency = policy->cpuinfo.transition_latency / 1000; - if (latency == 0) - latency = 1; - /* Bring kernel and HW constraints together */ - min_sampling_rate = max(min_sampling_rate, - MIN_LATENCY_MULTIPLIER * latency); - dbs_tuners_ins.sampling_rate = - max(min_sampling_rate, - latency * LATENCY_MULTIPLIER); - dbs_tuners_ins.io_is_busy = should_io_be_busy(); - } - mutex_unlock(&dbs_mutex); - - mutex_init(&this_dbs_info->timer_mutex); - dbs_timer_init(this_dbs_info); - break; - - case CPUFREQ_GOV_STOP: - dbs_timer_exit(this_dbs_info); - - mutex_lock(&dbs_mutex); - mutex_destroy(&this_dbs_info->timer_mutex); - dbs_enable--; - mutex_unlock(&dbs_mutex); - if (!dbs_enable) - sysfs_remove_group(cpufreq_global_kobject, - &dbs_attr_group); - - break; - - case CPUFREQ_GOV_LIMITS: - mutex_lock(&this_dbs_info->timer_mutex); - if (policy->max < this_dbs_info->cur_policy->cur) - __cpufreq_driver_target(this_dbs_info->cur_policy, - policy->max, CPUFREQ_RELATION_H); - else if (policy->min > this_dbs_info->cur_policy->cur) - __cpufreq_driver_target(this_dbs_info->cur_policy, - policy->min, CPUFREQ_RELATION_L); - dbs_check_cpu(this_dbs_info); - mutex_unlock(&this_dbs_info->timer_mutex); - break; - } - return 0; -} +struct cpufreq_governor cpufreq_gov_ondemand = { + .name = "ondemand", + .governor = od_cpufreq_governor_dbs, + .max_transition_latency = TRANSITION_LATENCY_LIMIT, + .owner = THIS_MODULE, +}; static int __init cpufreq_gov_dbs_init(void) { u64 idle_time; int cpu = get_cpu(); + mutex_init(&od_dbs_data.mutex); idle_time = get_cpu_idle_time_us(cpu, NULL); put_cpu(); if (idle_time != -1ULL) { /* Idle micro accounting is supported. Use finer thresholds */ - dbs_tuners_ins.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD; - dbs_tuners_ins.down_differential = - MICRO_FREQUENCY_DOWN_DIFFERENTIAL; + od_tuners.up_threshold = MICRO_FREQUENCY_UP_THRESHOLD; + od_tuners.down_differential = MICRO_FREQUENCY_DOWN_DIFFERENTIAL; /* * In nohz/micro accounting case we set the minimum frequency * not depending on HZ, but fixed (very low). The deferred * timer might skip some samples if idle/sleeping as needed. */ - min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE; + od_dbs_data.min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE; } else { /* For correct statistics, we need 10 ticks for each measure */ - min_sampling_rate = - MIN_SAMPLING_RATE_RATIO * jiffies_to_usecs(10); + od_dbs_data.min_sampling_rate = MIN_SAMPLING_RATE_RATIO * + jiffies_to_usecs(10); } return cpufreq_register_governor(&cpufreq_gov_ondemand); @@ -800,7 +528,6 @@ static void __exit cpufreq_gov_dbs_exit(void) cpufreq_unregister_governor(&cpufreq_gov_ondemand); } - MODULE_AUTHOR("Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>"); MODULE_AUTHOR("Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>"); MODULE_DESCRIPTION("'cpufreq_ondemand' - A dynamic cpufreq governor for " diff --git a/drivers/cpufreq/cpufreq_performance.c b/drivers/cpufreq/cpufreq_performance.c index f13a8a9af6a..ceee06849b9 100644 --- a/drivers/cpufreq/cpufreq_performance.c +++ b/drivers/cpufreq/cpufreq_performance.c @@ -10,6 +10,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/module.h> #include <linux/cpufreq.h> diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c index 4c2eb512f2b..2d948a17115 100644 --- a/drivers/cpufreq/cpufreq_powersave.c +++ b/drivers/cpufreq/cpufreq_powersave.c @@ -10,6 +10,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/module.h> #include <linux/cpufreq.h> diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 399831690fe..e40e5080964 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -37,7 +37,7 @@ struct cpufreq_stats { unsigned int max_state; unsigned int state_num; unsigned int last_index; - cputime64_t *time_in_state; + u64 *time_in_state; unsigned int *freq_table; #ifdef CONFIG_CPU_FREQ_STAT_DETAILS unsigned int *trans_table; @@ -223,7 +223,7 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy, count++; } - alloc_size = count * sizeof(int) + count * sizeof(cputime64_t); + alloc_size = count * sizeof(int) + count * sizeof(u64); #ifdef CONFIG_CPU_FREQ_STAT_DETAILS alloc_size += count * count * sizeof(int); diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c index bedac1aa9be..c8c3d293cc5 100644 --- a/drivers/cpufreq/cpufreq_userspace.c +++ b/drivers/cpufreq/cpufreq_userspace.c @@ -11,6 +11,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/module.h> #include <linux/smp.h> diff --git a/drivers/cpufreq/db8500-cpufreq.c b/drivers/cpufreq/db8500-cpufreq.c index 74b830b635a..4f154bc0ebe 100644 --- a/drivers/cpufreq/db8500-cpufreq.c +++ b/drivers/cpufreq/db8500-cpufreq.c @@ -8,43 +8,17 @@ * Author: Jonas Aaberg <jonas.aberg@stericsson.com> * */ +#include <linux/module.h> #include <linux/kernel.h> #include <linux/cpufreq.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/mfd/dbx500-prcmu.h> +#include <linux/platform_device.h> +#include <linux/clk.h> #include <mach/id.h> -static struct cpufreq_frequency_table freq_table[] = { - [0] = { - .index = 0, - .frequency = 200000, - }, - [1] = { - .index = 1, - .frequency = 400000, - }, - [2] = { - .index = 2, - .frequency = 800000, - }, - [3] = { - /* Used for MAX_OPP, if available */ - .index = 3, - .frequency = CPUFREQ_TABLE_END, - }, - [4] = { - .index = 4, - .frequency = CPUFREQ_TABLE_END, - }, -}; - -static enum arm_opp idx2opp[] = { - ARM_EXTCLK, - ARM_50_OPP, - ARM_100_OPP, - ARM_MAX_OPP -}; +static struct cpufreq_frequency_table *freq_table; +static struct clk *armss_clk; static struct freq_attr *db8500_cpufreq_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, @@ -85,9 +59,9 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy, for_each_cpu(freqs.cpu, policy->cpus) cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - /* request the PRCM unit for opp change */ - if (prcmu_set_arm_opp(idx2opp[idx])) { - pr_err("db8500-cpufreq: Failed to set OPP level\n"); + /* update armss clk frequency */ + if (clk_set_rate(armss_clk, freq_table[idx].frequency * 1000)) { + pr_err("db8500-cpufreq: Failed to update armss clk\n"); return -EINVAL; } @@ -100,25 +74,36 @@ static int db8500_cpufreq_target(struct cpufreq_policy *policy, static unsigned int db8500_cpufreq_getspeed(unsigned int cpu) { - int i; - /* request the prcm to get the current ARM opp */ - for (i = 0; prcmu_get_arm_opp() != idx2opp[i]; i++) - ; - return freq_table[i].frequency; + int i = 0; + unsigned long freq = clk_get_rate(armss_clk) / 1000; + + while (freq_table[i].frequency != CPUFREQ_TABLE_END) { + if (freq <= freq_table[i].frequency) + return freq_table[i].frequency; + i++; + } + + /* We could not find a corresponding frequency. */ + pr_err("db8500-cpufreq: Failed to find cpufreq speed\n"); + return 0; } static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy) { - int i, res; - - BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table)); + int i = 0; + int res; - if (prcmu_has_arm_maxopp()) - freq_table[3].frequency = 1000000; + armss_clk = clk_get(NULL, "armss"); + if (IS_ERR(armss_clk)) { + pr_err("db8500-cpufreq : Failed to get armss clk\n"); + return PTR_ERR(armss_clk); + } pr_info("db8500-cpufreq : Available frequencies:\n"); - for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) + while (freq_table[i].frequency != CPUFREQ_TABLE_END) { pr_info(" %d Mhz\n", freq_table[i].frequency/1000); + i++; + } /* get policy fields based on the table */ res = cpufreq_frequency_table_cpuinfo(policy, freq_table); @@ -126,6 +111,7 @@ static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy) cpufreq_frequency_table_get_attr(freq_table, policy->cpu); else { pr_err("db8500-cpufreq : Failed to read policy table\n"); + clk_put(armss_clk); return res; } @@ -159,12 +145,35 @@ static struct cpufreq_driver db8500_cpufreq_driver = { .attr = db8500_cpufreq_attr, }; +static int db8500_cpufreq_probe(struct platform_device *pdev) +{ + freq_table = dev_get_platdata(&pdev->dev); + + if (!freq_table) { + pr_err("db8500-cpufreq: Failed to fetch cpufreq table\n"); + return -ENODEV; + } + + return cpufreq_register_driver(&db8500_cpufreq_driver); +} + +static struct platform_driver db8500_cpufreq_plat_driver = { + .driver = { + .name = "cpufreq-u8500", + .owner = THIS_MODULE, + }, + .probe = db8500_cpufreq_probe, +}; + static int __init db8500_cpufreq_register(void) { if (!cpu_is_u8500_family()) return -ENODEV; pr_info("cpufreq for DB8500 started\n"); - return cpufreq_register_driver(&db8500_cpufreq_driver); + return platform_driver_register(&db8500_cpufreq_plat_driver); } device_initcall(db8500_cpufreq_register); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("cpufreq driver for DB8500"); diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index af2d81e10f7..7012ea8bf1e 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c @@ -31,13 +31,13 @@ static unsigned int locking_frequency; static bool frequency_locked; static DEFINE_MUTEX(cpufreq_lock); -int exynos_verify_speed(struct cpufreq_policy *policy) +static int exynos_verify_speed(struct cpufreq_policy *policy) { return cpufreq_frequency_table_verify(policy, exynos_info->freq_table); } -unsigned int exynos_getspeed(unsigned int cpu) +static unsigned int exynos_getspeed(unsigned int cpu) { return clk_get_rate(exynos_info->cpu_clk) / 1000; } @@ -100,7 +100,8 @@ static int exynos_target(struct cpufreq_policy *policy, } arm_volt = volt_table[index]; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + for_each_cpu(freqs.cpu, policy->cpus) + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); /* When the new frequency is higher than current frequency */ if ((freqs.new > freqs.old) && !safe_arm_volt) { @@ -115,7 +116,8 @@ static int exynos_target(struct cpufreq_policy *policy, if (freqs.new != freqs.old) exynos_info->set_freq(old_index, index); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + for_each_cpu(freqs.cpu, policy->cpus) + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); /* When the new frequency is lower than current frequency */ if ((freqs.new < freqs.old) || @@ -235,6 +237,7 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy) cpumask_copy(policy->related_cpus, cpu_possible_mask); cpumask_copy(policy->cpus, cpu_online_mask); } else { + policy->shared_type = CPUFREQ_SHARED_TYPE_ANY; cpumask_setall(policy->cpus); } diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index 90431cb9280..49cda256efb 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -9,6 +9,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c index 53ddbc760af..f1fa500ac10 100644 --- a/drivers/cpufreq/longhaul.c +++ b/drivers/cpufreq/longhaul.c @@ -930,7 +930,7 @@ static int __cpuinit longhaul_cpu_init(struct cpufreq_policy *policy) return 0; } -static int __devexit longhaul_cpu_exit(struct cpufreq_policy *policy) +static int longhaul_cpu_exit(struct cpufreq_policy *policy) { cpufreq_frequency_table_put_attr(policy->cpu); return 0; @@ -946,7 +946,7 @@ static struct cpufreq_driver longhaul_driver = { .target = longhaul_target, .get = longhaul_get, .init = longhaul_cpu_init, - .exit = __devexit_p(longhaul_cpu_exit), + .exit = longhaul_cpu_exit, .name = "longhaul", .owner = THIS_MODULE, .attr = longhaul_attr, diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index e3ebb4fa2c3..056faf6af1a 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -1186,7 +1186,7 @@ err_out: return -ENODEV; } -static int __devexit powernowk8_cpu_exit(struct cpufreq_policy *pol) +static int powernowk8_cpu_exit(struct cpufreq_policy *pol) { struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); @@ -1242,7 +1242,7 @@ static struct cpufreq_driver cpufreq_amd64_driver = { .target = powernowk8_target, .bios_limit = acpi_processor_get_bios_limit, .init = powernowk8_cpu_init, - .exit = __devexit_p(powernowk8_cpu_exit), + .exit = powernowk8_cpu_exit, .get = powernowk8_get, .name = "powernow-k8", .owner = THIS_MODULE, diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c new file mode 100644 index 00000000000..4575cfe4175 --- /dev/null +++ b/drivers/cpufreq/spear-cpufreq.c @@ -0,0 +1,291 @@ +/* + * drivers/cpufreq/spear-cpufreq.c + * + * CPU Frequency Scaling for SPEAr platform + * + * Copyright (C) 2012 ST Microelectronics + * Deepak Sikri <deepak.sikri@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/clk.h> +#include <linux/cpufreq.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/slab.h> +#include <linux/types.h> + +/* SPEAr CPUFreq driver data structure */ +static struct { + struct clk *clk; + unsigned int transition_latency; + struct cpufreq_frequency_table *freq_tbl; + u32 cnt; +} spear_cpufreq; + +int spear_cpufreq_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, spear_cpufreq.freq_tbl); +} + +static unsigned int spear_cpufreq_get(unsigned int cpu) +{ + return clk_get_rate(spear_cpufreq.clk) / 1000; +} + +static struct clk *spear1340_cpu_get_possible_parent(unsigned long newfreq) +{ + struct clk *sys_pclk; + int pclk; + /* + * In SPEAr1340, cpu clk's parent sys clk can take input from + * following sources + */ + const char *sys_clk_src[] = { + "sys_syn_clk", + "pll1_clk", + "pll2_clk", + "pll3_clk", + }; + + /* + * As sys clk can have multiple source with their own range + * limitation so we choose possible sources accordingly + */ + if (newfreq <= 300000000) + pclk = 0; /* src is sys_syn_clk */ + else if (newfreq > 300000000 && newfreq <= 500000000) + pclk = 3; /* src is pll3_clk */ + else if (newfreq == 600000000) + pclk = 1; /* src is pll1_clk */ + else + return ERR_PTR(-EINVAL); + + /* Get parent to sys clock */ + sys_pclk = clk_get(NULL, sys_clk_src[pclk]); + if (IS_ERR(sys_pclk)) + pr_err("Failed to get %s clock\n", sys_clk_src[pclk]); + + return sys_pclk; +} + +/* + * In SPEAr1340, we cannot use newfreq directly because we need to actually + * access a source clock (clk) which might not be ancestor of cpu at present. + * Hence in SPEAr1340 we would operate on source clock directly before switching + * cpu clock to it. + */ +static int spear1340_set_cpu_rate(struct clk *sys_pclk, unsigned long newfreq) +{ + struct clk *sys_clk; + int ret = 0; + + sys_clk = clk_get_parent(spear_cpufreq.clk); + if (IS_ERR(sys_clk)) { + pr_err("failed to get cpu's parent (sys) clock\n"); + return PTR_ERR(sys_clk); + } + + /* Set the rate of the source clock before changing the parent */ + ret = clk_set_rate(sys_pclk, newfreq); + if (ret) { + pr_err("Failed to set sys clk rate to %lu\n", newfreq); + return ret; + } + + ret = clk_set_parent(sys_clk, sys_pclk); + if (ret) { + pr_err("Failed to set sys clk parent\n"); + return ret; + } + + return 0; +} + +static int spear_cpufreq_target(struct cpufreq_policy *policy, + unsigned int target_freq, unsigned int relation) +{ + struct cpufreq_freqs freqs; + unsigned long newfreq; + struct clk *srcclk; + int index, ret, mult = 1; + + if (cpufreq_frequency_table_target(policy, spear_cpufreq.freq_tbl, + target_freq, relation, &index)) + return -EINVAL; + + freqs.cpu = policy->cpu; + freqs.old = spear_cpufreq_get(0); + + newfreq = spear_cpufreq.freq_tbl[index].frequency * 1000; + if (of_machine_is_compatible("st,spear1340")) { + /* + * SPEAr1340 is special in the sense that due to the possibility + * of multiple clock sources for cpu clk's parent we can have + * different clock source for different frequency of cpu clk. + * Hence we need to choose one from amongst these possible clock + * sources. + */ + srcclk = spear1340_cpu_get_possible_parent(newfreq); + if (IS_ERR(srcclk)) { + pr_err("Failed to get src clk\n"); + return PTR_ERR(srcclk); + } + + /* SPEAr1340: src clk is always 2 * intended cpu clk */ + mult = 2; + } else { + /* + * src clock to be altered is ancestor of cpu clock. Hence we + * can directly work on cpu clk + */ + srcclk = spear_cpufreq.clk; + } + + newfreq = clk_round_rate(srcclk, newfreq * mult); + if (newfreq < 0) { + pr_err("clk_round_rate failed for cpu src clock\n"); + return newfreq; + } + + freqs.new = newfreq / 1000; + freqs.new /= mult; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + if (mult == 2) + ret = spear1340_set_cpu_rate(srcclk, newfreq); + else + ret = clk_set_rate(spear_cpufreq.clk, newfreq); + + /* Get current rate after clk_set_rate, in case of failure */ + if (ret) { + pr_err("CPU Freq: cpu clk_set_rate failed: %d\n", ret); + freqs.new = clk_get_rate(spear_cpufreq.clk) / 1000; + } + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + return ret; +} + +static int spear_cpufreq_init(struct cpufreq_policy *policy) +{ + int ret; + + ret = cpufreq_frequency_table_cpuinfo(policy, spear_cpufreq.freq_tbl); + if (ret) { + pr_err("cpufreq_frequency_table_cpuinfo() failed"); + return ret; + } + + cpufreq_frequency_table_get_attr(spear_cpufreq.freq_tbl, policy->cpu); + policy->cpuinfo.transition_latency = spear_cpufreq.transition_latency; + policy->cur = spear_cpufreq_get(0); + + cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu)); + cpumask_copy(policy->related_cpus, policy->cpus); + + return 0; +} + +static int spear_cpufreq_exit(struct cpufreq_policy *policy) +{ + cpufreq_frequency_table_put_attr(policy->cpu); + return 0; +} + +static struct freq_attr *spear_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver spear_cpufreq_driver = { + .name = "cpufreq-spear", + .flags = CPUFREQ_STICKY, + .verify = spear_cpufreq_verify, + .target = spear_cpufreq_target, + .get = spear_cpufreq_get, + .init = spear_cpufreq_init, + .exit = spear_cpufreq_exit, + .attr = spear_cpufreq_attr, +}; + +static int spear_cpufreq_driver_init(void) +{ + struct device_node *np; + const struct property *prop; + struct cpufreq_frequency_table *freq_tbl; + const __be32 *val; + int cnt, i, ret; + + np = of_find_node_by_path("/cpus/cpu@0"); + if (!np) { + pr_err("No cpu node found"); + return -ENODEV; + } + + if (of_property_read_u32(np, "clock-latency", + &spear_cpufreq.transition_latency)) + spear_cpufreq.transition_latency = CPUFREQ_ETERNAL; + + prop = of_find_property(np, "cpufreq_tbl", NULL); + if (!prop || !prop->value) { + pr_err("Invalid cpufreq_tbl"); + ret = -ENODEV; + goto out_put_node; + } + + cnt = prop->length / sizeof(u32); + val = prop->value; + + freq_tbl = kmalloc(sizeof(*freq_tbl) * (cnt + 1), GFP_KERNEL); + if (!freq_tbl) { + ret = -ENOMEM; + goto out_put_node; + } + + for (i = 0; i < cnt; i++) { + freq_tbl[i].index = i; + freq_tbl[i].frequency = be32_to_cpup(val++); + } + + freq_tbl[i].index = i; + freq_tbl[i].frequency = CPUFREQ_TABLE_END; + + spear_cpufreq.freq_tbl = freq_tbl; + + of_node_put(np); + + spear_cpufreq.clk = clk_get(NULL, "cpu_clk"); + if (IS_ERR(spear_cpufreq.clk)) { + pr_err("Unable to get CPU clock\n"); + ret = PTR_ERR(spear_cpufreq.clk); + goto out_put_mem; + } + + ret = cpufreq_register_driver(&spear_cpufreq_driver); + if (!ret) + return 0; + + pr_err("failed register driver: %d\n", ret); + clk_put(spear_cpufreq.clk); + +out_put_mem: + kfree(freq_tbl); + return ret; + +out_put_node: + of_node_put(np); + return ret; +} +late_initcall(spear_cpufreq_driver_init); + +MODULE_AUTHOR("Deepak Sikri <deepak.sikri@st.com>"); +MODULE_DESCRIPTION("SPEAr CPUFreq driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index a76b689e553..234ae651b38 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig @@ -9,6 +9,15 @@ config CPU_IDLE If you're using an ACPI-enabled platform, you should say Y here. +config CPU_IDLE_MULTIPLE_DRIVERS + bool "Support multiple cpuidle drivers" + depends on CPU_IDLE + default n + help + Allows the cpuidle framework to use different drivers for each CPU. + This is useful if you have a system with different CPU latencies and + states. If unsure say N. + config CPU_IDLE_GOV_LADDER bool depends on CPU_IDLE diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 7f15b8514a1..8df53dd8dbe 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -68,7 +68,7 @@ static cpuidle_enter_t cpuidle_enter_ops; int cpuidle_play_dead(void) { struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); - struct cpuidle_driver *drv = cpuidle_get_driver(); + struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); int i, dead_state = -1; int power_usage = -1; @@ -109,8 +109,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, /* This can be moved to within driver enter routine * but that results in multiple copies of same code. */ - dev->states_usage[entered_state].time += - (unsigned long long)dev->last_residency; + dev->states_usage[entered_state].time += dev->last_residency; dev->states_usage[entered_state].usage++; } else { dev->last_residency = 0; @@ -128,7 +127,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, int cpuidle_idle_call(void) { struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); - struct cpuidle_driver *drv = cpuidle_get_driver(); + struct cpuidle_driver *drv; int next_state, entered_state; if (off) @@ -141,9 +140,15 @@ int cpuidle_idle_call(void) if (!dev || !dev->enabled) return -EBUSY; + drv = cpuidle_get_cpu_driver(dev); + /* ask the governor for the next state */ next_state = cpuidle_curr_governor->select(drv, dev); if (need_resched()) { + dev->last_residency = 0; + /* give the governor an opportunity to reflect on the outcome */ + if (cpuidle_curr_governor->reflect) + cpuidle_curr_governor->reflect(dev, next_state); local_irq_enable(); return 0; } @@ -308,15 +313,19 @@ static void poll_idle_init(struct cpuidle_driver *drv) {} int cpuidle_enable_device(struct cpuidle_device *dev) { int ret, i; - struct cpuidle_driver *drv = cpuidle_get_driver(); + struct cpuidle_driver *drv; if (!dev) return -EINVAL; if (dev->enabled) return 0; + + drv = cpuidle_get_cpu_driver(dev); + if (!drv || !cpuidle_curr_governor) return -EIO; + if (!dev->state_count) dev->state_count = drv->state_count; @@ -331,7 +340,8 @@ int cpuidle_enable_device(struct cpuidle_device *dev) poll_idle_init(drv); - if ((ret = cpuidle_add_state_sysfs(dev))) + ret = cpuidle_add_device_sysfs(dev); + if (ret) return ret; if (cpuidle_curr_governor->enable && @@ -352,7 +362,7 @@ int cpuidle_enable_device(struct cpuidle_device *dev) return 0; fail_sysfs: - cpuidle_remove_state_sysfs(dev); + cpuidle_remove_device_sysfs(dev); return ret; } @@ -368,17 +378,20 @@ EXPORT_SYMBOL_GPL(cpuidle_enable_device); */ void cpuidle_disable_device(struct cpuidle_device *dev) { + struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); + if (!dev || !dev->enabled) return; - if (!cpuidle_get_driver() || !cpuidle_curr_governor) + + if (!drv || !cpuidle_curr_governor) return; dev->enabled = 0; if (cpuidle_curr_governor->disable) - cpuidle_curr_governor->disable(cpuidle_get_driver(), dev); + cpuidle_curr_governor->disable(drv, dev); - cpuidle_remove_state_sysfs(dev); + cpuidle_remove_device_sysfs(dev); enabled_devices--; } @@ -394,17 +407,14 @@ EXPORT_SYMBOL_GPL(cpuidle_disable_device); static int __cpuidle_register_device(struct cpuidle_device *dev) { int ret; - struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu); - struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver(); + struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); - if (!try_module_get(cpuidle_driver->owner)) + if (!try_module_get(drv->owner)) return -EINVAL; - init_completion(&dev->kobj_unregister); - per_cpu(cpuidle_devices, dev->cpu) = dev; list_add(&dev->device_list, &cpuidle_detected_devices); - ret = cpuidle_add_sysfs(cpu_dev); + ret = cpuidle_add_sysfs(dev); if (ret) goto err_sysfs; @@ -416,12 +426,11 @@ static int __cpuidle_register_device(struct cpuidle_device *dev) return 0; err_coupled: - cpuidle_remove_sysfs(cpu_dev); - wait_for_completion(&dev->kobj_unregister); + cpuidle_remove_sysfs(dev); err_sysfs: list_del(&dev->device_list); per_cpu(cpuidle_devices, dev->cpu) = NULL; - module_put(cpuidle_driver->owner); + module_put(drv->owner); return ret; } @@ -460,8 +469,7 @@ EXPORT_SYMBOL_GPL(cpuidle_register_device); */ void cpuidle_unregister_device(struct cpuidle_device *dev) { - struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu); - struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver(); + struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); if (dev->registered == 0) return; @@ -470,16 +478,15 @@ void cpuidle_unregister_device(struct cpuidle_device *dev) cpuidle_disable_device(dev); - cpuidle_remove_sysfs(cpu_dev); + cpuidle_remove_sysfs(dev); list_del(&dev->device_list); - wait_for_completion(&dev->kobj_unregister); per_cpu(cpuidle_devices, dev->cpu) = NULL; cpuidle_coupled_unregister_device(dev); cpuidle_resume_and_unlock(); - module_put(cpuidle_driver->owner); + module_put(drv->owner); } EXPORT_SYMBOL_GPL(cpuidle_unregister_device); diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h index 76e7f696ad8..ee97e9672ec 100644 --- a/drivers/cpuidle/cpuidle.h +++ b/drivers/cpuidle/cpuidle.h @@ -5,8 +5,6 @@ #ifndef __DRIVER_CPUIDLE_H #define __DRIVER_CPUIDLE_H -#include <linux/device.h> - /* For internal use only */ extern struct cpuidle_governor *cpuidle_curr_governor; extern struct list_head cpuidle_governors; @@ -25,12 +23,15 @@ extern void cpuidle_uninstall_idle_handler(void); extern int cpuidle_switch_governor(struct cpuidle_governor *gov); /* sysfs */ + +struct device; + extern int cpuidle_add_interface(struct device *dev); extern void cpuidle_remove_interface(struct device *dev); -extern int cpuidle_add_state_sysfs(struct cpuidle_device *device); -extern void cpuidle_remove_state_sysfs(struct cpuidle_device *device); -extern int cpuidle_add_sysfs(struct device *dev); -extern void cpuidle_remove_sysfs(struct device *dev); +extern int cpuidle_add_device_sysfs(struct cpuidle_device *device); +extern void cpuidle_remove_device_sysfs(struct cpuidle_device *device); +extern int cpuidle_add_sysfs(struct cpuidle_device *dev); +extern void cpuidle_remove_sysfs(struct cpuidle_device *dev); #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED bool cpuidle_state_is_coupled(struct cpuidle_device *dev, diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index 87db3877fea..3af841fb397 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -14,9 +14,10 @@ #include "cpuidle.h" -static struct cpuidle_driver *cpuidle_curr_driver; DEFINE_SPINLOCK(cpuidle_driver_lock); -int cpuidle_driver_refcount; + +static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu); +static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu); static void set_power_states(struct cpuidle_driver *drv) { @@ -40,11 +41,15 @@ static void set_power_states(struct cpuidle_driver *drv) drv->states[i].power_usage = -1 - i; } -/** - * cpuidle_register_driver - registers a driver - * @drv: the driver - */ -int cpuidle_register_driver(struct cpuidle_driver *drv) +static void __cpuidle_driver_init(struct cpuidle_driver *drv) +{ + drv->refcnt = 0; + + if (!drv->power_specified) + set_power_states(drv); +} + +static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu) { if (!drv || !drv->state_count) return -EINVAL; @@ -52,31 +57,145 @@ int cpuidle_register_driver(struct cpuidle_driver *drv) if (cpuidle_disabled()) return -ENODEV; - spin_lock(&cpuidle_driver_lock); - if (cpuidle_curr_driver) { - spin_unlock(&cpuidle_driver_lock); + if (__cpuidle_get_cpu_driver(cpu)) return -EBUSY; + + __cpuidle_driver_init(drv); + + __cpuidle_set_cpu_driver(drv, cpu); + + return 0; +} + +static void __cpuidle_unregister_driver(struct cpuidle_driver *drv, int cpu) +{ + if (drv != __cpuidle_get_cpu_driver(cpu)) + return; + + if (!WARN_ON(drv->refcnt > 0)) + __cpuidle_set_cpu_driver(NULL, cpu); +} + +#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS + +static DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers); + +static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu) +{ + per_cpu(cpuidle_drivers, cpu) = drv; +} + +static struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu) +{ + return per_cpu(cpuidle_drivers, cpu); +} + +static void __cpuidle_unregister_all_cpu_driver(struct cpuidle_driver *drv) +{ + int cpu; + for_each_present_cpu(cpu) + __cpuidle_unregister_driver(drv, cpu); +} + +static int __cpuidle_register_all_cpu_driver(struct cpuidle_driver *drv) +{ + int ret = 0; + int i, cpu; + + for_each_present_cpu(cpu) { + ret = __cpuidle_register_driver(drv, cpu); + if (ret) + break; } - if (!drv->power_specified) - set_power_states(drv); + if (ret) + for_each_present_cpu(i) { + if (i == cpu) + break; + __cpuidle_unregister_driver(drv, i); + } - cpuidle_curr_driver = drv; + return ret; +} + +int cpuidle_register_cpu_driver(struct cpuidle_driver *drv, int cpu) +{ + int ret; + + spin_lock(&cpuidle_driver_lock); + ret = __cpuidle_register_driver(drv, cpu); spin_unlock(&cpuidle_driver_lock); - return 0; + return ret; +} + +void cpuidle_unregister_cpu_driver(struct cpuidle_driver *drv, int cpu) +{ + spin_lock(&cpuidle_driver_lock); + __cpuidle_unregister_driver(drv, cpu); + spin_unlock(&cpuidle_driver_lock); +} + +/** + * cpuidle_register_driver - registers a driver + * @drv: the driver + */ +int cpuidle_register_driver(struct cpuidle_driver *drv) +{ + int ret; + + spin_lock(&cpuidle_driver_lock); + ret = __cpuidle_register_all_cpu_driver(drv); + spin_unlock(&cpuidle_driver_lock); + + return ret; } EXPORT_SYMBOL_GPL(cpuidle_register_driver); /** - * cpuidle_get_driver - return the current driver + * cpuidle_unregister_driver - unregisters a driver + * @drv: the driver */ -struct cpuidle_driver *cpuidle_get_driver(void) +void cpuidle_unregister_driver(struct cpuidle_driver *drv) +{ + spin_lock(&cpuidle_driver_lock); + __cpuidle_unregister_all_cpu_driver(drv); + spin_unlock(&cpuidle_driver_lock); +} +EXPORT_SYMBOL_GPL(cpuidle_unregister_driver); + +#else + +static struct cpuidle_driver *cpuidle_curr_driver; + +static inline void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu) +{ + cpuidle_curr_driver = drv; +} + +static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu) { return cpuidle_curr_driver; } -EXPORT_SYMBOL_GPL(cpuidle_get_driver); + +/** + * cpuidle_register_driver - registers a driver + * @drv: the driver + */ +int cpuidle_register_driver(struct cpuidle_driver *drv) +{ + int ret, cpu; + + cpu = get_cpu(); + spin_lock(&cpuidle_driver_lock); + ret = __cpuidle_register_driver(drv, cpu); + spin_unlock(&cpuidle_driver_lock); + put_cpu(); + + return ret; +} +EXPORT_SYMBOL_GPL(cpuidle_register_driver); /** * cpuidle_unregister_driver - unregisters a driver @@ -84,20 +203,50 @@ EXPORT_SYMBOL_GPL(cpuidle_get_driver); */ void cpuidle_unregister_driver(struct cpuidle_driver *drv) { - if (drv != cpuidle_curr_driver) { - WARN(1, "invalid cpuidle_unregister_driver(%s)\n", - drv->name); - return; - } + int cpu; + cpu = get_cpu(); spin_lock(&cpuidle_driver_lock); + __cpuidle_unregister_driver(drv, cpu); + spin_unlock(&cpuidle_driver_lock); + put_cpu(); +} +EXPORT_SYMBOL_GPL(cpuidle_unregister_driver); +#endif + +/** + * cpuidle_get_driver - return the current driver + */ +struct cpuidle_driver *cpuidle_get_driver(void) +{ + struct cpuidle_driver *drv; + int cpu; - if (!WARN_ON(cpuidle_driver_refcount > 0)) - cpuidle_curr_driver = NULL; + cpu = get_cpu(); + drv = __cpuidle_get_cpu_driver(cpu); + put_cpu(); + return drv; +} +EXPORT_SYMBOL_GPL(cpuidle_get_driver); + +/** + * cpuidle_get_cpu_driver - return the driver tied with a cpu + */ +struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev) +{ + struct cpuidle_driver *drv; + + if (!dev) + return NULL; + + spin_lock(&cpuidle_driver_lock); + drv = __cpuidle_get_cpu_driver(dev->cpu); spin_unlock(&cpuidle_driver_lock); + + return drv; } -EXPORT_SYMBOL_GPL(cpuidle_unregister_driver); +EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver); struct cpuidle_driver *cpuidle_driver_ref(void) { @@ -105,8 +254,8 @@ struct cpuidle_driver *cpuidle_driver_ref(void) spin_lock(&cpuidle_driver_lock); - drv = cpuidle_curr_driver; - cpuidle_driver_refcount++; + drv = cpuidle_get_driver(); + drv->refcnt++; spin_unlock(&cpuidle_driver_lock); return drv; @@ -114,10 +263,12 @@ struct cpuidle_driver *cpuidle_driver_ref(void) void cpuidle_driver_unref(void) { + struct cpuidle_driver *drv = cpuidle_get_driver(); + spin_lock(&cpuidle_driver_lock); - if (!WARN_ON(cpuidle_driver_refcount <= 0)) - cpuidle_driver_refcount--; + if (drv && !WARN_ON(drv->refcnt <= 0)) + drv->refcnt--; spin_unlock(&cpuidle_driver_lock); } diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 5b1f2c372c1..bd40b943b6d 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -28,6 +28,13 @@ #define MAX_INTERESTING 50000 #define STDDEV_THRESH 400 +/* 60 * 60 > STDDEV_THRESH * INTERVALS = 400 * 8 */ +#define MAX_DEVIATION 60 + +static DEFINE_PER_CPU(struct hrtimer, menu_hrtimer); +static DEFINE_PER_CPU(int, hrtimer_status); +/* menu hrtimer mode */ +enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT, MENU_HRTIMER_GENERAL}; /* * Concepts and ideas behind the menu governor @@ -109,6 +116,13 @@ * */ +/* + * The C-state residency is so long that is is worthwhile to exit + * from the shallow C-state and re-enter into a deeper C-state. + */ +static unsigned int perfect_cstate_ms __read_mostly = 30; +module_param(perfect_cstate_ms, uint, 0000); + struct menu_device { int last_state_idx; int needs_update; @@ -191,40 +205,102 @@ static u64 div_round64(u64 dividend, u32 divisor) return div_u64(dividend + (divisor / 2), divisor); } +/* Cancel the hrtimer if it is not triggered yet */ +void menu_hrtimer_cancel(void) +{ + int cpu = smp_processor_id(); + struct hrtimer *hrtmr = &per_cpu(menu_hrtimer, cpu); + + /* The timer is still not time out*/ + if (per_cpu(hrtimer_status, cpu)) { + hrtimer_cancel(hrtmr); + per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP; + } +} +EXPORT_SYMBOL_GPL(menu_hrtimer_cancel); + +/* Call back for hrtimer is triggered */ +static enum hrtimer_restart menu_hrtimer_notify(struct hrtimer *hrtimer) +{ + int cpu = smp_processor_id(); + struct menu_device *data = &per_cpu(menu_devices, cpu); + + /* In general case, the expected residency is much larger than + * deepest C-state target residency, but prediction logic still + * predicts a small predicted residency, so the prediction + * history is totally broken if the timer is triggered. + * So reset the correction factor. + */ + if (per_cpu(hrtimer_status, cpu) == MENU_HRTIMER_GENERAL) + data->correction_factor[data->bucket] = RESOLUTION * DECAY; + + per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP; + + return HRTIMER_NORESTART; +} + /* * Try detecting repeating patterns by keeping track of the last 8 * intervals, and checking if the standard deviation of that set * of points is below a threshold. If it is... then use the * average of these 8 points as the estimated value. */ -static void detect_repeating_patterns(struct menu_device *data) +static u32 get_typical_interval(struct menu_device *data) { - int i; - uint64_t avg = 0; - uint64_t stddev = 0; /* contains the square of the std deviation */ - - /* first calculate average and standard deviation of the past */ - for (i = 0; i < INTERVALS; i++) - avg += data->intervals[i]; - avg = avg / INTERVALS; + int i = 0, divisor = 0; + uint64_t max = 0, avg = 0, stddev = 0; + int64_t thresh = LLONG_MAX; /* Discard outliers above this value. */ + unsigned int ret = 0; - /* if the avg is beyond the known next tick, it's worthless */ - if (avg > data->expected_us) - return; +again: - for (i = 0; i < INTERVALS; i++) - stddev += (data->intervals[i] - avg) * - (data->intervals[i] - avg); - - stddev = stddev / INTERVALS; + /* first calculate average and standard deviation of the past */ + max = avg = divisor = stddev = 0; + for (i = 0; i < INTERVALS; i++) { + int64_t value = data->intervals[i]; + if (value <= thresh) { + avg += value; + divisor++; + if (value > max) + max = value; + } + } + do_div(avg, divisor); + for (i = 0; i < INTERVALS; i++) { + int64_t value = data->intervals[i]; + if (value <= thresh) { + int64_t diff = value - avg; + stddev += diff * diff; + } + } + do_div(stddev, divisor); + stddev = int_sqrt(stddev); /* - * now.. if stddev is small.. then assume we have a - * repeating pattern and predict we keep doing this. + * If we have outliers to the upside in our distribution, discard + * those by setting the threshold to exclude these outliers, then + * calculate the average and standard deviation again. Once we get + * down to the bottom 3/4 of our samples, stop excluding samples. + * + * This can deal with workloads that have long pauses interspersed + * with sporadic activity with a bunch of short pauses. + * + * The typical interval is obtained when standard deviation is small + * or standard deviation is small compared to the average interval. */ - - if (avg && stddev < STDDEV_THRESH) + if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3)) + || stddev <= 20) { data->predicted_us = avg; + ret = 1; + return ret; + + } else if ((divisor * 4) > INTERVALS * 3) { + /* Exclude the max interval */ + thresh = max - 1; + goto again; + } + + return ret; } /** @@ -240,6 +316,9 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) int i; int multiplier; struct timespec t; + int repeat = 0, low_predicted = 0; + int cpu = smp_processor_id(); + struct hrtimer *hrtmr = &per_cpu(menu_hrtimer, cpu); if (data->needs_update) { menu_update(drv, dev); @@ -274,7 +353,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket], RESOLUTION * DECAY); - detect_repeating_patterns(data); + repeat = get_typical_interval(data); /* * We want to default to C1 (hlt), not to busy polling @@ -295,8 +374,10 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) if (s->disabled || su->disable) continue; - if (s->target_residency > data->predicted_us) + if (s->target_residency > data->predicted_us) { + low_predicted = 1; continue; + } if (s->exit_latency > latency_req) continue; if (s->exit_latency * multiplier > data->predicted_us) @@ -309,6 +390,44 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) } } + /* not deepest C-state chosen for low predicted residency */ + if (low_predicted) { + unsigned int timer_us = 0; + unsigned int perfect_us = 0; + + /* + * Set a timer to detect whether this sleep is much + * longer than repeat mode predicted. If the timer + * triggers, the code will evaluate whether to put + * the CPU into a deeper C-state. + * The timer is cancelled on CPU wakeup. + */ + timer_us = 2 * (data->predicted_us + MAX_DEVIATION); + + perfect_us = perfect_cstate_ms * 1000; + + if (repeat && (4 * timer_us < data->expected_us)) { + RCU_NONIDLE(hrtimer_start(hrtmr, + ns_to_ktime(1000 * timer_us), + HRTIMER_MODE_REL_PINNED)); + /* In repeat case, menu hrtimer is started */ + per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_REPEAT; + } else if (perfect_us < data->expected_us) { + /* + * The next timer is long. This could be because + * we did not make a useful prediction. + * In that case, it makes sense to re-enter + * into a deeper C-state after some time. + */ + RCU_NONIDLE(hrtimer_start(hrtmr, + ns_to_ktime(1000 * timer_us), + HRTIMER_MODE_REL_PINNED)); + /* In general case, menu hrtimer is started */ + per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_GENERAL; + } + + } + return data->last_state_idx; } @@ -399,6 +518,9 @@ static int menu_enable_device(struct cpuidle_driver *drv, struct cpuidle_device *dev) { struct menu_device *data = &per_cpu(menu_devices, dev->cpu); + struct hrtimer *t = &per_cpu(menu_hrtimer, dev->cpu); + hrtimer_init(t, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + t->function = menu_hrtimer_notify; memset(data, 0, sizeof(struct menu_device)); diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 5f809e337b8..34094294610 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/cpu.h> #include <linux/capability.h> +#include <linux/device.h> #include "cpuidle.h" @@ -297,6 +298,13 @@ static struct attribute *cpuidle_state_default_attrs[] = { NULL }; +struct cpuidle_state_kobj { + struct cpuidle_state *state; + struct cpuidle_state_usage *state_usage; + struct completion kobj_unregister; + struct kobject kobj; +}; + #define kobj_to_state_obj(k) container_of(k, struct cpuidle_state_kobj, kobj) #define kobj_to_state(k) (kobj_to_state_obj(k)->state) #define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage) @@ -356,17 +364,17 @@ static inline void cpuidle_free_state_kobj(struct cpuidle_device *device, int i) } /** - * cpuidle_add_driver_sysfs - adds driver-specific sysfs attributes + * cpuidle_add_state_sysfs - adds cpuidle states sysfs attributes * @device: the target device */ -int cpuidle_add_state_sysfs(struct cpuidle_device *device) +static int cpuidle_add_state_sysfs(struct cpuidle_device *device) { int i, ret = -ENOMEM; struct cpuidle_state_kobj *kobj; - struct cpuidle_driver *drv = cpuidle_get_driver(); + struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device); /* state statistics */ - for (i = 0; i < device->state_count; i++) { + for (i = 0; i < drv->state_count; i++) { kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL); if (!kobj) goto error_state; @@ -374,8 +382,8 @@ int cpuidle_add_state_sysfs(struct cpuidle_device *device) kobj->state_usage = &device->states_usage[i]; init_completion(&kobj->kobj_unregister); - ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, &device->kobj, - "state%d", i); + ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, + &device->kobj, "state%d", i); if (ret) { kfree(kobj); goto error_state; @@ -393,10 +401,10 @@ error_state: } /** - * cpuidle_remove_driver_sysfs - removes driver-specific sysfs attributes + * cpuidle_remove_driver_sysfs - removes the cpuidle states sysfs attributes * @device: the target device */ -void cpuidle_remove_state_sysfs(struct cpuidle_device *device) +static void cpuidle_remove_state_sysfs(struct cpuidle_device *device) { int i; @@ -404,17 +412,179 @@ void cpuidle_remove_state_sysfs(struct cpuidle_device *device) cpuidle_free_state_kobj(device, i); } +#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS +#define kobj_to_driver_kobj(k) container_of(k, struct cpuidle_driver_kobj, kobj) +#define attr_to_driver_attr(a) container_of(a, struct cpuidle_driver_attr, attr) + +#define define_one_driver_ro(_name, show) \ + static struct cpuidle_driver_attr attr_driver_##_name = \ + __ATTR(_name, 0644, show, NULL) + +struct cpuidle_driver_kobj { + struct cpuidle_driver *drv; + struct completion kobj_unregister; + struct kobject kobj; +}; + +struct cpuidle_driver_attr { + struct attribute attr; + ssize_t (*show)(struct cpuidle_driver *, char *); + ssize_t (*store)(struct cpuidle_driver *, const char *, size_t); +}; + +static ssize_t show_driver_name(struct cpuidle_driver *drv, char *buf) +{ + ssize_t ret; + + spin_lock(&cpuidle_driver_lock); + ret = sprintf(buf, "%s\n", drv ? drv->name : "none"); + spin_unlock(&cpuidle_driver_lock); + + return ret; +} + +static void cpuidle_driver_sysfs_release(struct kobject *kobj) +{ + struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj); + complete(&driver_kobj->kobj_unregister); +} + +static ssize_t cpuidle_driver_show(struct kobject *kobj, struct attribute * attr, + char * buf) +{ + int ret = -EIO; + struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj); + struct cpuidle_driver_attr *dattr = attr_to_driver_attr(attr); + + if (dattr->show) + ret = dattr->show(driver_kobj->drv, buf); + + return ret; +} + +static ssize_t cpuidle_driver_store(struct kobject *kobj, struct attribute *attr, + const char *buf, size_t size) +{ + int ret = -EIO; + struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj); + struct cpuidle_driver_attr *dattr = attr_to_driver_attr(attr); + + if (dattr->store) + ret = dattr->store(driver_kobj->drv, buf, size); + + return ret; +} + +define_one_driver_ro(name, show_driver_name); + +static const struct sysfs_ops cpuidle_driver_sysfs_ops = { + .show = cpuidle_driver_show, + .store = cpuidle_driver_store, +}; + +static struct attribute *cpuidle_driver_default_attrs[] = { + &attr_driver_name.attr, + NULL +}; + +static struct kobj_type ktype_driver_cpuidle = { + .sysfs_ops = &cpuidle_driver_sysfs_ops, + .default_attrs = cpuidle_driver_default_attrs, + .release = cpuidle_driver_sysfs_release, +}; + +/** + * cpuidle_add_driver_sysfs - adds the driver name sysfs attribute + * @device: the target device + */ +static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev) +{ + struct cpuidle_driver_kobj *kdrv; + struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); + int ret; + + kdrv = kzalloc(sizeof(*kdrv), GFP_KERNEL); + if (!kdrv) + return -ENOMEM; + + kdrv->drv = drv; + init_completion(&kdrv->kobj_unregister); + + ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle, + &dev->kobj, "driver"); + if (ret) { + kfree(kdrv); + return ret; + } + + kobject_uevent(&kdrv->kobj, KOBJ_ADD); + dev->kobj_driver = kdrv; + + return ret; +} + +/** + * cpuidle_remove_driver_sysfs - removes the driver name sysfs attribute + * @device: the target device + */ +static void cpuidle_remove_driver_sysfs(struct cpuidle_device *dev) +{ + struct cpuidle_driver_kobj *kdrv = dev->kobj_driver; + kobject_put(&kdrv->kobj); + wait_for_completion(&kdrv->kobj_unregister); + kfree(kdrv); +} +#else +static inline int cpuidle_add_driver_sysfs(struct cpuidle_device *dev) +{ + return 0; +} + +static inline void cpuidle_remove_driver_sysfs(struct cpuidle_device *dev) +{ + ; +} +#endif + +/** + * cpuidle_add_device_sysfs - adds device specific sysfs attributes + * @device: the target device + */ +int cpuidle_add_device_sysfs(struct cpuidle_device *device) +{ + int ret; + + ret = cpuidle_add_state_sysfs(device); + if (ret) + return ret; + + ret = cpuidle_add_driver_sysfs(device); + if (ret) + cpuidle_remove_state_sysfs(device); + return ret; +} + +/** + * cpuidle_remove_device_sysfs : removes device specific sysfs attributes + * @device : the target device + */ +void cpuidle_remove_device_sysfs(struct cpuidle_device *device) +{ + cpuidle_remove_driver_sysfs(device); + cpuidle_remove_state_sysfs(device); +} + /** * cpuidle_add_sysfs - creates a sysfs instance for the target device * @dev: the target device */ -int cpuidle_add_sysfs(struct device *cpu_dev) +int cpuidle_add_sysfs(struct cpuidle_device *dev) { - int cpu = cpu_dev->id; - struct cpuidle_device *dev; + struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu); int error; - dev = per_cpu(cpuidle_devices, cpu); + init_completion(&dev->kobj_unregister); + error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &cpu_dev->kobj, "cpuidle"); if (!error) @@ -426,11 +596,8 @@ int cpuidle_add_sysfs(struct device *cpu_dev) * cpuidle_remove_sysfs - deletes a sysfs instance on the target device * @dev: the target device */ -void cpuidle_remove_sysfs(struct device *cpu_dev) +void cpuidle_remove_sysfs(struct cpuidle_device *dev) { - int cpu = cpu_dev->id; - struct cpuidle_device *dev; - - dev = per_cpu(cpuidle_devices, cpu); kobject_put(&dev->kobj); + wait_for_completion(&dev->kobj_unregister); } diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 308c7fb92a6..f6644f59fd9 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -224,7 +224,7 @@ config CRYPTO_DEV_TALITOS config CRYPTO_DEV_IXP4XX tristate "Driver for IXP4xx crypto hardware acceleration" - depends on ARCH_IXP4XX + depends on ARCH_IXP4XX && IXP4XX_QMGR && IXP4XX_NPE select CRYPTO_DES select CRYPTO_ALGAPI select CRYPTO_AUTHENC diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c index 8f3f74ce8c7..21180d6cad6 100644 --- a/drivers/crypto/ixp4xx_crypto.c +++ b/drivers/crypto/ixp4xx_crypto.c @@ -750,12 +750,12 @@ static int setup_cipher(struct crypto_tfm *tfm, int encrypt, } if (cipher_cfg & MOD_AES) { switch (key_len) { - case 16: keylen_cfg = MOD_AES128 | KEYLEN_128; break; - case 24: keylen_cfg = MOD_AES192 | KEYLEN_192; break; - case 32: keylen_cfg = MOD_AES256 | KEYLEN_256; break; - default: - *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; - return -EINVAL; + case 16: keylen_cfg = MOD_AES128; break; + case 24: keylen_cfg = MOD_AES192; break; + case 32: keylen_cfg = MOD_AES256; break; + default: + *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; + return -EINVAL; } cipher_cfg |= keylen_cfg; } else if (cipher_cfg & MOD_3DES) { diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index f6b0a6e2ea5..0f079be1330 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -30,7 +30,7 @@ if PM_DEVFREQ comment "DEVFREQ Governors" config DEVFREQ_GOV_SIMPLE_ONDEMAND - bool "Simple Ondemand" + tristate "Simple Ondemand" help Chooses frequency based on the recent load on the device. Works similar as ONDEMAND governor of CPUFREQ does. A device with @@ -39,7 +39,7 @@ config DEVFREQ_GOV_SIMPLE_ONDEMAND values to the governor with data field at devfreq_add_device(). config DEVFREQ_GOV_PERFORMANCE - bool "Performance" + tristate "Performance" help Sets the frequency at the maximum available frequency. This governor always returns UINT_MAX as frequency so that @@ -47,7 +47,7 @@ config DEVFREQ_GOV_PERFORMANCE at any time. config DEVFREQ_GOV_POWERSAVE - bool "Powersave" + tristate "Powersave" help Sets the frequency at the minimum available frequency. This governor always returns 0 as frequency so that @@ -55,7 +55,7 @@ config DEVFREQ_GOV_POWERSAVE at any time. config DEVFREQ_GOV_USERSPACE - bool "Userspace" + tristate "Userspace" help Sets the frequency at the user specified one. This governor returns the user configured frequency if there diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index b146d76f04c..53766f39aad 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -27,21 +27,17 @@ #include <linux/hrtimer.h> #include "governor.h" -struct class *devfreq_class; +static struct class *devfreq_class; /* - * devfreq_work periodically monitors every registered device. - * The minimum polling interval is one jiffy. The polling interval is - * determined by the minimum polling period among all polling devfreq - * devices. The resolution of polling interval is one jiffy. + * devfreq core provides delayed work based load monitoring helper + * functions. Governors can use these or can implement their own + * monitoring mechanism. */ -static bool polling; static struct workqueue_struct *devfreq_wq; -static struct delayed_work devfreq_work; - -/* wait removing if this is to be removed */ -static struct devfreq *wait_remove_device; +/* The list of all device-devfreq governors */ +static LIST_HEAD(devfreq_governor_list); /* The list of all device-devfreq */ static LIST_HEAD(devfreq_list); static DEFINE_MUTEX(devfreq_list_lock); @@ -73,6 +69,79 @@ static struct devfreq *find_device_devfreq(struct device *dev) } /** + * devfreq_get_freq_level() - Lookup freq_table for the frequency + * @devfreq: the devfreq instance + * @freq: the target frequency + */ +static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq) +{ + int lev; + + for (lev = 0; lev < devfreq->profile->max_state; lev++) + if (freq == devfreq->profile->freq_table[lev]) + return lev; + + return -EINVAL; +} + +/** + * devfreq_update_status() - Update statistics of devfreq behavior + * @devfreq: the devfreq instance + * @freq: the update target frequency + */ +static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq) +{ + int lev, prev_lev; + unsigned long cur_time; + + lev = devfreq_get_freq_level(devfreq, freq); + if (lev < 0) + return lev; + + cur_time = jiffies; + devfreq->time_in_state[lev] += + cur_time - devfreq->last_stat_updated; + if (freq != devfreq->previous_freq) { + prev_lev = devfreq_get_freq_level(devfreq, + devfreq->previous_freq); + devfreq->trans_table[(prev_lev * + devfreq->profile->max_state) + lev]++; + devfreq->total_trans++; + } + devfreq->last_stat_updated = cur_time; + + return 0; +} + +/** + * find_devfreq_governor() - find devfreq governor from name + * @name: name of the governor + * + * Search the list of devfreq governors and return the matched + * governor's pointer. devfreq_list_lock should be held by the caller. + */ +static struct devfreq_governor *find_devfreq_governor(const char *name) +{ + struct devfreq_governor *tmp_governor; + + if (unlikely(IS_ERR_OR_NULL(name))) { + pr_err("DEVFREQ: %s: Invalid parameters\n", __func__); + return ERR_PTR(-EINVAL); + } + WARN(!mutex_is_locked(&devfreq_list_lock), + "devfreq_list_lock must be locked."); + + list_for_each_entry(tmp_governor, &devfreq_governor_list, node) { + if (!strncmp(tmp_governor->name, name, DEVFREQ_NAME_LEN)) + return tmp_governor; + } + + return ERR_PTR(-ENODEV); +} + +/* Load monitoring helper functions for governors use */ + +/** * update_devfreq() - Reevaluate the device and configure frequency. * @devfreq: the devfreq instance. * @@ -90,6 +159,9 @@ int update_devfreq(struct devfreq *devfreq) return -EINVAL; } + if (!devfreq->governor) + return -EINVAL; + /* Reevaluate the proper frequency */ err = devfreq->governor->get_target_freq(devfreq, &freq); if (err) @@ -116,16 +188,173 @@ int update_devfreq(struct devfreq *devfreq) if (err) return err; + if (devfreq->profile->freq_table) + if (devfreq_update_status(devfreq, freq)) + dev_err(&devfreq->dev, + "Couldn't update frequency transition information.\n"); + devfreq->previous_freq = freq; return err; } +EXPORT_SYMBOL(update_devfreq); + +/** + * devfreq_monitor() - Periodically poll devfreq objects. + * @work: the work struct used to run devfreq_monitor periodically. + * + */ +static void devfreq_monitor(struct work_struct *work) +{ + int err; + struct devfreq *devfreq = container_of(work, + struct devfreq, work.work); + + mutex_lock(&devfreq->lock); + err = update_devfreq(devfreq); + if (err) + dev_err(&devfreq->dev, "dvfs failed with (%d) error\n", err); + + queue_delayed_work(devfreq_wq, &devfreq->work, + msecs_to_jiffies(devfreq->profile->polling_ms)); + mutex_unlock(&devfreq->lock); +} + +/** + * devfreq_monitor_start() - Start load monitoring of devfreq instance + * @devfreq: the devfreq instance. + * + * Helper function for starting devfreq device load monitoing. By + * default delayed work based monitoring is supported. Function + * to be called from governor in response to DEVFREQ_GOV_START + * event when device is added to devfreq framework. + */ +void devfreq_monitor_start(struct devfreq *devfreq) +{ + INIT_DEFERRABLE_WORK(&devfreq->work, devfreq_monitor); + if (devfreq->profile->polling_ms) + queue_delayed_work(devfreq_wq, &devfreq->work, + msecs_to_jiffies(devfreq->profile->polling_ms)); +} +EXPORT_SYMBOL(devfreq_monitor_start); + +/** + * devfreq_monitor_stop() - Stop load monitoring of a devfreq instance + * @devfreq: the devfreq instance. + * + * Helper function to stop devfreq device load monitoing. Function + * to be called from governor in response to DEVFREQ_GOV_STOP + * event when device is removed from devfreq framework. + */ +void devfreq_monitor_stop(struct devfreq *devfreq) +{ + cancel_delayed_work_sync(&devfreq->work); +} +EXPORT_SYMBOL(devfreq_monitor_stop); + +/** + * devfreq_monitor_suspend() - Suspend load monitoring of a devfreq instance + * @devfreq: the devfreq instance. + * + * Helper function to suspend devfreq device load monitoing. Function + * to be called from governor in response to DEVFREQ_GOV_SUSPEND + * event or when polling interval is set to zero. + * + * Note: Though this function is same as devfreq_monitor_stop(), + * intentionally kept separate to provide hooks for collecting + * transition statistics. + */ +void devfreq_monitor_suspend(struct devfreq *devfreq) +{ + mutex_lock(&devfreq->lock); + if (devfreq->stop_polling) { + mutex_unlock(&devfreq->lock); + return; + } + + devfreq->stop_polling = true; + mutex_unlock(&devfreq->lock); + cancel_delayed_work_sync(&devfreq->work); +} +EXPORT_SYMBOL(devfreq_monitor_suspend); + +/** + * devfreq_monitor_resume() - Resume load monitoring of a devfreq instance + * @devfreq: the devfreq instance. + * + * Helper function to resume devfreq device load monitoing. Function + * to be called from governor in response to DEVFREQ_GOV_RESUME + * event or when polling interval is set to non-zero. + */ +void devfreq_monitor_resume(struct devfreq *devfreq) +{ + mutex_lock(&devfreq->lock); + if (!devfreq->stop_polling) + goto out; + + if (!delayed_work_pending(&devfreq->work) && + devfreq->profile->polling_ms) + queue_delayed_work(devfreq_wq, &devfreq->work, + msecs_to_jiffies(devfreq->profile->polling_ms)); + devfreq->stop_polling = false; + +out: + mutex_unlock(&devfreq->lock); +} +EXPORT_SYMBOL(devfreq_monitor_resume); + +/** + * devfreq_interval_update() - Update device devfreq monitoring interval + * @devfreq: the devfreq instance. + * @delay: new polling interval to be set. + * + * Helper function to set new load monitoring polling interval. Function + * to be called from governor in response to DEVFREQ_GOV_INTERVAL event. + */ +void devfreq_interval_update(struct devfreq *devfreq, unsigned int *delay) +{ + unsigned int cur_delay = devfreq->profile->polling_ms; + unsigned int new_delay = *delay; + + mutex_lock(&devfreq->lock); + devfreq->profile->polling_ms = new_delay; + + if (devfreq->stop_polling) + goto out; + + /* if new delay is zero, stop polling */ + if (!new_delay) { + mutex_unlock(&devfreq->lock); + cancel_delayed_work_sync(&devfreq->work); + return; + } + + /* if current delay is zero, start polling with new delay */ + if (!cur_delay) { + queue_delayed_work(devfreq_wq, &devfreq->work, + msecs_to_jiffies(devfreq->profile->polling_ms)); + goto out; + } + + /* if current delay is greater than new delay, restart polling */ + if (cur_delay > new_delay) { + mutex_unlock(&devfreq->lock); + cancel_delayed_work_sync(&devfreq->work); + mutex_lock(&devfreq->lock); + if (!devfreq->stop_polling) + queue_delayed_work(devfreq_wq, &devfreq->work, + msecs_to_jiffies(devfreq->profile->polling_ms)); + } +out: + mutex_unlock(&devfreq->lock); +} +EXPORT_SYMBOL(devfreq_interval_update); /** * devfreq_notifier_call() - Notify that the device frequency requirements * has been changed out of devfreq framework. - * @nb the notifier_block (supposed to be devfreq->nb) - * @type not used - * @devp not used + * @nb: the notifier_block (supposed to be devfreq->nb) + * @type: not used + * @devp: not used * * Called by a notifier that uses devfreq->nb. */ @@ -143,59 +372,34 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type, } /** - * _remove_devfreq() - Remove devfreq from the device. + * _remove_devfreq() - Remove devfreq from the list and release its resources. * @devfreq: the devfreq struct * @skip: skip calling device_unregister(). - * - * Note that the caller should lock devfreq->lock before calling - * this. _remove_devfreq() will unlock it and free devfreq - * internally. devfreq_list_lock should be locked by the caller - * as well (not relased at return) - * - * Lock usage: - * devfreq->lock: locked before call. - * unlocked at return (and freed) - * devfreq_list_lock: locked before call. - * kept locked at return. - * if devfreq is centrally polled. - * - * Freed memory: - * devfreq */ static void _remove_devfreq(struct devfreq *devfreq, bool skip) { - if (!mutex_is_locked(&devfreq->lock)) { - WARN(true, "devfreq->lock must be locked by the caller.\n"); - return; - } - if (!devfreq->governor->no_central_polling && - !mutex_is_locked(&devfreq_list_lock)) { - WARN(true, "devfreq_list_lock must be locked by the caller.\n"); + mutex_lock(&devfreq_list_lock); + if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) { + mutex_unlock(&devfreq_list_lock); + dev_warn(&devfreq->dev, "releasing devfreq which doesn't exist\n"); return; } + list_del(&devfreq->node); + mutex_unlock(&devfreq_list_lock); - if (devfreq->being_removed) - return; - - devfreq->being_removed = true; + if (devfreq->governor) + devfreq->governor->event_handler(devfreq, + DEVFREQ_GOV_STOP, NULL); if (devfreq->profile->exit) devfreq->profile->exit(devfreq->dev.parent); - if (devfreq->governor->exit) - devfreq->governor->exit(devfreq); - if (!skip && get_device(&devfreq->dev)) { device_unregister(&devfreq->dev); put_device(&devfreq->dev); } - if (!devfreq->governor->no_central_polling) - list_del(&devfreq->node); - - mutex_unlock(&devfreq->lock); mutex_destroy(&devfreq->lock); - kfree(devfreq); } @@ -210,163 +414,39 @@ static void _remove_devfreq(struct devfreq *devfreq, bool skip) static void devfreq_dev_release(struct device *dev) { struct devfreq *devfreq = to_devfreq(dev); - bool central_polling = !devfreq->governor->no_central_polling; - - /* - * If devfreq_dev_release() was called by device_unregister() of - * _remove_devfreq(), we cannot mutex_lock(&devfreq->lock) and - * being_removed is already set. This also partially checks the case - * where devfreq_dev_release() is called from a thread other than - * the one called _remove_devfreq(); however, this case is - * dealt completely with another following being_removed check. - * - * Because being_removed is never being - * unset, we do not need to worry about race conditions on - * being_removed. - */ - if (devfreq->being_removed) - return; - - if (central_polling) - mutex_lock(&devfreq_list_lock); - - mutex_lock(&devfreq->lock); - /* - * Check being_removed flag again for the case where - * devfreq_dev_release() was called in a thread other than the one - * possibly called _remove_devfreq(). - */ - if (devfreq->being_removed) { - mutex_unlock(&devfreq->lock); - goto out; - } - - /* devfreq->lock is unlocked and removed in _removed_devfreq() */ _remove_devfreq(devfreq, true); - -out: - if (central_polling) - mutex_unlock(&devfreq_list_lock); -} - -/** - * devfreq_monitor() - Periodically poll devfreq objects. - * @work: the work struct used to run devfreq_monitor periodically. - * - */ -static void devfreq_monitor(struct work_struct *work) -{ - static unsigned long last_polled_at; - struct devfreq *devfreq, *tmp; - int error; - unsigned long jiffies_passed; - unsigned long next_jiffies = ULONG_MAX, now = jiffies; - struct device *dev; - - /* Initially last_polled_at = 0, polling every device at bootup */ - jiffies_passed = now - last_polled_at; - last_polled_at = now; - if (jiffies_passed == 0) - jiffies_passed = 1; - - mutex_lock(&devfreq_list_lock); - list_for_each_entry_safe(devfreq, tmp, &devfreq_list, node) { - mutex_lock(&devfreq->lock); - dev = devfreq->dev.parent; - - /* Do not remove tmp for a while */ - wait_remove_device = tmp; - - if (devfreq->governor->no_central_polling || - devfreq->next_polling == 0) { - mutex_unlock(&devfreq->lock); - continue; - } - mutex_unlock(&devfreq_list_lock); - - /* - * Reduce more next_polling if devfreq_wq took an extra - * delay. (i.e., CPU has been idled.) - */ - if (devfreq->next_polling <= jiffies_passed) { - error = update_devfreq(devfreq); - - /* Remove a devfreq with an error. */ - if (error && error != -EAGAIN) { - - dev_err(dev, "Due to update_devfreq error(%d), devfreq(%s) is removed from the device\n", - error, devfreq->governor->name); - - /* - * Unlock devfreq before locking the list - * in order to avoid deadlock with - * find_device_devfreq or others - */ - mutex_unlock(&devfreq->lock); - mutex_lock(&devfreq_list_lock); - /* Check if devfreq is already removed */ - if (IS_ERR(find_device_devfreq(dev))) - continue; - mutex_lock(&devfreq->lock); - /* This unlocks devfreq->lock and free it */ - _remove_devfreq(devfreq, false); - continue; - } - devfreq->next_polling = devfreq->polling_jiffies; - } else { - devfreq->next_polling -= jiffies_passed; - } - - if (devfreq->next_polling) - next_jiffies = (next_jiffies > devfreq->next_polling) ? - devfreq->next_polling : next_jiffies; - - mutex_unlock(&devfreq->lock); - mutex_lock(&devfreq_list_lock); - } - wait_remove_device = NULL; - mutex_unlock(&devfreq_list_lock); - - if (next_jiffies > 0 && next_jiffies < ULONG_MAX) { - polling = true; - queue_delayed_work(devfreq_wq, &devfreq_work, next_jiffies); - } else { - polling = false; - } } /** * devfreq_add_device() - Add devfreq feature to the device * @dev: the device to add devfreq feature. * @profile: device-specific profile to run devfreq. - * @governor: the policy to choose frequency. + * @governor_name: name of the policy to choose frequency. * @data: private data for the governor. The devfreq framework does not * touch this value. */ struct devfreq *devfreq_add_device(struct device *dev, struct devfreq_dev_profile *profile, - const struct devfreq_governor *governor, + const char *governor_name, void *data) { struct devfreq *devfreq; + struct devfreq_governor *governor; int err = 0; - if (!dev || !profile || !governor) { + if (!dev || !profile || !governor_name) { dev_err(dev, "%s: Invalid parameters.\n", __func__); return ERR_PTR(-EINVAL); } - - if (!governor->no_central_polling) { - mutex_lock(&devfreq_list_lock); - devfreq = find_device_devfreq(dev); - mutex_unlock(&devfreq_list_lock); - if (!IS_ERR(devfreq)) { - dev_err(dev, "%s: Unable to create devfreq for the device. It already has one.\n", __func__); - err = -EINVAL; - goto err_out; - } + mutex_lock(&devfreq_list_lock); + devfreq = find_device_devfreq(dev); + mutex_unlock(&devfreq_list_lock); + if (!IS_ERR(devfreq)) { + dev_err(dev, "%s: Unable to create devfreq for the device. It already has one.\n", __func__); + err = -EINVAL; + goto err_out; } devfreq = kzalloc(sizeof(struct devfreq), GFP_KERNEL); @@ -383,92 +463,316 @@ struct devfreq *devfreq_add_device(struct device *dev, devfreq->dev.class = devfreq_class; devfreq->dev.release = devfreq_dev_release; devfreq->profile = profile; - devfreq->governor = governor; + strncpy(devfreq->governor_name, governor_name, DEVFREQ_NAME_LEN); devfreq->previous_freq = profile->initial_freq; devfreq->data = data; - devfreq->next_polling = devfreq->polling_jiffies - = msecs_to_jiffies(devfreq->profile->polling_ms); devfreq->nb.notifier_call = devfreq_notifier_call; + devfreq->trans_table = devm_kzalloc(dev, sizeof(unsigned int) * + devfreq->profile->max_state * + devfreq->profile->max_state, + GFP_KERNEL); + devfreq->time_in_state = devm_kzalloc(dev, sizeof(unsigned int) * + devfreq->profile->max_state, + GFP_KERNEL); + devfreq->last_stat_updated = jiffies; + dev_set_name(&devfreq->dev, dev_name(dev)); err = device_register(&devfreq->dev); if (err) { put_device(&devfreq->dev); + mutex_unlock(&devfreq->lock); goto err_dev; } - if (governor->init) - err = governor->init(devfreq); - if (err) - goto err_init; - mutex_unlock(&devfreq->lock); - if (governor->no_central_polling) - goto out; - mutex_lock(&devfreq_list_lock); - list_add(&devfreq->node, &devfreq_list); - if (devfreq_wq && devfreq->next_polling && !polling) { - polling = true; - queue_delayed_work(devfreq_wq, &devfreq_work, - devfreq->next_polling); - } + governor = find_devfreq_governor(devfreq->governor_name); + if (!IS_ERR(governor)) + devfreq->governor = governor; + if (devfreq->governor) + err = devfreq->governor->event_handler(devfreq, + DEVFREQ_GOV_START, NULL); mutex_unlock(&devfreq_list_lock); -out: + if (err) { + dev_err(dev, "%s: Unable to start governor for the device\n", + __func__); + goto err_init; + } + return devfreq; err_init: + list_del(&devfreq->node); device_unregister(&devfreq->dev); err_dev: - mutex_unlock(&devfreq->lock); kfree(devfreq); err_out: return ERR_PTR(err); } +EXPORT_SYMBOL(devfreq_add_device); /** * devfreq_remove_device() - Remove devfreq feature from a device. - * @devfreq the devfreq instance to be removed + * @devfreq: the devfreq instance to be removed */ int devfreq_remove_device(struct devfreq *devfreq) { - bool central_polling; + if (!devfreq) + return -EINVAL; + + _remove_devfreq(devfreq, false); + return 0; +} +EXPORT_SYMBOL(devfreq_remove_device); + +/** + * devfreq_suspend_device() - Suspend devfreq of a device. + * @devfreq: the devfreq instance to be suspended + */ +int devfreq_suspend_device(struct devfreq *devfreq) +{ if (!devfreq) return -EINVAL; - central_polling = !devfreq->governor->no_central_polling; + if (!devfreq->governor) + return 0; + + return devfreq->governor->event_handler(devfreq, + DEVFREQ_GOV_SUSPEND, NULL); +} +EXPORT_SYMBOL(devfreq_suspend_device); + +/** + * devfreq_resume_device() - Resume devfreq of a device. + * @devfreq: the devfreq instance to be resumed + */ +int devfreq_resume_device(struct devfreq *devfreq) +{ + if (!devfreq) + return -EINVAL; + + if (!devfreq->governor) + return 0; + + return devfreq->governor->event_handler(devfreq, + DEVFREQ_GOV_RESUME, NULL); +} +EXPORT_SYMBOL(devfreq_resume_device); + +/** + * devfreq_add_governor() - Add devfreq governor + * @governor: the devfreq governor to be added + */ +int devfreq_add_governor(struct devfreq_governor *governor) +{ + struct devfreq_governor *g; + struct devfreq *devfreq; + int err = 0; + + if (!governor) { + pr_err("%s: Invalid parameters.\n", __func__); + return -EINVAL; + } + + mutex_lock(&devfreq_list_lock); + g = find_devfreq_governor(governor->name); + if (!IS_ERR(g)) { + pr_err("%s: governor %s already registered\n", __func__, + g->name); + err = -EINVAL; + goto err_out; + } - if (central_polling) { - mutex_lock(&devfreq_list_lock); - while (wait_remove_device == devfreq) { - mutex_unlock(&devfreq_list_lock); - schedule(); - mutex_lock(&devfreq_list_lock); + list_add(&governor->node, &devfreq_governor_list); + + list_for_each_entry(devfreq, &devfreq_list, node) { + int ret = 0; + struct device *dev = devfreq->dev.parent; + + if (!strncmp(devfreq->governor_name, governor->name, + DEVFREQ_NAME_LEN)) { + /* The following should never occur */ + if (devfreq->governor) { + dev_warn(dev, + "%s: Governor %s already present\n", + __func__, devfreq->governor->name); + ret = devfreq->governor->event_handler(devfreq, + DEVFREQ_GOV_STOP, NULL); + if (ret) { + dev_warn(dev, + "%s: Governor %s stop = %d\n", + __func__, + devfreq->governor->name, ret); + } + /* Fall through */ + } + devfreq->governor = governor; + ret = devfreq->governor->event_handler(devfreq, + DEVFREQ_GOV_START, NULL); + if (ret) { + dev_warn(dev, "%s: Governor %s start=%d\n", + __func__, devfreq->governor->name, + ret); + } } } - mutex_lock(&devfreq->lock); - _remove_devfreq(devfreq, false); /* it unlocks devfreq->lock */ +err_out: + mutex_unlock(&devfreq_list_lock); - if (central_polling) - mutex_unlock(&devfreq_list_lock); + return err; +} +EXPORT_SYMBOL(devfreq_add_governor); - return 0; +/** + * devfreq_remove_device() - Remove devfreq feature from a device. + * @governor: the devfreq governor to be removed + */ +int devfreq_remove_governor(struct devfreq_governor *governor) +{ + struct devfreq_governor *g; + struct devfreq *devfreq; + int err = 0; + + if (!governor) { + pr_err("%s: Invalid parameters.\n", __func__); + return -EINVAL; + } + + mutex_lock(&devfreq_list_lock); + g = find_devfreq_governor(governor->name); + if (IS_ERR(g)) { + pr_err("%s: governor %s not registered\n", __func__, + governor->name); + err = PTR_ERR(g); + goto err_out; + } + list_for_each_entry(devfreq, &devfreq_list, node) { + int ret; + struct device *dev = devfreq->dev.parent; + + if (!strncmp(devfreq->governor_name, governor->name, + DEVFREQ_NAME_LEN)) { + /* we should have a devfreq governor! */ + if (!devfreq->governor) { + dev_warn(dev, "%s: Governor %s NOT present\n", + __func__, governor->name); + continue; + /* Fall through */ + } + ret = devfreq->governor->event_handler(devfreq, + DEVFREQ_GOV_STOP, NULL); + if (ret) { + dev_warn(dev, "%s: Governor %s stop=%d\n", + __func__, devfreq->governor->name, + ret); + } + devfreq->governor = NULL; + } + } + + list_del(&governor->node); +err_out: + mutex_unlock(&devfreq_list_lock); + + return err; } +EXPORT_SYMBOL(devfreq_remove_governor); static ssize_t show_governor(struct device *dev, struct device_attribute *attr, char *buf) { + if (!to_devfreq(dev)->governor) + return -EINVAL; + return sprintf(buf, "%s\n", to_devfreq(dev)->governor->name); } +static ssize_t store_governor(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct devfreq *df = to_devfreq(dev); + int ret; + char str_governor[DEVFREQ_NAME_LEN + 1]; + struct devfreq_governor *governor; + + ret = sscanf(buf, "%" __stringify(DEVFREQ_NAME_LEN) "s", str_governor); + if (ret != 1) + return -EINVAL; + + mutex_lock(&devfreq_list_lock); + governor = find_devfreq_governor(str_governor); + if (IS_ERR(governor)) { + ret = PTR_ERR(governor); + goto out; + } + if (df->governor == governor) + goto out; + + if (df->governor) { + ret = df->governor->event_handler(df, DEVFREQ_GOV_STOP, NULL); + if (ret) { + dev_warn(dev, "%s: Governor %s not stopped(%d)\n", + __func__, df->governor->name, ret); + goto out; + } + } + df->governor = governor; + strncpy(df->governor_name, governor->name, DEVFREQ_NAME_LEN); + ret = df->governor->event_handler(df, DEVFREQ_GOV_START, NULL); + if (ret) + dev_warn(dev, "%s: Governor %s not started(%d)\n", + __func__, df->governor->name, ret); +out: + mutex_unlock(&devfreq_list_lock); + + if (!ret) + ret = count; + return ret; +} +static ssize_t show_available_governors(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct devfreq_governor *tmp_governor; + ssize_t count = 0; + + mutex_lock(&devfreq_list_lock); + list_for_each_entry(tmp_governor, &devfreq_governor_list, node) + count += scnprintf(&buf[count], (PAGE_SIZE - count - 2), + "%s ", tmp_governor->name); + mutex_unlock(&devfreq_list_lock); + + /* Truncate the trailing space */ + if (count) + count--; + + count += sprintf(&buf[count], "\n"); + + return count; +} + static ssize_t show_freq(struct device *dev, struct device_attribute *attr, char *buf) { + unsigned long freq; + struct devfreq *devfreq = to_devfreq(dev); + + if (devfreq->profile->get_cur_freq && + !devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq)) + return sprintf(buf, "%lu\n", freq); + + return sprintf(buf, "%lu\n", devfreq->previous_freq); +} + +static ssize_t show_target_freq(struct device *dev, + struct device_attribute *attr, char *buf) +{ return sprintf(buf, "%lu\n", to_devfreq(dev)->previous_freq); } @@ -486,39 +790,19 @@ static ssize_t store_polling_interval(struct device *dev, unsigned int value; int ret; + if (!df->governor) + return -EINVAL; + ret = sscanf(buf, "%u", &value); if (ret != 1) - goto out; - - mutex_lock(&df->lock); - df->profile->polling_ms = value; - df->next_polling = df->polling_jiffies - = msecs_to_jiffies(value); - mutex_unlock(&df->lock); + return -EINVAL; + df->governor->event_handler(df, DEVFREQ_GOV_INTERVAL, &value); ret = count; - if (df->governor->no_central_polling) - goto out; - - mutex_lock(&devfreq_list_lock); - if (df->next_polling > 0 && !polling) { - polling = true; - queue_delayed_work(devfreq_wq, &devfreq_work, - df->next_polling); - } - mutex_unlock(&devfreq_list_lock); -out: return ret; } -static ssize_t show_central_polling(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", - !to_devfreq(dev)->governor->no_central_polling); -} - static ssize_t store_min_freq(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -529,7 +813,7 @@ static ssize_t store_min_freq(struct device *dev, struct device_attribute *attr, ret = sscanf(buf, "%lu", &value); if (ret != 1) - goto out; + return -EINVAL; mutex_lock(&df->lock); max = df->max_freq; @@ -543,7 +827,6 @@ static ssize_t store_min_freq(struct device *dev, struct device_attribute *attr, ret = count; unlock: mutex_unlock(&df->lock); -out: return ret; } @@ -563,7 +846,7 @@ static ssize_t store_max_freq(struct device *dev, struct device_attribute *attr, ret = sscanf(buf, "%lu", &value); if (ret != 1) - goto out; + return -EINVAL; mutex_lock(&df->lock); min = df->min_freq; @@ -577,7 +860,6 @@ static ssize_t store_max_freq(struct device *dev, struct device_attribute *attr, ret = count; unlock: mutex_unlock(&df->lock); -out: return ret; } @@ -587,34 +869,92 @@ static ssize_t show_max_freq(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%lu\n", to_devfreq(dev)->max_freq); } +static ssize_t show_available_freqs(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct devfreq *df = to_devfreq(d); + struct device *dev = df->dev.parent; + struct opp *opp; + ssize_t count = 0; + unsigned long freq = 0; + + rcu_read_lock(); + do { + opp = opp_find_freq_ceil(dev, &freq); + if (IS_ERR(opp)) + break; + + count += scnprintf(&buf[count], (PAGE_SIZE - count - 2), + "%lu ", freq); + freq++; + } while (1); + rcu_read_unlock(); + + /* Truncate the trailing space */ + if (count) + count--; + + count += sprintf(&buf[count], "\n"); + + return count; +} + +static ssize_t show_trans_table(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct devfreq *devfreq = to_devfreq(dev); + ssize_t len; + int i, j, err; + unsigned int max_state = devfreq->profile->max_state; + + err = devfreq_update_status(devfreq, devfreq->previous_freq); + if (err) + return 0; + + len = sprintf(buf, " From : To\n"); + len += sprintf(buf + len, " :"); + for (i = 0; i < max_state; i++) + len += sprintf(buf + len, "%8u", + devfreq->profile->freq_table[i]); + + len += sprintf(buf + len, " time(ms)\n"); + + for (i = 0; i < max_state; i++) { + if (devfreq->profile->freq_table[i] + == devfreq->previous_freq) { + len += sprintf(buf + len, "*"); + } else { + len += sprintf(buf + len, " "); + } + len += sprintf(buf + len, "%8u:", + devfreq->profile->freq_table[i]); + for (j = 0; j < max_state; j++) + len += sprintf(buf + len, "%8u", + devfreq->trans_table[(i * max_state) + j]); + len += sprintf(buf + len, "%10u\n", + jiffies_to_msecs(devfreq->time_in_state[i])); + } + + len += sprintf(buf + len, "Total transition : %u\n", + devfreq->total_trans); + return len; +} + static struct device_attribute devfreq_attrs[] = { - __ATTR(governor, S_IRUGO, show_governor, NULL), + __ATTR(governor, S_IRUGO | S_IWUSR, show_governor, store_governor), + __ATTR(available_governors, S_IRUGO, show_available_governors, NULL), __ATTR(cur_freq, S_IRUGO, show_freq, NULL), - __ATTR(central_polling, S_IRUGO, show_central_polling, NULL), + __ATTR(available_frequencies, S_IRUGO, show_available_freqs, NULL), + __ATTR(target_freq, S_IRUGO, show_target_freq, NULL), __ATTR(polling_interval, S_IRUGO | S_IWUSR, show_polling_interval, store_polling_interval), __ATTR(min_freq, S_IRUGO | S_IWUSR, show_min_freq, store_min_freq), __ATTR(max_freq, S_IRUGO | S_IWUSR, show_max_freq, store_max_freq), + __ATTR(trans_stat, S_IRUGO, show_trans_table, NULL), { }, }; -/** - * devfreq_start_polling() - Initialize data structure for devfreq framework and - * start polling registered devfreq devices. - */ -static int __init devfreq_start_polling(void) -{ - mutex_lock(&devfreq_list_lock); - polling = false; - devfreq_wq = create_freezable_workqueue("devfreq_wq"); - INIT_DEFERRABLE_WORK(&devfreq_work, devfreq_monitor); - mutex_unlock(&devfreq_list_lock); - - devfreq_monitor(&devfreq_work.work); - return 0; -} -late_initcall(devfreq_start_polling); - static int __init devfreq_init(void) { devfreq_class = class_create(THIS_MODULE, "devfreq"); @@ -622,7 +962,15 @@ static int __init devfreq_init(void) pr_err("%s: couldn't create class\n", __FILE__); return PTR_ERR(devfreq_class); } + + devfreq_wq = create_freezable_workqueue("devfreq_wq"); + if (IS_ERR(devfreq_wq)) { + class_destroy(devfreq_class); + pr_err("%s: couldn't create workqueue\n", __FILE__); + return PTR_ERR(devfreq_wq); + } devfreq_class->dev_attrs = devfreq_attrs; + return 0; } subsys_initcall(devfreq_init); @@ -630,6 +978,7 @@ subsys_initcall(devfreq_init); static void __exit devfreq_exit(void) { class_destroy(devfreq_class); + destroy_workqueue(devfreq_wq); } module_exit(devfreq_exit); @@ -641,9 +990,9 @@ module_exit(devfreq_exit); /** * devfreq_recommended_opp() - Helper function to get proper OPP for the * freq value given to target callback. - * @dev The devfreq user device. (parent of devfreq) - * @freq The frequency given to target function - * @flags Flags handed from devfreq framework. + * @dev: The devfreq user device. (parent of devfreq) + * @freq: The frequency given to target function + * @flags: Flags handed from devfreq framework. * */ struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, @@ -656,14 +1005,14 @@ struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, opp = opp_find_freq_floor(dev, freq); /* If not available, use the closest opp */ - if (opp == ERR_PTR(-ENODEV)) + if (opp == ERR_PTR(-ERANGE)) opp = opp_find_freq_ceil(dev, freq); } else { /* The freq is an lower bound. opp should be higher */ opp = opp_find_freq_ceil(dev, freq); /* If not available, use the closest opp */ - if (opp == ERR_PTR(-ENODEV)) + if (opp == ERR_PTR(-ERANGE)) opp = opp_find_freq_floor(dev, freq); } @@ -674,35 +1023,49 @@ struct opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, * devfreq_register_opp_notifier() - Helper function to get devfreq notified * for any changes in the OPP availability * changes - * @dev The devfreq user device. (parent of devfreq) - * @devfreq The devfreq object. + * @dev: The devfreq user device. (parent of devfreq) + * @devfreq: The devfreq object. */ int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq) { - struct srcu_notifier_head *nh = opp_get_notifier(dev); + struct srcu_notifier_head *nh; + int ret = 0; + rcu_read_lock(); + nh = opp_get_notifier(dev); if (IS_ERR(nh)) - return PTR_ERR(nh); - return srcu_notifier_chain_register(nh, &devfreq->nb); + ret = PTR_ERR(nh); + rcu_read_unlock(); + if (!ret) + ret = srcu_notifier_chain_register(nh, &devfreq->nb); + + return ret; } /** * devfreq_unregister_opp_notifier() - Helper function to stop getting devfreq * notified for any changes in the OPP * availability changes anymore. - * @dev The devfreq user device. (parent of devfreq) - * @devfreq The devfreq object. + * @dev: The devfreq user device. (parent of devfreq) + * @devfreq: The devfreq object. * * At exit() callback of devfreq_dev_profile, this must be included if * devfreq_recommended_opp is used. */ int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq) { - struct srcu_notifier_head *nh = opp_get_notifier(dev); + struct srcu_notifier_head *nh; + int ret = 0; + rcu_read_lock(); + nh = opp_get_notifier(dev); if (IS_ERR(nh)) - return PTR_ERR(nh); - return srcu_notifier_chain_unregister(nh, &devfreq->nb); + ret = PTR_ERR(nh); + rcu_read_unlock(); + if (!ret) + ret = srcu_notifier_chain_unregister(nh, &devfreq->nb); + + return ret; } MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); diff --git a/drivers/devfreq/exynos4_bus.c b/drivers/devfreq/exynos4_bus.c index 88ddc77a9bb..74183720871 100644 --- a/drivers/devfreq/exynos4_bus.c +++ b/drivers/devfreq/exynos4_bus.c @@ -987,7 +987,7 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; int err = 0; - data = kzalloc(sizeof(struct busfreq_data), GFP_KERNEL); + data = devm_kzalloc(&pdev->dev, sizeof(struct busfreq_data), GFP_KERNEL); if (data == NULL) { dev_err(dev, "Cannot allocate memory.\n"); return -ENOMEM; @@ -1012,31 +1012,26 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev) err = -EINVAL; } if (err) - goto err_regulator; + return err; - data->vdd_int = regulator_get(dev, "vdd_int"); + data->vdd_int = devm_regulator_get(dev, "vdd_int"); if (IS_ERR(data->vdd_int)) { dev_err(dev, "Cannot get the regulator \"vdd_int\"\n"); - err = PTR_ERR(data->vdd_int); - goto err_regulator; + return PTR_ERR(data->vdd_int); } if (data->type == TYPE_BUSF_EXYNOS4x12) { - data->vdd_mif = regulator_get(dev, "vdd_mif"); + data->vdd_mif = devm_regulator_get(dev, "vdd_mif"); if (IS_ERR(data->vdd_mif)) { dev_err(dev, "Cannot get the regulator \"vdd_mif\"\n"); - err = PTR_ERR(data->vdd_mif); - regulator_put(data->vdd_int); - goto err_regulator; - + return PTR_ERR(data->vdd_mif); } } opp = opp_find_freq_floor(dev, &exynos4_devfreq_profile.initial_freq); if (IS_ERR(opp)) { dev_err(dev, "Invalid initial frequency %lu kHz.\n", - exynos4_devfreq_profile.initial_freq); - err = PTR_ERR(opp); - goto err_opp_add; + exynos4_devfreq_profile.initial_freq); + return PTR_ERR(opp); } data->curr_opp = opp; @@ -1045,30 +1040,20 @@ static __devinit int exynos4_busfreq_probe(struct platform_device *pdev) busfreq_mon_reset(data); data->devfreq = devfreq_add_device(dev, &exynos4_devfreq_profile, - &devfreq_simple_ondemand, NULL); - if (IS_ERR(data->devfreq)) { - err = PTR_ERR(data->devfreq); - goto err_opp_add; - } + "simple_ondemand", NULL); + if (IS_ERR(data->devfreq)) + return PTR_ERR(data->devfreq); devfreq_register_opp_notifier(dev, data->devfreq); err = register_pm_notifier(&data->pm_notifier); if (err) { dev_err(dev, "Failed to setup pm notifier\n"); - goto err_devfreq_add; + devfreq_remove_device(data->devfreq); + return err; } return 0; -err_devfreq_add: - devfreq_remove_device(data->devfreq); -err_opp_add: - if (data->vdd_mif) - regulator_put(data->vdd_mif); - regulator_put(data->vdd_int); -err_regulator: - kfree(data); - return err; } static __devexit int exynos4_busfreq_remove(struct platform_device *pdev) @@ -1077,10 +1062,6 @@ static __devexit int exynos4_busfreq_remove(struct platform_device *pdev) unregister_pm_notifier(&data->pm_notifier); devfreq_remove_device(data->devfreq); - regulator_put(data->vdd_int); - if (data->vdd_mif) - regulator_put(data->vdd_mif); - kfree(data); return 0; } diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h index ea7f13c58de..fad7d632197 100644 --- a/drivers/devfreq/governor.h +++ b/drivers/devfreq/governor.h @@ -18,7 +18,24 @@ #define to_devfreq(DEV) container_of((DEV), struct devfreq, dev) +/* Devfreq events */ +#define DEVFREQ_GOV_START 0x1 +#define DEVFREQ_GOV_STOP 0x2 +#define DEVFREQ_GOV_INTERVAL 0x3 +#define DEVFREQ_GOV_SUSPEND 0x4 +#define DEVFREQ_GOV_RESUME 0x5 + /* Caution: devfreq->lock must be locked before calling update_devfreq */ extern int update_devfreq(struct devfreq *devfreq); +extern void devfreq_monitor_start(struct devfreq *devfreq); +extern void devfreq_monitor_stop(struct devfreq *devfreq); +extern void devfreq_monitor_suspend(struct devfreq *devfreq); +extern void devfreq_monitor_resume(struct devfreq *devfreq); +extern void devfreq_interval_update(struct devfreq *devfreq, + unsigned int *delay); + +extern int devfreq_add_governor(struct devfreq_governor *governor); +extern int devfreq_remove_governor(struct devfreq_governor *governor); + #endif /* _GOVERNOR_H */ diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c index af75ddd4f15..c72f942f30a 100644 --- a/drivers/devfreq/governor_performance.c +++ b/drivers/devfreq/governor_performance.c @@ -10,6 +10,7 @@ */ #include <linux/devfreq.h> +#include <linux/module.h> #include "governor.h" static int devfreq_performance_func(struct devfreq *df, @@ -26,14 +27,41 @@ static int devfreq_performance_func(struct devfreq *df, return 0; } -static int performance_init(struct devfreq *devfreq) +static int devfreq_performance_handler(struct devfreq *devfreq, + unsigned int event, void *data) { - return update_devfreq(devfreq); + int ret = 0; + + if (event == DEVFREQ_GOV_START) { + mutex_lock(&devfreq->lock); + ret = update_devfreq(devfreq); + mutex_unlock(&devfreq->lock); + } + + return ret; } -const struct devfreq_governor devfreq_performance = { +static struct devfreq_governor devfreq_performance = { .name = "performance", - .init = performance_init, .get_target_freq = devfreq_performance_func, - .no_central_polling = true, + .event_handler = devfreq_performance_handler, }; + +static int __init devfreq_performance_init(void) +{ + return devfreq_add_governor(&devfreq_performance); +} +subsys_initcall(devfreq_performance_init); + +static void __exit devfreq_performance_exit(void) +{ + int ret; + + ret = devfreq_remove_governor(&devfreq_performance); + if (ret) + pr_err("%s: failed remove governor %d\n", __func__, ret); + + return; +} +module_exit(devfreq_performance_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c index fec0cdbd247..0c6bed567e6 100644 --- a/drivers/devfreq/governor_powersave.c +++ b/drivers/devfreq/governor_powersave.c @@ -10,6 +10,7 @@ */ #include <linux/devfreq.h> +#include <linux/module.h> #include "governor.h" static int devfreq_powersave_func(struct devfreq *df, @@ -23,14 +24,41 @@ static int devfreq_powersave_func(struct devfreq *df, return 0; } -static int powersave_init(struct devfreq *devfreq) +static int devfreq_powersave_handler(struct devfreq *devfreq, + unsigned int event, void *data) { - return update_devfreq(devfreq); + int ret = 0; + + if (event == DEVFREQ_GOV_START) { + mutex_lock(&devfreq->lock); + ret = update_devfreq(devfreq); + mutex_unlock(&devfreq->lock); + } + + return ret; } -const struct devfreq_governor devfreq_powersave = { +static struct devfreq_governor devfreq_powersave = { .name = "powersave", - .init = powersave_init, .get_target_freq = devfreq_powersave_func, - .no_central_polling = true, + .event_handler = devfreq_powersave_handler, }; + +static int __init devfreq_powersave_init(void) +{ + return devfreq_add_governor(&devfreq_powersave); +} +subsys_initcall(devfreq_powersave_init); + +static void __exit devfreq_powersave_exit(void) +{ + int ret; + + ret = devfreq_remove_governor(&devfreq_powersave); + if (ret) + pr_err("%s: failed remove governor %d\n", __func__, ret); + + return; +} +module_exit(devfreq_powersave_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/devfreq/governor_simpleondemand.c b/drivers/devfreq/governor_simpleondemand.c index a2e3eae7901..0720ba84ca9 100644 --- a/drivers/devfreq/governor_simpleondemand.c +++ b/drivers/devfreq/governor_simpleondemand.c @@ -10,8 +10,10 @@ */ #include <linux/errno.h> +#include <linux/module.h> #include <linux/devfreq.h> #include <linux/math64.h> +#include "governor.h" /* Default constants for DevFreq-Simple-Ondemand (DFSO) */ #define DFSO_UPTHRESHOLD (90) @@ -88,7 +90,58 @@ static int devfreq_simple_ondemand_func(struct devfreq *df, return 0; } -const struct devfreq_governor devfreq_simple_ondemand = { +static int devfreq_simple_ondemand_handler(struct devfreq *devfreq, + unsigned int event, void *data) +{ + switch (event) { + case DEVFREQ_GOV_START: + devfreq_monitor_start(devfreq); + break; + + case DEVFREQ_GOV_STOP: + devfreq_monitor_stop(devfreq); + break; + + case DEVFREQ_GOV_INTERVAL: + devfreq_interval_update(devfreq, (unsigned int *)data); + break; + + case DEVFREQ_GOV_SUSPEND: + devfreq_monitor_suspend(devfreq); + break; + + case DEVFREQ_GOV_RESUME: + devfreq_monitor_resume(devfreq); + break; + + default: + break; + } + + return 0; +} + +static struct devfreq_governor devfreq_simple_ondemand = { .name = "simple_ondemand", .get_target_freq = devfreq_simple_ondemand_func, + .event_handler = devfreq_simple_ondemand_handler, }; + +static int __init devfreq_simple_ondemand_init(void) +{ + return devfreq_add_governor(&devfreq_simple_ondemand); +} +subsys_initcall(devfreq_simple_ondemand_init); + +static void __exit devfreq_simple_ondemand_exit(void) +{ + int ret; + + ret = devfreq_remove_governor(&devfreq_simple_ondemand); + if (ret) + pr_err("%s: failed remove governor %d\n", __func__, ret); + + return; +} +module_exit(devfreq_simple_ondemand_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c index 0681246fc89..35de6e83c1f 100644 --- a/drivers/devfreq/governor_userspace.c +++ b/drivers/devfreq/governor_userspace.c @@ -14,6 +14,7 @@ #include <linux/devfreq.h> #include <linux/pm.h> #include <linux/mutex.h> +#include <linux/module.h> #include "governor.h" struct userspace_data { @@ -116,10 +117,46 @@ static void userspace_exit(struct devfreq *devfreq) devfreq->data = NULL; } -const struct devfreq_governor devfreq_userspace = { +static int devfreq_userspace_handler(struct devfreq *devfreq, + unsigned int event, void *data) +{ + int ret = 0; + + switch (event) { + case DEVFREQ_GOV_START: + ret = userspace_init(devfreq); + break; + case DEVFREQ_GOV_STOP: + userspace_exit(devfreq); + break; + default: + break; + } + + return ret; +} + +static struct devfreq_governor devfreq_userspace = { .name = "userspace", .get_target_freq = devfreq_userspace_func, - .init = userspace_init, - .exit = userspace_exit, - .no_central_polling = true, + .event_handler = devfreq_userspace_handler, }; + +static int __init devfreq_userspace_init(void) +{ + return devfreq_add_governor(&devfreq_userspace); +} +subsys_initcall(devfreq_userspace_init); + +static void __exit devfreq_userspace_exit(void) +{ + int ret; + + ret = devfreq_remove_governor(&devfreq_userspace); + if (ret) + pr_err("%s: failed remove governor %d\n", __func__, ret); + + return; +} +module_exit(devfreq_userspace_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index c4b0eb3cde8..8f0b111af4d 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -1462,7 +1462,7 @@ static void dw_dma_off(struct dw_dma *dw) dw->chan[i].initialized = false; } -static int __devinit dw_probe(struct platform_device *pdev) +static int dw_probe(struct platform_device *pdev) { struct dw_dma_platform_data *pdata; struct resource *io; @@ -1700,7 +1700,7 @@ MODULE_DEVICE_TABLE(of, dw_dma_id_table); #endif static struct platform_driver dw_driver = { - .remove = __devexit_p(dw_remove), + .remove = dw_remove, .shutdown = dw_shutdown, .driver = { .name = "dw_dmac", diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index 05aea3ce850..232b4583ae9 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -545,7 +545,7 @@ static void edma_dma_init(struct edma_cc *ecc, struct dma_device *dma, INIT_LIST_HEAD(&dma->channels); } -static int __devinit edma_probe(struct platform_device *pdev) +static int edma_probe(struct platform_device *pdev) { struct edma_cc *ecc; int ret; @@ -598,7 +598,7 @@ static int __devexit edma_remove(struct platform_device *pdev) static struct platform_driver edma_driver = { .probe = edma_probe, - .remove = __devexit_p(edma_remove), + .remove = edma_remove, .driver = { .name = "edma-dma-engine", .owner = THIS_MODULE, diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 094437b9d82..4fc2980556a 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -1221,7 +1221,7 @@ out_unwind: /* OpenFirmware Subsystem */ /*----------------------------------------------------------------------------*/ -static int __devinit fsl_dma_chan_probe(struct fsldma_device *fdev, +static int fsl_dma_chan_probe(struct fsldma_device *fdev, struct device_node *node, u32 feature, const char *compatible) { struct fsldma_chan *chan; @@ -1324,7 +1324,7 @@ static void fsl_dma_chan_remove(struct fsldma_chan *chan) kfree(chan); } -static int __devinit fsldma_of_probe(struct platform_device *op) +static int fsldma_of_probe(struct platform_device *op) { struct fsldma_device *fdev; struct device_node *child; diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c index 02b21d7d38e..bc764afacd9 100644 --- a/drivers/dma/intel_mid_dma.c +++ b/drivers/dma/intel_mid_dma.c @@ -1225,7 +1225,7 @@ static void middma_shutdown(struct pci_dev *pdev) * Initialize the PCI device, map BARs, query driver data. * Call setup_dma to complete contoller and chan initilzation */ -static int __devinit intel_mid_dma_probe(struct pci_dev *pdev, +static int intel_mid_dma_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct middma_device *device; @@ -1432,7 +1432,7 @@ static struct pci_driver intel_mid_dma_pci_driver = { .name = "Intel MID DMA", .id_table = intel_mid_dma_ids, .probe = intel_mid_dma_probe, - .remove = __devexit_p(intel_mid_dma_remove), + .remove = intel_mid_dma_remove, #ifdef CONFIG_PM .driver = { .pm = &intel_mid_dma_pm, diff --git a/drivers/dma/ioat/pci.c b/drivers/dma/ioat/pci.c index c0573061b45..bfa9a3536e0 100644 --- a/drivers/dma/ioat/pci.c +++ b/drivers/dma/ioat/pci.c @@ -125,7 +125,7 @@ static struct pci_driver ioat_pci_driver = { .name = DRV_NAME, .id_table = ioat_pci_tbl, .probe = ioat_pci_probe, - .remove = __devexit_p(ioat_remove), + .remove = ioat_remove, }; static struct ioatdma_device * diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index 79e3eba2970..9072e173b86 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c @@ -968,7 +968,7 @@ static void iop_adma_issue_pending(struct dma_chan *chan) */ #define IOP_ADMA_TEST_SIZE 2000 -static int __devinit iop_adma_memcpy_self_test(struct iop_adma_device *device) +static int iop_adma_memcpy_self_test(struct iop_adma_device *device) { int i; void *src, *dest; @@ -1042,7 +1042,7 @@ out: } #define IOP_ADMA_NUM_SRC_TEST 4 /* must be <= 15 */ -static int __devinit +static int iop_adma_xor_val_self_test(struct iop_adma_device *device) { int i, src_idx; @@ -1243,7 +1243,7 @@ out: } #ifdef CONFIG_RAID6_PQ -static int __devinit +static int iop_adma_pq_zero_sum_self_test(struct iop_adma_device *device) { /* combined sources, software pq results, and extra hw pq results */ @@ -1429,7 +1429,7 @@ static int __devexit iop_adma_remove(struct platform_device *dev) return 0; } -static int __devinit iop_adma_probe(struct platform_device *pdev) +static int iop_adma_probe(struct platform_device *pdev) { struct resource *res; int ret = 0, i; @@ -1711,7 +1711,7 @@ static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan) static struct platform_driver iop_adma_driver = { .probe = iop_adma_probe, - .remove = __devexit_p(iop_adma_remove), + .remove = iop_adma_remove, .driver = { .owner = THIS_MODULE, .name = "iop-adma", diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index 14da1f403ed..13bdf4a7e1e 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -720,7 +720,7 @@ static int __devexit mmp_pdma_remove(struct platform_device *op) return 0; } -static int __devinit mmp_pdma_chan_init(struct mmp_pdma_device *pdev, +static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev, int idx, int irq) { struct mmp_pdma_phy *phy = &pdev->phy[idx]; @@ -764,7 +764,7 @@ static struct of_device_id mmp_pdma_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, mmp_pdma_dt_ids); -static int __devinit mmp_pdma_probe(struct platform_device *op) +static int mmp_pdma_probe(struct platform_device *op) { struct mmp_pdma_device *pdev; const struct of_device_id *of_id; @@ -865,7 +865,7 @@ static struct platform_driver mmp_pdma_driver = { }, .id_table = mmp_pdma_id_table, .probe = mmp_pdma_probe, - .remove = __devexit_p(mmp_pdma_remove), + .remove = mmp_pdma_remove, }; module_platform_driver(mmp_pdma_driver); diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c index f3e8d71bcbc..323821c0c09 100644 --- a/drivers/dma/mmp_tdma.c +++ b/drivers/dma/mmp_tdma.c @@ -475,7 +475,7 @@ static int __devexit mmp_tdma_remove(struct platform_device *pdev) return 0; } -static int __devinit mmp_tdma_chan_init(struct mmp_tdma_device *tdev, +static int mmp_tdma_chan_init(struct mmp_tdma_device *tdev, int idx, int irq, int type) { struct mmp_tdma_chan *tdmac; @@ -515,7 +515,7 @@ static struct of_device_id mmp_tdma_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, mmp_tdma_dt_ids); -static int __devinit mmp_tdma_probe(struct platform_device *pdev) +static int mmp_tdma_probe(struct platform_device *pdev) { enum mmp_tdma_type type; const struct of_device_id *of_id; @@ -609,7 +609,7 @@ static struct platform_driver mmp_tdma_driver = { }, .id_table = mmp_tdma_id_table, .probe = mmp_tdma_probe, - .remove = __devexit_p(mmp_tdma_remove), + .remove = mmp_tdma_remove, }; module_platform_driver(mmp_tdma_driver); diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c index 2ab0a3d0eed..2cd024a91d4 100644 --- a/drivers/dma/mpc512x_dma.c +++ b/drivers/dma/mpc512x_dma.c @@ -641,7 +641,7 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, return &mdesc->desc; } -static int __devinit mpc_dma_probe(struct platform_device *op) +static int mpc_dma_probe(struct platform_device *op) { struct device_node *dn = op->dev.of_node; struct device *dev = &op->dev; @@ -818,7 +818,7 @@ static struct of_device_id mpc_dma_match[] = { static struct platform_driver mpc_dma_driver = { .probe = mpc_dma_probe, - .remove = __devexit_p(mpc_dma_remove), + .remove = mpc_dma_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index e362e2b80ef..d12ad00da4c 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -901,7 +901,7 @@ static void mv_xor_issue_pending(struct dma_chan *chan) */ #define MV_XOR_TEST_SIZE 2000 -static int __devinit mv_xor_memcpy_self_test(struct mv_xor_device *device) +static int mv_xor_memcpy_self_test(struct mv_xor_device *device) { int i; void *src, *dest; @@ -975,7 +975,7 @@ out: } #define MV_XOR_NUM_SRC_TEST 4 /* must be <= 15 */ -static int __devinit +static int mv_xor_xor_self_test(struct mv_xor_device *device) { int i, src_idx; @@ -1100,7 +1100,7 @@ static int __devexit mv_xor_remove(struct platform_device *dev) return 0; } -static int __devinit mv_xor_probe(struct platform_device *pdev) +static int mv_xor_probe(struct platform_device *pdev) { int ret = 0; int irq; @@ -1262,7 +1262,7 @@ mv_xor_conf_mbus_windows(struct mv_xor_shared_private *msp, static struct platform_driver mv_xor_driver = { .probe = mv_xor_probe, - .remove = __devexit_p(mv_xor_remove), + .remove = mv_xor_remove, .driver = { .owner = THIS_MODULE, .name = MV_XOR_NAME, diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index 987ab5cd261..eca1c4ddf03 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -843,7 +843,7 @@ static int pch_dma_resume(struct pci_dev *pdev) } #endif -static int __devinit pch_dma_probe(struct pci_dev *pdev, +static int pch_dma_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct pch_dma *pd; @@ -1022,7 +1022,7 @@ static struct pci_driver pch_dma_driver = { .name = DRV_NAME, .id_table = pch_dma_id_table, .probe = pch_dma_probe, - .remove = __devexit_p(pch_dma_remove), + .remove = pch_dma_remove, #ifdef CONFIG_PM .suspend = pch_dma_suspend, .resume = pch_dma_resume, diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 665668b6f2b..95555f37ea6 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2851,7 +2851,7 @@ static irqreturn_t pl330_irq_handler(int irq, void *data) return IRQ_NONE; } -static int __devinit +static int pl330_probe(struct amba_device *adev, const struct amba_id *id) { struct dma_pl330_platdata *pdat; diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c index f72348d0bc4..b94afc339e7 100644 --- a/drivers/dma/ppc4xx/adma.c +++ b/drivers/dma/ppc4xx/adma.c @@ -4361,7 +4361,7 @@ static void ppc440spe_adma_release_irqs(struct ppc440spe_adma_device *adev, /** * ppc440spe_adma_probe - probe the asynch device */ -static int __devinit ppc440spe_adma_probe(struct platform_device *ofdev) +static int ppc440spe_adma_probe(struct platform_device *ofdev) { struct device_node *np = ofdev->dev.of_node; struct resource res; @@ -4914,7 +4914,7 @@ MODULE_DEVICE_TABLE(of, ppc440spe_adma_of_match); static struct platform_driver ppc440spe_adma_driver = { .probe = ppc440spe_adma_probe, - .remove = __devexit_p(ppc440spe_adma_remove), + .remove = ppc440spe_adma_remove, .driver = { .name = "PPC440SP(E)-ADMA", .owner = THIS_MODULE, diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c index b893159c1ec..2ad628df822 100644 --- a/drivers/dma/sa11x0-dma.c +++ b/drivers/dma/sa11x0-dma.c @@ -826,7 +826,7 @@ static const struct sa11x0_dma_channel_desc chan_desc[] = { CD(Ser4SSPRc, DDAR_RW), }; -static int __devinit sa11x0_dma_init_dmadev(struct dma_device *dmadev, +static int sa11x0_dma_init_dmadev(struct dma_device *dmadev, struct device *dev) { unsigned i; @@ -891,7 +891,7 @@ static void sa11x0_dma_free_channels(struct dma_device *dmadev) } } -static int __devinit sa11x0_dma_probe(struct platform_device *pdev) +static int sa11x0_dma_probe(struct platform_device *pdev) { struct sa11x0_dma_dev *d; struct resource *res; @@ -1072,7 +1072,7 @@ static struct platform_driver sa11x0_dma_driver = { .pm = &sa11x0_dma_pm_ops, }, .probe = sa11x0_dma_probe, - .remove = __devexit_p(sa11x0_dma_remove), + .remove = sa11x0_dma_remove, }; bool sa11x0_dma_filter_fn(struct dma_chan *chan, void *param) diff --git a/drivers/dma/sh/shdma.c b/drivers/dma/sh/shdma.c index f41bcc5267f..8201bb4e0cd 100644 --- a/drivers/dma/sh/shdma.c +++ b/drivers/dma/sh/shdma.c @@ -483,7 +483,7 @@ static struct notifier_block sh_dmae_nmi_notifier __read_mostly = { .priority = 1, }; -static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id, +static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id, int irq, unsigned long flags) { const struct sh_dmae_channel *chan_pdata = &shdev->pdata->channel[id]; @@ -646,7 +646,7 @@ static const struct shdma_ops sh_dmae_shdma_ops = { .get_partial = sh_dmae_get_partial, }; -static int __devinit sh_dmae_probe(struct platform_device *pdev) +static int sh_dmae_probe(struct platform_device *pdev) { struct sh_dmae_pdata *pdata = pdev->dev.platform_data; unsigned long irqflags = IRQF_DISABLED, @@ -926,7 +926,7 @@ static struct platform_driver sh_dmae_driver = { .pm = &sh_dmae_pm, .name = SH_DMAE_DRV_NAME, }, - .remove = __devexit_p(sh_dmae_remove), + .remove = sh_dmae_remove, .shutdown = sh_dmae_shutdown, }; diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c index d451caace80..c3de6edb965 100644 --- a/drivers/dma/sirf-dma.c +++ b/drivers/dma/sirf-dma.c @@ -550,7 +550,7 @@ bool sirfsoc_dma_filter_id(struct dma_chan *chan, void *chan_id) } EXPORT_SYMBOL(sirfsoc_dma_filter_id); -static int __devinit sirfsoc_dma_probe(struct platform_device *op) +static int sirfsoc_dma_probe(struct platform_device *op) { struct device_node *dn = op->dev.of_node; struct device *dev = &op->dev; @@ -673,7 +673,7 @@ static struct of_device_id sirfsoc_dma_match[] = { static struct platform_driver sirfsoc_dma_driver = { .probe = sirfsoc_dma_probe, - .remove = __devexit_p(sirfsoc_dma_remove), + .remove = sirfsoc_dma_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index 528c62dd4b0..efdfffa1334 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -1197,7 +1197,7 @@ static const struct of_device_id tegra_dma_of_match[] __devinitconst = { MODULE_DEVICE_TABLE(of, tegra_dma_of_match); #endif -static int __devinit tegra_dma_probe(struct platform_device *pdev) +static int tegra_dma_probe(struct platform_device *pdev) { struct resource *res; struct tegra_dma *tdma; @@ -1418,7 +1418,7 @@ static struct platform_driver tegra_dmac_driver = { .of_match_table = of_match_ptr(tegra_dma_of_match), }, .probe = tegra_dma_probe, - .remove = __devexit_p(tegra_dma_remove), + .remove = tegra_dma_remove, }; module_platform_driver(tegra_dmac_driver); diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c index 4e0dff59901..98cf51e1544 100644 --- a/drivers/dma/timb_dma.c +++ b/drivers/dma/timb_dma.c @@ -667,7 +667,7 @@ static irqreturn_t td_irq(int irq, void *devid) } -static int __devinit td_probe(struct platform_device *pdev) +static int td_probe(struct platform_device *pdev) { struct timb_dma_platform_data *pdata = pdev->dev.platform_data; struct timb_dma *td; diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 409b92b8d34..bb82d6be793 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -42,10 +42,10 @@ config EDAC_LEGACY_SYSFS config EDAC_DEBUG bool "Debugging" help - This turns on debugging information for the entire EDAC - sub-system. You can insert module with "debug_level=x", current - there're four debug levels (x=0,1,2,3 from low to high). - Usually you should select 'N'. + This turns on debugging information for the entire EDAC subsystem. + You do so by inserting edac_module with "edac_debug_level=x." Valid + levels are 0-4 (from low to high) and by default it is set to 2. + Usually you should select 'N' here. config EDAC_DECODE_MCE tristate "Decode MCEs in human-readable form (only on AMD for now)" diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index cc8e7c78a23..f74a684269f 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -60,8 +60,8 @@ struct scrubrate { { 0x00, 0UL}, /* scrubbing off */ }; -static int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset, - u32 *val, const char *func) +int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset, + u32 *val, const char *func) { int err = 0; @@ -423,7 +423,6 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base, u64 *hole_offset, u64 *hole_size) { struct amd64_pvt *pvt = mci->pvt_info; - u64 base; /* only revE and later have the DRAM Hole Address Register */ if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_E) { @@ -462,10 +461,8 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base, * addresses in the hole so that they start at 0x100000000. */ - base = dhar_base(pvt); - - *hole_base = base; - *hole_size = (0x1ull << 32) - base; + *hole_base = dhar_base(pvt); + *hole_size = (1ULL << 32) - *hole_base; if (boot_cpu_data.x86 > 0xf) *hole_offset = f10_dhar_offset(pvt); @@ -513,15 +510,15 @@ static u64 sys_addr_to_dram_addr(struct mem_ctl_info *mci, u64 sys_addr) { struct amd64_pvt *pvt = mci->pvt_info; u64 dram_base, hole_base, hole_offset, hole_size, dram_addr; - int ret = 0; + int ret; dram_base = get_dram_base(pvt, pvt->mc_node_id); ret = amd64_get_dram_hole_info(mci, &hole_base, &hole_offset, &hole_size); if (!ret) { - if ((sys_addr >= (1ull << 32)) && - (sys_addr < ((1ull << 32) + hole_size))) { + if ((sys_addr >= (1ULL << 32)) && + (sys_addr < ((1ULL << 32) + hole_size))) { /* use DHAR to translate SysAddr to DramAddr */ dram_addr = sys_addr - hole_offset; @@ -712,10 +709,10 @@ static inline u64 input_addr_to_sys_addr(struct mem_ctl_info *mci, /* Map the Error address to a PAGE and PAGE OFFSET. */ static inline void error_address_to_page_and_offset(u64 error_address, - u32 *page, u32 *offset) + struct err_info *err) { - *page = (u32) (error_address >> PAGE_SHIFT); - *offset = ((u32) error_address) & ~PAGE_MASK; + err->page = (u32) (error_address >> PAGE_SHIFT); + err->offset = ((u32) error_address) & ~PAGE_MASK; } /* @@ -1026,59 +1023,44 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) } static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, - u16 syndrome) + struct err_info *err) { - struct mem_ctl_info *src_mci; struct amd64_pvt *pvt = mci->pvt_info; - int channel, csrow; - u32 page, offset; - error_address_to_page_and_offset(sys_addr, &page, &offset); + error_address_to_page_and_offset(sys_addr, err); /* * Find out which node the error address belongs to. This may be * different from the node that detected the error. */ - src_mci = find_mc_by_sys_addr(mci, sys_addr); - if (!src_mci) { + err->src_mci = find_mc_by_sys_addr(mci, sys_addr); + if (!err->src_mci) { amd64_mc_err(mci, "failed to map error addr 0x%lx to a node\n", (unsigned long)sys_addr); - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, - page, offset, syndrome, - -1, -1, -1, - "failed to map error addr to a node", - ""); + err->err_code = ERR_NODE; return; } /* Now map the sys_addr to a CSROW */ - csrow = sys_addr_to_csrow(src_mci, sys_addr); - if (csrow < 0) { - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, - page, offset, syndrome, - -1, -1, -1, - "failed to map error addr to a csrow", - ""); + err->csrow = sys_addr_to_csrow(err->src_mci, sys_addr); + if (err->csrow < 0) { + err->err_code = ERR_CSROW; return; } /* CHIPKILL enabled */ if (pvt->nbcfg & NBCFG_CHIPKILL) { - channel = get_channel_from_ecc_syndrome(mci, syndrome); - if (channel < 0) { + err->channel = get_channel_from_ecc_syndrome(mci, err->syndrome); + if (err->channel < 0) { /* * Syndrome didn't map, so we don't know which of the * 2 DIMMs is in error. So we need to ID 'both' of them * as suspect. */ - amd64_mc_warn(src_mci, "unknown syndrome 0x%04x - " + amd64_mc_warn(err->src_mci, "unknown syndrome 0x%04x - " "possible error reporting race\n", - syndrome); - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, - page, offset, syndrome, - csrow, -1, -1, - "unknown syndrome - possible error reporting race", - ""); + err->syndrome); + err->err_code = ERR_CHANNEL; return; } } else { @@ -1090,13 +1072,8 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, * was obtained from email communication with someone at AMD. * (Wish the email was placed in this comment - norsk) */ - channel = ((sys_addr & BIT(3)) != 0); + err->channel = ((sys_addr & BIT(3)) != 0); } - - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, src_mci, 1, - page, offset, syndrome, - csrow, channel, -1, - "", ""); } static int ddr2_cs_size(unsigned i, bool dct_width) @@ -1482,7 +1459,7 @@ static u64 f1x_swap_interleaved_region(struct amd64_pvt *pvt, u64 sys_addr) /* For a given @dram_range, check if @sys_addr falls within it. */ static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range, - u64 sys_addr, int *nid, int *chan_sel) + u64 sys_addr, int *chan_sel) { int cs_found = -EINVAL; u64 chan_addr; @@ -1555,15 +1532,14 @@ static int f1x_match_to_this_node(struct amd64_pvt *pvt, unsigned range, cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, channel); - if (cs_found >= 0) { - *nid = node_id; + if (cs_found >= 0) *chan_sel = channel; - } + return cs_found; } static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr, - int *node, int *chan_sel) + int *chan_sel) { int cs_found = -EINVAL; unsigned range; @@ -1577,8 +1553,7 @@ static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr, (get_dram_limit(pvt, range) >= sys_addr)) { cs_found = f1x_match_to_this_node(pvt, range, - sys_addr, node, - chan_sel); + sys_addr, chan_sel); if (cs_found >= 0) break; } @@ -1594,22 +1569,15 @@ static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr, * (MCX_ADDR). */ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, - u16 syndrome) + struct err_info *err) { struct amd64_pvt *pvt = mci->pvt_info; - u32 page, offset; - int nid, csrow, chan = 0; - error_address_to_page_and_offset(sys_addr, &page, &offset); + error_address_to_page_and_offset(sys_addr, err); - csrow = f1x_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan); - - if (csrow < 0) { - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, - page, offset, syndrome, - -1, -1, -1, - "failed to map error addr to a csrow", - ""); + err->csrow = f1x_translate_sysaddr_to_cs(pvt, sys_addr, &err->channel); + if (err->csrow < 0) { + err->err_code = ERR_CSROW; return; } @@ -1619,12 +1587,7 @@ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, * this point. */ if (dct_ganging_enabled(pvt)) - chan = get_channel_from_ecc_syndrome(mci, syndrome); - - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, - page, offset, syndrome, - csrow, chan, -1, - "", ""); + err->channel = get_channel_from_ecc_syndrome(mci, err->syndrome); } /* @@ -1633,14 +1596,11 @@ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr, */ static void amd64_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl) { - int dimm, size0, size1, factor = 0; + int dimm, size0, size1; u32 *dcsb = ctrl ? pvt->csels[1].csbases : pvt->csels[0].csbases; u32 dbam = ctrl ? pvt->dbam1 : pvt->dbam0; if (boot_cpu_data.x86 == 0xf) { - if (pvt->dclr0 & WIDTH_128) - factor = 1; - /* K8 families < revF not supported yet */ if (pvt->ext_model < K8_REV_F) return; @@ -1671,8 +1631,8 @@ static void amd64_debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl) DBAM_DIMM(dimm, dbam)); amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n", - dimm * 2, size0 << factor, - dimm * 2 + 1, size1 << factor); + dimm * 2, size0, + dimm * 2 + 1, size1); } } @@ -1893,101 +1853,56 @@ static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome) return map_err_sym_to_channel(err_sym, pvt->ecc_sym_sz); } -/* - * Handle any Correctable Errors (CEs) that have occurred. Check for valid ERROR - * ADDRESS and process. - */ -static void amd64_handle_ce(struct mem_ctl_info *mci, struct mce *m) -{ - struct amd64_pvt *pvt = mci->pvt_info; - u64 sys_addr; - u16 syndrome; - - /* Ensure that the Error Address is VALID */ - if (!(m->status & MCI_STATUS_ADDRV)) { - amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n"); - edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, - 0, 0, 0, - -1, -1, -1, - "HW has no ERROR_ADDRESS available", - ""); - return; - } - - sys_addr = get_error_address(m); - syndrome = extract_syndrome(m->status); - - amd64_mc_err(mci, "CE ERROR_ADDRESS= 0x%llx\n", sys_addr); - - pvt->ops->map_sysaddr_to_csrow(mci, sys_addr, syndrome); -} - -/* Handle any Un-correctable Errors (UEs) */ -static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m) +static void __log_bus_error(struct mem_ctl_info *mci, struct err_info *err, + u8 ecc_type) { - struct mem_ctl_info *log_mci, *src_mci = NULL; - int csrow; - u64 sys_addr; - u32 page, offset; - - log_mci = mci; + enum hw_event_mc_err_type err_type; + const char *string; - if (!(m->status & MCI_STATUS_ADDRV)) { - amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n"); - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, - 0, 0, 0, - -1, -1, -1, - "HW has no ERROR_ADDRESS available", - ""); + if (ecc_type == 2) + err_type = HW_EVENT_ERR_CORRECTED; + else if (ecc_type == 1) + err_type = HW_EVENT_ERR_UNCORRECTED; + else { + WARN(1, "Something is rotten in the state of Denmark.\n"); return; } - sys_addr = get_error_address(m); - error_address_to_page_and_offset(sys_addr, &page, &offset); - - /* - * Find out which node the error address belongs to. This may be - * different from the node that detected the error. - */ - src_mci = find_mc_by_sys_addr(mci, sys_addr); - if (!src_mci) { - amd64_mc_err(mci, "ERROR ADDRESS (0x%lx) NOT mapped to a MC\n", - (unsigned long)sys_addr); - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, - page, offset, 0, - -1, -1, -1, - "ERROR ADDRESS NOT mapped to a MC", - ""); - return; + switch (err->err_code) { + case DECODE_OK: + string = ""; + break; + case ERR_NODE: + string = "Failed to map error addr to a node"; + break; + case ERR_CSROW: + string = "Failed to map error addr to a csrow"; + break; + case ERR_CHANNEL: + string = "unknown syndrome - possible error reporting race"; + break; + default: + string = "WTF error"; + break; } - log_mci = src_mci; - - csrow = sys_addr_to_csrow(log_mci, sys_addr); - if (csrow < 0) { - amd64_mc_err(mci, "ERROR_ADDRESS (0x%lx) NOT mapped to CS\n", - (unsigned long)sys_addr); - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, - page, offset, 0, - -1, -1, -1, - "ERROR ADDRESS NOT mapped to CS", - ""); - } else { - edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, - page, offset, 0, - csrow, -1, -1, - "", ""); - } + edac_mc_handle_error(err_type, mci, 1, + err->page, err->offset, err->syndrome, + err->csrow, err->channel, -1, + string, ""); } static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci, struct mce *m) { - u16 ec = EC(m->status); - u8 xec = XEC(m->status, 0x1f); + struct amd64_pvt *pvt = mci->pvt_info; u8 ecc_type = (m->status >> 45) & 0x3; + u8 xec = XEC(m->status, 0x1f); + u16 ec = EC(m->status); + u64 sys_addr; + struct err_info err; - /* Bail early out if this was an 'observed' error */ + /* Bail out early if this was an 'observed' error */ if (PP(ec) == NBSL_PP_OBS) return; @@ -1995,10 +1910,16 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci, if (xec && xec != F10_NBSL_EXT_ERR_ECC) return; + memset(&err, 0, sizeof(err)); + + sys_addr = get_error_address(m); + if (ecc_type == 2) - amd64_handle_ce(mci, m); - else if (ecc_type == 1) - amd64_handle_ue(mci, m); + err.syndrome = extract_syndrome(m->status); + + pvt->ops->map_sysaddr_to_csrow(mci, sys_addr, &err); + + __log_bus_error(mci, &err, ecc_type); } void amd64_decode_bus_error(int node_id, struct mce *m) @@ -2166,6 +2087,7 @@ static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr) u32 cs_mode, nr_pages; u32 dbam = dct ? pvt->dbam1 : pvt->dbam0; + /* * The math on this doesn't look right on the surface because x/2*4 can * be simplified to x*2 but this expression makes use of the fact that @@ -2173,13 +2095,13 @@ static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr) * number of bits to shift the DBAM register to extract the proper CSROW * field. */ - cs_mode = (dbam >> ((csrow_nr / 2) * 4)) & 0xF; + cs_mode = DBAM_DIMM(csrow_nr / 2, dbam); nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode) << (20 - PAGE_SHIFT); - edac_dbg(0, " (csrow=%d) DBAM map index= %d\n", csrow_nr, cs_mode); - edac_dbg(0, " nr_pages/channel= %u channel-count = %d\n", - nr_pages, pvt->channel_count); + edac_dbg(0, "csrow: %d, channel: %d, DBAM idx: %d\n", + csrow_nr, dct, cs_mode); + edac_dbg(0, "nr_pages/channel: %u\n", nr_pages); return nr_pages; } @@ -2190,15 +2112,14 @@ static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr) */ static int init_csrows(struct mem_ctl_info *mci) { + struct amd64_pvt *pvt = mci->pvt_info; struct csrow_info *csrow; struct dimm_info *dimm; - struct amd64_pvt *pvt = mci->pvt_info; - u64 base, mask; - u32 val; - int i, j, empty = 1; - enum mem_type mtype; enum edac_type edac_mode; + enum mem_type mtype; + int i, j, empty = 1; int nr_pages = 0; + u32 val; amd64_read_pci_cfg(pvt->F3, NBCFG, &val); @@ -2208,29 +2129,35 @@ static int init_csrows(struct mem_ctl_info *mci) pvt->mc_node_id, val, !!(val & NBCFG_CHIPKILL), !!(val & NBCFG_ECC_ENABLE)); + /* + * We iterate over DCT0 here but we look at DCT1 in parallel, if needed. + */ for_each_chip_select(i, 0, pvt) { - csrow = mci->csrows[i]; + bool row_dct0 = !!csrow_enabled(i, 0, pvt); + bool row_dct1 = false; + + if (boot_cpu_data.x86 != 0xf) + row_dct1 = !!csrow_enabled(i, 1, pvt); - if (!csrow_enabled(i, 0, pvt) && !csrow_enabled(i, 1, pvt)) { - edac_dbg(1, "----CSROW %d VALID for MC node %d\n", - i, pvt->mc_node_id); + if (!row_dct0 && !row_dct1) continue; - } + csrow = mci->csrows[i]; empty = 0; - if (csrow_enabled(i, 0, pvt)) + + edac_dbg(1, "MC node: %d, csrow: %d\n", + pvt->mc_node_id, i); + + if (row_dct0) nr_pages = amd64_csrow_nr_pages(pvt, 0, i); - if (csrow_enabled(i, 1, pvt)) - nr_pages += amd64_csrow_nr_pages(pvt, 1, i); - get_cs_base_and_mask(pvt, i, 0, &base, &mask); - /* 8 bytes of resolution */ + /* K8 has only one DCT */ + if (boot_cpu_data.x86 != 0xf && row_dct1) + nr_pages += amd64_csrow_nr_pages(pvt, 1, i); mtype = amd64_determine_memory_type(pvt, i); - edac_dbg(1, " for MC node %d csrow %d:\n", pvt->mc_node_id, i); - edac_dbg(1, " nr_pages: %u\n", - nr_pages * pvt->channel_count); + edac_dbg(1, "Total csrow%d pages: %u\n", i, nr_pages); /* * determine whether CHIPKILL or JUST ECC or NO ECC is operating @@ -2247,6 +2174,7 @@ static int init_csrows(struct mem_ctl_info *mci) dimm->edac_mode = edac_mode; dimm->nr_pages = nr_pages; } + csrow->nr_pages = nr_pages; } return empty; @@ -2591,6 +2519,7 @@ static int amd64_init_one_instance(struct pci_dev *F2) mci->pvt_info = pvt; mci->pdev = &pvt->F2->dev; + mci->csbased = 1; setup_mci_misc_attrs(mci, fam_type); diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 8d4804732ba..e864f407806 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -33,7 +33,7 @@ * detection. The mods to Rev F required more family * information detection. * - * Changes/Fixes by Borislav Petkov <borislav.petkov@amd.com>: + * Changes/Fixes by Borislav Petkov <bp@alien8.de>: * - misc fixes and code cleanups * * This module is based on the following documents @@ -219,7 +219,7 @@ #define DBAM1 0x180 /* Extract the DIMM 'type' on the i'th DIMM from the DBAM reg value passed */ -#define DBAM_DIMM(i, reg) ((((reg) >> (4*i))) & 0xF) +#define DBAM_DIMM(i, reg) ((((reg) >> (4*(i)))) & 0xF) #define DBAM_MAX_VALUE 11 @@ -267,18 +267,20 @@ #define online_spare_bad_dramcs(pvt, c) (((pvt)->online_spare >> (4 + 4 * (c))) & 0x7) #define F10_NB_ARRAY_ADDR 0xB8 -#define F10_NB_ARRAY_DRAM_ECC BIT(31) +#define F10_NB_ARRAY_DRAM BIT(31) /* Bits [2:1] are used to select 16-byte section within a 64-byte cacheline */ -#define SET_NB_ARRAY_ADDRESS(section) (((section) & 0x3) << 1) +#define SET_NB_ARRAY_ADDR(section) (((section) & 0x3) << 1) #define F10_NB_ARRAY_DATA 0xBC -#define SET_NB_DRAM_INJECTION_WRITE(word, bits) \ - (BIT(((word) & 0xF) + 20) | \ - BIT(17) | bits) -#define SET_NB_DRAM_INJECTION_READ(word, bits) \ - (BIT(((word) & 0xF) + 20) | \ - BIT(16) | bits) +#define F10_NB_ARR_ECC_WR_REQ BIT(17) +#define SET_NB_DRAM_INJECTION_WRITE(inj) \ + (BIT(((inj.word) & 0xF) + 20) | \ + F10_NB_ARR_ECC_WR_REQ | inj.bit_map) +#define SET_NB_DRAM_INJECTION_READ(inj) \ + (BIT(((inj.word) & 0xF) + 20) | \ + BIT(16) | inj.bit_map) + #define NBCAP 0xE8 #define NBCAP_CHIPKILL BIT(4) @@ -305,9 +307,9 @@ enum amd_families { /* Error injection control structure */ struct error_injection { - u32 section; - u32 word; - u32 bit_map; + u32 section; + u32 word; + u32 bit_map; }; /* low and high part of PCI config space regs */ @@ -374,6 +376,23 @@ struct amd64_pvt { struct error_injection injection; }; +enum err_codes { + DECODE_OK = 0, + ERR_NODE = -1, + ERR_CSROW = -2, + ERR_CHANNEL = -3, +}; + +struct err_info { + int err_code; + struct mem_ctl_info *src_mci; + int csrow; + int channel; + u16 syndrome; + u32 page; + u32 offset; +}; + static inline u64 get_dram_base(struct amd64_pvt *pvt, unsigned i) { u64 addr = ((u64)pvt->ranges[i].base.lo & 0xffff0000) << 8; @@ -447,7 +466,7 @@ static inline void amd64_remove_sysfs_inject_files(struct mem_ctl_info *mci) struct low_ops { int (*early_channel_count) (struct amd64_pvt *pvt); void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci, u64 sys_addr, - u16 syndrome); + struct err_info *); int (*dbam_to_cs) (struct amd64_pvt *pvt, u8 dct, unsigned cs_mode); int (*read_dct_pci_cfg) (struct amd64_pvt *pvt, int offset, u32 *val, const char *func); @@ -459,6 +478,8 @@ struct amd64_family_type { struct low_ops ops; }; +int __amd64_read_pci_cfg_dword(struct pci_dev *pdev, int offset, + u32 *val, const char *func); int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, int offset, u32 val, const char *func); @@ -475,3 +496,15 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base, u64 *hole_offset, u64 *hole_size); #define to_mci(k) container_of(k, struct mem_ctl_info, dev) + +/* Injection helpers */ +static inline void disable_caches(void *dummy) +{ + write_cr0(read_cr0() | X86_CR0_CD); + wbinvd(); +} + +static inline void enable_caches(void *dummy) +{ + write_cr0(read_cr0() & ~X86_CR0_CD); +} diff --git a/drivers/edac/amd64_edac_inj.c b/drivers/edac/amd64_edac_inj.c index 53d972e00df..8c171fa1cb9 100644 --- a/drivers/edac/amd64_edac_inj.c +++ b/drivers/edac/amd64_edac_inj.c @@ -22,20 +22,19 @@ static ssize_t amd64_inject_section_store(struct device *dev, struct mem_ctl_info *mci = to_mci(dev); struct amd64_pvt *pvt = mci->pvt_info; unsigned long value; - int ret = 0; + int ret; ret = strict_strtoul(data, 10, &value); - if (ret != -EINVAL) { + if (ret < 0) + return ret; - if (value > 3) { - amd64_warn("%s: invalid section 0x%lx\n", __func__, value); - return -EINVAL; - } - - pvt->injection.section = (u32) value; - return count; + if (value > 3) { + amd64_warn("%s: invalid section 0x%lx\n", __func__, value); + return -EINVAL; } - return ret; + + pvt->injection.section = (u32) value; + return count; } static ssize_t amd64_inject_word_show(struct device *dev, @@ -60,20 +59,19 @@ static ssize_t amd64_inject_word_store(struct device *dev, struct mem_ctl_info *mci = to_mci(dev); struct amd64_pvt *pvt = mci->pvt_info; unsigned long value; - int ret = 0; + int ret; ret = strict_strtoul(data, 10, &value); - if (ret != -EINVAL) { + if (ret < 0) + return ret; - if (value > 8) { - amd64_warn("%s: invalid word 0x%lx\n", __func__, value); - return -EINVAL; - } - - pvt->injection.word = (u32) value; - return count; + if (value > 8) { + amd64_warn("%s: invalid word 0x%lx\n", __func__, value); + return -EINVAL; } - return ret; + + pvt->injection.word = (u32) value; + return count; } static ssize_t amd64_inject_ecc_vector_show(struct device *dev, @@ -97,21 +95,19 @@ static ssize_t amd64_inject_ecc_vector_store(struct device *dev, struct mem_ctl_info *mci = to_mci(dev); struct amd64_pvt *pvt = mci->pvt_info; unsigned long value; - int ret = 0; + int ret; ret = strict_strtoul(data, 16, &value); - if (ret != -EINVAL) { + if (ret < 0) + return ret; - if (value & 0xFFFF0000) { - amd64_warn("%s: invalid EccVector: 0x%lx\n", - __func__, value); - return -EINVAL; - } - - pvt->injection.bit_map = (u32) value; - return count; + if (value & 0xFFFF0000) { + amd64_warn("%s: invalid EccVector: 0x%lx\n", __func__, value); + return -EINVAL; } - return ret; + + pvt->injection.bit_map = (u32) value; + return count; } /* @@ -126,28 +122,25 @@ static ssize_t amd64_inject_read_store(struct device *dev, struct amd64_pvt *pvt = mci->pvt_info; unsigned long value; u32 section, word_bits; - int ret = 0; + int ret; ret = strict_strtoul(data, 10, &value); - if (ret != -EINVAL) { + if (ret < 0) + return ret; - /* Form value to choose 16-byte section of cacheline */ - section = F10_NB_ARRAY_DRAM_ECC | - SET_NB_ARRAY_ADDRESS(pvt->injection.section); - amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section); + /* Form value to choose 16-byte section of cacheline */ + section = F10_NB_ARRAY_DRAM | SET_NB_ARRAY_ADDR(pvt->injection.section); - word_bits = SET_NB_DRAM_INJECTION_READ(pvt->injection.word, - pvt->injection.bit_map); + amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section); - /* Issue 'word' and 'bit' along with the READ request */ - amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits); + word_bits = SET_NB_DRAM_INJECTION_READ(pvt->injection); - edac_dbg(0, "section=0x%x word_bits=0x%x\n", - section, word_bits); + /* Issue 'word' and 'bit' along with the READ request */ + amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits); - return count; - } - return ret; + edac_dbg(0, "section=0x%x word_bits=0x%x\n", section, word_bits); + + return count; } /* @@ -160,30 +153,43 @@ static ssize_t amd64_inject_write_store(struct device *dev, { struct mem_ctl_info *mci = to_mci(dev); struct amd64_pvt *pvt = mci->pvt_info; + u32 section, word_bits, tmp; unsigned long value; - u32 section, word_bits; - int ret = 0; + int ret; ret = strict_strtoul(data, 10, &value); - if (ret != -EINVAL) { + if (ret < 0) + return ret; + + /* Form value to choose 16-byte section of cacheline */ + section = F10_NB_ARRAY_DRAM | SET_NB_ARRAY_ADDR(pvt->injection.section); + + amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section); - /* Form value to choose 16-byte section of cacheline */ - section = F10_NB_ARRAY_DRAM_ECC | - SET_NB_ARRAY_ADDRESS(pvt->injection.section); - amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section); + word_bits = SET_NB_DRAM_INJECTION_WRITE(pvt->injection); - word_bits = SET_NB_DRAM_INJECTION_WRITE(pvt->injection.word, - pvt->injection.bit_map); + pr_notice_once("Don't forget to decrease MCE polling interval in\n" + "/sys/bus/machinecheck/devices/machinecheck<CPUNUM>/check_interval\n" + "so that you can get the error report faster.\n"); - /* Issue 'word' and 'bit' along with the READ request */ - amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits); + on_each_cpu(disable_caches, NULL, 1); - edac_dbg(0, "section=0x%x word_bits=0x%x\n", - section, word_bits); + /* Issue 'word' and 'bit' along with the READ request */ + amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits); - return count; + retry: + /* wait until injection happens */ + amd64_read_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, &tmp); + if (tmp & F10_NB_ARR_ECC_WR_REQ) { + cpu_relax(); + goto retry; } - return ret; + + on_each_cpu(enable_caches, NULL, 1); + + edac_dbg(0, "section=0x%x word_bits=0x%x\n", section, word_bits); + + return count; } /* diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 90f0b730e9b..281f566a551 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -416,10 +416,18 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, dimm->cschannel = chn; /* Increment csrow location */ - row++; - if (row == tot_csrows) { - row = 0; + if (layers[0].is_virt_csrow) { chn++; + if (chn == tot_channels) { + chn = 0; + row++; + } + } else { + row++; + if (row == tot_csrows) { + row = 0; + chn++; + } } /* Increment dimm location */ @@ -966,20 +974,22 @@ static void edac_ce_error(struct mem_ctl_info *mci, long grain) { unsigned long remapped_page; + char *msg_aux = ""; + + if (*msg) + msg_aux = " "; if (edac_mc_get_log_ce()) { if (other_detail && *other_detail) edac_mc_printk(mci, KERN_WARNING, - "%d CE %s on %s (%s %s - %s)\n", - error_count, - msg, label, location, - detail, other_detail); + "%d CE %s%son %s (%s %s - %s)\n", + error_count, msg, msg_aux, label, + location, detail, other_detail); else edac_mc_printk(mci, KERN_WARNING, - "%d CE %s on %s (%s %s)\n", - error_count, - msg, label, location, - detail); + "%d CE %s%son %s (%s %s)\n", + error_count, msg, msg_aux, label, + location, detail); } edac_inc_ce_error(mci, enable_per_layer_report, pos, error_count); @@ -1014,27 +1024,31 @@ static void edac_ue_error(struct mem_ctl_info *mci, const char *other_detail, const bool enable_per_layer_report) { + char *msg_aux = ""; + + if (*msg) + msg_aux = " "; + if (edac_mc_get_log_ue()) { if (other_detail && *other_detail) edac_mc_printk(mci, KERN_WARNING, - "%d UE %s on %s (%s %s - %s)\n", - error_count, - msg, label, location, detail, - other_detail); + "%d UE %s%son %s (%s %s - %s)\n", + error_count, msg, msg_aux, label, + location, detail, other_detail); else edac_mc_printk(mci, KERN_WARNING, - "%d UE %s on %s (%s %s)\n", - error_count, - msg, label, location, detail); + "%d UE %s%son %s (%s %s)\n", + error_count, msg, msg_aux, label, + location, detail); } if (edac_mc_get_panic_on_ue()) { if (other_detail && *other_detail) - panic("UE %s on %s (%s%s - %s)\n", - msg, label, location, detail, other_detail); + panic("UE %s%son %s (%s%s - %s)\n", + msg, msg_aux, label, location, detail, other_detail); else - panic("UE %s on %s (%s%s)\n", - msg, label, location, detail); + panic("UE %s%son %s (%s%s)\n", + msg, msg_aux, label, location, detail); } edac_inc_ue_error(mci, enable_per_layer_report, pos, error_count); @@ -1093,10 +1107,6 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, */ for (i = 0; i < mci->n_layers; i++) { if (pos[i] >= (int)mci->layers[i].size) { - if (type == HW_EVENT_ERR_CORRECTED) - p = "CE"; - else - p = "UE"; edac_mc_printk(mci, KERN_ERR, "INTERNAL ERROR: %s value is out of range (%d >= %d)\n", @@ -1128,6 +1138,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, grain = 0; p = label; *p = '\0'; + for (i = 0; i < mci->tot_dimms; i++) { struct dimm_info *dimm = mci->dimms[i]; @@ -1195,6 +1206,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, /* Fill the RAM location data */ p = location; + for (i = 0; i < mci->n_layers; i++) { if (pos[i] < 0) continue; @@ -1207,7 +1219,6 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, *(p - 1) = '\0'; /* Report the error via the trace interface */ - grain_bits = fls_long(grain) + 1; trace_mc_event(type, msg, label, error_count, mci->mc_idx, top_layer, mid_layer, low_layer, diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index ed0bc07b850..de2df92f9c7 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -180,6 +180,9 @@ static ssize_t csrow_size_show(struct device *dev, int i; u32 nr_pages = 0; + if (csrow->mci->csbased) + return sprintf(data, "%u\n", PAGES_TO_MiB(csrow->nr_pages)); + for (i = 0; i < csrow->nr_channels; i++) nr_pages += csrow->channels[i]->dimm->nr_pages; return sprintf(data, "%u\n", PAGES_TO_MiB(nr_pages)); @@ -373,6 +376,7 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci, csrow->dev.bus = &mci->bus; device_initialize(&csrow->dev); csrow->dev.parent = &mci->dev; + csrow->mci = mci; dev_set_name(&csrow->dev, "csrow%d", index); dev_set_drvdata(&csrow->dev, csrow); @@ -777,10 +781,14 @@ static ssize_t mci_size_mb_show(struct device *dev, for (csrow_idx = 0; csrow_idx < mci->nr_csrows; csrow_idx++) { struct csrow_info *csrow = mci->csrows[csrow_idx]; - for (j = 0; j < csrow->nr_channels; j++) { - struct dimm_info *dimm = csrow->channels[j]->dimm; + if (csrow->mci->csbased) { + total_pages += csrow->nr_pages; + } else { + for (j = 0; j < csrow->nr_channels; j++) { + struct dimm_info *dimm = csrow->channels[j]->dimm; - total_pages += dimm->nr_pages; + total_pages += dimm->nr_pages; + } } } @@ -838,14 +846,8 @@ static ssize_t edac_fake_inject_write(struct file *file, return count; } -static int debugfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static const struct file_operations debug_fake_inject_fops = { - .open = debugfs_open, + .open = simple_open, .write = edac_fake_inject_write, .llseek = generic_file_llseek, }; @@ -1124,10 +1126,15 @@ int __init edac_mc_sysfs_init(void) edac_subsys = edac_get_sysfs_subsys(); if (edac_subsys == NULL) { edac_dbg(1, "no edac_subsys\n"); - return -EINVAL; + err = -EINVAL; + goto out; } mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL); + if (!mci_pdev) { + err = -ENOMEM; + goto out_put_sysfs; + } mci_pdev->bus = edac_subsys; mci_pdev->type = &mc_attr_type; @@ -1136,11 +1143,18 @@ int __init edac_mc_sysfs_init(void) err = device_add(mci_pdev); if (err < 0) - return err; + goto out_dev_free; edac_dbg(0, "device %s created\n", dev_name(mci_pdev)); return 0; + + out_dev_free: + kfree(mci_pdev); + out_put_sysfs: + edac_put_sysfs_subsys(); + out: + return err; } void __exit edac_mc_sysfs_exit(void) @@ -1148,4 +1162,5 @@ void __exit edac_mc_sysfs_exit(void) put_device(mci_pdev); device_del(mci_pdev); edac_put_sysfs_subsys(); + kfree(mci_pdev); } diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c index 58a28d838f3..12c951a2c33 100644 --- a/drivers/edac/edac_module.c +++ b/drivers/edac/edac_module.c @@ -18,9 +18,29 @@ #define EDAC_VERSION "Ver: 3.0.0" #ifdef CONFIG_EDAC_DEBUG + +static int edac_set_debug_level(const char *buf, struct kernel_param *kp) +{ + unsigned long val; + int ret; + + ret = kstrtoul(buf, 0, &val); + if (ret) + return ret; + + if (val < 0 || val > 4) + return -EINVAL; + + return param_set_int(buf, kp); +} + /* Values of 0 to 4 will generate output */ int edac_debug_level = 2; EXPORT_SYMBOL_GPL(edac_debug_level); + +module_param_call(edac_debug_level, edac_set_debug_level, param_get_int, + &edac_debug_level, 0644); +MODULE_PARM_DESC(edac_debug_level, "EDAC debug level: [0-4], default: 2"); #endif /* scope is to module level only */ @@ -132,10 +152,3 @@ module_exit(edac_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Doug Thompson www.softwarebitmaker.com, et al"); MODULE_DESCRIPTION("Core library routines for EDAC reporting"); - -/* refer to *_sysfs.c files for parameters that are exported via sysfs */ - -#ifdef CONFIG_EDAC_DEBUG -module_param(edac_debug_level, int, 0644); -MODULE_PARM_DESC(edac_debug_level, "Debug level"); -#endif diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c index ee87ef972ea..dd370f92ace 100644 --- a/drivers/edac/edac_pci.c +++ b/drivers/edac/edac_pci.c @@ -470,7 +470,8 @@ struct edac_pci_ctl_info *edac_pci_create_generic_ctl(struct device *dev, pci->mod_name = mod_name; pci->ctl_name = EDAC_PCI_GENCTL_NAME; - pci->edac_check = edac_pci_generic_check; + if (edac_op_state == EDAC_OPSTATE_POLL) + pci->edac_check = edac_pci_generic_check; pdata->edac_idx = edac_pci_idx++; diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index e164c555a33..dc6e905ee1a 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c @@ -645,20 +645,16 @@ typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev); /* * pci_dev parity list iterator - * Scan the PCI device list for one pass, looking for SERRORs - * Master Parity ERRORS or Parity ERRORs on primary or secondary devices + * + * Scan the PCI device list looking for SERRORs, Master Parity ERRORS or + * Parity ERRORs on primary or secondary devices. */ static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn) { struct pci_dev *dev = NULL; - /* request for kernel access to the next PCI device, if any, - * and while we are looking at it have its reference count - * bumped until we are done with it - */ - while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + for_each_pci_dev(dev) fn(dev); - } } /* diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c index 6c86f6e5455..351945fa2ec 100644 --- a/drivers/edac/edac_stub.c +++ b/drivers/edac/edac_stub.c @@ -5,7 +5,7 @@ * * 2007 (c) MontaVista Software, Inc. * 2010 (c) Advanced Micro Devices Inc. - * Borislav Petkov <borislav.petkov@amd.com> + * Borislav Petkov <bp@alien8.de> * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any diff --git a/drivers/edac/highbank_mc_edac.c b/drivers/edac/highbank_mc_edac.c index c769f477fd2..7ea4cc2e8bd 100644 --- a/drivers/edac/highbank_mc_edac.c +++ b/drivers/edac/highbank_mc_edac.c @@ -113,14 +113,8 @@ static ssize_t highbank_mc_err_inject_write(struct file *file, return count; } -static int debugfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - static const struct file_operations highbank_mc_debug_inject_fops = { - .open = debugfs_open, + .open = simple_open, .write = highbank_mc_err_inject_write, .llseek = generic_file_llseek, }; diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c index a09d0667f72..9d669cd4361 100644 --- a/drivers/edac/i7300_edac.c +++ b/drivers/edac/i7300_edac.c @@ -197,8 +197,8 @@ static const char *ferr_fat_fbd_name[] = { [0] = "Memory Write error on non-redundant retry or " "FBD configuration Write error on retry", }; -#define GET_FBD_FAT_IDX(fbderr) (fbderr & (3 << 28)) -#define FERR_FAT_FBD_ERR_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)) +#define GET_FBD_FAT_IDX(fbderr) (((fbderr) >> 28) & 3) +#define FERR_FAT_FBD_ERR_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 22)) #define FERR_NF_FBD 0xa0 static const char *ferr_nf_fbd_name[] = { @@ -225,7 +225,7 @@ static const char *ferr_nf_fbd_name[] = { [1] = "Aliased Uncorrectable Non-Mirrored Demand Data ECC", [0] = "Uncorrectable Data ECC on Replay", }; -#define GET_FBD_NF_IDX(fbderr) (fbderr & (3 << 28)) +#define GET_FBD_NF_IDX(fbderr) (((fbderr) >> 28) & 3) #define FERR_NF_FBD_ERR_MASK ((1 << 24) | (1 << 23) | (1 << 22) | (1 << 21) |\ (1 << 18) | (1 << 17) | (1 << 16) | (1 << 15) |\ (1 << 14) | (1 << 13) | (1 << 11) | (1 << 10) |\ @@ -464,7 +464,7 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci) errnum = find_first_bit(&errors, ARRAY_SIZE(ferr_nf_fbd_name)); specific = GET_ERR_FROM_TABLE(ferr_nf_fbd_name, errnum); - branch = (GET_FBD_FAT_IDX(error_reg) == 2) ? 1 : 0; + branch = (GET_FBD_NF_IDX(error_reg) == 2) ? 1 : 0; pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, REDMEMA, &syndrome); diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 3672101023b..10c8c00d646 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -816,7 +816,7 @@ static ssize_t i7core_inject_store_##param( \ struct device_attribute *mattr, \ const char *data, size_t count) \ { \ - struct mem_ctl_info *mci = to_mci(dev); \ + struct mem_ctl_info *mci = dev_get_drvdata(dev); \ struct i7core_pvt *pvt; \ long value; \ int rc; \ @@ -845,7 +845,7 @@ static ssize_t i7core_inject_show_##param( \ struct device_attribute *mattr, \ char *data) \ { \ - struct mem_ctl_info *mci = to_mci(dev); \ + struct mem_ctl_info *mci = dev_get_drvdata(dev); \ struct i7core_pvt *pvt; \ \ pvt = mci->pvt_info; \ @@ -1052,7 +1052,7 @@ static ssize_t i7core_show_counter_##param( \ struct device_attribute *mattr, \ char *data) \ { \ - struct mem_ctl_info *mci = to_mci(dev); \ + struct mem_ctl_info *mci = dev_get_drvdata(dev); \ struct i7core_pvt *pvt = mci->pvt_info; \ \ edac_dbg(1, "\n"); \ diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c index 069e26c11c4..a98020409fa 100644 --- a/drivers/edac/i82975x_edac.c +++ b/drivers/edac/i82975x_edac.c @@ -370,10 +370,6 @@ static enum dev_type i82975x_dram_type(void __iomem *mch_window, int rank) static void i82975x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev, void __iomem *mch_window) { - static const char *labels[4] = { - "DIMM A1", "DIMM A2", - "DIMM B1", "DIMM B2" - }; struct csrow_info *csrow; unsigned long last_cumul_size; u8 value; @@ -423,9 +419,10 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci, dimm = mci->csrows[index]->channels[chan]->dimm; dimm->nr_pages = nr_pages / csrow->nr_channels; - strncpy(csrow->channels[chan]->dimm->label, - labels[(index >> 1) + (chan * 2)], - EDAC_MC_LABEL_LEN); + + snprintf(csrow->channels[chan]->dimm->label, EDAC_MC_LABEL_LEN, "DIMM %c%d", + (chan == 0) ? 'A' : 'B', + index); dimm->grain = 1 << 7; /* 128Byte cache-line resolution */ dimm->dtype = i82975x_dram_type(mch_window, index); dimm->mtype = MEM_DDR2; /* I82975x supports only DDR2 */ diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c index d0c372e30de..ad637572d8c 100644 --- a/drivers/edac/mce_amd.c +++ b/drivers/edac/mce_amd.c @@ -64,7 +64,7 @@ EXPORT_SYMBOL_GPL(to_msgs); const char * const ii_msgs[] = { "MEM", "RESV", "IO", "GEN" }; EXPORT_SYMBOL_GPL(ii_msgs); -static const char * const f15h_ic_mce_desc[] = { +static const char * const f15h_mc1_mce_desc[] = { "UC during a demand linefill from L2", "Parity error during data load from IC", "Parity error for IC valid bit", @@ -84,7 +84,7 @@ static const char * const f15h_ic_mce_desc[] = { "fetch address FIFO" }; -static const char * const f15h_cu_mce_desc[] = { +static const char * const f15h_mc2_mce_desc[] = { "Fill ECC error on data fills", /* xec = 0x4 */ "Fill parity error on insn fills", "Prefetcher request FIFO parity error", @@ -101,7 +101,7 @@ static const char * const f15h_cu_mce_desc[] = { "PRB address parity error" }; -static const char * const nb_mce_desc[] = { +static const char * const mc4_mce_desc[] = { "DRAM ECC error detected on the NB", "CRC error detected on HT link", "Link-defined sync error packets detected on HT link", @@ -123,7 +123,7 @@ static const char * const nb_mce_desc[] = { "ECC Error in the Probe Filter directory" }; -static const char * const fr_ex_mce_desc[] = { +static const char * const mc5_mce_desc[] = { "CPU Watchdog timer expire", "Wakeup array dest tag", "AG payload array", @@ -139,7 +139,7 @@ static const char * const fr_ex_mce_desc[] = { "DE error occurred" }; -static bool f12h_dc_mce(u16 ec, u8 xec) +static bool f12h_mc0_mce(u16 ec, u8 xec) { bool ret = false; @@ -157,26 +157,26 @@ static bool f12h_dc_mce(u16 ec, u8 xec) return ret; } -static bool f10h_dc_mce(u16 ec, u8 xec) +static bool f10h_mc0_mce(u16 ec, u8 xec) { if (R4(ec) == R4_GEN && LL(ec) == LL_L1) { pr_cont("during data scrub.\n"); return true; } - return f12h_dc_mce(ec, xec); + return f12h_mc0_mce(ec, xec); } -static bool k8_dc_mce(u16 ec, u8 xec) +static bool k8_mc0_mce(u16 ec, u8 xec) { if (BUS_ERROR(ec)) { pr_cont("during system linefill.\n"); return true; } - return f10h_dc_mce(ec, xec); + return f10h_mc0_mce(ec, xec); } -static bool f14h_dc_mce(u16 ec, u8 xec) +static bool f14h_mc0_mce(u16 ec, u8 xec) { u8 r4 = R4(ec); bool ret = true; @@ -228,7 +228,7 @@ static bool f14h_dc_mce(u16 ec, u8 xec) return ret; } -static bool f15h_dc_mce(u16 ec, u8 xec) +static bool f15h_mc0_mce(u16 ec, u8 xec) { bool ret = true; @@ -275,12 +275,12 @@ static bool f15h_dc_mce(u16 ec, u8 xec) return ret; } -static void amd_decode_dc_mce(struct mce *m) +static void decode_mc0_mce(struct mce *m) { u16 ec = EC(m->status); u8 xec = XEC(m->status, xec_mask); - pr_emerg(HW_ERR "Data Cache Error: "); + pr_emerg(HW_ERR "MC0 Error: "); /* TLB error signatures are the same across families */ if (TLB_ERROR(ec)) { @@ -290,13 +290,13 @@ static void amd_decode_dc_mce(struct mce *m) : (xec ? "multimatch" : "parity"))); return; } - } else if (fam_ops->dc_mce(ec, xec)) + } else if (fam_ops->mc0_mce(ec, xec)) ; else - pr_emerg(HW_ERR "Corrupted DC MCE info?\n"); + pr_emerg(HW_ERR "Corrupted MC0 MCE info?\n"); } -static bool k8_ic_mce(u16 ec, u8 xec) +static bool k8_mc1_mce(u16 ec, u8 xec) { u8 ll = LL(ec); bool ret = true; @@ -330,7 +330,7 @@ static bool k8_ic_mce(u16 ec, u8 xec) return ret; } -static bool f14h_ic_mce(u16 ec, u8 xec) +static bool f14h_mc1_mce(u16 ec, u8 xec) { u8 r4 = R4(ec); bool ret = true; @@ -349,7 +349,7 @@ static bool f14h_ic_mce(u16 ec, u8 xec) return ret; } -static bool f15h_ic_mce(u16 ec, u8 xec) +static bool f15h_mc1_mce(u16 ec, u8 xec) { bool ret = true; @@ -358,19 +358,19 @@ static bool f15h_ic_mce(u16 ec, u8 xec) switch (xec) { case 0x0 ... 0xa: - pr_cont("%s.\n", f15h_ic_mce_desc[xec]); + pr_cont("%s.\n", f15h_mc1_mce_desc[xec]); break; case 0xd: - pr_cont("%s.\n", f15h_ic_mce_desc[xec-2]); + pr_cont("%s.\n", f15h_mc1_mce_desc[xec-2]); break; case 0x10: - pr_cont("%s.\n", f15h_ic_mce_desc[xec-4]); + pr_cont("%s.\n", f15h_mc1_mce_desc[xec-4]); break; case 0x11 ... 0x14: - pr_cont("Decoder %s parity error.\n", f15h_ic_mce_desc[xec-4]); + pr_cont("Decoder %s parity error.\n", f15h_mc1_mce_desc[xec-4]); break; default: @@ -379,12 +379,12 @@ static bool f15h_ic_mce(u16 ec, u8 xec) return ret; } -static void amd_decode_ic_mce(struct mce *m) +static void decode_mc1_mce(struct mce *m) { u16 ec = EC(m->status); u8 xec = XEC(m->status, xec_mask); - pr_emerg(HW_ERR "Instruction Cache Error: "); + pr_emerg(HW_ERR "MC1 Error: "); if (TLB_ERROR(ec)) pr_cont("%s TLB %s.\n", LL_MSG(ec), @@ -393,18 +393,18 @@ static void amd_decode_ic_mce(struct mce *m) bool k8 = (boot_cpu_data.x86 == 0xf && (m->status & BIT_64(58))); pr_cont("during %s.\n", (k8 ? "system linefill" : "NB data read")); - } else if (fam_ops->ic_mce(ec, xec)) + } else if (fam_ops->mc1_mce(ec, xec)) ; else - pr_emerg(HW_ERR "Corrupted IC MCE info?\n"); + pr_emerg(HW_ERR "Corrupted MC1 MCE info?\n"); } -static void amd_decode_bu_mce(struct mce *m) +static void decode_mc2_mce(struct mce *m) { u16 ec = EC(m->status); u8 xec = XEC(m->status, xec_mask); - pr_emerg(HW_ERR "Bus Unit Error"); + pr_emerg(HW_ERR "MC2 Error"); if (xec == 0x1) pr_cont(" in the write data buffers.\n"); @@ -429,24 +429,24 @@ static void amd_decode_bu_mce(struct mce *m) pr_cont(": %s parity/ECC error during data " "access from L2.\n", R4_MSG(ec)); else - goto wrong_bu_mce; + goto wrong_mc2_mce; } else - goto wrong_bu_mce; + goto wrong_mc2_mce; } else - goto wrong_bu_mce; + goto wrong_mc2_mce; return; -wrong_bu_mce: - pr_emerg(HW_ERR "Corrupted BU MCE info?\n"); + wrong_mc2_mce: + pr_emerg(HW_ERR "Corrupted MC2 MCE info?\n"); } -static void amd_decode_cu_mce(struct mce *m) +static void decode_f15_mc2_mce(struct mce *m) { u16 ec = EC(m->status); u8 xec = XEC(m->status, xec_mask); - pr_emerg(HW_ERR "Combined Unit Error: "); + pr_emerg(HW_ERR "MC2 Error: "); if (TLB_ERROR(ec)) { if (xec == 0x0) @@ -454,63 +454,63 @@ static void amd_decode_cu_mce(struct mce *m) else if (xec == 0x1) pr_cont("Poison data provided for TLB fill.\n"); else - goto wrong_cu_mce; + goto wrong_f15_mc2_mce; } else if (BUS_ERROR(ec)) { if (xec > 2) - goto wrong_cu_mce; + goto wrong_f15_mc2_mce; pr_cont("Error during attempted NB data read.\n"); } else if (MEM_ERROR(ec)) { switch (xec) { case 0x4 ... 0xc: - pr_cont("%s.\n", f15h_cu_mce_desc[xec - 0x4]); + pr_cont("%s.\n", f15h_mc2_mce_desc[xec - 0x4]); break; case 0x10 ... 0x14: - pr_cont("%s.\n", f15h_cu_mce_desc[xec - 0x7]); + pr_cont("%s.\n", f15h_mc2_mce_desc[xec - 0x7]); break; default: - goto wrong_cu_mce; + goto wrong_f15_mc2_mce; } } return; -wrong_cu_mce: - pr_emerg(HW_ERR "Corrupted CU MCE info?\n"); + wrong_f15_mc2_mce: + pr_emerg(HW_ERR "Corrupted MC2 MCE info?\n"); } -static void amd_decode_ls_mce(struct mce *m) +static void decode_mc3_mce(struct mce *m) { u16 ec = EC(m->status); u8 xec = XEC(m->status, xec_mask); if (boot_cpu_data.x86 >= 0x14) { - pr_emerg("You shouldn't be seeing an LS MCE on this cpu family," + pr_emerg("You shouldn't be seeing MC3 MCE on this cpu family," " please report on LKML.\n"); return; } - pr_emerg(HW_ERR "Load Store Error"); + pr_emerg(HW_ERR "MC3 Error"); if (xec == 0x0) { u8 r4 = R4(ec); if (!BUS_ERROR(ec) || (r4 != R4_DRD && r4 != R4_DWR)) - goto wrong_ls_mce; + goto wrong_mc3_mce; pr_cont(" during %s.\n", R4_MSG(ec)); } else - goto wrong_ls_mce; + goto wrong_mc3_mce; return; -wrong_ls_mce: - pr_emerg(HW_ERR "Corrupted LS MCE info?\n"); + wrong_mc3_mce: + pr_emerg(HW_ERR "Corrupted MC3 MCE info?\n"); } -void amd_decode_nb_mce(struct mce *m) +static void decode_mc4_mce(struct mce *m) { struct cpuinfo_x86 *c = &boot_cpu_data; int node_id = amd_get_nb_id(m->extcpu); @@ -518,7 +518,7 @@ void amd_decode_nb_mce(struct mce *m) u8 xec = XEC(m->status, 0x1f); u8 offset = 0; - pr_emerg(HW_ERR "Northbridge Error (node %d): ", node_id); + pr_emerg(HW_ERR "MC4 Error (node %d): ", node_id); switch (xec) { case 0x0 ... 0xe: @@ -527,9 +527,9 @@ void amd_decode_nb_mce(struct mce *m) if (xec == 0x0 || xec == 0x8) { /* no ECCs on F11h */ if (c->x86 == 0x11) - goto wrong_nb_mce; + goto wrong_mc4_mce; - pr_cont("%s.\n", nb_mce_desc[xec]); + pr_cont("%s.\n", mc4_mce_desc[xec]); if (nb_bus_decoder) nb_bus_decoder(node_id, m); @@ -543,14 +543,14 @@ void amd_decode_nb_mce(struct mce *m) else if (BUS_ERROR(ec)) pr_cont("DMA Exclusion Vector Table Walk error.\n"); else - goto wrong_nb_mce; + goto wrong_mc4_mce; return; case 0x19: if (boot_cpu_data.x86 == 0x15) pr_cont("Compute Unit Data Error.\n"); else - goto wrong_nb_mce; + goto wrong_mc4_mce; return; case 0x1c ... 0x1f: @@ -558,46 +558,44 @@ void amd_decode_nb_mce(struct mce *m) break; default: - goto wrong_nb_mce; + goto wrong_mc4_mce; } - pr_cont("%s.\n", nb_mce_desc[xec - offset]); + pr_cont("%s.\n", mc4_mce_desc[xec - offset]); return; -wrong_nb_mce: - pr_emerg(HW_ERR "Corrupted NB MCE info?\n"); + wrong_mc4_mce: + pr_emerg(HW_ERR "Corrupted MC4 MCE info?\n"); } -EXPORT_SYMBOL_GPL(amd_decode_nb_mce); -static void amd_decode_fr_mce(struct mce *m) +static void decode_mc5_mce(struct mce *m) { struct cpuinfo_x86 *c = &boot_cpu_data; u8 xec = XEC(m->status, xec_mask); if (c->x86 == 0xf || c->x86 == 0x11) - goto wrong_fr_mce; + goto wrong_mc5_mce; - pr_emerg(HW_ERR "%s Error: ", - (c->x86 == 0x15 ? "Execution Unit" : "FIROB")); + pr_emerg(HW_ERR "MC5 Error: "); if (xec == 0x0 || xec == 0xc) - pr_cont("%s.\n", fr_ex_mce_desc[xec]); + pr_cont("%s.\n", mc5_mce_desc[xec]); else if (xec < 0xd) - pr_cont("%s parity error.\n", fr_ex_mce_desc[xec]); + pr_cont("%s parity error.\n", mc5_mce_desc[xec]); else - goto wrong_fr_mce; + goto wrong_mc5_mce; return; -wrong_fr_mce: - pr_emerg(HW_ERR "Corrupted FR MCE info?\n"); + wrong_mc5_mce: + pr_emerg(HW_ERR "Corrupted MC5 MCE info?\n"); } -static void amd_decode_fp_mce(struct mce *m) +static void decode_mc6_mce(struct mce *m) { u8 xec = XEC(m->status, xec_mask); - pr_emerg(HW_ERR "Floating Point Unit Error: "); + pr_emerg(HW_ERR "MC6 Error: "); switch (xec) { case 0x1: @@ -621,7 +619,7 @@ static void amd_decode_fp_mce(struct mce *m) break; default: - goto wrong_fp_mce; + goto wrong_mc6_mce; break; } @@ -629,8 +627,8 @@ static void amd_decode_fp_mce(struct mce *m) return; -wrong_fp_mce: - pr_emerg(HW_ERR "Corrupted FP MCE info?\n"); + wrong_mc6_mce: + pr_emerg(HW_ERR "Corrupted MC6 MCE info?\n"); } static inline void amd_decode_err_code(u16 ec) @@ -669,74 +667,94 @@ static bool amd_filter_mce(struct mce *m) return false; } +static const char *decode_error_status(struct mce *m) +{ + if (m->status & MCI_STATUS_UC) { + if (m->status & MCI_STATUS_PCC) + return "System Fatal error."; + if (m->mcgstatus & MCG_STATUS_RIPV) + return "Uncorrected, software restartable error."; + return "Uncorrected, software containable error."; + } + + if (m->status & MCI_STATUS_DEFERRED) + return "Deferred error."; + + return "Corrected error, no action required."; +} + int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data) { struct mce *m = (struct mce *)data; - struct cpuinfo_x86 *c = &boot_cpu_data; + struct cpuinfo_x86 *c = &cpu_data(m->extcpu); int ecc; if (amd_filter_mce(m)) return NOTIFY_STOP; - pr_emerg(HW_ERR "CPU:%d\tMC%d_STATUS[%s|%s|%s|%s|%s", - m->extcpu, m->bank, - ((m->status & MCI_STATUS_OVER) ? "Over" : "-"), - ((m->status & MCI_STATUS_UC) ? "UE" : "CE"), - ((m->status & MCI_STATUS_MISCV) ? "MiscV" : "-"), - ((m->status & MCI_STATUS_PCC) ? "PCC" : "-"), - ((m->status & MCI_STATUS_ADDRV) ? "AddrV" : "-")); - - if (c->x86 == 0x15) - pr_cont("|%s|%s", - ((m->status & BIT_64(44)) ? "Deferred" : "-"), - ((m->status & BIT_64(43)) ? "Poison" : "-")); - - /* do the two bits[14:13] together */ - ecc = (m->status >> 45) & 0x3; - if (ecc) - pr_cont("|%sECC", ((ecc == 2) ? "C" : "U")); - - pr_cont("]: 0x%016llx\n", m->status); - - if (m->status & MCI_STATUS_ADDRV) - pr_emerg(HW_ERR "\tMC%d_ADDR: 0x%016llx\n", m->bank, m->addr); - switch (m->bank) { case 0: - amd_decode_dc_mce(m); + decode_mc0_mce(m); break; case 1: - amd_decode_ic_mce(m); + decode_mc1_mce(m); break; case 2: if (c->x86 == 0x15) - amd_decode_cu_mce(m); + decode_f15_mc2_mce(m); else - amd_decode_bu_mce(m); + decode_mc2_mce(m); break; case 3: - amd_decode_ls_mce(m); + decode_mc3_mce(m); break; case 4: - amd_decode_nb_mce(m); + decode_mc4_mce(m); break; case 5: - amd_decode_fr_mce(m); + decode_mc5_mce(m); break; case 6: - amd_decode_fp_mce(m); + decode_mc6_mce(m); break; default: break; } + pr_emerg(HW_ERR "Error Status: %s\n", decode_error_status(m)); + + pr_emerg(HW_ERR "CPU:%d (%x:%x:%x) MC%d_STATUS[%s|%s|%s|%s|%s", + m->extcpu, + c->x86, c->x86_model, c->x86_mask, + m->bank, + ((m->status & MCI_STATUS_OVER) ? "Over" : "-"), + ((m->status & MCI_STATUS_UC) ? "UE" : "CE"), + ((m->status & MCI_STATUS_MISCV) ? "MiscV" : "-"), + ((m->status & MCI_STATUS_PCC) ? "PCC" : "-"), + ((m->status & MCI_STATUS_ADDRV) ? "AddrV" : "-")); + + if (c->x86 == 0x15) + pr_cont("|%s|%s", + ((m->status & MCI_STATUS_DEFERRED) ? "Deferred" : "-"), + ((m->status & MCI_STATUS_POISON) ? "Poison" : "-")); + + /* do the two bits[14:13] together */ + ecc = (m->status >> 45) & 0x3; + if (ecc) + pr_cont("|%sECC", ((ecc == 2) ? "C" : "U")); + + pr_cont("]: 0x%016llx\n", m->status); + + if (m->status & MCI_STATUS_ADDRV) + pr_emerg(HW_ERR "MC%d_ADDR: 0x%016llx\n", m->bank, m->addr); + amd_decode_err_code(m->status & 0xffff); return NOTIFY_STOP; @@ -763,35 +781,35 @@ static int __init mce_amd_init(void) switch (c->x86) { case 0xf: - fam_ops->dc_mce = k8_dc_mce; - fam_ops->ic_mce = k8_ic_mce; + fam_ops->mc0_mce = k8_mc0_mce; + fam_ops->mc1_mce = k8_mc1_mce; break; case 0x10: - fam_ops->dc_mce = f10h_dc_mce; - fam_ops->ic_mce = k8_ic_mce; + fam_ops->mc0_mce = f10h_mc0_mce; + fam_ops->mc1_mce = k8_mc1_mce; break; case 0x11: - fam_ops->dc_mce = k8_dc_mce; - fam_ops->ic_mce = k8_ic_mce; + fam_ops->mc0_mce = k8_mc0_mce; + fam_ops->mc1_mce = k8_mc1_mce; break; case 0x12: - fam_ops->dc_mce = f12h_dc_mce; - fam_ops->ic_mce = k8_ic_mce; + fam_ops->mc0_mce = f12h_mc0_mce; + fam_ops->mc1_mce = k8_mc1_mce; break; case 0x14: nb_err_cpumask = 0x3; - fam_ops->dc_mce = f14h_dc_mce; - fam_ops->ic_mce = f14h_ic_mce; + fam_ops->mc0_mce = f14h_mc0_mce; + fam_ops->mc1_mce = f14h_mc1_mce; break; case 0x15: xec_mask = 0x1f; - fam_ops->dc_mce = f15h_dc_mce; - fam_ops->ic_mce = f15h_ic_mce; + fam_ops->mc0_mce = f15h_mc0_mce; + fam_ops->mc1_mce = f15h_mc1_mce; break; default: diff --git a/drivers/edac/mce_amd.h b/drivers/edac/mce_amd.h index 8c87a5e8705..679679951e2 100644 --- a/drivers/edac/mce_amd.h +++ b/drivers/edac/mce_amd.h @@ -29,10 +29,8 @@ #define R4(x) (((x) >> 4) & 0xf) #define R4_MSG(x) ((R4(x) < 9) ? rrrr_msgs[R4(x)] : "Wrong R4!") -/* - * F3x4C bits (MCi_STATUS' high half) - */ -#define NBSH_ERR_CPU_VAL BIT(24) +#define MCI_STATUS_DEFERRED BIT_64(44) +#define MCI_STATUS_POISON BIT_64(43) enum tt_ids { TT_INSTR = 0, @@ -78,14 +76,13 @@ extern const char * const ii_msgs[]; * per-family decoder ops */ struct amd_decoder_ops { - bool (*dc_mce)(u16, u8); - bool (*ic_mce)(u16, u8); + bool (*mc0_mce)(u16, u8); + bool (*mc1_mce)(u16, u8); }; void amd_report_gart_errors(bool); void amd_register_ecc_decoder(void (*f)(int, struct mce *)); void amd_unregister_ecc_decoder(void (*f)(int, struct mce *)); -void amd_decode_nb_mce(struct mce *); int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data); #endif /* _EDAC_MCE_AMD_H */ diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c index 66b5151c108..2ae78f20cc2 100644 --- a/drivers/edac/mce_amd_inj.c +++ b/drivers/edac/mce_amd_inj.c @@ -6,7 +6,7 @@ * This file may be distributed under the terms of the GNU General Public * License version 2. * - * Copyright (c) 2010: Borislav Petkov <borislav.petkov@amd.com> + * Copyright (c) 2010: Borislav Petkov <bp@alien8.de> * Advanced Micro Devices Inc. */ @@ -168,6 +168,6 @@ module_init(edac_init_mce_inject); module_exit(edac_exit_mce_inject); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Borislav Petkov <borislav.petkov@amd.com>"); +MODULE_AUTHOR("Borislav Petkov <bp@alien8.de>"); MODULE_AUTHOR("AMD Inc."); MODULE_DESCRIPTION("MCE injection facility for testing MCE decoding"); diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index e87196f6d2d..eda2a1aa4ad 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c @@ -91,7 +91,7 @@ static irqreturn_t adc_jack_irq_thread(int irq, void *_data) return IRQ_HANDLED; } -static int __devinit adc_jack_probe(struct platform_device *pdev) +static int adc_jack_probe(struct platform_device *pdev) { struct adc_jack_data *data; struct adc_jack_pdata *pdata = pdev->dev.platform_data; @@ -175,7 +175,7 @@ out: return err; } -static int __devexit adc_jack_remove(struct platform_device *pdev) +static int adc_jack_remove(struct platform_device *pdev) { struct adc_jack_data *data = platform_get_drvdata(pdev); @@ -188,7 +188,7 @@ static int __devexit adc_jack_remove(struct platform_device *pdev) static struct platform_driver adc_jack_driver = { .probe = adc_jack_probe, - .remove = __devexit_p(adc_jack_remove), + .remove = adc_jack_remove, .driver = { .name = "adc-jack", .owner = THIS_MODULE, diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index cdab9e59829..f10f05d4ee9 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -337,7 +337,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) return IRQ_HANDLED; } -static int __devinit arizona_extcon_probe(struct platform_device *pdev) +static int arizona_extcon_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); struct arizona_pdata *pdata; @@ -517,7 +517,7 @@ err: return ret; } -static int __devexit arizona_extcon_remove(struct platform_device *pdev) +static int arizona_extcon_remove(struct platform_device *pdev) { struct arizona_extcon_info *info = platform_get_drvdata(pdev); struct arizona *arizona = info->arizona; @@ -544,7 +544,7 @@ static struct platform_driver arizona_extcon_driver = { .owner = THIS_MODULE, }, .probe = arizona_extcon_probe, - .remove = __devexit_p(arizona_extcon_remove), + .remove = arizona_extcon_remove, }; module_platform_driver(arizona_extcon_driver); diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c index 71d3ab7b3d8..1b14bfcdc17 100644 --- a/drivers/extcon/extcon-gpio.c +++ b/drivers/extcon/extcon-gpio.c @@ -76,7 +76,7 @@ static ssize_t extcon_gpio_print_state(struct extcon_dev *edev, char *buf) return -EINVAL; } -static int __devinit gpio_extcon_probe(struct platform_device *pdev) +static int gpio_extcon_probe(struct platform_device *pdev) { struct gpio_extcon_platform_data *pdata = pdev->dev.platform_data; struct gpio_extcon_data *extcon_data; @@ -137,7 +137,7 @@ err: return ret; } -static int __devexit gpio_extcon_remove(struct platform_device *pdev) +static int gpio_extcon_remove(struct platform_device *pdev) { struct gpio_extcon_data *extcon_data = platform_get_drvdata(pdev); @@ -150,7 +150,7 @@ static int __devexit gpio_extcon_remove(struct platform_device *pdev) static struct platform_driver gpio_extcon_driver = { .probe = gpio_extcon_probe, - .remove = __devexit_p(gpio_extcon_remove), + .remove = gpio_extcon_remove, .driver = { .name = "extcon-gpio", .owner = THIS_MODULE, diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index a17d0d91ada..b656dfa401a 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -648,7 +648,7 @@ out: return ret; } -static int __devinit max77693_muic_probe(struct platform_device *pdev) +static int max77693_muic_probe(struct platform_device *pdev) { struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent); struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev); @@ -774,7 +774,7 @@ err_kfree: return ret; } -static int __devexit max77693_muic_remove(struct platform_device *pdev) +static int max77693_muic_remove(struct platform_device *pdev) { struct max77693_muic_info *info = platform_get_drvdata(pdev); int i; @@ -795,7 +795,7 @@ static struct platform_driver max77693_muic_driver = { .owner = THIS_MODULE, }, .probe = max77693_muic_probe, - .remove = __devexit_p(max77693_muic_remove), + .remove = max77693_muic_remove, }; module_platform_driver(max77693_muic_driver); diff --git a/drivers/extcon/extcon-max8997.c b/drivers/extcon/extcon-max8997.c index 77b66b0cc8f..bad76f51161 100644 --- a/drivers/extcon/extcon-max8997.c +++ b/drivers/extcon/extcon-max8997.c @@ -426,7 +426,7 @@ static void max8997_muic_detect_dev(struct max8997_muic_info *info) max8997_muic_handle_charger_type(info, chg_type); } -static int __devinit max8997_muic_probe(struct platform_device *pdev) +static int max8997_muic_probe(struct platform_device *pdev) { struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent); struct max8997_platform_data *pdata = dev_get_platdata(max8997->dev); @@ -508,7 +508,7 @@ err_kfree: return ret; } -static int __devexit max8997_muic_remove(struct platform_device *pdev) +static int max8997_muic_remove(struct platform_device *pdev) { struct max8997_muic_info *info = platform_get_drvdata(pdev); int i; @@ -531,7 +531,7 @@ static struct platform_driver max8997_muic_driver = { .owner = THIS_MODULE, }, .probe = max8997_muic_probe, - .remove = __devexit_p(max8997_muic_remove), + .remove = max8997_muic_remove, }; module_platform_driver(max8997_muic_driver); diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c index 4ebfb227367..76b2d390f6e 100644 --- a/drivers/firewire/nosy.c +++ b/drivers/firewire/nosy.c @@ -529,7 +529,7 @@ remove_card(struct pci_dev *dev) #define RCV_BUFFER_SIZE (16 * 1024) -static int __devinit +static int add_card(struct pci_dev *dev, const struct pci_device_id *unused) { struct pcilynx *lynx; @@ -683,7 +683,7 @@ fail_disable: return ret; } -static struct pci_device_id pci_table[] __devinitdata = { +static struct pci_device_id pci_table[] = { { .vendor = PCI_VENDOR_ID_TI, .device = PCI_DEVICE_ID_TI_PCILYNX, diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 834e71d2324..f25610bb314 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -3537,7 +3537,7 @@ static inline void pmac_ohci_on(struct pci_dev *dev) {} static inline void pmac_ohci_off(struct pci_dev *dev) {} #endif /* CONFIG_PPC_PMAC */ -static int __devinit pci_probe(struct pci_dev *dev, +static int pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) { struct fw_ohci *ohci; diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index 1162d6b3bf8..bb1b392f5cd 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -1546,6 +1546,8 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev) struct sbp2_logical_unit *lu = sdev->hostdata; sdev->use_10_for_rw = 1; + sdev->no_report_opcodes = 1; + sdev->no_write_same = 1; if (sbp2_param_exclusive_login) sdev->manage_start_stop = 1; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index f11d8e3b404..14a6c2913e4 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -49,6 +49,10 @@ config OF_GPIO def_bool y depends on OF +config GPIO_ACPI + def_bool y + depends on ACPI + config DEBUG_GPIO bool "Debug GPIO calls" depends on DEBUG_KERNEL @@ -86,11 +90,26 @@ config GPIO_DA9052 help Say yes here to enable the GPIO driver for the DA9052 chip. +config GPIO_DA9055 + tristate "Dialog Semiconductor DA9055 GPIO" + depends on MFD_DA9055 + help + Say yes here to enable the GPIO driver for the DA9055 chip. + + The Dialog DA9055 PMIC chip has 3 GPIO pins that can be + be controller by this driver. + + If driver is built as a module it will be called gpio-da9055. + config GPIO_MAX730X tristate comment "Memory mapped GPIO drivers:" +config GPIO_CLPS711X + def_bool y + depends on ARCH_CLPS711X + config GPIO_GENERIC_PLATFORM tristate "Generic memory-mapped GPIO controller support (MMIO platform device)" select GPIO_GENERIC @@ -170,7 +189,7 @@ config GPIO_MXS config GPIO_PL061 bool "PrimeCell PL061 GPIO support" - depends on ARM_AMBA + depends on ARM && ARM_AMBA select GENERIC_IRQ_CHIP help Say yes here to support the PrimeCell PL061 GPIO device @@ -181,6 +200,13 @@ config GPIO_PXA help Say yes here to support the PXA GPIO device +config GPIO_SPEAR_SPICS + bool "ST SPEAr13xx SPI Chip Select as GPIO support" + depends on PLAT_SPEAR + select GENERIC_IRQ_CHIP + help + Say yes here to support ST SPEAr SPI Chip Select as GPIO device + config GPIO_STA2X11 bool "STA2x11/ConneXt GPIO support" depends on MFD_STA2X11 @@ -189,6 +215,14 @@ config GPIO_STA2X11 Say yes here to support the STA2x11/ConneXt GPIO device. The GPIO module has 128 GPIO pins with alternate functions. +config GPIO_TS5500 + tristate "TS-5500 DIO blocks and compatibles" + help + This driver supports Digital I/O exposed by pin blocks found on some + Technologic Systems platforms. It includes, but is not limited to, 3 + blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600 + LCD port. + config GPIO_VT8500 bool "VIA/Wondermedia SoC GPIO Support" depends on ARCH_VT8500 @@ -466,7 +500,7 @@ config GPIO_ADP5588_IRQ config GPIO_ADNP tristate "Avionic Design N-bit GPIO expander" - depends on I2C && OF + depends on I2C && OF_GPIO help This option enables support for N GPIOs found on Avionic Design I2C GPIO expanders. The register space will be extended by powers diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 9aeed670732..76b34468325 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -4,6 +4,7 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o obj-$(CONFIG_OF_GPIO) += gpiolib-of.o +obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o # Device drivers. Generally keep list sorted alphabetically obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o @@ -16,8 +17,10 @@ obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o +obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o +obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o obj-$(CONFIG_GPIO_EM) += gpio-em.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o @@ -57,6 +60,7 @@ obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o obj-$(CONFIG_GPIO_SCH) += gpio-sch.o obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o +obj-$(CONFIG_GPIO_SPEAR_SPICS) += gpio-spear-spics.o obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o obj-$(CONFIG_GPIO_STP_XWAY) += gpio-stp-xway.o @@ -68,6 +72,7 @@ obj-$(CONFIG_ARCH_DAVINCI_TNETV107X) += gpio-tnetv107x.o obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o +obj-$(CONFIG_GPIO_TS5500) += gpio-ts5500.o obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index f05e54258ff..464be961f60 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -105,7 +105,7 @@ static int gen_74x164_direction_output(struct gpio_chip *gc, return 0; } -static int __devinit gen_74x164_probe(struct spi_device *spi) +static int gen_74x164_probe(struct spi_device *spi) { struct gen_74x164_chip *chip; struct gen_74x164_chip_platform_data *pdata; @@ -181,7 +181,7 @@ exit_destroy: return ret; } -static int __devexit gen_74x164_remove(struct spi_device *spi) +static int gen_74x164_remove(struct spi_device *spi) { struct gen_74x164_chip *chip; int ret; @@ -215,7 +215,7 @@ static struct spi_driver gen_74x164_driver = { .of_match_table = of_match_ptr(gen_74x164_dt_ids), }, .probe = gen_74x164_probe, - .remove = __devexit_p(gen_74x164_remove), + .remove = gen_74x164_remove, }; module_spi_driver(gen_74x164_driver); diff --git a/drivers/gpio/gpio-ab8500.c b/drivers/gpio/gpio-ab8500.c index 050c05d9189..983ad425f0a 100644 --- a/drivers/gpio/gpio-ab8500.c +++ b/drivers/gpio/gpio-ab8500.c @@ -402,7 +402,7 @@ static void ab8500_gpio_irq_remove(struct ab8500_gpio *ab8500_gpio) } } -static int __devinit ab8500_gpio_probe(struct platform_device *pdev) +static int ab8500_gpio_probe(struct platform_device *pdev) { struct ab8500_platform_data *ab8500_pdata = dev_get_platdata(pdev->dev.parent); @@ -474,7 +474,7 @@ out_free: * ab8500_gpio_remove() - remove Ab8500-gpio driver * @pdev : Platform device registered */ -static int __devexit ab8500_gpio_remove(struct platform_device *pdev) +static int ab8500_gpio_remove(struct platform_device *pdev) { struct ab8500_gpio *ab8500_gpio = platform_get_drvdata(pdev); int ret; @@ -499,7 +499,7 @@ static struct platform_driver ab8500_gpio_driver = { .owner = THIS_MODULE, }, .probe = ab8500_gpio_probe, - .remove = __devexit_p(ab8500_gpio_remove), + .remove = ab8500_gpio_remove, }; static int __init ab8500_gpio_init(void) diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index 3df88336415..e60567fc507 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -516,7 +516,7 @@ static void adnp_irq_teardown(struct adnp *adnp) irq_domain_remove(adnp->domain); } -static __devinit int adnp_i2c_probe(struct i2c_client *client, +static int adnp_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device_node *np = client->dev.of_node; @@ -563,7 +563,7 @@ teardown: return err; } -static __devexit int adnp_i2c_remove(struct i2c_client *client) +static int adnp_i2c_remove(struct i2c_client *client) { struct adnp *adnp = i2c_get_clientdata(client); struct device_node *np = client->dev.of_node; @@ -582,13 +582,13 @@ static __devexit int adnp_i2c_remove(struct i2c_client *client) return 0; } -static const struct i2c_device_id adnp_i2c_id[] __devinitconst = { +static const struct i2c_device_id adnp_i2c_id[] = { { "gpio-adnp" }, { }, }; MODULE_DEVICE_TABLE(i2c, adnp_i2c_id); -static const struct of_device_id adnp_of_match[] __devinitconst = { +static const struct of_device_id adnp_of_match[] = { { .compatible = "ad,gpio-adnp", }, { }, }; @@ -601,7 +601,7 @@ static struct i2c_driver adnp_i2c_driver = { .of_match_table = of_match_ptr(adnp_of_match), }, .probe = adnp_i2c_probe, - .remove = __devexit_p(adnp_i2c_remove), + .remove = adnp_i2c_remove, .id_table = adnp_i2c_id, }; module_i2c_driver(adnp_i2c_driver); diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c index 2f263cc3256..8afa95f831b 100644 --- a/drivers/gpio/gpio-adp5520.c +++ b/drivers/gpio/gpio-adp5520.c @@ -87,7 +87,7 @@ static int adp5520_gpio_direction_output(struct gpio_chip *chip, return ret; } -static int __devinit adp5520_gpio_probe(struct platform_device *pdev) +static int adp5520_gpio_probe(struct platform_device *pdev) { struct adp5520_gpio_platform_data *pdata = pdev->dev.platform_data; struct adp5520_gpio *dev; @@ -167,7 +167,7 @@ err: return ret; } -static int __devexit adp5520_gpio_remove(struct platform_device *pdev) +static int adp5520_gpio_remove(struct platform_device *pdev) { struct adp5520_gpio *dev; int ret; @@ -190,7 +190,7 @@ static struct platform_driver adp5520_gpio_driver = { .owner = THIS_MODULE, }, .probe = adp5520_gpio_probe, - .remove = __devexit_p(adp5520_gpio_remove), + .remove = adp5520_gpio_remove, }; module_platform_driver(adp5520_gpio_driver); diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index eeedad42913..2ba56987db0 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -346,7 +346,7 @@ static void adp5588_irq_teardown(struct adp5588_gpio *dev) } #endif /* CONFIG_GPIO_ADP5588_IRQ */ -static int __devinit adp5588_gpio_probe(struct i2c_client *client, +static int adp5588_gpio_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct adp5588_gpio_platform_data *pdata = client->dev.platform_data; @@ -438,7 +438,7 @@ err: return ret; } -static int __devexit adp5588_gpio_remove(struct i2c_client *client) +static int adp5588_gpio_remove(struct i2c_client *client) { struct adp5588_gpio_platform_data *pdata = client->dev.platform_data; struct adp5588_gpio *dev = i2c_get_clientdata(client); @@ -479,7 +479,7 @@ static struct i2c_driver adp5588_gpio_driver = { .name = DRV_NAME, }, .probe = adp5588_gpio_probe, - .remove = __devexit_p(adp5588_gpio_remove), + .remove = adp5588_gpio_remove, .id_table = adp5588_gpio_id, }; diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index 8740d2eb06f..0ea853f68db 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -94,7 +94,7 @@ static struct gpio_chip template_chip = { .can_sleep = 1, }; -static int __devinit arizona_gpio_probe(struct platform_device *pdev) +static int arizona_gpio_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); struct arizona_pdata *pdata = arizona->dev->platform_data; @@ -141,7 +141,7 @@ err: return ret; } -static int __devexit arizona_gpio_remove(struct platform_device *pdev) +static int arizona_gpio_remove(struct platform_device *pdev) { struct arizona_gpio *arizona_gpio = platform_get_drvdata(pdev); @@ -152,7 +152,7 @@ static struct platform_driver arizona_gpio_driver = { .driver.name = "arizona-gpio", .driver.owner = THIS_MODULE, .probe = arizona_gpio_probe, - .remove = __devexit_p(arizona_gpio_remove), + .remove = arizona_gpio_remove, }; module_platform_driver(arizona_gpio_driver); diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c new file mode 100644 index 00000000000..ce63b75b13f --- /dev/null +++ b/drivers/gpio/gpio-clps711x.c @@ -0,0 +1,199 @@ +/* + * CLPS711X GPIO driver + * + * Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru> + * + * 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/io.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/platform_device.h> + +#include <mach/hardware.h> + +#define CLPS711X_GPIO_PORTS 5 +#define CLPS711X_GPIO_NAME "gpio-clps711x" + +struct clps711x_gpio { + struct gpio_chip chip[CLPS711X_GPIO_PORTS]; + spinlock_t lock; +}; + +static void __iomem *clps711x_ports[] = { + CLPS711X_VIRT_BASE + PADR, + CLPS711X_VIRT_BASE + PBDR, + CLPS711X_VIRT_BASE + PCDR, + CLPS711X_VIRT_BASE + PDDR, + CLPS711X_VIRT_BASE + PEDR, +}; + +static void __iomem *clps711x_pdirs[] = { + CLPS711X_VIRT_BASE + PADDR, + CLPS711X_VIRT_BASE + PBDDR, + CLPS711X_VIRT_BASE + PCDDR, + CLPS711X_VIRT_BASE + PDDDR, + CLPS711X_VIRT_BASE + PEDDR, +}; + +#define clps711x_port(x) clps711x_ports[x->base / 8] +#define clps711x_pdir(x) clps711x_pdirs[x->base / 8] + +static int gpio_clps711x_get(struct gpio_chip *chip, unsigned offset) +{ + return !!(readb(clps711x_port(chip)) & (1 << offset)); +} + +static void gpio_clps711x_set(struct gpio_chip *chip, unsigned offset, + int value) +{ + int tmp; + unsigned long flags; + struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); + + spin_lock_irqsave(&gpio->lock, flags); + tmp = readb(clps711x_port(chip)) & ~(1 << offset); + if (value) + tmp |= 1 << offset; + writeb(tmp, clps711x_port(chip)); + spin_unlock_irqrestore(&gpio->lock, flags); +} + +static int gpio_clps711x_dir_in(struct gpio_chip *chip, unsigned offset) +{ + int tmp; + unsigned long flags; + struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); + + spin_lock_irqsave(&gpio->lock, flags); + tmp = readb(clps711x_pdir(chip)) & ~(1 << offset); + writeb(tmp, clps711x_pdir(chip)); + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +static int gpio_clps711x_dir_out(struct gpio_chip *chip, unsigned offset, + int value) +{ + int tmp; + unsigned long flags; + struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); + + spin_lock_irqsave(&gpio->lock, flags); + tmp = readb(clps711x_pdir(chip)) | (1 << offset); + writeb(tmp, clps711x_pdir(chip)); + tmp = readb(clps711x_port(chip)) & ~(1 << offset); + if (value) + tmp |= 1 << offset; + writeb(tmp, clps711x_port(chip)); + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +static int gpio_clps711x_dir_in_inv(struct gpio_chip *chip, unsigned offset) +{ + int tmp; + unsigned long flags; + struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); + + spin_lock_irqsave(&gpio->lock, flags); + tmp = readb(clps711x_pdir(chip)) | (1 << offset); + writeb(tmp, clps711x_pdir(chip)); + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +static int gpio_clps711x_dir_out_inv(struct gpio_chip *chip, unsigned offset, + int value) +{ + int tmp; + unsigned long flags; + struct clps711x_gpio *gpio = dev_get_drvdata(chip->dev); + + spin_lock_irqsave(&gpio->lock, flags); + tmp = readb(clps711x_pdir(chip)) & ~(1 << offset); + writeb(tmp, clps711x_pdir(chip)); + tmp = readb(clps711x_port(chip)) & ~(1 << offset); + if (value) + tmp |= 1 << offset; + writeb(tmp, clps711x_port(chip)); + spin_unlock_irqrestore(&gpio->lock, flags); + + return 0; +} + +static struct { + char *name; + int nr; + int inv_dir; +} clps711x_gpio_ports[] __initconst = { + { "PORTA", 8, 0, }, + { "PORTB", 8, 0, }, + { "PORTC", 8, 0, }, + { "PORTD", 8, 1, }, + { "PORTE", 3, 0, }, +}; + +static int __init gpio_clps711x_init(void) +{ + int i; + struct platform_device *pdev; + struct clps711x_gpio *gpio; + + pdev = platform_device_alloc(CLPS711X_GPIO_NAME, 0); + if (!pdev) { + pr_err("Cannot create platform device: %s\n", + CLPS711X_GPIO_NAME); + return -ENOMEM; + } + + platform_device_add(pdev); + + gpio = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_gpio), + GFP_KERNEL); + if (!gpio) { + dev_err(&pdev->dev, "GPIO allocating memory error\n"); + platform_device_unregister(pdev); + return -ENOMEM; + } + + platform_set_drvdata(pdev, gpio); + + spin_lock_init(&gpio->lock); + + for (i = 0; i < CLPS711X_GPIO_PORTS; i++) { + gpio->chip[i].owner = THIS_MODULE; + gpio->chip[i].dev = &pdev->dev; + gpio->chip[i].label = clps711x_gpio_ports[i].name; + gpio->chip[i].base = i * 8; + gpio->chip[i].ngpio = clps711x_gpio_ports[i].nr; + gpio->chip[i].get = gpio_clps711x_get; + gpio->chip[i].set = gpio_clps711x_set; + if (!clps711x_gpio_ports[i].inv_dir) { + gpio->chip[i].direction_input = gpio_clps711x_dir_in; + gpio->chip[i].direction_output = gpio_clps711x_dir_out; + } else { + gpio->chip[i].direction_input = gpio_clps711x_dir_in_inv; + gpio->chip[i].direction_output = gpio_clps711x_dir_out_inv; + } + WARN_ON(gpiochip_add(&gpio->chip[i])); + } + + dev_info(&pdev->dev, "GPIO driver initialized\n"); + + return 0; +} +arch_initcall(gpio_clps711x_init); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); +MODULE_DESCRIPTION("CLPS711X GPIO driver"); diff --git a/drivers/gpio/gpio-cs5535.c b/drivers/gpio/gpio-cs5535.c index 19eda1bbe34..c0a3aeba6f2 100644 --- a/drivers/gpio/gpio-cs5535.c +++ b/drivers/gpio/gpio-cs5535.c @@ -300,7 +300,7 @@ static struct cs5535_gpio_chip cs5535_gpio_chip = { }, }; -static int __devinit cs5535_gpio_probe(struct platform_device *pdev) +static int cs5535_gpio_probe(struct platform_device *pdev) { struct resource *res; int err = -EIO; @@ -355,7 +355,7 @@ done: return err; } -static int __devexit cs5535_gpio_remove(struct platform_device *pdev) +static int cs5535_gpio_remove(struct platform_device *pdev) { struct resource *r; int err; @@ -378,7 +378,7 @@ static struct platform_driver cs5535_gpio_driver = { .owner = THIS_MODULE, }, .probe = cs5535_gpio_probe, - .remove = __devexit_p(cs5535_gpio_remove), + .remove = cs5535_gpio_remove, }; module_platform_driver(cs5535_gpio_driver); diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c index 24b8c297404..a05aacd2777 100644 --- a/drivers/gpio/gpio-da9052.c +++ b/drivers/gpio/gpio-da9052.c @@ -188,7 +188,7 @@ static int da9052_gpio_to_irq(struct gpio_chip *gc, u32 offset) return da9052->irq_base + DA9052_IRQ_GPI0 + offset; } -static struct gpio_chip reference_gp __devinitdata = { +static struct gpio_chip reference_gp = { .label = "da9052-gpio", .owner = THIS_MODULE, .get = da9052_gpio_get, @@ -201,7 +201,7 @@ static struct gpio_chip reference_gp __devinitdata = { .base = -1, }; -static int __devinit da9052_gpio_probe(struct platform_device *pdev) +static int da9052_gpio_probe(struct platform_device *pdev) { struct da9052_gpio *gpio; struct da9052_pdata *pdata; @@ -229,7 +229,7 @@ static int __devinit da9052_gpio_probe(struct platform_device *pdev) return 0; } -static int __devexit da9052_gpio_remove(struct platform_device *pdev) +static int da9052_gpio_remove(struct platform_device *pdev) { struct da9052_gpio *gpio = platform_get_drvdata(pdev); @@ -238,7 +238,7 @@ static int __devexit da9052_gpio_remove(struct platform_device *pdev) static struct platform_driver da9052_gpio_driver = { .probe = da9052_gpio_probe, - .remove = __devexit_p(da9052_gpio_remove), + .remove = da9052_gpio_remove, .driver = { .name = "da9052-gpio", .owner = THIS_MODULE, diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c new file mode 100644 index 00000000000..55d83c7d9c7 --- /dev/null +++ b/drivers/gpio/gpio-da9055.c @@ -0,0 +1,204 @@ +/* + * GPIO Driver for Dialog DA9055 PMICs. + * + * Copyright(c) 2012 Dialog Semiconductor Ltd. + * + * Author: David Dajun Chen <dchen@diasemi.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 the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> + +#include <linux/mfd/da9055/core.h> +#include <linux/mfd/da9055/reg.h> +#include <linux/mfd/da9055/pdata.h> + +#define DA9055_VDD_IO 0x0 +#define DA9055_PUSH_PULL 0x3 +#define DA9055_ACT_LOW 0x0 +#define DA9055_GPI 0x1 +#define DA9055_PORT_MASK 0x3 +#define DA9055_PORT_SHIFT(offset) (4 * (offset % 2)) + +#define DA9055_INPUT DA9055_GPI +#define DA9055_OUTPUT DA9055_PUSH_PULL +#define DA9055_IRQ_GPI0 3 + +struct da9055_gpio { + struct da9055 *da9055; + struct gpio_chip gp; +}; + +static inline struct da9055_gpio *to_da9055_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct da9055_gpio, gp); +} + +static int da9055_gpio_get(struct gpio_chip *gc, unsigned offset) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + int gpio_direction = 0; + int ret; + + /* Get GPIO direction */ + ret = da9055_reg_read(gpio->da9055, (offset >> 1) + DA9055_REG_GPIO0_1); + if (ret < 0) + return ret; + + gpio_direction = ret & (DA9055_PORT_MASK) << DA9055_PORT_SHIFT(offset); + gpio_direction >>= DA9055_PORT_SHIFT(offset); + switch (gpio_direction) { + case DA9055_INPUT: + ret = da9055_reg_read(gpio->da9055, DA9055_REG_STATUS_B); + if (ret < 0) + return ret; + break; + case DA9055_OUTPUT: + ret = da9055_reg_read(gpio->da9055, DA9055_REG_GPIO_MODE0_2); + if (ret < 0) + return ret; + } + + return ret & (1 << offset); + +} + +static void da9055_gpio_set(struct gpio_chip *gc, unsigned offset, int value) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + + da9055_reg_update(gpio->da9055, + DA9055_REG_GPIO_MODE0_2, + 1 << offset, + value << offset); +} + +static int da9055_gpio_direction_input(struct gpio_chip *gc, unsigned offset) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + unsigned char reg_byte; + + reg_byte = (DA9055_ACT_LOW | DA9055_GPI) + << DA9055_PORT_SHIFT(offset); + + return da9055_reg_update(gpio->da9055, (offset >> 1) + + DA9055_REG_GPIO0_1, + DA9055_PORT_MASK << + DA9055_PORT_SHIFT(offset), + reg_byte); +} + +static int da9055_gpio_direction_output(struct gpio_chip *gc, + unsigned offset, int value) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + unsigned char reg_byte; + int ret; + + reg_byte = (DA9055_VDD_IO | DA9055_PUSH_PULL) + << DA9055_PORT_SHIFT(offset); + + ret = da9055_reg_update(gpio->da9055, (offset >> 1) + + DA9055_REG_GPIO0_1, + DA9055_PORT_MASK << + DA9055_PORT_SHIFT(offset), + reg_byte); + if (ret < 0) + return ret; + + da9055_gpio_set(gc, offset, value); + + return 0; +} + +static int da9055_gpio_to_irq(struct gpio_chip *gc, u32 offset) +{ + struct da9055_gpio *gpio = to_da9055_gpio(gc); + struct da9055 *da9055 = gpio->da9055; + + return regmap_irq_get_virq(da9055->irq_data, + DA9055_IRQ_GPI0 + offset); +} + +static struct gpio_chip reference_gp __devinitdata = { + .label = "da9055-gpio", + .owner = THIS_MODULE, + .get = da9055_gpio_get, + .set = da9055_gpio_set, + .direction_input = da9055_gpio_direction_input, + .direction_output = da9055_gpio_direction_output, + .to_irq = da9055_gpio_to_irq, + .can_sleep = 1, + .ngpio = 3, + .base = -1, +}; + +static int __devinit da9055_gpio_probe(struct platform_device *pdev) +{ + struct da9055_gpio *gpio; + struct da9055_pdata *pdata; + int ret; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (gpio == NULL) + return -ENOMEM; + + gpio->da9055 = dev_get_drvdata(pdev->dev.parent); + pdata = gpio->da9055->dev->platform_data; + + gpio->gp = reference_gp; + if (pdata && pdata->gpio_base) + gpio->gp.base = pdata->gpio_base; + + ret = gpiochip_add(&gpio->gp); + if (ret < 0) { + dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret); + goto err_mem; + } + + platform_set_drvdata(pdev, gpio); + + return 0; + +err_mem: + return ret; +} + +static int __devexit da9055_gpio_remove(struct platform_device *pdev) +{ + struct da9055_gpio *gpio = platform_get_drvdata(pdev); + + return gpiochip_remove(&gpio->gp); +} + +static struct platform_driver da9055_gpio_driver = { + .probe = da9055_gpio_probe, + .remove = __devexit_p(da9055_gpio_remove), + .driver = { + .name = "da9055-gpio", + .owner = THIS_MODULE, + }, +}; + +static int __init da9055_gpio_init(void) +{ + return platform_driver_register(&da9055_gpio_driver); +} +subsys_initcall(da9055_gpio_init); + +static void __exit da9055_gpio_exit(void) +{ + platform_driver_unregister(&da9055_gpio_driver); +} +module_exit(da9055_gpio_exit); + +MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); +MODULE_DESCRIPTION("DA9055 GPIO Device Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:da9055-gpio"); diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index efb4c2d0d13..bdc8302e711 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -35,7 +35,6 @@ struct em_gio_priv { void __iomem *base0; void __iomem *base1; - unsigned int irq_base; spinlock_t sense_lock; struct platform_device *pdev; struct gpio_chip gpio_chip; @@ -214,7 +213,7 @@ static int em_gio_direction_output(struct gpio_chip *chip, unsigned offset, static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset) { - return irq_find_mapping(gpio_to_priv(chip)->irq_domain, offset); + return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset); } static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq, @@ -234,41 +233,7 @@ static struct irq_domain_ops em_gio_irq_domain_ops = { .map = em_gio_irq_domain_map, }; -static int __devinit em_gio_irq_domain_init(struct em_gio_priv *p) -{ - struct platform_device *pdev = p->pdev; - struct gpio_em_config *pdata = pdev->dev.platform_data; - - p->irq_base = irq_alloc_descs(pdata->irq_base, 0, - pdata->number_of_pins, numa_node_id()); - if (p->irq_base < 0) { - dev_err(&pdev->dev, "cannot get irq_desc\n"); - return p->irq_base; - } - pr_debug("gio: hw base = %d, nr = %d, sw base = %d\n", - pdata->gpio_base, pdata->number_of_pins, p->irq_base); - - p->irq_domain = irq_domain_add_legacy(pdev->dev.of_node, - pdata->number_of_pins, - p->irq_base, 0, - &em_gio_irq_domain_ops, p); - if (!p->irq_domain) { - irq_free_descs(p->irq_base, pdata->number_of_pins); - return -ENXIO; - } - - return 0; -} - -static void em_gio_irq_domain_cleanup(struct em_gio_priv *p) -{ - struct gpio_em_config *pdata = p->pdev->dev.platform_data; - - irq_free_descs(p->irq_base, pdata->number_of_pins); - /* FIXME: irq domain wants to be freed! */ -} - -static int __devinit em_gio_probe(struct platform_device *pdev) +static int em_gio_probe(struct platform_device *pdev) { struct gpio_em_config *pdata = pdev->dev.platform_data; struct em_gio_priv *p; @@ -334,8 +299,11 @@ static int __devinit em_gio_probe(struct platform_device *pdev) irq_chip->irq_set_type = em_gio_irq_set_type; irq_chip->flags = IRQCHIP_SKIP_SET_WAKE; - ret = em_gio_irq_domain_init(p); - if (ret) { + p->irq_domain = irq_domain_add_linear(pdev->dev.of_node, + pdata->number_of_pins, + &em_gio_irq_domain_ops, p); + if (!p->irq_domain) { + ret = -ENXIO; dev_err(&pdev->dev, "cannot initialize irq domain\n"); goto err3; } @@ -364,7 +332,7 @@ err6: err5: free_irq(irq[0]->start, pdev); err4: - em_gio_irq_domain_cleanup(p); + irq_domain_remove(p->irq_domain); err3: iounmap(p->base1); err2: @@ -375,7 +343,7 @@ err0: return ret; } -static int __devexit em_gio_remove(struct platform_device *pdev) +static int em_gio_remove(struct platform_device *pdev) { struct em_gio_priv *p = platform_get_drvdata(pdev); struct resource *irq[2]; @@ -390,7 +358,7 @@ static int __devexit em_gio_remove(struct platform_device *pdev) free_irq(irq[1]->start, pdev); free_irq(irq[0]->start, pdev); - em_gio_irq_domain_cleanup(p); + irq_domain_remove(p->irq_domain); iounmap(p->base1); iounmap(p->base0); kfree(p); @@ -399,7 +367,7 @@ static int __devexit em_gio_remove(struct platform_device *pdev) static struct platform_driver em_gio_device_driver = { .probe = em_gio_probe, - .remove = __devexit_p(em_gio_remove), + .remove = em_gio_remove, .driver = { .name = "em_gio", } diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 9fe5b8fe9be..56b98eebe1f 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -340,7 +340,7 @@ static int ep93xx_gpio_add_bank(struct bgpio_chip *bgc, struct device *dev, return gpiochip_add(&bgc->gc); } -static int __devinit ep93xx_gpio_probe(struct platform_device *pdev) +static int ep93xx_gpio_probe(struct platform_device *pdev) { struct ep93xx_gpio *ep93xx_gpio; struct resource *res; diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index 82e2e4fe599..05fcc0f247c 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -444,7 +444,7 @@ static void __iomem *bgpio_map(struct platform_device *pdev, return ret; } -static int __devinit bgpio_pdev_probe(struct platform_device *pdev) +static int bgpio_pdev_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *r; @@ -507,7 +507,7 @@ static int __devinit bgpio_pdev_probe(struct platform_device *pdev) return gpiochip_add(&bgc->gc); } -static int __devexit bgpio_pdev_remove(struct platform_device *pdev) +static int bgpio_pdev_remove(struct platform_device *pdev) { struct bgpio_chip *bgc = platform_get_drvdata(pdev); @@ -527,7 +527,7 @@ static struct platform_driver bgpio_driver = { }, .id_table = bgpio_id_table, .probe = bgpio_pdev_probe, - .remove = __devexit_p(bgpio_pdev_remove), + .remove = bgpio_pdev_remove, }; module_platform_driver(bgpio_driver); diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index d4d61796669..6cc87ac8e01 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -238,7 +238,7 @@ static void ichx_gpio_set(struct gpio_chip *chip, unsigned nr, int val) ichx_write_bit(GPIO_LVL, nr, val, 0); } -static void __devinit ichx_gpiolib_setup(struct gpio_chip *chip) +static void ichx_gpiolib_setup(struct gpio_chip *chip) { chip->owner = THIS_MODULE; chip->label = DRV_NAME; @@ -313,7 +313,7 @@ static struct ichx_desc intel5_desc = { .ngpio = 76, }; -static int __devinit ichx_gpio_request_regions(struct resource *res_base, +static int ichx_gpio_request_regions(struct resource *res_base, const char *name, u8 use_gpio) { int i; @@ -353,7 +353,7 @@ static void ichx_gpio_release_regions(struct resource *res_base, u8 use_gpio) } } -static int __devinit ichx_gpio_probe(struct platform_device *pdev) +static int ichx_gpio_probe(struct platform_device *pdev) { struct resource *res_base, *res_pm; int err; @@ -442,7 +442,7 @@ add_err: return err; } -static int __devexit ichx_gpio_remove(struct platform_device *pdev) +static int ichx_gpio_remove(struct platform_device *pdev) { int err; @@ -467,7 +467,7 @@ static struct platform_driver ichx_gpio_driver = { .name = DRV_NAME, }, .probe = ichx_gpio_probe, - .remove = __devexit_p(ichx_gpio_remove), + .remove = ichx_gpio_remove, }; module_platform_driver(ichx_gpio_driver); diff --git a/drivers/gpio/gpio-janz-ttl.c b/drivers/gpio/gpio-janz-ttl.c index f2f000dd70b..7d0a04169a3 100644 --- a/drivers/gpio/gpio-janz-ttl.c +++ b/drivers/gpio/gpio-janz-ttl.c @@ -108,13 +108,13 @@ static void ttl_set_value(struct gpio_chip *gpio, unsigned offset, int value) spin_unlock(&mod->lock); } -static void __devinit ttl_write_reg(struct ttl_module *mod, u8 reg, u16 val) +static void ttl_write_reg(struct ttl_module *mod, u8 reg, u16 val) { iowrite16be(reg, &mod->regs->control); iowrite16be(val, &mod->regs->control); } -static void __devinit ttl_setup_device(struct ttl_module *mod) +static void ttl_setup_device(struct ttl_module *mod) { /* reset the device to a known state */ iowrite16be(0x0000, &mod->regs->control); @@ -140,7 +140,7 @@ static void __devinit ttl_setup_device(struct ttl_module *mod) ttl_write_reg(mod, MASTER_CONF_CTL, CONF_PAE | CONF_PBE | CONF_PCE); } -static int __devinit ttl_probe(struct platform_device *pdev) +static int ttl_probe(struct platform_device *pdev) { struct janz_platform_data *pdata; struct device *dev = &pdev->dev; @@ -211,7 +211,7 @@ out_return: return ret; } -static int __devexit ttl_remove(struct platform_device *pdev) +static int ttl_remove(struct platform_device *pdev) { struct ttl_module *mod = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; @@ -234,7 +234,7 @@ static struct platform_driver ttl_driver = { .owner = THIS_MODULE, }, .probe = ttl_probe, - .remove = __devexit_p(ttl_remove), + .remove = ttl_remove, }; module_platform_driver(ttl_driver); diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/gpio-langwell.c index 202a99207b7..e77b2b3e94a 100644 --- a/drivers/gpio/gpio-langwell.c +++ b/drivers/gpio/gpio-langwell.c @@ -332,7 +332,7 @@ static const struct dev_pm_ops lnw_gpio_pm_ops = { .runtime_idle = lnw_gpio_runtime_idle, }; -static int __devinit lnw_gpio_probe(struct pci_dev *pdev, +static int lnw_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) { void *base; @@ -435,7 +435,7 @@ static struct pci_driver lnw_gpio_driver = { }; -static int __devinit wp_gpio_probe(struct platform_device *pdev) +static int wp_gpio_probe(struct platform_device *pdev) { struct lnw_gpio *lnw; struct gpio_chip *gc; @@ -484,7 +484,7 @@ err_kmalloc: return retval; } -static int __devexit wp_gpio_remove(struct platform_device *pdev) +static int wp_gpio_remove(struct platform_device *pdev) { struct lnw_gpio *lnw = platform_get_drvdata(pdev); int err; @@ -499,7 +499,7 @@ static int __devexit wp_gpio_remove(struct platform_device *pdev) static struct platform_driver wp_gpio_driver = { .probe = wp_gpio_probe, - .remove = __devexit_p(wp_gpio_remove), + .remove = wp_gpio_remove, .driver = { .name = "wp_gpio", .owner = THIS_MODULE, diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index 3644e0dcb3d..36d7dee07b2 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -542,7 +542,7 @@ static int lpc32xx_of_xlate(struct gpio_chip *gc, return gpiospec->args[1]; } -static int __devinit lpc32xx_gpio_probe(struct platform_device *pdev) +static int lpc32xx_gpio_probe(struct platform_device *pdev) { int i; @@ -559,7 +559,7 @@ static int __devinit lpc32xx_gpio_probe(struct platform_device *pdev) } #ifdef CONFIG_OF -static struct of_device_id lpc32xx_gpio_of_match[] __devinitdata = { +static struct of_device_id lpc32xx_gpio_of_match[] = { { .compatible = "nxp,lpc3220-gpio", }, { }, }; diff --git a/drivers/gpio/gpio-max7300.c b/drivers/gpio/gpio-max7300.c index a5ca0ab1b37..4b6b9a04e32 100644 --- a/drivers/gpio/gpio-max7300.c +++ b/drivers/gpio/gpio-max7300.c @@ -31,7 +31,7 @@ static int max7300_i2c_read(struct device *dev, unsigned int reg) return i2c_smbus_read_byte_data(client, reg); } -static int __devinit max7300_probe(struct i2c_client *client, +static int max7300_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct max7301 *ts; @@ -55,7 +55,7 @@ static int __devinit max7300_probe(struct i2c_client *client, return ret; } -static int __devexit max7300_remove(struct i2c_client *client) +static int max7300_remove(struct i2c_client *client) { return __max730x_remove(&client->dev); } @@ -72,7 +72,7 @@ static struct i2c_driver max7300_driver = { .owner = THIS_MODULE, }, .probe = max7300_probe, - .remove = __devexit_p(max7300_remove), + .remove = max7300_remove, .id_table = max7300_id, }; diff --git a/drivers/gpio/gpio-max7301.c b/drivers/gpio/gpio-max7301.c index 741acfcbe76..c6c535c1310 100644 --- a/drivers/gpio/gpio-max7301.c +++ b/drivers/gpio/gpio-max7301.c @@ -50,7 +50,7 @@ static int max7301_spi_read(struct device *dev, unsigned int reg) return word & 0xff; } -static int __devinit max7301_probe(struct spi_device *spi) +static int max7301_probe(struct spi_device *spi) { struct max7301 *ts; int ret; @@ -75,7 +75,7 @@ static int __devinit max7301_probe(struct spi_device *spi) return ret; } -static int __devexit max7301_remove(struct spi_device *spi) +static int max7301_remove(struct spi_device *spi) { return __max730x_remove(&spi->dev); } @@ -92,7 +92,7 @@ static struct spi_driver max7301_driver = { .owner = THIS_MODULE, }, .probe = max7301_probe, - .remove = __devexit_p(max7301_remove), + .remove = max7301_remove, .id_table = max7301_id, }; diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c index 05e2dac60b3..00092342b84 100644 --- a/drivers/gpio/gpio-max730x.c +++ b/drivers/gpio/gpio-max730x.c @@ -160,17 +160,13 @@ static void max7301_set(struct gpio_chip *chip, unsigned offset, int value) mutex_unlock(&ts->lock); } -int __devinit __max730x_probe(struct max7301 *ts) +int __max730x_probe(struct max7301 *ts) { struct device *dev = ts->dev; struct max7301_platform_data *pdata; int i, ret; pdata = dev->platform_data; - if (!pdata || !pdata->base) { - dev_err(dev, "incorrect or missing platform data\n"); - return -EINVAL; - } mutex_init(&ts->lock); dev_set_drvdata(dev, ts); @@ -178,7 +174,12 @@ int __devinit __max730x_probe(struct max7301 *ts) /* Power up the chip and disable IRQ output */ ts->write(dev, 0x04, 0x01); - ts->input_pullup_active = pdata->input_pullup_active; + if (pdata) { + ts->input_pullup_active = pdata->input_pullup_active; + ts->chip.base = pdata->base; + } else { + ts->chip.base = -1; + } ts->chip.label = dev->driver->name; ts->chip.direction_input = max7301_direction_input; @@ -186,7 +187,6 @@ int __devinit __max730x_probe(struct max7301 *ts) ts->chip.direction_output = max7301_direction_output; ts->chip.set = max7301_set; - ts->chip.base = pdata->base; ts->chip.ngpio = PIN_NUMBER; ts->chip.can_sleep = 1; ts->chip.dev = dev; @@ -226,7 +226,7 @@ exit_destroy: } EXPORT_SYMBOL_GPL(__max730x_probe); -int __devexit __max730x_remove(struct device *dev) +int __max730x_remove(struct device *dev) { struct max7301 *ts = dev_get_drvdata(dev); int ret; diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 9504120812a..1e0467ce4c3 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -526,7 +526,7 @@ static void max732x_irq_teardown(struct max732x_chip *chip) } #endif -static int __devinit max732x_setup_gpio(struct max732x_chip *chip, +static int max732x_setup_gpio(struct max732x_chip *chip, const struct i2c_device_id *id, unsigned gpio_start) { @@ -574,7 +574,7 @@ static int __devinit max732x_setup_gpio(struct max732x_chip *chip, return port; } -static int __devinit max732x_probe(struct i2c_client *client, +static int max732x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct max732x_platform_data *pdata; @@ -651,7 +651,7 @@ out_failed: return ret; } -static int __devexit max732x_remove(struct i2c_client *client) +static int max732x_remove(struct i2c_client *client) { struct max732x_platform_data *pdata = client->dev.platform_data; struct max732x_chip *chip = i2c_get_clientdata(client); @@ -690,7 +690,7 @@ static struct i2c_driver max732x_driver = { .owner = THIS_MODULE, }, .probe = max732x_probe, - .remove = __devexit_p(max732x_remove), + .remove = max732x_remove, .id_table = max732x_id, }; diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index 2de57ce5feb..6a8fdc26ae6 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/gpio-mc33880.c @@ -80,7 +80,7 @@ static void mc33880_set(struct gpio_chip *chip, unsigned offset, int value) mutex_unlock(&mc->lock); } -static int __devinit mc33880_probe(struct spi_device *spi) +static int mc33880_probe(struct spi_device *spi) { struct mc33880 *mc; struct mc33880_platform_data *pdata; @@ -147,7 +147,7 @@ exit_destroy: return ret; } -static int __devexit mc33880_remove(struct spi_device *spi) +static int mc33880_remove(struct spi_device *spi) { struct mc33880 *mc; int ret; @@ -175,7 +175,7 @@ static struct spi_driver mc33880_driver = { .owner = THIS_MODULE, }, .probe = mc33880_probe, - .remove = __devexit_p(mc33880_remove), + .remove = mc33880_remove, }; static int __init mc33880_init(void) diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 0f425189de1..3cea0ea79e8 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -77,7 +77,7 @@ struct mcp23s08_driver_data { /*----------------------------------------------------------------------*/ -#ifdef CONFIG_I2C +#if IS_ENABLED(CONFIG_I2C) static int mcp23008_read(struct mcp23s08 *mcp, unsigned reg) { @@ -399,7 +399,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, break; #endif /* CONFIG_SPI_MASTER */ -#ifdef CONFIG_I2C +#if IS_ENABLED(CONFIG_I2C) case MCP_TYPE_008: mcp->ops = &mcp23008_ops; mcp->chip.ngpio = 8; @@ -473,9 +473,9 @@ fail: /*----------------------------------------------------------------------*/ -#ifdef CONFIG_I2C +#if IS_ENABLED(CONFIG_I2C) -static int __devinit mcp230xx_probe(struct i2c_client *client, +static int mcp230xx_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct mcp23s08_platform_data *pdata; @@ -508,7 +508,7 @@ fail: return status; } -static int __devexit mcp230xx_remove(struct i2c_client *client) +static int mcp230xx_remove(struct i2c_client *client) { struct mcp23s08 *mcp = i2c_get_clientdata(client); int status; @@ -533,7 +533,7 @@ static struct i2c_driver mcp230xx_driver = { .owner = THIS_MODULE, }, .probe = mcp230xx_probe, - .remove = __devexit_p(mcp230xx_remove), + .remove = mcp230xx_remove, .id_table = mcp230xx_id, }; diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index 6a29ee1847b..b73366523fa 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -385,7 +385,7 @@ static irqreturn_t ioh_gpio_handler(int irq, void *dev_id) return ret; } -static __devinit void ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip, +static void ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip, unsigned int irq_start, unsigned int num) { struct irq_chip_generic *gc; @@ -406,7 +406,7 @@ static __devinit void ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip, IRQ_NOREQUEST | IRQ_NOPROBE, 0); } -static int __devinit ioh_gpio_probe(struct pci_dev *pdev, +static int ioh_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int ret; @@ -517,7 +517,7 @@ err_pci_enable: return ret; } -static void __devexit ioh_gpio_remove(struct pci_dev *pdev) +static void ioh_gpio_remove(struct pci_dev *pdev) { int err; int i; @@ -606,7 +606,7 @@ static struct pci_driver ioh_gpio_driver = { .name = "ml_ioh_gpio", .id_table = ioh_gpio_pcidev_id, .probe = ioh_gpio_probe, - .remove = __devexit_p(ioh_gpio_remove), + .remove = ioh_gpio_remove, .suspend = ioh_gpio_suspend, .resume = ioh_gpio_resume }; diff --git a/drivers/gpio/gpio-mpc5200.c b/drivers/gpio/gpio-mpc5200.c index 2c7cef367fc..42647f26c9e 100644 --- a/drivers/gpio/gpio-mpc5200.c +++ b/drivers/gpio/gpio-mpc5200.c @@ -148,7 +148,7 @@ mpc52xx_wkup_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) return 0; } -static int __devinit mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev) +static int mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev) { struct mpc52xx_gpiochip *chip; struct mpc52xx_gpio_wkup __iomem *regs; @@ -308,7 +308,7 @@ mpc52xx_simple_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) return 0; } -static int __devinit mpc52xx_simple_gpiochip_probe(struct platform_device *ofdev) +static int mpc52xx_simple_gpiochip_probe(struct platform_device *ofdev) { struct mpc52xx_gpiochip *chip; struct gpio_chip *gc; diff --git a/drivers/gpio/gpio-msic.c b/drivers/gpio/gpio-msic.c index b3898628586..27ea7b9257f 100644 --- a/drivers/gpio/gpio-msic.c +++ b/drivers/gpio/gpio-msic.c @@ -256,7 +256,7 @@ static void msic_gpio_irq_handler(unsigned irq, struct irq_desc *desc) chip->irq_eoi(data); } -static int __devinit platform_msic_gpio_probe(struct platform_device *pdev) +static int platform_msic_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct intel_msic_gpio_pdata *pdata = dev->platform_data; diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c index 38305beb437..55a7e7769af 100644 --- a/drivers/gpio/gpio-msm-v2.c +++ b/drivers/gpio/gpio-msm-v2.c @@ -352,7 +352,7 @@ static struct irq_chip msm_gpio_irq_chip = { .irq_set_wake = msm_gpio_irq_set_wake, }; -static int __devinit msm_gpio_probe(struct platform_device *dev) +static int msm_gpio_probe(struct platform_device *dev) { int i, irq, ret; @@ -376,7 +376,7 @@ static int __devinit msm_gpio_probe(struct platform_device *dev) return 0; } -static int __devexit msm_gpio_remove(struct platform_device *dev) +static int msm_gpio_remove(struct platform_device *dev) { int ret = gpiochip_remove(&msm_gpio.gpio_chip); @@ -390,7 +390,7 @@ static int __devexit msm_gpio_remove(struct platform_device *dev) static struct platform_driver msm_gpio_driver = { .probe = msm_gpio_probe, - .remove = __devexit_p(msm_gpio_remove), + .remove = msm_gpio_remove, .driver = { .name = "msmgpio", .owner = THIS_MODULE, diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index cf7afb9eb61..d767b534c4a 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -92,6 +92,11 @@ static inline void __iomem *mvebu_gpioreg_out(struct mvebu_gpio_chip *mvchip) return mvchip->membase + GPIO_OUT_OFF; } +static inline void __iomem *mvebu_gpioreg_blink(struct mvebu_gpio_chip *mvchip) +{ + return mvchip->membase + GPIO_BLINK_EN_OFF; +} + static inline void __iomem *mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip) { return mvchip->membase + GPIO_IO_CONF_OFF; @@ -163,12 +168,12 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip) * Functions implementing the gpio_chip methods */ -int mvebu_gpio_request(struct gpio_chip *chip, unsigned pin) +static int mvebu_gpio_request(struct gpio_chip *chip, unsigned pin) { return pinctrl_request_gpio(chip->base + pin); } -void mvebu_gpio_free(struct gpio_chip *chip, unsigned pin) +static void mvebu_gpio_free(struct gpio_chip *chip, unsigned pin) { pinctrl_free_gpio(chip->base + pin); } @@ -206,6 +211,23 @@ static int mvebu_gpio_get(struct gpio_chip *chip, unsigned pin) return (u >> pin) & 1; } +static void mvebu_gpio_blink(struct gpio_chip *chip, unsigned pin, int value) +{ + struct mvebu_gpio_chip *mvchip = + container_of(chip, struct mvebu_gpio_chip, chip); + unsigned long flags; + u32 u; + + spin_lock_irqsave(&mvchip->lock, flags); + u = readl_relaxed(mvebu_gpioreg_blink(mvchip)); + if (value) + u |= 1 << pin; + else + u &= ~(1 << pin); + writel_relaxed(u, mvebu_gpioreg_blink(mvchip)); + spin_unlock_irqrestore(&mvchip->lock, flags); +} + static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned pin) { struct mvebu_gpio_chip *mvchip = @@ -244,6 +266,7 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin, if (ret) return ret; + mvebu_gpio_blink(chip, pin, 0); mvebu_gpio_set(chip, pin, value); spin_lock_irqsave(&mvchip->lock, flags); @@ -459,7 +482,7 @@ static struct platform_device_id mvebu_gpio_ids[] = { }; MODULE_DEVICE_TABLE(platform, mvebu_gpio_ids); -static struct of_device_id mvebu_gpio_of_match[] __devinitdata = { +static struct of_device_id mvebu_gpio_of_match[] = { { .compatible = "marvell,orion-gpio", .data = (void*) MVEBU_GPIO_SOC_VARIANT_ORION, @@ -478,7 +501,7 @@ static struct of_device_id mvebu_gpio_of_match[] __devinitdata = { }; MODULE_DEVICE_TABLE(of, mvebu_gpio_of_match); -static int __devinit mvebu_gpio_probe(struct platform_device *pdev) +static int mvebu_gpio_probe(struct platform_device *pdev) { struct mvebu_gpio_chip *mvchip; const struct of_device_id *match; @@ -523,6 +546,7 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev) mvchip->chip.label = dev_name(&pdev->dev); mvchip->chip.dev = &pdev->dev; mvchip->chip.request = mvebu_gpio_request; + mvchip->chip.free = mvebu_gpio_free; mvchip->chip.direction_input = mvebu_gpio_direction_input; mvchip->chip.get = mvebu_gpio_get; mvchip->chip.direction_output = mvebu_gpio_direction_output; @@ -650,8 +674,8 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev) IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE); /* Setup irq domain on top of the generic chip. */ - mvchip->domain = irq_domain_add_legacy(np, mvchip->chip.ngpio, - mvchip->irqbase, 0, + mvchip->domain = irq_domain_add_simple(np, mvchip->chip.ngpio, + mvchip->irqbase, &irq_domain_simple_ops, mvchip); if (!mvchip->domain) { diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index 80f44bb64a8..7877335c4cc 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -356,7 +356,7 @@ static void __init mxc_gpio_init_gc(struct mxc_gpio_port *port, int irq_base) IRQ_NOREQUEST, 0); } -static void __devinit mxc_gpio_get_hw(struct platform_device *pdev) +static void mxc_gpio_get_hw(struct platform_device *pdev) { const struct of_device_id *of_id = of_match_device(mxc_gpio_dt_ids, &pdev->dev); @@ -395,7 +395,7 @@ static int mxc_gpio_to_irq(struct gpio_chip *gc, unsigned offset) return irq_find_mapping(port->domain, offset); } -static int __devinit mxc_gpio_probe(struct platform_device *pdev) +static int mxc_gpio_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct mxc_gpio_port *port; diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 796fb13e481..fa2a63cad32 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -214,7 +214,7 @@ static const struct of_device_id mxs_gpio_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, mxs_gpio_dt_ids); -static int __devinit mxs_gpio_probe(struct platform_device *pdev) +static int mxs_gpio_probe(struct platform_device *pdev) { const struct of_device_id *of_id = of_match_device(mxs_gpio_dt_ids, &pdev->dev); diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index d335af1d4d8..f1fbedb2a6f 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1012,7 +1012,7 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) dev_err(bank->dev, "Could not get gpio dbck\n"); } -static __devinit void +static void omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start, unsigned int num) { @@ -1041,7 +1041,7 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start, IRQ_NOREQUEST | IRQ_NOPROBE, 0); } -static void __devinit omap_gpio_chip_init(struct gpio_bank *bank) +static void omap_gpio_chip_init(struct gpio_bank *bank) { int j; static int gpio; @@ -1089,7 +1089,7 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank) static const struct of_device_id omap_gpio_match[]; -static int __devinit omap_gpio_probe(struct platform_device *pdev) +static int omap_gpio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *node = dev->of_node; @@ -1105,7 +1105,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev) if (!pdata) return -EINVAL; - bank = devm_kzalloc(&pdev->dev, sizeof(struct gpio_bank), GFP_KERNEL); + bank = devm_kzalloc(dev, sizeof(struct gpio_bank), GFP_KERNEL); if (!bank) { dev_err(dev, "Memory alloc failed\n"); return -ENOMEM; diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 9c693ae1795..cc102d25ee2 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -16,6 +16,7 @@ #include <linux/gpio.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/i2c.h> #include <linux/i2c/pca953x.h> #include <linux/slab.h> @@ -83,6 +84,7 @@ struct pca953x_chip { u32 irq_trig_raise; u32 irq_trig_fall; int irq_base; + struct irq_domain *domain; #endif struct i2c_client *client; @@ -333,14 +335,14 @@ static void pca953x_irq_mask(struct irq_data *d) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask &= ~(1 << (d->irq - chip->irq_base)); + chip->irq_mask &= ~(1 << d->hwirq); } static void pca953x_irq_unmask(struct irq_data *d) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - chip->irq_mask |= 1 << (d->irq - chip->irq_base); + chip->irq_mask |= 1 << d->hwirq; } static void pca953x_irq_bus_lock(struct irq_data *d) @@ -372,8 +374,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) static int pca953x_irq_set_type(struct irq_data *d, unsigned int type) { struct pca953x_chip *chip = irq_data_get_irq_chip_data(d); - u32 level = d->irq - chip->irq_base; - u32 mask = 1 << level; + u32 mask = 1 << d->hwirq; if (!(type & IRQ_TYPE_EDGE_BOTH)) { dev_err(&chip->client->dev, "irq %d: unsupported type %d\n", @@ -454,7 +455,7 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid) do { level = __ffs(pending); - handle_nested_irq(level + chip->irq_base); + handle_nested_irq(irq_find_mapping(chip->domain, level)); pending &= ~(1 << level); } while (pending); @@ -499,6 +500,17 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, if (chip->irq_base < 0) goto out_failed; + chip->domain = irq_domain_add_legacy(client->dev.of_node, + chip->gpio_chip.ngpio, + chip->irq_base, + 0, + &irq_domain_simple_ops, + NULL); + if (!chip->domain) { + ret = -ENODEV; + goto out_irqdesc_free; + } + for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) { int irq = lvl + chip->irq_base; @@ -521,7 +533,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, if (ret) { dev_err(&client->dev, "failed to request irq %d\n", client->irq); - goto out_failed; + goto out_irqdesc_free; } chip->gpio_chip.to_irq = pca953x_gpio_to_irq; @@ -529,6 +541,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, return 0; +out_irqdesc_free: + irq_free_descs(chip->irq_base, chip->gpio_chip.ngpio); out_failed: chip->irq_base = -1; return ret; @@ -602,7 +616,7 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, u32 *invert) } #endif -static int __devinit device_pca953x_init(struct pca953x_chip *chip, u32 invert) +static int device_pca953x_init(struct pca953x_chip *chip, u32 invert) { int ret; @@ -621,7 +635,7 @@ out: return ret; } -static int __devinit device_pca957x_init(struct pca953x_chip *chip, u32 invert) +static int device_pca957x_init(struct pca953x_chip *chip, u32 invert) { int ret; u32 val = 0; @@ -652,7 +666,7 @@ out: return ret; } -static int __devinit pca953x_probe(struct i2c_client *client, +static int pca953x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct pca953x_platform_data *pdata; @@ -751,9 +765,38 @@ static int pca953x_remove(struct i2c_client *client) return 0; } +static const struct of_device_id pca953x_dt_ids[] = { + { .compatible = "nxp,pca9534", }, + { .compatible = "nxp,pca9535", }, + { .compatible = "nxp,pca9536", }, + { .compatible = "nxp,pca9537", }, + { .compatible = "nxp,pca9538", }, + { .compatible = "nxp,pca9539", }, + { .compatible = "nxp,pca9554", }, + { .compatible = "nxp,pca9555", }, + { .compatible = "nxp,pca9556", }, + { .compatible = "nxp,pca9557", }, + { .compatible = "nxp,pca9574", }, + { .compatible = "nxp,pca9575", }, + + { .compatible = "maxim,max7310", }, + { .compatible = "maxim,max7312", }, + { .compatible = "maxim,max7313", }, + { .compatible = "maxim,max7315", }, + + { .compatible = "ti,pca6107", }, + { .compatible = "ti,tca6408", }, + { .compatible = "ti,tca6416", }, + { .compatible = "ti,tca6424", }, + { } +}; + +MODULE_DEVICE_TABLE(of, pca953x_dt_ids); + static struct i2c_driver pca953x_driver = { .driver = { .name = "pca953x", + .of_match_table = pca953x_dt_ids, }, .probe = pca953x_probe, .remove = pca953x_remove, diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 16af35cd2b1..a19b7457a72 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -223,11 +223,11 @@ static void pcf857x_irq_domain_cleanup(struct pcf857x *gpio) static int pcf857x_irq_domain_init(struct pcf857x *gpio, struct pcf857x_platform_data *pdata, - struct device *dev) + struct i2c_client *client) { int status; - gpio->irq_domain = irq_domain_add_linear(dev->of_node, + gpio->irq_domain = irq_domain_add_linear(client->dev.of_node, gpio->chip.ngpio, &pcf857x_irq_domain_ops, NULL); @@ -235,15 +235,15 @@ static int pcf857x_irq_domain_init(struct pcf857x *gpio, goto fail; /* enable real irq */ - status = request_irq(pdata->irq, pcf857x_irq_demux, 0, - dev_name(dev), gpio); + status = request_irq(client->irq, pcf857x_irq_demux, 0, + dev_name(&client->dev), gpio); if (status) goto fail; /* enable gpio_to_irq() */ INIT_WORK(&gpio->work, pcf857x_irq_demux_work); gpio->chip.to_irq = pcf857x_to_irq; - gpio->irq = pdata->irq; + gpio->irq = client->irq; return 0; @@ -285,8 +285,8 @@ static int pcf857x_probe(struct i2c_client *client, gpio->chip.ngpio = id->driver_data; /* enable gpio_to_irq() if platform has settings */ - if (pdata && pdata->irq) { - status = pcf857x_irq_domain_init(gpio, pdata, &client->dev); + if (pdata && client->irq) { + status = pcf857x_irq_domain_init(gpio, pdata, client); if (status < 0) { dev_err(&client->dev, "irq_domain init failed\n"); goto fail; @@ -368,15 +368,6 @@ static int pcf857x_probe(struct i2c_client *client, if (status < 0) goto fail; - /* NOTE: these chips can issue "some pin-changed" IRQs, which we - * don't yet even try to use. Among other issues, the relevant - * genirq state isn't available to modular drivers; and most irq - * methods can't be called from sleeping contexts. - */ - - dev_info(&client->dev, "%s\n", - client->irq ? " (irq ignored)" : ""); - /* Let platform code set up the GPIOs and their users. * Now is the first time anyone could use them. */ @@ -388,13 +379,15 @@ static int pcf857x_probe(struct i2c_client *client, dev_warn(&client->dev, "setup --> %d\n", status); } + dev_info(&client->dev, "probed\n"); + return 0; fail: dev_dbg(&client->dev, "probe error %d for '%s'\n", status, client->name); - if (pdata && pdata->irq) + if (pdata && client->irq) pcf857x_irq_domain_cleanup(gpio); kfree(gpio); @@ -418,7 +411,7 @@ static int pcf857x_remove(struct i2c_client *client) } } - if (pdata && pdata->irq) + if (pdata && client->irq) pcf857x_irq_domain_cleanup(gpio); status = gpiochip_remove(&gpio->chip); diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 4ad0c4f9171..cdf599687cf 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -215,6 +215,7 @@ static void pch_gpio_setup(struct pch_gpio *chip) struct gpio_chip *gpio = &chip->gpio; gpio->label = dev_name(chip->dev); + gpio->dev = chip->dev; gpio->owner = THIS_MODULE; gpio->direction_input = pch_gpio_direction_input; gpio->get = pch_gpio_get; @@ -325,7 +326,7 @@ static irqreturn_t pch_gpio_handler(int irq, void *dev_id) return ret; } -static __devinit void pch_gpio_alloc_generic_chip(struct pch_gpio *chip, +static void pch_gpio_alloc_generic_chip(struct pch_gpio *chip, unsigned int irq_start, unsigned int num) { struct irq_chip_generic *gc; @@ -345,7 +346,7 @@ static __devinit void pch_gpio_alloc_generic_chip(struct pch_gpio *chip, IRQ_NOREQUEST | IRQ_NOPROBE, 0); } -static int __devinit pch_gpio_probe(struct pci_dev *pdev, +static int pch_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *id) { s32 ret; @@ -442,7 +443,7 @@ err_pci_enable: return ret; } -static void __devexit pch_gpio_remove(struct pci_dev *pdev) +static void pch_gpio_remove(struct pci_dev *pdev) { int err; struct pch_gpio *chip = pci_get_drvdata(pdev); @@ -531,7 +532,7 @@ static struct pci_driver pch_gpio_driver = { .name = "pch_gpio", .id_table = pch_gpio_pcidev_id, .probe = pch_gpio_probe, - .remove = __devexit_p(pch_gpio_remove), + .remove = pch_gpio_remove, .suspend = pch_gpio_suspend, .resume = pch_gpio_resume }; diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index b4b5da4fd2c..c1720de18a4 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -48,12 +48,7 @@ struct pl061_context_save_regs { #endif struct pl061_gpio { - /* Each of the two spinlocks protects a different set of hardware - * regiters and data structurs. This decouples the code of the IRQ from - * the GPIO code. This also makes the case of a GPIO routine call from - * the IRQ code simpler. - */ - spinlock_t lock; /* GPIO registers */ + spinlock_t lock; void __iomem *base; int irq_base; @@ -216,39 +211,34 @@ static void __init pl061_init_gc(struct pl061_gpio *chip, int irq_base) IRQ_GC_INIT_NESTED_LOCK, IRQ_NOREQUEST, 0); } -static int pl061_probe(struct amba_device *dev, const struct amba_id *id) +static int pl061_probe(struct amba_device *adev, const struct amba_id *id) { - struct pl061_platform_data *pdata; + struct device *dev = &adev->dev; + struct pl061_platform_data *pdata = dev->platform_data; struct pl061_gpio *chip; int ret, irq, i; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; - pdata = dev->dev.platform_data; if (pdata) { chip->gc.base = pdata->gpio_base; chip->irq_base = pdata->irq_base; - } else if (dev->dev.of_node) { + } else if (adev->dev.of_node) { chip->gc.base = -1; chip->irq_base = 0; - } else { - ret = -ENODEV; - goto free_mem; - } + } else + return -ENODEV; - if (!request_mem_region(dev->res.start, - resource_size(&dev->res), "pl061")) { - ret = -EBUSY; - goto free_mem; - } + if (!devm_request_mem_region(dev, adev->res.start, + resource_size(&adev->res), "pl061")) + return -EBUSY; - chip->base = ioremap(dev->res.start, resource_size(&dev->res)); - if (chip->base == NULL) { - ret = -ENOMEM; - goto release_region; - } + chip->base = devm_ioremap(dev, adev->res.start, + resource_size(&adev->res)); + if (chip->base == NULL) + return -ENOMEM; spin_lock_init(&chip->lock); @@ -258,13 +248,13 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) chip->gc.set = pl061_set_value; chip->gc.to_irq = pl061_to_irq; chip->gc.ngpio = PL061_GPIO_NR; - chip->gc.label = dev_name(&dev->dev); - chip->gc.dev = &dev->dev; + chip->gc.label = dev_name(dev); + chip->gc.dev = dev; chip->gc.owner = THIS_MODULE; ret = gpiochip_add(&chip->gc); if (ret) - goto iounmap; + return ret; /* * irq_chip support @@ -276,11 +266,10 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) pl061_init_gc(chip, chip->irq_base); writeb(0, chip->base + GPIOIE); /* disable irqs */ - irq = dev->irq[0]; - if (irq < 0) { - ret = -ENODEV; - goto iounmap; - } + irq = adev->irq[0]; + if (irq < 0) + return -ENODEV; + irq_set_chained_handler(irq, pl061_irq_handler); irq_set_handler_data(irq, chip); @@ -294,18 +283,9 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) } } - amba_set_drvdata(dev, chip); + amba_set_drvdata(adev, chip); return 0; - -iounmap: - iounmap(chip->base); -release_region: - release_mem_region(dev->res.start, resource_size(&dev->res)); -free_mem: - kfree(chip); - - return ret; } #ifdef CONFIG_PM diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index 98d52cb3fd1..3e35243c136 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -250,7 +250,7 @@ static int pxa_gpio_of_xlate(struct gpio_chip *gc, } #endif -static int __devinit pxa_init_gpio_chip(int gpio_end, +static int pxa_init_gpio_chip(int gpio_end, int (*set_wake)(unsigned int, unsigned int)) { int i, gpio, nbanks = gpio_to_bank(gpio_end) + 1; @@ -490,7 +490,7 @@ const struct irq_domain_ops pxa_irq_domain_ops = { .xlate = irq_domain_xlate_twocell, }; -static int __devinit pxa_gpio_probe_dt(struct platform_device *pdev) +static int pxa_gpio_probe_dt(struct platform_device *pdev) { int ret, nr_banks, nr_gpios; struct device_node *prev, *next, *np = pdev->dev.of_node; @@ -537,7 +537,7 @@ err: #define pxa_gpio_probe_dt(pdev) (-1) #endif -static int __devinit pxa_gpio_probe(struct platform_device *pdev) +static int pxa_gpio_probe(struct platform_device *pdev) { struct pxa_gpio_chip *c; struct resource *res; diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c index 08428bf1771..e63d6a397e1 100644 --- a/drivers/gpio/gpio-rc5t583.c +++ b/drivers/gpio/gpio-rc5t583.c @@ -111,7 +111,7 @@ static void rc5t583_gpio_free(struct gpio_chip *gc, unsigned offset) rc5t583_set_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset)); } -static int __devinit rc5t583_gpio_probe(struct platform_device *pdev) +static int rc5t583_gpio_probe(struct platform_device *pdev) { struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent); struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev); @@ -146,7 +146,7 @@ static int __devinit rc5t583_gpio_probe(struct platform_device *pdev) return gpiochip_add(&rc5t583_gpio->gpio_chip); } -static int __devexit rc5t583_gpio_remove(struct platform_device *pdev) +static int rc5t583_gpio_remove(struct platform_device *pdev) { struct rc5t583_gpio *rc5t583_gpio = platform_get_drvdata(pdev); @@ -159,7 +159,7 @@ static struct platform_driver rc5t583_gpio_driver = { .owner = THIS_MODULE, }, .probe = rc5t583_gpio_probe, - .remove = __devexit_p(rc5t583_gpio_remove), + .remove = rc5t583_gpio_remove, }; static int __init rc5t583_gpio_init(void) diff --git a/drivers/gpio/gpio-rdc321x.c b/drivers/gpio/gpio-rdc321x.c index b62d443e9a5..1bf55f67f7a 100644 --- a/drivers/gpio/gpio-rdc321x.c +++ b/drivers/gpio/gpio-rdc321x.c @@ -128,7 +128,7 @@ static int rdc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) /* * Cache the initial value of both GPIO data registers */ -static int __devinit rdc321x_gpio_probe(struct platform_device *pdev) +static int rdc321x_gpio_probe(struct platform_device *pdev) { int err; struct resource *r; @@ -206,7 +206,7 @@ out_free: return err; } -static int __devexit rdc321x_gpio_remove(struct platform_device *pdev) +static int rdc321x_gpio_remove(struct platform_device *pdev) { int ret; struct rdc321x_gpio *rdc321x_gpio_dev = platform_get_drvdata(pdev); @@ -225,7 +225,7 @@ static struct platform_driver rdc321x_gpio_driver = { .driver.name = "rdc321x-gpio", .driver.owner = THIS_MODULE, .probe = rdc321x_gpio_probe, - .remove = __devexit_p(rdc321x_gpio_remove), + .remove = rdc321x_gpio_remove, }; module_platform_driver(rdc321x_gpio_driver); diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c index 8707d4572a0..edae963f462 100644 --- a/drivers/gpio/gpio-sch.c +++ b/drivers/gpio/gpio-sch.c @@ -185,7 +185,7 @@ static struct gpio_chip sch_gpio_resume = { .set = sch_gpio_resume_set, }; -static int __devinit sch_gpio_probe(struct platform_device *pdev) +static int sch_gpio_probe(struct platform_device *pdev) { struct resource *res; int err, id; @@ -271,7 +271,7 @@ err_sch_gpio_core: return err; } -static int __devexit sch_gpio_remove(struct platform_device *pdev) +static int sch_gpio_remove(struct platform_device *pdev) { struct resource *res; if (gpio_ba) { @@ -303,7 +303,7 @@ static struct platform_driver sch_gpio_driver = { .owner = THIS_MODULE, }, .probe = sch_gpio_probe, - .remove = __devexit_p(sch_gpio_remove), + .remove = sch_gpio_remove, }; module_platform_driver(sch_gpio_driver); diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c index e25f73130b4..88f374ac775 100644 --- a/drivers/gpio/gpio-sodaville.c +++ b/drivers/gpio/gpio-sodaville.c @@ -129,7 +129,7 @@ static struct irq_domain_ops irq_domain_sdv_ops = { .xlate = sdv_xlate, }; -static __devinit int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd, +static int sdv_register_irqsupport(struct sdv_gpio_chip_data *sd, struct pci_dev *pdev) { struct irq_chip_type *ct; @@ -186,7 +186,7 @@ out_free_desc: return ret; } -static int __devinit sdv_gpio_probe(struct pci_dev *pdev, +static int sdv_gpio_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) { struct sdv_gpio_chip_data *sd; diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c new file mode 100644 index 00000000000..5f45fc4ed5d --- /dev/null +++ b/drivers/gpio/gpio-spear-spics.c @@ -0,0 +1,217 @@ +/* + * SPEAr platform SPI chipselect abstraction over gpiolib + * + * Copyright (C) 2012 ST Microelectronics + * Shiraz Hashim <shiraz.hashim@st.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/types.h> + +/* maximum chipselects */ +#define NUM_OF_GPIO 4 + +/* + * Provision is available on some SPEAr SoCs to control ARM PL022 spi cs + * through system registers. This register lies outside spi (pl022) + * address space into system registers. + * + * It provides control for spi chip select lines so that any chipselect + * (out of 4 possible chipselects in pl022) can be made low to select + * the particular slave. + */ + +/** + * struct spear_spics - represents spi chip select control + * @base: base address + * @perip_cfg: configuration register + * @sw_enable_bit: bit to enable s/w control over chipselects + * @cs_value_bit: bit to program high or low chipselect + * @cs_enable_mask: mask to select bits required to select chipselect + * @cs_enable_shift: bit pos of cs_enable_mask + * @use_count: use count of a spi controller cs lines + * @last_off: stores last offset caller of set_value() + * @chip: gpio_chip abstraction + */ +struct spear_spics { + void __iomem *base; + u32 perip_cfg; + u32 sw_enable_bit; + u32 cs_value_bit; + u32 cs_enable_mask; + u32 cs_enable_shift; + unsigned long use_count; + int last_off; + struct gpio_chip chip; +}; + +/* gpio framework specific routines */ +static int spics_get_value(struct gpio_chip *chip, unsigned offset) +{ + return -ENXIO; +} + +static void spics_set_value(struct gpio_chip *chip, unsigned offset, int value) +{ + struct spear_spics *spics = container_of(chip, struct spear_spics, + chip); + u32 tmp; + + /* select chip select from register */ + tmp = readl_relaxed(spics->base + spics->perip_cfg); + if (spics->last_off != offset) { + spics->last_off = offset; + tmp &= ~(spics->cs_enable_mask << spics->cs_enable_shift); + tmp |= offset << spics->cs_enable_shift; + } + + /* toggle chip select line */ + tmp &= ~(0x1 << spics->cs_value_bit); + tmp |= value << spics->cs_value_bit; + writel_relaxed(tmp, spics->base + spics->perip_cfg); +} + +static int spics_direction_input(struct gpio_chip *chip, unsigned offset) +{ + return -ENXIO; +} + +static int spics_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + spics_set_value(chip, offset, value); + return 0; +} + +static int spics_request(struct gpio_chip *chip, unsigned offset) +{ + struct spear_spics *spics = container_of(chip, struct spear_spics, + chip); + u32 tmp; + + if (!spics->use_count++) { + tmp = readl_relaxed(spics->base + spics->perip_cfg); + tmp |= 0x1 << spics->sw_enable_bit; + tmp |= 0x1 << spics->cs_value_bit; + writel_relaxed(tmp, spics->base + spics->perip_cfg); + } + + return 0; +} + +static void spics_free(struct gpio_chip *chip, unsigned offset) +{ + struct spear_spics *spics = container_of(chip, struct spear_spics, + chip); + u32 tmp; + + if (!--spics->use_count) { + tmp = readl_relaxed(spics->base + spics->perip_cfg); + tmp &= ~(0x1 << spics->sw_enable_bit); + writel_relaxed(tmp, spics->base + spics->perip_cfg); + } +} + +static int spics_gpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct spear_spics *spics; + struct resource *res; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "invalid IORESOURCE_MEM\n"); + return -EBUSY; + } + + spics = devm_kzalloc(&pdev->dev, sizeof(*spics), GFP_KERNEL); + if (!spics) { + dev_err(&pdev->dev, "memory allocation fail\n"); + return -ENOMEM; + } + + spics->base = devm_request_and_ioremap(&pdev->dev, res); + if (!spics->base) { + dev_err(&pdev->dev, "request and ioremap fail\n"); + return -ENOMEM; + } + + if (of_property_read_u32(np, "st-spics,peripcfg-reg", + &spics->perip_cfg)) + goto err_dt_data; + if (of_property_read_u32(np, "st-spics,sw-enable-bit", + &spics->sw_enable_bit)) + goto err_dt_data; + if (of_property_read_u32(np, "st-spics,cs-value-bit", + &spics->cs_value_bit)) + goto err_dt_data; + if (of_property_read_u32(np, "st-spics,cs-enable-mask", + &spics->cs_enable_mask)) + goto err_dt_data; + if (of_property_read_u32(np, "st-spics,cs-enable-shift", + &spics->cs_enable_shift)) + goto err_dt_data; + + platform_set_drvdata(pdev, spics); + + spics->chip.ngpio = NUM_OF_GPIO; + spics->chip.base = -1; + spics->chip.request = spics_request; + spics->chip.free = spics_free; + spics->chip.direction_input = spics_direction_input; + spics->chip.direction_output = spics_direction_output; + spics->chip.get = spics_get_value; + spics->chip.set = spics_set_value; + spics->chip.label = dev_name(&pdev->dev); + spics->chip.dev = &pdev->dev; + spics->chip.owner = THIS_MODULE; + spics->last_off = -1; + + ret = gpiochip_add(&spics->chip); + if (ret) { + dev_err(&pdev->dev, "unable to add gpio chip\n"); + return ret; + } + + dev_info(&pdev->dev, "spear spics registered\n"); + return 0; + +err_dt_data: + dev_err(&pdev->dev, "DT probe failed\n"); + return -EINVAL; +} + +static const struct of_device_id spics_gpio_of_match[] = { + { .compatible = "st,spear-spics-gpio" }, + {} +}; +MODULE_DEVICE_TABLE(of, spics_gpio_of_match); + +static struct platform_driver spics_gpio_driver = { + .probe = spics_gpio_probe, + .driver = { + .owner = THIS_MODULE, + .name = "spear-spics-gpio", + .of_match_table = spics_gpio_of_match, + }, +}; + +static int __init spics_gpio_init(void) +{ + return platform_driver_register(&spics_gpio_driver); +} +subsys_initcall(spics_gpio_init); + +MODULE_AUTHOR("Shiraz Hashim <shiraz.hashim@st.com>"); +MODULE_DESCRIPTION("ST Microlectronics SPEAr SPI Chip Select Abstraction"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c index 6064fb376e1..558542552aa 100644 --- a/drivers/gpio/gpio-sta2x11.c +++ b/drivers/gpio/gpio-sta2x11.c @@ -320,7 +320,7 @@ static irqreturn_t gsta_gpio_handler(int irq, void *dev_id) return ret; } -static __devinit void gsta_alloc_irq_chip(struct gsta_gpio *chip) +static void gsta_alloc_irq_chip(struct gsta_gpio *chip) { struct irq_chip_generic *gc; struct irq_chip_type *ct; @@ -353,7 +353,7 @@ static __devinit void gsta_alloc_irq_chip(struct gsta_gpio *chip) } /* The platform device used here is instantiated by the MFD device */ -static int __devinit gsta_probe(struct platform_device *dev) +static int gsta_probe(struct platform_device *dev) { int i, err; struct pci_dev *pdev; diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index dce34727bbf..770476a9da8 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -11,7 +11,9 @@ #include <linux/slab.h> #include <linux/gpio.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/interrupt.h> +#include <linux/of.h> #include <linux/mfd/stmpe.h> /* @@ -28,6 +30,7 @@ struct stmpe_gpio { struct stmpe *stmpe; struct device *dev; struct mutex irq_lock; + struct irq_domain *domain; int irq_base; unsigned norequest_mask; @@ -103,7 +106,7 @@ static int stmpe_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip); - return stmpe_gpio->irq_base + offset; + return irq_create_mapping(stmpe_gpio->domain, offset); } static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset) @@ -132,7 +135,7 @@ static struct gpio_chip template_chip = { static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type) { struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); - int offset = d->irq - stmpe_gpio->irq_base; + int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -199,7 +202,7 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d) static void stmpe_gpio_irq_mask(struct irq_data *d) { struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); - int offset = d->irq - stmpe_gpio->irq_base; + int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -209,7 +212,7 @@ static void stmpe_gpio_irq_mask(struct irq_data *d) static void stmpe_gpio_irq_unmask(struct irq_data *d) { struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); - int offset = d->irq - stmpe_gpio->irq_base; + int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -251,8 +254,9 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) while (stat) { int bit = __ffs(stat); int line = bank * 8 + bit; + int virq = irq_find_mapping(stmpe_gpio->domain, line); - handle_nested_irq(stmpe_gpio->irq_base + line); + handle_nested_irq(virq); stat &= ~(1 << bit); } @@ -267,43 +271,61 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev) return IRQ_HANDLED; } -static int __devinit stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio) +int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hwirq) { - int base = stmpe_gpio->irq_base; - int irq; + struct stmpe_gpio *stmpe_gpio = d->host_data; + + if (!stmpe_gpio) + return -EINVAL; - for (irq = base; irq < base + stmpe_gpio->chip.ngpio; irq++) { - irq_set_chip_data(irq, stmpe_gpio); - irq_set_chip_and_handler(irq, &stmpe_gpio_irq_chip, - handle_simple_irq); - irq_set_nested_thread(irq, 1); + irq_set_chip_data(hwirq, stmpe_gpio); + irq_set_chip_and_handler(hwirq, &stmpe_gpio_irq_chip, + handle_simple_irq); + irq_set_nested_thread(hwirq, 1); #ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); + set_irq_flags(hwirq, IRQF_VALID); #else - irq_set_noprobe(irq); + irq_set_noprobe(hwirq); #endif - } return 0; } -static void stmpe_gpio_irq_remove(struct stmpe_gpio *stmpe_gpio) +void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int virq) { - int base = stmpe_gpio->irq_base; - int irq; - - for (irq = base; irq < base + stmpe_gpio->chip.ngpio; irq++) { #ifdef CONFIG_ARM - set_irq_flags(irq, 0); + set_irq_flags(virq, 0); #endif - irq_set_chip_and_handler(irq, NULL, NULL); - irq_set_chip_data(irq, NULL); + irq_set_chip_and_handler(virq, NULL, NULL); + irq_set_chip_data(virq, NULL); +} + +static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = { + .unmap = stmpe_gpio_irq_unmap, + .map = stmpe_gpio_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio) +{ + int base = stmpe_gpio->irq_base; + + stmpe_gpio->domain = irq_domain_add_simple(NULL, + stmpe_gpio->chip.ngpio, base, + &stmpe_gpio_irq_simple_ops, stmpe_gpio); + if (!stmpe_gpio->domain) { + dev_err(stmpe_gpio->dev, "failed to create irqdomain\n"); + return -ENOSYS; } + + return 0; } -static int __devinit stmpe_gpio_probe(struct platform_device *pdev) +static int stmpe_gpio_probe(struct platform_device *pdev) { struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); + struct device_node *np = pdev->dev.of_node; struct stmpe_gpio_platform_data *pdata; struct stmpe_gpio *stmpe_gpio; int ret; @@ -321,13 +343,17 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev) stmpe_gpio->dev = &pdev->dev; stmpe_gpio->stmpe = stmpe; - stmpe_gpio->norequest_mask = pdata ? pdata->norequest_mask : 0; - stmpe_gpio->chip = template_chip; stmpe_gpio->chip.ngpio = stmpe->num_gpios; stmpe_gpio->chip.dev = &pdev->dev; stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1; + if (pdata) + stmpe_gpio->norequest_mask = pdata->norequest_mask; + else if (np) + of_property_read_u32(np, "st,norequest-mask", + &stmpe_gpio->norequest_mask); + if (irq >= 0) stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0); else @@ -348,7 +374,7 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev) IRQF_ONESHOT, "stmpe-gpio", stmpe_gpio); if (ret) { dev_err(&pdev->dev, "unable to get irq: %d\n", ret); - goto out_removeirq; + goto out_disable; } } @@ -368,9 +394,6 @@ static int __devinit stmpe_gpio_probe(struct platform_device *pdev) out_freeirq: if (irq >= 0) free_irq(irq, stmpe_gpio); -out_removeirq: - if (irq >= 0) - stmpe_gpio_irq_remove(stmpe_gpio); out_disable: stmpe_disable(stmpe, STMPE_BLOCK_GPIO); out_free: @@ -378,7 +401,7 @@ out_free: return ret; } -static int __devexit stmpe_gpio_remove(struct platform_device *pdev) +static int stmpe_gpio_remove(struct platform_device *pdev) { struct stmpe_gpio *stmpe_gpio = platform_get_drvdata(pdev); struct stmpe *stmpe = stmpe_gpio->stmpe; @@ -398,10 +421,9 @@ static int __devexit stmpe_gpio_remove(struct platform_device *pdev) stmpe_disable(stmpe, STMPE_BLOCK_GPIO); - if (irq >= 0) { + if (irq >= 0) free_irq(irq, stmpe_gpio); - stmpe_gpio_irq_remove(stmpe_gpio); - } + platform_set_drvdata(pdev, NULL); kfree(stmpe_gpio); @@ -412,7 +434,7 @@ static struct platform_driver stmpe_gpio_driver = { .driver.name = "stmpe-gpio", .driver.owner = THIS_MODULE, .probe = stmpe_gpio_probe, - .remove = __devexit_p(stmpe_gpio_remove), + .remove = stmpe_gpio_remove, }; static int __init stmpe_gpio_init(void) diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c index 8bead0bb645..85841ee70b1 100644 --- a/drivers/gpio/gpio-stp-xway.c +++ b/drivers/gpio/gpio-stp-xway.c @@ -197,7 +197,7 @@ static int xway_stp_hw_init(struct xway_stp *chip) return 0; } -static int __devinit xway_stp_probe(struct platform_device *pdev) +static int xway_stp_probe(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); const __be32 *shadow, *groups, *dsl, *phy; diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index eb3e215d239..796b6c42fa7 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -575,7 +575,7 @@ static void sx150x_remove_irq_chip(struct sx150x_chip *chip) } } -static int __devinit sx150x_probe(struct i2c_client *client, +static int sx150x_probe(struct i2c_client *client, const struct i2c_device_id *id) { static const u32 i2c_funcs = I2C_FUNC_SMBUS_BYTE_DATA | @@ -622,7 +622,7 @@ probe_fail_pre_gpiochip_add: return rc; } -static int __devexit sx150x_remove(struct i2c_client *client) +static int sx150x_remove(struct i2c_client *client) { struct sx150x_chip *chip; int rc; @@ -646,7 +646,7 @@ static struct i2c_driver sx150x_driver = { .owner = THIS_MODULE }, .probe = sx150x_probe, - .remove = __devexit_p(sx150x_remove), + .remove = sx150x_remove, .id_table = sx150x_id, }; diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 1e48317e70f..c0595bbf326 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -292,17 +292,15 @@ static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio, { int base = tc3589x_gpio->irq_base; - if (base) { - tc3589x_gpio->domain = irq_domain_add_legacy( - NULL, tc3589x_gpio->chip.ngpio, base, - 0, &tc3589x_irq_ops, tc3589x_gpio); - } - else { - tc3589x_gpio->domain = irq_domain_add_linear( - np, tc3589x_gpio->chip.ngpio, - &tc3589x_irq_ops, tc3589x_gpio); - } - + /* + * If this results in a linear domain, irq_create_mapping() will + * take care of allocating IRQ descriptors at runtime. When a base + * is provided, the IRQ descriptors will be allocated when the + * domain is instantiated. + */ + tc3589x_gpio->domain = irq_domain_add_simple(np, + tc3589x_gpio->chip.ngpio, base, &tc3589x_irq_ops, + tc3589x_gpio); if (!tc3589x_gpio->domain) { dev_err(tc3589x_gpio->dev, "Failed to create irqdomain\n"); return -ENOSYS; @@ -311,7 +309,7 @@ static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio, return 0; } -static int __devinit tc3589x_gpio_probe(struct platform_device *pdev) +static int tc3589x_gpio_probe(struct platform_device *pdev) { struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); struct tc3589x_gpio_platform_data *pdata; @@ -389,7 +387,7 @@ out_free: return ret; } -static int __devexit tc3589x_gpio_remove(struct platform_device *pdev) +static int tc3589x_gpio_remove(struct platform_device *pdev) { struct tc3589x_gpio *tc3589x_gpio = platform_get_drvdata(pdev); struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; @@ -419,7 +417,7 @@ static struct platform_driver tc3589x_gpio_driver = { .driver.name = "tc3589x-gpio", .driver.owner = THIS_MODULE, .probe = tc3589x_gpio_probe, - .remove = __devexit_p(tc3589x_gpio_remove), + .remove = tc3589x_gpio_remove, }; static int __init tc3589x_gpio_init(void) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index d982593d756..63cb643d4b5 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/irqdomain.h> #include <linux/pinctrl/consumer.h> +#include <linux/pm.h> #include <asm/mach/irq.h> @@ -64,7 +65,7 @@ struct tegra_gpio_bank { int bank; int irq; spinlock_t lvl_lock[4]; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP u32 cnf[4]; u32 out[4]; u32 oe[4]; @@ -109,20 +110,18 @@ static void tegra_gpio_enable(int gpio) { tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1); } -EXPORT_SYMBOL_GPL(tegra_gpio_enable); static void tegra_gpio_disable(int gpio) { tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0); } -EXPORT_SYMBOL_GPL(tegra_gpio_disable); -int tegra_gpio_request(struct gpio_chip *chip, unsigned offset) +static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset) { return pinctrl_request_gpio(offset); } -void tegra_gpio_free(struct gpio_chip *chip, unsigned offset) +static void tegra_gpio_free(struct gpio_chip *chip, unsigned offset) { pinctrl_free_gpio(offset); tegra_gpio_disable(offset); @@ -135,6 +134,11 @@ static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value) static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset) { + /* If gpio is in output mode then read from the out value */ + if ((tegra_gpio_readl(GPIO_OE(offset)) >> GPIO_BIT(offset)) & 1) + return (tegra_gpio_readl(GPIO_OUT(offset)) >> + GPIO_BIT(offset)) & 0x1; + return (tegra_gpio_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1; } @@ -285,8 +289,8 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) } -#ifdef CONFIG_PM -void tegra_gpio_resume(void) +#ifdef CONFIG_PM_SLEEP +static int tegra_gpio_resume(struct device *dev) { unsigned long flags; int b; @@ -308,9 +312,10 @@ void tegra_gpio_resume(void) } local_irq_restore(flags); + return 0; } -void tegra_gpio_suspend(void) +static int tegra_gpio_suspend(struct device *dev) { unsigned long flags; int b; @@ -330,6 +335,7 @@ void tegra_gpio_suspend(void) } } local_irq_restore(flags); + return 0; } static int tegra_gpio_wake_enable(struct irq_data *d, unsigned int enable) @@ -345,11 +351,15 @@ static struct irq_chip tegra_gpio_irq_chip = { .irq_mask = tegra_gpio_irq_mask, .irq_unmask = tegra_gpio_irq_unmask, .irq_set_type = tegra_gpio_irq_set_type, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP .irq_set_wake = tegra_gpio_wake_enable, #endif }; +static const struct dev_pm_ops tegra_gpio_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume) +}; + struct tegra_gpio_soc_config { u32 bank_stride; u32 upper_offset; @@ -365,7 +375,7 @@ static struct tegra_gpio_soc_config tegra30_gpio_config = { .upper_offset = 0x80, }; -static struct of_device_id tegra_gpio_of_match[] __devinitdata = { +static struct of_device_id tegra_gpio_of_match[] = { { .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config }, { .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config }, { }, @@ -376,11 +386,10 @@ static struct of_device_id tegra_gpio_of_match[] __devinitdata = { */ static struct lock_class_key gpio_lock_class; -static int __devinit tegra_gpio_probe(struct platform_device *pdev) +static int tegra_gpio_probe(struct platform_device *pdev) { const struct of_device_id *match; struct tegra_gpio_soc_config *config; - int irq_base; struct resource *res; struct tegra_gpio_bank *bank; int gpio; @@ -417,14 +426,11 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) return -ENODEV; } - irq_base = irq_alloc_descs(-1, 0, tegra_gpio_chip.ngpio, 0); - if (irq_base < 0) { - dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n"); - return -ENODEV; - } - irq_domain = irq_domain_add_legacy(pdev->dev.of_node, - tegra_gpio_chip.ngpio, irq_base, 0, + irq_domain = irq_domain_add_linear(pdev->dev.of_node, + tegra_gpio_chip.ngpio, &irq_domain_simple_ops, NULL); + if (!irq_domain) + return -ENODEV; for (i = 0; i < tegra_gpio_bank_count; i++) { res = platform_get_resource(pdev, IORESOURCE_IRQ, i); @@ -464,7 +470,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) gpiochip_add(&tegra_gpio_chip); for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) { - int irq = irq_find_mapping(irq_domain, gpio); + int irq = irq_create_mapping(irq_domain, gpio); /* No validity check; all Tegra GPIOs are valid IRQs */ bank = &tegra_gpio_banks[GPIO_BANK(gpio)]; @@ -493,6 +499,7 @@ static struct platform_driver tegra_gpio_driver = { .driver = { .name = "tegra-gpio", .owner = THIS_MODULE, + .pm = &tegra_gpio_pm_ops, .of_match_table = tegra_gpio_of_match, }, .probe = tegra_gpio_probe, diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index 1a3e2b9b477..702cca9284f 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -222,7 +222,7 @@ static struct irq_chip timbgpio_irqchip = { .irq_set_type = timbgpio_irq_type, }; -static int __devinit timbgpio_probe(struct platform_device *pdev) +static int timbgpio_probe(struct platform_device *pdev) { int err, i; struct gpio_chip *gc; @@ -316,7 +316,7 @@ err_mem: return err; } -static int __devexit timbgpio_remove(struct platform_device *pdev) +static int timbgpio_remove(struct platform_device *pdev) { int err; struct timbgpio_platform_data *pdata = pdev->dev.platform_data; diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c index 2526b3bb0fa..c1b82da5650 100644 --- a/drivers/gpio/gpio-tps6586x.c +++ b/drivers/gpio/gpio-tps6586x.c @@ -80,7 +80,7 @@ static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset, val, mask); } -static int __devinit tps6586x_gpio_probe(struct platform_device *pdev) +static int tps6586x_gpio_probe(struct platform_device *pdev) { struct tps6586x_platform_data *pdata; struct tps6586x_gpio *tps6586x_gpio; @@ -126,7 +126,7 @@ static int __devinit tps6586x_gpio_probe(struct platform_device *pdev) return ret; } -static int __devexit tps6586x_gpio_remove(struct platform_device *pdev) +static int tps6586x_gpio_remove(struct platform_device *pdev) { struct tps6586x_gpio *tps6586x_gpio = platform_get_drvdata(pdev); @@ -137,7 +137,7 @@ static struct platform_driver tps6586x_gpio_driver = { .driver.name = "tps6586x-gpio", .driver.owner = THIS_MODULE, .probe = tps6586x_gpio_probe, - .remove = __devexit_p(tps6586x_gpio_remove), + .remove = tps6586x_gpio_remove, }; static int __init tps6586x_gpio_init(void) diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c index 11f29c82253..5083825a034 100644 --- a/drivers/gpio/gpio-tps65910.c +++ b/drivers/gpio/gpio-tps65910.c @@ -113,7 +113,7 @@ static struct tps65910_board *tps65910_parse_dt_for_gpio(struct device *dev, } #endif -static int __devinit tps65910_gpio_probe(struct platform_device *pdev) +static int tps65910_gpio_probe(struct platform_device *pdev) { struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); struct tps65910_board *pdata = dev_get_platdata(tps65910->dev); @@ -188,7 +188,7 @@ skip_init: return ret; } -static int __devexit tps65910_gpio_remove(struct platform_device *pdev) +static int tps65910_gpio_remove(struct platform_device *pdev) { struct tps65910_gpio *tps65910_gpio = platform_get_drvdata(pdev); @@ -199,7 +199,7 @@ static struct platform_driver tps65910_gpio_driver = { .driver.name = "tps65910-gpio", .driver.owner = THIS_MODULE, .probe = tps65910_gpio_probe, - .remove = __devexit_p(tps65910_gpio_remove), + .remove = tps65910_gpio_remove, }; static int __init tps65910_gpio_init(void) diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c index 99106d1e2e5..30a5844a7dc 100644 --- a/drivers/gpio/gpio-tps65912.c +++ b/drivers/gpio/gpio-tps65912.c @@ -84,7 +84,7 @@ static struct gpio_chip template_chip = { .base = -1, }; -static int __devinit tps65912_gpio_probe(struct platform_device *pdev) +static int tps65912_gpio_probe(struct platform_device *pdev) { struct tps65912 *tps65912 = dev_get_drvdata(pdev->dev.parent); struct tps65912_board *pdata = tps65912->dev->platform_data; @@ -113,7 +113,7 @@ static int __devinit tps65912_gpio_probe(struct platform_device *pdev) return ret; } -static int __devexit tps65912_gpio_remove(struct platform_device *pdev) +static int tps65912_gpio_remove(struct platform_device *pdev) { struct tps65912_gpio_data *tps65912_gpio = platform_get_drvdata(pdev); @@ -126,7 +126,7 @@ static struct platform_driver tps65912_gpio_driver = { .owner = THIS_MODULE, }, .probe = tps65912_gpio_probe, - .remove = __devexit_p(tps65912_gpio_remove), + .remove = tps65912_gpio_remove, }; static int __init tps65912_gpio_init(void) diff --git a/drivers/gpio/gpio-ts5500.c b/drivers/gpio/gpio-ts5500.c new file mode 100644 index 00000000000..0634ceea3c2 --- /dev/null +++ b/drivers/gpio/gpio-ts5500.c @@ -0,0 +1,466 @@ +/* + * Digital I/O driver for Technologic Systems TS-5500 + * + * Copyright (c) 2012 Savoir-faire Linux Inc. + * Vivien Didelot <vivien.didelot@savoirfairelinux.com> + * + * Technologic Systems platforms have pin blocks, exposing several Digital + * Input/Output lines (DIO). This driver aims to support single pin blocks. + * In that sense, the support is not limited to the TS-5500 blocks. + * Actually, the following platforms have DIO support: + * + * TS-5500: + * Documentation: http://wiki.embeddedarm.com/wiki/TS-5500 + * Blocks: DIO1, DIO2 and LCD port. + * + * TS-5600: + * Documentation: http://wiki.embeddedarm.com/wiki/TS-5600 + * Blocks: LCD port (identical to TS-5500 LCD). + * + * 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/bitops.h> +#include <linux/gpio.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_data/gpio-ts5500.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +/* List of supported Technologic Systems platforms DIO blocks */ +enum ts5500_blocks { TS5500_DIO1, TS5500_DIO2, TS5500_LCD, TS5600_LCD }; + +struct ts5500_priv { + const struct ts5500_dio *pinout; + struct gpio_chip gpio_chip; + spinlock_t lock; + bool strap; + u8 hwirq; +}; + +/* + * Hex 7D is used to control several blocks (e.g. DIO2 and LCD port). + * This flag ensures that the region has been requested by this driver. + */ +static bool hex7d_reserved; + +/* + * This structure is used to describe capabilities of DIO lines, + * such as available directions and connected interrupt (if any). + */ +struct ts5500_dio { + const u8 value_addr; + const u8 value_mask; + const u8 control_addr; + const u8 control_mask; + const bool no_input; + const bool no_output; + const u8 irq; +}; + +#define TS5500_DIO_IN_OUT(vaddr, vbit, caddr, cbit) \ + { \ + .value_addr = vaddr, \ + .value_mask = BIT(vbit), \ + .control_addr = caddr, \ + .control_mask = BIT(cbit), \ + } + +#define TS5500_DIO_IN(addr, bit) \ + { \ + .value_addr = addr, \ + .value_mask = BIT(bit), \ + .no_output = true, \ + } + +#define TS5500_DIO_IN_IRQ(addr, bit, _irq) \ + { \ + .value_addr = addr, \ + .value_mask = BIT(bit), \ + .no_output = true, \ + .irq = _irq, \ + } + +#define TS5500_DIO_OUT(addr, bit) \ + { \ + .value_addr = addr, \ + .value_mask = BIT(bit), \ + .no_input = true, \ + } + +/* + * Input/Output DIO lines are programmed in groups of 4. Their values are + * available through 4 consecutive bits in a value port, whereas the direction + * of these 4 lines is driven by only 1 bit in a control port. + */ +#define TS5500_DIO_GROUP(vaddr, vbitfrom, caddr, cbit) \ + TS5500_DIO_IN_OUT(vaddr, vbitfrom + 0, caddr, cbit), \ + TS5500_DIO_IN_OUT(vaddr, vbitfrom + 1, caddr, cbit), \ + TS5500_DIO_IN_OUT(vaddr, vbitfrom + 2, caddr, cbit), \ + TS5500_DIO_IN_OUT(vaddr, vbitfrom + 3, caddr, cbit) + +/* + * TS-5500 DIO1 block + * + * value control dir hw + * addr bit addr bit in out irq name pin offset + * + * 0x7b 0 0x7a 0 x x DIO1_0 1 0 + * 0x7b 1 0x7a 0 x x DIO1_1 3 1 + * 0x7b 2 0x7a 0 x x DIO1_2 5 2 + * 0x7b 3 0x7a 0 x x DIO1_3 7 3 + * 0x7b 4 0x7a 1 x x DIO1_4 9 4 + * 0x7b 5 0x7a 1 x x DIO1_5 11 5 + * 0x7b 6 0x7a 1 x x DIO1_6 13 6 + * 0x7b 7 0x7a 1 x x DIO1_7 15 7 + * 0x7c 0 0x7a 5 x x DIO1_8 4 8 + * 0x7c 1 0x7a 5 x x DIO1_9 6 9 + * 0x7c 2 0x7a 5 x x DIO1_10 8 10 + * 0x7c 3 0x7a 5 x x DIO1_11 10 11 + * 0x7c 4 x DIO1_12 12 12 + * 0x7c 5 x 7 DIO1_13 14 13 + */ +static const struct ts5500_dio ts5500_dio1[] = { + TS5500_DIO_GROUP(0x7b, 0, 0x7a, 0), + TS5500_DIO_GROUP(0x7b, 4, 0x7a, 1), + TS5500_DIO_GROUP(0x7c, 0, 0x7a, 5), + TS5500_DIO_IN(0x7c, 4), + TS5500_DIO_IN_IRQ(0x7c, 5, 7), +}; + +/* + * TS-5500 DIO2 block + * + * value control dir hw + * addr bit addr bit in out irq name pin offset + * + * 0x7e 0 0x7d 0 x x DIO2_0 1 0 + * 0x7e 1 0x7d 0 x x DIO2_1 3 1 + * 0x7e 2 0x7d 0 x x DIO2_2 5 2 + * 0x7e 3 0x7d 0 x x DIO2_3 7 3 + * 0x7e 4 0x7d 1 x x DIO2_4 9 4 + * 0x7e 5 0x7d 1 x x DIO2_5 11 5 + * 0x7e 6 0x7d 1 x x DIO2_6 13 6 + * 0x7e 7 0x7d 1 x x DIO2_7 15 7 + * 0x7f 0 0x7d 5 x x DIO2_8 4 8 + * 0x7f 1 0x7d 5 x x DIO2_9 6 9 + * 0x7f 2 0x7d 5 x x DIO2_10 8 10 + * 0x7f 3 0x7d 5 x x DIO2_11 10 11 + * 0x7f 4 x 6 DIO2_13 14 12 + */ +static const struct ts5500_dio ts5500_dio2[] = { + TS5500_DIO_GROUP(0x7e, 0, 0x7d, 0), + TS5500_DIO_GROUP(0x7e, 4, 0x7d, 1), + TS5500_DIO_GROUP(0x7f, 0, 0x7d, 5), + TS5500_DIO_IN_IRQ(0x7f, 4, 6), +}; + +/* + * TS-5500 LCD port used as DIO block + * TS-5600 LCD port is identical + * + * value control dir hw + * addr bit addr bit in out irq name pin offset + * + * 0x72 0 0x7d 2 x x LCD_0 8 0 + * 0x72 1 0x7d 2 x x LCD_1 7 1 + * 0x72 2 0x7d 2 x x LCD_2 10 2 + * 0x72 3 0x7d 2 x x LCD_3 9 3 + * 0x72 4 0x7d 3 x x LCD_4 12 4 + * 0x72 5 0x7d 3 x x LCD_5 11 5 + * 0x72 6 0x7d 3 x x LCD_6 14 6 + * 0x72 7 0x7d 3 x x LCD_7 13 7 + * 0x73 0 x LCD_EN 5 8 + * 0x73 6 x LCD_WR 6 9 + * 0x73 7 x 1 LCD_RS 3 10 + */ +static const struct ts5500_dio ts5500_lcd[] = { + TS5500_DIO_GROUP(0x72, 0, 0x7d, 2), + TS5500_DIO_GROUP(0x72, 4, 0x7d, 3), + TS5500_DIO_OUT(0x73, 0), + TS5500_DIO_IN(0x73, 6), + TS5500_DIO_IN_IRQ(0x73, 7, 1), +}; + +static inline struct ts5500_priv *ts5500_gc_to_priv(struct gpio_chip *chip) +{ + return container_of(chip, struct ts5500_priv, gpio_chip); +} + +static inline void ts5500_set_mask(u8 mask, u8 addr) +{ + u8 val = inb(addr); + val |= mask; + outb(val, addr); +} + +static inline void ts5500_clear_mask(u8 mask, u8 addr) +{ + u8 val = inb(addr); + val &= ~mask; + outb(val, addr); +} + +static int ts5500_gpio_input(struct gpio_chip *chip, unsigned offset) +{ + struct ts5500_priv *priv = ts5500_gc_to_priv(chip); + const struct ts5500_dio line = priv->pinout[offset]; + unsigned long flags; + + if (line.no_input) + return -ENXIO; + + if (line.no_output) + return 0; + + spin_lock_irqsave(&priv->lock, flags); + ts5500_clear_mask(line.control_mask, line.control_addr); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int ts5500_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct ts5500_priv *priv = ts5500_gc_to_priv(chip); + const struct ts5500_dio line = priv->pinout[offset]; + + return !!(inb(line.value_addr) & line.value_mask); +} + +static int ts5500_gpio_output(struct gpio_chip *chip, unsigned offset, int val) +{ + struct ts5500_priv *priv = ts5500_gc_to_priv(chip); + const struct ts5500_dio line = priv->pinout[offset]; + unsigned long flags; + + if (line.no_output) + return -ENXIO; + + spin_lock_irqsave(&priv->lock, flags); + if (!line.no_input) + ts5500_set_mask(line.control_mask, line.control_addr); + + if (val) + ts5500_set_mask(line.value_mask, line.value_addr); + else + ts5500_clear_mask(line.value_mask, line.value_addr); + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static void ts5500_gpio_set(struct gpio_chip *chip, unsigned offset, int val) +{ + struct ts5500_priv *priv = ts5500_gc_to_priv(chip); + const struct ts5500_dio line = priv->pinout[offset]; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (val) + ts5500_set_mask(line.value_mask, line.value_addr); + else + ts5500_clear_mask(line.value_mask, line.value_addr); + spin_unlock_irqrestore(&priv->lock, flags); +} + +static int ts5500_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct ts5500_priv *priv = ts5500_gc_to_priv(chip); + const struct ts5500_dio *block = priv->pinout; + const struct ts5500_dio line = block[offset]; + + /* Only one pin is connected to an interrupt */ + if (line.irq) + return line.irq; + + /* As this pin is input-only, we may strap it to another in/out pin */ + if (priv->strap) + return priv->hwirq; + + return -ENXIO; +} + +static int ts5500_enable_irq(struct ts5500_priv *priv) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (priv->hwirq == 7) + ts5500_set_mask(BIT(7), 0x7a); /* DIO1_13 on IRQ7 */ + else if (priv->hwirq == 6) + ts5500_set_mask(BIT(7), 0x7d); /* DIO2_13 on IRQ6 */ + else if (priv->hwirq == 1) + ts5500_set_mask(BIT(6), 0x7d); /* LCD_RS on IRQ1 */ + else + ret = -EINVAL; + spin_unlock_irqrestore(&priv->lock, flags); + + return ret; +} + +static void ts5500_disable_irq(struct ts5500_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + if (priv->hwirq == 7) + ts5500_clear_mask(BIT(7), 0x7a); /* DIO1_13 on IRQ7 */ + else if (priv->hwirq == 6) + ts5500_clear_mask(BIT(7), 0x7d); /* DIO2_13 on IRQ6 */ + else if (priv->hwirq == 1) + ts5500_clear_mask(BIT(6), 0x7d); /* LCD_RS on IRQ1 */ + else + dev_err(priv->gpio_chip.dev, "invalid hwirq %d\n", priv->hwirq); + spin_unlock_irqrestore(&priv->lock, flags); +} + +static int __devinit ts5500_dio_probe(struct platform_device *pdev) +{ + enum ts5500_blocks block = platform_get_device_id(pdev)->driver_data; + struct ts5500_dio_platform_data *pdata = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + const char *name = dev_name(dev); + struct ts5500_priv *priv; + struct resource *res; + unsigned long flags; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(dev, "missing IRQ resource\n"); + return -EINVAL; + } + + priv = devm_kzalloc(dev, sizeof(struct ts5500_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + priv->hwirq = res->start; + spin_lock_init(&priv->lock); + + priv->gpio_chip.owner = THIS_MODULE; + priv->gpio_chip.label = name; + priv->gpio_chip.dev = dev; + priv->gpio_chip.direction_input = ts5500_gpio_input; + priv->gpio_chip.direction_output = ts5500_gpio_output; + priv->gpio_chip.get = ts5500_gpio_get; + priv->gpio_chip.set = ts5500_gpio_set; + priv->gpio_chip.to_irq = ts5500_gpio_to_irq; + priv->gpio_chip.base = -1; + if (pdata) { + priv->gpio_chip.base = pdata->base; + priv->strap = pdata->strap; + } + + switch (block) { + case TS5500_DIO1: + priv->pinout = ts5500_dio1; + priv->gpio_chip.ngpio = ARRAY_SIZE(ts5500_dio1); + + if (!devm_request_region(dev, 0x7a, 3, name)) { + dev_err(dev, "failed to request %s ports\n", name); + return -EBUSY; + } + break; + case TS5500_DIO2: + priv->pinout = ts5500_dio2; + priv->gpio_chip.ngpio = ARRAY_SIZE(ts5500_dio2); + + if (!devm_request_region(dev, 0x7e, 2, name)) { + dev_err(dev, "failed to request %s ports\n", name); + return -EBUSY; + } + + if (hex7d_reserved) + break; + + if (!devm_request_region(dev, 0x7d, 1, name)) { + dev_err(dev, "failed to request %s 7D\n", name); + return -EBUSY; + } + + hex7d_reserved = true; + break; + case TS5500_LCD: + case TS5600_LCD: + priv->pinout = ts5500_lcd; + priv->gpio_chip.ngpio = ARRAY_SIZE(ts5500_lcd); + + if (!devm_request_region(dev, 0x72, 2, name)) { + dev_err(dev, "failed to request %s ports\n", name); + return -EBUSY; + } + + if (!hex7d_reserved) { + if (!devm_request_region(dev, 0x7d, 1, name)) { + dev_err(dev, "failed to request %s 7D\n", name); + return -EBUSY; + } + + hex7d_reserved = true; + } + + /* Ensure usage of LCD port as DIO */ + spin_lock_irqsave(&priv->lock, flags); + ts5500_clear_mask(BIT(4), 0x7d); + spin_unlock_irqrestore(&priv->lock, flags); + break; + } + + ret = gpiochip_add(&priv->gpio_chip); + if (ret) { + dev_err(dev, "failed to register the gpio chip\n"); + return ret; + } + + ret = ts5500_enable_irq(priv); + if (ret) { + dev_err(dev, "invalid interrupt %d\n", priv->hwirq); + goto cleanup; + } + + return 0; +cleanup: + if (gpiochip_remove(&priv->gpio_chip)) + dev_err(dev, "failed to remove gpio chip\n"); + return ret; +} + +static int __devexit ts5500_dio_remove(struct platform_device *pdev) +{ + struct ts5500_priv *priv = platform_get_drvdata(pdev); + + ts5500_disable_irq(priv); + return gpiochip_remove(&priv->gpio_chip); +} + +static struct platform_device_id ts5500_dio_ids[] = { + { "ts5500-dio1", TS5500_DIO1 }, + { "ts5500-dio2", TS5500_DIO2 }, + { "ts5500-dio-lcd", TS5500_LCD }, + { "ts5600-dio-lcd", TS5600_LCD }, + { } +}; +MODULE_DEVICE_TABLE(platform, ts5500_dio_ids); + +static struct platform_driver ts5500_dio_driver = { + .driver = { + .name = "ts5500-dio", + .owner = THIS_MODULE, + }, + .probe = ts5500_dio_probe, + .remove = __devexit_p(ts5500_dio_remove), + .id_table = ts5500_dio_ids, +}; + +module_platform_driver(ts5500_dio_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>"); +MODULE_DESCRIPTION("Technologic Systems TS-5500 Digital I/O driver"); diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index c5f8ca233e1..00329f2fc05 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -88,11 +88,15 @@ static inline int gpio_twl4030_write(u8 address, u8 data) /*----------------------------------------------------------------------*/ /* - * LED register offsets (use TWL4030_MODULE_{LED,PWMA,PWMB})) + * LED register offsets from TWL_MODULE_LED base * PWMs A and B are dedicated to LEDs A and B, respectively. */ -#define TWL4030_LED_LEDEN 0x0 +#define TWL4030_LED_LEDEN_REG 0x00 +#define TWL4030_PWMAON_REG 0x01 +#define TWL4030_PWMAOFF_REG 0x02 +#define TWL4030_PWMBON_REG 0x03 +#define TWL4030_PWMBOFF_REG 0x04 /* LEDEN bits */ #define LEDEN_LEDAON BIT(0) @@ -104,9 +108,6 @@ static inline int gpio_twl4030_write(u8 address, u8 data) #define LEDEN_PWM_LENGTHA BIT(6) #define LEDEN_PWM_LENGTHB BIT(7) -#define TWL4030_PWMx_PWMxON 0x0 -#define TWL4030_PWMx_PWMxOFF 0x1 - #define PWMxON_LENGTH BIT(7) /*----------------------------------------------------------------------*/ @@ -145,7 +146,7 @@ static void twl4030_led_set_value(int led, int value) else cached_leden |= mask; status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, - TWL4030_LED_LEDEN); + TWL4030_LED_LEDEN_REG); mutex_unlock(&gpio_lock); } @@ -216,33 +217,33 @@ static int twl_request(struct gpio_chip *chip, unsigned offset) if (offset >= TWL4030_GPIO_MAX) { u8 ledclr_mask = LEDEN_LEDAON | LEDEN_LEDAEXT | LEDEN_LEDAPWM | LEDEN_PWM_LENGTHA; - u8 module = TWL4030_MODULE_PWMA; + u8 reg = TWL4030_PWMAON_REG; offset -= TWL4030_GPIO_MAX; if (offset) { ledclr_mask <<= 1; - module = TWL4030_MODULE_PWMB; + reg = TWL4030_PWMBON_REG; } /* initialize PWM to always-drive */ - status = twl_i2c_write_u8(module, 0x7f, - TWL4030_PWMx_PWMxOFF); + /* Configure PWM OFF register first */ + status = twl_i2c_write_u8(TWL4030_MODULE_LED, 0x7f, reg + 1); if (status < 0) goto done; - status = twl_i2c_write_u8(module, 0x7f, - TWL4030_PWMx_PWMxON); + + /* Followed by PWM ON register */ + status = twl_i2c_write_u8(TWL4030_MODULE_LED, 0x7f, reg); if (status < 0) goto done; /* init LED to not-driven (high) */ - module = TWL4030_MODULE_LED; - status = twl_i2c_read_u8(module, &cached_leden, - TWL4030_LED_LEDEN); + status = twl_i2c_read_u8(TWL4030_MODULE_LED, &cached_leden, + TWL4030_LED_LEDEN_REG); if (status < 0) goto done; cached_leden &= ~ledclr_mask; - status = twl_i2c_write_u8(module, cached_leden, - TWL4030_LED_LEDEN); + status = twl_i2c_write_u8(TWL4030_MODULE_LED, cached_leden, + TWL4030_LED_LEDEN_REG); if (status < 0) goto done; @@ -352,7 +353,7 @@ static struct gpio_chip twl_gpiochip = { /*----------------------------------------------------------------------*/ -static int __devinit gpio_twl4030_pulls(u32 ups, u32 downs) +static int gpio_twl4030_pulls(u32 ups, u32 downs) { u8 message[6]; unsigned i, gpio_bit; @@ -377,7 +378,7 @@ static int __devinit gpio_twl4030_pulls(u32 ups, u32 downs) REG_GPIOPUPDCTR1, 5); } -static int __devinit gpio_twl4030_debounce(u32 debounce, u8 mmc_cd) +static int gpio_twl4030_debounce(u32 debounce, u8 mmc_cd) { u8 message[4]; @@ -419,7 +420,7 @@ static struct twl4030_gpio_platform_data *of_gpio_twl4030(struct device *dev) return omap_twl_info; } -static int __devinit gpio_twl4030_probe(struct platform_device *pdev) +static int gpio_twl4030_probe(struct platform_device *pdev) { struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; struct device_node *node = pdev->dev.of_node; @@ -505,7 +506,7 @@ out: return ret; } -/* Cannot use __devexit as gpio_twl4030_probe() calls us */ +/* Cannot use as gpio_twl4030_probe() calls us */ static int gpio_twl4030_remove(struct platform_device *pdev) { struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data; diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c index dd58e8b2504..0be82c6dd79 100644 --- a/drivers/gpio/gpio-twl6040.c +++ b/drivers/gpio/gpio-twl6040.c @@ -82,7 +82,7 @@ static struct gpio_chip twl6040gpo_chip = { /*----------------------------------------------------------------------*/ -static int __devinit gpo_twl6040_probe(struct platform_device *pdev) +static int gpo_twl6040_probe(struct platform_device *pdev) { struct twl6040_gpo_data *pdata = pdev->dev.platform_data; struct device *twl6040_core_dev = pdev->dev.parent; @@ -113,7 +113,7 @@ static int __devinit gpo_twl6040_probe(struct platform_device *pdev) return ret; } -static int __devexit gpo_twl6040_remove(struct platform_device *pdev) +static int gpo_twl6040_remove(struct platform_device *pdev) { return gpiochip_remove(&twl6040gpo_chip); } diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c index 82d5c20ad3c..9902732a382 100644 --- a/drivers/gpio/gpio-vr41xx.c +++ b/drivers/gpio/gpio-vr41xx.c @@ -490,7 +490,7 @@ static struct gpio_chip vr41xx_gpio_chip = { .to_irq = vr41xx_gpio_to_irq, }; -static int __devinit giu_probe(struct platform_device *pdev) +static int giu_probe(struct platform_device *pdev) { struct resource *res; unsigned int trigger, i, pin; @@ -552,7 +552,7 @@ static int __devinit giu_probe(struct platform_device *pdev) return cascade_irq(irq, giu_get_irq); } -static int __devexit giu_remove(struct platform_device *pdev) +static int giu_remove(struct platform_device *pdev) { if (giu_base) { iounmap(giu_base); @@ -564,7 +564,7 @@ static int __devexit giu_remove(struct platform_device *pdev) static struct platform_driver giu_device_driver = { .probe = giu_probe, - .remove = __devexit_p(giu_remove), + .remove = giu_remove, .driver = { .name = "GIU", .owner = THIS_MODULE, diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c index bcd8e4aa7c7..b53320a16fc 100644 --- a/drivers/gpio/gpio-vt8500.c +++ b/drivers/gpio/gpio-vt8500.c @@ -96,6 +96,7 @@ static struct vt8500_gpio_data wm8505_data = { VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12), VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16), VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22), + VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6), }, }; @@ -115,6 +116,7 @@ static struct vt8500_gpio_data wm8650_data = { VT8500_BANK(0x58, 0x98, 0xD8, 0x18, 32), VT8500_BANK(0x5C, 0x9C, 0xDC, 0x1C, 32), VT8500_BANK(0x7C, 0xBC, 0xFC, 0x3C, 32), + VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6), }, }; @@ -269,7 +271,7 @@ static struct of_device_id vt8500_gpio_dt_ids[] = { { /* Sentinel */ }, }; -static int __devinit vt8500_gpio_probe(struct platform_device *pdev) +static int vt8500_gpio_probe(struct platform_device *pdev) { void __iomem *gpio_base; struct device_node *np; diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c index 76ebfe5ff70..2b7252cb242 100644 --- a/drivers/gpio/gpio-vx855.c +++ b/drivers/gpio/gpio-vx855.c @@ -219,7 +219,7 @@ static void vx855gpio_gpio_setup(struct vx855_gpio *vg) } /* This platform device is ordinarily registered by the vx855 mfd driver */ -static __devinit int vx855gpio_probe(struct platform_device *pdev) +static int vx855gpio_probe(struct platform_device *pdev) { struct resource *res_gpi; struct resource *res_gpo; @@ -284,7 +284,7 @@ out_release: return ret; } -static int __devexit vx855gpio_remove(struct platform_device *pdev) +static int vx855gpio_remove(struct platform_device *pdev) { struct vx855_gpio *vg = platform_get_drvdata(pdev); struct resource *res; @@ -312,7 +312,7 @@ static struct platform_driver vx855gpio_driver = { .owner = THIS_MODULE, }, .probe = vx855gpio_probe, - .remove = __devexit_p(vx855gpio_remove), + .remove = vx855gpio_remove, }; module_platform_driver(vx855gpio_driver); diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c index b6eda35089d..2a743e10ecb 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/gpio-wm831x.c @@ -243,7 +243,7 @@ static struct gpio_chip template_chip = { .can_sleep = 1, }; -static int __devinit wm831x_gpio_probe(struct platform_device *pdev) +static int wm831x_gpio_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *pdata = wm831x->dev->platform_data; @@ -275,7 +275,7 @@ static int __devinit wm831x_gpio_probe(struct platform_device *pdev) return ret; } -static int __devexit wm831x_gpio_remove(struct platform_device *pdev) +static int wm831x_gpio_remove(struct platform_device *pdev) { struct wm831x_gpio *wm831x_gpio = platform_get_drvdata(pdev); @@ -286,7 +286,7 @@ static struct platform_driver wm831x_gpio_driver = { .driver.name = "wm831x-gpio", .driver.owner = THIS_MODULE, .probe = wm831x_gpio_probe, - .remove = __devexit_p(wm831x_gpio_remove), + .remove = wm831x_gpio_remove, }; static int __init wm831x_gpio_init(void) diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c index fb429388939..0b598cf3df9 100644 --- a/drivers/gpio/gpio-wm8350.c +++ b/drivers/gpio/gpio-wm8350.c @@ -109,7 +109,7 @@ static struct gpio_chip template_chip = { .can_sleep = 1, }; -static int __devinit wm8350_gpio_probe(struct platform_device *pdev) +static int wm8350_gpio_probe(struct platform_device *pdev) { struct wm8350 *wm8350 = dev_get_drvdata(pdev->dev.parent); struct wm8350_platform_data *pdata = wm8350->dev->platform_data; @@ -141,7 +141,7 @@ static int __devinit wm8350_gpio_probe(struct platform_device *pdev) return ret; } -static int __devexit wm8350_gpio_remove(struct platform_device *pdev) +static int wm8350_gpio_remove(struct platform_device *pdev) { struct wm8350_gpio_data *wm8350_gpio = platform_get_drvdata(pdev); @@ -152,7 +152,7 @@ static struct platform_driver wm8350_gpio_driver = { .driver.name = "wm8350-gpio", .driver.owner = THIS_MODULE, .probe = wm8350_gpio_probe, - .remove = __devexit_p(wm8350_gpio_remove), + .remove = wm8350_gpio_remove, }; static int __init wm8350_gpio_init(void) diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c index 1c764e779d8..ae409fd94af 100644 --- a/drivers/gpio/gpio-wm8994.c +++ b/drivers/gpio/gpio-wm8994.c @@ -245,7 +245,7 @@ static struct gpio_chip template_chip = { .can_sleep = 1, }; -static int __devinit wm8994_gpio_probe(struct platform_device *pdev) +static int wm8994_gpio_probe(struct platform_device *pdev) { struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent); struct wm8994_pdata *pdata = wm8994->dev->platform_data; @@ -281,7 +281,7 @@ err: return ret; } -static int __devexit wm8994_gpio_remove(struct platform_device *pdev) +static int wm8994_gpio_remove(struct platform_device *pdev) { struct wm8994_gpio *wm8994_gpio = platform_get_drvdata(pdev); @@ -292,7 +292,7 @@ static struct platform_driver wm8994_gpio_driver = { .driver.name = "wm8994-gpio", .driver.owner = THIS_MODULE, .probe = wm8994_gpio_probe, - .remove = __devexit_p(wm8994_gpio_remove), + .remove = wm8994_gpio_remove, }; static int __init wm8994_gpio_init(void) diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index 79b0fe8a725..9ae7aa8ca48 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -159,7 +159,7 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) * driver data structure. It returns 0, if the driver is bound to the GPIO * device, or a negative value if there is an error. */ -static int __devinit xgpio_of_probe(struct device_node *np) +static int xgpio_of_probe(struct device_node *np) { struct xgpio_instance *chip; int status = 0; @@ -209,7 +209,7 @@ static int __devinit xgpio_of_probe(struct device_node *np) return 0; } -static struct of_device_id xgpio_of_match[] __devinitdata = { +static struct of_device_id xgpio_of_match[] = { { .compatible = "xlnx,xps-gpio-1.00.a", }, { /* end of list */ }, }; diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c new file mode 100644 index 00000000000..cbad6e908d3 --- /dev/null +++ b/drivers/gpio/gpiolib-acpi.c @@ -0,0 +1,54 @@ +/* + * ACPI helpers for GPIO API + * + * Copyright (C) 2012, Intel Corporation + * Authors: Mathias Nyman <mathias.nyman@linux.intel.com> + * Mika Westerberg <mika.westerberg@linux.intel.com> + * + * 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/errno.h> +#include <linux/gpio.h> +#include <linux/export.h> +#include <linux/acpi_gpio.h> +#include <linux/acpi.h> + +static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) +{ + if (!gc->dev) + return false; + + return ACPI_HANDLE(gc->dev) == data; +} + +/** + * acpi_get_gpio() - Translate ACPI GPIO pin to GPIO number usable with GPIO API + * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1") + * @pin: ACPI GPIO pin number (0-based, controller-relative) + * + * Returns GPIO number to use with Linux generic GPIO API, or errno error value + */ + +int acpi_get_gpio(char *path, int pin) +{ + struct gpio_chip *chip; + acpi_handle handle; + acpi_status status; + + status = acpi_get_handle(NULL, path, &handle); + if (ACPI_FAILURE(status)) + return -ENODEV; + + chip = gpiochip_find(handle, acpi_gpiochip_find); + if (!chip) + return -ENODEV; + + if (!gpio_is_valid(chip->base + pin)) + return -EINVAL; + + return chip->base + pin; +} +EXPORT_SYMBOL_GPL(acpi_get_gpio); diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index f1a45997aea..d542a141811 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -19,6 +19,7 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_gpio.h> +#include <linux/pinctrl/pinctrl.h> #include <linux/slab.h> /* Private data structure for of_gpiochip_find_and_xlate */ @@ -216,6 +217,54 @@ err0: } EXPORT_SYMBOL(of_mm_gpiochip_add); +#ifdef CONFIG_PINCTRL +static void of_gpiochip_add_pin_range(struct gpio_chip *chip) +{ + struct device_node *np = chip->of_node; + struct of_phandle_args pinspec; + struct pinctrl_dev *pctldev; + int index = 0, ret; + + if (!np) + return; + + do { + ret = of_parse_phandle_with_args(np, "gpio-ranges", + "#gpio-range-cells", index, &pinspec); + if (ret) + break; + + pctldev = of_pinctrl_get(pinspec.np); + if (!pctldev) + break; + + /* + * This assumes that the n GPIO pins are consecutive in the + * GPIO number space, and that the pins are also consecutive + * in their local number space. Currently it is not possible + * to add different ranges for one and the same GPIO chip, + * as the code assumes that we have one consecutive range + * on both, mapping 1-to-1. + * + * TODO: make the OF bindings handle multiple sparse ranges + * on the same GPIO chip. + */ + ret = gpiochip_add_pin_range(chip, + pinctrl_dev_get_name(pctldev), + 0, /* offset in gpiochip */ + pinspec.args[0], + pinspec.args[1]); + + if (ret) + break; + + } while (index++); +} + +#else +static void of_gpiochip_add_pin_range(struct gpio_chip *chip) {} +#endif + void of_gpiochip_add(struct gpio_chip *chip) { if ((!chip->of_node) && (chip->dev)) @@ -229,11 +278,14 @@ void of_gpiochip_add(struct gpio_chip *chip) chip->of_xlate = of_gpio_simple_xlate; } + of_gpiochip_add_pin_range(chip); of_node_get(chip->of_node); } void of_gpiochip_remove(struct gpio_chip *chip) { + gpiochip_remove_pin_ranges(chip); + if (chip->of_node) of_node_put(chip->of_node); } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 1c8d9e3380e..199fca15f27 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -191,6 +191,32 @@ err: return ret; } +/* caller ensures gpio is valid and requested, chip->get_direction may sleep */ +static int gpio_get_direction(unsigned gpio) +{ + struct gpio_chip *chip; + struct gpio_desc *desc = &gpio_desc[gpio]; + int status = -EINVAL; + + chip = gpio_to_chip(gpio); + gpio -= chip->base; + + if (!chip->get_direction) + return status; + + status = chip->get_direction(chip, gpio); + if (status > 0) { + /* GPIOF_DIR_IN, or other positive */ + status = 1; + clear_bit(FLAG_IS_OUT, &desc->flags); + } + if (status == 0) { + /* GPIOF_DIR_OUT */ + set_bit(FLAG_IS_OUT, &desc->flags); + } + return status; +} + #ifdef CONFIG_GPIO_SYSFS /* lock protects against unexport_gpio() being called while @@ -223,6 +249,7 @@ static ssize_t gpio_direction_show(struct device *dev, struct device_attribute *attr, char *buf) { const struct gpio_desc *desc = dev_get_drvdata(dev); + unsigned gpio = desc - gpio_desc; ssize_t status; mutex_lock(&sysfs_lock); @@ -230,6 +257,7 @@ static ssize_t gpio_direction_show(struct device *dev, if (!test_bit(FLAG_EXPORT, &desc->flags)) status = -EIO; else + gpio_get_direction(gpio); status = sprintf(buf, "%s\n", test_bit(FLAG_IS_OUT, &desc->flags) ? "out" : "in"); @@ -704,8 +732,9 @@ int gpio_export(unsigned gpio, bool direction_may_change) { unsigned long flags; struct gpio_desc *desc; - int status = -EINVAL; + int status; const char *ioname = NULL; + struct device *dev; /* can't export until sysfs is available ... */ if (!gpio_class.p) { @@ -713,59 +742,66 @@ int gpio_export(unsigned gpio, bool direction_may_change) return -ENOENT; } - if (!gpio_is_valid(gpio)) - goto done; + if (!gpio_is_valid(gpio)) { + pr_debug("%s: gpio %d is not valid\n", __func__, gpio); + return -EINVAL; + } mutex_lock(&sysfs_lock); spin_lock_irqsave(&gpio_lock, flags); desc = &gpio_desc[gpio]; - if (test_bit(FLAG_REQUESTED, &desc->flags) - && !test_bit(FLAG_EXPORT, &desc->flags)) { - status = 0; - if (!desc->chip->direction_input - || !desc->chip->direction_output) - direction_may_change = false; + if (!test_bit(FLAG_REQUESTED, &desc->flags) || + test_bit(FLAG_EXPORT, &desc->flags)) { + spin_unlock_irqrestore(&gpio_lock, flags); + pr_debug("%s: gpio %d unavailable (requested=%d, exported=%d)\n", + __func__, gpio, + test_bit(FLAG_REQUESTED, &desc->flags), + test_bit(FLAG_EXPORT, &desc->flags)); + status = -EPERM; + goto fail_unlock; } + + if (!desc->chip->direction_input || !desc->chip->direction_output) + direction_may_change = false; spin_unlock_irqrestore(&gpio_lock, flags); if (desc->chip->names && desc->chip->names[gpio - desc->chip->base]) ioname = desc->chip->names[gpio - desc->chip->base]; - if (status == 0) { - struct device *dev; - - dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), - desc, ioname ? ioname : "gpio%u", gpio); - if (!IS_ERR(dev)) { - status = sysfs_create_group(&dev->kobj, - &gpio_attr_group); - - if (!status && direction_may_change) - status = device_create_file(dev, - &dev_attr_direction); - - if (!status && gpio_to_irq(gpio) >= 0 - && (direction_may_change - || !test_bit(FLAG_IS_OUT, - &desc->flags))) - status = device_create_file(dev, - &dev_attr_edge); - - if (status != 0) - device_unregister(dev); - } else - status = PTR_ERR(dev); - if (status == 0) - set_bit(FLAG_EXPORT, &desc->flags); + dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0), + desc, ioname ? ioname : "gpio%u", gpio); + if (IS_ERR(dev)) { + status = PTR_ERR(dev); + goto fail_unlock; } - mutex_unlock(&sysfs_lock); - -done: + status = sysfs_create_group(&dev->kobj, &gpio_attr_group); if (status) - pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); + goto fail_unregister_device; + + if (direction_may_change) { + status = device_create_file(dev, &dev_attr_direction); + if (status) + goto fail_unregister_device; + } + + if (gpio_to_irq(gpio) >= 0 && (direction_may_change || + !test_bit(FLAG_IS_OUT, &desc->flags))) { + status = device_create_file(dev, &dev_attr_edge); + if (status) + goto fail_unregister_device; + } + + set_bit(FLAG_EXPORT, &desc->flags); + mutex_unlock(&sysfs_lock); + return 0; +fail_unregister_device: + device_unregister(dev); +fail_unlock: + mutex_unlock(&sysfs_lock); + pr_debug("%s: gpio%d status %d\n", __func__, gpio, status); return status; } EXPORT_SYMBOL_GPL(gpio_export); @@ -1075,6 +1111,7 @@ int gpiochip_add(struct gpio_chip *chip) * inputs (often with pullups enabled) so power * usage is minimized. Linux code should set the * gpio direction first thing; but until it does, + * and in case chip->get_direction is not set, * we may expose the wrong direction in sysfs. */ gpio_desc[id].flags = !chip->direction_input @@ -1083,6 +1120,10 @@ int gpiochip_add(struct gpio_chip *chip) } } +#ifdef CONFIG_PINCTRL + INIT_LIST_HEAD(&chip->pin_ranges); +#endif + of_gpiochip_add(chip); unlock: @@ -1123,6 +1164,7 @@ int gpiochip_remove(struct gpio_chip *chip) spin_lock_irqsave(&gpio_lock, flags); + gpiochip_remove_pin_ranges(chip); of_gpiochip_remove(chip); for (id = chip->base; id < chip->base + chip->ngpio; id++) { @@ -1180,6 +1222,77 @@ struct gpio_chip *gpiochip_find(void *data, } EXPORT_SYMBOL_GPL(gpiochip_find); +#ifdef CONFIG_PINCTRL + +/** + * gpiochip_add_pin_range() - add a range for GPIO <-> pin mapping + * @chip: the gpiochip to add the range for + * @pinctrl_name: the dev_name() of the pin controller to map to + * @gpio_offset: the start offset in the current gpio_chip number space + * @pin_offset: the start offset in the pin controller number space + * @npins: the number of pins from the offset of each pin space (GPIO and + * pin controller) to accumulate in this range + */ +int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name, + unsigned int gpio_offset, unsigned int pin_offset, + unsigned int npins) +{ + struct gpio_pin_range *pin_range; + int ret; + + pin_range = kzalloc(sizeof(*pin_range), GFP_KERNEL); + if (!pin_range) { + pr_err("%s: GPIO chip: failed to allocate pin ranges\n", + chip->label); + return -ENOMEM; + } + + /* Use local offset as range ID */ + pin_range->range.id = gpio_offset; + pin_range->range.gc = chip; + pin_range->range.name = chip->label; + pin_range->range.base = chip->base + gpio_offset; + pin_range->range.pin_base = pin_offset; + pin_range->range.npins = npins; + pin_range->pctldev = pinctrl_find_and_add_gpio_range(pinctl_name, + &pin_range->range); + if (IS_ERR(pin_range->pctldev)) { + ret = PTR_ERR(pin_range->pctldev); + pr_err("%s: GPIO chip: could not create pin range\n", + chip->label); + kfree(pin_range); + return ret; + } + pr_debug("GPIO chip %s: created GPIO range %d->%d ==> %s PIN %d->%d\n", + chip->label, gpio_offset, gpio_offset + npins - 1, + pinctl_name, + pin_offset, pin_offset + npins - 1); + + list_add_tail(&pin_range->node, &chip->pin_ranges); + + return 0; +} +EXPORT_SYMBOL_GPL(gpiochip_add_pin_range); + +/** + * gpiochip_remove_pin_ranges() - remove all the GPIO <-> pin mappings + * @chip: the chip to remove all the mappings for + */ +void gpiochip_remove_pin_ranges(struct gpio_chip *chip) +{ + struct gpio_pin_range *pin_range, *tmp; + + list_for_each_entry_safe(pin_range, tmp, &chip->pin_ranges, node) { + list_del(&pin_range->node); + pinctrl_remove_gpio_range(pin_range->pctldev, + &pin_range->range); + kfree(pin_range); + } +} +EXPORT_SYMBOL_GPL(gpiochip_remove_pin_ranges); + +#endif /* CONFIG_PINCTRL */ + /* These "optional" allocation calls help prevent drivers from stomping * on each other, and help provide better diagnostics in debugfs. * They're called even less than the "set direction" calls. @@ -1228,9 +1341,15 @@ int gpio_request(unsigned gpio, const char *label) desc_set_label(desc, NULL); module_put(chip->owner); clear_bit(FLAG_REQUESTED, &desc->flags); + goto done; } } - + if (chip->get_direction) { + /* chip->get_direction may sleep */ + spin_unlock_irqrestore(&gpio_lock, flags); + gpio_get_direction(gpio); + spin_lock_irqsave(&gpio_lock, flags); + } done: if (status) pr_debug("gpio_request: gpio-%d (%s) status %d\n", @@ -1766,6 +1885,7 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip) if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) continue; + gpio_get_direction(gpio); is_out = test_bit(FLAG_IS_OUT, &gdesc->flags); seq_printf(s, " gpio-%-3d (%-20.20s) %s %s", gpio, gdesc->label, diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c index 241ad1eeec6..f2df06c603f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -226,6 +226,12 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder) * already updated or not by exynos_drm_encoder_dpms function. */ exynos_encoder->updated = true; + + /* + * In case of setcrtc, there is no way to update encoder's dpms + * so update it here. + */ + exynos_encoder->dpms = DRM_MODE_DPMS_ON; } static void exynos_drm_encoder_disable(struct drm_encoder *encoder) @@ -507,6 +513,6 @@ void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data) * because the setting for disabling the overlay will be updated * at vsync. */ - if (overlay_ops->wait_for_vblank) + if (overlay_ops && overlay_ops->wait_for_vblank) overlay_ops->wait_for_vblank(manager->dev); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 67eb6ba56ed..e7466c4414c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -87,7 +87,8 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, dev->mode_config.fb_base = (resource_size_t)buffer->dma_addr; fbi->screen_base = buffer->kvaddr + offset; - fbi->fix.smem_start = (unsigned long)(buffer->dma_addr + offset); + fbi->fix.smem_start = (unsigned long)(page_to_phys(buffer->pages[0]) + + offset); fbi->screen_size = size; fbi->fix.smem_len = size; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 130a2b510d4..e08478f19f1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -61,11 +61,11 @@ struct fimd_driver_data { unsigned int timing_base; }; -struct fimd_driver_data exynos4_fimd_driver_data = { +static struct fimd_driver_data exynos4_fimd_driver_data = { .timing_base = 0x0, }; -struct fimd_driver_data exynos5_fimd_driver_data = { +static struct fimd_driver_data exynos5_fimd_driver_data = { .timing_base = 0x20000, }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 60b877a388c..862ca1eb210 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -204,7 +204,6 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, return ret; plane->crtc = crtc; - plane->fb = crtc->fb; exynos_plane_commit(plane); exynos_plane_dpms(plane, DRM_MODE_DPMS_ON); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 107f09befe9..9b285da4449 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1796,7 +1796,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) */ mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping; gfp = mapping_gfp_mask(mapping); - gfp |= __GFP_NORETRY | __GFP_NOWARN; + gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD; gfp &= ~(__GFP_IO | __GFP_WAIT); for_each_sg(st->sgl, sg, page_count, i) { page = shmem_read_mapping_page_gfp(mapping, i, gfp); @@ -1809,7 +1809,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) * our own buffer, now let the real VM do its job and * go down in flames if truly OOM. */ - gfp &= ~(__GFP_NORETRY | __GFP_NOWARN); + gfp &= ~(__GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD); gfp |= __GFP_IO | __GFP_WAIT; i915_gem_shrink_all(dev_priv); @@ -1817,7 +1817,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) if (IS_ERR(page)) goto err_pages; - gfp |= __GFP_NORETRY | __GFP_NOWARN; + gfp |= __GFP_NORETRY | __GFP_NOWARN | __GFP_NO_KSWAPD; gfp &= ~(__GFP_IO | __GFP_WAIT); } diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 0ed6baff4b0..56846ed5ee5 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -499,12 +499,8 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb) edp = find_section(bdb, BDB_EDP); if (!edp) { - if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) { - DRM_DEBUG_KMS("No eDP BDB found but eDP panel " - "supported, assume %dbpp panel color " - "depth.\n", - dev_priv->edp.bpp); - } + if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp.support) + DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported.\n"); return; } @@ -657,9 +653,6 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) dev_priv->lvds_use_ssc = 1; dev_priv->lvds_ssc_freq = intel_bios_ssc_frequency(dev, 1); DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->lvds_ssc_freq); - - /* eDP data */ - dev_priv->edp.bpp = 18; } static int __init intel_no_opregion_vbt_callback(const struct dmi_system_id *id) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4154bcd7a07..b426d44a2b0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3845,7 +3845,7 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, /* Use VBT settings if we have an eDP panel */ unsigned int edp_bpc = dev_priv->edp.bpp / 3; - if (edp_bpc < display_bpc) { + if (edp_bpc && edp_bpc < display_bpc) { DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc); display_bpc = edp_bpc; } diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 72f41aaa71f..442968f8b20 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2373,15 +2373,9 @@ int intel_enable_rc6(const struct drm_device *dev) if (i915_enable_rc6 >= 0) return i915_enable_rc6; - if (INTEL_INFO(dev)->gen == 5) { -#ifdef CONFIG_INTEL_IOMMU - /* Disable rc6 on ilk if VT-d is on. */ - if (intel_iommu_gfx_mapped) - return false; -#endif - DRM_DEBUG_DRIVER("Ironlake: only RC6 available\n"); - return INTEL_RC6_ENABLE; - } + /* Disable RC6 on Ironlake */ + if (INTEL_INFO(dev)->gen == 5) + return 0; if (IS_HASWELL(dev)) { DRM_DEBUG_DRIVER("Haswell: only RC6 available\n"); diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index c600fb06e25..a6ac0b41696 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -2201,7 +2201,6 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device) connector->connector_type = DRM_MODE_CONNECTOR_HDMIA; intel_sdvo->is_hdmi = true; } - intel_sdvo->base.cloneable = true; intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); if (intel_sdvo->is_hdmi) @@ -2232,7 +2231,6 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type) intel_sdvo->is_tv = true; intel_sdvo->base.needs_tv_clock = true; - intel_sdvo->base.cloneable = false; intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); @@ -2275,8 +2273,6 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1; } - intel_sdvo->base.cloneable = true; - intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); return true; @@ -2307,9 +2303,6 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device) intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1; } - /* SDVO LVDS is not cloneable because the input mode gets adjusted by the encoder */ - intel_sdvo->base.cloneable = false; - intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo); if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector)) goto err; @@ -2721,6 +2714,16 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) goto err_output; } + /* + * Cloning SDVO with anything is often impossible, since the SDVO + * encoder can request a special input timing mode. And even if that's + * not the case we have evidence that cloning a plain unscaled mode with + * VGA doesn't really work. Furthermore the cloning flags are way too + * simplistic anyway to express such constraints, so just give up on + * cloning for SDVO encoders. + */ + intel_sdvo->base.cloneable = false; + /* Only enable the hotplug irq if we need it, to work around noisy * hotplug lines. */ diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index 05a909a17ce..15b182c84ce 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -49,13 +49,7 @@ nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc) if (chan->vblank.crtc != crtc) continue; - if (nv_device(priv)->chipset == 0x50) { - nv_wr32(priv, 0x001704, chan->vblank.channel); - nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma); - bar->flush(bar); - nv_wr32(priv, 0x001570, chan->vblank.offset); - nv_wr32(priv, 0x001574, chan->vblank.value); - } else { + if (nv_device(priv)->chipset >= 0xc0) { nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel); bar->flush(bar); nv_wr32(priv, 0x06000c, @@ -63,6 +57,17 @@ nv50_disp_intr_vblank(struct nv50_disp_priv *priv, int crtc) nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset)); nv_wr32(priv, 0x060014, chan->vblank.value); + } else { + nv_wr32(priv, 0x001704, chan->vblank.channel); + nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma); + bar->flush(bar); + if (nv_device(priv)->chipset == 0x50) { + nv_wr32(priv, 0x001570, chan->vblank.offset); + nv_wr32(priv, 0x001574, chan->vblank.value); + } else { + nv_wr32(priv, 0x060010, chan->vblank.offset); + nv_wr32(priv, 0x060014, chan->vblank.value); + } } list_del(&chan->vblank.head); diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c index e45035efb8c..7bbb1e1b7a8 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c @@ -669,21 +669,27 @@ nv40_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem) }); } -void +int nv40_grctx_init(struct nouveau_device *device, u32 *size) { - u32 ctxprog[256], i; + u32 *ctxprog = kmalloc(256 * 4, GFP_KERNEL), i; struct nouveau_grctx ctx = { .device = device, .mode = NOUVEAU_GRCTX_PROG, .data = ctxprog, - .ctxprog_max = ARRAY_SIZE(ctxprog) + .ctxprog_max = 256, }; + if (!ctxprog) + return -ENOMEM; + nv40_grctx_generate(&ctx); nv_wr32(device, 0x400324, 0); for (i = 0; i < ctx.ctxprog_len; i++) nv_wr32(device, 0x400328, ctxprog[i]); *size = ctx.ctxvals_pos * 4; + + kfree(ctxprog); + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c index 425001204a8..cc6574eeb80 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c @@ -346,7 +346,9 @@ nv40_graph_init(struct nouveau_object *object) return ret; /* generate and upload context program */ - nv40_grctx_init(nv_device(priv), &priv->size); + ret = nv40_grctx_init(nv_device(priv), &priv->size); + if (ret) + return ret; /* No context present currently */ nv_wr32(priv, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h index d2ac975afc2..7da35a4e797 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h @@ -15,7 +15,7 @@ nv44_graph_class(void *priv) return !(0x0baf & (1 << (device->chipset & 0x0f))); } -void nv40_grctx_init(struct nouveau_device *, u32 *size); +int nv40_grctx_init(struct nouveau_device *, u32 *size); void nv40_grctx_fill(struct nouveau_device *, struct nouveau_gpuobj *); #endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/object.h b/drivers/gpu/drm/nouveau/core/include/core/object.h index 818feabbf4a..486f1a9217f 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/object.h +++ b/drivers/gpu/drm/nouveau/core/include/core/object.h @@ -175,14 +175,18 @@ nv_mo32(void *obj, u32 addr, u32 mask, u32 data) return temp; } -static inline bool -nv_strncmp(void *obj, u32 addr, u32 len, const char *str) +static inline int +nv_memcmp(void *obj, u32 addr, const char *str, u32 len) { + unsigned char c1, c2; + while (len--) { - if (nv_ro08(obj, addr++) != *(str++)) - return false; + c1 = nv_ro08(obj, addr++); + c2 = *(str++); + if (c1 != c2) + return c1 - c2; } - return true; + return 0; } #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h index 39e73b91d36..41b7a6a76f1 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h @@ -54,6 +54,7 @@ int nv04_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *, int clk, struct nouveau_pll_vals *); int nv04_clock_pll_prog(struct nouveau_clock *, u32 reg1, struct nouveau_pll_vals *); - +int nva3_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *, + int clk, struct nouveau_pll_vals *); #endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c index 7d750382a83..c5119715774 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c @@ -64,7 +64,7 @@ dcb_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) } } else if (*ver >= 0x15) { - if (!nv_strncmp(bios, dcb - 7, 7, "DEV_REC")) { + if (!nv_memcmp(bios, dcb - 7, "DEV_REC", 7)) { u16 i2c = nv_ro16(bios, dcb + 2); *hdr = 4; *cnt = (i2c - dcb) / 10; diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c index cc8d7d162d7..9068c98b96f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c @@ -66,6 +66,24 @@ nva3_clock_pll_set(struct nouveau_clock *clk, u32 type, u32 freq) return ret; } +int +nva3_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info, + int clk, struct nouveau_pll_vals *pv) +{ + int ret, N, M, P; + + ret = nva3_pll_calc(clock, info, clk, &N, NULL, &M, &P); + + if (ret > 0) { + pv->refclk = info->refclk; + pv->N1 = N; + pv->M1 = M; + pv->log2P = P; + } + return ret; +} + + static int nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -80,6 +98,7 @@ nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return ret; priv->base.pll_set = nva3_clock_pll_set; + priv->base.pll_calc = nva3_clock_pll_calc; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c index 5ccce0b17bf..f6962c9b6c3 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c @@ -79,6 +79,7 @@ nvc0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return ret; priv->base.pll_set = nvc0_clock_pll_set; + priv->base.pll_calc = nva3_clock_pll_calc; return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index cc79c796afe..cbf1fc60a38 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -241,6 +241,10 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) if (unlikely(!abi16)) return -ENOMEM; + + if (!drm->channel) + return nouveau_abi16_put(abi16, -ENODEV); + client = nv_client(abi16->client); if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 0910125cbbc..8503b2ea570 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -129,7 +129,8 @@ nouveau_accel_init(struct nouveau_drm *drm) /* initialise synchronisation routines */ if (device->card_type < NV_10) ret = nv04_fence_create(drm); - else if (device->chipset < 0x84) ret = nv10_fence_create(drm); + else if (device->card_type < NV_50) ret = nv10_fence_create(drm); + else if (device->chipset < 0x84) ret = nv50_fence_create(drm); else if (device->card_type < NV_C0) ret = nv84_fence_create(drm); else ret = nvc0_fence_create(drm); if (ret) { diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 3bce0299f64..24d932f5320 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1696,42 +1696,22 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) return ATOM_PPLL2; DRM_ERROR("unable to allocate a PPLL\n"); return ATOM_PPLL_INVALID; - } else if (ASIC_IS_AVIVO(rdev)) { - /* in DP mode, the DP ref clock can come from either PPLL - * depending on the asic: - * DCE3: PPLL1 or PPLL2 - */ - if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { - /* use the same PPLL for all DP monitors */ - pll = radeon_get_shared_dp_ppll(crtc); - if (pll != ATOM_PPLL_INVALID) - return pll; - } else { - /* use the same PPLL for all monitors with the same clock */ - pll = radeon_get_shared_nondp_ppll(crtc); - if (pll != ATOM_PPLL_INVALID) - return pll; - } - /* all other cases */ - pll_in_use = radeon_get_pll_use_mask(crtc); - /* the order shouldn't matter here, but we probably - * need this until we have atomic modeset - */ - if (rdev->flags & RADEON_IS_IGP) { - if (!(pll_in_use & (1 << ATOM_PPLL1))) - return ATOM_PPLL1; - if (!(pll_in_use & (1 << ATOM_PPLL2))) - return ATOM_PPLL2; - } else { - if (!(pll_in_use & (1 << ATOM_PPLL2))) - return ATOM_PPLL2; - if (!(pll_in_use & (1 << ATOM_PPLL1))) - return ATOM_PPLL1; - } - DRM_ERROR("unable to allocate a PPLL\n"); - return ATOM_PPLL_INVALID; } else { /* on pre-R5xx asics, the crtc to pll mapping is hardcoded */ + /* some atombios (observed in some DCE2/DCE3) code have a bug, + * the matching btw pll and crtc is done through + * PCLK_CRTC[1|2]_CNTL (0x480/0x484) but atombios code use the + * pll (1 or 2) to select which register to write. ie if using + * pll1 it will use PCLK_CRTC1_CNTL (0x480) and if using pll2 + * it will use PCLK_CRTC2_CNTL (0x484), it then use crtc id to + * choose which value to write. Which is reverse order from + * register logic. So only case that works is when pllid is + * same as crtcid or when both pll and crtc are enabled and + * both use same clock. + * + * So just return crtc id as if crtc and pll were hard linked + * together even if they aren't + */ return radeon_crtc->crtc_id; } } diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index af31f829f4a..219942c660d 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1330,6 +1330,8 @@ void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *sav break; udelay(1); } + } else { + save->crtc_enabled[i] = false; } } diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c index 10ea17a6b2a..42433344cb1 100644 --- a/drivers/gpu/drm/radeon/radeon_agp.c +++ b/drivers/gpu/drm/radeon/radeon_agp.c @@ -69,9 +69,12 @@ static struct radeon_agpmode_quirk radeon_agpmode_quirk_list[] = { /* Intel 82830 830 Chipset Host Bridge / Mobility M6 LY Needs AGPMode 2 (fdo #17360)*/ { PCI_VENDOR_ID_INTEL, 0x3575, PCI_VENDOR_ID_ATI, 0x4c59, PCI_VENDOR_ID_DELL, 0x00e3, 2}, - /* Intel 82852/82855 host bridge / Mobility FireGL 9000 R250 Needs AGPMode 1 (lp #296617) */ + /* Intel 82852/82855 host bridge / Mobility FireGL 9000 RV250 Needs AGPMode 1 (lp #296617) */ { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4c66, PCI_VENDOR_ID_DELL, 0x0149, 1}, + /* Intel 82855PM host bridge / Mobility FireGL 9000 RV250 Needs AGPMode 1 for suspend/resume */ + { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c66, + PCI_VENDOR_ID_IBM, 0x0531, 1}, /* Intel 82852/82855 host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (deb #467460) */ { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50, 0x1025, 0x0061, 1}, diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig index 70f5dde1cc5..b38ef6d8d04 100644 --- a/drivers/hv/Kconfig +++ b/drivers/hv/Kconfig @@ -13,4 +13,10 @@ config HYPERV_UTILS help Select this option to enable the Hyper-V Utilities. +config HYPERV_BALLOON + tristate "Microsoft Hyper-V Balloon driver" + depends on HYPERV + help + Select this option to enable Hyper-V Balloon driver. + endmenu diff --git a/drivers/hv/Makefile b/drivers/hv/Makefile index a23938b991c..e6abfa02d8b 100644 --- a/drivers/hv/Makefile +++ b/drivers/hv/Makefile @@ -1,5 +1,6 @@ obj-$(CONFIG_HYPERV) += hv_vmbus.o obj-$(CONFIG_HYPERV_UTILS) += hv_utils.o +obj-$(CONFIG_HYPERV_BALLOON) += hv_balloon.o hv_vmbus-y := vmbus_drv.o \ hv.o connection.o channel.o \ diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index f4c3d28cd1f..773a2f25a8f 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -33,14 +33,6 @@ #define NUM_PAGES_SPANNED(addr, len) \ ((PAGE_ALIGN(addr + len) >> PAGE_SHIFT) - (addr >> PAGE_SHIFT)) -/* Internal routines */ -static int create_gpadl_header( - void *kbuffer, /* must be phys and virt contiguous */ - u32 size, /* page-size multiple */ - struct vmbus_channel_msginfo **msginfo, - u32 *messagecount); -static void vmbus_setevent(struct vmbus_channel *channel); - /* * vmbus_setevent- Trigger an event notification on the specified * channel. diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 2b8b8d4558d..2f84c5cff8d 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -265,14 +265,9 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr) { struct vmbus_channel_offer_channel *offer; struct vmbus_channel *newchannel; - uuid_le *guidtype; - uuid_le *guidinstance; offer = (struct vmbus_channel_offer_channel *)hdr; - guidtype = &offer->offer.if_type; - guidinstance = &offer->offer.if_instance; - /* Allocate the channel object and save this offer. */ newchannel = alloc_channel(); if (!newchannel) { @@ -470,7 +465,6 @@ static void vmbus_onversion_response( { struct vmbus_channel_msginfo *msginfo; struct vmbus_channel_message_header *requestheader; - struct vmbus_channel_initiate_contact *initiate; struct vmbus_channel_version_response *version_response; unsigned long flags; @@ -484,8 +478,6 @@ static void vmbus_onversion_response( if (requestheader->msgtype == CHANNELMSG_INITIATE_CONTACT) { - initiate = - (struct vmbus_channel_initiate_contact *)requestheader; memcpy(&msginfo->response.version_response, version_response, sizeof(struct vmbus_channel_version_response)); diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c new file mode 100644 index 00000000000..f6c0011a033 --- /dev/null +++ b/drivers/hv/hv_balloon.c @@ -0,0 +1,1041 @@ +/* + * Copyright (c) 2012, Microsoft Corporation. + * + * Author: + * K. Y. Srinivasan <kys@microsoft.com> + * + * 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. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/kernel.h> +#include <linux/mman.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/kthread.h> +#include <linux/completion.h> +#include <linux/memory_hotplug.h> +#include <linux/memory.h> +#include <linux/notifier.h> +#include <linux/mman.h> +#include <linux/percpu_counter.h> + +#include <linux/hyperv.h> + +/* + * We begin with definitions supporting the Dynamic Memory protocol + * with the host. + * + * Begin protocol definitions. + */ + + + +/* + * Protocol versions. The low word is the minor version, the high word the major + * version. + * + * History: + * Initial version 1.0 + * Changed to 0.1 on 2009/03/25 + * Changes to 0.2 on 2009/05/14 + * Changes to 0.3 on 2009/12/03 + * Changed to 1.0 on 2011/04/05 + */ + +#define DYNMEM_MAKE_VERSION(Major, Minor) ((__u32)(((Major) << 16) | (Minor))) +#define DYNMEM_MAJOR_VERSION(Version) ((__u32)(Version) >> 16) +#define DYNMEM_MINOR_VERSION(Version) ((__u32)(Version) & 0xff) + +enum { + DYNMEM_PROTOCOL_VERSION_1 = DYNMEM_MAKE_VERSION(0, 3), + DYNMEM_PROTOCOL_VERSION_2 = DYNMEM_MAKE_VERSION(1, 0), + + DYNMEM_PROTOCOL_VERSION_WIN7 = DYNMEM_PROTOCOL_VERSION_1, + DYNMEM_PROTOCOL_VERSION_WIN8 = DYNMEM_PROTOCOL_VERSION_2, + + DYNMEM_PROTOCOL_VERSION_CURRENT = DYNMEM_PROTOCOL_VERSION_WIN8 +}; + + + +/* + * Message Types + */ + +enum dm_message_type { + /* + * Version 0.3 + */ + DM_ERROR = 0, + DM_VERSION_REQUEST = 1, + DM_VERSION_RESPONSE = 2, + DM_CAPABILITIES_REPORT = 3, + DM_CAPABILITIES_RESPONSE = 4, + DM_STATUS_REPORT = 5, + DM_BALLOON_REQUEST = 6, + DM_BALLOON_RESPONSE = 7, + DM_UNBALLOON_REQUEST = 8, + DM_UNBALLOON_RESPONSE = 9, + DM_MEM_HOT_ADD_REQUEST = 10, + DM_MEM_HOT_ADD_RESPONSE = 11, + DM_VERSION_03_MAX = 11, + /* + * Version 1.0. + */ + DM_INFO_MESSAGE = 12, + DM_VERSION_1_MAX = 12 +}; + + +/* + * Structures defining the dynamic memory management + * protocol. + */ + +union dm_version { + struct { + __u16 minor_version; + __u16 major_version; + }; + __u32 version; +} __packed; + + +union dm_caps { + struct { + __u64 balloon:1; + __u64 hot_add:1; + __u64 reservedz:62; + } cap_bits; + __u64 caps; +} __packed; + +union dm_mem_page_range { + struct { + /* + * The PFN number of the first page in the range. + * 40 bits is the architectural limit of a PFN + * number for AMD64. + */ + __u64 start_page:40; + /* + * The number of pages in the range. + */ + __u64 page_cnt:24; + } finfo; + __u64 page_range; +} __packed; + + + +/* + * The header for all dynamic memory messages: + * + * type: Type of the message. + * size: Size of the message in bytes; including the header. + * trans_id: The guest is responsible for manufacturing this ID. + */ + +struct dm_header { + __u16 type; + __u16 size; + __u32 trans_id; +} __packed; + +/* + * A generic message format for dynamic memory. + * Specific message formats are defined later in the file. + */ + +struct dm_message { + struct dm_header hdr; + __u8 data[]; /* enclosed message */ +} __packed; + + +/* + * Specific message types supporting the dynamic memory protocol. + */ + +/* + * Version negotiation message. Sent from the guest to the host. + * The guest is free to try different versions until the host + * accepts the version. + * + * dm_version: The protocol version requested. + * is_last_attempt: If TRUE, this is the last version guest will request. + * reservedz: Reserved field, set to zero. + */ + +struct dm_version_request { + struct dm_header hdr; + union dm_version version; + __u32 is_last_attempt:1; + __u32 reservedz:31; +} __packed; + +/* + * Version response message; Host to Guest and indicates + * if the host has accepted the version sent by the guest. + * + * is_accepted: If TRUE, host has accepted the version and the guest + * should proceed to the next stage of the protocol. FALSE indicates that + * guest should re-try with a different version. + * + * reservedz: Reserved field, set to zero. + */ + +struct dm_version_response { + struct dm_header hdr; + __u64 is_accepted:1; + __u64 reservedz:63; +} __packed; + +/* + * Message reporting capabilities. This is sent from the guest to the + * host. + */ + +struct dm_capabilities { + struct dm_header hdr; + union dm_caps caps; + __u64 min_page_cnt; + __u64 max_page_number; +} __packed; + +/* + * Response to the capabilities message. This is sent from the host to the + * guest. This message notifies if the host has accepted the guest's + * capabilities. If the host has not accepted, the guest must shutdown + * the service. + * + * is_accepted: Indicates if the host has accepted guest's capabilities. + * reservedz: Must be 0. + */ + +struct dm_capabilities_resp_msg { + struct dm_header hdr; + __u64 is_accepted:1; + __u64 reservedz:63; +} __packed; + +/* + * This message is used to report memory pressure from the guest. + * This message is not part of any transaction and there is no + * response to this message. + * + * num_avail: Available memory in pages. + * num_committed: Committed memory in pages. + * page_file_size: The accumulated size of all page files + * in the system in pages. + * zero_free: The nunber of zero and free pages. + * page_file_writes: The writes to the page file in pages. + * io_diff: An indicator of file cache efficiency or page file activity, + * calculated as File Cache Page Fault Count - Page Read Count. + * This value is in pages. + * + * Some of these metrics are Windows specific and fortunately + * the algorithm on the host side that computes the guest memory + * pressure only uses num_committed value. + */ + +struct dm_status { + struct dm_header hdr; + __u64 num_avail; + __u64 num_committed; + __u64 page_file_size; + __u64 zero_free; + __u32 page_file_writes; + __u32 io_diff; +} __packed; + + +/* + * Message to ask the guest to allocate memory - balloon up message. + * This message is sent from the host to the guest. The guest may not be + * able to allocate as much memory as requested. + * + * num_pages: number of pages to allocate. + */ + +struct dm_balloon { + struct dm_header hdr; + __u32 num_pages; + __u32 reservedz; +} __packed; + + +/* + * Balloon response message; this message is sent from the guest + * to the host in response to the balloon message. + * + * reservedz: Reserved; must be set to zero. + * more_pages: If FALSE, this is the last message of the transaction. + * if TRUE there will atleast one more message from the guest. + * + * range_count: The number of ranges in the range array. + * + * range_array: An array of page ranges returned to the host. + * + */ + +struct dm_balloon_response { + struct dm_header hdr; + __u32 reservedz; + __u32 more_pages:1; + __u32 range_count:31; + union dm_mem_page_range range_array[]; +} __packed; + +/* + * Un-balloon message; this message is sent from the host + * to the guest to give guest more memory. + * + * more_pages: If FALSE, this is the last message of the transaction. + * if TRUE there will atleast one more message from the guest. + * + * reservedz: Reserved; must be set to zero. + * + * range_count: The number of ranges in the range array. + * + * range_array: An array of page ranges returned to the host. + * + */ + +struct dm_unballoon_request { + struct dm_header hdr; + __u32 more_pages:1; + __u32 reservedz:31; + __u32 range_count; + union dm_mem_page_range range_array[]; +} __packed; + +/* + * Un-balloon response message; this message is sent from the guest + * to the host in response to an unballoon request. + * + */ + +struct dm_unballoon_response { + struct dm_header hdr; +} __packed; + + +/* + * Hot add request message. Message sent from the host to the guest. + * + * mem_range: Memory range to hot add. + * + * On Linux we currently don't support this since we cannot hot add + * arbitrary granularity of memory. + */ + +struct dm_hot_add { + struct dm_header hdr; + union dm_mem_page_range range; +} __packed; + +/* + * Hot add response message. + * This message is sent by the guest to report the status of a hot add request. + * If page_count is less than the requested page count, then the host should + * assume all further hot add requests will fail, since this indicates that + * the guest has hit an upper physical memory barrier. + * + * Hot adds may also fail due to low resources; in this case, the guest must + * not complete this message until the hot add can succeed, and the host must + * not send a new hot add request until the response is sent. + * If VSC fails to hot add memory DYNMEM_NUMBER_OF_UNSUCCESSFUL_HOTADD_ATTEMPTS + * times it fails the request. + * + * + * page_count: number of pages that were successfully hot added. + * + * result: result of the operation 1: success, 0: failure. + * + */ + +struct dm_hot_add_response { + struct dm_header hdr; + __u32 page_count; + __u32 result; +} __packed; + +/* + * Types of information sent from host to the guest. + */ + +enum dm_info_type { + INFO_TYPE_MAX_PAGE_CNT = 0, + MAX_INFO_TYPE +}; + + +/* + * Header for the information message. + */ + +struct dm_info_header { + enum dm_info_type type; + __u32 data_size; +} __packed; + +/* + * This message is sent from the host to the guest to pass + * some relevant information (win8 addition). + * + * reserved: no used. + * info_size: size of the information blob. + * info: information blob. + */ + +struct dm_info_msg { + struct dm_info_header header; + __u32 reserved; + __u32 info_size; + __u8 info[]; +}; + +/* + * End protocol definitions. + */ + +static bool hot_add; +static bool do_hot_add; + +module_param(hot_add, bool, (S_IRUGO | S_IWUSR)); +MODULE_PARM_DESC(hot_add, "If set attempt memory hot_add"); + +static atomic_t trans_id = ATOMIC_INIT(0); + +static int dm_ring_size = (5 * PAGE_SIZE); + +/* + * Driver specific state. + */ + +enum hv_dm_state { + DM_INITIALIZING = 0, + DM_INITIALIZED, + DM_BALLOON_UP, + DM_BALLOON_DOWN, + DM_HOT_ADD, + DM_INIT_ERROR +}; + + +static __u8 recv_buffer[PAGE_SIZE]; +static __u8 *send_buffer; +#define PAGES_IN_2M 512 + +struct hv_dynmem_device { + struct hv_device *dev; + enum hv_dm_state state; + struct completion host_event; + struct completion config_event; + + /* + * Number of pages we have currently ballooned out. + */ + unsigned int num_pages_ballooned; + + /* + * This thread handles both balloon/hot-add + * requests from the host as well as notifying + * the host with regards to memory pressure in + * the guest. + */ + struct task_struct *thread; + + /* + * We start with the highest version we can support + * and downgrade based on the host; we save here the + * next version to try. + */ + __u32 next_version; +}; + +static struct hv_dynmem_device dm_device; + +static void hot_add_req(struct hv_dynmem_device *dm, struct dm_hot_add *msg) +{ + + struct dm_hot_add_response resp; + + if (do_hot_add) { + + pr_info("Memory hot add not supported\n"); + + /* + * Currently we do not support hot add. + * Just fail the request. + */ + } + + memset(&resp, 0, sizeof(struct dm_hot_add_response)); + resp.hdr.type = DM_MEM_HOT_ADD_RESPONSE; + resp.hdr.size = sizeof(struct dm_hot_add_response); + resp.hdr.trans_id = atomic_inc_return(&trans_id); + + resp.page_count = 0; + resp.result = 0; + + dm->state = DM_INITIALIZED; + vmbus_sendpacket(dm->dev->channel, &resp, + sizeof(struct dm_hot_add_response), + (unsigned long)NULL, + VM_PKT_DATA_INBAND, 0); + +} + +static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg) +{ + switch (msg->header.type) { + case INFO_TYPE_MAX_PAGE_CNT: + pr_info("Received INFO_TYPE_MAX_PAGE_CNT\n"); + pr_info("Data Size is %d\n", msg->header.data_size); + break; + default: + pr_info("Received Unknown type: %d\n", msg->header.type); + } +} + +/* + * Post our status as it relates memory pressure to the + * host. Host expects the guests to post this status + * periodically at 1 second intervals. + * + * The metrics specified in this protocol are very Windows + * specific and so we cook up numbers here to convey our memory + * pressure. + */ + +static void post_status(struct hv_dynmem_device *dm) +{ + struct dm_status status; + + + memset(&status, 0, sizeof(struct dm_status)); + status.hdr.type = DM_STATUS_REPORT; + status.hdr.size = sizeof(struct dm_status); + status.hdr.trans_id = atomic_inc_return(&trans_id); + + + status.num_committed = vm_memory_committed(); + + vmbus_sendpacket(dm->dev->channel, &status, + sizeof(struct dm_status), + (unsigned long)NULL, + VM_PKT_DATA_INBAND, 0); + +} + + + +static void free_balloon_pages(struct hv_dynmem_device *dm, + union dm_mem_page_range *range_array) +{ + int num_pages = range_array->finfo.page_cnt; + __u64 start_frame = range_array->finfo.start_page; + struct page *pg; + int i; + + for (i = 0; i < num_pages; i++) { + pg = pfn_to_page(i + start_frame); + __free_page(pg); + dm->num_pages_ballooned--; + } +} + + + +static int alloc_balloon_pages(struct hv_dynmem_device *dm, int num_pages, + struct dm_balloon_response *bl_resp, int alloc_unit, + bool *alloc_error) +{ + int i = 0; + struct page *pg; + + if (num_pages < alloc_unit) + return 0; + + for (i = 0; (i * alloc_unit) < num_pages; i++) { + if (bl_resp->hdr.size + sizeof(union dm_mem_page_range) > + PAGE_SIZE) + return i * alloc_unit; + + /* + * We execute this code in a thread context. Furthermore, + * we don't want the kernel to try too hard. + */ + pg = alloc_pages(GFP_HIGHUSER | __GFP_NORETRY | + __GFP_NOMEMALLOC | __GFP_NOWARN, + get_order(alloc_unit << PAGE_SHIFT)); + + if (!pg) { + *alloc_error = true; + return i * alloc_unit; + } + + + dm->num_pages_ballooned += alloc_unit; + + bl_resp->range_count++; + bl_resp->range_array[i].finfo.start_page = + page_to_pfn(pg); + bl_resp->range_array[i].finfo.page_cnt = alloc_unit; + bl_resp->hdr.size += sizeof(union dm_mem_page_range); + + } + + return num_pages; +} + + + +static void balloon_up(struct hv_dynmem_device *dm, struct dm_balloon *req) +{ + int num_pages = req->num_pages; + int num_ballooned = 0; + struct dm_balloon_response *bl_resp; + int alloc_unit; + int ret; + bool alloc_error = false; + bool done = false; + int i; + + + /* + * Currently, we only support 4k allocations. + */ + alloc_unit = 1; + + while (!done) { + bl_resp = (struct dm_balloon_response *)send_buffer; + memset(send_buffer, 0, PAGE_SIZE); + bl_resp->hdr.type = DM_BALLOON_RESPONSE; + bl_resp->hdr.trans_id = atomic_inc_return(&trans_id); + bl_resp->hdr.size = sizeof(struct dm_balloon_response); + bl_resp->more_pages = 1; + + + num_pages -= num_ballooned; + num_ballooned = alloc_balloon_pages(dm, num_pages, + bl_resp, alloc_unit, + &alloc_error); + + if ((alloc_error) || (num_ballooned == num_pages)) { + bl_resp->more_pages = 0; + done = true; + dm->state = DM_INITIALIZED; + } + + /* + * We are pushing a lot of data through the channel; + * deal with transient failures caused because of the + * lack of space in the ring buffer. + */ + + do { + ret = vmbus_sendpacket(dm_device.dev->channel, + bl_resp, + bl_resp->hdr.size, + (unsigned long)NULL, + VM_PKT_DATA_INBAND, 0); + + if (ret == -EAGAIN) + msleep(20); + + } while (ret == -EAGAIN); + + if (ret) { + /* + * Free up the memory we allocatted. + */ + pr_info("Balloon response failed\n"); + + for (i = 0; i < bl_resp->range_count; i++) + free_balloon_pages(dm, + &bl_resp->range_array[i]); + + done = true; + } + } + +} + +static void balloon_down(struct hv_dynmem_device *dm, + struct dm_unballoon_request *req) +{ + union dm_mem_page_range *range_array = req->range_array; + int range_count = req->range_count; + struct dm_unballoon_response resp; + int i; + + for (i = 0; i < range_count; i++) + free_balloon_pages(dm, &range_array[i]); + + if (req->more_pages == 1) + return; + + memset(&resp, 0, sizeof(struct dm_unballoon_response)); + resp.hdr.type = DM_UNBALLOON_RESPONSE; + resp.hdr.trans_id = atomic_inc_return(&trans_id); + resp.hdr.size = sizeof(struct dm_unballoon_response); + + vmbus_sendpacket(dm_device.dev->channel, &resp, + sizeof(struct dm_unballoon_response), + (unsigned long)NULL, + VM_PKT_DATA_INBAND, 0); + + dm->state = DM_INITIALIZED; +} + +static void balloon_onchannelcallback(void *context); + +static int dm_thread_func(void *dm_dev) +{ + struct hv_dynmem_device *dm = dm_dev; + int t; + unsigned long scan_start; + + while (!kthread_should_stop()) { + t = wait_for_completion_timeout(&dm_device.config_event, 1*HZ); + /* + * The host expects us to post information on the memory + * pressure every second. + */ + + if (t == 0) + post_status(dm); + + scan_start = jiffies; + switch (dm->state) { + case DM_BALLOON_UP: + balloon_up(dm, (struct dm_balloon *)recv_buffer); + break; + + case DM_HOT_ADD: + hot_add_req(dm, (struct dm_hot_add *)recv_buffer); + break; + default: + break; + } + + if (!time_in_range(jiffies, scan_start, scan_start + HZ)) + post_status(dm); + + } + + return 0; +} + + +static void version_resp(struct hv_dynmem_device *dm, + struct dm_version_response *vresp) +{ + struct dm_version_request version_req; + int ret; + + if (vresp->is_accepted) { + /* + * We are done; wakeup the + * context waiting for version + * negotiation. + */ + complete(&dm->host_event); + return; + } + /* + * If there are more versions to try, continue + * with negotiations; if not + * shutdown the service since we are not able + * to negotiate a suitable version number + * with the host. + */ + if (dm->next_version == 0) + goto version_error; + + dm->next_version = 0; + memset(&version_req, 0, sizeof(struct dm_version_request)); + version_req.hdr.type = DM_VERSION_REQUEST; + version_req.hdr.size = sizeof(struct dm_version_request); + version_req.hdr.trans_id = atomic_inc_return(&trans_id); + version_req.version.version = DYNMEM_PROTOCOL_VERSION_WIN7; + version_req.is_last_attempt = 1; + + ret = vmbus_sendpacket(dm->dev->channel, &version_req, + sizeof(struct dm_version_request), + (unsigned long)NULL, + VM_PKT_DATA_INBAND, 0); + + if (ret) + goto version_error; + + return; + +version_error: + dm->state = DM_INIT_ERROR; + complete(&dm->host_event); +} + +static void cap_resp(struct hv_dynmem_device *dm, + struct dm_capabilities_resp_msg *cap_resp) +{ + if (!cap_resp->is_accepted) { + pr_info("Capabilities not accepted by host\n"); + dm->state = DM_INIT_ERROR; + } + complete(&dm->host_event); +} + +static void balloon_onchannelcallback(void *context) +{ + struct hv_device *dev = context; + u32 recvlen; + u64 requestid; + struct dm_message *dm_msg; + struct dm_header *dm_hdr; + struct hv_dynmem_device *dm = hv_get_drvdata(dev); + + memset(recv_buffer, 0, sizeof(recv_buffer)); + vmbus_recvpacket(dev->channel, recv_buffer, + PAGE_SIZE, &recvlen, &requestid); + + if (recvlen > 0) { + dm_msg = (struct dm_message *)recv_buffer; + dm_hdr = &dm_msg->hdr; + + switch (dm_hdr->type) { + case DM_VERSION_RESPONSE: + version_resp(dm, + (struct dm_version_response *)dm_msg); + break; + + case DM_CAPABILITIES_RESPONSE: + cap_resp(dm, + (struct dm_capabilities_resp_msg *)dm_msg); + break; + + case DM_BALLOON_REQUEST: + dm->state = DM_BALLOON_UP; + complete(&dm->config_event); + break; + + case DM_UNBALLOON_REQUEST: + dm->state = DM_BALLOON_DOWN; + balloon_down(dm, + (struct dm_unballoon_request *)recv_buffer); + break; + + case DM_MEM_HOT_ADD_REQUEST: + dm->state = DM_HOT_ADD; + complete(&dm->config_event); + break; + + case DM_INFO_MESSAGE: + process_info(dm, (struct dm_info_msg *)dm_msg); + break; + + default: + pr_err("Unhandled message: type: %d\n", dm_hdr->type); + + } + } + +} + +static int balloon_probe(struct hv_device *dev, + const struct hv_vmbus_device_id *dev_id) +{ + int ret, t; + struct dm_version_request version_req; + struct dm_capabilities cap_msg; + + do_hot_add = hot_add; + + /* + * First allocate a send buffer. + */ + + send_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!send_buffer) + return -ENOMEM; + + ret = vmbus_open(dev->channel, dm_ring_size, dm_ring_size, NULL, 0, + balloon_onchannelcallback, dev); + + if (ret) + return ret; + + dm_device.dev = dev; + dm_device.state = DM_INITIALIZING; + dm_device.next_version = DYNMEM_PROTOCOL_VERSION_WIN7; + init_completion(&dm_device.host_event); + init_completion(&dm_device.config_event); + + dm_device.thread = + kthread_run(dm_thread_func, &dm_device, "hv_balloon"); + if (IS_ERR(dm_device.thread)) { + ret = PTR_ERR(dm_device.thread); + goto probe_error0; + } + + hv_set_drvdata(dev, &dm_device); + /* + * Initiate the hand shake with the host and negotiate + * a version that the host can support. We start with the + * highest version number and go down if the host cannot + * support it. + */ + memset(&version_req, 0, sizeof(struct dm_version_request)); + version_req.hdr.type = DM_VERSION_REQUEST; + version_req.hdr.size = sizeof(struct dm_version_request); + version_req.hdr.trans_id = atomic_inc_return(&trans_id); + version_req.version.version = DYNMEM_PROTOCOL_VERSION_WIN8; + version_req.is_last_attempt = 0; + + ret = vmbus_sendpacket(dev->channel, &version_req, + sizeof(struct dm_version_request), + (unsigned long)NULL, + VM_PKT_DATA_INBAND, + VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); + if (ret) + goto probe_error1; + + t = wait_for_completion_timeout(&dm_device.host_event, 5*HZ); + if (t == 0) { + ret = -ETIMEDOUT; + goto probe_error1; + } + + /* + * If we could not negotiate a compatible version with the host + * fail the probe function. + */ + if (dm_device.state == DM_INIT_ERROR) { + ret = -ETIMEDOUT; + goto probe_error1; + } + /* + * Now submit our capabilities to the host. + */ + memset(&cap_msg, 0, sizeof(struct dm_capabilities)); + cap_msg.hdr.type = DM_CAPABILITIES_REPORT; + cap_msg.hdr.size = sizeof(struct dm_capabilities); + cap_msg.hdr.trans_id = atomic_inc_return(&trans_id); + + cap_msg.caps.cap_bits.balloon = 1; + /* + * While we currently don't support hot-add, + * we still advertise this capability since the + * host requires that guests partcipating in the + * dynamic memory protocol support hot add. + */ + cap_msg.caps.cap_bits.hot_add = 1; + + /* + * Currently the host does not use these + * values and we set them to what is done in the + * Windows driver. + */ + cap_msg.min_page_cnt = 0; + cap_msg.max_page_number = -1; + + ret = vmbus_sendpacket(dev->channel, &cap_msg, + sizeof(struct dm_capabilities), + (unsigned long)NULL, + VM_PKT_DATA_INBAND, + VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); + if (ret) + goto probe_error1; + + t = wait_for_completion_timeout(&dm_device.host_event, 5*HZ); + if (t == 0) { + ret = -ETIMEDOUT; + goto probe_error1; + } + + /* + * If the host does not like our capabilities, + * fail the probe function. + */ + if (dm_device.state == DM_INIT_ERROR) { + ret = -ETIMEDOUT; + goto probe_error1; + } + + dm_device.state = DM_INITIALIZED; + + return 0; + +probe_error1: + kthread_stop(dm_device.thread); + +probe_error0: + vmbus_close(dev->channel); + return ret; +} + +static int balloon_remove(struct hv_device *dev) +{ + struct hv_dynmem_device *dm = hv_get_drvdata(dev); + + if (dm->num_pages_ballooned != 0) + pr_warn("Ballooned pages: %d\n", dm->num_pages_ballooned); + + vmbus_close(dev->channel); + kthread_stop(dm->thread); + + return 0; +} + +static const struct hv_vmbus_device_id id_table[] = { + /* Dynamic Memory Class ID */ + /* 525074DC-8985-46e2-8057-A307DC18A502 */ + { VMBUS_DEVICE(0xdc, 0x74, 0x50, 0X52, 0x85, 0x89, 0xe2, 0x46, + 0x80, 0x57, 0xa3, 0x07, 0xdc, 0x18, 0xa5, 0x02) + }, + { }, +}; + +MODULE_DEVICE_TABLE(vmbus, id_table); + +static struct hv_driver balloon_drv = { + .name = "hv_balloon", + .id_table = id_table, + .probe = balloon_probe, + .remove = balloon_remove, +}; + +static int __init init_balloon_drv(void) +{ + + return vmbus_driver_register(&balloon_drv); +} + +static void exit_balloon_drv(void) +{ + + vmbus_driver_unregister(&balloon_drv); +} + +module_init(init_balloon_drv); +module_exit(exit_balloon_drv); + +MODULE_DESCRIPTION("Hyper-V Balloon"); +MODULE_VERSION(HV_DRV_VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index c4633de6446..4800d4c2a7b 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -334,6 +334,16 @@ config SENSORS_DA9052_ADC This driver can also be built as module. If so, the module will be called da9052-hwmon. +config SENSORS_DA9055 + tristate "Dialog Semiconductor DA9055 ADC" + depends on MFD_DA9055 + help + If you say yes here you get support for ADC on the Dialog + Semiconductor DA9055 PMIC. + + This driver can also be built as a module. If so, the module + will be called da9055-hwmon. + config SENSORS_I5K_AMB tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets" depends on PCI @@ -455,7 +465,7 @@ config SENSORS_HIH6130 config SENSORS_CORETEMP tristate "Intel Core/Core2/Atom temperature sensor" - depends on X86 && PCI + depends on X86 help If you say yes here you get support for the temperature sensor inside your CPU. Most of the family 6 CPUs @@ -1106,11 +1116,12 @@ config SENSORS_ADS1015 will be called ads1015. config SENSORS_ADS7828 - tristate "Texas Instruments ADS7828" + tristate "Texas Instruments ADS7828 and compatibles" depends on I2C help - If you say yes here you get support for Texas Instruments ADS7828 - 12-bit 8-channel ADC device. + If you say yes here you get support for Texas Instruments ADS7828 and + ADS7830 8-channel A/D converters. ADS7828 resolution is 12-bit, while + it is 8-bit on ADS7830. This driver can also be built as a module. If so, the module will be called ads7828. diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 8d5fcb5e8e9..a930f0997d2 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o +obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o obj-$(CONFIG_SENSORS_DME1737) += dme1737.o obj-$(CONFIG_SENSORS_DS620) += ds620.o obj-$(CONFIG_SENSORS_DS1621) += ds1621.o diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c index 78b81793ddd..6119ff8e8c8 100644 --- a/drivers/hwmon/abituguru.c +++ b/drivers/hwmon/abituguru.c @@ -478,7 +478,7 @@ static int abituguru_write(struct abituguru_data *data, * alarm for sensor type X and then enabling the sensor as sensor type * X, if we then get an alarm it is a sensor of type X. */ -static int __devinit +static int abituguru_detect_bank1_sensor_type(struct abituguru_data *data, u8 sensor_addr) { @@ -635,7 +635,7 @@ abituguru_detect_bank1_sensor_type_exit: * read/write test would be feasible because of the reaction above, I've * however opted to stay on the safe side. */ -static void __devinit +static void abituguru_detect_no_bank2_sensors(struct abituguru_data *data) { int i; @@ -691,7 +691,7 @@ abituguru_detect_no_bank2_sensors(struct abituguru_data *data) (int)data->bank2_sensors); } -static void __devinit +static void abituguru_detect_no_pwms(struct abituguru_data *data) { int i, j; @@ -1264,7 +1264,7 @@ static struct sensor_device_attribute_2 abituguru_sysfs_attr[] = { SENSOR_ATTR_2(name, 0444, show_name, NULL, 0, 0), }; -static int __devinit abituguru_probe(struct platform_device *pdev) +static int abituguru_probe(struct platform_device *pdev) { struct abituguru_data *data; int i, j, used, sysfs_names_free, sysfs_attr_i, res = -ENODEV; @@ -1434,7 +1434,7 @@ abituguru_probe_error: return res; } -static int __devexit abituguru_remove(struct platform_device *pdev) +static int abituguru_remove(struct platform_device *pdev) { int i; struct abituguru_data *data = platform_get_drvdata(pdev); @@ -1545,7 +1545,7 @@ static struct platform_driver abituguru_driver = { .pm = ABIT_UGURU_PM, }, .probe = abituguru_probe, - .remove = __devexit_p(abituguru_remove), + .remove = abituguru_remove, }; static int __init abituguru_detect(void) diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index b174b8b2b4d..205327d33c4 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -966,7 +966,7 @@ static struct sensor_device_attribute_2 abituguru3_sysfs_attr[] = { SENSOR_ATTR_2(name, 0444, show_name, NULL, 0, 0), }; -static int __devinit abituguru3_probe(struct platform_device *pdev) +static int abituguru3_probe(struct platform_device *pdev) { const int no_sysfs_attr[3] = { 10, 8, 7 }; int sensor_index[3] = { 0, 1, 1 }; @@ -1072,7 +1072,7 @@ abituguru3_probe_error: return res; } -static int __devexit abituguru3_remove(struct platform_device *pdev) +static int abituguru3_remove(struct platform_device *pdev) { int i; struct abituguru3_data *data = platform_get_drvdata(pdev); @@ -1171,7 +1171,7 @@ static struct platform_driver abituguru3_driver = { .pm = ABIT_UGURU3_PM }, .probe = abituguru3_probe, - .remove = __devexit_p(abituguru3_remove), + .remove = abituguru3_remove, }; static int __init abituguru3_dmi_detect(void) diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c index 37c01e72d69..a57584d28a4 100644 --- a/drivers/hwmon/ad7314.c +++ b/drivers/hwmon/ad7314.c @@ -107,7 +107,7 @@ static const struct attribute_group ad7314_group = { .attrs = ad7314_attributes, }; -static int __devinit ad7314_probe(struct spi_device *spi_dev) +static int ad7314_probe(struct spi_device *spi_dev) { int ret; struct ad7314_data *chip; @@ -135,7 +135,7 @@ error_remove_group: return ret; } -static int __devexit ad7314_remove(struct spi_device *spi_dev) +static int ad7314_remove(struct spi_device *spi_dev) { struct ad7314_data *chip = dev_get_drvdata(&spi_dev->dev); @@ -159,7 +159,7 @@ static struct spi_driver ad7314_driver = { .owner = THIS_MODULE, }, .probe = ad7314_probe, - .remove = __devexit_p(ad7314_remove), + .remove = ad7314_remove, .id_table = ad7314_id, }; diff --git a/drivers/hwmon/ad7414.c b/drivers/hwmon/ad7414.c index b420fb3f3a7..f3a5d4764eb 100644 --- a/drivers/hwmon/ad7414.c +++ b/drivers/hwmon/ad7414.c @@ -226,7 +226,7 @@ exit_remove: return err; } -static int __devexit ad7414_remove(struct i2c_client *client) +static int ad7414_remove(struct i2c_client *client) { struct ad7414_data *data = i2c_get_clientdata(client); @@ -246,7 +246,7 @@ static struct i2c_driver ad7414_driver = { .name = "ad7414", }, .probe = ad7414_probe, - .remove = __devexit_p(ad7414_remove), + .remove = ad7414_remove, .id_table = ad7414_id, }; diff --git a/drivers/hwmon/adcxx.c b/drivers/hwmon/adcxx.c index f4c5867170d..751b1f0264a 100644 --- a/drivers/hwmon/adcxx.c +++ b/drivers/hwmon/adcxx.c @@ -161,7 +161,7 @@ static struct sensor_device_attribute ad_input[] = { /*----------------------------------------------------------------------*/ -static int __devinit adcxx_probe(struct spi_device *spi) +static int adcxx_probe(struct spi_device *spi) { int channels = spi_get_device_id(spi)->driver_data; struct adcxx *adc; @@ -208,7 +208,7 @@ out_err: return status; } -static int __devexit adcxx_remove(struct spi_device *spi) +static int adcxx_remove(struct spi_device *spi) { struct adcxx *adc = spi_get_drvdata(spi); int i; @@ -240,7 +240,7 @@ static struct spi_driver adcxx_driver = { }, .id_table = adcxx_ids, .probe = adcxx_probe, - .remove = __devexit_p(adcxx_remove), + .remove = adcxx_remove, }; module_spi_driver(adcxx_driver); diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c index 1f9e8af0f32..409b5c16def 100644 --- a/drivers/hwmon/ads7828.c +++ b/drivers/hwmon/ads7828.c @@ -1,12 +1,14 @@ /* - * ads7828.c - lm_sensors driver for ads7828 12-bit 8-channel ADC + * ads7828.c - driver for TI ADS7828 8-channel A/D converter and compatibles * (C) 2007 EADS Astrium * * This driver is based on the lm75 and other lm_sensors/hwmon drivers * * Written by Steve Hardy <shardy@redhat.com> * - * Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads7828.pdf + * ADS7830 support, by Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> + * + * For further information, see the Documentation/hwmon/ads7828 file. * * 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 @@ -23,63 +25,48 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/jiffies.h> -#include <linux/i2c.h> +#include <linux/err.h> #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> -#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/jiffies.h> +#include <linux/module.h> #include <linux/mutex.h> +#include <linux/platform_data/ads7828.h> +#include <linux/slab.h> /* The ADS7828 registers */ -#define ADS7828_NCH 8 /* 8 channels of 12-bit A-D supported */ -#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */ -#define ADS7828_CMD_SD_DIFF 0x00 /* Differential inputs */ -#define ADS7828_CMD_PD0 0x0 /* Power Down between A-D conversions */ -#define ADS7828_CMD_PD1 0x04 /* Internal ref OFF && A-D ON */ -#define ADS7828_CMD_PD2 0x08 /* Internal ref ON && A-D OFF */ -#define ADS7828_CMD_PD3 0x0C /* Internal ref ON && A-D ON */ -#define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */ - -/* Addresses to scan */ -static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, - I2C_CLIENT_END }; - -/* Module parameters */ -static bool se_input = 1; /* Default is SE, 0 == diff */ -static bool int_vref = 1; /* Default is internal ref ON */ -static int vref_mv = ADS7828_INT_VREF_MV; /* set if vref != 2.5V */ -module_param(se_input, bool, S_IRUGO); -module_param(int_vref, bool, S_IRUGO); -module_param(vref_mv, int, S_IRUGO); - -/* Global Variables */ -static u8 ads7828_cmd_byte; /* cmd byte without channel bits */ -static unsigned int ads7828_lsb_resol; /* resolution of the ADC sample lsb */ - -/* Each client has this additional data */ +#define ADS7828_NCH 8 /* 8 channels supported */ +#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */ +#define ADS7828_CMD_PD1 0x04 /* Internal vref OFF && A/D ON */ +#define ADS7828_CMD_PD3 0x0C /* Internal vref ON && A/D ON */ +#define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */ +#define ADS7828_EXT_VREF_MV_MIN 50 /* External vref min value 0.05V */ +#define ADS7828_EXT_VREF_MV_MAX 5250 /* External vref max value 5.25V */ + +/* List of supported devices */ +enum ads7828_chips { ads7828, ads7830 }; + +/* Client specific data */ struct ads7828_data { struct device *hwmon_dev; - struct mutex update_lock; /* mutex protect updates */ - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH 12-bit samples */ + struct mutex update_lock; /* Mutex protecting updates */ + unsigned long last_updated; /* Last updated time (in jiffies) */ + u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH samples */ + bool valid; /* Validity flag */ + bool diff_input; /* Differential input */ + bool ext_vref; /* External voltage reference */ + unsigned int vref_mv; /* voltage reference value */ + u8 cmd_byte; /* Command byte without channel bits */ + unsigned int lsb_resol; /* Resolution of the ADC sample LSB */ + s32 (*read_channel)(const struct i2c_client *client, u8 command); }; -/* Function declaration - necessary due to function dependencies */ -static int ads7828_detect(struct i2c_client *client, - struct i2c_board_info *info); -static int ads7828_probe(struct i2c_client *client, - const struct i2c_device_id *id); - -static inline u8 channel_cmd_byte(int ch) +/* Command byte C2,C1,C0 - see datasheet */ +static inline u8 ads7828_cmd_byte(u8 cmd, int ch) { - /* cmd byte C2,C1,C0 - see datasheet */ - u8 cmd = (((ch>>1) | (ch&0x01)<<2)<<4); - cmd |= ads7828_cmd_byte; - return cmd; + return cmd | (((ch >> 1) | (ch & 0x01) << 2) << 4); } /* Update data for the device (all 8 channels) */ @@ -96,12 +83,11 @@ static struct ads7828_data *ads7828_update_device(struct device *dev) dev_dbg(&client->dev, "Starting ads7828 update\n"); for (ch = 0; ch < ADS7828_NCH; ch++) { - u8 cmd = channel_cmd_byte(ch); - data->adc_input[ch] = - i2c_smbus_read_word_swapped(client, cmd); + u8 cmd = ads7828_cmd_byte(data->cmd_byte, ch); + data->adc_input[ch] = data->read_channel(client, cmd); } data->last_updated = jiffies; - data->valid = 1; + data->valid = true; } mutex_unlock(&data->update_lock); @@ -110,28 +96,25 @@ static struct ads7828_data *ads7828_update_device(struct device *dev) } /* sysfs callback function */ -static ssize_t show_in(struct device *dev, struct device_attribute *da, - char *buf) +static ssize_t ads7828_show_in(struct device *dev, struct device_attribute *da, + char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct ads7828_data *data = ads7828_update_device(dev); - /* Print value (in mV as specified in sysfs-interface documentation) */ - return sprintf(buf, "%d\n", (data->adc_input[attr->index] * - ads7828_lsb_resol)/1000); -} + unsigned int value = DIV_ROUND_CLOSEST(data->adc_input[attr->index] * + data->lsb_resol, 1000); -#define in_reg(offset)\ -static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in,\ - NULL, offset) + return sprintf(buf, "%d\n", value); +} -in_reg(0); -in_reg(1); -in_reg(2); -in_reg(3); -in_reg(4); -in_reg(5); -in_reg(6); -in_reg(7); +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ads7828_show_in, NULL, 0); +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ads7828_show_in, NULL, 1); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ads7828_show_in, NULL, 2); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ads7828_show_in, NULL, 3); +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ads7828_show_in, NULL, 4); +static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ads7828_show_in, NULL, 5); +static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ads7828_show_in, NULL, 6); +static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ads7828_show_in, NULL, 7); static struct attribute *ads7828_attributes[] = { &sensor_dev_attr_in0_input.dev_attr.attr, @@ -152,60 +135,9 @@ static const struct attribute_group ads7828_group = { static int ads7828_remove(struct i2c_client *client) { struct ads7828_data *data = i2c_get_clientdata(client); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &ads7828_group); - return 0; -} - -static const struct i2c_device_id ads7828_id[] = { - { "ads7828", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ads7828_id); - -/* This is the driver that will be inserted */ -static struct i2c_driver ads7828_driver = { - .class = I2C_CLASS_HWMON, - .driver = { - .name = "ads7828", - }, - .probe = ads7828_probe, - .remove = ads7828_remove, - .id_table = ads7828_id, - .detect = ads7828_detect, - .address_list = normal_i2c, -}; - -/* Return 0 if detection is successful, -ENODEV otherwise */ -static int ads7828_detect(struct i2c_client *client, - struct i2c_board_info *info) -{ - struct i2c_adapter *adapter = client->adapter; - int ch; - - /* Check we have a valid client */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)) - return -ENODEV; - - /* - * Now, we do the remaining detection. There is no identification - * dedicated register so attempt to sanity check using knowledge of - * the chip - * - Read from the 8 channel addresses - * - Check the top 4 bits of each result are not set (12 data bits) - */ - for (ch = 0; ch < ADS7828_NCH; ch++) { - u16 in_data; - u8 cmd = channel_cmd_byte(ch); - in_data = i2c_smbus_read_word_swapped(client, cmd); - if (in_data & 0xF000) { - pr_debug("%s : Doesn't look like an ads7828 device\n", - __func__); - return -ENODEV; - } - } - - strlcpy(info->type, "ads7828", I2C_NAME_SIZE); return 0; } @@ -213,6 +145,7 @@ static int ads7828_detect(struct i2c_client *client, static int ads7828_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct ads7828_platform_data *pdata = client->dev.platform_data; struct ads7828_data *data; int err; @@ -221,10 +154,37 @@ static int ads7828_probe(struct i2c_client *client, if (!data) return -ENOMEM; + if (pdata) { + data->diff_input = pdata->diff_input; + data->ext_vref = pdata->ext_vref; + if (data->ext_vref) + data->vref_mv = pdata->vref_mv; + } + + /* Bound Vref with min/max values if it was provided */ + if (data->vref_mv) + data->vref_mv = SENSORS_LIMIT(data->vref_mv, + ADS7828_EXT_VREF_MV_MIN, + ADS7828_EXT_VREF_MV_MAX); + else + data->vref_mv = ADS7828_INT_VREF_MV; + + /* ADS7828 uses 12-bit samples, while ADS7830 is 8-bit */ + if (id->driver_data == ads7828) { + data->lsb_resol = DIV_ROUND_CLOSEST(data->vref_mv * 1000, 4096); + data->read_channel = i2c_smbus_read_word_swapped; + } else { + data->lsb_resol = DIV_ROUND_CLOSEST(data->vref_mv * 1000, 256); + data->read_channel = i2c_smbus_read_byte_data; + } + + data->cmd_byte = data->ext_vref ? ADS7828_CMD_PD1 : ADS7828_CMD_PD3; + if (!data->diff_input) + data->cmd_byte |= ADS7828_CMD_SD_SE; + i2c_set_clientdata(client, data); mutex_init(&data->update_lock); - /* Register sysfs hooks */ err = sysfs_create_group(&client->dev.kobj, &ads7828_group); if (err) return err; @@ -232,38 +192,35 @@ static int ads7828_probe(struct i2c_client *client, data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); - goto exit_remove; + goto error; } return 0; -exit_remove: +error: sysfs_remove_group(&client->dev.kobj, &ads7828_group); return err; } -static int __init sensors_ads7828_init(void) -{ - /* Initialize the command byte according to module parameters */ - ads7828_cmd_byte = se_input ? - ADS7828_CMD_SD_SE : ADS7828_CMD_SD_DIFF; - ads7828_cmd_byte |= int_vref ? - ADS7828_CMD_PD3 : ADS7828_CMD_PD1; +static const struct i2c_device_id ads7828_device_ids[] = { + { "ads7828", ads7828 }, + { "ads7830", ads7830 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ads7828_device_ids); - /* Calculate the LSB resolution */ - ads7828_lsb_resol = (vref_mv*1000)/4096; +static struct i2c_driver ads7828_driver = { + .driver = { + .name = "ads7828", + }, - return i2c_add_driver(&ads7828_driver); -} + .id_table = ads7828_device_ids, + .probe = ads7828_probe, + .remove = ads7828_remove, +}; -static void __exit sensors_ads7828_exit(void) -{ - i2c_del_driver(&ads7828_driver); -} +module_i2c_driver(ads7828_driver); -MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>"); -MODULE_DESCRIPTION("ADS7828 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_ads7828_init); -module_exit(sensors_ads7828_exit); +MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>"); +MODULE_DESCRIPTION("Driver for TI ADS7828 A/D converter and compatibles"); diff --git a/drivers/hwmon/ads7871.c b/drivers/hwmon/ads7871.c index 1b53aa42b6d..a79875986f9 100644 --- a/drivers/hwmon/ads7871.c +++ b/drivers/hwmon/ads7871.c @@ -173,7 +173,7 @@ static const struct attribute_group ads7871_group = { .attrs = ads7871_attributes, }; -static int __devinit ads7871_probe(struct spi_device *spi) +static int ads7871_probe(struct spi_device *spi) { int ret, err; uint8_t val; @@ -225,7 +225,7 @@ error_remove: return err; } -static int __devexit ads7871_remove(struct spi_device *spi) +static int ads7871_remove(struct spi_device *spi) { struct ads7871_data *pdata = spi_get_drvdata(spi); @@ -241,7 +241,7 @@ static struct spi_driver ads7871_driver = { }, .probe = ads7871_probe, - .remove = __devexit_p(ads7871_remove), + .remove = ads7871_remove, }; module_spi_driver(ads7871_driver); diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c index 517f1856c70..34ff03abb50 100644 --- a/drivers/hwmon/adt7411.c +++ b/drivers/hwmon/adt7411.c @@ -276,7 +276,7 @@ static int adt7411_detect(struct i2c_client *client, return 0; } -static int __devinit adt7411_probe(struct i2c_client *client, +static int adt7411_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct adt7411_data *data; @@ -317,7 +317,7 @@ static int __devinit adt7411_probe(struct i2c_client *client, return ret; } -static int __devexit adt7411_remove(struct i2c_client *client) +static int adt7411_remove(struct i2c_client *client) { struct adt7411_data *data = i2c_get_clientdata(client); @@ -337,7 +337,7 @@ static struct i2c_driver adt7411_driver = { .name = "adt7411", }, .probe = adt7411_probe, - .remove = __devexit_p(adt7411_remove), + .remove = adt7411_remove, .id_table = adt7411_id, .detect = adt7411_detect, .address_list = normal_i2c, diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 47b8d84b489..d64923d6353 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -34,7 +34,6 @@ #include <linux/list.h> #include <linux/platform_device.h> #include <linux/cpu.h> -#include <linux/pci.h> #include <linux/smp.h> #include <linux/moduleparam.h> #include <asm/msr.h> @@ -197,14 +196,6 @@ struct tjmax { }; static const struct tjmax __cpuinitconst tjmax_table[] = { - { "CPU D410", 100000 }, - { "CPU D425", 100000 }, - { "CPU D510", 100000 }, - { "CPU D525", 100000 }, - { "CPU N450", 100000 }, - { "CPU N455", 100000 }, - { "CPU N470", 100000 }, - { "CPU N475", 100000 }, { "CPU 230", 100000 }, /* Model 0x1c, stepping 2 */ { "CPU 330", 125000 }, /* Model 0x1c, stepping 2 */ { "CPU CE4110", 110000 }, /* Model 0x1c, stepping 10 */ @@ -212,6 +203,28 @@ static const struct tjmax __cpuinitconst tjmax_table[] = { { "CPU CE4170", 110000 }, /* Model 0x1c, stepping 10 */ }; +struct tjmax_model { + u8 model; + u8 mask; + int tjmax; +}; + +#define ANY 0xff + +static const struct tjmax_model __cpuinitconst tjmax_model_table[] = { + { 0x1c, 10, 100000 }, /* D4xx, N4xx, D5xx, N5xx */ + { 0x1c, ANY, 90000 }, /* Z5xx, N2xx, possibly others + * Note: Also matches 230 and 330, + * which are covered by tjmax_table + */ + { 0x26, ANY, 90000 }, /* Atom Tunnel Creek (Exx), Lincroft (Z6xx) + * Note: TjMax for E6xxT is 110C, but CPU type + * is undetectable by software + */ + { 0x27, ANY, 90000 }, /* Atom Medfield (Z2460) */ + { 0x36, ANY, 100000 }, /* Atom Cedar Trail/Cedarview (N2xxx, D2xxx) */ +}; + static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev) { @@ -222,7 +235,6 @@ static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, int usemsr_ee = 1; int err; u32 eax, edx; - struct pci_dev *host_bridge; int i; /* explicit tjmax table entries override heuristics */ @@ -231,32 +243,18 @@ static int __cpuinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, return tjmax_table[i].tjmax; } + for (i = 0; i < ARRAY_SIZE(tjmax_model_table); i++) { + const struct tjmax_model *tm = &tjmax_model_table[i]; + if (c->x86_model == tm->model && + (tm->mask == ANY || c->x86_mask == tm->mask)) + return tm->tjmax; + } + /* Early chips have no MSR for TjMax */ if (c->x86_model == 0xf && c->x86_mask < 4) usemsr_ee = 0; - /* Atom CPUs */ - - if (c->x86_model == 0x1c || c->x86_model == 0x26 - || c->x86_model == 0x27) { - usemsr_ee = 0; - - host_bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0)); - - if (host_bridge && host_bridge->vendor == PCI_VENDOR_ID_INTEL - && (host_bridge->device == 0xa000 /* NM10 based nettop */ - || host_bridge->device == 0xa010)) /* NM10 based netbook */ - tjmax = 100000; - else - tjmax = 90000; - - pci_dev_put(host_bridge); - } else if (c->x86_model == 0x36) { - usemsr_ee = 0; - tjmax = 100000; - } - if (c->x86_model > 0xe && usemsr_ee) { u8 platform_id; @@ -358,7 +356,7 @@ static int __cpuinit get_tjmax(struct cpuinfo_x86 *c, u32 id, return adjust_tjmax(c, id, dev); } -static int __devinit create_name_attr(struct platform_data *pdata, +static int create_name_attr(struct platform_data *pdata, struct device *dev) { sysfs_attr_init(&pdata->name_attr.attr); @@ -553,7 +551,7 @@ static void coretemp_remove_core(struct platform_data *pdata, pdata->core_data[indx] = NULL; } -static int __devinit coretemp_probe(struct platform_device *pdev) +static int coretemp_probe(struct platform_device *pdev) { struct platform_data *pdata; int err; @@ -586,7 +584,7 @@ exit_free: return err; } -static int __devexit coretemp_remove(struct platform_device *pdev) +static int coretemp_remove(struct platform_device *pdev) { struct platform_data *pdata = platform_get_drvdata(pdev); int i; @@ -608,7 +606,7 @@ static struct platform_driver coretemp_driver = { .name = DRVNAME, }, .probe = coretemp_probe, - .remove = __devexit_p(coretemp_remove), + .remove = coretemp_remove, }; static int __cpuinit coretemp_device_add(unsigned int cpu) diff --git a/drivers/hwmon/da9052-hwmon.c b/drivers/hwmon/da9052-hwmon.c index b8d01c5f571..ab4452c5a98 100644 --- a/drivers/hwmon/da9052-hwmon.c +++ b/drivers/hwmon/da9052-hwmon.c @@ -60,30 +60,17 @@ static inline int vbbat_reg_to_mV(int value) return DIV_ROUND_CLOSEST(value * 2500, 512); } -static int da9052_enable_vddout_channel(struct da9052 *da9052) +static inline int da9052_enable_vddout_channel(struct da9052 *da9052) { - int ret; - - ret = da9052_reg_read(da9052, DA9052_ADC_CONT_REG); - if (ret < 0) - return ret; - - ret |= DA9052_ADCCONT_AUTOVDDEN; - - return da9052_reg_write(da9052, DA9052_ADC_CONT_REG, ret); + return da9052_reg_update(da9052, DA9052_ADC_CONT_REG, + DA9052_ADCCONT_AUTOVDDEN, + DA9052_ADCCONT_AUTOVDDEN); } -static int da9052_disable_vddout_channel(struct da9052 *da9052) +static inline int da9052_disable_vddout_channel(struct da9052 *da9052) { - int ret; - - ret = da9052_reg_read(da9052, DA9052_ADC_CONT_REG); - if (ret < 0) - return ret; - - ret &= ~DA9052_ADCCONT_AUTOVDDEN; - - return da9052_reg_write(da9052, DA9052_ADC_CONT_REG, ret); + return da9052_reg_update(da9052, DA9052_ADC_CONT_REG, + DA9052_ADCCONT_AUTOVDDEN, 0); } static ssize_t da9052_read_vddout(struct device *dev, @@ -283,7 +270,7 @@ static struct attribute *da9052_attr[] = { static const struct attribute_group da9052_attr_group = {.attrs = da9052_attr}; -static int __devinit da9052_hwmon_probe(struct platform_device *pdev) +static int da9052_hwmon_probe(struct platform_device *pdev) { struct da9052_hwmon *hwmon; int ret; @@ -316,7 +303,7 @@ err_mem: return ret; } -static int __devexit da9052_hwmon_remove(struct platform_device *pdev) +static int da9052_hwmon_remove(struct platform_device *pdev) { struct da9052_hwmon *hwmon = platform_get_drvdata(pdev); @@ -328,7 +315,7 @@ static int __devexit da9052_hwmon_remove(struct platform_device *pdev) static struct platform_driver da9052_hwmon_driver = { .probe = da9052_hwmon_probe, - .remove = __devexit_p(da9052_hwmon_remove), + .remove = da9052_hwmon_remove, .driver = { .name = "da9052-hwmon", .owner = THIS_MODULE, diff --git a/drivers/hwmon/da9055-hwmon.c b/drivers/hwmon/da9055-hwmon.c new file mode 100644 index 00000000000..9465c050c32 --- /dev/null +++ b/drivers/hwmon/da9055-hwmon.c @@ -0,0 +1,336 @@ +/* + * HWMON Driver for Dialog DA9055 + * + * Copyright(c) 2012 Dialog Semiconductor Ltd. + * + * Author: David Dajun Chen <dchen@diasemi.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 the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/completion.h> + +#include <linux/mfd/da9055/core.h> +#include <linux/mfd/da9055/reg.h> + +#define DA9055_ADCIN_DIV 102 +#define DA9055_VSYS_DIV 85 + +#define DA9055_ADC_VSYS 0 +#define DA9055_ADC_ADCIN1 1 +#define DA9055_ADC_ADCIN2 2 +#define DA9055_ADC_ADCIN3 3 +#define DA9055_ADC_TJUNC 4 + +struct da9055_hwmon { + struct da9055 *da9055; + struct device *class_device; + struct mutex hwmon_lock; + struct mutex irq_lock; + struct completion done; +}; + +static const char * const input_names[] = { + [DA9055_ADC_VSYS] = "VSYS", + [DA9055_ADC_ADCIN1] = "ADC IN1", + [DA9055_ADC_ADCIN2] = "ADC IN2", + [DA9055_ADC_ADCIN3] = "ADC IN3", + [DA9055_ADC_TJUNC] = "CHIP TEMP", +}; + +static const u8 chan_mux[DA9055_ADC_TJUNC + 1] = { + [DA9055_ADC_VSYS] = DA9055_ADC_MUX_VSYS, + [DA9055_ADC_ADCIN1] = DA9055_ADC_MUX_ADCIN1, + [DA9055_ADC_ADCIN2] = DA9055_ADC_MUX_ADCIN2, + [DA9055_ADC_ADCIN3] = DA9055_ADC_MUX_ADCIN3, + [DA9055_ADC_TJUNC] = DA9055_ADC_MUX_T_SENSE, +}; + +static int da9055_adc_manual_read(struct da9055_hwmon *hwmon, + unsigned char channel) +{ + int ret; + unsigned short calc_data; + unsigned short data; + unsigned char mux_sel; + struct da9055 *da9055 = hwmon->da9055; + + if (channel > DA9055_ADC_TJUNC) + return -EINVAL; + + mutex_lock(&hwmon->irq_lock); + + /* Selects desired MUX for manual conversion */ + mux_sel = chan_mux[channel] | DA9055_ADC_MAN_CONV; + + ret = da9055_reg_write(da9055, DA9055_REG_ADC_MAN, mux_sel); + if (ret < 0) + goto err; + + /* Wait for an interrupt */ + if (!wait_for_completion_timeout(&hwmon->done, + msecs_to_jiffies(500))) { + dev_err(da9055->dev, + "timeout waiting for ADC conversion interrupt\n"); + ret = -ETIMEDOUT; + goto err; + } + + ret = da9055_reg_read(da9055, DA9055_REG_ADC_RES_H); + if (ret < 0) + goto err; + + calc_data = (unsigned short)ret; + data = calc_data << 2; + + ret = da9055_reg_read(da9055, DA9055_REG_ADC_RES_L); + if (ret < 0) + goto err; + + calc_data = (unsigned short)(ret & DA9055_ADC_LSB_MASK); + data |= calc_data; + + ret = data; + +err: + mutex_unlock(&hwmon->irq_lock); + return ret; +} + +static irqreturn_t da9055_auxadc_irq(int irq, void *irq_data) +{ + struct da9055_hwmon *hwmon = irq_data; + + complete(&hwmon->done); + + return IRQ_HANDLED; +} + +/* Conversion function for VSYS and ADCINx */ +static inline int volt_reg_to_mV(int value, int channel) +{ + if (channel == DA9055_ADC_VSYS) + return DIV_ROUND_CLOSEST(value * 1000, DA9055_VSYS_DIV) + 2500; + else + return DIV_ROUND_CLOSEST(value * 1000, DA9055_ADCIN_DIV); +} + +static int da9055_enable_auto_mode(struct da9055 *da9055, int channel) +{ + + return da9055_reg_update(da9055, DA9055_REG_ADC_CONT, 1 << channel, + 1 << channel); + +} + +static int da9055_disable_auto_mode(struct da9055 *da9055, int channel) +{ + + return da9055_reg_update(da9055, DA9055_REG_ADC_CONT, 1 << channel, 0); +} + +static ssize_t da9055_read_auto_ch(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct da9055_hwmon *hwmon = dev_get_drvdata(dev); + int ret, adc; + int channel = to_sensor_dev_attr(devattr)->index; + + mutex_lock(&hwmon->hwmon_lock); + + ret = da9055_enable_auto_mode(hwmon->da9055, channel); + if (ret < 0) + goto hwmon_err; + + usleep_range(10000, 10500); + + adc = da9055_reg_read(hwmon->da9055, DA9055_REG_VSYS_RES + channel); + if (adc < 0) { + ret = adc; + goto hwmon_err_release; + } + + ret = da9055_disable_auto_mode(hwmon->da9055, channel); + if (ret < 0) + goto hwmon_err; + + mutex_unlock(&hwmon->hwmon_lock); + + return sprintf(buf, "%d\n", volt_reg_to_mV(adc, channel)); + +hwmon_err_release: + da9055_disable_auto_mode(hwmon->da9055, channel); +hwmon_err: + mutex_unlock(&hwmon->hwmon_lock); + return ret; +} + +static ssize_t da9055_read_tjunc(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct da9055_hwmon *hwmon = dev_get_drvdata(dev); + int tjunc; + int toffset; + + tjunc = da9055_adc_manual_read(hwmon, DA9055_ADC_TJUNC); + if (tjunc < 0) + return tjunc; + + toffset = da9055_reg_read(hwmon->da9055, DA9055_REG_T_OFFSET); + if (toffset < 0) + return toffset; + + /* + * Degrees celsius = -0.4084 * (ADC_RES - T_OFFSET) + 307.6332 + * T_OFFSET is a trim value used to improve accuracy of the result + */ + return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(-4084 * (tjunc - toffset) + + 3076332, 10000)); +} + +static ssize_t da9055_hwmon_show_name(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + return sprintf(buf, "da9055-hwmon\n"); +} + +static ssize_t show_label(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return sprintf(buf, "%s\n", + input_names[to_sensor_dev_attr(devattr)->index]); +} + +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, da9055_read_auto_ch, NULL, + DA9055_ADC_VSYS); +static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL, + DA9055_ADC_VSYS); +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, da9055_read_auto_ch, NULL, + DA9055_ADC_ADCIN1); +static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_label, NULL, + DA9055_ADC_ADCIN1); +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, da9055_read_auto_ch, NULL, + DA9055_ADC_ADCIN2); +static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_label, NULL, + DA9055_ADC_ADCIN2); +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, da9055_read_auto_ch, NULL, + DA9055_ADC_ADCIN3); +static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, + DA9055_ADC_ADCIN3); + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, da9055_read_tjunc, NULL, + DA9055_ADC_TJUNC); +static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL, + DA9055_ADC_TJUNC); + +static DEVICE_ATTR(name, S_IRUGO, da9055_hwmon_show_name, NULL); + +static struct attribute *da9055_attr[] = { + &dev_attr_name.attr, + &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_label.dev_attr.attr, + &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_label.dev_attr.attr, + &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_label.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_label.dev_attr.attr, + + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_label.dev_attr.attr, + NULL +}; + +static const struct attribute_group da9055_attr_group = {.attrs = da9055_attr}; + +static int da9055_hwmon_probe(struct platform_device *pdev) +{ + struct da9055_hwmon *hwmon; + int hwmon_irq, ret; + + hwmon = devm_kzalloc(&pdev->dev, sizeof(struct da9055_hwmon), + GFP_KERNEL); + if (!hwmon) + return -ENOMEM; + + mutex_init(&hwmon->hwmon_lock); + mutex_init(&hwmon->irq_lock); + + init_completion(&hwmon->done); + hwmon->da9055 = dev_get_drvdata(pdev->dev.parent); + + platform_set_drvdata(pdev, hwmon); + + hwmon_irq = platform_get_irq_byname(pdev, "HWMON"); + if (hwmon_irq < 0) + return hwmon_irq; + + hwmon_irq = regmap_irq_get_virq(hwmon->da9055->irq_data, hwmon_irq); + if (hwmon_irq < 0) + return hwmon_irq; + + ret = devm_request_threaded_irq(&pdev->dev, hwmon_irq, + NULL, da9055_auxadc_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "adc-irq", hwmon); + if (ret != 0) { + dev_err(hwmon->da9055->dev, "DA9055 ADC IRQ failed ret=%d\n", + ret); + return ret; + } + + ret = sysfs_create_group(&pdev->dev.kobj, &da9055_attr_group); + if (ret) + return ret; + + hwmon->class_device = hwmon_device_register(&pdev->dev); + if (IS_ERR(hwmon->class_device)) { + ret = PTR_ERR(hwmon->class_device); + goto err; + } + + return 0; + +err: + sysfs_remove_group(&pdev->dev.kobj, &da9055_attr_group); + return ret; +} + +static int da9055_hwmon_remove(struct platform_device *pdev) +{ + struct da9055_hwmon *hwmon = platform_get_drvdata(pdev); + + sysfs_remove_group(&pdev->dev.kobj, &da9055_attr_group); + hwmon_device_unregister(hwmon->class_device); + + return 0; +} + +static struct platform_driver da9055_hwmon_driver = { + .probe = da9055_hwmon_probe, + .remove = da9055_hwmon_remove, + .driver = { + .name = "da9055-hwmon", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(da9055_hwmon_driver); + +MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); +MODULE_DESCRIPTION("DA9055 HWMON driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:da9055-hwmon"); diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index fe0eeec0b75..7430f70ae45 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -2630,7 +2630,7 @@ exit: return err; } -static int __devinit dme1737_isa_probe(struct platform_device *pdev) +static int dme1737_isa_probe(struct platform_device *pdev) { u8 company, device; struct resource *res; @@ -2718,7 +2718,7 @@ exit_remove_files: return err; } -static int __devexit dme1737_isa_remove(struct platform_device *pdev) +static int dme1737_isa_remove(struct platform_device *pdev) { struct dme1737_data *data = platform_get_drvdata(pdev); @@ -2734,7 +2734,7 @@ static struct platform_driver dme1737_isa_driver = { .name = "dme1737", }, .probe = dme1737_isa_probe, - .remove = __devexit_p(dme1737_isa_remove), + .remove = dme1737_isa_remove, }; /* --------------------------------------------------------------------- diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 4dd7723d257..a9816979c5d 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -1343,7 +1343,7 @@ static struct attribute *f71805f_attr_pwm[] = { * Device registration and initialization */ -static void __devinit f71805f_init_device(struct f71805f_data *data) +static void f71805f_init_device(struct f71805f_data *data) { u8 reg; int i; @@ -1374,7 +1374,7 @@ static void __devinit f71805f_init_device(struct f71805f_data *data) } } -static int __devinit f71805f_probe(struct platform_device *pdev) +static int f71805f_probe(struct platform_device *pdev) { struct f71805f_sio_data *sio_data = pdev->dev.platform_data; struct f71805f_data *data; @@ -1490,7 +1490,7 @@ exit_remove_files: return err; } -static int __devexit f71805f_remove(struct platform_device *pdev) +static int f71805f_remove(struct platform_device *pdev) { struct f71805f_data *data = platform_get_drvdata(pdev); int i; @@ -1510,7 +1510,7 @@ static struct platform_driver f71805f_driver = { .name = DRVNAME, }, .probe = f71805f_probe, - .remove = __devexit_p(f71805f_remove), + .remove = f71805f_remove, }; static int __init f71805f_device_add(unsigned short address, diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 50e4ce2d22d..bb7275cc47f 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -364,7 +364,7 @@ static ssize_t store_pwm_auto_point_temp(struct device *dev, static ssize_t show_name(struct device *dev, struct device_attribute *devattr, char *buf); -static int __devinit f71882fg_probe(struct platform_device *pdev); +static int f71882fg_probe(struct platform_device *pdev); static int f71882fg_remove(struct platform_device *pdev); static struct platform_driver f71882fg_driver = { @@ -2145,7 +2145,7 @@ static ssize_t show_name(struct device *dev, struct device_attribute *devattr, return sprintf(buf, "%s\n", f71882fg_names[data->type]); } -static int __devinit f71882fg_create_sysfs_files(struct platform_device *pdev, +static int f71882fg_create_sysfs_files(struct platform_device *pdev, struct sensor_device_attribute_2 *attr, int count) { int err, i; @@ -2167,7 +2167,7 @@ static void f71882fg_remove_sysfs_files(struct platform_device *pdev, device_remove_file(&pdev->dev, &attr[i].dev_attr); } -static int __devinit f71882fg_create_fan_sysfs_files( +static int f71882fg_create_fan_sysfs_files( struct platform_device *pdev, int idx) { struct f71882fg_data *data = platform_get_drvdata(pdev); @@ -2265,7 +2265,7 @@ static int __devinit f71882fg_create_fan_sysfs_files( return err; } -static int __devinit f71882fg_probe(struct platform_device *pdev) +static int f71882fg_probe(struct platform_device *pdev) { struct f71882fg_data *data; struct f71882fg_sio_data *sio_data = pdev->dev.platform_data; diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c index 4f411040738..b757088aedd 100644 --- a/drivers/hwmon/fam15h_power.c +++ b/drivers/hwmon/fam15h_power.c @@ -31,6 +31,9 @@ MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor"); MODULE_AUTHOR("Andreas Herrmann <herrmann.der.user@googlemail.com>"); MODULE_LICENSE("GPL"); +/* Family 16h Northbridge's function 4 PCI ID */ +#define PCI_DEVICE_ID_AMD_16H_NB_F4 0x1534 + /* D18F3 */ #define REG_NORTHBRIDGE_CAP 0xe8 @@ -111,7 +114,7 @@ static const struct attribute_group fam15h_power_attr_group = { .attrs = fam15h_power_attrs, }; -static bool __devinit fam15h_power_is_internal_node0(struct pci_dev *f4) +static bool fam15h_power_is_internal_node0(struct pci_dev *f4) { u32 val; @@ -168,7 +171,7 @@ static int fam15h_power_resume(struct pci_dev *pdev) #define fam15h_power_resume NULL #endif -static void __devinit fam15h_power_init_data(struct pci_dev *f4, +static void fam15h_power_init_data(struct pci_dev *f4, struct fam15h_power_data *data) { u32 val; @@ -194,7 +197,7 @@ static void __devinit fam15h_power_init_data(struct pci_dev *f4, data->processor_pwr_watts = (tmp * 15625) >> 10; } -static int __devinit fam15h_power_probe(struct pci_dev *pdev, +static int fam15h_power_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct fam15h_power_data *data; @@ -235,7 +238,7 @@ exit_remove_group: return err; } -static void __devexit fam15h_power_remove(struct pci_dev *pdev) +static void fam15h_power_remove(struct pci_dev *pdev) { struct device *dev; struct fam15h_power_data *data; @@ -248,6 +251,7 @@ static void __devexit fam15h_power_remove(struct pci_dev *pdev) static DEFINE_PCI_DEVICE_TABLE(fam15h_power_id_table) = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) }, {} }; MODULE_DEVICE_TABLE(pci, fam15h_power_id_table); @@ -256,7 +260,7 @@ static struct pci_driver fam15h_power_driver = { .name = "fam15h_power", .id_table = fam15h_power_id_table, .probe = fam15h_power_probe, - .remove = __devexit_p(fam15h_power_remove), + .remove = fam15h_power_remove, .resume = fam15h_power_resume, }; diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index 1381a2e3bbd..4e04c1228e5 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -499,13 +499,13 @@ static int gpio_fan_get_of_pdata(struct device *dev, return 0; } -static struct of_device_id of_gpio_fan_match[] __devinitdata = { +static struct of_device_id of_gpio_fan_match[] = { { .compatible = "gpio-fan", }, {}, }; #endif /* CONFIG_OF_GPIO */ -static int __devinit gpio_fan_probe(struct platform_device *pdev) +static int gpio_fan_probe(struct platform_device *pdev) { int err; struct gpio_fan_data *fan_data; @@ -581,7 +581,7 @@ err_free_alarm: return err; } -static int __devexit gpio_fan_remove(struct platform_device *pdev) +static int gpio_fan_remove(struct platform_device *pdev) { struct gpio_fan_data *fan_data = platform_get_drvdata(pdev); @@ -626,7 +626,7 @@ static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume); static struct platform_driver gpio_fan_driver = { .probe = gpio_fan_probe, - .remove = __devexit_p(gpio_fan_remove), + .remove = gpio_fan_remove, .driver = { .name = "gpio-fan", .pm = GPIO_FAN_PM, diff --git a/drivers/hwmon/hih6130.c b/drivers/hwmon/hih6130.c index 9a675efaa78..2dc37c7c694 100644 --- a/drivers/hwmon/hih6130.c +++ b/drivers/hwmon/hih6130.c @@ -220,7 +220,7 @@ static const struct attribute_group hih6130_attr_group = { * device's name. * Returns 0 on success. */ -static int __devinit hih6130_probe(struct i2c_client *client, +static int hih6130_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct hih6130 *hih6130; @@ -263,7 +263,7 @@ fail_remove_sysfs: * hih6130_remove() - remove device * @client: I2C client device */ -static int __devexit hih6130_remove(struct i2c_client *client) +static int hih6130_remove(struct i2c_client *client) { struct hih6130 *hih6130 = i2c_get_clientdata(client); @@ -283,7 +283,7 @@ MODULE_DEVICE_TABLE(i2c, hih6130_id); static struct i2c_driver hih6130_driver = { .driver.name = "hih6130", .probe = hih6130_probe, - .remove = __devexit_p(hih6130_remove), + .remove = hih6130_remove, .id_table = hih6130_id, }; diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c index 46141abaafb..b87c2ccee06 100644 --- a/drivers/hwmon/i5k_amb.c +++ b/drivers/hwmon/i5k_amb.c @@ -260,7 +260,7 @@ static ssize_t show_label(struct device *dev, attr->index & DIMM_MASK); } -static int __devinit i5k_amb_hwmon_init(struct platform_device *pdev) +static int i5k_amb_hwmon_init(struct platform_device *pdev) { int i, j, k, d = 0; u16 c; @@ -406,7 +406,7 @@ exit_remove: return res; } -static int __devinit i5k_amb_add(void) +static int i5k_amb_add(void) { int res = -ENODEV; @@ -425,7 +425,7 @@ err: return res; } -static int __devinit i5k_find_amb_registers(struct i5k_amb_data *data, +static int i5k_find_amb_registers(struct i5k_amb_data *data, unsigned long devid) { struct pci_dev *pcidev; @@ -459,7 +459,7 @@ out: return res; } -static int __devinit i5k_channel_probe(u16 *amb_present, unsigned long dev_id) +static int i5k_channel_probe(u16 *amb_present, unsigned long dev_id) { struct pci_dev *pcidev; u16 val16; @@ -488,14 +488,14 @@ out: static struct { unsigned long err; unsigned long fbd0; -} chipset_ids[] __devinitdata = { +} chipset_ids[] = { { PCI_DEVICE_ID_INTEL_5000_ERR, PCI_DEVICE_ID_INTEL_5000_FBD0 }, { PCI_DEVICE_ID_INTEL_5400_ERR, PCI_DEVICE_ID_INTEL_5400_FBD0 }, { 0, 0 } }; #ifdef MODULE -static struct pci_device_id i5k_amb_ids[] __devinitdata = { +static struct pci_device_id i5k_amb_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5000_ERR) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_ERR) }, { 0, } @@ -503,7 +503,7 @@ static struct pci_device_id i5k_amb_ids[] __devinitdata = { MODULE_DEVICE_TABLE(pci, i5k_amb_ids); #endif -static int __devinit i5k_amb_probe(struct platform_device *pdev) +static int i5k_amb_probe(struct platform_device *pdev) { struct i5k_amb_data *data; struct resource *reso; @@ -564,7 +564,7 @@ err: return res; } -static int __devexit i5k_amb_remove(struct platform_device *pdev) +static int i5k_amb_remove(struct platform_device *pdev) { int i; struct i5k_amb_data *data = platform_get_drvdata(pdev); @@ -587,7 +587,7 @@ static struct platform_driver i5k_amb_driver = { .name = DRVNAME, }, .probe = i5k_amb_probe, - .remove = __devexit_p(i5k_amb_remove), + .remove = i5k_amb_remove, }; static int __init i5k_amb_init(void) diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index 2b726346f8f..8e7158c3ad2 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -302,19 +302,8 @@ static struct i2c_driver ina2xx_driver = { .id_table = ina2xx_id, }; -static int __init ina2xx_init(void) -{ - return i2c_add_driver(&ina2xx_driver); -} - -static void __exit ina2xx_exit(void) -{ - i2c_del_driver(&ina2xx_driver); -} +module_i2c_driver(ina2xx_driver); MODULE_AUTHOR("Lothar Felten <l-felten@ti.com>"); MODULE_DESCRIPTION("ina2xx driver"); MODULE_LICENSE("GPL"); - -module_init(ina2xx_init); -module_exit(ina2xx_exit); diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index f1de3979181..d32aa354cbd 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -428,7 +428,7 @@ static inline int has_old_autopwm(const struct it87_data *data) } static int it87_probe(struct platform_device *pdev); -static int __devexit it87_remove(struct platform_device *pdev); +static int it87_remove(struct platform_device *pdev); static int it87_read_value(struct it87_data *data, u8 reg); static void it87_write_value(struct it87_data *data, u8 reg, u8 value); @@ -443,7 +443,7 @@ static struct platform_driver it87_driver = { .name = DRVNAME, }, .probe = it87_probe, - .remove = __devexit_p(it87_remove), + .remove = it87_remove, }; static ssize_t show_in(struct device *dev, struct device_attribute *attr, @@ -1966,7 +1966,7 @@ static void it87_remove_files(struct device *dev) sysfs_remove_group(&dev->kobj, &it87_group_label); } -static int __devinit it87_probe(struct platform_device *pdev) +static int it87_probe(struct platform_device *pdev) { struct it87_data *data; struct resource *res; @@ -2158,7 +2158,7 @@ error: return err; } -static int __devexit it87_remove(struct platform_device *pdev) +static int it87_remove(struct platform_device *pdev) { struct it87_data *data = platform_get_drvdata(pdev); @@ -2191,7 +2191,7 @@ static void it87_write_value(struct it87_data *data, u8 reg, u8 value) } /* Return 1 if and only if the PWM interface is safe to use */ -static int __devinit it87_check_pwm(struct device *dev) +static int it87_check_pwm(struct device *dev) { struct it87_data *data = dev_get_drvdata(dev); /* @@ -2248,7 +2248,7 @@ static int __devinit it87_check_pwm(struct device *dev) } /* Called when we have found a new IT87. */ -static void __devinit it87_init_device(struct platform_device *pdev) +static void it87_init_device(struct platform_device *pdev) { struct it87_sio_data *sio_data = pdev->dev.platform_data; struct it87_data *data = platform_get_drvdata(pdev); diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c index dee9eec2036..e0d66b9590a 100644 --- a/drivers/hwmon/jz4740-hwmon.c +++ b/drivers/hwmon/jz4740-hwmon.c @@ -102,7 +102,7 @@ static const struct attribute_group jz4740_hwmon_attr_group = { .attrs = jz4740_hwmon_attributes, }; -static int __devinit jz4740_hwmon_probe(struct platform_device *pdev) +static int jz4740_hwmon_probe(struct platform_device *pdev) { int ret; struct jz4740_hwmon *hwmon; @@ -172,7 +172,7 @@ err_remove_file: return ret; } -static int __devexit jz4740_hwmon_remove(struct platform_device *pdev) +static int jz4740_hwmon_remove(struct platform_device *pdev) { struct jz4740_hwmon *hwmon = platform_get_drvdata(pdev); @@ -184,7 +184,7 @@ static int __devexit jz4740_hwmon_remove(struct platform_device *pdev) static struct platform_driver jz4740_hwmon_driver = { .probe = jz4740_hwmon_probe, - .remove = __devexit_p(jz4740_hwmon_remove), + .remove = jz4740_hwmon_remove, .driver = { .name = "jz4740-hwmon", .owner = THIS_MODULE, diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index f2fe8078633..e3b037c73a7 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -95,7 +95,7 @@ static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit, NULL, 1); static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); -static bool __devinit has_erratum_319(struct pci_dev *pdev) +static bool has_erratum_319(struct pci_dev *pdev) { u32 pkg_type, reg_dram_cfg; @@ -129,7 +129,7 @@ static bool __devinit has_erratum_319(struct pci_dev *pdev) (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_mask <= 2); } -static int __devinit k10temp_probe(struct pci_dev *pdev, +static int k10temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct device *hwmon_dev; @@ -192,7 +192,7 @@ exit: return err; } -static void __devexit k10temp_remove(struct pci_dev *pdev) +static void k10temp_remove(struct pci_dev *pdev) { hwmon_device_unregister(pci_get_drvdata(pdev)); device_remove_file(&pdev->dev, &dev_attr_name); @@ -219,7 +219,7 @@ static struct pci_driver k10temp_driver = { .name = "k10temp", .id_table = k10temp_id_table, .probe = k10temp_probe, - .remove = __devexit_p(k10temp_remove), + .remove = k10temp_remove, }; module_pci_driver(k10temp_driver); diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c index e8c7fb0bbf9..9f3c0aeacdb 100644 --- a/drivers/hwmon/k8temp.c +++ b/drivers/hwmon/k8temp.c @@ -142,7 +142,7 @@ static DEFINE_PCI_DEVICE_TABLE(k8temp_ids) = { MODULE_DEVICE_TABLE(pci, k8temp_ids); -static int __devinit is_rev_g_desktop(u8 model) +static int is_rev_g_desktop(u8 model) { u32 brandidx; @@ -173,7 +173,7 @@ static int __devinit is_rev_g_desktop(u8 model) return 1; } -static int __devinit k8temp_probe(struct pci_dev *pdev, +static int k8temp_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int err; @@ -304,7 +304,7 @@ exit_remove: return err; } -static void __devexit k8temp_remove(struct pci_dev *pdev) +static void k8temp_remove(struct pci_dev *pdev) { struct k8temp_data *data = pci_get_drvdata(pdev); @@ -324,7 +324,7 @@ static struct pci_driver k8temp_driver = { .name = "k8temp", .id_table = k8temp_ids, .probe = k8temp_probe, - .remove = __devexit_p(k8temp_remove), + .remove = k8temp_remove, }; module_pci_driver(k8temp_driver); diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index 2d1777a03ed..016efa26ba7 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c @@ -131,7 +131,7 @@ static DEVICE_ATTR(name, S_IRUGO, lm70_show_name, NULL); /*----------------------------------------------------------------------*/ -static int __devinit lm70_probe(struct spi_device *spi) +static int lm70_probe(struct spi_device *spi) { int chip = spi_get_device_id(spi)->driver_data; struct lm70 *p_lm70; @@ -178,7 +178,7 @@ out_dev_create_temp_file_failed: return status; } -static int __devexit lm70_remove(struct spi_device *spi) +static int lm70_remove(struct spi_device *spi) { struct lm70 *p_lm70 = spi_get_drvdata(spi); @@ -207,7 +207,7 @@ static struct spi_driver lm70_driver = { }, .id_table = lm70_ids, .probe = lm70_probe, - .remove = __devexit_p(lm70_remove), + .remove = lm70_remove, }; module_spi_driver(lm70_driver); diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index c6ffafe600a..53d6ee8ffa3 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -833,7 +833,7 @@ static struct lm78_data *lm78_update_device(struct device *dev) } #ifdef CONFIG_ISA -static int __devinit lm78_isa_probe(struct platform_device *pdev) +static int lm78_isa_probe(struct platform_device *pdev) { int err; struct lm78_data *data; @@ -886,7 +886,7 @@ static int __devinit lm78_isa_probe(struct platform_device *pdev) return err; } -static int __devexit lm78_isa_remove(struct platform_device *pdev) +static int lm78_isa_remove(struct platform_device *pdev) { struct lm78_data *data = platform_get_drvdata(pdev); @@ -903,7 +903,7 @@ static struct platform_driver lm78_isa_driver = { .name = "lm78", }, .probe = lm78_isa_probe, - .remove = __devexit_p(lm78_isa_remove), + .remove = lm78_isa_remove, }; /* return 1 if a supported chip is found, 0 otherwise */ diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c index b4eb0889c46..eda077de8a9 100644 --- a/drivers/hwmon/max1111.c +++ b/drivers/hwmon/max1111.c @@ -157,7 +157,7 @@ static const struct attribute_group max1110_attr_group = { .attrs = max1110_attributes, }; -static int __devinit setup_transfer(struct max1111_data *data) +static int setup_transfer(struct max1111_data *data) { struct spi_message *m; struct spi_transfer *x; @@ -179,7 +179,7 @@ static int __devinit setup_transfer(struct max1111_data *data) return 0; } -static int __devinit max1111_probe(struct spi_device *spi) +static int max1111_probe(struct spi_device *spi) { enum chips chip = spi_get_device_id(spi)->driver_data; struct max1111_data *data; @@ -256,7 +256,7 @@ err_remove: return err; } -static int __devexit max1111_remove(struct spi_device *spi) +static int max1111_remove(struct spi_device *spi) { struct max1111_data *data = spi_get_drvdata(spi); @@ -283,7 +283,7 @@ static struct spi_driver max1111_driver = { }, .id_table = max1111_ids, .probe = max1111_probe, - .remove = __devexit_p(max1111_remove), + .remove = max1111_remove, }; module_spi_driver(max1111_driver); diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c index 6304f2616fa..b5ebb9198c7 100644 --- a/drivers/hwmon/max197.c +++ b/drivers/hwmon/max197.c @@ -257,7 +257,7 @@ static const struct attribute_group max197_sysfs_group = { }, }; -static int __devinit max197_probe(struct platform_device *pdev) +static int max197_probe(struct platform_device *pdev) { int ch, ret; struct max197_data *data; @@ -316,7 +316,7 @@ error: return ret; } -static int __devexit max197_remove(struct platform_device *pdev) +static int max197_remove(struct platform_device *pdev) { struct max197_data *data = platform_get_drvdata(pdev); @@ -339,7 +339,7 @@ static struct platform_driver max197_driver = { .owner = THIS_MODULE, }, .probe = max197_probe, - .remove = __devexit_p(max197_remove), + .remove = max197_remove, .id_table = max197_device_ids, }; module_platform_driver(max197_driver); diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c index cf47a59657a..2a7f331cd3c 100644 --- a/drivers/hwmon/mc13783-adc.c +++ b/drivers/hwmon/mc13783-adc.c @@ -233,7 +233,7 @@ out_err_create_16chans: return ret; } -static int __devexit mc13783_adc_remove(struct platform_device *pdev) +static int mc13783_adc_remove(struct platform_device *pdev) { struct mc13783_adc_priv *priv = platform_get_drvdata(pdev); kernel_ulong_t driver_data = platform_get_device_id(pdev)->driver_data; @@ -265,7 +265,7 @@ static const struct platform_device_id mc13783_adc_idtable[] = { MODULE_DEVICE_TABLE(platform, mc13783_adc_idtable); static struct platform_driver mc13783_adc_driver = { - .remove = __devexit_p(mc13783_adc_remove), + .remove = mc13783_adc_remove, .driver = { .owner = THIS_MODULE, .name = DRIVER_NAME, diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c index 74a6c58d021..a87eb8986e3 100644 --- a/drivers/hwmon/ntc_thermistor.c +++ b/drivers/hwmon/ntc_thermistor.c @@ -309,7 +309,7 @@ static const struct attribute_group ntc_attr_group = { .attrs = ntc_attributes, }; -static int __devinit ntc_thermistor_probe(struct platform_device *pdev) +static int ntc_thermistor_probe(struct platform_device *pdev) { struct ntc_data *data; struct ntc_thermistor_platform_data *pdata = pdev->dev.platform_data; @@ -393,7 +393,7 @@ err_after_sysfs: return ret; } -static int __devexit ntc_thermistor_remove(struct platform_device *pdev) +static int ntc_thermistor_remove(struct platform_device *pdev) { struct ntc_data *data = platform_get_drvdata(pdev); @@ -419,7 +419,7 @@ static struct platform_driver ntc_thermistor_driver = { .owner = THIS_MODULE, }, .probe = ntc_thermistor_probe, - .remove = __devexit_p(ntc_thermistor_remove), + .remove = ntc_thermistor_remove, .id_table = ntc_thermistor_id, }; diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index 91d5b2a21dd..e35856bb79b 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -228,7 +228,7 @@ struct pc87360_data { */ static int pc87360_probe(struct platform_device *pdev); -static int __devexit pc87360_remove(struct platform_device *pdev); +static int pc87360_remove(struct platform_device *pdev); static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, u8 reg); @@ -248,7 +248,7 @@ static struct platform_driver pc87360_driver = { .name = "pc87360", }, .probe = pc87360_probe, - .remove = __devexit_p(pc87360_remove), + .remove = pc87360_remove, }; /* @@ -1221,7 +1221,7 @@ static void pc87360_remove_files(struct device *dev) sysfs_remove_group(&dev->kobj, &pc8736x_vin_group); } -static int __devinit pc87360_probe(struct platform_device *pdev) +static int pc87360_probe(struct platform_device *pdev) { int i; struct pc87360_data *data; @@ -1375,7 +1375,7 @@ error: return err; } -static int __devexit pc87360_remove(struct platform_device *pdev) +static int pc87360_remove(struct platform_device *pdev) { struct pc87360_data *data = platform_get_drvdata(pdev); diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index f185b1fa53e..6086ad039d7 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c @@ -956,7 +956,7 @@ static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); * Device detection, attach and detach */ -static int __devinit pc87427_request_regions(struct platform_device *pdev, +static int pc87427_request_regions(struct platform_device *pdev, int count) { struct resource *res; @@ -980,7 +980,7 @@ static int __devinit pc87427_request_regions(struct platform_device *pdev, return 0; } -static void __devinit pc87427_init_device(struct device *dev) +static void pc87427_init_device(struct device *dev) { struct pc87427_sio_data *sio_data = dev->platform_data; struct pc87427_data *data = dev_get_drvdata(dev); @@ -1072,7 +1072,7 @@ static void pc87427_remove_files(struct device *dev) } } -static int __devinit pc87427_probe(struct platform_device *pdev) +static int pc87427_probe(struct platform_device *pdev) { struct pc87427_sio_data *sio_data = pdev->dev.platform_data; struct pc87427_data *data; @@ -1141,7 +1141,7 @@ exit_remove_files: return err; } -static int __devexit pc87427_remove(struct platform_device *pdev) +static int pc87427_remove(struct platform_device *pdev) { struct pc87427_data *data = platform_get_drvdata(pdev); @@ -1158,7 +1158,7 @@ static struct platform_driver pc87427_driver = { .name = DRVNAME, }, .probe = pc87427_probe, - .remove = __devexit_p(pc87427_remove), + .remove = pc87427_remove, }; static int __init pc87427_device_add(const struct pc87427_sio_data *sio_data) diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c index bcecd025fcc..ff2ae0252a4 100644 --- a/drivers/hwmon/s3c-hwmon.c +++ b/drivers/hwmon/s3c-hwmon.c @@ -275,7 +275,7 @@ static void s3c_hwmon_remove_attr(struct device *dev, * s3c_hwmon_probe - device probe entry. * @dev: The device being probed. */ -static int __devinit s3c_hwmon_probe(struct platform_device *dev) +static int s3c_hwmon_probe(struct platform_device *dev) { struct s3c_hwmon_pdata *pdata = dev->dev.platform_data; struct s3c_hwmon *hwmon; @@ -364,7 +364,7 @@ static int __devinit s3c_hwmon_probe(struct platform_device *dev) return ret; } -static int __devexit s3c_hwmon_remove(struct platform_device *dev) +static int s3c_hwmon_remove(struct platform_device *dev) { struct s3c_hwmon *hwmon = platform_get_drvdata(dev); int i; @@ -386,7 +386,7 @@ static struct platform_driver s3c_hwmon_driver = { .owner = THIS_MODULE, }, .probe = s3c_hwmon_probe, - .remove = __devexit_p(s3c_hwmon_remove), + .remove = s3c_hwmon_remove, }; module_platform_driver(s3c_hwmon_driver); diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c index 49f6230bdcf..0cc99fd83e8 100644 --- a/drivers/hwmon/sch5627.c +++ b/drivers/hwmon/sch5627.c @@ -153,7 +153,7 @@ abort: return ret; } -static int __devinit sch5627_read_limits(struct sch5627_data *data) +static int sch5627_read_limits(struct sch5627_data *data) { int i, val; @@ -465,7 +465,7 @@ static int sch5627_remove(struct platform_device *pdev) return 0; } -static int __devinit sch5627_probe(struct platform_device *pdev) +static int sch5627_probe(struct platform_device *pdev) { struct sch5627_data *data; int err, build_code, build_id, hwmon_rev, val; diff --git a/drivers/hwmon/sch5636.c b/drivers/hwmon/sch5636.c index 51711801619..547b5c952ef 100644 --- a/drivers/hwmon/sch5636.c +++ b/drivers/hwmon/sch5636.c @@ -405,7 +405,7 @@ static int sch5636_remove(struct platform_device *pdev) return 0; } -static int __devinit sch5636_probe(struct platform_device *pdev) +static int sch5636_probe(struct platform_device *pdev) { struct sch5636_data *data; int i, err, val, revision[2]; diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 07a0c1a0b84..1c85d39df17 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -884,7 +884,7 @@ static int sht15_invalidate_voltage(struct notifier_block *nb, return NOTIFY_OK; } -static int __devinit sht15_probe(struct platform_device *pdev) +static int sht15_probe(struct platform_device *pdev) { int ret; struct sht15_data *data; @@ -1002,7 +1002,7 @@ err_release_reg: return ret; } -static int __devexit sht15_remove(struct platform_device *pdev) +static int sht15_remove(struct platform_device *pdev) { struct sht15_data *data = platform_get_drvdata(pdev); @@ -1043,7 +1043,7 @@ static struct platform_driver sht15_driver = { .owner = THIS_MODULE, }, .probe = sht15_probe, - .remove = __devexit_p(sht15_remove), + .remove = sht15_remove, .id_table = sht15_device_ids, }; module_platform_driver(sht15_driver); diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c index 5f67546950b..2e9f9570b6f 100644 --- a/drivers/hwmon/sht21.c +++ b/drivers/hwmon/sht21.c @@ -187,7 +187,7 @@ static const struct attribute_group sht21_attr_group = { * device's name. * Returns 0 on success. */ -static int __devinit sht21_probe(struct i2c_client *client, +static int sht21_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct sht21 *sht21; @@ -233,7 +233,7 @@ fail_remove_sysfs: * sht21_remove() - remove device * @client: I2C client device */ -static int __devexit sht21_remove(struct i2c_client *client) +static int sht21_remove(struct i2c_client *client) { struct sht21 *sht21 = i2c_get_clientdata(client); @@ -253,7 +253,7 @@ MODULE_DEVICE_TABLE(i2c, sht21_id); static struct i2c_driver sht21_driver = { .driver.name = "sht21", .probe = sht21_probe, - .remove = __devexit_p(sht21_remove), + .remove = sht21_remove, .id_table = sht21_id, }; diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index 8275f0e14eb..06ce3c911db 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -204,7 +204,7 @@ struct sis5595_data { static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */ static int sis5595_probe(struct platform_device *pdev); -static int __devexit sis5595_remove(struct platform_device *pdev); +static int sis5595_remove(struct platform_device *pdev); static int sis5595_read_value(struct sis5595_data *data, u8 reg); static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value); @@ -217,7 +217,7 @@ static struct platform_driver sis5595_driver = { .name = "sis5595", }, .probe = sis5595_probe, - .remove = __devexit_p(sis5595_remove), + .remove = sis5595_remove, }; /* 4 Voltages */ @@ -583,7 +583,7 @@ static const struct attribute_group sis5595_group_temp1 = { }; /* This is called when the module is loaded */ -static int __devinit sis5595_probe(struct platform_device *pdev) +static int sis5595_probe(struct platform_device *pdev) { int err = 0; int i; @@ -659,7 +659,7 @@ exit_remove_files: return err; } -static int __devexit sis5595_remove(struct platform_device *pdev) +static int sis5595_remove(struct platform_device *pdev) { struct sis5595_data *data = platform_get_drvdata(pdev); @@ -693,7 +693,7 @@ static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value) } /* Called when we have found a new SIS5595. */ -static void __devinit sis5595_init_device(struct sis5595_data *data) +static void sis5595_init_device(struct sis5595_data *data) { u8 config = sis5595_read_value(data, SIS5595_REG_CONFIG); if (!(config & 0x01)) @@ -758,7 +758,7 @@ static DEFINE_PCI_DEVICE_TABLE(sis5595_pci_ids) = { MODULE_DEVICE_TABLE(pci, sis5595_pci_ids); -static int blacklist[] __devinitdata = { +static int blacklist[] = { PCI_DEVICE_ID_SI_540, PCI_DEVICE_ID_SI_550, PCI_DEVICE_ID_SI_630, @@ -774,7 +774,7 @@ static int blacklist[] __devinitdata = { PCI_DEVICE_ID_SI_5598, 0 }; -static int __devinit sis5595_device_add(unsigned short address) +static int sis5595_device_add(unsigned short address) { struct resource res = { .start = address, @@ -815,7 +815,7 @@ exit: return err; } -static int __devinit sis5595_pci_probe(struct pci_dev *dev, +static int sis5595_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { u16 address; diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c index 65b07de11a0..81348fadf3b 100644 --- a/drivers/hwmon/smsc47b397.c +++ b/drivers/hwmon/smsc47b397.c @@ -228,7 +228,7 @@ static const struct attribute_group smsc47b397_group = { .attrs = smsc47b397_attributes, }; -static int __devexit smsc47b397_remove(struct platform_device *pdev) +static int smsc47b397_remove(struct platform_device *pdev) { struct smsc47b397_data *data = platform_get_drvdata(pdev); @@ -246,10 +246,10 @@ static struct platform_driver smsc47b397_driver = { .name = DRVNAME, }, .probe = smsc47b397_probe, - .remove = __devexit_p(smsc47b397_remove), + .remove = smsc47b397_remove, }; -static int __devinit smsc47b397_probe(struct platform_device *pdev) +static int smsc47b397_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct smsc47b397_data *data; diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index b8777e54190..b10c3d36ccb 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -147,7 +147,7 @@ static const struct attribute_group tmp102_attr_group = { #define TMP102_CONFIG (TMP102_CONF_TM | TMP102_CONF_EM | TMP102_CONF_CR1) #define TMP102_CONFIG_RD_ONLY (TMP102_CONF_R0 | TMP102_CONF_R1 | TMP102_CONF_AL) -static int __devinit tmp102_probe(struct i2c_client *client, +static int tmp102_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct tmp102 *tmp102; @@ -216,7 +216,7 @@ fail_restore_config: return status; } -static int __devexit tmp102_remove(struct i2c_client *client) +static int tmp102_remove(struct i2c_client *client) { struct tmp102 *tmp102 = i2c_get_clientdata(client); @@ -283,7 +283,7 @@ static struct i2c_driver tmp102_driver = { .driver.name = DRIVER_NAME, .driver.pm = TMP102_DEV_PM_OPS, .probe = tmp102_probe, - .remove = __devexit_p(tmp102_remove), + .remove = tmp102_remove, .id_table = tmp102_id, }; diff --git a/drivers/hwmon/twl4030-madc-hwmon.c b/drivers/hwmon/twl4030-madc-hwmon.c index 1a174f0a3cd..149d44a7c58 100644 --- a/drivers/hwmon/twl4030-madc-hwmon.c +++ b/drivers/hwmon/twl4030-madc-hwmon.c @@ -96,7 +96,7 @@ static const struct attribute_group twl4030_madc_group = { .attrs = twl4030_madc_attributes, }; -static int __devinit twl4030_madc_hwmon_probe(struct platform_device *pdev) +static int twl4030_madc_hwmon_probe(struct platform_device *pdev) { int ret; struct device *hwmon; @@ -120,7 +120,7 @@ err_sysfs: return ret; } -static int __devexit twl4030_madc_hwmon_remove(struct platform_device *pdev) +static int twl4030_madc_hwmon_remove(struct platform_device *pdev) { hwmon_device_unregister(&pdev->dev); sysfs_remove_group(&pdev->dev.kobj, &twl4030_madc_group); diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c index 44136bb6d04..fb3e69341c1 100644 --- a/drivers/hwmon/ultra45_env.c +++ b/drivers/hwmon/ultra45_env.c @@ -250,7 +250,7 @@ static const struct attribute_group env_group = { .attrs = env_attributes, }; -static int __devinit env_probe(struct platform_device *op) +static int env_probe(struct platform_device *op) { struct env *p = kzalloc(sizeof(*p), GFP_KERNEL); int err = -ENOMEM; @@ -291,7 +291,7 @@ out_free: goto out; } -static int __devexit env_remove(struct platform_device *op) +static int env_remove(struct platform_device *op) { struct env *p = platform_get_drvdata(op); @@ -321,7 +321,7 @@ static struct platform_driver env_driver = { .of_match_table = env_match, }, .probe = env_probe, - .remove = __devexit_p(env_remove), + .remove = env_remove, }; module_platform_driver(env_driver); diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c index 4cddee04f2e..76f157b568e 100644 --- a/drivers/hwmon/via-cputemp.c +++ b/drivers/hwmon/via-cputemp.c @@ -121,7 +121,7 @@ static const struct attribute_group via_cputemp_group = { /* Optional attributes */ static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_cpu_vid, NULL); -static int __devinit via_cputemp_probe(struct platform_device *pdev) +static int via_cputemp_probe(struct platform_device *pdev) { struct via_cputemp_data *data; struct cpuinfo_x86 *c = &cpu_data(pdev->id); @@ -192,7 +192,7 @@ exit_remove: return err; } -static int __devexit via_cputemp_remove(struct platform_device *pdev) +static int via_cputemp_remove(struct platform_device *pdev) { struct via_cputemp_data *data = platform_get_drvdata(pdev); @@ -209,7 +209,7 @@ static struct platform_driver via_cputemp_driver = { .name = DRVNAME, }, .probe = via_cputemp_probe, - .remove = __devexit_p(via_cputemp_remove), + .remove = via_cputemp_remove, }; struct pdev_entry { diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 299399aa30f..e0e14a9f165 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -339,7 +339,7 @@ struct via686a_data { static struct pci_dev *s_bridge; /* pointer to the (only) via686a */ static int via686a_probe(struct platform_device *pdev); -static int __devexit via686a_remove(struct platform_device *pdev); +static int via686a_remove(struct platform_device *pdev); static inline int via686a_read_value(struct via686a_data *data, u8 reg) { @@ -677,12 +677,12 @@ static struct platform_driver via686a_driver = { .name = "via686a", }, .probe = via686a_probe, - .remove = __devexit_p(via686a_remove), + .remove = via686a_remove, }; /* This is called when the module is loaded */ -static int __devinit via686a_probe(struct platform_device *pdev) +static int via686a_probe(struct platform_device *pdev) { struct via686a_data *data; struct resource *res; @@ -728,7 +728,7 @@ exit_remove_files: return err; } -static int __devexit via686a_remove(struct platform_device *pdev) +static int via686a_remove(struct platform_device *pdev) { struct via686a_data *data = platform_get_drvdata(pdev); @@ -745,7 +745,7 @@ static void via686a_update_fan_div(struct via686a_data *data) data->fan_div[1] = reg >> 6; } -static void __devinit via686a_init_device(struct via686a_data *data) +static void via686a_init_device(struct via686a_data *data) { u8 reg; @@ -833,7 +833,7 @@ static DEFINE_PCI_DEVICE_TABLE(via686a_pci_ids) = { }; MODULE_DEVICE_TABLE(pci, via686a_pci_ids); -static int __devinit via686a_device_add(unsigned short address) +static int via686a_device_add(unsigned short address) { struct resource res = { .start = address, @@ -874,7 +874,7 @@ exit: return err; } -static int __devinit via686a_pci_probe(struct pci_dev *dev, +static int via686a_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { u16 address, val; diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c index f2c61153dba..751703059fa 100644 --- a/drivers/hwmon/vt1211.c +++ b/drivers/hwmon/vt1211.c @@ -1086,7 +1086,7 @@ static struct device_attribute vt1211_sysfs_misc[] = { * Device registration and initialization * --------------------------------------------------------------------- */ -static void __devinit vt1211_init_device(struct vt1211_data *data) +static void vt1211_init_device(struct vt1211_data *data) { /* set VRM */ data->vrm = vid_which_vrm(); @@ -1141,7 +1141,7 @@ static void vt1211_remove_sysfs(struct platform_device *pdev) device_remove_file(dev, &vt1211_sysfs_misc[i]); } -static int __devinit vt1211_probe(struct platform_device *pdev) +static int vt1211_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct vt1211_data *data; @@ -1217,7 +1217,7 @@ EXIT_DEV_REMOVE_SILENT: return err; } -static int __devexit vt1211_remove(struct platform_device *pdev) +static int vt1211_remove(struct platform_device *pdev) { struct vt1211_data *data = platform_get_drvdata(pdev); @@ -1233,7 +1233,7 @@ static struct platform_driver vt1211_driver = { .name = DRVNAME, }, .probe = vt1211_probe, - .remove = __devexit_p(vt1211_remove), + .remove = vt1211_remove, }; static int __init vt1211_device_add(unsigned short address) diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index 84e3dc5e3a8..a56355cef18 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -176,7 +176,7 @@ struct vt8231_data { static struct pci_dev *s_bridge; static int vt8231_probe(struct platform_device *pdev); -static int __devexit vt8231_remove(struct platform_device *pdev); +static int vt8231_remove(struct platform_device *pdev); static struct vt8231_data *vt8231_update_device(struct device *dev); static void vt8231_init_device(struct vt8231_data *data); @@ -762,7 +762,7 @@ static struct platform_driver vt8231_driver = { .name = "vt8231", }, .probe = vt8231_probe, - .remove = __devexit_p(vt8231_remove), + .remove = vt8231_remove, }; static DEFINE_PCI_DEVICE_TABLE(vt8231_pci_ids) = { @@ -772,7 +772,7 @@ static DEFINE_PCI_DEVICE_TABLE(vt8231_pci_ids) = { MODULE_DEVICE_TABLE(pci, vt8231_pci_ids); -static int __devinit vt8231_pci_probe(struct pci_dev *dev, +static int vt8231_pci_probe(struct pci_dev *dev, const struct pci_device_id *id); static struct pci_driver vt8231_pci_driver = { @@ -851,7 +851,7 @@ exit_remove_files: return err; } -static int __devexit vt8231_remove(struct platform_device *pdev) +static int vt8231_remove(struct platform_device *pdev) { struct vt8231_data *data = platform_get_drvdata(pdev); int i; @@ -943,7 +943,7 @@ static struct vt8231_data *vt8231_update_device(struct device *dev) return data; } -static int __devinit vt8231_device_add(unsigned short address) +static int vt8231_device_add(unsigned short address) { struct resource res = { .start = address, @@ -984,7 +984,7 @@ exit: return err; } -static int __devinit vt8231_pci_probe(struct pci_dev *dev, +static int vt8231_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { u16 address, val; diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index de3c7e04c3b..55ac41c0556 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1866,7 +1866,7 @@ static void w83627ehf_device_remove_files(struct device *dev) } /* Get the monitoring functions started */ -static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data, +static inline void w83627ehf_init_device(struct w83627ehf_data *data, enum kinds kind) { int i; @@ -1952,7 +1952,7 @@ static void w82627ehf_swap_tempreg(struct w83627ehf_data *data, data->reg_temp_config[r2] = tmp; } -static void __devinit +static void w83627ehf_set_temp_reg_ehf(struct w83627ehf_data *data, int n_temp) { int i; @@ -1965,7 +1965,7 @@ w83627ehf_set_temp_reg_ehf(struct w83627ehf_data *data, int n_temp) } } -static void __devinit +static void w83627ehf_check_fan_inputs(const struct w83627ehf_sio_data *sio_data, struct w83627ehf_data *data) { @@ -2054,7 +2054,7 @@ w83627ehf_check_fan_inputs(const struct w83627ehf_sio_data *sio_data, } } -static int __devinit w83627ehf_probe(struct platform_device *pdev) +static int w83627ehf_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct w83627ehf_sio_data *sio_data = dev->platform_data; @@ -2596,7 +2596,7 @@ exit: return err; } -static int __devexit w83627ehf_remove(struct platform_device *pdev) +static int w83627ehf_remove(struct platform_device *pdev) { struct w83627ehf_data *data = platform_get_drvdata(pdev); @@ -2614,7 +2614,7 @@ static struct platform_driver w83627ehf_driver = { .name = DRVNAME, }, .probe = w83627ehf_probe, - .remove = __devexit_p(w83627ehf_remove), + .remove = w83627ehf_remove, }; /* w83627ehf_find() looks for a '627 in the Super-I/O config space */ diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index af158990870..7f68b8309d1 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -393,7 +393,7 @@ struct w83627hf_data { static int w83627hf_probe(struct platform_device *pdev); -static int __devexit w83627hf_remove(struct platform_device *pdev); +static int w83627hf_remove(struct platform_device *pdev); static int w83627hf_read_value(struct w83627hf_data *data, u16 reg); static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value); @@ -407,7 +407,7 @@ static struct platform_driver w83627hf_driver = { .name = DRVNAME, }, .probe = w83627hf_probe, - .remove = __devexit_p(w83627hf_remove), + .remove = w83627hf_remove, }; static ssize_t @@ -1342,7 +1342,7 @@ static const struct attribute_group w83627hf_group_opt = { .attrs = w83627hf_attributes_opt, }; -static int __devinit w83627hf_probe(struct platform_device *pdev) +static int w83627hf_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct w83627hf_sio_data *sio_data = dev->platform_data; @@ -1508,7 +1508,7 @@ static int __devinit w83627hf_probe(struct platform_device *pdev) return err; } -static int __devexit w83627hf_remove(struct platform_device *pdev) +static int w83627hf_remove(struct platform_device *pdev) { struct w83627hf_data *data = platform_get_drvdata(pdev); @@ -1564,7 +1564,7 @@ static int w83627hf_read_value(struct w83627hf_data *data, u16 reg) return res; } -static int __devinit w83627thf_read_gpio5(struct platform_device *pdev) +static int w83627thf_read_gpio5(struct platform_device *pdev) { struct w83627hf_sio_data *sio_data = pdev->dev.platform_data; int res = 0xff, sel; @@ -1597,7 +1597,7 @@ exit: return res; } -static int __devinit w83687thf_read_vid(struct platform_device *pdev) +static int w83687thf_read_vid(struct platform_device *pdev) { struct w83627hf_sio_data *sio_data = pdev->dev.platform_data; int res = 0xff; @@ -1649,7 +1649,7 @@ static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value) return 0; } -static void __devinit w83627hf_init_device(struct platform_device *pdev) +static void w83627hf_init_device(struct platform_device *pdev) { struct w83627hf_data *data = platform_get_drvdata(pdev); int i; diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 20f11d31da4..93bd2863959 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -1764,7 +1764,7 @@ w83781d_write_value(struct w83781d_data *data, u16 reg, u16 value) return 0; } -static int __devinit +static int w83781d_isa_probe(struct platform_device *pdev) { int err, reg; @@ -1824,7 +1824,7 @@ w83781d_isa_probe(struct platform_device *pdev) return err; } -static int __devexit +static int w83781d_isa_remove(struct platform_device *pdev) { struct w83781d_data *data = platform_get_drvdata(pdev); @@ -1842,7 +1842,7 @@ static struct platform_driver w83781d_isa_driver = { .name = "w83781d", }, .probe = w83781d_isa_probe, - .remove = __devexit_p(w83781d_isa_remove), + .remove = w83781d_isa_remove, }; /* return 1 if a supported chip is found, 0 otherwise */ diff --git a/drivers/hwmon/wm831x-hwmon.c b/drivers/hwmon/wm831x-hwmon.c index d0db1f2738f..df6ceaf8d58 100644 --- a/drivers/hwmon/wm831x-hwmon.c +++ b/drivers/hwmon/wm831x-hwmon.c @@ -157,7 +157,7 @@ static const struct attribute_group wm831x_attr_group = { .attrs = wm831x_attributes, }; -static int __devinit wm831x_hwmon_probe(struct platform_device *pdev) +static int wm831x_hwmon_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_hwmon *hwmon; @@ -189,7 +189,7 @@ err_sysfs: return ret; } -static int __devexit wm831x_hwmon_remove(struct platform_device *pdev) +static int wm831x_hwmon_remove(struct platform_device *pdev) { struct wm831x_hwmon *hwmon = platform_get_drvdata(pdev); @@ -201,7 +201,7 @@ static int __devexit wm831x_hwmon_remove(struct platform_device *pdev) static struct platform_driver wm831x_hwmon_driver = { .probe = wm831x_hwmon_probe, - .remove = __devexit_p(wm831x_hwmon_remove), + .remove = wm831x_hwmon_remove, .driver = { .name = "wm831x-hwmon", .owner = THIS_MODULE, diff --git a/drivers/hwmon/wm8350-hwmon.c b/drivers/hwmon/wm8350-hwmon.c index b955756bdb4..64bf75c9442 100644 --- a/drivers/hwmon/wm8350-hwmon.c +++ b/drivers/hwmon/wm8350-hwmon.c @@ -91,7 +91,7 @@ static const struct attribute_group wm8350_attr_group = { .attrs = wm8350_attributes, }; -static int __devinit wm8350_hwmon_probe(struct platform_device *pdev) +static int wm8350_hwmon_probe(struct platform_device *pdev) { struct wm8350 *wm8350 = platform_get_drvdata(pdev); int ret; @@ -114,7 +114,7 @@ err: return ret; } -static int __devexit wm8350_hwmon_remove(struct platform_device *pdev) +static int wm8350_hwmon_remove(struct platform_device *pdev) { struct wm8350 *wm8350 = platform_get_drvdata(pdev); @@ -126,7 +126,7 @@ static int __devexit wm8350_hwmon_remove(struct platform_device *pdev) static struct platform_driver wm8350_hwmon_driver = { .probe = wm8350_hwmon_probe, - .remove = __devexit_p(wm8350_hwmon_remove), + .remove = wm8350_hwmon_remove, .driver = { .name = "wm8350-hwmon", .owner = THIS_MODULE, diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c index 887d34effb3..292869cc903 100644 --- a/drivers/hwspinlock/omap_hwspinlock.c +++ b/drivers/hwspinlock/omap_hwspinlock.c @@ -78,7 +78,7 @@ static const struct hwspinlock_ops omap_hwspinlock_ops = { .relax = omap_hwspinlock_relax, }; -static int __devinit omap_hwspinlock_probe(struct platform_device *pdev) +static int omap_hwspinlock_probe(struct platform_device *pdev) { struct hwspinlock_pdata *pdata = pdev->dev.platform_data; struct hwspinlock_device *bank; @@ -142,7 +142,7 @@ iounmap_base: return ret; } -static int __devexit omap_hwspinlock_remove(struct platform_device *pdev) +static int omap_hwspinlock_remove(struct platform_device *pdev) { struct hwspinlock_device *bank = platform_get_drvdata(pdev); void __iomem *io_base = bank->lock[0].priv - LOCK_BASE_OFFSET; @@ -163,7 +163,7 @@ static int __devexit omap_hwspinlock_remove(struct platform_device *pdev) static struct platform_driver omap_hwspinlock_driver = { .probe = omap_hwspinlock_probe, - .remove = __devexit_p(omap_hwspinlock_remove), + .remove = omap_hwspinlock_remove, .driver = { .name = "omap_hwspinlock", .owner = THIS_MODULE, diff --git a/drivers/hwspinlock/u8500_hsem.c b/drivers/hwspinlock/u8500_hsem.c index 86980fe0411..401c33bcdb4 100644 --- a/drivers/hwspinlock/u8500_hsem.c +++ b/drivers/hwspinlock/u8500_hsem.c @@ -91,7 +91,7 @@ static const struct hwspinlock_ops u8500_hwspinlock_ops = { .relax = u8500_hsem_relax, }; -static int __devinit u8500_hsem_probe(struct platform_device *pdev) +static int u8500_hsem_probe(struct platform_device *pdev) { struct hwspinlock_pdata *pdata = pdev->dev.platform_data; struct hwspinlock_device *bank; @@ -148,7 +148,7 @@ iounmap_base: return ret; } -static int __devexit u8500_hsem_remove(struct platform_device *pdev) +static int u8500_hsem_remove(struct platform_device *pdev) { struct hwspinlock_device *bank = platform_get_drvdata(pdev); void __iomem *io_base = bank->lock[0].priv - HSEM_REGISTER_OFFSET; @@ -172,7 +172,7 @@ static int __devexit u8500_hsem_remove(struct platform_device *pdev) static struct platform_driver u8500_hsem_driver = { .probe = u8500_hsem_probe, - .remove = __devexit_p(u8500_hsem_remove), + .remove = u8500_hsem_remove, .driver = { .name = "u8500_hsem", .owner = THIS_MODULE, diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index aa59a254be2..c02bf208084 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -39,6 +39,7 @@ #define AT91_TWI_STOP 0x0002 /* Send a Stop Condition */ #define AT91_TWI_MSEN 0x0004 /* Master Transfer Enable */ #define AT91_TWI_SVDIS 0x0020 /* Slave Transfer Disable */ +#define AT91_TWI_QUICK 0x0040 /* SMBus quick command */ #define AT91_TWI_SWRST 0x0080 /* Software Reset */ #define AT91_TWI_MMR 0x0004 /* Master Mode Register */ @@ -212,7 +213,11 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) INIT_COMPLETION(dev->cmd_complete); dev->transfer_status = 0; - if (dev->msg->flags & I2C_M_RD) { + + if (!dev->buf_len) { + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_QUICK); + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); + } else if (dev->msg->flags & I2C_M_RD) { unsigned start_flags = AT91_TWI_START; if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) { diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 286ca191782..0670da79ee5 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -287,12 +287,14 @@ read_init_dma_fail: select_init_dma_fail: dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE); select_init_pio_fail: + dmaengine_terminate_all(i2c->dmach); return -EINVAL; /* Write failpath. */ write_init_dma_fail: dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE); write_init_pio_fail: + dmaengine_terminate_all(i2c->dmach); return -EINVAL; } diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index bffd5501ac2..15da1ac7cf9 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -9,10 +9,6 @@ * kind, whether express or implied. */ -/* - * This driver can be used from the device tree, see - * Documentation/devicetree/bindings/i2c/ocore-i2c.txt - */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index db31eaed6ea..3525c9e62cb 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -43,7 +43,6 @@ #include <linux/slab.h> #include <linux/i2c-omap.h> #include <linux/pm_runtime.h> -#include <linux/pm_qos.h> /* I2C controller revisions */ #define OMAP_I2C_OMAP1_REV_2 0x20 @@ -187,8 +186,9 @@ struct omap_i2c_dev { int reg_shift; /* bit shift for I2C register addresses */ struct completion cmd_complete; struct resource *ioarea; - u32 latency; /* maximum MPU wkup latency */ - struct pm_qos_request pm_qos_request; + u32 latency; /* maximum mpu wkup latency */ + void (*set_mpu_wkup_lat)(struct device *dev, + long latency); u32 speed; /* Speed of bus in kHz */ u32 dtrev; /* extra revision from DT */ u32 flags; @@ -494,7 +494,9 @@ static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ - dev->latency = (1000000 * dev->threshold) / (1000 * dev->speed / 8); + if (dev->set_mpu_wkup_lat != NULL) + dev->latency = (1000000 * dev->threshold) / + (1000 * dev->speed / 8); } /* @@ -522,6 +524,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, dev->buf = msg->buf; dev->buf_len = msg->len; + /* make sure writes to dev->buf_len are ordered */ + barrier(); + omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len); /* Clear the FIFO Buffers */ @@ -579,7 +584,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, */ timeout = wait_for_completion_timeout(&dev->cmd_complete, OMAP_I2C_TIMEOUT); - dev->buf_len = 0; if (timeout == 0) { dev_err(dev->dev, "controller timed out\n"); omap_i2c_init(dev); @@ -629,16 +633,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) if (r < 0) goto out; - /* - * When waiting for completion of a i2c transfer, we need to - * set a wake up latency constraint for the MPU. This is to - * ensure quick enough wakeup from idle, when transfer - * completes. - */ - if (dev->latency) - pm_qos_add_request(&dev->pm_qos_request, - PM_QOS_CPU_DMA_LATENCY, - dev->latency); + if (dev->set_mpu_wkup_lat != NULL) + dev->set_mpu_wkup_lat(dev->dev, dev->latency); for (i = 0; i < num; i++) { r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); @@ -646,8 +642,8 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) break; } - if (dev->latency) - pm_qos_remove_request(&dev->pm_qos_request); + if (dev->set_mpu_wkup_lat != NULL) + dev->set_mpu_wkup_lat(dev->dev, -1); if (r == 0) r = num; @@ -1104,6 +1100,7 @@ omap_i2c_probe(struct platform_device *pdev) } else if (pdata != NULL) { dev->speed = pdata->clkrate; dev->flags = pdata->flags; + dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat; dev->dtrev = pdata->rev; } @@ -1159,8 +1156,9 @@ omap_i2c_probe(struct platform_device *pdev) dev->b_hw = 1; /* Enable hardware fixes */ /* calculate wakeup latency constraint for MPU */ - dev->latency = (1000000 * dev->fifo_size) / - (1000 * dev->speed / 8); + if (dev->set_mpu_wkup_lat != NULL) + dev->latency = (1000000 * dev->fifo_size) / + (1000 * dev->speed / 8); } /* reset ASAP, clearing any IRQs */ diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 3e0335f1fc6..9d902725bac 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -806,6 +806,7 @@ static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c) dev_err(i2c->dev, "invalid gpio[%d]: %d\n", idx, gpio); goto free_gpio; } + i2c->gpios[idx] = gpio; ret = gpio_request(gpio, "i2c-bus"); if (ret) { diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index a7edf987a33..e388590b44a 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -39,6 +39,7 @@ #include <linux/irqflags.h> #include <linux/rwsem.h> #include <linux/pm_runtime.h> +#include <linux/acpi.h> #include <asm/uaccess.h> #include "i2c-core.h" @@ -78,6 +79,10 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) if (of_driver_match_device(dev, drv)) return 1; + /* Then ACPI style match */ + if (acpi_driver_match_device(dev, drv)) + return 1; + driver = to_i2c_driver(drv); /* match on an id table if there is one */ if (driver->id_table) @@ -539,6 +544,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->dev.bus = &i2c_bus_type; client->dev.type = &i2c_client_type; client->dev.of_node = info->of_node; + ACPI_HANDLE_SET(&client->dev, info->acpi_node.handle); /* For 10-bit clients, add an arbitrary offset to avoid collisions */ dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index b0f6b4c8ee1..c49c04d9c2b 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -56,7 +56,6 @@ #include <linux/kernel.h> #include <linux/cpuidle.h> #include <linux/clockchips.h> -#include <linux/hrtimer.h> /* ktime_get_real() */ #include <trace/events/power.h> #include <linux/sched.h> #include <linux/notifier.h> @@ -72,6 +71,7 @@ static struct cpuidle_driver intel_idle_driver = { .name = "intel_idle", .owner = THIS_MODULE, + .en_core_tk_irqen = 1, }; /* intel_idle.max_cstate=0 disables driver */ static int max_cstate = MWAIT_MAX_NUM_CSTATES - 1; @@ -281,8 +281,6 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage); unsigned int cstate; - ktime_t kt_before, kt_after; - s64 usec_delta; int cpu = smp_processor_id(); cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) + 1; @@ -297,8 +295,6 @@ static int intel_idle(struct cpuidle_device *dev, if (!(lapic_timer_reliable_states & (1 << (cstate)))) clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); - kt_before = ktime_get_real(); - stop_critical_timings(); if (!need_resched()) { @@ -310,17 +306,9 @@ static int intel_idle(struct cpuidle_device *dev, start_critical_timings(); - kt_after = ktime_get_real(); - usec_delta = ktime_to_us(ktime_sub(kt_after, kt_before)); - - local_irq_enable(); - if (!(lapic_timer_reliable_states & (1 << (cstate)))) clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); - /* Update cpuidle counters */ - dev->last_residency = (int)usec_delta; - return index; } diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c index c0ec7d42c3b..1abbc170d8b 100644 --- a/drivers/input/input-mt.c +++ b/drivers/input/input-mt.c @@ -26,10 +26,14 @@ static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src) * input_mt_init_slots() - initialize MT input slots * @dev: input device supporting MT events and finger tracking * @num_slots: number of slots used by the device + * @flags: mt tasks to handle in core * * This function allocates all necessary memory for MT slot handling * in the input device, prepares the ABS_MT_SLOT and * ABS_MT_TRACKING_ID events for use and sets up appropriate buffers. + * Depending on the flags set, it also performs pointer emulation and + * frame synchronization. + * * May be called repeatedly. Returns -EINVAL if attempting to * reinitialize with a different number of slots. */ diff --git a/drivers/input/matrix-keymap.c b/drivers/input/matrix-keymap.c index 443ad64b7f2..d88d9be1d1b 100644 --- a/drivers/input/matrix-keymap.c +++ b/drivers/input/matrix-keymap.c @@ -23,6 +23,7 @@ #include <linux/input.h> #include <linux/of.h> #include <linux/export.h> +#include <linux/module.h> #include <linux/input/matrix_keypad.h> static bool matrix_keypad_map_key(struct input_dev *input_dev, @@ -161,3 +162,5 @@ int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data, return 0; } EXPORT_SYMBOL(matrix_keypad_build_keymap); + +MODULE_LICENSE("GPL"); diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 8f02e3d0e71..4c842c320c2 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -12,8 +12,8 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define MOUSEDEV_MINOR_BASE 32 -#define MOUSEDEV_MINORS 32 -#define MOUSEDEV_MIX 31 +#define MOUSEDEV_MINORS 31 +#define MOUSEDEV_MIX 63 #include <linux/sched.h> #include <linux/slab.h> diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index f02028ec3db..78e5d9ab0ba 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -955,7 +955,8 @@ static int ads7846_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(ads7846_pm, ads7846_suspend, ads7846_resume); -static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads7846 *ts) +static int __devinit ads7846_setup_pendown(struct spi_device *spi, + struct ads7846 *ts) { struct ads7846_platform_data *pdata = spi->dev.platform_data; int err; @@ -981,6 +982,9 @@ static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads784 ts->gpio_pendown = pdata->gpio_pendown; + if (pdata->gpio_pendown_debounce) + gpio_set_debounce(pdata->gpio_pendown, + pdata->gpio_pendown_debounce); } else { dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n"); return -EINVAL; diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index d4a4cd445ca..0badfa48b32 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -4108,7 +4108,7 @@ static void swap_pci_ref(struct pci_dev **from, struct pci_dev *to) static int intel_iommu_add_device(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); - struct pci_dev *bridge, *dma_pdev; + struct pci_dev *bridge, *dma_pdev = NULL; struct iommu_group *group; int ret; @@ -4122,7 +4122,7 @@ static int intel_iommu_add_device(struct device *dev) dma_pdev = pci_get_domain_bus_and_slot( pci_domain_nr(pdev->bus), bridge->subordinate->number, 0); - else + if (!dma_pdev) dma_pdev = pci_dev_get(bridge); } else dma_pdev = pci_dev_get(pdev); diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index a649f146d17..c0f7a426626 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -1054,6 +1054,7 @@ static int smmu_debugfs_stats_show(struct seq_file *s, void *v) stats[i], val, offs); } seq_printf(s, "\n"); + dput(dent); return 0; } diff --git a/drivers/leds/leds-adp5520.c b/drivers/leds/leds-adp5520.c index aa56a867693..dcd9128a51a 100644 --- a/drivers/leds/leds-adp5520.c +++ b/drivers/leds/leds-adp5520.c @@ -85,7 +85,7 @@ static int adp5520_led_setup(struct adp5520_led *led) return ret; } -static int __devinit adp5520_led_prepare(struct platform_device *pdev) +static int adp5520_led_prepare(struct platform_device *pdev) { struct adp5520_leds_platform_data *pdata = pdev->dev.platform_data; struct device *dev = pdev->dev.parent; @@ -101,7 +101,7 @@ static int __devinit adp5520_led_prepare(struct platform_device *pdev) return ret; } -static int __devinit adp5520_led_probe(struct platform_device *pdev) +static int adp5520_led_probe(struct platform_device *pdev) { struct adp5520_leds_platform_data *pdata = pdev->dev.platform_data; struct adp5520_led *led, *led_dat; @@ -183,7 +183,7 @@ err: return ret; } -static int __devexit adp5520_led_remove(struct platform_device *pdev) +static int adp5520_led_remove(struct platform_device *pdev) { struct adp5520_leds_platform_data *pdata = pdev->dev.platform_data; struct adp5520_led *led; @@ -208,7 +208,7 @@ static struct platform_driver adp5520_led_driver = { .owner = THIS_MODULE, }, .probe = adp5520_led_probe, - .remove = __devexit_p(adp5520_led_remove), + .remove = adp5520_led_remove, }; module_platform_driver(adp5520_led_driver); diff --git a/drivers/leds/leds-asic3.c b/drivers/leds/leds-asic3.c index 5de74ff90dc..b474745e001 100644 --- a/drivers/leds/leds-asic3.c +++ b/drivers/leds/leds-asic3.c @@ -92,7 +92,7 @@ static int blink_set(struct led_classdev *cdev, return 0; } -static int __devinit asic3_led_probe(struct platform_device *pdev) +static int asic3_led_probe(struct platform_device *pdev) { struct asic3_led *led = pdev->dev.platform_data; int ret; @@ -125,7 +125,7 @@ out: return ret; } -static int __devexit asic3_led_remove(struct platform_device *pdev) +static int asic3_led_remove(struct platform_device *pdev) { struct asic3_led *led = pdev->dev.platform_data; @@ -167,7 +167,7 @@ static const struct dev_pm_ops asic3_led_pm_ops = { static struct platform_driver asic3_led_driver = { .probe = asic3_led_probe, - .remove = __devexit_p(asic3_led_remove), + .remove = asic3_led_remove, .driver = { .name = "leds-asic3", .owner = THIS_MODULE, diff --git a/drivers/leds/leds-atmel-pwm.c b/drivers/leds/leds-atmel-pwm.c index 45430632faa..386773532d9 100644 --- a/drivers/leds/leds-atmel-pwm.c +++ b/drivers/leds/leds-atmel-pwm.c @@ -35,7 +35,7 @@ static void pwmled_brightness(struct led_classdev *cdev, enum led_brightness b) * NOTE: we reuse the platform_data structure of GPIO leds, * but repurpose its "gpio" number as a PWM channel number. */ -static int __devinit pwmled_probe(struct platform_device *pdev) +static int pwmled_probe(struct platform_device *pdev) { const struct gpio_led_platform_data *pdata; struct pwmled *leds; diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c index 89ca6a2a19d..9abe8de40ed 100644 --- a/drivers/leds/leds-bd2802.c +++ b/drivers/leds/leds-bd2802.c @@ -670,7 +670,7 @@ static void bd2802_unregister_led_classdev(struct bd2802_led *led) led_classdev_unregister(&led->cdev_led1r); } -static int __devinit bd2802_probe(struct i2c_client *client, +static int bd2802_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct bd2802_led *led; diff --git a/drivers/leds/leds-blinkm.c b/drivers/leds/leds-blinkm.c index f7c3d7f1ec5..a502678cc7f 100644 --- a/drivers/leds/leds-blinkm.c +++ b/drivers/leds/leds-blinkm.c @@ -632,7 +632,7 @@ static int blinkm_detect(struct i2c_client *client, struct i2c_board_info *info) return 0; } -static int __devinit blinkm_probe(struct i2c_client *client, +static int blinkm_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct blinkm_data *data; @@ -743,7 +743,7 @@ exit: return err; } -static int __devexit blinkm_remove(struct i2c_client *client) +static int blinkm_remove(struct i2c_client *client) { struct blinkm_data *data = i2c_get_clientdata(client); int ret = 0; @@ -801,7 +801,7 @@ static struct i2c_driver blinkm_driver = { .name = "blinkm", }, .probe = blinkm_probe, - .remove = __devexit_p(blinkm_remove), + .remove = blinkm_remove, .id_table = blinkm_id, .detect = blinkm_detect, .address_list = normal_i2c, diff --git a/drivers/leds/leds-clevo-mail.c b/drivers/leds/leds-clevo-mail.c index e024b0b1c3b..b02547052e1 100644 --- a/drivers/leds/leds-clevo-mail.c +++ b/drivers/leds/leds-clevo-mail.c @@ -153,7 +153,7 @@ static struct led_classdev clevo_mail_led = { .flags = LED_CORE_SUSPENDRESUME, }; -static int __devinit clevo_mail_led_probe(struct platform_device *pdev) +static int clevo_mail_led_probe(struct platform_device *pdev) { return led_classdev_register(&pdev->dev, &clevo_mail_led); } diff --git a/drivers/leds/leds-cobalt-qube.c b/drivers/leds/leds-cobalt-qube.c index 6a8725cc7b4..ffa99303b62 100644 --- a/drivers/leds/leds-cobalt-qube.c +++ b/drivers/leds/leds-cobalt-qube.c @@ -34,7 +34,7 @@ static struct led_classdev qube_front_led = { .default_trigger = "default-on", }; -static int __devinit cobalt_qube_led_probe(struct platform_device *pdev) +static int cobalt_qube_led_probe(struct platform_device *pdev) { struct resource *res; int retval; @@ -63,7 +63,7 @@ err_iounmap: return retval; } -static int __devexit cobalt_qube_led_remove(struct platform_device *pdev) +static int cobalt_qube_led_remove(struct platform_device *pdev) { led_classdev_unregister(&qube_front_led); @@ -77,7 +77,7 @@ static int __devexit cobalt_qube_led_remove(struct platform_device *pdev) static struct platform_driver cobalt_qube_led_driver = { .probe = cobalt_qube_led_probe, - .remove = __devexit_p(cobalt_qube_led_remove), + .remove = cobalt_qube_led_remove, .driver = { .name = "cobalt-qube-leds", .owner = THIS_MODULE, diff --git a/drivers/leds/leds-cobalt-raq.c b/drivers/leds/leds-cobalt-raq.c index aac1c073fe7..d52e47de396 100644 --- a/drivers/leds/leds-cobalt-raq.c +++ b/drivers/leds/leds-cobalt-raq.c @@ -76,7 +76,7 @@ static struct led_classdev raq_power_off_led = { .default_trigger = "power-off", }; -static int __devinit cobalt_raq_led_probe(struct platform_device *pdev) +static int cobalt_raq_led_probe(struct platform_device *pdev) { struct resource *res; int retval; @@ -109,7 +109,7 @@ err_iounmap: return retval; } -static int __devexit cobalt_raq_led_remove(struct platform_device *pdev) +static int cobalt_raq_led_remove(struct platform_device *pdev) { led_classdev_unregister(&raq_power_off_led); led_classdev_unregister(&raq_web_led); @@ -124,7 +124,7 @@ static int __devexit cobalt_raq_led_remove(struct platform_device *pdev) static struct platform_driver cobalt_raq_led_driver = { .probe = cobalt_raq_led_probe, - .remove = __devexit_p(cobalt_raq_led_remove), + .remove = cobalt_raq_led_remove, .driver = { .name = "cobalt-raq-leds", .owner = THIS_MODULE, diff --git a/drivers/leds/leds-da903x.c b/drivers/leds/leds-da903x.c index cc77c9d9261..6f31b776765 100644 --- a/drivers/leds/leds-da903x.c +++ b/drivers/leds/leds-da903x.c @@ -91,7 +91,7 @@ static void da903x_led_set(struct led_classdev *led_cdev, schedule_work(&led->work); } -static int __devinit da903x_led_probe(struct platform_device *pdev) +static int da903x_led_probe(struct platform_device *pdev) { struct led_info *pdata = pdev->dev.platform_data; struct da903x_led *led; @@ -136,7 +136,7 @@ static int __devinit da903x_led_probe(struct platform_device *pdev) return 0; } -static int __devexit da903x_led_remove(struct platform_device *pdev) +static int da903x_led_remove(struct platform_device *pdev) { struct da903x_led *led = platform_get_drvdata(pdev); @@ -150,7 +150,7 @@ static struct platform_driver da903x_led_driver = { .owner = THIS_MODULE, }, .probe = da903x_led_probe, - .remove = __devexit_p(da903x_led_remove), + .remove = da903x_led_remove, }; module_platform_driver(da903x_led_driver); diff --git a/drivers/leds/leds-da9052.c b/drivers/leds/leds-da9052.c index 58a5244c437..efec43344e9 100644 --- a/drivers/leds/leds-da9052.c +++ b/drivers/leds/leds-da9052.c @@ -102,7 +102,7 @@ static int da9052_configure_leds(struct da9052 *da9052) return error; } -static int __devinit da9052_led_probe(struct platform_device *pdev) +static int da9052_led_probe(struct platform_device *pdev) { struct da9052_pdata *pdata; struct da9052 *da9052; @@ -176,7 +176,7 @@ err: return error; } -static int __devexit da9052_led_remove(struct platform_device *pdev) +static int da9052_led_remove(struct platform_device *pdev) { struct da9052_led *led = platform_get_drvdata(pdev); struct da9052_pdata *pdata; @@ -204,7 +204,7 @@ static struct platform_driver da9052_led_driver = { .owner = THIS_MODULE, }, .probe = da9052_led_probe, - .remove = __devexit_p(da9052_led_remove), + .remove = da9052_led_remove, }; module_platform_driver(da9052_led_driver); diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index 087d1e66f4f..291c20797ca 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -91,7 +91,7 @@ static int gpio_blink_set(struct led_classdev *led_cdev, delay_on, delay_off); } -static int __devinit create_gpio_led(const struct gpio_led *template, +static int create_gpio_led(const struct gpio_led *template, struct gpio_led_data *led_dat, struct device *parent, int (*blink_set)(unsigned, int, unsigned long *, unsigned long *)) { @@ -167,7 +167,7 @@ static inline int sizeof_gpio_leds_priv(int num_leds) /* Code to create from OpenFirmware platform devices */ #ifdef CONFIG_OF_GPIO -static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_device *pdev) +static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node, *child; struct gpio_leds_priv *priv; @@ -224,14 +224,14 @@ static const struct of_device_id of_gpio_leds_match[] = { {}, }; #else /* CONFIG_OF_GPIO */ -static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_device *pdev) +static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev) { return NULL; } #endif /* CONFIG_OF_GPIO */ -static int __devinit gpio_led_probe(struct platform_device *pdev) +static int gpio_led_probe(struct platform_device *pdev) { struct gpio_led_platform_data *pdata = pdev->dev.platform_data; struct gpio_leds_priv *priv; @@ -273,7 +273,7 @@ static int __devinit gpio_led_probe(struct platform_device *pdev) return 0; } -static int __devexit gpio_led_remove(struct platform_device *pdev) +static int gpio_led_remove(struct platform_device *pdev) { struct gpio_leds_priv *priv = platform_get_drvdata(pdev); int i; @@ -288,7 +288,7 @@ static int __devexit gpio_led_remove(struct platform_device *pdev) static struct platform_driver gpio_led_driver = { .probe = gpio_led_probe, - .remove = __devexit_p(gpio_led_remove), + .remove = gpio_led_remove, .driver = { .name = "leds-gpio", .owner = THIS_MODULE, diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c index b26306f6724..21414548383 100644 --- a/drivers/leds/leds-lm3530.c +++ b/drivers/leds/leds-lm3530.c @@ -377,7 +377,7 @@ static ssize_t lm3530_mode_set(struct device *dev, struct device_attribute } static DEVICE_ATTR(mode, 0644, lm3530_mode_get, lm3530_mode_set); -static int __devinit lm3530_probe(struct i2c_client *client, +static int lm3530_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct lm3530_platform_data *pdata = client->dev.platform_data; @@ -452,7 +452,7 @@ err_create_file: return err; } -static int __devexit lm3530_remove(struct i2c_client *client) +static int lm3530_remove(struct i2c_client *client) { struct lm3530_data *drvdata = i2c_get_clientdata(client); @@ -472,7 +472,7 @@ MODULE_DEVICE_TABLE(i2c, lm3530_id); static struct i2c_driver lm3530_i2c_driver = { .probe = lm3530_probe, - .remove = __devexit_p(lm3530_remove), + .remove = lm3530_remove, .id_table = lm3530_id, .driver = { .name = LM3530_NAME, diff --git a/drivers/leds/leds-lm3533.c b/drivers/leds/leds-lm3533.c index f6837b99908..bbf24d038a7 100644 --- a/drivers/leds/leds-lm3533.c +++ b/drivers/leds/leds-lm3533.c @@ -646,7 +646,7 @@ static struct attribute_group lm3533_led_attribute_group = { .attrs = lm3533_led_attributes }; -static int __devinit lm3533_led_setup(struct lm3533_led *led, +static int lm3533_led_setup(struct lm3533_led *led, struct lm3533_led_platform_data *pdata) { int ret; @@ -658,7 +658,7 @@ static int __devinit lm3533_led_setup(struct lm3533_led *led, return lm3533_ctrlbank_set_pwm(&led->cb, pdata->pwm); } -static int __devinit lm3533_led_probe(struct platform_device *pdev) +static int lm3533_led_probe(struct platform_device *pdev) { struct lm3533 *lm3533; struct lm3533_led_platform_data *pdata; @@ -742,7 +742,7 @@ err_unregister: return ret; } -static int __devexit lm3533_led_remove(struct platform_device *pdev) +static int lm3533_led_remove(struct platform_device *pdev) { struct lm3533_led *led = platform_get_drvdata(pdev); @@ -774,7 +774,7 @@ static struct platform_driver lm3533_led_driver = { .owner = THIS_MODULE, }, .probe = lm3533_led_probe, - .remove = __devexit_p(lm3533_led_remove), + .remove = lm3533_led_remove, .shutdown = lm3533_led_shutdown, }; module_platform_driver(lm3533_led_driver); diff --git a/drivers/leds/leds-lm355x.c b/drivers/leds/leds-lm355x.c index 065ec015d67..b13ce037191 100644 --- a/drivers/leds/leds-lm355x.c +++ b/drivers/leds/leds-lm355x.c @@ -168,7 +168,7 @@ static char lm355x_name[][I2C_NAME_SIZE] = { }; /* chip initialize */ -static int __devinit lm355x_chip_init(struct lm355x_chip_data *chip) +static int lm355x_chip_init(struct lm355x_chip_data *chip) { int ret; unsigned int reg_val; @@ -420,7 +420,7 @@ static const struct regmap_config lm355x_regmap = { }; /* module initialize */ -static int __devinit lm355x_probe(struct i2c_client *client, +static int lm355x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct lm355x_platform_data *pdata = client->dev.platform_data; @@ -526,7 +526,7 @@ err_out: return err; } -static int __devexit lm355x_remove(struct i2c_client *client) +static int lm355x_remove(struct i2c_client *client) { struct lm355x_chip_data *chip = i2c_get_clientdata(client); struct lm355x_reg_data *preg = chip->regs; @@ -560,7 +560,7 @@ static struct i2c_driver lm355x_i2c_driver = { .pm = NULL, }, .probe = lm355x_probe, - .remove = __devexit_p(lm355x_remove), + .remove = lm355x_remove, .id_table = lm355x_id, }; diff --git a/drivers/leds/leds-lm3642.c b/drivers/leds/leds-lm3642.c index 3285006e988..215a7c1e56c 100644 --- a/drivers/leds/leds-lm3642.c +++ b/drivers/leds/leds-lm3642.c @@ -93,7 +93,7 @@ struct lm3642_chip_data { }; /* chip initialize */ -static int __devinit lm3642_chip_init(struct lm3642_chip_data *chip) +static int lm3642_chip_init(struct lm3642_chip_data *chip) { int ret; struct lm3642_platform_data *pdata = chip->pdata; @@ -313,7 +313,7 @@ static const struct regmap_config lm3642_regmap = { .max_register = REG_MAX, }; -static int __devinit lm3642_probe(struct i2c_client *client, +static int lm3642_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct lm3642_platform_data *pdata = client->dev.platform_data; @@ -420,7 +420,7 @@ err_out: return err; } -static int __devexit lm3642_remove(struct i2c_client *client) +static int lm3642_remove(struct i2c_client *client) { struct lm3642_chip_data *chip = i2c_get_clientdata(client); @@ -450,7 +450,7 @@ static struct i2c_driver lm3642_i2c_driver = { .pm = NULL, }, .probe = lm3642_probe, - .remove = __devexit_p(lm3642_remove), + .remove = lm3642_remove, .id_table = lm3642_id, }; diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c index c298f7d9f53..b081f67e1de 100644 --- a/drivers/leds/leds-lp3944.c +++ b/drivers/leds/leds-lp3944.c @@ -374,7 +374,7 @@ exit: return err; } -static int __devinit lp3944_probe(struct i2c_client *client, +static int lp3944_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct lp3944_platform_data *lp3944_pdata = client->dev.platform_data; @@ -411,7 +411,7 @@ static int __devinit lp3944_probe(struct i2c_client *client, return 0; } -static int __devexit lp3944_remove(struct i2c_client *client) +static int lp3944_remove(struct i2c_client *client) { struct lp3944_platform_data *pdata = client->dev.platform_data; struct lp3944_data *data = i2c_get_clientdata(client); @@ -446,7 +446,7 @@ static struct i2c_driver lp3944_driver = { .name = "lp3944", }, .probe = lp3944_probe, - .remove = __devexit_p(lp3944_remove), + .remove = lp3944_remove, .id_table = lp3944_id, }; diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index 2064aefedc0..966f158a07d 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -687,7 +687,7 @@ static void lp5521_unregister_sysfs(struct i2c_client *client) &lp5521_led_attribute_group); } -static int __devinit lp5521_init_led(struct lp5521_led *led, +static int lp5521_init_led(struct lp5521_led *led, struct i2c_client *client, int chan, struct lp5521_platform_data *pdata) { @@ -736,7 +736,7 @@ static int __devinit lp5521_init_led(struct lp5521_led *led, return 0; } -static int __devinit lp5521_probe(struct i2c_client *client, +static int lp5521_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct lp5521_chip *chip; @@ -855,7 +855,7 @@ fail1: return ret; } -static int __devexit lp5521_remove(struct i2c_client *client) +static int lp5521_remove(struct i2c_client *client) { struct lp5521_chip *chip = i2c_get_clientdata(client); int i; @@ -886,7 +886,7 @@ static struct i2c_driver lp5521_driver = { .name = "lp5521", }, .probe = lp5521_probe, - .remove = __devexit_p(lp5521_remove), + .remove = lp5521_remove, .id_table = lp5521_id, }; diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index 97994ffdc01..7e304b7ff77 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -833,7 +833,7 @@ static int __init lp5523_init_engine(struct lp5523_engine *engine, int id) return 0; } -static int __devinit lp5523_init_led(struct lp5523_led *led, struct device *dev, +static int lp5523_init_led(struct lp5523_led *led, struct device *dev, int chan, struct lp5523_platform_data *pdata, const char *chip_name) { @@ -882,7 +882,7 @@ static int __devinit lp5523_init_led(struct lp5523_led *led, struct device *dev, return 0; } -static int __devinit lp5523_probe(struct i2c_client *client, +static int lp5523_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct lp5523_chip *chip; diff --git a/drivers/leds/leds-lp8788.c b/drivers/leds/leds-lp8788.c index 64009a17665..4353942c5fd 100644 --- a/drivers/leds/leds-lp8788.c +++ b/drivers/leds/leds-lp8788.c @@ -125,7 +125,7 @@ static void lp8788_brightness_set(struct led_classdev *led_cdev, schedule_work(&led->work); } -static __devinit int lp8788_led_probe(struct platform_device *pdev) +static int lp8788_led_probe(struct platform_device *pdev) { struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); struct lp8788_led_platform_data *led_pdata; @@ -167,7 +167,7 @@ static __devinit int lp8788_led_probe(struct platform_device *pdev) return 0; } -static int __devexit lp8788_led_remove(struct platform_device *pdev) +static int lp8788_led_remove(struct platform_device *pdev) { struct lp8788_led *led = platform_get_drvdata(pdev); @@ -179,7 +179,7 @@ static int __devexit lp8788_led_remove(struct platform_device *pdev) static struct platform_driver lp8788_led_driver = { .probe = lp8788_led_probe, - .remove = __devexit_p(lp8788_led_remove), + .remove = lp8788_led_remove, .driver = { .name = LP8788_DEV_KEYLED, .owner = THIS_MODULE, diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c index 09a732217f6..34b3ba4376f 100644 --- a/drivers/leds/leds-lt3593.c +++ b/drivers/leds/leds-lt3593.c @@ -82,7 +82,7 @@ static void lt3593_led_set(struct led_classdev *led_cdev, schedule_work(&led_dat->work); } -static int __devinit create_lt3593_led(const struct gpio_led *template, +static int create_lt3593_led(const struct gpio_led *template, struct lt3593_led_data *led_dat, struct device *parent) { int ret, state; @@ -140,7 +140,7 @@ static void delete_lt3593_led(struct lt3593_led_data *led) gpio_free(led->gpio); } -static int __devinit lt3593_led_probe(struct platform_device *pdev) +static int lt3593_led_probe(struct platform_device *pdev) { struct gpio_led_platform_data *pdata = pdev->dev.platform_data; struct lt3593_led_data *leds_data; @@ -173,7 +173,7 @@ err: return ret; } -static int __devexit lt3593_led_remove(struct platform_device *pdev) +static int lt3593_led_remove(struct platform_device *pdev) { int i; struct gpio_led_platform_data *pdata = pdev->dev.platform_data; @@ -189,7 +189,7 @@ static int __devexit lt3593_led_remove(struct platform_device *pdev) static struct platform_driver lt3593_led_driver = { .probe = lt3593_led_probe, - .remove = __devexit_p(lt3593_led_remove), + .remove = lt3593_led_remove, .driver = { .name = "leds-lt3593", .owner = THIS_MODULE, diff --git a/drivers/leds/leds-max8997.c b/drivers/leds/leds-max8997.c index 569e36de37d..f449a8bdddc 100644 --- a/drivers/leds/leds-max8997.c +++ b/drivers/leds/leds-max8997.c @@ -229,7 +229,7 @@ static ssize_t max8997_led_store_mode(struct device *dev, static DEVICE_ATTR(mode, 0644, max8997_led_show_mode, max8997_led_store_mode); -static int __devinit max8997_led_probe(struct platform_device *pdev) +static int max8997_led_probe(struct platform_device *pdev) { struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev); @@ -292,7 +292,7 @@ static int __devinit max8997_led_probe(struct platform_device *pdev) return 0; } -static int __devexit max8997_led_remove(struct platform_device *pdev) +static int max8997_led_remove(struct platform_device *pdev) { struct max8997_led *led = platform_get_drvdata(pdev); @@ -308,7 +308,7 @@ static struct platform_driver max8997_led_driver = { .owner = THIS_MODULE, }, .probe = max8997_led_probe, - .remove = __devexit_p(max8997_led_remove), + .remove = max8997_led_remove, }; module_platform_driver(max8997_led_driver); diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c index 2a5d4340067..e942adaa750 100644 --- a/drivers/leds/leds-mc13783.c +++ b/drivers/leds/leds-mc13783.c @@ -128,7 +128,7 @@ static void mc13783_led_set(struct led_classdev *led_cdev, schedule_work(&led->work); } -static int __devinit mc13783_led_setup(struct mc13783_led *led, int max_current) +static int mc13783_led_setup(struct mc13783_led *led, int max_current) { int shift = 0; int mask = 0; @@ -181,7 +181,7 @@ static int __devinit mc13783_led_setup(struct mc13783_led *led, int max_current) return ret; } -static int __devinit mc13783_leds_prepare(struct platform_device *pdev) +static int mc13783_leds_prepare(struct platform_device *pdev) { struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); struct mc13xxx *dev = dev_get_drvdata(pdev->dev.parent); @@ -262,7 +262,7 @@ out: return ret; } -static int __devinit mc13783_led_probe(struct platform_device *pdev) +static int mc13783_led_probe(struct platform_device *pdev) { struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); struct mc13xxx_led_platform_data *led_cur; @@ -348,7 +348,7 @@ err_register: return ret; } -static int __devexit mc13783_led_remove(struct platform_device *pdev) +static int mc13783_led_remove(struct platform_device *pdev) { struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); struct mc13783_led *led = platform_get_drvdata(pdev); @@ -381,7 +381,7 @@ static struct platform_driver mc13783_led_driver = { .owner = THIS_MODULE, }, .probe = mc13783_led_probe, - .remove = __devexit_p(mc13783_led_remove), + .remove = mc13783_led_remove, }; module_platform_driver(mc13783_led_driver); diff --git a/drivers/leds/leds-netxbig.c b/drivers/leds/leds-netxbig.c index 461bbf9b33f..58a800b17dc 100644 --- a/drivers/leds/leds-netxbig.c +++ b/drivers/leds/leds-netxbig.c @@ -71,7 +71,7 @@ static void gpio_ext_set_value(struct netxbig_gpio_ext *gpio_ext, spin_unlock_irqrestore(&gpio_ext_lock, flags); } -static int __devinit gpio_ext_init(struct netxbig_gpio_ext *gpio_ext) +static int gpio_ext_init(struct netxbig_gpio_ext *gpio_ext) { int err; int i; @@ -301,7 +301,7 @@ static void delete_netxbig_led(struct netxbig_led_data *led_dat) led_classdev_unregister(&led_dat->cdev); } -static int __devinit +static int create_netxbig_led(struct platform_device *pdev, struct netxbig_led_data *led_dat, const struct netxbig_led *template) @@ -352,7 +352,7 @@ create_netxbig_led(struct platform_device *pdev, return ret; } -static int __devinit netxbig_led_probe(struct platform_device *pdev) +static int netxbig_led_probe(struct platform_device *pdev) { struct netxbig_led_platform_data *pdata = pdev->dev.platform_data; struct netxbig_led_data *leds_data; @@ -389,7 +389,7 @@ err_free_leds: return ret; } -static int __devexit netxbig_led_remove(struct platform_device *pdev) +static int netxbig_led_remove(struct platform_device *pdev) { struct netxbig_led_platform_data *pdata = pdev->dev.platform_data; struct netxbig_led_data *leds_data; @@ -407,7 +407,7 @@ static int __devexit netxbig_led_remove(struct platform_device *pdev) static struct platform_driver netxbig_led_driver = { .probe = netxbig_led_probe, - .remove = __devexit_p(netxbig_led_remove), + .remove = netxbig_led_remove, .driver = { .name = "leds-netxbig", .owner = THIS_MODULE, diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c index d176ec83f5d..6315e88d04f 100644 --- a/drivers/leds/leds-ns2.c +++ b/drivers/leds/leds-ns2.c @@ -184,7 +184,7 @@ static ssize_t ns2_led_sata_show(struct device *dev, static DEVICE_ATTR(sata, 0644, ns2_led_sata_show, ns2_led_sata_store); -static int __devinit +static int create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat, const struct ns2_led *template) { @@ -263,7 +263,7 @@ static void delete_ns2_led(struct ns2_led_data *led_dat) gpio_free(led_dat->slow); } -static int __devinit ns2_led_probe(struct platform_device *pdev) +static int ns2_led_probe(struct platform_device *pdev) { struct ns2_led_platform_data *pdata = pdev->dev.platform_data; struct ns2_led_data *leds_data; @@ -292,7 +292,7 @@ static int __devinit ns2_led_probe(struct platform_device *pdev) return 0; } -static int __devexit ns2_led_remove(struct platform_device *pdev) +static int ns2_led_remove(struct platform_device *pdev) { int i; struct ns2_led_platform_data *pdata = pdev->dev.platform_data; @@ -310,7 +310,7 @@ static int __devexit ns2_led_remove(struct platform_device *pdev) static struct platform_driver ns2_led_driver = { .probe = ns2_led_probe, - .remove = __devexit_p(ns2_led_remove), + .remove = ns2_led_remove, .driver = { .name = "leds-ns2", .owner = THIS_MODULE, diff --git a/drivers/leds/leds-ot200.c b/drivers/leds/leds-ot200.c index c4646825a62..ee14662ed5c 100644 --- a/drivers/leds/leds-ot200.c +++ b/drivers/leds/leds-ot200.c @@ -115,7 +115,7 @@ static void ot200_led_brightness_set(struct led_classdev *led_cdev, spin_unlock_irqrestore(&value_lock, flags); } -static int __devinit ot200_led_probe(struct platform_device *pdev) +static int ot200_led_probe(struct platform_device *pdev) { int i; int ret; @@ -144,7 +144,7 @@ err: return ret; } -static int __devexit ot200_led_remove(struct platform_device *pdev) +static int ot200_led_remove(struct platform_device *pdev) { int i; @@ -156,7 +156,7 @@ static int __devexit ot200_led_remove(struct platform_device *pdev) static struct platform_driver ot200_led_driver = { .probe = ot200_led_probe, - .remove = __devexit_p(ot200_led_remove), + .remove = ot200_led_remove, .driver = { .name = "leds-ot200", .owner = THIS_MODULE, diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c index aef3cf0432f..706791af8fc 100644 --- a/drivers/leds/leds-pca955x.c +++ b/drivers/leds/leds-pca955x.c @@ -255,7 +255,7 @@ static void pca955x_led_set(struct led_classdev *led_cdev, enum led_brightness v schedule_work(&pca955x->work); } -static int __devinit pca955x_probe(struct i2c_client *client, +static int pca955x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct pca955x *pca955x; @@ -363,7 +363,7 @@ exit: return err; } -static int __devexit pca955x_remove(struct i2c_client *client) +static int pca955x_remove(struct i2c_client *client) { struct pca955x *pca955x = i2c_get_clientdata(client); int i; @@ -382,7 +382,7 @@ static struct i2c_driver pca955x_driver = { .owner = THIS_MODULE, }, .probe = pca955x_probe, - .remove = __devexit_p(pca955x_remove), + .remove = pca955x_remove, .id_table = pca955x_id, }; diff --git a/drivers/leds/leds-pca9633.c b/drivers/leds/leds-pca9633.c index 2f2f9c43535..9aae5679ffb 100644 --- a/drivers/leds/leds-pca9633.c +++ b/drivers/leds/leds-pca9633.c @@ -93,7 +93,7 @@ static void pca9633_led_set(struct led_classdev *led_cdev, schedule_work(&pca9633->work); } -static int __devinit pca9633_probe(struct i2c_client *client, +static int pca9633_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct pca9633_led *pca9633; @@ -164,7 +164,7 @@ exit: return err; } -static int __devexit pca9633_remove(struct i2c_client *client) +static int pca9633_remove(struct i2c_client *client) { struct pca9633_led *pca9633 = i2c_get_clientdata(client); int i; @@ -183,7 +183,7 @@ static struct i2c_driver pca9633_driver = { .owner = THIS_MODULE, }, .probe = pca9633_probe, - .remove = __devexit_p(pca9633_remove), + .remove = pca9633_remove, .id_table = pca9633_id, }; diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c index f2e44c71943..e51ff7a3cd8 100644 --- a/drivers/leds/leds-pwm.c +++ b/drivers/leds/leds-pwm.c @@ -107,7 +107,7 @@ err: return ret; } -static int __devexit led_pwm_remove(struct platform_device *pdev) +static int led_pwm_remove(struct platform_device *pdev) { int i; struct led_pwm_platform_data *pdata = pdev->dev.platform_data; @@ -125,7 +125,7 @@ static int __devexit led_pwm_remove(struct platform_device *pdev) static struct platform_driver led_pwm_driver = { .probe = led_pwm_probe, - .remove = __devexit_p(led_pwm_remove), + .remove = led_pwm_remove, .driver = { .name = "leds_pwm", .owner = THIS_MODULE, diff --git a/drivers/leds/leds-rb532.c b/drivers/leds/leds-rb532.c index a7815b6cd85..9ebdd5011a7 100644 --- a/drivers/leds/leds-rb532.c +++ b/drivers/leds/leds-rb532.c @@ -37,12 +37,12 @@ static struct led_classdev rb532_uled = { .default_trigger = "nand-disk", }; -static int __devinit rb532_led_probe(struct platform_device *pdev) +static int rb532_led_probe(struct platform_device *pdev) { return led_classdev_register(&pdev->dev, &rb532_uled); } -static int __devexit rb532_led_remove(struct platform_device *pdev) +static int rb532_led_remove(struct platform_device *pdev) { led_classdev_unregister(&rb532_uled); return 0; @@ -50,7 +50,7 @@ static int __devexit rb532_led_remove(struct platform_device *pdev) static struct platform_driver rb532_led_driver = { .probe = rb532_led_probe, - .remove = __devexit_p(rb532_led_remove), + .remove = rb532_led_remove, .driver = { .name = "rb532-led", .owner = THIS_MODULE, diff --git a/drivers/leds/leds-regulator.c b/drivers/leds/leds-regulator.c index 25d382d60fa..4253a9b03db 100644 --- a/drivers/leds/leds-regulator.c +++ b/drivers/leds/leds-regulator.c @@ -140,7 +140,7 @@ static void regulator_led_brightness_set(struct led_classdev *led_cdev, schedule_work(&led->work); } -static int __devinit regulator_led_probe(struct platform_device *pdev) +static int regulator_led_probe(struct platform_device *pdev) { struct led_regulator_platform_data *pdata = pdev->dev.platform_data; struct regulator_led *led; @@ -206,7 +206,7 @@ err_vcc: return ret; } -static int __devexit regulator_led_remove(struct platform_device *pdev) +static int regulator_led_remove(struct platform_device *pdev) { struct regulator_led *led = platform_get_drvdata(pdev); @@ -223,7 +223,7 @@ static struct platform_driver regulator_led_driver = { .owner = THIS_MODULE, }, .probe = regulator_led_probe, - .remove = __devexit_p(regulator_led_remove), + .remove = regulator_led_remove, }; module_platform_driver(regulator_led_driver); diff --git a/drivers/leds/leds-renesas-tpu.c b/drivers/leds/leds-renesas-tpu.c index 771ea067e68..bc8984795a3 100644 --- a/drivers/leds/leds-renesas-tpu.c +++ b/drivers/leds/leds-renesas-tpu.c @@ -238,7 +238,7 @@ static void r_tpu_set_brightness(struct led_classdev *ldev, schedule_work(&p->work); } -static int __devinit r_tpu_probe(struct platform_device *pdev) +static int r_tpu_probe(struct platform_device *pdev) { struct led_renesas_tpu_config *cfg = pdev->dev.platform_data; struct r_tpu_priv *p; @@ -309,7 +309,7 @@ static int __devinit r_tpu_probe(struct platform_device *pdev) return ret; } -static int __devexit r_tpu_remove(struct platform_device *pdev) +static int r_tpu_remove(struct platform_device *pdev) { struct r_tpu_priv *p = platform_get_drvdata(pdev); @@ -328,7 +328,7 @@ static int __devexit r_tpu_remove(struct platform_device *pdev) static struct platform_driver r_tpu_device_driver = { .probe = r_tpu_probe, - .remove = __devexit_p(r_tpu_remove), + .remove = r_tpu_remove, .driver = { .name = "leds-renesas-tpu", } diff --git a/drivers/leds/leds-ss4200.c b/drivers/leds/leds-ss4200.c index 57371e1485a..6469849e826 100644 --- a/drivers/leds/leds-ss4200.c +++ b/drivers/leds/leds-ss4200.c @@ -263,7 +263,7 @@ static int nasgpio_led_set_blink(struct led_classdev *led_cdev, * already taken care of this, but we will do so in a non destructive manner * so that we have what we need whether the BIOS did it or not. */ -static int __devinit ich7_gpio_init(struct device *dev) +static int ich7_gpio_init(struct device *dev) { int i; u32 config_data = 0; @@ -342,7 +342,7 @@ static void ich7_lpc_cleanup(struct device *dev) * so we can retrive the required operational information and prepare the GPIO. */ static struct pci_dev *nas_gpio_pci_dev; -static int __devinit ich7_lpc_probe(struct pci_dev *dev, +static int ich7_lpc_probe(struct pci_dev *dev, const struct pci_device_id *id) { int status; diff --git a/drivers/leds/leds-sunfire.c b/drivers/leds/leds-sunfire.c index 134d9a4b34f..07ff5a3a6ce 100644 --- a/drivers/leds/leds-sunfire.c +++ b/drivers/leds/leds-sunfire.c @@ -123,7 +123,7 @@ struct sunfire_drvdata { struct sunfire_led leds[NUM_LEDS_PER_BOARD]; }; -static int __devinit sunfire_led_generic_probe(struct platform_device *pdev, +static int sunfire_led_generic_probe(struct platform_device *pdev, struct led_type *types) { struct sunfire_drvdata *p; @@ -165,7 +165,7 @@ static int __devinit sunfire_led_generic_probe(struct platform_device *pdev, return 0; } -static int __devexit sunfire_led_generic_remove(struct platform_device *pdev) +static int sunfire_led_generic_remove(struct platform_device *pdev) { struct sunfire_drvdata *p = dev_get_drvdata(&pdev->dev); int i; @@ -192,7 +192,7 @@ static struct led_type clockboard_led_types[NUM_LEDS_PER_BOARD] = { }, }; -static int __devinit sunfire_clockboard_led_probe(struct platform_device *pdev) +static int sunfire_clockboard_led_probe(struct platform_device *pdev) { return sunfire_led_generic_probe(pdev, clockboard_led_types); } @@ -213,7 +213,7 @@ static struct led_type fhc_led_types[NUM_LEDS_PER_BOARD] = { }, }; -static int __devinit sunfire_fhc_led_probe(struct platform_device *pdev) +static int sunfire_fhc_led_probe(struct platform_device *pdev) { return sunfire_led_generic_probe(pdev, fhc_led_types); } @@ -223,7 +223,7 @@ MODULE_ALIAS("platform:sunfire-fhc-leds"); static struct platform_driver sunfire_clockboard_led_driver = { .probe = sunfire_clockboard_led_probe, - .remove = __devexit_p(sunfire_led_generic_remove), + .remove = sunfire_led_generic_remove, .driver = { .name = "sunfire-clockboard-leds", .owner = THIS_MODULE, @@ -232,7 +232,7 @@ static struct platform_driver sunfire_clockboard_led_driver = { static struct platform_driver sunfire_fhc_led_driver = { .probe = sunfire_fhc_led_probe, - .remove = __devexit_p(sunfire_led_generic_remove), + .remove = sunfire_led_generic_remove, .driver = { .name = "sunfire-fhc-leds", .owner = THIS_MODULE, diff --git a/drivers/leds/leds-tca6507.c b/drivers/leds/leds-tca6507.c index dabcf7ae8d0..b26a63bae16 100644 --- a/drivers/leds/leds-tca6507.c +++ b/drivers/leds/leds-tca6507.c @@ -667,7 +667,7 @@ static void tca6507_remove_gpio(struct tca6507_chip *tca) } #endif /* CONFIG_GPIOLIB */ -static int __devinit tca6507_probe(struct i2c_client *client, +static int tca6507_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct tca6507_chip *tca; @@ -730,7 +730,7 @@ exit: return err; } -static int __devexit tca6507_remove(struct i2c_client *client) +static int tca6507_remove(struct i2c_client *client) { int i; struct tca6507_chip *tca = i2c_get_clientdata(client); @@ -752,7 +752,7 @@ static struct i2c_driver tca6507_driver = { .owner = THIS_MODULE, }, .probe = tca6507_probe, - .remove = __devexit_p(tca6507_remove), + .remove = tca6507_remove, .id_table = tca6507_id, }; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 02db9183ca0..77e6eff41ca 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -740,8 +740,14 @@ static void rq_completed(struct mapped_device *md, int rw, int run_queue) if (!md_in_flight(md)) wake_up(&md->wait); + /* + * Run this off this callpath, as drivers could invoke end_io while + * inside their request_fn (and holding the queue lock). Calling + * back into ->request_fn() could deadlock attempting to grab the + * queue lock again. + */ if (run_queue) - blk_run_queue(md->queue); + blk_run_queue_async(md->queue); /* * dm_put() must be at the end of this function. See the comment above diff --git a/drivers/md/md.c b/drivers/md/md.c index 9ab768acfb6..61200717687 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1817,10 +1817,10 @@ retry: memset(bbp, 0xff, PAGE_SIZE); for (i = 0 ; i < bb->count ; i++) { - u64 internal_bb = *p++; + u64 internal_bb = p[i]; u64 store_bb = ((BB_OFFSET(internal_bb) << 10) | BB_LEN(internal_bb)); - *bbp++ = cpu_to_le64(store_bb); + bbp[i] = cpu_to_le64(store_bb); } bb->changed = 0; if (read_seqretry(&bb->lock, seq)) @@ -5294,7 +5294,7 @@ void md_stop_writes(struct mddev *mddev) } EXPORT_SYMBOL_GPL(md_stop_writes); -void md_stop(struct mddev *mddev) +static void __md_stop(struct mddev *mddev) { mddev->ready = 0; mddev->pers->stop(mddev); @@ -5304,6 +5304,18 @@ void md_stop(struct mddev *mddev) mddev->pers = NULL; clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); } + +void md_stop(struct mddev *mddev) +{ + /* stop the array and free an attached data structures. + * This is called from dm-raid + */ + __md_stop(mddev); + bitmap_destroy(mddev); + if (mddev->bio_set) + bioset_free(mddev->bio_set); +} + EXPORT_SYMBOL_GPL(md_stop); static int md_set_readonly(struct mddev *mddev, struct block_device *bdev) @@ -5364,7 +5376,7 @@ static int do_md_stop(struct mddev * mddev, int mode, set_disk_ro(disk, 0); __md_stop_writes(mddev); - md_stop(mddev); + __md_stop(mddev); mddev->queue->merge_bvec_fn = NULL; mddev->queue->backing_dev_info.congested_fn = NULL; @@ -7936,9 +7948,9 @@ int md_is_badblock(struct badblocks *bb, sector_t s, int sectors, sector_t *first_bad, int *bad_sectors) { int hi; - int lo = 0; + int lo; u64 *p = bb->page; - int rv = 0; + int rv; sector_t target = s + sectors; unsigned seq; @@ -7953,7 +7965,8 @@ int md_is_badblock(struct badblocks *bb, sector_t s, int sectors, retry: seq = read_seqbegin(&bb->lock); - + lo = 0; + rv = 0; hi = bb->count; /* Binary search between lo and hi for 'target' diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 636bae0405e..a0f73092176 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -963,7 +963,7 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule) struct r1conf *conf = mddev->private; struct bio *bio; - if (from_schedule) { + if (from_schedule || current->bio_list) { spin_lock_irq(&conf->device_lock); bio_list_merge(&conf->pending_bio_list, &plug->pending); conf->pending_count += plug->pending_cnt; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index d1295aff417..c9acbd71713 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -499,7 +499,7 @@ static void raid10_end_write_request(struct bio *bio, int error) */ one_write_done(r10_bio); if (dec_rdev) - rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev); + rdev_dec_pending(rdev, conf->mddev); } /* @@ -1069,7 +1069,7 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule) struct r10conf *conf = mddev->private; struct bio *bio; - if (from_schedule) { + if (from_schedule || current->bio_list) { spin_lock_irq(&conf->device_lock); bio_list_merge(&conf->pending_bio_list, &plug->pending); conf->pending_count += plug->pending_cnt; @@ -1334,18 +1334,21 @@ retry_write: blocked_rdev = rrdev; break; } + if (rdev && (test_bit(Faulty, &rdev->flags) + || test_bit(Unmerged, &rdev->flags))) + rdev = NULL; if (rrdev && (test_bit(Faulty, &rrdev->flags) || test_bit(Unmerged, &rrdev->flags))) rrdev = NULL; r10_bio->devs[i].bio = NULL; r10_bio->devs[i].repl_bio = NULL; - if (!rdev || test_bit(Faulty, &rdev->flags) || - test_bit(Unmerged, &rdev->flags)) { + + if (!rdev && !rrdev) { set_bit(R10BIO_Degraded, &r10_bio->state); continue; } - if (test_bit(WriteErrorSeen, &rdev->flags)) { + if (rdev && test_bit(WriteErrorSeen, &rdev->flags)) { sector_t first_bad; sector_t dev_sector = r10_bio->devs[i].addr; int bad_sectors; @@ -1387,8 +1390,10 @@ retry_write: max_sectors = good_sectors; } } - r10_bio->devs[i].bio = bio; - atomic_inc(&rdev->nr_pending); + if (rdev) { + r10_bio->devs[i].bio = bio; + atomic_inc(&rdev->nr_pending); + } if (rrdev) { r10_bio->devs[i].repl_bio = bio; atomic_inc(&rrdev->nr_pending); @@ -1444,69 +1449,71 @@ retry_write: for (i = 0; i < conf->copies; i++) { struct bio *mbio; int d = r10_bio->devs[i].devnum; - if (!r10_bio->devs[i].bio) - continue; + if (r10_bio->devs[i].bio) { + struct md_rdev *rdev = conf->mirrors[d].rdev; + mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); + md_trim_bio(mbio, r10_bio->sector - bio->bi_sector, + max_sectors); + r10_bio->devs[i].bio = mbio; + + mbio->bi_sector = (r10_bio->devs[i].addr+ + choose_data_offset(r10_bio, + rdev)); + mbio->bi_bdev = rdev->bdev; + mbio->bi_end_io = raid10_end_write_request; + mbio->bi_rw = WRITE | do_sync | do_fua | do_discard; + mbio->bi_private = r10_bio; - mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - md_trim_bio(mbio, r10_bio->sector - bio->bi_sector, - max_sectors); - r10_bio->devs[i].bio = mbio; + atomic_inc(&r10_bio->remaining); - mbio->bi_sector = (r10_bio->devs[i].addr+ - choose_data_offset(r10_bio, - conf->mirrors[d].rdev)); - mbio->bi_bdev = conf->mirrors[d].rdev->bdev; - mbio->bi_end_io = raid10_end_write_request; - mbio->bi_rw = WRITE | do_sync | do_fua | do_discard; - mbio->bi_private = r10_bio; + cb = blk_check_plugged(raid10_unplug, mddev, + sizeof(*plug)); + if (cb) + plug = container_of(cb, struct raid10_plug_cb, + cb); + else + plug = NULL; + spin_lock_irqsave(&conf->device_lock, flags); + if (plug) { + bio_list_add(&plug->pending, mbio); + plug->pending_cnt++; + } else { + bio_list_add(&conf->pending_bio_list, mbio); + conf->pending_count++; + } + spin_unlock_irqrestore(&conf->device_lock, flags); + if (!plug) + md_wakeup_thread(mddev->thread); + } - atomic_inc(&r10_bio->remaining); + if (r10_bio->devs[i].repl_bio) { + struct md_rdev *rdev = conf->mirrors[d].replacement; + if (rdev == NULL) { + /* Replacement just got moved to main 'rdev' */ + smp_mb(); + rdev = conf->mirrors[d].rdev; + } + mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); + md_trim_bio(mbio, r10_bio->sector - bio->bi_sector, + max_sectors); + r10_bio->devs[i].repl_bio = mbio; + + mbio->bi_sector = (r10_bio->devs[i].addr + + choose_data_offset( + r10_bio, rdev)); + mbio->bi_bdev = rdev->bdev; + mbio->bi_end_io = raid10_end_write_request; + mbio->bi_rw = WRITE | do_sync | do_fua | do_discard; + mbio->bi_private = r10_bio; - cb = blk_check_plugged(raid10_unplug, mddev, sizeof(*plug)); - if (cb) - plug = container_of(cb, struct raid10_plug_cb, cb); - else - plug = NULL; - spin_lock_irqsave(&conf->device_lock, flags); - if (plug) { - bio_list_add(&plug->pending, mbio); - plug->pending_cnt++; - } else { + atomic_inc(&r10_bio->remaining); + spin_lock_irqsave(&conf->device_lock, flags); bio_list_add(&conf->pending_bio_list, mbio); conf->pending_count++; + spin_unlock_irqrestore(&conf->device_lock, flags); + if (!mddev_check_plugged(mddev)) + md_wakeup_thread(mddev->thread); } - spin_unlock_irqrestore(&conf->device_lock, flags); - if (!plug) - md_wakeup_thread(mddev->thread); - - if (!r10_bio->devs[i].repl_bio) - continue; - - mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - md_trim_bio(mbio, r10_bio->sector - bio->bi_sector, - max_sectors); - r10_bio->devs[i].repl_bio = mbio; - - /* We are actively writing to the original device - * so it cannot disappear, so the replacement cannot - * become NULL here - */ - mbio->bi_sector = (r10_bio->devs[i].addr + - choose_data_offset( - r10_bio, - conf->mirrors[d].replacement)); - mbio->bi_bdev = conf->mirrors[d].replacement->bdev; - mbio->bi_end_io = raid10_end_write_request; - mbio->bi_rw = WRITE | do_sync | do_fua | do_discard; - mbio->bi_private = r10_bio; - - atomic_inc(&r10_bio->remaining); - spin_lock_irqsave(&conf->device_lock, flags); - bio_list_add(&conf->pending_bio_list, mbio); - conf->pending_count++; - spin_unlock_irqrestore(&conf->device_lock, flags); - if (!mddev_check_plugged(mddev)) - md_wakeup_thread(mddev->thread); } /* Don't remove the bias on 'remaining' (one_write_done) until diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index c5439dce029..a4502686e7a 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2774,10 +2774,12 @@ static void handle_stripe_clean_event(struct r5conf *conf, dev = &sh->dev[i]; if (!test_bit(R5_LOCKED, &dev->flags) && (test_bit(R5_UPTODATE, &dev->flags) || - test_and_clear_bit(R5_Discard, &dev->flags))) { + test_bit(R5_Discard, &dev->flags))) { /* We can return any write requests */ struct bio *wbi, *wbi2; pr_debug("Return write for disc %d\n", i); + if (test_and_clear_bit(R5_Discard, &dev->flags)) + clear_bit(R5_UPTODATE, &dev->flags); wbi = dev->written; dev->written = NULL; while (wbi && wbi->bi_sector < @@ -2795,7 +2797,8 @@ static void handle_stripe_clean_event(struct r5conf *conf, !test_bit(STRIPE_DEGRADED, &sh->state), 0); } - } + } else if (test_bit(R5_Discard, &sh->dev[i].flags)) + clear_bit(R5_Discard, &sh->dev[i].flags); if (test_and_clear_bit(STRIPE_FULL_WRITE, &sh->state)) if (atomic_dec_and_test(&conf->pending_full_writes)) @@ -3490,40 +3493,6 @@ static void handle_stripe(struct stripe_head *sh) handle_failed_sync(conf, sh, &s); } - /* - * might be able to return some write requests if the parity blocks - * are safe, or on a failed drive - */ - pdev = &sh->dev[sh->pd_idx]; - s.p_failed = (s.failed >= 1 && s.failed_num[0] == sh->pd_idx) - || (s.failed >= 2 && s.failed_num[1] == sh->pd_idx); - qdev = &sh->dev[sh->qd_idx]; - s.q_failed = (s.failed >= 1 && s.failed_num[0] == sh->qd_idx) - || (s.failed >= 2 && s.failed_num[1] == sh->qd_idx) - || conf->level < 6; - - if (s.written && - (s.p_failed || ((test_bit(R5_Insync, &pdev->flags) - && !test_bit(R5_LOCKED, &pdev->flags) - && (test_bit(R5_UPTODATE, &pdev->flags) || - test_bit(R5_Discard, &pdev->flags))))) && - (s.q_failed || ((test_bit(R5_Insync, &qdev->flags) - && !test_bit(R5_LOCKED, &qdev->flags) - && (test_bit(R5_UPTODATE, &qdev->flags) || - test_bit(R5_Discard, &qdev->flags)))))) - handle_stripe_clean_event(conf, sh, disks, &s.return_bi); - - /* Now we might consider reading some blocks, either to check/generate - * parity, or to satisfy requests - * or to load a block that is being partially written. - */ - if (s.to_read || s.non_overwrite - || (conf->level == 6 && s.to_write && s.failed) - || (s.syncing && (s.uptodate + s.compute < disks)) - || s.replacing - || s.expanding) - handle_stripe_fill(sh, &s, disks); - /* Now we check to see if any write operations have recently * completed */ @@ -3561,6 +3530,40 @@ static void handle_stripe(struct stripe_head *sh) s.dec_preread_active = 1; } + /* + * might be able to return some write requests if the parity blocks + * are safe, or on a failed drive + */ + pdev = &sh->dev[sh->pd_idx]; + s.p_failed = (s.failed >= 1 && s.failed_num[0] == sh->pd_idx) + || (s.failed >= 2 && s.failed_num[1] == sh->pd_idx); + qdev = &sh->dev[sh->qd_idx]; + s.q_failed = (s.failed >= 1 && s.failed_num[0] == sh->qd_idx) + || (s.failed >= 2 && s.failed_num[1] == sh->qd_idx) + || conf->level < 6; + + if (s.written && + (s.p_failed || ((test_bit(R5_Insync, &pdev->flags) + && !test_bit(R5_LOCKED, &pdev->flags) + && (test_bit(R5_UPTODATE, &pdev->flags) || + test_bit(R5_Discard, &pdev->flags))))) && + (s.q_failed || ((test_bit(R5_Insync, &qdev->flags) + && !test_bit(R5_LOCKED, &qdev->flags) + && (test_bit(R5_UPTODATE, &qdev->flags) || + test_bit(R5_Discard, &qdev->flags)))))) + handle_stripe_clean_event(conf, sh, disks, &s.return_bi); + + /* Now we might consider reading some blocks, either to check/generate + * parity, or to satisfy requests + * or to load a block that is being partially written. + */ + if (s.to_read || s.non_overwrite + || (conf->level == 6 && s.to_write && s.failed) + || (s.syncing && (s.uptodate + s.compute < disks)) + || s.replacing + || s.expanding) + handle_stripe_fill(sh, &s, disks); + /* Now to consider new write requests and what else, if anything * should be read. We do not handle new writes when: * 1/ A 'write' operation (copy+xor) is already in flight. @@ -5529,6 +5532,10 @@ static int run(struct mddev *mddev) * discard data disk but write parity disk */ stripe = stripe * PAGE_SIZE; + /* Round up to power of 2, as discard handling + * currently assumes that */ + while ((stripe-1) & stripe) + stripe = (stripe | (stripe-1)) + 1; mddev->queue->limits.discard_alignment = stripe; mddev->queue->limits.discard_granularity = stripe; /* diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c index 262dfa503c2..b551ca350e0 100644 --- a/drivers/media/dvb-frontends/stv0900_core.c +++ b/drivers/media/dvb-frontends/stv0900_core.c @@ -300,15 +300,15 @@ static enum fe_stv0900_error stv0900_set_mclk(struct stv0900_internal *intp, u32 { u32 m_div, clk_sel; - dprintk("%s: Mclk set to %d, Quartz = %d\n", __func__, mclk, - intp->quartz); - if (intp == NULL) return STV0900_INVALID_HANDLE; if (intp->errs) return STV0900_I2C_ERROR; + dprintk("%s: Mclk set to %d, Quartz = %d\n", __func__, mclk, + intp->quartz); + clk_sel = ((stv0900_get_bits(intp, F0900_SELX1RATIO) == 1) ? 4 : 6); m_div = ((clk_sel * mclk) / intp->quartz) - 1; stv0900_write_bits(intp, F0900_M_DIV, m_div); diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 109bc9b12e7..05f8950f6f9 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -53,8 +53,7 @@ MODULE_LICENSE("GPL"); /* ADV7604 system clock frequency */ #define ADV7604_fsc (28636360) -#define DIGITAL_INPUT ((state->prim_mode == ADV7604_PRIM_MODE_HDMI_COMP) || \ - (state->prim_mode == ADV7604_PRIM_MODE_HDMI_GR)) +#define DIGITAL_INPUT (state->mode == ADV7604_MODE_HDMI) /* ********************************************************************** @@ -68,7 +67,7 @@ struct adv7604_state { struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler hdl; - enum adv7604_prim_mode prim_mode; + enum adv7604_mode mode; struct v4l2_dv_timings timings; u8 edid[256]; unsigned edid_blocks; @@ -77,6 +76,7 @@ struct adv7604_state { struct workqueue_struct *work_queues; struct delayed_work delayed_work_enable_hotplug; bool connector_hdmi; + bool restart_stdi_once; /* i2c clients */ struct i2c_client *i2c_avlink; @@ -106,7 +106,6 @@ static const struct v4l2_dv_timings adv7604_timings[] = { V4L2_DV_BT_CEA_720X576P50, V4L2_DV_BT_CEA_1280X720P24, V4L2_DV_BT_CEA_1280X720P25, - V4L2_DV_BT_CEA_1280X720P30, V4L2_DV_BT_CEA_1280X720P50, V4L2_DV_BT_CEA_1280X720P60, V4L2_DV_BT_CEA_1920X1080P24, @@ -115,6 +114,7 @@ static const struct v4l2_dv_timings adv7604_timings[] = { V4L2_DV_BT_CEA_1920X1080P50, V4L2_DV_BT_CEA_1920X1080P60, + /* sorted by DMT ID */ V4L2_DV_BT_DMT_640X350P85, V4L2_DV_BT_DMT_640X400P85, V4L2_DV_BT_DMT_720X400P85, @@ -164,6 +164,89 @@ static const struct v4l2_dv_timings adv7604_timings[] = { { }, }; +struct adv7604_video_standards { + struct v4l2_dv_timings timings; + u8 vid_std; + u8 v_freq; +}; + +/* sorted by number of lines */ +static const struct adv7604_video_standards adv7604_prim_mode_comp[] = { + /* { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 }, TODO flickering */ + { V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 }, + { V4L2_DV_BT_CEA_1280X720P50, 0x19, 0x01 }, + { V4L2_DV_BT_CEA_1280X720P60, 0x19, 0x00 }, + { V4L2_DV_BT_CEA_1920X1080P24, 0x1e, 0x04 }, + { V4L2_DV_BT_CEA_1920X1080P25, 0x1e, 0x03 }, + { V4L2_DV_BT_CEA_1920X1080P30, 0x1e, 0x02 }, + { V4L2_DV_BT_CEA_1920X1080P50, 0x1e, 0x01 }, + { V4L2_DV_BT_CEA_1920X1080P60, 0x1e, 0x00 }, + /* TODO add 1920x1080P60_RB (CVT timing) */ + { }, +}; + +/* sorted by number of lines */ +static const struct adv7604_video_standards adv7604_prim_mode_gr[] = { + { V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 }, + { V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 }, + { V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 }, + { V4L2_DV_BT_DMT_640X480P85, 0x0b, 0x00 }, + { V4L2_DV_BT_DMT_800X600P56, 0x00, 0x00 }, + { V4L2_DV_BT_DMT_800X600P60, 0x01, 0x00 }, + { V4L2_DV_BT_DMT_800X600P72, 0x02, 0x00 }, + { V4L2_DV_BT_DMT_800X600P75, 0x03, 0x00 }, + { V4L2_DV_BT_DMT_800X600P85, 0x04, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P60, 0x0c, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P70, 0x0d, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P75, 0x0e, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P85, 0x0f, 0x00 }, + { V4L2_DV_BT_DMT_1280X1024P60, 0x05, 0x00 }, + { V4L2_DV_BT_DMT_1280X1024P75, 0x06, 0x00 }, + { V4L2_DV_BT_DMT_1360X768P60, 0x12, 0x00 }, + { V4L2_DV_BT_DMT_1366X768P60, 0x13, 0x00 }, + { V4L2_DV_BT_DMT_1400X1050P60, 0x14, 0x00 }, + { V4L2_DV_BT_DMT_1400X1050P75, 0x15, 0x00 }, + { V4L2_DV_BT_DMT_1600X1200P60, 0x16, 0x00 }, /* TODO not tested */ + /* TODO add 1600X1200P60_RB (not a DMT timing) */ + { V4L2_DV_BT_DMT_1680X1050P60, 0x18, 0x00 }, + { V4L2_DV_BT_DMT_1920X1200P60_RB, 0x19, 0x00 }, /* TODO not tested */ + { }, +}; + +/* sorted by number of lines */ +static const struct adv7604_video_standards adv7604_prim_mode_hdmi_comp[] = { + { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 }, + { V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 }, + { V4L2_DV_BT_CEA_1280X720P50, 0x13, 0x01 }, + { V4L2_DV_BT_CEA_1280X720P60, 0x13, 0x00 }, + { V4L2_DV_BT_CEA_1920X1080P24, 0x1e, 0x04 }, + { V4L2_DV_BT_CEA_1920X1080P25, 0x1e, 0x03 }, + { V4L2_DV_BT_CEA_1920X1080P30, 0x1e, 0x02 }, + { V4L2_DV_BT_CEA_1920X1080P50, 0x1e, 0x01 }, + { V4L2_DV_BT_CEA_1920X1080P60, 0x1e, 0x00 }, + { }, +}; + +/* sorted by number of lines */ +static const struct adv7604_video_standards adv7604_prim_mode_hdmi_gr[] = { + { V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 }, + { V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 }, + { V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 }, + { V4L2_DV_BT_DMT_640X480P85, 0x0b, 0x00 }, + { V4L2_DV_BT_DMT_800X600P56, 0x00, 0x00 }, + { V4L2_DV_BT_DMT_800X600P60, 0x01, 0x00 }, + { V4L2_DV_BT_DMT_800X600P72, 0x02, 0x00 }, + { V4L2_DV_BT_DMT_800X600P75, 0x03, 0x00 }, + { V4L2_DV_BT_DMT_800X600P85, 0x04, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P60, 0x0c, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P70, 0x0d, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P75, 0x0e, 0x00 }, + { V4L2_DV_BT_DMT_1024X768P85, 0x0f, 0x00 }, + { V4L2_DV_BT_DMT_1280X1024P60, 0x05, 0x00 }, + { V4L2_DV_BT_DMT_1280X1024P75, 0x06, 0x00 }, + { }, +}; + /* ----------------------------------------------------------------------- */ static inline struct adv7604_state *to_state(struct v4l2_subdev *sd) @@ -672,64 +755,144 @@ static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) ((io_read(sd, 0x6f) & 0x10) >> 4)); } -static void configure_free_run(struct v4l2_subdev *sd, const struct v4l2_bt_timings *timings) +static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, + u8 prim_mode, + const struct adv7604_video_standards *predef_vid_timings, + const struct v4l2_dv_timings *timings) +{ + struct adv7604_state *state = to_state(sd); + int i; + + for (i = 0; predef_vid_timings[i].timings.bt.width; i++) { + if (!v4l_match_dv_timings(timings, &predef_vid_timings[i].timings, + DIGITAL_INPUT ? 250000 : 1000000)) + continue; + io_write(sd, 0x00, predef_vid_timings[i].vid_std); /* video std */ + io_write(sd, 0x01, (predef_vid_timings[i].v_freq << 4) + + prim_mode); /* v_freq and prim mode */ + return 0; + } + + return -1; +} + +static int configure_predefined_video_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) { + struct adv7604_state *state = to_state(sd); + int err; + + v4l2_dbg(1, debug, sd, "%s", __func__); + + /* reset to default values */ + io_write(sd, 0x16, 0x43); + io_write(sd, 0x17, 0x5a); + /* disable embedded syncs for auto graphics mode */ + cp_write_and_or(sd, 0x81, 0xef, 0x00); + cp_write(sd, 0x8f, 0x00); + cp_write(sd, 0x90, 0x00); + cp_write(sd, 0xa2, 0x00); + cp_write(sd, 0xa3, 0x00); + cp_write(sd, 0xa4, 0x00); + cp_write(sd, 0xa5, 0x00); + cp_write(sd, 0xa6, 0x00); + cp_write(sd, 0xa7, 0x00); + cp_write(sd, 0xab, 0x00); + cp_write(sd, 0xac, 0x00); + + switch (state->mode) { + case ADV7604_MODE_COMP: + case ADV7604_MODE_GR: + err = find_and_set_predefined_video_timings(sd, + 0x01, adv7604_prim_mode_comp, timings); + if (err) + err = find_and_set_predefined_video_timings(sd, + 0x02, adv7604_prim_mode_gr, timings); + break; + case ADV7604_MODE_HDMI: + err = find_and_set_predefined_video_timings(sd, + 0x05, adv7604_prim_mode_hdmi_comp, timings); + if (err) + err = find_and_set_predefined_video_timings(sd, + 0x06, adv7604_prim_mode_hdmi_gr, timings); + break; + default: + v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", + __func__, state->mode); + err = -1; + break; + } + + + return err; +} + +static void configure_custom_video_timings(struct v4l2_subdev *sd, + const struct v4l2_bt_timings *bt) +{ + struct adv7604_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - u32 width = htotal(timings); - u32 height = vtotal(timings); - u16 ch1_fr_ll = (((u32)timings->pixelclock / 100) > 0) ? - ((width * (ADV7604_fsc / 100)) / ((u32)timings->pixelclock / 100)) : 0; + u32 width = htotal(bt); + u32 height = vtotal(bt); + u16 cp_start_sav = bt->hsync + bt->hbackporch - 4; + u16 cp_start_eav = width - bt->hfrontporch; + u16 cp_start_vbi = height - bt->vfrontporch; + u16 cp_end_vbi = bt->vsync + bt->vbackporch; + u16 ch1_fr_ll = (((u32)bt->pixelclock / 100) > 0) ? + ((width * (ADV7604_fsc / 100)) / ((u32)bt->pixelclock / 100)) : 0; + const u8 pll[2] = { + 0xc0 | ((width >> 8) & 0x1f), + width & 0xff + }; v4l2_dbg(2, debug, sd, "%s\n", __func__); - cp_write(sd, 0x8f, (ch1_fr_ll >> 8) & 0x7); /* CH1_FR_LL */ - cp_write(sd, 0x90, ch1_fr_ll & 0xff); /* CH1_FR_LL */ - cp_write(sd, 0xab, (height >> 4) & 0xff); /* CP_LCOUNT_MAX */ - cp_write(sd, 0xac, (height & 0x0f) << 4); /* CP_LCOUNT_MAX */ - /* TODO support interlaced */ - cp_write(sd, 0x91, 0x10); /* INTERLACED */ - - /* Should only be set in auto-graphics mode [REF_02 p. 91-92] */ - if ((io_read(sd, 0x00) == 0x07) && (io_read(sd, 0x01) == 0x02)) { - u16 cp_start_sav, cp_start_eav, cp_start_vbi, cp_end_vbi; - const u8 pll[2] = { - (0xc0 | ((width >> 8) & 0x1f)), - (width & 0xff) - }; + switch (state->mode) { + case ADV7604_MODE_COMP: + case ADV7604_MODE_GR: + /* auto graphics */ + io_write(sd, 0x00, 0x07); /* video std */ + io_write(sd, 0x01, 0x02); /* prim mode */ + /* enable embedded syncs for auto graphics mode */ + cp_write_and_or(sd, 0x81, 0xef, 0x10); + /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */ /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */ /* IO-map reg. 0x16 and 0x17 should be written in sequence */ if (adv_smbus_write_i2c_block_data(client, 0x16, 2, pll)) { v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n"); - return; + break; } /* active video - horizontal timing */ - cp_start_sav = timings->hsync + timings->hbackporch - 4; - cp_start_eav = width - timings->hfrontporch; cp_write(sd, 0xa2, (cp_start_sav >> 4) & 0xff); - cp_write(sd, 0xa3, ((cp_start_sav & 0x0f) << 4) | ((cp_start_eav >> 8) & 0x0f)); + cp_write(sd, 0xa3, ((cp_start_sav & 0x0f) << 4) | + ((cp_start_eav >> 8) & 0x0f)); cp_write(sd, 0xa4, cp_start_eav & 0xff); /* active video - vertical timing */ - cp_start_vbi = height - timings->vfrontporch; - cp_end_vbi = timings->vsync + timings->vbackporch; cp_write(sd, 0xa5, (cp_start_vbi >> 4) & 0xff); - cp_write(sd, 0xa6, ((cp_start_vbi & 0xf) << 4) | ((cp_end_vbi >> 8) & 0xf)); + cp_write(sd, 0xa6, ((cp_start_vbi & 0xf) << 4) | + ((cp_end_vbi >> 8) & 0xf)); cp_write(sd, 0xa7, cp_end_vbi & 0xff); - } else { - /* reset to default values */ - io_write(sd, 0x16, 0x43); - io_write(sd, 0x17, 0x5a); - cp_write(sd, 0xa2, 0x00); - cp_write(sd, 0xa3, 0x00); - cp_write(sd, 0xa4, 0x00); - cp_write(sd, 0xa5, 0x00); - cp_write(sd, 0xa6, 0x00); - cp_write(sd, 0xa7, 0x00); + break; + case ADV7604_MODE_HDMI: + /* set default prim_mode/vid_std for HDMI + accoring to [REF_03, c. 4.2] */ + io_write(sd, 0x00, 0x02); /* video std */ + io_write(sd, 0x01, 0x06); /* prim mode */ + break; + default: + v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", + __func__, state->mode); + break; } -} + cp_write(sd, 0x8f, (ch1_fr_ll >> 8) & 0x7); + cp_write(sd, 0x90, ch1_fr_ll & 0xff); + cp_write(sd, 0xab, (height >> 4) & 0xff); + cp_write(sd, 0xac, (height & 0x0f) << 4); +} static void set_rgb_quantization_range(struct v4l2_subdev *sd) { @@ -738,12 +901,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) switch (state->rgb_quantization_range) { case V4L2_DV_RGB_RANGE_AUTO: /* automatic */ - if ((hdmi_read(sd, 0x05) & 0x80) || - (state->prim_mode == ADV7604_PRIM_MODE_COMP) || - (state->prim_mode == ADV7604_PRIM_MODE_RGB)) { - /* receiving HDMI or analog signal */ - io_write_and_or(sd, 0x02, 0x0f, 0xf0); - } else { + if (DIGITAL_INPUT && !(hdmi_read(sd, 0x05) & 0x80)) { /* receiving DVI-D signal */ /* ADV7604 selects RGB limited range regardless of @@ -756,6 +914,9 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) /* RGB full range (0-255) */ io_write_and_or(sd, 0x02, 0x0f, 0x10); } + } else { + /* receiving HDMI or analog signal, set automode */ + io_write_and_or(sd, 0x02, 0x0f, 0xf0); } break; case V4L2_DV_RGB_RANGE_LIMITED: @@ -967,8 +1128,10 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, state->aspect_ratio, timings)) return 0; - v4l2_dbg(2, debug, sd, "%s: No format candidate found for lcf=%d, bl = %d\n", - __func__, stdi->lcf, stdi->bl); + v4l2_dbg(2, debug, sd, + "%s: No format candidate found for lcvs = %d, lcf=%d, bl = %d, %chsync, %cvsync\n", + __func__, stdi->lcvs, stdi->lcf, stdi->bl, + stdi->hs_pol, stdi->vs_pol); return -1; } @@ -1123,7 +1286,7 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd, adv7604_fill_optional_dv_timings_fields(sd, timings); } else { /* find format - * Since LCVS values are inaccurate (REF_03, page 275-276), + * Since LCVS values are inaccurate [REF_03, p. 275-276], * stdi2dv_timings() is called with lcvs +-1 if the first attempt fails. */ if (!stdi2dv_timings(sd, &stdi, timings)) @@ -1135,9 +1298,31 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd, stdi.lcvs -= 2; v4l2_dbg(1, debug, sd, "%s: lcvs - 1 = %d\n", __func__, stdi.lcvs); if (stdi2dv_timings(sd, &stdi, timings)) { + /* + * The STDI block may measure wrong values, especially + * for lcvs and lcf. If the driver can not find any + * valid timing, the STDI block is restarted to measure + * the video timings again. The function will return an + * error, but the restart of STDI will generate a new + * STDI interrupt and the format detection process will + * restart. + */ + if (state->restart_stdi_once) { + v4l2_dbg(1, debug, sd, "%s: restart STDI\n", __func__); + /* TODO restart STDI for Sync Channel 2 */ + /* enter one-shot mode */ + cp_write_and_or(sd, 0x86, 0xf9, 0x00); + /* trigger STDI restart */ + cp_write_and_or(sd, 0x86, 0xf9, 0x04); + /* reset to continuous mode */ + cp_write_and_or(sd, 0x86, 0xf9, 0x02); + state->restart_stdi_once = false; + return -ENOLINK; + } v4l2_dbg(1, debug, sd, "%s: format not supported\n", __func__); return -ERANGE; } + state->restart_stdi_once = true; } found: @@ -1166,6 +1351,7 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd, { struct adv7604_state *state = to_state(sd); struct v4l2_bt_timings *bt; + int err; if (!timings) return -EINVAL; @@ -1178,12 +1364,20 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd, __func__, (u32)bt->pixelclock); return -ERANGE; } + adv7604_fill_optional_dv_timings_fields(sd, timings); state->timings = *timings; - /* freerun */ - configure_free_run(sd, bt); + cp_write(sd, 0x91, bt->interlaced ? 0x50 : 0x10); + + /* Use prim_mode and vid_std when available */ + err = configure_predefined_video_timings(sd, timings); + if (err) { + /* custom settings when the video format + does not have prim_mode/vid_std */ + configure_custom_video_timings(sd, bt); + } set_rgb_quantization_range(sd); @@ -1203,24 +1397,25 @@ static int adv7604_g_dv_timings(struct v4l2_subdev *sd, return 0; } -static void enable_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mode) +static void enable_input(struct v4l2_subdev *sd) { - switch (prim_mode) { - case ADV7604_PRIM_MODE_COMP: - case ADV7604_PRIM_MODE_RGB: + struct adv7604_state *state = to_state(sd); + + switch (state->mode) { + case ADV7604_MODE_COMP: + case ADV7604_MODE_GR: /* enable */ io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */ break; - case ADV7604_PRIM_MODE_HDMI_COMP: - case ADV7604_PRIM_MODE_HDMI_GR: + case ADV7604_MODE_HDMI: /* enable */ hdmi_write(sd, 0x1a, 0x0a); /* Unmute audio */ hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */ io_write(sd, 0x15, 0xa0); /* Disable Tristate of Pins */ break; default: - v4l2_err(sd, "%s: reserved primary mode 0x%0x\n", - __func__, prim_mode); + v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", + __func__, state->mode); break; } } @@ -1233,17 +1428,13 @@ static void disable_input(struct v4l2_subdev *sd) hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */ } -static void select_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mode) +static void select_input(struct v4l2_subdev *sd) { - switch (prim_mode) { - case ADV7604_PRIM_MODE_COMP: - case ADV7604_PRIM_MODE_RGB: - /* set mode and select free run resolution */ - io_write(sd, 0x00, 0x07); /* video std */ - io_write(sd, 0x01, 0x02); /* prim mode */ - /* enable embedded syncs for auto graphics mode */ - cp_write_and_or(sd, 0x81, 0xef, 0x10); + struct adv7604_state *state = to_state(sd); + switch (state->mode) { + case ADV7604_MODE_COMP: + case ADV7604_MODE_GR: /* reset ADI recommended settings for HDMI: */ /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ hdmi_write(sd, 0x0d, 0x04); /* HDMI filter optimization */ @@ -1271,16 +1462,7 @@ static void select_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mod cp_write(sd, 0x40, 0x5c); /* CP core pre-gain control. Graphics mode */ break; - case ADV7604_PRIM_MODE_HDMI_COMP: - case ADV7604_PRIM_MODE_HDMI_GR: - /* set mode and select free run resolution */ - /* video std */ - io_write(sd, 0x00, - (prim_mode == ADV7604_PRIM_MODE_HDMI_GR) ? 0x02 : 0x1e); - io_write(sd, 0x01, prim_mode); /* prim mode */ - /* disable embedded syncs for auto graphics mode */ - cp_write_and_or(sd, 0x81, 0xef, 0x00); - + case ADV7604_MODE_HDMI: /* set ADI recommended settings for HDMI: */ /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ hdmi_write(sd, 0x0d, 0x84); /* HDMI filter optimization */ @@ -1309,7 +1491,8 @@ static void select_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mod break; default: - v4l2_err(sd, "%s: reserved primary mode 0x%0x\n", __func__, prim_mode); + v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", + __func__, state->mode); break; } } @@ -1321,26 +1504,13 @@ static int adv7604_s_routing(struct v4l2_subdev *sd, v4l2_dbg(2, debug, sd, "%s: input %d", __func__, input); - switch (input) { - case 0: - /* TODO select HDMI_COMP or HDMI_GR */ - state->prim_mode = ADV7604_PRIM_MODE_HDMI_COMP; - break; - case 1: - state->prim_mode = ADV7604_PRIM_MODE_RGB; - break; - case 2: - state->prim_mode = ADV7604_PRIM_MODE_COMP; - break; - default: - return -EINVAL; - } + state->mode = input; disable_input(sd); - select_input(sd, state->prim_mode); + select_input(sd); - enable_input(sd, state->prim_mode); + enable_input(sd); return 0; } @@ -1549,8 +1719,9 @@ static int adv7604_log_status(struct v4l2_subdev *sd) v4l2_info(sd, "CP locked: %s\n", no_lock_cp(sd) ? "false" : "true"); v4l2_info(sd, "CP free run: %s\n", (!!(cp_read(sd, 0xff) & 0x10) ? "on" : "off")); - v4l2_info(sd, "Prim-mode = 0x%x, video std = 0x%x\n", - io_read(sd, 0x01) & 0x0f, io_read(sd, 0x00) & 0x3f); + v4l2_info(sd, "Prim-mode = 0x%x, video std = 0x%x, v_freq = 0x%x\n", + io_read(sd, 0x01) & 0x0f, io_read(sd, 0x00) & 0x3f, + (io_read(sd, 0x01) & 0x70) >> 4); v4l2_info(sd, "-----Video Timings-----\n"); if (read_stdi(sd, &stdi)) @@ -1712,9 +1883,9 @@ static int adv7604_core_init(struct v4l2_subdev *sd) cp_write(sd, 0xba, (pdata->hdmi_free_run_mode << 1) | 0x01); /* HDMI free run */ cp_write(sd, 0xf3, 0xdc); /* Low threshold to enter/exit free run mode */ cp_write(sd, 0xf9, 0x23); /* STDI ch. 1 - LCVS change threshold - - ADI recommended setting [REF_01 c. 2.3.3] */ + ADI recommended setting [REF_01, c. 2.3.3] */ cp_write(sd, 0x45, 0x23); /* STDI ch. 2 - LCVS change threshold - - ADI recommended setting [REF_01 c. 2.3.3] */ + ADI recommended setting [REF_01, c. 2.3.3] */ cp_write(sd, 0xc9, 0x2d); /* use prim_mode and vid_std as free run resolution for digital formats */ @@ -1724,11 +1895,6 @@ static int adv7604_core_init(struct v4l2_subdev *sd) afe_write(sd, 0x02, pdata->ain_sel); /* Select analog input muxing mode */ io_write_and_or(sd, 0x30, ~(1 << 4), pdata->output_bus_lsb_to_msb << 4); - state->prim_mode = pdata->prim_mode; - select_input(sd, pdata->prim_mode); - - enable_input(sd, pdata->prim_mode); - /* interrupts */ io_write(sd, 0x40, 0xc2); /* Configure INT1 */ io_write(sd, 0x41, 0xd7); /* STDI irq for any change, disable INT2 */ @@ -1883,6 +2049,7 @@ static int adv7604_probe(struct i2c_client *client, v4l2_err(sd, "failed to create all i2c clients\n"); goto err_i2c; } + state->restart_stdi_once = true; /* work queues */ state->work_queues = create_singlethread_workqueue(client->name); diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index 13057b966ee..333ef178d6f 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c @@ -263,9 +263,14 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) if (ret & 1) /* Autoexposure */ ret = reg_write(client, mt9v022->reg->max_total_shutter_width, rect.height + mt9v022->y_skip_top + 43); - else - ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, - rect.height + mt9v022->y_skip_top + 43); + /* + * If autoexposure is off, there is no need to set + * MT9V022_TOTAL_SHUTTER_WIDTH here. Autoexposure can be off + * only if the user has set exposure manually, using the + * V4L2_CID_EXPOSURE_AUTO with the value V4L2_EXPOSURE_MANUAL. + * In this case the register MT9V022_TOTAL_SHUTTER_WIDTH + * already contains the correct value. + */ } /* Setup frame format: defaults apart from width and height */ if (!ret) diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index bfec9e65aef..19cbb12a12a 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -965,8 +965,10 @@ static struct platform_device_id gsc_driver_ids[] = { MODULE_DEVICE_TABLE(platform, gsc_driver_ids); static const struct of_device_id exynos_gsc_match[] = { - { .compatible = "samsung,exynos5250-gsc", - .data = &gsc_v_100_drvdata, }, + { + .compatible = "samsung,exynos5-gsc", + .data = &gsc_v_100_drvdata, + }, {}, }; MODULE_DEVICE_TABLE(of, exynos_gsc_match); diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index 3c7f00577bd..c065d040ed9 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -657,8 +657,7 @@ static int gsc_m2m_release(struct file *file) pr_debug("pid: %d, state: 0x%lx, refcnt= %d", task_pid_nr(current), gsc->state, gsc->m2m.refcnt); - if (mutex_lock_interruptible(&gsc->lock)) - return -ERESTARTSYS; + mutex_lock(&gsc->lock); v4l2_m2m_ctx_release(ctx->m2m_ctx); gsc_ctrls_delete(ctx); @@ -732,6 +731,7 @@ int gsc_register_m2m_device(struct gsc_dev *gsc) gsc->vdev.ioctl_ops = &gsc_m2m_ioctl_ops; gsc->vdev.release = video_device_release_empty; gsc->vdev.lock = &gsc->lock; + gsc->vdev.vfl_dir = VFL_DIR_M2M; snprintf(gsc->vdev.name, sizeof(gsc->vdev.name), "%s.%d:m2m", GSC_MODULE_NAME, gsc->id); diff --git a/drivers/media/platform/exynos-gsc/gsc-regs.h b/drivers/media/platform/exynos-gsc/gsc-regs.h index 533e9947a92..4678f9a6a4f 100644 --- a/drivers/media/platform/exynos-gsc/gsc-regs.h +++ b/drivers/media/platform/exynos-gsc/gsc-regs.h @@ -40,10 +40,10 @@ #define GSC_IN_ROT_YFLIP (2 << 16) #define GSC_IN_ROT_XFLIP (1 << 16) #define GSC_IN_RGB_TYPE_MASK (3 << 14) -#define GSC_IN_RGB_HD_WIDE (3 << 14) -#define GSC_IN_RGB_HD_NARROW (2 << 14) -#define GSC_IN_RGB_SD_WIDE (1 << 14) -#define GSC_IN_RGB_SD_NARROW (0 << 14) +#define GSC_IN_RGB_HD_NARROW (3 << 14) +#define GSC_IN_RGB_HD_WIDE (2 << 14) +#define GSC_IN_RGB_SD_NARROW (1 << 14) +#define GSC_IN_RGB_SD_WIDE (0 << 14) #define GSC_IN_YUV422_1P_ORDER_MASK (1 << 13) #define GSC_IN_YUV422_1P_ORDER_LSB_Y (0 << 13) #define GSC_IN_YUV422_1P_OEDER_LSB_C (1 << 13) @@ -85,10 +85,10 @@ #define GSC_OUT_GLOBAL_ALPHA_MASK (0xff << 24) #define GSC_OUT_GLOBAL_ALPHA(x) ((x) << 24) #define GSC_OUT_RGB_TYPE_MASK (3 << 10) -#define GSC_OUT_RGB_HD_NARROW (3 << 10) -#define GSC_OUT_RGB_HD_WIDE (2 << 10) -#define GSC_OUT_RGB_SD_NARROW (1 << 10) -#define GSC_OUT_RGB_SD_WIDE (0 << 10) +#define GSC_OUT_RGB_HD_WIDE (3 << 10) +#define GSC_OUT_RGB_HD_NARROW (2 << 10) +#define GSC_OUT_RGB_SD_WIDE (1 << 10) +#define GSC_OUT_RGB_SD_NARROW (0 << 10) #define GSC_OUT_YUV422_1P_ORDER_MASK (1 << 9) #define GSC_OUT_YUV422_1P_ORDER_LSB_Y (0 << 9) #define GSC_OUT_YUV422_1P_OEDER_LSB_C (1 << 9) diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 60181ab9606..aa9df9d71a7 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -1706,7 +1706,7 @@ static long ccdc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) } static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) + struct v4l2_event_subscription *sub) { if (sub->type != V4L2_EVENT_FRAME_SYNC) return -EINVAL; @@ -1719,7 +1719,7 @@ static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, } static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) + struct v4l2_event_subscription *sub) { return v4l2_event_unsubscribe(fh, sub); } diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c index d7ac76b5c2a..b8640be692f 100644 --- a/drivers/media/platform/omap3isp/ispstat.c +++ b/drivers/media/platform/omap3isp/ispstat.c @@ -1025,7 +1025,7 @@ void omap3isp_stat_dma_isr(struct ispstat *stat) int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) + struct v4l2_event_subscription *sub) { struct ispstat *stat = v4l2_get_subdevdata(subdev); @@ -1037,7 +1037,7 @@ int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev, struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) + struct v4l2_event_subscription *sub) { return v4l2_event_unsubscribe(fh, sub); } diff --git a/drivers/media/platform/omap3isp/ispstat.h b/drivers/media/platform/omap3isp/ispstat.h index a6fe653eb23..9b7c8654dc8 100644 --- a/drivers/media/platform/omap3isp/ispstat.h +++ b/drivers/media/platform/omap3isp/ispstat.h @@ -147,10 +147,10 @@ int omap3isp_stat_init(struct ispstat *stat, const char *name, void omap3isp_stat_cleanup(struct ispstat *stat); int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub); + struct v4l2_event_subscription *sub); int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev, struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub); + struct v4l2_event_subscription *sub); int omap3isp_stat_s_stream(struct v4l2_subdev *subdev, int enable); int omap3isp_stat_busy(struct ispstat *stat); diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index a0b737fecf1..75cd309035f 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -792,7 +792,7 @@ isp_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop) } static int -isp_video_set_crop(struct file *file, void *fh, struct v4l2_crop *crop) +isp_video_set_crop(struct file *file, void *fh, const struct v4l2_crop *crop) { struct isp_video *video = video_drvdata(file); struct v4l2_subdev *subdev; diff --git a/drivers/media/platform/s5p-fimc/Kconfig b/drivers/media/platform/s5p-fimc/Kconfig index 8f090a8f270..c16b20d86ed 100644 --- a/drivers/media/platform/s5p-fimc/Kconfig +++ b/drivers/media/platform/s5p-fimc/Kconfig @@ -24,6 +24,7 @@ config VIDEO_S5P_FIMC config VIDEO_S5P_MIPI_CSIS tristate "S5P/EXYNOS MIPI-CSI2 receiver (MIPI-CSIS) driver" depends on REGULATOR + select S5P_SETUP_MIPIPHY help This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC MIPI-CSI2 receiver (MIPI-CSIS) devices. diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c index 367efd164d0..891ee873c62 100644 --- a/drivers/media/platform/s5p-fimc/fimc-capture.c +++ b/drivers/media/platform/s5p-fimc/fimc-capture.c @@ -556,8 +556,7 @@ static int fimc_capture_close(struct file *file) dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; + mutex_lock(&fimc->lock); if (--fimc->vid_cap.refcnt == 0) { clear_bit(ST_CAPT_BUSY, &fimc->state); @@ -1736,7 +1735,9 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, q->mem_ops = &vb2_dma_contig_memops; q->buf_struct_size = sizeof(struct fimc_vid_buffer); - vb2_queue_init(q); + ret = vb2_queue_init(q); + if (ret) + goto err_ent; vid_cap->vd_pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_init(&vfd->entity, 1, &vid_cap->vd_pad, 0); @@ -1772,9 +1773,13 @@ static int fimc_capture_subdev_registered(struct v4l2_subdev *sd) if (ret) return ret; + fimc->pipeline_ops = v4l2_get_subdev_hostdata(sd); + ret = fimc_register_capture_device(fimc, sd->v4l2_dev); - if (ret) + if (ret) { fimc_unregister_m2m_device(fimc); + fimc->pipeline_ops = NULL; + } return ret; } @@ -1791,6 +1796,7 @@ static void fimc_capture_subdev_unregistered(struct v4l2_subdev *sd) if (video_is_registered(&fimc->vid_cap.vfd)) { video_unregister_device(&fimc->vid_cap.vfd); media_entity_cleanup(&fimc->vid_cap.vfd.entity); + fimc->pipeline_ops = NULL; } kfree(fimc->vid_cap.ctx); fimc->vid_cap.ctx = NULL; diff --git a/drivers/media/platform/s5p-fimc/fimc-lite.c b/drivers/media/platform/s5p-fimc/fimc-lite.c index 70bcf39de87..1b309a72f09 100644 --- a/drivers/media/platform/s5p-fimc/fimc-lite.c +++ b/drivers/media/platform/s5p-fimc/fimc-lite.c @@ -491,8 +491,7 @@ static int fimc_lite_close(struct file *file) struct fimc_lite *fimc = video_drvdata(file); int ret; - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; + mutex_lock(&fimc->lock); if (--fimc->ref_count == 0 && fimc->out_path == FIMC_IO_DMA) { clear_bit(ST_FLITE_IN_USE, &fimc->state); @@ -1253,7 +1252,9 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) q->buf_struct_size = sizeof(struct flite_buffer); q->drv_priv = fimc; - vb2_queue_init(q); + ret = vb2_queue_init(q); + if (ret < 0) + return ret; fimc->vd_pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_init(&vfd->entity, 1, &fimc->vd_pad, 0); @@ -1261,10 +1262,12 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) return ret; video_set_drvdata(vfd, fimc); + fimc->pipeline_ops = v4l2_get_subdev_hostdata(sd); ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); if (ret < 0) { media_entity_cleanup(&vfd->entity); + fimc->pipeline_ops = NULL; return ret; } @@ -1283,6 +1286,7 @@ static void fimc_lite_subdev_unregistered(struct v4l2_subdev *sd) if (video_is_registered(&fimc->vfd)) { video_unregister_device(&fimc->vfd); media_entity_cleanup(&fimc->vfd.entity); + fimc->pipeline_ops = NULL; } } diff --git a/drivers/media/platform/s5p-fimc/fimc-m2m.c b/drivers/media/platform/s5p-fimc/fimc-m2m.c index 4500e44f685..62afed3162e 100644 --- a/drivers/media/platform/s5p-fimc/fimc-m2m.c +++ b/drivers/media/platform/s5p-fimc/fimc-m2m.c @@ -718,8 +718,7 @@ static int fimc_m2m_release(struct file *file) dbg("pid: %d, state: 0x%lx, refcnt= %d", task_pid_nr(current), fimc->state, fimc->m2m.refcnt); - if (mutex_lock_interruptible(&fimc->lock)) - return -ERESTARTSYS; + mutex_lock(&fimc->lock); v4l2_m2m_ctx_release(ctx->m2m_ctx); fimc_ctrls_delete(ctx); diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index 80ada5882f6..0531ab70a94 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c @@ -343,53 +343,50 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) static int fimc_register_callback(struct device *dev, void *p) { struct fimc_dev *fimc = dev_get_drvdata(dev); - struct v4l2_subdev *sd = &fimc->vid_cap.subdev; + struct v4l2_subdev *sd; struct fimc_md *fmd = p; - int ret = 0; - - if (!fimc || !fimc->pdev) - return 0; + int ret; - if (fimc->pdev->id < 0 || fimc->pdev->id >= FIMC_MAX_DEVS) + if (fimc == NULL || fimc->id >= FIMC_MAX_DEVS) return 0; - fimc->pipeline_ops = &fimc_pipeline_ops; - fmd->fimc[fimc->pdev->id] = fimc; + sd = &fimc->vid_cap.subdev; sd->grp_id = FIMC_GROUP_ID; + v4l2_set_subdev_hostdata(sd, (void *)&fimc_pipeline_ops); ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); if (ret) { v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC.%d (%d)\n", fimc->id, ret); + return ret; } - return ret; + fmd->fimc[fimc->id] = fimc; + return 0; } static int fimc_lite_register_callback(struct device *dev, void *p) { struct fimc_lite *fimc = dev_get_drvdata(dev); - struct v4l2_subdev *sd = &fimc->subdev; struct fimc_md *fmd = p; int ret; - if (fimc == NULL) + if (fimc == NULL || fimc->index >= FIMC_LITE_MAX_DEVS) return 0; - if (fimc->index >= FIMC_LITE_MAX_DEVS) - return 0; - - fimc->pipeline_ops = &fimc_pipeline_ops; - fmd->fimc_lite[fimc->index] = fimc; - sd->grp_id = FLITE_GROUP_ID; + fimc->subdev.grp_id = FLITE_GROUP_ID; + v4l2_set_subdev_hostdata(&fimc->subdev, (void *)&fimc_pipeline_ops); - ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); + ret = v4l2_device_register_subdev(&fmd->v4l2_dev, &fimc->subdev); if (ret) { v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC-LITE.%d (%d)\n", fimc->index, ret); + return ret; } - return ret; + + fmd->fimc_lite[fimc->index] = fimc; + return 0; } static int csis_register_callback(struct device *dev, void *p) @@ -407,10 +404,12 @@ static int csis_register_callback(struct device *dev, void *p) v4l2_info(sd, "csis%d sd: %s\n", pdev->id, sd->name); id = pdev->id < 0 ? 0 : pdev->id; - fmd->csis[id].sd = sd; sd->grp_id = CSIS_GROUP_ID; + ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd); - if (ret) + if (!ret) + fmd->csis[id].sd = sd; + else v4l2_err(&fmd->v4l2_dev, "Failed to register CSIS subdevice: %d\n", ret); return ret; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 130f4ac8649..3afe879d54d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -381,11 +381,8 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, ctx->consumed_stream += s5p_mfc_hw_call(dev->mfc_ops, get_consumed_stream, dev); if (ctx->codec_mode != S5P_MFC_CODEC_H264_DEC && - s5p_mfc_hw_call(dev->mfc_ops, - get_dec_frame_type, dev) == - S5P_FIMV_DECODE_FRAME_P_FRAME - && ctx->consumed_stream + STUFF_BYTE < - src_buf->b->v4l2_planes[0].bytesused) { + ctx->consumed_stream + STUFF_BYTE < + src_buf->b->v4l2_planes[0].bytesused) { /* Run MFC again on the same buffer */ mfc_debug(2, "Running again the same buffer\n"); ctx->after_packed_pb = 1; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 50b5bee3c44..3a8cfd9fc1b 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -1762,7 +1762,7 @@ int s5p_mfc_get_dspl_y_adr_v6(struct s5p_mfc_dev *dev) int s5p_mfc_get_dec_y_adr_v6(struct s5p_mfc_dev *dev) { - return mfc_read(dev, S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6); + return mfc_read(dev, S5P_FIMV_D_DECODED_LUMA_ADDR_V6); } int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev) diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 85fd312f0a8..a1c87f0ceaa 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -935,9 +935,10 @@ static int sh_vou_g_crop(struct file *file, void *fh, struct v4l2_crop *a) /* Assume a dull encoder, do all the work ourselves. */ static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) { + struct v4l2_crop a_writable = *a; struct video_device *vdev = video_devdata(file); struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - struct v4l2_rect *rect = &a->c; + struct v4l2_rect *rect = &a_writable.c; struct v4l2_crop sd_crop = {.type = V4L2_BUF_TYPE_VIDEO_OUTPUT}; struct v4l2_pix_format *pix = &vou_dev->pix; struct sh_vou_geometry geo; diff --git a/drivers/media/platform/soc_camera/mx1_camera.c b/drivers/media/platform/soc_camera/mx1_camera.c index bbe70991d30..032b8c9097f 100644 --- a/drivers/media/platform/soc_camera/mx1_camera.c +++ b/drivers/media/platform/soc_camera/mx1_camera.c @@ -470,14 +470,6 @@ static void mx1_camera_remove_device(struct soc_camera_device *icd) pcdev->icd = NULL; } -static int mx1_camera_set_crop(struct soc_camera_device *icd, - struct v4l2_crop *a) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - - return v4l2_subdev_call(sd, video, s_crop, a); -} - static int mx1_camera_set_bus_param(struct soc_camera_device *icd) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); @@ -689,7 +681,6 @@ static struct soc_camera_host_ops mx1_soc_camera_host_ops = { .add = mx1_camera_add_device, .remove = mx1_camera_remove_device, .set_bus_param = mx1_camera_set_bus_param, - .set_crop = mx1_camera_set_crop, .set_fmt = mx1_camera_set_fmt, .try_fmt = mx1_camera_try_fmt, .init_videobuf = mx1_camera_init_videobuf, diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index 9fd9d1c5b21..9a55f4c4c7f 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -864,8 +864,10 @@ static int mx2_start_streaming(struct vb2_queue *q, unsigned int count) bytesperline = soc_mbus_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); - if (bytesperline < 0) + if (bytesperline < 0) { + spin_unlock_irqrestore(&pcdev->lock, flags); return bytesperline; + } /* * I didn't manage to properly enable/disable the prp @@ -878,8 +880,10 @@ static int mx2_start_streaming(struct vb2_queue *q, unsigned int count) pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev, pcdev->discard_size, &pcdev->discard_buffer_dma, GFP_KERNEL); - if (!pcdev->discard_buffer) + if (!pcdev->discard_buffer) { + spin_unlock_irqrestore(&pcdev->lock, flags); return -ENOMEM; + } pcdev->buf_discard[0].discard = true; list_add_tail(&pcdev->buf_discard[0].queue, @@ -1099,9 +1103,10 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd) } static int mx2_camera_set_crop(struct soc_camera_device *icd, - struct v4l2_crop *a) + const struct v4l2_crop *a) { - struct v4l2_rect *rect = &a->c; + struct v4l2_crop a_writable = *a; + struct v4l2_rect *rect = &a_writable.c; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct v4l2_mbus_framefmt mf; int ret; diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c index 3557ac97e43..261f6e9e1b1 100644 --- a/drivers/media/platform/soc_camera/mx3_camera.c +++ b/drivers/media/platform/soc_camera/mx3_camera.c @@ -799,9 +799,10 @@ static inline void stride_align(__u32 *width) * default g_crop and cropcap from soc_camera.c */ static int mx3_camera_set_crop(struct soc_camera_device *icd, - struct v4l2_crop *a) + const struct v4l2_crop *a) { - struct v4l2_rect *rect = &a->c; + struct v4l2_crop a_writable = *a; + struct v4l2_rect *rect = &a_writable.c; struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c index fa08c7695cc..13636a58510 100644 --- a/drivers/media/platform/soc_camera/omap1_camera.c +++ b/drivers/media/platform/soc_camera/omap1_camera.c @@ -1215,9 +1215,9 @@ static int set_mbus_format(struct omap1_cam_dev *pcdev, struct device *dev, } static int omap1_cam_set_crop(struct soc_camera_device *icd, - struct v4l2_crop *crop) + const struct v4l2_crop *crop) { - struct v4l2_rect *rect = &crop->c; + const struct v4l2_rect *rect = &crop->c; const struct soc_camera_format_xlate *xlate = icd->current_fmt; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->parent; diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c index 1e3776d08da..3434ffe79c6 100644 --- a/drivers/media/platform/soc_camera/pxa_camera.c +++ b/drivers/media/platform/soc_camera/pxa_camera.c @@ -1337,9 +1337,9 @@ static int pxa_camera_check_frame(u32 width, u32 height) } static int pxa_camera_set_crop(struct soc_camera_device *icd, - struct v4l2_crop *a) + const struct v4l2_crop *a) { - struct v4l2_rect *rect = &a->c; + const struct v4l2_rect *rect = &a->c; struct device *dev = icd->parent; struct soc_camera_host *ici = to_soc_camera_host(dev); struct pxa_camera_dev *pcdev = ici->priv; diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index 0a24253dcda..2d8861c0e8f 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -1182,13 +1182,13 @@ static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd) } /* Check if any dimension of r1 is smaller than respective one of r2 */ -static bool is_smaller(struct v4l2_rect *r1, struct v4l2_rect *r2) +static bool is_smaller(const struct v4l2_rect *r1, const struct v4l2_rect *r2) { return r1->width < r2->width || r1->height < r2->height; } /* Check if r1 fails to cover r2 */ -static bool is_inside(struct v4l2_rect *r1, struct v4l2_rect *r2) +static bool is_inside(const struct v4l2_rect *r1, const struct v4l2_rect *r2) { return r1->left > r2->left || r1->top > r2->top || r1->left + r1->width < r2->left + r2->width || @@ -1263,7 +1263,7 @@ static void update_subrect(struct sh_mobile_ceu_cam *cam) * 3. if (2) failed, try to request the maximum image */ static int client_s_crop(struct soc_camera_device *icd, struct v4l2_crop *crop, - const struct v4l2_crop *cam_crop) + struct v4l2_crop *cam_crop) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct v4l2_rect *rect = &crop->c, *cam_rect = &cam_crop->c; @@ -1519,7 +1519,8 @@ static int client_scale(struct soc_camera_device *icd, static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, const struct v4l2_crop *a) { - struct v4l2_rect *rect = &a->c; + struct v4l2_crop a_writable = *a; + const struct v4l2_rect *rect = &a_writable.c; struct device *dev = icd->parent; struct soc_camera_host *ici = to_soc_camera_host(dev); struct sh_mobile_ceu_dev *pcdev = ici->priv; @@ -1545,7 +1546,7 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, * 1. - 2. Apply iterative camera S_CROP for new input window, read back * actual camera rectangle. */ - ret = client_s_crop(icd, a, &cam_crop); + ret = client_s_crop(icd, &a_writable, &cam_crop); if (ret < 0) return ret; @@ -1946,7 +1947,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, } static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd, - struct v4l2_crop *a) + const struct v4l2_crop *a) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index 9859d2a2449..ba51f65204d 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -283,14 +283,13 @@ static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, /* activate the pid on the device pid filter */ if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER && - adap->pid_filtering && - adap->props->pid_filter) + adap->pid_filtering && adap->props->pid_filter) { ret = adap->props->pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid, (count == 1) ? 1 : 0); - if (ret < 0) - dev_err(&d->udev->dev, "%s: pid_filter() " \ - "failed=%d\n", KBUILD_MODNAME, - ret); + if (ret < 0) + dev_err(&d->udev->dev, "%s: pid_filter() failed=%d\n", + KBUILD_MODNAME, ret); + } /* start feeding if it is first pid */ if (adap->feed_count == 1 && count == 1) { diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c index 0431beed0ef..5716662b483 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c @@ -32,9 +32,7 @@ int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf, return -EINVAL; } - ret = mutex_lock_interruptible(&d->usb_mutex); - if (ret < 0) - return ret; + mutex_lock(&d->usb_mutex); dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, wlen, wbuf); diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index adabba8d28b..093f1acce40 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -1346,6 +1346,10 @@ static const struct usb_device_id rtl28xxu_id_table[] = { &rtl2832u_props, "DigitalNow Quad DVB-T Receiver", NULL) }, { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d3, &rtl2832u_props, "TerraTec Cinergy T Stick RC (Rev. 3)", NULL) }, + { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1102, + &rtl2832u_props, "Dexatek DK mini DVB-T Dongle", NULL) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d7, + &rtl2832u_props, "TerraTec Cinergy T Stick+", NULL) }, { } }; MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table); diff --git a/drivers/memstick/host/Kconfig b/drivers/memstick/host/Kconfig index cc0997a0517..4f7a17fd1aa 100644 --- a/drivers/memstick/host/Kconfig +++ b/drivers/memstick/host/Kconfig @@ -42,3 +42,13 @@ config MEMSTICK_R592 To compile this driver as a module, choose M here: the module will be called r592. + +config MEMSTICK_REALTEK_PCI + tristate "Realtek PCI-E Memstick Card Interface Driver" + depends on MFD_RTSX_PCI + help + Say Y here to include driver code to support Memstick card interface + of Realtek PCI-E card reader + + To compile this driver as a module, choose M here: the module will + be called rtsx_pci_ms. diff --git a/drivers/memstick/host/Makefile b/drivers/memstick/host/Makefile index 31ba8d378e4..af3459d7686 100644 --- a/drivers/memstick/host/Makefile +++ b/drivers/memstick/host/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_MEMSTICK_TIFM_MS) += tifm_ms.o obj-$(CONFIG_MEMSTICK_JMICRON_38X) += jmb38x_ms.o obj-$(CONFIG_MEMSTICK_R592) += r592.o +obj-$(CONFIG_MEMSTICK_REALTEK_PCI) += rtsx_pci_ms.o diff --git a/drivers/memstick/host/rtsx_pci_ms.c b/drivers/memstick/host/rtsx_pci_ms.c new file mode 100644 index 00000000000..f5ddb82dadb --- /dev/null +++ b/drivers/memstick/host/rtsx_pci_ms.c @@ -0,0 +1,641 @@ +/* Realtek PCI-Express Memstick Card Interface driver + * + * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * + * 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, 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, see <http://www.gnu.org/licenses/>. + * + * Author: + * Wei WANG <wei_wang@realsil.com.cn> + * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + */ + +#include <linux/module.h> +#include <linux/highmem.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/memstick.h> +#include <linux/mfd/rtsx_pci.h> +#include <asm/unaligned.h> + +struct realtek_pci_ms { + struct platform_device *pdev; + struct rtsx_pcr *pcr; + struct memstick_host *msh; + struct memstick_request *req; + + struct mutex host_mutex; + struct work_struct handle_req; + + u8 ssc_depth; + unsigned int clock; + unsigned char ifmode; + bool eject; +}; + +static inline struct device *ms_dev(struct realtek_pci_ms *host) +{ + return &(host->pdev->dev); +} + +static inline void ms_clear_error(struct realtek_pci_ms *host) +{ + rtsx_pci_write_register(host->pcr, CARD_STOP, + MS_STOP | MS_CLR_ERR, MS_STOP | MS_CLR_ERR); +} + +#ifdef DEBUG + +static void ms_print_debug_regs(struct realtek_pci_ms *host) +{ + struct rtsx_pcr *pcr = host->pcr; + u16 i; + u8 *ptr; + + /* Print MS host internal registers */ + rtsx_pci_init_cmd(pcr); + for (i = 0xFD40; i <= 0xFD44; i++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0); + for (i = 0xFD52; i <= 0xFD69; i++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0); + rtsx_pci_send_cmd(pcr, 100); + + ptr = rtsx_pci_get_cmd_data(pcr); + for (i = 0xFD40; i <= 0xFD44; i++) + dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); + for (i = 0xFD52; i <= 0xFD69; i++) + dev_dbg(ms_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); +} + +#else + +#define ms_print_debug_regs(host) + +#endif + +static int ms_power_on(struct realtek_pci_ms *host) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SELECT, 0x07, MS_MOD_SEL); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SHARE_MODE, + CARD_SHARE_MASK, CARD_SHARE_48_MS); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, + MS_CLK_EN, MS_CLK_EN); + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + err = rtsx_pci_card_pull_ctl_enable(pcr, RTSX_MS_CARD); + if (err < 0) + return err; + + err = rtsx_pci_card_power_on(pcr, RTSX_MS_CARD); + if (err < 0) + return err; + + /* Wait ms power stable */ + msleep(150); + + err = rtsx_pci_write_register(pcr, CARD_OE, + MS_OUTPUT_EN, MS_OUTPUT_EN); + if (err < 0) + return err; + + return 0; +} + +static int ms_power_off(struct realtek_pci_ms *host) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, MS_CLK_EN, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_OE, MS_OUTPUT_EN, 0); + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + err = rtsx_pci_card_power_off(pcr, RTSX_MS_CARD); + if (err < 0) + return err; + + return rtsx_pci_card_pull_ctl_disable(pcr, RTSX_MS_CARD); +} + +static int ms_transfer_data(struct realtek_pci_ms *host, unsigned char data_dir, + u8 tpc, u8 cfg, struct scatterlist *sg) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + unsigned int length = sg->length; + u16 sec_cnt = (u16)(length / 512); + u8 val, trans_mode, dma_dir; + + dev_dbg(ms_dev(host), "%s: tpc = 0x%02x, data_dir = %s, length = %d\n", + __func__, tpc, (data_dir == READ) ? "READ" : "WRITE", + length); + + if (data_dir == READ) { + dma_dir = DMA_DIR_FROM_CARD; + trans_mode = MS_TM_AUTO_READ; + } else { + dma_dir = DMA_DIR_TO_CARD; + trans_mode = MS_TM_AUTO_WRITE; + } + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_SECTOR_CNT_H, + 0xFF, (u8)(sec_cnt >> 8)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_SECTOR_CNT_L, + 0xFF, (u8)sec_cnt); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0, + DMA_DONE_INT, DMA_DONE_INT); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC3, 0xFF, (u8)(length >> 24)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC2, 0xFF, (u8)(length >> 16)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC1, 0xFF, (u8)(length >> 8)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC0, 0xFF, (u8)length); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL, + 0x03 | DMA_PACK_SIZE_MASK, dma_dir | DMA_EN | DMA_512); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, + 0x01, RING_BUFFER); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANSFER, + 0xFF, MS_TRANSFER_START | trans_mode); + rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, MS_TRANSFER, + MS_TRANSFER_END, MS_TRANSFER_END); + + rtsx_pci_send_cmd_no_wait(pcr); + + err = rtsx_pci_transfer_data(pcr, sg, 1, data_dir == READ, 10000); + if (err < 0) { + ms_clear_error(host); + return err; + } + + rtsx_pci_read_register(pcr, MS_TRANS_CFG, &val); + if (val & (MS_INT_CMDNK | MS_INT_ERR | MS_CRC16_ERR | MS_RDY_TIMEOUT)) + return -EIO; + + return 0; +} + +static int ms_write_bytes(struct realtek_pci_ms *host, u8 tpc, + u8 cfg, u8 cnt, u8 *data, u8 *int_reg) +{ + struct rtsx_pcr *pcr = host->pcr; + int err, i; + + dev_dbg(ms_dev(host), "%s: tpc = 0x%02x\n", __func__, tpc); + + if (!data) + return -EINVAL; + + rtsx_pci_init_cmd(pcr); + + for (i = 0; i < cnt; i++) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + PPBUF_BASE2 + i, 0xFF, data[i]); + if (cnt % 2) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + PPBUF_BASE2 + i, 0xFF, 0xFF); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, + 0x01, PINGPONG_BUFFER); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANSFER, + 0xFF, MS_TRANSFER_START | MS_TM_WRITE_BYTES); + rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, MS_TRANSFER, + MS_TRANSFER_END, MS_TRANSFER_END); + if (int_reg) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, MS_TRANS_CFG, 0, 0); + + err = rtsx_pci_send_cmd(pcr, 5000); + if (err < 0) { + u8 val; + + rtsx_pci_read_register(pcr, MS_TRANS_CFG, &val); + dev_dbg(ms_dev(host), "MS_TRANS_CFG: 0x%02x\n", val); + + if (int_reg) + *int_reg = val & 0x0F; + + ms_print_debug_regs(host); + + ms_clear_error(host); + + if (!(tpc & 0x08)) { + if (val & MS_CRC16_ERR) + return -EIO; + } else { + if (!(val & 0x80)) { + if (val & (MS_INT_ERR | MS_INT_CMDNK)) + return -EIO; + } + } + + return -ETIMEDOUT; + } + + if (int_reg) { + u8 *ptr = rtsx_pci_get_cmd_data(pcr) + 1; + *int_reg = *ptr & 0x0F; + } + + return 0; +} + +static int ms_read_bytes(struct realtek_pci_ms *host, u8 tpc, + u8 cfg, u8 cnt, u8 *data, u8 *int_reg) +{ + struct rtsx_pcr *pcr = host->pcr; + int err, i; + u8 *ptr; + + dev_dbg(ms_dev(host), "%s: tpc = 0x%02x\n", __func__, tpc); + + if (!data) + return -EINVAL; + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANS_CFG, 0xFF, cfg); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, + 0x01, PINGPONG_BUFFER); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, MS_TRANSFER, + 0xFF, MS_TRANSFER_START | MS_TM_READ_BYTES); + rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, MS_TRANSFER, + MS_TRANSFER_END, MS_TRANSFER_END); + for (i = 0; i < cnt - 1; i++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0); + if (cnt % 2) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, PPBUF_BASE2 + cnt, 0, 0); + else + rtsx_pci_add_cmd(pcr, READ_REG_CMD, + PPBUF_BASE2 + cnt - 1, 0, 0); + if (int_reg) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, MS_TRANS_CFG, 0, 0); + + err = rtsx_pci_send_cmd(pcr, 5000); + if (err < 0) { + u8 val; + + rtsx_pci_read_register(pcr, MS_TRANS_CFG, &val); + dev_dbg(ms_dev(host), "MS_TRANS_CFG: 0x%02x\n", val); + + if (int_reg) + *int_reg = val & 0x0F; + + ms_print_debug_regs(host); + + ms_clear_error(host); + + if (!(tpc & 0x08)) { + if (val & MS_CRC16_ERR) + return -EIO; + } else { + if (!(val & 0x80)) { + if (val & (MS_INT_ERR | MS_INT_CMDNK)) + return -EIO; + } + } + + return -ETIMEDOUT; + } + + ptr = rtsx_pci_get_cmd_data(pcr) + 1; + for (i = 0; i < cnt; i++) + data[i] = *ptr++; + + if (int_reg) + *int_reg = *ptr & 0x0F; + + return 0; +} + +static int rtsx_pci_ms_issue_cmd(struct realtek_pci_ms *host) +{ + struct memstick_request *req = host->req; + int err = 0; + u8 cfg = 0, int_reg; + + dev_dbg(ms_dev(host), "%s\n", __func__); + + if (req->need_card_int) { + if (host->ifmode != MEMSTICK_SERIAL) + cfg = WAIT_INT; + } + + if (req->long_data) { + err = ms_transfer_data(host, req->data_dir, + req->tpc, cfg, &(req->sg)); + } else { + if (req->data_dir == READ) { + err = ms_read_bytes(host, req->tpc, cfg, + req->data_len, req->data, &int_reg); + } else { + err = ms_write_bytes(host, req->tpc, cfg, + req->data_len, req->data, &int_reg); + } + } + if (err < 0) + return err; + + if (req->need_card_int && (host->ifmode == MEMSTICK_SERIAL)) { + err = ms_read_bytes(host, MS_TPC_GET_INT, + NO_WAIT_INT, 1, &int_reg, NULL); + if (err < 0) + return err; + } + + if (req->need_card_int) { + dev_dbg(ms_dev(host), "int_reg: 0x%02x\n", int_reg); + + if (int_reg & MS_INT_CMDNK) + req->int_reg |= MEMSTICK_INT_CMDNAK; + if (int_reg & MS_INT_BREQ) + req->int_reg |= MEMSTICK_INT_BREQ; + if (int_reg & MS_INT_ERR) + req->int_reg |= MEMSTICK_INT_ERR; + if (int_reg & MS_INT_CED) + req->int_reg |= MEMSTICK_INT_CED; + } + + return 0; +} + +static void rtsx_pci_ms_handle_req(struct work_struct *work) +{ + struct realtek_pci_ms *host = container_of(work, + struct realtek_pci_ms, handle_req); + struct rtsx_pcr *pcr = host->pcr; + struct memstick_host *msh = host->msh; + int rc; + + mutex_lock(&pcr->pcr_mutex); + + rtsx_pci_start_run(pcr); + + rtsx_pci_switch_clock(host->pcr, host->clock, host->ssc_depth, + false, true, false); + rtsx_pci_write_register(pcr, CARD_SELECT, 0x07, MS_MOD_SEL); + rtsx_pci_write_register(pcr, CARD_SHARE_MODE, + CARD_SHARE_MASK, CARD_SHARE_48_MS); + + if (!host->req) { + do { + rc = memstick_next_req(msh, &host->req); + dev_dbg(ms_dev(host), "next req %d\n", rc); + + if (!rc) + host->req->error = rtsx_pci_ms_issue_cmd(host); + } while (!rc); + } + + mutex_unlock(&pcr->pcr_mutex); +} + +static void rtsx_pci_ms_request(struct memstick_host *msh) +{ + struct realtek_pci_ms *host = memstick_priv(msh); + + dev_dbg(ms_dev(host), "--> %s\n", __func__); + + schedule_work(&host->handle_req); +} + +static int rtsx_pci_ms_set_param(struct memstick_host *msh, + enum memstick_param param, int value) +{ + struct realtek_pci_ms *host = memstick_priv(msh); + struct rtsx_pcr *pcr = host->pcr; + unsigned int clock = 0; + u8 ssc_depth = 0; + int err; + + dev_dbg(ms_dev(host), "%s: param = %d, value = %d\n", + __func__, param, value); + + switch (param) { + case MEMSTICK_POWER: + if (value == MEMSTICK_POWER_ON) + err = ms_power_on(host); + else if (value == MEMSTICK_POWER_OFF) + err = ms_power_off(host); + else + return -EINVAL; + break; + + case MEMSTICK_INTERFACE: + if (value == MEMSTICK_SERIAL) { + clock = 19000000; + ssc_depth = RTSX_SSC_DEPTH_500K; + + err = rtsx_pci_write_register(pcr, MS_CFG, + 0x18, MS_BUS_WIDTH_1); + if (err < 0) + return err; + } else if (value == MEMSTICK_PAR4) { + clock = 39000000; + ssc_depth = RTSX_SSC_DEPTH_1M; + + err = rtsx_pci_write_register(pcr, MS_CFG, + 0x58, MS_BUS_WIDTH_4 | PUSH_TIME_ODD); + if (err < 0) + return err; + } else { + return -EINVAL; + } + + err = rtsx_pci_switch_clock(pcr, clock, + ssc_depth, false, true, false); + if (err < 0) + return err; + + host->ssc_depth = ssc_depth; + host->clock = clock; + host->ifmode = value; + break; + } + + return 0; +} + +#ifdef CONFIG_PM + +static int rtsx_pci_ms_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct realtek_pci_ms *host = platform_get_drvdata(pdev); + struct memstick_host *msh = host->msh; + + dev_dbg(ms_dev(host), "--> %s\n", __func__); + + memstick_suspend_host(msh); + return 0; +} + +static int rtsx_pci_ms_resume(struct platform_device *pdev) +{ + struct realtek_pci_ms *host = platform_get_drvdata(pdev); + struct memstick_host *msh = host->msh; + + dev_dbg(ms_dev(host), "--> %s\n", __func__); + + memstick_resume_host(msh); + return 0; +} + +#else /* CONFIG_PM */ + +#define rtsx_pci_ms_suspend NULL +#define rtsx_pci_ms_resume NULL + +#endif /* CONFIG_PM */ + +static void rtsx_pci_ms_card_event(struct platform_device *pdev) +{ + struct realtek_pci_ms *host = platform_get_drvdata(pdev); + + memstick_detect_change(host->msh); +} + +static int rtsx_pci_ms_drv_probe(struct platform_device *pdev) +{ + struct memstick_host *msh; + struct realtek_pci_ms *host; + struct rtsx_pcr *pcr; + struct pcr_handle *handle = pdev->dev.platform_data; + int rc; + + if (!handle) + return -ENXIO; + + pcr = handle->pcr; + if (!pcr) + return -ENXIO; + + dev_dbg(&(pdev->dev), + ": Realtek PCI-E Memstick controller found\n"); + + msh = memstick_alloc_host(sizeof(*host), &pdev->dev); + if (!msh) + return -ENOMEM; + + host = memstick_priv(msh); + host->pcr = pcr; + host->msh = msh; + host->pdev = pdev; + platform_set_drvdata(pdev, host); + pcr->slots[RTSX_MS_CARD].p_dev = pdev; + pcr->slots[RTSX_MS_CARD].card_event = rtsx_pci_ms_card_event; + + mutex_init(&host->host_mutex); + + INIT_WORK(&host->handle_req, rtsx_pci_ms_handle_req); + msh->request = rtsx_pci_ms_request; + msh->set_param = rtsx_pci_ms_set_param; + msh->caps = MEMSTICK_CAP_PAR4; + + rc = memstick_add_host(msh); + if (rc) { + memstick_free_host(msh); + return rc; + } + + return 0; +} + +static int rtsx_pci_ms_drv_remove(struct platform_device *pdev) +{ + struct realtek_pci_ms *host = platform_get_drvdata(pdev); + struct rtsx_pcr *pcr; + struct memstick_host *msh; + int rc; + + if (!host) + return 0; + + pcr = host->pcr; + pcr->slots[RTSX_MS_CARD].p_dev = NULL; + pcr->slots[RTSX_MS_CARD].card_event = NULL; + msh = host->msh; + host->eject = true; + + mutex_lock(&host->host_mutex); + if (host->req) { + dev_dbg(&(pdev->dev), + "%s: Controller removed during transfer\n", + dev_name(&msh->dev)); + + rtsx_pci_complete_unfinished_transfer(pcr); + + host->req->error = -ENOMEDIUM; + do { + rc = memstick_next_req(msh, &host->req); + if (!rc) + host->req->error = -ENOMEDIUM; + } while (!rc); + } + mutex_unlock(&host->host_mutex); + + memstick_remove_host(msh); + memstick_free_host(msh); + + platform_set_drvdata(pdev, NULL); + + dev_dbg(&(pdev->dev), + ": Realtek PCI-E Memstick controller has been removed\n"); + + return 0; +} + +static struct platform_device_id rtsx_pci_ms_ids[] = { + { + .name = DRV_NAME_RTSX_PCI_MS, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, rtsx_pci_ms_ids); + +static struct platform_driver rtsx_pci_ms_driver = { + .probe = rtsx_pci_ms_drv_probe, + .remove = rtsx_pci_ms_drv_remove, + .id_table = rtsx_pci_ms_ids, + .suspend = rtsx_pci_ms_suspend, + .resume = rtsx_pci_ms_resume, + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME_RTSX_PCI_MS, + }, +}; +module_platform_driver(rtsx_pci_ms_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Wei WANG <wei_wang@realsil.com.cn>"); +MODULE_DESCRIPTION("Realtek PCI-E Memstick Card Host Driver"); diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c index ce229ea933d..391e23e6a64 100644 --- a/drivers/mfd/88pm800.c +++ b/drivers/mfd/88pm800.c @@ -248,7 +248,7 @@ static const struct regmap_irq pm800_irqs[] = { }, }; -static int __devinit device_gpadc_init(struct pm80x_chip *chip, +static int device_gpadc_init(struct pm80x_chip *chip, struct pm80x_platform_data *pdata) { struct pm80x_subchip *subchip = chip->subchip; @@ -315,7 +315,7 @@ out: return ret; } -static int __devinit device_irq_init_800(struct pm80x_chip *chip) +static int device_irq_init_800(struct pm80x_chip *chip) { struct regmap *map = chip->regmap; unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; @@ -415,7 +415,7 @@ static void pm800_pages_exit(struct pm80x_chip *chip) } } -static int __devinit device_800_init(struct pm80x_chip *chip, +static int device_800_init(struct pm80x_chip *chip, struct pm80x_platform_data *pdata) { int ret, pmic_id; @@ -499,7 +499,7 @@ out: return ret; } -static int __devinit pm800_probe(struct i2c_client *client, +static int pm800_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = 0; @@ -554,7 +554,7 @@ out_init: return ret; } -static int __devexit pm800_remove(struct i2c_client *client) +static int pm800_remove(struct i2c_client *client) { struct pm80x_chip *chip = i2c_get_clientdata(client); @@ -576,7 +576,7 @@ static struct i2c_driver pm800_driver = { .pm = &pm80x_pm_ops, }, .probe = pm800_probe, - .remove = __devexit_p(pm800_remove), + .remove = pm800_remove, .id_table = pm80x_id_table, }; diff --git a/drivers/mfd/88pm805.c b/drivers/mfd/88pm805.c index c20a31136f0..e671230be2b 100644 --- a/drivers/mfd/88pm805.c +++ b/drivers/mfd/88pm805.c @@ -135,7 +135,7 @@ static struct regmap_irq pm805_irqs[] = { }, }; -static int __devinit device_irq_init_805(struct pm80x_chip *chip) +static int device_irq_init_805(struct pm80x_chip *chip) { struct regmap *map = chip->regmap; unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; @@ -189,7 +189,7 @@ static struct regmap_irq_chip pm805_irq_chip = { .ack_base = PM805_INT_STATUS1, }; -static int __devinit device_805_init(struct pm80x_chip *chip) +static int device_805_init(struct pm80x_chip *chip) { int ret = 0; unsigned int val; @@ -232,7 +232,7 @@ out_irq_init: return ret; } -static int __devinit pm805_probe(struct i2c_client *client, +static int pm805_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = 0; @@ -262,7 +262,7 @@ out_init: return ret; } -static int __devexit pm805_remove(struct i2c_client *client) +static int pm805_remove(struct i2c_client *client) { struct pm80x_chip *chip = i2c_get_clientdata(client); @@ -281,7 +281,7 @@ static struct i2c_driver pm805_driver = { .pm = &pm80x_pm_ops, }, .probe = pm805_probe, - .remove = __devexit_p(pm805_remove), + .remove = pm805_remove, .id_table = pm80x_id_table, }; diff --git a/drivers/mfd/88pm80x.c b/drivers/mfd/88pm80x.c index cd0bf527d76..1adb355d86d 100644 --- a/drivers/mfd/88pm80x.c +++ b/drivers/mfd/88pm80x.c @@ -31,7 +31,7 @@ const struct regmap_config pm80x_regmap_config = { }; EXPORT_SYMBOL_GPL(pm80x_regmap_config); -int __devinit pm80x_init(struct i2c_client *client, +int pm80x_init(struct i2c_client *client, const struct i2c_device_id *id) { struct pm80x_chip *chip; diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 8fa86edf70d..893fc1ba6ea 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -28,111 +28,111 @@ #define INT_STATUS_NUM 3 -static struct resource bk0_resources[] __devinitdata = { +static struct resource bk0_resources[] = { {2, 2, "duty cycle", IORESOURCE_REG, }, {3, 3, "always on", IORESOURCE_REG, }, {3, 3, "current", IORESOURCE_REG, }, }; -static struct resource bk1_resources[] __devinitdata = { +static struct resource bk1_resources[] = { {4, 4, "duty cycle", IORESOURCE_REG, }, {5, 5, "always on", IORESOURCE_REG, }, {5, 5, "current", IORESOURCE_REG, }, }; -static struct resource bk2_resources[] __devinitdata = { +static struct resource bk2_resources[] = { {6, 6, "duty cycle", IORESOURCE_REG, }, {7, 7, "always on", IORESOURCE_REG, }, {5, 5, "current", IORESOURCE_REG, }, }; -static struct resource led0_resources[] __devinitdata = { +static struct resource led0_resources[] = { /* RGB1 Red LED */ {0xd, 0xd, "control", IORESOURCE_REG, }, {0xc, 0xc, "blink", IORESOURCE_REG, }, }; -static struct resource led1_resources[] __devinitdata = { +static struct resource led1_resources[] = { /* RGB1 Green LED */ {0xe, 0xe, "control", IORESOURCE_REG, }, {0xc, 0xc, "blink", IORESOURCE_REG, }, }; -static struct resource led2_resources[] __devinitdata = { +static struct resource led2_resources[] = { /* RGB1 Blue LED */ {0xf, 0xf, "control", IORESOURCE_REG, }, {0xc, 0xc, "blink", IORESOURCE_REG, }, }; -static struct resource led3_resources[] __devinitdata = { +static struct resource led3_resources[] = { /* RGB2 Red LED */ {0x9, 0x9, "control", IORESOURCE_REG, }, {0x8, 0x8, "blink", IORESOURCE_REG, }, }; -static struct resource led4_resources[] __devinitdata = { +static struct resource led4_resources[] = { /* RGB2 Green LED */ {0xa, 0xa, "control", IORESOURCE_REG, }, {0x8, 0x8, "blink", IORESOURCE_REG, }, }; -static struct resource led5_resources[] __devinitdata = { +static struct resource led5_resources[] = { /* RGB2 Blue LED */ {0xb, 0xb, "control", IORESOURCE_REG, }, {0x8, 0x8, "blink", IORESOURCE_REG, }, }; -static struct resource buck1_resources[] __devinitdata = { +static struct resource buck1_resources[] = { {0x24, 0x24, "buck set", IORESOURCE_REG, }, }; -static struct resource buck2_resources[] __devinitdata = { +static struct resource buck2_resources[] = { {0x25, 0x25, "buck set", IORESOURCE_REG, }, }; -static struct resource buck3_resources[] __devinitdata = { +static struct resource buck3_resources[] = { {0x26, 0x26, "buck set", IORESOURCE_REG, }, }; -static struct resource ldo1_resources[] __devinitdata = { +static struct resource ldo1_resources[] = { {0x10, 0x10, "ldo set", IORESOURCE_REG, }, }; -static struct resource ldo2_resources[] __devinitdata = { +static struct resource ldo2_resources[] = { {0x11, 0x11, "ldo set", IORESOURCE_REG, }, }; -static struct resource ldo3_resources[] __devinitdata = { +static struct resource ldo3_resources[] = { {0x12, 0x12, "ldo set", IORESOURCE_REG, }, }; -static struct resource ldo4_resources[] __devinitdata = { +static struct resource ldo4_resources[] = { {0x13, 0x13, "ldo set", IORESOURCE_REG, }, }; -static struct resource ldo5_resources[] __devinitdata = { +static struct resource ldo5_resources[] = { {0x14, 0x14, "ldo set", IORESOURCE_REG, }, }; -static struct resource ldo6_resources[] __devinitdata = { +static struct resource ldo6_resources[] = { {0x15, 0x15, "ldo set", IORESOURCE_REG, }, }; -static struct resource ldo7_resources[] __devinitdata = { +static struct resource ldo7_resources[] = { {0x16, 0x16, "ldo set", IORESOURCE_REG, }, }; -static struct resource ldo8_resources[] __devinitdata = { +static struct resource ldo8_resources[] = { {0x17, 0x17, "ldo set", IORESOURCE_REG, }, }; -static struct resource ldo9_resources[] __devinitdata = { +static struct resource ldo9_resources[] = { {0x18, 0x18, "ldo set", IORESOURCE_REG, }, }; -static struct resource ldo10_resources[] __devinitdata = { +static struct resource ldo10_resources[] = { {0x19, 0x19, "ldo set", IORESOURCE_REG, }, }; -static struct resource ldo12_resources[] __devinitdata = { +static struct resource ldo12_resources[] = { {0x1a, 0x1a, "ldo set", IORESOURCE_REG, }, }; -static struct resource ldo_vibrator_resources[] __devinitdata = { +static struct resource ldo_vibrator_resources[] = { {0x28, 0x28, "ldo set", IORESOURCE_REG, }, }; -static struct resource ldo14_resources[] __devinitdata = { +static struct resource ldo14_resources[] = { {0x1b, 0x1b, "ldo set", IORESOURCE_REG, }, }; -static struct resource touch_resources[] __devinitdata = { +static struct resource touch_resources[] = { {PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,}, }; -static struct resource onkey_resources[] __devinitdata = { +static struct resource onkey_resources[] = { {PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,}, }; -static struct resource codec_resources[] __devinitdata = { +static struct resource codec_resources[] = { /* Headset microphone insertion or removal */ {PM8607_IRQ_MICIN, PM8607_IRQ_MICIN, "micin", IORESOURCE_IRQ,}, /* Hook-switch press or release */ @@ -143,12 +143,12 @@ static struct resource codec_resources[] __devinitdata = { {PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,}, }; -static struct resource battery_resources[] __devinitdata = { +static struct resource battery_resources[] = { {PM8607_IRQ_CC, PM8607_IRQ_CC, "columb counter", IORESOURCE_IRQ,}, {PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery", IORESOURCE_IRQ,}, }; -static struct resource charger_resources[] __devinitdata = { +static struct resource charger_resources[] = { {PM8607_IRQ_CHG, PM8607_IRQ_CHG, "charger detect", IORESOURCE_IRQ,}, {PM8607_IRQ_CHG_DONE, PM8607_IRQ_CHG_DONE, "charging done", IORESOURCE_IRQ,}, {PM8607_IRQ_CHG_FAIL, PM8607_IRQ_CHG_FAIL, "charging timeout", IORESOURCE_IRQ,}, @@ -158,11 +158,11 @@ static struct resource charger_resources[] __devinitdata = { {PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage", IORESOURCE_IRQ,}, }; -static struct resource rtc_resources[] __devinitdata = { +static struct resource rtc_resources[] = { {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,}, }; -static struct mfd_cell bk_devs[] __devinitdata = { +static struct mfd_cell bk_devs[] = { { .name = "88pm860x-backlight", .id = 0, @@ -181,7 +181,7 @@ static struct mfd_cell bk_devs[] __devinitdata = { }, }; -static struct mfd_cell led_devs[] __devinitdata = { +static struct mfd_cell led_devs[] = { { .name = "88pm860x-led", .id = 0, @@ -215,7 +215,7 @@ static struct mfd_cell led_devs[] __devinitdata = { }, }; -static struct mfd_cell reg_devs[] __devinitdata = { +static struct mfd_cell reg_devs[] = { { .name = "88pm860x-regulator", .id = 0, @@ -565,7 +565,7 @@ static struct irq_domain_ops pm860x_irq_domain_ops = { .xlate = irq_domain_xlate_onetwocell, }; -static int __devinit device_irq_init(struct pm860x_chip *chip, +static int device_irq_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ @@ -730,7 +730,7 @@ out: } EXPORT_SYMBOL(pm8606_osc_disable); -static void __devinit device_osc_init(struct i2c_client *i2c) +static void device_osc_init(struct i2c_client *i2c) { struct pm860x_chip *chip = i2c_get_clientdata(i2c); @@ -745,7 +745,7 @@ static void __devinit device_osc_init(struct i2c_client *i2c) chip->osc_status = PM8606_REF_GP_OSC_OFF; } -static void __devinit device_bk_init(struct pm860x_chip *chip, +static void device_bk_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { int ret, i; @@ -765,7 +765,7 @@ static void __devinit device_bk_init(struct pm860x_chip *chip, dev_err(chip->dev, "Failed to add backlight subdev\n"); } -static void __devinit device_led_init(struct pm860x_chip *chip, +static void device_led_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { int ret, i; @@ -787,7 +787,7 @@ static void __devinit device_led_init(struct pm860x_chip *chip, } } -static void __devinit device_regulator_init(struct pm860x_chip *chip, +static void device_regulator_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { int ret; @@ -866,7 +866,7 @@ static void __devinit device_regulator_init(struct pm860x_chip *chip, } } -static void __devinit device_rtc_init(struct pm860x_chip *chip, +static void device_rtc_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { int ret; @@ -885,7 +885,7 @@ static void __devinit device_rtc_init(struct pm860x_chip *chip, dev_err(chip->dev, "Failed to add rtc subdev\n"); } -static void __devinit device_touch_init(struct pm860x_chip *chip, +static void device_touch_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { int ret; @@ -904,7 +904,7 @@ static void __devinit device_touch_init(struct pm860x_chip *chip, dev_err(chip->dev, "Failed to add touch subdev\n"); } -static void __devinit device_power_init(struct pm860x_chip *chip, +static void device_power_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { int ret; @@ -951,7 +951,7 @@ static void __devinit device_power_init(struct pm860x_chip *chip, } } -static void __devinit device_onkey_init(struct pm860x_chip *chip, +static void device_onkey_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { int ret; @@ -965,7 +965,7 @@ static void __devinit device_onkey_init(struct pm860x_chip *chip, dev_err(chip->dev, "Failed to add onkey subdev\n"); } -static void __devinit device_codec_init(struct pm860x_chip *chip, +static void device_codec_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { int ret; @@ -979,7 +979,7 @@ static void __devinit device_codec_init(struct pm860x_chip *chip, dev_err(chip->dev, "Failed to add codec subdev\n"); } -static void __devinit device_8607_init(struct pm860x_chip *chip, +static void device_8607_init(struct pm860x_chip *chip, struct i2c_client *i2c, struct pm860x_platform_data *pdata) { @@ -1040,7 +1040,7 @@ out: return; } -static void __devinit device_8606_init(struct pm860x_chip *chip, +static void device_8606_init(struct pm860x_chip *chip, struct i2c_client *i2c, struct pm860x_platform_data *pdata) { @@ -1049,7 +1049,7 @@ static void __devinit device_8606_init(struct pm860x_chip *chip, device_led_init(chip, pdata); } -static int __devinit pm860x_device_init(struct pm860x_chip *chip, +static int pm860x_device_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { chip->core_irq = 0; @@ -1077,7 +1077,7 @@ static int __devinit pm860x_device_init(struct pm860x_chip *chip, return 0; } -static void __devexit pm860x_device_exit(struct pm860x_chip *chip) +static void pm860x_device_exit(struct pm860x_chip *chip) { device_irq_exit(chip); mfd_remove_devices(chip->dev); @@ -1109,7 +1109,7 @@ static struct regmap_config pm860x_regmap_config = { .val_bits = 8, }; -static int __devinit pm860x_dt_init(struct device_node *np, +static int pm860x_dt_init(struct device_node *np, struct device *dev, struct pm860x_platform_data *pdata) { @@ -1127,7 +1127,7 @@ static int __devinit pm860x_dt_init(struct device_node *np, return 0; } -static int __devinit pm860x_probe(struct i2c_client *client, +static int pm860x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct pm860x_platform_data *pdata = client->dev.platform_data; @@ -1200,7 +1200,7 @@ err: return ret; } -static int __devexit pm860x_remove(struct i2c_client *client) +static int pm860x_remove(struct i2c_client *client) { struct pm860x_chip *chip = i2c_get_clientdata(client); @@ -1258,7 +1258,7 @@ static struct i2c_driver pm860x_driver = { .of_match_table = of_match_ptr(pm860x_dt_ids), }, .probe = pm860x_probe, - .remove = __devexit_p(pm860x_remove), + .remove = pm860x_remove, .id_table = pm860x_id_table, }; diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index acab3ef8a31..2c10938b356 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -63,6 +63,16 @@ config MFD_SM501_GPIO lines on the SM501. The platform data is used to supply the base number for the first GPIO line to register. +config MFD_RTSX_PCI + tristate "Support for Realtek PCI-E card reader" + depends on PCI + select MFD_CORE + help + This supports for Realtek PCI-Express card reader including rts5209, + rts5229, rtl8411, etc. Realtek card reader supports access to many + types of memory cards, such as Memory Stick, Memory Stick Pro, + Secure Digital and MultiMediaCard. + config MFD_ASIC3 bool "Support for Compaq ASIC3" depends on GENERIC_HARDIRQS && GPIOLIB && ARM diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index d8ccb630ddb..b53db06d1b4 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -9,6 +9,9 @@ obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o obj-$(CONFIG_MFD_SM501) += sm501.o obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o +rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o +obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o + obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 2b3dde571a5..2ec7725f4a0 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -661,8 +661,7 @@ struct ab3100_init_setting { u8 setting; }; -static const struct ab3100_init_setting __devinitconst -ab3100_init_settings[] = { +static const struct ab3100_init_setting ab3100_init_settings[] = { { .abreg = AB3100_MCA, .setting = 0x01 @@ -708,7 +707,7 @@ ab3100_init_settings[] = { }, }; -static int __devinit ab3100_setup(struct ab3100 *ab3100) +static int ab3100_setup(struct ab3100 *ab3100) { int err = 0; int i; @@ -803,7 +802,7 @@ struct ab_family_id { char *name; }; -static const struct ab_family_id ids[] __devinitconst = { +static const struct ab_family_id ids[] = { /* AB3100 */ { .id = 0xc0, @@ -857,7 +856,7 @@ static const struct ab_family_id ids[] __devinitconst = { }, }; -static int __devinit ab3100_probe(struct i2c_client *client, +static int ab3100_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct ab3100 *ab3100; @@ -962,7 +961,7 @@ static int __devinit ab3100_probe(struct i2c_client *client, return err; } -static int __devexit ab3100_remove(struct i2c_client *client) +static int ab3100_remove(struct i2c_client *client) { struct ab3100 *ab3100 = i2c_get_clientdata(client); @@ -986,7 +985,7 @@ static struct i2c_driver ab3100_driver = { }, .id_table = ab3100_id, .probe = ab3100_probe, - .remove = __devexit_p(ab3100_remove), + .remove = ab3100_remove, }; static int __init ab3100_i2c_init(void) diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 1667c77b5cd..127b00aadae 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -623,7 +623,7 @@ static struct resource __devinitdata ab9540_gpio_resources[] = { } }; -static struct resource __devinitdata ab8500_gpadc_resources[] = { +static struct resource ab8500_gpadc_resources[] = { { .name = "HW_CONV_END", .start = AB8500_INT_GP_HW_ADC_CONV_END, @@ -638,7 +638,7 @@ static struct resource __devinitdata ab8500_gpadc_resources[] = { }, }; -static struct resource __devinitdata ab8500_rtc_resources[] = { +static struct resource ab8500_rtc_resources[] = { { .name = "60S", .start = AB8500_INT_RTC_60S, @@ -653,7 +653,7 @@ static struct resource __devinitdata ab8500_rtc_resources[] = { }, }; -static struct resource __devinitdata ab8500_poweronkey_db_resources[] = { +static struct resource ab8500_poweronkey_db_resources[] = { { .name = "ONKEY_DBF", .start = AB8500_INT_PON_KEY1DB_F, @@ -668,7 +668,7 @@ static struct resource __devinitdata ab8500_poweronkey_db_resources[] = { }, }; -static struct resource __devinitdata ab8500_av_acc_detect_resources[] = { +static struct resource ab8500_av_acc_detect_resources[] = { { .name = "ACC_DETECT_1DB_F", .start = AB8500_INT_ACC_DETECT_1DB_F, @@ -707,7 +707,7 @@ static struct resource __devinitdata ab8500_av_acc_detect_resources[] = { }, }; -static struct resource __devinitdata ab8500_charger_resources[] = { +static struct resource ab8500_charger_resources[] = { { .name = "MAIN_CH_UNPLUG_DET", .start = AB8500_INT_MAIN_CH_UNPLUG_DET, @@ -788,7 +788,7 @@ static struct resource __devinitdata ab8500_charger_resources[] = { }, }; -static struct resource __devinitdata ab8500_btemp_resources[] = { +static struct resource ab8500_btemp_resources[] = { { .name = "BAT_CTRL_INDB", .start = AB8500_INT_BAT_CTRL_INDB, @@ -821,7 +821,7 @@ static struct resource __devinitdata ab8500_btemp_resources[] = { }, }; -static struct resource __devinitdata ab8500_fg_resources[] = { +static struct resource ab8500_fg_resources[] = { { .name = "NCONV_ACCU", .start = AB8500_INT_CCN_CONV_ACC, @@ -860,10 +860,10 @@ static struct resource __devinitdata ab8500_fg_resources[] = { }, }; -static struct resource __devinitdata ab8500_chargalg_resources[] = {}; +static struct resource ab8500_chargalg_resources[] = {}; #ifdef CONFIG_DEBUG_FS -static struct resource __devinitdata ab8500_debug_resources[] = { +static struct resource ab8500_debug_resources[] = { { .name = "IRQ_FIRST", .start = AB8500_INT_MAIN_EXT_CH_NOT_OK, @@ -879,7 +879,7 @@ static struct resource __devinitdata ab8500_debug_resources[] = { }; #endif -static struct resource __devinitdata ab8500_usb_resources[] = { +static struct resource ab8500_usb_resources[] = { { .name = "ID_WAKEUP_R", .start = AB8500_INT_ID_WAKEUP_R, @@ -924,7 +924,7 @@ static struct resource __devinitdata ab8500_usb_resources[] = { }, }; -static struct resource __devinitdata ab8505_iddet_resources[] = { +static struct resource ab8505_iddet_resources[] = { { .name = "KeyDeglitch", .start = AB8505_INT_KEYDEGLITCH, @@ -957,7 +957,7 @@ static struct resource __devinitdata ab8505_iddet_resources[] = { }, }; -static struct resource __devinitdata ab8500_temp_resources[] = { +static struct resource ab8500_temp_resources[] = { { .name = "AB8500_TEMP_WARM", .start = AB8500_INT_TEMP_WARM, @@ -966,7 +966,7 @@ static struct resource __devinitdata ab8500_temp_resources[] = { }, }; -static struct mfd_cell __devinitdata abx500_common_devs[] = { +static struct mfd_cell abx500_common_devs[] = { #ifdef CONFIG_DEBUG_FS { .name = "ab8500-debug", @@ -1038,7 +1038,7 @@ static struct mfd_cell __devinitdata abx500_common_devs[] = { }, }; -static struct mfd_cell __devinitdata ab8500_bm_devs[] = { +static struct mfd_cell ab8500_bm_devs[] = { { .name = "ab8500-charger", .num_resources = ARRAY_SIZE(ab8500_charger_resources), @@ -1061,7 +1061,7 @@ static struct mfd_cell __devinitdata ab8500_bm_devs[] = { }, }; -static struct mfd_cell __devinitdata ab8500_devs[] = { +static struct mfd_cell ab8500_devs[] = { { .name = "ab8500-gpio", .of_compatible = "stericsson,ab8500-gpio", @@ -1080,7 +1080,7 @@ static struct mfd_cell __devinitdata ab8500_devs[] = { }, }; -static struct mfd_cell __devinitdata ab9540_devs[] = { +static struct mfd_cell ab9540_devs[] = { { .name = "ab8500-gpio", .num_resources = ARRAY_SIZE(ab9540_gpio_resources), @@ -1097,7 +1097,7 @@ static struct mfd_cell __devinitdata ab9540_devs[] = { }; /* Device list common to ab9540 and ab8505 */ -static struct mfd_cell __devinitdata ab9540_ab8505_devs[] = { +static struct mfd_cell ab9540_ab8505_devs[] = { { .name = "ab-iddet", .num_resources = ARRAY_SIZE(ab8505_iddet_resources), @@ -1248,7 +1248,7 @@ static struct attribute_group ab9540_attr_group = { .attrs = ab9540_sysfs_entries, }; -static int __devinit ab8500_probe(struct platform_device *pdev) +static int ab8500_probe(struct platform_device *pdev) { static char *switch_off_status[] = { "Swoff bit programming", @@ -1473,7 +1473,7 @@ out_free_ab8500: return ret; } -static int __devexit ab8500_remove(struct platform_device *pdev) +static int ab8500_remove(struct platform_device *pdev) { struct ab8500 *ab8500 = platform_get_drvdata(pdev); @@ -1506,7 +1506,7 @@ static struct platform_driver ab8500_core_driver = { .owner = THIS_MODULE, }, .probe = ab8500_probe, - .remove = __devexit_p(ab8500_remove), + .remove = ab8500_remove, .id_table = ab8500_id, }; diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index c4cb806978a..5a8e707bc03 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -552,7 +552,7 @@ static struct dentry *ab8500_bank_file; static struct dentry *ab8500_address_file; static struct dentry *ab8500_val_file; -static int __devinit ab8500_debug_probe(struct platform_device *plf) +static int ab8500_debug_probe(struct platform_device *plf) { debug_bank = AB8500_MISC; debug_address = AB8500_REV_REG & 0x00FF; @@ -597,7 +597,7 @@ exit_no_debugfs: return -ENOMEM; } -static int __devexit ab8500_debug_remove(struct platform_device *plf) +static int ab8500_debug_remove(struct platform_device *plf) { debugfs_remove(ab8500_val_file); debugfs_remove(ab8500_address_file); @@ -614,7 +614,7 @@ static struct platform_driver ab8500_debug_driver = { .owner = THIS_MODULE, }, .probe = ab8500_debug_probe, - .remove = __devexit_p(ab8500_debug_remove) + .remove = ab8500_debug_remove }; static int __init ab8500_debug_init(void) diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index 29d72a259c8..3fb1f40d638 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c @@ -571,7 +571,7 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc) gpadc->cal_data[ADC_INPUT_VBAT].offset); } -static int __devinit ab8500_gpadc_probe(struct platform_device *pdev) +static int ab8500_gpadc_probe(struct platform_device *pdev) { int ret = 0; struct ab8500_gpadc *gpadc; @@ -634,7 +634,7 @@ fail: return ret; } -static int __devexit ab8500_gpadc_remove(struct platform_device *pdev) +static int ab8500_gpadc_remove(struct platform_device *pdev) { struct ab8500_gpadc *gpadc = platform_get_drvdata(pdev); @@ -651,7 +651,7 @@ static int __devexit ab8500_gpadc_remove(struct platform_device *pdev) static struct platform_driver ab8500_gpadc_driver = { .probe = ab8500_gpadc_probe, - .remove = __devexit_p(ab8500_gpadc_remove), + .remove = ab8500_gpadc_remove, .driver = { .name = "ab8500-gpadc", .owner = THIS_MODULE, diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c index c28d4eb1eff..8a33b2c7eea 100644 --- a/drivers/mfd/ab8500-sysctrl.c +++ b/drivers/mfd/ab8500-sysctrl.c @@ -49,13 +49,13 @@ int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value) (u8)(reg & 0xFF), mask, value); } -static int __devinit ab8500_sysctrl_probe(struct platform_device *pdev) +static int ab8500_sysctrl_probe(struct platform_device *pdev) { sysctrl_dev = &pdev->dev; return 0; } -static int __devexit ab8500_sysctrl_remove(struct platform_device *pdev) +static int ab8500_sysctrl_remove(struct platform_device *pdev) { sysctrl_dev = NULL; return 0; @@ -67,7 +67,7 @@ static struct platform_driver ab8500_sysctrl_driver = { .owner = THIS_MODULE, }, .probe = ab8500_sysctrl_probe, - .remove = __devexit_p(ab8500_sysctrl_remove), + .remove = ab8500_sysctrl_remove, }; static int __init ab8500_sysctrl_init(void) diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c index ea8b9475731..210dd038bb5 100644 --- a/drivers/mfd/adp5520.c +++ b/drivers/mfd/adp5520.c @@ -203,7 +203,7 @@ static int adp5520_remove_subdevs(struct adp5520_chip *chip) return device_for_each_child(chip->dev, NULL, __remove_subdev); } -static int __devinit adp5520_probe(struct i2c_client *client, +static int adp5520_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct adp5520_platform_data *pdata = client->dev.platform_data; @@ -307,7 +307,7 @@ out_free_chip: return ret; } -static int __devexit adp5520_remove(struct i2c_client *client) +static int adp5520_remove(struct i2c_client *client) { struct adp5520_chip *chip = dev_get_drvdata(&client->dev); @@ -356,7 +356,7 @@ static struct i2c_driver adp5520_driver = { .pm = &adp5520_pm, }, .probe = adp5520_probe, - .remove = __devexit_p(adp5520_remove), + .remove = adp5520_remove, .id_table = adp5520_id, }; diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 1b48f209480..1a6f943f733 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -98,9 +98,9 @@ static irqreturn_t arizona_underclocked(int irq, void *data) if (val & ARIZONA_AIF3_UNDERCLOCKED_STS) dev_err(arizona->dev, "AIF3 underclocked\n"); - if (val & ARIZONA_AIF3_UNDERCLOCKED_STS) - dev_err(arizona->dev, "AIF3 underclocked\n"); if (val & ARIZONA_AIF2_UNDERCLOCKED_STS) + dev_err(arizona->dev, "AIF2 underclocked\n"); + if (val & ARIZONA_AIF1_UNDERCLOCKED_STS) dev_err(arizona->dev, "AIF1 underclocked\n"); if (val & ARIZONA_ISRC2_UNDERCLOCKED_STS) dev_err(arizona->dev, "ISRC2 underclocked\n"); @@ -285,7 +285,7 @@ static struct mfd_cell wm5110_devs[] = { { .name = "wm5110-codec" }, }; -int __devinit arizona_dev_init(struct arizona *arizona) +int arizona_dev_init(struct arizona *arizona) { struct device *dev = arizona->dev; const char *type_name; @@ -415,11 +415,19 @@ int __devinit arizona_dev_init(struct arizona *arizona) /* If we have a /RESET GPIO we'll already be reset */ if (!arizona->pdata.reset) { + regcache_mark_dirty(arizona->regmap); + ret = regmap_write(arizona->regmap, ARIZONA_SOFTWARE_RESET, 0); if (ret != 0) { dev_err(dev, "Failed to reset device: %d\n", ret); goto err_reset; } + + ret = regcache_sync(arizona->regmap); + if (ret != 0) { + dev_err(dev, "Failed to sync device: %d\n", ret); + goto err_reset; + } } ret = arizona_wait_for_boot(arizona); @@ -520,7 +528,7 @@ int __devinit arizona_dev_init(struct arizona *arizona) break; case WM5110: ret = mfd_add_devices(arizona->dev, -1, wm5110_devs, - ARRAY_SIZE(wm5102_devs), NULL, 0, NULL); + ARRAY_SIZE(wm5110_devs), NULL, 0, NULL); break; } @@ -553,7 +561,7 @@ err_early: } EXPORT_SYMBOL_GPL(arizona_dev_init); -int __devexit arizona_dev_exit(struct arizona *arizona) +int arizona_dev_exit(struct arizona *arizona) { mfd_remove_devices(arizona->dev); arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona); diff --git a/drivers/mfd/arizona-i2c.c b/drivers/mfd/arizona-i2c.c index 570c4b43808..44a1bb96984 100644 --- a/drivers/mfd/arizona-i2c.c +++ b/drivers/mfd/arizona-i2c.c @@ -22,7 +22,7 @@ #include "arizona.h" -static __devinit int arizona_i2c_probe(struct i2c_client *i2c, +static int arizona_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct arizona *arizona; @@ -65,7 +65,7 @@ static __devinit int arizona_i2c_probe(struct i2c_client *i2c, return arizona_dev_init(arizona); } -static int __devexit arizona_i2c_remove(struct i2c_client *i2c) +static int arizona_i2c_remove(struct i2c_client *i2c) { struct arizona *arizona = dev_get_drvdata(&i2c->dev); arizona_dev_exit(arizona); @@ -86,7 +86,7 @@ static struct i2c_driver arizona_i2c_driver = { .pm = &arizona_pm_ops, }, .probe = arizona_i2c_probe, - .remove = __devexit_p(arizona_i2c_remove), + .remove = arizona_i2c_remove, .id_table = arizona_i2c_id, }; diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index ef0f2d001df..b1b00917740 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -178,6 +178,7 @@ int arizona_irq_init(struct arizona *arizona) switch (arizona->rev) { case 0: + case 1: ctrlif_error = false; break; default: diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c index df2e5a8bee2..1b9fdd698b0 100644 --- a/drivers/mfd/arizona-spi.c +++ b/drivers/mfd/arizona-spi.c @@ -22,7 +22,7 @@ #include "arizona.h" -static int __devinit arizona_spi_probe(struct spi_device *spi) +static int arizona_spi_probe(struct spi_device *spi) { const struct spi_device_id *id = spi_get_device_id(spi); struct arizona *arizona; @@ -65,7 +65,7 @@ static int __devinit arizona_spi_probe(struct spi_device *spi) return arizona_dev_init(arizona); } -static int __devexit arizona_spi_remove(struct spi_device *spi) +static int arizona_spi_remove(struct spi_device *spi) { struct arizona *arizona = dev_get_drvdata(&spi->dev); arizona_dev_exit(arizona); @@ -86,7 +86,7 @@ static struct spi_driver arizona_spi_driver = { .pm = &arizona_pm_ops, }, .probe = arizona_spi_probe, - .remove = __devexit_p(arizona_spi_remove), + .remove = arizona_spi_remove, .id_table = arizona_spi_ids, }; diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 62f0883a763..1b15986c01e 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -1039,7 +1039,7 @@ static int __init asic3_probe(struct platform_device *pdev) return ret; } -static int __devexit asic3_remove(struct platform_device *pdev) +static int asic3_remove(struct platform_device *pdev) { int ret; struct asic3 *asic = platform_get_drvdata(pdev); @@ -1071,7 +1071,7 @@ static struct platform_driver asic3_device_driver = { .driver = { .name = "asic3", }, - .remove = __devexit_p(asic3_remove), + .remove = asic3_remove, .shutdown = asic3_shutdown, }; diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c index 2b282133c72..2e4752a9220 100644 --- a/drivers/mfd/cs5535-mfd.c +++ b/drivers/mfd/cs5535-mfd.c @@ -71,9 +71,9 @@ static int cs5535_mfd_res_disable(struct platform_device *pdev) return 0; } -static __devinitdata struct resource cs5535_mfd_resources[NR_BARS]; +static struct resource cs5535_mfd_resources[NR_BARS]; -static __devinitdata struct mfd_cell cs5535_mfd_cells[] = { +static struct mfd_cell cs5535_mfd_cells[] = { { .id = SMB_BAR, .name = "cs5535-smb", @@ -113,7 +113,7 @@ static __devinitdata struct mfd_cell cs5535_mfd_cells[] = { }; #ifdef CONFIG_OLPC -static void __devinit cs5535_clone_olpc_cells(void) +static void cs5535_clone_olpc_cells(void) { const char *acpi_clones[] = { "olpc-xo1-pm-acpi", "olpc-xo1-sci-acpi" }; @@ -126,7 +126,7 @@ static void __devinit cs5535_clone_olpc_cells(void) static void cs5535_clone_olpc_cells(void) { } #endif -static int __devinit cs5535_mfd_probe(struct pci_dev *pdev, +static int cs5535_mfd_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int err, i; @@ -166,7 +166,7 @@ err_disable: return err; } -static void __devexit cs5535_mfd_remove(struct pci_dev *pdev) +static void cs5535_mfd_remove(struct pci_dev *pdev) { mfd_remove_devices(&pdev->dev); pci_disable_device(pdev); @@ -183,7 +183,7 @@ static struct pci_driver cs5535_mfd_driver = { .name = DRV_NAME, .id_table = cs5535_mfd_pci_tbl, .probe = cs5535_mfd_probe, - .remove = __devexit_p(cs5535_mfd_remove), + .remove = cs5535_mfd_remove, }; module_pci_driver(cs5535_mfd_driver); diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index 1924b857a0f..05176cd2862 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c @@ -246,7 +246,7 @@ int da903x_query_status(struct device *dev, unsigned int sbits) } EXPORT_SYMBOL(da903x_query_status); -static int __devinit da9030_init_chip(struct da903x_chip *chip) +static int da9030_init_chip(struct da903x_chip *chip) { uint8_t chip_id; int err; @@ -459,7 +459,7 @@ static int da903x_remove_subdevs(struct da903x_chip *chip) return device_for_each_child(chip->dev, NULL, __remove_subdev); } -static int __devinit da903x_add_subdevs(struct da903x_chip *chip, +static int da903x_add_subdevs(struct da903x_chip *chip, struct da903x_platform_data *pdata) { struct da903x_subdev_info *subdev; @@ -491,7 +491,7 @@ failed: return ret; } -static int __devinit da903x_probe(struct i2c_client *client, +static int da903x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct da903x_platform_data *pdata = client->dev.platform_data; @@ -544,7 +544,7 @@ out_free_chip: return ret; } -static int __devexit da903x_remove(struct i2c_client *client) +static int da903x_remove(struct i2c_client *client) { struct da903x_chip *chip = i2c_get_clientdata(client); @@ -560,7 +560,7 @@ static struct i2c_driver da903x_driver = { .owner = THIS_MODULE, }, .probe = da903x_probe, - .remove = __devexit_p(da903x_remove), + .remove = da903x_remove, .id_table = da903x_id_table, }; diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c index a0a62b24621..689b747416a 100644 --- a/drivers/mfd/da9052-core.c +++ b/drivers/mfd/da9052-core.c @@ -515,7 +515,7 @@ static struct resource da9052_tsi_resources[] = { }, }; -static struct mfd_cell __devinitdata da9052_subdev_info[] = { +static struct mfd_cell da9052_subdev_info[] = { { .name = "da9052-regulator", .id = 1, @@ -769,7 +769,7 @@ struct regmap_config da9052_regmap_config = { }; EXPORT_SYMBOL_GPL(da9052_regmap_config); -int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id) +int da9052_device_init(struct da9052 *da9052, u8 chip_id) { struct da9052_pdata *pdata = da9052->dev->platform_data; int ret; diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c index 352c58b5a90..ac74a4d1dae 100644 --- a/drivers/mfd/da9052-i2c.c +++ b/drivers/mfd/da9052-i2c.c @@ -64,7 +64,7 @@ static const struct of_device_id dialog_dt_ids[] = { }; #endif -static int __devinit da9052_i2c_probe(struct i2c_client *client, +static int da9052_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct da9052 *da9052; @@ -121,7 +121,7 @@ static int __devinit da9052_i2c_probe(struct i2c_client *client, return 0; } -static int __devexit da9052_i2c_remove(struct i2c_client *client) +static int da9052_i2c_remove(struct i2c_client *client) { struct da9052 *da9052 = i2c_get_clientdata(client); @@ -131,7 +131,7 @@ static int __devexit da9052_i2c_remove(struct i2c_client *client) static struct i2c_driver da9052_i2c_driver = { .probe = da9052_i2c_probe, - .remove = __devexit_p(da9052_i2c_remove), + .remove = da9052_i2c_remove, .id_table = da9052_i2c_id, .driver = { .name = "da9052", diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c index dbeadc5a643..61d63b93576 100644 --- a/drivers/mfd/da9052-spi.c +++ b/drivers/mfd/da9052-spi.c @@ -21,7 +21,7 @@ #include <linux/mfd/da9052/da9052.h> -static int __devinit da9052_spi_probe(struct spi_device *spi) +static int da9052_spi_probe(struct spi_device *spi) { int ret; const struct spi_device_id *id = spi_get_device_id(spi); @@ -58,7 +58,7 @@ static int __devinit da9052_spi_probe(struct spi_device *spi) return 0; } -static int __devexit da9052_spi_remove(struct spi_device *spi) +static int da9052_spi_remove(struct spi_device *spi) { struct da9052 *da9052 = dev_get_drvdata(&spi->dev); @@ -76,7 +76,7 @@ static struct spi_device_id da9052_spi_id[] = { static struct spi_driver da9052_spi_driver = { .probe = da9052_spi_probe, - .remove = __devexit_p(da9052_spi_remove), + .remove = da9052_spi_remove, .id_table = da9052_spi_id, .driver = { .name = "da9052", diff --git a/drivers/mfd/da9055-core.c b/drivers/mfd/da9055-core.c index ff6c77f392b..f56a1a9f777 100644 --- a/drivers/mfd/da9055-core.c +++ b/drivers/mfd/da9055-core.c @@ -377,7 +377,7 @@ static struct regmap_irq_chip da9055_regmap_irq_chip = { .num_irqs = ARRAY_SIZE(da9055_irqs), }; -int __devinit da9055_device_init(struct da9055 *da9055) +int da9055_device_init(struct da9055 *da9055) { struct da9055_pdata *pdata = da9055->dev->platform_data; int ret; @@ -412,7 +412,7 @@ err: return ret; } -void __devexit da9055_device_exit(struct da9055 *da9055) +void da9055_device_exit(struct da9055 *da9055) { regmap_del_irq_chip(da9055->chip_irq, da9055->irq_data); mfd_remove_devices(da9055->dev); diff --git a/drivers/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c index 88f6dca53ba..607387ffe8c 100644 --- a/drivers/mfd/da9055-i2c.c +++ b/drivers/mfd/da9055-i2c.c @@ -18,7 +18,7 @@ #include <linux/mfd/da9055/core.h> -static int __devinit da9055_i2c_probe(struct i2c_client *i2c, +static int da9055_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct da9055 *da9055; @@ -44,7 +44,7 @@ static int __devinit da9055_i2c_probe(struct i2c_client *i2c, return da9055_device_init(da9055); } -static int __devexit da9055_i2c_remove(struct i2c_client *i2c) +static int da9055_i2c_remove(struct i2c_client *i2c) { struct da9055 *da9055 = i2c_get_clientdata(i2c); @@ -60,7 +60,7 @@ static struct i2c_device_id da9055_i2c_id[] = { static struct i2c_driver da9055_i2c_driver = { .probe = da9055_i2c_probe, - .remove = __devexit_p(da9055_i2c_remove), + .remove = da9055_i2c_remove, .id_table = da9055_i2c_id, .driver = { .name = "da9055", diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c index 45e83a68641..c0bcc872af4 100644 --- a/drivers/mfd/davinci_voicecodec.c +++ b/drivers/mfd/davinci_voicecodec.c @@ -151,7 +151,7 @@ fail1: return ret; } -static int __devexit davinci_vc_remove(struct platform_device *pdev) +static int davinci_vc_remove(struct platform_device *pdev) { struct davinci_vc *davinci_vc = platform_get_drvdata(pdev); @@ -174,7 +174,7 @@ static struct platform_driver davinci_vc_driver = { .name = "davinci_voicecodec", .owner = THIS_MODULE, }, - .remove = __devexit_p(davinci_vc_remove), + .remove = davinci_vc_remove, }; static int __init davinci_vc_init(void) diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 00b8b0f3dfb..dc569156937 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -31,6 +31,7 @@ #include <linux/mfd/abx500/ab8500.h> #include <linux/regulator/db8500-prcmu.h> #include <linux/regulator/machine.h> +#include <linux/cpufreq.h> #include <asm/hardware/gic.h> #include <mach/hardware.h> #include <mach/irqs.h> @@ -420,9 +421,6 @@ static struct { static atomic_t ac_wake_req_state = ATOMIC_INIT(0); -/* Functions definition */ -static void compute_armss_rate(void); - /* Spinlocks */ static DEFINE_SPINLOCK(prcmu_lock); static DEFINE_SPINLOCK(clkout_lock); @@ -1019,7 +1017,6 @@ int db8500_prcmu_set_arm_opp(u8 opp) (mb1_transfer.ack.arm_opp != opp)) r = -EIO; - compute_armss_rate(); mutex_unlock(&mb1_transfer.lock); return r; @@ -1169,12 +1166,12 @@ int db8500_prcmu_get_ape_opp(void) } /** - * prcmu_request_ape_opp_100_voltage - Request APE OPP 100% voltage + * db8500_prcmu_request_ape_opp_100_voltage - Request APE OPP 100% voltage * @enable: true to request the higher voltage, false to drop a request. * * Calls to this function to enable and disable requests must be balanced. */ -int prcmu_request_ape_opp_100_voltage(bool enable) +int db8500_prcmu_request_ape_opp_100_voltage(bool enable) { int r = 0; u8 header; @@ -1669,13 +1666,8 @@ static unsigned long clock_rate(u8 clock) else return 0; } -static unsigned long latest_armss_rate; -static unsigned long armss_rate(void) -{ - return latest_armss_rate; -} -static void compute_armss_rate(void) +static unsigned long armss_rate(void) { u32 r; unsigned long rate; @@ -1700,7 +1692,7 @@ static void compute_armss_rate(void) rate = pll_rate(PRCM_PLLARM_FREQ, ROOT_CLOCK_RATE, PLL_DIV); } - latest_armss_rate = rate; + return rate; } static unsigned long dsiclk_rate(u8 n) @@ -1820,6 +1812,35 @@ static long round_clock_rate(u8 clock, unsigned long rate) return rounded_rate; } +/* CPU FREQ table, may be changed due to if MAX_OPP is supported. */ +static struct cpufreq_frequency_table db8500_cpufreq_table[] = { + { .frequency = 200000, .index = ARM_EXTCLK,}, + { .frequency = 400000, .index = ARM_50_OPP,}, + { .frequency = 800000, .index = ARM_100_OPP,}, + { .frequency = CPUFREQ_TABLE_END,}, /* To be used for MAX_OPP. */ + { .frequency = CPUFREQ_TABLE_END,}, +}; + +static long round_armss_rate(unsigned long rate) +{ + long freq = 0; + int i = 0; + + /* cpufreq table frequencies is in KHz. */ + rate = rate / 1000; + + /* Find the corresponding arm opp from the cpufreq table. */ + while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) { + freq = db8500_cpufreq_table[i].frequency; + if (freq == rate) + break; + i++; + } + + /* Return the last valid value, even if a match was not found. */ + return freq * 1000; +} + #define MIN_PLL_VCO_RATE 600000000ULL #define MAX_PLL_VCO_RATE 1680640000ULL @@ -1891,6 +1912,8 @@ long prcmu_round_clock_rate(u8 clock, unsigned long rate) { if (clock < PRCMU_NUM_REG_CLOCKS) return round_clock_rate(clock, rate); + else if (clock == PRCMU_ARMSS) + return round_armss_rate(rate); else if (clock == PRCMU_PLLDSI) return round_plldsi_rate(rate); else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK)) @@ -1950,6 +1973,27 @@ static void set_clock_rate(u8 clock, unsigned long rate) spin_unlock_irqrestore(&clk_mgt_lock, flags); } +static int set_armss_rate(unsigned long rate) +{ + int i = 0; + + /* cpufreq table frequencies is in KHz. */ + rate = rate / 1000; + + /* Find the corresponding arm opp from the cpufreq table. */ + while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) { + if (db8500_cpufreq_table[i].frequency == rate) + break; + i++; + } + + if (db8500_cpufreq_table[i].frequency != rate) + return -EINVAL; + + /* Set the new arm opp. */ + return db8500_prcmu_set_arm_opp(db8500_cpufreq_table[i].index); +} + static int set_plldsi_rate(unsigned long rate) { unsigned long src_rate; @@ -2030,6 +2074,8 @@ int prcmu_set_clock_rate(u8 clock, unsigned long rate) { if (clock < PRCMU_NUM_REG_CLOCKS) set_clock_rate(clock, rate); + else if (clock == PRCMU_ARMSS) + return set_armss_rate(rate); else if (clock == PRCMU_PLLDSI) return set_plldsi_rate(rate); else if ((clock == PRCMU_DSI0CLK) || (clock == PRCMU_DSI1CLK)) @@ -2754,8 +2800,6 @@ void __init db8500_prcmu_early_init(void) init_completion(&mb5_transfer.work); INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work); - - compute_armss_rate(); } static void __init init_prcm_registers(void) @@ -3020,6 +3064,8 @@ static struct mfd_cell db8500_prcmu_devs[] = { { .name = "cpufreq-u8500", .of_compatible = "stericsson,cpufreq-u8500", + .platform_data = &db8500_cpufreq_table, + .pdata_size = sizeof(db8500_cpufreq_table), }, { .name = "ab8500-core", @@ -3030,11 +3076,19 @@ static struct mfd_cell db8500_prcmu_devs[] = { }, }; +static void db8500_prcmu_update_cpufreq(void) +{ + if (prcmu_has_arm_maxopp()) { + db8500_cpufreq_table[3].frequency = 1000000; + db8500_cpufreq_table[3].index = ARM_MAX_OPP; + } +} + /** * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic * */ -static int __devinit db8500_prcmu_probe(struct platform_device *pdev) +static int db8500_prcmu_probe(struct platform_device *pdev) { struct ab8500_platform_data *ab8500_platdata = pdev->dev.platform_data; struct device_node *np = pdev->dev.of_node; @@ -3074,6 +3128,8 @@ static int __devinit db8500_prcmu_probe(struct platform_device *pdev) if (cpu_is_u8500v20_or_later()) prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET); + db8500_prcmu_update_cpufreq(); + err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs, ARRAY_SIZE(db8500_prcmu_devs), NULL, 0, NULL); if (err) { diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index db662e2dcfa..b7a61f0f27a 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c @@ -371,7 +371,7 @@ static int pcap_remove_subdev(struct device *dev, void *unused) return 0; } -static int __devinit pcap_add_subdev(struct pcap_chip *pcap, +static int pcap_add_subdev(struct pcap_chip *pcap, struct pcap_subdev *subdev) { struct platform_device *pdev; @@ -391,7 +391,7 @@ static int __devinit pcap_add_subdev(struct pcap_chip *pcap, return ret; } -static int __devexit ezx_pcap_remove(struct spi_device *spi) +static int ezx_pcap_remove(struct spi_device *spi) { struct pcap_chip *pcap = dev_get_drvdata(&spi->dev); struct pcap_platform_data *pdata = spi->dev.platform_data; @@ -420,7 +420,7 @@ static int __devexit ezx_pcap_remove(struct spi_device *spi) return 0; } -static int __devinit ezx_pcap_probe(struct spi_device *spi) +static int ezx_pcap_probe(struct spi_device *spi) { struct pcap_platform_data *pdata = spi->dev.platform_data; struct pcap_chip *pcap; @@ -525,7 +525,7 @@ ret: static struct spi_driver ezxpcap_driver = { .probe = ezx_pcap_probe, - .remove = __devexit_p(ezx_pcap_remove), + .remove = ezx_pcap_remove, .driver = { .name = "ezx-pcap", .owner = THIS_MODULE, diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c index d55065cc324..324187c0c12 100644 --- a/drivers/mfd/htc-i2cpld.c +++ b/drivers/mfd/htc-i2cpld.c @@ -327,7 +327,7 @@ static void htcpld_chip_reset(struct i2c_client *client) client, (chip_data->cache_out = chip_data->reset)); } -static int __devinit htcpld_setup_chip_irq( +static int htcpld_setup_chip_irq( struct platform_device *pdev, int chip_index) { @@ -361,7 +361,7 @@ static int __devinit htcpld_setup_chip_irq( return ret; } -static int __devinit htcpld_register_chip_i2c( +static int htcpld_register_chip_i2c( struct platform_device *pdev, int chip_index) { @@ -419,7 +419,7 @@ static int __devinit htcpld_register_chip_i2c( return 0; } -static void __devinit htcpld_unregister_chip_i2c( +static void htcpld_unregister_chip_i2c( struct platform_device *pdev, int chip_index) { @@ -434,7 +434,7 @@ static void __devinit htcpld_unregister_chip_i2c( i2c_unregister_device(chip->client); } -static int __devinit htcpld_register_chip_gpio( +static int htcpld_register_chip_gpio( struct platform_device *pdev, int chip_index) { @@ -501,7 +501,7 @@ static int __devinit htcpld_register_chip_gpio( return 0; } -static int __devinit htcpld_setup_chips(struct platform_device *pdev) +static int htcpld_setup_chips(struct platform_device *pdev) { struct htcpld_data *htcpld; struct device *dev = &pdev->dev; @@ -563,7 +563,7 @@ static int __devinit htcpld_setup_chips(struct platform_device *pdev) return 0; } -static int __devinit htcpld_core_probe(struct platform_device *pdev) +static int htcpld_core_probe(struct platform_device *pdev) { struct htcpld_data *htcpld; struct device *dev = &pdev->dev; diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c index 266bdc5bd96..ab8d0b2739b 100644 --- a/drivers/mfd/intel_msic.c +++ b/drivers/mfd/intel_msic.c @@ -306,7 +306,7 @@ int intel_msic_irq_read(struct intel_msic *msic, unsigned short reg, u8 *val) } EXPORT_SYMBOL_GPL(intel_msic_irq_read); -static int __devinit intel_msic_init_devices(struct intel_msic *msic) +static int intel_msic_init_devices(struct intel_msic *msic) { struct platform_device *pdev = msic->pdev; struct intel_msic_platform_data *pdata = pdev->dev.platform_data; @@ -364,7 +364,7 @@ fail: return ret; } -static void __devexit intel_msic_remove_devices(struct intel_msic *msic) +static void intel_msic_remove_devices(struct intel_msic *msic) { struct platform_device *pdev = msic->pdev; struct intel_msic_platform_data *pdata = pdev->dev.platform_data; @@ -375,7 +375,7 @@ static void __devexit intel_msic_remove_devices(struct intel_msic *msic) gpio_free(pdata->ocd->gpio); } -static int __devinit intel_msic_probe(struct platform_device *pdev) +static int intel_msic_probe(struct platform_device *pdev) { struct intel_msic_platform_data *pdata = pdev->dev.platform_data; struct intel_msic *msic; @@ -445,7 +445,7 @@ static int __devinit intel_msic_probe(struct platform_device *pdev) return 0; } -static int __devexit intel_msic_remove(struct platform_device *pdev) +static int intel_msic_remove(struct platform_device *pdev) { struct intel_msic *msic = platform_get_drvdata(pdev); @@ -457,7 +457,7 @@ static int __devexit intel_msic_remove(struct platform_device *pdev) static struct platform_driver intel_msic_driver = { .probe = intel_msic_probe, - .remove = __devexit_p(intel_msic_remove), + .remove = intel_msic_remove, .driver = { .name = "intel_msic", .owner = THIS_MODULE, diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c index 965c4801df8..45ece11cc27 100644 --- a/drivers/mfd/janz-cmodio.c +++ b/drivers/mfd/janz-cmodio.c @@ -63,7 +63,7 @@ struct cmodio_device { * Subdevices using the mfd-core API */ -static int __devinit cmodio_setup_subdevice(struct cmodio_device *priv, +static int cmodio_setup_subdevice(struct cmodio_device *priv, char *name, unsigned int devno, unsigned int modno) { @@ -120,7 +120,7 @@ static int __devinit cmodio_setup_subdevice(struct cmodio_device *priv, } /* Probe each submodule using kernel parameters */ -static int __devinit cmodio_probe_submodules(struct cmodio_device *priv) +static int cmodio_probe_submodules(struct cmodio_device *priv) { struct pci_dev *pdev = priv->pdev; unsigned int num_probed = 0; @@ -177,7 +177,7 @@ static const struct attribute_group cmodio_sysfs_attr_group = { * PCI Driver */ -static int __devinit cmodio_pci_probe(struct pci_dev *dev, +static int cmodio_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct cmodio_device *priv; @@ -254,7 +254,7 @@ out_return: return ret; } -static void __devexit cmodio_pci_remove(struct pci_dev *dev) +static void cmodio_pci_remove(struct pci_dev *dev) { struct cmodio_device *priv = pci_get_drvdata(dev); @@ -280,7 +280,7 @@ static struct pci_driver cmodio_pci_driver = { .name = DRV_NAME, .id_table = cmodio_pci_ids, .probe = cmodio_pci_probe, - .remove = __devexit_p(cmodio_pci_remove), + .remove = cmodio_pci_remove, }; module_pci_driver(cmodio_pci_driver); diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index c6b6d7dda51..0b8b55bb9b1 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c @@ -202,7 +202,7 @@ static struct mfd_cell jz4740_adc_cells[] = { }, }; -static int __devinit jz4740_adc_probe(struct platform_device *pdev) +static int jz4740_adc_probe(struct platform_device *pdev) { struct irq_chip_generic *gc; struct irq_chip_type *ct; @@ -307,7 +307,7 @@ err_free: return ret; } -static int __devexit jz4740_adc_remove(struct platform_device *pdev) +static int jz4740_adc_remove(struct platform_device *pdev) { struct jz4740_adc *adc = platform_get_drvdata(pdev); @@ -332,7 +332,7 @@ static int __devexit jz4740_adc_remove(struct platform_device *pdev) static struct platform_driver jz4740_adc_driver = { .probe = jz4740_adc_probe, - .remove = __devexit_p(jz4740_adc_remove), + .remove = jz4740_adc_remove, .driver = { .name = "jz4740-adc", .owner = THIS_MODULE, diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c index 24212f45b20..ceebf2c1ea9 100644 --- a/drivers/mfd/lm3533-core.c +++ b/drivers/mfd/lm3533-core.c @@ -382,7 +382,7 @@ static struct attribute_group lm3533_attribute_group = { .attrs = lm3533_attributes }; -static int __devinit lm3533_device_als_init(struct lm3533 *lm3533) +static int lm3533_device_als_init(struct lm3533 *lm3533) { struct lm3533_platform_data *pdata = lm3533->dev->platform_data; int ret; @@ -405,7 +405,7 @@ static int __devinit lm3533_device_als_init(struct lm3533 *lm3533) return 0; } -static int __devinit lm3533_device_bl_init(struct lm3533 *lm3533) +static int lm3533_device_bl_init(struct lm3533 *lm3533) { struct lm3533_platform_data *pdata = lm3533->dev->platform_data; int i; @@ -434,7 +434,7 @@ static int __devinit lm3533_device_bl_init(struct lm3533 *lm3533) return 0; } -static int __devinit lm3533_device_led_init(struct lm3533 *lm3533) +static int lm3533_device_led_init(struct lm3533 *lm3533) { struct lm3533_platform_data *pdata = lm3533->dev->platform_data; int i; @@ -463,7 +463,7 @@ static int __devinit lm3533_device_led_init(struct lm3533 *lm3533) return 0; } -static int __devinit lm3533_device_setup(struct lm3533 *lm3533, +static int lm3533_device_setup(struct lm3533 *lm3533, struct lm3533_platform_data *pdata) { int ret; @@ -479,7 +479,7 @@ static int __devinit lm3533_device_setup(struct lm3533 *lm3533, return 0; } -static int __devinit lm3533_device_init(struct lm3533 *lm3533) +static int lm3533_device_init(struct lm3533 *lm3533) { struct lm3533_platform_data *pdata = lm3533->dev->platform_data; int ret; @@ -534,7 +534,7 @@ err_disable: return ret; } -static void __devexit lm3533_device_exit(struct lm3533 *lm3533) +static void lm3533_device_exit(struct lm3533 *lm3533) { dev_dbg(lm3533->dev, "%s\n", __func__); @@ -596,7 +596,7 @@ static struct regmap_config regmap_config = { .precious_reg = lm3533_precious_register, }; -static int __devinit lm3533_i2c_probe(struct i2c_client *i2c, +static int lm3533_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct lm3533 *lm3533; @@ -624,7 +624,7 @@ static int __devinit lm3533_i2c_probe(struct i2c_client *i2c, return 0; } -static int __devexit lm3533_i2c_remove(struct i2c_client *i2c) +static int lm3533_i2c_remove(struct i2c_client *i2c) { struct lm3533 *lm3533 = i2c_get_clientdata(i2c); @@ -648,7 +648,7 @@ static struct i2c_driver lm3533_i2c_driver = { }, .id_table = lm3533_i2c_ids, .probe = lm3533_i2c_probe, - .remove = __devexit_p(lm3533_i2c_remove), + .remove = lm3533_i2c_remove, }; static int __init lm3533_i2c_init(void) diff --git a/drivers/mfd/lp8788.c b/drivers/mfd/lp8788.c index 3e94a699833..c3d3c9b4d3a 100644 --- a/drivers/mfd/lp8788.c +++ b/drivers/mfd/lp8788.c @@ -203,7 +203,7 @@ static int lp8788_probe(struct i2c_client *cl, const struct i2c_device_id *id) ARRAY_SIZE(lp8788_devs), NULL, 0, NULL); } -static int __devexit lp8788_remove(struct i2c_client *cl) +static int lp8788_remove(struct i2c_client *cl) { struct lp8788 *lp = i2c_get_clientdata(cl); @@ -224,7 +224,7 @@ static struct i2c_driver lp8788_driver = { .owner = THIS_MODULE, }, .probe = lp8788_probe, - .remove = __devexit_p(lp8788_remove), + .remove = lp8788_remove, .id_table = lp8788_ids, }; diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index a22544fe531..2ad24caa07d 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -196,7 +196,7 @@ enum lpc_chipsets { LPC_LPT_LP, /* Lynx Point-LP */ }; -struct lpc_ich_info lpc_chipset_info[] __devinitdata = { +struct lpc_ich_info lpc_chipset_info[] = { [LPC_ICH] = { .name = "ICH", .iTCO_version = 1, @@ -672,7 +672,7 @@ static void lpc_ich_restore_config_space(struct pci_dev *dev) } } -static void __devinit lpc_ich_enable_acpi_space(struct pci_dev *dev) +static void lpc_ich_enable_acpi_space(struct pci_dev *dev) { u8 reg_save; @@ -681,7 +681,7 @@ static void __devinit lpc_ich_enable_acpi_space(struct pci_dev *dev) lpc_ich_acpi_save = reg_save; } -static void __devinit lpc_ich_enable_gpio_space(struct pci_dev *dev) +static void lpc_ich_enable_gpio_space(struct pci_dev *dev) { u8 reg_save; @@ -690,7 +690,7 @@ static void __devinit lpc_ich_enable_gpio_space(struct pci_dev *dev) lpc_ich_gpio_save = reg_save; } -static void __devinit lpc_ich_finalize_cell(struct mfd_cell *cell, +static void lpc_ich_finalize_cell(struct mfd_cell *cell, const struct pci_device_id *id) { cell->platform_data = &lpc_chipset_info[id->driver_data]; @@ -702,7 +702,7 @@ static void __devinit lpc_ich_finalize_cell(struct mfd_cell *cell, * GPIO groups and it's enough to have access to one of these to instantiate * the device. */ -static int __devinit lpc_ich_check_conflict_gpio(struct resource *res) +static int lpc_ich_check_conflict_gpio(struct resource *res) { int ret; u8 use_gpio = 0; @@ -721,7 +721,7 @@ static int __devinit lpc_ich_check_conflict_gpio(struct resource *res) return use_gpio ? use_gpio : ret; } -static int __devinit lpc_ich_init_gpio(struct pci_dev *dev, +static int lpc_ich_init_gpio(struct pci_dev *dev, const struct pci_device_id *id) { u32 base_addr_cfg; @@ -798,7 +798,7 @@ gpio_done: return ret; } -static int __devinit lpc_ich_init_wdt(struct pci_dev *dev, +static int lpc_ich_init_wdt(struct pci_dev *dev, const struct pci_device_id *id) { u32 base_addr_cfg; @@ -852,7 +852,7 @@ wdt_done: return ret; } -static int __devinit lpc_ich_probe(struct pci_dev *dev, +static int lpc_ich_probe(struct pci_dev *dev, const struct pci_device_id *id) { int ret; @@ -878,7 +878,7 @@ static int __devinit lpc_ich_probe(struct pci_dev *dev, return 0; } -static void __devexit lpc_ich_remove(struct pci_dev *dev) +static void lpc_ich_remove(struct pci_dev *dev) { mfd_remove_devices(&dev->dev); lpc_ich_restore_config_space(dev); @@ -888,7 +888,7 @@ static struct pci_driver lpc_ich_driver = { .name = "lpc_ich", .id_table = lpc_ich_ids, .probe = lpc_ich_probe, - .remove = __devexit_p(lpc_ich_remove), + .remove = lpc_ich_remove, }; static int __init lpc_ich_init(void) diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c index f6b9c5c96b2..5624fcbba69 100644 --- a/drivers/mfd/lpc_sch.c +++ b/drivers/mfd/lpc_sch.c @@ -83,7 +83,7 @@ static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = { }; MODULE_DEVICE_TABLE(pci, lpc_sch_ids); -static int __devinit lpc_sch_probe(struct pci_dev *dev, +static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id) { unsigned int base_addr_cfg; @@ -164,7 +164,7 @@ out_dev: return ret; } -static void __devexit lpc_sch_remove(struct pci_dev *dev) +static void lpc_sch_remove(struct pci_dev *dev) { mfd_remove_devices(&dev->dev); } @@ -173,7 +173,7 @@ static struct pci_driver lpc_sch_driver = { .name = "lpc_sch", .id_table = lpc_sch_ids, .probe = lpc_sch_probe, - .remove = __devexit_p(lpc_sch_remove), + .remove = lpc_sch_remove, }; module_pci_driver(lpc_sch_driver); diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index d9e24c849a0..f6878f8db57 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -45,7 +45,7 @@ static struct regmap_config max77686_regmap_config = { }; #ifdef CONFIG_OF -static struct of_device_id __devinitdata max77686_pmic_dt_match[] = { +static struct of_device_id max77686_pmic_dt_match[] = { {.compatible = "maxim,max77686", .data = 0}, {}, }; diff --git a/drivers/mfd/max8907.c b/drivers/mfd/max8907.c index 17f2593d82b..e9b1c93a3ad 100644 --- a/drivers/mfd/max8907.c +++ b/drivers/mfd/max8907.c @@ -183,7 +183,7 @@ static void max8907_power_off(void) MAX8907_MASK_POWER_OFF, MAX8907_MASK_POWER_OFF); } -static __devinit int max8907_i2c_probe(struct i2c_client *i2c, +static int max8907_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct max8907 *max8907; @@ -288,7 +288,7 @@ err_alloc_drvdata: return ret; } -static __devexit int max8907_i2c_remove(struct i2c_client *i2c) +static int max8907_i2c_remove(struct i2c_client *i2c) { struct max8907 *max8907 = i2c_get_clientdata(i2c); diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 9f54c04912f..e32466e865b 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -19,12 +19,12 @@ #include <linux/mfd/core.h> #include <linux/mfd/max8925.h> -static struct resource bk_resources[] __devinitdata = { +static struct resource bk_resources[] = { { 0x84, 0x84, "mode control", IORESOURCE_REG, }, { 0x85, 0x85, "control", IORESOURCE_REG, }, }; -static struct mfd_cell bk_devs[] __devinitdata = { +static struct mfd_cell bk_devs[] = { { .name = "max8925-backlight", .num_resources = ARRAY_SIZE(bk_resources), @@ -110,99 +110,99 @@ static struct mfd_cell onkey_devs[] = { }, }; -static struct resource sd1_resources[] __devinitdata = { +static struct resource sd1_resources[] = { {0x06, 0x06, "sdv", IORESOURCE_REG, }, }; -static struct resource sd2_resources[] __devinitdata = { +static struct resource sd2_resources[] = { {0x09, 0x09, "sdv", IORESOURCE_REG, }, }; -static struct resource sd3_resources[] __devinitdata = { +static struct resource sd3_resources[] = { {0x0c, 0x0c, "sdv", IORESOURCE_REG, }, }; -static struct resource ldo1_resources[] __devinitdata = { +static struct resource ldo1_resources[] = { {0x1a, 0x1a, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo2_resources[] __devinitdata = { +static struct resource ldo2_resources[] = { {0x1e, 0x1e, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo3_resources[] __devinitdata = { +static struct resource ldo3_resources[] = { {0x22, 0x22, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo4_resources[] __devinitdata = { +static struct resource ldo4_resources[] = { {0x26, 0x26, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo5_resources[] __devinitdata = { +static struct resource ldo5_resources[] = { {0x2a, 0x2a, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo6_resources[] __devinitdata = { +static struct resource ldo6_resources[] = { {0x2e, 0x2e, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo7_resources[] __devinitdata = { +static struct resource ldo7_resources[] = { {0x32, 0x32, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo8_resources[] __devinitdata = { +static struct resource ldo8_resources[] = { {0x36, 0x36, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo9_resources[] __devinitdata = { +static struct resource ldo9_resources[] = { {0x3a, 0x3a, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo10_resources[] __devinitdata = { +static struct resource ldo10_resources[] = { {0x3e, 0x3e, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo11_resources[] __devinitdata = { +static struct resource ldo11_resources[] = { {0x42, 0x42, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo12_resources[] __devinitdata = { +static struct resource ldo12_resources[] = { {0x46, 0x46, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo13_resources[] __devinitdata = { +static struct resource ldo13_resources[] = { {0x4a, 0x4a, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo14_resources[] __devinitdata = { +static struct resource ldo14_resources[] = { {0x4e, 0x4e, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo15_resources[] __devinitdata = { +static struct resource ldo15_resources[] = { {0x52, 0x52, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo16_resources[] __devinitdata = { +static struct resource ldo16_resources[] = { {0x12, 0x12, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo17_resources[] __devinitdata = { +static struct resource ldo17_resources[] = { {0x16, 0x16, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo18_resources[] __devinitdata = { +static struct resource ldo18_resources[] = { {0x74, 0x74, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo19_resources[] __devinitdata = { +static struct resource ldo19_resources[] = { {0x5e, 0x5e, "ldov", IORESOURCE_REG, }, }; -static struct resource ldo20_resources[] __devinitdata = { +static struct resource ldo20_resources[] = { {0x9e, 0x9e, "ldov", IORESOURCE_REG, }, }; -static struct mfd_cell reg_devs[] __devinitdata = { +static struct mfd_cell reg_devs[] = { { .name = "max8925-regulator", .id = 0, @@ -714,7 +714,7 @@ tsc_irq: return 0; } -static void __devinit init_regulator(struct max8925_chip *chip, +static void init_regulator(struct max8925_chip *chip, struct max8925_platform_data *pdata) { int ret; @@ -821,7 +821,7 @@ static void __devinit init_regulator(struct max8925_chip *chip, } } -int __devinit max8925_device_init(struct max8925_chip *chip, +int max8925_device_init(struct max8925_chip *chip, struct max8925_platform_data *pdata) { int ret; @@ -901,7 +901,7 @@ out: return ret; } -void __devexit max8925_device_exit(struct max8925_chip *chip) +void max8925_device_exit(struct max8925_chip *chip) { if (chip->core_irq) free_irq(chip->core_irq, chip); diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c index d9e4b36edee..00b5b456063 100644 --- a/drivers/mfd/max8925-i2c.c +++ b/drivers/mfd/max8925-i2c.c @@ -135,7 +135,7 @@ static const struct i2c_device_id max8925_id_table[] = { }; MODULE_DEVICE_TABLE(i2c, max8925_id_table); -static int __devinit max8925_probe(struct i2c_client *client, +static int max8925_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct max8925_platform_data *pdata = client->dev.platform_data; @@ -168,7 +168,7 @@ static int __devinit max8925_probe(struct i2c_client *client, return 0; } -static int __devexit max8925_remove(struct i2c_client *client) +static int max8925_remove(struct i2c_client *client) { struct max8925_chip *chip = i2c_get_clientdata(client); @@ -210,7 +210,7 @@ static struct i2c_driver max8925_driver = { .pm = &max8925_pm_ops, }, .probe = max8925_probe, - .remove = __devexit_p(max8925_remove), + .remove = max8925_remove, .id_table = max8925_id_table, }; diff --git a/drivers/mfd/mc13xxx-i2c.c b/drivers/mfd/mc13xxx-i2c.c index 9d18dde3cd2..7957999f30b 100644 --- a/drivers/mfd/mc13xxx-i2c.c +++ b/drivers/mfd/mc13xxx-i2c.c @@ -85,7 +85,7 @@ static int mc13xxx_i2c_probe(struct i2c_client *client, return ret; } -static int __devexit mc13xxx_i2c_remove(struct i2c_client *client) +static int mc13xxx_i2c_remove(struct i2c_client *client) { struct mc13xxx *mc13xxx = dev_get_drvdata(&client->dev); @@ -102,7 +102,7 @@ static struct i2c_driver mc13xxx_i2c_driver = { .of_match_table = mc13xxx_dt_ids, }, .probe = mc13xxx_i2c_probe, - .remove = __devexit_p(mc13xxx_i2c_remove), + .remove = mc13xxx_i2c_remove, }; static int __init mc13xxx_i2c_init(void) diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c index 0bdb43a0aff..cb32f69d80b 100644 --- a/drivers/mfd/mc13xxx-spi.c +++ b/drivers/mfd/mc13xxx-spi.c @@ -159,7 +159,7 @@ static int mc13xxx_spi_probe(struct spi_device *spi) return ret; } -static int __devexit mc13xxx_spi_remove(struct spi_device *spi) +static int mc13xxx_spi_remove(struct spi_device *spi) { struct mc13xxx *mc13xxx = dev_get_drvdata(&spi->dev); @@ -176,7 +176,7 @@ static struct spi_driver mc13xxx_spi_driver = { .of_match_table = mc13xxx_dt_ids, }, .probe = mc13xxx_spi_probe, - .remove = __devexit_p(mc13xxx_spi_remove), + .remove = mc13xxx_spi_remove, }; static int __init mc13xxx_init(void) diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 23cec57c02b..29b8ed21213 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -464,7 +464,7 @@ static void omap_usbhs_deinit(struct device *dev) * * Allocates basic resources for this USB host controller. */ -static int __devinit usbhs_omap_probe(struct platform_device *pdev) +static int usbhs_omap_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct usbhs_omap_platform_data *pdata = dev->platform_data; @@ -652,7 +652,7 @@ end_probe: * * Reverses the effect of usbhs_omap_probe(). */ -static int __devexit usbhs_omap_remove(struct platform_device *pdev) +static int usbhs_omap_remove(struct platform_device *pdev) { struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c index 4b7757b8430..401b976e3af 100644 --- a/drivers/mfd/omap-usb-tll.c +++ b/drivers/mfd/omap-usb-tll.c @@ -200,7 +200,7 @@ static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode) * * Allocates basic resources for this USB host controller. */ -static int __devinit usbtll_omap_probe(struct platform_device *pdev) +static int usbtll_omap_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct usbtll_omap_platform_data *pdata = dev->platform_data; @@ -348,7 +348,7 @@ end: * * Reverses the effect of usbtll_omap_probe(). */ -static int __devexit usbtll_omap_remove(struct platform_device *pdev) +static int usbtll_omap_remove(struct platform_device *pdev) { struct usbtll_omap *tll = platform_get_drvdata(pdev); @@ -424,7 +424,7 @@ static struct platform_driver usbtll_omap_driver = { .pm = &usbtllomap_dev_pm_ops, }, .probe = usbtll_omap_probe, - .remove = __devexit_p(usbtll_omap_remove), + .remove = usbtll_omap_remove, }; int omap_tll_enable(void) diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index 4f8d6e6b19a..6ffd7a2affd 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -247,7 +247,7 @@ static struct regmap_irq_chip palmas_irq_chip = { PALMAS_INT1_MASK), }; -static void __devinit palmas_dt_to_pdata(struct device_node *node, +static void palmas_dt_to_pdata(struct device_node *node, struct palmas_platform_data *pdata) { int ret; @@ -275,7 +275,7 @@ static void __devinit palmas_dt_to_pdata(struct device_node *node, PALMAS_POWER_CTRL_ENABLE2_MASK; } -static int __devinit palmas_i2c_probe(struct i2c_client *i2c, +static int palmas_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct palmas *palmas; @@ -492,7 +492,7 @@ static const struct i2c_device_id palmas_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, palmas_i2c_id); -static struct of_device_id __devinitdata of_palmas_match_tbl[] = { +static struct of_device_id of_palmas_match_tbl[] = { { .compatible = "ti,palmas", }, { /* end */ } }; diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c index 3927c17e417..18b53cb72fe 100644 --- a/drivers/mfd/pcf50633-adc.c +++ b/drivers/mfd/pcf50633-adc.c @@ -199,7 +199,7 @@ static void pcf50633_adc_irq(int irq, void *data) kfree(req); } -static int __devinit pcf50633_adc_probe(struct platform_device *pdev) +static int pcf50633_adc_probe(struct platform_device *pdev) { struct pcf50633_adc *adc; @@ -218,7 +218,7 @@ static int __devinit pcf50633_adc_probe(struct platform_device *pdev) return 0; } -static int __devexit pcf50633_adc_remove(struct platform_device *pdev) +static int pcf50633_adc_remove(struct platform_device *pdev) { struct pcf50633_adc *adc = platform_get_drvdata(pdev); int i, head; @@ -246,7 +246,7 @@ static struct platform_driver pcf50633_adc_driver = { .name = "pcf50633-adc", }, .probe = pcf50633_adc_probe, - .remove = __devexit_p(pcf50633_adc_remove), + .remove = pcf50633_adc_remove, }; module_platform_driver(pcf50633_adc_driver); diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index 45ce1fb5a54..64803f13bce 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -191,7 +191,7 @@ static struct regmap_config pcf50633_regmap_config = { .val_bits = 8, }; -static int __devinit pcf50633_probe(struct i2c_client *client, +static int pcf50633_probe(struct i2c_client *client, const struct i2c_device_id *ids) { struct pcf50633 *pcf; @@ -275,7 +275,7 @@ static int __devinit pcf50633_probe(struct i2c_client *client, return 0; } -static int __devexit pcf50633_remove(struct i2c_client *client) +static int pcf50633_remove(struct i2c_client *client) { struct pcf50633 *pcf = i2c_get_clientdata(client); int i; @@ -308,7 +308,7 @@ static struct i2c_driver pcf50633_driver = { }, .id_table = pcf50633_id_table, .probe = pcf50633_probe, - .remove = __devexit_p(pcf50633_remove), + .remove = pcf50633_remove, }; static int __init pcf50633_init(void) diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c index e873b15753d..d4b297cbd80 100644 --- a/drivers/mfd/pm8921-core.c +++ b/drivers/mfd/pm8921-core.c @@ -80,7 +80,7 @@ static struct pm8xxx_drvdata pm8921_drvdata = { .pmic_read_irq_stat = pm8921_read_irq_stat, }; -static int __devinit pm8921_add_subdevices(const struct pm8921_platform_data +static int pm8921_add_subdevices(const struct pm8921_platform_data *pdata, struct pm8921 *pmic, u32 rev) @@ -104,7 +104,7 @@ static int __devinit pm8921_add_subdevices(const struct pm8921_platform_data return ret; } -static int __devinit pm8921_probe(struct platform_device *pdev) +static int pm8921_probe(struct platform_device *pdev) { const struct pm8921_platform_data *pdata = pdev->dev.platform_data; struct pm8921 *pmic; @@ -165,7 +165,7 @@ err_read_rev: return rc; } -static int __devexit pm8921_remove(struct platform_device *pdev) +static int pm8921_remove(struct platform_device *pdev) { struct pm8xxx_drvdata *drvdata; struct pm8921 *pmic = NULL; @@ -187,7 +187,7 @@ static int __devexit pm8921_remove(struct platform_device *pdev) static struct platform_driver pm8921_driver = { .probe = pm8921_probe, - .remove = __devexit_p(pm8921_remove), + .remove = pm8921_remove, .driver = { .name = "pm8921-core", .owner = THIS_MODULE, diff --git a/drivers/mfd/pm8xxx-irq.c b/drivers/mfd/pm8xxx-irq.c index d452dd01308..1360e20adf1 100644 --- a/drivers/mfd/pm8xxx-irq.c +++ b/drivers/mfd/pm8xxx-irq.c @@ -309,7 +309,7 @@ bail_out: } EXPORT_SYMBOL_GPL(pm8xxx_get_irq_stat); -struct pm_irq_chip * __devinit pm8xxx_irq_init(struct device *dev, +struct pm_irq_chip * pm8xxx_irq_init(struct device *dev, const struct pm8xxx_irq_platform_data *pdata) { struct pm_irq_chip *chip; @@ -363,7 +363,7 @@ struct pm_irq_chip * __devinit pm8xxx_irq_init(struct device *dev, return chip; } -int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip) +int pm8xxx_irq_exit(struct pm_irq_chip *chip) { irq_set_chained_handler(chip->devirq, NULL); kfree(chip); diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c index f1a024ecdb1..14bdaccefbe 100644 --- a/drivers/mfd/rc5t583.c +++ b/drivers/mfd/rc5t583.c @@ -246,7 +246,7 @@ static const struct regmap_config rc5t583_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c, +static int rc5t583_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct rc5t583 *rc5t583; @@ -303,7 +303,7 @@ err_add_devs: return ret; } -static int __devexit rc5t583_i2c_remove(struct i2c_client *i2c) +static int rc5t583_i2c_remove(struct i2c_client *i2c) { struct rc5t583 *rc5t583 = i2c_get_clientdata(i2c); @@ -325,7 +325,7 @@ static struct i2c_driver rc5t583_i2c_driver = { .owner = THIS_MODULE, }, .probe = rc5t583_i2c_probe, - .remove = __devexit_p(rc5t583_i2c_remove), + .remove = rc5t583_i2c_remove, .id_table = rc5t583_i2c_id, }; diff --git a/drivers/mfd/rdc321x-southbridge.c b/drivers/mfd/rdc321x-southbridge.c index fbabc3cbe35..21b7bef7350 100644 --- a/drivers/mfd/rdc321x-southbridge.c +++ b/drivers/mfd/rdc321x-southbridge.c @@ -72,7 +72,7 @@ static struct mfd_cell rdc321x_sb_cells[] = { }, }; -static int __devinit rdc321x_sb_probe(struct pci_dev *pdev, +static int rdc321x_sb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int err; @@ -91,7 +91,7 @@ static int __devinit rdc321x_sb_probe(struct pci_dev *pdev, NULL, 0, NULL); } -static void __devexit rdc321x_sb_remove(struct pci_dev *pdev) +static void rdc321x_sb_remove(struct pci_dev *pdev) { mfd_remove_devices(&pdev->dev); } @@ -106,7 +106,7 @@ static struct pci_driver rdc321x_sb_driver = { .name = "RDC321x Southbridge", .id_table = rdc321x_sb_table, .probe = rdc321x_sb_probe, - .remove = __devexit_p(rdc321x_sb_remove), + .remove = rdc321x_sb_remove, }; module_pci_driver(rdc321x_sb_driver); diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c new file mode 100644 index 00000000000..89f046ca9e4 --- /dev/null +++ b/drivers/mfd/rtl8411.c @@ -0,0 +1,251 @@ +/* Driver for Realtek PCI-Express card reader + * + * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * + * 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, 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, see <http://www.gnu.org/licenses/>. + * + * Author: + * Wei WANG <wei_wang@realsil.com.cn> + * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + */ + +#include <linux/module.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/mfd/rtsx_pci.h> + +#include "rtsx_pcr.h" + +static u8 rtl8411_get_ic_version(struct rtsx_pcr *pcr) +{ + u8 val; + + rtsx_pci_read_register(pcr, SYS_VER, &val); + return val & 0x0F; +} + +static int rtl8411_extra_init_hw(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, CD_PAD_CTL, + CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE); +} + +static int rtl8411_turn_on_led(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00); +} + +static int rtl8411_turn_off_led(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x01); +} + +static int rtl8411_enable_auto_blink(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0xFF, 0x0D); +} + +static int rtl8411_disable_auto_blink(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0x08, 0x00); +} + +static int rtl8411_card_power_on(struct rtsx_pcr *pcr, int card) +{ + int err; + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, + BPP_POWER_MASK, BPP_POWER_5_PERCENT_ON); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_CTL, + BPP_LDO_POWB, BPP_LDO_SUSPEND); + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + /* To avoid too large in-rush current */ + udelay(150); + + err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, + BPP_POWER_MASK, BPP_POWER_10_PERCENT_ON); + if (err < 0) + return err; + + udelay(150); + + err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, + BPP_POWER_MASK, BPP_POWER_15_PERCENT_ON); + if (err < 0) + return err; + + udelay(150); + + err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, + BPP_POWER_MASK, BPP_POWER_ON); + if (err < 0) + return err; + + return rtsx_pci_write_register(pcr, LDO_CTL, BPP_LDO_POWB, BPP_LDO_ON); +} + +static int rtl8411_card_power_off(struct rtsx_pcr *pcr, int card) +{ + int err; + + err = rtsx_pci_write_register(pcr, CARD_PWR_CTL, + BPP_POWER_MASK, BPP_POWER_OFF); + if (err < 0) + return err; + + return rtsx_pci_write_register(pcr, LDO_CTL, + BPP_LDO_POWB, BPP_LDO_SUSPEND); +} + +static unsigned int rtl8411_cd_deglitch(struct rtsx_pcr *pcr) +{ + unsigned int card_exist; + + card_exist = rtsx_pci_readl(pcr, RTSX_BIPR); + card_exist &= CARD_EXIST; + if (!card_exist) { + /* Enable card CD */ + rtsx_pci_write_register(pcr, CD_PAD_CTL, + CD_DISABLE_MASK, CD_ENABLE); + /* Enable card interrupt */ + rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x00); + return 0; + } + + if (hweight32(card_exist) > 1) { + rtsx_pci_write_register(pcr, CARD_PWR_CTL, + BPP_POWER_MASK, BPP_POWER_5_PERCENT_ON); + msleep(100); + + card_exist = rtsx_pci_readl(pcr, RTSX_BIPR); + if (card_exist & MS_EXIST) + card_exist = MS_EXIST; + else if (card_exist & SD_EXIST) + card_exist = SD_EXIST; + else + card_exist = 0; + + rtsx_pci_write_register(pcr, CARD_PWR_CTL, + BPP_POWER_MASK, BPP_POWER_OFF); + + dev_dbg(&(pcr->pci->dev), + "After CD deglitch, card_exist = 0x%x\n", + card_exist); + } + + if (card_exist & MS_EXIST) { + /* Disable SD interrupt */ + rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x40); + rtsx_pci_write_register(pcr, CD_PAD_CTL, + CD_DISABLE_MASK, MS_CD_EN_ONLY); + } else if (card_exist & SD_EXIST) { + /* Disable MS interrupt */ + rtsx_pci_write_register(pcr, EFUSE_CONTENT, 0xe0, 0x80); + rtsx_pci_write_register(pcr, CD_PAD_CTL, + CD_DISABLE_MASK, SD_CD_EN_ONLY); + } + + return card_exist; +} + +static const struct pcr_ops rtl8411_pcr_ops = { + .extra_init_hw = rtl8411_extra_init_hw, + .optimize_phy = NULL, + .turn_on_led = rtl8411_turn_on_led, + .turn_off_led = rtl8411_turn_off_led, + .enable_auto_blink = rtl8411_enable_auto_blink, + .disable_auto_blink = rtl8411_disable_auto_blink, + .card_power_on = rtl8411_card_power_on, + .card_power_off = rtl8411_card_power_off, + .cd_deglitch = rtl8411_cd_deglitch, +}; + +/* SD Pull Control Enable: + * SD_DAT[3:0] ==> pull up + * SD_CD ==> pull up + * SD_WP ==> pull up + * SD_CMD ==> pull up + * SD_CLK ==> pull down + */ +static const u32 rtl8411_sd_pull_ctl_enable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA), + RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0xA9), + RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09), + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x09), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), + 0, +}; + +/* SD Pull Control Disable: + * SD_DAT[3:0] ==> pull down + * SD_CD ==> pull up + * SD_WP ==> pull down + * SD_CMD ==> pull down + * SD_CLK ==> pull down + */ +static const u32 rtl8411_sd_pull_ctl_disable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), + RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95), + RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09), + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), + 0, +}; + +/* MS Pull Control Enable: + * MS CD ==> pull up + * others ==> pull down + */ +static const u32 rtl8411_ms_pull_ctl_enable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), + RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95), + RTSX_REG_PAIR(CARD_PULL_CTL4, 0x05), + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), + 0, +}; + +/* MS Pull Control Disable: + * MS CD ==> pull up + * others ==> pull down + */ +static const u32 rtl8411_ms_pull_ctl_disable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), + RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0x95), + RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09), + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04), + 0, +}; + +void rtl8411_init_params(struct rtsx_pcr *pcr) +{ + pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; + pcr->num_slots = 2; + pcr->ops = &rtl8411_pcr_ops; + + pcr->ic_version = rtl8411_get_ic_version(pcr); + pcr->sd_pull_ctl_enable_tbl = rtl8411_sd_pull_ctl_enable_tbl; + pcr->sd_pull_ctl_disable_tbl = rtl8411_sd_pull_ctl_disable_tbl; + pcr->ms_pull_ctl_enable_tbl = rtl8411_ms_pull_ctl_enable_tbl; + pcr->ms_pull_ctl_disable_tbl = rtl8411_ms_pull_ctl_disable_tbl; +} diff --git a/drivers/mfd/rts5209.c b/drivers/mfd/rts5209.c new file mode 100644 index 00000000000..283a4f14808 --- /dev/null +++ b/drivers/mfd/rts5209.c @@ -0,0 +1,223 @@ +/* Driver for Realtek PCI-Express card reader + * + * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * + * 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, 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, see <http://www.gnu.org/licenses/>. + * + * Author: + * Wei WANG <wei_wang@realsil.com.cn> + * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/mfd/rtsx_pci.h> + +#include "rtsx_pcr.h" + +static u8 rts5209_get_ic_version(struct rtsx_pcr *pcr) +{ + u8 val; + + val = rtsx_pci_readb(pcr, 0x1C); + return val & 0x0F; +} + +static void rts5209_init_vendor_cfg(struct rtsx_pcr *pcr) +{ + u32 val; + + rtsx_pci_read_config_dword(pcr, 0x724, &val); + dev_dbg(&(pcr->pci->dev), "Cfg 0x724: 0x%x\n", val); + + if (!(val & 0x80)) { + if (val & 0x08) + pcr->ms_pmos = false; + else + pcr->ms_pmos = true; + } +} + +static int rts5209_extra_init_hw(struct rtsx_pcr *pcr) +{ + rtsx_pci_init_cmd(pcr); + + /* Turn off LED */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO, 0xFF, 0x03); + /* Configure GPIO as output */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO_DIR, 0xFF, 0x03); + + return rtsx_pci_send_cmd(pcr, 100); +} + +static int rts5209_optimize_phy(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_phy_register(pcr, 0x00, 0xB966); +} + +static int rts5209_turn_on_led(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00); +} + +static int rts5209_turn_off_led(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x01); +} + +static int rts5209_enable_auto_blink(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0xFF, 0x0D); +} + +static int rts5209_disable_auto_blink(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, CARD_AUTO_BLINK, 0x08, 0x00); +} + +static int rts5209_card_power_on(struct rtsx_pcr *pcr, int card) +{ + int err; + u8 pwr_mask, partial_pwr_on, pwr_on; + + pwr_mask = SD_POWER_MASK; + partial_pwr_on = SD_PARTIAL_POWER_ON; + pwr_on = SD_POWER_ON; + + if (pcr->ms_pmos && (card == RTSX_MS_CARD)) { + pwr_mask = MS_POWER_MASK; + partial_pwr_on = MS_PARTIAL_POWER_ON; + pwr_on = MS_POWER_ON; + } + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, + pwr_mask, partial_pwr_on); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, + LDO3318_PWR_MASK, 0x04); + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + /* To avoid too large in-rush current */ + udelay(150); + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, pwr_mask, pwr_on); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, + LDO3318_PWR_MASK, 0x00); + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + return 0; +} + +static int rts5209_card_power_off(struct rtsx_pcr *pcr, int card) +{ + u8 pwr_mask, pwr_off; + + pwr_mask = SD_POWER_MASK; + pwr_off = SD_POWER_OFF; + + if (pcr->ms_pmos && (card == RTSX_MS_CARD)) { + pwr_mask = MS_POWER_MASK; + pwr_off = MS_POWER_OFF; + } + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, + pwr_mask | PMOS_STRG_MASK, pwr_off | PMOS_STRG_400mA); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, + LDO3318_PWR_MASK, 0X06); + return rtsx_pci_send_cmd(pcr, 100); +} + +static const struct pcr_ops rts5209_pcr_ops = { + .extra_init_hw = rts5209_extra_init_hw, + .optimize_phy = rts5209_optimize_phy, + .turn_on_led = rts5209_turn_on_led, + .turn_off_led = rts5209_turn_off_led, + .enable_auto_blink = rts5209_enable_auto_blink, + .disable_auto_blink = rts5209_disable_auto_blink, + .card_power_on = rts5209_card_power_on, + .card_power_off = rts5209_card_power_off, + .cd_deglitch = NULL, +}; + +/* SD Pull Control Enable: + * SD_DAT[3:0] ==> pull up + * SD_CD ==> pull up + * SD_WP ==> pull up + * SD_CMD ==> pull up + * SD_CLK ==> pull down + */ +static const u32 rts5209_sd_pull_ctl_enable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA), + RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9), + 0, +}; + +/* SD Pull Control Disable: + * SD_DAT[3:0] ==> pull down + * SD_CD ==> pull up + * SD_WP ==> pull down + * SD_CMD ==> pull down + * SD_CLK ==> pull down + */ +static const u32 rts5209_sd_pull_ctl_disable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL1, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5), + 0, +}; + +/* MS Pull Control Enable: + * MS CD ==> pull up + * others ==> pull down + */ +static const u32 rts5209_ms_pull_ctl_enable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), + 0, +}; + +/* MS Pull Control Disable: + * MS CD ==> pull up + * others ==> pull down + */ +static const u32 rts5209_ms_pull_ctl_disable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL4, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), + 0, +}; + +void rts5209_init_params(struct rtsx_pcr *pcr) +{ + pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | + EXTRA_CAPS_SD_SDR104 | EXTRA_CAPS_MMC_8BIT; + pcr->num_slots = 2; + pcr->ops = &rts5209_pcr_ops; + + rts5209_init_vendor_cfg(pcr); + + pcr->ic_version = rts5209_get_ic_version(pcr); + pcr->sd_pull_ctl_enable_tbl = rts5209_sd_pull_ctl_enable_tbl; + pcr->sd_pull_ctl_disable_tbl = rts5209_sd_pull_ctl_disable_tbl; + pcr->ms_pull_ctl_enable_tbl = rts5209_ms_pull_ctl_enable_tbl; + pcr->ms_pull_ctl_disable_tbl = rts5209_ms_pull_ctl_disable_tbl; +} diff --git a/drivers/mfd/rts5229.c b/drivers/mfd/rts5229.c new file mode 100644 index 00000000000..b9dbab266fd --- /dev/null +++ b/drivers/mfd/rts5229.c @@ -0,0 +1,205 @@ +/* Driver for Realtek PCI-Express card reader + * + * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * + * 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, 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, see <http://www.gnu.org/licenses/>. + * + * Author: + * Wei WANG <wei_wang@realsil.com.cn> + * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/mfd/rtsx_pci.h> + +#include "rtsx_pcr.h" + +static u8 rts5229_get_ic_version(struct rtsx_pcr *pcr) +{ + u8 val; + + rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val); + return val & 0x0F; +} + +static int rts5229_extra_init_hw(struct rtsx_pcr *pcr) +{ + rtsx_pci_init_cmd(pcr); + + /* Configure GPIO as output */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02); + /* Switch LDO3318 source from DV33 to card_3v3 */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01); + /* LED shine disabled, set initial shine cycle period */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02); + + return rtsx_pci_send_cmd(pcr, 100); +} + +static int rts5229_optimize_phy(struct rtsx_pcr *pcr) +{ + /* Optimize RX sensitivity */ + return rtsx_pci_write_phy_register(pcr, 0x00, 0xBA42); +} + +static int rts5229_turn_on_led(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x02); +} + +static int rts5229_turn_off_led(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, GPIO_CTL, 0x02, 0x00); +} + +static int rts5229_enable_auto_blink(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x08); +} + +static int rts5229_disable_auto_blink(struct rtsx_pcr *pcr) +{ + return rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x08, 0x00); +} + +static int rts5229_card_power_on(struct rtsx_pcr *pcr, int card) +{ + int err; + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, + SD_POWER_MASK, SD_PARTIAL_POWER_ON); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, + LDO3318_PWR_MASK, 0x02); + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + /* To avoid too large in-rush current */ + udelay(150); + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, + SD_POWER_MASK, SD_POWER_ON); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, + LDO3318_PWR_MASK, 0x06); + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + return 0; +} + +static int rts5229_card_power_off(struct rtsx_pcr *pcr, int card) +{ + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, + SD_POWER_MASK | PMOS_STRG_MASK, + SD_POWER_OFF | PMOS_STRG_400mA); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, + LDO3318_PWR_MASK, 0X00); + return rtsx_pci_send_cmd(pcr, 100); +} + +static const struct pcr_ops rts5229_pcr_ops = { + .extra_init_hw = rts5229_extra_init_hw, + .optimize_phy = rts5229_optimize_phy, + .turn_on_led = rts5229_turn_on_led, + .turn_off_led = rts5229_turn_off_led, + .enable_auto_blink = rts5229_enable_auto_blink, + .disable_auto_blink = rts5229_disable_auto_blink, + .card_power_on = rts5229_card_power_on, + .card_power_off = rts5229_card_power_off, + .cd_deglitch = NULL, +}; + +/* SD Pull Control Enable: + * SD_DAT[3:0] ==> pull up + * SD_CD ==> pull up + * SD_WP ==> pull up + * SD_CMD ==> pull up + * SD_CLK ==> pull down + */ +static const u32 rts5229_sd_pull_ctl_enable_tbl1[] = { + RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9), + 0, +}; + +/* For RTS5229 version C */ +static const u32 rts5229_sd_pull_ctl_enable_tbl2[] = { + RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD9), + 0, +}; + +/* SD Pull Control Disable: + * SD_DAT[3:0] ==> pull down + * SD_CD ==> pull up + * SD_WP ==> pull down + * SD_CMD ==> pull down + * SD_CLK ==> pull down + */ +static const u32 rts5229_sd_pull_ctl_disable_tbl1[] = { + RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5), + 0, +}; + +/* For RTS5229 version C */ +static const u32 rts5229_sd_pull_ctl_disable_tbl2[] = { + RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE5), + 0, +}; + +/* MS Pull Control Enable: + * MS CD ==> pull up + * others ==> pull down + */ +static const u32 rts5229_ms_pull_ctl_enable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), + 0, +}; + +/* MS Pull Control Disable: + * MS CD ==> pull up + * others ==> pull down + */ +static const u32 rts5229_ms_pull_ctl_disable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x15), + 0, +}; + +void rts5229_init_params(struct rtsx_pcr *pcr) +{ + pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; + pcr->num_slots = 2; + pcr->ops = &rts5229_pcr_ops; + + pcr->ic_version = rts5229_get_ic_version(pcr); + if (pcr->ic_version == IC_VER_C) { + pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl2; + pcr->sd_pull_ctl_disable_tbl = rts5229_sd_pull_ctl_disable_tbl2; + } else { + pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl1; + pcr->sd_pull_ctl_disable_tbl = rts5229_sd_pull_ctl_disable_tbl1; + } + pcr->ms_pull_ctl_enable_tbl = rts5229_ms_pull_ctl_enable_tbl; + pcr->ms_pull_ctl_disable_tbl = rts5229_ms_pull_ctl_disable_tbl; +} diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c new file mode 100644 index 00000000000..56d4377c62c --- /dev/null +++ b/drivers/mfd/rtsx_pcr.c @@ -0,0 +1,1251 @@ +/* Driver for Realtek PCI-Express card reader + * + * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * + * 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, 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, see <http://www.gnu.org/licenses/>. + * + * Author: + * Wei WANG <wei_wang@realsil.com.cn> + * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + */ + +#include <linux/pci.h> +#include <linux/module.h> +#include <linux/dma-mapping.h> +#include <linux/highmem.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/idr.h> +#include <linux/platform_device.h> +#include <linux/mfd/core.h> +#include <linux/mfd/rtsx_pci.h> +#include <asm/unaligned.h> + +#include "rtsx_pcr.h" + +static bool msi_en = true; +module_param(msi_en, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(msi_en, "Enable MSI"); + +static DEFINE_IDR(rtsx_pci_idr); +static DEFINE_SPINLOCK(rtsx_pci_lock); + +static struct mfd_cell rtsx_pcr_cells[] = { + [RTSX_SD_CARD] = { + .name = DRV_NAME_RTSX_PCI_SDMMC, + }, + [RTSX_MS_CARD] = { + .name = DRV_NAME_RTSX_PCI_MS, + }, +}; + +static DEFINE_PCI_DEVICE_TABLE(rtsx_pci_ids) = { + { PCI_DEVICE(0x10EC, 0x5209), PCI_CLASS_OTHERS << 16, 0xFF0000 }, + { PCI_DEVICE(0x10EC, 0x5229), PCI_CLASS_OTHERS << 16, 0xFF0000 }, + { PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, rtsx_pci_ids); + +void rtsx_pci_start_run(struct rtsx_pcr *pcr) +{ + /* If pci device removed, don't queue idle work any more */ + if (pcr->remove_pci) + return; + + if (pcr->state != PDEV_STAT_RUN) { + pcr->state = PDEV_STAT_RUN; + if (pcr->ops->enable_auto_blink) + pcr->ops->enable_auto_blink(pcr); + } + + mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200)); +} +EXPORT_SYMBOL_GPL(rtsx_pci_start_run); + +int rtsx_pci_write_register(struct rtsx_pcr *pcr, u16 addr, u8 mask, u8 data) +{ + int i; + u32 val = HAIMR_WRITE_START; + + val |= (u32)(addr & 0x3FFF) << 16; + val |= (u32)mask << 8; + val |= (u32)data; + + rtsx_pci_writel(pcr, RTSX_HAIMR, val); + + for (i = 0; i < MAX_RW_REG_CNT; i++) { + val = rtsx_pci_readl(pcr, RTSX_HAIMR); + if ((val & HAIMR_TRANS_END) == 0) { + if (data != (u8)val) + return -EIO; + return 0; + } + } + + return -ETIMEDOUT; +} +EXPORT_SYMBOL_GPL(rtsx_pci_write_register); + +int rtsx_pci_read_register(struct rtsx_pcr *pcr, u16 addr, u8 *data) +{ + u32 val = HAIMR_READ_START; + int i; + + val |= (u32)(addr & 0x3FFF) << 16; + rtsx_pci_writel(pcr, RTSX_HAIMR, val); + + for (i = 0; i < MAX_RW_REG_CNT; i++) { + val = rtsx_pci_readl(pcr, RTSX_HAIMR); + if ((val & HAIMR_TRANS_END) == 0) + break; + } + + if (i >= MAX_RW_REG_CNT) + return -ETIMEDOUT; + + if (data) + *data = (u8)(val & 0xFF); + + return 0; +} +EXPORT_SYMBOL_GPL(rtsx_pci_read_register); + +int rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val) +{ + int err, i, finished = 0; + u8 tmp; + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYDATA0, 0xFF, (u8)val); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYDATA1, 0xFF, (u8)(val >> 8)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x81); + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + for (i = 0; i < 100000; i++) { + err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp); + if (err < 0) + return err; + + if (!(tmp & 0x80)) { + finished = 1; + break; + } + } + + if (!finished) + return -ETIMEDOUT; + + return 0; +} +EXPORT_SYMBOL_GPL(rtsx_pci_write_phy_register); + +int rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val) +{ + int err, i, finished = 0; + u16 data; + u8 *ptr, tmp; + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x80); + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + for (i = 0; i < 100000; i++) { + err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp); + if (err < 0) + return err; + + if (!(tmp & 0x80)) { + finished = 1; + break; + } + } + + if (!finished) + return -ETIMEDOUT; + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA0, 0, 0); + rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA1, 0, 0); + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + ptr = rtsx_pci_get_cmd_data(pcr); + data = ((u16)ptr[1] << 8) | ptr[0]; + + if (val) + *val = data; + + return 0; +} +EXPORT_SYMBOL_GPL(rtsx_pci_read_phy_register); + +void rtsx_pci_stop_cmd(struct rtsx_pcr *pcr) +{ + rtsx_pci_writel(pcr, RTSX_HCBCTLR, STOP_CMD); + rtsx_pci_writel(pcr, RTSX_HDBCTLR, STOP_DMA); + + rtsx_pci_write_register(pcr, DMACTL, 0x80, 0x80); + rtsx_pci_write_register(pcr, RBCTL, 0x80, 0x80); +} +EXPORT_SYMBOL_GPL(rtsx_pci_stop_cmd); + +void rtsx_pci_add_cmd(struct rtsx_pcr *pcr, + u8 cmd_type, u16 reg_addr, u8 mask, u8 data) +{ + unsigned long flags; + u32 val = 0; + u32 *ptr = (u32 *)(pcr->host_cmds_ptr); + + val |= (u32)(cmd_type & 0x03) << 30; + val |= (u32)(reg_addr & 0x3FFF) << 16; + val |= (u32)mask << 8; + val |= (u32)data; + + spin_lock_irqsave(&pcr->lock, flags); + ptr += pcr->ci; + if (pcr->ci < (HOST_CMDS_BUF_LEN / 4)) { + put_unaligned_le32(val, ptr); + ptr++; + pcr->ci++; + } + spin_unlock_irqrestore(&pcr->lock, flags); +} +EXPORT_SYMBOL_GPL(rtsx_pci_add_cmd); + +void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr) +{ + u32 val = 1 << 31; + + rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr); + + val |= (u32)(pcr->ci * 4) & 0x00FFFFFF; + /* Hardware Auto Response */ + val |= 0x40000000; + rtsx_pci_writel(pcr, RTSX_HCBCTLR, val); +} +EXPORT_SYMBOL_GPL(rtsx_pci_send_cmd_no_wait); + +int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout) +{ + struct completion trans_done; + u32 val = 1 << 31; + long timeleft; + unsigned long flags; + int err = 0; + + spin_lock_irqsave(&pcr->lock, flags); + + /* set up data structures for the wakeup system */ + pcr->done = &trans_done; + pcr->trans_result = TRANS_NOT_READY; + init_completion(&trans_done); + + rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr); + + val |= (u32)(pcr->ci * 4) & 0x00FFFFFF; + /* Hardware Auto Response */ + val |= 0x40000000; + rtsx_pci_writel(pcr, RTSX_HCBCTLR, val); + + spin_unlock_irqrestore(&pcr->lock, flags); + + /* Wait for TRANS_OK_INT */ + timeleft = wait_for_completion_interruptible_timeout( + &trans_done, msecs_to_jiffies(timeout)); + if (timeleft <= 0) { + dev_dbg(&(pcr->pci->dev), "Timeout (%s %d)\n", + __func__, __LINE__); + err = -ETIMEDOUT; + goto finish_send_cmd; + } + + spin_lock_irqsave(&pcr->lock, flags); + if (pcr->trans_result == TRANS_RESULT_FAIL) + err = -EINVAL; + else if (pcr->trans_result == TRANS_RESULT_OK) + err = 0; + else if (pcr->trans_result == TRANS_NO_DEVICE) + err = -ENODEV; + spin_unlock_irqrestore(&pcr->lock, flags); + +finish_send_cmd: + spin_lock_irqsave(&pcr->lock, flags); + pcr->done = NULL; + spin_unlock_irqrestore(&pcr->lock, flags); + + if ((err < 0) && (err != -ENODEV)) + rtsx_pci_stop_cmd(pcr); + + if (pcr->finish_me) + complete(pcr->finish_me); + + return err; +} +EXPORT_SYMBOL_GPL(rtsx_pci_send_cmd); + +static void rtsx_pci_add_sg_tbl(struct rtsx_pcr *pcr, + dma_addr_t addr, unsigned int len, int end) +{ + u64 *ptr = (u64 *)(pcr->host_sg_tbl_ptr) + pcr->sgi; + u64 val; + u8 option = SG_VALID | SG_TRANS_DATA; + + dev_dbg(&(pcr->pci->dev), "DMA addr: 0x%x, Len: 0x%x\n", + (unsigned int)addr, len); + + if (end) + option |= SG_END; + val = ((u64)addr << 32) | ((u64)len << 12) | option; + + put_unaligned_le64(val, ptr); + ptr++; + pcr->sgi++; +} + +int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist, + int num_sg, bool read, int timeout) +{ + struct completion trans_done; + u8 dir; + int err = 0, i, count; + long timeleft; + unsigned long flags; + struct scatterlist *sg; + enum dma_data_direction dma_dir; + u32 val; + dma_addr_t addr; + unsigned int len; + + dev_dbg(&(pcr->pci->dev), "--> %s: num_sg = %d\n", __func__, num_sg); + + /* don't transfer data during abort processing */ + if (pcr->remove_pci) + return -EINVAL; + + if ((sglist == NULL) || (num_sg <= 0)) + return -EINVAL; + + if (read) { + dir = DEVICE_TO_HOST; + dma_dir = DMA_FROM_DEVICE; + } else { + dir = HOST_TO_DEVICE; + dma_dir = DMA_TO_DEVICE; + } + + count = dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir); + if (count < 1) { + dev_err(&(pcr->pci->dev), "scatterlist map failed\n"); + return -EINVAL; + } + dev_dbg(&(pcr->pci->dev), "DMA mapping count: %d\n", count); + + val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE; + pcr->sgi = 0; + for_each_sg(sglist, sg, count, i) { + addr = sg_dma_address(sg); + len = sg_dma_len(sg); + rtsx_pci_add_sg_tbl(pcr, addr, len, i == count - 1); + } + + spin_lock_irqsave(&pcr->lock, flags); + + pcr->done = &trans_done; + pcr->trans_result = TRANS_NOT_READY; + init_completion(&trans_done); + rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr); + rtsx_pci_writel(pcr, RTSX_HDBCTLR, val); + + spin_unlock_irqrestore(&pcr->lock, flags); + + timeleft = wait_for_completion_interruptible_timeout( + &trans_done, msecs_to_jiffies(timeout)); + if (timeleft <= 0) { + dev_dbg(&(pcr->pci->dev), "Timeout (%s %d)\n", + __func__, __LINE__); + err = -ETIMEDOUT; + goto out; + } + + spin_lock_irqsave(&pcr->lock, flags); + + if (pcr->trans_result == TRANS_RESULT_FAIL) + err = -EINVAL; + else if (pcr->trans_result == TRANS_NO_DEVICE) + err = -ENODEV; + + spin_unlock_irqrestore(&pcr->lock, flags); + +out: + spin_lock_irqsave(&pcr->lock, flags); + pcr->done = NULL; + spin_unlock_irqrestore(&pcr->lock, flags); + + dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir); + + if ((err < 0) && (err != -ENODEV)) + rtsx_pci_stop_cmd(pcr); + + if (pcr->finish_me) + complete(pcr->finish_me); + + return err; +} +EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data); + +int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len) +{ + int err; + int i, j; + u16 reg; + u8 *ptr; + + if (buf_len > 512) + buf_len = 512; + + ptr = buf; + reg = PPBUF_BASE2; + for (i = 0; i < buf_len / 256; i++) { + rtsx_pci_init_cmd(pcr); + + for (j = 0; j < 256; j++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, reg++, 0, 0); + + err = rtsx_pci_send_cmd(pcr, 250); + if (err < 0) + return err; + + memcpy(ptr, rtsx_pci_get_cmd_data(pcr), 256); + ptr += 256; + } + + if (buf_len % 256) { + rtsx_pci_init_cmd(pcr); + + for (j = 0; j < buf_len % 256; j++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, reg++, 0, 0); + + err = rtsx_pci_send_cmd(pcr, 250); + if (err < 0) + return err; + } + + memcpy(ptr, rtsx_pci_get_cmd_data(pcr), buf_len % 256); + + return 0; +} +EXPORT_SYMBOL_GPL(rtsx_pci_read_ppbuf); + +int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len) +{ + int err; + int i, j; + u16 reg; + u8 *ptr; + + if (buf_len > 512) + buf_len = 512; + + ptr = buf; + reg = PPBUF_BASE2; + for (i = 0; i < buf_len / 256; i++) { + rtsx_pci_init_cmd(pcr); + + for (j = 0; j < 256; j++) { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + reg++, 0xFF, *ptr); + ptr++; + } + + err = rtsx_pci_send_cmd(pcr, 250); + if (err < 0) + return err; + } + + if (buf_len % 256) { + rtsx_pci_init_cmd(pcr); + + for (j = 0; j < buf_len % 256; j++) { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + reg++, 0xFF, *ptr); + ptr++; + } + + err = rtsx_pci_send_cmd(pcr, 250); + if (err < 0) + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rtsx_pci_write_ppbuf); + +static int rtsx_pci_set_pull_ctl(struct rtsx_pcr *pcr, const u32 *tbl) +{ + int err; + + rtsx_pci_init_cmd(pcr); + + while (*tbl & 0xFFFF0000) { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + (u16)(*tbl >> 16), 0xFF, (u8)(*tbl)); + tbl++; + } + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + return 0; +} + +int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card) +{ + const u32 *tbl; + + if (card == RTSX_SD_CARD) + tbl = pcr->sd_pull_ctl_enable_tbl; + else if (card == RTSX_MS_CARD) + tbl = pcr->ms_pull_ctl_enable_tbl; + else + return -EINVAL; + + return rtsx_pci_set_pull_ctl(pcr, tbl); +} +EXPORT_SYMBOL_GPL(rtsx_pci_card_pull_ctl_enable); + +int rtsx_pci_card_pull_ctl_disable(struct rtsx_pcr *pcr, int card) +{ + const u32 *tbl; + + if (card == RTSX_SD_CARD) + tbl = pcr->sd_pull_ctl_disable_tbl; + else if (card == RTSX_MS_CARD) + tbl = pcr->ms_pull_ctl_disable_tbl; + else + return -EINVAL; + + + return rtsx_pci_set_pull_ctl(pcr, tbl); +} +EXPORT_SYMBOL_GPL(rtsx_pci_card_pull_ctl_disable); + +static void rtsx_pci_enable_bus_int(struct rtsx_pcr *pcr) +{ + pcr->bier = TRANS_OK_INT_EN | TRANS_FAIL_INT_EN | SD_INT_EN; + + if (pcr->num_slots > 1) + pcr->bier |= MS_INT_EN; + + /* Enable Bus Interrupt */ + rtsx_pci_writel(pcr, RTSX_BIER, pcr->bier); + + dev_dbg(&(pcr->pci->dev), "RTSX_BIER: 0x%08x\n", pcr->bier); +} + +static inline u8 double_ssc_depth(u8 depth) +{ + return ((depth > 1) ? (depth - 1) : depth); +} + +static u8 revise_ssc_depth(u8 ssc_depth, u8 div) +{ + if (div > CLK_DIV_1) { + if (ssc_depth > (div - 1)) + ssc_depth -= (div - 1); + else + ssc_depth = SSC_DEPTH_4M; + } + + return ssc_depth; +} + +int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock, + u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk) +{ + int err, clk; + u8 N, min_N, max_N, clk_divider; + u8 mcu_cnt, div, max_div; + u8 depth[] = { + [RTSX_SSC_DEPTH_4M] = SSC_DEPTH_4M, + [RTSX_SSC_DEPTH_2M] = SSC_DEPTH_2M, + [RTSX_SSC_DEPTH_1M] = SSC_DEPTH_1M, + [RTSX_SSC_DEPTH_500K] = SSC_DEPTH_500K, + [RTSX_SSC_DEPTH_250K] = SSC_DEPTH_250K, + }; + + if (initial_mode) { + /* We use 250k(around) here, in initial stage */ + clk_divider = SD_CLK_DIVIDE_128; + card_clock = 30000000; + } else { + clk_divider = SD_CLK_DIVIDE_0; + } + err = rtsx_pci_write_register(pcr, SD_CFG1, + SD_CLK_DIVIDE_MASK, clk_divider); + if (err < 0) + return err; + + card_clock /= 1000000; + dev_dbg(&(pcr->pci->dev), "Switch card clock to %dMHz\n", card_clock); + + min_N = 80; + max_N = 208; + max_div = CLK_DIV_8; + + clk = card_clock; + if (!initial_mode && double_clk) + clk = card_clock * 2; + dev_dbg(&(pcr->pci->dev), + "Internal SSC clock: %dMHz (cur_clock = %d)\n", + clk, pcr->cur_clock); + + if (clk == pcr->cur_clock) + return 0; + + N = (u8)(clk - 2); + if ((clk <= 2) || (N > max_N)) + return -EINVAL; + + mcu_cnt = (u8)(125/clk + 3); + if (mcu_cnt > 15) + mcu_cnt = 15; + + /* Make sure that the SSC clock div_n is equal or greater than min_N */ + div = CLK_DIV_1; + while ((N < min_N) && (div < max_div)) { + N = (N + 2) * 2 - 2; + div++; + } + dev_dbg(&(pcr->pci->dev), "N = %d, div = %d\n", N, div); + + ssc_depth = depth[ssc_depth]; + if (double_clk) + ssc_depth = double_ssc_depth(ssc_depth); + + ssc_depth = revise_ssc_depth(ssc_depth, div); + dev_dbg(&(pcr->pci->dev), "ssc_depth = %d\n", ssc_depth); + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, + CLK_LOW_FREQ, CLK_LOW_FREQ); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_DIV, + 0xFF, (div << 4) | mcu_cnt); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, + SSC_DEPTH_MASK, ssc_depth); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, N); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB); + if (vpclk) { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, + PHASE_NOT_RESET, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, + PHASE_NOT_RESET, PHASE_NOT_RESET); + } + + err = rtsx_pci_send_cmd(pcr, 2000); + if (err < 0) + return err; + + /* Wait SSC clock stable */ + udelay(10); + err = rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, 0); + if (err < 0) + return err; + + pcr->cur_clock = clk; + return 0; +} +EXPORT_SYMBOL_GPL(rtsx_pci_switch_clock); + +int rtsx_pci_card_power_on(struct rtsx_pcr *pcr, int card) +{ + if (pcr->ops->card_power_on) + return pcr->ops->card_power_on(pcr, card); + + return 0; +} +EXPORT_SYMBOL_GPL(rtsx_pci_card_power_on); + +int rtsx_pci_card_power_off(struct rtsx_pcr *pcr, int card) +{ + if (pcr->ops->card_power_off) + return pcr->ops->card_power_off(pcr, card); + + return 0; +} +EXPORT_SYMBOL_GPL(rtsx_pci_card_power_off); + +unsigned int rtsx_pci_card_exist(struct rtsx_pcr *pcr) +{ + unsigned int val; + + val = rtsx_pci_readl(pcr, RTSX_BIPR); + if (pcr->ops->cd_deglitch) + val = pcr->ops->cd_deglitch(pcr); + + return val; +} +EXPORT_SYMBOL_GPL(rtsx_pci_card_exist); + +void rtsx_pci_complete_unfinished_transfer(struct rtsx_pcr *pcr) +{ + struct completion finish; + + pcr->finish_me = &finish; + init_completion(&finish); + + if (pcr->done) + complete(pcr->done); + + if (!pcr->remove_pci) + rtsx_pci_stop_cmd(pcr); + + wait_for_completion_interruptible_timeout(&finish, + msecs_to_jiffies(2)); + pcr->finish_me = NULL; +} +EXPORT_SYMBOL_GPL(rtsx_pci_complete_unfinished_transfer); + +static void rtsx_pci_card_detect(struct work_struct *work) +{ + struct delayed_work *dwork; + struct rtsx_pcr *pcr; + unsigned long flags; + unsigned int card_detect = 0; + u32 irq_status; + + dwork = to_delayed_work(work); + pcr = container_of(dwork, struct rtsx_pcr, carddet_work); + + dev_dbg(&(pcr->pci->dev), "--> %s\n", __func__); + + spin_lock_irqsave(&pcr->lock, flags); + + irq_status = rtsx_pci_readl(pcr, RTSX_BIPR); + dev_dbg(&(pcr->pci->dev), "irq_status: 0x%08x\n", irq_status); + + if (pcr->card_inserted || pcr->card_removed) { + dev_dbg(&(pcr->pci->dev), + "card_inserted: 0x%x, card_removed: 0x%x\n", + pcr->card_inserted, pcr->card_removed); + + if (pcr->ops->cd_deglitch) + pcr->card_inserted = pcr->ops->cd_deglitch(pcr); + + card_detect = pcr->card_inserted | pcr->card_removed; + pcr->card_inserted = 0; + pcr->card_removed = 0; + } + + spin_unlock_irqrestore(&pcr->lock, flags); + + if (card_detect & SD_EXIST) + pcr->slots[RTSX_SD_CARD].card_event( + pcr->slots[RTSX_SD_CARD].p_dev); + if (card_detect & MS_EXIST) + pcr->slots[RTSX_MS_CARD].card_event( + pcr->slots[RTSX_MS_CARD].p_dev); +} + +static irqreturn_t rtsx_pci_isr(int irq, void *dev_id) +{ + struct rtsx_pcr *pcr = dev_id; + u32 int_reg; + + if (!pcr) + return IRQ_NONE; + + spin_lock(&pcr->lock); + + int_reg = rtsx_pci_readl(pcr, RTSX_BIPR); + /* Clear interrupt flag */ + rtsx_pci_writel(pcr, RTSX_BIPR, int_reg); + if ((int_reg & pcr->bier) == 0) { + spin_unlock(&pcr->lock); + return IRQ_NONE; + } + if (int_reg == 0xFFFFFFFF) { + spin_unlock(&pcr->lock); + return IRQ_HANDLED; + } + + int_reg &= (pcr->bier | 0x7FFFFF); + + if (int_reg & SD_INT) { + if (int_reg & SD_EXIST) { + pcr->card_inserted |= SD_EXIST; + } else { + pcr->card_removed |= SD_EXIST; + pcr->card_inserted &= ~SD_EXIST; + } + } + + if (int_reg & MS_INT) { + if (int_reg & MS_EXIST) { + pcr->card_inserted |= MS_EXIST; + } else { + pcr->card_removed |= MS_EXIST; + pcr->card_inserted &= ~MS_EXIST; + } + } + + if (pcr->card_inserted || pcr->card_removed) + schedule_delayed_work(&pcr->carddet_work, + msecs_to_jiffies(200)); + + if (int_reg & (NEED_COMPLETE_INT | DELINK_INT)) { + if (int_reg & (TRANS_FAIL_INT | DELINK_INT)) { + pcr->trans_result = TRANS_RESULT_FAIL; + if (pcr->done) + complete(pcr->done); + } else if (int_reg & TRANS_OK_INT) { + pcr->trans_result = TRANS_RESULT_OK; + if (pcr->done) + complete(pcr->done); + } + } + + spin_unlock(&pcr->lock); + return IRQ_HANDLED; +} + +static int rtsx_pci_acquire_irq(struct rtsx_pcr *pcr) +{ + dev_info(&(pcr->pci->dev), "%s: pcr->msi_en = %d, pci->irq = %d\n", + __func__, pcr->msi_en, pcr->pci->irq); + + if (request_irq(pcr->pci->irq, rtsx_pci_isr, + pcr->msi_en ? 0 : IRQF_SHARED, + DRV_NAME_RTSX_PCI, pcr)) { + dev_err(&(pcr->pci->dev), + "rtsx_sdmmc: unable to grab IRQ %d, disabling device\n", + pcr->pci->irq); + return -1; + } + + pcr->irq = pcr->pci->irq; + pci_intx(pcr->pci, !pcr->msi_en); + + return 0; +} + +static void rtsx_pci_idle_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work); + + dev_dbg(&(pcr->pci->dev), "--> %s\n", __func__); + + mutex_lock(&pcr->pcr_mutex); + + pcr->state = PDEV_STAT_IDLE; + + if (pcr->ops->disable_auto_blink) + pcr->ops->disable_auto_blink(pcr); + if (pcr->ops->turn_off_led) + pcr->ops->turn_off_led(pcr); + + mutex_unlock(&pcr->pcr_mutex); +} + +static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) +{ + int err; + + rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr); + + rtsx_pci_enable_bus_int(pcr); + + /* Power on SSC */ + err = rtsx_pci_write_register(pcr, FPDCTL, SSC_POWER_DOWN, 0); + if (err < 0) + return err; + + /* Wait SSC power stable */ + udelay(200); + + if (pcr->ops->optimize_phy) { + err = pcr->ops->optimize_phy(pcr); + if (err < 0) + return err; + } + + rtsx_pci_init_cmd(pcr); + + /* Set mcu_cnt to 7 to ensure data can be sampled properly */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_DIV, 0x07, 0x07); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, HOST_SLEEP_STATE, 0x03, 0x00); + /* Disable card clock */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, 0x1E, 0); + /* Reset ASPM state to default value */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); + /* Reset delink mode */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x0A, 0); + /* Card driving select */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL, + 0x07, DRIVER_TYPE_D); + /* Enable SSC Clock */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, + 0xFF, SSC_8X_EN | SSC_SEL_4M); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, 0xFF, 0x12); + /* Disable cd_pwr_save */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x16, 0x10); + /* Clear Link Ready Interrupt */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0, + LINK_RDY_INT, LINK_RDY_INT); + /* Enlarge the estimation window of PERST# glitch + * to reduce the chance of invalid card interrupt + */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PERST_GLITCH_WIDTH, 0xFF, 0x80); + /* Update RC oscillator to 400k + * bit[0] F_HIGH: for RC oscillator, Rst_value is 1'b1 + * 1: 2M 0: 400k + */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RCCTL, 0x01, 0x00); + /* Set interrupt write clear + * bit 1: U_elbi_if_rd_clr_en + * 1: Enable ELBI interrupt[31:22] & [7:0] flag read clear + * 0: ELBI interrupt flag[31:22] & [7:0] only can be write clear + */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, NFTS_TX_CTRL, 0x02, 0); + /* Force CLKREQ# PIN to drive 0 to request clock */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08); + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + /* Enable clk_request_n to enable clock power management */ + rtsx_pci_write_config_byte(pcr, 0x81, 1); + /* Enter L1 when host tx idle */ + rtsx_pci_write_config_byte(pcr, 0x70F, 0x5B); + + if (pcr->ops->extra_init_hw) { + err = pcr->ops->extra_init_hw(pcr); + if (err < 0) + return err; + } + + return 0; +} + +static int rtsx_pci_init_chip(struct rtsx_pcr *pcr) +{ + int err; + + spin_lock_init(&pcr->lock); + mutex_init(&pcr->pcr_mutex); + + switch (PCI_PID(pcr)) { + default: + case 0x5209: + rts5209_init_params(pcr); + break; + + case 0x5229: + rts5229_init_params(pcr); + break; + + case 0x5289: + rtl8411_init_params(pcr); + break; + } + + dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n", + PCI_PID(pcr), pcr->ic_version); + + pcr->slots = kcalloc(pcr->num_slots, sizeof(struct rtsx_slot), + GFP_KERNEL); + if (!pcr->slots) + return -ENOMEM; + + pcr->state = PDEV_STAT_IDLE; + err = rtsx_pci_init_hw(pcr); + if (err < 0) { + kfree(pcr->slots); + return err; + } + + return 0; +} + +static int __devinit rtsx_pci_probe(struct pci_dev *pcidev, + const struct pci_device_id *id) +{ + struct rtsx_pcr *pcr; + struct pcr_handle *handle; + u32 base, len; + int ret, i; + + dev_dbg(&(pcidev->dev), + ": Realtek PCI-E Card Reader found at %s [%04x:%04x] (rev %x)\n", + pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device, + (int)pcidev->revision); + + ret = pci_enable_device(pcidev); + if (ret) + return ret; + + ret = pci_request_regions(pcidev, DRV_NAME_RTSX_PCI); + if (ret) + goto disable; + + pcr = kzalloc(sizeof(*pcr), GFP_KERNEL); + if (!pcr) { + ret = -ENOMEM; + goto release_pci; + } + + handle = kzalloc(sizeof(*handle), GFP_KERNEL); + if (!handle) { + ret = -ENOMEM; + goto free_pcr; + } + handle->pcr = pcr; + + if (!idr_pre_get(&rtsx_pci_idr, GFP_KERNEL)) { + ret = -ENOMEM; + goto free_handle; + } + + spin_lock(&rtsx_pci_lock); + ret = idr_get_new(&rtsx_pci_idr, pcr, &pcr->id); + spin_unlock(&rtsx_pci_lock); + if (ret) + goto free_handle; + + pcr->pci = pcidev; + dev_set_drvdata(&pcidev->dev, handle); + + len = pci_resource_len(pcidev, 0); + base = pci_resource_start(pcidev, 0); + pcr->remap_addr = ioremap_nocache(base, len); + if (!pcr->remap_addr) { + ret = -ENOMEM; + goto free_host; + } + + pcr->rtsx_resv_buf = dma_alloc_coherent(&(pcidev->dev), + RTSX_RESV_BUF_LEN, &(pcr->rtsx_resv_buf_addr), + GFP_KERNEL); + if (pcr->rtsx_resv_buf == NULL) { + ret = -ENXIO; + goto unmap; + } + pcr->host_cmds_ptr = pcr->rtsx_resv_buf; + pcr->host_cmds_addr = pcr->rtsx_resv_buf_addr; + pcr->host_sg_tbl_ptr = pcr->rtsx_resv_buf + HOST_CMDS_BUF_LEN; + pcr->host_sg_tbl_addr = pcr->rtsx_resv_buf_addr + HOST_CMDS_BUF_LEN; + + pcr->card_inserted = 0; + pcr->card_removed = 0; + INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect); + INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work); + + pcr->msi_en = msi_en; + if (pcr->msi_en) { + ret = pci_enable_msi(pcidev); + if (ret < 0) + pcr->msi_en = false; + } + + ret = rtsx_pci_acquire_irq(pcr); + if (ret < 0) + goto free_dma; + + pci_set_master(pcidev); + synchronize_irq(pcr->irq); + + ret = rtsx_pci_init_chip(pcr); + if (ret < 0) + goto disable_irq; + + for (i = 0; i < ARRAY_SIZE(rtsx_pcr_cells); i++) { + rtsx_pcr_cells[i].platform_data = handle; + rtsx_pcr_cells[i].pdata_size = sizeof(*handle); + } + ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells, + ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL); + if (ret < 0) + goto disable_irq; + + schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200)); + + return 0; + +disable_irq: + free_irq(pcr->irq, (void *)pcr); +free_dma: + dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN, + pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr); +unmap: + iounmap(pcr->remap_addr); +free_host: + dev_set_drvdata(&pcidev->dev, NULL); +free_handle: + kfree(handle); +free_pcr: + kfree(pcr); +release_pci: + pci_release_regions(pcidev); +disable: + pci_disable_device(pcidev); + + return ret; +} + +static void __devexit rtsx_pci_remove(struct pci_dev *pcidev) +{ + struct pcr_handle *handle = pci_get_drvdata(pcidev); + struct rtsx_pcr *pcr = handle->pcr; + + pcr->remove_pci = true; + + cancel_delayed_work(&pcr->carddet_work); + cancel_delayed_work(&pcr->idle_work); + + mfd_remove_devices(&pcidev->dev); + + dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN, + pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr); + free_irq(pcr->irq, (void *)pcr); + if (pcr->msi_en) + pci_disable_msi(pcr->pci); + iounmap(pcr->remap_addr); + + dev_set_drvdata(&pcidev->dev, NULL); + pci_release_regions(pcidev); + pci_disable_device(pcidev); + + spin_lock(&rtsx_pci_lock); + idr_remove(&rtsx_pci_idr, pcr->id); + spin_unlock(&rtsx_pci_lock); + + kfree(pcr->slots); + kfree(pcr); + kfree(handle); + + dev_dbg(&(pcidev->dev), + ": Realtek PCI-E Card Reader at %s [%04x:%04x] has been removed\n", + pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device); +} + +#ifdef CONFIG_PM + +static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state) +{ + struct pcr_handle *handle; + struct rtsx_pcr *pcr; + int ret = 0; + + dev_dbg(&(pcidev->dev), "--> %s\n", __func__); + + handle = pci_get_drvdata(pcidev); + pcr = handle->pcr; + + cancel_delayed_work(&pcr->carddet_work); + cancel_delayed_work(&pcr->idle_work); + + mutex_lock(&pcr->pcr_mutex); + + if (pcr->ops->turn_off_led) + pcr->ops->turn_off_led(pcr); + + rtsx_pci_writel(pcr, RTSX_BIER, 0); + pcr->bier = 0; + + rtsx_pci_write_register(pcr, PETXCFG, 0x08, 0x08); + rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x02); + + pci_save_state(pcidev); + pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0); + pci_disable_device(pcidev); + pci_set_power_state(pcidev, pci_choose_state(pcidev, state)); + + mutex_unlock(&pcr->pcr_mutex); + return ret; +} + +static int rtsx_pci_resume(struct pci_dev *pcidev) +{ + struct pcr_handle *handle; + struct rtsx_pcr *pcr; + int ret = 0; + + dev_dbg(&(pcidev->dev), "--> %s\n", __func__); + + handle = pci_get_drvdata(pcidev); + pcr = handle->pcr; + + mutex_lock(&pcr->pcr_mutex); + + pci_set_power_state(pcidev, PCI_D0); + pci_restore_state(pcidev); + ret = pci_enable_device(pcidev); + if (ret) + goto out; + pci_set_master(pcidev); + + ret = rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00); + if (ret) + goto out; + + ret = rtsx_pci_init_hw(pcr); + if (ret) + goto out; + + schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200)); + +out: + mutex_unlock(&pcr->pcr_mutex); + return ret; +} + +#else /* CONFIG_PM */ + +#define rtsx_pci_suspend NULL +#define rtsx_pci_resume NULL + +#endif /* CONFIG_PM */ + +static struct pci_driver rtsx_pci_driver = { + .name = DRV_NAME_RTSX_PCI, + .id_table = rtsx_pci_ids, + .probe = rtsx_pci_probe, + .remove = __devexit_p(rtsx_pci_remove), + .suspend = rtsx_pci_suspend, + .resume = rtsx_pci_resume, +}; +module_pci_driver(rtsx_pci_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Wei WANG <wei_wang@realsil.com.cn>"); +MODULE_DESCRIPTION("Realtek PCI-E Card Reader Driver"); diff --git a/drivers/mfd/rtsx_pcr.h b/drivers/mfd/rtsx_pcr.h new file mode 100644 index 00000000000..12462c1df1a --- /dev/null +++ b/drivers/mfd/rtsx_pcr.h @@ -0,0 +1,32 @@ +/* Driver for Realtek PCI-Express card reader + * + * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * + * 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, 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, see <http://www.gnu.org/licenses/>. + * + * Author: + * Wei WANG <wei_wang@realsil.com.cn> + * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + */ + +#ifndef __RTSX_PCR_H +#define __RTSX_PCR_H + +#include <linux/mfd/rtsx_pci.h> + +void rts5209_init_params(struct rtsx_pcr *pcr); +void rts5229_init_params(struct rtsx_pcr *pcr); +void rtl8411_init_params(struct rtsx_pcr *pcr); + +#endif diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index d927dd49acb..9816c232e58 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -1014,7 +1014,7 @@ static struct gpio_chip gpio_chip_template = { .get = sm501_gpio_get, }; -static int __devinit sm501_gpio_register_chip(struct sm501_devdata *sm, +static int sm501_gpio_register_chip(struct sm501_devdata *sm, struct sm501_gpio *gpio, struct sm501_gpio_chip *chip) { @@ -1042,7 +1042,7 @@ static int __devinit sm501_gpio_register_chip(struct sm501_devdata *sm, return gpiochip_add(gchip); } -static int __devinit sm501_register_gpio(struct sm501_devdata *sm) +static int sm501_register_gpio(struct sm501_devdata *sm) { struct sm501_gpio *gpio = &sm->gpio; resource_size_t iobase = sm->io_res->start + SM501_GPIO; @@ -1313,7 +1313,7 @@ static unsigned int sm501_mem_local[] = { * Common init code for an SM501 */ -static int __devinit sm501_init_dev(struct sm501_devdata *sm) +static int sm501_init_dev(struct sm501_devdata *sm) { struct sm501_initdata *idata; struct sm501_platdata *pdata; @@ -1389,7 +1389,7 @@ static int __devinit sm501_init_dev(struct sm501_devdata *sm) return 0; } -static int __devinit sm501_plat_probe(struct platform_device *dev) +static int sm501_plat_probe(struct platform_device *dev) { struct sm501_devdata *sm; int ret; @@ -1578,7 +1578,7 @@ static struct sm501_platdata sm501_pci_platdata = { .gpio_base = -1, }; -static int __devinit sm501_pci_probe(struct pci_dev *dev, +static int sm501_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct sm501_devdata *sm; @@ -1685,7 +1685,7 @@ static void sm501_dev_remove(struct sm501_devdata *sm) sm501_gpio_remove(sm); } -static void __devexit sm501_pci_remove(struct pci_dev *dev) +static void sm501_pci_remove(struct pci_dev *dev) { struct sm501_devdata *sm = pci_get_drvdata(dev); @@ -1723,12 +1723,12 @@ static struct pci_driver sm501_pci_driver = { .name = "sm501", .id_table = sm501_pci_tbl, .probe = sm501_pci_probe, - .remove = __devexit_p(sm501_pci_remove), + .remove = sm501_pci_remove, }; MODULE_ALIAS("platform:sm501"); -static struct of_device_id __devinitdata of_sm501_match_tbl[] = { +static struct of_device_id of_sm501_match_tbl[] = { { .compatible = "smi,sm501", }, { /* end */ } }; diff --git a/drivers/mfd/sta2x11-mfd.c b/drivers/mfd/sta2x11-mfd.c index d35da6820be..d6284cacd27 100644 --- a/drivers/mfd/sta2x11-mfd.c +++ b/drivers/mfd/sta2x11-mfd.c @@ -69,7 +69,7 @@ static struct sta2x11_mfd *sta2x11_mfd_find(struct pci_dev *pdev) return NULL; } -static int __devinit sta2x11_mfd_add(struct pci_dev *pdev, gfp_t flags) +static int sta2x11_mfd_add(struct pci_dev *pdev, gfp_t flags) { struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev); struct sta2x11_instance *instance; @@ -89,7 +89,7 @@ static int __devinit sta2x11_mfd_add(struct pci_dev *pdev, gfp_t flags) return 0; } -static int __devexit mfd_remove(struct pci_dev *pdev) +static int mfd_remove(struct pci_dev *pdev) { struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev); @@ -305,7 +305,7 @@ enum bar1_cells { .flags = IORESOURCE_MEM, \ } -static const __devinitconst struct resource gpio_resources[] = { +static const struct resource gpio_resources[] = { { .name = "sta2x11_gpio", /* 4 consecutive cells, 1 driver */ .start = 0, @@ -313,31 +313,31 @@ static const __devinitconst struct resource gpio_resources[] = { .flags = IORESOURCE_MEM, } }; -static const __devinitconst struct resource sctl_resources[] = { +static const struct resource sctl_resources[] = { CELL_4K("sta2x11-sctl", STA2X11_SCTL), }; -static const __devinitconst struct resource scr_resources[] = { +static const struct resource scr_resources[] = { CELL_4K("sta2x11-scr", STA2X11_SCR), }; -static const __devinitconst struct resource time_resources[] = { +static const struct resource time_resources[] = { CELL_4K("sta2x11-time", STA2X11_TIME), }; -static const __devinitconst struct resource apbreg_resources[] = { +static const struct resource apbreg_resources[] = { CELL_4K("sta2x11-apbreg", STA2X11_APBREG), }; #define DEV(_name, _r) \ { .name = _name, .num_resources = ARRAY_SIZE(_r), .resources = _r, } -static __devinitdata struct mfd_cell sta2x11_mfd_bar0[] = { +static struct mfd_cell sta2x11_mfd_bar0[] = { DEV("sta2x11-gpio", gpio_resources), /* offset 0: we add pdata later */ DEV("sta2x11-sctl", sctl_resources), DEV("sta2x11-scr", scr_resources), DEV("sta2x11-time", time_resources), }; -static __devinitdata struct mfd_cell sta2x11_mfd_bar1[] = { +static struct mfd_cell sta2x11_mfd_bar1[] = { DEV("sta2x11-apbreg", apbreg_resources), }; @@ -363,7 +363,7 @@ static int sta2x11_mfd_resume(struct pci_dev *pdev) return 0; } -static int __devinit sta2x11_mfd_probe(struct pci_dev *pdev, +static int sta2x11_mfd_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) { int err, i; diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c index 947a06a1845..36df1877802 100644 --- a/drivers/mfd/stmpe-i2c.c +++ b/drivers/mfd/stmpe-i2c.c @@ -52,7 +52,7 @@ static struct stmpe_client_info i2c_ci = { .write_block = i2c_block_write, }; -static int __devinit +static int stmpe_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { i2c_ci.data = (void *)id; @@ -63,7 +63,7 @@ stmpe_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) return stmpe_probe(&i2c_ci, id->driver_data); } -static int __devexit stmpe_i2c_remove(struct i2c_client *i2c) +static int stmpe_i2c_remove(struct i2c_client *i2c) { struct stmpe *stmpe = dev_get_drvdata(&i2c->dev); @@ -88,7 +88,7 @@ static struct i2c_driver stmpe_i2c_driver = { .driver.pm = &stmpe_dev_pm_ops, #endif .probe = stmpe_i2c_probe, - .remove = __devexit_p(stmpe_i2c_remove), + .remove = stmpe_i2c_remove, .id_table = stmpe_i2c_id, }; diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c index 9edfe864cc0..973659f8abd 100644 --- a/drivers/mfd/stmpe-spi.c +++ b/drivers/mfd/stmpe-spi.c @@ -82,7 +82,7 @@ static struct stmpe_client_info spi_ci = { .init = spi_init, }; -static int __devinit +static int stmpe_spi_probe(struct spi_device *spi) { const struct spi_device_id *id = spi_get_device_id(spi); @@ -101,7 +101,7 @@ stmpe_spi_probe(struct spi_device *spi) return stmpe_probe(&spi_ci, id->driver_data); } -static int __devexit stmpe_spi_remove(struct spi_device *spi) +static int stmpe_spi_remove(struct spi_device *spi) { struct stmpe *stmpe = dev_get_drvdata(&spi->dev); @@ -128,7 +128,7 @@ static struct spi_driver stmpe_spi_driver = { #endif }, .probe = stmpe_spi_probe, - .remove = __devexit_p(stmpe_spi_remove), + .remove = stmpe_spi_remove, .id_table = stmpe_spi_id, }; diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index c94f521f392..79e88d1fd99 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -294,12 +294,14 @@ static struct resource stmpe_gpio_resources[] = { static struct mfd_cell stmpe_gpio_cell = { .name = "stmpe-gpio", + .of_compatible = "st,stmpe-gpio", .resources = stmpe_gpio_resources, .num_resources = ARRAY_SIZE(stmpe_gpio_resources), }; static struct mfd_cell stmpe_gpio_cell_noirq = { .name = "stmpe-gpio", + .of_compatible = "st,stmpe-gpio", /* gpio cell resources consist of an irq only so no resources here */ }; diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index 65fe609026c..3f10591ea94 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -97,7 +97,7 @@ static struct regmap_config syscon_regmap_config = { .reg_stride = 4, }; -static int __devinit syscon_probe(struct platform_device *pdev) +static int syscon_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; @@ -138,7 +138,7 @@ static int __devinit syscon_probe(struct platform_device *pdev) return 0; } -static int __devexit syscon_remove(struct platform_device *pdev) +static int syscon_remove(struct platform_device *pdev) { struct syscon *syscon; @@ -156,7 +156,7 @@ static struct platform_driver syscon_driver = { .of_match_table = of_syscon_match, }, .probe = syscon_probe, - .remove = __devexit_p(syscon_remove), + .remove = syscon_remove, }; static int __init syscon_init(void) diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index 8f4c853ca11..a06d66b929b 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c @@ -282,7 +282,7 @@ static int tc3589x_chip_init(struct tc3589x *tc3589x) return tc3589x_reg_write(tc3589x, TC3589x_RSTINTCLR, 0x1); } -static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) +static int tc3589x_device_init(struct tc3589x *tc3589x) { int ret = 0; unsigned int blocks = tc3589x->pdata->block; @@ -329,7 +329,7 @@ static int tc3589x_of_probe(struct device_node *np, return 0; } -static int __devinit tc3589x_probe(struct i2c_client *i2c, +static int tc3589x_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct tc3589x_platform_data *pdata = i2c->dev.platform_data; @@ -402,7 +402,7 @@ out_free: return ret; } -static int __devexit tc3589x_remove(struct i2c_client *client) +static int tc3589x_remove(struct i2c_client *client) { struct tc3589x *tc3589x = i2c_get_clientdata(client); @@ -458,7 +458,7 @@ static struct i2c_driver tc3589x_driver = { .driver.owner = THIS_MODULE, .driver.pm = &tc3589x_dev_pm_ops, .probe = tc3589x_probe, - .remove = __devexit_p(tc3589x_remove), + .remove = tc3589x_remove, .id_table = tc3589x_id, }; diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index 413c891102f..366f7b90627 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c @@ -138,7 +138,7 @@ static struct mfd_cell tc6387xb_cells[] = { }, }; -static int __devinit tc6387xb_probe(struct platform_device *dev) +static int tc6387xb_probe(struct platform_device *dev) { struct tc6387xb_platform_data *pdata = dev->dev.platform_data; struct resource *iomem, *rscr; @@ -208,7 +208,7 @@ err_no_irq: return ret; } -static int __devexit tc6387xb_remove(struct platform_device *dev) +static int tc6387xb_remove(struct platform_device *dev) { struct tc6387xb *tc6387xb = platform_get_drvdata(dev); @@ -229,7 +229,7 @@ static struct platform_driver tc6387xb_platform_driver = { .name = "tc6387xb", }, .probe = tc6387xb_probe, - .remove = __devexit_p(tc6387xb_remove), + .remove = tc6387xb_remove, .suspend = tc6387xb_suspend, .resume = tc6387xb_resume, }; diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index dcab026fcbb..15e1463e5e1 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -137,7 +137,7 @@ static int tc6393xb_nand_enable(struct platform_device *nand) return 0; } -static struct resource __devinitdata tc6393xb_nand_resources[] = { +static struct resource tc6393xb_nand_resources[] = { { .start = 0x1000, .end = 0x1007, @@ -196,7 +196,7 @@ static const struct resource tc6393xb_ohci_resources[] = { }, }; -static struct resource __devinitdata tc6393xb_fb_resources[] = { +static struct resource tc6393xb_fb_resources[] = { { .start = 0x5000, .end = 0x51ff, @@ -382,7 +382,7 @@ static struct tmio_mmc_data tc6393xb_mmc_data = { .set_clk_div = tc6393xb_mmc_clk_div, }; -static struct mfd_cell __devinitdata tc6393xb_cells[] = { +static struct mfd_cell tc6393xb_cells[] = { [TC6393XB_CELL_NAND] = { .name = "tmio-nand", .enable = tc6393xb_nand_enable, @@ -602,7 +602,7 @@ static void tc6393xb_detach_irq(struct platform_device *dev) /*--------------------------------------------------------------------------*/ -static int __devinit tc6393xb_probe(struct platform_device *dev) +static int tc6393xb_probe(struct platform_device *dev) { struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; struct tc6393xb *tc6393xb; @@ -731,7 +731,7 @@ err_kzalloc: return ret; } -static int __devexit tc6393xb_remove(struct platform_device *dev) +static int tc6393xb_remove(struct platform_device *dev) { struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; struct tc6393xb *tc6393xb = platform_get_drvdata(dev); @@ -831,7 +831,7 @@ static int tc6393xb_resume(struct platform_device *dev) static struct platform_driver tc6393xb_driver = { .probe = tc6393xb_probe, - .remove = __devexit_p(tc6393xb_remove), + .remove = tc6393xb_remove, .suspend = tc6393xb_suspend, .resume = tc6393xb_resume, diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c index 7c3675a74f9..09a14cec351 100644 --- a/drivers/mfd/ti-ssp.c +++ b/drivers/mfd/ti-ssp.c @@ -315,7 +315,7 @@ static irqreturn_t ti_ssp_interrupt(int irq, void *dev_data) return IRQ_HANDLED; } -static int __devinit ti_ssp_probe(struct platform_device *pdev) +static int ti_ssp_probe(struct platform_device *pdev) { static struct ti_ssp *ssp; const struct ti_ssp_data *pdata = pdev->dev.platform_data; @@ -433,7 +433,7 @@ error_res: return error; } -static int __devexit ti_ssp_remove(struct platform_device *pdev) +static int ti_ssp_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct ti_ssp *ssp = dev_get_drvdata(dev); @@ -451,7 +451,7 @@ static int __devexit ti_ssp_remove(struct platform_device *pdev) static struct platform_driver ti_ssp_driver = { .probe = ti_ssp_probe, - .remove = __devexit_p(ti_ssp_remove), + .remove = ti_ssp_remove, .driver = { .name = "ti-ssp", .owner = THIS_MODULE, diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index cccc626c83c..59e0ee247e8 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c @@ -75,13 +75,13 @@ static struct i2c_board_info timberdale_i2c_board_info[] = { }, }; -static __devinitdata struct xiic_i2c_platform_data +static struct xiic_i2c_platform_data timberdale_xiic_platform_data = { .devices = timberdale_i2c_board_info, .num_devices = ARRAY_SIZE(timberdale_i2c_board_info) }; -static __devinitdata struct ocores_i2c_platform_data +static struct ocores_i2c_platform_data timberdale_ocores_platform_data = { .reg_shift = 2, .clock_khz = 62500, @@ -89,7 +89,7 @@ timberdale_ocores_platform_data = { .num_devices = ARRAY_SIZE(timberdale_i2c_board_info) }; -static const __devinitconst struct resource timberdale_xiic_resources[] = { +static const struct resource timberdale_xiic_resources[] = { { .start = XIICOFFSET, .end = XIICEND, @@ -102,7 +102,7 @@ static const __devinitconst struct resource timberdale_xiic_resources[] = { }, }; -static const __devinitconst struct resource timberdale_ocores_resources[] = { +static const struct resource timberdale_ocores_resources[] = { { .start = OCORESOFFSET, .end = OCORESEND, @@ -143,7 +143,7 @@ static struct spi_board_info timberdale_spi_8bit_board_info[] = { }, }; -static __devinitdata struct xspi_platform_data timberdale_xspi_platform_data = { +static struct xspi_platform_data timberdale_xspi_platform_data = { .num_chipselect = 3, .little_endian = true, /* bits per word and devices will be filled in runtime depending @@ -151,7 +151,7 @@ static __devinitdata struct xspi_platform_data timberdale_xspi_platform_data = { */ }; -static const __devinitconst struct resource timberdale_spi_resources[] = { +static const struct resource timberdale_spi_resources[] = { { .start = SPIOFFSET, .end = SPIEND, @@ -164,13 +164,13 @@ static const __devinitconst struct resource timberdale_spi_resources[] = { }, }; -static __devinitdata struct ks8842_platform_data +static struct ks8842_platform_data timberdale_ks8842_platform_data = { .rx_dma_channel = DMA_ETH_RX, .tx_dma_channel = DMA_ETH_TX }; -static const __devinitconst struct resource timberdale_eth_resources[] = { +static const struct resource timberdale_eth_resources[] = { { .start = ETHOFFSET, .end = ETHEND, @@ -183,14 +183,14 @@ static const __devinitconst struct resource timberdale_eth_resources[] = { }, }; -static __devinitdata struct timbgpio_platform_data +static struct timbgpio_platform_data timberdale_gpio_platform_data = { .gpio_base = 0, .nr_pins = GPIO_NR_PINS, .irq_base = 200, }; -static const __devinitconst struct resource timberdale_gpio_resources[] = { +static const struct resource timberdale_gpio_resources[] = { { .start = GPIOOFFSET, .end = GPIOEND, @@ -203,7 +203,7 @@ static const __devinitconst struct resource timberdale_gpio_resources[] = { }, }; -static const __devinitconst struct resource timberdale_mlogicore_resources[] = { +static const struct resource timberdale_mlogicore_resources[] = { { .start = MLCOREOFFSET, .end = MLCOREEND, @@ -221,7 +221,7 @@ static const __devinitconst struct resource timberdale_mlogicore_resources[] = { }, }; -static const __devinitconst struct resource timberdale_uart_resources[] = { +static const struct resource timberdale_uart_resources[] = { { .start = UARTOFFSET, .end = UARTEND, @@ -234,7 +234,7 @@ static const __devinitconst struct resource timberdale_uart_resources[] = { }, }; -static const __devinitconst struct resource timberdale_uartlite_resources[] = { +static const struct resource timberdale_uartlite_resources[] = { { .start = UARTLITEOFFSET, .end = UARTLITEEND, @@ -247,13 +247,13 @@ static const __devinitconst struct resource timberdale_uartlite_resources[] = { }, }; -static __devinitdata struct i2c_board_info timberdale_adv7180_i2c_board_info = { +static struct i2c_board_info timberdale_adv7180_i2c_board_info = { /* Requires jumper JP9 to be off */ I2C_BOARD_INFO("adv7180", 0x42 >> 1), .irq = IRQ_TIMBERDALE_ADV7180 }; -static __devinitdata struct timb_video_platform_data +static struct timb_video_platform_data timberdale_video_platform_data = { .dma_channel = DMA_VIDEO_RX, .i2c_adapter = 0, @@ -262,7 +262,7 @@ static __devinitdata struct timb_video_platform_data } }; -static const __devinitconst struct resource +static const struct resource timberdale_radio_resources[] = { { .start = RDSOFFSET, @@ -276,22 +276,22 @@ timberdale_radio_resources[] = { }, }; -static __devinitdata struct i2c_board_info timberdale_tef6868_i2c_board_info = { +static struct i2c_board_info timberdale_tef6868_i2c_board_info = { I2C_BOARD_INFO("tef6862", 0x60) }; -static __devinitdata struct i2c_board_info timberdale_saa7706_i2c_board_info = { +static struct i2c_board_info timberdale_saa7706_i2c_board_info = { I2C_BOARD_INFO("saa7706h", 0x1C) }; -static __devinitdata struct timb_radio_platform_data +static struct timb_radio_platform_data timberdale_radio_platform_data = { .i2c_adapter = 0, .tuner = &timberdale_tef6868_i2c_board_info, .dsp = &timberdale_saa7706_i2c_board_info }; -static const __devinitconst struct resource timberdale_video_resources[] = { +static const struct resource timberdale_video_resources[] = { { .start = LOGIWOFFSET, .end = LOGIWEND, @@ -303,7 +303,7 @@ static const __devinitconst struct resource timberdale_video_resources[] = { */ }; -static __devinitdata struct timb_dma_platform_data timb_dma_platform_data = { +static struct timb_dma_platform_data timb_dma_platform_data = { .nr_channels = 10, .channels = { { @@ -362,7 +362,7 @@ static __devinitdata struct timb_dma_platform_data timb_dma_platform_data = { } }; -static const __devinitconst struct resource timberdale_dma_resources[] = { +static const struct resource timberdale_dma_resources[] = { { .start = DMAOFFSET, .end = DMAEND, @@ -375,7 +375,7 @@ static const __devinitconst struct resource timberdale_dma_resources[] = { }, }; -static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = { +static struct mfd_cell timberdale_cells_bar0_cfg0[] = { { .name = "timb-dma", .num_resources = ARRAY_SIZE(timberdale_dma_resources), @@ -432,7 +432,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = { }, }; -static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { +static struct mfd_cell timberdale_cells_bar0_cfg1[] = { { .name = "timb-dma", .num_resources = ARRAY_SIZE(timberdale_dma_resources), @@ -499,7 +499,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { }, }; -static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = { +static struct mfd_cell timberdale_cells_bar0_cfg2[] = { { .name = "timb-dma", .num_resources = ARRAY_SIZE(timberdale_dma_resources), @@ -549,7 +549,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = { }, }; -static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = { +static struct mfd_cell timberdale_cells_bar0_cfg3[] = { { .name = "timb-dma", .num_resources = ARRAY_SIZE(timberdale_dma_resources), @@ -606,7 +606,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = { }, }; -static const __devinitconst struct resource timberdale_sdhc_resources[] = { +static const struct resource timberdale_sdhc_resources[] = { /* located in bar 1 and bar 2 */ { .start = SDHC0OFFSET, @@ -620,7 +620,7 @@ static const __devinitconst struct resource timberdale_sdhc_resources[] = { }, }; -static __devinitdata struct mfd_cell timberdale_cells_bar1[] = { +static struct mfd_cell timberdale_cells_bar1[] = { { .name = "sdhci", .num_resources = ARRAY_SIZE(timberdale_sdhc_resources), @@ -628,7 +628,7 @@ static __devinitdata struct mfd_cell timberdale_cells_bar1[] = { }, }; -static __devinitdata struct mfd_cell timberdale_cells_bar2[] = { +static struct mfd_cell timberdale_cells_bar2[] = { { .name = "sdhci", .num_resources = ARRAY_SIZE(timberdale_sdhc_resources), @@ -650,7 +650,7 @@ static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL); /*--------------------------------------------------------------------------*/ -static int __devinit timb_probe(struct pci_dev *dev, +static int timb_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct timberdale_device *priv; @@ -840,7 +840,7 @@ err_enable: return -ENODEV; } -static void __devexit timb_remove(struct pci_dev *dev) +static void timb_remove(struct pci_dev *dev) { struct timberdale_device *priv = pci_get_drvdata(dev); @@ -867,7 +867,7 @@ static struct pci_driver timberdale_pci_driver = { .name = DRIVER_NAME, .id_table = timberdale_pci_tbl, .probe = timb_probe, - .remove = __devexit_p(timb_remove), + .remove = timb_remove, }; static int __init timberdale_init(void) diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c index 14051bdc714..1d302f583ad 100644 --- a/drivers/mfd/tps6105x.c +++ b/drivers/mfd/tps6105x.c @@ -86,7 +86,7 @@ fail: } EXPORT_SYMBOL(tps6105x_mask_and_set); -static int __devinit tps6105x_startup(struct tps6105x *tps6105x) +static int tps6105x_startup(struct tps6105x *tps6105x) { int ret; u8 regval; @@ -133,7 +133,7 @@ static struct mfd_cell tps6105x_cells[] = { }, }; -static int __devinit tps6105x_probe(struct i2c_client *client, +static int tps6105x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct tps6105x *tps6105x; @@ -199,7 +199,7 @@ fail: return ret; } -static int __devexit tps6105x_remove(struct i2c_client *client) +static int tps6105x_remove(struct i2c_client *client) { struct tps6105x *tps6105x = i2c_get_clientdata(client); @@ -226,7 +226,7 @@ static struct i2c_driver tps6105x_driver = { .name = "tps6105x", }, .probe = tps6105x_probe, - .remove = __devexit_p(tps6105x_remove), + .remove = tps6105x_remove, .id_table = tps6105x_id, }; diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c index 074ae32b0d2..382a857b0dd 100644 --- a/drivers/mfd/tps65090.c +++ b/drivers/mfd/tps65090.c @@ -188,7 +188,7 @@ static irqreturn_t tps65090_irq(int irq, void *data) return acks ? IRQ_HANDLED : IRQ_NONE; } -static int __devinit tps65090_irq_init(struct tps65090 *tps65090, int irq, +static int tps65090_irq_init(struct tps65090 *tps65090, int irq, int irq_base) { int i, ret; @@ -251,7 +251,7 @@ static const struct regmap_config tps65090_regmap_config = { .volatile_reg = is_volatile_reg, }; -static int __devinit tps65090_i2c_probe(struct i2c_client *client, +static int tps65090_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct tps65090_platform_data *pdata = client->dev.platform_data; @@ -308,7 +308,7 @@ err_exit: return ret; } -static int __devexit tps65090_i2c_remove(struct i2c_client *client) +static int tps65090_i2c_remove(struct i2c_client *client) { struct tps65090 *tps65090 = i2c_get_clientdata(client); @@ -354,7 +354,7 @@ static struct i2c_driver tps65090_driver = { .pm = &tps65090_pm_ops, }, .probe = tps65090_i2c_probe, - .remove = __devexit_p(tps65090_i2c_remove), + .remove = tps65090_i2c_remove, .id_table = tps65090_id_table, }; diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index 3fb32e65525..e14e252e347 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -153,7 +153,7 @@ static const struct of_device_id tps65217_of_match[] = { { /* sentinel */ }, }; -static int __devinit tps65217_probe(struct i2c_client *client, +static int tps65217_probe(struct i2c_client *client, const struct i2c_device_id *ids) { struct tps65217 *tps; @@ -214,7 +214,7 @@ static int __devinit tps65217_probe(struct i2c_client *client, return 0; } -static int __devexit tps65217_remove(struct i2c_client *client) +static int tps65217_remove(struct i2c_client *client) { struct tps65217 *tps = i2c_get_clientdata(client); @@ -237,7 +237,7 @@ static struct i2c_driver tps65217_driver = { }, .id_table = tps65217_id_table, .probe = tps65217_probe, - .remove = __devexit_p(tps65217_remove), + .remove = tps65217_remove, }; static int __init tps65217_init(void) diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 46746436877..9f92c3b2209 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -267,7 +267,7 @@ static irqreturn_t tps6586x_irq(int irq, void *data) return IRQ_HANDLED; } -static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq, +static int tps6586x_irq_init(struct tps6586x *tps6586x, int irq, int irq_base) { int i, ret; @@ -316,7 +316,7 @@ static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq, return ret; } -static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x, +static int tps6586x_add_subdevs(struct tps6586x *tps6586x, struct tps6586x_platform_data *pdata) { struct tps6586x_subdev_info *subdev; @@ -468,7 +468,7 @@ static void tps6586x_power_off(void) tps6586x_set_bits(tps6586x_dev, TPS6586X_SUPPLYENE, SLEEP_MODE_BIT); } -static int __devinit tps6586x_i2c_probe(struct i2c_client *client, +static int tps6586x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct tps6586x_platform_data *pdata = client->dev.platform_data; @@ -548,7 +548,7 @@ err_mfd_add: return ret; } -static int __devexit tps6586x_i2c_remove(struct i2c_client *client) +static int tps6586x_i2c_remove(struct i2c_client *client) { struct tps6586x *tps6586x = i2c_get_clientdata(client); @@ -572,7 +572,7 @@ static struct i2c_driver tps6586x_driver = { .of_match_table = of_match_ptr(tps6586x_of_match), }, .probe = tps6586x_i2c_probe, - .remove = __devexit_p(tps6586x_i2c_remove), + .remove = tps6586x_i2c_remove, .id_table = tps6586x_id_table, }; diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 0d79ce2b501..ce054654f5b 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -78,7 +78,7 @@ static const struct regmap_config tps65910_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int __devinit tps65910_ck32k_init(struct tps65910 *tps65910, +static int tps65910_ck32k_init(struct tps65910 *tps65910, struct tps65910_board *pmic_pdata) { int ret; @@ -96,7 +96,7 @@ static int __devinit tps65910_ck32k_init(struct tps65910 *tps65910, return 0; } -static int __devinit tps65910_sleepinit(struct tps65910 *tps65910, +static int tps65910_sleepinit(struct tps65910 *tps65910, struct tps65910_board *pmic_pdata) { struct device *dev = NULL; @@ -237,7 +237,7 @@ static void tps65910_power_off(void) DEVCTRL_DEV_ON_MASK); } -static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, +static int tps65910_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct tps65910 *tps65910; @@ -302,7 +302,7 @@ static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, return ret; } -static __devexit int tps65910_i2c_remove(struct i2c_client *i2c) +static int tps65910_i2c_remove(struct i2c_client *i2c) { struct tps65910 *tps65910 = i2c_get_clientdata(i2c); @@ -327,7 +327,7 @@ static struct i2c_driver tps65910_i2c_driver = { .of_match_table = of_match_ptr(tps65910_of_match), }, .probe = tps65910_i2c_probe, - .remove = __devexit_p(tps65910_i2c_remove), + .remove = tps65910_i2c_remove, .id_table = tps65910_i2c_id, }; diff --git a/drivers/mfd/tps65911-comparator.c b/drivers/mfd/tps65911-comparator.c index 0b6e361432c..c0816ebd9d7 100644 --- a/drivers/mfd/tps65911-comparator.c +++ b/drivers/mfd/tps65911-comparator.c @@ -122,7 +122,7 @@ static ssize_t comp_threshold_show(struct device *dev, static DEVICE_ATTR(comp1_threshold, S_IRUGO, comp_threshold_show, NULL); static DEVICE_ATTR(comp2_threshold, S_IRUGO, comp_threshold_show, NULL); -static __devinit int tps65911_comparator_probe(struct platform_device *pdev) +static int tps65911_comparator_probe(struct platform_device *pdev) { struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); struct tps65910_board *pdata = dev_get_platdata(tps65910->dev); @@ -152,7 +152,7 @@ static __devinit int tps65911_comparator_probe(struct platform_device *pdev) return ret; } -static __devexit int tps65911_comparator_remove(struct platform_device *pdev) +static int tps65911_comparator_remove(struct platform_device *pdev) { struct tps65910 *tps65910; @@ -169,7 +169,7 @@ static struct platform_driver tps65911_comparator_driver = { .owner = THIS_MODULE, }, .probe = tps65911_comparator_probe, - .remove = __devexit_p(tps65911_comparator_remove), + .remove = tps65911_comparator_remove, }; static int __init tps65911_comparator_init(void) diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c index 27d3302d56b..b45f460d299 100644 --- a/drivers/mfd/tps65912-spi.c +++ b/drivers/mfd/tps65912-spi.c @@ -81,7 +81,7 @@ static int tps65912_spi_read(struct tps65912 *tps65912, u8 addr, return ret; } -static int __devinit tps65912_spi_probe(struct spi_device *spi) +static int tps65912_spi_probe(struct spi_device *spi) { struct tps65912 *tps65912; @@ -99,7 +99,7 @@ static int __devinit tps65912_spi_probe(struct spi_device *spi) return tps65912_device_init(tps65912); } -static int __devexit tps65912_spi_remove(struct spi_device *spi) +static int tps65912_spi_remove(struct spi_device *spi) { struct tps65912 *tps65912 = spi_get_drvdata(spi); @@ -114,7 +114,7 @@ static struct spi_driver tps65912_spi_driver = { .owner = THIS_MODULE, }, .probe = tps65912_spi_probe, - .remove = __devexit_p(tps65912_spi_remove), + .remove = tps65912_spi_remove, }; static int __init tps65912_spi_init(void) diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 4ae64232020..11b76c0109f 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -671,7 +671,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } if (IS_ENABLED(CONFIG_PWM_TWL6030) && twl_class_is_6030()) { - child = add_child(TWL6030_MODULE_ID1, "twl6030-pwm", NULL, 0, + child = add_child(SUB_CHIP_ID1, "twl6030-pwm", NULL, 0, false, 0, 0); if (IS_ERR(child)) return PTR_ERR(child); @@ -1170,7 +1170,7 @@ static int twl_remove(struct i2c_client *client) } /* NOTE: This driver only handles a single twl4030/tps659x0 chip */ -static int __devinit +static int twl_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct twl4030_platform_data *pdata = client->dev.platform_data; diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index 5c11acf9e0f..e16edca9267 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -184,7 +184,7 @@ static bool twl4030_audio_has_vibra(struct twl4030_audio_data *pdata, return false; } -static int __devinit twl4030_audio_probe(struct platform_device *pdev) +static int twl4030_audio_probe(struct platform_device *pdev) { struct twl4030_audio *audio; struct twl4030_audio_data *pdata = pdev->dev.platform_data; @@ -269,7 +269,7 @@ static int __devinit twl4030_audio_probe(struct platform_device *pdev) return ret; } -static int __devexit twl4030_audio_remove(struct platform_device *pdev) +static int twl4030_audio_remove(struct platform_device *pdev) { mfd_remove_devices(&pdev->dev); platform_set_drvdata(pdev, NULL); @@ -291,7 +291,7 @@ static struct platform_driver twl4030_audio_driver = { .of_match_table = twl4030_audio_of_match, }, .probe = twl4030_audio_probe, - .remove = __devexit_p(twl4030_audio_remove), + .remove = twl4030_audio_remove, }; module_platform_driver(twl4030_audio_driver); diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index ad733d76207..cdd1173ed4e 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -672,7 +672,8 @@ int twl4030_sih_setup(struct device *dev, int module, int irq_base) irq = sih_mod + twl4030_irq_base; irq_set_handler_data(irq, agent); agent->irq_name = kasprintf(GFP_KERNEL, "twl4030_%s", sih->name); - status = request_threaded_irq(irq, NULL, handle_twl4030_sih, 0, + status = request_threaded_irq(irq, NULL, handle_twl4030_sih, + IRQF_EARLY_RESUME, agent->irq_name ?: sih->name, NULL); dev_info(dev, "%s (irq %d) chaining IRQs %d..%d\n", sih->name, diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index 456ecb5ac4f..a39dcf3e213 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c @@ -692,7 +692,7 @@ static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on) /* * Initialize MADC and request for threaded irq */ -static int __devinit twl4030_madc_probe(struct platform_device *pdev) +static int twl4030_madc_probe(struct platform_device *pdev) { struct twl4030_madc_data *madc; struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data; @@ -785,7 +785,7 @@ err_power: return ret; } -static int __devexit twl4030_madc_remove(struct platform_device *pdev) +static int twl4030_madc_remove(struct platform_device *pdev) { struct twl4030_madc_data *madc = platform_get_drvdata(pdev); diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index 79ca33dfacc..a5332063183 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -124,7 +124,7 @@ static u8 res_config_addrs[] = { [RES_MAIN_REF] = 0x94, }; -static int __devinit twl4030_write_script_byte(u8 address, u8 byte) +static int twl4030_write_script_byte(u8 address, u8 byte) { int err; @@ -138,7 +138,7 @@ out: return err; } -static int __devinit twl4030_write_script_ins(u8 address, u16 pmb_message, +static int twl4030_write_script_ins(u8 address, u16 pmb_message, u8 delay, u8 next) { int err; @@ -158,7 +158,7 @@ out: return err; } -static int __devinit twl4030_write_script(u8 address, struct twl4030_ins *script, +static int twl4030_write_script(u8 address, struct twl4030_ins *script, int len) { int err; @@ -183,7 +183,7 @@ static int __devinit twl4030_write_script(u8 address, struct twl4030_ins *script return err; } -static int __devinit twl4030_config_wakeup3_sequence(u8 address) +static int twl4030_config_wakeup3_sequence(u8 address) { int err; u8 data; @@ -208,7 +208,7 @@ out: return err; } -static int __devinit twl4030_config_wakeup12_sequence(u8 address) +static int twl4030_config_wakeup12_sequence(u8 address) { int err = 0; u8 data; @@ -262,7 +262,7 @@ out: return err; } -static int __devinit twl4030_config_sleep_sequence(u8 address) +static int twl4030_config_sleep_sequence(u8 address) { int err; @@ -276,7 +276,7 @@ static int __devinit twl4030_config_sleep_sequence(u8 address) return err; } -static int __devinit twl4030_config_warmreset_sequence(u8 address) +static int twl4030_config_warmreset_sequence(u8 address) { int err; u8 rd_data; @@ -324,7 +324,7 @@ out: return err; } -static int __devinit twl4030_configure_resource(struct twl4030_resconfig *rconfig) +static int twl4030_configure_resource(struct twl4030_resconfig *rconfig) { int rconfig_addr; int err; @@ -416,7 +416,7 @@ static int __devinit twl4030_configure_resource(struct twl4030_resconfig *rconfi return 0; } -static int __devinit load_twl4030_script(struct twl4030_script *tscript, +static int load_twl4030_script(struct twl4030_script *tscript, u8 address) { int err; @@ -527,7 +527,7 @@ void twl4030_power_off(void) pr_err("TWL4030 Unable to power off\n"); } -void __devinit twl4030_power_init(struct twl4030_power_data *twl4030_scripts) +void twl4030_power_init(struct twl4030_power_data *twl4030_scripts) { int err = 0; int i; diff --git a/drivers/mfd/vx855.c b/drivers/mfd/vx855.c index b9a636d44c7..757ecc63338 100644 --- a/drivers/mfd/vx855.c +++ b/drivers/mfd/vx855.c @@ -72,7 +72,7 @@ static struct mfd_cell vx855_cells[] = { }, }; -static __devinit int vx855_probe(struct pci_dev *pdev, +static int vx855_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int ret; @@ -112,7 +112,7 @@ out: return ret; } -static void __devexit vx855_remove(struct pci_dev *pdev) +static void vx855_remove(struct pci_dev *pdev) { mfd_remove_devices(&pdev->dev); pci_disable_device(pdev); @@ -128,7 +128,7 @@ static struct pci_driver vx855_pci_driver = { .name = "vx855", .id_table = vx855_pci_tbl, .probe = vx855_probe, - .remove = __devexit_p(vx855_remove), + .remove = vx855_remove, }; module_pci_driver(vx855_pci_driver); diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index 86e0e4309fc..edbe6c1b755 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c @@ -182,7 +182,7 @@ static int wl1273_core_remove(struct i2c_client *client) return 0; } -static int __devinit wl1273_core_probe(struct i2c_client *client, +static int wl1273_core_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct wl1273_fm_platform_data *pdata = client->dev.platform_data; @@ -262,7 +262,7 @@ static struct i2c_driver wl1273_core_driver = { }, .probe = wl1273_core_probe, .id_table = wl1273_driver_id_table, - .remove = __devexit_p(wl1273_core_remove), + .remove = wl1273_core_remove, }; static int __init wl1273_core_init(void) diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index 01b9255ed63..14490cc785d 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -43,6 +43,7 @@ static const struct reg_default wm5102_reva_patch[] = { { 0x479, 0x0A30 }, { 0x47B, 0x0810 }, { 0x47D, 0x0510 }, + { 0x4D1, 0x017F }, { 0x500, 0x000D }, { 0x507, 0x1820 }, { 0x508, 0x1820 }, @@ -52,524 +53,6 @@ static const struct reg_default wm5102_reva_patch[] = { { 0x580, 0x000D }, { 0x587, 0x1820 }, { 0x588, 0x1820 }, - { 0x101, 0x8140 }, - { 0x3000, 0x2225 }, - { 0x3001, 0x3a03 }, - { 0x3002, 0x0225 }, - { 0x3003, 0x0801 }, - { 0x3004, 0x6249 }, - { 0x3005, 0x0c04 }, - { 0x3006, 0x0225 }, - { 0x3007, 0x5901 }, - { 0x3008, 0xe249 }, - { 0x3009, 0x030d }, - { 0x300a, 0x0249 }, - { 0x300b, 0x2c01 }, - { 0x300c, 0xe249 }, - { 0x300d, 0x4342 }, - { 0x300e, 0xe249 }, - { 0x300f, 0x73c0 }, - { 0x3010, 0x4249 }, - { 0x3011, 0x0c00 }, - { 0x3012, 0x0225 }, - { 0x3013, 0x1f01 }, - { 0x3014, 0x0225 }, - { 0x3015, 0x1e01 }, - { 0x3016, 0x0225 }, - { 0x3017, 0xfa00 }, - { 0x3018, 0x0000 }, - { 0x3019, 0xf000 }, - { 0x301a, 0x0000 }, - { 0x301b, 0xf000 }, - { 0x301c, 0x0000 }, - { 0x301d, 0xf000 }, - { 0x301e, 0x0000 }, - { 0x301f, 0xf000 }, - { 0x3020, 0x0000 }, - { 0x3021, 0xf000 }, - { 0x3022, 0x0000 }, - { 0x3023, 0xf000 }, - { 0x3024, 0x0000 }, - { 0x3025, 0xf000 }, - { 0x3026, 0x0000 }, - { 0x3027, 0xf000 }, - { 0x3028, 0x0000 }, - { 0x3029, 0xf000 }, - { 0x302a, 0x0000 }, - { 0x302b, 0xf000 }, - { 0x302c, 0x0000 }, - { 0x302d, 0xf000 }, - { 0x302e, 0x0000 }, - { 0x302f, 0xf000 }, - { 0x3030, 0x0225 }, - { 0x3031, 0x1a01 }, - { 0x3032, 0x0225 }, - { 0x3033, 0x1e00 }, - { 0x3034, 0x0225 }, - { 0x3035, 0x1f00 }, - { 0x3036, 0x6225 }, - { 0x3037, 0xf800 }, - { 0x3038, 0x0000 }, - { 0x3039, 0xf000 }, - { 0x303a, 0x0000 }, - { 0x303b, 0xf000 }, - { 0x303c, 0x0000 }, - { 0x303d, 0xf000 }, - { 0x303e, 0x0000 }, - { 0x303f, 0xf000 }, - { 0x3040, 0x2226 }, - { 0x3041, 0x3a03 }, - { 0x3042, 0x0226 }, - { 0x3043, 0x0801 }, - { 0x3044, 0x6249 }, - { 0x3045, 0x0c06 }, - { 0x3046, 0x0226 }, - { 0x3047, 0x5901 }, - { 0x3048, 0xe249 }, - { 0x3049, 0x030d }, - { 0x304a, 0x0249 }, - { 0x304b, 0x2c01 }, - { 0x304c, 0xe249 }, - { 0x304d, 0x4342 }, - { 0x304e, 0xe249 }, - { 0x304f, 0x73c0 }, - { 0x3050, 0x4249 }, - { 0x3051, 0x0c00 }, - { 0x3052, 0x0226 }, - { 0x3053, 0x1f01 }, - { 0x3054, 0x0226 }, - { 0x3055, 0x1e01 }, - { 0x3056, 0x0226 }, - { 0x3057, 0xfa00 }, - { 0x3058, 0x0000 }, - { 0x3059, 0xf000 }, - { 0x305a, 0x0000 }, - { 0x305b, 0xf000 }, - { 0x305c, 0x0000 }, - { 0x305d, 0xf000 }, - { 0x305e, 0x0000 }, - { 0x305f, 0xf000 }, - { 0x3060, 0x0000 }, - { 0x3061, 0xf000 }, - { 0x3062, 0x0000 }, - { 0x3063, 0xf000 }, - { 0x3064, 0x0000 }, - { 0x3065, 0xf000 }, - { 0x3066, 0x0000 }, - { 0x3067, 0xf000 }, - { 0x3068, 0x0000 }, - { 0x3069, 0xf000 }, - { 0x306a, 0x0000 }, - { 0x306b, 0xf000 }, - { 0x306c, 0x0000 }, - { 0x306d, 0xf000 }, - { 0x306e, 0x0000 }, - { 0x306f, 0xf000 }, - { 0x3070, 0x0226 }, - { 0x3071, 0x1a01 }, - { 0x3072, 0x0226 }, - { 0x3073, 0x1e00 }, - { 0x3074, 0x0226 }, - { 0x3075, 0x1f00 }, - { 0x3076, 0x6226 }, - { 0x3077, 0xf800 }, - { 0x3078, 0x0000 }, - { 0x3079, 0xf000 }, - { 0x307a, 0x0000 }, - { 0x307b, 0xf000 }, - { 0x307c, 0x0000 }, - { 0x307d, 0xf000 }, - { 0x307e, 0x0000 }, - { 0x307f, 0xf000 }, - { 0x3080, 0x2227 }, - { 0x3081, 0x3a03 }, - { 0x3082, 0x0227 }, - { 0x3083, 0x0801 }, - { 0x3084, 0x6255 }, - { 0x3085, 0x0c04 }, - { 0x3086, 0x0227 }, - { 0x3087, 0x5901 }, - { 0x3088, 0xe255 }, - { 0x3089, 0x030d }, - { 0x308a, 0x0255 }, - { 0x308b, 0x2c01 }, - { 0x308c, 0xe255 }, - { 0x308d, 0x4342 }, - { 0x308e, 0xe255 }, - { 0x308f, 0x73c0 }, - { 0x3090, 0x4255 }, - { 0x3091, 0x0c00 }, - { 0x3092, 0x0227 }, - { 0x3093, 0x1f01 }, - { 0x3094, 0x0227 }, - { 0x3095, 0x1e01 }, - { 0x3096, 0x0227 }, - { 0x3097, 0xfa00 }, - { 0x3098, 0x0000 }, - { 0x3099, 0xf000 }, - { 0x309a, 0x0000 }, - { 0x309b, 0xf000 }, - { 0x309c, 0x0000 }, - { 0x309d, 0xf000 }, - { 0x309e, 0x0000 }, - { 0x309f, 0xf000 }, - { 0x30a0, 0x0000 }, - { 0x30a1, 0xf000 }, - { 0x30a2, 0x0000 }, - { 0x30a3, 0xf000 }, - { 0x30a4, 0x0000 }, - { 0x30a5, 0xf000 }, - { 0x30a6, 0x0000 }, - { 0x30a7, 0xf000 }, - { 0x30a8, 0x0000 }, - { 0x30a9, 0xf000 }, - { 0x30aa, 0x0000 }, - { 0x30ab, 0xf000 }, - { 0x30ac, 0x0000 }, - { 0x30ad, 0xf000 }, - { 0x30ae, 0x0000 }, - { 0x30af, 0xf000 }, - { 0x30b0, 0x0227 }, - { 0x30b1, 0x1a01 }, - { 0x30b2, 0x0227 }, - { 0x30b3, 0x1e00 }, - { 0x30b4, 0x0227 }, - { 0x30b5, 0x1f00 }, - { 0x30b6, 0x6227 }, - { 0x30b7, 0xf800 }, - { 0x30b8, 0x0000 }, - { 0x30b9, 0xf000 }, - { 0x30ba, 0x0000 }, - { 0x30bb, 0xf000 }, - { 0x30bc, 0x0000 }, - { 0x30bd, 0xf000 }, - { 0x30be, 0x0000 }, - { 0x30bf, 0xf000 }, - { 0x30c0, 0x2228 }, - { 0x30c1, 0x3a03 }, - { 0x30c2, 0x0228 }, - { 0x30c3, 0x0801 }, - { 0x30c4, 0x6255 }, - { 0x30c5, 0x0c06 }, - { 0x30c6, 0x0228 }, - { 0x30c7, 0x5901 }, - { 0x30c8, 0xe255 }, - { 0x30c9, 0x030d }, - { 0x30ca, 0x0255 }, - { 0x30cb, 0x2c01 }, - { 0x30cc, 0xe255 }, - { 0x30cd, 0x4342 }, - { 0x30ce, 0xe255 }, - { 0x30cf, 0x73c0 }, - { 0x30d0, 0x4255 }, - { 0x30d1, 0x0c00 }, - { 0x30d2, 0x0228 }, - { 0x30d3, 0x1f01 }, - { 0x30d4, 0x0228 }, - { 0x30d5, 0x1e01 }, - { 0x30d6, 0x0228 }, - { 0x30d7, 0xfa00 }, - { 0x30d8, 0x0000 }, - { 0x30d9, 0xf000 }, - { 0x30da, 0x0000 }, - { 0x30db, 0xf000 }, - { 0x30dc, 0x0000 }, - { 0x30dd, 0xf000 }, - { 0x30de, 0x0000 }, - { 0x30df, 0xf000 }, - { 0x30e0, 0x0000 }, - { 0x30e1, 0xf000 }, - { 0x30e2, 0x0000 }, - { 0x30e3, 0xf000 }, - { 0x30e4, 0x0000 }, - { 0x30e5, 0xf000 }, - { 0x30e6, 0x0000 }, - { 0x30e7, 0xf000 }, - { 0x30e8, 0x0000 }, - { 0x30e9, 0xf000 }, - { 0x30ea, 0x0000 }, - { 0x30eb, 0xf000 }, - { 0x30ec, 0x0000 }, - { 0x30ed, 0xf000 }, - { 0x30ee, 0x0000 }, - { 0x30ef, 0xf000 }, - { 0x30f0, 0x0228 }, - { 0x30f1, 0x1a01 }, - { 0x30f2, 0x0228 }, - { 0x30f3, 0x1e00 }, - { 0x30f4, 0x0228 }, - { 0x30f5, 0x1f00 }, - { 0x30f6, 0x6228 }, - { 0x30f7, 0xf800 }, - { 0x30f8, 0x0000 }, - { 0x30f9, 0xf000 }, - { 0x30fa, 0x0000 }, - { 0x30fb, 0xf000 }, - { 0x30fc, 0x0000 }, - { 0x30fd, 0xf000 }, - { 0x30fe, 0x0000 }, - { 0x30ff, 0xf000 }, - { 0x3100, 0x222b }, - { 0x3101, 0x3a03 }, - { 0x3102, 0x222b }, - { 0x3103, 0x5803 }, - { 0x3104, 0xe26f }, - { 0x3105, 0x030d }, - { 0x3106, 0x626f }, - { 0x3107, 0x2c01 }, - { 0x3108, 0xe26f }, - { 0x3109, 0x4342 }, - { 0x310a, 0xe26f }, - { 0x310b, 0x73c0 }, - { 0x310c, 0x026f }, - { 0x310d, 0x0c00 }, - { 0x310e, 0x022b }, - { 0x310f, 0x1f01 }, - { 0x3110, 0x022b }, - { 0x3111, 0x1e01 }, - { 0x3112, 0x022b }, - { 0x3113, 0xfa00 }, - { 0x3114, 0x0000 }, - { 0x3115, 0xf000 }, - { 0x3116, 0x0000 }, - { 0x3117, 0xf000 }, - { 0x3118, 0x0000 }, - { 0x3119, 0xf000 }, - { 0x311a, 0x0000 }, - { 0x311b, 0xf000 }, - { 0x311c, 0x0000 }, - { 0x311d, 0xf000 }, - { 0x311e, 0x0000 }, - { 0x311f, 0xf000 }, - { 0x3120, 0x022b }, - { 0x3121, 0x0a01 }, - { 0x3122, 0x022b }, - { 0x3123, 0x1e00 }, - { 0x3124, 0x022b }, - { 0x3125, 0x1f00 }, - { 0x3126, 0x622b }, - { 0x3127, 0xf800 }, - { 0x3128, 0x0000 }, - { 0x3129, 0xf000 }, - { 0x312a, 0x0000 }, - { 0x312b, 0xf000 }, - { 0x312c, 0x0000 }, - { 0x312d, 0xf000 }, - { 0x312e, 0x0000 }, - { 0x312f, 0xf000 }, - { 0x3130, 0x0000 }, - { 0x3131, 0xf000 }, - { 0x3132, 0x0000 }, - { 0x3133, 0xf000 }, - { 0x3134, 0x0000 }, - { 0x3135, 0xf000 }, - { 0x3136, 0x0000 }, - { 0x3137, 0xf000 }, - { 0x3138, 0x0000 }, - { 0x3139, 0xf000 }, - { 0x313a, 0x0000 }, - { 0x313b, 0xf000 }, - { 0x313c, 0x0000 }, - { 0x313d, 0xf000 }, - { 0x313e, 0x0000 }, - { 0x313f, 0xf000 }, - { 0x3140, 0x0000 }, - { 0x3141, 0xf000 }, - { 0x3142, 0x0000 }, - { 0x3143, 0xf000 }, - { 0x3144, 0x0000 }, - { 0x3145, 0xf000 }, - { 0x3146, 0x0000 }, - { 0x3147, 0xf000 }, - { 0x3148, 0x0000 }, - { 0x3149, 0xf000 }, - { 0x314a, 0x0000 }, - { 0x314b, 0xf000 }, - { 0x314c, 0x0000 }, - { 0x314d, 0xf000 }, - { 0x314e, 0x0000 }, - { 0x314f, 0xf000 }, - { 0x3150, 0x0000 }, - { 0x3151, 0xf000 }, - { 0x3152, 0x0000 }, - { 0x3153, 0xf000 }, - { 0x3154, 0x0000 }, - { 0x3155, 0xf000 }, - { 0x3156, 0x0000 }, - { 0x3157, 0xf000 }, - { 0x3158, 0x0000 }, - { 0x3159, 0xf000 }, - { 0x315a, 0x0000 }, - { 0x315b, 0xf000 }, - { 0x315c, 0x0000 }, - { 0x315d, 0xf000 }, - { 0x315e, 0x0000 }, - { 0x315f, 0xf000 }, - { 0x3160, 0x0000 }, - { 0x3161, 0xf000 }, - { 0x3162, 0x0000 }, - { 0x3163, 0xf000 }, - { 0x3164, 0x0000 }, - { 0x3165, 0xf000 }, - { 0x3166, 0x0000 }, - { 0x3167, 0xf000 }, - { 0x3168, 0x0000 }, - { 0x3169, 0xf000 }, - { 0x316a, 0x0000 }, - { 0x316b, 0xf000 }, - { 0x316c, 0x0000 }, - { 0x316d, 0xf000 }, - { 0x316e, 0x0000 }, - { 0x316f, 0xf000 }, - { 0x3170, 0x0000 }, - { 0x3171, 0xf000 }, - { 0x3172, 0x0000 }, - { 0x3173, 0xf000 }, - { 0x3174, 0x0000 }, - { 0x3175, 0xf000 }, - { 0x3176, 0x0000 }, - { 0x3177, 0xf000 }, - { 0x3178, 0x0000 }, - { 0x3179, 0xf000 }, - { 0x317a, 0x0000 }, - { 0x317b, 0xf000 }, - { 0x317c, 0x0000 }, - { 0x317d, 0xf000 }, - { 0x317e, 0x0000 }, - { 0x317f, 0xf000 }, - { 0x3180, 0x2001 }, - { 0x3181, 0xf101 }, - { 0x3182, 0x0000 }, - { 0x3183, 0xf000 }, - { 0x3184, 0x0000 }, - { 0x3185, 0xf000 }, - { 0x3186, 0x0000 }, - { 0x3187, 0xf000 }, - { 0x3188, 0x0000 }, - { 0x3189, 0xf000 }, - { 0x318a, 0x0000 }, - { 0x318b, 0xf000 }, - { 0x318c, 0x0000 }, - { 0x318d, 0xf000 }, - { 0x318e, 0x0000 }, - { 0x318f, 0xf000 }, - { 0x3190, 0x0000 }, - { 0x3191, 0xf000 }, - { 0x3192, 0x0000 }, - { 0x3193, 0xf000 }, - { 0x3194, 0x0000 }, - { 0x3195, 0xf000 }, - { 0x3196, 0x0000 }, - { 0x3197, 0xf000 }, - { 0x3198, 0x0000 }, - { 0x3199, 0xf000 }, - { 0x319a, 0x0000 }, - { 0x319b, 0xf000 }, - { 0x319c, 0x0000 }, - { 0x319d, 0xf000 }, - { 0x319e, 0x0000 }, - { 0x319f, 0xf000 }, - { 0x31a0, 0x0000 }, - { 0x31a1, 0xf000 }, - { 0x31a2, 0x0000 }, - { 0x31a3, 0xf000 }, - { 0x31a4, 0x0000 }, - { 0x31a5, 0xf000 }, - { 0x31a6, 0x0000 }, - { 0x31a7, 0xf000 }, - { 0x31a8, 0x0000 }, - { 0x31a9, 0xf000 }, - { 0x31aa, 0x0000 }, - { 0x31ab, 0xf000 }, - { 0x31ac, 0x0000 }, - { 0x31ad, 0xf000 }, - { 0x31ae, 0x0000 }, - { 0x31af, 0xf000 }, - { 0x31b0, 0x0000 }, - { 0x31b1, 0xf000 }, - { 0x31b2, 0x0000 }, - { 0x31b3, 0xf000 }, - { 0x31b4, 0x0000 }, - { 0x31b5, 0xf000 }, - { 0x31b6, 0x0000 }, - { 0x31b7, 0xf000 }, - { 0x31b8, 0x0000 }, - { 0x31b9, 0xf000 }, - { 0x31ba, 0x0000 }, - { 0x31bb, 0xf000 }, - { 0x31bc, 0x0000 }, - { 0x31bd, 0xf000 }, - { 0x31be, 0x0000 }, - { 0x31bf, 0xf000 }, - { 0x31c0, 0x0000 }, - { 0x31c1, 0xf000 }, - { 0x31c2, 0x0000 }, - { 0x31c3, 0xf000 }, - { 0x31c4, 0x0000 }, - { 0x31c5, 0xf000 }, - { 0x31c6, 0x0000 }, - { 0x31c7, 0xf000 }, - { 0x31c8, 0x0000 }, - { 0x31c9, 0xf000 }, - { 0x31ca, 0x0000 }, - { 0x31cb, 0xf000 }, - { 0x31cc, 0x0000 }, - { 0x31cd, 0xf000 }, - { 0x31ce, 0x0000 }, - { 0x31cf, 0xf000 }, - { 0x31d0, 0x0000 }, - { 0x31d1, 0xf000 }, - { 0x31d2, 0x0000 }, - { 0x31d3, 0xf000 }, - { 0x31d4, 0x0000 }, - { 0x31d5, 0xf000 }, - { 0x31d6, 0x0000 }, - { 0x31d7, 0xf000 }, - { 0x31d8, 0x0000 }, - { 0x31d9, 0xf000 }, - { 0x31da, 0x0000 }, - { 0x31db, 0xf000 }, - { 0x31dc, 0x0000 }, - { 0x31dd, 0xf000 }, - { 0x31de, 0x0000 }, - { 0x31df, 0xf000 }, - { 0x31e0, 0x0000 }, - { 0x31e1, 0xf000 }, - { 0x31e2, 0x0000 }, - { 0x31e3, 0xf000 }, - { 0x31e4, 0x0000 }, - { 0x31e5, 0xf000 }, - { 0x31e6, 0x0000 }, - { 0x31e7, 0xf000 }, - { 0x31e8, 0x0000 }, - { 0x31e9, 0xf000 }, - { 0x31ea, 0x0000 }, - { 0x31eb, 0xf000 }, - { 0x31ec, 0x0000 }, - { 0x31ed, 0xf000 }, - { 0x31ee, 0x0000 }, - { 0x31ef, 0xf000 }, - { 0x31f0, 0x0000 }, - { 0x31f1, 0xf000 }, - { 0x31f2, 0x0000 }, - { 0x31f3, 0xf000 }, - { 0x31f4, 0x0000 }, - { 0x31f5, 0xf000 }, - { 0x31f6, 0x0000 }, - { 0x31f7, 0xf000 }, - { 0x31f8, 0x0000 }, - { 0x31f9, 0xf000 }, - { 0x31fa, 0x0000 }, - { 0x31fb, 0xf000 }, - { 0x31fc, 0x0000 }, - { 0x31fd, 0xf000 }, - { 0x31fe, 0x0000 }, - { 0x31ff, 0xf000 }, - { 0x024d, 0xff50 }, - { 0x0252, 0xff50 }, - { 0x0259, 0x0112 }, - { 0x025e, 0x0112 }, - { 0x101, 0x0304 }, { 0x80, 0x0000 }, }; diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c index 4bceee98f0a..4e70e157a90 100644 --- a/drivers/mfd/wm831x-spi.c +++ b/drivers/mfd/wm831x-spi.c @@ -21,7 +21,7 @@ #include <linux/mfd/wm831x/core.h> -static int __devinit wm831x_spi_probe(struct spi_device *spi) +static int wm831x_spi_probe(struct spi_device *spi) { const struct spi_device_id *id = spi_get_device_id(spi); struct wm831x *wm831x; @@ -51,7 +51,7 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi) return wm831x_device_init(wm831x, type, spi->irq); } -static int __devexit wm831x_spi_remove(struct spi_device *spi) +static int wm831x_spi_remove(struct spi_device *spi) { struct wm831x *wm831x = dev_get_drvdata(&spi->dev); @@ -99,7 +99,7 @@ static struct spi_driver wm831x_spi_driver = { }, .id_table = wm831x_spi_ids, .probe = wm831x_spi_probe, - .remove = __devexit_p(wm831x_spi_remove), + .remove = wm831x_spi_remove, .shutdown = wm831x_spi_shutdown, }; diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 8fefc961ec0..c7f62ac544a 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -374,21 +374,21 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo) } #endif -static const __devinitconst struct reg_default wm8994_revc_patch[] = { +static const struct reg_default wm8994_revc_patch[] = { { 0x102, 0x3 }, { 0x56, 0x3 }, { 0x817, 0x0 }, { 0x102, 0x0 }, }; -static const __devinitconst struct reg_default wm8958_reva_patch[] = { +static const struct reg_default wm8958_reva_patch[] = { { 0x102, 0x3 }, { 0xcb, 0x81 }, { 0x817, 0x0 }, { 0x102, 0x0 }, }; -static const __devinitconst struct reg_default wm1811_reva_patch[] = { +static const struct reg_default wm1811_reva_patch[] = { { 0x102, 0x3 }, { 0x56, 0xc07 }, { 0x5d, 0x7e }, @@ -399,7 +399,7 @@ static const __devinitconst struct reg_default wm1811_reva_patch[] = { /* * Instantiate the generic non-control parts of the device. */ -static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq) +static int wm8994_device_init(struct wm8994 *wm8994, int irq) { struct wm8994_pdata *pdata = wm8994->dev->platform_data; struct regmap_config *regmap_config; @@ -671,7 +671,7 @@ err: return ret; } -static __devexit void wm8994_device_exit(struct wm8994 *wm8994) +static void wm8994_device_exit(struct wm8994 *wm8994) { pm_runtime_disable(wm8994->dev); mfd_remove_devices(wm8994->dev); @@ -689,7 +689,7 @@ static const struct of_device_id wm8994_of_match[] = { }; MODULE_DEVICE_TABLE(of, wm8994_of_match); -static __devinit int wm8994_i2c_probe(struct i2c_client *i2c, +static int wm8994_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm8994 *wm8994; @@ -715,7 +715,7 @@ static __devinit int wm8994_i2c_probe(struct i2c_client *i2c, return wm8994_device_init(wm8994, i2c->irq); } -static __devexit int wm8994_i2c_remove(struct i2c_client *i2c) +static int wm8994_i2c_remove(struct i2c_client *i2c) { struct wm8994 *wm8994 = i2c_get_clientdata(i2c); @@ -744,7 +744,7 @@ static struct i2c_driver wm8994_i2c_driver = { .of_match_table = wm8994_of_match, }, .probe = wm8994_i2c_probe, - .remove = __devexit_p(wm8994_i2c_remove), + .remove = wm8994_i2c_remove, .id_table = wm8994_i2c_id, }; diff --git a/drivers/misc/ad525x_dpot-i2c.c b/drivers/misc/ad525x_dpot-i2c.c index 820826270b6..705b881e186 100644 --- a/drivers/misc/ad525x_dpot-i2c.c +++ b/drivers/misc/ad525x_dpot-i2c.c @@ -51,7 +51,7 @@ static const struct ad_dpot_bus_ops bops = { .write_r8d16 = write_r8d16, }; -static int __devinit ad_dpot_i2c_probe(struct i2c_client *client, +static int ad_dpot_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct ad_dpot_bus_data bdata = { @@ -68,7 +68,7 @@ static int __devinit ad_dpot_i2c_probe(struct i2c_client *client, return ad_dpot_probe(&client->dev, &bdata, id->driver_data, id->name); } -static int __devexit ad_dpot_i2c_remove(struct i2c_client *client) +static int ad_dpot_i2c_remove(struct i2c_client *client) { return ad_dpot_remove(&client->dev); } @@ -109,7 +109,7 @@ static struct i2c_driver ad_dpot_i2c_driver = { .owner = THIS_MODULE, }, .probe = ad_dpot_i2c_probe, - .remove = __devexit_p(ad_dpot_i2c_remove), + .remove = ad_dpot_i2c_remove, .id_table = ad_dpot_id, }; diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c index f62317540d0..9da04ede04f 100644 --- a/drivers/misc/ad525x_dpot-spi.c +++ b/drivers/misc/ad525x_dpot-spi.c @@ -75,7 +75,7 @@ static const struct ad_dpot_bus_ops bops = { .write_r8d8 = write16, .write_r8d16 = write24, }; -static int __devinit ad_dpot_spi_probe(struct spi_device *spi) +static int ad_dpot_spi_probe(struct spi_device *spi) { struct ad_dpot_bus_data bdata = { .client = spi, @@ -87,7 +87,7 @@ static int __devinit ad_dpot_spi_probe(struct spi_device *spi) spi_get_device_id(spi)->name); } -static int __devexit ad_dpot_spi_remove(struct spi_device *spi) +static int ad_dpot_spi_remove(struct spi_device *spi) { return ad_dpot_remove(&spi->dev); } @@ -131,7 +131,7 @@ static struct spi_driver ad_dpot_spi_driver = { .owner = THIS_MODULE, }, .probe = ad_dpot_spi_probe, - .remove = __devexit_p(ad_dpot_spi_remove), + .remove = ad_dpot_spi_remove, .id_table = ad_dpot_spi_id, }; diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c index 6938f1be664..8f99e8e3f0a 100644 --- a/drivers/misc/ad525x_dpot.c +++ b/drivers/misc/ad525x_dpot.c @@ -641,7 +641,7 @@ static const struct attribute_group ad525x_group_commands = { .attrs = ad525x_attributes_commands, }; -__devinit int ad_dpot_add_files(struct device *dev, +int ad_dpot_add_files(struct device *dev, unsigned features, unsigned rdac) { int err = sysfs_create_file(&dev->kobj, @@ -685,7 +685,7 @@ inline void ad_dpot_remove_files(struct device *dev, } } -int __devinit ad_dpot_probe(struct device *dev, +int ad_dpot_probe(struct device *dev, struct ad_dpot_bus_data *bdata, unsigned long devid, const char *name) { diff --git a/drivers/misc/apds9802als.c b/drivers/misc/apds9802als.c index 0314773f6db..d648b089302 100644 --- a/drivers/misc/apds9802als.c +++ b/drivers/misc/apds9802als.c @@ -68,7 +68,7 @@ static int als_wait_for_data_ready(struct device *dev) ret = i2c_smbus_read_byte_data(client, 0x86); } while (!(ret & 0x80) && retry--); - if (!retry) { + if (retry < 0) { dev_warn(dev, "timeout waiting for data ready\n"); return -ETIMEDOUT; } @@ -254,7 +254,7 @@ als_error1: return res; } -static int __devexit apds9802als_remove(struct i2c_client *client) +static int apds9802als_remove(struct i2c_client *client) { struct als_data *data = i2c_get_clientdata(client); @@ -326,7 +326,7 @@ static struct i2c_driver apds9802als_driver = { .pm = APDS9802ALS_PM_OPS, }, .probe = apds9802als_probe, - .remove = __devexit_p(apds9802als_remove), + .remove = apds9802als_remove, .suspend = apds9802als_suspend, .resume = apds9802als_resume, .id_table = apds9802als_id, diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c index ee74244aa03..0e67f8263cd 100644 --- a/drivers/misc/apds990x.c +++ b/drivers/misc/apds990x.c @@ -1047,7 +1047,7 @@ static struct attribute_group apds990x_attribute_group[] = { {.attrs = sysfs_attrs_ctrl }, }; -static int __devinit apds990x_probe(struct i2c_client *client, +static int apds990x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct apds990x_chip *chip; @@ -1181,7 +1181,7 @@ fail1: return err; } -static int __devexit apds990x_remove(struct i2c_client *client) +static int apds990x_remove(struct i2c_client *client) { struct apds990x_chip *chip = i2c_get_clientdata(client); @@ -1275,7 +1275,7 @@ static struct i2c_driver apds990x_driver = { .pm = &apds990x_pm_ops, }, .probe = apds990x_probe, - .remove = __devexit_p(apds990x_remove), + .remove = apds990x_remove, .id_table = apds990x_id, }; diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index 5bb18778107..c58f9abcb35 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c @@ -137,7 +137,7 @@ out: return retval; } -static int __devexit ssc_remove(struct platform_device *pdev) +static int ssc_remove(struct platform_device *pdev) { struct ssc_device *ssc = platform_get_drvdata(pdev); @@ -152,7 +152,7 @@ static int __devexit ssc_remove(struct platform_device *pdev) } static struct platform_driver ssc_driver = { - .remove = __devexit_p(ssc_remove), + .remove = ssc_remove, .driver = { .name = "ssc", .owner = THIS_MODULE, diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c index 3d56ae7ef8d..2ed8fc3be7e 100644 --- a/drivers/misc/bh1770glc.c +++ b/drivers/misc/bh1770glc.c @@ -1162,7 +1162,7 @@ static struct attribute_group bh1770_attribute_group = { .attrs = sysfs_attrs }; -static int __devinit bh1770_probe(struct i2c_client *client, +static int bh1770_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct bh1770_chip *chip; @@ -1285,7 +1285,7 @@ fail1: return err; } -static int __devexit bh1770_remove(struct i2c_client *client) +static int bh1770_remove(struct i2c_client *client) { struct bh1770_chip *chip = i2c_get_clientdata(client); @@ -1395,7 +1395,7 @@ static struct i2c_driver bh1770_driver = { .pm = &bh1770_pm_ops, }, .probe = bh1770_probe, - .remove = __devexit_p(bh1770_remove), + .remove = bh1770_remove, .id_table = bh1770_id, }; diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c index f1f9877f3fd..cf03d0abf33 100644 --- a/drivers/misc/bh1780gli.c +++ b/drivers/misc/bh1780gli.c @@ -144,7 +144,7 @@ static const struct attribute_group bh1780_attr_group = { .attrs = bh1780_attributes, }; -static int __devinit bh1780_probe(struct i2c_client *client, +static int bh1780_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret; @@ -185,7 +185,7 @@ err_op_failed: return ret; } -static int __devexit bh1780_remove(struct i2c_client *client) +static int bh1780_remove(struct i2c_client *client) { struct bh1780_data *ddata; @@ -248,7 +248,7 @@ static const struct i2c_device_id bh1780_id[] = { static struct i2c_driver bh1780_driver = { .probe = bh1780_probe, - .remove = __devexit_p(bh1780_remove), + .remove = bh1780_remove, .id_table = bh1780_id, .driver = { .name = "bh1780", diff --git a/drivers/misc/bmp085-i2c.c b/drivers/misc/bmp085-i2c.c index a4f33c995ea..3abfcecf842 100644 --- a/drivers/misc/bmp085-i2c.c +++ b/drivers/misc/bmp085-i2c.c @@ -36,7 +36,7 @@ static int bmp085_i2c_detect(struct i2c_client *client, return bmp085_detect(&client->dev); } -static int __devinit bmp085_i2c_probe(struct i2c_client *client, +static int bmp085_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int err; @@ -71,7 +71,7 @@ static struct i2c_driver bmp085_i2c_driver = { }, .id_table = bmp085_id, .probe = bmp085_i2c_probe, - .remove = __devexit_p(bmp085_i2c_remove), + .remove = bmp085_i2c_remove, .detect = bmp085_i2c_detect, .address_list = normal_i2c diff --git a/drivers/misc/bmp085-spi.c b/drivers/misc/bmp085-spi.c index 5e982af9973..d6a52659cf2 100644 --- a/drivers/misc/bmp085-spi.c +++ b/drivers/misc/bmp085-spi.c @@ -22,7 +22,7 @@ #include <linux/err.h> #include "bmp085.h" -static int __devinit bmp085_spi_probe(struct spi_device *client) +static int bmp085_spi_probe(struct spi_device *client) { int err; struct regmap *regmap; @@ -70,7 +70,7 @@ static struct spi_driver bmp085_spi_driver = { }, .id_table = bmp085_id, .probe = bmp085_spi_probe, - .remove = __devexit_p(bmp085_spi_remove) + .remove = bmp085_spi_remove }; module_spi_driver(bmp085_spi_driver); diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c index 62e418293b7..849e2fed4da 100644 --- a/drivers/misc/bmp085.c +++ b/drivers/misc/bmp085.c @@ -420,7 +420,7 @@ struct regmap_config bmp085_regmap_config = { }; EXPORT_SYMBOL_GPL(bmp085_regmap_config); -__devinit int bmp085_probe(struct device *dev, struct regmap *regmap) +int bmp085_probe(struct device *dev, struct regmap *regmap) { struct bmp085_data *data; int err = 0; diff --git a/drivers/misc/cb710/core.c b/drivers/misc/cb710/core.c index 9d5eed75466..2e50f811ff5 100644 --- a/drivers/misc/cb710/core.c +++ b/drivers/misc/cb710/core.c @@ -30,7 +30,7 @@ void cb710_pci_update_config_reg(struct pci_dev *pdev, EXPORT_SYMBOL_GPL(cb710_pci_update_config_reg); /* Some magic writes based on Windows driver init code */ -static int __devinit cb710_pci_configure(struct pci_dev *pdev) +static int cb710_pci_configure(struct pci_dev *pdev) { unsigned int devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); struct pci_dev *pdev0; @@ -96,7 +96,7 @@ static void cb710_release_slot(struct device *dev) #endif } -static int __devinit cb710_register_slot(struct cb710_chip *chip, +static int cb710_register_slot(struct cb710_chip *chip, unsigned slot_mask, unsigned io_offset, const char *name) { int nr = chip->slots; @@ -201,7 +201,7 @@ static int cb710_resume(struct pci_dev *pdev) #endif /* CONFIG_PM */ -static int __devinit cb710_probe(struct pci_dev *pdev, +static int cb710_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct cb710_chip *chip; @@ -305,7 +305,7 @@ unreg_mmc: return err; } -static void __devexit cb710_remove_one(struct pci_dev *pdev) +static void cb710_remove_one(struct pci_dev *pdev) { struct cb710_chip *chip = pci_get_drvdata(pdev); unsigned long flags; @@ -332,7 +332,7 @@ static struct pci_driver cb710_driver = { .name = KBUILD_MODNAME, .id_table = cb710_pci_tbl, .probe = cb710_probe, - .remove = __devexit_p(cb710_remove_one), + .remove = cb710_remove_one, #ifdef CONFIG_PM .suspend = cb710_suspend, .resume = cb710_resume, diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c index f505a40a8f4..9858f36dad8 100644 --- a/drivers/misc/cs5535-mfgpt.c +++ b/drivers/misc/cs5535-mfgpt.c @@ -246,7 +246,7 @@ EXPORT_SYMBOL_GPL(cs5535_mfgpt_write); * Jordan tells me that he and Mitch once played w/ it, but it's unclear * what the results of that were (and they experienced some instability). */ -static void __devinit reset_all_timers(void) +static void reset_all_timers(void) { uint32_t val, dummy; @@ -262,7 +262,7 @@ static void __devinit reset_all_timers(void) * In other cases (such as with VSAless OpenFirmware), the system firmware * leaves timers available for us to use. */ -static int __devinit scan_timers(struct cs5535_mfgpt_chip *mfgpt) +static int scan_timers(struct cs5535_mfgpt_chip *mfgpt) { struct cs5535_mfgpt_timer timer = { .chip = mfgpt }; unsigned long flags; @@ -289,7 +289,7 @@ static int __devinit scan_timers(struct cs5535_mfgpt_chip *mfgpt) return timers; } -static int __devinit cs5535_mfgpt_probe(struct platform_device *pdev) +static int cs5535_mfgpt_probe(struct platform_device *pdev) { struct resource *res; int err = -EIO, t; diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index ab1ad41786d..2baeec56edf 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -656,7 +656,7 @@ err_out: return err; } -static int __devexit at24_remove(struct i2c_client *client) +static int at24_remove(struct i2c_client *client) { struct at24_data *at24; int i; @@ -680,7 +680,7 @@ static struct i2c_driver at24_driver = { .owner = THIS_MODULE, }, .probe = at24_probe, - .remove = __devexit_p(at24_remove), + .remove = at24_remove, .id_table = at24_ids, }; diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index 4ed93dd5411..b08cf8a0878 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -459,7 +459,7 @@ fail: return err; } -static int __devexit at25_remove(struct spi_device *spi) +static int at25_remove(struct spi_device *spi) { struct at25_data *at25; @@ -477,7 +477,7 @@ static struct spi_driver at25_driver = { .owner = THIS_MODULE, }, .probe = at25_probe, - .remove = __devexit_p(at25_remove), + .remove = at25_remove, }; module_spi_driver(at25_driver); diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index ce3fe3633dd..a6b5d5e7348 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -309,7 +309,7 @@ static ssize_t eeprom_93xx46_store_erase(struct device *dev, } static DEVICE_ATTR(erase, S_IWUSR, NULL, eeprom_93xx46_store_erase); -static int __devinit eeprom_93xx46_probe(struct spi_device *spi) +static int eeprom_93xx46_probe(struct spi_device *spi) { struct eeprom_93xx46_platform_data *pd; struct eeprom_93xx46_dev *edev; @@ -370,7 +370,7 @@ fail: return err; } -static int __devexit eeprom_93xx46_remove(struct spi_device *spi) +static int eeprom_93xx46_remove(struct spi_device *spi) { struct eeprom_93xx46_dev *edev = dev_get_drvdata(&spi->dev); @@ -389,7 +389,7 @@ static struct spi_driver eeprom_93xx46_driver = { .owner = THIS_MODULE, }, .probe = eeprom_93xx46_probe, - .remove = __devexit_p(eeprom_93xx46_remove), + .remove = eeprom_93xx46_remove, }; module_spi_driver(eeprom_93xx46_driver); diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c index ac96c3a4034..e8cbb1c59f4 100644 --- a/drivers/misc/fsa9480.c +++ b/drivers/misc/fsa9480.c @@ -407,7 +407,7 @@ static int fsa9480_irq_init(struct fsa9480_usbsw *usbsw) return 0; } -static int __devinit fsa9480_probe(struct i2c_client *client, +static int fsa9480_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); @@ -462,7 +462,7 @@ fail1: return ret; } -static int __devexit fsa9480_remove(struct i2c_client *client) +static int fsa9480_remove(struct i2c_client *client) { struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client); if (client->irq) @@ -533,7 +533,7 @@ static struct i2c_driver fsa9480_i2c_driver = { .name = "fsa9480", }, .probe = fsa9480_probe, - .remove = __devexit_p(fsa9480_remove), + .remove = fsa9480_remove, .resume = fsa9480_resume, .suspend = fsa9480_suspend, .id_table = fsa9480_id, diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index 12ccdf94e4f..621c7a37339 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c @@ -30,7 +30,7 @@ static struct class *ilo_class; static unsigned int ilo_major; -static unsigned int max_ccb = MIN_CCB; +static unsigned int max_ccb = 16; static char ilo_hwdev[MAX_ILO_DEV]; static inline int get_entry_id(int entry) @@ -686,7 +686,7 @@ static void ilo_unmap_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) pci_iounmap(pdev, hw->mmio_vaddr); } -static int __devinit ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) +static int ilo_map_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) { int error = -ENOMEM; @@ -725,6 +725,9 @@ static void ilo_remove(struct pci_dev *pdev) int i, minor; struct ilo_hwinfo *ilo_hw = pci_get_drvdata(pdev); + if (!ilo_hw) + return; + clear_device(ilo_hw); minor = MINOR(ilo_hw->cdev.dev); @@ -748,12 +751,16 @@ static void ilo_remove(struct pci_dev *pdev) ilo_hwdev[(minor / max_ccb)] = 0; } -static int __devinit ilo_probe(struct pci_dev *pdev, +static int ilo_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - int devnum, minor, start, error; + int devnum, minor, start, error = 0; struct ilo_hwinfo *ilo_hw; + /* Ignore subsystem_device = 0x1979 (set by BIOS) */ + if (pdev->subsystem_device == 0x1979) + goto out; + if (max_ccb > MAX_CCB) max_ccb = MAX_CCB; else if (max_ccb < MIN_CCB) @@ -852,7 +859,7 @@ static struct pci_driver ilo_driver = { .name = ILO_NAME, .id_table = ilo_devices, .probe = ilo_probe, - .remove = __devexit_p(ilo_remove), + .remove = ilo_remove, }; static int __init ilo_init(void) @@ -892,14 +899,14 @@ static void __exit ilo_exit(void) class_destroy(ilo_class); } -MODULE_VERSION("1.3"); +MODULE_VERSION("1.4"); MODULE_ALIAS(ILO_NAME); MODULE_DESCRIPTION(ILO_NAME); MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>"); MODULE_LICENSE("GPL v2"); module_param(max_ccb, uint, 0444); -MODULE_PARM_DESC(max_ccb, "Maximum number of HP iLO channels to attach (8)"); +MODULE_PARM_DESC(max_ccb, "Maximum number of HP iLO channels to attach (16)"); module_init(ilo_init); module_exit(ilo_exit); diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c index 168d8008f46..0346d87c5fe 100644 --- a/drivers/misc/ibmasm/module.c +++ b/drivers/misc/ibmasm/module.c @@ -62,7 +62,7 @@ module_param(ibmasm_debug, int , S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ibmasm_debug, " Set debug mode on or off"); -static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id) +static int ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { int result; struct service_processor *sp; @@ -163,7 +163,7 @@ error_resources: return result; } -static void __devexit ibmasm_remove_one(struct pci_dev *pdev) +static void ibmasm_remove_one(struct pci_dev *pdev) { struct service_processor *sp = (struct service_processor *)pci_get_drvdata(pdev); @@ -198,7 +198,7 @@ static struct pci_driver ibmasm_driver = { .name = DRIVER_NAME, .id_table = ibmasm_pci_table, .probe = ibmasm_init_one, - .remove = __devexit_p(ibmasm_remove_one), + .remove = ibmasm_remove_one, }; static void __exit ibmasm_exit (void) diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c index 6a7710603a9..06f6ad29cef 100644 --- a/drivers/misc/ioc4.c +++ b/drivers/misc/ioc4.c @@ -139,7 +139,7 @@ ioc4_unregister_submodule(struct ioc4_submodule *is) * even though the following code utilizes external interrupt registers * to perform the speed calculation. */ -static void __devinit +static void ioc4_clock_calibrate(struct ioc4_driver_data *idd) { union ioc4_int_out int_out; @@ -231,7 +231,7 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd) * on the same PCI bus at slot number 3 to differentiate IO9 from IO10. * If neither is present, it's a PCI-RT. */ -static unsigned int __devinit +static unsigned int ioc4_variant(struct ioc4_driver_data *idd) { struct pci_dev *pdev = NULL; @@ -279,7 +279,7 @@ ioc4_load_modules(struct work_struct *work) static DECLARE_WORK(ioc4_load_modules_work, ioc4_load_modules); /* Adds a new instance of an IOC4 card */ -static int __devinit +static int ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) { struct ioc4_driver_data *idd; @@ -415,7 +415,7 @@ out: } /* Removes a particular instance of an IOC4 card. */ -static void __devexit +static void ioc4_remove(struct pci_dev *pdev) { struct ioc4_submodule *is; @@ -466,7 +466,7 @@ static struct pci_driver ioc4_driver = { .name = "IOC4", .id_table = ioc4_id_table, .probe = ioc4_probe, - .remove = __devexit_p(ioc4_remove), + .remove = ioc4_remove, }; MODULE_DEVICE_TABLE(pci, ioc4_id_table); diff --git a/drivers/misc/isl29003.c b/drivers/misc/isl29003.c index eb5de2e210d..29b306c6bdb 100644 --- a/drivers/misc/isl29003.c +++ b/drivers/misc/isl29003.c @@ -365,7 +365,7 @@ static int isl29003_init_client(struct i2c_client *client) * I2C layer */ -static int __devinit isl29003_probe(struct i2c_client *client, +static int isl29003_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); @@ -401,7 +401,7 @@ exit_kfree: return err; } -static int __devexit isl29003_remove(struct i2c_client *client) +static int isl29003_remove(struct i2c_client *client) { sysfs_remove_group(&client->dev.kobj, &isl29003_attr_group); isl29003_set_power_state(client, 0); @@ -451,7 +451,7 @@ static struct i2c_driver isl29003_driver = { .suspend = isl29003_suspend, .resume = isl29003_resume, .probe = isl29003_probe, - .remove = __devexit_p(isl29003_remove), + .remove = isl29003_remove, .id_table = isl29003_id, }; diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c index 60ec8689d6e..7c97550240f 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c +++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c @@ -114,7 +114,7 @@ static struct of_device_id lis3lv02d_i2c_dt_ids[] = { MODULE_DEVICE_TABLE(of, lis3lv02d_i2c_dt_ids); #endif -static int __devinit lis3lv02d_i2c_probe(struct i2c_client *client, +static int lis3lv02d_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = 0; @@ -191,7 +191,7 @@ fail: return ret; } -static int __devexit lis3lv02d_i2c_remove(struct i2c_client *client) +static int lis3lv02d_i2c_remove(struct i2c_client *client) { struct lis3lv02d *lis3 = i2c_get_clientdata(client); struct lis3lv02d_platform_data *pdata = client->dev.platform_data; @@ -280,7 +280,7 @@ static struct i2c_driver lis3lv02d_i2c_driver = { .of_match_table = of_match_ptr(lis3lv02d_i2c_dt_ids), }, .probe = lis3lv02d_i2c_probe, - .remove = __devexit_p(lis3lv02d_i2c_remove), + .remove = lis3lv02d_i2c_remove, .id_table = lis3lv02d_id, }; diff --git a/drivers/misc/lis3lv02d/lis3lv02d_spi.c b/drivers/misc/lis3lv02d/lis3lv02d_spi.c index ccb6475fa05..9aa2bd2a71a 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d_spi.c +++ b/drivers/misc/lis3lv02d/lis3lv02d_spi.c @@ -69,7 +69,7 @@ static struct of_device_id lis302dl_spi_dt_ids[] = { MODULE_DEVICE_TABLE(of, lis302dl_spi_dt_ids); #endif -static int __devinit lis302dl_spi_probe(struct spi_device *spi) +static int lis302dl_spi_probe(struct spi_device *spi) { int ret; @@ -100,7 +100,7 @@ static int __devinit lis302dl_spi_probe(struct spi_device *spi) return lis3lv02d_init_device(&lis3_dev); } -static int __devexit lis302dl_spi_remove(struct spi_device *spi) +static int lis302dl_spi_remove(struct spi_device *spi) { struct lis3lv02d *lis3 = spi_get_drvdata(spi); lis3lv02d_joystick_disable(lis3); @@ -144,7 +144,7 @@ static struct spi_driver lis302dl_spi_driver = { .of_match_table = of_match_ptr(lis302dl_spi_dt_ids), }, .probe = lis302dl_spi_probe, - .remove = __devexit_p(lis302dl_spi_remove), + .remove = lis302dl_spi_remove, }; module_spi_driver(lis302dl_spi_driver); diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile index 57168db6c7e..0017842e166 100644 --- a/drivers/misc/mei/Makefile +++ b/drivers/misc/mei/Makefile @@ -8,4 +8,5 @@ mei-objs += interrupt.o mei-objs += interface.o mei-objs += iorw.o mei-objs += main.o +mei-objs += amthif.o mei-objs += wd.o diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c new file mode 100644 index 00000000000..18794aea606 --- /dev/null +++ b/drivers/misc/mei/amthif.c @@ -0,0 +1,722 @@ +/* + * + * Intel Management Engine Interface (Intel MEI) Linux driver + * Copyright (c) 2003-2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + */ + +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/aio.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/ioctl.h> +#include <linux/cdev.h> +#include <linux/list.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/uuid.h> +#include <linux/jiffies.h> +#include <linux/uaccess.h> + + +#include "mei_dev.h" +#include "hw.h" +#include <linux/mei.h> +#include "interface.h" + +const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac, + 0xa8, 0x46, 0xe0, 0xff, 0x65, + 0x81, 0x4c); + +/** + * mei_amthif_reset_params - initializes mei device iamthif + * + * @dev: the device structure + */ +void mei_amthif_reset_params(struct mei_device *dev) +{ + /* reset iamthif parameters. */ + dev->iamthif_current_cb = NULL; + dev->iamthif_msg_buf_size = 0; + dev->iamthif_msg_buf_index = 0; + dev->iamthif_canceled = false; + dev->iamthif_ioctl = false; + dev->iamthif_state = MEI_IAMTHIF_IDLE; + dev->iamthif_timer = 0; +} + +/** + * mei_amthif_host_init_ - mei initialization amthif client. + * + * @dev: the device structure + * + */ +void mei_amthif_host_init(struct mei_device *dev) +{ + int i; + unsigned char *msg_buf; + + mei_cl_init(&dev->iamthif_cl, dev); + dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; + + /* find ME amthi client */ + i = mei_me_cl_link(dev, &dev->iamthif_cl, + &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID); + if (i < 0) { + dev_info(&dev->pdev->dev, "failed to find iamthif client.\n"); + return; + } + + /* Assign iamthif_mtu to the value received from ME */ + + dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length; + dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n", + dev->me_clients[i].props.max_msg_length); + + kfree(dev->iamthif_msg_buf); + dev->iamthif_msg_buf = NULL; + + /* allocate storage for ME message buffer */ + msg_buf = kcalloc(dev->iamthif_mtu, + sizeof(unsigned char), GFP_KERNEL); + if (!msg_buf) { + dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n"); + return; + } + + dev->iamthif_msg_buf = msg_buf; + + if (mei_connect(dev, &dev->iamthif_cl)) { + dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n"); + dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; + dev->iamthif_cl.host_client_id = 0; + } else { + dev->iamthif_cl.timer_count = MEI_CONNECT_TIMEOUT; + } +} + +/** + * mei_amthif_find_read_list_entry - finds a amthilist entry for current file + * + * @dev: the device structure + * @file: pointer to file object + * + * returns returned a list entry on success, NULL on failure. + */ +struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev, + struct file *file) +{ + struct mei_cl_cb *pos = NULL; + struct mei_cl_cb *next = NULL; + + list_for_each_entry_safe(pos, next, + &dev->amthif_rd_complete_list.list, list) { + if (pos->cl && pos->cl == &dev->iamthif_cl && + pos->file_object == file) + return pos; + } + return NULL; +} + + +/** + * mei_amthif_read - read data from AMTHIF client + * + * @dev: the device structure + * @if_num: minor number + * @file: pointer to file object + * @*ubuf: pointer to user data in user space + * @length: data length to read + * @offset: data read offset + * + * Locking: called under "dev->device_lock" lock + * + * returns + * returned data length on success, + * zero if no data to read, + * negative on failure. + */ +int mei_amthif_read(struct mei_device *dev, struct file *file, + char __user *ubuf, size_t length, loff_t *offset) +{ + int rets; + int wait_ret; + struct mei_cl_cb *cb = NULL; + struct mei_cl *cl = file->private_data; + unsigned long timeout; + int i; + + /* Only Posible if we are in timeout */ + if (!cl || cl != &dev->iamthif_cl) { + dev_dbg(&dev->pdev->dev, "bad file ext.\n"); + return -ETIMEDOUT; + } + + i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id); + + if (i < 0) { + dev_dbg(&dev->pdev->dev, "amthi client not found.\n"); + return -ENODEV; + } + dev_dbg(&dev->pdev->dev, "checking amthi data\n"); + cb = mei_amthif_find_read_list_entry(dev, file); + + /* Check for if we can block or not*/ + if (cb == NULL && file->f_flags & O_NONBLOCK) + return -EAGAIN; + + + dev_dbg(&dev->pdev->dev, "waiting for amthi data\n"); + while (cb == NULL) { + /* unlock the Mutex */ + mutex_unlock(&dev->device_lock); + + wait_ret = wait_event_interruptible(dev->iamthif_cl.wait, + (cb = mei_amthif_find_read_list_entry(dev, file))); + + if (wait_ret) + return -ERESTARTSYS; + + dev_dbg(&dev->pdev->dev, "woke up from sleep\n"); + + /* Locking again the Mutex */ + mutex_lock(&dev->device_lock); + } + + + dev_dbg(&dev->pdev->dev, "Got amthi data\n"); + dev->iamthif_timer = 0; + + if (cb) { + timeout = cb->read_time + + mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); + dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n", + timeout); + + if (time_after(jiffies, timeout)) { + dev_dbg(&dev->pdev->dev, "amthi Time out\n"); + /* 15 sec for the message has expired */ + list_del(&cb->list); + rets = -ETIMEDOUT; + goto free; + } + } + /* if the whole message will fit remove it from the list */ + if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset)) + list_del(&cb->list); + else if (cb->buf_idx > 0 && cb->buf_idx <= *offset) { + /* end of the message has been reached */ + list_del(&cb->list); + rets = 0; + goto free; + } + /* else means that not full buffer will be read and do not + * remove message from deletion list + */ + + dev_dbg(&dev->pdev->dev, "amthi cb->response_buffer size - %d\n", + cb->response_buffer.size); + dev_dbg(&dev->pdev->dev, "amthi cb->buf_idx - %lu\n", cb->buf_idx); + + /* length is being turncated to PAGE_SIZE, however, + * the buf_idx may point beyond */ + length = min_t(size_t, length, (cb->buf_idx - *offset)); + + if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) + rets = -EFAULT; + else { + rets = length; + if ((*offset + length) < cb->buf_idx) { + *offset += length; + goto out; + } + } +free: + dev_dbg(&dev->pdev->dev, "free amthi cb memory.\n"); + *offset = 0; + mei_io_cb_free(cb); +out: + return rets; +} + +/** + * mei_amthif_send_cmd - send amthif command to the ME + * + * @dev: the device structure + * @cb: mei call back struct + * + * returns 0 on success, <0 on failure. + * + */ +static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb) +{ + struct mei_msg_hdr mei_hdr; + int ret; + + if (!dev || !cb) + return -ENODEV; + + dev_dbg(&dev->pdev->dev, "write data to amthi client.\n"); + + dev->iamthif_state = MEI_IAMTHIF_WRITING; + dev->iamthif_current_cb = cb; + dev->iamthif_file_object = cb->file_object; + dev->iamthif_canceled = false; + dev->iamthif_ioctl = true; + dev->iamthif_msg_buf_size = cb->request_buffer.size; + memcpy(dev->iamthif_msg_buf, cb->request_buffer.data, + cb->request_buffer.size); + + ret = mei_flow_ctrl_creds(dev, &dev->iamthif_cl); + if (ret < 0) + return ret; + + if (ret && dev->mei_host_buffer_is_empty) { + ret = 0; + dev->mei_host_buffer_is_empty = false; + if (cb->request_buffer.size > mei_hbuf_max_data(dev)) { + mei_hdr.length = mei_hbuf_max_data(dev); + mei_hdr.msg_complete = 0; + } else { + mei_hdr.length = cb->request_buffer.size; + mei_hdr.msg_complete = 1; + } + + mei_hdr.host_addr = dev->iamthif_cl.host_client_id; + mei_hdr.me_addr = dev->iamthif_cl.me_client_id; + mei_hdr.reserved = 0; + dev->iamthif_msg_buf_index += mei_hdr.length; + if (mei_write_message(dev, &mei_hdr, + (unsigned char *)(dev->iamthif_msg_buf), + mei_hdr.length)) + return -ENODEV; + + if (mei_hdr.msg_complete) { + if (mei_flow_ctrl_reduce(dev, &dev->iamthif_cl)) + return -ENODEV; + dev->iamthif_flow_control_pending = true; + dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; + dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n"); + dev->iamthif_current_cb = cb; + dev->iamthif_file_object = cb->file_object; + list_add_tail(&cb->list, &dev->write_waiting_list.list); + } else { + dev_dbg(&dev->pdev->dev, "message does not complete, so add amthi cb to write list.\n"); + list_add_tail(&cb->list, &dev->write_list.list); + } + } else { + if (!(dev->mei_host_buffer_is_empty)) + dev_dbg(&dev->pdev->dev, "host buffer is not empty"); + + dev_dbg(&dev->pdev->dev, "No flow control credentials, so add iamthif cb to write list.\n"); + list_add_tail(&cb->list, &dev->write_list.list); + } + return 0; +} + +/** + * mei_amthif_write - write amthif data to amthif client + * + * @dev: the device structure + * @cb: mei call back struct + * + * returns 0 on success, <0 on failure. + * + */ +int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *cb) +{ + int ret; + + if (!dev || !cb) + return -ENODEV; + + ret = mei_io_cb_alloc_resp_buf(cb, dev->iamthif_mtu); + if (ret) + return ret; + + cb->fop_type = MEI_FOP_IOCTL; + + if (!list_empty(&dev->amthif_cmd_list.list) || + dev->iamthif_state != MEI_IAMTHIF_IDLE) { + dev_dbg(&dev->pdev->dev, + "amthif state = %d\n", dev->iamthif_state); + dev_dbg(&dev->pdev->dev, "AMTHIF: add cb to the wait list\n"); + list_add_tail(&cb->list, &dev->amthif_cmd_list.list); + return 0; + } + return mei_amthif_send_cmd(dev, cb); +} +/** + * mei_amthif_run_next_cmd + * + * @dev: the device structure + * + * returns 0 on success, <0 on failure. + */ +void mei_amthif_run_next_cmd(struct mei_device *dev) +{ + struct mei_cl_cb *pos = NULL; + struct mei_cl_cb *next = NULL; + int status; + + if (!dev) + return; + + dev->iamthif_msg_buf_size = 0; + dev->iamthif_msg_buf_index = 0; + dev->iamthif_canceled = false; + dev->iamthif_ioctl = true; + dev->iamthif_state = MEI_IAMTHIF_IDLE; + dev->iamthif_timer = 0; + dev->iamthif_file_object = NULL; + + dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n"); + + list_for_each_entry_safe(pos, next, &dev->amthif_cmd_list.list, list) { + list_del(&pos->list); + + if (pos->cl && pos->cl == &dev->iamthif_cl) { + status = mei_amthif_send_cmd(dev, pos); + if (status) { + dev_dbg(&dev->pdev->dev, + "amthi write failed status = %d\n", + status); + return; + } + break; + } + } +} + + +unsigned int mei_amthif_poll(struct mei_device *dev, + struct file *file, poll_table *wait) +{ + unsigned int mask = 0; + mutex_unlock(&dev->device_lock); + poll_wait(file, &dev->iamthif_cl.wait, wait); + mutex_lock(&dev->device_lock); + if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE && + dev->iamthif_file_object == file) { + mask |= (POLLIN | POLLRDNORM); + dev_dbg(&dev->pdev->dev, "run next amthi cb\n"); + mei_amthif_run_next_cmd(dev); + } + return mask; +} + + + +/** + * mei_amthif_irq_process_completed - processes completed iamthif operation. + * + * @dev: the device structure. + * @slots: free slots. + * @cb_pos: callback block. + * @cl: private data of the file object. + * @cmpl_list: complete list. + * + * returns 0, OK; otherwise, error. + */ +int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots, + struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list) +{ + struct mei_msg_hdr *mei_hdr; + struct mei_cl *cl = cb->cl; + size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index; + size_t msg_slots = mei_data2slots(len); + + mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; + mei_hdr->host_addr = cl->host_client_id; + mei_hdr->me_addr = cl->me_client_id; + mei_hdr->reserved = 0; + + if (*slots >= msg_slots) { + mei_hdr->length = len; + mei_hdr->msg_complete = 1; + /* Split the message only if we can write the whole host buffer */ + } else if (*slots == dev->hbuf_depth) { + msg_slots = *slots; + len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); + mei_hdr->length = len; + mei_hdr->msg_complete = 0; + } else { + /* wait for next time the host buffer is empty */ + return 0; + } + + dev_dbg(&dev->pdev->dev, "msg: len = %d complete = %d\n", + mei_hdr->length, mei_hdr->msg_complete); + + *slots -= msg_slots; + if (mei_write_message(dev, mei_hdr, + dev->iamthif_msg_buf + dev->iamthif_msg_buf_index, + mei_hdr->length)) { + dev->iamthif_state = MEI_IAMTHIF_IDLE; + cl->status = -ENODEV; + list_del(&cb->list); + return -ENODEV; + } + + if (mei_flow_ctrl_reduce(dev, cl)) + return -ENODEV; + + dev->iamthif_msg_buf_index += mei_hdr->length; + cl->status = 0; + + if (mei_hdr->msg_complete) { + dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; + dev->iamthif_flow_control_pending = true; + + /* save iamthif cb sent to amthi client */ + cb->buf_idx = dev->iamthif_msg_buf_index; + dev->iamthif_current_cb = cb; + + list_move_tail(&cb->list, &dev->write_waiting_list.list); + } + + + return 0; +} + +/** + * mei_amthif_irq_read_message - read routine after ISR to + * handle the read amthi message + * + * @complete_list: An instance of our list structure + * @dev: the device structure + * @mei_hdr: header of amthi message + * + * returns 0 on success, <0 on failure. + */ +int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list, + struct mei_device *dev, struct mei_msg_hdr *mei_hdr) +{ + struct mei_cl_cb *cb; + unsigned char *buffer; + + BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id); + BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING); + + buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index; + BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length); + + mei_read_slots(dev, buffer, mei_hdr->length); + + dev->iamthif_msg_buf_index += mei_hdr->length; + + if (!mei_hdr->msg_complete) + return 0; + + dev_dbg(&dev->pdev->dev, + "amthi_message_buffer_index =%d\n", + mei_hdr->length); + + dev_dbg(&dev->pdev->dev, "completed amthi read.\n "); + if (!dev->iamthif_current_cb) + return -ENODEV; + + cb = dev->iamthif_current_cb; + dev->iamthif_current_cb = NULL; + + if (!cb->cl) + return -ENODEV; + + dev->iamthif_stall_timer = 0; + cb->buf_idx = dev->iamthif_msg_buf_index; + cb->read_time = jiffies; + if (dev->iamthif_ioctl && cb->cl == &dev->iamthif_cl) { + /* found the iamthif cb */ + dev_dbg(&dev->pdev->dev, "complete the amthi read cb.\n "); + dev_dbg(&dev->pdev->dev, "add the amthi read cb to complete.\n "); + list_add_tail(&cb->list, &complete_list->list); + } + return 0; +} + +/** + * mei_amthif_irq_read - prepares to read amthif data. + * + * @dev: the device structure. + * @slots: free slots. + * + * returns 0, OK; otherwise, error. + */ +int mei_amthif_irq_read(struct mei_device *dev, s32 *slots) +{ + + if (((*slots) * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + + sizeof(struct hbm_flow_control))) { + return -EMSGSIZE; + } + *slots -= mei_data2slots(sizeof(struct hbm_flow_control)); + if (mei_send_flow_control(dev, &dev->iamthif_cl)) { + dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n"); + return -EIO; + } + + dev_dbg(&dev->pdev->dev, "iamthif flow control success\n"); + dev->iamthif_state = MEI_IAMTHIF_READING; + dev->iamthif_flow_control_pending = false; + dev->iamthif_msg_buf_index = 0; + dev->iamthif_msg_buf_size = 0; + dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER; + dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev); + return 0; +} + +/** + * mei_amthif_complete - complete amthif callback. + * + * @dev: the device structure. + * @cb_pos: callback block. + */ +void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb) +{ + if (dev->iamthif_canceled != 1) { + dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE; + dev->iamthif_stall_timer = 0; + memcpy(cb->response_buffer.data, + dev->iamthif_msg_buf, + dev->iamthif_msg_buf_index); + list_add_tail(&cb->list, &dev->amthif_rd_complete_list.list); + dev_dbg(&dev->pdev->dev, "amthi read completed\n"); + dev->iamthif_timer = jiffies; + dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n", + dev->iamthif_timer); + } else { + mei_amthif_run_next_cmd(dev); + } + + dev_dbg(&dev->pdev->dev, "completing amthi call back.\n"); + wake_up_interruptible(&dev->iamthif_cl.wait); +} + +/** + * mei_clear_list - removes all callbacks associated with file + * from mei_cb_list + * + * @dev: device structure. + * @file: file structure + * @mei_cb_list: callbacks list + * + * mei_clear_list is called to clear resources associated with file + * when application calls close function or Ctrl-C was pressed + * + * returns true if callback removed from the list, false otherwise + */ +static bool mei_clear_list(struct mei_device *dev, + const struct file *file, struct list_head *mei_cb_list) +{ + struct mei_cl_cb *cb_pos = NULL; + struct mei_cl_cb *cb_next = NULL; + bool removed = false; + + /* list all list member */ + list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, list) { + /* check if list member associated with a file */ + if (file == cb_pos->file_object) { + /* remove member from the list */ + list_del(&cb_pos->list); + /* check if cb equal to current iamthif cb */ + if (dev->iamthif_current_cb == cb_pos) { + dev->iamthif_current_cb = NULL; + /* send flow control to iamthif client */ + mei_send_flow_control(dev, &dev->iamthif_cl); + } + /* free all allocated buffers */ + mei_io_cb_free(cb_pos); + cb_pos = NULL; + removed = true; + } + } + return removed; +} + +/** + * mei_clear_lists - removes all callbacks associated with file + * + * @dev: device structure + * @file: file structure + * + * mei_clear_lists is called to clear resources associated with file + * when application calls close function or Ctrl-C was pressed + * + * returns true if callback removed from the list, false otherwise + */ +static bool mei_clear_lists(struct mei_device *dev, struct file *file) +{ + bool removed = false; + + /* remove callbacks associated with a file */ + mei_clear_list(dev, file, &dev->amthif_cmd_list.list); + if (mei_clear_list(dev, file, &dev->amthif_rd_complete_list.list)) + removed = true; + + mei_clear_list(dev, file, &dev->ctrl_rd_list.list); + + if (mei_clear_list(dev, file, &dev->ctrl_wr_list.list)) + removed = true; + + if (mei_clear_list(dev, file, &dev->write_waiting_list.list)) + removed = true; + + if (mei_clear_list(dev, file, &dev->write_list.list)) + removed = true; + + /* check if iamthif_current_cb not NULL */ + if (dev->iamthif_current_cb && !removed) { + /* check file and iamthif current cb association */ + if (dev->iamthif_current_cb->file_object == file) { + /* remove cb */ + mei_io_cb_free(dev->iamthif_current_cb); + dev->iamthif_current_cb = NULL; + removed = true; + } + } + return removed; +} + +/** +* mei_amthif_release - the release function +* +* @inode: pointer to inode structure +* @file: pointer to file structure +* +* returns 0 on success, <0 on error +*/ +int mei_amthif_release(struct mei_device *dev, struct file *file) +{ + if (dev->open_handle_count > 0) + dev->open_handle_count--; + + if (dev->iamthif_file_object == file && + dev->iamthif_state != MEI_IAMTHIF_IDLE) { + + dev_dbg(&dev->pdev->dev, "amthi canceled iamthif state %d\n", + dev->iamthif_state); + dev->iamthif_canceled = true; + if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) { + dev_dbg(&dev->pdev->dev, "run next amthi iamthif cb\n"); + mei_amthif_run_next_cmd(dev); + } + } + + if (mei_clear_lists(dev, file)) + dev->iamthif_state = MEI_IAMTHIF_IDLE; + + return 0; +} diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index 9700532f02f..be8ca6b333c 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -20,16 +20,16 @@ #include <linux/uuid.h> /* - * Timeouts + * Timeouts in Seconds */ -#define MEI_INTEROP_TIMEOUT (HZ * 7) -#define MEI_CONNECT_TIMEOUT 3 /* at least 2 seconds */ +#define MEI_INTEROP_TIMEOUT 7 /* Timeout on ready message */ +#define MEI_CONNECT_TIMEOUT 3 /* HPS: at least 2 seconds */ -#define CONNECT_TIMEOUT 15 /* HPS definition */ -#define INIT_CLIENTS_TIMEOUT 15 /* HPS definition */ +#define MEI_CL_CONNECT_TIMEOUT 15 /* HPS: Client Connect Timeout */ +#define MEI_CLIENTS_INIT_TIMEOUT 15 /* HPS: Clients Enumeration Timeout */ -#define IAMTHIF_STALL_TIMER 12 /* seconds */ -#define IAMTHIF_READ_TIMER 10000 /* ms */ +#define MEI_IAMTHIF_STALL_TIMER 12 /* HPS */ +#define MEI_IAMTHIF_READ_TIMER 10 /* HPS */ /* * Internal Clients Number @@ -293,6 +293,14 @@ struct hbm_props_response { struct mei_client_properties client_properties; } __packed; +/** + * struct hbm_client_connect_request - connect/disconnect request + * + * @hbm_cmd - bus message command header + * @me_addr - address of the client in ME + * @host_addr - address of the client in the driver + * @reserved + */ struct hbm_client_connect_request { u8 hbm_cmd; u8 me_addr; @@ -300,6 +308,14 @@ struct hbm_client_connect_request { u8 reserved; } __packed; +/** + * struct hbm_client_connect_response - connect/disconnect response + * + * @hbm_cmd - bus message command header + * @me_addr - address of the client in ME + * @host_addr - address of the client in the driver + * @status - status of the request + */ struct hbm_client_connect_response { u8 hbm_cmd; u8 me_addr; @@ -307,12 +323,6 @@ struct hbm_client_connect_response { u8 status; } __packed; -struct hbm_client_disconnect_request { - u8 hbm_cmd; - u8 me_addr; - u8 host_addr; - u8 reserved[1]; -} __packed; #define MEI_FC_MESSAGE_RESERVED_LENGTH 5 diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 98f1430e3e1..a54cd5567ca 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -43,21 +43,6 @@ const char *mei_dev_state_str(int state) } -const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac, - 0xa8, 0x46, 0xe0, 0xff, 0x65, - 0x81, 0x4c); - -/** - * mei_io_list_init - Sets up a queue list. - * - * @list: An instance io list structure - * @dev: the device structure - */ -void mei_io_list_init(struct mei_io_list *list) -{ - /* initialize our queue list */ - INIT_LIST_HEAD(&list->mei_cb.cb_list); -} /** * mei_io_list_flush - removes list entry belonging to cl. @@ -65,17 +50,15 @@ void mei_io_list_init(struct mei_io_list *list) * @list: An instance of our list structure * @cl: private data of the file object */ -void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl) +void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl) { struct mei_cl_cb *pos; struct mei_cl_cb *next; - list_for_each_entry_safe(pos, next, &list->mei_cb.cb_list, cb_list) { - if (pos->file_private) { - struct mei_cl *cl_tmp; - cl_tmp = (struct mei_cl *)pos->file_private; - if (mei_cl_cmp_id(cl, cl_tmp)) - list_del(&pos->cb_list); + list_for_each_entry_safe(pos, next, &list->list, list) { + if (pos->cl) { + if (mei_cl_cmp_id(cl, pos->cl)) + list_del(&pos->list); } } } @@ -96,31 +79,14 @@ int mei_cl_flush_queues(struct mei_cl *cl) mei_io_list_flush(&cl->dev->write_waiting_list, cl); mei_io_list_flush(&cl->dev->ctrl_wr_list, cl); mei_io_list_flush(&cl->dev->ctrl_rd_list, cl); - mei_io_list_flush(&cl->dev->amthi_cmd_list, cl); - mei_io_list_flush(&cl->dev->amthi_read_complete_list, cl); + mei_io_list_flush(&cl->dev->amthif_cmd_list, cl); + mei_io_list_flush(&cl->dev->amthif_rd_complete_list, cl); return 0; } /** - * mei_reset_iamthif_params - initializes mei device iamthif - * - * @dev: the device structure - */ -static void mei_reset_iamthif_params(struct mei_device *dev) -{ - /* reset iamthif parameters. */ - dev->iamthif_current_cb = NULL; - dev->iamthif_msg_buf_size = 0; - dev->iamthif_msg_buf_index = 0; - dev->iamthif_canceled = false; - dev->iamthif_ioctl = false; - dev->iamthif_state = MEI_IAMTHIF_IDLE; - dev->iamthif_timer = 0; -} - -/** * init_mei_device - allocates and initializes the mei device structure * * @pdev: The pci device structure @@ -144,16 +110,14 @@ struct mei_device *mei_device_init(struct pci_dev *pdev) init_waitqueue_head(&dev->wait_stop_wd); dev->dev_state = MEI_DEV_INITIALIZING; dev->iamthif_state = MEI_IAMTHIF_IDLE; - dev->wd_interface_reg = false; - mei_io_list_init(&dev->read_list); mei_io_list_init(&dev->write_list); mei_io_list_init(&dev->write_waiting_list); mei_io_list_init(&dev->ctrl_wr_list); mei_io_list_init(&dev->ctrl_rd_list); - mei_io_list_init(&dev->amthi_cmd_list); - mei_io_list_init(&dev->amthi_read_complete_list); + mei_io_list_init(&dev->amthif_cmd_list); + mei_io_list_init(&dev->amthif_rd_complete_list); dev->pdev = pdev; return dev; } @@ -196,7 +160,8 @@ int mei_hw_init(struct mei_device *dev) if (!dev->recvd_msg) { mutex_unlock(&dev->device_lock); err = wait_event_interruptible_timeout(dev->wait_recvd_msg, - dev->recvd_msg, MEI_INTEROP_TIMEOUT); + dev->recvd_msg, + mei_secs_to_jiffies(MEI_INTEROP_TIMEOUT)); mutex_lock(&dev->device_lock); } @@ -317,15 +282,13 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) cl_pos->timer_count = 0; } /* remove entry if already in list */ - dev_dbg(&dev->pdev->dev, "list del iamthif and wd file list.\n"); - mei_remove_client_from_file_list(dev, - dev->wd_cl.host_client_id); + dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n"); + mei_me_cl_unlink(dev, &dev->wd_cl); - mei_remove_client_from_file_list(dev, - dev->iamthif_cl.host_client_id); + mei_me_cl_unlink(dev, &dev->iamthif_cl); - mei_reset_iamthif_params(dev); - dev->extra_write_index = 0; + mei_amthif_reset_params(dev); + memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg)); } dev->me_clients_num = 0; @@ -351,10 +314,9 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) } } /* remove all waiting requests */ - list_for_each_entry_safe(cb_pos, cb_next, - &dev->write_list.mei_cb.cb_list, cb_list) { - list_del(&cb_pos->cb_list); - mei_free_cb_private(cb_pos); + list_for_each_entry_safe(cb_pos, cb_next, &dev->write_list.list, list) { + list_del(&cb_pos->list); + mei_io_cb_free(cb_pos); } } @@ -370,31 +332,26 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) void mei_host_start_message(struct mei_device *dev) { struct mei_msg_hdr *mei_hdr; - struct hbm_host_version_request *host_start_req; + struct hbm_host_version_request *start_req; + const size_t len = sizeof(struct hbm_host_version_request); + + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); /* host start message */ - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_host_version_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - host_start_req = - (struct hbm_host_version_request *) &dev->wr_msg_buf[1]; - memset(host_start_req, 0, sizeof(struct hbm_host_version_request)); - host_start_req->hbm_cmd = HOST_START_REQ_CMD; - host_start_req->host_version.major_version = HBM_MAJOR_VERSION; - host_start_req->host_version.minor_version = HBM_MINOR_VERSION; + start_req = (struct hbm_host_version_request *)&dev->wr_msg_buf[1]; + memset(start_req, 0, len); + start_req->hbm_cmd = HOST_START_REQ_CMD; + start_req->host_version.major_version = HBM_MAJOR_VERSION; + start_req->host_version.minor_version = HBM_MINOR_VERSION; + dev->recvd_msg = false; - if (mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req, - mei_hdr->length)) { + if (mei_write_message(dev, mei_hdr, (unsigned char *)start_req, len)) { dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n"); dev->dev_state = MEI_DEV_RESETING; mei_reset(dev, 1); } dev->init_clients_state = MEI_START_MESSAGE; - dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; + dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; return ; } @@ -408,26 +365,22 @@ void mei_host_start_message(struct mei_device *dev) void mei_host_enum_clients_message(struct mei_device *dev) { struct mei_msg_hdr *mei_hdr; - struct hbm_host_enum_request *host_enum_req; - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; + struct hbm_host_enum_request *enum_req; + const size_t len = sizeof(struct hbm_host_enum_request); /* enumerate clients */ - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_host_enum_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - host_enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1]; - memset(host_enum_req, 0, sizeof(struct hbm_host_enum_request)); - host_enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; - if (mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req, - mei_hdr->length)) { + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); + + enum_req = (struct hbm_host_enum_request *) &dev->wr_msg_buf[1]; + memset(enum_req, 0, sizeof(struct hbm_host_enum_request)); + enum_req->hbm_cmd = HOST_ENUM_REQ_CMD; + + if (mei_write_message(dev, mei_hdr, (unsigned char *)enum_req, len)) { dev->dev_state = MEI_DEV_RESETING; dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); mei_reset(dev, 1); } dev->init_clients_state = MEI_ENUM_CLIENTS_MESSAGE; - dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; + dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; return; } @@ -470,56 +423,87 @@ void mei_allocate_me_clients_storage(struct mei_device *dev) dev->me_clients = clients; return ; } -/** - * host_client_properties - reads properties for client - * - * @dev: the device structure - * - * returns: - * < 0 - Error. - * = 0 - no more clients. - * = 1 - still have clients to send properties request. - */ -int mei_host_client_properties(struct mei_device *dev) + +void mei_host_client_init(struct work_struct *work) { - struct mei_msg_hdr *mei_header; - struct hbm_props_request *host_cli_req; - int b; - u8 client_num = dev->me_client_presentation_num; - - b = dev->me_client_index; - b = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, b); - if (b < MEI_CLIENTS_MAX) { - dev->me_clients[client_num].client_id = b; - dev->me_clients[client_num].mei_flow_ctrl_creds = 0; - mei_header = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; - mei_header->host_addr = 0; - mei_header->me_addr = 0; - mei_header->length = sizeof(struct hbm_props_request); - mei_header->msg_complete = 1; - mei_header->reserved = 0; - - host_cli_req = (struct hbm_props_request *)&dev->wr_msg_buf[1]; - - memset(host_cli_req, 0, sizeof(struct hbm_props_request)); - - host_cli_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; - host_cli_req->address = b; - - if (mei_write_message(dev, mei_header, - (unsigned char *)host_cli_req, - mei_header->length)) { - dev->dev_state = MEI_DEV_RESETING; - dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n"); - mei_reset(dev, 1); - return -EIO; - } + struct mei_device *dev = container_of(work, + struct mei_device, init_work); + struct mei_client_properties *client_props; + int i; + + mutex_lock(&dev->device_lock); + + bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); + dev->open_handle_count = 0; + + /* + * Reserving the first three client IDs + * 0: Reserved for MEI Bus Message communications + * 1: Reserved for Watchdog + * 2: Reserved for AMTHI + */ + bitmap_set(dev->host_clients_map, 0, 3); + + for (i = 0; i < dev->me_clients_num; i++) { + client_props = &dev->me_clients[i].props; + + if (!uuid_le_cmp(client_props->protocol_name, mei_amthi_guid)) + mei_amthif_host_init(dev); + else if (!uuid_le_cmp(client_props->protocol_name, mei_wd_guid)) + mei_wd_host_init(dev); + } + + dev->dev_state = MEI_DEV_ENABLED; - dev->init_clients_timer = INIT_CLIENTS_TIMEOUT; - dev->me_client_index = b; - return 1; + mutex_unlock(&dev->device_lock); +} + +int mei_host_client_enumerate(struct mei_device *dev) +{ + + struct mei_msg_hdr *mei_hdr; + struct hbm_props_request *prop_req; + const size_t len = sizeof(struct hbm_props_request); + unsigned long next_client_index; + u8 client_num; + + + client_num = dev->me_client_presentation_num; + + next_client_index = find_next_bit(dev->me_clients_map, MEI_CLIENTS_MAX, + dev->me_client_index); + + /* We got all client properties */ + if (next_client_index == MEI_CLIENTS_MAX) { + schedule_work(&dev->init_work); + + return 0; } + dev->me_clients[client_num].client_id = next_client_index; + dev->me_clients[client_num].mei_flow_ctrl_creds = 0; + + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); + prop_req = (struct hbm_props_request *)&dev->wr_msg_buf[1]; + + memset(prop_req, 0, sizeof(struct hbm_props_request)); + + + prop_req->hbm_cmd = HOST_CLIENT_PROPERTIES_REQ_CMD; + prop_req->address = next_client_index; + + if (mei_write_message(dev, mei_hdr, (unsigned char *) prop_req, + mei_hdr->length)) { + dev->dev_state = MEI_DEV_RESETING; + dev_err(&dev->pdev->dev, "Properties request command failed\n"); + mei_reset(dev, 1); + + return -EIO; + } + + dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; + dev->me_client_index = next_client_index; + return 0; } @@ -557,17 +541,20 @@ int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid) /** - * mei_me_cl_update_filext - searches for ME client guid - * sets client_id in mei_file_private if found + * mei_me_cl_link - create link between host and me clinet and add + * me_cl to the list + * * @dev: the device structure - * @cl: private file structure to set client_id in - * @cuuid: searched uuid of ME client - * @client_id: id of host client to be set in file private structure + * @cl: link between me and host client assocated with opened file descriptor + * @cuuid: uuid of ME client + * @client_id: id of the host client * - * returns ME client index + * returns ME client index if ME client + * -EINVAL on incorrect values + * -ENONET if client not found */ -int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl, - const uuid_le *cuuid, u8 host_cl_id) +int mei_me_cl_link(struct mei_device *dev, struct mei_cl *cl, + const uuid_le *cuuid, u8 host_cl_id) { int i; @@ -587,54 +574,22 @@ int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl, return -ENOENT; } - /** - * host_init_iamthif - mei initialization iamthif client. + * mei_me_cl_unlink - remove me_cl from the list * * @dev: the device structure - * + * @host_client_id: host client id to be removed */ -void mei_host_init_iamthif(struct mei_device *dev) +void mei_me_cl_unlink(struct mei_device *dev, struct mei_cl *cl) { - int i; - unsigned char *msg_buf; - - mei_cl_init(&dev->iamthif_cl, dev); - dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; - - /* find ME amthi client */ - i = mei_me_cl_update_filext(dev, &dev->iamthif_cl, - &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID); - if (i < 0) { - dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n"); - return; - } - - /* Assign iamthif_mtu to the value received from ME */ - - dev->iamthif_mtu = dev->me_clients[i].props.max_msg_length; - dev_dbg(&dev->pdev->dev, "IAMTHIF_MTU = %d\n", - dev->me_clients[i].props.max_msg_length); - - kfree(dev->iamthif_msg_buf); - dev->iamthif_msg_buf = NULL; - - /* allocate storage for ME message buffer */ - msg_buf = kcalloc(dev->iamthif_mtu, - sizeof(unsigned char), GFP_KERNEL); - if (!msg_buf) { - dev_dbg(&dev->pdev->dev, "memory allocation for ME message buffer failed.\n"); - return; - } - - dev->iamthif_msg_buf = msg_buf; - - if (mei_connect(dev, &dev->iamthif_cl)) { - dev_dbg(&dev->pdev->dev, "Failed to connect to AMTHI client\n"); - dev->iamthif_cl.state = MEI_FILE_DISCONNECTED; - dev->iamthif_cl.host_client_id = 0; - } else { - dev->iamthif_cl.timer_count = CONNECT_TIMEOUT; + struct mei_cl *pos, *next; + list_for_each_entry_safe(pos, next, &dev->file_list, link) { + if (cl->host_client_id == pos->host_client_id) { + dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", + pos->host_client_id, pos->me_client_id); + list_del_init(&pos->link); + break; + } } } @@ -671,9 +626,8 @@ struct mei_cl *mei_cl_allocate(struct mei_device *dev) */ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) { - int rets, err; - long timeout = 15; /* 15 seconds */ struct mei_cl_cb *cb; + int rets, err; if (!dev || !cl) return -ENODEV; @@ -681,13 +635,11 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) if (cl->state != MEI_FILE_DISCONNECTING) return 0; - cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); + cb = mei_io_cb_init(cl, NULL); if (!cb) return -ENOMEM; - INIT_LIST_HEAD(&cb->cb_list); - cb->file_private = cl; - cb->major_file_operations = MEI_CLOSE; + cb->fop_type = MEI_FOP_CLOSE; if (dev->mei_host_buffer_is_empty) { dev->mei_host_buffer_is_empty = false; if (mei_disconnect(dev, cl)) { @@ -696,17 +648,17 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) goto free; } mdelay(10); /* Wait for hardware disconnection ready */ - list_add_tail(&cb->cb_list, &dev->ctrl_rd_list.mei_cb.cb_list); + list_add_tail(&cb->list, &dev->ctrl_rd_list.list); } else { dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); - list_add_tail(&cb->cb_list, - &dev->ctrl_wr_list.mei_cb.cb_list); + list_add_tail(&cb->list, &dev->ctrl_wr_list.list); + } mutex_unlock(&dev->device_lock); err = wait_event_timeout(dev->wait_recvd_msg, - (MEI_FILE_DISCONNECTED == cl->state), - timeout * HZ); + MEI_FILE_DISCONNECTED == cl->state, + mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT)); mutex_lock(&dev->device_lock); if (MEI_FILE_DISCONNECTED == cl->state) { @@ -728,29 +680,7 @@ int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl) mei_io_list_flush(&dev->ctrl_rd_list, cl); mei_io_list_flush(&dev->ctrl_wr_list, cl); free: - mei_free_cb_private(cb); + mei_io_cb_free(cb); return rets; } -/** - * mei_remove_client_from_file_list - - * removes file private data from device file list - * - * @dev: the device structure - * @host_client_id: host client id to be removed - */ -void mei_remove_client_from_file_list(struct mei_device *dev, - u8 host_client_id) -{ - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; - list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { - if (host_client_id == cl_pos->host_client_id) { - dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", - cl_pos->host_client_id, - cl_pos->me_client_id); - list_del_init(&cl_pos->link); - break; - } - } -} diff --git a/drivers/misc/mei/interface.c b/drivers/misc/mei/interface.c index 509c3957ff4..8de85478596 100644 --- a/drivers/misc/mei/interface.c +++ b/drivers/misc/mei/interface.c @@ -292,28 +292,23 @@ int mei_flow_ctrl_reduce(struct mei_device *dev, struct mei_cl *cl) int mei_send_flow_control(struct mei_device *dev, struct mei_cl *cl) { struct mei_msg_hdr *mei_hdr; - struct hbm_flow_control *mei_flow_control; - - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_flow_control); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - mei_flow_control = (struct hbm_flow_control *) &dev->wr_msg_buf[1]; - memset(mei_flow_control, 0, sizeof(*mei_flow_control)); - mei_flow_control->host_addr = cl->host_client_id; - mei_flow_control->me_addr = cl->me_client_id; - mei_flow_control->hbm_cmd = MEI_FLOW_CONTROL_CMD; - memset(mei_flow_control->reserved, 0, - sizeof(mei_flow_control->reserved)); + struct hbm_flow_control *flow_ctrl; + const size_t len = sizeof(struct hbm_flow_control); + + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); + + flow_ctrl = (struct hbm_flow_control *)&dev->wr_msg_buf[1]; + memset(flow_ctrl, 0, len); + flow_ctrl->hbm_cmd = MEI_FLOW_CONTROL_CMD; + flow_ctrl->host_addr = cl->host_client_id; + flow_ctrl->me_addr = cl->me_client_id; + /* FIXME: reserved !? */ + memset(flow_ctrl->reserved, 0, sizeof(flow_ctrl->reserved)); dev_dbg(&dev->pdev->dev, "sending flow control host client = %d, ME client = %d\n", cl->host_client_id, cl->me_client_id); return mei_write_message(dev, mei_hdr, - (unsigned char *) mei_flow_control, - sizeof(struct hbm_flow_control)); + (unsigned char *) flow_ctrl, len); } /** @@ -352,26 +347,19 @@ int mei_other_client_is_connecting(struct mei_device *dev, int mei_disconnect(struct mei_device *dev, struct mei_cl *cl) { struct mei_msg_hdr *mei_hdr; - struct hbm_client_disconnect_request *mei_cli_disconnect; - - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_client_disconnect_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - mei_cli_disconnect = - (struct hbm_client_disconnect_request *) &dev->wr_msg_buf[1]; - memset(mei_cli_disconnect, 0, sizeof(*mei_cli_disconnect)); - mei_cli_disconnect->host_addr = cl->host_client_id; - mei_cli_disconnect->me_addr = cl->me_client_id; - mei_cli_disconnect->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD; - mei_cli_disconnect->reserved[0] = 0; + struct hbm_client_connect_request *req; + const size_t len = sizeof(struct hbm_client_connect_request); - return mei_write_message(dev, mei_hdr, - (unsigned char *) mei_cli_disconnect, - sizeof(struct hbm_client_disconnect_request)); + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); + + req = (struct hbm_client_connect_request *)&dev->wr_msg_buf[1]; + memset(req, 0, len); + req->hbm_cmd = CLIENT_DISCONNECT_REQ_CMD; + req->host_addr = cl->host_client_id; + req->me_addr = cl->me_client_id; + req->reserved = 0; + + return mei_write_message(dev, mei_hdr, (unsigned char *)req, len); } /** @@ -385,23 +373,16 @@ int mei_disconnect(struct mei_device *dev, struct mei_cl *cl) int mei_connect(struct mei_device *dev, struct mei_cl *cl) { struct mei_msg_hdr *mei_hdr; - struct hbm_client_connect_request *mei_cli_connect; - - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_client_connect_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - mei_cli_connect = - (struct hbm_client_connect_request *) &dev->wr_msg_buf[1]; - mei_cli_connect->host_addr = cl->host_client_id; - mei_cli_connect->me_addr = cl->me_client_id; - mei_cli_connect->hbm_cmd = CLIENT_CONNECT_REQ_CMD; - mei_cli_connect->reserved = 0; + struct hbm_client_connect_request *req; + const size_t len = sizeof(struct hbm_client_connect_request); - return mei_write_message(dev, mei_hdr, - (unsigned char *) mei_cli_connect, - sizeof(struct hbm_client_connect_request)); + mei_hdr = mei_hbm_hdr(&dev->wr_msg_buf[0], len); + + req = (struct hbm_client_connect_request *) &dev->wr_msg_buf[1]; + req->hbm_cmd = CLIENT_CONNECT_REQ_CMD; + req->host_addr = cl->host_client_id; + req->me_addr = cl->me_client_id; + req->reserved = 0; + + return mei_write_message(dev, mei_hdr, (unsigned char *) req, len); } diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 3533edde04a..04fa2134615 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -57,14 +57,14 @@ irqreturn_t mei_interrupt_quick_handler(int irq, void *dev_id) */ static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos) { - if (cb_pos->major_file_operations == MEI_WRITE) { - mei_free_cb_private(cb_pos); + if (cb_pos->fop_type == MEI_FOP_WRITE) { + mei_io_cb_free(cb_pos); cb_pos = NULL; cl->writing_state = MEI_WRITE_COMPLETE; if (waitqueue_active(&cl->tx_wait)) wake_up_interruptible(&cl->tx_wait); - } else if (cb_pos->major_file_operations == MEI_READ && + } else if (cb_pos->fop_type == MEI_FOP_READ && MEI_READING == cl->reading_state) { cl->reading_state = MEI_READ_COMPLETE; if (waitqueue_active(&cl->rx_wait)) @@ -74,94 +74,6 @@ static void _mei_cmpl(struct mei_cl *cl, struct mei_cl_cb *cb_pos) } /** - * _mei_cmpl_iamthif - processes completed iamthif operation. - * - * @dev: the device structure. - * @cb_pos: callback block. - */ -static void _mei_cmpl_iamthif(struct mei_device *dev, struct mei_cl_cb *cb_pos) -{ - if (dev->iamthif_canceled != 1) { - dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE; - dev->iamthif_stall_timer = 0; - memcpy(cb_pos->response_buffer.data, - dev->iamthif_msg_buf, - dev->iamthif_msg_buf_index); - list_add_tail(&cb_pos->cb_list, - &dev->amthi_read_complete_list.mei_cb.cb_list); - dev_dbg(&dev->pdev->dev, "amthi read completed.\n"); - dev->iamthif_timer = jiffies; - dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n", - dev->iamthif_timer); - } else { - mei_run_next_iamthif_cmd(dev); - } - - dev_dbg(&dev->pdev->dev, "completing amthi call back.\n"); - wake_up_interruptible(&dev->iamthif_cl.wait); -} - - -/** - * mei_irq_thread_read_amthi_message - bottom half read routine after ISR to - * handle the read amthi message data processing. - * - * @complete_list: An instance of our list structure - * @dev: the device structure - * @mei_hdr: header of amthi message - * - * returns 0 on success, <0 on failure. - */ -static int mei_irq_thread_read_amthi_message(struct mei_io_list *complete_list, - struct mei_device *dev, - struct mei_msg_hdr *mei_hdr) -{ - struct mei_cl *cl; - struct mei_cl_cb *cb; - unsigned char *buffer; - - BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id); - BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING); - - buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index; - BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length); - - mei_read_slots(dev, buffer, mei_hdr->length); - - dev->iamthif_msg_buf_index += mei_hdr->length; - - if (!mei_hdr->msg_complete) - return 0; - - dev_dbg(&dev->pdev->dev, - "amthi_message_buffer_index =%d\n", - mei_hdr->length); - - dev_dbg(&dev->pdev->dev, "completed amthi read.\n "); - if (!dev->iamthif_current_cb) - return -ENODEV; - - cb = dev->iamthif_current_cb; - dev->iamthif_current_cb = NULL; - - cl = (struct mei_cl *)cb->file_private; - if (!cl) - return -ENODEV; - - dev->iamthif_stall_timer = 0; - cb->information = dev->iamthif_msg_buf_index; - cb->read_time = jiffies; - if (dev->iamthif_ioctl && cl == &dev->iamthif_cl) { - /* found the iamthif cb */ - dev_dbg(&dev->pdev->dev, "complete the amthi read cb.\n "); - dev_dbg(&dev->pdev->dev, "add the amthi read cb to complete.\n "); - list_add_tail(&cb->cb_list, - &complete_list->mei_cb.cb_list); - } - return 0; -} - -/** * _mei_irq_thread_state_ok - checks if mei header matches file private data * * @cl: private data of the file object @@ -188,7 +100,7 @@ static int _mei_irq_thread_state_ok(struct mei_cl *cl, * * returns 0 on success, <0 on failure. */ -static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list, +static int mei_irq_thread_read_client_message(struct mei_cl_cb *complete_list, struct mei_device *dev, struct mei_msg_hdr *mei_hdr) { @@ -197,36 +109,36 @@ static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list, unsigned char *buffer = NULL; dev_dbg(&dev->pdev->dev, "start client msg\n"); - if (list_empty(&dev->read_list.mei_cb.cb_list)) + if (list_empty(&dev->read_list.list)) goto quit; - list_for_each_entry_safe(cb_pos, cb_next, - &dev->read_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)cb_pos->file_private; + list_for_each_entry_safe(cb_pos, cb_next, &dev->read_list.list, list) { + cl = cb_pos->cl; if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) { cl->reading_state = MEI_READING; - buffer = cb_pos->response_buffer.data + cb_pos->information; + buffer = cb_pos->response_buffer.data + cb_pos->buf_idx; if (cb_pos->response_buffer.size < - mei_hdr->length + cb_pos->information) { + mei_hdr->length + cb_pos->buf_idx) { dev_dbg(&dev->pdev->dev, "message overflow.\n"); - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); return -ENOMEM; } if (buffer) mei_read_slots(dev, buffer, mei_hdr->length); - cb_pos->information += mei_hdr->length; + cb_pos->buf_idx += mei_hdr->length; if (mei_hdr->msg_complete) { cl->status = 0; - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); dev_dbg(&dev->pdev->dev, "completed read H cl = %d, ME cl = %d, length = %lu\n", cl->host_client_id, cl->me_client_id, - cb_pos->information); - list_add_tail(&cb_pos->cb_list, - &complete_list->mei_cb.cb_list); + cb_pos->buf_idx); + + list_add_tail(&cb_pos->list, + &complete_list->list); } break; @@ -246,37 +158,6 @@ quit: } /** - * _mei_irq_thread_iamthif_read - prepares to read iamthif data. - * - * @dev: the device structure. - * @slots: free slots. - * - * returns 0, OK; otherwise, error. - */ -static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots) -{ - - if (((*slots) * sizeof(u32)) < (sizeof(struct mei_msg_hdr) - + sizeof(struct hbm_flow_control))) { - return -EMSGSIZE; - } - *slots -= mei_data2slots(sizeof(struct hbm_flow_control)); - if (mei_send_flow_control(dev, &dev->iamthif_cl)) { - dev_dbg(&dev->pdev->dev, "iamthif flow control failed\n"); - return -EIO; - } - - dev_dbg(&dev->pdev->dev, "iamthif flow control success\n"); - dev->iamthif_state = MEI_IAMTHIF_READING; - dev->iamthif_flow_control_pending = false; - dev->iamthif_msg_buf_index = 0; - dev->iamthif_msg_buf_size = 0; - dev->iamthif_stall_timer = IAMTHIF_STALL_TIMER; - dev->mei_host_buffer_is_empty = mei_hbuf_is_empty(dev); - return 0; -} - -/** * _mei_irq_thread_close - processes close related operation. * * @dev: the device structure. @@ -290,26 +171,24 @@ static int _mei_irq_thread_iamthif_read(struct mei_device *dev, s32 *slots) static int _mei_irq_thread_close(struct mei_device *dev, s32 *slots, struct mei_cl_cb *cb_pos, struct mei_cl *cl, - struct mei_io_list *cmpl_list) + struct mei_cl_cb *cmpl_list) { if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + - sizeof(struct hbm_client_disconnect_request))) + sizeof(struct hbm_client_connect_request))) return -EBADMSG; - *slots -= mei_data2slots(sizeof(struct hbm_client_disconnect_request)); + *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request)); if (mei_disconnect(dev, cl)) { cl->status = 0; - cb_pos->information = 0; - list_move_tail(&cb_pos->cb_list, - &cmpl_list->mei_cb.cb_list); + cb_pos->buf_idx = 0; + list_move_tail(&cb_pos->list, &cmpl_list->list); return -EMSGSIZE; } else { cl->state = MEI_FILE_DISCONNECTING; cl->status = 0; - cb_pos->information = 0; - list_move_tail(&cb_pos->cb_list, - &dev->ctrl_rd_list.mei_cb.cb_list); + cb_pos->buf_idx = 0; + list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list); cl->timer_count = MEI_CONNECT_TIMEOUT; } @@ -356,7 +235,7 @@ static void mei_client_connect_response(struct mei_device *dev, { struct mei_cl *cl; - struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; + struct mei_cl_cb *pos = NULL, *next = NULL; dev_dbg(&dev->pdev->dev, "connect_response:\n" @@ -373,8 +252,6 @@ static void mei_client_connect_response(struct mei_device *dev, dev_dbg(&dev->pdev->dev, "successfully connected to WD client.\n"); mei_watchdog_register(dev); - /* next step in the state maching */ - mei_host_init_iamthif(dev); return; } @@ -382,17 +259,16 @@ static void mei_client_connect_response(struct mei_device *dev, dev->iamthif_state = MEI_IAMTHIF_IDLE; return; } - list_for_each_entry_safe(cb_pos, cb_next, - &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) { + list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) { - cl = (struct mei_cl *)cb_pos->file_private; + cl = pos->cl; if (!cl) { - list_del(&cb_pos->cb_list); + list_del(&pos->list); return; } - if (MEI_IOCTL == cb_pos->major_file_operations) { + if (pos->fop_type == MEI_FOP_IOCTL) { if (is_treat_specially_client(cl, rs)) { - list_del(&cb_pos->cb_list); + list_del(&pos->list); cl->status = 0; cl->timer_count = 0; break; @@ -411,7 +287,7 @@ static void mei_client_disconnect_response(struct mei_device *dev, struct hbm_client_connect_response *rs) { struct mei_cl *cl; - struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; + struct mei_cl_cb *pos = NULL, *next = NULL; dev_dbg(&dev->pdev->dev, "disconnect_response:\n" @@ -422,12 +298,11 @@ static void mei_client_disconnect_response(struct mei_device *dev, rs->host_addr, rs->status); - list_for_each_entry_safe(cb_pos, cb_next, - &dev->ctrl_rd_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)cb_pos->file_private; + list_for_each_entry_safe(pos, next, &dev->ctrl_rd_list.list, list) { + cl = pos->cl; if (!cl) { - list_del(&cb_pos->cb_list); + list_del(&pos->list); return; } @@ -435,7 +310,7 @@ static void mei_client_disconnect_response(struct mei_device *dev, if (cl->host_client_id == rs->host_addr && cl->me_client_id == rs->me_addr) { - list_del(&cb_pos->cb_list); + list_del(&pos->list); if (!rs->status) cl->state = MEI_FILE_DISCONNECTED; @@ -537,10 +412,10 @@ static void mei_client_flow_control_response(struct mei_device *dev, * returns !=0, same; 0,not. */ static int same_disconn_addr(struct mei_cl *cl, - struct hbm_client_disconnect_request *disconn) + struct hbm_client_connect_request *req) { - return (cl->host_client_id == disconn->host_addr && - cl->me_client_id == disconn->me_addr); + return (cl->host_client_id == req->host_addr && + cl->me_client_id == req->me_addr); } /** @@ -550,49 +425,38 @@ static int same_disconn_addr(struct mei_cl *cl, * @disconnect_req: disconnect request bus message. */ static void mei_client_disconnect_request(struct mei_device *dev, - struct hbm_client_disconnect_request *disconnect_req) + struct hbm_client_connect_request *disconnect_req) { - struct mei_msg_hdr *mei_hdr; struct hbm_client_connect_response *disconnect_res; - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; + struct mei_cl *pos, *next; + const size_t len = sizeof(struct hbm_client_connect_response); - list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) { - if (same_disconn_addr(cl_pos, disconnect_req)) { + list_for_each_entry_safe(pos, next, &dev->file_list, link) { + if (same_disconn_addr(pos, disconnect_req)) { dev_dbg(&dev->pdev->dev, "disconnect request host client %d ME client %d.\n", disconnect_req->host_addr, disconnect_req->me_addr); - cl_pos->state = MEI_FILE_DISCONNECTED; - cl_pos->timer_count = 0; - if (cl_pos == &dev->wd_cl) + pos->state = MEI_FILE_DISCONNECTED; + pos->timer_count = 0; + if (pos == &dev->wd_cl) dev->wd_pending = false; - else if (cl_pos == &dev->iamthif_cl) + else if (pos == &dev->iamthif_cl) dev->iamthif_timer = 0; /* prepare disconnect response */ - mei_hdr = - (struct mei_msg_hdr *) &dev->ext_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = - sizeof(struct hbm_client_connect_response); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - + (void)mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len); disconnect_res = (struct hbm_client_connect_response *) - &dev->ext_msg_buf[1]; - disconnect_res->host_addr = cl_pos->host_client_id; - disconnect_res->me_addr = cl_pos->me_client_id; + &dev->wr_ext_msg.data; disconnect_res->hbm_cmd = CLIENT_DISCONNECT_RES_CMD; + disconnect_res->host_addr = pos->host_client_id; + disconnect_res->me_addr = pos->me_client_id; disconnect_res->status = 0; - dev->extra_write_index = 2; break; } } } - /** * mei_irq_thread_read_bus_message - bottom half read routine after ISR to * handle the read bus message cmd processing. @@ -604,16 +468,15 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, struct mei_msg_hdr *mei_hdr) { struct mei_bus_message *mei_msg; + struct mei_me_client *me_client; struct hbm_host_version_response *version_res; struct hbm_client_connect_response *connect_res; struct hbm_client_connect_response *disconnect_res; + struct hbm_client_connect_request *disconnect_req; struct hbm_flow_control *flow_control; struct hbm_props_response *props_res; struct hbm_host_enum_response *enum_res; - struct hbm_client_disconnect_request *disconnect_req; - struct hbm_host_stop_request *host_stop_req; - int res; - + struct hbm_host_stop_request *stop_req; /* read the message to our buffer */ BUG_ON(mei_hdr->length >= sizeof(dev->rd_msg_buf)); @@ -637,26 +500,20 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, return; } } else { + u32 *buf = dev->wr_msg_buf; + const size_t len = sizeof(struct hbm_host_stop_request); + dev->version = version_res->me_max_version; + /* send stop message */ - mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_host_stop_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - host_stop_req = (struct hbm_host_stop_request *) - &dev->wr_msg_buf[1]; - - memset(host_stop_req, - 0, - sizeof(struct hbm_host_stop_request)); - host_stop_req->hbm_cmd = HOST_STOP_REQ_CMD; - host_stop_req->reason = DRIVER_STOP_REQUEST; + mei_hdr = mei_hbm_hdr(&buf[0], len); + stop_req = (struct hbm_host_stop_request *)&buf[1]; + memset(stop_req, 0, len); + stop_req->hbm_cmd = HOST_STOP_REQ_CMD; + stop_req->reason = DRIVER_STOP_REQUEST; + mei_write_message(dev, mei_hdr, - (unsigned char *) (host_stop_req), - mei_hdr->length); + (unsigned char *)stop_req, len); dev_dbg(&dev->pdev->dev, "version mismatch.\n"); return; } @@ -666,16 +523,14 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, break; case CLIENT_CONNECT_RES_CMD: - connect_res = - (struct hbm_client_connect_response *) mei_msg; + connect_res = (struct hbm_client_connect_response *) mei_msg; mei_client_connect_response(dev, connect_res); dev_dbg(&dev->pdev->dev, "client connect response message received.\n"); wake_up(&dev->wait_recvd_msg); break; case CLIENT_DISCONNECT_RES_CMD: - disconnect_res = - (struct hbm_client_connect_response *) mei_msg; + disconnect_res = (struct hbm_client_connect_response *) mei_msg; mei_client_disconnect_response(dev, disconnect_res); dev_dbg(&dev->pdev->dev, "client disconnect response message received.\n"); wake_up(&dev->wait_recvd_msg); @@ -689,64 +544,37 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, case HOST_CLIENT_PROPERTIES_RES_CMD: props_res = (struct hbm_props_response *)mei_msg; + me_client = &dev->me_clients[dev->me_client_presentation_num]; + if (props_res->status || !dev->me_clients) { dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message wrong status.\n"); mei_reset(dev, 1); return; } - if (dev->me_clients[dev->me_client_presentation_num] - .client_id == props_res->address) { - dev->me_clients[dev->me_client_presentation_num].props - = props_res->client_properties; + if (me_client->client_id != props_res->address) { + dev_err(&dev->pdev->dev, + "Host client properties reply mismatch\n"); + mei_reset(dev, 1); - if (dev->dev_state == MEI_DEV_INIT_CLIENTS && - dev->init_clients_state == - MEI_CLIENT_PROPERTIES_MESSAGE) { - dev->me_client_index++; - dev->me_client_presentation_num++; - - /** Send Client Properties request **/ - res = mei_host_client_properties(dev); - if (res < 0) { - dev_dbg(&dev->pdev->dev, "mei_host_client_properties() failed"); - return; - } else if (!res) { - /* - * No more clients to send to. - * Clear Map for indicating now ME clients - * with associated host client - */ - bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); - dev->open_handle_count = 0; - - /* - * Reserving the first three client IDs - * Client Id 0 - Reserved for MEI Bus Message communications - * Client Id 1 - Reserved for Watchdog - * Client ID 2 - Reserved for AMTHI - */ - bitmap_set(dev->host_clients_map, 0, 3); - dev->dev_state = MEI_DEV_ENABLED; - - /* if wd initialization fails, initialization the AMTHI client, - * otherwise the AMTHI client will be initialized after the WD client connect response - * will be received - */ - if (mei_wd_host_init(dev)) - mei_host_init_iamthif(dev); - } + return; + } - } else { - dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message"); - mei_reset(dev, 1); - return; - } - } else { - dev_dbg(&dev->pdev->dev, "reset due to received host client properties response bus message for wrong client ID\n"); + if (dev->dev_state != MEI_DEV_INIT_CLIENTS || + dev->init_clients_state != MEI_CLIENT_PROPERTIES_MESSAGE) { + dev_err(&dev->pdev->dev, + "Unexpected client properties reply\n"); mei_reset(dev, 1); + return; } + + me_client->props = props_res->client_properties; + dev->me_client_index++; + dev->me_client_presentation_num++; + + mei_host_client_enumerate(dev); + break; case HOST_ENUM_RES_CMD: @@ -760,7 +588,8 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, mei_allocate_me_clients_storage(dev); dev->init_clients_state = MEI_CLIENT_PROPERTIES_MESSAGE; - mei_host_client_properties(dev); + + mei_host_client_enumerate(dev); } else { dev_dbg(&dev->pdev->dev, "reset due to received host enumeration clients response bus message.\n"); mei_reset(dev, 1); @@ -776,29 +605,23 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, case CLIENT_DISCONNECT_REQ_CMD: /* search for client */ - disconnect_req = - (struct hbm_client_disconnect_request *) mei_msg; + disconnect_req = (struct hbm_client_connect_request *)mei_msg; mei_client_disconnect_request(dev, disconnect_req); break; case ME_STOP_REQ_CMD: - /* prepare stop request */ - mei_hdr = (struct mei_msg_hdr *) &dev->ext_msg_buf[0]; - mei_hdr->host_addr = 0; - mei_hdr->me_addr = 0; - mei_hdr->length = sizeof(struct hbm_host_stop_request); - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - host_stop_req = - (struct hbm_host_stop_request *) &dev->ext_msg_buf[1]; - memset(host_stop_req, 0, sizeof(struct hbm_host_stop_request)); - host_stop_req->hbm_cmd = HOST_STOP_REQ_CMD; - host_stop_req->reason = DRIVER_STOP_REQUEST; - host_stop_req->reserved[0] = 0; - host_stop_req->reserved[1] = 0; - dev->extra_write_index = 2; - break; + { + /* prepare stop request: sent in next interrupt event */ + + const size_t len = sizeof(struct hbm_host_stop_request); + mei_hdr = mei_hbm_hdr((u32 *)&dev->wr_ext_msg.hdr, len); + stop_req = (struct hbm_host_stop_request *)&dev->wr_ext_msg.data; + memset(stop_req, 0, len); + stop_req->hbm_cmd = HOST_STOP_REQ_CMD; + stop_req->reason = DRIVER_STOP_REQUEST; + break; + } default: BUG(); break; @@ -821,12 +644,12 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev, static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, struct mei_cl_cb *cb_pos, struct mei_cl *cl, - struct mei_io_list *cmpl_list) + struct mei_cl_cb *cmpl_list) { if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + sizeof(struct hbm_flow_control))) { /* return the cancel routine */ - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); return -EBADMSG; } @@ -834,11 +657,11 @@ static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, if (mei_send_flow_control(dev, cl)) { cl->status = -ENODEV; - cb_pos->information = 0; - list_move_tail(&cb_pos->cb_list, &cmpl_list->mei_cb.cb_list); + cb_pos->buf_idx = 0; + list_move_tail(&cb_pos->list, &cmpl_list->list); return -ENODEV; } - list_move_tail(&cb_pos->cb_list, &dev->read_list.mei_cb.cb_list); + list_move_tail(&cb_pos->list, &dev->read_list.list); return 0; } @@ -858,12 +681,12 @@ static int _mei_irq_thread_read(struct mei_device *dev, s32 *slots, static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots, struct mei_cl_cb *cb_pos, struct mei_cl *cl, - struct mei_io_list *cmpl_list) + struct mei_cl_cb *cmpl_list) { if ((*slots * sizeof(u32)) < (sizeof(struct mei_msg_hdr) + sizeof(struct hbm_client_connect_request))) { /* return the cancel routine */ - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); return -EBADMSG; } @@ -871,188 +694,73 @@ static int _mei_irq_thread_ioctl(struct mei_device *dev, s32 *slots, *slots -= mei_data2slots(sizeof(struct hbm_client_connect_request)); if (mei_connect(dev, cl)) { cl->status = -ENODEV; - cb_pos->information = 0; - list_del(&cb_pos->cb_list); + cb_pos->buf_idx = 0; + list_del(&cb_pos->list); return -ENODEV; } else { - list_move_tail(&cb_pos->cb_list, - &dev->ctrl_rd_list.mei_cb.cb_list); + list_move_tail(&cb_pos->list, &dev->ctrl_rd_list.list); cl->timer_count = MEI_CONNECT_TIMEOUT; } return 0; } /** - * _mei_irq_thread_cmpl - processes completed and no-iamthif operation. + * mei_irq_thread_write_complete - write messages to device. * * @dev: the device structure. * @slots: free slots. - * @cb_pos: callback block. - * @cl: private data of the file object. + * @cb: callback block. * @cmpl_list: complete list. * * returns 0, OK; otherwise, error. */ -static int _mei_irq_thread_cmpl(struct mei_device *dev, s32 *slots, - struct mei_cl_cb *cb_pos, - struct mei_cl *cl, - struct mei_io_list *cmpl_list) +static int mei_irq_thread_write_complete(struct mei_device *dev, s32 *slots, + struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list) { struct mei_msg_hdr *mei_hdr; + struct mei_cl *cl = cb->cl; + size_t len = cb->request_buffer.size - cb->buf_idx; + size_t msg_slots = mei_data2slots(len); + + mei_hdr = (struct mei_msg_hdr *)&dev->wr_msg_buf[0]; + mei_hdr->host_addr = cl->host_client_id; + mei_hdr->me_addr = cl->me_client_id; + mei_hdr->reserved = 0; - if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) + - (cb_pos->request_buffer.size - - cb_pos->information))) { - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = cl->host_client_id; - mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = cb_pos->request_buffer.size - - cb_pos->information; + if (*slots >= msg_slots) { + mei_hdr->length = len; mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - dev_dbg(&dev->pdev->dev, "cb_pos->request_buffer.size =%d" - "mei_hdr->msg_complete = %d\n", - cb_pos->request_buffer.size, - mei_hdr->msg_complete); - dev_dbg(&dev->pdev->dev, "cb_pos->information =%lu\n", - cb_pos->information); - dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", - mei_hdr->length); - *slots -= mei_data2slots(mei_hdr->length); - if (mei_write_message(dev, mei_hdr, - (unsigned char *) - (cb_pos->request_buffer.data + - cb_pos->information), - mei_hdr->length)) { - cl->status = -ENODEV; - list_move_tail(&cb_pos->cb_list, - &cmpl_list->mei_cb.cb_list); - return -ENODEV; - } else { - if (mei_flow_ctrl_reduce(dev, cl)) - return -ENODEV; - cl->status = 0; - cb_pos->information += mei_hdr->length; - list_move_tail(&cb_pos->cb_list, - &dev->write_waiting_list.mei_cb.cb_list); - } + /* Split the message only if we can write the whole host buffer */ } else if (*slots == dev->hbuf_depth) { - /* buffer is still empty */ - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = cl->host_client_id; - mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = - (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); + msg_slots = *slots; + len = (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); + mei_hdr->length = len; mei_hdr->msg_complete = 0; - mei_hdr->reserved = 0; - *slots -= mei_data2slots(mei_hdr->length); - if (mei_write_message(dev, mei_hdr, - (unsigned char *) - (cb_pos->request_buffer.data + - cb_pos->information), - mei_hdr->length)) { - cl->status = -ENODEV; - list_move_tail(&cb_pos->cb_list, - &cmpl_list->mei_cb.cb_list); - return -ENODEV; - } else { - cb_pos->information += mei_hdr->length; - dev_dbg(&dev->pdev->dev, - "cb_pos->request_buffer.size =%d" - " mei_hdr->msg_complete = %d\n", - cb_pos->request_buffer.size, - mei_hdr->msg_complete); - dev_dbg(&dev->pdev->dev, "cb_pos->information =%lu\n", - cb_pos->information); - dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", - mei_hdr->length); - } - return -EMSGSIZE; } else { - return -EBADMSG; + /* wait for next time the host buffer is empty */ + return 0; } - return 0; -} - -/** - * _mei_irq_thread_cmpl_iamthif - processes completed iamthif operation. - * - * @dev: the device structure. - * @slots: free slots. - * @cb_pos: callback block. - * @cl: private data of the file object. - * @cmpl_list: complete list. - * - * returns 0, OK; otherwise, error. - */ -static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots, - struct mei_cl_cb *cb_pos, - struct mei_cl *cl, - struct mei_io_list *cmpl_list) -{ - struct mei_msg_hdr *mei_hdr; - - if ((*slots * sizeof(u32)) >= (sizeof(struct mei_msg_hdr) + - dev->iamthif_msg_buf_size - - dev->iamthif_msg_buf_index)) { - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = cl->host_client_id; - mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = dev->iamthif_msg_buf_size - - dev->iamthif_msg_buf_index; - mei_hdr->msg_complete = 1; - mei_hdr->reserved = 0; - - *slots -= mei_data2slots(mei_hdr->length); - - if (mei_write_message(dev, mei_hdr, - (dev->iamthif_msg_buf + - dev->iamthif_msg_buf_index), - mei_hdr->length)) { - dev->iamthif_state = MEI_IAMTHIF_IDLE; - cl->status = -ENODEV; - list_del(&cb_pos->cb_list); - return -ENODEV; - } else { - if (mei_flow_ctrl_reduce(dev, cl)) - return -ENODEV; - dev->iamthif_msg_buf_index += mei_hdr->length; - cb_pos->information = dev->iamthif_msg_buf_index; - cl->status = 0; - dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; - dev->iamthif_flow_control_pending = true; - /* save iamthif cb sent to amthi client */ - dev->iamthif_current_cb = cb_pos; - list_move_tail(&cb_pos->cb_list, - &dev->write_waiting_list.mei_cb.cb_list); + dev_dbg(&dev->pdev->dev, "buf: size = %d idx = %lu\n", + cb->request_buffer.size, cb->buf_idx); + dev_dbg(&dev->pdev->dev, "msg: len = %d complete = %d\n", + mei_hdr->length, mei_hdr->msg_complete); - } - } else if (*slots == dev->hbuf_depth) { - /* buffer is still empty */ - mei_hdr = (struct mei_msg_hdr *) &dev->wr_msg_buf[0]; - mei_hdr->host_addr = cl->host_client_id; - mei_hdr->me_addr = cl->me_client_id; - mei_hdr->length = - (*slots * sizeof(u32)) - sizeof(struct mei_msg_hdr); - mei_hdr->msg_complete = 0; - mei_hdr->reserved = 0; + *slots -= msg_slots; + if (mei_write_message(dev, mei_hdr, + cb->request_buffer.data + cb->buf_idx, len)) { + cl->status = -ENODEV; + list_move_tail(&cb->list, &cmpl_list->list); + return -ENODEV; + } - *slots -= mei_data2slots(mei_hdr->length); + if (mei_flow_ctrl_reduce(dev, cl)) + return -ENODEV; - if (mei_write_message(dev, mei_hdr, - (dev->iamthif_msg_buf + - dev->iamthif_msg_buf_index), - mei_hdr->length)) { - cl->status = -ENODEV; - list_del(&cb_pos->cb_list); - } else { - dev->iamthif_msg_buf_index += mei_hdr->length; - } - return -EMSGSIZE; - } else { - return -EBADMSG; - } + cl->status = 0; + cb->buf_idx += mei_hdr->length; + if (mei_hdr->msg_complete) + list_move_tail(&cb->list, &dev->write_waiting_list.list); return 0; } @@ -1067,7 +775,7 @@ static int _mei_irq_thread_cmpl_iamthif(struct mei_device *dev, s32 *slots, * * returns 0 on success, <0 on failure. */ -static int mei_irq_thread_read_handler(struct mei_io_list *cmpl_list, +static int mei_irq_thread_read_handler(struct mei_cl_cb *cmpl_list, struct mei_device *dev, s32 *slots) { @@ -1130,8 +838,8 @@ static int mei_irq_thread_read_handler(struct mei_io_list *cmpl_list, dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_iamthif_message.\n"); dev_dbg(&dev->pdev->dev, "mei_hdr->length =%d\n", mei_hdr->length); - ret = mei_irq_thread_read_amthi_message(cmpl_list, - dev, mei_hdr); + + ret = mei_amthif_irq_read_message(cmpl_list, dev, mei_hdr); if (ret) goto end; @@ -1164,53 +872,51 @@ end: * mei_irq_thread_write_handler - bottom half write routine after * ISR to handle the write processing. * - * @cmpl_list: An instance of our list structure * @dev: the device structure - * @slots: slots to write. + * @cmpl_list: An instance of our list structure * * returns 0 on success, <0 on failure. */ -static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, - struct mei_device *dev, - s32 *slots) +static int mei_irq_thread_write_handler(struct mei_device *dev, + struct mei_cl_cb *cmpl_list) { struct mei_cl *cl; struct mei_cl_cb *pos = NULL, *next = NULL; - struct mei_io_list *list; + struct mei_cl_cb *list; + s32 slots; int ret; if (!mei_hbuf_is_empty(dev)) { dev_dbg(&dev->pdev->dev, "host buffer is not empty.\n"); return 0; } - *slots = mei_hbuf_empty_slots(dev); - if (*slots <= 0) + slots = mei_hbuf_empty_slots(dev); + if (slots <= 0) return -EMSGSIZE; /* complete all waiting for write CB */ dev_dbg(&dev->pdev->dev, "complete all waiting for write cb.\n"); list = &dev->write_waiting_list; - list_for_each_entry_safe(pos, next, &list->mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)pos->file_private; + list_for_each_entry_safe(pos, next, &list->list, list) { + cl = pos->cl; if (cl == NULL) continue; cl->status = 0; - list_del(&pos->cb_list); + list_del(&pos->list); if (MEI_WRITING == cl->writing_state && - (pos->major_file_operations == MEI_WRITE) && - (cl != &dev->iamthif_cl)) { + pos->fop_type == MEI_FOP_WRITE && + cl != &dev->iamthif_cl) { dev_dbg(&dev->pdev->dev, "MEI WRITE COMPLETE\n"); cl->writing_state = MEI_WRITE_COMPLETE; - list_add_tail(&pos->cb_list, - &cmpl_list->mei_cb.cb_list); + list_add_tail(&pos->list, &cmpl_list->list); } if (cl == &dev->iamthif_cl) { dev_dbg(&dev->pdev->dev, "check iamthif flow control.\n"); if (dev->iamthif_flow_control_pending) { - ret = _mei_irq_thread_iamthif_read(dev, slots); + ret = mei_amthif_irq_read(dev, &slots); if (ret) return ret; } @@ -1222,15 +928,11 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, wake_up_interruptible(&dev->wait_stop_wd); } - if (dev->extra_write_index) { - dev_dbg(&dev->pdev->dev, "extra_write_index =%d.\n", - dev->extra_write_index); - mei_write_message(dev, - (struct mei_msg_hdr *) &dev->ext_msg_buf[0], - (unsigned char *) &dev->ext_msg_buf[1], - (dev->extra_write_index - 1) * sizeof(u32)); - *slots -= dev->extra_write_index; - dev->extra_write_index = 0; + if (dev->wr_ext_msg.hdr.length) { + mei_write_message(dev, &dev->wr_ext_msg.hdr, + dev->wr_ext_msg.data, dev->wr_ext_msg.hdr.length); + slots -= mei_data2slots(dev->wr_ext_msg.hdr.length); + dev->wr_ext_msg.hdr.length = 0; } if (dev->dev_state == MEI_DEV_ENABLED) { if (dev->wd_pending && @@ -1243,41 +945,43 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, dev->wd_pending = false; if (dev->wd_state == MEI_WD_RUNNING) - *slots -= mei_data2slots(MEI_WD_START_MSG_SIZE); + slots -= mei_data2slots(MEI_WD_START_MSG_SIZE); else - *slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE); + slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE); } } /* complete control write list CB */ dev_dbg(&dev->pdev->dev, "complete control write list cb.\n"); - list_for_each_entry_safe(pos, next, - &dev->ctrl_wr_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *) pos->file_private; + list_for_each_entry_safe(pos, next, &dev->ctrl_wr_list.list, list) { + cl = pos->cl; if (!cl) { - list_del(&pos->cb_list); + list_del(&pos->list); return -ENODEV; } - switch (pos->major_file_operations) { - case MEI_CLOSE: + switch (pos->fop_type) { + case MEI_FOP_CLOSE: /* send disconnect message */ - ret = _mei_irq_thread_close(dev, slots, pos, cl, cmpl_list); + ret = _mei_irq_thread_close(dev, &slots, pos, + cl, cmpl_list); if (ret) return ret; break; - case MEI_READ: + case MEI_FOP_READ: /* send flow control message */ - ret = _mei_irq_thread_read(dev, slots, pos, cl, cmpl_list); + ret = _mei_irq_thread_read(dev, &slots, pos, + cl, cmpl_list); if (ret) return ret; break; - case MEI_IOCTL: + case MEI_FOP_IOCTL: /* connect message */ if (mei_other_client_is_connecting(dev, cl)) continue; - ret = _mei_irq_thread_ioctl(dev, slots, pos, cl, cmpl_list); + ret = _mei_irq_thread_ioctl(dev, &slots, pos, + cl, cmpl_list); if (ret) return ret; @@ -1290,40 +994,26 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list, } /* complete write list CB */ dev_dbg(&dev->pdev->dev, "complete write list cb.\n"); - list_for_each_entry_safe(pos, next, - &dev->write_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)pos->file_private; + list_for_each_entry_safe(pos, next, &dev->write_list.list, list) { + cl = pos->cl; if (cl == NULL) continue; - - if (cl != &dev->iamthif_cl) { - if (mei_flow_ctrl_creds(dev, cl) <= 0) { - dev_dbg(&dev->pdev->dev, - "No flow control credentials for client %d, not sending.\n", - cl->host_client_id); - continue; - } - ret = _mei_irq_thread_cmpl(dev, slots, pos, - cl, cmpl_list); - if (ret) - return ret; - - } else if (cl == &dev->iamthif_cl) { - /* IAMTHIF IOCTL */ - dev_dbg(&dev->pdev->dev, "complete amthi write cb.\n"); - if (mei_flow_ctrl_creds(dev, cl) <= 0) { - dev_dbg(&dev->pdev->dev, - "No flow control credentials for amthi client %d.\n", - cl->host_client_id); - continue; - } - ret = _mei_irq_thread_cmpl_iamthif(dev, slots, pos, - cl, cmpl_list); - if (ret) - return ret; - + if (mei_flow_ctrl_creds(dev, cl) <= 0) { + dev_dbg(&dev->pdev->dev, + "No flow control credentials for client %d, not sending.\n", + cl->host_client_id); + continue; } + if (cl == &dev->iamthif_cl) + ret = mei_amthif_irq_write_complete(dev, &slots, + pos, cmpl_list); + else + ret = mei_irq_thread_write_complete(dev, &slots, pos, + cmpl_list); + if (ret) + return ret; + } return 0; } @@ -1342,7 +1032,6 @@ void mei_timer(struct work_struct *work) unsigned long timeout; struct mei_cl *cl_pos = NULL; struct mei_cl *cl_next = NULL; - struct list_head *amthi_complete_list = NULL; struct mei_cl_cb *cb_pos = NULL; struct mei_cl_cb *cb_next = NULL; @@ -1385,19 +1074,18 @@ void mei_timer(struct work_struct *work) dev->iamthif_state = MEI_IAMTHIF_IDLE; dev->iamthif_timer = 0; - if (dev->iamthif_current_cb) - mei_free_cb_private(dev->iamthif_current_cb); + mei_io_cb_free(dev->iamthif_current_cb); + dev->iamthif_current_cb = NULL; dev->iamthif_file_object = NULL; - dev->iamthif_current_cb = NULL; - mei_run_next_iamthif_cmd(dev); + mei_amthif_run_next_cmd(dev); } } if (dev->iamthif_timer) { timeout = dev->iamthif_timer + - msecs_to_jiffies(IAMTHIF_READ_TIMER); + mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); dev_dbg(&dev->pdev->dev, "dev->iamthif_timer = %ld\n", dev->iamthif_timer); @@ -1411,25 +1099,22 @@ void mei_timer(struct work_struct *work) dev_dbg(&dev->pdev->dev, "freeing AMTHI for other requests\n"); - amthi_complete_list = &dev->amthi_read_complete_list. - mei_cb.cb_list; - - list_for_each_entry_safe(cb_pos, cb_next, amthi_complete_list, cb_list) { + list_for_each_entry_safe(cb_pos, cb_next, + &dev->amthif_rd_complete_list.list, list) { cl_pos = cb_pos->file_object->private_data; /* Finding the AMTHI entry. */ if (cl_pos == &dev->iamthif_cl) - list_del(&cb_pos->cb_list); + list_del(&cb_pos->list); } - if (dev->iamthif_current_cb) - mei_free_cb_private(dev->iamthif_current_cb); + mei_io_cb_free(dev->iamthif_current_cb); + dev->iamthif_current_cb = NULL; dev->iamthif_file_object->private_data = NULL; dev->iamthif_file_object = NULL; - dev->iamthif_current_cb = NULL; dev->iamthif_timer = 0; - mei_run_next_iamthif_cmd(dev); + mei_amthif_run_next_cmd(dev); } } @@ -1451,7 +1136,7 @@ out: irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id) { struct mei_device *dev = (struct mei_device *) dev_id; - struct mei_io_list complete_list; + struct mei_cl_cb complete_list; struct mei_cl_cb *cb_pos = NULL, *cb_next = NULL; struct mei_cl *cl; s32 slots; @@ -1504,17 +1189,17 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id) } /* check slots available for reading */ slots = mei_count_full_read_slots(dev); - dev_dbg(&dev->pdev->dev, "slots =%08x extra_write_index =%08x.\n", - slots, dev->extra_write_index); - while (slots > 0 && !dev->extra_write_index) { - dev_dbg(&dev->pdev->dev, "slots =%08x extra_write_index =%08x.\n", - slots, dev->extra_write_index); + while (slots > 0) { + /* we have urgent data to send so break the read */ + if (dev->wr_ext_msg.hdr.length) + break; + dev_dbg(&dev->pdev->dev, "slots =%08x\n", slots); dev_dbg(&dev->pdev->dev, "call mei_irq_thread_read_handler.\n"); rets = mei_irq_thread_read_handler(&complete_list, dev, &slots); if (rets) goto end; } - rets = mei_irq_thread_write_handler(&complete_list, dev, &slots); + rets = mei_irq_thread_write_handler(dev, &complete_list); end: dev_dbg(&dev->pdev->dev, "end of bottom half function.\n"); dev->host_hw_state = mei_hcsr_read(dev); @@ -1531,21 +1216,20 @@ end: wake_up_interruptible(&dev->wait_recvd_msg); bus_message_received = false; } - if (list_empty(&complete_list.mei_cb.cb_list)) + if (list_empty(&complete_list.list)) return IRQ_HANDLED; - list_for_each_entry_safe(cb_pos, cb_next, - &complete_list.mei_cb.cb_list, cb_list) { - cl = (struct mei_cl *)cb_pos->file_private; - list_del(&cb_pos->cb_list); + list_for_each_entry_safe(cb_pos, cb_next, &complete_list.list, list) { + cl = cb_pos->cl; + list_del(&cb_pos->list); if (cl) { if (cl != &dev->iamthif_cl) { dev_dbg(&dev->pdev->dev, "completing call back.\n"); _mei_cmpl(cl, cb_pos); cb_pos = NULL; } else if (cl == &dev->iamthif_cl) { - _mei_cmpl_iamthif(dev, cb_pos); + mei_amthif_complete(dev, cb_pos); } } } diff --git a/drivers/misc/mei/iorw.c b/drivers/misc/mei/iorw.c index fcba98eb892..eb93a1b53b9 100644 --- a/drivers/misc/mei/iorw.c +++ b/drivers/misc/mei/iorw.c @@ -39,6 +39,95 @@ #include "interface.h" /** + * mei_io_cb_free - free mei_cb_private related memory + * + * @cb: mei callback struct + */ +void mei_io_cb_free(struct mei_cl_cb *cb) +{ + if (cb == NULL) + return; + + kfree(cb->request_buffer.data); + kfree(cb->response_buffer.data); + kfree(cb); +} +/** + * mei_io_cb_init - allocate and initialize io callback + * + * @cl - mei client + * @file: pointer to file structure + * + * returns mei_cl_cb pointer or NULL; + */ +struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp) +{ + struct mei_cl_cb *cb; + + cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); + if (!cb) + return NULL; + + mei_io_list_init(cb); + + cb->file_object = fp; + cb->cl = cl; + cb->buf_idx = 0; + return cb; +} + + +/** + * mei_io_cb_alloc_req_buf - allocate request buffer + * + * @cb - io callback structure + * @size: size of the buffer + * + * returns 0 on success + * -EINVAL if cb is NULL + * -ENOMEM if allocation failed + */ +int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length) +{ + if (!cb) + return -EINVAL; + + if (length == 0) + return 0; + + cb->request_buffer.data = kmalloc(length, GFP_KERNEL); + if (!cb->request_buffer.data) + return -ENOMEM; + cb->request_buffer.size = length; + return 0; +} +/** + * mei_io_cb_alloc_req_buf - allocate respose buffer + * + * @cb - io callback structure + * @size: size of the buffer + * + * returns 0 on success + * -EINVAL if cb is NULL + * -ENOMEM if allocation failed + */ +int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length) +{ + if (!cb) + return -EINVAL; + + if (length == 0) + return 0; + + cb->response_buffer.data = kmalloc(length, GFP_KERNEL); + if (!cb->response_buffer.data) + return -ENOMEM; + cb->response_buffer.size = length; + return 0; +} + + +/** * mei_me_cl_by_id return index to me_clients for client_id * * @dev: the device structure @@ -82,9 +171,7 @@ int mei_ioctl_connect_client(struct file *file, struct mei_cl_cb *cb; struct mei_client *client; struct mei_cl *cl; - struct mei_cl *cl_pos = NULL; - struct mei_cl *cl_next = NULL; - long timeout = CONNECT_TIMEOUT; + long timeout = mei_secs_to_jiffies(MEI_CL_CONNECT_TIMEOUT); int i; int err; int rets; @@ -97,16 +184,14 @@ int mei_ioctl_connect_client(struct file *file, dev_dbg(&dev->pdev->dev, "mei_ioctl_connect_client() Entry\n"); - /* buffered ioctl cb */ - cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); + cb = mei_io_cb_init(cl, file); if (!cb) { rets = -ENOMEM; goto end; } - INIT_LIST_HEAD(&cb->cb_list); - cb->major_file_operations = MEI_IOCTL; + cb->fop_type = MEI_FOP_IOCTL; if (dev->dev_state != MEI_DEV_ENABLED) { rets = -ENODEV; @@ -142,21 +227,9 @@ int mei_ioctl_connect_client(struct file *file, goto end; } clear_bit(cl->host_client_id, dev->host_clients_map); - list_for_each_entry_safe(cl_pos, cl_next, - &dev->file_list, link) { - if (mei_cl_cmp_id(cl, cl_pos)) { - dev_dbg(&dev->pdev->dev, - "remove file private data node host" - " client = %d, ME client = %d.\n", - cl_pos->host_client_id, - cl_pos->me_client_id); - list_del(&cl_pos->link); - } + mei_me_cl_unlink(dev, cl); - } - dev_dbg(&dev->pdev->dev, "free file private data memory.\n"); kfree(cl); - cl = NULL; file->private_data = &dev->iamthif_cl; @@ -192,25 +265,19 @@ int mei_ioctl_connect_client(struct file *file, } else { dev_dbg(&dev->pdev->dev, "Sending connect message - succeeded\n"); cl->timer_count = MEI_CONNECT_TIMEOUT; - cb->file_private = cl; - list_add_tail(&cb->cb_list, - &dev->ctrl_rd_list.mei_cb. - cb_list); + list_add_tail(&cb->list, &dev->ctrl_rd_list.list); } } else { dev_dbg(&dev->pdev->dev, "Queuing the connect request due to device busy\n"); - cb->file_private = cl; dev_dbg(&dev->pdev->dev, "add connect cb to control write list.\n"); - list_add_tail(&cb->cb_list, - &dev->ctrl_wr_list.mei_cb.cb_list); + list_add_tail(&cb->list, &dev->ctrl_wr_list.list); } mutex_unlock(&dev->device_lock); err = wait_event_timeout(dev->wait_recvd_msg, (MEI_FILE_CONNECTED == cl->state || - MEI_FILE_DISCONNECTED == cl->state), - timeout * HZ); + MEI_FILE_DISCONNECTED == cl->state), timeout); mutex_lock(&dev->device_lock); if (MEI_FILE_CONNECTED == cl->state) { @@ -234,153 +301,7 @@ int mei_ioctl_connect_client(struct file *file, rets = 0; end: dev_dbg(&dev->pdev->dev, "free connect cb memory."); - kfree(cb); - return rets; -} - -/** - * find_amthi_read_list_entry - finds a amthilist entry for current file - * - * @dev: the device structure - * @file: pointer to file object - * - * returns returned a list entry on success, NULL on failure. - */ -struct mei_cl_cb *find_amthi_read_list_entry( - struct mei_device *dev, - struct file *file) -{ - struct mei_cl *cl_temp; - struct mei_cl_cb *pos = NULL; - struct mei_cl_cb *next = NULL; - - list_for_each_entry_safe(pos, next, - &dev->amthi_read_complete_list.mei_cb.cb_list, cb_list) { - cl_temp = (struct mei_cl *)pos->file_private; - if (cl_temp && cl_temp == &dev->iamthif_cl && - pos->file_object == file) - return pos; - } - return NULL; -} - -/** - * amthi_read - read data from AMTHI client - * - * @dev: the device structure - * @if_num: minor number - * @file: pointer to file object - * @*ubuf: pointer to user data in user space - * @length: data length to read - * @offset: data read offset - * - * Locking: called under "dev->device_lock" lock - * - * returns - * returned data length on success, - * zero if no data to read, - * negative on failure. - */ -int amthi_read(struct mei_device *dev, struct file *file, - char __user *ubuf, size_t length, loff_t *offset) -{ - int rets; - int wait_ret; - struct mei_cl_cb *cb = NULL; - struct mei_cl *cl = file->private_data; - unsigned long timeout; - int i; - - /* Only Posible if we are in timeout */ - if (!cl || cl != &dev->iamthif_cl) { - dev_dbg(&dev->pdev->dev, "bad file ext.\n"); - return -ETIMEDOUT; - } - - i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id); - - if (i < 0) { - dev_dbg(&dev->pdev->dev, "amthi client not found.\n"); - return -ENODEV; - } - dev_dbg(&dev->pdev->dev, "checking amthi data\n"); - cb = find_amthi_read_list_entry(dev, file); - - /* Check for if we can block or not*/ - if (cb == NULL && file->f_flags & O_NONBLOCK) - return -EAGAIN; - - - dev_dbg(&dev->pdev->dev, "waiting for amthi data\n"); - while (cb == NULL) { - /* unlock the Mutex */ - mutex_unlock(&dev->device_lock); - - wait_ret = wait_event_interruptible(dev->iamthif_cl.wait, - (cb = find_amthi_read_list_entry(dev, file))); - - if (wait_ret) - return -ERESTARTSYS; - - dev_dbg(&dev->pdev->dev, "woke up from sleep\n"); - - /* Locking again the Mutex */ - mutex_lock(&dev->device_lock); - } - - - dev_dbg(&dev->pdev->dev, "Got amthi data\n"); - dev->iamthif_timer = 0; - - if (cb) { - timeout = cb->read_time + msecs_to_jiffies(IAMTHIF_READ_TIMER); - dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n", - timeout); - - if (time_after(jiffies, timeout)) { - dev_dbg(&dev->pdev->dev, "amthi Time out\n"); - /* 15 sec for the message has expired */ - list_del(&cb->cb_list); - rets = -ETIMEDOUT; - goto free; - } - } - /* if the whole message will fit remove it from the list */ - if (cb->information >= *offset && length >= (cb->information - *offset)) - list_del(&cb->cb_list); - else if (cb->information > 0 && cb->information <= *offset) { - /* end of the message has been reached */ - list_del(&cb->cb_list); - rets = 0; - goto free; - } - /* else means that not full buffer will be read and do not - * remove message from deletion list - */ - - dev_dbg(&dev->pdev->dev, "amthi cb->response_buffer size - %d\n", - cb->response_buffer.size); - dev_dbg(&dev->pdev->dev, "amthi cb->information - %lu\n", - cb->information); - - /* length is being turncated to PAGE_SIZE, however, - * the information may be longer */ - length = min_t(size_t, length, (cb->information - *offset)); - - if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) - rets = -EFAULT; - else { - rets = length; - if ((*offset + length) < cb->information) { - *offset += length; - goto out; - } - } -free: - dev_dbg(&dev->pdev->dev, "free amthi cb memory.\n"); - *offset = 0; - mei_free_cb_private(cb); -out: + mei_io_cb_free(cb); return rets; } @@ -396,7 +317,7 @@ out: int mei_start_read(struct mei_device *dev, struct mei_cl *cl) { struct mei_cl_cb *cb; - int rets = 0; + int rets; int i; if (cl->state != MEI_FILE_CONNECTED) @@ -405,187 +326,41 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl) if (dev->dev_state != MEI_DEV_ENABLED) return -ENODEV; - dev_dbg(&dev->pdev->dev, "check if read is pending.\n"); if (cl->read_pending || cl->read_cb) { dev_dbg(&dev->pdev->dev, "read is pending.\n"); return -EBUSY; } + i = mei_me_cl_by_id(dev, cl->me_client_id); + if (i < 0) { + dev_err(&dev->pdev->dev, "no such me client %d\n", + cl->me_client_id); + return -ENODEV; + } - cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); + cb = mei_io_cb_init(cl, NULL); if (!cb) return -ENOMEM; - dev_dbg(&dev->pdev->dev, "allocation call back successful. host client = %d, ME client = %d\n", - cl->host_client_id, cl->me_client_id); - i = mei_me_cl_by_id(dev, cl->me_client_id); - if (i < 0) { - rets = -ENODEV; - goto unlock; - } + rets = mei_io_cb_alloc_resp_buf(cb, + dev->me_clients[i].props.max_msg_length); + if (rets) + goto err; - cb->response_buffer.size = dev->me_clients[i].props.max_msg_length; - cb->response_buffer.data = - kmalloc(cb->response_buffer.size, GFP_KERNEL); - if (!cb->response_buffer.data) { - rets = -ENOMEM; - goto unlock; - } - dev_dbg(&dev->pdev->dev, "allocation call back data success.\n"); - cb->major_file_operations = MEI_READ; - /* make sure information is zero before we start */ - cb->information = 0; - cb->file_private = (void *) cl; + cb->fop_type = MEI_FOP_READ; cl->read_cb = cb; if (dev->mei_host_buffer_is_empty) { dev->mei_host_buffer_is_empty = false; if (mei_send_flow_control(dev, cl)) { rets = -ENODEV; - goto unlock; + goto err; } - list_add_tail(&cb->cb_list, &dev->read_list.mei_cb.cb_list); + list_add_tail(&cb->list, &dev->read_list.list); } else { - list_add_tail(&cb->cb_list, &dev->ctrl_wr_list.mei_cb.cb_list); + list_add_tail(&cb->list, &dev->ctrl_wr_list.list); } return rets; -unlock: - mei_free_cb_private(cb); +err: + mei_io_cb_free(cb); return rets; } -/** - * amthi_write - write iamthif data to amthi client - * - * @dev: the device structure - * @cb: mei call back struct - * - * returns 0 on success, <0 on failure. - */ -int amthi_write(struct mei_device *dev, struct mei_cl_cb *cb) -{ - struct mei_msg_hdr mei_hdr; - int ret; - - if (!dev || !cb) - return -ENODEV; - - dev_dbg(&dev->pdev->dev, "write data to amthi client.\n"); - - dev->iamthif_state = MEI_IAMTHIF_WRITING; - dev->iamthif_current_cb = cb; - dev->iamthif_file_object = cb->file_object; - dev->iamthif_canceled = false; - dev->iamthif_ioctl = true; - dev->iamthif_msg_buf_size = cb->request_buffer.size; - memcpy(dev->iamthif_msg_buf, cb->request_buffer.data, - cb->request_buffer.size); - - ret = mei_flow_ctrl_creds(dev, &dev->iamthif_cl); - if (ret < 0) - return ret; - - if (ret && dev->mei_host_buffer_is_empty) { - ret = 0; - dev->mei_host_buffer_is_empty = false; - if (cb->request_buffer.size > mei_hbuf_max_data(dev)) { - mei_hdr.length = mei_hbuf_max_data(dev); - mei_hdr.msg_complete = 0; - } else { - mei_hdr.length = cb->request_buffer.size; - mei_hdr.msg_complete = 1; - } - - mei_hdr.host_addr = dev->iamthif_cl.host_client_id; - mei_hdr.me_addr = dev->iamthif_cl.me_client_id; - mei_hdr.reserved = 0; - dev->iamthif_msg_buf_index += mei_hdr.length; - if (mei_write_message(dev, &mei_hdr, - (unsigned char *)(dev->iamthif_msg_buf), - mei_hdr.length)) - return -ENODEV; - - if (mei_hdr.msg_complete) { - if (mei_flow_ctrl_reduce(dev, &dev->iamthif_cl)) - return -ENODEV; - dev->iamthif_flow_control_pending = true; - dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; - dev_dbg(&dev->pdev->dev, "add amthi cb to write waiting list\n"); - dev->iamthif_current_cb = cb; - dev->iamthif_file_object = cb->file_object; - list_add_tail(&cb->cb_list, - &dev->write_waiting_list.mei_cb.cb_list); - } else { - dev_dbg(&dev->pdev->dev, "message does not complete, " - "so add amthi cb to write list.\n"); - list_add_tail(&cb->cb_list, - &dev->write_list.mei_cb.cb_list); - } - } else { - if (!(dev->mei_host_buffer_is_empty)) - dev_dbg(&dev->pdev->dev, "host buffer is not empty"); - - dev_dbg(&dev->pdev->dev, "No flow control credentials, " - "so add iamthif cb to write list.\n"); - list_add_tail(&cb->cb_list, &dev->write_list.mei_cb.cb_list); - } - return 0; -} - -/** - * iamthif_ioctl_send_msg - send cmd data to amthi client - * - * @dev: the device structure - * - * returns 0 on success, <0 on failure. - */ -void mei_run_next_iamthif_cmd(struct mei_device *dev) -{ - struct mei_cl *cl_tmp; - struct mei_cl_cb *pos = NULL; - struct mei_cl_cb *next = NULL; - int status; - - if (!dev) - return; - - dev->iamthif_msg_buf_size = 0; - dev->iamthif_msg_buf_index = 0; - dev->iamthif_canceled = false; - dev->iamthif_ioctl = true; - dev->iamthif_state = MEI_IAMTHIF_IDLE; - dev->iamthif_timer = 0; - dev->iamthif_file_object = NULL; - - dev_dbg(&dev->pdev->dev, "complete amthi cmd_list cb.\n"); - - list_for_each_entry_safe(pos, next, - &dev->amthi_cmd_list.mei_cb.cb_list, cb_list) { - list_del(&pos->cb_list); - cl_tmp = (struct mei_cl *)pos->file_private; - - if (cl_tmp && cl_tmp == &dev->iamthif_cl) { - status = amthi_write(dev, pos); - if (status) { - dev_dbg(&dev->pdev->dev, - "amthi write failed status = %d\n", - status); - return; - } - break; - } - } -} - -/** - * mei_free_cb_private - free mei_cb_private related memory - * - * @cb: mei callback struct - */ -void mei_free_cb_private(struct mei_cl_cb *cb) -{ - if (cb == NULL) - return; - - kfree(cb->request_buffer.data); - kfree(cb->response_buffer.data); - kfree(cb); -} diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index e8b0858132c..43fb52ff98a 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -90,93 +90,6 @@ static DEFINE_MUTEX(mei_mutex); /** - * mei_clear_list - removes all callbacks associated with file - * from mei_cb_list - * - * @dev: device structure. - * @file: file structure - * @mei_cb_list: callbacks list - * - * mei_clear_list is called to clear resources associated with file - * when application calls close function or Ctrl-C was pressed - * - * returns true if callback removed from the list, false otherwise - */ -static bool mei_clear_list(struct mei_device *dev, - struct file *file, struct list_head *mei_cb_list) -{ - struct mei_cl_cb *cb_pos = NULL; - struct mei_cl_cb *cb_next = NULL; - struct file *file_temp; - bool removed = false; - - /* list all list member */ - list_for_each_entry_safe(cb_pos, cb_next, mei_cb_list, cb_list) { - file_temp = (struct file *)cb_pos->file_object; - /* check if list member associated with a file */ - if (file_temp == file) { - /* remove member from the list */ - list_del(&cb_pos->cb_list); - /* check if cb equal to current iamthif cb */ - if (dev->iamthif_current_cb == cb_pos) { - dev->iamthif_current_cb = NULL; - /* send flow control to iamthif client */ - mei_send_flow_control(dev, &dev->iamthif_cl); - } - /* free all allocated buffers */ - mei_free_cb_private(cb_pos); - cb_pos = NULL; - removed = true; - } - } - return removed; -} - -/** - * mei_clear_lists - removes all callbacks associated with file - * - * @dev: device structure - * @file: file structure - * - * mei_clear_lists is called to clear resources associated with file - * when application calls close function or Ctrl-C was pressed - * - * returns true if callback removed from the list, false otherwise - */ -static bool mei_clear_lists(struct mei_device *dev, struct file *file) -{ - bool removed = false; - - /* remove callbacks associated with a file */ - mei_clear_list(dev, file, &dev->amthi_cmd_list.mei_cb.cb_list); - if (mei_clear_list(dev, file, - &dev->amthi_read_complete_list.mei_cb.cb_list)) - removed = true; - - mei_clear_list(dev, file, &dev->ctrl_rd_list.mei_cb.cb_list); - - if (mei_clear_list(dev, file, &dev->ctrl_wr_list.mei_cb.cb_list)) - removed = true; - - if (mei_clear_list(dev, file, &dev->write_waiting_list.mei_cb.cb_list)) - removed = true; - - if (mei_clear_list(dev, file, &dev->write_list.mei_cb.cb_list)) - removed = true; - - /* check if iamthif_current_cb not NULL */ - if (dev->iamthif_current_cb && !removed) { - /* check file and iamthif current cb association */ - if (dev->iamthif_current_cb->file_object == file) { - /* remove cb */ - mei_free_cb_private(dev->iamthif_current_cb); - dev->iamthif_current_cb = NULL; - removed = true; - } - } - return removed; -} -/** * find_read_list_entry - find read list entry * * @dev: device structure @@ -192,14 +105,9 @@ static struct mei_cl_cb *find_read_list_entry( struct mei_cl_cb *next = NULL; dev_dbg(&dev->pdev->dev, "remove read_list CB\n"); - list_for_each_entry_safe(pos, next, - &dev->read_list.mei_cb.cb_list, cb_list) { - struct mei_cl *cl_temp; - cl_temp = (struct mei_cl *)pos->file_private; - - if (mei_cl_cmp_id(cl, cl_temp)) + list_for_each_entry_safe(pos, next, &dev->read_list.list, list) + if (mei_cl_cmp_id(cl, pos->cl)) return pos; - } return NULL; } @@ -297,67 +205,51 @@ static int mei_release(struct inode *inode, struct file *file) dev = cl->dev; mutex_lock(&dev->device_lock); - if (cl != &dev->iamthif_cl) { - if (cl->state == MEI_FILE_CONNECTED) { - cl->state = MEI_FILE_DISCONNECTING; - dev_dbg(&dev->pdev->dev, - "disconnecting client host client = %d, " - "ME client = %d\n", - cl->host_client_id, - cl->me_client_id); - rets = mei_disconnect_host_client(dev, cl); - } - mei_cl_flush_queues(cl); - dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n", + if (cl == &dev->iamthif_cl) { + rets = mei_amthif_release(dev, file); + goto out; + } + if (cl->state == MEI_FILE_CONNECTED) { + cl->state = MEI_FILE_DISCONNECTING; + dev_dbg(&dev->pdev->dev, + "disconnecting client host client = %d, " + "ME client = %d\n", cl->host_client_id, cl->me_client_id); + rets = mei_disconnect_host_client(dev, cl); + } + mei_cl_flush_queues(cl); + dev_dbg(&dev->pdev->dev, "remove client host client = %d, ME client = %d\n", + cl->host_client_id, + cl->me_client_id); + + if (dev->open_handle_count > 0) { + clear_bit(cl->host_client_id, dev->host_clients_map); + dev->open_handle_count--; + } + mei_me_cl_unlink(dev, cl); - if (dev->open_handle_count > 0) { - clear_bit(cl->host_client_id, dev->host_clients_map); - dev->open_handle_count--; - } - mei_remove_client_from_file_list(dev, cl->host_client_id); - - /* free read cb */ - cb = NULL; - if (cl->read_cb) { - cb = find_read_list_entry(dev, cl); - /* Remove entry from read list */ - if (cb) - list_del(&cb->cb_list); - - cb = cl->read_cb; - cl->read_cb = NULL; - } - - file->private_data = NULL; - - if (cb) { - mei_free_cb_private(cb); - cb = NULL; - } + /* free read cb */ + cb = NULL; + if (cl->read_cb) { + cb = find_read_list_entry(dev, cl); + /* Remove entry from read list */ + if (cb) + list_del(&cb->list); - kfree(cl); - } else { - if (dev->open_handle_count > 0) - dev->open_handle_count--; - - if (dev->iamthif_file_object == file && - dev->iamthif_state != MEI_IAMTHIF_IDLE) { - - dev_dbg(&dev->pdev->dev, "amthi canceled iamthif state %d\n", - dev->iamthif_state); - dev->iamthif_canceled = true; - if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) { - dev_dbg(&dev->pdev->dev, "run next amthi iamthif cb\n"); - mei_run_next_iamthif_cmd(dev); - } - } + cb = cl->read_cb; + cl->read_cb = NULL; + } - if (mei_clear_lists(dev, file)) - dev->iamthif_state = MEI_IAMTHIF_IDLE; + file->private_data = NULL; + if (cb) { + mei_io_cb_free(cb); + cb = NULL; } + + kfree(cl); +out: mutex_unlock(&dev->device_lock); return rets; } @@ -411,20 +303,19 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, } if (cl == &dev->iamthif_cl) { - rets = amthi_read(dev, file, ubuf, length, offset); + rets = mei_amthif_read(dev, file, ubuf, length, offset); goto out; } - if (cl->read_cb && cl->read_cb->information > *offset) { + if (cl->read_cb && cl->read_cb->buf_idx > *offset) { cb = cl->read_cb; goto copy_buffer; - } else if (cl->read_cb && cl->read_cb->information > 0 && - cl->read_cb->information <= *offset) { + } else if (cl->read_cb && cl->read_cb->buf_idx > 0 && + cl->read_cb->buf_idx <= *offset) { cb = cl->read_cb; rets = 0; goto free; - } else if ((!cl->read_cb || !cl->read_cb->information) && - *offset > 0) { + } else if ((!cl->read_cb || !cl->read_cb->buf_idx) && *offset > 0) { /*Offset needs to be cleaned for contiguous reads*/ *offset = 0; rets = 0; @@ -481,16 +372,15 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, copy_buffer: dev_dbg(&dev->pdev->dev, "cb->response_buffer size - %d\n", cb->response_buffer.size); - dev_dbg(&dev->pdev->dev, "cb->information - %lu\n", - cb->information); - if (length == 0 || ubuf == NULL || *offset > cb->information) { + dev_dbg(&dev->pdev->dev, "cb->buf_idx - %lu\n", cb->buf_idx); + if (length == 0 || ubuf == NULL || *offset > cb->buf_idx) { rets = -EMSGSIZE; goto free; } - /* length is being truncated to PAGE_SIZE, however, */ - /* information size may be longer */ - length = min_t(size_t, length, (cb->information - *offset)); + /* length is being truncated to PAGE_SIZE, + * however buf_idx may point beyond that */ + length = min_t(size_t, length, cb->buf_idx - *offset); if (copy_to_user(ubuf, cb->response_buffer.data + *offset, length)) { rets = -EFAULT; @@ -499,15 +389,15 @@ copy_buffer: rets = length; *offset += length; - if ((unsigned long)*offset < cb->information) + if ((unsigned long)*offset < cb->buf_idx) goto out; free: cb_pos = find_read_list_entry(dev, cl); /* Remove entry from read list */ if (cb_pos) - list_del(&cb_pos->cb_list); - mei_free_cb_private(cb); + list_del(&cb_pos->list); + mei_io_cb_free(cb); cl->reading_state = MEI_IDLE; cl->read_cb = NULL; cl->read_pending = 0; @@ -516,7 +406,6 @@ out: mutex_unlock(&dev->device_lock); return rets; } - /** * mei_write - the write function. * @@ -546,23 +435,39 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, mutex_lock(&dev->device_lock); if (dev->dev_state != MEI_DEV_ENABLED) { - mutex_unlock(&dev->device_lock); - return -ENODEV; + rets = -ENODEV; + goto err; } + i = mei_me_cl_by_id(dev, cl->me_client_id); + if (i < 0) { + rets = -ENODEV; + goto err; + } + if (length > dev->me_clients[i].props.max_msg_length || length <= 0) { + rets = -EMSGSIZE; + goto err; + } + + if (cl->state != MEI_FILE_CONNECTED) { + rets = -ENODEV; + dev_err(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d", + cl->host_client_id, cl->me_client_id); + goto err; + } if (cl == &dev->iamthif_cl) { - write_cb = find_amthi_read_list_entry(dev, file); + write_cb = mei_amthif_find_read_list_entry(dev, file); if (write_cb) { timeout = write_cb->read_time + - msecs_to_jiffies(IAMTHIF_READ_TIMER); + mei_secs_to_jiffies(MEI_IAMTHIF_READ_TIMER); if (time_after(jiffies, timeout) || - cl->reading_state == MEI_READ_COMPLETE) { - *offset = 0; - list_del(&write_cb->cb_list); - mei_free_cb_private(write_cb); - write_cb = NULL; + cl->reading_state == MEI_READ_COMPLETE) { + *offset = 0; + list_del(&write_cb->list); + mei_io_cb_free(write_cb); + write_cb = NULL; } } } @@ -572,8 +477,8 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, *offset = 0; write_cb = find_read_list_entry(dev, cl); if (write_cb) { - list_del(&write_cb->cb_list); - mei_free_cb_private(write_cb); + list_del(&write_cb->list); + mei_io_cb_free(write_cb); write_cb = NULL; cl->reading_state = MEI_IDLE; cl->read_cb = NULL; @@ -583,24 +488,21 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, *offset = 0; - write_cb = kzalloc(sizeof(struct mei_cl_cb), GFP_KERNEL); + write_cb = mei_io_cb_init(cl, file); if (!write_cb) { - mutex_unlock(&dev->device_lock); - return -ENOMEM; + dev_err(&dev->pdev->dev, "write cb allocation failed\n"); + rets = -ENOMEM; + goto err; } + rets = mei_io_cb_alloc_req_buf(write_cb, length); + if (rets) + goto err; - write_cb->file_object = file; - write_cb->file_private = cl; - write_cb->request_buffer.data = kmalloc(length, GFP_KERNEL); - rets = -ENOMEM; - if (!write_cb->request_buffer.data) - goto unlock_dev; - - dev_dbg(&dev->pdev->dev, "length =%d\n", (int) length); + dev_dbg(&dev->pdev->dev, "cb request size = %zd\n", length); - rets = -EFAULT; - if (copy_from_user(write_cb->request_buffer.data, ubuf, length)) - goto unlock_dev; + rets = copy_from_user(write_cb->request_buffer.data, ubuf, length); + if (rets) + goto err; cl->sm_state = 0; if (length == 4 && @@ -612,139 +514,71 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, write_cb->request_buffer.data, 4) == 0))) cl->sm_state |= MEI_WD_STATE_INDEPENDENCE_MSG_SENT; - INIT_LIST_HEAD(&write_cb->cb_list); if (cl == &dev->iamthif_cl) { - write_cb->response_buffer.data = - kmalloc(dev->iamthif_mtu, GFP_KERNEL); - if (!write_cb->response_buffer.data) { - rets = -ENOMEM; - goto unlock_dev; - } - if (dev->dev_state != MEI_DEV_ENABLED) { - rets = -ENODEV; - goto unlock_dev; - } - i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id); - if (i < 0) { - rets = -ENODEV; - goto unlock_dev; - } - if (length > dev->me_clients[i].props.max_msg_length || - length <= 0) { - rets = -EMSGSIZE; - goto unlock_dev; - } + rets = mei_amthif_write(dev, write_cb); - write_cb->response_buffer.size = dev->iamthif_mtu; - write_cb->major_file_operations = MEI_IOCTL; - write_cb->information = 0; - write_cb->request_buffer.size = length; - if (dev->iamthif_cl.state != MEI_FILE_CONNECTED) { - rets = -ENODEV; - goto unlock_dev; - } - - if (!list_empty(&dev->amthi_cmd_list.mei_cb.cb_list) || - dev->iamthif_state != MEI_IAMTHIF_IDLE) { - dev_dbg(&dev->pdev->dev, "amthi_state = %d\n", - (int) dev->iamthif_state); - dev_dbg(&dev->pdev->dev, "add amthi cb to amthi cmd waiting list\n"); - list_add_tail(&write_cb->cb_list, - &dev->amthi_cmd_list.mei_cb.cb_list); - rets = length; - } else { - dev_dbg(&dev->pdev->dev, "call amthi write\n"); - rets = amthi_write(dev, write_cb); - - if (rets) { - dev_dbg(&dev->pdev->dev, "amthi write failed with status = %d\n", - rets); - goto unlock_dev; - } - rets = length; + if (rets) { + dev_err(&dev->pdev->dev, + "amthi write failed with status = %d\n", rets); + goto err; } mutex_unlock(&dev->device_lock); - return rets; + return length; } - write_cb->major_file_operations = MEI_WRITE; - /* make sure information is zero before we start */ - - write_cb->information = 0; - write_cb->request_buffer.size = length; + write_cb->fop_type = MEI_FOP_WRITE; dev_dbg(&dev->pdev->dev, "host client = %d, ME client = %d\n", cl->host_client_id, cl->me_client_id); - if (cl->state != MEI_FILE_CONNECTED) { - rets = -ENODEV; - dev_dbg(&dev->pdev->dev, "host client = %d, is not connected to ME client = %d", - cl->host_client_id, - cl->me_client_id); - goto unlock_dev; - } - i = mei_me_cl_by_id(dev, cl->me_client_id); - if (i < 0) { - rets = -ENODEV; - goto unlock_dev; - } - if (length > dev->me_clients[i].props.max_msg_length || length <= 0) { - rets = -EINVAL; - goto unlock_dev; - } - write_cb->file_private = cl; - rets = mei_flow_ctrl_creds(dev, cl); if (rets < 0) - goto unlock_dev; + goto err; - if (rets && dev->mei_host_buffer_is_empty) { - rets = 0; - dev->mei_host_buffer_is_empty = false; - if (length > mei_hbuf_max_data(dev)) { - mei_hdr.length = mei_hbuf_max_data(dev); - mei_hdr.msg_complete = 0; - } else { - mei_hdr.length = length; - mei_hdr.msg_complete = 1; - } - mei_hdr.host_addr = cl->host_client_id; - mei_hdr.me_addr = cl->me_client_id; - mei_hdr.reserved = 0; - dev_dbg(&dev->pdev->dev, "call mei_write_message header=%08x.\n", - *((u32 *) &mei_hdr)); - if (mei_write_message(dev, &mei_hdr, - (unsigned char *) (write_cb->request_buffer.data), - mei_hdr.length)) { - rets = -ENODEV; - goto unlock_dev; - } + if (rets == 0 || dev->mei_host_buffer_is_empty == false) { + write_cb->buf_idx = 0; + mei_hdr.msg_complete = 0; cl->writing_state = MEI_WRITING; - write_cb->information = mei_hdr.length; - if (mei_hdr.msg_complete) { - if (mei_flow_ctrl_reduce(dev, cl)) { - rets = -ENODEV; - goto unlock_dev; - } - list_add_tail(&write_cb->cb_list, - &dev->write_waiting_list.mei_cb.cb_list); - } else { - list_add_tail(&write_cb->cb_list, - &dev->write_list.mei_cb.cb_list); - } + goto out; + } + dev->mei_host_buffer_is_empty = false; + if (length > mei_hbuf_max_data(dev)) { + mei_hdr.length = mei_hbuf_max_data(dev); + mei_hdr.msg_complete = 0; } else { + mei_hdr.length = length; + mei_hdr.msg_complete = 1; + } + mei_hdr.host_addr = cl->host_client_id; + mei_hdr.me_addr = cl->me_client_id; + mei_hdr.reserved = 0; + dev_dbg(&dev->pdev->dev, "call mei_write_message header=%08x.\n", + *((u32 *) &mei_hdr)); + if (mei_write_message(dev, &mei_hdr, + write_cb->request_buffer.data, mei_hdr.length)) { + rets = -ENODEV; + goto err; + } + cl->writing_state = MEI_WRITING; + write_cb->buf_idx = mei_hdr.length; - write_cb->information = 0; - cl->writing_state = MEI_WRITING; - list_add_tail(&write_cb->cb_list, - &dev->write_list.mei_cb.cb_list); +out: + if (mei_hdr.msg_complete) { + if (mei_flow_ctrl_reduce(dev, cl)) { + rets = -ENODEV; + goto err; + } + list_add_tail(&write_cb->list, &dev->write_waiting_list.list); + } else { + list_add_tail(&write_cb->list, &dev->write_list.list); } + mutex_unlock(&dev->device_lock); return length; -unlock_dev: +err: mutex_unlock(&dev->device_lock); - mei_free_cb_private(write_cb); + mei_io_cb_free(write_cb); return rets; } @@ -860,15 +694,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait) if (cl == &dev->iamthif_cl) { - mutex_unlock(&dev->device_lock); - poll_wait(file, &dev->iamthif_cl.wait, wait); - mutex_lock(&dev->device_lock); - if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE && - dev->iamthif_file_object == file) { - mask |= (POLLIN | POLLRDNORM); - dev_dbg(&dev->pdev->dev, "run next amthi cb\n"); - mei_run_next_iamthif_cmd(dev); - } + mask = mei_amthif_poll(dev, file, wait); goto out; } @@ -917,7 +743,7 @@ static struct miscdevice mei_misc_device = { * * returns true if ME Interface is valid, false otherwise */ -static bool __devinit mei_quirk_probe(struct pci_dev *pdev, +static bool mei_quirk_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { u32 reg; @@ -939,7 +765,7 @@ static bool __devinit mei_quirk_probe(struct pci_dev *pdev, * * returns 0 on success, <0 on failure. */ -static int __devinit mei_probe(struct pci_dev *pdev, +static int mei_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct mei_device *dev; @@ -1003,6 +829,8 @@ static int __devinit mei_probe(struct pci_dev *pdev, goto disable_msi; } INIT_DELAYED_WORK(&dev->timer_work, mei_timer); + INIT_WORK(&dev->init_work, mei_host_client_init); + if (mei_hw_init(dev)) { dev_err(&pdev->dev, "init hw failure.\n"); err = -ENODEV; @@ -1054,7 +882,7 @@ end: * mei_remove is called by the PCI subsystem to alert the driver * that it should release a PCI device. */ -static void __devexit mei_remove(struct pci_dev *pdev) +static void mei_remove(struct pci_dev *pdev) { struct mei_device *dev; @@ -1087,8 +915,8 @@ static void __devexit mei_remove(struct pci_dev *pdev) /* remove entry if already in list */ dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n"); - mei_remove_client_from_file_list(dev, dev->wd_cl.host_client_id); - mei_remove_client_from_file_list(dev, dev->iamthif_cl.host_client_id); + mei_me_cl_unlink(dev, &dev->wd_cl); + mei_me_cl_unlink(dev, &dev->iamthif_cl); dev->iamthif_current_cb = NULL; dev->me_clients_num = 0; @@ -1195,8 +1023,8 @@ static struct pci_driver mei_driver = { .name = KBUILD_MODNAME, .id_table = mei_pci_tbl, .probe = mei_probe, - .remove = __devexit_p(mei_remove), - .shutdown = __devexit_p(mei_remove), + .remove = mei_remove, + .shutdown = mei_remove, .driver.pm = MEI_PM_OPS, }; diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index adb35fb9281..25da04549d0 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -19,6 +19,7 @@ #include <linux/types.h> #include <linux/watchdog.h> +#include <linux/poll.h> #include <linux/mei.h> #include "hw.h" @@ -125,13 +126,20 @@ enum mei_wd_states { MEI_WD_STOPPING, }; -/* MEI CB */ -enum mei_cb_major_types { - MEI_READ = 0, - MEI_WRITE, - MEI_IOCTL, - MEI_OPEN, - MEI_CLOSE +/** + * enum mei_cb_file_ops - file operation associated with the callback + * @MEI_FOP_READ - read + * @MEI_FOP_WRITE - write + * @MEI_FOP_IOCTL - ioctl + * @MEI_FOP_OPEN - open + * @MEI_FOP_CLOSE - close + */ +enum mei_cb_file_ops { + MEI_FOP_READ = 0, + MEI_FOP_WRITE, + MEI_FOP_IOCTL, + MEI_FOP_OPEN, + MEI_FOP_CLOSE }; /* @@ -143,13 +151,21 @@ struct mei_message_data { }; +struct mei_cl; + +/** + * struct mei_cl_cb - file operation callback structure + * + * @cl - file client who is running this operation + * @fop_type - file operation type + */ struct mei_cl_cb { - struct list_head cb_list; - enum mei_cb_major_types major_file_operations; - void *file_private; + struct list_head list; + struct mei_cl *cl; + enum mei_cb_file_ops fop_type; struct mei_message_data request_buffer; struct mei_message_data response_buffer; - unsigned long information; + unsigned long buf_idx; unsigned long read_time; struct file *file_object; }; @@ -175,29 +191,23 @@ struct mei_cl { struct mei_cl_cb *read_cb; }; -struct mei_io_list { - struct mei_cl_cb mei_cb; -}; - /** - * struct mei_deive - MEI private device struct + * struct mei_device - MEI private device struct * @hbuf_depth - depth of host(write) buffer + * @wr_ext_msg - buffer for hbm control responses (set in read cycle) */ struct mei_device { struct pci_dev *pdev; /* pointer to pci device struct */ /* * lists of queues */ - /* array of pointers to aio lists */ - struct mei_io_list read_list; /* driver read queue */ - struct mei_io_list write_list; /* driver write queue */ - struct mei_io_list write_waiting_list; /* write waiting queue */ - struct mei_io_list ctrl_wr_list; /* managed write IOCTL list */ - struct mei_io_list ctrl_rd_list; /* managed read IOCTL list */ - struct mei_io_list amthi_cmd_list; /* amthi list for cmd waiting */ - - /* driver managed amthi list for reading completed amthi cmd data */ - struct mei_io_list amthi_read_complete_list; + /* array of pointers to aio lists */ + struct mei_cl_cb read_list; /* driver read queue */ + struct mei_cl_cb write_list; /* driver write queue */ + struct mei_cl_cb write_waiting_list; /* write waiting queue */ + struct mei_cl_cb ctrl_wr_list; /* managed write IOCTL list */ + struct mei_cl_cb ctrl_rd_list; /* managed read IOCTL list */ + /* * list of files */ @@ -235,11 +245,13 @@ struct mei_device { u16 init_clients_timer; bool need_reset; - u32 extra_write_index; unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */ - u32 wr_msg_buf[128]; /* used for control messages */ - u32 ext_msg_buf[8]; /* for control responses */ u32 rd_msg_hdr; + u32 wr_msg_buf[128]; /* used for control messages */ + struct { + struct mei_msg_hdr hdr; + unsigned char data[4]; /* All HBM messages are 4 bytes */ + } wr_ext_msg; /* for control responses */ struct hbm_version version; @@ -253,12 +265,15 @@ struct mei_device { struct mei_cl wd_cl; enum mei_wd_states wd_state; - bool wd_interface_reg; bool wd_pending; u16 wd_timeout; unsigned char wd_data[MEI_WD_START_MSG_SIZE]; + /* amthif list for cmd waiting */ + struct mei_cl_cb amthif_cmd_list; + /* driver managed amthif list for reading completed amthif cmd data */ + struct mei_cl_cb amthif_rd_complete_list; struct file *iamthif_file_object; struct mei_cl iamthif_cl; struct mei_cl_cb *iamthif_current_cb; @@ -272,8 +287,15 @@ struct mei_device { bool iamthif_flow_control_pending; bool iamthif_ioctl; bool iamthif_canceled; + + struct work_struct init_work; }; +static inline unsigned long mei_secs_to_jiffies(unsigned long sec) +{ + return msecs_to_jiffies(sec * MSEC_PER_SEC); +} + /* * mei init function prototypes @@ -284,21 +306,34 @@ int mei_hw_init(struct mei_device *dev); int mei_task_initialize_clients(void *data); int mei_initialize_clients(struct mei_device *dev); int mei_disconnect_host_client(struct mei_device *dev, struct mei_cl *cl); -void mei_remove_client_from_file_list(struct mei_device *dev, u8 host_client_id); -void mei_host_init_iamthif(struct mei_device *dev); void mei_allocate_me_clients_storage(struct mei_device *dev); -int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl, +int mei_me_cl_link(struct mei_device *dev, struct mei_cl *cl, const uuid_le *cguid, u8 host_client_id); +void mei_me_cl_unlink(struct mei_device *dev, struct mei_cl *cl); int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid); int mei_me_cl_by_id(struct mei_device *dev, u8 client_id); /* - * MEI IO List Functions + * MEI IO Functions + */ +struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, struct file *fp); +void mei_io_cb_free(struct mei_cl_cb *priv_cb); +int mei_io_cb_alloc_req_buf(struct mei_cl_cb *cb, size_t length); +int mei_io_cb_alloc_resp_buf(struct mei_cl_cb *cb, size_t length); + + +/** + * mei_io_list_init - Sets up a queue list. + * + * @list: An instance cl callback structure */ -void mei_io_list_init(struct mei_io_list *list); -void mei_io_list_flush(struct mei_io_list *list, struct mei_cl *cl); +static inline void mei_io_list_init(struct mei_cl_cb *list) +{ + INIT_LIST_HEAD(&list->list); +} +void mei_io_list_flush(struct mei_cl_cb *list, struct mei_cl *cl); /* * MEI ME Client Functions @@ -330,7 +365,8 @@ static inline bool mei_cl_cmp_id(const struct mei_cl *cl1, */ void mei_host_start_message(struct mei_device *dev); void mei_host_enum_clients_message(struct mei_device *dev); -int mei_host_client_properties(struct mei_device *dev); +int mei_host_client_enumerate(struct mei_device *dev); +void mei_host_client_init(struct work_struct *work); /* * MEI interrupt functions prototype @@ -347,18 +383,40 @@ int mei_ioctl_connect_client(struct file *file, int mei_start_read(struct mei_device *dev, struct mei_cl *cl); -int amthi_write(struct mei_device *dev, struct mei_cl_cb *priv_cb); -int amthi_read(struct mei_device *dev, struct file *file, - char __user *ubuf, size_t length, loff_t *offset); +/* + * AMTHIF - AMT Host Interface Functions + */ +void mei_amthif_reset_params(struct mei_device *dev); + +void mei_amthif_host_init(struct mei_device *dev); + +int mei_amthif_write(struct mei_device *dev, struct mei_cl_cb *priv_cb); -struct mei_cl_cb *find_amthi_read_list_entry(struct mei_device *dev, +int mei_amthif_read(struct mei_device *dev, struct file *file, + char __user *ubuf, size_t length, loff_t *offset); + +unsigned int mei_amthif_poll(struct mei_device *dev, + struct file *file, poll_table *wait); + +int mei_amthif_release(struct mei_device *dev, struct file *file); + +struct mei_cl_cb *mei_amthif_find_read_list_entry(struct mei_device *dev, struct file *file); -void mei_run_next_iamthif_cmd(struct mei_device *dev); +void mei_amthif_run_next_cmd(struct mei_device *dev); + -void mei_free_cb_private(struct mei_cl_cb *priv_cb); +int mei_amthif_read_message(struct mei_cl_cb *complete_list, + struct mei_device *dev, struct mei_msg_hdr *mei_hdr); +int mei_amthif_irq_write_complete(struct mei_device *dev, s32 *slots, + struct mei_cl_cb *cb, struct mei_cl_cb *cmpl_list); + +void mei_amthif_complete(struct mei_device *dev, struct mei_cl_cb *cb); +int mei_amthif_irq_read_message(struct mei_cl_cb *complete_list, + struct mei_device *dev, struct mei_msg_hdr *mei_hdr); +int mei_amthif_irq_read(struct mei_device *dev, s32 *slots); /* * Register Access Function @@ -437,4 +495,15 @@ void mei_csr_clear_his(struct mei_device *dev); void mei_enable_interrupts(struct mei_device *dev); void mei_disable_interrupts(struct mei_device *dev); +static inline struct mei_msg_hdr *mei_hbm_hdr(u32 *buf, size_t length) +{ + struct mei_msg_hdr *hdr = (struct mei_msg_hdr *)buf; + hdr->host_addr = 0; + hdr->me_addr = 0; + hdr->length = length; + hdr->msg_complete = 1; + hdr->reserved = 0; + return hdr; +} + #endif diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index d96c537f046..636409f9667 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c @@ -62,6 +62,7 @@ static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout) */ int mei_wd_host_init(struct mei_device *dev) { + int id; mei_cl_init(&dev->wd_cl, dev); /* look for WD client and connect to it */ @@ -69,12 +70,11 @@ int mei_wd_host_init(struct mei_device *dev) dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT; dev->wd_state = MEI_WD_IDLE; - /* find ME WD client */ - mei_me_cl_update_filext(dev, &dev->wd_cl, + /* Connect WD ME client to the host client */ + id = mei_me_cl_link(dev, &dev->wd_cl, &mei_wd_guid, MEI_WD_HOST_CLIENT_ID); - dev_dbg(&dev->pdev->dev, "wd: check client\n"); - if (MEI_FILE_CONNECTING != dev->wd_cl.state) { + if (id < 0) { dev_info(&dev->pdev->dev, "wd: failed to find the client\n"); return -ENOENT; } @@ -85,7 +85,7 @@ int mei_wd_host_init(struct mei_device *dev) dev->wd_cl.host_client_id = 0; return -EIO; } - dev->wd_cl.timer_count = CONNECT_TIMEOUT; + dev->wd_cl.timer_count = MEI_CONNECT_TIMEOUT; return 0; } @@ -360,23 +360,20 @@ void mei_watchdog_register(struct mei_device *dev) if (watchdog_register_device(&amt_wd_dev)) { dev_err(&dev->pdev->dev, "wd: unable to register watchdog device.\n"); - dev->wd_interface_reg = false; return; } dev_dbg(&dev->pdev->dev, "wd: successfully register watchdog interface.\n"); - dev->wd_interface_reg = true; watchdog_set_drvdata(&amt_wd_dev, dev); } void mei_watchdog_unregister(struct mei_device *dev) { - if (!dev->wd_interface_reg) + if (test_bit(WDOG_UNREGISTERED, &amt_wd_dev.status)) return; watchdog_set_drvdata(&amt_wd_dev, NULL); watchdog_unregister_device(&amt_wd_dev); - dev->wd_interface_reg = false; } diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c index c9f20dae185..931e635aa49 100644 --- a/drivers/misc/pch_phub.c +++ b/drivers/misc/pch_phub.c @@ -666,7 +666,7 @@ static struct bin_attribute pch_bin_attr = { .write = pch_phub_bin_write, }; -static int __devinit pch_phub_probe(struct pci_dev *pdev, +static int pch_phub_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int retval; @@ -819,7 +819,7 @@ err_pci_enable_dev: return ret; } -static void __devexit pch_phub_remove(struct pci_dev *pdev) +static void pch_phub_remove(struct pci_dev *pdev) { struct pch_phub_reg *chip = pci_get_drvdata(pdev); @@ -888,7 +888,7 @@ static struct pci_driver pch_phub_driver = { .name = "pch_phub", .id_table = pch_phub_pcidev_id, .probe = pch_phub_probe, - .remove = __devexit_p(pch_phub_remove), + .remove = pch_phub_remove, .suspend = pch_phub_suspend, .resume = pch_phub_resume }; diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index 21b28fc6d91..68b7c773d2c 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c @@ -324,7 +324,7 @@ static irqreturn_t phantom_isr(int irq, void *data) * Init and deinit driver */ -static unsigned int __devinit phantom_get_free(void) +static unsigned int phantom_get_free(void) { unsigned int i; @@ -335,7 +335,7 @@ static unsigned int __devinit phantom_get_free(void) return i; } -static int __devinit phantom_probe(struct pci_dev *pdev, +static int phantom_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) { struct phantom_device *pht; @@ -435,7 +435,7 @@ err: return retval; } -static void __devexit phantom_remove(struct pci_dev *pdev) +static void phantom_remove(struct pci_dev *pdev) { struct phantom_device *pht = pci_get_drvdata(pdev); unsigned int minor = MINOR(pht->cdev.dev); @@ -487,7 +487,7 @@ static int phantom_resume(struct pci_dev *pdev) #define phantom_resume NULL #endif -static struct pci_device_id phantom_pci_tbl[] __devinitdata = { +static struct pci_device_id phantom_pci_tbl[] = { { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9050, .subvendor = PCI_VENDOR_ID_PLX, .subdevice = PCI_DEVICE_ID_PLX_9050, .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 }, @@ -499,7 +499,7 @@ static struct pci_driver phantom_pci_driver = { .name = "phantom", .id_table = phantom_pci_tbl, .probe = phantom_probe, - .remove = __devexit_p(phantom_remove), + .remove = phantom_remove, .suspend = phantom_suspend, .resume = phantom_resume }; diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c index 4999b34b7a6..7003031c918 100644 --- a/drivers/misc/pti.c +++ b/drivers/misc/pti.c @@ -76,7 +76,7 @@ struct pti_dev { */ static DEFINE_MUTEX(alloclock); -static const struct pci_device_id pci_ids[] __devinitconst = { +static const struct pci_device_id pci_ids[] = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x82B)}, {0} }; @@ -796,7 +796,7 @@ static const struct tty_port_operations tty_port_ops = { * 0 for success * otherwise, error */ -static int __devinit pti_pci_probe(struct pci_dev *pdev, +static int pti_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { unsigned int a; @@ -879,7 +879,7 @@ err: * PCI bus. * @pdev: variable containing pci info of PTI. */ -static void __devexit pti_pci_remove(struct pci_dev *pdev) +static void pti_pci_remove(struct pci_dev *pdev) { struct pti_dev *drv_data = pci_get_drvdata(pdev); @@ -901,7 +901,7 @@ static struct pci_driver pti_pci_driver = { .name = PCINAME, .id_table = pci_ids, .probe = pti_pci_probe, - .remove = __devexit_p(pti_pci_remove), + .remove = pti_pci_remove, }; /** diff --git a/drivers/misc/spear13xx_pcie_gadget.c b/drivers/misc/spear13xx_pcie_gadget.c index 123ed98eec3..7deb25dc86a 100644 --- a/drivers/misc/spear13xx_pcie_gadget.c +++ b/drivers/misc/spear13xx_pcie_gadget.c @@ -711,7 +711,7 @@ static void spear13xx_pcie_device_init(struct spear_pcie_gadget_config *config) spear_dbi_write_reg(config, PCI_INTERRUPT_LINE, 1, 1); } -static int __devinit spear_pcie_gadget_probe(struct platform_device *pdev) +static int spear_pcie_gadget_probe(struct platform_device *pdev) { struct resource *res0, *res1; unsigned int status = 0; @@ -853,7 +853,7 @@ err_rel_res0: return status; } -static int __devexit spear_pcie_gadget_remove(struct platform_device *pdev) +static int spear_pcie_gadget_remove(struct platform_device *pdev) { struct resource *res0, *res1; static struct pcie_gadget_target *target; diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index 46937b10726..b90a2241d79 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -511,7 +511,6 @@ long st_register(struct st_proto_s *new_proto) unsigned long flags = 0; st_kim_ref(&st_gdata, 0); - pr_info("%s(%d) ", __func__, new_proto->chnl_id); if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL || new_proto->reg_complete_cb == NULL) { pr_err("gdata/new_proto/recv or reg_complete_cb not ready"); diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c index 04a819944f6..9ff942a346e 100644 --- a/drivers/misc/ti-st/st_kim.c +++ b/drivers/misc/ti-st/st_kim.c @@ -705,9 +705,9 @@ static const struct file_operations list_debugfs_fops = { static struct dentry *kim_debugfs_dir; static int kim_probe(struct platform_device *pdev) { - long status; struct kim_data_s *kim_gdata; struct ti_st_plat_data *pdata = pdev->dev.platform_data; + int err; if ((pdev->id != -1) && (pdev->id < MAX_ST_DEVICES)) { /* multiple devices could exist */ @@ -724,10 +724,11 @@ static int kim_probe(struct platform_device *pdev) } dev_set_drvdata(&pdev->dev, kim_gdata); - status = st_core_init(&kim_gdata->core_data); - if (status != 0) { + err = st_core_init(&kim_gdata->core_data); + if (err != 0) { pr_err(" ST core init failed"); - return -EIO; + err = -EIO; + goto err_core_init; } /* refer to itself */ kim_gdata->core_data->kim_data = kim_gdata; @@ -738,10 +739,10 @@ static int kim_probe(struct platform_device *pdev) init_completion(&kim_gdata->kim_rcvd); init_completion(&kim_gdata->ldisc_installed); - status = sysfs_create_group(&pdev->dev.kobj, &uim_attr_grp); - if (status) { + err = sysfs_create_group(&pdev->dev.kobj, &uim_attr_grp); + if (err) { pr_err("failed to create sysfs entries"); - return status; + goto err_sysfs_group; } /* copying platform data */ @@ -753,8 +754,8 @@ static int kim_probe(struct platform_device *pdev) kim_debugfs_dir = debugfs_create_dir("ti-st", NULL); if (IS_ERR(kim_debugfs_dir)) { pr_err(" debugfs entries creation failed "); - kim_debugfs_dir = NULL; - return -EIO; + err = -EIO; + goto err_debugfs_dir; } debugfs_create_file("version", S_IRUGO, kim_debugfs_dir, @@ -763,6 +764,17 @@ static int kim_probe(struct platform_device *pdev) kim_gdata, &list_debugfs_fops); pr_info(" debugfs entries created "); return 0; + +err_debugfs_dir: + sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp); + +err_sysfs_group: + st_core_exit(kim_gdata->core_data); + +err_core_init: + kfree(kim_gdata); + + return err; } static int kim_remove(struct platform_device *pdev) diff --git a/drivers/misc/ti_dac7512.c b/drivers/misc/ti_dac7512.c index 5acbba120de..1d86407189e 100644 --- a/drivers/misc/ti_dac7512.c +++ b/drivers/misc/ti_dac7512.c @@ -54,7 +54,7 @@ static const struct attribute_group dac7512_attr_group = { .attrs = dac7512_attributes, }; -static int __devinit dac7512_probe(struct spi_device *spi) +static int dac7512_probe(struct spi_device *spi) { int ret; @@ -67,7 +67,7 @@ static int __devinit dac7512_probe(struct spi_device *spi) return sysfs_create_group(&spi->dev.kobj, &dac7512_attr_group); } -static int __devexit dac7512_remove(struct spi_device *spi) +static int dac7512_remove(struct spi_device *spi) { sysfs_remove_group(&spi->dev.kobj, &dac7512_attr_group); return 0; @@ -79,7 +79,7 @@ static struct spi_driver dac7512_driver = { .owner = THIS_MODULE, }, .probe = dac7512_probe, - .remove = __devexit_p(dac7512_remove), + .remove = dac7512_remove, }; module_spi_driver(dac7512_driver); diff --git a/drivers/misc/tsl2550.c b/drivers/misc/tsl2550.c index 0beb298a17d..1e7bc0eb081 100644 --- a/drivers/misc/tsl2550.c +++ b/drivers/misc/tsl2550.c @@ -347,7 +347,7 @@ static int tsl2550_init_client(struct i2c_client *client) */ static struct i2c_driver tsl2550_driver; -static int __devinit tsl2550_probe(struct i2c_client *client, +static int tsl2550_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); @@ -405,7 +405,7 @@ exit: return err; } -static int __devexit tsl2550_remove(struct i2c_client *client) +static int tsl2550_remove(struct i2c_client *client) { sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group); @@ -450,7 +450,7 @@ static struct i2c_driver tsl2550_driver = { .suspend = tsl2550_suspend, .resume = tsl2550_resume, .probe = tsl2550_probe, - .remove = __devexit_p(tsl2550_remove), + .remove = tsl2550_remove, .id_table = tsl2550_id, }; diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 172a768036d..21056b9ef0a 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -57,6 +57,7 @@ MODULE_ALIAS("mmc:block"); #define INAND_CMD38_ARG_SECERASE 0x80 #define INAND_CMD38_ARG_SECTRIM1 0x81 #define INAND_CMD38_ARG_SECTRIM2 0x88 +#define MMC_BLK_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */ static DEFINE_MUTEX(block_mutex); @@ -126,6 +127,10 @@ enum mmc_blk_status { module_param(perdev_minors, int, 0444); MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device"); +static inline int mmc_blk_part_switch(struct mmc_card *card, + struct mmc_blk_data *md); +static int get_card_status(struct mmc_card *card, u32 *status, int retries); + static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk) { struct mmc_blk_data *md; @@ -357,6 +362,38 @@ out: return ERR_PTR(err); } +static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status, + u32 retries_max) +{ + int err; + u32 retry_count = 0; + + if (!status || !retries_max) + return -EINVAL; + + do { + err = get_card_status(card, status, 5); + if (err) + break; + + if (!R1_STATUS(*status) && + (R1_CURRENT_STATE(*status) != R1_STATE_PRG)) + break; /* RPMB programming operation complete */ + + /* + * Rechedule to give the MMC device a chance to continue + * processing the previous command without being polled too + * frequently. + */ + usleep_range(1000, 5000); + } while (++retry_count < retries_max); + + if (retry_count == retries_max) + err = -EPERM; + + return err; +} + static int mmc_blk_ioctl_cmd(struct block_device *bdev, struct mmc_ioc_cmd __user *ic_ptr) { @@ -368,6 +405,8 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, struct mmc_request mrq = {NULL}; struct scatterlist sg; int err; + int is_rpmb = false; + u32 status = 0; /* * The caller must have CAP_SYS_RAWIO, and must be calling this on the @@ -387,6 +426,9 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, goto cmd_err; } + if (md->area_type & MMC_BLK_DATA_AREA_RPMB) + is_rpmb = true; + card = md->queue.card; if (IS_ERR(card)) { err = PTR_ERR(card); @@ -437,12 +479,23 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, mmc_claim_host(card->host); + err = mmc_blk_part_switch(card, md); + if (err) + goto cmd_rel_host; + if (idata->ic.is_acmd) { err = mmc_app_cmd(card->host, card); if (err) goto cmd_rel_host; } + if (is_rpmb) { + err = mmc_set_blockcount(card, data.blocks, + idata->ic.write_flag & (1 << 31)); + if (err) + goto cmd_rel_host; + } + mmc_wait_for_req(card->host, &mrq); if (cmd.error) { @@ -478,6 +531,18 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, } } + if (is_rpmb) { + /* + * Ensure RPMB command has completed by polling CMD13 + * "Send Status". + */ + err = ioctl_rpmb_card_status_poll(card, &status, 5); + if (err) + dev_err(mmc_dev(card->host), + "%s: Card Status=0x%08X, error %d\n", + __func__, status, err); + } + cmd_rel_host: mmc_release_host(card->host); @@ -1034,6 +1099,9 @@ static int mmc_blk_err_check(struct mmc_card *card, */ if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) { u32 status; + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(MMC_BLK_TIMEOUT_MS); do { int err = get_card_status(card, &status, 5); if (err) { @@ -1041,6 +1109,17 @@ static int mmc_blk_err_check(struct mmc_card *card, req->rq_disk->disk_name, err); return MMC_BLK_CMD_ERR; } + + /* Timeout if the device never becomes ready for data + * and never leaves the program state. + */ + if (time_after(jiffies, timeout)) { + pr_err("%s: Card stuck in programming state!"\ + " %s %s\n", mmc_hostname(card->host), + req->rq_disk->disk_name, __func__); + + return MMC_BLK_CMD_ERR; + } /* * Some cards mishandle the status bits, * so make sure to check both the busy @@ -1504,6 +1583,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, md->disk->queue = md->queue.queue; md->disk->driverfs_dev = parent; set_disk_ro(md->disk, md->read_only || default_ro); + if (area_type & MMC_BLK_DATA_AREA_RPMB) + md->disk->flags |= GENHD_FL_NO_PART_SCAN; /* * As discussed on lkml, GENHD_FL_REMOVABLE should: diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index e360a979857..fadf52eb5d7 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -68,6 +68,16 @@ static int mmc_queue_thread(void *d) if (req || mq->mqrq_prev->req) { set_current_state(TASK_RUNNING); mq->issue_fn(mq, req); + + /* + * Current request becomes previous request + * and vice versa. + */ + mq->mqrq_prev->brq.mrq.data = NULL; + mq->mqrq_prev->req = NULL; + tmp = mq->mqrq_prev; + mq->mqrq_prev = mq->mqrq_cur; + mq->mqrq_cur = tmp; } else { if (kthread_should_stop()) { set_current_state(TASK_RUNNING); @@ -77,13 +87,6 @@ static int mmc_queue_thread(void *d) schedule(); down(&mq->thread_sem); } - - /* Current request becomes previous request and vice versa. */ - mq->mqrq_prev->brq.mrq.data = NULL; - mq->mqrq_prev->req = NULL; - tmp = mq->mqrq_prev; - mq->mqrq_prev = mq->mqrq_cur; - mq->mqrq_cur = tmp; } while (1); up(&mq->thread_sem); diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 9b68933f27e..420cb6753c1 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -225,8 +225,7 @@ static void mmc_release_card(struct device *dev) sdio_free_common_cis(card); - if (card->info) - kfree(card->info); + kfree(card->info); kfree(card); } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 06c42cfb7c3..aaed7687cf0 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -42,6 +42,9 @@ #include "sd_ops.h" #include "sdio_ops.h" +/* If the device is not responding */ +#define MMC_CORE_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */ + /* * Background operations can take a long time, depending on the housekeeping * operations the card has to perform. @@ -1631,6 +1634,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, { struct mmc_command cmd = {0}; unsigned int qty = 0; + unsigned long timeout; int err; /* @@ -1708,6 +1712,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, if (mmc_host_is_spi(card->host)) goto out; + timeout = jiffies + msecs_to_jiffies(MMC_CORE_TIMEOUT_MS); do { memset(&cmd, 0, sizeof(struct mmc_command)); cmd.opcode = MMC_SEND_STATUS; @@ -1721,8 +1726,19 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, err = -EIO; goto out; } + + /* Timeout if the device never becomes ready for data and + * never leaves the program state. + */ + if (time_after(jiffies, timeout)) { + pr_err("%s: Card stuck in programming state! %s\n", + mmc_hostname(card->host), __func__); + err = -EIO; + goto out; + } + } while (!(cmd.resp[0] & R1_READY_FOR_DATA) || - R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG); + (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG)); out: return err; } @@ -1942,6 +1958,20 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen) } EXPORT_SYMBOL(mmc_set_blocklen); +int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount, + bool is_rel_write) +{ + struct mmc_command cmd = {0}; + + cmd.opcode = MMC_SET_BLOCK_COUNT; + cmd.arg = blockcount & 0x0000FFFF; + if (is_rel_write) + cmd.arg |= 1 << 31; + cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; + return mmc_wait_for_cmd(card->host, &cmd, 5); +} +EXPORT_SYMBOL(mmc_set_blockcount); + static void mmc_hw_reset_for_init(struct mmc_host *host) { if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index d96c643dde1..35c2f85b195 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -144,6 +144,22 @@ static int mmc_ios_show(struct seq_file *s, void *data) } seq_printf(s, "timing spec:\t%u (%s)\n", ios->timing, str); + switch (ios->signal_voltage) { + case MMC_SIGNAL_VOLTAGE_330: + str = "3.30 V"; + break; + case MMC_SIGNAL_VOLTAGE_180: + str = "1.80 V"; + break; + case MMC_SIGNAL_VOLTAGE_120: + str = "1.20 V"; + break; + default: + str = "invalid"; + break; + } + seq_printf(s, "signal voltage:\t%u (%s)\n", ios->chip_select, str); + return 0; } diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 7cc46382fd6..e6e39111e05 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -239,7 +239,7 @@ static void mmc_select_card_type(struct mmc_card *card) { struct mmc_host *host = card->host; u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK; - unsigned int caps = host->caps, caps2 = host->caps2; + u32 caps = host->caps, caps2 = host->caps2; unsigned int hs_max_dtr = 0; if (card_type & EXT_CSD_CARD_TYPE_26) @@ -491,6 +491,17 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; + + /* + * RPMB regions are defined in multiples of 128K. + */ + card->ext_csd.raw_rpmb_size_mult = ext_csd[EXT_CSD_RPMB_MULT]; + if (ext_csd[EXT_CSD_RPMB_MULT]) { + mmc_part_add(card, ext_csd[EXT_CSD_RPMB_MULT] << 17, + EXT_CSD_PART_CONFIG_ACC_RPMB, + "rpmb", 0, false, + MMC_BLK_DATA_AREA_RPMB); + } } card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT]; @@ -615,6 +626,8 @@ MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial); MMC_DEV_ATTR(enhanced_area_offset, "%llu\n", card->ext_csd.enhanced_area_offset); MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size); +MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult); +MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors); static struct attribute *mmc_std_attrs[] = { &dev_attr_cid.attr, @@ -630,6 +643,8 @@ static struct attribute *mmc_std_attrs[] = { &dev_attr_serial.attr, &dev_attr_enhanced_area_offset.attr, &dev_attr_enhanced_area_size.attr, + &dev_attr_raw_rpmb_size_mult.attr, + &dev_attr_rel_sectors.attr, NULL, }; @@ -1051,6 +1066,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (mmc_card_highspeed(card) || mmc_card_hs200(card)) { if (max_dtr > card->ext_csd.hs_max_dtr) max_dtr = card->ext_csd.hs_max_dtr; + if (mmc_card_highspeed(card) && (max_dtr > 52000000)) + max_dtr = 52000000; } else if (max_dtr > card->csd.max_dtr) { max_dtr = card->csd.max_dtr; } diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index a0e172042e6..6d8f7012d73 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -21,6 +21,8 @@ #include "core.h" #include "mmc_ops.h" +#define MMC_OPS_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */ + static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) { int err; @@ -409,6 +411,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, { int err; struct mmc_command cmd = {0}; + unsigned long timeout; u32 status; BUG_ON(!card); @@ -437,6 +440,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, return 0; /* Must check status to be sure of no errors */ + timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS); do { err = mmc_send_status(card, &status); if (err) @@ -445,6 +449,13 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, break; if (mmc_host_is_spi(card->host)) break; + + /* Timeout if the device never leaves the program state. */ + if (time_after(jiffies, timeout)) { + pr_err("%s: Card stuck in programming state! %s\n", + mmc_hostname(card->host), __func__); + return -ETIMEDOUT; + } } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); if (mmc_host_is_spi(card->host)) { diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 6bf68799fe9..5e57048e2c1 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -193,7 +193,21 @@ static int sdio_bus_remove(struct device *dev) } #ifdef CONFIG_PM + +#ifdef CONFIG_PM_SLEEP +static int pm_no_operation(struct device *dev) +{ + /* + * Prevent the PM core from calling SDIO device drivers' suspend + * callback routines, which it is not supposed to do, by using this + * empty function as the bus type suspend callaback for SDIO. + */ + return 0; +} +#endif + static const struct dev_pm_ops sdio_bus_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_no_operation, pm_no_operation) SET_RUNTIME_PM_OPS( pm_generic_runtime_suspend, pm_generic_runtime_resume, @@ -258,8 +272,7 @@ static void sdio_release_func(struct device *dev) sdio_free_func_cis(func); - if (func->info) - kfree(func->info); + kfree(func->info); kfree(func); } diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index 8f6f5ac131f..78cb4d5d9d5 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -188,8 +188,7 @@ EXPORT_SYMBOL_GPL(sdio_set_block_size); */ static inline unsigned int sdio_max_byte_size(struct sdio_func *func) { - unsigned mval = min(func->card->host->max_seg_size, - func->card->host->max_blk_size); + unsigned mval = func->card->host->max_blk_size; if (mmc_blksz_for_byte_mode(func->card)) mval = min(mval, func->cur_blksize); @@ -311,11 +310,8 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write, /* Do the bulk of the transfer using block mode (if supported). */ if (func->card->cccr.multi_block && (size > sdio_max_byte_size(func))) { /* Blocks per command is limited by host count, host transfer - * size (we only use a single sg entry) and the maximum for - * IO_RW_EXTENDED of 511 blocks. */ - max_blocks = min(func->card->host->max_blk_count, - func->card->host->max_seg_size / func->cur_blksize); - max_blocks = min(max_blocks, 511u); + * size and the maximum for IO_RW_EXTENDED of 511 blocks. */ + max_blocks = min(func->card->host->max_blk_count, 511u); while (remainder >= func->cur_blksize) { unsigned blocks; diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index d29e20630ee..62508b457c4 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -124,7 +124,10 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, struct mmc_request mrq = {NULL}; struct mmc_command cmd = {0}; struct mmc_data data = {0}; - struct scatterlist sg; + struct scatterlist sg, *sg_ptr; + struct sg_table sgtable; + unsigned int nents, left_size, i; + unsigned int seg_size = card->host->max_seg_size; BUG_ON(!card); BUG_ON(fn > 7); @@ -152,15 +155,36 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, /* Code in host drivers/fwk assumes that "blocks" always is >=1 */ data.blocks = blocks ? blocks : 1; data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; - data.sg = &sg; - data.sg_len = 1; - sg_init_one(&sg, buf, data.blksz * data.blocks); + left_size = data.blksz * data.blocks; + nents = (left_size - 1) / seg_size + 1; + if (nents > 1) { + if (sg_alloc_table(&sgtable, nents, GFP_KERNEL)) + return -ENOMEM; + + data.sg = sgtable.sgl; + data.sg_len = nents; + + for_each_sg(data.sg, sg_ptr, data.sg_len, i) { + sg_set_page(sg_ptr, virt_to_page(buf + (i * seg_size)), + min(seg_size, left_size), + offset_in_page(buf + (i * seg_size))); + left_size = left_size - seg_size; + } + } else { + data.sg = &sg; + data.sg_len = 1; + + sg_init_one(&sg, buf, left_size); + } mmc_set_data_timeout(&data, card); mmc_wait_for_req(card->host, &mrq); + if (nents > 1) + sg_free_table(&sgtable); + if (cmd.error) return cmd.error; if (data.error) diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 08c6b3dfe08..16a1c0b6f26 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -27,7 +27,13 @@ struct mmc_gpio { static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id) { /* Schedule a card detection after a debounce timeout */ - mmc_detect_change(dev_id, msecs_to_jiffies(100)); + struct mmc_host *host = dev_id; + + if (host->ops->card_event) + host->ops->card_event(host); + + mmc_detect_change(host, msecs_to_jiffies(200)); + return IRQ_HANDLED; } diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 9bf10e7bbfa..737e4edc241 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -81,6 +81,18 @@ config MMC_RICOH_MMC If unsure, say Y. +config MMC_SDHCI_ACPI + tristate "SDHCI support for ACPI enumerated SDHCI controllers" + depends on MMC_SDHCI && ACPI + help + This selects support for ACPI enumerated SDHCI controllers, + identified by ACPI Compatibility ID PNP0D40 or specific + ACPI Hardware IDs. + + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + config MMC_SDHCI_PLTFM tristate "SDHCI platform and OF driver helper" depends on MMC_SDHCI @@ -270,26 +282,8 @@ config MMC_AU1X If unsure, say N. -choice - prompt "Atmel SD/MMC Driver" - depends on AVR32 || ARCH_AT91 - default MMC_ATMELMCI if AVR32 - help - Choose which driver to use for the Atmel MCI Silicon - -config MMC_AT91 - tristate "AT91 SD/MMC Card Interface support (DEPRECATED)" - depends on ARCH_AT91 - help - This selects the AT91 MCI controller. This driver will - be removed soon (for more information have a look to - Documentation/feature-removal-schedule.txt). Please use - MMC_ATMEL_MCI. - - If unsure, say N. - config MMC_ATMELMCI - tristate "Atmel Multimedia Card Interface support" + tristate "Atmel SD/MMC Driver (Multimedia Card Interface)" depends on AVR32 || ARCH_AT91 help This selects the Atmel Multimedia Card Interface driver. If @@ -298,8 +292,6 @@ config MMC_ATMELMCI If unsure, say N. -endchoice - config MMC_ATMELMCI_DMA bool "Atmel MCI DMA support" depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE @@ -621,3 +613,21 @@ config MMC_USHC Note: These controllers only support SDIO cards and do not support MMC or SD memory cards. + +config MMC_WMT + tristate "Wondermedia SD/MMC Host Controller support" + depends on ARCH_VT8500 + default y + help + This selects support for the SD/MMC Host Controller on + Wondermedia WM8505/WM8650 based SoCs. + + To compile this driver as a module, choose M here: the + module will be called wmt-sdmmc. + +config MMC_REALTEK_PCI + tristate "Realtek PCI-E SD/MMC Card Interface Driver" + depends on MFD_RTSX_PCI + help + Say Y here to include driver code to support SD/MMC card interface + of Realtek PCI-E card reader diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 17ad0a7ba40..b648058d718 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_MMC_MXS) += mxs-mmc.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o +obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o @@ -17,7 +18,6 @@ obj-$(CONFIG_MMC_WBSD) += wbsd.o obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_OMAP) += omap.o obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.o -obj-$(CONFIG_MMC_AT91) += at91_mci.o obj-$(CONFIG_MMC_ATMELMCI) += atmel-mci.o obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o obj-$(CONFIG_MMC_MSM) += msm_sdcc.o @@ -45,6 +45,9 @@ obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o obj-$(CONFIG_MMC_VUB300) += vub300.o obj-$(CONFIG_MMC_USHC) += ushc.o +obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o + +obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c deleted file mode 100644 index 74bed0fc23e..00000000000 --- a/drivers/mmc/host/at91_mci.c +++ /dev/null @@ -1,1219 +0,0 @@ -/* - * linux/drivers/mmc/host/at91_mci.c - ATMEL AT91 MCI Driver - * - * Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved - * - * Copyright (C) 2006 Malcolm Noyes - * - * 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. - */ - -/* - This is the AT91 MCI driver that has been tested with both MMC cards - and SD-cards. Boards that support write protect are now supported. - The CCAT91SBC001 board does not support SD cards. - - The three entry points are at91_mci_request, at91_mci_set_ios - and at91_mci_get_ro. - - SET IOS - This configures the device to put it into the correct mode and clock speed - required. - - MCI REQUEST - MCI request processes the commands sent in the mmc_request structure. This - can consist of a processing command and a stop command in the case of - multiple block transfers. - - There are three main types of request, commands, reads and writes. - - Commands are straight forward. The command is submitted to the controller and - the request function returns. When the controller generates an interrupt to indicate - the command is finished, the response to the command are read and the mmc_request_done - function called to end the request. - - Reads and writes work in a similar manner to normal commands but involve the PDC (DMA) - controller to manage the transfers. - - A read is done from the controller directly to the scatterlist passed in from the request. - Due to a bug in the AT91RM9200 controller, when a read is completed, all the words are byte - swapped in the scatterlist buffers. AT91SAM926x are not affected by this bug. - - The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY - - A write is slightly different in that the bytes to write are read from the scatterlist - into a dma memory buffer (this is in case the source buffer should be read only). The - entire write buffer is then done from this single dma memory buffer. - - The sequence of write interrupts is: ENDTX, TXBUFE, NOTBUSY, CMDRDY - - GET RO - Gets the status of the write protect pin, if available. -*/ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/blkdev.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/dma-mapping.h> -#include <linux/clk.h> -#include <linux/atmel_pdc.h> -#include <linux/gfp.h> -#include <linux/highmem.h> - -#include <linux/mmc/host.h> -#include <linux/mmc/sdio.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/gpio.h> - -#include <mach/board.h> -#include <mach/cpu.h> - -#include "at91_mci.h" - -#define DRIVER_NAME "at91_mci" - -static inline int at91mci_is_mci1rev2xx(void) -{ - return ( cpu_is_at91sam9260() - || cpu_is_at91sam9263() - || cpu_is_at91sam9rl() - || cpu_is_at91sam9g10() - || cpu_is_at91sam9g20() - ); -} - -#define FL_SENT_COMMAND (1 << 0) -#define FL_SENT_STOP (1 << 1) - -#define AT91_MCI_ERRORS (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE \ - | AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE \ - | AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE) - -#define at91_mci_read(host, reg) __raw_readl((host)->baseaddr + (reg)) -#define at91_mci_write(host, reg, val) __raw_writel((val), (host)->baseaddr + (reg)) - -#define MCI_BLKSIZE 512 -#define MCI_MAXBLKSIZE 4095 -#define MCI_BLKATONCE 256 -#define MCI_BUFSIZE (MCI_BLKSIZE * MCI_BLKATONCE) - -/* - * Low level type for this driver - */ -struct at91mci_host -{ - struct mmc_host *mmc; - struct mmc_command *cmd; - struct mmc_request *request; - - void __iomem *baseaddr; - int irq; - - struct at91_mmc_data *board; - int present; - - struct clk *mci_clk; - - /* - * Flag indicating when the command has been sent. This is used to - * work out whether or not to send the stop - */ - unsigned int flags; - /* flag for current bus settings */ - u32 bus_mode; - - /* DMA buffer used for transmitting */ - unsigned int* buffer; - dma_addr_t physical_address; - unsigned int total_length; - - /* Latest in the scatterlist that has been enabled for transfer, but not freed */ - int in_use_index; - - /* Latest in the scatterlist that has been enabled for transfer */ - int transfer_index; - - /* Timer for timeouts */ - struct timer_list timer; -}; - -/* - * Reset the controller and restore most of the state - */ -static void at91_reset_host(struct at91mci_host *host) -{ - unsigned long flags; - u32 mr; - u32 sdcr; - u32 dtor; - u32 imr; - - local_irq_save(flags); - imr = at91_mci_read(host, AT91_MCI_IMR); - - at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); - - /* save current state */ - mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; - sdcr = at91_mci_read(host, AT91_MCI_SDCR); - dtor = at91_mci_read(host, AT91_MCI_DTOR); - - /* reset the controller */ - at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST); - - /* restore state */ - at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN); - at91_mci_write(host, AT91_MCI_MR, mr); - at91_mci_write(host, AT91_MCI_SDCR, sdcr); - at91_mci_write(host, AT91_MCI_DTOR, dtor); - at91_mci_write(host, AT91_MCI_IER, imr); - - /* make sure sdio interrupts will fire */ - at91_mci_read(host, AT91_MCI_SR); - - local_irq_restore(flags); -} - -static void at91_timeout_timer(unsigned long data) -{ - struct at91mci_host *host; - - host = (struct at91mci_host *)data; - - if (host->request) { - dev_err(host->mmc->parent, "Timeout waiting end of packet\n"); - - if (host->cmd && host->cmd->data) { - host->cmd->data->error = -ETIMEDOUT; - } else { - if (host->cmd) - host->cmd->error = -ETIMEDOUT; - else - host->request->cmd->error = -ETIMEDOUT; - } - - at91_reset_host(host); - mmc_request_done(host->mmc, host->request); - } -} - -/* - * Copy from sg to a dma block - used for transfers - */ -static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data) -{ - unsigned int len, i, size; - unsigned *dmabuf = host->buffer; - - size = data->blksz * data->blocks; - len = data->sg_len; - - /* MCI1 rev2xx Data Write Operation and number of bytes erratum */ - if (at91mci_is_mci1rev2xx()) - if (host->total_length == 12) - memset(dmabuf, 0, 12); - - /* - * Just loop through all entries. Size might not - * be the entire list though so make sure that - * we do not transfer too much. - */ - for (i = 0; i < len; i++) { - struct scatterlist *sg; - int amount; - unsigned int *sgbuffer; - - sg = &data->sg[i]; - - sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset; - amount = min(size, sg->length); - size -= amount; - - if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */ - int index; - - for (index = 0; index < (amount / 4); index++) - *dmabuf++ = swab32(sgbuffer[index]); - } else { - char *tmpv = (char *)dmabuf; - memcpy(tmpv, sgbuffer, amount); - tmpv += amount; - dmabuf = (unsigned *)tmpv; - } - - kunmap_atomic(sgbuffer); - - if (size == 0) - break; - } - - /* - * Check that we didn't get a request to transfer - * more data than can fit into the SG list. - */ - BUG_ON(size != 0); -} - -/* - * Handle after a dma read - */ -static void at91_mci_post_dma_read(struct at91mci_host *host) -{ - struct mmc_command *cmd; - struct mmc_data *data; - unsigned int len, i, size; - unsigned *dmabuf = host->buffer; - - pr_debug("post dma read\n"); - - cmd = host->cmd; - if (!cmd) { - pr_debug("no command\n"); - return; - } - - data = cmd->data; - if (!data) { - pr_debug("no data\n"); - return; - } - - size = data->blksz * data->blocks; - len = data->sg_len; - - at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_ENDRX); - at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF); - - for (i = 0; i < len; i++) { - struct scatterlist *sg; - int amount; - unsigned int *sgbuffer; - - sg = &data->sg[i]; - - sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset; - amount = min(size, sg->length); - size -= amount; - - if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */ - int index; - for (index = 0; index < (amount / 4); index++) - sgbuffer[index] = swab32(*dmabuf++); - } else { - char *tmpv = (char *)dmabuf; - memcpy(sgbuffer, tmpv, amount); - tmpv += amount; - dmabuf = (unsigned *)tmpv; - } - - flush_kernel_dcache_page(sg_page(sg)); - kunmap_atomic(sgbuffer); - data->bytes_xfered += amount; - if (size == 0) - break; - } - - pr_debug("post dma read done\n"); -} - -/* - * Handle transmitted data - */ -static void at91_mci_handle_transmitted(struct at91mci_host *host) -{ - struct mmc_command *cmd; - struct mmc_data *data; - - pr_debug("Handling the transmit\n"); - - /* Disable the transfer */ - at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); - - /* Now wait for cmd ready */ - at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE); - - cmd = host->cmd; - if (!cmd) return; - - data = cmd->data; - if (!data) return; - - if (cmd->data->blocks > 1) { - pr_debug("multiple write : wait for BLKE...\n"); - at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE); - } else - at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY); -} - -/* - * Update bytes transfered count during a write operation - */ -static void at91_mci_update_bytes_xfered(struct at91mci_host *host) -{ - struct mmc_data *data; - - /* always deal with the effective request (and not the current cmd) */ - - if (host->request->cmd && host->request->cmd->error != 0) - return; - - if (host->request->data) { - data = host->request->data; - if (data->flags & MMC_DATA_WRITE) { - /* card is in IDLE mode now */ - pr_debug("-> bytes_xfered %d, total_length = %d\n", - data->bytes_xfered, host->total_length); - data->bytes_xfered = data->blksz * data->blocks; - } - } -} - - -/*Handle after command sent ready*/ -static int at91_mci_handle_cmdrdy(struct at91mci_host *host) -{ - if (!host->cmd) - return 1; - else if (!host->cmd->data) { - if (host->flags & FL_SENT_STOP) { - /*After multi block write, we must wait for NOTBUSY*/ - at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY); - } else return 1; - } else if (host->cmd->data->flags & MMC_DATA_WRITE) { - /*After sendding multi-block-write command, start DMA transfer*/ - at91_mci_write(host, AT91_MCI_IER, AT91_MCI_TXBUFE | AT91_MCI_BLKE); - at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); - } - - /* command not completed, have to wait */ - return 0; -} - - -/* - * Enable the controller - */ -static void at91_mci_enable(struct at91mci_host *host) -{ - unsigned int mr; - - at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN); - at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); - at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC); - mr = AT91_MCI_PDCMODE | 0x34a; - - if (at91mci_is_mci1rev2xx()) - mr |= AT91_MCI_RDPROOF | AT91_MCI_WRPROOF; - - at91_mci_write(host, AT91_MCI_MR, mr); - - /* use Slot A or B (only one at same time) */ - at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b); -} - -/* - * Disable the controller - */ -static void at91_mci_disable(struct at91mci_host *host) -{ - at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST); -} - -/* - * Send a command - */ -static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd) -{ - unsigned int cmdr, mr; - unsigned int block_length; - struct mmc_data *data = cmd->data; - - unsigned int blocks; - unsigned int ier = 0; - - host->cmd = cmd; - - /* Needed for leaving busy state before CMD1 */ - if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) { - pr_debug("Clearing timeout\n"); - at91_mci_write(host, AT91_MCI_ARGR, 0); - at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD); - while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) { - /* spin */ - pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR)); - } - } - - cmdr = cmd->opcode; - - if (mmc_resp_type(cmd) == MMC_RSP_NONE) - cmdr |= AT91_MCI_RSPTYP_NONE; - else { - /* if a response is expected then allow maximum response latancy */ - cmdr |= AT91_MCI_MAXLAT; - /* set 136 bit response for R2, 48 bit response otherwise */ - if (mmc_resp_type(cmd) == MMC_RSP_R2) - cmdr |= AT91_MCI_RSPTYP_136; - else - cmdr |= AT91_MCI_RSPTYP_48; - } - - if (data) { - - if (cpu_is_at91rm9200() || cpu_is_at91sam9261()) { - if (data->blksz & 0x3) { - pr_debug("Unsupported block size\n"); - cmd->error = -EINVAL; - mmc_request_done(host->mmc, host->request); - return; - } - if (data->flags & MMC_DATA_STREAM) { - pr_debug("Stream commands not supported\n"); - cmd->error = -EINVAL; - mmc_request_done(host->mmc, host->request); - return; - } - } - - block_length = data->blksz; - blocks = data->blocks; - - /* always set data start - also set direction flag for read */ - if (data->flags & MMC_DATA_READ) - cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START); - else if (data->flags & MMC_DATA_WRITE) - cmdr |= AT91_MCI_TRCMD_START; - - if (cmd->opcode == SD_IO_RW_EXTENDED) { - cmdr |= AT91_MCI_TRTYP_SDIO_BLOCK; - } else { - if (data->flags & MMC_DATA_STREAM) - cmdr |= AT91_MCI_TRTYP_STREAM; - if (data->blocks > 1) - cmdr |= AT91_MCI_TRTYP_MULTIPLE; - } - } - else { - block_length = 0; - blocks = 0; - } - - if (host->flags & FL_SENT_STOP) - cmdr |= AT91_MCI_TRCMD_STOP; - - if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) - cmdr |= AT91_MCI_OPDCMD; - - /* - * Set the arguments and send the command - */ - pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n", - cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR)); - - if (!data) { - at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS); - at91_mci_write(host, ATMEL_PDC_RPR, 0); - at91_mci_write(host, ATMEL_PDC_RCR, 0); - at91_mci_write(host, ATMEL_PDC_RNPR, 0); - at91_mci_write(host, ATMEL_PDC_RNCR, 0); - at91_mci_write(host, ATMEL_PDC_TPR, 0); - at91_mci_write(host, ATMEL_PDC_TCR, 0); - at91_mci_write(host, ATMEL_PDC_TNPR, 0); - at91_mci_write(host, ATMEL_PDC_TNCR, 0); - ier = AT91_MCI_CMDRDY; - } else { - /* zero block length and PDC mode */ - mr = at91_mci_read(host, AT91_MCI_MR) & 0x5fff; - mr |= (data->blksz & 0x3) ? AT91_MCI_PDCFBYTE : 0; - mr |= (block_length << 16); - mr |= AT91_MCI_PDCMODE; - at91_mci_write(host, AT91_MCI_MR, mr); - - if (!(cpu_is_at91rm9200() || cpu_is_at91sam9261())) - at91_mci_write(host, AT91_MCI_BLKR, - AT91_MCI_BLKR_BCNT(blocks) | - AT91_MCI_BLKR_BLKLEN(block_length)); - - /* - * Disable the PDC controller - */ - at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); - - if (cmdr & AT91_MCI_TRCMD_START) { - data->bytes_xfered = 0; - host->transfer_index = 0; - host->in_use_index = 0; - if (cmdr & AT91_MCI_TRDIR) { - /* - * Handle a read - */ - host->total_length = 0; - - at91_mci_write(host, ATMEL_PDC_RPR, host->physical_address); - at91_mci_write(host, ATMEL_PDC_RCR, (data->blksz & 0x3) ? - (blocks * block_length) : (blocks * block_length) / 4); - at91_mci_write(host, ATMEL_PDC_RNPR, 0); - at91_mci_write(host, ATMEL_PDC_RNCR, 0); - - ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */; - } - else { - /* - * Handle a write - */ - host->total_length = block_length * blocks; - /* - * MCI1 rev2xx Data Write Operation and - * number of bytes erratum - */ - if (at91mci_is_mci1rev2xx()) - if (host->total_length < 12) - host->total_length = 12; - - at91_mci_sg_to_dma(host, data); - - pr_debug("Transmitting %d bytes\n", host->total_length); - - at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address); - at91_mci_write(host, ATMEL_PDC_TCR, (data->blksz & 0x3) ? - host->total_length : host->total_length / 4); - - ier = AT91_MCI_CMDRDY; - } - } - } - - /* - * Send the command and then enable the PDC - not the other way round as - * the data sheet says - */ - - at91_mci_write(host, AT91_MCI_ARGR, cmd->arg); - at91_mci_write(host, AT91_MCI_CMDR, cmdr); - - if (cmdr & AT91_MCI_TRCMD_START) { - if (cmdr & AT91_MCI_TRDIR) - at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); - } - - /* Enable selected interrupts */ - at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier); -} - -/* - * Process the next step in the request - */ -static void at91_mci_process_next(struct at91mci_host *host) -{ - if (!(host->flags & FL_SENT_COMMAND)) { - host->flags |= FL_SENT_COMMAND; - at91_mci_send_command(host, host->request->cmd); - } - else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) { - host->flags |= FL_SENT_STOP; - at91_mci_send_command(host, host->request->stop); - } else { - del_timer(&host->timer); - /* the at91rm9200 mci controller hangs after some transfers, - * and the workaround is to reset it after each transfer. - */ - if (cpu_is_at91rm9200()) - at91_reset_host(host); - mmc_request_done(host->mmc, host->request); - } -} - -/* - * Handle a command that has been completed - */ -static void at91_mci_completed_command(struct at91mci_host *host, unsigned int status) -{ - struct mmc_command *cmd = host->cmd; - struct mmc_data *data = cmd->data; - - at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB)); - - cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0)); - cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1)); - cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2)); - cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3)); - - pr_debug("Status = %08X/%08x [%08X %08X %08X %08X]\n", - status, at91_mci_read(host, AT91_MCI_SR), - cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); - - if (status & AT91_MCI_ERRORS) { - if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) { - cmd->error = 0; - } - else { - if (status & (AT91_MCI_DTOE | AT91_MCI_DCRCE)) { - if (data) { - if (status & AT91_MCI_DTOE) - data->error = -ETIMEDOUT; - else if (status & AT91_MCI_DCRCE) - data->error = -EILSEQ; - } - } else { - if (status & AT91_MCI_RTOE) - cmd->error = -ETIMEDOUT; - else if (status & AT91_MCI_RCRCE) - cmd->error = -EILSEQ; - else - cmd->error = -EIO; - } - - pr_debug("Error detected and set to %d/%d (cmd = %d, retries = %d)\n", - cmd->error, data ? data->error : 0, - cmd->opcode, cmd->retries); - } - } - else - cmd->error = 0; - - at91_mci_process_next(host); -} - -/* - * Handle an MMC request - */ -static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ - struct at91mci_host *host = mmc_priv(mmc); - host->request = mrq; - host->flags = 0; - - /* more than 1s timeout needed with slow SD cards */ - mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000)); - - at91_mci_process_next(host); -} - -/* - * Set the IOS - */ -static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ - int clkdiv; - struct at91mci_host *host = mmc_priv(mmc); - unsigned long at91_master_clock = clk_get_rate(host->mci_clk); - - host->bus_mode = ios->bus_mode; - - if (ios->clock == 0) { - /* Disable the MCI controller */ - at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS); - clkdiv = 0; - } - else { - /* Enable the MCI controller */ - at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN); - - if ((at91_master_clock % (ios->clock * 2)) == 0) - clkdiv = ((at91_master_clock / ios->clock) / 2) - 1; - else - clkdiv = (at91_master_clock / ios->clock) / 2; - - pr_debug("clkdiv = %d. mcck = %ld\n", clkdiv, - at91_master_clock / (2 * (clkdiv + 1))); - } - if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) { - pr_debug("MMC: Setting controller bus width to 4\n"); - at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) | AT91_MCI_SDCBUS); - } - else { - pr_debug("MMC: Setting controller bus width to 1\n"); - at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS); - } - - /* Set the clock divider */ - at91_mci_write(host, AT91_MCI_MR, (at91_mci_read(host, AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv); - - /* maybe switch power to the card */ - if (gpio_is_valid(host->board->vcc_pin)) { - switch (ios->power_mode) { - case MMC_POWER_OFF: - gpio_set_value(host->board->vcc_pin, 0); - break; - case MMC_POWER_UP: - gpio_set_value(host->board->vcc_pin, 1); - break; - case MMC_POWER_ON: - break; - default: - WARN_ON(1); - } - } -} - -/* - * Handle an interrupt - */ -static irqreturn_t at91_mci_irq(int irq, void *devid) -{ - struct at91mci_host *host = devid; - int completed = 0; - unsigned int int_status, int_mask; - - int_status = at91_mci_read(host, AT91_MCI_SR); - int_mask = at91_mci_read(host, AT91_MCI_IMR); - - pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask, - int_status & int_mask); - - int_status = int_status & int_mask; - - if (int_status & AT91_MCI_ERRORS) { - completed = 1; - - if (int_status & AT91_MCI_UNRE) - pr_debug("MMC: Underrun error\n"); - if (int_status & AT91_MCI_OVRE) - pr_debug("MMC: Overrun error\n"); - if (int_status & AT91_MCI_DTOE) - pr_debug("MMC: Data timeout\n"); - if (int_status & AT91_MCI_DCRCE) - pr_debug("MMC: CRC error in data\n"); - if (int_status & AT91_MCI_RTOE) - pr_debug("MMC: Response timeout\n"); - if (int_status & AT91_MCI_RENDE) - pr_debug("MMC: Response end bit error\n"); - if (int_status & AT91_MCI_RCRCE) - pr_debug("MMC: Response CRC error\n"); - if (int_status & AT91_MCI_RDIRE) - pr_debug("MMC: Response direction error\n"); - if (int_status & AT91_MCI_RINDE) - pr_debug("MMC: Response index error\n"); - } else { - /* Only continue processing if no errors */ - - if (int_status & AT91_MCI_TXBUFE) { - pr_debug("TX buffer empty\n"); - at91_mci_handle_transmitted(host); - } - - if (int_status & AT91_MCI_ENDRX) { - pr_debug("ENDRX\n"); - at91_mci_post_dma_read(host); - } - - if (int_status & AT91_MCI_RXBUFF) { - pr_debug("RX buffer full\n"); - at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); - at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_RXBUFF | AT91_MCI_ENDRX); - completed = 1; - } - - if (int_status & AT91_MCI_ENDTX) - pr_debug("Transmit has ended\n"); - - if (int_status & AT91_MCI_NOTBUSY) { - pr_debug("Card is ready\n"); - at91_mci_update_bytes_xfered(host); - completed = 1; - } - - if (int_status & AT91_MCI_DTIP) - pr_debug("Data transfer in progress\n"); - - if (int_status & AT91_MCI_BLKE) { - pr_debug("Block transfer has ended\n"); - if (host->request->data && host->request->data->blocks > 1) { - /* multi block write : complete multi write - * command and send stop */ - completed = 1; - } else { - at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY); - } - } - - if (int_status & AT91_MCI_SDIOIRQA) - mmc_signal_sdio_irq(host->mmc); - - if (int_status & AT91_MCI_SDIOIRQB) - mmc_signal_sdio_irq(host->mmc); - - if (int_status & AT91_MCI_TXRDY) - pr_debug("Ready to transmit\n"); - - if (int_status & AT91_MCI_RXRDY) - pr_debug("Ready to receive\n"); - - if (int_status & AT91_MCI_CMDRDY) { - pr_debug("Command ready\n"); - completed = at91_mci_handle_cmdrdy(host); - } - } - - if (completed) { - pr_debug("Completed command\n"); - at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB)); - at91_mci_completed_command(host, int_status); - } else - at91_mci_write(host, AT91_MCI_IDR, int_status & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB)); - - return IRQ_HANDLED; -} - -static irqreturn_t at91_mmc_det_irq(int irq, void *_host) -{ - struct at91mci_host *host = _host; - int present; - - /* entering this ISR means that we have configured det_pin: - * we can use its value in board structure */ - present = !gpio_get_value(host->board->det_pin); - - /* - * we expect this irq on both insert and remove, - * and use a short delay to debounce. - */ - if (present != host->present) { - host->present = present; - pr_debug("%s: card %s\n", mmc_hostname(host->mmc), - present ? "insert" : "remove"); - if (!present) { - pr_debug("****** Resetting SD-card bus width ******\n"); - at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS); - } - /* 0.5s needed because of early card detect switch firing */ - mmc_detect_change(host->mmc, msecs_to_jiffies(500)); - } - return IRQ_HANDLED; -} - -static int at91_mci_get_ro(struct mmc_host *mmc) -{ - struct at91mci_host *host = mmc_priv(mmc); - - if (gpio_is_valid(host->board->wp_pin)) - return !!gpio_get_value(host->board->wp_pin); - /* - * Board doesn't support read only detection; let the mmc core - * decide what to do. - */ - return -ENOSYS; -} - -static void at91_mci_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ - struct at91mci_host *host = mmc_priv(mmc); - - pr_debug("%s: sdio_irq %c : %s\n", mmc_hostname(host->mmc), - host->board->slot_b ? 'B':'A', enable ? "enable" : "disable"); - at91_mci_write(host, enable ? AT91_MCI_IER : AT91_MCI_IDR, - host->board->slot_b ? AT91_MCI_SDIOIRQB : AT91_MCI_SDIOIRQA); - -} - -static const struct mmc_host_ops at91_mci_ops = { - .request = at91_mci_request, - .set_ios = at91_mci_set_ios, - .get_ro = at91_mci_get_ro, - .enable_sdio_irq = at91_mci_enable_sdio_irq, -}; - -/* - * Probe for the device - */ -static int __init at91_mci_probe(struct platform_device *pdev) -{ - struct mmc_host *mmc; - struct at91mci_host *host; - struct resource *res; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENXIO; - - if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) - return -EBUSY; - - mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - dev_dbg(&pdev->dev, "couldn't allocate mmc host\n"); - goto fail6; - } - - mmc->ops = &at91_mci_ops; - mmc->f_min = 375000; - mmc->f_max = 25000000; - mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; - mmc->caps = 0; - - mmc->max_blk_size = MCI_MAXBLKSIZE; - mmc->max_blk_count = MCI_BLKATONCE; - mmc->max_req_size = MCI_BUFSIZE; - mmc->max_segs = MCI_BLKATONCE; - mmc->max_seg_size = MCI_BUFSIZE; - - host = mmc_priv(mmc); - host->mmc = mmc; - host->bus_mode = 0; - host->board = pdev->dev.platform_data; - if (host->board->wire4) { - if (at91mci_is_mci1rev2xx()) - mmc->caps |= MMC_CAP_4_BIT_DATA; - else - dev_warn(&pdev->dev, "4 wire bus mode not supported" - " - using 1 wire\n"); - } - - host->buffer = dma_alloc_coherent(&pdev->dev, MCI_BUFSIZE, - &host->physical_address, GFP_KERNEL); - if (!host->buffer) { - ret = -ENOMEM; - dev_err(&pdev->dev, "Can't allocate transmit buffer\n"); - goto fail5; - } - - /* Add SDIO capability when available */ - if (at91mci_is_mci1rev2xx()) { - /* at91mci MCI1 rev2xx sdio interrupt erratum */ - if (host->board->wire4 || !host->board->slot_b) - mmc->caps |= MMC_CAP_SDIO_IRQ; - } - - /* - * Reserve GPIOs ... board init code makes sure these pins are set - * up as GPIOs with the right direction (input, except for vcc) - */ - if (gpio_is_valid(host->board->det_pin)) { - ret = gpio_request(host->board->det_pin, "mmc_detect"); - if (ret < 0) { - dev_dbg(&pdev->dev, "couldn't claim card detect pin\n"); - goto fail4b; - } - } - if (gpio_is_valid(host->board->wp_pin)) { - ret = gpio_request(host->board->wp_pin, "mmc_wp"); - if (ret < 0) { - dev_dbg(&pdev->dev, "couldn't claim wp sense pin\n"); - goto fail4; - } - } - if (gpio_is_valid(host->board->vcc_pin)) { - ret = gpio_request(host->board->vcc_pin, "mmc_vcc"); - if (ret < 0) { - dev_dbg(&pdev->dev, "couldn't claim vcc switch pin\n"); - goto fail3; - } - } - - /* - * Get Clock - */ - host->mci_clk = clk_get(&pdev->dev, "mci_clk"); - if (IS_ERR(host->mci_clk)) { - ret = -ENODEV; - dev_dbg(&pdev->dev, "no mci_clk?\n"); - goto fail2; - } - - /* - * Map I/O region - */ - host->baseaddr = ioremap(res->start, resource_size(res)); - if (!host->baseaddr) { - ret = -ENOMEM; - goto fail1; - } - - /* - * Reset hardware - */ - clk_enable(host->mci_clk); /* Enable the peripheral clock */ - at91_mci_disable(host); - at91_mci_enable(host); - - /* - * Allocate the MCI interrupt - */ - host->irq = platform_get_irq(pdev, 0); - ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED, - mmc_hostname(mmc), host); - if (ret) { - dev_dbg(&pdev->dev, "request MCI interrupt failed\n"); - goto fail0; - } - - setup_timer(&host->timer, at91_timeout_timer, (unsigned long)host); - - platform_set_drvdata(pdev, mmc); - - /* - * Add host to MMC layer - */ - if (gpio_is_valid(host->board->det_pin)) { - host->present = !gpio_get_value(host->board->det_pin); - } - else - host->present = -1; - - mmc_add_host(mmc); - - /* - * monitor card insertion/removal if we can - */ - if (gpio_is_valid(host->board->det_pin)) { - ret = request_irq(gpio_to_irq(host->board->det_pin), - at91_mmc_det_irq, 0, mmc_hostname(mmc), host); - if (ret) - dev_warn(&pdev->dev, "request MMC detect irq failed\n"); - else - device_init_wakeup(&pdev->dev, 1); - } - - pr_debug("Added MCI driver\n"); - - return 0; - -fail0: - clk_disable(host->mci_clk); - iounmap(host->baseaddr); -fail1: - clk_put(host->mci_clk); -fail2: - if (gpio_is_valid(host->board->vcc_pin)) - gpio_free(host->board->vcc_pin); -fail3: - if (gpio_is_valid(host->board->wp_pin)) - gpio_free(host->board->wp_pin); -fail4: - if (gpio_is_valid(host->board->det_pin)) - gpio_free(host->board->det_pin); -fail4b: - if (host->buffer) - dma_free_coherent(&pdev->dev, MCI_BUFSIZE, - host->buffer, host->physical_address); -fail5: - mmc_free_host(mmc); -fail6: - release_mem_region(res->start, resource_size(res)); - dev_err(&pdev->dev, "probe failed, err %d\n", ret); - return ret; -} - -/* - * Remove a device - */ -static int __exit at91_mci_remove(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct at91mci_host *host; - struct resource *res; - - if (!mmc) - return -1; - - host = mmc_priv(mmc); - - if (host->buffer) - dma_free_coherent(&pdev->dev, MCI_BUFSIZE, - host->buffer, host->physical_address); - - if (gpio_is_valid(host->board->det_pin)) { - if (device_can_wakeup(&pdev->dev)) - free_irq(gpio_to_irq(host->board->det_pin), host); - device_init_wakeup(&pdev->dev, 0); - gpio_free(host->board->det_pin); - } - - at91_mci_disable(host); - del_timer_sync(&host->timer); - mmc_remove_host(mmc); - free_irq(host->irq, host); - - clk_disable(host->mci_clk); /* Disable the peripheral clock */ - clk_put(host->mci_clk); - - if (gpio_is_valid(host->board->vcc_pin)) - gpio_free(host->board->vcc_pin); - if (gpio_is_valid(host->board->wp_pin)) - gpio_free(host->board->wp_pin); - - iounmap(host->baseaddr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - - mmc_free_host(mmc); - platform_set_drvdata(pdev, NULL); - pr_debug("MCI Removed\n"); - - return 0; -} - -#ifdef CONFIG_PM -static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct at91mci_host *host = mmc_priv(mmc); - int ret = 0; - - if (gpio_is_valid(host->board->det_pin) && device_may_wakeup(&pdev->dev)) - enable_irq_wake(host->board->det_pin); - - if (mmc) - ret = mmc_suspend_host(mmc); - - return ret; -} - -static int at91_mci_resume(struct platform_device *pdev) -{ - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct at91mci_host *host = mmc_priv(mmc); - int ret = 0; - - if (gpio_is_valid(host->board->det_pin) && device_may_wakeup(&pdev->dev)) - disable_irq_wake(host->board->det_pin); - - if (mmc) - ret = mmc_resume_host(mmc); - - return ret; -} -#else -#define at91_mci_suspend NULL -#define at91_mci_resume NULL -#endif - -static struct platform_driver at91_mci_driver = { - .remove = __exit_p(at91_mci_remove), - .suspend = at91_mci_suspend, - .resume = at91_mci_resume, - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, -}; - -static int __init at91_mci_init(void) -{ - return platform_driver_probe(&at91_mci_driver, at91_mci_probe); -} - -static void __exit at91_mci_exit(void) -{ - platform_driver_unregister(&at91_mci_driver); -} - -module_init(at91_mci_init); -module_exit(at91_mci_exit); - -MODULE_DESCRIPTION("AT91 Multimedia Card Interface driver"); -MODULE_AUTHOR("Nick Randell"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:at91_mci"); diff --git a/drivers/mmc/host/at91_mci.h b/drivers/mmc/host/at91_mci.h deleted file mode 100644 index eec3a6b1c2b..00000000000 --- a/drivers/mmc/host/at91_mci.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * drivers/mmc/host/at91_mci.h - * - * Copyright (C) 2005 Ivan Kokshaysky - * Copyright (C) SAN People - * - * MultiMedia Card Interface (MCI) registers. - * Based on AT91RM9200 datasheet revision F. - * - * 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. - */ - -#ifndef AT91_MCI_H -#define AT91_MCI_H - -#define AT91_MCI_CR 0x00 /* Control Register */ -#define AT91_MCI_MCIEN (1 << 0) /* Multi-Media Interface Enable */ -#define AT91_MCI_MCIDIS (1 << 1) /* Multi-Media Interface Disable */ -#define AT91_MCI_PWSEN (1 << 2) /* Power Save Mode Enable */ -#define AT91_MCI_PWSDIS (1 << 3) /* Power Save Mode Disable */ -#define AT91_MCI_SWRST (1 << 7) /* Software Reset */ - -#define AT91_MCI_MR 0x04 /* Mode Register */ -#define AT91_MCI_CLKDIV (0xff << 0) /* Clock Divider */ -#define AT91_MCI_PWSDIV (7 << 8) /* Power Saving Divider */ -#define AT91_MCI_RDPROOF (1 << 11) /* Read Proof Enable [SAM926[03] only] */ -#define AT91_MCI_WRPROOF (1 << 12) /* Write Proof Enable [SAM926[03] only] */ -#define AT91_MCI_PDCFBYTE (1 << 13) /* PDC Force Byte Transfer [SAM926[03] only] */ -#define AT91_MCI_PDCPADV (1 << 14) /* PDC Padding Value */ -#define AT91_MCI_PDCMODE (1 << 15) /* PDC-orientated Mode */ -#define AT91_MCI_BLKLEN (0xfff << 18) /* Data Block Length */ - -#define AT91_MCI_DTOR 0x08 /* Data Timeout Register */ -#define AT91_MCI_DTOCYC (0xf << 0) /* Data Timeout Cycle Number */ -#define AT91_MCI_DTOMUL (7 << 4) /* Data Timeout Multiplier */ -#define AT91_MCI_DTOMUL_1 (0 << 4) -#define AT91_MCI_DTOMUL_16 (1 << 4) -#define AT91_MCI_DTOMUL_128 (2 << 4) -#define AT91_MCI_DTOMUL_256 (3 << 4) -#define AT91_MCI_DTOMUL_1K (4 << 4) -#define AT91_MCI_DTOMUL_4K (5 << 4) -#define AT91_MCI_DTOMUL_64K (6 << 4) -#define AT91_MCI_DTOMUL_1M (7 << 4) - -#define AT91_MCI_SDCR 0x0c /* SD Card Register */ -#define AT91_MCI_SDCSEL (3 << 0) /* SD Card Selector */ -#define AT91_MCI_SDCBUS (1 << 7) /* 1-bit or 4-bit bus */ - -#define AT91_MCI_ARGR 0x10 /* Argument Register */ - -#define AT91_MCI_CMDR 0x14 /* Command Register */ -#define AT91_MCI_CMDNB (0x3f << 0) /* Command Number */ -#define AT91_MCI_RSPTYP (3 << 6) /* Response Type */ -#define AT91_MCI_RSPTYP_NONE (0 << 6) -#define AT91_MCI_RSPTYP_48 (1 << 6) -#define AT91_MCI_RSPTYP_136 (2 << 6) -#define AT91_MCI_SPCMD (7 << 8) /* Special Command */ -#define AT91_MCI_SPCMD_NONE (0 << 8) -#define AT91_MCI_SPCMD_INIT (1 << 8) -#define AT91_MCI_SPCMD_SYNC (2 << 8) -#define AT91_MCI_SPCMD_ICMD (4 << 8) -#define AT91_MCI_SPCMD_IRESP (5 << 8) -#define AT91_MCI_OPDCMD (1 << 11) /* Open Drain Command */ -#define AT91_MCI_MAXLAT (1 << 12) /* Max Latency for Command to Response */ -#define AT91_MCI_TRCMD (3 << 16) /* Transfer Command */ -#define AT91_MCI_TRCMD_NONE (0 << 16) -#define AT91_MCI_TRCMD_START (1 << 16) -#define AT91_MCI_TRCMD_STOP (2 << 16) -#define AT91_MCI_TRDIR (1 << 18) /* Transfer Direction */ -#define AT91_MCI_TRTYP (3 << 19) /* Transfer Type */ -#define AT91_MCI_TRTYP_BLOCK (0 << 19) -#define AT91_MCI_TRTYP_MULTIPLE (1 << 19) -#define AT91_MCI_TRTYP_STREAM (2 << 19) -#define AT91_MCI_TRTYP_SDIO_BYTE (4 << 19) -#define AT91_MCI_TRTYP_SDIO_BLOCK (5 << 19) - -#define AT91_MCI_BLKR 0x18 /* Block Register */ -#define AT91_MCI_BLKR_BCNT(n) ((0xffff & (n)) << 0) /* Block count */ -#define AT91_MCI_BLKR_BLKLEN(n) ((0xffff & (n)) << 16) /* Block length */ - -#define AT91_MCI_RSPR(n) (0x20 + ((n) * 4)) /* Response Registers 0-3 */ -#define AT91_MCR_RDR 0x30 /* Receive Data Register */ -#define AT91_MCR_TDR 0x34 /* Transmit Data Register */ - -#define AT91_MCI_SR 0x40 /* Status Register */ -#define AT91_MCI_CMDRDY (1 << 0) /* Command Ready */ -#define AT91_MCI_RXRDY (1 << 1) /* Receiver Ready */ -#define AT91_MCI_TXRDY (1 << 2) /* Transmit Ready */ -#define AT91_MCI_BLKE (1 << 3) /* Data Block Ended */ -#define AT91_MCI_DTIP (1 << 4) /* Data Transfer in Progress */ -#define AT91_MCI_NOTBUSY (1 << 5) /* Data Not Busy */ -#define AT91_MCI_ENDRX (1 << 6) /* End of RX Buffer */ -#define AT91_MCI_ENDTX (1 << 7) /* End fo TX Buffer */ -#define AT91_MCI_SDIOIRQA (1 << 8) /* SDIO Interrupt for Slot A */ -#define AT91_MCI_SDIOIRQB (1 << 9) /* SDIO Interrupt for Slot B */ -#define AT91_MCI_RXBUFF (1 << 14) /* RX Buffer Full */ -#define AT91_MCI_TXBUFE (1 << 15) /* TX Buffer Empty */ -#define AT91_MCI_RINDE (1 << 16) /* Response Index Error */ -#define AT91_MCI_RDIRE (1 << 17) /* Response Direction Error */ -#define AT91_MCI_RCRCE (1 << 18) /* Response CRC Error */ -#define AT91_MCI_RENDE (1 << 19) /* Response End Bit Error */ -#define AT91_MCI_RTOE (1 << 20) /* Response Time-out Error */ -#define AT91_MCI_DCRCE (1 << 21) /* Data CRC Error */ -#define AT91_MCI_DTOE (1 << 22) /* Data Time-out Error */ -#define AT91_MCI_OVRE (1 << 30) /* Overrun */ -#define AT91_MCI_UNRE (1 << 31) /* Underrun */ - -#define AT91_MCI_IER 0x44 /* Interrupt Enable Register */ -#define AT91_MCI_IDR 0x48 /* Interrupt Disable Register */ -#define AT91_MCI_IMR 0x4c /* Interrupt Mask Register */ - -#endif diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index ddf096e3803..5248ba4369a 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -511,7 +511,7 @@ static const struct of_device_id atmci_dt_ids[] = { MODULE_DEVICE_TABLE(of, atmci_dt_ids); -static struct mci_platform_data __devinit* +static struct mci_platform_data* atmci_of_init(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index dbd0c8a4e98..127a8fade4d 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -943,7 +943,7 @@ static const struct mmc_host_ops au1xmmc_ops = { .enable_sdio_irq = au1xmmc_enable_sdio_irq, }; -static int __devinit au1xmmc_probe(struct platform_device *pdev) +static int au1xmmc_probe(struct platform_device *pdev) { struct mmc_host *mmc; struct au1xmmc_host *host; @@ -1114,7 +1114,7 @@ out0: return ret; } -static int __devexit au1xmmc_remove(struct platform_device *pdev) +static int au1xmmc_remove(struct platform_device *pdev) { struct au1xmmc_host *host = platform_get_drvdata(pdev); diff --git a/drivers/mmc/host/bfin_sdh.c b/drivers/mmc/host/bfin_sdh.c index b9b463eca1e..fb4348c5b6a 100644 --- a/drivers/mmc/host/bfin_sdh.c +++ b/drivers/mmc/host/bfin_sdh.c @@ -522,7 +522,7 @@ static void sdh_reset(void) SSYNC(); } -static int __devinit sdh_probe(struct platform_device *pdev) +static int sdh_probe(struct platform_device *pdev) { struct mmc_host *mmc; struct sdh_host *host; @@ -617,7 +617,7 @@ out1: return ret; } -static int __devexit sdh_remove(struct platform_device *pdev) +static int sdh_remove(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); @@ -680,7 +680,7 @@ static int sdh_resume(struct platform_device *dev) static struct platform_driver sdh_driver = { .probe = sdh_probe, - .remove = __devexit_p(sdh_remove), + .remove = sdh_remove, .suspend = sdh_suspend, .resume = sdh_resume, .driver = { diff --git a/drivers/mmc/host/cb710-mmc.c b/drivers/mmc/host/cb710-mmc.c index 83693fd7c6b..777ca2046b2 100644 --- a/drivers/mmc/host/cb710-mmc.c +++ b/drivers/mmc/host/cb710-mmc.c @@ -690,7 +690,7 @@ static int cb710_mmc_resume(struct platform_device *pdev) #endif /* CONFIG_PM */ -static int __devinit cb710_mmc_init(struct platform_device *pdev) +static int cb710_mmc_init(struct platform_device *pdev) { struct cb710_slot *slot = cb710_pdev_to_slot(pdev); struct cb710_chip *chip = cb710_slot_to_chip(slot); @@ -746,7 +746,7 @@ err_free_mmc: return err; } -static int __devexit cb710_mmc_exit(struct platform_device *pdev) +static int cb710_mmc_exit(struct platform_device *pdev) { struct cb710_slot *slot = cb710_pdev_to_slot(pdev); struct mmc_host *mmc = cb710_slot_to_mmc(slot); @@ -773,7 +773,7 @@ static int __devexit cb710_mmc_exit(struct platform_device *pdev) static struct platform_driver cb710_mmc_driver = { .driver.name = "cb710-mmc", .probe = cb710_mmc_init, - .remove = __devexit_p(cb710_mmc_exit), + .remove = cb710_mmc_exit, #ifdef CONFIG_PM .suspend = cb710_mmc_suspend, .resume = cb710_mmc_resume, diff --git a/drivers/mmc/host/dw_mmc-pci.c b/drivers/mmc/host/dw_mmc-pci.c index edb37e9135a..8ee0f74f937 100644 --- a/drivers/mmc/host/dw_mmc-pci.c +++ b/drivers/mmc/host/dw_mmc-pci.c @@ -37,7 +37,7 @@ static struct dw_mci_board pci_board_data = { .fifo_depth = 32, }; -static int __devinit dw_mci_pci_probe(struct pci_dev *pdev, +static int dw_mci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *entries) { struct dw_mci *host; @@ -85,7 +85,7 @@ err_disable_dev: return ret; } -static void __devexit dw_mci_pci_remove(struct pci_dev *pdev) +static void dw_mci_pci_remove(struct pci_dev *pdev) { struct dw_mci *host = pci_get_drvdata(pdev); @@ -134,7 +134,7 @@ static struct pci_driver dw_mci_pci_driver = { .name = "dw_mmc_pci", .id_table = dw_mci_pci_id, .probe = dw_mci_pci_probe, - .remove = dw_mci_pci_remove, + .remove = __devexit_p(dw_mci_pci_remove), .driver = { .pm = &dw_mci_pci_pmops }, diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index 917936bee5d..222036c9e05 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c @@ -62,12 +62,12 @@ int dw_mci_pltfm_register(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(dw_mci_pltfm_register); -static int __devinit dw_mci_pltfm_probe(struct platform_device *pdev) +static int dw_mci_pltfm_probe(struct platform_device *pdev) { return dw_mci_pltfm_register(pdev, NULL); } -static int __devexit dw_mci_pltfm_remove(struct platform_device *pdev) +static int dw_mci_pltfm_remove(struct platform_device *pdev) { struct dw_mci *host = platform_get_drvdata(pdev); @@ -119,7 +119,8 @@ static const struct of_device_id dw_mci_pltfm_match[] = { MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match); static struct platform_driver dw_mci_pltfm_driver = { - .remove = __exit_p(dw_mci_pltfm_remove), + .probe = dw_mci_pltfm_probe, + .remove = __devexit_p(dw_mci_pltfm_remove), .driver = { .name = "dw_mmc", .of_match_table = of_match_ptr(dw_mci_pltfm_match), @@ -127,18 +128,7 @@ static struct platform_driver dw_mci_pltfm_driver = { }, }; -static int __init dw_mci_init(void) -{ - return platform_driver_probe(&dw_mci_pltfm_driver, dw_mci_pltfm_probe); -} - -static void __exit dw_mci_exit(void) -{ - platform_driver_unregister(&dw_mci_pltfm_driver); -} - -module_init(dw_mci_init); -module_exit(dw_mci_exit); +module_platform_driver(dw_mci_pltfm_driver); MODULE_DESCRIPTION("DW Multimedia Card Interface driver"); MODULE_AUTHOR("NXP Semiconductor VietNam"); diff --git a/drivers/mmc/host/dw_mmc-pltfm.h b/drivers/mmc/host/dw_mmc-pltfm.h index 2ac37b81de4..68e7fd2f614 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.h +++ b/drivers/mmc/host/dw_mmc-pltfm.h @@ -14,7 +14,7 @@ extern int dw_mci_pltfm_register(struct platform_device *pdev, const struct dw_mci_drv_data *drv_data); -extern int __devexit dw_mci_pltfm_remove(struct platform_device *pdev); +extern int dw_mci_pltfm_remove(struct platform_device *pdev); extern const struct dev_pm_ops dw_mci_pltfm_pmops; #endif /* _DW_MMC_PLTFM_H_ */ diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index c0667c8af2b..323c5022c2c 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -232,7 +232,7 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) { struct mmc_data *data; struct dw_mci_slot *slot = mmc_priv(mmc); - struct dw_mci_drv_data *drv_data = slot->host->drv_data; + const struct dw_mci_drv_data *drv_data = slot->host->drv_data; u32 cmdr; cmd->error = -EINPROGRESS; @@ -617,13 +617,13 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg) cmd, arg, cmd_status); } -static void dw_mci_setup_bus(struct dw_mci_slot *slot) +static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit) { struct dw_mci *host = slot->host; u32 div; u32 clk_en_a; - if (slot->clock != host->current_speed) { + if (slot->clock != host->current_speed || force_clkinit) { div = host->bus_hz / slot->clock; if (host->bus_hz % slot->clock && host->bus_hz > slot->clock) /* @@ -683,9 +683,6 @@ static void __dw_mci_start_request(struct dw_mci *host, if (host->pdata->select_slot) host->pdata->select_slot(slot->id); - /* Slot specific timing and width adjustment */ - dw_mci_setup_bus(slot); - host->cur_slot = slot; host->mrq = mrq; @@ -773,22 +770,19 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct dw_mci_slot *slot = mmc_priv(mmc); - struct dw_mci_drv_data *drv_data = slot->host->drv_data; + const struct dw_mci_drv_data *drv_data = slot->host->drv_data; u32 regs; - /* set default 1 bit mode */ - slot->ctype = SDMMC_CTYPE_1BIT; - switch (ios->bus_width) { - case MMC_BUS_WIDTH_1: - slot->ctype = SDMMC_CTYPE_1BIT; - break; case MMC_BUS_WIDTH_4: slot->ctype = SDMMC_CTYPE_4BIT; break; case MMC_BUS_WIDTH_8: slot->ctype = SDMMC_CTYPE_8BIT; break; + default: + /* set default 1 bit mode */ + slot->ctype = SDMMC_CTYPE_1BIT; } regs = mci_readl(slot->host, UHS_REG); @@ -812,6 +806,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (drv_data && drv_data->set_ios) drv_data->set_ios(slot->host, ios); + /* Slot specific timing and width adjustment */ + dw_mci_setup_bus(slot, false); + switch (ios->power_mode) { case MMC_POWER_UP: set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); @@ -1817,7 +1814,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) { struct mmc_host *mmc; struct dw_mci_slot *slot; - struct dw_mci_drv_data *drv_data = host->drv_data; + const struct dw_mci_drv_data *drv_data = host->drv_data; int ctrl_id, ret; u8 bus_width; @@ -1850,6 +1847,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) if (host->pdata->caps) mmc->caps = host->pdata->caps; + if (host->pdata->pm_caps) + mmc->pm_caps = host->pdata->pm_caps; + if (host->dev->of_node) { ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); if (ctrl_id < 0) @@ -1911,7 +1911,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) #endif /* CONFIG_MMC_DW_IDMAC */ } - host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); + host->vmmc = devm_regulator_get(mmc_dev(mmc), "vmmc"); if (IS_ERR(host->vmmc)) { pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); host->vmmc = NULL; @@ -1960,7 +1960,7 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) static void dw_mci_init_dma(struct dw_mci *host) { /* Alloc memory for sg translation */ - host->sg_cpu = dma_alloc_coherent(host->dev, PAGE_SIZE, + host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); if (!host->sg_cpu) { dev_err(host->dev, "%s: could not alloc DMA memory\n", @@ -2038,7 +2038,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) struct dw_mci_board *pdata; struct device *dev = host->dev; struct device_node *np = dev->of_node; - struct dw_mci_drv_data *drv_data = host->drv_data; + const struct dw_mci_drv_data *drv_data = host->drv_data; int idx, ret; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); @@ -2072,6 +2072,12 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) return ERR_PTR(ret); } + if (of_find_property(np, "keep-power-in-suspend", NULL)) + pdata->pm_caps |= MMC_PM_KEEP_POWER; + + if (of_find_property(np, "enable-sdio-wakeup", NULL)) + pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; + return pdata; } @@ -2084,7 +2090,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) int dw_mci_probe(struct dw_mci *host) { - struct dw_mci_drv_data *drv_data = host->drv_data; + const struct dw_mci_drv_data *drv_data = host->drv_data; int width, i, ret = 0; u32 fifo_size; int init_slots = 0; @@ -2103,26 +2109,24 @@ int dw_mci_probe(struct dw_mci *host) return -ENODEV; } - host->biu_clk = clk_get(host->dev, "biu"); + host->biu_clk = devm_clk_get(host->dev, "biu"); if (IS_ERR(host->biu_clk)) { dev_dbg(host->dev, "biu clock not available\n"); } else { ret = clk_prepare_enable(host->biu_clk); if (ret) { dev_err(host->dev, "failed to enable biu clock\n"); - clk_put(host->biu_clk); return ret; } } - host->ciu_clk = clk_get(host->dev, "ciu"); + host->ciu_clk = devm_clk_get(host->dev, "ciu"); if (IS_ERR(host->ciu_clk)) { dev_dbg(host->dev, "ciu clock not available\n"); } else { ret = clk_prepare_enable(host->ciu_clk); if (ret) { dev_err(host->dev, "failed to enable ciu clock\n"); - clk_put(host->ciu_clk); goto err_clk_biu; } } @@ -2224,7 +2228,8 @@ int dw_mci_probe(struct dw_mci *host) if (!host->card_workqueue) goto err_dmaunmap; INIT_WORK(&host->card_work, dw_mci_work_routine_card); - ret = request_irq(host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host); + ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, + host->irq_flags, "dw-mci", host); if (ret) goto err_workqueue; @@ -2262,7 +2267,7 @@ int dw_mci_probe(struct dw_mci *host) } else { dev_dbg(host->dev, "attempted to initialize %d slots, " "but failed on all\n", host->num_slots); - goto err_init_slot; + goto err_workqueue; } /* @@ -2282,33 +2287,24 @@ int dw_mci_probe(struct dw_mci *host) return 0; -err_init_slot: - free_irq(host->irq, host); - err_workqueue: destroy_workqueue(host->card_workqueue); err_dmaunmap: if (host->use_dma && host->dma_ops->exit) host->dma_ops->exit(host); - dma_free_coherent(host->dev, PAGE_SIZE, - host->sg_cpu, host->sg_dma); - if (host->vmmc) { + if (host->vmmc) regulator_disable(host->vmmc); - regulator_put(host->vmmc); - } err_clk_ciu: - if (!IS_ERR(host->ciu_clk)) { + if (!IS_ERR(host->ciu_clk)) clk_disable_unprepare(host->ciu_clk); - clk_put(host->ciu_clk); - } + err_clk_biu: - if (!IS_ERR(host->biu_clk)) { + if (!IS_ERR(host->biu_clk)) clk_disable_unprepare(host->biu_clk); - clk_put(host->biu_clk); - } + return ret; } EXPORT_SYMBOL(dw_mci_probe); @@ -2330,24 +2326,19 @@ void dw_mci_remove(struct dw_mci *host) mci_writel(host, CLKENA, 0); mci_writel(host, CLKSRC, 0); - free_irq(host->irq, host); destroy_workqueue(host->card_workqueue); - dma_free_coherent(host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); if (host->use_dma && host->dma_ops->exit) host->dma_ops->exit(host); - if (host->vmmc) { + if (host->vmmc) regulator_disable(host->vmmc); - regulator_put(host->vmmc); - } if (!IS_ERR(host->ciu_clk)) clk_disable_unprepare(host->ciu_clk); + if (!IS_ERR(host->biu_clk)) clk_disable_unprepare(host->biu_clk); - clk_put(host->ciu_clk); - clk_put(host->biu_clk); } EXPORT_SYMBOL(dw_mci_remove); @@ -2411,6 +2402,11 @@ int dw_mci_resume(struct dw_mci *host) struct dw_mci_slot *slot = host->slot[i]; if (!slot) continue; + if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) { + dw_mci_set_ios(slot->mmc, &slot->mmc->ios); + dw_mci_setup_bus(slot, true); + } + ret = mmc_resume_host(host->slot[i]->mmc); if (ret < 0) return ret; diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index c8852a8128a..2391c6b7a4b 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -702,7 +702,7 @@ static const struct jz_gpio_bulk_request jz4740_mmc_pins[] = { JZ_GPIO_BULK_PIN(MSC_DATA3), }; -static int __devinit jz4740_mmc_request_gpio(struct device *dev, int gpio, +static int jz4740_mmc_request_gpio(struct device *dev, int gpio, const char *name, bool output, int value) { int ret; @@ -724,7 +724,7 @@ static int __devinit jz4740_mmc_request_gpio(struct device *dev, int gpio, return 0; } -static int __devinit jz4740_mmc_request_gpios(struct platform_device *pdev) +static int jz4740_mmc_request_gpios(struct platform_device *pdev) { int ret; struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data; @@ -759,7 +759,7 @@ err: return ret; } -static int __devinit jz4740_mmc_request_cd_irq(struct platform_device *pdev, +static int jz4740_mmc_request_cd_irq(struct platform_device *pdev, struct jz4740_mmc_host *host) { struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data; @@ -802,7 +802,7 @@ static inline size_t jz4740_mmc_num_pins(struct jz4740_mmc_host *host) return num_pins; } -static int __devinit jz4740_mmc_probe(struct platform_device* pdev) +static int jz4740_mmc_probe(struct platform_device* pdev) { int ret; struct mmc_host *mmc; @@ -938,7 +938,7 @@ err_free_host: return ret; } -static int __devexit jz4740_mmc_remove(struct platform_device *pdev) +static int jz4740_mmc_remove(struct platform_device *pdev) { struct jz4740_mmc_host *host = platform_get_drvdata(pdev); @@ -1004,7 +1004,7 @@ const struct dev_pm_ops jz4740_mmc_pm_ops = { static struct platform_driver jz4740_mmc_driver = { .probe = jz4740_mmc_probe, - .remove = __devexit_p(jz4740_mmc_remove), + .remove = jz4740_mmc_remove, .driver = { .name = "jz4740-mmc", .owner = THIS_MODULE, diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index a600eabbd6c..74145d1d51f 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1485,7 +1485,7 @@ nomem: } -static int __devexit mmc_spi_remove(struct spi_device *spi) +static int mmc_spi_remove(struct spi_device *spi) { struct mmc_host *mmc = dev_get_drvdata(&spi->dev); struct mmc_spi_host *host; @@ -1517,7 +1517,7 @@ static int __devexit mmc_spi_remove(struct spi_device *spi) return 0; } -static struct of_device_id mmc_spi_of_match_table[] __devinitdata = { +static struct of_device_id mmc_spi_of_match_table[] = { { .compatible = "mmc-spi-slot", }, {}, }; @@ -1529,7 +1529,7 @@ static struct spi_driver mmc_spi_driver = { .of_match_table = mmc_spi_of_match_table, }, .probe = mmc_spi_probe, - .remove = __devexit_p(mmc_spi_remove), + .remove = mmc_spi_remove, }; module_spi_driver(mmc_spi_driver); diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index edc3e9baf0e..ec28d175d9c 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -261,7 +261,7 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) * no custom DMA interfaces are supported. */ #ifdef CONFIG_DMA_ENGINE -static void __devinit mmci_dma_setup(struct mmci_host *host) +static void mmci_dma_setup(struct mmci_host *host) { struct mmci_platform_data *plat = host->plat; const char *rxname, *txname; @@ -337,7 +337,7 @@ static void __devinit mmci_dma_setup(struct mmci_host *host) } /* - * This is used in __devinit or __devexit so inline it + * This is used in or so inline it * so it can be discarded. */ static inline void mmci_dma_release(struct mmci_host *host) @@ -1255,7 +1255,7 @@ static void mmci_dt_populate_generic_pdata(struct device_node *np, } #endif -static int __devinit mmci_probe(struct amba_device *dev, +static int mmci_probe(struct amba_device *dev, const struct amba_id *id) { struct mmci_platform_data *plat = dev->dev.platform_data; @@ -1522,7 +1522,7 @@ static int __devinit mmci_probe(struct amba_device *dev, return ret; } -static int __devexit mmci_remove(struct amba_device *dev) +static int mmci_remove(struct amba_device *dev) { struct mmc_host *mmc = amba_get_drvdata(dev); @@ -1669,7 +1669,7 @@ static struct amba_driver mmci_driver = { .pm = &mmci_dev_pm_ops, }, .probe = mmci_probe, - .remove = __devexit_p(mmci_remove), + .remove = mmci_remove, .id_table = mmci_ids, }; diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 6290b7f1ccf..29e680f193a 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -240,7 +240,7 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) return 0; for_each_sg(data->sg, sg, data->sg_len, i) { - if (sg->offset & 3 || sg->length & 3) { + if (sg->offset & 3 || sg->length & 3 || sg->length < 512) { host->do_dma = 0; return 0; } diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index 80d1e6d4b0a..206fe499ded 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -43,7 +43,6 @@ #include <linux/module.h> #include <linux/pinctrl/consumer.h> #include <linux/stmp_device.h> -#include <linux/mmc/mxs-mmc.h> #include <linux/spi/mxs-spi.h> #define DRIVER_NAME "mxs-mmc" @@ -593,13 +592,13 @@ static int mxs_mmc_probe(struct platform_device *pdev) struct mxs_mmc_host *host; struct mmc_host *mmc; struct resource *iores, *dmares; - struct mxs_mmc_platform_data *pdata; struct pinctrl *pinctrl; int ret = 0, irq_err, irq_dma; dma_cap_mask_t mask; struct regulator *reg_vmmc; enum of_gpio_flags flags; struct mxs_ssp *ssp; + u32 bus_width = 0; iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); @@ -682,25 +681,15 @@ static int mxs_mmc_probe(struct platform_device *pdev) mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL; - pdata = mmc_dev(host->mmc)->platform_data; - if (!pdata) { - u32 bus_width = 0; - of_property_read_u32(np, "bus-width", &bus_width); - if (bus_width == 4) - mmc->caps |= MMC_CAP_4_BIT_DATA; - else if (bus_width == 8) - mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; - host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, - &flags); - if (flags & OF_GPIO_ACTIVE_LOW) - host->wp_inverted = 1; - } else { - if (pdata->flags & SLOTF_8_BIT_CAPABLE) - mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; - if (pdata->flags & SLOTF_4_BIT_CAPABLE) - mmc->caps |= MMC_CAP_4_BIT_DATA; - host->wp_gpio = pdata->wp_gpio; - } + of_property_read_u32(np, "bus-width", &bus_width); + if (bus_width == 4) + mmc->caps |= MMC_CAP_4_BIT_DATA; + else if (bus_width == 8) + mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; + host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags); + + if (flags & OF_GPIO_ACTIVE_LOW) + host->wp_inverted = 1; mmc->f_min = 400000; mmc->f_max = 288000000; diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 48ad361613e..4e749ab690c 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1214,7 +1214,7 @@ static const struct mmc_host_ops mmc_omap_ops = { .set_ios = mmc_omap_set_ios, }; -static int __devinit mmc_omap_new_slot(struct mmc_omap_host *host, int id) +static int mmc_omap_new_slot(struct mmc_omap_host *host, int id) { struct mmc_omap_slot *slot = NULL; struct mmc_host *mmc; @@ -1309,7 +1309,7 @@ static void mmc_omap_remove_slot(struct mmc_omap_slot *slot) mmc_free_host(mmc); } -static int __devinit mmc_omap_probe(struct platform_device *pdev) +static int mmc_omap_probe(struct platform_device *pdev) { struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; struct mmc_omap_host *host = NULL; @@ -1478,7 +1478,7 @@ err_free_mem_region: return ret; } -static int __devexit mmc_omap_remove(struct platform_device *pdev) +static int mmc_omap_remove(struct platform_device *pdev) { struct mmc_omap_host *host = platform_get_drvdata(pdev); int i; @@ -1566,7 +1566,7 @@ static int mmc_omap_resume(struct platform_device *pdev) static struct platform_driver mmc_omap_driver = { .probe = mmc_omap_probe, - .remove = __devexit_p(mmc_omap_remove), + .remove = mmc_omap_remove, .suspend = mmc_omap_suspend, .resume = mmc_omap_resume, .driver = { diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index fedd258cc4e..e1f3c1135f9 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -37,6 +37,7 @@ #include <linux/io.h> #include <linux/gpio.h> #include <linux/regulator/consumer.h> +#include <linux/pinctrl/consumer.h> #include <linux/pm_runtime.h> #include <mach/hardware.h> #include <plat/mmc.h> @@ -62,6 +63,7 @@ #define VS18 (1 << 26) #define VS30 (1 << 25) +#define HSS (1 << 21) #define SDVS18 (0x5 << 9) #define SDVS30 (0x6 << 9) #define SDVS33 (0x7 << 9) @@ -78,28 +80,17 @@ #define CLKD_SHIFT 6 #define DTO_MASK 0x000F0000 #define DTO_SHIFT 16 -#define INT_EN_MASK 0x307F0033 -#define BWR_ENABLE (1 << 4) -#define BRR_ENABLE (1 << 5) -#define DTO_ENABLE (1 << 20) #define INIT_STREAM (1 << 1) #define DP_SELECT (1 << 21) #define DDIR (1 << 4) -#define DMA_EN 0x1 +#define DMAE 0x1 #define MSBS (1 << 5) #define BCE (1 << 1) #define FOUR_BIT (1 << 1) +#define HSPE (1 << 2) #define DDR (1 << 19) #define DW8 (1 << 5) -#define CC 0x1 -#define TC 0x02 #define OD 0x1 -#define ERR (1 << 15) -#define CMD_TIMEOUT (1 << 16) -#define DATA_TIMEOUT (1 << 20) -#define CMD_CRC (1 << 17) -#define DATA_CRC (1 << 21) -#define CARD_ERR (1 << 28) #define STAT_CLEAR 0xFFFFFFFF #define INIT_STREAM_CMD 0x00000000 #define DUAL_VOLT_OCR_BIT 7 @@ -108,6 +99,26 @@ #define SOFTRESET (1 << 1) #define RESETDONE (1 << 0) +/* Interrupt masks for IE and ISE register */ +#define CC_EN (1 << 0) +#define TC_EN (1 << 1) +#define BWR_EN (1 << 4) +#define BRR_EN (1 << 5) +#define ERR_EN (1 << 15) +#define CTO_EN (1 << 16) +#define CCRC_EN (1 << 17) +#define CEB_EN (1 << 18) +#define CIE_EN (1 << 19) +#define DTO_EN (1 << 20) +#define DCRC_EN (1 << 21) +#define DEB_EN (1 << 22) +#define CERR_EN (1 << 28) +#define BADA_EN (1 << 29) + +#define INT_EN_MASK (BADA_EN | CERR_EN | DEB_EN | DCRC_EN |\ + DTO_EN | CIE_EN | CEB_EN | CCRC_EN | CTO_EN | \ + BRR_EN | BWR_EN | TC_EN | CC_EN) + #define MMC_AUTOSUSPEND_DELAY 100 #define MMC_TIMEOUT_MS 20 #define OMAP_MMC_MIN_CLOCK 400000 @@ -302,7 +313,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) reg = regulator_get(host->dev, "vmmc"); if (IS_ERR(reg)) { - dev_dbg(host->dev, "vmmc regulator missing\n"); + dev_err(host->dev, "vmmc regulator missing\n"); return PTR_ERR(reg); } else { mmc_slot(host).set_power = omap_hsmmc_set_power; @@ -455,13 +466,13 @@ static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host, unsigned int irq_mask; if (host->use_dma) - irq_mask = INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE); + irq_mask = INT_EN_MASK & ~(BRR_EN | BWR_EN); else irq_mask = INT_EN_MASK; /* Disable timeout for erases */ if (cmd->opcode == MMC_ERASE) - irq_mask &= ~DTO_ENABLE; + irq_mask &= ~DTO_EN; OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR); OMAP_HSMMC_WRITE(host->base, ISE, irq_mask); @@ -494,6 +505,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) struct mmc_ios *ios = &host->mmc->ios; unsigned long regval; unsigned long timeout; + unsigned long clkdiv; dev_vdbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock); @@ -501,7 +513,8 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) regval = OMAP_HSMMC_READ(host->base, SYSCTL); regval = regval & ~(CLKD_MASK | DTO_MASK); - regval = regval | (calc_divisor(host, ios) << 6) | (DTO << 16); + clkdiv = calc_divisor(host, ios); + regval = regval | (clkdiv << 6) | (DTO << 16); OMAP_HSMMC_WRITE(host->base, SYSCTL, regval); OMAP_HSMMC_WRITE(host->base, SYSCTL, OMAP_HSMMC_READ(host->base, SYSCTL) | ICE); @@ -512,6 +525,27 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host) && time_before(jiffies, timeout)) cpu_relax(); + /* + * Enable High-Speed Support + * Pre-Requisites + * - Controller should support High-Speed-Enable Bit + * - Controller should not be using DDR Mode + * - Controller should advertise that it supports High Speed + * in capabilities register + * - MMC/SD clock coming out of controller > 25MHz + */ + if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) && + (ios->timing != MMC_TIMING_UHS_DDR50) && + ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) { + regval = OMAP_HSMMC_READ(host->base, HCTL); + if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000) + regval |= HSPE; + else + regval &= ~HSPE; + + OMAP_HSMMC_WRITE(host->base, HCTL, regval); + } + omap_hsmmc_start_clock(host); } @@ -676,8 +710,8 @@ static void send_init_stream(struct omap_hsmmc_host *host) OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD); timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS); - while ((reg != CC) && time_before(jiffies, timeout)) - reg = OMAP_HSMMC_READ(host->base, STAT) & CC; + while ((reg != CC_EN) && time_before(jiffies, timeout)) + reg = OMAP_HSMMC_READ(host->base, STAT) & CC_EN; OMAP_HSMMC_WRITE(host->base, CON, OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM); @@ -768,7 +802,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd, } if (host->use_dma) - cmdreg |= DMA_EN; + cmdreg |= DMAE; host->req_in_progress = 1; @@ -968,16 +1002,20 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, __func__); } -static void hsmmc_command_incomplete(struct omap_hsmmc_host *host, int err) +static void hsmmc_command_incomplete(struct omap_hsmmc_host *host, + int err, int end_cmd) { - omap_hsmmc_reset_controller_fsm(host, SRC); - host->cmd->error = err; + if (end_cmd) { + omap_hsmmc_reset_controller_fsm(host, SRC); + if (host->cmd) + host->cmd->error = err; + } if (host->data) { omap_hsmmc_reset_controller_fsm(host, SRD); omap_hsmmc_dma_cleanup(host, err); - } - + } else if (host->mrq && host->mrq->cmd) + host->mrq->cmd->error = err; } static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) @@ -988,23 +1026,25 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) data = host->data; dev_vdbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status); - if (status & ERR) { + if (status & ERR_EN) { omap_hsmmc_dbg_report_irq(host, status); - if (status & (CMD_TIMEOUT | DATA_TIMEOUT)) - hsmmc_command_incomplete(host, -ETIMEDOUT); - else if (status & (CMD_CRC | DATA_CRC)) - hsmmc_command_incomplete(host, -EILSEQ); - end_cmd = 1; + if (status & (CTO_EN | CCRC_EN)) + end_cmd = 1; + if (status & (CTO_EN | DTO_EN)) + hsmmc_command_incomplete(host, -ETIMEDOUT, end_cmd); + else if (status & (CCRC_EN | DCRC_EN)) + hsmmc_command_incomplete(host, -EILSEQ, end_cmd); + if (host->data || host->response_busy) { - end_trans = 1; + end_trans = !end_cmd; host->response_busy = 0; } } - if (end_cmd || ((status & CC) && host->cmd)) + if (end_cmd || ((status & CC_EN) && host->cmd)) omap_hsmmc_cmd_done(host, host->cmd); - if ((end_trans || (status & TC)) && host->mrq) + if ((end_trans || (status & TC_EN)) && host->mrq) omap_hsmmc_xfer_done(host, data); } @@ -1101,7 +1141,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) return 0; err: - dev_dbg(mmc_dev(host->mmc), "Unable to switch operating voltage\n"); + dev_err(mmc_dev(host->mmc), "Unable to switch operating voltage\n"); return ret; } @@ -1360,7 +1400,7 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req) if (host->use_dma) { ret = omap_hsmmc_start_dma_transfer(host, req); if (ret != 0) { - dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n"); + dev_err(mmc_dev(host->mmc), "MMC start dma failure\n"); return ret; } } @@ -1678,7 +1718,7 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev) { struct omap_mmc_platform_data *pdata; struct device_node *np = dev->of_node; - u32 bus_width; + u32 bus_width, max_freq; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -1705,6 +1745,12 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev) if (of_find_property(np, "ti,needs-special-reset", NULL)) pdata->slots[0].features |= HSMMC_HAS_UPDATED_RESET; + if (!of_property_read_u32(np, "max-frequency", &max_freq)) + pdata->max_freq = max_freq; + + if (of_find_property(np, "ti,needs-special-hs-handling", NULL)) + pdata->slots[0].features |= HSMMC_HAS_HSPE_SUPPORT; + return pdata; } #else @@ -1715,7 +1761,7 @@ static inline struct omap_mmc_platform_data } #endif -static int __devinit omap_hsmmc_probe(struct platform_device *pdev) +static int omap_hsmmc_probe(struct platform_device *pdev) { struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; struct mmc_host *mmc; @@ -1725,6 +1771,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) const struct of_device_id *match; dma_cap_mask_t mask; unsigned tx_req, rx_req; + struct pinctrl *pinctrl; match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev); if (match) { @@ -1821,7 +1868,6 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) * MMC can still work without debounce clock. */ if (IS_ERR(host->dbclk)) { - dev_warn(mmc_dev(host->mmc), "Failed to get debounce clk\n"); host->dbclk = NULL; } else if (clk_prepare_enable(host->dbclk) != 0) { dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n"); @@ -1889,13 +1935,13 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) ret = request_irq(host->irq, omap_hsmmc_irq, 0, mmc_hostname(mmc), host); if (ret) { - dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n"); + dev_err(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n"); goto err_irq; } if (pdata->init != NULL) { if (pdata->init(&pdev->dev) != 0) { - dev_dbg(mmc_dev(host->mmc), + dev_err(mmc_dev(host->mmc), "Unable to configure MMC IRQs\n"); goto err_irq_cd_init; } @@ -1918,7 +1964,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, mmc_hostname(mmc), host); if (ret) { - dev_dbg(mmc_dev(host->mmc), + dev_err(mmc_dev(host->mmc), "Unable to grab MMC CD IRQ\n"); goto err_irq_cd; } @@ -1928,6 +1974,11 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev) omap_hsmmc_disable_irq(host); + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) + dev_warn(&pdev->dev, + "pins are not configured from the driver\n"); + omap_hsmmc_protect_card(host); mmc_add_host(mmc); @@ -1986,7 +2037,7 @@ err: return ret; } -static int __devexit omap_hsmmc_remove(struct platform_device *pdev) +static int omap_hsmmc_remove(struct platform_device *pdev) { struct omap_hsmmc_host *host = platform_get_drvdata(pdev); struct resource *res; @@ -2027,6 +2078,25 @@ static int __devexit omap_hsmmc_remove(struct platform_device *pdev) } #ifdef CONFIG_PM +static int omap_hsmmc_prepare(struct device *dev) +{ + struct omap_hsmmc_host *host = dev_get_drvdata(dev); + + if (host->pdata->suspend) + return host->pdata->suspend(dev, host->slot_id); + + return 0; +} + +static void omap_hsmmc_complete(struct device *dev) +{ + struct omap_hsmmc_host *host = dev_get_drvdata(dev); + + if (host->pdata->resume) + host->pdata->resume(dev, host->slot_id); + +} + static int omap_hsmmc_suspend(struct device *dev) { int ret = 0; @@ -2040,23 +2110,10 @@ static int omap_hsmmc_suspend(struct device *dev) pm_runtime_get_sync(host->dev); host->suspended = 1; - if (host->pdata->suspend) { - ret = host->pdata->suspend(dev, host->slot_id); - if (ret) { - dev_dbg(dev, "Unable to handle MMC board" - " level suspend\n"); - host->suspended = 0; - return ret; - } - } ret = mmc_suspend_host(host->mmc); if (ret) { host->suspended = 0; - if (host->pdata->resume) { - if (host->pdata->resume(dev, host->slot_id)) - dev_dbg(dev, "Unmask interrupt failed\n"); - } goto err; } @@ -2093,12 +2150,6 @@ static int omap_hsmmc_resume(struct device *dev) if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) omap_hsmmc_conf_bus_power(host); - if (host->pdata->resume) { - ret = host->pdata->resume(dev, host->slot_id); - if (ret) - dev_dbg(dev, "Unmask interrupt failed\n"); - } - omap_hsmmc_protect_card(host); /* Notify the core to resume the host */ @@ -2114,8 +2165,10 @@ static int omap_hsmmc_resume(struct device *dev) } #else +#define omap_hsmmc_prepare NULL +#define omap_hsmmc_complete NULL #define omap_hsmmc_suspend NULL -#define omap_hsmmc_resume NULL +#define omap_hsmmc_resume NULL #endif static int omap_hsmmc_runtime_suspend(struct device *dev) @@ -2143,13 +2196,15 @@ static int omap_hsmmc_runtime_resume(struct device *dev) static struct dev_pm_ops omap_hsmmc_dev_pm_ops = { .suspend = omap_hsmmc_suspend, .resume = omap_hsmmc_resume, + .prepare = omap_hsmmc_prepare, + .complete = omap_hsmmc_complete, .runtime_suspend = omap_hsmmc_runtime_suspend, .runtime_resume = omap_hsmmc_runtime_resume, }; static struct platform_driver omap_hsmmc_driver = { .probe = omap_hsmmc_probe, - .remove = __devexit_p(omap_hsmmc_remove), + .remove = omap_hsmmc_remove, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 3f9d6d577a9..2b2f65ada22 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -584,7 +584,7 @@ static const struct of_device_id pxa_mmc_dt_ids[] = { MODULE_DEVICE_TABLE(of, pxa_mmc_dt_ids); -static int __devinit pxamci_of_init(struct platform_device *pdev) +static int pxamci_of_init(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct pxamci_platform_data *pdata; @@ -614,7 +614,7 @@ static int __devinit pxamci_of_init(struct platform_device *pdev) return 0; } #else -static int __devinit pxamci_of_init(struct platform_device *pdev) +static int pxamci_of_init(struct platform_device *pdev) { return 0; } diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c new file mode 100644 index 00000000000..12eff6f8cab --- /dev/null +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -0,0 +1,1348 @@ +/* Realtek PCI-Express SD/MMC Card Interface driver + * + * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * + * 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, 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, see <http://www.gnu.org/licenses/>. + * + * Author: + * Wei WANG <wei_wang@realsil.com.cn> + * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + */ + +#include <linux/module.h> +#include <linux/highmem.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/mmc/host.h> +#include <linux/mmc/mmc.h> +#include <linux/mmc/sd.h> +#include <linux/mmc/card.h> +#include <linux/mfd/rtsx_pci.h> +#include <asm/unaligned.h> + +/* SD Tuning Data Structure + * Record continuous timing phase path + */ +struct timing_phase_path { + int start; + int end; + int mid; + int len; +}; + +struct realtek_pci_sdmmc { + struct platform_device *pdev; + struct rtsx_pcr *pcr; + struct mmc_host *mmc; + struct mmc_request *mrq; + + struct mutex host_mutex; + + u8 ssc_depth; + unsigned int clock; + bool vpclk; + bool double_clk; + bool eject; + bool initial_mode; + bool ddr_mode; +}; + +static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host) +{ + return &(host->pdev->dev); +} + +static inline void sd_clear_error(struct realtek_pci_sdmmc *host) +{ + rtsx_pci_write_register(host->pcr, CARD_STOP, + SD_STOP | SD_CLR_ERR, SD_STOP | SD_CLR_ERR); +} + +#ifdef DEBUG +static void sd_print_debug_regs(struct realtek_pci_sdmmc *host) +{ + struct rtsx_pcr *pcr = host->pcr; + u16 i; + u8 *ptr; + + /* Print SD host internal registers */ + rtsx_pci_init_cmd(pcr); + for (i = 0xFDA0; i <= 0xFDAE; i++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0); + for (i = 0xFD52; i <= 0xFD69; i++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0); + rtsx_pci_send_cmd(pcr, 100); + + ptr = rtsx_pci_get_cmd_data(pcr); + for (i = 0xFDA0; i <= 0xFDAE; i++) + dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); + for (i = 0xFD52; i <= 0xFD69; i++) + dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++)); +} +#else +#define sd_print_debug_regs(host) +#endif /* DEBUG */ + +static int sd_read_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt, + u8 *buf, int buf_len, int timeout) +{ + struct rtsx_pcr *pcr = host->pcr; + int err, i; + u8 trans_mode; + + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD%d\n", __func__, cmd[0] - 0x40); + + if (!buf) + buf_len = 0; + + if ((cmd[0] & 0x3F) == MMC_SEND_TUNING_BLOCK) + trans_mode = SD_TM_AUTO_TUNING; + else + trans_mode = SD_TM_NORMAL_READ; + + rtsx_pci_init_cmd(pcr); + + for (i = 0; i < 5; i++) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD0 + i, 0xFF, cmd[i]); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, + 0xFF, (u8)(byte_cnt >> 8)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, + SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6); + if (trans_mode != SD_TM_AUTO_TUNING) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, + 0xFF, trans_mode | SD_TRANSFER_START); + rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END, SD_TRANSFER_END); + + err = rtsx_pci_send_cmd(pcr, timeout); + if (err < 0) { + sd_print_debug_regs(host); + dev_dbg(sdmmc_dev(host), + "rtsx_pci_send_cmd fail (err = %d)\n", err); + return err; + } + + if (buf && buf_len) { + err = rtsx_pci_read_ppbuf(pcr, buf, buf_len); + if (err < 0) { + dev_dbg(sdmmc_dev(host), + "rtsx_pci_read_ppbuf fail (err = %d)\n", err); + return err; + } + } + + return 0; +} + +static int sd_write_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt, + u8 *buf, int buf_len, int timeout) +{ + struct rtsx_pcr *pcr = host->pcr; + int err, i; + u8 trans_mode; + + if (!buf) + buf_len = 0; + + if (buf && buf_len) { + err = rtsx_pci_write_ppbuf(pcr, buf, buf_len); + if (err < 0) { + dev_dbg(sdmmc_dev(host), + "rtsx_pci_write_ppbuf fail (err = %d)\n", err); + return err; + } + } + + trans_mode = cmd ? SD_TM_AUTO_WRITE_2 : SD_TM_AUTO_WRITE_3; + rtsx_pci_init_cmd(pcr); + + if (cmd) { + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d\n", __func__, + cmd[0] - 0x40); + + for (i = 0; i < 5; i++) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + SD_CMD0 + i, 0xFF, cmd[i]); + } + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, + 0xFF, (u8)(byte_cnt >> 8)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, + SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, + trans_mode | SD_TRANSFER_START); + rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END, SD_TRANSFER_END); + + err = rtsx_pci_send_cmd(pcr, timeout); + if (err < 0) { + sd_print_debug_regs(host); + dev_dbg(sdmmc_dev(host), + "rtsx_pci_send_cmd fail (err = %d)\n", err); + return err; + } + + return 0; +} + +static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, + struct mmc_command *cmd) +{ + struct rtsx_pcr *pcr = host->pcr; + u8 cmd_idx = (u8)cmd->opcode; + u32 arg = cmd->arg; + int err = 0; + int timeout = 100; + int i; + u8 *ptr; + int stat_idx = 0; + u8 rsp_type; + int rsp_len = 5; + + dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", + __func__, cmd_idx, arg); + + /* Response type: + * R0 + * R1, R5, R6, R7 + * R1b + * R2 + * R3, R4 + */ + switch (mmc_resp_type(cmd)) { + case MMC_RSP_NONE: + rsp_type = SD_RSP_TYPE_R0; + rsp_len = 0; + break; + case MMC_RSP_R1: + rsp_type = SD_RSP_TYPE_R1; + break; + case MMC_RSP_R1B: + rsp_type = SD_RSP_TYPE_R1b; + break; + case MMC_RSP_R2: + rsp_type = SD_RSP_TYPE_R2; + rsp_len = 16; + break; + case MMC_RSP_R3: + rsp_type = SD_RSP_TYPE_R3; + break; + default: + dev_dbg(sdmmc_dev(host), "cmd->flag is not valid\n"); + err = -EINVAL; + goto out; + } + + if (rsp_type == SD_RSP_TYPE_R1b) + timeout = 3000; + + if (cmd->opcode == SD_SWITCH_VOLTAGE) { + err = rtsx_pci_write_register(pcr, SD_BUS_STAT, + 0xFF, SD_CLK_TOGGLE_EN); + if (err < 0) + goto out; + } + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | cmd_idx); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD1, 0xFF, (u8)(arg >> 24)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD2, 0xFF, (u8)(arg >> 16)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD3, 0xFF, (u8)(arg >> 8)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8)arg); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, + 0x01, PINGPONG_BUFFER); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, + 0xFF, SD_TM_CMD_RSP | SD_TRANSFER_START); + rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END | SD_STAT_IDLE, + SD_TRANSFER_END | SD_STAT_IDLE); + + if (rsp_type == SD_RSP_TYPE_R2) { + /* Read data from ping-pong buffer */ + for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0); + stat_idx = 16; + } else if (rsp_type != SD_RSP_TYPE_R0) { + /* Read data from SD_CMDx registers */ + for (i = SD_CMD0; i <= SD_CMD4; i++) + rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0); + stat_idx = 5; + } + + rtsx_pci_add_cmd(pcr, READ_REG_CMD, SD_STAT1, 0, 0); + + err = rtsx_pci_send_cmd(pcr, timeout); + if (err < 0) { + sd_print_debug_regs(host); + sd_clear_error(host); + dev_dbg(sdmmc_dev(host), + "rtsx_pci_send_cmd error (err = %d)\n", err); + goto out; + } + + if (rsp_type == SD_RSP_TYPE_R0) { + err = 0; + goto out; + } + + /* Eliminate returned value of CHECK_REG_CMD */ + ptr = rtsx_pci_get_cmd_data(pcr) + 1; + + /* Check (Start,Transmission) bit of Response */ + if ((ptr[0] & 0xC0) != 0) { + err = -EILSEQ; + dev_dbg(sdmmc_dev(host), "Invalid response bit\n"); + goto out; + } + + /* Check CRC7 */ + if (!(rsp_type & SD_NO_CHECK_CRC7)) { + if (ptr[stat_idx] & SD_CRC7_ERR) { + err = -EILSEQ; + dev_dbg(sdmmc_dev(host), "CRC7 error\n"); + goto out; + } + } + + if (rsp_type == SD_RSP_TYPE_R2) { + for (i = 0; i < 4; i++) { + cmd->resp[i] = get_unaligned_be32(ptr + 1 + i * 4); + dev_dbg(sdmmc_dev(host), "cmd->resp[%d] = 0x%08x\n", + i, cmd->resp[i]); + } + } else { + cmd->resp[0] = get_unaligned_be32(ptr + 1); + dev_dbg(sdmmc_dev(host), "cmd->resp[0] = 0x%08x\n", + cmd->resp[0]); + } + +out: + cmd->error = err; +} + +static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq) +{ + struct rtsx_pcr *pcr = host->pcr; + struct mmc_host *mmc = host->mmc; + struct mmc_card *card = mmc->card; + struct mmc_data *data = mrq->data; + int uhs = mmc_sd_card_uhs(card); + int read = (data->flags & MMC_DATA_READ) ? 1 : 0; + u8 cfg2, trans_mode; + int err; + size_t data_len = data->blksz * data->blocks; + + if (read) { + cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0; + trans_mode = SD_TM_AUTO_READ_3; + } else { + cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 | + SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 | SD_RSP_LEN_0; + trans_mode = SD_TM_AUTO_WRITE_3; + } + + if (!uhs) + cfg2 |= SD_NO_CHECK_WAIT_CRC_TO; + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0x00); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, 0x02); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, + 0xFF, (u8)data->blocks); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, + 0xFF, (u8)(data->blocks >> 8)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + CARD_DATA_SOURCE, 0x01, RING_BUFFER); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0, + DMA_DONE_INT, DMA_DONE_INT); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC3, + 0xFF, (u8)(data_len >> 24)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC2, + 0xFF, (u8)(data_len >> 16)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC1, + 0xFF, (u8)(data_len >> 8)); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC0, 0xFF, (u8)data_len); + if (read) { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL, + 0x03 | DMA_PACK_SIZE_MASK, + DMA_DIR_FROM_CARD | DMA_EN | DMA_512); + } else { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL, + 0x03 | DMA_PACK_SIZE_MASK, + DMA_DIR_TO_CARD | DMA_EN | DMA_512); + } + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE, + 0x01, RING_BUFFER); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF, + trans_mode | SD_TRANSFER_START); + rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER, + SD_TRANSFER_END, SD_TRANSFER_END); + + rtsx_pci_send_cmd_no_wait(pcr); + + err = rtsx_pci_transfer_data(pcr, data->sg, data->sg_len, read, 10000); + if (err < 0) { + sd_clear_error(host); + return err; + } + + return 0; +} + +static inline void sd_enable_initial_mode(struct realtek_pci_sdmmc *host) +{ + rtsx_pci_write_register(host->pcr, SD_CFG1, + SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_128); +} + +static inline void sd_disable_initial_mode(struct realtek_pci_sdmmc *host) +{ + rtsx_pci_write_register(host->pcr, SD_CFG1, + SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_0); +} + +static void sd_normal_rw(struct realtek_pci_sdmmc *host, + struct mmc_request *mrq) +{ + struct mmc_command *cmd = mrq->cmd; + struct mmc_data *data = mrq->data; + u8 _cmd[5], *buf; + + _cmd[0] = 0x40 | (u8)cmd->opcode; + put_unaligned_be32(cmd->arg, (u32 *)(&_cmd[1])); + + buf = kzalloc(data->blksz, GFP_NOIO); + if (!buf) { + cmd->error = -ENOMEM; + return; + } + + if (data->flags & MMC_DATA_READ) { + if (host->initial_mode) + sd_disable_initial_mode(host); + + cmd->error = sd_read_data(host, _cmd, (u16)data->blksz, buf, + data->blksz, 200); + + if (host->initial_mode) + sd_enable_initial_mode(host); + + sg_copy_from_buffer(data->sg, data->sg_len, buf, data->blksz); + } else { + sg_copy_to_buffer(data->sg, data->sg_len, buf, data->blksz); + + cmd->error = sd_write_data(host, _cmd, (u16)data->blksz, buf, + data->blksz, 200); + } + + kfree(buf); +} + +static int sd_change_phase(struct realtek_pci_sdmmc *host, u8 sample_point) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + + dev_dbg(sdmmc_dev(host), "%s: sample_point = %d\n", + __func__, sample_point); + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CHANGE_CLK, CHANGE_CLK); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPRX_CTL, 0x1F, sample_point); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, + PHASE_NOT_RESET, PHASE_NOT_RESET); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CHANGE_CLK, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0); + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + return 0; +} + +static u8 sd_search_final_phase(struct realtek_pci_sdmmc *host, u32 phase_map) +{ + struct timing_phase_path path[MAX_PHASE + 1]; + int i, j, cont_path_cnt; + int new_block, max_len, final_path_idx; + u8 final_phase = 0xFF; + + /* Parse phase_map, take it as a bit-ring */ + cont_path_cnt = 0; + new_block = 1; + j = 0; + for (i = 0; i < MAX_PHASE + 1; i++) { + if (phase_map & (1 << i)) { + if (new_block) { + new_block = 0; + j = cont_path_cnt++; + path[j].start = i; + path[j].end = i; + } else { + path[j].end = i; + } + } else { + new_block = 1; + if (cont_path_cnt) { + /* Calculate path length and middle point */ + int idx = cont_path_cnt - 1; + path[idx].len = + path[idx].end - path[idx].start + 1; + path[idx].mid = + path[idx].start + path[idx].len / 2; + } + } + } + + if (cont_path_cnt == 0) { + dev_dbg(sdmmc_dev(host), "No continuous phase path\n"); + goto finish; + } else { + /* Calculate last continuous path length and middle point */ + int idx = cont_path_cnt - 1; + path[idx].len = path[idx].end - path[idx].start + 1; + path[idx].mid = path[idx].start + path[idx].len / 2; + } + + /* Connect the first and last continuous paths if they are adjacent */ + if (!path[0].start && (path[cont_path_cnt - 1].end == MAX_PHASE)) { + /* Using negative index */ + path[0].start = path[cont_path_cnt - 1].start - MAX_PHASE - 1; + path[0].len += path[cont_path_cnt - 1].len; + path[0].mid = path[0].start + path[0].len / 2; + /* Convert negative middle point index to positive one */ + if (path[0].mid < 0) + path[0].mid += MAX_PHASE + 1; + cont_path_cnt--; + } + + /* Choose the longest continuous phase path */ + max_len = 0; + final_phase = 0; + final_path_idx = 0; + for (i = 0; i < cont_path_cnt; i++) { + if (path[i].len > max_len) { + max_len = path[i].len; + final_phase = (u8)path[i].mid; + final_path_idx = i; + } + + dev_dbg(sdmmc_dev(host), "path[%d].start = %d\n", + i, path[i].start); + dev_dbg(sdmmc_dev(host), "path[%d].end = %d\n", + i, path[i].end); + dev_dbg(sdmmc_dev(host), "path[%d].len = %d\n", + i, path[i].len); + dev_dbg(sdmmc_dev(host), "path[%d].mid = %d\n", + i, path[i].mid); + } + +finish: + dev_dbg(sdmmc_dev(host), "Final chosen phase: %d\n", final_phase); + return final_phase; +} + +static void sd_wait_data_idle(struct realtek_pci_sdmmc *host) +{ + int err, i; + u8 val = 0; + + for (i = 0; i < 100; i++) { + err = rtsx_pci_read_register(host->pcr, SD_DATA_STATE, &val); + if (val & SD_DATA_IDLE) + return; + + udelay(100); + } +} + +static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host, + u8 opcode, u8 sample_point) +{ + int err; + u8 cmd[5] = {0}; + + err = sd_change_phase(host, sample_point); + if (err < 0) + return err; + + cmd[0] = 0x40 | opcode; + err = sd_read_data(host, cmd, 0x40, NULL, 0, 100); + if (err < 0) { + /* Wait till SD DATA IDLE */ + sd_wait_data_idle(host); + sd_clear_error(host); + return err; + } + + return 0; +} + +static int sd_tuning_phase(struct realtek_pci_sdmmc *host, + u8 opcode, u32 *phase_map) +{ + int err, i; + u32 raw_phase_map = 0; + + for (i = MAX_PHASE; i >= 0; i--) { + err = sd_tuning_rx_cmd(host, opcode, (u8)i); + if (err == 0) + raw_phase_map |= 1 << i; + } + + if (phase_map) + *phase_map = raw_phase_map; + + return 0; +} + +static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode) +{ + int err, i; + u32 raw_phase_map[RX_TUNING_CNT] = {0}, phase_map; + u8 final_phase; + + for (i = 0; i < RX_TUNING_CNT; i++) { + err = sd_tuning_phase(host, opcode, &(raw_phase_map[i])); + if (err < 0) + return err; + + if (raw_phase_map[i] == 0) + break; + } + + phase_map = 0xFFFFFFFF; + for (i = 0; i < RX_TUNING_CNT; i++) { + dev_dbg(sdmmc_dev(host), "RX raw_phase_map[%d] = 0x%08x\n", + i, raw_phase_map[i]); + phase_map &= raw_phase_map[i]; + } + dev_dbg(sdmmc_dev(host), "RX phase_map = 0x%08x\n", phase_map); + + if (phase_map) { + final_phase = sd_search_final_phase(host, phase_map); + if (final_phase == 0xFF) + return -EINVAL; + + err = sd_change_phase(host, final_phase); + if (err < 0) + return err; + } else { + return -EINVAL; + } + + return 0; +} + +static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct realtek_pci_sdmmc *host = mmc_priv(mmc); + struct rtsx_pcr *pcr = host->pcr; + struct mmc_command *cmd = mrq->cmd; + struct mmc_data *data = mrq->data; + unsigned int data_size = 0; + + if (host->eject) { + cmd->error = -ENOMEDIUM; + goto finish; + } + + mutex_lock(&pcr->pcr_mutex); + + rtsx_pci_start_run(pcr); + + rtsx_pci_switch_clock(pcr, host->clock, host->ssc_depth, + host->initial_mode, host->double_clk, host->vpclk); + rtsx_pci_write_register(pcr, CARD_SELECT, 0x07, SD_MOD_SEL); + rtsx_pci_write_register(pcr, CARD_SHARE_MODE, + CARD_SHARE_MASK, CARD_SHARE_48_SD); + + mutex_lock(&host->host_mutex); + host->mrq = mrq; + mutex_unlock(&host->host_mutex); + + if (mrq->data) + data_size = data->blocks * data->blksz; + + if (!data_size || mmc_op_multi(cmd->opcode) || + (cmd->opcode == MMC_READ_SINGLE_BLOCK) || + (cmd->opcode == MMC_WRITE_BLOCK)) { + sd_send_cmd_get_rsp(host, cmd); + + if (!cmd->error && data_size) { + sd_rw_multi(host, mrq); + + if (mmc_op_multi(cmd->opcode) && mrq->stop) + sd_send_cmd_get_rsp(host, mrq->stop); + } + } else { + sd_normal_rw(host, mrq); + } + + if (mrq->data) { + if (cmd->error || data->error) + data->bytes_xfered = 0; + else + data->bytes_xfered = data->blocks * data->blksz; + } + + mutex_unlock(&pcr->pcr_mutex); + +finish: + if (cmd->error) + dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error); + + mutex_lock(&host->host_mutex); + host->mrq = NULL; + mutex_unlock(&host->host_mutex); + + mmc_request_done(mmc, mrq); +} + +static int sd_set_bus_width(struct realtek_pci_sdmmc *host, + unsigned char bus_width) +{ + int err = 0; + u8 width[] = { + [MMC_BUS_WIDTH_1] = SD_BUS_WIDTH_1BIT, + [MMC_BUS_WIDTH_4] = SD_BUS_WIDTH_4BIT, + [MMC_BUS_WIDTH_8] = SD_BUS_WIDTH_8BIT, + }; + + if (bus_width <= MMC_BUS_WIDTH_8) + err = rtsx_pci_write_register(host->pcr, SD_CFG1, + 0x03, width[bus_width]); + + return err; +} + +static int sd_power_on(struct realtek_pci_sdmmc *host) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + + rtsx_pci_init_cmd(pcr); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SHARE_MODE, + CARD_SHARE_MASK, CARD_SHARE_48_SD); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, + SD_CLK_EN, SD_CLK_EN); + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + err = rtsx_pci_card_pull_ctl_enable(pcr, RTSX_SD_CARD); + if (err < 0) + return err; + + err = rtsx_pci_card_power_on(pcr, RTSX_SD_CARD); + if (err < 0) + return err; + + err = rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN); + if (err < 0) + return err; + + return 0; +} + +static int sd_power_off(struct realtek_pci_sdmmc *host) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_OE, SD_OUTPUT_EN, 0); + + err = rtsx_pci_send_cmd(pcr, 100); + if (err < 0) + return err; + + err = rtsx_pci_card_power_off(pcr, RTSX_SD_CARD); + if (err < 0) + return err; + + return rtsx_pci_card_pull_ctl_disable(pcr, RTSX_SD_CARD); +} + +static int sd_set_power_mode(struct realtek_pci_sdmmc *host, + unsigned char power_mode) +{ + int err; + + if (power_mode == MMC_POWER_OFF) + err = sd_power_off(host); + else + err = sd_power_on(host); + + return err; +} + +static int sd_set_timing(struct realtek_pci_sdmmc *host, + unsigned char timing, bool *ddr_mode) +{ + struct rtsx_pcr *pcr = host->pcr; + int err = 0; + + *ddr_mode = false; + + rtsx_pci_init_cmd(pcr); + + switch (timing) { + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_UHS_SDR50: + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, + 0x0C | SD_ASYNC_FIFO_NOT_RST, + SD_30_MODE | SD_ASYNC_FIFO_NOT_RST); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, + CLK_LOW_FREQ, CLK_LOW_FREQ); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, + CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0); + break; + + case MMC_TIMING_UHS_DDR50: + *ddr_mode = true; + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, + 0x0C | SD_ASYNC_FIFO_NOT_RST, + SD_DDR_MODE | SD_ASYNC_FIFO_NOT_RST); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, + CLK_LOW_FREQ, CLK_LOW_FREQ); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, + CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_PUSH_POINT_CTL, + DDR_VAR_TX_CMD_DAT, DDR_VAR_TX_CMD_DAT); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, + DDR_VAR_RX_DAT | DDR_VAR_RX_CMD, + DDR_VAR_RX_DAT | DDR_VAR_RX_CMD); + break; + + case MMC_TIMING_MMC_HS: + case MMC_TIMING_SD_HS: + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, + 0x0C, SD_20_MODE); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, + CLK_LOW_FREQ, CLK_LOW_FREQ); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, + CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_PUSH_POINT_CTL, + SD20_TX_SEL_MASK, SD20_TX_14_AHEAD); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, + SD20_RX_SEL_MASK, SD20_RX_14_DELAY); + break; + + default: + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + SD_CFG1, 0x0C, SD_20_MODE); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, + CLK_LOW_FREQ, CLK_LOW_FREQ); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_SOURCE, 0xFF, + CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + SD_PUSH_POINT_CTL, 0xFF, 0); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_SAMPLE_POINT_CTL, + SD20_RX_SEL_MASK, SD20_RX_POS_EDGE); + break; + } + + err = rtsx_pci_send_cmd(pcr, 100); + + return err; +} + +static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct realtek_pci_sdmmc *host = mmc_priv(mmc); + struct rtsx_pcr *pcr = host->pcr; + + if (host->eject) + return; + + mutex_lock(&pcr->pcr_mutex); + + rtsx_pci_start_run(pcr); + + sd_set_bus_width(host, ios->bus_width); + sd_set_power_mode(host, ios->power_mode); + sd_set_timing(host, ios->timing, &host->ddr_mode); + + host->vpclk = false; + host->double_clk = true; + + switch (ios->timing) { + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_UHS_SDR50: + host->ssc_depth = RTSX_SSC_DEPTH_2M; + host->vpclk = true; + host->double_clk = false; + break; + case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_UHS_SDR25: + host->ssc_depth = RTSX_SSC_DEPTH_1M; + break; + default: + host->ssc_depth = RTSX_SSC_DEPTH_500K; + break; + } + + host->initial_mode = (ios->clock <= 1000000) ? true : false; + + host->clock = ios->clock; + rtsx_pci_switch_clock(pcr, ios->clock, host->ssc_depth, + host->initial_mode, host->double_clk, host->vpclk); + + mutex_unlock(&pcr->pcr_mutex); +} + +static int sdmmc_get_ro(struct mmc_host *mmc) +{ + struct realtek_pci_sdmmc *host = mmc_priv(mmc); + struct rtsx_pcr *pcr = host->pcr; + int ro = 0; + u32 val; + + if (host->eject) + return -ENOMEDIUM; + + mutex_lock(&pcr->pcr_mutex); + + rtsx_pci_start_run(pcr); + + /* Check SD mechanical write-protect switch */ + val = rtsx_pci_readl(pcr, RTSX_BIPR); + dev_dbg(sdmmc_dev(host), "%s: RTSX_BIPR = 0x%08x\n", __func__, val); + if (val & SD_WRITE_PROTECT) + ro = 1; + + mutex_unlock(&pcr->pcr_mutex); + + return ro; +} + +static int sdmmc_get_cd(struct mmc_host *mmc) +{ + struct realtek_pci_sdmmc *host = mmc_priv(mmc); + struct rtsx_pcr *pcr = host->pcr; + int cd = 0; + u32 val; + + if (host->eject) + return -ENOMEDIUM; + + mutex_lock(&pcr->pcr_mutex); + + rtsx_pci_start_run(pcr); + + /* Check SD card detect */ + val = rtsx_pci_card_exist(pcr); + dev_dbg(sdmmc_dev(host), "%s: RTSX_BIPR = 0x%08x\n", __func__, val); + if (val & SD_EXIST) + cd = 1; + + mutex_unlock(&pcr->pcr_mutex); + + return cd; +} + +static int sd_wait_voltage_stable_1(struct realtek_pci_sdmmc *host) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + u8 stat; + + /* Reference to Signal Voltage Switch Sequence in SD spec. + * Wait for a period of time so that the card can drive SD_CMD and + * SD_DAT[3:0] to low after sending back CMD11 response. + */ + mdelay(1); + + /* SD_CMD, SD_DAT[3:0] should be driven to low by card; + * If either one of SD_CMD,SD_DAT[3:0] is not low, + * abort the voltage switch sequence; + */ + err = rtsx_pci_read_register(pcr, SD_BUS_STAT, &stat); + if (err < 0) + return err; + + if (stat & (SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS | + SD_DAT1_STATUS | SD_DAT0_STATUS)) + return -EINVAL; + + /* Stop toggle SD clock */ + err = rtsx_pci_write_register(pcr, SD_BUS_STAT, + 0xFF, SD_CLK_FORCE_STOP); + if (err < 0) + return err; + + return 0; +} + +static int sd_wait_voltage_stable_2(struct realtek_pci_sdmmc *host) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + u8 stat, mask, val; + + /* Wait 1.8V output of voltage regulator in card stable */ + msleep(50); + + /* Toggle SD clock again */ + err = rtsx_pci_write_register(pcr, SD_BUS_STAT, 0xFF, SD_CLK_TOGGLE_EN); + if (err < 0) + return err; + + /* Wait for a period of time so that the card can drive + * SD_DAT[3:0] to high at 1.8V + */ + msleep(20); + + /* SD_CMD, SD_DAT[3:0] should be pulled high by host */ + err = rtsx_pci_read_register(pcr, SD_BUS_STAT, &stat); + if (err < 0) + return err; + + mask = SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS | + SD_DAT1_STATUS | SD_DAT0_STATUS; + val = SD_CMD_STATUS | SD_DAT3_STATUS | SD_DAT2_STATUS | + SD_DAT1_STATUS | SD_DAT0_STATUS; + if ((stat & mask) != val) { + dev_dbg(sdmmc_dev(host), + "%s: SD_BUS_STAT = 0x%x\n", __func__, stat); + rtsx_pci_write_register(pcr, SD_BUS_STAT, + SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); + rtsx_pci_write_register(pcr, CARD_CLK_EN, 0xFF, 0); + return -EINVAL; + } + + return 0; +} + +static int sd_change_bank_voltage(struct realtek_pci_sdmmc *host, u8 voltage) +{ + struct rtsx_pcr *pcr = host->pcr; + int err; + + if (voltage == SD_IO_3V3) { + err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24); + if (err < 0) + return err; + } else if (voltage == SD_IO_1V8) { + err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24); + if (err < 0) + return err; + } else { + return -EINVAL; + } + + return 0; +} + +static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct realtek_pci_sdmmc *host = mmc_priv(mmc); + struct rtsx_pcr *pcr = host->pcr; + int err = 0; + u8 voltage; + + dev_dbg(sdmmc_dev(host), "%s: signal_voltage = %d\n", + __func__, ios->signal_voltage); + + if (host->eject) + return -ENOMEDIUM; + + mutex_lock(&pcr->pcr_mutex); + + rtsx_pci_start_run(pcr); + + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) + voltage = SD_IO_3V3; + else + voltage = SD_IO_1V8; + + if (voltage == SD_IO_1V8) { + err = rtsx_pci_write_register(pcr, + SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B); + if (err < 0) + goto out; + + err = sd_wait_voltage_stable_1(host); + if (err < 0) + goto out; + } + + err = sd_change_bank_voltage(host, voltage); + if (err < 0) + goto out; + + if (voltage == SD_IO_1V8) { + err = sd_wait_voltage_stable_2(host); + if (err < 0) + goto out; + } + + /* Stop toggle SD clock in idle */ + err = rtsx_pci_write_register(pcr, SD_BUS_STAT, + SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); + +out: + mutex_unlock(&pcr->pcr_mutex); + + return err; +} + +static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + struct realtek_pci_sdmmc *host = mmc_priv(mmc); + struct rtsx_pcr *pcr = host->pcr; + int err = 0; + + if (host->eject) + return -ENOMEDIUM; + + mutex_lock(&pcr->pcr_mutex); + + rtsx_pci_start_run(pcr); + + if (!host->ddr_mode) + err = sd_tuning_rx(host, MMC_SEND_TUNING_BLOCK); + + mutex_unlock(&pcr->pcr_mutex); + + return err; +} + +static const struct mmc_host_ops realtek_pci_sdmmc_ops = { + .request = sdmmc_request, + .set_ios = sdmmc_set_ios, + .get_ro = sdmmc_get_ro, + .get_cd = sdmmc_get_cd, + .start_signal_voltage_switch = sdmmc_switch_voltage, + .execute_tuning = sdmmc_execute_tuning, +}; + +#ifdef CONFIG_PM +static int rtsx_pci_sdmmc_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); + struct mmc_host *mmc = host->mmc; + int err; + + dev_dbg(sdmmc_dev(host), "--> %s\n", __func__); + + err = mmc_suspend_host(mmc); + if (err) + return err; + + return 0; +} + +static int rtsx_pci_sdmmc_resume(struct platform_device *pdev) +{ + struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); + struct mmc_host *mmc = host->mmc; + + dev_dbg(sdmmc_dev(host), "--> %s\n", __func__); + + return mmc_resume_host(mmc); +} +#else /* CONFIG_PM */ +#define rtsx_pci_sdmmc_suspend NULL +#define rtsx_pci_sdmmc_resume NULL +#endif /* CONFIG_PM */ + +static void init_extra_caps(struct realtek_pci_sdmmc *host) +{ + struct mmc_host *mmc = host->mmc; + struct rtsx_pcr *pcr = host->pcr; + + dev_dbg(sdmmc_dev(host), "pcr->extra_caps = 0x%x\n", pcr->extra_caps); + + if (pcr->extra_caps & EXTRA_CAPS_SD_SDR50) + mmc->caps |= MMC_CAP_UHS_SDR50; + if (pcr->extra_caps & EXTRA_CAPS_SD_SDR104) + mmc->caps |= MMC_CAP_UHS_SDR104; + if (pcr->extra_caps & EXTRA_CAPS_SD_DDR50) + mmc->caps |= MMC_CAP_UHS_DDR50; + if (pcr->extra_caps & EXTRA_CAPS_MMC_HSDDR) + mmc->caps |= MMC_CAP_1_8V_DDR; + if (pcr->extra_caps & EXTRA_CAPS_MMC_8BIT) + mmc->caps |= MMC_CAP_8_BIT_DATA; +} + +static void realtek_init_host(struct realtek_pci_sdmmc *host) +{ + struct mmc_host *mmc = host->mmc; + + mmc->f_min = 250000; + mmc->f_max = 208000000; + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; + mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST | + MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25; + mmc->max_current_330 = 400; + mmc->max_current_180 = 800; + mmc->ops = &realtek_pci_sdmmc_ops; + + init_extra_caps(host); + + mmc->max_segs = 256; + mmc->max_seg_size = 65536; + mmc->max_blk_size = 512; + mmc->max_blk_count = 65535; + mmc->max_req_size = 524288; +} + +static void rtsx_pci_sdmmc_card_event(struct platform_device *pdev) +{ + struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); + + mmc_detect_change(host->mmc, 0); +} + +static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) +{ + struct mmc_host *mmc; + struct realtek_pci_sdmmc *host; + struct rtsx_pcr *pcr; + struct pcr_handle *handle = pdev->dev.platform_data; + + if (!handle) + return -ENXIO; + + pcr = handle->pcr; + if (!pcr) + return -ENXIO; + + dev_dbg(&(pdev->dev), ": Realtek PCI-E SDMMC controller found\n"); + + mmc = mmc_alloc_host(sizeof(*host), &pdev->dev); + if (!mmc) + return -ENOMEM; + + host = mmc_priv(mmc); + host->pcr = pcr; + host->mmc = mmc; + host->pdev = pdev; + platform_set_drvdata(pdev, host); + pcr->slots[RTSX_SD_CARD].p_dev = pdev; + pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event; + + mutex_init(&host->host_mutex); + + realtek_init_host(host); + + mmc_add_host(mmc); + + return 0; +} + +static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev) +{ + struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev); + struct rtsx_pcr *pcr; + struct mmc_host *mmc; + + if (!host) + return 0; + + pcr = host->pcr; + pcr->slots[RTSX_SD_CARD].p_dev = NULL; + pcr->slots[RTSX_SD_CARD].card_event = NULL; + mmc = host->mmc; + host->eject = true; + + mutex_lock(&host->host_mutex); + if (host->mrq) { + dev_dbg(&(pdev->dev), + "%s: Controller removed during transfer\n", + mmc_hostname(mmc)); + + rtsx_pci_complete_unfinished_transfer(pcr); + + host->mrq->cmd->error = -ENOMEDIUM; + if (host->mrq->stop) + host->mrq->stop->error = -ENOMEDIUM; + mmc_request_done(mmc, host->mrq); + } + mutex_unlock(&host->host_mutex); + + mmc_remove_host(mmc); + mmc_free_host(mmc); + + platform_set_drvdata(pdev, NULL); + + dev_dbg(&(pdev->dev), + ": Realtek PCI-E SDMMC controller has been removed\n"); + + return 0; +} + +static struct platform_device_id rtsx_pci_sdmmc_ids[] = { + { + .name = DRV_NAME_RTSX_PCI_SDMMC, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(platform, rtsx_pci_sdmmc_ids); + +static struct platform_driver rtsx_pci_sdmmc_driver = { + .probe = rtsx_pci_sdmmc_drv_probe, + .remove = rtsx_pci_sdmmc_drv_remove, + .id_table = rtsx_pci_sdmmc_ids, + .suspend = rtsx_pci_sdmmc_suspend, + .resume = rtsx_pci_sdmmc_resume, + .driver = { + .owner = THIS_MODULE, + .name = DRV_NAME_RTSX_PCI_SDMMC, + }, +}; +module_platform_driver(rtsx_pci_sdmmc_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Wei WANG <wei_wang@realsil.com.cn>"); +MODULE_DESCRIPTION("Realtek PCI-E SD/MMC Card Host Driver"); diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 4638ddab97b..63fb265e0da 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -1540,7 +1540,7 @@ static inline void s3cmci_debugfs_remove(struct s3cmci_host *host) { } #endif /* CONFIG_DEBUG_FS */ -static int __devinit s3cmci_probe(struct platform_device *pdev) +static int s3cmci_probe(struct platform_device *pdev) { struct s3cmci_host *host; struct mmc_host *mmc; @@ -1819,7 +1819,7 @@ static void s3cmci_shutdown(struct platform_device *pdev) clk_disable(host->clk); } -static int __devexit s3cmci_remove(struct platform_device *pdev) +static int s3cmci_remove(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct s3cmci_host *host = mmc_priv(mmc); @@ -1906,7 +1906,7 @@ static struct platform_driver s3cmci_driver = { }, .id_table = s3cmci_driver_ids, .probe = s3cmci_probe, - .remove = __devexit_p(s3cmci_remove), + .remove = s3cmci_remove, .shutdown = s3cmci_shutdown, }; diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c new file mode 100644 index 00000000000..12b0a78497f --- /dev/null +++ b/drivers/mmc/host/sdhci-acpi.c @@ -0,0 +1,312 @@ +/* + * Secure Digital Host Controller Interface ACPI driver. + * + * Copyright (c) 2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <linux/init.h> +#include <linux/export.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/ioport.h> +#include <linux/io.h> +#include <linux/dma-mapping.h> +#include <linux/compiler.h> +#include <linux/stddef.h> +#include <linux/bitops.h> +#include <linux/types.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/acpi.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> + +#include <linux/mmc/host.h> +#include <linux/mmc/pm.h> +#include <linux/mmc/sdhci.h> + +#include "sdhci.h" + +enum { + SDHCI_ACPI_SD_CD = BIT(0), + SDHCI_ACPI_RUNTIME_PM = BIT(1), +}; + +struct sdhci_acpi_chip { + const struct sdhci_ops *ops; + unsigned int quirks; + unsigned int quirks2; + unsigned long caps; + unsigned int caps2; + mmc_pm_flag_t pm_caps; +}; + +struct sdhci_acpi_slot { + const struct sdhci_acpi_chip *chip; + unsigned int quirks; + unsigned int quirks2; + unsigned long caps; + unsigned int caps2; + mmc_pm_flag_t pm_caps; + unsigned int flags; +}; + +struct sdhci_acpi_host { + struct sdhci_host *host; + const struct sdhci_acpi_slot *slot; + struct platform_device *pdev; + bool use_runtime_pm; +}; + +static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag) +{ + return c->slot && (c->slot->flags & flag); +} + +static int sdhci_acpi_enable_dma(struct sdhci_host *host) +{ + return 0; +} + +static const struct sdhci_ops sdhci_acpi_ops_dflt = { + .enable_dma = sdhci_acpi_enable_dma, +}; + +static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { + .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, + .caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD, + .flags = SDHCI_ACPI_RUNTIME_PM, + .pm_caps = MMC_PM_KEEP_POWER, +}; + +static const struct acpi_device_id sdhci_acpi_ids[] = { + { "INT33C6", (kernel_ulong_t)&sdhci_acpi_slot_int_sdio }, + { "PNP0D40" }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids); + +static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid) +{ + const struct acpi_device_id *id; + + for (id = sdhci_acpi_ids; id->id[0]; id++) + if (!strcmp(id->id, hid)) + return (const struct sdhci_acpi_slot *)id->driver_data; + return NULL; +} + +static int __devinit sdhci_acpi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + acpi_handle handle = ACPI_HANDLE(dev); + struct acpi_device *device; + struct sdhci_acpi_host *c; + struct sdhci_host *host; + struct resource *iomem; + resource_size_t len; + const char *hid; + int err; + + if (acpi_bus_get_device(handle, &device)) + return -ENODEV; + + if (acpi_bus_get_status(device) || !device->status.present) + return -ENODEV; + + hid = acpi_device_hid(device); + + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!iomem) + return -ENOMEM; + + len = resource_size(iomem); + if (len < 0x100) + dev_err(dev, "Invalid iomem size!\n"); + + if (!devm_request_mem_region(dev, iomem->start, len, dev_name(dev))) + return -ENOMEM; + + host = sdhci_alloc_host(dev, sizeof(struct sdhci_acpi_host)); + if (IS_ERR(host)) + return PTR_ERR(host); + + c = sdhci_priv(host); + c->host = host; + c->slot = sdhci_acpi_get_slot(hid); + c->pdev = pdev; + c->use_runtime_pm = sdhci_acpi_flag(c, SDHCI_ACPI_RUNTIME_PM); + + platform_set_drvdata(pdev, c); + + host->hw_name = "ACPI"; + host->ops = &sdhci_acpi_ops_dflt; + host->irq = platform_get_irq(pdev, 0); + + host->ioaddr = devm_ioremap_nocache(dev, iomem->start, + resource_size(iomem)); + if (host->ioaddr == NULL) { + err = -ENOMEM; + goto err_free; + } + + if (!dev->dma_mask) { + u64 dma_mask; + + if (sdhci_readl(host, SDHCI_CAPABILITIES) & SDHCI_CAN_64BIT) { + /* 64-bit DMA is not supported at present */ + dma_mask = DMA_BIT_MASK(32); + } else { + dma_mask = DMA_BIT_MASK(32); + } + + dev->dma_mask = &dev->coherent_dma_mask; + dev->coherent_dma_mask = dma_mask; + } + + if (c->slot) { + if (c->slot->chip) { + host->ops = c->slot->chip->ops; + host->quirks |= c->slot->chip->quirks; + host->quirks2 |= c->slot->chip->quirks2; + host->mmc->caps |= c->slot->chip->caps; + host->mmc->caps2 |= c->slot->chip->caps2; + host->mmc->pm_caps |= c->slot->chip->pm_caps; + } + host->quirks |= c->slot->quirks; + host->quirks2 |= c->slot->quirks2; + host->mmc->caps |= c->slot->caps; + host->mmc->caps2 |= c->slot->caps2; + host->mmc->pm_caps |= c->slot->pm_caps; + } + + err = sdhci_add_host(host); + if (err) + goto err_free; + + if (c->use_runtime_pm) { + pm_suspend_ignore_children(dev, 1); + pm_runtime_set_autosuspend_delay(dev, 50); + pm_runtime_use_autosuspend(dev); + pm_runtime_enable(dev); + } + + return 0; + +err_free: + platform_set_drvdata(pdev, NULL); + sdhci_free_host(c->host); + return err; +} + +static int __devexit sdhci_acpi_remove(struct platform_device *pdev) +{ + struct sdhci_acpi_host *c = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + int dead; + + if (c->use_runtime_pm) { + pm_runtime_get_sync(dev); + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + } + + dead = (sdhci_readl(c->host, SDHCI_INT_STATUS) == ~0); + sdhci_remove_host(c->host, dead); + platform_set_drvdata(pdev, NULL); + sdhci_free_host(c->host); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP + +static int sdhci_acpi_suspend(struct device *dev) +{ + struct sdhci_acpi_host *c = dev_get_drvdata(dev); + + return sdhci_suspend_host(c->host); +} + +static int sdhci_acpi_resume(struct device *dev) +{ + struct sdhci_acpi_host *c = dev_get_drvdata(dev); + + return sdhci_resume_host(c->host); +} + +#else + +#define sdhci_acpi_suspend NULL +#define sdhci_acpi_resume NULL + +#endif + +#ifdef CONFIG_PM_RUNTIME + +static int sdhci_acpi_runtime_suspend(struct device *dev) +{ + struct sdhci_acpi_host *c = dev_get_drvdata(dev); + + return sdhci_runtime_suspend_host(c->host); +} + +static int sdhci_acpi_runtime_resume(struct device *dev) +{ + struct sdhci_acpi_host *c = dev_get_drvdata(dev); + + return sdhci_runtime_resume_host(c->host); +} + +static int sdhci_acpi_runtime_idle(struct device *dev) +{ + return 0; +} + +#else + +#define sdhci_acpi_runtime_suspend NULL +#define sdhci_acpi_runtime_resume NULL +#define sdhci_acpi_runtime_idle NULL + +#endif + +static const struct dev_pm_ops sdhci_acpi_pm_ops = { + .suspend = sdhci_acpi_suspend, + .resume = sdhci_acpi_resume, + .runtime_suspend = sdhci_acpi_runtime_suspend, + .runtime_resume = sdhci_acpi_runtime_resume, + .runtime_idle = sdhci_acpi_runtime_idle, +}; + +static struct platform_driver sdhci_acpi_driver = { + .driver = { + .name = "sdhci-acpi", + .owner = THIS_MODULE, + .acpi_match_table = sdhci_acpi_ids, + .pm = &sdhci_acpi_pm_ops, + }, + .probe = sdhci_acpi_probe, + .remove = __devexit_p(sdhci_acpi_remove), +}; + +module_platform_driver(sdhci_acpi_driver); + +MODULE_DESCRIPTION("Secure Digital Host Controller Interface ACPI driver"); +MODULE_AUTHOR("Adrian Hunter"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c index 28a870804f6..30bfdc4ae52 100644 --- a/drivers/mmc/host/sdhci-cns3xxx.c +++ b/drivers/mmc/host/sdhci-cns3xxx.c @@ -95,12 +95,12 @@ static struct sdhci_pltfm_data sdhci_cns3xxx_pdata = { SDHCI_QUIRK_NONSTANDARD_CLOCK, }; -static int __devinit sdhci_cns3xxx_probe(struct platform_device *pdev) +static int sdhci_cns3xxx_probe(struct platform_device *pdev) { return sdhci_pltfm_register(pdev, &sdhci_cns3xxx_pdata); } -static int __devexit sdhci_cns3xxx_remove(struct platform_device *pdev) +static int sdhci_cns3xxx_remove(struct platform_device *pdev) { return sdhci_pltfm_unregister(pdev); } @@ -112,7 +112,7 @@ static struct platform_driver sdhci_cns3xxx_driver = { .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_cns3xxx_probe, - .remove = __devexit_p(sdhci_cns3xxx_remove), + .remove = sdhci_cns3xxx_remove, }; module_platform_driver(sdhci_cns3xxx_driver); diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index 8fd50a21103..169fab91778 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c @@ -19,20 +19,30 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/err.h> -#include <linux/io.h> #include <linux/clk.h> #include <linux/err.h> -#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/io.h> #include <linux/mmc/host.h> +#include <linux/module.h> #include <linux/of.h> +#include <linux/of_gpio.h> #include "sdhci-pltfm.h" struct sdhci_dove_priv { struct clk *clk; + int gpio_cd; }; +static irqreturn_t sdhci_dove_carddetect_irq(int irq, void *data) +{ + struct sdhci_host *host = data; + + tasklet_schedule(&host->card_tasklet); + return IRQ_HANDLED; +} + static u16 sdhci_dove_readw(struct sdhci_host *host, int reg) { u16 ret; @@ -50,16 +60,25 @@ static u16 sdhci_dove_readw(struct sdhci_host *host, int reg) static u32 sdhci_dove_readl(struct sdhci_host *host, int reg) { + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_dove_priv *priv = pltfm_host->priv; u32 ret; + ret = readl(host->ioaddr + reg); + switch (reg) { case SDHCI_CAPABILITIES: - ret = readl(host->ioaddr + reg); /* Mask the support for 3.0V */ ret &= ~SDHCI_CAN_VDD_300; break; - default: - ret = readl(host->ioaddr + reg); + case SDHCI_PRESENT_STATE: + if (gpio_is_valid(priv->gpio_cd)) { + if (gpio_get_value(priv->gpio_cd) == 0) + ret |= SDHCI_CARD_PRESENT; + else + ret &= ~SDHCI_CARD_PRESENT; + } + break; } return ret; } @@ -78,7 +97,7 @@ static struct sdhci_pltfm_data sdhci_dove_pdata = { SDHCI_QUIRK_NO_HISPD_BIT, }; -static int __devinit sdhci_dove_probe(struct platform_device *pdev) +static int sdhci_dove_probe(struct platform_device *pdev) { struct sdhci_host *host; struct sdhci_pltfm_host *pltfm_host; @@ -92,29 +111,74 @@ static int __devinit sdhci_dove_probe(struct platform_device *pdev) return -ENOMEM; } - priv->clk = clk_get(&pdev->dev, NULL); - if (!IS_ERR(priv->clk)) - clk_prepare_enable(priv->clk); + priv->clk = devm_clk_get(&pdev->dev, NULL); - ret = sdhci_pltfm_register(pdev, &sdhci_dove_pdata); - if (ret) - goto sdhci_dove_register_fail; + if (pdev->dev.of_node) { + priv->gpio_cd = of_get_named_gpio(pdev->dev.of_node, + "cd-gpios", 0); + } else { + priv->gpio_cd = -EINVAL; + } + + if (gpio_is_valid(priv->gpio_cd)) { + ret = gpio_request(priv->gpio_cd, "sdhci-cd"); + if (ret) { + dev_err(&pdev->dev, "card detect gpio request failed: %d\n", + ret); + return ret; + } + gpio_direction_input(priv->gpio_cd); + } + + host = sdhci_pltfm_init(pdev, &sdhci_dove_pdata); + if (IS_ERR(host)) { + ret = PTR_ERR(host); + goto err_sdhci_pltfm_init; + } - host = platform_get_drvdata(pdev); pltfm_host = sdhci_priv(host); pltfm_host->priv = priv; + if (!IS_ERR(priv->clk)) + clk_prepare_enable(priv->clk); + + sdhci_get_of_property(pdev); + + ret = sdhci_add_host(host); + if (ret) + goto err_sdhci_add; + + /* + * We must request the IRQ after sdhci_add_host(), as the tasklet only + * gets setup in sdhci_add_host() and we oops. + */ + if (gpio_is_valid(priv->gpio_cd)) { + ret = request_irq(gpio_to_irq(priv->gpio_cd), + sdhci_dove_carddetect_irq, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + mmc_hostname(host->mmc), host); + if (ret) { + dev_err(&pdev->dev, "card detect irq request failed: %d\n", + ret); + goto err_request_irq; + } + } + return 0; -sdhci_dove_register_fail: - if (!IS_ERR(priv->clk)) { +err_request_irq: + sdhci_remove_host(host, 0); +err_sdhci_add: + if (!IS_ERR(priv->clk)) clk_disable_unprepare(priv->clk); - clk_put(priv->clk); - } + sdhci_pltfm_free(pdev); +err_sdhci_pltfm_init: + if (gpio_is_valid(priv->gpio_cd)) + gpio_free(priv->gpio_cd); return ret; } -static int __devexit sdhci_dove_remove(struct platform_device *pdev) +static int sdhci_dove_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -122,14 +186,18 @@ static int __devexit sdhci_dove_remove(struct platform_device *pdev) sdhci_pltfm_unregister(pdev); - if (!IS_ERR(priv->clk)) { - clk_disable_unprepare(priv->clk); - clk_put(priv->clk); + if (gpio_is_valid(priv->gpio_cd)) { + free_irq(gpio_to_irq(priv->gpio_cd), host); + gpio_free(priv->gpio_cd); } + + if (!IS_ERR(priv->clk)) + clk_disable_unprepare(priv->clk); + return 0; } -static const struct of_device_id sdhci_dove_of_match_table[] __devinitdata = { +static const struct of_device_id sdhci_dove_of_match_table[] = { { .compatible = "marvell,dove-sdhci", }, {} }; @@ -143,7 +211,7 @@ static struct platform_driver sdhci_dove_driver = { .of_match_table = of_match_ptr(sdhci_dove_of_match_table), }, .probe = sdhci_dove_probe, - .remove = __devexit_p(sdhci_dove_remove), + .remove = sdhci_dove_remove, }; module_platform_driver(sdhci_dove_driver); diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index effc2acfe77..e07df812ff1 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -403,7 +403,7 @@ static irqreturn_t cd_irq(int irq, void *data) }; #ifdef CONFIG_OF -static int __devinit +static int sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, struct esdhc_platform_data *boarddata) { @@ -440,7 +440,7 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, } #endif -static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) +static int sdhci_esdhc_imx_probe(struct platform_device *pdev) { const struct of_device_id *of_id = of_match_device(imx_esdhc_dt_ids, &pdev->dev); @@ -456,10 +456,10 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) pltfm_host = sdhci_priv(host); - imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL); + imx_data = devm_kzalloc(&pdev->dev, sizeof(*imx_data), GFP_KERNEL); if (!imx_data) { err = -ENOMEM; - goto err_imx_data; + goto free_sdhci; } if (of_id) @@ -470,19 +470,19 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(imx_data->clk_ipg)) { err = PTR_ERR(imx_data->clk_ipg); - goto err_clk_get; + goto free_sdhci; } imx_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); if (IS_ERR(imx_data->clk_ahb)) { err = PTR_ERR(imx_data->clk_ahb); - goto err_clk_get; + goto free_sdhci; } imx_data->clk_per = devm_clk_get(&pdev->dev, "per"); if (IS_ERR(imx_data->clk_per)) { err = PTR_ERR(imx_data->clk_per); - goto err_clk_get; + goto free_sdhci; } pltfm_host->clk = imx_data->clk_per; @@ -494,7 +494,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev); if (IS_ERR(imx_data->pinctrl)) { err = PTR_ERR(imx_data->pinctrl); - goto pin_err; + goto disable_clk; } host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; @@ -519,7 +519,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) if (!host->mmc->parent->platform_data) { dev_err(mmc_dev(host->mmc), "no board data!\n"); err = -EINVAL; - goto no_board_data; + goto disable_clk; } imx_data->boarddata = *((struct esdhc_platform_data *) host->mmc->parent->platform_data); @@ -527,7 +527,8 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) /* write_protect */ if (boarddata->wp_type == ESDHC_WP_GPIO) { - err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); + err = devm_gpio_request_one(&pdev->dev, boarddata->wp_gpio, + GPIOF_IN, "ESDHC_WP"); if (err) { dev_warn(mmc_dev(host->mmc), "no write-protect pin available!\n"); @@ -543,19 +544,21 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) switch (boarddata->cd_type) { case ESDHC_CD_GPIO: - err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD"); + err = devm_gpio_request_one(&pdev->dev, boarddata->cd_gpio, + GPIOF_IN, "ESDHC_CD"); if (err) { dev_err(mmc_dev(host->mmc), "no card-detect pin available!\n"); - goto no_card_detect_pin; + goto disable_clk; } - err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq, + err = devm_request_irq(&pdev->dev, + gpio_to_irq(boarddata->cd_gpio), cd_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, mmc_hostname(host->mmc), host); if (err) { dev_err(mmc_dev(host->mmc), "request irq error\n"); - goto no_card_detect_irq; + goto disable_clk; } /* fall through */ @@ -574,55 +577,32 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) err = sdhci_add_host(host); if (err) - goto err_add_host; + goto disable_clk; return 0; -err_add_host: - if (gpio_is_valid(boarddata->cd_gpio)) - free_irq(gpio_to_irq(boarddata->cd_gpio), host); -no_card_detect_irq: - if (gpio_is_valid(boarddata->cd_gpio)) - gpio_free(boarddata->cd_gpio); - if (gpio_is_valid(boarddata->wp_gpio)) - gpio_free(boarddata->wp_gpio); -no_card_detect_pin: -no_board_data: -pin_err: +disable_clk: clk_disable_unprepare(imx_data->clk_per); clk_disable_unprepare(imx_data->clk_ipg); clk_disable_unprepare(imx_data->clk_ahb); -err_clk_get: - kfree(imx_data); -err_imx_data: +free_sdhci: sdhci_pltfm_free(pdev); return err; } -static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev) +static int sdhci_esdhc_imx_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct pltfm_imx_data *imx_data = pltfm_host->priv; - struct esdhc_platform_data *boarddata = &imx_data->boarddata; int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); sdhci_remove_host(host, dead); - if (gpio_is_valid(boarddata->wp_gpio)) - gpio_free(boarddata->wp_gpio); - - if (gpio_is_valid(boarddata->cd_gpio)) { - free_irq(gpio_to_irq(boarddata->cd_gpio), host); - gpio_free(boarddata->cd_gpio); - } - clk_disable_unprepare(imx_data->clk_per); clk_disable_unprepare(imx_data->clk_ipg); clk_disable_unprepare(imx_data->clk_ahb); - kfree(imx_data); - sdhci_pltfm_free(pdev); return 0; @@ -637,7 +617,7 @@ static struct platform_driver sdhci_esdhc_imx_driver = { }, .id_table = imx_esdhc_devtype, .probe = sdhci_esdhc_imx_probe, - .remove = __devexit_p(sdhci_esdhc_imx_remove), + .remove = sdhci_esdhc_imx_remove, }; module_platform_driver(sdhci_esdhc_imx_driver); diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 63d219f57ca..f32526d2d96 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -22,6 +22,7 @@ #include "sdhci-esdhc.h" #define VENDOR_V_22 0x12 +#define VENDOR_V_23 0x13 static u32 esdhc_readl(struct sdhci_host *host, int reg) { u32 ret; @@ -85,6 +86,18 @@ static u8 esdhc_readb(struct sdhci_host *host, int reg) return ret; } +static void esdhc_writel(struct sdhci_host *host, u32 val, int reg) +{ + /* + * Enable IRQSTATEN[BGESEN] is just to set IRQSTAT[BGE] + * when SYSCTL[RSTD]) is set for some special operations. + * No any impact other operation. + */ + if (reg == SDHCI_INT_ENABLE) + val |= SDHCI_INT_BLK_GAP; + sdhci_be32bs_writel(host, val, reg); +} + static void esdhc_writew(struct sdhci_host *host, u16 val, int reg) { if (reg == SDHCI_BLOCK_SIZE) { @@ -121,6 +134,41 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg) sdhci_be32bs_writeb(host, val, reg); } +/* + * For Abort or Suspend after Stop at Block Gap, ignore the ADMA + * error(IRQSTAT[ADMAE]) if both Transfer Complete(IRQSTAT[TC]) + * and Block Gap Event(IRQSTAT[BGE]) are also set. + * For Continue, apply soft reset for data(SYSCTL[RSTD]); + * and re-issue the entire read transaction from beginning. + */ +static void esdhci_of_adma_workaround(struct sdhci_host *host, u32 intmask) +{ + u32 tmp; + bool applicable; + dma_addr_t dmastart; + dma_addr_t dmanow; + + tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS); + tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT; + + applicable = (intmask & SDHCI_INT_DATA_END) && + (intmask & SDHCI_INT_BLK_GAP) && + (tmp == VENDOR_V_23); + if (!applicable) + return; + + host->data->error = 0; + dmastart = sg_dma_address(host->data->sg); + dmanow = dmastart + host->data->bytes_xfered; + /* + * Force update to the next DMA block boundary. + */ + dmanow = (dmanow & ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) + + SDHCI_DEFAULT_BOUNDARY_SIZE; + host->data->bytes_xfered = dmanow - dmastart; + sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS); +} + static int esdhc_of_enable_dma(struct sdhci_host *host) { setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP); @@ -177,13 +225,16 @@ static void esdhc_of_platform_init(struct sdhci_host *host) vvn = (vvn & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT; if (vvn == VENDOR_V_22) host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23; + + if (vvn > VENDOR_V_22) + host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; } static struct sdhci_ops sdhci_esdhc_ops = { .read_l = esdhc_readl, .read_w = esdhc_readw, .read_b = esdhc_readb, - .write_l = sdhci_be32bs_writel, + .write_l = esdhc_writel, .write_w = esdhc_writew, .write_b = esdhc_writeb, .set_clock = esdhc_of_set_clock, @@ -195,6 +246,7 @@ static struct sdhci_ops sdhci_esdhc_ops = { .platform_suspend = esdhc_of_suspend, .platform_resume = esdhc_of_resume, #endif + .adma_workaround = esdhci_of_adma_workaround, }; static struct sdhci_pltfm_data sdhci_esdhc_pdata = { @@ -208,12 +260,12 @@ static struct sdhci_pltfm_data sdhci_esdhc_pdata = { .ops = &sdhci_esdhc_ops, }; -static int __devinit sdhci_esdhc_probe(struct platform_device *pdev) +static int sdhci_esdhc_probe(struct platform_device *pdev) { return sdhci_pltfm_register(pdev, &sdhci_esdhc_pdata); } -static int __devexit sdhci_esdhc_remove(struct platform_device *pdev) +static int sdhci_esdhc_remove(struct platform_device *pdev) { return sdhci_pltfm_unregister(pdev); } @@ -234,7 +286,7 @@ static struct platform_driver sdhci_esdhc_driver = { .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_esdhc_probe, - .remove = __devexit_p(sdhci_esdhc_remove), + .remove = sdhci_esdhc_remove, }; module_platform_driver(sdhci_esdhc_driver); diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c index 0ce088ae022..c3d3715ec3d 100644 --- a/drivers/mmc/host/sdhci-of-hlwd.c +++ b/drivers/mmc/host/sdhci-of-hlwd.c @@ -66,12 +66,12 @@ static struct sdhci_pltfm_data sdhci_hlwd_pdata = { .ops = &sdhci_hlwd_ops, }; -static int __devinit sdhci_hlwd_probe(struct platform_device *pdev) +static int sdhci_hlwd_probe(struct platform_device *pdev) { return sdhci_pltfm_register(pdev, &sdhci_hlwd_pdata); } -static int __devexit sdhci_hlwd_remove(struct platform_device *pdev) +static int sdhci_hlwd_remove(struct platform_device *pdev) { return sdhci_pltfm_unregister(pdev); } @@ -90,7 +90,7 @@ static struct platform_driver sdhci_hlwd_driver = { .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_hlwd_probe, - .remove = __devexit_p(sdhci_hlwd_remove), + .remove = sdhci_hlwd_remove, }; module_platform_driver(sdhci_hlwd_driver); diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 04936f353ce..c7dd0cbc99d 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -114,6 +114,7 @@ static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot) SDHCI_TIMEOUT_CLK_UNIT | SDHCI_CAN_VDD_330 | + SDHCI_CAN_DO_HISPD | SDHCI_CAN_DO_SDMA; return 0; } @@ -653,7 +654,7 @@ static const struct sdhci_pci_fixes sdhci_via = { .probe = via_probe, }; -static const struct pci_device_id pci_ids[] __devinitconst = { +static const struct pci_device_id pci_ids[] = { { .vendor = PCI_VENDOR_ID_RICOH, .device = PCI_DEVICE_ID_RICOH_R5C822, @@ -1183,7 +1184,7 @@ static const struct dev_pm_ops sdhci_pci_pm_ops = { * * \*****************************************************************************/ -static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( +static struct sdhci_pci_slot *sdhci_pci_probe_slot( struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar, int slotno) { @@ -1338,7 +1339,7 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) sdhci_free_host(slot->host); } -static void __devinit sdhci_pci_runtime_pm_allow(struct device *dev) +static void sdhci_pci_runtime_pm_allow(struct device *dev) { pm_runtime_put_noidle(dev); pm_runtime_allow(dev); @@ -1347,13 +1348,13 @@ static void __devinit sdhci_pci_runtime_pm_allow(struct device *dev) pm_suspend_ignore_children(dev, 1); } -static void __devexit sdhci_pci_runtime_pm_forbid(struct device *dev) +static void sdhci_pci_runtime_pm_forbid(struct device *dev) { pm_runtime_forbid(dev); pm_runtime_get_noresume(dev); } -static int __devinit sdhci_pci_probe(struct pci_dev *pdev, +static int sdhci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct sdhci_pci_chip *chip; @@ -1445,7 +1446,7 @@ err: return ret; } -static void __devexit sdhci_pci_remove(struct pci_dev *pdev) +static void sdhci_pci_remove(struct pci_dev *pdev) { int i; struct sdhci_pci_chip *chip; @@ -1470,7 +1471,7 @@ static struct pci_driver sdhci_driver = { .name = "sdhci-pci", .id_table = pci_ids, .probe = sdhci_pci_probe, - .remove = __devexit_p(sdhci_pci_remove), + .remove = sdhci_pci_remove, .driver = { .pm = &sdhci_pci_pm_ops }, diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 27164457f86..d4283ef5917 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -78,6 +78,9 @@ void sdhci_get_of_property(struct platform_device *pdev) if (of_get_property(np, "broken-cd", NULL)) host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; + if (of_get_property(np, "no-1-8-v", NULL)) + host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; + if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc")) host->quirks |= SDHCI_QUIRK_BROKEN_DMA; @@ -89,6 +92,12 @@ void sdhci_get_of_property(struct platform_device *pdev) clk = of_get_property(np, "clock-frequency", &size); if (clk && size == sizeof(*clk) && *clk) pltfm_host->clock = be32_to_cpup(clk); + + if (of_find_property(np, "keep-power-in-suspend", NULL)) + host->mmc->pm_caps |= MMC_PM_KEEP_POWER; + + if (of_find_property(np, "enable-sdio-wakeup", NULL)) + host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; } } #else diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index 8e63a9c04e3..ac854aa192a 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -166,7 +166,7 @@ static inline struct sdhci_pxa_platdata *pxav2_get_mmc_pdata(struct device *dev) } #endif -static int __devinit sdhci_pxav2_probe(struct platform_device *pdev) +static int sdhci_pxav2_probe(struct platform_device *pdev) { struct sdhci_pltfm_host *pltfm_host; struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; @@ -247,7 +247,7 @@ err_clk_get: return ret; } -static int __devexit sdhci_pxav2_remove(struct platform_device *pdev) +static int sdhci_pxav2_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -275,7 +275,7 @@ static struct platform_driver sdhci_pxav2_driver = { .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_pxav2_probe, - .remove = __devexit_p(sdhci_pxav2_remove), + .remove = sdhci_pxav2_remove, }; module_platform_driver(sdhci_pxav2_driver); diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index e918a2bb3af..fad0966427f 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -163,10 +163,18 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) return 0; } +static u32 pxav3_get_max_clock(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + + return clk_get_rate(pltfm_host->clk); +} + static struct sdhci_ops pxav3_sdhci_ops = { .platform_reset_exit = pxav3_set_private_registers, .set_uhs_signaling = pxav3_set_uhs_signaling, .platform_send_init_74_clocks = pxav3_gen_init_74_clocks, + .get_max_clock = pxav3_get_max_clock, }; #ifdef CONFIG_OF @@ -214,7 +222,7 @@ static inline struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev) } #endif -static int __devinit sdhci_pxav3_probe(struct platform_device *pdev) +static int sdhci_pxav3_probe(struct platform_device *pdev) { struct sdhci_pltfm_host *pltfm_host; struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; @@ -249,7 +257,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev) host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC - | SDHCI_QUIRK_32BIT_ADMA_SIZE; + | SDHCI_QUIRK_32BIT_ADMA_SIZE + | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN; /* enable 1/8V DDR capable */ host->mmc->caps |= MMC_CAP_1_8V_DDR; @@ -271,6 +280,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev) if (pdata->quirks) host->quirks |= pdata->quirks; + if (pdata->quirks2) + host->quirks2 |= pdata->quirks2; if (pdata->host_caps) host->mmc->caps |= pdata->host_caps; if (pdata->host_caps2) @@ -313,7 +324,7 @@ err_clk_get: return ret; } -static int __devexit sdhci_pxav3_remove(struct platform_device *pdev) +static int sdhci_pxav3_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -346,7 +357,7 @@ static struct platform_driver sdhci_pxav3_driver = { .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_pxav3_probe, - .remove = __devexit_p(sdhci_pxav3_remove), + .remove = sdhci_pxav3_remove, }; module_platform_driver(sdhci_pxav3_driver); diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index a54dd5d7a5f..82a8de148a8 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -24,6 +24,7 @@ #include <linux/of_gpio.h> #include <linux/pm.h> #include <linux/pm_runtime.h> +#include <linux/pinctrl/consumer.h> #include <linux/mmc/host.h> @@ -57,6 +58,7 @@ struct sdhci_s3c { int ext_cd_irq; int ext_cd_gpio; int *gpios; + struct pinctrl *pctrl; struct clk *clk_io; struct clk *clk_bus[MAX_BUS_CLK]; @@ -373,18 +375,27 @@ static struct sdhci_ops sdhci_s3c_ops = { static void sdhci_s3c_notify_change(struct platform_device *dev, int state) { struct sdhci_host *host = platform_get_drvdata(dev); +#ifdef CONFIG_PM_RUNTIME + struct sdhci_s3c *sc = sdhci_priv(host); +#endif unsigned long flags; if (host) { spin_lock_irqsave(&host->lock, flags); if (state) { dev_dbg(&dev->dev, "card inserted.\n"); +#ifdef CONFIG_PM_RUNTIME + clk_prepare_enable(sc->clk_io); +#endif host->flags &= ~SDHCI_DEVICE_DEAD; host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; } else { dev_dbg(&dev->dev, "card removed.\n"); host->flags |= SDHCI_DEVICE_DEAD; host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; +#ifdef CONFIG_PM_RUNTIME + clk_disable_unprepare(sc->clk_io); +#endif } tasklet_schedule(&host->card_tasklet); spin_unlock_irqrestore(&host->lock, flags); @@ -406,7 +417,7 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc) struct s3c_sdhci_platdata *pdata = sc->pdata; struct device *dev = &sc->pdev->dev; - if (gpio_request(pdata->ext_cd_gpio, "SDHCI EXT CD") == 0) { + if (devm_gpio_request(dev, pdata->ext_cd_gpio, "SDHCI EXT CD") == 0) { sc->ext_cd_gpio = pdata->ext_cd_gpio; sc->ext_cd_irq = gpio_to_irq(pdata->ext_cd_gpio); if (sc->ext_cd_irq && @@ -430,7 +441,7 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc) } #ifdef CONFIG_OF -static int __devinit sdhci_s3c_parse_dt(struct device *dev, +static int sdhci_s3c_parse_dt(struct device *dev, struct sdhci_host *host, struct s3c_sdhci_platdata *pdata) { struct device_node *node = dev->of_node; @@ -449,12 +460,12 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev, return -ENOMEM; /* get the card detection method */ - if (of_get_property(node, "broken-cd", 0)) { + if (of_get_property(node, "broken-cd", NULL)) { pdata->cd_type = S3C_SDHCI_CD_NONE; goto setup_bus; } - if (of_get_property(node, "non-removable", 0)) { + if (of_get_property(node, "non-removable", NULL)) { pdata->cd_type = S3C_SDHCI_CD_PERMANENT; goto setup_bus; } @@ -477,8 +488,9 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev, return -EINVAL; } - dev_info(dev, "assuming no card detect line available\n"); - pdata->cd_type = S3C_SDHCI_CD_NONE; + /* assuming internal card detect that will be configured by pinctrl */ + pdata->cd_type = S3C_SDHCI_CD_INTERNAL; + goto setup_bus; found_cd: if (pdata->cd_type == S3C_SDHCI_CD_GPIO) { @@ -487,7 +499,7 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev, if (of_get_property(node, "cd-inverted", NULL)) pdata->ext_cd_gpio_invert = 1; } else if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { - ret = gpio_request(gpio, "sdhci-cd"); + ret = devm_gpio_request(dev, gpio, "sdhci-cd"); if (ret) { dev_err(dev, "card detect gpio request failed\n"); return -EINVAL; @@ -496,36 +508,31 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev, } setup_bus: + if (!IS_ERR(ourhost->pctrl)) + return 0; + /* get the gpios for command, clock and data lines */ for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) { gpio = of_get_gpio(node, cnt); if (!gpio_is_valid(gpio)) { dev_err(dev, "invalid gpio[%d]\n", cnt); - goto err_free_dt_cd_gpio; + return -EINVAL; } ourhost->gpios[cnt] = gpio; } for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) { - ret = gpio_request(ourhost->gpios[cnt], "sdhci-gpio"); + ret = devm_gpio_request(dev, ourhost->gpios[cnt], "sdhci-gpio"); if (ret) { dev_err(dev, "gpio[%d] request failed\n", cnt); - goto err_free_dt_gpios; + return -EINVAL; } } return 0; - - err_free_dt_gpios: - while (--cnt >= 0) - gpio_free(ourhost->gpios[cnt]); - err_free_dt_cd_gpio: - if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) - gpio_free(ourhost->ext_cd_gpio); - return -EINVAL; } #else -static int __devinit sdhci_s3c_parse_dt(struct device *dev, +static int sdhci_s3c_parse_dt(struct device *dev, struct sdhci_host *host, struct s3c_sdhci_platdata *pdata) { return -EINVAL; @@ -548,7 +555,7 @@ static inline struct sdhci_s3c_drv_data *sdhci_s3c_get_driver_data( platform_get_device_id(pdev)->driver_data; } -static int __devinit sdhci_s3c_probe(struct platform_device *pdev) +static int sdhci_s3c_probe(struct platform_device *pdev) { struct s3c_sdhci_platdata *pdata; struct sdhci_s3c_drv_data *drv_data; @@ -579,13 +586,15 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) { ret = -ENOMEM; - goto err_pdata; + goto err_pdata_io_clk; } + sc->pctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (pdev->dev.of_node) { ret = sdhci_s3c_parse_dt(&pdev->dev, host, pdata); if (ret) - goto err_pdata; + goto err_pdata_io_clk; } else { memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata)); sc->ext_cd_gpio = -1; /* invalid gpio number */ @@ -603,7 +612,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) if (IS_ERR(sc->clk_io)) { dev_err(dev, "failed to get io clock\n"); ret = PTR_ERR(sc->clk_io); - goto err_io_clk; + goto err_pdata_io_clk; } /* enable the local io clock and keep it running for the moment. */ @@ -766,19 +775,13 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) clk_disable_unprepare(sc->clk_io); clk_put(sc->clk_io); - err_io_clk: - for (ptr = 0; ptr < NUM_GPIOS(sc->pdata->max_width); ptr++) - gpio_free(sc->gpios[ptr]); - if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) - gpio_free(sc->ext_cd_gpio); - - err_pdata: + err_pdata_io_clk: sdhci_free_host(host); return ret; } -static int __devexit sdhci_s3c_remove(struct platform_device *pdev) +static int sdhci_s3c_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_s3c *sc = sdhci_priv(host); @@ -791,9 +794,6 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev) if (sc->ext_cd_irq) free_irq(sc->ext_cd_irq, sc); - if (gpio_is_valid(sc->ext_cd_gpio)) - gpio_free(sc->ext_cd_gpio); - #ifdef CONFIG_PM_RUNTIME if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL) clk_prepare_enable(sc->clk_io); @@ -814,11 +814,6 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev) clk_disable_unprepare(sc->clk_io); clk_put(sc->clk_io); - if (pdev->dev.of_node) { - for (ptr = 0; ptr < NUM_GPIOS(sc->pdata->max_width); ptr++) - gpio_free(sc->gpios[ptr]); - } - sdhci_free_host(host); platform_set_drvdata(pdev, NULL); @@ -916,7 +911,7 @@ MODULE_DEVICE_TABLE(of, sdhci_s3c_dt_match); static struct platform_driver sdhci_s3c_driver = { .probe = sdhci_s3c_probe, - .remove = __devexit_p(sdhci_s3c_remove), + .remove = sdhci_s3c_remove, .id_table = sdhci_s3c_driver_ids, .driver = { .owner = THIS_MODULE, diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index 6be89c032de..c6ece0bd03b 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -71,8 +71,7 @@ static irqreturn_t sdhci_gpio_irq(int irq, void *dev_id) } #ifdef CONFIG_OF -static struct sdhci_plat_data * __devinit -sdhci_probe_config_dt(struct platform_device *pdev) +static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct sdhci_plat_data *pdata = NULL; @@ -96,14 +95,13 @@ sdhci_probe_config_dt(struct platform_device *pdev) return pdata; } #else -static struct sdhci_plat_data * __devinit -sdhci_probe_config_dt(struct platform_device *pdev) +static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pdev) { return ERR_PTR(-ENOSYS); } #endif -static int __devinit sdhci_probe(struct platform_device *pdev) +static int sdhci_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct sdhci_host *host; @@ -146,6 +144,11 @@ static int __devinit sdhci_probe(struct platform_device *pdev) goto put_clk; } + ret = clk_set_rate(sdhci->clk, 50000000); + if (ret) + dev_dbg(&pdev->dev, "Error setting desired clk, clk=%lu\n", + clk_get_rate(sdhci->clk)); + if (np) { sdhci->data = sdhci_probe_config_dt(pdev); if (IS_ERR(sdhci->data)) { @@ -268,7 +271,7 @@ err: return ret; } -static int __devexit sdhci_remove(struct platform_device *pdev) +static int sdhci_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev); @@ -297,7 +300,7 @@ static int sdhci_suspend(struct device *dev) ret = sdhci_suspend_host(host); if (!ret) - clk_disable_unprepare(sdhci->clk); + clk_disable(sdhci->clk); return ret; } @@ -308,7 +311,7 @@ static int sdhci_resume(struct device *dev) struct spear_sdhci *sdhci = dev_get_platdata(dev); int ret; - ret = clk_prepare_enable(sdhci->clk); + ret = clk_enable(sdhci->clk); if (ret) { dev_dbg(dev, "Resume: Error enabling clock\n"); return ret; @@ -336,7 +339,7 @@ static struct platform_driver sdhci_driver = { .of_match_table = of_match_ptr(sdhci_spear_id_table), }, .probe = sdhci_probe, - .remove = __devexit_p(sdhci_remove), + .remove = sdhci_remove, }; module_platform_driver(sdhci_driver); diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index f9eb9162370..3695b2e0cbd 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -206,7 +206,7 @@ static struct sdhci_tegra_soc_data soc_data_tegra30 = { }; #endif -static const struct of_device_id sdhci_tegra_dt_match[] __devinitdata = { +static const struct of_device_id sdhci_tegra_dt_match[] = { #ifdef CONFIG_ARCH_TEGRA_3x_SOC { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 }, #endif @@ -217,7 +217,7 @@ static const struct of_device_id sdhci_tegra_dt_match[] __devinitdata = { }; MODULE_DEVICE_TABLE(of, sdhci_dt_ids); -static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata( +static struct tegra_sdhci_platform_data *sdhci_tegra_dt_parse_pdata( struct platform_device *pdev) { struct tegra_sdhci_platform_data *plat; @@ -244,7 +244,7 @@ static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata( return plat; } -static int __devinit sdhci_tegra_probe(struct platform_device *pdev) +static int sdhci_tegra_probe(struct platform_device *pdev) { const struct of_device_id *match; const struct sdhci_tegra_soc_data *soc_data; @@ -370,7 +370,7 @@ err_no_plat: return rc; } -static int __devexit sdhci_tegra_remove(struct platform_device *pdev) +static int sdhci_tegra_remove(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -407,7 +407,7 @@ static struct platform_driver sdhci_tegra_driver = { .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_tegra_probe, - .remove = __devexit_p(sdhci_tegra_remove), + .remove = sdhci_tegra_remove, }; module_platform_driver(sdhci_tegra_driver); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index c7851c0aabc..6f0bfc0c8c9 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1618,7 +1618,7 @@ static int sdhci_do_3_3v_signal_voltage_switch(struct sdhci_host *host, sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); if (host->vqmmc) { - ret = regulator_set_voltage(host->vqmmc, 3300000, 3300000); + ret = regulator_set_voltage(host->vqmmc, 2700000, 3600000); if (ret) { pr_warning("%s: Switching to 3.3V signalling voltage " " failed\n", mmc_hostname(host->mmc)); @@ -1662,7 +1662,7 @@ static int sdhci_do_1_8v_signal_voltage_switch(struct sdhci_host *host, */ if (host->vqmmc) ret = regulator_set_voltage(host->vqmmc, - 1800000, 1800000); + 1700000, 1950000); else ret = 0; @@ -1994,30 +1994,11 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) sdhci_runtime_pm_put(host); } -static const struct mmc_host_ops sdhci_ops = { - .request = sdhci_request, - .set_ios = sdhci_set_ios, - .get_ro = sdhci_get_ro, - .hw_reset = sdhci_hw_reset, - .enable_sdio_irq = sdhci_enable_sdio_irq, - .start_signal_voltage_switch = sdhci_start_signal_voltage_switch, - .execute_tuning = sdhci_execute_tuning, - .enable_preset_value = sdhci_enable_preset_value, -}; - -/*****************************************************************************\ - * * - * Tasklets * - * * -\*****************************************************************************/ - -static void sdhci_tasklet_card(unsigned long param) +static void sdhci_card_event(struct mmc_host *mmc) { - struct sdhci_host *host; + struct sdhci_host *host = mmc_priv(mmc); unsigned long flags; - host = (struct sdhci_host*)param; - spin_lock_irqsave(&host->lock, flags); /* Check host->mrq first in case we are runtime suspended */ @@ -2036,6 +2017,31 @@ static void sdhci_tasklet_card(unsigned long param) } spin_unlock_irqrestore(&host->lock, flags); +} + +static const struct mmc_host_ops sdhci_ops = { + .request = sdhci_request, + .set_ios = sdhci_set_ios, + .get_ro = sdhci_get_ro, + .hw_reset = sdhci_hw_reset, + .enable_sdio_irq = sdhci_enable_sdio_irq, + .start_signal_voltage_switch = sdhci_start_signal_voltage_switch, + .execute_tuning = sdhci_execute_tuning, + .enable_preset_value = sdhci_enable_preset_value, + .card_event = sdhci_card_event, +}; + +/*****************************************************************************\ + * * + * Tasklets * + * * +\*****************************************************************************/ + +static void sdhci_tasklet_card(unsigned long param) +{ + struct sdhci_host *host = (struct sdhci_host*)param; + + sdhci_card_event(host->mmc); mmc_detect_change(host->mmc, msecs_to_jiffies(200)); } @@ -2282,6 +2288,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) pr_err("%s: ADMA error\n", mmc_hostname(host->mmc)); sdhci_show_adma_error(host); host->data->error = -EIO; + if (host->ops->adma_workaround) + host->ops->adma_workaround(host, intmask); } if (host->data->error) @@ -2858,10 +2866,16 @@ int sdhci_add_host(struct sdhci_host *host) mmc_hostname(mmc)); host->vqmmc = NULL; } - } - else if (regulator_is_supported_voltage(host->vqmmc, 1800000, 1800000)) + } else { regulator_enable(host->vqmmc); - else + if (!regulator_is_supported_voltage(host->vqmmc, 1700000, + 1950000)) + caps[1] &= ~(SDHCI_SUPPORT_SDR104 | + SDHCI_SUPPORT_SDR50 | + SDHCI_SUPPORT_DDR50); + } + + if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) caps[1] &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50); @@ -2919,21 +2933,18 @@ int sdhci_add_host(struct sdhci_host *host) mmc_hostname(mmc)); host->vmmc = NULL; } - } else - regulator_enable(host->vmmc); + } #ifdef CONFIG_REGULATOR if (host->vmmc) { - ret = regulator_is_supported_voltage(host->vmmc, 3300000, - 3300000); + ret = regulator_is_supported_voltage(host->vmmc, 2700000, + 3600000); if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_330))) caps[0] &= ~SDHCI_CAN_VDD_330; - ret = regulator_is_supported_voltage(host->vmmc, 3000000, - 3000000); if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_300))) caps[0] &= ~SDHCI_CAN_VDD_300; - ret = regulator_is_supported_voltage(host->vmmc, 1800000, - 1800000); + ret = regulator_is_supported_voltage(host->vmmc, 1700000, + 1950000); if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_180))) caps[0] &= ~SDHCI_CAN_VDD_180; } diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 71a4a7ed46c..a6d69b7bdea 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -120,6 +120,7 @@ #define SDHCI_SIGNAL_ENABLE 0x38 #define SDHCI_INT_RESPONSE 0x00000001 #define SDHCI_INT_DATA_END 0x00000002 +#define SDHCI_INT_BLK_GAP 0x00000004 #define SDHCI_INT_DMA_END 0x00000008 #define SDHCI_INT_SPACE_AVAIL 0x00000010 #define SDHCI_INT_DATA_AVAIL 0x00000020 @@ -146,7 +147,8 @@ #define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \ SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \ SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ - SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR) + SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \ + SDHCI_INT_BLK_GAP) #define SDHCI_INT_ALL_MASK ((unsigned int)-1) #define SDHCI_ACMD12_ERR 0x3C @@ -278,6 +280,7 @@ struct sdhci_ops { void (*hw_reset)(struct sdhci_host *host); void (*platform_suspend)(struct sdhci_host *host); void (*platform_resume)(struct sdhci_host *host); + void (*adma_workaround)(struct sdhci_host *host, u32 intmask); void (*platform_init)(struct sdhci_host *host); }; diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index d25bc97dc5c..9a4c151067d 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1104,7 +1104,6 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id) { struct sh_mmcif_host *host = dev_id; struct mmc_request *mrq = host->mrq; - struct mmc_data *data = mrq->data; cancel_delayed_work_sync(&host->timeout_work); @@ -1152,13 +1151,14 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id) case MMCIF_WAIT_FOR_READ_END: case MMCIF_WAIT_FOR_WRITE_END: if (host->sd_error) - data->error = sh_mmcif_error_manage(host); + mrq->data->error = sh_mmcif_error_manage(host); break; default: BUG(); } if (host->wait_for != MMCIF_WAIT_FOR_STOP) { + struct mmc_data *data = mrq->data; if (!mrq->cmd->error && data && !data->error) data->bytes_xfered = data->blocks * data->blksz; @@ -1231,10 +1231,6 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) host->sd_error = true; dev_dbg(&host->pd->dev, "int err state = %08x\n", state); } - if (host->state == STATE_IDLE) { - dev_info(&host->pd->dev, "Spurious IRQ status 0x%x", state); - return IRQ_HANDLED; - } if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) { if (!host->dma_active) return IRQ_WAKE_THREAD; @@ -1302,7 +1298,7 @@ static void sh_mmcif_init_ocr(struct sh_mmcif_host *host) dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); } -static int __devinit sh_mmcif_probe(struct platform_device *pdev) +static int sh_mmcif_probe(struct platform_device *pdev) { int ret = 0, irq[2]; struct mmc_host *mmc; @@ -1310,7 +1306,6 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) struct sh_mmcif_plat_data *pd = pdev->dev.platform_data; struct resource *res; void __iomem *reg; - char clk_name[8]; irq[0] = platform_get_irq(pdev, 0); irq[1] = platform_get_irq(pdev, 1); @@ -1360,11 +1355,10 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); host->power = false; - snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id); - host->hclk = clk_get(&pdev->dev, clk_name); + host->hclk = clk_get(&pdev->dev, NULL); if (IS_ERR(host->hclk)) { ret = PTR_ERR(host->hclk); - dev_err(&pdev->dev, "cannot get clock \"%s\": %d\n", clk_name, ret); + dev_err(&pdev->dev, "cannot get clock: %d\n", ret); goto eclkget; } ret = sh_mmcif_clk_update(host); @@ -1430,7 +1424,7 @@ ealloch: return ret; } -static int __devexit sh_mmcif_remove(struct platform_device *pdev) +static int sh_mmcif_remove(struct platform_device *pdev) { struct sh_mmcif_host *host = platform_get_drvdata(pdev); struct sh_mmcif_plat_data *pd = pdev->dev.platform_data; diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 0bdc146178d..524a7f77382 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -117,13 +117,12 @@ static const struct sh_mobile_sdhi_ops sdhi_ops = { .cd_wakeup = sh_mobile_sdhi_cd_wakeup, }; -static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) +static int sh_mobile_sdhi_probe(struct platform_device *pdev) { struct sh_mobile_sdhi *priv; struct tmio_mmc_data *mmc_data; struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; struct tmio_mmc_host *host; - char clk_name[8]; int irq, ret, i = 0; bool multiplexed_isr = true; @@ -144,11 +143,10 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) } } - snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id); - priv->clk = clk_get(&pdev->dev, clk_name); + priv->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { - dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); ret = PTR_ERR(priv->clk); + dev_err(&pdev->dev, "cannot get clock: %d\n", ret); goto eclkget; } @@ -250,7 +248,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n", mmc_hostname(host->mmc), (unsigned long) (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start), - mmc_data->hclk / 1000000); + host->mmc->f_max / 1000000); return ret; @@ -330,7 +328,7 @@ static struct platform_driver sh_mobile_sdhi_driver = { .of_match_table = sh_mobile_sdhi_of_match, }, .probe = sh_mobile_sdhi_probe, - .remove = __devexit_p(sh_mobile_sdhi_remove), + .remove = sh_mobile_sdhi_remove, }; module_platform_driver(sh_mobile_sdhi_driver); diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 113ce6c9cf3..139212e79cd 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -57,7 +57,7 @@ static int tmio_mmc_resume(struct platform_device *dev) #define tmio_mmc_resume NULL #endif -static int __devinit tmio_mmc_probe(struct platform_device *pdev) +static int tmio_mmc_probe(struct platform_device *pdev) { const struct mfd_cell *cell = mfd_get_cell(pdev); struct tmio_mmc_data *pdata; @@ -107,7 +107,7 @@ out: return ret; } -static int __devexit tmio_mmc_remove(struct platform_device *pdev) +static int tmio_mmc_remove(struct platform_device *pdev) { const struct mfd_cell *cell = mfd_get_cell(pdev); struct mmc_host *mmc = platform_get_drvdata(pdev); @@ -133,7 +133,7 @@ static struct platform_driver tmio_mmc_driver = { .owner = THIS_MODULE, }, .probe = tmio_mmc_probe, - .remove = __devexit_p(tmio_mmc_remove), + .remove = tmio_mmc_remove, .suspend = tmio_mmc_suspend, .resume = tmio_mmc_resume, }; diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 0d8a9bbe30b..50bf495a988 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -918,7 +918,7 @@ static void tmio_mmc_init_ocr(struct tmio_mmc_host *host) dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); } -int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, +int tmio_mmc_host_probe(struct tmio_mmc_host **host, struct platform_device *pdev, struct tmio_mmc_data *pdata) { diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index f18becef156..4f84586c6e9 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c @@ -1082,7 +1082,7 @@ static void via_init_mmc_host(struct via_crdr_mmc_host *host) msleep(1); } -static int __devinit via_sd_probe(struct pci_dev *pcidev, +static int via_sd_probe(struct pci_dev *pcidev, const struct pci_device_id *id) { struct mmc_host *mmc; @@ -1176,7 +1176,7 @@ disable: return ret; } -static void __devexit via_sd_remove(struct pci_dev *pcidev) +static void via_sd_remove(struct pci_dev *pcidev) { struct via_crdr_mmc_host *sdhost = pci_get_drvdata(pcidev); unsigned long flags; @@ -1332,7 +1332,7 @@ static struct pci_driver via_sd_driver = { .name = DRV_NAME, .id_table = via_ids, .probe = via_sd_probe, - .remove = __devexit_p(via_sd_remove), + .remove = via_sd_remove, .suspend = via_sd_suspend, .resume = via_sd_resume, }; diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index d5655a63eda..cb9f361c03a 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -2362,6 +2362,7 @@ error4: error1: usb_free_urb(command_out_urb); error0: + usb_put_dev(udev); return retval; } diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index 64acd9ce141..e954b775887 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -1196,7 +1196,7 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id) * Allocate/free MMC structure. */ -static int __devinit wbsd_alloc_mmc(struct device *dev) +static int wbsd_alloc_mmc(struct device *dev) { struct mmc_host *mmc; struct wbsd_host *host; @@ -1288,7 +1288,7 @@ static void wbsd_free_mmc(struct device *dev) * Scan for known chip id:s */ -static int __devinit wbsd_scan(struct wbsd_host *host) +static int wbsd_scan(struct wbsd_host *host) { int i, j, k; int id; @@ -1344,7 +1344,7 @@ static int __devinit wbsd_scan(struct wbsd_host *host) * Allocate/free io port ranges */ -static int __devinit wbsd_request_region(struct wbsd_host *host, int base) +static int wbsd_request_region(struct wbsd_host *host, int base) { if (base & 0x7) return -EINVAL; @@ -1374,7 +1374,7 @@ static void wbsd_release_regions(struct wbsd_host *host) * Allocate/free DMA port and buffer */ -static void __devinit wbsd_request_dma(struct wbsd_host *host, int dma) +static void wbsd_request_dma(struct wbsd_host *host, int dma) { if (dma < 0) return; @@ -1452,7 +1452,7 @@ static void wbsd_release_dma(struct wbsd_host *host) * Allocate/free IRQ. */ -static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq) +static int wbsd_request_irq(struct wbsd_host *host, int irq) { int ret; @@ -1502,7 +1502,7 @@ static void wbsd_release_irq(struct wbsd_host *host) * Allocate all resources for the host. */ -static int __devinit wbsd_request_resources(struct wbsd_host *host, +static int wbsd_request_resources(struct wbsd_host *host, int base, int irq, int dma) { int ret; @@ -1644,7 +1644,7 @@ static void wbsd_chip_poweroff(struct wbsd_host *host) * * \*****************************************************************************/ -static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma, +static int wbsd_init(struct device *dev, int base, int irq, int dma, int pnp) { struct wbsd_host *host = NULL; @@ -1735,7 +1735,7 @@ static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma, return 0; } -static void __devexit wbsd_shutdown(struct device *dev, int pnp) +static void wbsd_shutdown(struct device *dev, int pnp) { struct mmc_host *mmc = dev_get_drvdata(dev); struct wbsd_host *host; @@ -1762,13 +1762,13 @@ static void __devexit wbsd_shutdown(struct device *dev, int pnp) * Non-PnP */ -static int __devinit wbsd_probe(struct platform_device *dev) +static int wbsd_probe(struct platform_device *dev) { /* Use the module parameters for resources */ return wbsd_init(&dev->dev, param_io, param_irq, param_dma, 0); } -static int __devexit wbsd_remove(struct platform_device *dev) +static int wbsd_remove(struct platform_device *dev) { wbsd_shutdown(&dev->dev, 0); @@ -1781,7 +1781,7 @@ static int __devexit wbsd_remove(struct platform_device *dev) #ifdef CONFIG_PNP -static int __devinit +static int wbsd_pnp_probe(struct pnp_dev *pnpdev, const struct pnp_device_id *dev_id) { int io, irq, dma; @@ -1801,7 +1801,7 @@ wbsd_pnp_probe(struct pnp_dev *pnpdev, const struct pnp_device_id *dev_id) return wbsd_init(&pnpdev->dev, io, irq, dma, 1); } -static void __devexit wbsd_pnp_remove(struct pnp_dev *dev) +static void wbsd_pnp_remove(struct pnp_dev *dev) { wbsd_shutdown(&dev->dev, 1); } @@ -1941,7 +1941,7 @@ static struct platform_device *wbsd_device; static struct platform_driver wbsd_driver = { .probe = wbsd_probe, - .remove = __devexit_p(wbsd_remove), + .remove = wbsd_remove, .suspend = wbsd_platform_suspend, .resume = wbsd_platform_resume, @@ -1957,7 +1957,7 @@ static struct pnp_driver wbsd_pnp_driver = { .name = DRIVER_NAME, .id_table = pnp_dev_table, .probe = wbsd_pnp_probe, - .remove = __devexit_p(wbsd_pnp_remove), + .remove = wbsd_pnp_remove, .suspend = wbsd_pnp_suspend, .resume = wbsd_pnp_resume, diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c new file mode 100644 index 00000000000..5ba4605e4f8 --- /dev/null +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -0,0 +1,1029 @@ +/* + * WM8505/WM8650 SD/MMC Host Controller + * + * Copyright (C) 2010 Tony Prisk + * Copyright (C) 2008 WonderMedia Technologies, Inc. + * + * 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/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/ioport.h> +#include <linux/errno.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/clk.h> +#include <linux/gpio.h> + +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_device.h> + +#include <linux/mmc/host.h> +#include <linux/mmc/mmc.h> +#include <linux/mmc/sd.h> + +#include <asm/byteorder.h> + + +#define DRIVER_NAME "wmt-sdhc" + + +/* MMC/SD controller registers */ +#define SDMMC_CTLR 0x00 +#define SDMMC_CMD 0x01 +#define SDMMC_RSPTYPE 0x02 +#define SDMMC_ARG 0x04 +#define SDMMC_BUSMODE 0x08 +#define SDMMC_BLKLEN 0x0C +#define SDMMC_BLKCNT 0x0E +#define SDMMC_RSP 0x10 +#define SDMMC_CBCR 0x20 +#define SDMMC_INTMASK0 0x24 +#define SDMMC_INTMASK1 0x25 +#define SDMMC_STS0 0x28 +#define SDMMC_STS1 0x29 +#define SDMMC_STS2 0x2A +#define SDMMC_STS3 0x2B +#define SDMMC_RSPTIMEOUT 0x2C +#define SDMMC_CLK 0x30 /* VT8500 only */ +#define SDMMC_EXTCTRL 0x34 +#define SDMMC_SBLKLEN 0x38 +#define SDMMC_DMATIMEOUT 0x3C + + +/* SDMMC_CTLR bit fields */ +#define CTLR_CMD_START 0x01 +#define CTLR_CMD_WRITE 0x04 +#define CTLR_FIFO_RESET 0x08 + +/* SDMMC_BUSMODE bit fields */ +#define BM_SPI_MODE 0x01 +#define BM_FOURBIT_MODE 0x02 +#define BM_EIGHTBIT_MODE 0x04 +#define BM_SD_OFF 0x10 +#define BM_SPI_CS 0x20 +#define BM_SD_POWER 0x40 +#define BM_SOFT_RESET 0x80 +#define BM_ONEBIT_MASK 0xFD + +/* SDMMC_BLKLEN bit fields */ +#define BLKL_CRCERR_ABORT 0x0800 +#define BLKL_CD_POL_HIGH 0x1000 +#define BLKL_GPI_CD 0x2000 +#define BLKL_DATA3_CD 0x4000 +#define BLKL_INT_ENABLE 0x8000 + +/* SDMMC_INTMASK0 bit fields */ +#define INT0_MBLK_TRAN_DONE_INT_EN 0x10 +#define INT0_BLK_TRAN_DONE_INT_EN 0x20 +#define INT0_CD_INT_EN 0x40 +#define INT0_DI_INT_EN 0x80 + +/* SDMMC_INTMASK1 bit fields */ +#define INT1_CMD_RES_TRAN_DONE_INT_EN 0x02 +#define INT1_CMD_RES_TOUT_INT_EN 0x04 +#define INT1_MBLK_AUTO_STOP_INT_EN 0x08 +#define INT1_DATA_TOUT_INT_EN 0x10 +#define INT1_RESCRC_ERR_INT_EN 0x20 +#define INT1_RCRC_ERR_INT_EN 0x40 +#define INT1_WCRC_ERR_INT_EN 0x80 + +/* SDMMC_STS0 bit fields */ +#define STS0_WRITE_PROTECT 0x02 +#define STS0_CD_DATA3 0x04 +#define STS0_CD_GPI 0x08 +#define STS0_MBLK_DONE 0x10 +#define STS0_BLK_DONE 0x20 +#define STS0_CARD_DETECT 0x40 +#define STS0_DEVICE_INS 0x80 + +/* SDMMC_STS1 bit fields */ +#define STS1_SDIO_INT 0x01 +#define STS1_CMDRSP_DONE 0x02 +#define STS1_RSP_TIMEOUT 0x04 +#define STS1_AUTOSTOP_DONE 0x08 +#define STS1_DATA_TIMEOUT 0x10 +#define STS1_RSP_CRC_ERR 0x20 +#define STS1_RCRC_ERR 0x40 +#define STS1_WCRC_ERR 0x80 + +/* SDMMC_STS2 bit fields */ +#define STS2_CMD_RES_BUSY 0x10 +#define STS2_DATARSP_BUSY 0x20 +#define STS2_DIS_FORCECLK 0x80 + + +/* MMC/SD DMA Controller Registers */ +#define SDDMA_GCR 0x100 +#define SDDMA_IER 0x104 +#define SDDMA_ISR 0x108 +#define SDDMA_DESPR 0x10C +#define SDDMA_RBR 0x110 +#define SDDMA_DAR 0x114 +#define SDDMA_BAR 0x118 +#define SDDMA_CPR 0x11C +#define SDDMA_CCR 0x120 + + +/* SDDMA_GCR bit fields */ +#define DMA_GCR_DMA_EN 0x00000001 +#define DMA_GCR_SOFT_RESET 0x00000100 + +/* SDDMA_IER bit fields */ +#define DMA_IER_INT_EN 0x00000001 + +/* SDDMA_ISR bit fields */ +#define DMA_ISR_INT_STS 0x00000001 + +/* SDDMA_RBR bit fields */ +#define DMA_RBR_FORMAT 0x40000000 +#define DMA_RBR_END 0x80000000 + +/* SDDMA_CCR bit fields */ +#define DMA_CCR_RUN 0x00000080 +#define DMA_CCR_IF_TO_PERIPHERAL 0x00000000 +#define DMA_CCR_PERIPHERAL_TO_IF 0x00400000 + +/* SDDMA_CCR event status */ +#define DMA_CCR_EVT_NO_STATUS 0x00000000 +#define DMA_CCR_EVT_UNDERRUN 0x00000001 +#define DMA_CCR_EVT_OVERRUN 0x00000002 +#define DMA_CCR_EVT_DESP_READ 0x00000003 +#define DMA_CCR_EVT_DATA_RW 0x00000004 +#define DMA_CCR_EVT_EARLY_END 0x00000005 +#define DMA_CCR_EVT_SUCCESS 0x0000000F + +#define PDMA_READ 0x00 +#define PDMA_WRITE 0x01 + +#define WMT_SD_POWER_OFF 0 +#define WMT_SD_POWER_ON 1 + +struct wmt_dma_descriptor { + u32 flags; + u32 data_buffer_addr; + u32 branch_addr; + u32 reserved1; +}; + +struct wmt_mci_caps { + unsigned int f_min; + unsigned int f_max; + u32 ocr_avail; + u32 caps; + u32 max_seg_size; + u32 max_segs; + u32 max_blk_size; +}; + +struct wmt_mci_priv { + struct mmc_host *mmc; + void __iomem *sdmmc_base; + + int irq_regular; + int irq_dma; + + void *dma_desc_buffer; + dma_addr_t dma_desc_device_addr; + + struct completion cmdcomp; + struct completion datacomp; + + struct completion *comp_cmd; + struct completion *comp_dma; + + struct mmc_request *req; + struct mmc_command *cmd; + + struct clk *clk_sdmmc; + struct device *dev; + + u8 power_inverted; + u8 cd_inverted; +}; + +static void wmt_set_sd_power(struct wmt_mci_priv *priv, int enable) +{ + u32 reg_tmp; + if (enable) { + if (priv->power_inverted) { + reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); + writeb(reg_tmp | BM_SD_OFF, + priv->sdmmc_base + SDMMC_BUSMODE); + } else { + reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); + writeb(reg_tmp & (~BM_SD_OFF), + priv->sdmmc_base + SDMMC_BUSMODE); + } + } else { + if (priv->power_inverted) { + reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); + writeb(reg_tmp & (~BM_SD_OFF), + priv->sdmmc_base + SDMMC_BUSMODE); + } else { + reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); + writeb(reg_tmp | BM_SD_OFF, + priv->sdmmc_base + SDMMC_BUSMODE); + } + } +} + +static void wmt_mci_read_response(struct mmc_host *mmc) +{ + struct wmt_mci_priv *priv; + int idx1, idx2; + u8 tmp_resp; + u32 response; + + priv = mmc_priv(mmc); + + for (idx1 = 0; idx1 < 4; idx1++) { + response = 0; + for (idx2 = 0; idx2 < 4; idx2++) { + if ((idx1 == 3) && (idx2 == 3)) + tmp_resp = readb(priv->sdmmc_base + SDMMC_RSP); + else + tmp_resp = readb(priv->sdmmc_base + SDMMC_RSP + + (idx1*4) + idx2 + 1); + response |= (tmp_resp << (idx2 * 8)); + } + priv->cmd->resp[idx1] = cpu_to_be32(response); + } +} + +static void wmt_mci_start_command(struct wmt_mci_priv *priv) +{ + u32 reg_tmp; + + reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR); + writeb(reg_tmp | CTLR_CMD_START, priv->sdmmc_base + SDMMC_CTLR); +} + +static int wmt_mci_send_command(struct mmc_host *mmc, u8 command, u8 cmdtype, + u32 arg, u8 rsptype) +{ + struct wmt_mci_priv *priv; + u32 reg_tmp; + + priv = mmc_priv(mmc); + + /* write command, arg, resptype registers */ + writeb(command, priv->sdmmc_base + SDMMC_CMD); + writel(arg, priv->sdmmc_base + SDMMC_ARG); + writeb(rsptype, priv->sdmmc_base + SDMMC_RSPTYPE); + + /* reset response FIFO */ + reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR); + writeb(reg_tmp | CTLR_FIFO_RESET, priv->sdmmc_base + SDMMC_CTLR); + + /* ensure clock enabled - VT3465 */ + wmt_set_sd_power(priv, WMT_SD_POWER_ON); + + /* clear status bits */ + writeb(0xFF, priv->sdmmc_base + SDMMC_STS0); + writeb(0xFF, priv->sdmmc_base + SDMMC_STS1); + writeb(0xFF, priv->sdmmc_base + SDMMC_STS2); + writeb(0xFF, priv->sdmmc_base + SDMMC_STS3); + + /* set command type */ + reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR); + writeb((reg_tmp & 0x0F) | (cmdtype << 4), + priv->sdmmc_base + SDMMC_CTLR); + + return 0; +} + +static void wmt_mci_disable_dma(struct wmt_mci_priv *priv) +{ + writel(DMA_ISR_INT_STS, priv->sdmmc_base + SDDMA_ISR); + writel(0, priv->sdmmc_base + SDDMA_IER); +} + +static void wmt_complete_data_request(struct wmt_mci_priv *priv) +{ + struct mmc_request *req; + req = priv->req; + + req->data->bytes_xfered = req->data->blksz * req->data->blocks; + + /* unmap the DMA pages used for write data */ + if (req->data->flags & MMC_DATA_WRITE) + dma_unmap_sg(mmc_dev(priv->mmc), req->data->sg, + req->data->sg_len, DMA_TO_DEVICE); + else + dma_unmap_sg(mmc_dev(priv->mmc), req->data->sg, + req->data->sg_len, DMA_FROM_DEVICE); + + /* Check if the DMA ISR returned a data error */ + if ((req->cmd->error) || (req->data->error)) + mmc_request_done(priv->mmc, req); + else { + wmt_mci_read_response(priv->mmc); + if (!req->data->stop) { + /* single-block read/write requests end here */ + mmc_request_done(priv->mmc, req); + } else { + /* + * we change the priv->cmd variable so the response is + * stored in the stop struct rather than the original + * calling command struct + */ + priv->comp_cmd = &priv->cmdcomp; + init_completion(priv->comp_cmd); + priv->cmd = req->data->stop; + wmt_mci_send_command(priv->mmc, req->data->stop->opcode, + 7, req->data->stop->arg, 9); + wmt_mci_start_command(priv); + } + } +} + +static irqreturn_t wmt_mci_dma_isr(int irq_num, void *data) +{ + struct mmc_host *mmc; + struct wmt_mci_priv *priv; + + int status; + + priv = (struct wmt_mci_priv *)data; + mmc = priv->mmc; + + status = readl(priv->sdmmc_base + SDDMA_CCR) & 0x0F; + + if (status != DMA_CCR_EVT_SUCCESS) { + dev_err(priv->dev, "DMA Error: Status = %d\n", status); + priv->req->data->error = -ETIMEDOUT; + complete(priv->comp_dma); + return IRQ_HANDLED; + } + + priv->req->data->error = 0; + + wmt_mci_disable_dma(priv); + + complete(priv->comp_dma); + + if (priv->comp_cmd) { + if (completion_done(priv->comp_cmd)) { + /* + * if the command (regular) interrupt has already + * completed, finish off the request otherwise we wait + * for the command interrupt and finish from there. + */ + wmt_complete_data_request(priv); + } + } + + return IRQ_HANDLED; +} + +static irqreturn_t wmt_mci_regular_isr(int irq_num, void *data) +{ + struct wmt_mci_priv *priv; + u32 status0; + u32 status1; + u32 status2; + u32 reg_tmp; + int cmd_done; + + priv = (struct wmt_mci_priv *)data; + cmd_done = 0; + status0 = readb(priv->sdmmc_base + SDMMC_STS0); + status1 = readb(priv->sdmmc_base + SDMMC_STS1); + status2 = readb(priv->sdmmc_base + SDMMC_STS2); + + /* Check for card insertion */ + reg_tmp = readb(priv->sdmmc_base + SDMMC_INTMASK0); + if ((reg_tmp & INT0_DI_INT_EN) && (status0 & STS0_DEVICE_INS)) { + mmc_detect_change(priv->mmc, 0); + if (priv->cmd) + priv->cmd->error = -ETIMEDOUT; + if (priv->comp_cmd) + complete(priv->comp_cmd); + if (priv->comp_dma) { + wmt_mci_disable_dma(priv); + complete(priv->comp_dma); + } + writeb(STS0_DEVICE_INS, priv->sdmmc_base + SDMMC_STS0); + return IRQ_HANDLED; + } + + if ((!priv->req->data) || + ((priv->req->data->stop) && (priv->cmd == priv->req->data->stop))) { + /* handle non-data & stop_transmission requests */ + if (status1 & STS1_CMDRSP_DONE) { + priv->cmd->error = 0; + cmd_done = 1; + } else if ((status1 & STS1_RSP_TIMEOUT) || + (status1 & STS1_DATA_TIMEOUT)) { + priv->cmd->error = -ETIMEDOUT; + cmd_done = 1; + } + + if (cmd_done) { + priv->comp_cmd = NULL; + + if (!priv->cmd->error) + wmt_mci_read_response(priv->mmc); + + priv->cmd = NULL; + + mmc_request_done(priv->mmc, priv->req); + } + } else { + /* handle data requests */ + if (status1 & STS1_CMDRSP_DONE) { + if (priv->cmd) + priv->cmd->error = 0; + if (priv->comp_cmd) + complete(priv->comp_cmd); + } + + if ((status1 & STS1_RSP_TIMEOUT) || + (status1 & STS1_DATA_TIMEOUT)) { + if (priv->cmd) + priv->cmd->error = -ETIMEDOUT; + if (priv->comp_cmd) + complete(priv->comp_cmd); + if (priv->comp_dma) { + wmt_mci_disable_dma(priv); + complete(priv->comp_dma); + } + } + + if (priv->comp_dma) { + /* + * If the dma interrupt has already completed, finish + * off the request; otherwise we wait for the DMA + * interrupt and finish from there. + */ + if (completion_done(priv->comp_dma)) + wmt_complete_data_request(priv); + } + } + + writeb(status0, priv->sdmmc_base + SDMMC_STS0); + writeb(status1, priv->sdmmc_base + SDMMC_STS1); + writeb(status2, priv->sdmmc_base + SDMMC_STS2); + + return IRQ_HANDLED; +} + +static void wmt_reset_hardware(struct mmc_host *mmc) +{ + struct wmt_mci_priv *priv; + u32 reg_tmp; + + priv = mmc_priv(mmc); + + /* reset controller */ + reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); + writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + SDMMC_BUSMODE); + + /* reset response FIFO */ + reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR); + writeb(reg_tmp | CTLR_FIFO_RESET, priv->sdmmc_base + SDMMC_CTLR); + + /* enable GPI pin to detect card */ + writew(BLKL_INT_ENABLE | BLKL_GPI_CD, priv->sdmmc_base + SDMMC_BLKLEN); + + /* clear interrupt status */ + writeb(0xFF, priv->sdmmc_base + SDMMC_STS0); + writeb(0xFF, priv->sdmmc_base + SDMMC_STS1); + + /* setup interrupts */ + writeb(INT0_CD_INT_EN | INT0_DI_INT_EN, priv->sdmmc_base + + SDMMC_INTMASK0); + writeb(INT1_DATA_TOUT_INT_EN | INT1_CMD_RES_TRAN_DONE_INT_EN | + INT1_CMD_RES_TOUT_INT_EN, priv->sdmmc_base + SDMMC_INTMASK1); + + /* set the DMA timeout */ + writew(8191, priv->sdmmc_base + SDMMC_DMATIMEOUT); + + /* auto clock freezing enable */ + reg_tmp = readb(priv->sdmmc_base + SDMMC_STS2); + writeb(reg_tmp | STS2_DIS_FORCECLK, priv->sdmmc_base + SDMMC_STS2); + + /* set a default clock speed of 400Khz */ + clk_set_rate(priv->clk_sdmmc, 400000); +} + +static int wmt_dma_init(struct mmc_host *mmc) +{ + struct wmt_mci_priv *priv; + + priv = mmc_priv(mmc); + + writel(DMA_GCR_SOFT_RESET, priv->sdmmc_base + SDDMA_GCR); + writel(DMA_GCR_DMA_EN, priv->sdmmc_base + SDDMA_GCR); + if ((readl(priv->sdmmc_base + SDDMA_GCR) & DMA_GCR_DMA_EN) != 0) + return 0; + else + return 1; +} + +static void wmt_dma_init_descriptor(struct wmt_dma_descriptor *desc, + u16 req_count, u32 buffer_addr, u32 branch_addr, int end) +{ + desc->flags = 0x40000000 | req_count; + if (end) + desc->flags |= 0x80000000; + desc->data_buffer_addr = buffer_addr; + desc->branch_addr = branch_addr; +} + +static void wmt_dma_config(struct mmc_host *mmc, u32 descaddr, u8 dir) +{ + struct wmt_mci_priv *priv; + u32 reg_tmp; + + priv = mmc_priv(mmc); + + /* Enable DMA Interrupts */ + writel(DMA_IER_INT_EN, priv->sdmmc_base + SDDMA_IER); + + /* Write DMA Descriptor Pointer Register */ + writel(descaddr, priv->sdmmc_base + SDDMA_DESPR); + + writel(0x00, priv->sdmmc_base + SDDMA_CCR); + + if (dir == PDMA_WRITE) { + reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR); + writel(reg_tmp & DMA_CCR_IF_TO_PERIPHERAL, priv->sdmmc_base + + SDDMA_CCR); + } else { + reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR); + writel(reg_tmp | DMA_CCR_PERIPHERAL_TO_IF, priv->sdmmc_base + + SDDMA_CCR); + } +} + +static void wmt_dma_start(struct wmt_mci_priv *priv) +{ + u32 reg_tmp; + + reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR); + writel(reg_tmp | DMA_CCR_RUN, priv->sdmmc_base + SDDMA_CCR); +} + +static void wmt_mci_request(struct mmc_host *mmc, struct mmc_request *req) +{ + struct wmt_mci_priv *priv; + struct wmt_dma_descriptor *desc; + u8 command; + u8 cmdtype; + u32 arg; + u8 rsptype; + u32 reg_tmp; + + struct scatterlist *sg; + int i; + int sg_cnt; + int offset; + u32 dma_address; + int desc_cnt; + + priv = mmc_priv(mmc); + priv->req = req; + + /* + * Use the cmd variable to pass a pointer to the resp[] structure + * This is required on multi-block requests to pass the pointer to the + * stop command + */ + priv->cmd = req->cmd; + + command = req->cmd->opcode; + arg = req->cmd->arg; + rsptype = mmc_resp_type(req->cmd); + cmdtype = 0; + + /* rsptype=7 only valid for SPI commands - should be =2 for SD */ + if (rsptype == 7) + rsptype = 2; + /* rsptype=21 is R1B, convert for controller */ + if (rsptype == 21) + rsptype = 9; + + if (!req->data) { + wmt_mci_send_command(mmc, command, cmdtype, arg, rsptype); + wmt_mci_start_command(priv); + /* completion is now handled in the regular_isr() */ + } + if (req->data) { + priv->comp_cmd = &priv->cmdcomp; + init_completion(priv->comp_cmd); + + wmt_dma_init(mmc); + + /* set controller data length */ + reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN); + writew((reg_tmp & 0xF800) | (req->data->blksz - 1), + priv->sdmmc_base + SDMMC_BLKLEN); + + /* set controller block count */ + writew(req->data->blocks, priv->sdmmc_base + SDMMC_BLKCNT); + + desc = (struct wmt_dma_descriptor *)priv->dma_desc_buffer; + + if (req->data->flags & MMC_DATA_WRITE) { + sg_cnt = dma_map_sg(mmc_dev(mmc), req->data->sg, + req->data->sg_len, DMA_TO_DEVICE); + cmdtype = 1; + if (req->data->blocks > 1) + cmdtype = 3; + } else { + sg_cnt = dma_map_sg(mmc_dev(mmc), req->data->sg, + req->data->sg_len, DMA_FROM_DEVICE); + cmdtype = 2; + if (req->data->blocks > 1) + cmdtype = 4; + } + + dma_address = priv->dma_desc_device_addr + 16; + desc_cnt = 0; + + for_each_sg(req->data->sg, sg, sg_cnt, i) { + offset = 0; + while (offset < sg_dma_len(sg)) { + wmt_dma_init_descriptor(desc, req->data->blksz, + sg_dma_address(sg)+offset, + dma_address, 0); + desc++; + desc_cnt++; + offset += req->data->blksz; + dma_address += 16; + if (desc_cnt == req->data->blocks) + break; + } + } + desc--; + desc->flags |= 0x80000000; + + if (req->data->flags & MMC_DATA_WRITE) + wmt_dma_config(mmc, priv->dma_desc_device_addr, + PDMA_WRITE); + else + wmt_dma_config(mmc, priv->dma_desc_device_addr, + PDMA_READ); + + wmt_mci_send_command(mmc, command, cmdtype, arg, rsptype); + + priv->comp_dma = &priv->datacomp; + init_completion(priv->comp_dma); + + wmt_dma_start(priv); + wmt_mci_start_command(priv); + } +} + +static void wmt_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct wmt_mci_priv *priv; + u32 reg_tmp; + + priv = mmc_priv(mmc); + + if (ios->power_mode == MMC_POWER_UP) { + wmt_reset_hardware(mmc); + + wmt_set_sd_power(priv, WMT_SD_POWER_ON); + } + if (ios->power_mode == MMC_POWER_OFF) + wmt_set_sd_power(priv, WMT_SD_POWER_OFF); + + if (ios->clock != 0) + clk_set_rate(priv->clk_sdmmc, ios->clock); + + switch (ios->bus_width) { + case MMC_BUS_WIDTH_8: + reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL); + writeb(reg_tmp | 0x04, priv->sdmmc_base + SDMMC_EXTCTRL); + break; + case MMC_BUS_WIDTH_4: + reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); + writeb(reg_tmp | BM_FOURBIT_MODE, priv->sdmmc_base + + SDMMC_BUSMODE); + + reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL); + writeb(reg_tmp & 0xFB, priv->sdmmc_base + SDMMC_EXTCTRL); + break; + case MMC_BUS_WIDTH_1: + reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); + writeb(reg_tmp & BM_ONEBIT_MASK, priv->sdmmc_base + + SDMMC_BUSMODE); + + reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL); + writeb(reg_tmp & 0xFB, priv->sdmmc_base + SDMMC_EXTCTRL); + break; + } +} + +static int wmt_mci_get_ro(struct mmc_host *mmc) +{ + struct wmt_mci_priv *priv = mmc_priv(mmc); + + return !(readb(priv->sdmmc_base + SDMMC_STS0) & STS0_WRITE_PROTECT); +} + +static int wmt_mci_get_cd(struct mmc_host *mmc) +{ + struct wmt_mci_priv *priv = mmc_priv(mmc); + u32 cd = (readb(priv->sdmmc_base + SDMMC_STS0) & STS0_CD_GPI) >> 3; + + return !(cd ^ priv->cd_inverted); +} + +static struct mmc_host_ops wmt_mci_ops = { + .request = wmt_mci_request, + .set_ios = wmt_mci_set_ios, + .get_ro = wmt_mci_get_ro, + .get_cd = wmt_mci_get_cd, +}; + +/* Controller capabilities */ +static struct wmt_mci_caps wm8505_caps = { + .f_min = 390425, + .f_max = 50000000, + .ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_SD_HIGHSPEED, + .max_seg_size = 65024, + .max_segs = 128, + .max_blk_size = 2048, +}; + +static struct of_device_id wmt_mci_dt_ids[] = { + { .compatible = "wm,wm8505-sdhc", .data = &wm8505_caps }, + { /* Sentinel */ }, +}; + +static int __devinit wmt_mci_probe(struct platform_device *pdev) +{ + struct mmc_host *mmc; + struct wmt_mci_priv *priv; + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *of_id = + of_match_device(wmt_mci_dt_ids, &pdev->dev); + const struct wmt_mci_caps *wmt_caps = of_id->data; + int ret; + int regular_irq, dma_irq; + + if (!of_id || !of_id->data) { + dev_err(&pdev->dev, "Controller capabilities data missing\n"); + return -EFAULT; + } + + if (!np) { + dev_err(&pdev->dev, "Missing SDMMC description in devicetree\n"); + return -EFAULT; + } + + regular_irq = irq_of_parse_and_map(np, 0); + dma_irq = irq_of_parse_and_map(np, 1); + + if (!regular_irq || !dma_irq) { + dev_err(&pdev->dev, "Getting IRQs failed!\n"); + ret = -ENXIO; + goto fail1; + } + + mmc = mmc_alloc_host(sizeof(struct wmt_mci_priv), &pdev->dev); + if (!mmc) { + dev_err(&pdev->dev, "Failed to allocate mmc_host\n"); + ret = -ENOMEM; + goto fail1; + } + + mmc->ops = &wmt_mci_ops; + mmc->f_min = wmt_caps->f_min; + mmc->f_max = wmt_caps->f_max; + mmc->ocr_avail = wmt_caps->ocr_avail; + mmc->caps = wmt_caps->caps; + + mmc->max_seg_size = wmt_caps->max_seg_size; + mmc->max_segs = wmt_caps->max_segs; + mmc->max_blk_size = wmt_caps->max_blk_size; + + mmc->max_req_size = (16*512*mmc->max_segs); + mmc->max_blk_count = mmc->max_req_size / 512; + + priv = mmc_priv(mmc); + priv->mmc = mmc; + priv->dev = &pdev->dev; + + priv->power_inverted = 0; + priv->cd_inverted = 0; + + if (of_get_property(np, "sdon-inverted", NULL)) + priv->power_inverted = 1; + if (of_get_property(np, "cd-inverted", NULL)) + priv->cd_inverted = 1; + + priv->sdmmc_base = of_iomap(np, 0); + if (!priv->sdmmc_base) { + dev_err(&pdev->dev, "Failed to map IO space\n"); + ret = -ENOMEM; + goto fail2; + } + + priv->irq_regular = regular_irq; + priv->irq_dma = dma_irq; + + ret = request_irq(regular_irq, wmt_mci_regular_isr, 0, "sdmmc", priv); + if (ret) { + dev_err(&pdev->dev, "Register regular IRQ fail\n"); + goto fail3; + } + + ret = request_irq(dma_irq, wmt_mci_dma_isr, 32, "sdmmc", priv); + if (ret) { + dev_err(&pdev->dev, "Register DMA IRQ fail\n"); + goto fail4; + } + + /* alloc some DMA buffers for descriptors/transfers */ + priv->dma_desc_buffer = dma_alloc_coherent(&pdev->dev, + mmc->max_blk_count * 16, + &priv->dma_desc_device_addr, + 208); + if (!priv->dma_desc_buffer) { + dev_err(&pdev->dev, "DMA alloc fail\n"); + ret = -EPERM; + goto fail5; + } + + platform_set_drvdata(pdev, mmc); + + priv->clk_sdmmc = of_clk_get(np, 0); + if (IS_ERR(priv->clk_sdmmc)) { + dev_err(&pdev->dev, "Error getting clock\n"); + ret = PTR_ERR(priv->clk_sdmmc); + goto fail5; + } + + clk_prepare_enable(priv->clk_sdmmc); + + /* configure the controller to a known 'ready' state */ + wmt_reset_hardware(mmc); + + mmc_add_host(mmc); + + dev_info(&pdev->dev, "WMT SDHC Controller initialized\n"); + + return 0; +fail5: + free_irq(dma_irq, priv); +fail4: + free_irq(regular_irq, priv); +fail3: + iounmap(priv->sdmmc_base); +fail2: + mmc_free_host(mmc); +fail1: + return ret; +} + +static int __devexit wmt_mci_remove(struct platform_device *pdev) +{ + struct mmc_host *mmc; + struct wmt_mci_priv *priv; + struct resource *res; + u32 reg_tmp; + + mmc = platform_get_drvdata(pdev); + priv = mmc_priv(mmc); + + /* reset SD controller */ + reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); + writel(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + SDMMC_BUSMODE); + reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN); + writew(reg_tmp & ~(0xA000), priv->sdmmc_base + SDMMC_BLKLEN); + writeb(0xFF, priv->sdmmc_base + SDMMC_STS0); + writeb(0xFF, priv->sdmmc_base + SDMMC_STS1); + + /* release the dma buffers */ + dma_free_coherent(&pdev->dev, priv->mmc->max_blk_count * 16, + priv->dma_desc_buffer, priv->dma_desc_device_addr); + + mmc_remove_host(mmc); + + free_irq(priv->irq_regular, priv); + free_irq(priv->irq_dma, priv); + + iounmap(priv->sdmmc_base); + + clk_disable_unprepare(priv->clk_sdmmc); + clk_put(priv->clk_sdmmc); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, res->end - res->start + 1); + + mmc_free_host(mmc); + + platform_set_drvdata(pdev, NULL); + + dev_info(&pdev->dev, "WMT MCI device removed\n"); + + return 0; +} + +#ifdef CONFIG_PM +static int wmt_mci_suspend(struct device *dev) +{ + u32 reg_tmp; + struct platform_device *pdev = to_platform_device(dev); + struct mmc_host *mmc = platform_get_drvdata(pdev); + struct wmt_mci_priv *priv; + int ret; + + if (!mmc) + return 0; + + priv = mmc_priv(mmc); + ret = mmc_suspend_host(mmc); + + if (!ret) { + reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); + writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + + SDMMC_BUSMODE); + + reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN); + writew(reg_tmp & 0x5FFF, priv->sdmmc_base + SDMMC_BLKLEN); + + writeb(0xFF, priv->sdmmc_base + SDMMC_STS0); + writeb(0xFF, priv->sdmmc_base + SDMMC_STS1); + + clk_disable(priv->clk_sdmmc); + } + return ret; +} + +static int wmt_mci_resume(struct device *dev) +{ + u32 reg_tmp; + struct platform_device *pdev = to_platform_device(dev); + struct mmc_host *mmc = platform_get_drvdata(pdev); + struct wmt_mci_priv *priv; + int ret = 0; + + if (mmc) { + priv = mmc_priv(mmc); + clk_enable(priv->clk_sdmmc); + + reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); + writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + + SDMMC_BUSMODE); + + reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN); + writew(reg_tmp | (BLKL_GPI_CD | BLKL_INT_ENABLE), + priv->sdmmc_base + SDMMC_BLKLEN); + + reg_tmp = readb(priv->sdmmc_base + SDMMC_INTMASK0); + writeb(reg_tmp | INT0_DI_INT_EN, priv->sdmmc_base + + SDMMC_INTMASK0); + + ret = mmc_resume_host(mmc); + } + + return ret; +} + +static const struct dev_pm_ops wmt_mci_pm = { + .suspend = wmt_mci_suspend, + .resume = wmt_mci_resume, +}; + +#define wmt_mci_pm_ops (&wmt_mci_pm) + +#else /* !CONFIG_PM */ + +#define wmt_mci_pm_ops NULL + +#endif + +static struct platform_driver wmt_mci_driver = { + .probe = wmt_mci_probe, + .remove = __exit_p(wmt_mci_remove), + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .pm = wmt_mci_pm_ops, + .of_match_table = wmt_mci_dt_ids, + }, +}; + +module_platform_driver(wmt_mci_driver); + +MODULE_DESCRIPTION("Wondermedia MMC/SD Driver"); +MODULE_AUTHOR("Tony Prisk"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, wmt_mci_dt_ids); diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index 8f52fc858e4..5a5cd2ace4a 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c @@ -240,7 +240,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength) if (*(szlength) != '+') { devlength = simple_strtoul(szlength, &buffer, 0); - devlength = handle_unit(devlength, buffer) - devstart; + devlength = handle_unit(devlength, buffer); if (devlength < devstart) goto err_out; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 374c46dff7d..ec794a72975 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1077,7 +1077,8 @@ EXPORT_SYMBOL_GPL(mtd_writev); * until the request succeeds or until the allocation size falls below * the system page size. This attempts to make sure it does not adversely * impact system performance, so when allocating more than one page, we - * ask the memory allocator to avoid re-trying. + * ask the memory allocator to avoid re-trying, swapping, writing back + * or performing I/O. * * Note, this function also makes sure that the allocated buffer is aligned to * the MTD device's min. I/O unit, i.e. the "mtd->writesize" value. @@ -1091,7 +1092,8 @@ EXPORT_SYMBOL_GPL(mtd_writev); */ void *mtd_kmalloc_up_to(const struct mtd_info *mtd, size_t *size) { - gfp_t flags = __GFP_NOWARN | __GFP_WAIT | __GFP_NORETRY; + gfp_t flags = __GFP_NOWARN | __GFP_WAIT | + __GFP_NORETRY | __GFP_NO_KSWAPD; size_t min_alloc = max_t(size_t, mtd->writesize, PAGE_SIZE); void *kbuf; diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 91445578330..92623ac2015 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -41,6 +41,7 @@ #include <linux/gpio.h> #include <linux/io.h> #include <linux/platform_data/atmel.h> +#include <linux/pinctrl/consumer.h> #include <mach/cpu.h> @@ -1370,6 +1371,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) struct resource *mem; struct mtd_part_parser_data ppdata = {}; int res; + struct pinctrl *pinctrl; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { @@ -1414,6 +1416,13 @@ static int __init atmel_nand_probe(struct platform_device *pdev) nand_chip->IO_ADDR_W = host->io_base; nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl; + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) { + dev_err(host->dev, "Failed to request pinctrl\n"); + res = PTR_ERR(pinctrl); + goto err_ecc_ioremap; + } + if (gpio_is_valid(host->board.rdy_pin)) { res = gpio_request(host->board.rdy_pin, "nand_rdy"); if (res < 0) { diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ec6841d8e95..1a03b7f673c 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2983,13 +2983,15 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip, /* * Field definitions are in the following datasheets: * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32) - * New style (6 byte ID): Samsung K9GAG08U0F (p.44) + * New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) * Hynix MLC (6 byte ID): Hynix H27UBG8T2B (p.22) * - * Check for ID length, cell type, and Hynix/Samsung ID to decide what - * to do. + * Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung + * ID to decide what to do. */ - if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG) { + if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG && + (chip->cellinfo & NAND_CI_CELLTYPE_MSK) && + id_data[5] != 0x00) { /* Calc pagesize */ mtd->writesize = 2048 << (extid & 0x03); extid >>= 2; diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index 4fbfe96e37a..f48ac5d80bb 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c @@ -727,7 +727,9 @@ static void flctl_select_chip(struct mtd_info *mtd, int chipnr) if (!flctl->qos_request) { ret = dev_pm_qos_add_request(&flctl->pdev->dev, - &flctl->pm_qos, 100); + &flctl->pm_qos, + DEV_PM_QOS_LATENCY, + 100); if (ret < 0) dev_err(&flctl->pdev->dev, "PM QoS request failed: %d\n", ret); diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index 64be8f0848b..d9127e2ed80 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -121,7 +121,7 @@ static int parse_ofoldpart_partitions(struct mtd_info *master, nr_parts = plen / sizeof(part[0]); *pparts = kzalloc(nr_parts * sizeof(*(*pparts)), GFP_KERNEL); - if (!pparts) + if (!*pparts) return -ENOMEM; names = of_get_property(dp, "partition-names", &plen); diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 7153e0d2710..b3f41f20062 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -3694,7 +3694,7 @@ static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int * flexonenand_set_boundary - Writes the SLC boundary * @param mtd - mtd info structure */ -int flexonenand_set_boundary(struct mtd_info *mtd, int die, +static int flexonenand_set_boundary(struct mtd_info *mtd, int die, int boundary, int lock) { struct onenand_chip *this = mtd->priv; diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index da7b44998b4..2144f611196 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -498,7 +498,7 @@ out: * @ubi: UBI device description object * * This function returns a physical eraseblock in case of success and a - * negative error code in case of failure. Might sleep. + * negative error code in case of failure. */ static int __wl_get_peb(struct ubi_device *ubi) { @@ -540,13 +540,6 @@ retry: * ubi_wl_get_peb() after removing e from the pool. */ prot_queue_add(ubi, e); #endif - err = ubi_self_check_all_ff(ubi, e->pnum, ubi->vid_hdr_aloffset, - ubi->peb_size - ubi->vid_hdr_aloffset); - if (err) { - ubi_err("new PEB %d does not contain all 0xFF bytes", e->pnum); - return err; - } - return e->pnum; } @@ -679,17 +672,30 @@ static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi) #else static struct ubi_wl_entry *get_peb_for_wl(struct ubi_device *ubi) { - return find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF); + struct ubi_wl_entry *e; + + e = find_wl_entry(ubi, &ubi->free, WL_FREE_MAX_DIFF); + self_check_in_wl_tree(ubi, e, &ubi->free); + rb_erase(&e->u.rb, &ubi->free); + + return e; } int ubi_wl_get_peb(struct ubi_device *ubi) { - int peb; + int peb, err; spin_lock(&ubi->wl_lock); peb = __wl_get_peb(ubi); spin_unlock(&ubi->wl_lock); + err = ubi_self_check_all_ff(ubi, peb, ubi->vid_hdr_aloffset, + ubi->peb_size - ubi->vid_hdr_aloffset); + if (err) { + ubi_err("new PEB %d does not contain all 0xFF bytes", peb); + return err; + } + return peb; } #endif diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index b2530b00212..a7d47350ea4 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1379,6 +1379,8 @@ static void bond_compute_features(struct bonding *bond) struct net_device *bond_dev = bond->dev; netdev_features_t vlan_features = BOND_VLAN_FEATURES; unsigned short max_hard_header_len = ETH_HLEN; + unsigned int gso_max_size = GSO_MAX_SIZE; + u16 gso_max_segs = GSO_MAX_SEGS; int i; unsigned int flags, dst_release_flag = IFF_XMIT_DST_RELEASE; @@ -1394,11 +1396,16 @@ static void bond_compute_features(struct bonding *bond) dst_release_flag &= slave->dev->priv_flags; if (slave->dev->hard_header_len > max_hard_header_len) max_hard_header_len = slave->dev->hard_header_len; + + gso_max_size = min(gso_max_size, slave->dev->gso_max_size); + gso_max_segs = min(gso_max_segs, slave->dev->gso_max_segs); } done: bond_dev->vlan_features = vlan_features; bond_dev->hard_header_len = max_hard_header_len; + bond_dev->gso_max_segs = gso_max_segs; + netif_set_gso_max_size(bond_dev, gso_max_size); flags = bond_dev->priv_flags & ~IFF_XMIT_DST_RELEASE; bond_dev->priv_flags = flags | dst_release_flag; @@ -3452,6 +3459,28 @@ static int bond_xmit_hash_policy_l34(struct sk_buff *skb, int count) /*-------------------------- Device entry points ----------------------------*/ +static void bond_work_init_all(struct bonding *bond) +{ + INIT_DELAYED_WORK(&bond->mcast_work, + bond_resend_igmp_join_requests_delayed); + INIT_DELAYED_WORK(&bond->alb_work, bond_alb_monitor); + INIT_DELAYED_WORK(&bond->mii_work, bond_mii_monitor); + if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) + INIT_DELAYED_WORK(&bond->arp_work, bond_activebackup_arp_mon); + else + INIT_DELAYED_WORK(&bond->arp_work, bond_loadbalance_arp_mon); + INIT_DELAYED_WORK(&bond->ad_work, bond_3ad_state_machine_handler); +} + +static void bond_work_cancel_all(struct bonding *bond) +{ + cancel_delayed_work_sync(&bond->mii_work); + cancel_delayed_work_sync(&bond->arp_work); + cancel_delayed_work_sync(&bond->alb_work); + cancel_delayed_work_sync(&bond->ad_work); + cancel_delayed_work_sync(&bond->mcast_work); +} + static int bond_open(struct net_device *bond_dev) { struct bonding *bond = netdev_priv(bond_dev); @@ -3474,41 +3503,27 @@ static int bond_open(struct net_device *bond_dev) } read_unlock(&bond->lock); - INIT_DELAYED_WORK(&bond->mcast_work, bond_resend_igmp_join_requests_delayed); + bond_work_init_all(bond); if (bond_is_lb(bond)) { /* bond_alb_initialize must be called before the timer * is started. */ - if (bond_alb_initialize(bond, (bond->params.mode == BOND_MODE_ALB))) { - /* something went wrong - fail the open operation */ + if (bond_alb_initialize(bond, (bond->params.mode == BOND_MODE_ALB))) return -ENOMEM; - } - - INIT_DELAYED_WORK(&bond->alb_work, bond_alb_monitor); queue_delayed_work(bond->wq, &bond->alb_work, 0); } - if (bond->params.miimon) { /* link check interval, in milliseconds. */ - INIT_DELAYED_WORK(&bond->mii_work, bond_mii_monitor); + if (bond->params.miimon) /* link check interval, in milliseconds. */ queue_delayed_work(bond->wq, &bond->mii_work, 0); - } if (bond->params.arp_interval) { /* arp interval, in milliseconds. */ - if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) - INIT_DELAYED_WORK(&bond->arp_work, - bond_activebackup_arp_mon); - else - INIT_DELAYED_WORK(&bond->arp_work, - bond_loadbalance_arp_mon); - queue_delayed_work(bond->wq, &bond->arp_work, 0); if (bond->params.arp_validate) bond->recv_probe = bond_arp_rcv; } if (bond->params.mode == BOND_MODE_8023AD) { - INIT_DELAYED_WORK(&bond->ad_work, bond_3ad_state_machine_handler); queue_delayed_work(bond->wq, &bond->ad_work, 0); /* register to receive LACPDUs */ bond->recv_probe = bond_3ad_lacpdu_recv; @@ -3523,34 +3538,10 @@ static int bond_close(struct net_device *bond_dev) struct bonding *bond = netdev_priv(bond_dev); write_lock_bh(&bond->lock); - bond->send_peer_notif = 0; - write_unlock_bh(&bond->lock); - if (bond->params.miimon) { /* link check interval, in milliseconds. */ - cancel_delayed_work_sync(&bond->mii_work); - } - - if (bond->params.arp_interval) { /* arp interval, in milliseconds. */ - cancel_delayed_work_sync(&bond->arp_work); - } - - switch (bond->params.mode) { - case BOND_MODE_8023AD: - cancel_delayed_work_sync(&bond->ad_work); - break; - case BOND_MODE_TLB: - case BOND_MODE_ALB: - cancel_delayed_work_sync(&bond->alb_work); - break; - default: - break; - } - - if (delayed_work_pending(&bond->mcast_work)) - cancel_delayed_work_sync(&bond->mcast_work); - + bond_work_cancel_all(bond); if (bond_is_lb(bond)) { /* Must be called only after all * slaves have been released @@ -4429,26 +4420,6 @@ static void bond_setup(struct net_device *bond_dev) bond_dev->features |= bond_dev->hw_features; } -static void bond_work_cancel_all(struct bonding *bond) -{ - if (bond->params.miimon && delayed_work_pending(&bond->mii_work)) - cancel_delayed_work_sync(&bond->mii_work); - - if (bond->params.arp_interval && delayed_work_pending(&bond->arp_work)) - cancel_delayed_work_sync(&bond->arp_work); - - if (bond->params.mode == BOND_MODE_ALB && - delayed_work_pending(&bond->alb_work)) - cancel_delayed_work_sync(&bond->alb_work); - - if (bond->params.mode == BOND_MODE_8023AD && - delayed_work_pending(&bond->ad_work)) - cancel_delayed_work_sync(&bond->ad_work); - - if (delayed_work_pending(&bond->mcast_work)) - cancel_delayed_work_sync(&bond->mcast_work); -} - /* * Destroy a bonding device. * Must be under rtnl_lock when this function is called. @@ -4699,12 +4670,13 @@ static int bond_check_params(struct bond_params *params) arp_ip_count++) { /* not complete check, but should be good enough to catch mistakes */ - if (!isdigit(arp_ip_target[arp_ip_count][0])) { + __be32 ip = in_aton(arp_ip_target[arp_ip_count]); + if (!isdigit(arp_ip_target[arp_ip_count][0]) || + ip == 0 || ip == htonl(INADDR_BROADCAST)) { pr_warning("Warning: bad arp_ip_target module parameter (%s), ARP monitoring will not be performed\n", arp_ip_target[arp_ip_count]); arp_interval = 0; } else { - __be32 ip = in_aton(arp_ip_target[arp_ip_count]); arp_target[arp_ip_count] = ip; } } diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index ef8d2a080d1..1877ed7ca08 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -513,6 +513,8 @@ static ssize_t bonding_store_arp_interval(struct device *d, int new_value, ret = count; struct bonding *bond = to_bond(d); + if (!rtnl_trylock()) + return restart_syscall(); if (sscanf(buf, "%d", &new_value) != 1) { pr_err("%s: no arp_interval value specified.\n", bond->dev->name); @@ -539,10 +541,6 @@ static ssize_t bonding_store_arp_interval(struct device *d, pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n", bond->dev->name, bond->dev->name); bond->params.miimon = 0; - if (delayed_work_pending(&bond->mii_work)) { - cancel_delayed_work(&bond->mii_work); - flush_workqueue(bond->wq); - } } if (!bond->params.arp_targets[0]) { pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified.\n", @@ -554,19 +552,12 @@ static ssize_t bonding_store_arp_interval(struct device *d, * timer will get fired off when the open function * is called. */ - if (!delayed_work_pending(&bond->arp_work)) { - if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) - INIT_DELAYED_WORK(&bond->arp_work, - bond_activebackup_arp_mon); - else - INIT_DELAYED_WORK(&bond->arp_work, - bond_loadbalance_arp_mon); - - queue_delayed_work(bond->wq, &bond->arp_work, 0); - } + cancel_delayed_work_sync(&bond->mii_work); + queue_delayed_work(bond->wq, &bond->arp_work, 0); } out: + rtnl_unlock(); return ret; } static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR, @@ -962,6 +953,8 @@ static ssize_t bonding_store_miimon(struct device *d, int new_value, ret = count; struct bonding *bond = to_bond(d); + if (!rtnl_trylock()) + return restart_syscall(); if (sscanf(buf, "%d", &new_value) != 1) { pr_err("%s: no miimon value specified.\n", bond->dev->name); @@ -993,10 +986,6 @@ static ssize_t bonding_store_miimon(struct device *d, bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; } - if (delayed_work_pending(&bond->arp_work)) { - cancel_delayed_work(&bond->arp_work); - flush_workqueue(bond->wq); - } } if (bond->dev->flags & IFF_UP) { @@ -1005,15 +994,12 @@ static ssize_t bonding_store_miimon(struct device *d, * timer will get fired off when the open function * is called. */ - if (!delayed_work_pending(&bond->mii_work)) { - INIT_DELAYED_WORK(&bond->mii_work, - bond_mii_monitor); - queue_delayed_work(bond->wq, - &bond->mii_work, 0); - } + cancel_delayed_work_sync(&bond->arp_work); + queue_delayed_work(bond->wq, &bond->mii_work, 0); } } out: + rtnl_unlock(); return ret; } static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, @@ -1582,6 +1568,7 @@ static ssize_t bonding_store_slaves_active(struct device *d, goto out; } + read_lock(&bond->lock); bond_for_each_slave(bond, slave, i) { if (!bond_is_active_slave(slave)) { if (new_value) @@ -1590,6 +1577,7 @@ static ssize_t bonding_store_slaves_active(struct device *d, slave->inactive = 1; } } + read_unlock(&bond->lock); out: return ret; } diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index 86f26a1ede4..25723d8ee20 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -519,8 +519,10 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n, mc->pdev->dev.can.state = new_state; if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) { + struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb); + peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv); - skb->tstamp = timeval_to_ktime(tv); + hwts->hwtstamp = timeval_to_ktime(tv); } netif_rx(skb); @@ -605,6 +607,7 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len) struct sk_buff *skb; struct can_frame *cf; struct timeval tv; + struct skb_shared_hwtstamps *hwts; skb = alloc_can_skb(mc->netdev, &cf); if (!skb) @@ -652,7 +655,8 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len) /* convert timestamp into kernel time */ peak_usb_get_ts_tv(&mc->pdev->time_ref, mc->ts16, &tv); - skb->tstamp = timeval_to_ktime(tv); + hwts = skb_hwtstamps(skb); + hwts->hwtstamp = timeval_to_ktime(tv); /* push the skb */ netif_rx(skb); diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c index e1626d92511..30d79bfa5b1 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c @@ -532,6 +532,7 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if, struct can_frame *can_frame; struct sk_buff *skb; struct timeval tv; + struct skb_shared_hwtstamps *hwts; skb = alloc_can_skb(netdev, &can_frame); if (!skb) @@ -549,7 +550,8 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if, memcpy(can_frame->data, rx->data, can_frame->can_dlc); peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(rx->ts32), &tv); - skb->tstamp = timeval_to_ktime(tv); + hwts = skb_hwtstamps(skb); + hwts->hwtstamp = timeval_to_ktime(tv); netif_rx(skb); netdev->stats.rx_packets++; @@ -570,6 +572,7 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if, u8 err_mask = 0; struct sk_buff *skb; struct timeval tv; + struct skb_shared_hwtstamps *hwts; /* nothing should be sent while in BUS_OFF state */ if (dev->can.state == CAN_STATE_BUS_OFF) @@ -664,7 +667,8 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if, dev->can.state = new_state; peak_usb_get_ts_tv(&usb_if->time_ref, le32_to_cpu(er->ts32), &tv); - skb->tstamp = timeval_to_ktime(tv); + hwts = skb_hwtstamps(skb); + hwts->hwtstamp = timeval_to_ktime(tv); netif_rx(skb); netdev->stats.rx_packets++; netdev->stats.rx_bytes += can_frame->can_dlc; diff --git a/drivers/net/ethernet/8390/ne.c b/drivers/net/ethernet/8390/ne.c index d04911d33b6..47618e50535 100644 --- a/drivers/net/ethernet/8390/ne.c +++ b/drivers/net/ethernet/8390/ne.c @@ -813,6 +813,7 @@ static int __init ne_drv_probe(struct platform_device *pdev) dev->irq = irq[this_dev]; dev->mem_end = bad[this_dev]; } + SET_NETDEV_DEV(dev, &pdev->dev); err = do_ne_probe(dev); if (err) { free_netdev(dev); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index bd1fd3d87c2..01611b33a93 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -9545,10 +9545,13 @@ static int __devinit bnx2x_prev_unload_common(struct bnx2x *bp) */ static void __devinit bnx2x_prev_interrupted_dmae(struct bnx2x *bp) { - u32 val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS); - if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) { - BNX2X_ERR("was error bit was found to be set in pglueb upon startup. Clearing"); - REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR, 1 << BP_FUNC(bp)); + if (!CHIP_IS_E1x(bp)) { + u32 val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS); + if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) { + BNX2X_ERR("was error bit was found to be set in pglueb upon startup. Clearing"); + REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR, + 1 << BP_FUNC(bp)); + } } } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c index 5d36795877c..b799ab12a29 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c @@ -237,7 +237,7 @@ static int mlx4_en_dcbnl_ieee_setmaxrate(struct net_device *dev, if (err) return err; - memcpy(priv->maxrate, tmp, sizeof(*priv->maxrate)); + memcpy(priv->maxrate, tmp, sizeof(priv->maxrate)); return 0; } diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index 1c818254b7b..609125a249d 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -979,17 +979,6 @@ static void cp_init_hw (struct cp_private *cp) cpw32_f (MAC0 + 0, le32_to_cpu (*(__le32 *) (dev->dev_addr + 0))); cpw32_f (MAC0 + 4, le32_to_cpu (*(__le32 *) (dev->dev_addr + 4))); - cpw32_f(HiTxRingAddr, 0); - cpw32_f(HiTxRingAddr + 4, 0); - - ring_dma = cp->ring_dma; - cpw32_f(RxRingAddr, ring_dma & 0xffffffff); - cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16); - - ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE; - cpw32_f(TxRingAddr, ring_dma & 0xffffffff); - cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16); - cp_start_hw(cp); cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */ @@ -1003,6 +992,17 @@ static void cp_init_hw (struct cp_private *cp) cpw8(Config5, cpr8(Config5) & PMEStatus); + cpw32_f(HiTxRingAddr, 0); + cpw32_f(HiTxRingAddr + 4, 0); + + ring_dma = cp->ring_dma; + cpw32_f(RxRingAddr, ring_dma & 0xffffffff); + cpw32_f(RxRingAddr + 4, (ring_dma >> 16) >> 16); + + ring_dma += sizeof(struct cp_desc) * CP_RX_RING_SIZE; + cpw32_f(TxRingAddr, ring_dma & 0xffffffff); + cpw32_f(TxRingAddr + 4, (ring_dma >> 16) >> 16); + cpw16(MultiIntr, 0); cpw8_f(Cfg9346, Cfg9346_Lock); @@ -1060,17 +1060,22 @@ static int cp_init_rings (struct cp_private *cp) static int cp_alloc_rings (struct cp_private *cp) { + struct device *d = &cp->pdev->dev; void *mem; + int rc; - mem = dma_alloc_coherent(&cp->pdev->dev, CP_RING_BYTES, - &cp->ring_dma, GFP_KERNEL); + mem = dma_alloc_coherent(d, CP_RING_BYTES, &cp->ring_dma, GFP_KERNEL); if (!mem) return -ENOMEM; cp->rx_ring = mem; cp->tx_ring = &cp->rx_ring[CP_RX_RING_SIZE]; - return cp_init_rings(cp); + rc = cp_init_rings(cp); + if (rc < 0) + dma_free_coherent(d, CP_RING_BYTES, cp->rx_ring, cp->ring_dma); + + return rc; } static void cp_clean_rings (struct cp_private *cp) diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c index fb9f6b38511..edf5edb1314 100644 --- a/drivers/net/ethernet/sis/sis900.c +++ b/drivers/net/ethernet/sis/sis900.c @@ -2479,7 +2479,7 @@ static int sis900_resume(struct pci_dev *pci_dev) netif_start_queue(net_dev); /* Workaround for EDB */ - sis900_set_mode(ioaddr, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED); + sis900_set_mode(sis_priv, HW_SPEED_10_MBPS, FDX_CAPABLE_HALF_SELECTED); /* Enable all known interrupts by setting the interrupt mask. */ sw32(imr, RxSOVR | RxORN | RxERR | RxOK | TxURN | TxERR | TxIDLE); diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 77e6db9dcfe..a788501e978 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -894,6 +894,8 @@ out: return IRQ_HANDLED; } +static void axienet_dma_err_handler(unsigned long data); + /** * axienet_open - Driver open routine. * @ndev: Pointer to net_device structure diff --git a/drivers/net/ethernet/xscale/ixp4xx_eth.c b/drivers/net/ethernet/xscale/ixp4xx_eth.c index 98934bdf6ac..477d6729b17 100644 --- a/drivers/net/ethernet/xscale/ixp4xx_eth.c +++ b/drivers/net/ethernet/xscale/ixp4xx_eth.c @@ -1102,10 +1102,12 @@ static int init_queues(struct port *port) { int i; - if (!ports_open) - if (!(dma_pool = dma_pool_create(DRV_NAME, NULL, - POOL_ALLOC_SIZE, 32, 0))) + if (!ports_open) { + dma_pool = dma_pool_create(DRV_NAME, &port->netdev->dev, + POOL_ALLOC_SIZE, 32, 0); + if (!dma_pool) return -ENOMEM; + } if (!(port->desc_tab = dma_pool_alloc(dma_pool, GFP_KERNEL, &port->desc_tab_phys))) diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index 5039f08f5a5..43e9ab4f4d7 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -222,7 +222,7 @@ static void sirdev_config_fsm(struct work_struct *work) break; case SIRDEV_STATE_DONGLE_SPEED: - if (dev->dongle_drv->reset) { + if (dev->dongle_drv->set_speed) { ret = dev->dongle_drv->set_speed(dev, fsm->param); if (ret < 0) { fsm->result = ret; diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index 899274f2f9b..2ed1140df3e 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -185,17 +185,20 @@ static int __devinit mdio_gpio_probe(struct platform_device *pdev) { struct mdio_gpio_platform_data *pdata; struct mii_bus *new_bus; - int ret; + int ret, bus_id; - if (pdev->dev.of_node) + if (pdev->dev.of_node) { pdata = mdio_gpio_of_get_data(pdev); - else + bus_id = of_alias_get_id(pdev->dev.of_node, "mdio-gpio"); + } else { pdata = pdev->dev.platform_data; + bus_id = pdev->id; + } if (!pdata) return -ENODEV; - new_bus = mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id); + new_bus = mdio_gpio_bus_init(&pdev->dev, pdata, bus_id); if (!new_bus) return -ENODEV; diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index d44cca32758..ad86660fb8f 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1794,10 +1794,12 @@ static void team_setup(struct net_device *dev) dev->features |= NETIF_F_LLTX; dev->features |= NETIF_F_GRO; - dev->hw_features = NETIF_F_HW_VLAN_TX | + dev->hw_features = TEAM_VLAN_FEATURES | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; + dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_HW_CSUM); dev->features |= dev->hw_features; } diff --git a/drivers/net/team/team_mode_broadcast.c b/drivers/net/team/team_mode_broadcast.c index 9db0171e936..c5db428e73f 100644 --- a/drivers/net/team/team_mode_broadcast.c +++ b/drivers/net/team/team_mode_broadcast.c @@ -29,8 +29,8 @@ static bool bc_transmit(struct team *team, struct sk_buff *skb) if (last) { skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2) { - ret = team_dev_queue_xmit(team, last, - skb2); + ret = !team_dev_queue_xmit(team, last, + skb2); if (!sum_ret) sum_ret = ret; } @@ -39,7 +39,7 @@ static bool bc_transmit(struct team *team, struct sk_buff *skb) } } if (last) { - ret = team_dev_queue_xmit(team, last, skb); + ret = !team_dev_queue_xmit(team, last, skb); if (!sum_ret) sum_ret = ret; } diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 3b566fa0f8e..1ea91f4237f 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -385,6 +385,7 @@ static const struct usb_device_id products[] = { }, /* 3. Combined interface devices matching on interface number */ + {QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */ {QMI_FIXED_INTF(0x19d2, 0x0002, 1)}, {QMI_FIXED_INTF(0x19d2, 0x0012, 1)}, {QMI_FIXED_INTF(0x19d2, 0x0017, 3)}, diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c index 3f575afd8cf..760776b3d66 100644 --- a/drivers/net/wan/ixp4xx_hss.c +++ b/drivers/net/wan/ixp4xx_hss.c @@ -969,10 +969,12 @@ static int init_hdlc_queues(struct port *port) { int i; - if (!ports_open) - if (!(dma_pool = dma_pool_create(DRV_NAME, NULL, - POOL_ALLOC_SIZE, 32, 0))) + if (!ports_open) { + dma_pool = dma_pool_create(DRV_NAME, &port->netdev->dev, + POOL_ALLOC_SIZE, 32, 0); + if (!dma_pool) return -ENOMEM; + } if (!(port->desc_tab = dma_pool_alloc(dma_pool, GFP_KERNEL, &port->desc_tab_phys))) @@ -1363,7 +1365,7 @@ static int __devinit hss_init_one(struct platform_device *pdev) platform_set_drvdata(pdev, port); - netdev_info(dev, "HSS-%i\n", port->id); + netdev_info(dev, "initialized\n"); return 0; err_free_netdev: diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8e1559aba49..1829b445d0b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1456,7 +1456,7 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) switch (type) { case ATH9K_RESET_POWER_ON: ret = ath9k_hw_set_reset_power_on(ah); - if (!ret) + if (ret) ah->reset_power_on = true; break; case ATH9K_RESET_WARM: diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index fa4d1b8cd9f..2d9eee93c74 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -1354,6 +1354,20 @@ static int iwlagn_mac_add_interface(struct ieee80211_hw *hw, vif_priv->ctx = ctx; ctx->vif = vif; + /* + * In SNIFFER device type, the firmware reports the FCS to + * the host, rather than snipping it off. Unfortunately, + * mac80211 doesn't (yet) provide a per-packet flag for + * this, so that we have to set the hardware flag based + * on the interfaces added. As the monitor interface can + * only be present by itself, and will be removed before + * other interfaces are added, this is safe. + */ + if (vif->type == NL80211_IFTYPE_MONITOR) + priv->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS; + else + priv->hw->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS; + err = iwl_setup_interface(priv, ctx); if (!err || reset) goto out; diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c index 10896393e5a..2830ea29050 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c @@ -1012,12 +1012,12 @@ static void iwl_calc_basic_rates(struct iwl_priv *priv, * As a consequence, it's not as complicated as it sounds, just add * any lower rates to the ACK rate bitmap. */ - if (IWL_RATE_11M_INDEX < lowest_present_ofdm) - ofdm |= IWL_RATE_11M_MASK >> IWL_FIRST_CCK_RATE; - if (IWL_RATE_5M_INDEX < lowest_present_ofdm) - ofdm |= IWL_RATE_5M_MASK >> IWL_FIRST_CCK_RATE; - if (IWL_RATE_2M_INDEX < lowest_present_ofdm) - ofdm |= IWL_RATE_2M_MASK >> IWL_FIRST_CCK_RATE; + if (IWL_RATE_11M_INDEX < lowest_present_cck) + cck |= IWL_RATE_11M_MASK >> IWL_FIRST_CCK_RATE; + if (IWL_RATE_5M_INDEX < lowest_present_cck) + cck |= IWL_RATE_5M_MASK >> IWL_FIRST_CCK_RATE; + if (IWL_RATE_2M_INDEX < lowest_present_cck) + cck |= IWL_RATE_2M_MASK >> IWL_FIRST_CCK_RATE; /* 1M already there or needed so always add */ cck |= IWL_RATE_1M_MASK >> IWL_FIRST_CCK_RATE; diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 105e3af3c62..79a4ddc002d 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -480,20 +480,12 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u16 rd_ptr, wr_ptr; - int n_bd = trans_pcie->txq[txq_id].q.n_bd; if (!test_and_clear_bit(txq_id, trans_pcie->queue_used)) { WARN_ONCE(1, "queue %d not used", txq_id); return; } - rd_ptr = iwl_read_prph(trans, SCD_QUEUE_RDPTR(txq_id)) & (n_bd - 1); - wr_ptr = iwl_read_prph(trans, SCD_QUEUE_WRPTR(txq_id)); - - WARN_ONCE(rd_ptr != wr_ptr, "queue %d isn't empty: [%d,%d]", - txq_id, rd_ptr, wr_ptr); - iwl_txq_set_inactive(trans, txq_id); IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", txq_id); } diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 8d465107f52..ae9010ed58d 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -890,9 +890,6 @@ mwifiex_cmd_timeout_func(unsigned long function_context) return; } cmd_node = adapter->curr_cmd; - if (cmd_node->wait_q_enabled) - adapter->cmd_wait_q.status = -ETIMEDOUT; - if (cmd_node) { adapter->dbg.timeout_cmd_id = adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index]; @@ -938,6 +935,14 @@ mwifiex_cmd_timeout_func(unsigned long function_context) dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n", adapter->ps_mode, adapter->ps_state); + + if (cmd_node->wait_q_enabled) { + adapter->cmd_wait_q.status = -ETIMEDOUT; + wake_up_interruptible(&adapter->cmd_wait_q.wait); + mwifiex_cancel_pending_ioctl(adapter); + /* reset cmd_sent flag to unblock new commands */ + adapter->cmd_sent = false; + } } if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) mwifiex_init_fw_complete(adapter); diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index fc8a9bfa124..82cf0fa2d9f 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -161,7 +161,6 @@ static int mwifiex_sdio_suspend(struct device *dev) struct sdio_mmc_card *card; struct mwifiex_adapter *adapter; mmc_pm_flag_t pm_flag = 0; - int hs_actived = 0; int i; int ret = 0; @@ -188,12 +187,14 @@ static int mwifiex_sdio_suspend(struct device *dev) adapter = card->adapter; /* Enable the Host Sleep */ - hs_actived = mwifiex_enable_hs(adapter); - if (hs_actived) { - pr_debug("cmd: suspend with MMC_PM_KEEP_POWER\n"); - ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + if (!mwifiex_enable_hs(adapter)) { + dev_err(adapter->dev, "cmd: failed to suspend\n"); + return -EFAULT; } + dev_dbg(adapter->dev, "cmd: suspend with MMC_PM_KEEP_POWER\n"); + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + /* Indicate device suspended */ adapter->is_suspended = true; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 9970c2b1b19..b7e6607e6b6 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -297,6 +297,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { /*=== Customer ID ===*/ /****** 8188CU ********/ {RTL_USB_DEVICE(0x050d, 0x1102, rtl92cu_hal_cfg)}, /*Belkin - Edimax*/ + {RTL_USB_DEVICE(0x050d, 0x11f2, rtl92cu_hal_cfg)}, /*Belkin - ISY*/ {RTL_USB_DEVICE(0x06f8, 0xe033, rtl92cu_hal_cfg)}, /*Hercules - Edimax*/ {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/ {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/ diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index caa011008cd..fc24eb9b394 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -452,29 +452,85 @@ static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev, /* Grant backend access to each skb fragment page. */ for (i = 0; i < frags; i++) { skb_frag_t *frag = skb_shinfo(skb)->frags + i; + struct page *page = skb_frag_page(frag); - tx->flags |= XEN_NETTXF_more_data; + len = skb_frag_size(frag); + offset = frag->page_offset; - id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs); - np->tx_skbs[id].skb = skb_get(skb); - tx = RING_GET_REQUEST(&np->tx, prod++); - tx->id = id; - ref = gnttab_claim_grant_reference(&np->gref_tx_head); - BUG_ON((signed short)ref < 0); + /* Data must not cross a page boundary. */ + BUG_ON(len + offset > PAGE_SIZE<<compound_order(page)); - mfn = pfn_to_mfn(page_to_pfn(skb_frag_page(frag))); - gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id, - mfn, GNTMAP_readonly); + /* Skip unused frames from start of page */ + page += offset >> PAGE_SHIFT; + offset &= ~PAGE_MASK; - tx->gref = np->grant_tx_ref[id] = ref; - tx->offset = frag->page_offset; - tx->size = skb_frag_size(frag); - tx->flags = 0; + while (len > 0) { + unsigned long bytes; + + BUG_ON(offset >= PAGE_SIZE); + + bytes = PAGE_SIZE - offset; + if (bytes > len) + bytes = len; + + tx->flags |= XEN_NETTXF_more_data; + + id = get_id_from_freelist(&np->tx_skb_freelist, + np->tx_skbs); + np->tx_skbs[id].skb = skb_get(skb); + tx = RING_GET_REQUEST(&np->tx, prod++); + tx->id = id; + ref = gnttab_claim_grant_reference(&np->gref_tx_head); + BUG_ON((signed short)ref < 0); + + mfn = pfn_to_mfn(page_to_pfn(page)); + gnttab_grant_foreign_access_ref(ref, + np->xbdev->otherend_id, + mfn, GNTMAP_readonly); + + tx->gref = np->grant_tx_ref[id] = ref; + tx->offset = offset; + tx->size = bytes; + tx->flags = 0; + + offset += bytes; + len -= bytes; + + /* Next frame */ + if (offset == PAGE_SIZE && len) { + BUG_ON(!PageCompound(page)); + page++; + offset = 0; + } + } } np->tx.req_prod_pvt = prod; } +/* + * Count how many ring slots are required to send the frags of this + * skb. Each frag might be a compound page. + */ +static int xennet_count_skb_frag_slots(struct sk_buff *skb) +{ + int i, frags = skb_shinfo(skb)->nr_frags; + int pages = 0; + + for (i = 0; i < frags; i++) { + skb_frag_t *frag = skb_shinfo(skb)->frags + i; + unsigned long size = skb_frag_size(frag); + unsigned long offset = frag->page_offset; + + /* Skip unused frames from start of page */ + offset &= ~PAGE_MASK; + + pages += PFN_UP(offset + size); + } + + return pages; +} + static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned short id; @@ -487,23 +543,23 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev) grant_ref_t ref; unsigned long mfn; int notify; - int frags = skb_shinfo(skb)->nr_frags; + int slots; unsigned int offset = offset_in_page(data); unsigned int len = skb_headlen(skb); unsigned long flags; - frags += DIV_ROUND_UP(offset + len, PAGE_SIZE); - if (unlikely(frags > MAX_SKB_FRAGS + 1)) { - printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n", - frags); - dump_stack(); + slots = DIV_ROUND_UP(offset + len, PAGE_SIZE) + + xennet_count_skb_frag_slots(skb); + if (unlikely(slots > MAX_SKB_FRAGS + 1)) { + net_alert_ratelimited( + "xennet: skb rides the rocket: %d slots\n", slots); goto drop; } spin_lock_irqsave(&np->tx_lock, flags); if (unlikely(!netif_carrier_ok(dev) || - (frags > 1 && !xennet_can_sg(dev)) || + (slots > 1 && !xennet_can_sg(dev)) || netif_needs_gso(skb, netif_skb_features(skb)))) { spin_unlock_irqrestore(&np->tx_lock, flags); goto drop; diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 97c440a8cd6..30ae18a03a9 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -698,13 +698,14 @@ static void pn533_wq_cmd(struct work_struct *work) cmd = list_first_entry(&dev->cmd_queue, struct pn533_cmd, queue); + list_del(&cmd->queue); + mutex_unlock(&dev->cmd_lock); __pn533_send_cmd_frame_async(dev, cmd->out_frame, cmd->in_frame, cmd->in_frame_len, cmd->cmd_complete, cmd->arg, cmd->flags); - list_del(&cmd->queue); kfree(cmd); } @@ -1678,11 +1679,14 @@ static void pn533_deactivate_target(struct nfc_dev *nfc_dev, static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, u8 *params, int params_len) { - struct pn533_cmd_jump_dep *cmd; struct pn533_cmd_jump_dep_response *resp; struct nfc_target nfc_target; u8 target_gt_len; int rc; + struct pn533_cmd_jump_dep *cmd = (struct pn533_cmd_jump_dep *)arg; + u8 active = cmd->active; + + kfree(arg); if (params_len == -ENOENT) { nfc_dev_dbg(&dev->interface->dev, ""); @@ -1704,7 +1708,6 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, } resp = (struct pn533_cmd_jump_dep_response *) params; - cmd = (struct pn533_cmd_jump_dep *) arg; rc = resp->status & PN533_CMD_RET_MASK; if (rc != PN533_CMD_RET_SUCCESS) { nfc_dev_err(&dev->interface->dev, @@ -1734,7 +1737,7 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, if (rc == 0) rc = nfc_dep_link_is_up(dev->nfc_dev, dev->nfc_dev->targets[0].idx, - !cmd->active, NFC_RF_INITIATOR); + !active, NFC_RF_INITIATOR); return 0; } @@ -1819,12 +1822,8 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame, dev->in_maxlen, pn533_in_dep_link_up_complete, cmd, GFP_KERNEL); - if (rc) - goto out; - - -out: - kfree(cmd); + if (rc < 0) + kfree(cmd); return rc; } @@ -2078,8 +2077,12 @@ error: static int pn533_tm_send_complete(struct pn533 *dev, void *arg, u8 *params, int params_len) { + struct sk_buff *skb_out = arg; + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + dev_kfree_skb(skb_out); + if (params_len < 0) { nfc_dev_err(&dev->interface->dev, "Error %d when sending data", @@ -2117,7 +2120,7 @@ static int pn533_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb) rc = pn533_send_cmd_frame_async(dev, out_frame, dev->in_frame, dev->in_maxlen, pn533_tm_send_complete, - NULL, GFP_KERNEL); + skb, GFP_KERNEL); if (rc) { nfc_dev_err(&dev->interface->dev, "Error %d when trying to send data", rc); diff --git a/drivers/of/base.c b/drivers/of/base.c index af3b22ac762..538e3cfad23 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -45,7 +45,8 @@ struct alias_prop { static LIST_HEAD(aliases_lookup); -struct device_node *allnodes; +struct device_node *of_allnodes; +EXPORT_SYMBOL(of_allnodes); struct device_node *of_chosen; struct device_node *of_aliases; @@ -199,7 +200,7 @@ struct device_node *of_find_all_nodes(struct device_node *prev) struct device_node *np; read_lock(&devtree_lock); - np = prev ? prev->allnext : allnodes; + np = prev ? prev->allnext : of_allnodes; for (; np != NULL; np = np->allnext) if (of_node_get(np)) break; @@ -422,7 +423,7 @@ EXPORT_SYMBOL(of_get_child_by_name); */ struct device_node *of_find_node_by_path(const char *path) { - struct device_node *np = allnodes; + struct device_node *np = of_allnodes; read_lock(&devtree_lock); for (; np; np = np->allnext) { @@ -452,7 +453,7 @@ struct device_node *of_find_node_by_name(struct device_node *from, struct device_node *np; read_lock(&devtree_lock); - np = from ? from->allnext : allnodes; + np = from ? from->allnext : of_allnodes; for (; np; np = np->allnext) if (np->name && (of_node_cmp(np->name, name) == 0) && of_node_get(np)) @@ -481,7 +482,7 @@ struct device_node *of_find_node_by_type(struct device_node *from, struct device_node *np; read_lock(&devtree_lock); - np = from ? from->allnext : allnodes; + np = from ? from->allnext : of_allnodes; for (; np; np = np->allnext) if (np->type && (of_node_cmp(np->type, type) == 0) && of_node_get(np)) @@ -512,7 +513,7 @@ struct device_node *of_find_compatible_node(struct device_node *from, struct device_node *np; read_lock(&devtree_lock); - np = from ? from->allnext : allnodes; + np = from ? from->allnext : of_allnodes; for (; np; np = np->allnext) { if (type && !(np->type && (of_node_cmp(np->type, type) == 0))) @@ -545,7 +546,7 @@ struct device_node *of_find_node_with_property(struct device_node *from, struct property *pp; read_lock(&devtree_lock); - np = from ? from->allnext : allnodes; + np = from ? from->allnext : of_allnodes; for (; np; np = np->allnext) { for (pp = np->properties; pp; pp = pp->next) { if (of_prop_cmp(pp->name, prop_name) == 0) { @@ -594,27 +595,35 @@ const struct of_device_id *of_match_node(const struct of_device_id *matches, EXPORT_SYMBOL(of_match_node); /** - * of_find_matching_node - Find a node based on an of_device_id match - * table. + * of_find_matching_node_and_match - Find a node based on an of_device_id + * match table. * @from: The node to start searching from or NULL, the node * you pass will not be searched, only the next one * will; typically, you pass what the previous call * returned. of_node_put() will be called on it * @matches: array of of device match structures to search in + * @match Updated to point at the matches entry which matched * * Returns a node pointer with refcount incremented, use * of_node_put() on it when done. */ -struct device_node *of_find_matching_node(struct device_node *from, - const struct of_device_id *matches) +struct device_node *of_find_matching_node_and_match(struct device_node *from, + const struct of_device_id *matches, + const struct of_device_id **match) { struct device_node *np; + if (match) + *match = NULL; + read_lock(&devtree_lock); - np = from ? from->allnext : allnodes; + np = from ? from->allnext : of_allnodes; for (; np; np = np->allnext) { - if (of_match_node(matches, np) && of_node_get(np)) + if (of_match_node(matches, np) && of_node_get(np)) { + if (match) + *match = matches; break; + } } of_node_put(from); read_unlock(&devtree_lock); @@ -661,7 +670,7 @@ struct device_node *of_find_node_by_phandle(phandle handle) struct device_node *np; read_lock(&devtree_lock); - for (np = allnodes; np; np = np->allnext) + for (np = of_allnodes; np; np = np->allnext) if (np->phandle == handle) break; of_node_get(np); @@ -671,12 +680,89 @@ struct device_node *of_find_node_by_phandle(phandle handle) EXPORT_SYMBOL(of_find_node_by_phandle); /** + * of_property_read_u8_array - Find and read an array of u8 from a property. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @out_value: pointer to return value, modified only if return value is 0. + * @sz: number of array elements to read + * + * Search for a property in a device node and read 8-bit value(s) from + * it. Returns 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + * + * dts entry of array should be like: + * property = /bits/ 8 <0x50 0x60 0x70>; + * + * The out_value is modified only if a valid u8 value can be decoded. + */ +int of_property_read_u8_array(const struct device_node *np, + const char *propname, u8 *out_values, size_t sz) +{ + struct property *prop = of_find_property(np, propname, NULL); + const u8 *val; + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + if ((sz * sizeof(*out_values)) > prop->length) + return -EOVERFLOW; + + val = prop->value; + while (sz--) + *out_values++ = *val++; + return 0; +} +EXPORT_SYMBOL_GPL(of_property_read_u8_array); + +/** + * of_property_read_u16_array - Find and read an array of u16 from a property. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @out_value: pointer to return value, modified only if return value is 0. + * @sz: number of array elements to read + * + * Search for a property in a device node and read 16-bit value(s) from + * it. Returns 0 on success, -EINVAL if the property does not exist, + * -ENODATA if property does not have a value, and -EOVERFLOW if the + * property data isn't large enough. + * + * dts entry of array should be like: + * property = /bits/ 16 <0x5000 0x6000 0x7000>; + * + * The out_value is modified only if a valid u16 value can be decoded. + */ +int of_property_read_u16_array(const struct device_node *np, + const char *propname, u16 *out_values, size_t sz) +{ + struct property *prop = of_find_property(np, propname, NULL); + const __be16 *val; + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + if ((sz * sizeof(*out_values)) > prop->length) + return -EOVERFLOW; + + val = prop->value; + while (sz--) + *out_values++ = be16_to_cpup(val++); + return 0; +} +EXPORT_SYMBOL_GPL(of_property_read_u16_array); + +/** * of_property_read_u32_array - Find and read an array of 32 bit integers * from a property. * * @np: device node from which the property value is to be read. * @propname: name of the property to be searched. * @out_value: pointer to return value, modified only if return value is 0. + * @sz: number of array elements to read * * Search for a property in a device node and read 32-bit value(s) from * it. Returns 0 on success, -EINVAL if the property does not exist, @@ -893,8 +979,8 @@ EXPORT_SYMBOL_GPL(of_property_count_strings); * Returns the device_node pointer with refcount incremented. Use * of_node_put() on it when done. */ -struct device_node * -of_parse_phandle(struct device_node *np, const char *phandle_name, int index) +struct device_node *of_parse_phandle(const struct device_node *np, + const char *phandle_name, int index) { const __be32 *phandle; int size; @@ -1169,9 +1255,9 @@ void of_attach_node(struct device_node *np) write_lock_irqsave(&devtree_lock, flags); np->sibling = np->parent->child; - np->allnext = allnodes; + np->allnext = of_allnodes; np->parent->child = np; - allnodes = np; + of_allnodes = np; write_unlock_irqrestore(&devtree_lock, flags); } @@ -1192,11 +1278,11 @@ void of_detach_node(struct device_node *np) if (!parent) goto out_unlock; - if (allnodes == np) - allnodes = np->allnext; + if (of_allnodes == np) + of_allnodes = np->allnext; else { struct device_node *prev; - for (prev = allnodes; + for (prev = of_allnodes; prev->allnext != np; prev = prev->allnext) ; diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 91a375fb6ae..a65c39c473b 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -186,6 +186,8 @@ static unsigned long unflatten_dt_node(struct boot_param_header *blob, */ fpsize = 1; allocl = 2; + l = 1; + *pathp = '\0'; } else { /* account for '/' and path size minus terminal 0 * already in 'l' @@ -198,10 +200,10 @@ static unsigned long unflatten_dt_node(struct boot_param_header *blob, np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, __alignof__(struct device_node)); if (allnextpp) { + char *fn; memset(np, 0, sizeof(*np)); - np->full_name = ((char *)np) + sizeof(struct device_node); + np->full_name = fn = ((char *)np) + sizeof(*np); if (new_format) { - char *fn = np->full_name; /* rebuild full path for new format */ if (dad && dad->parent) { strcpy(fn, dad->full_name); @@ -215,9 +217,9 @@ static unsigned long unflatten_dt_node(struct boot_param_header *blob, fn += strlen(fn); } *(fn++) = '/'; - memcpy(fn, pathp, l); - } else - memcpy(np->full_name, pathp, l); + } + memcpy(fn, pathp, l); + prev_pp = &np->properties; **allnextpp = np; *allnextpp = &np->allnext; @@ -459,7 +461,7 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, do { u32 tag = be32_to_cpup((__be32 *)p); - char *pathp; + const char *pathp; p += 4; if (tag == OF_DT_END_NODE) { @@ -487,7 +489,7 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node, pathp = (char *)p; p = ALIGN(p + strlen(pathp) + 1, 4); if ((*pathp) == '/') { - char *lp, *np; + const char *lp, *np; for (lp = NULL, np = pathp; *np; np++) if ((*np) == '/') lp = np+1; @@ -710,7 +712,7 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, */ void __init unflatten_device_tree(void) { - __unflatten_device_tree(initial_boot_params, &allnodes, + __unflatten_device_tree(initial_boot_params, &of_allnodes, early_init_dt_alloc_memory_arch); /* Get pointer to "/chosen" and "/aliasas" nodes for use everywhere */ diff --git a/drivers/of/of_i2c.c b/drivers/of/of_i2c.c index 3550f3bf4f9..b667264222c 100644 --- a/drivers/of/of_i2c.c +++ b/drivers/of/of_i2c.c @@ -29,7 +29,7 @@ void of_i2c_register_devices(struct i2c_adapter *adap) dev_dbg(&adap->dev, "of_i2c: walking child nodes\n"); - for_each_child_of_node(adap->dev.of_node, node) { + for_each_available_child_of_node(adap->dev.of_node, node) { struct i2c_board_info info = {}; struct dev_archdata dev_ad = {}; const __be32 *addr; diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 8e6c25f3504..83ca06f4312 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -53,7 +53,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np) return rc; /* Loop over the child nodes and register a phy_device for each one */ - for_each_child_of_node(np, child) { + for_each_available_child_of_node(np, child) { const __be32 *paddr; u32 addr; int len; diff --git a/drivers/of/pdt.c b/drivers/of/pdt.c index 07cc1d678e4..37b56fd716e 100644 --- a/drivers/of/pdt.c +++ b/drivers/of/pdt.c @@ -241,15 +241,15 @@ void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops) BUG_ON(!ops); of_pdt_prom_ops = ops; - allnodes = of_pdt_create_node(root_node, NULL); + of_allnodes = of_pdt_create_node(root_node, NULL); #if defined(CONFIG_SPARC) - allnodes->path_component_name = ""; + of_allnodes->path_component_name = ""; #endif - allnodes->full_name = "/"; + of_allnodes->full_name = "/"; - nextp = &allnodes->allnext; - allnodes->child = of_pdt_build_tree(allnodes, - of_pdt_prom_ops->getchild(allnodes->phandle), &nextp); + nextp = &of_allnodes->allnext; + of_allnodes->child = of_pdt_build_tree(of_allnodes, + of_pdt_prom_ops->getchild(of_allnodes->phandle), &nextp); /* Get pointer to "/chosen" and "/aliasas" nodes for use everywhere */ of_alias_scan(kernel_tree_alloc); diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig index 4b6e4e7aca8..0e60438ebe3 100644 --- a/drivers/parport/Kconfig +++ b/drivers/parport/Kconfig @@ -57,8 +57,8 @@ config PARPORT_SERIAL will be called parport_serial. config PARPORT_PC_FIFO - bool "Use FIFO/DMA if available (EXPERIMENTAL)" - depends on PARPORT_PC && EXPERIMENTAL + bool "Use FIFO/DMA if available" + depends on PARPORT_PC help Many parallel port chipsets provide hardware that can speed up printing. Say Y here if you want to take advantage of that. @@ -70,8 +70,8 @@ config PARPORT_PC_FIFO specify which IRQ/DMA to use. config PARPORT_PC_SUPERIO - bool "SuperIO chipset support (EXPERIMENTAL)" - depends on PARPORT_PC && EXPERIMENTAL + bool "SuperIO chipset support" + depends on PARPORT_PC help Saying Y here enables some probes for Super-IO chipsets in order to find out things like base addresses, IRQ lines and DMA channels. It @@ -85,8 +85,8 @@ config PARPORT_PC_PCMCIA ports. If unsure, say N. config PARPORT_IP32 - tristate "SGI IP32 builtin port (EXPERIMENTAL)" - depends on SGI_IP32 && EXPERIMENTAL + tristate "SGI IP32 builtin port" + depends on SGI_IP32 select PARPORT_NOT_PC help Say Y here if you need support for the parallel port on @@ -126,8 +126,8 @@ config PARPORT_GSC select PARPORT_NOT_PC config PARPORT_SUNBPP - tristate "Sparc hardware (EXPERIMENTAL)" - depends on SBUS && EXPERIMENTAL + tristate "Sparc hardware" + depends on SBUS select PARPORT_NOT_PC help This driver provides support for the bidirectional parallel port diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 8d688b260e2..0c3efcffa83 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -4,7 +4,7 @@ obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \ pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \ - irq.o vpd.o + irq.o vpd.o setup-bus.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_SYSFS) += slot.o @@ -15,8 +15,6 @@ obj-$(CONFIG_PCIEPORTBUS) += pcie/ obj-$(CONFIG_PCI_IOAPIC) += ioapic.o -obj-$(CONFIG_HOTPLUG) += hotplug.o - # Build the PCI Hotplug drivers if we were asked to obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ ifdef CONFIG_HOTPLUG_PCI @@ -60,9 +58,6 @@ obj-$(CONFIG_ACPI) += pci-acpi.o # SMBIOS provided firmware instance and labels obj-$(CONFIG_PCI_LABEL) += pci-label.o -# Cardbus & CompactPCI use setup-bus -obj-$(CONFIG_HOTPLUG) += setup-bus.o - obj-$(CONFIG_PCI_SYSCALL) += syscall.o obj-$(CONFIG_PCI_STUB) += pci-stub.o diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c deleted file mode 100644 index 2b5352a7dff..00000000000 --- a/drivers/pci/hotplug.c +++ /dev/null @@ -1,37 +0,0 @@ -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/module.h> -#include "pci.h" - -int pci_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct pci_dev *pdev; - - if (!dev) - return -ENODEV; - - pdev = to_pci_dev(dev); - if (!pdev) - return -ENODEV; - - if (add_uevent_var(env, "PCI_CLASS=%04X", pdev->class)) - return -ENOMEM; - - if (add_uevent_var(env, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device)) - return -ENOMEM; - - if (add_uevent_var(env, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, - pdev->subsystem_device)) - return -ENOMEM; - - if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev))) - return -ENOMEM; - - if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", - pdev->vendor, pdev->device, - pdev->subsystem_vendor, pdev->subsystem_device, - (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), - (u8)(pdev->class))) - return -ENOMEM; - return 0; -} diff --git a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c index 6bf8d2ab164..449b4bbc830 100644 --- a/drivers/pci/hotplug/cpcihp_zt5550.c +++ b/drivers/pci/hotplug/cpcihp_zt5550.c @@ -271,7 +271,7 @@ init_hc_error: } -static void __devexit zt5550_hc_remove_one(struct pci_dev *pdev) +static void zt5550_hc_remove_one(struct pci_dev *pdev) { cpci_hp_stop(); cpci_hp_unregister_bus(bus0); @@ -290,7 +290,7 @@ static struct pci_driver zt5550_hc_driver = { .name = "zt5550_hc", .id_table = zt5550_hc_pci_tbl, .probe = zt5550_hc_init_one, - .remove = __devexit_p(zt5550_hc_remove_one), + .remove = zt5550_hc_remove_one, }; static int __init zt5550_init(void) diff --git a/drivers/pci/ioapic.c b/drivers/pci/ioapic.c index 205af8dc83c..2eca902a428 100644 --- a/drivers/pci/ioapic.c +++ b/drivers/pci/ioapic.c @@ -27,7 +27,7 @@ struct ioapic { u32 gsi_base; }; -static int __devinit ioapic_probe(struct pci_dev *dev, const struct pci_device_id *ent) +static int ioapic_probe(struct pci_dev *dev, const struct pci_device_id *ent) { acpi_handle handle; acpi_status status; @@ -88,7 +88,7 @@ exit_free: return -ENODEV; } -static void __devexit ioapic_remove(struct pci_dev *dev) +static void ioapic_remove(struct pci_dev *dev) { struct ioapic *ioapic = pci_get_drvdata(dev); @@ -110,7 +110,7 @@ static struct pci_driver ioapic_driver = { .name = "ioapic", .id_table = ioapic_devices, .probe = ioapic_probe, - .remove = __devexit_p(ioapic_remove), + .remove = ioapic_remove, }; static int __init ioapic_init(void) diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index c5792d622dc..1af4008182f 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -17,10 +17,9 @@ #include <linux/pci-acpi.h> #include <linux/pm_runtime.h> +#include <linux/pm_qos.h> #include "pci.h" -static DEFINE_MUTEX(pci_acpi_pm_notify_mtx); - /** * pci_acpi_wake_bus - Wake-up notification handler for root buses. * @handle: ACPI handle of a device the notification is for. @@ -68,67 +67,6 @@ static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context) } /** - * add_pm_notifier - Register PM notifier for given ACPI device. - * @dev: ACPI device to add the notifier for. - * @context: PCI device or bus to check for PME status if an event is signaled. - * - * NOTE: @dev need not be a run-wake or wake-up device to be a valid source of - * PM wake-up events. For example, wake-up events may be generated for bridges - * if one of the devices below the bridge is signaling PME, even if the bridge - * itself doesn't have a wake-up GPE associated with it. - */ -static acpi_status add_pm_notifier(struct acpi_device *dev, - acpi_notify_handler handler, - void *context) -{ - acpi_status status = AE_ALREADY_EXISTS; - - mutex_lock(&pci_acpi_pm_notify_mtx); - - if (dev->wakeup.flags.notifier_present) - goto out; - - status = acpi_install_notify_handler(dev->handle, - ACPI_SYSTEM_NOTIFY, - handler, context); - if (ACPI_FAILURE(status)) - goto out; - - dev->wakeup.flags.notifier_present = true; - - out: - mutex_unlock(&pci_acpi_pm_notify_mtx); - return status; -} - -/** - * remove_pm_notifier - Unregister PM notifier from given ACPI device. - * @dev: ACPI device to remove the notifier from. - */ -static acpi_status remove_pm_notifier(struct acpi_device *dev, - acpi_notify_handler handler) -{ - acpi_status status = AE_BAD_PARAMETER; - - mutex_lock(&pci_acpi_pm_notify_mtx); - - if (!dev->wakeup.flags.notifier_present) - goto out; - - status = acpi_remove_notify_handler(dev->handle, - ACPI_SYSTEM_NOTIFY, - handler); - if (ACPI_FAILURE(status)) - goto out; - - dev->wakeup.flags.notifier_present = false; - - out: - mutex_unlock(&pci_acpi_pm_notify_mtx); - return status; -} - -/** * pci_acpi_add_bus_pm_notifier - Register PM notifier for given PCI bus. * @dev: ACPI device to add the notifier for. * @pci_bus: PCI bus to walk checking for PME status if an event is signaled. @@ -136,7 +74,7 @@ static acpi_status remove_pm_notifier(struct acpi_device *dev, acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev, struct pci_bus *pci_bus) { - return add_pm_notifier(dev, pci_acpi_wake_bus, pci_bus); + return acpi_add_pm_notifier(dev, pci_acpi_wake_bus, pci_bus); } /** @@ -145,7 +83,7 @@ acpi_status pci_acpi_add_bus_pm_notifier(struct acpi_device *dev, */ acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev) { - return remove_pm_notifier(dev, pci_acpi_wake_bus); + return acpi_remove_pm_notifier(dev, pci_acpi_wake_bus); } /** @@ -156,7 +94,7 @@ acpi_status pci_acpi_remove_bus_pm_notifier(struct acpi_device *dev) acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev, struct pci_dev *pci_dev) { - return add_pm_notifier(dev, pci_acpi_wake_dev, pci_dev); + return acpi_add_pm_notifier(dev, pci_acpi_wake_dev, pci_dev); } /** @@ -165,7 +103,7 @@ acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev, */ acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev) { - return remove_pm_notifier(dev, pci_acpi_wake_dev); + return acpi_remove_pm_notifier(dev, pci_acpi_wake_dev); } phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle) @@ -257,11 +195,16 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) return -ENODEV; switch (state) { + case PCI_D3cold: + if (dev_pm_qos_flags(&dev->dev, PM_QOS_FLAG_NO_POWER_OFF) == + PM_QOS_FLAGS_ALL) { + error = -EBUSY; + break; + } case PCI_D0: case PCI_D1: case PCI_D2: case PCI_D3hot: - case PCI_D3cold: error = acpi_bus_set_power(handle, state_conv[state]); } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 6c94fc9489e..1dc78c5cabf 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -89,10 +89,6 @@ static void pci_free_dynids(struct pci_driver *drv) spin_unlock(&drv->dynids.lock); } -/* - * Dynamic device ID manipulation via sysfs is disabled for !CONFIG_HOTPLUG - */ -#ifdef CONFIG_HOTPLUG /** * store_new_id - sysfs frontend to pci_add_dynid() * @driver: target device driver @@ -191,10 +187,6 @@ static struct driver_attribute pci_drv_attrs[] = { __ATTR_NULL, }; -#else -#define pci_drv_attrs NULL -#endif /* CONFIG_HOTPLUG */ - /** * pci_match_id - See if a pci device matches a given pci_id table * @ids: array of PCI device id structures to search in @@ -1223,12 +1215,38 @@ void pci_dev_put(struct pci_dev *dev) put_device(&dev->dev); } -#ifndef CONFIG_HOTPLUG -int pci_uevent(struct device *dev, struct kobj_uevent_env *env) +static int pci_uevent(struct device *dev, struct kobj_uevent_env *env) { - return -ENODEV; + struct pci_dev *pdev; + + if (!dev) + return -ENODEV; + + pdev = to_pci_dev(dev); + if (!pdev) + return -ENODEV; + + if (add_uevent_var(env, "PCI_CLASS=%04X", pdev->class)) + return -ENOMEM; + + if (add_uevent_var(env, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device)) + return -ENOMEM; + + if (add_uevent_var(env, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, + pdev->subsystem_device)) + return -ENOMEM; + + if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev))) + return -ENOMEM; + + if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x", + pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device, + (u8)(pdev->class >> 16), (u8)(pdev->class >> 8), + (u8)(pdev->class))) + return -ENOMEM; + return 0; } -#endif struct bus_type pci_bus_type = { .name = "pci", diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index f39378d9da1..68d56f02e72 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -284,7 +284,6 @@ msi_bus_store(struct device *dev, struct device_attribute *attr, return count; } -#ifdef CONFIG_HOTPLUG static DEFINE_MUTEX(pci_remove_rescan_mutex); static ssize_t bus_rescan_store(struct bus_type *bus, const char *buf, size_t count) @@ -377,8 +376,6 @@ dev_bus_rescan_store(struct device *dev, struct device_attribute *attr, return count; } -#endif - #if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI) static ssize_t d3cold_allowed_store(struct device *dev, struct device_attribute *attr, @@ -424,10 +421,8 @@ struct device_attribute pci_dev_attrs[] = { __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), broken_parity_status_show,broken_parity_status_store), __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store), -#ifdef CONFIG_HOTPLUG __ATTR(remove, (S_IWUSR|S_IWGRP), NULL, remove_store), __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_rescan_store), -#endif #if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI) __ATTR(d3cold_allowed, 0644, d3cold_allowed_show, d3cold_allowed_store), #endif @@ -435,9 +430,7 @@ struct device_attribute pci_dev_attrs[] = { }; struct device_attribute pcibus_dev_attrs[] = { -#ifdef CONFIG_HOTPLUG __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_bus_rescan_store), -#endif __ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpumaskaffinity, NULL), __ATTR(cpulistaffinity, S_IRUGO, pci_bus_show_cpulistaffinity, NULL), __ATTR_NULL, diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index aabf64798bd..bdf66b500f2 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -86,7 +86,7 @@ enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_TUNE_OFF; * the dfl or actual value as it sees fit. Don't forget this is * measured in 32-bit words, not bytes. */ -u8 pci_dfl_cache_line_size __devinitdata = L1_CACHE_BYTES >> 2; +u8 pci_dfl_cache_line_size = L1_CACHE_BYTES >> 2; u8 pci_cache_line_size; /* @@ -3857,7 +3857,7 @@ static int __init pci_resource_alignment_sysfs_init(void) late_initcall(pci_resource_alignment_sysfs_init); -static void __devinit pci_no_domains(void) +static void pci_no_domains(void) { #ifdef CONFIG_PCI_DOMAINS pci_domains_supported = 0; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index fd92aab9904..e253881c427 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -8,7 +8,6 @@ /* Functions internal to the PCI core code */ -extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env); extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); #if !defined(CONFIG_DMI) && !defined(CONFIG_ACPI) @@ -159,11 +158,7 @@ static inline int pci_no_d1d2(struct pci_dev *dev) } extern struct device_attribute pci_dev_attrs[]; extern struct device_attribute pcibus_dev_attrs[]; -#ifdef CONFIG_HOTPLUG extern struct bus_attribute pci_bus_attrs[]; -#else -#define pci_bus_attrs NULL -#endif /** diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 030cf12d546..76ef634caf6 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -41,7 +41,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); -static int __devinit aer_probe(struct pcie_device *dev); +static int aer_probe(struct pcie_device *dev); static void aer_remove(struct pcie_device *dev); static pci_ers_result_t aer_error_detected(struct pci_dev *dev, enum pci_channel_state error); @@ -300,7 +300,7 @@ static void aer_remove(struct pcie_device *dev) * * Invoked when PCI Express bus loads AER service driver. */ -static int __devinit aer_probe(struct pcie_device *dev) +static int aer_probe(struct pcie_device *dev) { int status; struct aer_rpc *rpc; diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 0761d90ca27..d4824cb78b4 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -182,7 +182,7 @@ static const struct pci_device_id port_runtime_pm_black_list[] = { * this port device. * */ -static int __devinit pcie_portdrv_probe(struct pci_dev *dev, +static int pcie_portdrv_probe(struct pci_dev *dev, const struct pci_device_id *id) { int status; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ec909afa90b..3683f6094e3 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -305,7 +305,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) } } -static void __devinit pci_read_bridge_io(struct pci_bus *child) +static void pci_read_bridge_io(struct pci_bus *child) { struct pci_dev *dev = child->self; u8 io_base_lo, io_limit_lo; @@ -345,7 +345,7 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child) } } -static void __devinit pci_read_bridge_mmio(struct pci_bus *child) +static void pci_read_bridge_mmio(struct pci_bus *child) { struct pci_dev *dev = child->self; u16 mem_base_lo, mem_limit_lo; @@ -367,7 +367,7 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child) } } -static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child) +static void pci_read_bridge_mmio_pref(struct pci_bus *child) { struct pci_dev *dev = child->self; u16 mem_base_lo, mem_limit_lo; @@ -417,7 +417,7 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child) } } -void __devinit pci_read_bridge_bases(struct pci_bus *child) +void pci_read_bridge_bases(struct pci_bus *child) { struct pci_dev *dev = child->self; struct resource *res; @@ -705,7 +705,7 @@ static void pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max) * them, we proceed to assigning numbers to the remaining buses in * order to avoid overlaps between old and new bus numbers. */ -int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) +int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass) { struct pci_bus *child; int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS); @@ -1586,7 +1586,7 @@ void pcie_bus_configure_settings(struct pci_bus *bus, u8 mpss) } EXPORT_SYMBOL_GPL(pcie_bus_configure_settings); -unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus) +unsigned int pci_scan_child_bus(struct pci_bus *bus) { unsigned int devfn, pass, max = bus->busn_res.start; struct pci_dev *dev; @@ -1790,7 +1790,7 @@ void pci_bus_release_busn_res(struct pci_bus *b) res, ret ? "can not be" : "is"); } -struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus, +struct pci_bus *pci_scan_root_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata, struct list_head *resources) { struct pci_host_bridge_window *window; @@ -1826,7 +1826,7 @@ struct pci_bus * __devinit pci_scan_root_bus(struct device *parent, int bus, EXPORT_SYMBOL(pci_scan_root_bus); /* Deprecated; use pci_scan_root_bus() instead */ -struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, +struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata) { LIST_HEAD(resources); @@ -1844,7 +1844,7 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, } EXPORT_SYMBOL(pci_scan_bus_parented); -struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops, +struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata) { LIST_HEAD(resources); @@ -1864,7 +1864,6 @@ struct pci_bus * __devinit pci_scan_bus(int bus, struct pci_ops *ops, } EXPORT_SYMBOL(pci_scan_bus); -#ifdef CONFIG_HOTPLUG /** * pci_rescan_bus_bridge_resize - scan a PCI bus for devices. * @bridge: PCI bridge for the bus to scan @@ -1894,7 +1893,6 @@ EXPORT_SYMBOL(pci_add_new_bus); EXPORT_SYMBOL(pci_scan_slot); EXPORT_SYMBOL(pci_scan_bridge); EXPORT_SYMBOL_GPL(pci_scan_child_bus); -#endif static int __init pci_sort_bf_cmp(const struct device *d_a, const struct device *d_b) { diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 7a451ff56ec..22ad3ee0cf0 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -37,7 +37,7 @@ * key system devices. For devices that need to have mmio decoding always-on, * we need to set the dev->mmio_always_on bit. */ -static void __devinit quirk_mmio_always_on(struct pci_dev *dev) +static void quirk_mmio_always_on(struct pci_dev *dev) { dev->mmio_always_on = 1; } @@ -48,7 +48,7 @@ DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID, * Mark this device with a broken_parity_status, to allow * PCI scanning code to "skip" this now blacklisted device. */ -static void __devinit quirk_mellanox_tavor(struct pci_dev *dev) +static void quirk_mellanox_tavor(struct pci_dev *dev) { dev->broken_parity_status = 1; /* This device gives false positives */ } @@ -83,7 +83,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_p This appears to be BIOS not version dependent. So presumably there is a chipset level fix */ -static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev) +static void quirk_isa_dma_hangs(struct pci_dev *dev) { if (!isa_dma_bridge_buggy) { isa_dma_bridge_buggy=1; @@ -106,7 +106,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_d * Intel NM10 "TigerPoint" LPC PM1a_STS.BM_STS must be clear * for some HT machines to use C4 w/o hanging. */ -static void __devinit quirk_tigerpoint_bm_sts(struct pci_dev *dev) +static void quirk_tigerpoint_bm_sts(struct pci_dev *dev) { u32 pmbase; u16 pm1a; @@ -125,7 +125,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TGP_LPC, quirk /* * Chipsets where PCI->PCI transfers vanish or hang */ -static void __devinit quirk_nopcipci(struct pci_dev *dev) +static void quirk_nopcipci(struct pci_dev *dev) { if ((pci_pci_problems & PCIPCI_FAIL)==0) { dev_info(&dev->dev, "Disabling direct PCI/PCI transfers\n"); @@ -135,7 +135,7 @@ static void __devinit quirk_nopcipci(struct pci_dev *dev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci); -static void __devinit quirk_nopciamd(struct pci_dev *dev) +static void quirk_nopciamd(struct pci_dev *dev) { u8 rev; pci_read_config_byte(dev, 0x08, &rev); @@ -150,7 +150,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8151_0, quirk_nopci /* * Triton requires workarounds to be used by the drivers */ -static void __devinit quirk_triton(struct pci_dev *dev) +static void quirk_triton(struct pci_dev *dev) { if ((pci_pci_problems&PCIPCI_TRITON)==0) { dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); @@ -229,7 +229,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_viala /* * VIA Apollo VP3 needs ETBF on BT848/878 */ -static void __devinit quirk_viaetbf(struct pci_dev *dev) +static void quirk_viaetbf(struct pci_dev *dev) { if ((pci_pci_problems&PCIPCI_VIAETBF)==0) { dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); @@ -238,7 +238,7 @@ static void __devinit quirk_viaetbf(struct pci_dev *dev) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_viaetbf); -static void __devinit quirk_vsfx(struct pci_dev *dev) +static void quirk_vsfx(struct pci_dev *dev) { if ((pci_pci_problems&PCIPCI_VSFX)==0) { dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); @@ -253,7 +253,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, quirk_vsfx) * workaround applied too * [Info kindly provided by ALi] */ -static void __devinit quirk_alimagik(struct pci_dev *dev) +static void quirk_alimagik(struct pci_dev *dev) { if ((pci_pci_problems&PCIPCI_ALIMAGIK)==0) { dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); @@ -267,7 +267,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1651, quirk_alimag * Natoma has some interesting boundary conditions with Zoran stuff * at least */ -static void __devinit quirk_natoma(struct pci_dev *dev) +static void quirk_natoma(struct pci_dev *dev) { if ((pci_pci_problems&PCIPCI_NATOMA)==0) { dev_info(&dev->dev, "Limiting direct PCI/PCI transfers\n"); @@ -285,7 +285,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, qu * This chip can cause PCI parity errors if config register 0xA0 is read * while DMAs are occurring. */ -static void __devinit quirk_citrine(struct pci_dev *dev) +static void quirk_citrine(struct pci_dev *dev) { dev->cfg_size = 0xA0; } @@ -295,7 +295,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, quirk_cit * S3 868 and 968 chips report region size equal to 32M, but they decode 64M. * If it's needed, re-allocate the region. */ -static void __devinit quirk_s3_64M(struct pci_dev *dev) +static void quirk_s3_64M(struct pci_dev *dev) { struct resource *r = &dev->resource[0]; @@ -313,7 +313,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M); * BAR0 should be 8 bytes; instead, it may be set to something like 8k * (which conflicts w/ BAR1's memory range). */ -static void __devinit quirk_cs5536_vsa(struct pci_dev *dev) +static void quirk_cs5536_vsa(struct pci_dev *dev) { if (pci_resource_len(dev, 0) != 8) { struct resource *res = &dev->resource[0]; @@ -324,7 +324,7 @@ static void __devinit quirk_cs5536_vsa(struct pci_dev *dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, quirk_cs5536_vsa); -static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, +static void quirk_io_region(struct pci_dev *dev, unsigned region, unsigned size, int nr, const char *name) { region &= ~(size-1); @@ -352,7 +352,7 @@ static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, * ATI Northbridge setups MCE the processor if you even * read somewhere between 0x3b0->0x3bb or read 0x3d3 */ -static void __devinit quirk_ati_exploding_mce(struct pci_dev *dev) +static void quirk_ati_exploding_mce(struct pci_dev *dev) { dev_info(&dev->dev, "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb\n"); /* Mae rhaid i ni beidio ag edrych ar y lleoliadiau I/O hyn */ @@ -372,7 +372,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_ * 0xE0 (64 bytes of ACPI registers) * 0xE2 (32 bytes of SMB registers) */ -static void __devinit quirk_ali7101_acpi(struct pci_dev *dev) +static void quirk_ali7101_acpi(struct pci_dev *dev) { u16 region; @@ -440,7 +440,7 @@ static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int * 0x90 (16 bytes of SMB registers) * and a few strange programmable PIIX4 device resources. */ -static void __devinit quirk_piix4_acpi(struct pci_dev *dev) +static void quirk_piix4_acpi(struct pci_dev *dev) { u32 region, res_a; @@ -489,7 +489,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3, qui * 0x40 (128 bytes of ACPI, GPIO & TCO registers) * 0x58 (64 bytes of GPIO I/O space) */ -static void __devinit quirk_ich4_lpc_acpi(struct pci_dev *dev) +static void quirk_ich4_lpc_acpi(struct pci_dev *dev) { u32 region; u8 enable; @@ -531,7 +531,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, quirk_ich4_lpc_acpi); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, quirk_ich4_lpc_acpi); -static void __devinit ich6_lpc_acpi_gpio(struct pci_dev *dev) +static void ich6_lpc_acpi_gpio(struct pci_dev *dev) { u32 region; u8 enable; @@ -555,7 +555,7 @@ static void __devinit ich6_lpc_acpi_gpio(struct pci_dev *dev) } } -static void __devinit ich6_lpc_generic_decode(struct pci_dev *dev, unsigned reg, const char *name, int dynsize) +static void ich6_lpc_generic_decode(struct pci_dev *dev, unsigned reg, const char *name, int dynsize) { u32 val; u32 size, base; @@ -583,7 +583,7 @@ static void __devinit ich6_lpc_generic_decode(struct pci_dev *dev, unsigned reg, dev_info(&dev->dev, "%s PIO at %04x-%04x\n", name, base, base+size-1); } -static void __devinit quirk_ich6_lpc(struct pci_dev *dev) +static void quirk_ich6_lpc(struct pci_dev *dev) { /* Shared ACPI/GPIO decode with all ICH6+ */ ich6_lpc_acpi_gpio(dev); @@ -595,7 +595,7 @@ static void __devinit quirk_ich6_lpc(struct pci_dev *dev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, quirk_ich6_lpc); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc); -static void __devinit ich7_lpc_generic_decode(struct pci_dev *dev, unsigned reg, const char *name) +static void ich7_lpc_generic_decode(struct pci_dev *dev, unsigned reg, const char *name) { u32 val; u32 mask, base; @@ -619,7 +619,7 @@ static void __devinit ich7_lpc_generic_decode(struct pci_dev *dev, unsigned reg, } /* ICH7-10 has the same common LPC generic IO decode registers */ -static void __devinit quirk_ich7_lpc(struct pci_dev *dev) +static void quirk_ich7_lpc(struct pci_dev *dev) { /* We share the common ACPI/GPIO decode with ICH6 */ ich6_lpc_acpi_gpio(dev); @@ -648,7 +648,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_1, qui * VIA ACPI: One IO region pointed to by longword at * 0x48 or 0x20 (256 bytes of ACPI registers) */ -static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev) +static void quirk_vt82c586_acpi(struct pci_dev *dev) { u32 region; @@ -666,7 +666,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt * 0x70 (128 bytes of hardware monitoring register) * 0x90 (16 bytes of SMB registers) */ -static void __devinit quirk_vt82c686_acpi(struct pci_dev *dev) +static void quirk_vt82c686_acpi(struct pci_dev *dev) { u16 hm; u32 smb; @@ -688,7 +688,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt * 0x88 (128 bytes of power management registers) * 0xd0 (16 bytes of SMB registers) */ -static void __devinit quirk_vt8235_acpi(struct pci_dev *dev) +static void quirk_vt8235_acpi(struct pci_dev *dev) { u16 pm, smb; @@ -706,7 +706,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, quirk_vt8235 * TI XIO2000a PCIe-PCI Bridge erroneously reports it supports fast back-to-back: * Disable fast back-to-back on the secondary bus segment */ -static void __devinit quirk_xio2000a(struct pci_dev *dev) +static void quirk_xio2000a(struct pci_dev *dev) { struct pci_dev *pdev; u16 command; @@ -780,7 +780,7 @@ DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk * noapic specified. For the moment we assume it's the erratum. We may be wrong * of course. However the advice is demonstrably good even if so.. */ -static void __devinit quirk_amd_ioapic(struct pci_dev *dev) +static void quirk_amd_ioapic(struct pci_dev *dev) { if (dev->revision >= 0x02) { dev_warn(&dev->dev, "I/O APIC: AMD Erratum #22 may be present. In the event of instability try\n"); @@ -789,7 +789,7 @@ static void __devinit quirk_amd_ioapic(struct pci_dev *dev) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, quirk_amd_ioapic); -static void __devinit quirk_ioapic_rmw(struct pci_dev *dev) +static void quirk_ioapic_rmw(struct pci_dev *dev) { if (dev->devfn == 0 && dev->bus->number == 0) sis_apic_bug = 1; @@ -801,7 +801,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw); * Some settings of MMRBC can lead to data corruption so block changes. * See AMD 8131 HyperTransport PCI-X Tunnel Revision Guide */ -static void __devinit quirk_amd_8131_mmrbc(struct pci_dev *dev) +static void quirk_amd_8131_mmrbc(struct pci_dev *dev) { if (dev->subordinate && dev->revision <= 0x12) { dev_info(&dev->dev, "AMD8131 rev %x detected; " @@ -819,7 +819,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_ * value of the ACPI SCI interrupt is only done for convenience. * -jgarzik */ -static void __devinit quirk_via_acpi(struct pci_dev *d) +static void quirk_via_acpi(struct pci_dev *d) { /* * VIA ACPI device: SCI IRQ line in PCI config byte 0x42 @@ -926,7 +926,7 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_vlink); * We need to switch it off to be able to recognize the real * type of the chip. */ -static void __devinit quirk_vt82c598_id(struct pci_dev *dev) +static void quirk_vt82c598_id(struct pci_dev *dev) { pci_write_config_byte(dev, 0xfc, 0); pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device); @@ -978,7 +978,7 @@ DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C * assigned to it. We force a larger allocation to ensure that * nothing gets put too close to it. */ -static void __devinit quirk_dunord ( struct pci_dev * dev ) +static void quirk_dunord(struct pci_dev *dev) { struct resource *r = &dev->resource [1]; r->start = 0; @@ -992,7 +992,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_DUNORD, PCI_DEVICE_ID_DUNORD_I3000, quirk * in the ProgIf. Unfortunately, the ProgIf value is wrong - 0x80 * instead of 0x01. */ -static void __devinit quirk_transparent_bridge(struct pci_dev *dev) +static void quirk_transparent_bridge(struct pci_dev *dev) { dev->transparent = 1; } @@ -1066,7 +1066,7 @@ DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_HUDSON2_SATA /* * Serverworks CSB5 IDE does not fully support native mode */ -static void __devinit quirk_svwks_csb5ide(struct pci_dev *pdev) +static void quirk_svwks_csb5ide(struct pci_dev *pdev) { u8 prog; pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog); @@ -1082,7 +1082,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB /* * Intel 82801CAM ICH3-M datasheet says IDE modes must be the same */ -static void __devinit quirk_ide_samemode(struct pci_dev *pdev) +static void quirk_ide_samemode(struct pci_dev *pdev) { u8 prog; @@ -1101,7 +1101,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_10, qui * Some ATA devices break if put into D3 */ -static void __devinit quirk_no_ata_d3(struct pci_dev *pdev) +static void quirk_no_ata_d3(struct pci_dev *pdev) { pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3; } @@ -1121,7 +1121,7 @@ DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_VIA, PCI_ANY_ID, /* This was originally an Alpha specific thing, but it really fits here. * The i82375 PCI/EISA bridge appears as non-classified. Fix that. */ -static void __devinit quirk_eisa_bridge(struct pci_dev *dev) +static void quirk_eisa_bridge(struct pci_dev *dev) { dev->class = PCI_CLASS_BRIDGE_EISA << 8; } @@ -1155,7 +1155,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_e */ static int asus_hides_smbus; -static void __devinit asus_hides_smbus_hostbridge(struct pci_dev *dev) +static void asus_hides_smbus_hostbridge(struct pci_dev *dev) { if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_ASUSTEK)) { if (dev->device == PCI_DEVICE_ID_INTEL_82845_HB) @@ -1538,7 +1538,7 @@ DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB3 #endif #ifdef CONFIG_X86_IO_APIC -static void __devinit quirk_alder_ioapic(struct pci_dev *pdev) +static void quirk_alder_ioapic(struct pci_dev *pdev) { int i; @@ -1561,7 +1561,7 @@ static void __devinit quirk_alder_ioapic(struct pci_dev *pdev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EESSC, quirk_alder_ioapic); #endif -static void __devinit quirk_pcie_mch(struct pci_dev *pdev) +static void quirk_pcie_mch(struct pci_dev *pdev) { pci_msi_off(pdev); pdev->no_msi = 1; @@ -1575,7 +1575,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quir * It's possible for the MSI to get corrupted if shpc and acpi * are used together on certain PXH-based systems. */ -static void __devinit quirk_pcie_pxh(struct pci_dev *dev) +static void quirk_pcie_pxh(struct pci_dev *dev) { pci_msi_off(dev); dev->no_msi = 1; @@ -1777,7 +1777,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS, qui * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes. * Re-allocate the region if needed... */ -static void __devinit quirk_tc86c001_ide(struct pci_dev *dev) +static void quirk_tc86c001_ide(struct pci_dev *dev) { struct resource *r = &dev->resource[0]; @@ -1790,7 +1790,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE, quirk_tc86c001_ide); -static void __devinit quirk_netmos(struct pci_dev *dev) +static void quirk_netmos(struct pci_dev *dev) { unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4; unsigned int num_serial = dev->subsystem_device & 0xf; @@ -1828,7 +1828,7 @@ static void __devinit quirk_netmos(struct pci_dev *dev) DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, PCI_CLASS_COMMUNICATION_SERIAL, 8, quirk_netmos); -static void __devinit quirk_e100_interrupt(struct pci_dev *dev) +static void quirk_e100_interrupt(struct pci_dev *dev) { u16 command, pmcsr; u8 __iomem *csr; @@ -1901,7 +1901,7 @@ DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, * The 82575 and 82598 may experience data corruption issues when transitioning * out of L0S. To prevent this we need to disable L0S on the pci-e link */ -static void __devinit quirk_disable_aspm_l0s(struct pci_dev *dev) +static void quirk_disable_aspm_l0s(struct pci_dev *dev) { dev_info(&dev->dev, "Disabling L0s\n"); pci_disable_link_state(dev, PCIE_LINK_STATE_L0S); @@ -1921,7 +1921,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10f1, quirk_disable_aspm_l0s); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10f4, quirk_disable_aspm_l0s); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1508, quirk_disable_aspm_l0s); -static void __devinit fixup_rev1_53c810(struct pci_dev* dev) +static void fixup_rev1_53c810(struct pci_dev *dev) { /* rev 1 ncr53c810 chips don't set the class at all which means * they don't get their resources remapped. Fix that here. @@ -1935,7 +1935,7 @@ static void __devinit fixup_rev1_53c810(struct pci_dev* dev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810); /* Enable 1k I/O space granularity on the Intel P64H2 */ -static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev) +static void quirk_p64h2_1k_io(struct pci_dev *dev) { u16 en1k; @@ -1968,7 +1968,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, quirk_nvidia_ck804_pcie_aer_ext_cap); -static void __devinit quirk_via_cx700_pci_parking_caching(struct pci_dev *dev) +static void quirk_via_cx700_pci_parking_caching(struct pci_dev *dev) { /* * Disable PCI Bus Parking and PCI Master read caching on CX700 @@ -2031,7 +2031,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, 0x324e, quirk_via_cx700_pci_parking_c * We believe that it is legal to read beyond the end tag and * therefore the solution is to limit the read/write length. */ -static void __devinit quirk_brcm_570x_limit_vpd(struct pci_dev *dev) +static void quirk_brcm_570x_limit_vpd(struct pci_dev *dev) { /* * Only disable the VPD capability for 5706, 5706S, 5708, @@ -2091,7 +2091,7 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_BROADCOM, * the DRBs - this is where we expose device 6. * http://www.x86-secret.com/articles/tweak/pat/patsecrets-2.htm */ -static void __devinit quirk_unhide_mch_dev6(struct pci_dev *dev) +static void quirk_unhide_mch_dev6(struct pci_dev *dev) { u8 reg; @@ -2115,7 +2115,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82875_HB, * supports link speed auto negotiation, but falsely sets * the link speed to 5GT/s. */ -static void __devinit quirk_tile_plx_gen1(struct pci_dev *dev) +static void quirk_tile_plx_gen1(struct pci_dev *dev) { if (tile_plx_gen1) { pci_write_config_dword(dev, 0x98, 0x1); @@ -2132,7 +2132,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8624, quirk_tile_plx_gen1); * aware of it. Instead of setting the flag on all busses in the * machine, simply disable MSI globally. */ -static void __devinit quirk_disable_all_msi(struct pci_dev *dev) +static void quirk_disable_all_msi(struct pci_dev *dev) { pci_no_msi(); dev_warn(&dev->dev, "MSI quirk detected; MSI disabled\n"); @@ -2146,7 +2146,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3364, quirk_disab DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8380_0, quirk_disable_all_msi); /* Disable MSI on chipsets that are known to not support it */ -static void __devinit quirk_disable_msi(struct pci_dev *dev) +static void quirk_disable_msi(struct pci_dev *dev) { if (dev->subordinate) { dev_warn(&dev->dev, "MSI quirk detected; " @@ -2164,7 +2164,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x5a3f, quirk_disable_msi); * we use the possible vendor/device IDs of the host bridge for the * declared quirk, and search for the APC bridge by slot number. */ -static void __devinit quirk_amd_780_apc_msi(struct pci_dev *host_bridge) +static void quirk_amd_780_apc_msi(struct pci_dev *host_bridge) { struct pci_dev *apc_bridge; @@ -2272,7 +2272,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8132_BRIDGE, * for the MCP55 NIC. It is not yet determined whether the msi problem * also affects other devices. As for now, turn off msi for this device. */ -static void __devinit nvenet_msi_disable(struct pci_dev *dev) +static void nvenet_msi_disable(struct pci_dev *dev) { const char *board_name = dmi_get_system_info(DMI_BOARD_NAME); @@ -2298,7 +2298,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA, * we have it set correctly. * Note this is an undocumented register. */ -static void __devinit nvbridge_check_legacy_irq_routing(struct pci_dev *dev) +static void nvbridge_check_legacy_irq_routing(struct pci_dev *dev) { u32 cfg; @@ -2534,11 +2534,11 @@ DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_q DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk_all); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk_all); -static void __devinit quirk_msi_intx_disable_bug(struct pci_dev *dev) +static void quirk_msi_intx_disable_bug(struct pci_dev *dev) { dev->dev_flags |= PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG; } -static void __devinit quirk_msi_intx_disable_ati_bug(struct pci_dev *dev) +static void quirk_msi_intx_disable_ati_bug(struct pci_dev *dev) { struct pci_dev *p; @@ -2612,7 +2612,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATTANSIC, 0x1083, * kernel fails to allocate resources when hotplug device is * inserted and PCI bus is rescanned. */ -static void __devinit quirk_hotplug_bridge(struct pci_dev *dev) +static void quirk_hotplug_bridge(struct pci_dev *dev) { dev->is_hotplug_bridge = 1; } @@ -2752,7 +2752,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x342e, vtd_mask_spec_errors); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x3c28, vtd_mask_spec_errors); #endif -static void __devinit fixup_ti816x_class(struct pci_dev* dev) +static void fixup_ti816x_class(struct pci_dev *dev) { /* TI 816x devices do not have class code set when in PCIe boot mode */ dev_info(&dev->dev, "Setting PCI class for 816x PCIe device\n"); @@ -2764,7 +2764,7 @@ DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_TI, 0xb800, /* Some PCIe devices do not work reliably with the claimed maximum * payload size supported. */ -static void __devinit fixup_mpss_256(struct pci_dev *dev) +static void fixup_mpss_256(struct pci_dev *dev) { dev->pcie_mpss = 1; /* 256 bytes */ } @@ -2782,7 +2782,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SOLARFLARE, * coalescing must be disabled. Unfortunately, it cannot be re-enabled because * it is possible to hotplug a device with MPS of 256B. */ -static void __devinit quirk_intel_mc_errata(struct pci_dev *dev) +static void quirk_intel_mc_errata(struct pci_dev *dev) { int err; u16 rcc; @@ -2888,7 +2888,7 @@ static void fixup_debug_report(struct pci_dev *dev, ktime_t calltime, * This resolves crashes often seen on monitor unplug. */ #define I915_DEIER_REG 0x4400c -static void __devinit disable_igfx_irq(struct pci_dev *dev) +static void disable_igfx_irq(struct pci_dev *dev) { void __iomem *regs = pci_iomap(dev, 0, 0); if (regs == NULL) { @@ -2914,7 +2914,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq); * PCI_COMMAND_INTX_DISABLE works though they actually do not properly * support this feature. */ -static void __devinit quirk_broken_intx_masking(struct pci_dev *dev) +static void quirk_broken_intx_masking(struct pci_dev *dev) { dev->broken_intx_masking = 1; } diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 0aab85a5155..db542f4196a 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -412,7 +412,7 @@ static int pcifront_claim_resource(struct pci_dev *dev, void *data) return 0; } -static int __devinit pcifront_scan_bus(struct pcifront_device *pdev, +static int pcifront_scan_bus(struct pcifront_device *pdev, unsigned int domain, unsigned int bus, struct pci_bus *b) { @@ -441,7 +441,7 @@ static int __devinit pcifront_scan_bus(struct pcifront_device *pdev, return 0; } -static int __devinit pcifront_scan_root(struct pcifront_device *pdev, +static int pcifront_scan_root(struct pcifront_device *pdev, unsigned int domain, unsigned int bus) { struct pci_bus *b; @@ -503,7 +503,7 @@ err_out: return err; } -static int __devinit pcifront_rescan_root(struct pcifront_device *pdev, +static int pcifront_rescan_root(struct pcifront_device *pdev, unsigned int domain, unsigned int bus) { int err; @@ -834,7 +834,7 @@ out: return err; } -static int __devinit pcifront_try_connect(struct pcifront_device *pdev) +static int pcifront_try_connect(struct pcifront_device *pdev) { int err = -EFAULT; int i, num_roots, len; @@ -924,7 +924,7 @@ out: return err; } -static int __devinit pcifront_attach_devices(struct pcifront_device *pdev) +static int pcifront_attach_devices(struct pcifront_device *pdev) { int err = -EFAULT; int i, num_roots, len; diff --git a/drivers/pcmcia/bcm63xx_pcmcia.c b/drivers/pcmcia/bcm63xx_pcmcia.c index c2e997a570b..0c6aac1232f 100644 --- a/drivers/pcmcia/bcm63xx_pcmcia.c +++ b/drivers/pcmcia/bcm63xx_pcmcia.c @@ -323,7 +323,7 @@ static struct pccard_operations bcm63xx_pcmcia_operations = { /* * register pcmcia socket to core */ -static int __devinit bcm63xx_drv_pcmcia_probe(struct platform_device *pdev) +static int bcm63xx_drv_pcmcia_probe(struct platform_device *pdev) { struct bcm63xx_pcmcia_socket *skt; struct pcmcia_socket *sock; @@ -436,7 +436,7 @@ err: return ret; } -static int __devexit bcm63xx_drv_pcmcia_remove(struct platform_device *pdev) +static int bcm63xx_drv_pcmcia_remove(struct platform_device *pdev) { struct bcm63xx_pcmcia_socket *skt; struct resource *res; @@ -453,7 +453,7 @@ static int __devexit bcm63xx_drv_pcmcia_remove(struct platform_device *pdev) struct platform_driver bcm63xx_pcmcia_driver = { .probe = bcm63xx_drv_pcmcia_probe, - .remove = __devexit_p(bcm63xx_drv_pcmcia_remove), + .remove = bcm63xx_drv_pcmcia_remove, .driver = { .name = "bcm63xx_pcmcia", .owner = THIS_MODULE, @@ -461,7 +461,7 @@ struct platform_driver bcm63xx_pcmcia_driver = { }; #ifdef CONFIG_CARDBUS -static int __devinit bcm63xx_cb_probe(struct pci_dev *dev, +static int bcm63xx_cb_probe(struct pci_dev *dev, const struct pci_device_id *id) { /* keep pci device */ @@ -469,7 +469,7 @@ static int __devinit bcm63xx_cb_probe(struct pci_dev *dev, return platform_driver_register(&bcm63xx_pcmcia_driver); } -static void __devexit bcm63xx_cb_exit(struct pci_dev *dev) +static void bcm63xx_cb_exit(struct pci_dev *dev) { platform_driver_unregister(&bcm63xx_pcmcia_driver); bcm63xx_cb_dev = NULL; @@ -503,7 +503,7 @@ static struct pci_driver bcm63xx_cardbus_driver = { .name = "bcm63xx_cardbus", .id_table = bcm63xx_cb_table, .probe = bcm63xx_cb_probe, - .remove = __devexit_p(bcm63xx_cb_exit), + .remove = bcm63xx_cb_exit, }; #endif diff --git a/drivers/pcmcia/bfin_cf_pcmcia.c b/drivers/pcmcia/bfin_cf_pcmcia.c index ac1a2232eab..ed3b522601b 100644 --- a/drivers/pcmcia/bfin_cf_pcmcia.c +++ b/drivers/pcmcia/bfin_cf_pcmcia.c @@ -195,7 +195,7 @@ static struct pccard_operations bfin_cf_ops = { /*--------------------------------------------------------------------------*/ -static int __devinit bfin_cf_probe(struct platform_device *pdev) +static int bfin_cf_probe(struct platform_device *pdev) { struct bfin_cf_socket *cf; struct resource *io_mem, *attr_mem; @@ -286,7 +286,7 @@ fail0: return status; } -static int __devexit bfin_cf_remove(struct platform_device *pdev) +static int bfin_cf_remove(struct platform_device *pdev) { struct bfin_cf_socket *cf = platform_get_drvdata(pdev); @@ -307,7 +307,7 @@ static struct platform_driver bfin_cf_driver = { .owner = THIS_MODULE, }, .probe = bfin_cf_probe, - .remove = __devexit_p(bfin_cf_remove), + .remove = bfin_cf_remove, }; module_platform_driver(bfin_cf_driver); diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c index a484b1fb338..a31e69ea99f 100644 --- a/drivers/pcmcia/db1xxx_ss.c +++ b/drivers/pcmcia/db1xxx_ss.c @@ -409,7 +409,7 @@ static struct pccard_operations db1x_pcmcia_operations = { .set_mem_map = au1x00_pcmcia_set_mem_map, }; -static int __devinit db1x_pcmcia_socket_probe(struct platform_device *pdev) +static int db1x_pcmcia_socket_probe(struct platform_device *pdev) { struct db1x_pcmcia_sock *sock; struct resource *r; @@ -559,7 +559,7 @@ out0: return ret; } -static int __devexit db1x_pcmcia_socket_remove(struct platform_device *pdev) +static int db1x_pcmcia_socket_remove(struct platform_device *pdev) { struct db1x_pcmcia_sock *sock = platform_get_drvdata(pdev); @@ -577,7 +577,7 @@ static struct platform_driver db1x_pcmcia_socket_driver = { .owner = THIS_MODULE, }, .probe = db1x_pcmcia_socket_probe, - .remove = __devexit_p(db1x_pcmcia_socket_remove), + .remove = db1x_pcmcia_socket_remove, }; module_platform_driver(db1x_pcmcia_socket_driver); diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 079629bff95..2deacbb2ffd 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -920,8 +920,6 @@ static int pcmcia_bus_match(struct device *dev, struct device_driver *drv) return 0; } -#ifdef CONFIG_HOTPLUG - static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env) { struct pcmcia_device *p_dev; @@ -962,15 +960,6 @@ static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env) return 0; } -#else - -static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - return -ENODEV; -} - -#endif - /************************ runtime PM support ***************************/ static int pcmcia_dev_suspend(struct device *dev, pm_message_t state); @@ -1329,7 +1318,7 @@ static struct pcmcia_callback pcmcia_bus_callback = { .resume = pcmcia_bus_resume, }; -static int __devinit pcmcia_bus_add_socket(struct device *dev, +static int pcmcia_bus_add_socket(struct device *dev, struct class_interface *class_intf) { struct pcmcia_socket *socket = dev_get_drvdata(dev); diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c index 7647d232e9e..a007321ad31 100644 --- a/drivers/pcmcia/electra_cf.c +++ b/drivers/pcmcia/electra_cf.c @@ -181,7 +181,7 @@ static struct pccard_operations electra_cf_ops = { .set_mem_map = electra_cf_set_mem_map, }; -static int __devinit electra_cf_probe(struct platform_device *ofdev) +static int electra_cf_probe(struct platform_device *ofdev) { struct device *device = &ofdev->dev; struct device_node *np = ofdev->dev.of_node; @@ -324,7 +324,7 @@ fail1: } -static int __devexit electra_cf_remove(struct platform_device *ofdev) +static int electra_cf_remove(struct platform_device *ofdev) { struct device *device = &ofdev->dev; struct electra_cf_socket *cf; diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c index 4e8831bdb6e..3578e1ca97a 100644 --- a/drivers/pcmcia/i82092.c +++ b/drivers/pcmcia/i82092.c @@ -35,7 +35,7 @@ static struct pci_driver i82092aa_pci_driver = { .name = "i82092aa", .id_table = i82092aa_pci_ids, .probe = i82092aa_pci_probe, - .remove = __devexit_p(i82092aa_pci_remove), + .remove = i82092aa_pci_remove, }; @@ -67,7 +67,7 @@ static struct socket_info sockets[MAX_SOCKETS]; static int socket_count; /* shortcut */ -static int __devinit i82092aa_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +static int i82092aa_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { unsigned char configbyte; int i, ret; @@ -162,7 +162,7 @@ err_out_disable: return ret; } -static void __devexit i82092aa_pci_remove(struct pci_dev *dev) +static void i82092aa_pci_remove(struct pci_dev *dev) { struct pcmcia_socket *socket = pci_get_drvdata(dev); diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index 253e3867dec..b29d97e170a 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c @@ -589,7 +589,7 @@ static int pd6729_check_irq(int irq) return 0; } -static u_int __devinit pd6729_isa_scan(void) +static u_int pd6729_isa_scan(void) { u_int mask0, mask = 0; int i; @@ -620,7 +620,7 @@ static u_int __devinit pd6729_isa_scan(void) return mask; } -static int __devinit pd6729_pci_probe(struct pci_dev *dev, +static int pd6729_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { int i, j, ret; @@ -739,7 +739,7 @@ err_out_free_mem: return ret; } -static void __devexit pd6729_pci_remove(struct pci_dev *dev) +static void pd6729_pci_remove(struct pci_dev *dev) { int i; struct pd6729_socket *socket = pci_get_drvdata(dev); @@ -772,7 +772,7 @@ static struct pci_driver pd6729_pci_driver = { .name = "pd6729", .id_table = pd6729_pci_ids, .probe = pd6729_pci_probe, - .remove = __devexit_p(pd6729_pci_remove), + .remove = pd6729_pci_remove, }; static int pd6729_module_init(void) diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index 7dd879ce514..89ebd8c7663 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c @@ -208,7 +208,7 @@ static struct pcmcia_low_level sharpsl_pcmcia_ops = { #ifdef CONFIG_SA1100_COLLIE #include "sa11xx_base.h" -int __devinit pcmcia_collie_init(struct device *dev) +int pcmcia_collie_init(struct device *dev) { int ret = -ENODEV; diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 9da9656242a..430a9ac5609 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c @@ -1199,7 +1199,7 @@ static const struct attribute_group rsrc_attributes = { .attrs = pccard_rsrc_attributes, }; -static int __devinit pccard_sysfs_add_rsrc(struct device *dev, +static int pccard_sysfs_add_rsrc(struct device *dev, struct class_interface *class_intf) { struct pcmcia_socket *s = dev_get_drvdata(dev); @@ -1209,7 +1209,7 @@ static int __devinit pccard_sysfs_add_rsrc(struct device *dev, return sysfs_create_group(&dev->kobj, &rsrc_attributes); } -static void __devexit pccard_sysfs_remove_rsrc(struct device *dev, +static void pccard_sysfs_remove_rsrc(struct device *dev, struct class_interface *class_intf) { struct pcmcia_socket *s = dev_get_drvdata(dev); @@ -1222,7 +1222,7 @@ static void __devexit pccard_sysfs_remove_rsrc(struct device *dev, static struct class_interface pccard_rsrc_interface __refdata = { .class = &pcmcia_socket_class, .add_dev = &pccard_sysfs_add_rsrc, - .remove_dev = __devexit_p(&pccard_sysfs_remove_rsrc), + .remove_dev = &pccard_sysfs_remove_rsrc, }; static int __init nonstatic_sysfs_init(void) diff --git a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c index ba8557eea61..44cfc4416e5 100644 --- a/drivers/pcmcia/sa1100_assabet.c +++ b/drivers/pcmcia/sa1100_assabet.c @@ -95,7 +95,7 @@ static struct pcmcia_low_level assabet_pcmcia_ops = { .socket_suspend = assabet_pcmcia_socket_suspend, }; -int __devinit pcmcia_assabet_init(struct device *dev) +int pcmcia_assabet_init(struct device *dev) { int ret = -ENODEV; diff --git a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c index c59c44921a3..b3774e5d039 100644 --- a/drivers/pcmcia/sa1100_cerf.c +++ b/drivers/pcmcia/sa1100_cerf.c @@ -81,7 +81,7 @@ static struct pcmcia_low_level cerf_pcmcia_ops = { .configure_socket = cerf_pcmcia_configure_socket, }; -int __devinit pcmcia_cerf_init(struct device *dev) +int pcmcia_cerf_init(struct device *dev) { int ret = -ENODEV; diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index 2eea664bc07..ff8a027a4af 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -43,7 +43,7 @@ int __init pcmcia_collie_init(struct device *dev); -static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) __devinitdata = { +static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = { #ifdef CONFIG_SA1100_ASSABET pcmcia_assabet_init, #endif @@ -67,7 +67,7 @@ static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) __devinitdata = { #endif }; -static int __devinit sa11x0_drv_pcmcia_probe(struct platform_device *dev) +static int sa11x0_drv_pcmcia_probe(struct platform_device *dev) { int i, ret = -ENODEV; diff --git a/drivers/pcmcia/sa1100_h3600.c b/drivers/pcmcia/sa1100_h3600.c index d9c7337b909..431d8b07cba 100644 --- a/drivers/pcmcia/sa1100_h3600.c +++ b/drivers/pcmcia/sa1100_h3600.c @@ -153,7 +153,7 @@ struct pcmcia_low_level h3600_pcmcia_ops = { .socket_suspend = h3600_pcmcia_socket_suspend, }; -int __devinit pcmcia_h3600_init(struct device *dev) +int pcmcia_h3600_init(struct device *dev) { int ret = -ENODEV; diff --git a/drivers/pcmcia/sa1100_shannon.c b/drivers/pcmcia/sa1100_shannon.c index 56ab7391560..b07a2dc3296 100644 --- a/drivers/pcmcia/sa1100_shannon.c +++ b/drivers/pcmcia/sa1100_shannon.c @@ -92,7 +92,7 @@ static struct pcmcia_low_level shannon_pcmcia_ops = { .configure_socket = shannon_pcmcia_configure_socket, }; -int __devinit pcmcia_shannon_init(struct device *dev) +int pcmcia_shannon_init(struct device *dev) { int ret = -ENODEV; diff --git a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c index 8647b17c449..73fd37968b6 100644 --- a/drivers/pcmcia/sa1100_simpad.c +++ b/drivers/pcmcia/sa1100_simpad.c @@ -109,7 +109,7 @@ static struct pcmcia_low_level simpad_pcmcia_ops = { .socket_suspend = simpad_pcmcia_socket_suspend, }; -int __devinit pcmcia_simpad_init(struct device *dev) +int pcmcia_simpad_init(struct device *dev) { int ret = -ENODEV; diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index 70f728ce185..65b02c3e14c 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -211,7 +211,7 @@ static int pcmcia_probe(struct sa1111_dev *dev) return 0; } -static int __devexit pcmcia_remove(struct sa1111_dev *dev) +static int pcmcia_remove(struct sa1111_dev *dev) { struct sa1111_pcmcia_socket *next, *s = dev_get_drvdata(&dev->dev); @@ -234,7 +234,7 @@ static struct sa1111_driver pcmcia_driver = { }, .devid = SA1111_DEVID_PCMCIA, .probe = pcmcia_probe, - .remove = __devexit_p(pcmcia_remove), + .remove = pcmcia_remove, }; static int __init sa1111_drv_pcmcia_init(void) diff --git a/drivers/pcmcia/sa1111_jornada720.c b/drivers/pcmcia/sa1111_jornada720.c index 69428d1f5ae..3baa3ef0968 100644 --- a/drivers/pcmcia/sa1111_jornada720.c +++ b/drivers/pcmcia/sa1111_jornada720.c @@ -91,7 +91,7 @@ static struct pcmcia_low_level jornada720_pcmcia_ops = { .nr = 2, }; -int __devinit pcmcia_jornada720_init(struct device *dev) +int pcmcia_jornada720_init(struct device *dev) { int ret = -ENODEV; diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c index 86e4a1a3c64..75806be344e 100644 --- a/drivers/pcmcia/vrc4171_card.c +++ b/drivers/pcmcia/vrc4171_card.c @@ -564,7 +564,7 @@ static inline void reserve_using_irq(int slot) vrc4171_irq_mask &= ~(1 << irq); } -static int __devinit vrc4171_add_sockets(void) +static int vrc4171_add_sockets(void) { vrc4171_socket_t *socket; int slot, retval; @@ -631,7 +631,7 @@ static void vrc4171_remove_sockets(void) } } -static int __devinit vrc4171_card_setup(char *options) +static int vrc4171_card_setup(char *options) { if (options == NULL || *options == '\0') return 1; @@ -712,7 +712,7 @@ static struct platform_driver vrc4171_card_driver = { }, }; -static int __devinit vrc4171_card_init(void) +static int vrc4171_card_init(void) { int retval; @@ -746,7 +746,7 @@ static int __devinit vrc4171_card_init(void) return 0; } -static void __devexit vrc4171_card_exit(void) +static void vrc4171_card_exit(void) { free_irq(vrc4171_irq, vrc4171_sockets); vrc4171_remove_sockets(); diff --git a/drivers/pcmcia/vrc4173_cardu.c b/drivers/pcmcia/vrc4173_cardu.c index cd0a315d922..d92692056e2 100644 --- a/drivers/pcmcia/vrc4173_cardu.c +++ b/drivers/pcmcia/vrc4173_cardu.c @@ -456,7 +456,7 @@ static void cardu_interrupt(int irq, void *dev_id) } } -static int __devinit vrc4173_cardu_probe(struct pci_dev *dev, +static int vrc4173_cardu_probe(struct pci_dev *dev, const struct pci_device_id *ent) { vrc4173_socket_t *socket; @@ -533,7 +533,7 @@ disable: return ret; } -static int __devinit vrc4173_cardu_setup(char *options) +static int vrc4173_cardu_setup(char *options) { if (options == NULL || *options == '\0') return 1; @@ -574,14 +574,14 @@ static struct pci_driver vrc4173_cardu_driver = { .id_table = vrc4173_cardu_id_table, }; -static int __devinit vrc4173_cardu_init(void) +static int vrc4173_cardu_init(void) { vrc4173_cardu_slots = 0; return pci_register_driver(&vrc4173_cardu_driver); } -static void __devexit vrc4173_cardu_exit(void) +static void vrc4173_cardu_exit(void) { pci_unregister_driver(&vrc4173_cardu_driver); } diff --git a/drivers/pcmcia/xxs1500_ss.c b/drivers/pcmcia/xxs1500_ss.c index fd5fbd10aad..95f5b270ad4 100644 --- a/drivers/pcmcia/xxs1500_ss.c +++ b/drivers/pcmcia/xxs1500_ss.c @@ -204,7 +204,7 @@ static struct pccard_operations xxs1500_pcmcia_operations = { .set_mem_map = au1x00_pcmcia_set_mem_map, }; -static int __devinit xxs1500_pcmcia_probe(struct platform_device *pdev) +static int xxs1500_pcmcia_probe(struct platform_device *pdev) { struct xxs1500_pcmcia_sock *sock; struct resource *r; @@ -299,7 +299,7 @@ out0: return ret; } -static int __devexit xxs1500_pcmcia_remove(struct platform_device *pdev) +static int xxs1500_pcmcia_remove(struct platform_device *pdev) { struct xxs1500_pcmcia_sock *sock = platform_get_drvdata(pdev); @@ -317,7 +317,7 @@ static struct platform_driver xxs1500_pcmcia_socket_driver = { .owner = THIS_MODULE, }, .probe = xxs1500_pcmcia_probe, - .remove = __devexit_p(xxs1500_pcmcia_remove), + .remove = xxs1500_pcmcia_remove, }; module_platform_driver(xxs1500_pcmcia_socket_driver); diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 667678db115..6b4ff099fb1 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -783,7 +783,7 @@ static void yenta_free_resources(struct yenta_socket *socket) /* * Close it down - release our resources and go home.. */ -static void __devexit yenta_close(struct pci_dev *dev) +static void yenta_close(struct pci_dev *dev) { struct yenta_socket *sock = pci_get_drvdata(dev); @@ -1142,7 +1142,7 @@ static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge) * interrupt, and that we can map the cardbus area. Fill in the * socket information structure.. */ -static int __devinit yenta_probe(struct pci_dev *dev, const struct pci_device_id *id) +static int yenta_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct yenta_socket *socket; int ret; @@ -1435,7 +1435,7 @@ static struct pci_driver yenta_cardbus_driver = { .name = "yenta_cardbus", .id_table = yenta_table, .probe = yenta_probe, - .remove = __devexit_p(yenta_close), + .remove = yenta_close, .driver.pm = YENTA_PM_OPS, }; diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index d96caefd914..390ab69ea56 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -26,6 +26,15 @@ config DEBUG_PINCTRL help Say Y here to add some extra checks and diagnostics to PINCTRL calls. +config PINCTRL_AT91 + bool "AT91 pinctrl driver" + depends on OF + depends on ARCH_AT91 + select PINMUX + select PINCONF + help + Say Y here to enable the at91 pinctrl driver + config PINCTRL_BCM2835 bool select PINMUX @@ -87,21 +96,18 @@ config PINCTRL_MMP2 bool "MMP2 pin controller driver" depends on ARCH_MMP select PINCTRL_PXA3xx - select PINCONF config PINCTRL_MXS bool + select PINMUX + select PINCONF config PINCTRL_IMX23 bool - select PINMUX - select PINCONF select PINCTRL_MXS config PINCTRL_IMX28 bool - select PINMUX - select PINCONF select PINCTRL_MXS config PINCTRL_NOMADIK @@ -126,13 +132,11 @@ config PINCTRL_PXA168 bool "PXA168 pin controller driver" depends on ARCH_MMP select PINCTRL_PXA3xx - select PINCONF config PINCTRL_PXA910 bool "PXA910 pin controller driver" depends on ARCH_MMP select PINCTRL_PXA3xx - select PINCONF config PINCTRL_SINGLE tristate "One-register-per-pin type device tree based pinctrl driver" @@ -143,23 +147,21 @@ config PINCTRL_SINGLE This selects the device tree based generic pinctrl driver. config PINCTRL_SIRF - bool "CSR SiRFprimaII pin controller driver" - depends on ARCH_PRIMA2 + bool "CSR SiRFprimaII/SiRFmarco pin controller driver" + depends on ARCH_SIRF select PINMUX config PINCTRL_TEGRA bool + select PINMUX + select PINCONF config PINCTRL_TEGRA20 bool - select PINMUX - select PINCONF select PINCTRL_TEGRA config PINCTRL_TEGRA30 bool - select PINMUX - select PINCONF select PINCTRL_TEGRA config PINCTRL_U300 @@ -178,7 +180,7 @@ config PINCTRL_COH901 ports of 8 GPIO pins each. config PINCTRL_SAMSUNG - bool "Samsung pinctrl driver" + bool depends on OF && GPIOLIB select PINMUX select PINCONF @@ -188,27 +190,7 @@ config PINCTRL_EXYNOS4 depends on OF && GPIOLIB select PINCTRL_SAMSUNG -config PINCTRL_MVEBU - bool - depends on ARCH_MVEBU - select PINMUX - select PINCONF - -config PINCTRL_DOVE - bool - select PINCTRL_MVEBU - -config PINCTRL_KIRKWOOD - bool - select PINCTRL_MVEBU - -config PINCTRL_ARMADA_370 - bool - select PINCTRL_MVEBU - -config PINCTRL_ARMADA_XP - bool - select PINCTRL_MVEBU +source "drivers/pinctrl/mvebu/Kconfig" source "drivers/pinctrl/spear/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f395ba5cec2..f95f5ed923b 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -9,6 +9,7 @@ ifeq ($(CONFIG_OF),y) obj-$(CONFIG_PINCTRL) += devicetree.o endif obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o +obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o obj-$(CONFIG_PINCTRL_IMX35) += pinctrl-imx35.o @@ -36,12 +37,8 @@ obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o obj-$(CONFIG_PINCTRL_EXYNOS4) += pinctrl-exynos.o -obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o -obj-$(CONFIG_PINCTRL_DOVE) += pinctrl-dove.o -obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o -obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o -obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o +obj-$(CONFIG_PLAT_ORION) += mvebu/ obj-$(CONFIG_PLAT_SPEAR) += spear/ diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 2e39c04fc16..5cdee8669ea 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -345,6 +345,62 @@ void pinctrl_add_gpio_ranges(struct pinctrl_dev *pctldev, } EXPORT_SYMBOL_GPL(pinctrl_add_gpio_ranges); +struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname, + struct pinctrl_gpio_range *range) +{ + struct pinctrl_dev *pctldev = get_pinctrl_dev_from_devname(devname); + + /* + * If we can't find this device, let's assume that is because + * it has not probed yet, so the driver trying to register this + * range need to defer probing. + */ + if (!pctldev) + return ERR_PTR(-EPROBE_DEFER); + + pinctrl_add_gpio_range(pctldev, range); + return pctldev; +} +EXPORT_SYMBOL_GPL(pinctrl_find_and_add_gpio_range); + +/** + * pinctrl_find_gpio_range_from_pin() - locate the GPIO range for a pin + * @pctldev: the pin controller device to look in + * @pin: a controller-local number to find the range for + */ +struct pinctrl_gpio_range * +pinctrl_find_gpio_range_from_pin(struct pinctrl_dev *pctldev, + unsigned int pin) +{ + struct pinctrl_gpio_range *range = NULL; + + /* Loop over the ranges */ + list_for_each_entry(range, &pctldev->gpio_ranges, node) { + /* Check if we're in the valid range */ + if (pin >= range->pin_base && + pin < range->pin_base + range->npins) { + return range; + } + } + + return NULL; +} +EXPORT_SYMBOL_GPL(pinctrl_find_gpio_range_from_pin); + +/** + * pinctrl_remove_gpio_range() - remove a range of GPIOs fro a pin controller + * @pctldev: pin controller device to remove the range from + * @range: the GPIO range to remove + */ +void pinctrl_remove_gpio_range(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range) +{ + mutex_lock(&pinctrl_mutex); + list_del(&range->node); + mutex_unlock(&pinctrl_mutex); +} +EXPORT_SYMBOL_GPL(pinctrl_remove_gpio_range); + /** * pinctrl_get_group_selector() - returns the group selector for a group * @pctldev: the pin controller handling the group @@ -563,6 +619,8 @@ static int add_setting(struct pinctrl *p, struct pinctrl_map const *map) return -EPROBE_DEFER; } + setting->dev_name = map->dev_name; + switch (map->type) { case PIN_MAP_TYPE_MUX_GROUP: ret = pinmux_map_to_setting(map, setting); diff --git a/drivers/pinctrl/core.h b/drivers/pinctrl/core.h index 1f40ff68a8c..12f5694f3d5 100644 --- a/drivers/pinctrl/core.h +++ b/drivers/pinctrl/core.h @@ -105,12 +105,14 @@ struct pinctrl_setting_configs { * @type: the type of setting * @pctldev: pin control device handling to be programmed. Not used for * PIN_MAP_TYPE_DUMMY_STATE. + * @dev_name: the name of the device using this state * @data: Data specific to the setting type */ struct pinctrl_setting { struct list_head node; enum pinctrl_map_type type; struct pinctrl_dev *pctldev; + const char *dev_name; union { struct pinctrl_setting_mux mux; struct pinctrl_setting_configs configs; diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index fcb1de45473..fe2d1af7cfa 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -106,6 +106,17 @@ static struct pinctrl_dev *find_pinctrl_by_of_node(struct device_node *np) return NULL; } +struct pinctrl_dev *of_pinctrl_get(struct device_node *np) +{ + struct pinctrl_dev *pctldev; + + pctldev = find_pinctrl_by_of_node(np); + if (!pctldev) + return NULL; + + return pctldev; +} + static int dt_to_map_one_config(struct pinctrl *p, const char *statename, struct device_node *np_config) { diff --git a/drivers/pinctrl/mvebu/Kconfig b/drivers/pinctrl/mvebu/Kconfig new file mode 100644 index 00000000000..366fa541ee9 --- /dev/null +++ b/drivers/pinctrl/mvebu/Kconfig @@ -0,0 +1,24 @@ +if PLAT_ORION + +config PINCTRL_MVEBU + bool + select PINMUX + select PINCONF + +config PINCTRL_DOVE + bool + select PINCTRL_MVEBU + +config PINCTRL_KIRKWOOD + bool + select PINCTRL_MVEBU + +config PINCTRL_ARMADA_370 + bool + select PINCTRL_MVEBU + +config PINCTRL_ARMADA_XP + bool + select PINCTRL_MVEBU + +endif diff --git a/drivers/pinctrl/mvebu/Makefile b/drivers/pinctrl/mvebu/Makefile new file mode 100644 index 00000000000..37c253297af --- /dev/null +++ b/drivers/pinctrl/mvebu/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o +obj-$(CONFIG_PINCTRL_DOVE) += pinctrl-dove.o +obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o +obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o +obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o diff --git a/drivers/pinctrl/pinctrl-armada-370.c b/drivers/pinctrl/mvebu/pinctrl-armada-370.c index c907647de6a..c907647de6a 100644 --- a/drivers/pinctrl/pinctrl-armada-370.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-370.c diff --git a/drivers/pinctrl/pinctrl-armada-xp.c b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c index 40bd52a46b4..40bd52a46b4 100644 --- a/drivers/pinctrl/pinctrl-armada-xp.c +++ b/drivers/pinctrl/mvebu/pinctrl-armada-xp.c diff --git a/drivers/pinctrl/pinctrl-dove.c b/drivers/pinctrl/mvebu/pinctrl-dove.c index ffe74b27d66..ffe74b27d66 100644 --- a/drivers/pinctrl/pinctrl-dove.c +++ b/drivers/pinctrl/mvebu/pinctrl-dove.c diff --git a/drivers/pinctrl/pinctrl-kirkwood.c b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c index 9a74ef674a0..9a74ef674a0 100644 --- a/drivers/pinctrl/pinctrl-kirkwood.c +++ b/drivers/pinctrl/mvebu/pinctrl-kirkwood.c diff --git a/drivers/pinctrl/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c index 8e6266c6249..6c44b7e8964 100644 --- a/drivers/pinctrl/pinctrl-mvebu.c +++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c @@ -24,7 +24,6 @@ #include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/pinmux.h> -#include "core.h" #include "pinctrl-mvebu.h" #define MPPS_PER_REG 8 diff --git a/drivers/pinctrl/pinctrl-mvebu.h b/drivers/pinctrl/mvebu/pinctrl-mvebu.h index 90bd3beee86..90bd3beee86 100644 --- a/drivers/pinctrl/pinctrl-mvebu.h +++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.h diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 33fbaeaa65d..833a3645815 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -41,6 +41,7 @@ struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL), PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL), PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL), + PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_DISABLE, "input schmitt disabled", NULL), PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL), PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "time units"), PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector"), diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c new file mode 100644 index 00000000000..c5e75715718 --- /dev/null +++ b/drivers/pinctrl/pinctrl-at91.c @@ -0,0 +1,1634 @@ +/* + * at91 pinctrl driver based on at91 pinmux core + * + * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> + * + * Under GPLv2 only + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/pinctrl/machine.h> +#include <linux/pinctrl/pinconf.h> +#include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinmux.h> +/* Since we request GPIOs from ourself */ +#include <linux/pinctrl/consumer.h> + +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <mach/at91_pio.h> + +#include "core.h" + +#define MAX_NB_GPIO_PER_BANK 32 + +struct at91_pinctrl_mux_ops; + +struct at91_gpio_chip { + struct gpio_chip chip; + struct pinctrl_gpio_range range; + struct at91_gpio_chip *next; /* Bank sharing same clock */ + int pioc_hwirq; /* PIO bank interrupt identifier on AIC */ + int pioc_virq; /* PIO bank Linux virtual interrupt */ + int pioc_idx; /* PIO bank index */ + void __iomem *regbase; /* PIO bank virtual address */ + struct clk *clock; /* associated clock */ + struct irq_domain *domain; /* associated irq domain */ + struct at91_pinctrl_mux_ops *ops; /* ops */ +}; + +#define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip) + +static struct at91_gpio_chip *gpio_chips[MAX_GPIO_BANKS]; + +static int gpio_banks; + +#define PULL_UP (1 << 0) +#define MULTI_DRIVE (1 << 1) +#define DEGLITCH (1 << 2) +#define PULL_DOWN (1 << 3) +#define DIS_SCHMIT (1 << 4) +#define DEBOUNCE (1 << 16) +#define DEBOUNCE_VAL_SHIFT 17 +#define DEBOUNCE_VAL (0x3fff << DEBOUNCE_VAL_SHIFT) + +/** + * struct at91_pmx_func - describes AT91 pinmux functions + * @name: the name of this specific function + * @groups: corresponding pin groups + * @ngroups: the number of groups + */ +struct at91_pmx_func { + const char *name; + const char **groups; + unsigned ngroups; +}; + +enum at91_mux { + AT91_MUX_GPIO = 0, + AT91_MUX_PERIPH_A = 1, + AT91_MUX_PERIPH_B = 2, + AT91_MUX_PERIPH_C = 3, + AT91_MUX_PERIPH_D = 4, +}; + +/** + * struct at91_pmx_pin - describes an At91 pin mux + * @bank: the bank of the pin + * @pin: the pin number in the @bank + * @mux: the mux mode : gpio or periph_x of the pin i.e. alternate function. + * @conf: the configuration of the pin: PULL_UP, MULTIDRIVE etc... + */ +struct at91_pmx_pin { + uint32_t bank; + uint32_t pin; + enum at91_mux mux; + unsigned long conf; +}; + +/** + * struct at91_pin_group - describes an At91 pin group + * @name: the name of this specific pin group + * @pins_conf: the mux mode for each pin in this group. The size of this + * array is the same as pins. + * @pins: an array of discrete physical pins used in this group, taken + * from the driver-local pin enumeration space + * @npins: the number of pins in this group array, i.e. the number of + * elements in .pins so we can iterate over that array + */ +struct at91_pin_group { + const char *name; + struct at91_pmx_pin *pins_conf; + unsigned int *pins; + unsigned npins; +}; + +/** + * struct at91_pinctrl_mux_ops - describes an At91 mux ops group + * on new IP with support for periph C and D the way to mux in + * periph A and B has changed + * So provide the right call back + * if not present means the IP does not support it + * @get_periph: return the periph mode configured + * @mux_A_periph: mux as periph A + * @mux_B_periph: mux as periph B + * @mux_C_periph: mux as periph C + * @mux_D_periph: mux as periph D + * @get_deglitch: get deglitch status + * @set_deglitch: enable/disable deglitch + * @get_debounce: get debounce status + * @set_debounce: enable/disable debounce + * @get_pulldown: get pulldown status + * @set_pulldown: enable/disable pulldown + * @get_schmitt_trig: get schmitt trigger status + * @disable_schmitt_trig: disable schmitt trigger + * @irq_type: return irq type + */ +struct at91_pinctrl_mux_ops { + enum at91_mux (*get_periph)(void __iomem *pio, unsigned mask); + void (*mux_A_periph)(void __iomem *pio, unsigned mask); + void (*mux_B_periph)(void __iomem *pio, unsigned mask); + void (*mux_C_periph)(void __iomem *pio, unsigned mask); + void (*mux_D_periph)(void __iomem *pio, unsigned mask); + bool (*get_deglitch)(void __iomem *pio, unsigned pin); + void (*set_deglitch)(void __iomem *pio, unsigned mask, bool in_on); + bool (*get_debounce)(void __iomem *pio, unsigned pin, u32 *div); + void (*set_debounce)(void __iomem *pio, unsigned mask, bool in_on, u32 div); + bool (*get_pulldown)(void __iomem *pio, unsigned pin); + void (*set_pulldown)(void __iomem *pio, unsigned mask, bool in_on); + bool (*get_schmitt_trig)(void __iomem *pio, unsigned pin); + void (*disable_schmitt_trig)(void __iomem *pio, unsigned mask); + /* irq */ + int (*irq_type)(struct irq_data *d, unsigned type); +}; + +static int gpio_irq_type(struct irq_data *d, unsigned type); +static int alt_gpio_irq_type(struct irq_data *d, unsigned type); + +struct at91_pinctrl { + struct device *dev; + struct pinctrl_dev *pctl; + + int nbanks; + + uint32_t *mux_mask; + int nmux; + + struct at91_pmx_func *functions; + int nfunctions; + + struct at91_pin_group *groups; + int ngroups; + + struct at91_pinctrl_mux_ops *ops; +}; + +static const inline struct at91_pin_group *at91_pinctrl_find_group_by_name( + const struct at91_pinctrl *info, + const char *name) +{ + const struct at91_pin_group *grp = NULL; + int i; + + for (i = 0; i < info->ngroups; i++) { + if (strcmp(info->groups[i].name, name)) + continue; + + grp = &info->groups[i]; + dev_dbg(info->dev, "%s: %d 0:%d\n", name, grp->npins, grp->pins[0]); + break; + } + + return grp; +} + +static int at91_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->ngroups; +} + +static const char *at91_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->groups[selector].name; +} + +static int at91_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, + const unsigned **pins, + unsigned *npins) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + if (selector >= info->ngroups) + return -EINVAL; + + *pins = info->groups[selector].pins; + *npins = info->groups[selector].npins; + + return 0; +} + +static void at91_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, + unsigned offset) +{ + seq_printf(s, "%s", dev_name(pctldev->dev)); +} + +static int at91_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, unsigned *num_maps) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + const struct at91_pin_group *grp; + struct pinctrl_map *new_map; + struct device_node *parent; + int map_num = 1; + int i; + + /* + * first find the group of this node and check if we need create + * config maps for pins + */ + grp = at91_pinctrl_find_group_by_name(info, np->name); + if (!grp) { + dev_err(info->dev, "unable to find group for node %s\n", + np->name); + return -EINVAL; + } + + map_num += grp->npins; + new_map = devm_kzalloc(pctldev->dev, sizeof(*new_map) * map_num, GFP_KERNEL); + if (!new_map) + return -ENOMEM; + + *map = new_map; + *num_maps = map_num; + + /* create mux map */ + parent = of_get_parent(np); + if (!parent) { + kfree(new_map); + return -EINVAL; + } + new_map[0].type = PIN_MAP_TYPE_MUX_GROUP; + new_map[0].data.mux.function = parent->name; + new_map[0].data.mux.group = np->name; + of_node_put(parent); + + /* create config map */ + new_map++; + for (i = 0; i < grp->npins; i++) { + new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN; + new_map[i].data.configs.group_or_pin = + pin_get_name(pctldev, grp->pins[i]); + new_map[i].data.configs.configs = &grp->pins_conf[i].conf; + new_map[i].data.configs.num_configs = 1; + } + + dev_dbg(pctldev->dev, "maps: function %s group %s num %d\n", + (*map)->data.mux.function, (*map)->data.mux.group, map_num); + + return 0; +} + +static void at91_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) +{ +} + +static struct pinctrl_ops at91_pctrl_ops = { + .get_groups_count = at91_get_groups_count, + .get_group_name = at91_get_group_name, + .get_group_pins = at91_get_group_pins, + .pin_dbg_show = at91_pin_dbg_show, + .dt_node_to_map = at91_dt_node_to_map, + .dt_free_map = at91_dt_free_map, +}; + +static void __iomem * pin_to_controller(struct at91_pinctrl *info, + unsigned int bank) +{ + return gpio_chips[bank]->regbase; +} + +static inline int pin_to_bank(unsigned pin) +{ + return pin /= MAX_NB_GPIO_PER_BANK; +} + +static unsigned pin_to_mask(unsigned int pin) +{ + return 1 << pin; +} + +static void at91_mux_disable_interrupt(void __iomem *pio, unsigned mask) +{ + writel_relaxed(mask, pio + PIO_IDR); +} + +static unsigned at91_mux_get_pullup(void __iomem *pio, unsigned pin) +{ + return (readl_relaxed(pio + PIO_PUSR) >> pin) & 0x1; +} + +static void at91_mux_set_pullup(void __iomem *pio, unsigned mask, bool on) +{ + writel_relaxed(mask, pio + (on ? PIO_PUER : PIO_PUDR)); +} + +static unsigned at91_mux_get_multidrive(void __iomem *pio, unsigned pin) +{ + return (readl_relaxed(pio + PIO_MDSR) >> pin) & 0x1; +} + +static void at91_mux_set_multidrive(void __iomem *pio, unsigned mask, bool on) +{ + writel_relaxed(mask, pio + (on ? PIO_MDER : PIO_MDDR)); +} + +static void at91_mux_set_A_periph(void __iomem *pio, unsigned mask) +{ + writel_relaxed(mask, pio + PIO_ASR); +} + +static void at91_mux_set_B_periph(void __iomem *pio, unsigned mask) +{ + writel_relaxed(mask, pio + PIO_BSR); +} + +static void at91_mux_pio3_set_A_periph(void __iomem *pio, unsigned mask) +{ + + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) & ~mask, + pio + PIO_ABCDSR1); + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) & ~mask, + pio + PIO_ABCDSR2); +} + +static void at91_mux_pio3_set_B_periph(void __iomem *pio, unsigned mask) +{ + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) | mask, + pio + PIO_ABCDSR1); + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) & ~mask, + pio + PIO_ABCDSR2); +} + +static void at91_mux_pio3_set_C_periph(void __iomem *pio, unsigned mask) +{ + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) & ~mask, pio + PIO_ABCDSR1); + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2); +} + +static void at91_mux_pio3_set_D_periph(void __iomem *pio, unsigned mask) +{ + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR1) | mask, pio + PIO_ABCDSR1); + writel_relaxed(readl_relaxed(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2); +} + +static enum at91_mux at91_mux_pio3_get_periph(void __iomem *pio, unsigned mask) +{ + unsigned select; + + if (readl_relaxed(pio + PIO_PSR) & mask) + return AT91_MUX_GPIO; + + select = !!(readl_relaxed(pio + PIO_ABCDSR1) & mask); + select |= (!!(readl_relaxed(pio + PIO_ABCDSR2) & mask) << 1); + + return select + 1; +} + +static enum at91_mux at91_mux_get_periph(void __iomem *pio, unsigned mask) +{ + unsigned select; + + if (readl_relaxed(pio + PIO_PSR) & mask) + return AT91_MUX_GPIO; + + select = readl_relaxed(pio + PIO_ABSR) & mask; + + return select + 1; +} + +static bool at91_mux_get_deglitch(void __iomem *pio, unsigned pin) +{ + return (__raw_readl(pio + PIO_IFSR) >> pin) & 0x1; +} + +static void at91_mux_set_deglitch(void __iomem *pio, unsigned mask, bool is_on) +{ + __raw_writel(mask, pio + (is_on ? PIO_IFER : PIO_IFDR)); +} + +static void at91_mux_pio3_set_deglitch(void __iomem *pio, unsigned mask, bool is_on) +{ + if (is_on) + __raw_writel(mask, pio + PIO_IFSCDR); + at91_mux_set_deglitch(pio, mask, is_on); +} + +static bool at91_mux_pio3_get_debounce(void __iomem *pio, unsigned pin, u32 *div) +{ + *div = __raw_readl(pio + PIO_SCDR); + + return (__raw_readl(pio + PIO_IFSCSR) >> pin) & 0x1; +} + +static void at91_mux_pio3_set_debounce(void __iomem *pio, unsigned mask, + bool is_on, u32 div) +{ + if (is_on) { + __raw_writel(mask, pio + PIO_IFSCER); + __raw_writel(div & PIO_SCDR_DIV, pio + PIO_SCDR); + __raw_writel(mask, pio + PIO_IFER); + } else { + __raw_writel(mask, pio + PIO_IFDR); + } +} + +static bool at91_mux_pio3_get_pulldown(void __iomem *pio, unsigned pin) +{ + return (__raw_readl(pio + PIO_PPDSR) >> pin) & 0x1; +} + +static void at91_mux_pio3_set_pulldown(void __iomem *pio, unsigned mask, bool is_on) +{ + __raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR)); +} + +static void at91_mux_pio3_disable_schmitt_trig(void __iomem *pio, unsigned mask) +{ + __raw_writel(__raw_readl(pio + PIO_SCHMITT) | mask, pio + PIO_SCHMITT); +} + +static bool at91_mux_pio3_get_schmitt_trig(void __iomem *pio, unsigned pin) +{ + return (__raw_readl(pio + PIO_SCHMITT) >> pin) & 0x1; +} + +static struct at91_pinctrl_mux_ops at91rm9200_ops = { + .get_periph = at91_mux_get_periph, + .mux_A_periph = at91_mux_set_A_periph, + .mux_B_periph = at91_mux_set_B_periph, + .get_deglitch = at91_mux_get_deglitch, + .set_deglitch = at91_mux_set_deglitch, + .irq_type = gpio_irq_type, +}; + +static struct at91_pinctrl_mux_ops at91sam9x5_ops = { + .get_periph = at91_mux_pio3_get_periph, + .mux_A_periph = at91_mux_pio3_set_A_periph, + .mux_B_periph = at91_mux_pio3_set_B_periph, + .mux_C_periph = at91_mux_pio3_set_C_periph, + .mux_D_periph = at91_mux_pio3_set_D_periph, + .get_deglitch = at91_mux_get_deglitch, + .set_deglitch = at91_mux_pio3_set_deglitch, + .get_debounce = at91_mux_pio3_get_debounce, + .set_debounce = at91_mux_pio3_set_debounce, + .get_pulldown = at91_mux_pio3_get_pulldown, + .set_pulldown = at91_mux_pio3_set_pulldown, + .get_schmitt_trig = at91_mux_pio3_get_schmitt_trig, + .disable_schmitt_trig = at91_mux_pio3_disable_schmitt_trig, + .irq_type = alt_gpio_irq_type, +}; + +static void at91_pin_dbg(const struct device *dev, const struct at91_pmx_pin *pin) +{ + if (pin->mux) { + dev_dbg(dev, "pio%c%d configured as periph%c with conf = 0x%lu\n", + pin->bank + 'A', pin->pin, pin->mux - 1 + 'A', pin->conf); + } else { + dev_dbg(dev, "pio%c%d configured as gpio with conf = 0x%lu\n", + pin->bank + 'A', pin->pin, pin->conf); + } +} + +static int pin_check_config(struct at91_pinctrl *info, const char* name, + int index, const struct at91_pmx_pin *pin) +{ + int mux; + + /* check if it's a valid config */ + if (pin->bank >= info->nbanks) { + dev_err(info->dev, "%s: pin conf %d bank_id %d >= nbanks %d\n", + name, index, pin->bank, info->nbanks); + return -EINVAL; + } + + if (pin->pin >= MAX_NB_GPIO_PER_BANK) { + dev_err(info->dev, "%s: pin conf %d pin_bank_id %d >= %d\n", + name, index, pin->pin, MAX_NB_GPIO_PER_BANK); + return -EINVAL; + } + + if (!pin->mux) + return 0; + + mux = pin->mux - 1; + + if (mux >= info->nmux) { + dev_err(info->dev, "%s: pin conf %d mux_id %d >= nmux %d\n", + name, index, mux, info->nmux); + return -EINVAL; + } + + if (!(info->mux_mask[pin->bank * info->nmux + mux] & 1 << pin->pin)) { + dev_err(info->dev, "%s: pin conf %d mux_id %d not supported for pio%c%d\n", + name, index, mux, pin->bank + 'A', pin->pin); + return -EINVAL; + } + + return 0; +} + +static void at91_mux_gpio_disable(void __iomem *pio, unsigned mask) +{ + writel_relaxed(mask, pio + PIO_PDR); +} + +static void at91_mux_gpio_enable(void __iomem *pio, unsigned mask, bool input) +{ + writel_relaxed(mask, pio + PIO_PER); + writel_relaxed(mask, pio + (input ? PIO_ODR : PIO_OER)); +} + +static int at91_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf; + const struct at91_pmx_pin *pin; + uint32_t npins = info->groups[group].npins; + int i, ret; + unsigned mask; + void __iomem *pio; + + dev_dbg(info->dev, "enable function %s group %s\n", + info->functions[selector].name, info->groups[group].name); + + /* first check that all the pins of the group are valid with a valid + * paramter */ + for (i = 0; i < npins; i++) { + pin = &pins_conf[i]; + ret = pin_check_config(info, info->groups[group].name, i, pin); + if (ret) + return ret; + } + + for (i = 0; i < npins; i++) { + pin = &pins_conf[i]; + at91_pin_dbg(info->dev, pin); + pio = pin_to_controller(info, pin->bank); + mask = pin_to_mask(pin->pin); + at91_mux_disable_interrupt(pio, mask); + switch(pin->mux) { + case AT91_MUX_GPIO: + at91_mux_gpio_enable(pio, mask, 1); + break; + case AT91_MUX_PERIPH_A: + info->ops->mux_A_periph(pio, mask); + break; + case AT91_MUX_PERIPH_B: + info->ops->mux_B_periph(pio, mask); + break; + case AT91_MUX_PERIPH_C: + if (!info->ops->mux_C_periph) + return -EINVAL; + info->ops->mux_C_periph(pio, mask); + break; + case AT91_MUX_PERIPH_D: + if (!info->ops->mux_D_periph) + return -EINVAL; + info->ops->mux_D_periph(pio, mask); + break; + } + if (pin->mux) + at91_mux_gpio_disable(pio, mask); + } + + return 0; +} + +static void at91_pmx_disable(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + const struct at91_pmx_pin *pins_conf = info->groups[group].pins_conf; + const struct at91_pmx_pin *pin; + uint32_t npins = info->groups[group].npins; + int i; + unsigned mask; + void __iomem *pio; + + for (i = 0; i < npins; i++) { + pin = &pins_conf[i]; + at91_pin_dbg(info->dev, pin); + pio = pin_to_controller(info, pin->bank); + mask = pin_to_mask(pin->pin); + at91_mux_gpio_enable(pio, mask, 1); + } +} + +static int at91_pmx_get_funcs_count(struct pinctrl_dev *pctldev) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->nfunctions; +} + +static const char *at91_pmx_get_func_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + return info->functions[selector].name; +} + +static int at91_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + + *groups = info->functions[selector].groups; + *num_groups = info->functions[selector].ngroups; + + return 0; +} + +static int at91_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct at91_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + struct at91_gpio_chip *at91_chip; + struct gpio_chip *chip; + unsigned mask; + + if (!range) { + dev_err(npct->dev, "invalid range\n"); + return -EINVAL; + } + if (!range->gc) { + dev_err(npct->dev, "missing GPIO chip in range\n"); + return -EINVAL; + } + chip = range->gc; + at91_chip = container_of(chip, struct at91_gpio_chip, chip); + + dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset); + + mask = 1 << (offset - chip->base); + + dev_dbg(npct->dev, "enable pin %u as PIO%c%d 0x%x\n", + offset, 'A' + range->id, offset - chip->base, mask); + + writel_relaxed(mask, at91_chip->regbase + PIO_PER); + + return 0; +} + +static void at91_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct at91_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + + dev_dbg(npct->dev, "disable pin %u as GPIO\n", offset); + /* Set the pin to some default state, GPIO is usually default */ +} + +static struct pinmux_ops at91_pmx_ops = { + .get_functions_count = at91_pmx_get_funcs_count, + .get_function_name = at91_pmx_get_func_name, + .get_function_groups = at91_pmx_get_groups, + .enable = at91_pmx_enable, + .disable = at91_pmx_disable, + .gpio_request_enable = at91_gpio_request_enable, + .gpio_disable_free = at91_gpio_disable_free, +}; + +static int at91_pinconf_get(struct pinctrl_dev *pctldev, + unsigned pin_id, unsigned long *config) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + void __iomem *pio; + unsigned pin; + int div; + + dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, *config); + pio = pin_to_controller(info, pin_to_bank(pin_id)); + pin = pin_id % MAX_NB_GPIO_PER_BANK; + + if (at91_mux_get_multidrive(pio, pin)) + *config |= MULTI_DRIVE; + + if (at91_mux_get_pullup(pio, pin)) + *config |= PULL_UP; + + if (info->ops->get_deglitch && info->ops->get_deglitch(pio, pin)) + *config |= DEGLITCH; + if (info->ops->get_debounce && info->ops->get_debounce(pio, pin, &div)) + *config |= DEBOUNCE | (div << DEBOUNCE_VAL_SHIFT); + if (info->ops->get_pulldown && info->ops->get_pulldown(pio, pin)) + *config |= PULL_DOWN; + if (info->ops->get_schmitt_trig && info->ops->get_schmitt_trig(pio, pin)) + *config |= DIS_SCHMIT; + + return 0; +} + +static int at91_pinconf_set(struct pinctrl_dev *pctldev, + unsigned pin_id, unsigned long config) +{ + struct at91_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); + unsigned mask; + void __iomem *pio; + + dev_dbg(info->dev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, config); + pio = pin_to_controller(info, pin_to_bank(pin_id)); + mask = pin_to_mask(pin_id % MAX_NB_GPIO_PER_BANK); + + if (config & PULL_UP && config & PULL_DOWN) + return -EINVAL; + + at91_mux_set_pullup(pio, mask, config & PULL_UP); + at91_mux_set_multidrive(pio, mask, config & MULTI_DRIVE); + if (info->ops->set_deglitch) + info->ops->set_deglitch(pio, mask, config & DEGLITCH); + if (info->ops->set_debounce) + info->ops->set_debounce(pio, mask, config & DEBOUNCE, + (config & DEBOUNCE_VAL) >> DEBOUNCE_VAL_SHIFT); + if (info->ops->set_pulldown) + info->ops->set_pulldown(pio, mask, config & PULL_DOWN); + if (info->ops->disable_schmitt_trig && config & DIS_SCHMIT) + info->ops->disable_schmitt_trig(pio, mask); + + return 0; +} + +static void at91_pinconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned pin_id) +{ + +} + +static void at91_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned group) +{ +} + +static struct pinconf_ops at91_pinconf_ops = { + .pin_config_get = at91_pinconf_get, + .pin_config_set = at91_pinconf_set, + .pin_config_dbg_show = at91_pinconf_dbg_show, + .pin_config_group_dbg_show = at91_pinconf_group_dbg_show, +}; + +static struct pinctrl_desc at91_pinctrl_desc = { + .pctlops = &at91_pctrl_ops, + .pmxops = &at91_pmx_ops, + .confops = &at91_pinconf_ops, + .owner = THIS_MODULE, +}; + +static const char *gpio_compat = "atmel,at91rm9200-gpio"; + +static void __devinit at91_pinctrl_child_count(struct at91_pinctrl *info, + struct device_node *np) +{ + struct device_node *child; + + for_each_child_of_node(np, child) { + if (of_device_is_compatible(child, gpio_compat)) { + info->nbanks++; + } else { + info->nfunctions++; + info->ngroups += of_get_child_count(child); + } + } +} + +static int __devinit at91_pinctrl_mux_mask(struct at91_pinctrl *info, + struct device_node *np) +{ + int ret = 0; + int size; + const const __be32 *list; + + list = of_get_property(np, "atmel,mux-mask", &size); + if (!list) { + dev_err(info->dev, "can not read the mux-mask of %d\n", size); + return -EINVAL; + } + + size /= sizeof(*list); + if (!size || size % info->nbanks) { + dev_err(info->dev, "wrong mux mask array should be by %d\n", info->nbanks); + return -EINVAL; + } + info->nmux = size / info->nbanks; + + info->mux_mask = devm_kzalloc(info->dev, sizeof(u32) * size, GFP_KERNEL); + if (!info->mux_mask) { + dev_err(info->dev, "could not alloc mux_mask\n"); + return -ENOMEM; + } + + ret = of_property_read_u32_array(np, "atmel,mux-mask", + info->mux_mask, size); + if (ret) + dev_err(info->dev, "can not read the mux-mask of %d\n", size); + return ret; +} + +static int __devinit at91_pinctrl_parse_groups(struct device_node *np, + struct at91_pin_group *grp, + struct at91_pinctrl *info, + u32 index) +{ + struct at91_pmx_pin *pin; + int size; + const const __be32 *list; + int i, j; + + dev_dbg(info->dev, "group(%d): %s\n", index, np->name); + + /* Initialise group */ + grp->name = np->name; + + /* + * the binding format is atmel,pins = <bank pin mux CONFIG ...>, + * do sanity check and calculate pins number + */ + list = of_get_property(np, "atmel,pins", &size); + /* we do not check return since it's safe node passed down */ + size /= sizeof(*list); + if (!size || size % 4) { + dev_err(info->dev, "wrong pins number or pins and configs should be by 4\n"); + return -EINVAL; + } + + grp->npins = size / 4; + pin = grp->pins_conf = devm_kzalloc(info->dev, grp->npins * sizeof(struct at91_pmx_pin), + GFP_KERNEL); + grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int), + GFP_KERNEL); + if (!grp->pins_conf || !grp->pins) + return -ENOMEM; + + for (i = 0, j = 0; i < size; i += 4, j++) { + pin->bank = be32_to_cpu(*list++); + pin->pin = be32_to_cpu(*list++); + grp->pins[j] = pin->bank * MAX_NB_GPIO_PER_BANK + pin->pin; + pin->mux = be32_to_cpu(*list++); + pin->conf = be32_to_cpu(*list++); + + at91_pin_dbg(info->dev, pin); + pin++; + } + + return 0; +} + +static int __devinit at91_pinctrl_parse_functions(struct device_node *np, + struct at91_pinctrl *info, u32 index) +{ + struct device_node *child; + struct at91_pmx_func *func; + struct at91_pin_group *grp; + int ret; + static u32 grp_index; + u32 i = 0; + + dev_dbg(info->dev, "parse function(%d): %s\n", index, np->name); + + func = &info->functions[index]; + + /* Initialise function */ + func->name = np->name; + func->ngroups = of_get_child_count(np); + if (func->ngroups <= 0) { + dev_err(info->dev, "no groups defined\n"); + return -EINVAL; + } + func->groups = devm_kzalloc(info->dev, + func->ngroups * sizeof(char *), GFP_KERNEL); + if (!func->groups) + return -ENOMEM; + + for_each_child_of_node(np, child) { + func->groups[i] = child->name; + grp = &info->groups[grp_index++]; + ret = at91_pinctrl_parse_groups(child, grp, info, i++); + if (ret) + return ret; + } + + return 0; +} + +static struct of_device_id at91_pinctrl_of_match[] __devinitdata = { + { .compatible = "atmel,at91sam9x5-pinctrl", .data = &at91sam9x5_ops }, + { .compatible = "atmel,at91rm9200-pinctrl", .data = &at91rm9200_ops }, + { /* sentinel */ } +}; + +static int __devinit at91_pinctrl_probe_dt(struct platform_device *pdev, + struct at91_pinctrl *info) +{ + int ret = 0; + int i, j; + uint32_t *tmp; + struct device_node *np = pdev->dev.of_node; + struct device_node *child; + + if (!np) + return -ENODEV; + + info->dev = &pdev->dev; + info->ops = (struct at91_pinctrl_mux_ops*) + of_match_device(at91_pinctrl_of_match, &pdev->dev)->data; + at91_pinctrl_child_count(info, np); + + if (info->nbanks < 1) { + dev_err(&pdev->dev, "you need to specify atleast one gpio-controller\n"); + return -EINVAL; + } + + ret = at91_pinctrl_mux_mask(info, np); + if (ret) + return ret; + + dev_dbg(&pdev->dev, "nmux = %d\n", info->nmux); + + dev_dbg(&pdev->dev, "mux-mask\n"); + tmp = info->mux_mask; + for (i = 0; i < info->nbanks; i++) { + for (j = 0; j < info->nmux; j++, tmp++) { + dev_dbg(&pdev->dev, "%d:%d\t0x%x\n", i, j, tmp[0]); + } + } + + dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions); + dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups); + info->functions = devm_kzalloc(&pdev->dev, info->nfunctions * sizeof(struct at91_pmx_func), + GFP_KERNEL); + if (!info->functions) + return -ENOMEM; + + info->groups = devm_kzalloc(&pdev->dev, info->ngroups * sizeof(struct at91_pin_group), + GFP_KERNEL); + if (!info->groups) + return -ENOMEM; + + dev_dbg(&pdev->dev, "nbanks = %d\n", info->nbanks); + dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions); + dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups); + + i = 0; + + for_each_child_of_node(np, child) { + if (of_device_is_compatible(child, gpio_compat)) + continue; + ret = at91_pinctrl_parse_functions(child, info, i++); + if (ret) { + dev_err(&pdev->dev, "failed to parse function\n"); + return ret; + } + } + + return 0; +} + +static int __devinit at91_pinctrl_probe(struct platform_device *pdev) +{ + struct at91_pinctrl *info; + struct pinctrl_pin_desc *pdesc; + int ret, i, j ,k; + + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + ret = at91_pinctrl_probe_dt(pdev, info); + if (ret) + return ret; + + /* + * We need all the GPIO drivers to probe FIRST, or we will not be able + * to obtain references to the struct gpio_chip * for them, and we + * need this to proceed. + */ + for (i = 0; i < info->nbanks; i++) { + if (!gpio_chips[i]) { + dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i); + devm_kfree(&pdev->dev, info); + return -EPROBE_DEFER; + } + } + + at91_pinctrl_desc.name = dev_name(&pdev->dev); + at91_pinctrl_desc.npins = info->nbanks * MAX_NB_GPIO_PER_BANK; + at91_pinctrl_desc.pins = pdesc = + devm_kzalloc(&pdev->dev, sizeof(*pdesc) * at91_pinctrl_desc.npins, GFP_KERNEL); + + if (!at91_pinctrl_desc.pins) + return -ENOMEM; + + for (i = 0 , k = 0; i < info->nbanks; i++) { + for (j = 0; j < MAX_NB_GPIO_PER_BANK; j++, k++) { + pdesc->number = k; + pdesc->name = kasprintf(GFP_KERNEL, "pio%c%d", i + 'A', j); + pdesc++; + } + } + + platform_set_drvdata(pdev, info); + info->pctl = pinctrl_register(&at91_pinctrl_desc, &pdev->dev, info); + + if (!info->pctl) { + dev_err(&pdev->dev, "could not register AT91 pinctrl driver\n"); + ret = -EINVAL; + goto err; + } + + /* We will handle a range of GPIO pins */ + for (i = 0; i < info->nbanks; i++) + pinctrl_add_gpio_range(info->pctl, &gpio_chips[i]->range); + + dev_info(&pdev->dev, "initialized AT91 pinctrl driver\n"); + + return 0; + +err: + return ret; +} + +static int __devexit at91_pinctrl_remove(struct platform_device *pdev) +{ + struct at91_pinctrl *info = platform_get_drvdata(pdev); + + pinctrl_unregister(info->pctl); + + return 0; +} + +static int at91_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + /* + * Map back to global GPIO space and request muxing, the direction + * parameter does not matter for this controller. + */ + int gpio = chip->base + offset; + int bank = chip->base / chip->ngpio; + + dev_dbg(chip->dev, "%s:%d pio%c%d(%d)\n", __func__, __LINE__, + 'A' + bank, offset, gpio); + + return pinctrl_request_gpio(gpio); +} + +static void at91_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + int gpio = chip->base + offset; + + pinctrl_free_gpio(gpio); +} + +static int at91_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + + writel_relaxed(mask, pio + PIO_ODR); + return 0; +} + +static int at91_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + u32 pdsr; + + pdsr = readl_relaxed(pio + PIO_PDSR); + return (pdsr & mask) != 0; +} + +static void at91_gpio_set(struct gpio_chip *chip, unsigned offset, + int val) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + + writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR)); +} + +static int at91_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int val) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << offset; + + writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR)); + writel_relaxed(mask, pio + PIO_OER); + + return 0; +} + +static int at91_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + int virq; + + if (offset < chip->ngpio) + virq = irq_create_mapping(at91_gpio->domain, offset); + else + virq = -ENXIO; + + dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n", + chip->label, offset + chip->base, virq); + return virq; +} + +#ifdef CONFIG_DEBUG_FS +static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + enum at91_mux mode; + int i; + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + + for (i = 0; i < chip->ngpio; i++) { + unsigned pin = chip->base + i; + unsigned mask = pin_to_mask(pin); + const char *gpio_label; + u32 pdsr; + + gpio_label = gpiochip_is_requested(chip, i); + if (!gpio_label) + continue; + mode = at91_gpio->ops->get_periph(pio, mask); + seq_printf(s, "[%s] GPIO%s%d: ", + gpio_label, chip->label, i); + if (mode == AT91_MUX_GPIO) { + pdsr = readl_relaxed(pio + PIO_PDSR); + + seq_printf(s, "[gpio] %s\n", + pdsr & mask ? + "set" : "clear"); + } else { + seq_printf(s, "[periph %c]\n", + mode + 'A' - 1); + } + } +} +#else +#define at91_gpio_dbg_show NULL +#endif + +/* Several AIC controller irqs are dispatched through this GPIO handler. + * To use any AT91_PIN_* as an externally triggered IRQ, first call + * at91_set_gpio_input() then maybe enable its glitch filter. + * Then just request_irq() with the pin ID; it works like any ARM IRQ + * handler. + * First implementation always triggers on rising and falling edges + * whereas the newer PIO3 can be additionally configured to trigger on + * level, edge with any polarity. + * + * Alternatively, certain pins may be used directly as IRQ0..IRQ6 after + * configuring them with at91_set_a_periph() or at91_set_b_periph(). + * IRQ0..IRQ6 should be configurable, e.g. level vs edge triggering. + */ + +static void gpio_irq_mask(struct irq_data *d) +{ + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << d->hwirq; + + if (pio) + writel_relaxed(mask, pio + PIO_IDR); +} + +static void gpio_irq_unmask(struct irq_data *d) +{ + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << d->hwirq; + + if (pio) + writel_relaxed(mask, pio + PIO_IER); +} + +static int gpio_irq_type(struct irq_data *d, unsigned type) +{ + switch (type) { + case IRQ_TYPE_NONE: + case IRQ_TYPE_EDGE_BOTH: + return 0; + default: + return -EINVAL; + } +} + +/* Alternate irq type for PIO3 support */ +static int alt_gpio_irq_type(struct irq_data *d, unsigned type) +{ + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); + void __iomem *pio = at91_gpio->regbase; + unsigned mask = 1 << d->hwirq; + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + writel_relaxed(mask, pio + PIO_ESR); + writel_relaxed(mask, pio + PIO_REHLSR); + break; + case IRQ_TYPE_EDGE_FALLING: + writel_relaxed(mask, pio + PIO_ESR); + writel_relaxed(mask, pio + PIO_FELLSR); + break; + case IRQ_TYPE_LEVEL_LOW: + writel_relaxed(mask, pio + PIO_LSR); + writel_relaxed(mask, pio + PIO_FELLSR); + break; + case IRQ_TYPE_LEVEL_HIGH: + writel_relaxed(mask, pio + PIO_LSR); + writel_relaxed(mask, pio + PIO_REHLSR); + break; + case IRQ_TYPE_EDGE_BOTH: + /* + * disable additional interrupt modes: + * fall back to default behavior + */ + writel_relaxed(mask, pio + PIO_AIMDR); + return 0; + case IRQ_TYPE_NONE: + default: + pr_warn("AT91: No type for irq %d\n", gpio_to_irq(d->irq)); + return -EINVAL; + } + + /* enable additional interrupt modes */ + writel_relaxed(mask, pio + PIO_AIMER); + + return 0; +} + +#ifdef CONFIG_PM +static int gpio_irq_set_wake(struct irq_data *d, unsigned state) +{ + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); + unsigned bank = at91_gpio->pioc_idx; + + if (unlikely(bank >= MAX_GPIO_BANKS)) + return -EINVAL; + + irq_set_irq_wake(at91_gpio->pioc_virq, state); + + return 0; +} +#else +#define gpio_irq_set_wake NULL +#endif + +static struct irq_chip gpio_irqchip = { + .name = "GPIO", + .irq_disable = gpio_irq_mask, + .irq_mask = gpio_irq_mask, + .irq_unmask = gpio_irq_unmask, + /* .irq_set_type is set dynamically */ + .irq_set_wake = gpio_irq_set_wake, +}; + +static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + struct irq_data *idata = irq_desc_get_irq_data(desc); + struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata); + void __iomem *pio = at91_gpio->regbase; + unsigned long isr; + int n; + + chained_irq_enter(chip, desc); + for (;;) { + /* Reading ISR acks pending (edge triggered) GPIO interrupts. + * When there none are pending, we're finished unless we need + * to process multiple banks (like ID_PIOCDE on sam9263). + */ + isr = readl_relaxed(pio + PIO_ISR) & readl_relaxed(pio + PIO_IMR); + if (!isr) { + if (!at91_gpio->next) + break; + at91_gpio = at91_gpio->next; + pio = at91_gpio->regbase; + continue; + } + + for_each_set_bit(n, &isr, BITS_PER_LONG) { + generic_handle_irq(irq_find_mapping(at91_gpio->domain, n)); + } + } + chained_irq_exit(chip, desc); + /* now it may re-trigger */ +} + +/* + * This lock class tells lockdep that GPIO irqs are in a different + * category than their parents, so it won't report false recursion. + */ +static struct lock_class_key gpio_lock_class; + +static int at91_gpio_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct at91_gpio_chip *at91_gpio = h->host_data; + + irq_set_lockdep_class(virq, &gpio_lock_class); + + /* + * Can use the "simple" and not "edge" handler since it's + * shorter, and the AIC handles interrupts sanely. + */ + irq_set_chip_and_handler(virq, &gpio_irqchip, + handle_simple_irq); + set_irq_flags(virq, IRQF_VALID); + irq_set_chip_data(virq, at91_gpio); + + return 0; +} + +static int at91_gpio_irq_domain_xlate(struct irq_domain *d, + struct device_node *ctrlr, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, + unsigned int *out_type) +{ + struct at91_gpio_chip *at91_gpio = d->host_data; + int ret; + int pin = at91_gpio->chip.base + intspec[0]; + + if (WARN_ON(intsize < 2)) + return -EINVAL; + *out_hwirq = intspec[0]; + *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK; + + ret = gpio_request(pin, ctrlr->full_name); + if (ret) + return ret; + + ret = gpio_direction_input(pin); + if (ret) + return ret; + + return 0; +} + +static struct irq_domain_ops at91_gpio_ops = { + .map = at91_gpio_irq_map, + .xlate = at91_gpio_irq_domain_xlate, +}; + +static int at91_gpio_of_irq_setup(struct device_node *node, + struct at91_gpio_chip *at91_gpio) +{ + struct at91_gpio_chip *prev = NULL; + struct irq_data *d = irq_get_irq_data(at91_gpio->pioc_virq); + + at91_gpio->pioc_hwirq = irqd_to_hwirq(d); + + /* Setup proper .irq_set_type function */ + gpio_irqchip.irq_set_type = at91_gpio->ops->irq_type; + + /* Disable irqs of this PIO controller */ + writel_relaxed(~0, at91_gpio->regbase + PIO_IDR); + + /* Setup irq domain */ + at91_gpio->domain = irq_domain_add_linear(node, at91_gpio->chip.ngpio, + &at91_gpio_ops, at91_gpio); + if (!at91_gpio->domain) + panic("at91_gpio.%d: couldn't allocate irq domain (DT).\n", + at91_gpio->pioc_idx); + + /* Setup chained handler */ + if (at91_gpio->pioc_idx) + prev = gpio_chips[at91_gpio->pioc_idx - 1]; + + /* The toplevel handler handles one bank of GPIOs, except + * on some SoC it can handles up to three... + * We only set up the handler for the first of the list. + */ + if (prev && prev->next == at91_gpio) + return 0; + + irq_set_chip_data(at91_gpio->pioc_virq, at91_gpio); + irq_set_chained_handler(at91_gpio->pioc_virq, gpio_irq_handler); + + return 0; +} + +/* This structure is replicated for each GPIO block allocated at probe time */ +static struct gpio_chip at91_gpio_template = { + .request = at91_gpio_request, + .free = at91_gpio_free, + .direction_input = at91_gpio_direction_input, + .get = at91_gpio_get, + .direction_output = at91_gpio_direction_output, + .set = at91_gpio_set, + .to_irq = at91_gpio_to_irq, + .dbg_show = at91_gpio_dbg_show, + .can_sleep = 0, + .ngpio = MAX_NB_GPIO_PER_BANK, +}; + +static void __devinit at91_gpio_probe_fixup(void) +{ + unsigned i; + struct at91_gpio_chip *at91_gpio, *last = NULL; + + for (i = 0; i < gpio_banks; i++) { + at91_gpio = gpio_chips[i]; + + /* + * GPIO controller are grouped on some SoC: + * PIOC, PIOD and PIOE can share the same IRQ line + */ + if (last && last->pioc_virq == at91_gpio->pioc_virq) + last->next = at91_gpio; + last = at91_gpio; + } +} + +static struct of_device_id at91_gpio_of_match[] __devinitdata = { + { .compatible = "atmel,at91sam9x5-gpio", .data = &at91sam9x5_ops, }, + { .compatible = "atmel,at91rm9200-gpio", .data = &at91rm9200_ops }, + { /* sentinel */ } +}; + +static int __devinit at91_gpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct resource *res; + struct at91_gpio_chip *at91_chip = NULL; + struct gpio_chip *chip; + struct pinctrl_gpio_range *range; + int ret = 0; + int irq, i; + int alias_idx = of_alias_get_id(np, "gpio"); + uint32_t ngpio; + char **names; + + BUG_ON(alias_idx >= ARRAY_SIZE(gpio_chips)); + if (gpio_chips[alias_idx]) { + ret = -EBUSY; + goto err; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENOENT; + goto err; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; + goto err; + } + + at91_chip = devm_kzalloc(&pdev->dev, sizeof(*at91_chip), GFP_KERNEL); + if (!at91_chip) { + ret = -ENOMEM; + goto err; + } + + at91_chip->regbase = devm_request_and_ioremap(&pdev->dev, res); + if (!at91_chip->regbase) { + dev_err(&pdev->dev, "failed to map registers, ignoring.\n"); + ret = -EBUSY; + goto err; + } + + at91_chip->ops = (struct at91_pinctrl_mux_ops*) + of_match_device(at91_gpio_of_match, &pdev->dev)->data; + at91_chip->pioc_virq = irq; + at91_chip->pioc_idx = alias_idx; + + at91_chip->clock = clk_get(&pdev->dev, NULL); + if (IS_ERR(at91_chip->clock)) { + dev_err(&pdev->dev, "failed to get clock, ignoring.\n"); + goto err; + } + + if (clk_prepare(at91_chip->clock)) + goto clk_prep_err; + + /* enable PIO controller's clock */ + if (clk_enable(at91_chip->clock)) { + dev_err(&pdev->dev, "failed to enable clock, ignoring.\n"); + goto clk_err; + } + + at91_chip->chip = at91_gpio_template; + + chip = &at91_chip->chip; + chip->of_node = np; + chip->label = dev_name(&pdev->dev); + chip->dev = &pdev->dev; + chip->owner = THIS_MODULE; + chip->base = alias_idx * MAX_NB_GPIO_PER_BANK; + + if (!of_property_read_u32(np, "#gpio-lines", &ngpio)) { + if (ngpio >= MAX_NB_GPIO_PER_BANK) + pr_err("at91_gpio.%d, gpio-nb >= %d failback to %d\n", + alias_idx, MAX_NB_GPIO_PER_BANK, MAX_NB_GPIO_PER_BANK); + else + chip->ngpio = ngpio; + } + + names = devm_kzalloc(&pdev->dev, sizeof(char*) * chip->ngpio, GFP_KERNEL); + + if (!names) { + ret = -ENOMEM; + goto clk_err; + } + + for (i = 0; i < chip->ngpio; i++) + names[i] = kasprintf(GFP_KERNEL, "pio%c%d", alias_idx + 'A', i); + + chip->names = (const char*const*)names; + + range = &at91_chip->range; + range->name = chip->label; + range->id = alias_idx; + range->pin_base = range->base = range->id * MAX_NB_GPIO_PER_BANK; + + range->npins = chip->ngpio; + range->gc = chip; + + ret = gpiochip_add(chip); + if (ret) + goto clk_err; + + gpio_chips[alias_idx] = at91_chip; + gpio_banks = max(gpio_banks, alias_idx + 1); + + at91_gpio_probe_fixup(); + + at91_gpio_of_irq_setup(np, at91_chip); + + dev_info(&pdev->dev, "at address %p\n", at91_chip->regbase); + + return 0; + +clk_err: + clk_unprepare(at91_chip->clock); +clk_prep_err: + clk_put(at91_chip->clock); +err: + dev_err(&pdev->dev, "Failure %i for GPIO %i\n", ret, alias_idx); + + return ret; +} + +static struct platform_driver at91_gpio_driver = { + .driver = { + .name = "gpio-at91", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(at91_gpio_of_match), + }, + .probe = at91_gpio_probe, +}; + +static struct platform_driver at91_pinctrl_driver = { + .driver = { + .name = "pinctrl-at91", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(at91_pinctrl_of_match), + }, + .probe = at91_pinctrl_probe, + .remove = __devexit_p(at91_pinctrl_remove), +}; + +static int __init at91_pinctrl_init(void) +{ + int ret; + + ret = platform_driver_register(&at91_gpio_driver); + if (ret) + return ret; + return platform_driver_register(&at91_pinctrl_driver); +} +arch_initcall(at91_pinctrl_init); + +static void __exit at91_pinctrl_exit(void) +{ + platform_driver_unregister(&at91_pinctrl_driver); +} + +module_exit(at91_pinctrl_exit); +MODULE_AUTHOR("Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>"); +MODULE_DESCRIPTION("Atmel AT91 pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/pinctrl-bcm2835.c b/drivers/pinctrl/pinctrl-bcm2835.c index 7e9be18ec2d..0b0e9b49a1b 100644 --- a/drivers/pinctrl/pinctrl-bcm2835.c +++ b/drivers/pinctrl/pinctrl-bcm2835.c @@ -372,7 +372,7 @@ static int bcm2835_gpio_to_irq(struct gpio_chip *chip, unsigned offset) return irq_linear_revmap(pc->irq_domain, offset); } -static struct gpio_chip bcm2835_gpio_chip __devinitconst = { +static struct gpio_chip bcm2835_gpio_chip = { .label = MODULE_NAME, .owner = THIS_MODULE, .request = bcm2835_gpio_request, @@ -916,7 +916,7 @@ static int bcm2835_pinconf_set(struct pinctrl_dev *pctldev, return 0; } -struct pinconf_ops bcm2835_pinconf_ops = { +static struct pinconf_ops bcm2835_pinconf_ops = { .pin_config_get = bcm2835_pinconf_get, .pin_config_set = bcm2835_pinconf_set, }; @@ -931,7 +931,7 @@ static struct pinctrl_desc bcm2835_pinctrl_desc = { .owner = THIS_MODULE, }; -static struct pinctrl_gpio_range bcm2835_pinctrl_gpio_range __devinitconst = { +static struct pinctrl_gpio_range bcm2835_pinctrl_gpio_range = { .name = MODULE_NAME, .npins = BCM2835_NUM_GPIOS, }; @@ -1042,7 +1042,7 @@ static int __devinit bcm2835_pinctrl_probe(struct platform_device *pdev) return 0; } -static int __devexit bcm2835_pinctrl_remove(struct platform_device *pdev) +static int bcm2835_pinctrl_remove(struct platform_device *pdev) { struct bcm2835_pinctrl *pc = platform_get_drvdata(pdev); @@ -1052,7 +1052,7 @@ static int __devexit bcm2835_pinctrl_remove(struct platform_device *pdev) return 0; } -static struct of_device_id bcm2835_pinctrl_match[] __devinitconst = { +static struct of_device_id bcm2835_pinctrl_match[] = { { .compatible = "brcm,bcm2835-gpio" }, {} }; diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index b446c964121..fbb37154471 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -13,6 +13,7 @@ #include <linux/delay.h> #include <linux/errno.h> #include <linux/io.h> +#include <linux/irqdomain.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/platform_device.h> @@ -64,10 +65,8 @@ struct u300_gpio { struct gpio_chip chip; struct list_head port_list; struct clk *clk; - struct resource *memres; void __iomem *base; struct device *dev; - int irq_base; u32 stride; /* Register offsets */ u32 pcr; @@ -83,6 +82,7 @@ struct u300_gpio_port { struct list_head node; struct u300_gpio *gpio; char name[8]; + struct irq_domain *domain; int irq; int number; u8 toggle_edge_mode; @@ -314,10 +314,30 @@ static int u300_gpio_direction_output(struct gpio_chip *chip, unsigned offset, static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct u300_gpio *gpio = to_u300_gpio(chip); - int retirq = gpio->irq_base + offset; + int portno = offset >> 3; + struct u300_gpio_port *port = NULL; + struct list_head *p; + int retirq; - dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d\n", offset, - retirq); + list_for_each(p, &gpio->port_list) { + port = list_entry(p, struct u300_gpio_port, node); + if (port->number == portno) + break; + } + if (port == NULL) { + dev_err(gpio->dev, "could not locate port for GPIO %d IRQ\n", + offset); + return -EINVAL; + } + + /* + * The local hwirqs on the port are the lower three bits, there + * are exactly 8 IRQs per port since they are 8-bit + */ + retirq = irq_find_mapping(port->domain, (offset & 0x7)); + + dev_dbg(gpio->dev, "request IRQ for GPIO %d, return %d from port %d\n", + offset, retirq, port->number); return retirq; } @@ -467,7 +487,7 @@ static int u300_gpio_irq_type(struct irq_data *d, unsigned trigger) { struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); struct u300_gpio *gpio = port->gpio; - int offset = d->irq - gpio->irq_base; + int offset = (port->number << 3) + d->hwirq; u32 val; if ((trigger & IRQF_TRIGGER_RISING) && @@ -503,10 +523,12 @@ static void u300_gpio_irq_enable(struct irq_data *d) { struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); struct u300_gpio *gpio = port->gpio; - int offset = d->irq - gpio->irq_base; + int offset = (port->number << 3) + d->hwirq; u32 val; unsigned long flags; + dev_dbg(gpio->dev, "enable IRQ for hwirq %lu on port %s, offset %d\n", + d->hwirq, port->name, offset); local_irq_save(flags); val = readl(U300_PIN_REG(offset, ien)); writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, ien)); @@ -517,7 +539,7 @@ static void u300_gpio_irq_disable(struct irq_data *d) { struct u300_gpio_port *port = irq_data_get_irq_chip_data(d); struct u300_gpio *gpio = port->gpio; - int offset = d->irq - gpio->irq_base; + int offset = (port->number << 3) + d->hwirq; u32 val; unsigned long flags; @@ -555,8 +577,7 @@ static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) int irqoffset; for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) { - int pin_irq = gpio->irq_base + (port->number << 3) - + irqoffset; + int pin_irq = irq_find_mapping(port->domain, irqoffset); int offset = pinoffset + irqoffset; dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n", @@ -631,64 +652,86 @@ static inline void u300_gpio_free_ports(struct u300_gpio *gpio) list_for_each_safe(p, n, &gpio->port_list) { port = list_entry(p, struct u300_gpio_port, node); list_del(&port->node); + if (port->domain) + irq_domain_remove(port->domain); kfree(port); } } +/* + * Here we map a GPIO in the local gpio_chip pin space to a pin in + * the local pinctrl pin space. The pin controller used is + * pinctrl-u300. + */ +struct coh901_pinpair { + unsigned int offset; + unsigned int pin_base; +}; + +#define COH901_PINRANGE(a, b) { .offset = a, .pin_base = b } + +static struct coh901_pinpair coh901_pintable[] = { + COH901_PINRANGE(10, 426), + COH901_PINRANGE(11, 180), + COH901_PINRANGE(12, 165), /* MS/MMC card insertion */ + COH901_PINRANGE(13, 179), + COH901_PINRANGE(14, 178), + COH901_PINRANGE(16, 194), + COH901_PINRANGE(17, 193), + COH901_PINRANGE(18, 192), + COH901_PINRANGE(19, 191), + COH901_PINRANGE(20, 186), + COH901_PINRANGE(21, 185), + COH901_PINRANGE(22, 184), + COH901_PINRANGE(23, 183), + COH901_PINRANGE(24, 182), + COH901_PINRANGE(25, 181), +}; + static int __init u300_gpio_probe(struct platform_device *pdev) { struct u300_gpio_platform *plat = dev_get_platdata(&pdev->dev); struct u300_gpio *gpio; + struct resource *memres; int err = 0; int portno; u32 val; u32 ifr; int i; - gpio = kzalloc(sizeof(struct u300_gpio), GFP_KERNEL); - if (gpio == NULL) { - dev_err(&pdev->dev, "failed to allocate memory\n"); + gpio = devm_kzalloc(&pdev->dev, sizeof(struct u300_gpio), GFP_KERNEL); + if (gpio == NULL) return -ENOMEM; - } gpio->chip = u300_gpio_chip; gpio->chip.ngpio = plat->ports * U300_GPIO_PINS_PER_PORT; - gpio->irq_base = plat->gpio_irq_base; gpio->chip.dev = &pdev->dev; gpio->chip.base = plat->gpio_base; gpio->dev = &pdev->dev; - /* Get GPIO clock */ - gpio->clk = clk_get(gpio->dev, NULL); + memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!memres) { + dev_err(gpio->dev, "could not get GPIO memory resource\n"); + return -ENODEV; + } + + gpio->base = devm_request_and_ioremap(&pdev->dev, memres); + if (!gpio->base) { + dev_err(gpio->dev, "could not get remap memory\n"); + return -ENOMEM; + } + + gpio->clk = devm_clk_get(gpio->dev, NULL); if (IS_ERR(gpio->clk)) { err = PTR_ERR(gpio->clk); dev_err(gpio->dev, "could not get GPIO clock\n"); - goto err_no_clk; + return err; } + err = clk_prepare_enable(gpio->clk); if (err) { dev_err(gpio->dev, "could not enable GPIO clock\n"); - goto err_no_clk_enable; - } - - gpio->memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!gpio->memres) { - dev_err(gpio->dev, "could not get GPIO memory resource\n"); - err = -ENODEV; - goto err_no_resource; - } - - if (!request_mem_region(gpio->memres->start, - resource_size(gpio->memres), - "GPIO Controller")) { - err = -ENODEV; - goto err_no_ioregion; - } - - gpio->base = ioremap(gpio->memres->start, resource_size(gpio->memres)); - if (!gpio->base) { - err = -ENOMEM; - goto err_no_ioremap; + return err; } dev_info(gpio->dev, @@ -732,18 +775,28 @@ static int __init u300_gpio_probe(struct platform_device *pdev) port->irq = platform_get_irq_byname(pdev, port->name); - dev_dbg(gpio->dev, "register IRQ %d for %s\n", port->irq, + dev_dbg(gpio->dev, "register IRQ %d for port %s\n", port->irq, port->name); + port->domain = irq_domain_add_linear(pdev->dev.of_node, + U300_GPIO_PINS_PER_PORT, + &irq_domain_simple_ops, + port); + if (!port->domain) { + err = -ENOMEM; + goto err_no_domain; + } + irq_set_chained_handler(port->irq, u300_gpio_irq_handler); irq_set_handler_data(port->irq, port); /* For each GPIO pin set the unique IRQ handler */ for (i = 0; i < U300_GPIO_PINS_PER_PORT; i++) { - int irqno = gpio->irq_base + (portno << 3) + i; + int irqno = irq_create_mapping(port->domain, i); - dev_dbg(gpio->dev, "handler for IRQ %d on %s\n", - irqno, port->name); + dev_dbg(gpio->dev, "GPIO%d on port %s gets IRQ %d\n", + gpio->chip.base + (port->number << 3) + i, + port->name, irqno); irq_set_chip_and_handler(irqno, &u300_gpio_irqchip, handle_simple_irq); set_irq_flags(irqno, IRQF_VALID); @@ -763,32 +816,31 @@ static int __init u300_gpio_probe(struct platform_device *pdev) goto err_no_chip; } - /* Spawn pin controller device as child of the GPIO, pass gpio chip */ - plat->pinctrl_device->dev.platform_data = &gpio->chip; - err = platform_device_register(plat->pinctrl_device); - if (err) - goto err_no_pinctrl; + /* + * Add pinctrl pin ranges, the pin controller must be registered + * at this point + */ + for (i = 0; i < ARRAY_SIZE(coh901_pintable); i++) { + struct coh901_pinpair *p = &coh901_pintable[i]; + + err = gpiochip_add_pin_range(&gpio->chip, "pinctrl-u300", + p->offset, p->pin_base, 1); + if (err) + goto err_no_range; + } platform_set_drvdata(pdev, gpio); return 0; -err_no_pinctrl: +err_no_range: err = gpiochip_remove(&gpio->chip); err_no_chip: +err_no_domain: err_no_port: u300_gpio_free_ports(gpio); - iounmap(gpio->base); -err_no_ioremap: - release_mem_region(gpio->memres->start, resource_size(gpio->memres)); -err_no_ioregion: -err_no_resource: clk_disable_unprepare(gpio->clk); -err_no_clk_enable: - clk_put(gpio->clk); -err_no_clk: - kfree(gpio); - dev_info(&pdev->dev, "module ERROR:%d\n", err); + dev_err(&pdev->dev, "module ERROR:%d\n", err); return err; } @@ -806,13 +858,8 @@ static int __exit u300_gpio_remove(struct platform_device *pdev) return err; } u300_gpio_free_ports(gpio); - iounmap(gpio->base); - release_mem_region(gpio->memres->start, - resource_size(gpio->memres)); clk_disable_unprepare(gpio->clk); - clk_put(gpio->clk); platform_set_drvdata(pdev, NULL); - kfree(gpio); return 0; } diff --git a/drivers/pinctrl/pinctrl-exynos.c b/drivers/pinctrl/pinctrl-exynos.c index 21362f48d37..6ff665209a4 100644 --- a/drivers/pinctrl/pinctrl-exynos.c +++ b/drivers/pinctrl/pinctrl-exynos.c @@ -36,6 +36,7 @@ /* list of external wakeup controllers supported */ static const struct of_device_id exynos_wkup_irq_ids[] = { { .compatible = "samsung,exynos4210-wakeup-eint", }, + { } }; static void exynos_gpio_irq_unmask(struct irq_data *irqd) diff --git a/drivers/pinctrl/pinctrl-falcon.c b/drivers/pinctrl/pinctrl-falcon.c index ee730590347..8ed20e84cb0 100644 --- a/drivers/pinctrl/pinctrl-falcon.c +++ b/drivers/pinctrl/pinctrl-falcon.c @@ -322,7 +322,7 @@ static void falcon_pinconf_group_dbg_show(struct pinctrl_dev *pctrldev, { } -struct pinconf_ops falcon_pinconf_ops = { +static struct pinconf_ops falcon_pinconf_ops = { .pin_config_get = falcon_pinconf_get, .pin_config_set = falcon_pinconf_set, .pin_config_group_get = falcon_pinconf_group_get, diff --git a/drivers/pinctrl/pinctrl-imx.c b/drivers/pinctrl/pinctrl-imx.c index 63866d95357..131d86d7c2a 100644 --- a/drivers/pinctrl/pinctrl-imx.c +++ b/drivers/pinctrl/pinctrl-imx.c @@ -71,7 +71,7 @@ static const struct imx_pin_reg *imx_find_pin_reg( break; } - if (!pin_reg) { + if (i == info->npin_regs) { dev_err(info->dev, "Pin(%s): unable to find pin reg map\n", info->pins[pin].name); return NULL; @@ -397,7 +397,7 @@ static void imx_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, } } -struct pinconf_ops imx_pinconf_ops = { +static struct pinconf_ops imx_pinconf_ops = { .pin_config_get = imx_pinconf_get, .pin_config_set = imx_pinconf_set, .pin_config_dbg_show = imx_pinconf_dbg_show, @@ -611,7 +611,7 @@ int __devinit imx_pinctrl_probe(struct platform_device *pdev, return 0; } -int __devexit imx_pinctrl_remove(struct platform_device *pdev) +int imx_pinctrl_remove(struct platform_device *pdev) { struct imx_pinctrl *ipctl = platform_get_drvdata(pdev); diff --git a/drivers/pinctrl/pinctrl-imx23.c b/drivers/pinctrl/pinctrl-imx23.c index 3674d877ed7..04364f7822b 100644 --- a/drivers/pinctrl/pinctrl-imx23.c +++ b/drivers/pinctrl/pinctrl-imx23.c @@ -272,7 +272,7 @@ static int __devinit imx23_pinctrl_probe(struct platform_device *pdev) return mxs_pinctrl_probe(pdev, &imx23_pinctrl_data); } -static struct of_device_id imx23_pinctrl_of_match[] __devinitdata = { +static struct of_device_id imx23_pinctrl_of_match[] = { { .compatible = "fsl,imx23-pinctrl", }, { /* sentinel */ } }; @@ -285,7 +285,7 @@ static struct platform_driver imx23_pinctrl_driver = { .of_match_table = imx23_pinctrl_of_match, }, .probe = imx23_pinctrl_probe, - .remove = __devexit_p(mxs_pinctrl_remove), + .remove = mxs_pinctrl_remove, }; static int __init imx23_pinctrl_init(void) diff --git a/drivers/pinctrl/pinctrl-imx28.c b/drivers/pinctrl/pinctrl-imx28.c index 0f5b2122b1b..e1af2ba8900 100644 --- a/drivers/pinctrl/pinctrl-imx28.c +++ b/drivers/pinctrl/pinctrl-imx28.c @@ -388,7 +388,7 @@ static int __devinit imx28_pinctrl_probe(struct platform_device *pdev) return mxs_pinctrl_probe(pdev, &imx28_pinctrl_data); } -static struct of_device_id imx28_pinctrl_of_match[] __devinitdata = { +static struct of_device_id imx28_pinctrl_of_match[] = { { .compatible = "fsl,imx28-pinctrl", }, { /* sentinel */ } }; @@ -401,7 +401,7 @@ static struct platform_driver imx28_pinctrl_driver = { .of_match_table = imx28_pinctrl_of_match, }, .probe = imx28_pinctrl_probe, - .remove = __devexit_p(mxs_pinctrl_remove), + .remove = mxs_pinctrl_remove, }; static int __init imx28_pinctrl_init(void) diff --git a/drivers/pinctrl/pinctrl-imx35.c b/drivers/pinctrl/pinctrl-imx35.c index 82f109e26f2..1dbf5278ace 100644 --- a/drivers/pinctrl/pinctrl-imx35.c +++ b/drivers/pinctrl/pinctrl-imx35.c @@ -1559,7 +1559,7 @@ static struct imx_pinctrl_soc_info imx35_pinctrl_info = { .npin_regs = ARRAY_SIZE(imx35_pin_regs), }; -static struct of_device_id imx35_pinctrl_of_match[] __devinitdata = { +static struct of_device_id imx35_pinctrl_of_match[] = { { .compatible = "fsl,imx35-iomuxc", }, { /* sentinel */ } }; @@ -1576,7 +1576,7 @@ static struct platform_driver imx35_pinctrl_driver = { .of_match_table = of_match_ptr(imx35_pinctrl_of_match), }, .probe = imx35_pinctrl_probe, - .remove = __devexit_p(imx_pinctrl_remove), + .remove = imx_pinctrl_remove, }; static int __init imx35_pinctrl_init(void) diff --git a/drivers/pinctrl/pinctrl-imx51.c b/drivers/pinctrl/pinctrl-imx51.c index fb846896677..131216558a7 100644 --- a/drivers/pinctrl/pinctrl-imx51.c +++ b/drivers/pinctrl/pinctrl-imx51.c @@ -1286,7 +1286,7 @@ static struct imx_pinctrl_soc_info imx51_pinctrl_info = { .npin_regs = ARRAY_SIZE(imx51_pin_regs), }; -static struct of_device_id imx51_pinctrl_of_match[] __devinitdata = { +static struct of_device_id imx51_pinctrl_of_match[] = { { .compatible = "fsl,imx51-iomuxc", }, { /* sentinel */ } }; @@ -1303,7 +1303,7 @@ static struct platform_driver imx51_pinctrl_driver = { .of_match_table = of_match_ptr(imx51_pinctrl_of_match), }, .probe = imx51_pinctrl_probe, - .remove = __devexit_p(imx_pinctrl_remove), + .remove = imx_pinctrl_remove, }; static int __init imx51_pinctrl_init(void) diff --git a/drivers/pinctrl/pinctrl-imx53.c b/drivers/pinctrl/pinctrl-imx53.c index 783feb1ce06..ec404869177 100644 --- a/drivers/pinctrl/pinctrl-imx53.c +++ b/drivers/pinctrl/pinctrl-imx53.c @@ -1613,7 +1613,7 @@ static struct imx_pinctrl_soc_info imx53_pinctrl_info = { .npin_regs = ARRAY_SIZE(imx53_pin_regs), }; -static struct of_device_id imx53_pinctrl_of_match[] __devinitdata = { +static struct of_device_id imx53_pinctrl_of_match[] = { { .compatible = "fsl,imx53-iomuxc", }, { /* sentinel */ } }; @@ -1630,7 +1630,7 @@ static struct platform_driver imx53_pinctrl_driver = { .of_match_table = of_match_ptr(imx53_pinctrl_of_match), }, .probe = imx53_pinctrl_probe, - .remove = __devexit_p(imx_pinctrl_remove), + .remove = imx_pinctrl_remove, }; static int __init imx53_pinctrl_init(void) diff --git a/drivers/pinctrl/pinctrl-imx6q.c b/drivers/pinctrl/pinctrl-imx6q.c index e9bf71fbedc..844ab13c93a 100644 --- a/drivers/pinctrl/pinctrl-imx6q.c +++ b/drivers/pinctrl/pinctrl-imx6q.c @@ -2297,7 +2297,7 @@ static struct imx_pinctrl_soc_info imx6q_pinctrl_info = { .npin_regs = ARRAY_SIZE(imx6q_pin_regs), }; -static struct of_device_id imx6q_pinctrl_of_match[] __devinitdata = { +static struct of_device_id imx6q_pinctrl_of_match[] = { { .compatible = "fsl,imx6q-iomuxc", }, { /* sentinel */ } }; @@ -2314,7 +2314,7 @@ static struct platform_driver imx6q_pinctrl_driver = { .of_match_table = of_match_ptr(imx6q_pinctrl_of_match), }, .probe = imx6q_pinctrl_probe, - .remove = __devexit_p(imx_pinctrl_remove), + .remove = imx_pinctrl_remove, }; static int __init imx6q_pinctrl_init(void) diff --git a/drivers/pinctrl/pinctrl-lantiq.c b/drivers/pinctrl/pinctrl-lantiq.c index 07ba7682cf2..15f501d8902 100644 --- a/drivers/pinctrl/pinctrl-lantiq.c +++ b/drivers/pinctrl/pinctrl-lantiq.c @@ -46,8 +46,8 @@ static int ltq_get_group_pins(struct pinctrl_dev *pctrldev, return 0; } -void ltq_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, - struct pinctrl_map *map, unsigned num_maps) +static void ltq_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, unsigned num_maps) { int i; @@ -128,10 +128,10 @@ static int ltq_pinctrl_dt_subnode_size(struct device_node *np) return ret; } -int ltq_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, - struct device_node *np_config, - struct pinctrl_map **map, - unsigned *num_maps) +static int ltq_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, + unsigned *num_maps) { struct pinctrl_map *tmp; struct device_node *np; @@ -275,16 +275,6 @@ static int ltq_pmx_enable(struct pinctrl_dev *pctrldev, return 0; } -static void ltq_pmx_disable(struct pinctrl_dev *pctrldev, - unsigned func, - unsigned group) -{ - /* - * Nothing to do here. However, pinconf_check_ops() requires this - * callback to be defined. - */ -} - static int ltq_pmx_gpio_request_enable(struct pinctrl_dev *pctrldev, struct pinctrl_gpio_range *range, unsigned pin) @@ -312,7 +302,6 @@ static struct pinmux_ops ltq_pmx_ops = { .get_function_name = ltq_pmx_func_name, .get_function_groups = ltq_pmx_get_groups, .enable = ltq_pmx_enable, - .disable = ltq_pmx_disable, .gpio_request_enable = ltq_pmx_gpio_request_enable, }; diff --git a/drivers/pinctrl/pinctrl-mmp2.c b/drivers/pinctrl/pinctrl-mmp2.c index 2cfed552bbe..4fbb3db3f1c 100644 --- a/drivers/pinctrl/pinctrl-mmp2.c +++ b/drivers/pinctrl/pinctrl-mmp2.c @@ -691,7 +691,7 @@ static int __devinit mmp2_pinmux_probe(struct platform_device *pdev) return pxa3xx_pinctrl_register(pdev, &mmp2_info); } -static int __devexit mmp2_pinmux_remove(struct platform_device *pdev) +static int mmp2_pinmux_remove(struct platform_device *pdev) { return pxa3xx_pinctrl_unregister(pdev); } @@ -702,7 +702,7 @@ static struct platform_driver mmp2_pinmux_driver = { .owner = THIS_MODULE, }, .probe = mmp2_pinmux_probe, - .remove = __devexit_p(mmp2_pinmux_remove), + .remove = mmp2_pinmux_remove, }; static int __init mmp2_pinmux_init(void) diff --git a/drivers/pinctrl/pinctrl-mxs.c b/drivers/pinctrl/pinctrl-mxs.c index 4ba4636b6a4..180f16379ec 100644 --- a/drivers/pinctrl/pinctrl-mxs.c +++ b/drivers/pinctrl/pinctrl-mxs.c @@ -319,7 +319,7 @@ static void mxs_pinconf_group_dbg_show(struct pinctrl_dev *pctldev, seq_printf(s, "0x%lx", config); } -struct pinconf_ops mxs_pinconf_ops = { +static struct pinconf_ops mxs_pinconf_ops = { .pin_config_get = mxs_pinconf_get, .pin_config_set = mxs_pinconf_set, .pin_config_group_get = mxs_pinconf_group_get, @@ -522,7 +522,7 @@ err: } EXPORT_SYMBOL_GPL(mxs_pinctrl_probe); -int __devexit mxs_pinctrl_remove(struct platform_device *pdev) +int mxs_pinctrl_remove(struct platform_device *pdev) { struct mxs_pinctrl_data *d = platform_get_drvdata(pdev); diff --git a/drivers/pinctrl/pinctrl-nomadik-db8500.c b/drivers/pinctrl/pinctrl-nomadik-db8500.c index debaa75b055..7d88ae35211 100644 --- a/drivers/pinctrl/pinctrl-nomadik-db8500.c +++ b/drivers/pinctrl/pinctrl-nomadik-db8500.c @@ -475,8 +475,10 @@ static const unsigned hsit_a_1_pins[] = { DB8500_PIN_AJ9, DB8500_PIN_AH9, DB8500_PIN_AG9, DB8500_PIN_AG8, DB8500_PIN_AF8 }; static const unsigned hsit_a_2_pins[] = { DB8500_PIN_AJ9, DB8500_PIN_AH9, DB8500_PIN_AG9, DB8500_PIN_AG8 }; -static const unsigned clkout_a_1_pins[] = { DB8500_PIN_AH7, DB8500_PIN_AJ6 }; -static const unsigned clkout_a_2_pins[] = { DB8500_PIN_AG7, DB8500_PIN_AF7 }; +static const unsigned clkout1_a_1_pins[] = { DB8500_PIN_AH7 }; +static const unsigned clkout1_a_2_pins[] = { DB8500_PIN_AG7 }; +static const unsigned clkout2_a_1_pins[] = { DB8500_PIN_AJ6 }; +static const unsigned clkout2_a_2_pins[] = { DB8500_PIN_AF7 }; static const unsigned usb_a_1_pins[] = { DB8500_PIN_AF28, DB8500_PIN_AE29, DB8500_PIN_AD29, DB8500_PIN_AC29, DB8500_PIN_AD28, DB8500_PIN_AD26, DB8500_PIN_AE26, DB8500_PIN_AG29, DB8500_PIN_AE27, DB8500_PIN_AD27, @@ -592,7 +594,8 @@ static const unsigned stmmod_c_1_pins[] = { DB8500_PIN_C20, DB8500_PIN_B21, DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24 }; static const unsigned usbsim_c_1_pins[] = { DB8500_PIN_D22 }; static const unsigned mc4rstn_c_1_pins[] = { DB8500_PIN_AF25 }; -static const unsigned clkout_c_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AH12 }; +static const unsigned clkout1_c_1_pins[] = { DB8500_PIN_AH13 }; +static const unsigned clkout2_c_1_pins[] = { DB8500_PIN_AH12 }; static const unsigned i2c3_c_1_pins[] = { DB8500_PIN_AG12, DB8500_PIN_AH11 }; static const unsigned spi0_c_1_pins[] = { DB8500_PIN_AH10, DB8500_PIN_AH9, DB8500_PIN_AG9, DB8500_PIN_AG8 }; @@ -600,14 +603,66 @@ static const unsigned usbsim_c_2_pins[] = { DB8500_PIN_AF8 }; static const unsigned i2c3_c_2_pins[] = { DB8500_PIN_AG7, DB8500_PIN_AF7 }; /* Other C1 column */ +static const unsigned u2rx_oc1_1_pins[] = { DB8500_PIN_AB2 }; +static const unsigned stmape_oc1_1_pins[] = { DB8500_PIN_AA4, DB8500_PIN_Y4, + DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 }; +static const unsigned remap0_oc1_1_pins[] = { DB8500_PIN_E1 }; +static const unsigned remap1_oc1_1_pins[] = { DB8500_PIN_E2 }; +static const unsigned ptma9_oc1_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4, + DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3, DB8500_PIN_H2, + DB8500_PIN_J2, DB8500_PIN_H1 }; static const unsigned kp_oc1_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3, DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6, DB8500_PIN_D6, DB8500_PIN_B7 }; +static const unsigned rf_oc1_1_pins[] = { DB8500_PIN_D8, DB8500_PIN_D9 }; +static const unsigned hxclk_oc1_1_pins[] = { DB8500_PIN_D16 }; +static const unsigned uartmodrx_oc1_1_pins[] = { DB8500_PIN_B17 }; +static const unsigned uartmodtx_oc1_1_pins[] = { DB8500_PIN_C16 }; +static const unsigned stmmod_oc1_1_pins[] = { DB8500_PIN_C19, DB8500_PIN_C17, + DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19 }; +static const unsigned hxgpio_oc1_1_pins[] = { DB8500_PIN_D21, DB8500_PIN_D20, + DB8500_PIN_C20, DB8500_PIN_B21, DB8500_PIN_C21, DB8500_PIN_A22, + DB8500_PIN_B24, DB8500_PIN_C22 }; +static const unsigned rf_oc1_2_pins[] = { DB8500_PIN_C23, DB8500_PIN_D23 }; static const unsigned spi2_oc1_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12, DB8500_PIN_AH12, DB8500_PIN_AH11 }; static const unsigned spi2_oc1_2_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AH12, DB8500_PIN_AH11 }; +/* Other C2 column */ +static const unsigned sbag_oc2_1_pins[] = { DB8500_PIN_AA4, DB8500_PIN_AB2, + DB8500_PIN_Y4, DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 }; +static const unsigned etmr4_oc2_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4, + DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3, DB8500_PIN_H2, + DB8500_PIN_J2, DB8500_PIN_H1 }; +static const unsigned ptma9_oc2_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16, + DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17, + DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20, + DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21, + DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 }; + +/* Other C3 column */ +static const unsigned stmmod_oc3_1_pins[] = { DB8500_PIN_AB2, DB8500_PIN_W2, + DB8500_PIN_W3, DB8500_PIN_V3, DB8500_PIN_V2 }; +static const unsigned stmmod_oc3_2_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4, + DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3 }; +static const unsigned uartmodrx_oc3_1_pins[] = { DB8500_PIN_H2 }; +static const unsigned uartmodtx_oc3_1_pins[] = { DB8500_PIN_J2 }; +static const unsigned etmr4_oc3_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16, + DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17, + DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20, + DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21, + DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 }; + +/* Other C4 column */ +static const unsigned sbag_oc4_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4, + DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3, DB8500_PIN_H1 }; +static const unsigned hwobs_oc4_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16, + DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17, + DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20, + DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21, + DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 }; + #define DB8500_PIN_GROUP(a,b) { .name = #a, .pins = a##_pins, \ .npins = ARRAY_SIZE(a##_pins), .altsetting = b } @@ -639,6 +694,7 @@ static const struct nmk_pingroup nmk_db8500_groups[] = { DB8500_PIN_GROUP(i2c0_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(ipgpio0_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(ipgpio1_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(kp_a_2, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(msp2sck_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(msp2_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(mc4_a_1, NMK_GPIO_ALT_A), @@ -647,8 +703,10 @@ static const struct nmk_pingroup nmk_db8500_groups[] = { DB8500_PIN_GROUP(hsir_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(hsit_a_1, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(hsit_a_2, NMK_GPIO_ALT_A), - DB8500_PIN_GROUP(clkout_a_1, NMK_GPIO_ALT_A), - DB8500_PIN_GROUP(clkout_a_2, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(clkout1_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(clkout1_a_2, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(clkout2_a_1, NMK_GPIO_ALT_A), + DB8500_PIN_GROUP(clkout2_a_2, NMK_GPIO_ALT_A), DB8500_PIN_GROUP(usb_a_1, NMK_GPIO_ALT_A), /* Altfunction B column */ DB8500_PIN_GROUP(trig_b_1, NMK_GPIO_ALT_B), @@ -720,15 +778,41 @@ static const struct nmk_pingroup nmk_db8500_groups[] = { DB8500_PIN_GROUP(stmmod_c_1, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(usbsim_c_1, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(mc4rstn_c_1, NMK_GPIO_ALT_C), - DB8500_PIN_GROUP(clkout_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(clkout1_c_1, NMK_GPIO_ALT_C), + DB8500_PIN_GROUP(clkout2_c_1, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(i2c3_c_1, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(spi0_c_1, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(usbsim_c_2, NMK_GPIO_ALT_C), DB8500_PIN_GROUP(i2c3_c_2, NMK_GPIO_ALT_C), /* Other alt C1 column */ + DB8500_PIN_GROUP(u2rx_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(stmape_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(remap0_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(remap1_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(ptma9_oc1_1, NMK_GPIO_ALT_C1), DB8500_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(rf_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(hxclk_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(uartmodrx_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(uartmodtx_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(stmmod_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(hxgpio_oc1_1, NMK_GPIO_ALT_C1), + DB8500_PIN_GROUP(rf_oc1_2, NMK_GPIO_ALT_C1), DB8500_PIN_GROUP(spi2_oc1_1, NMK_GPIO_ALT_C1), DB8500_PIN_GROUP(spi2_oc1_2, NMK_GPIO_ALT_C1), + /* Other alt C2 column */ + DB8500_PIN_GROUP(sbag_oc2_1, NMK_GPIO_ALT_C2), + DB8500_PIN_GROUP(etmr4_oc2_1, NMK_GPIO_ALT_C2), + DB8500_PIN_GROUP(ptma9_oc2_1, NMK_GPIO_ALT_C2), + /* Other alt C3 column */ + DB8500_PIN_GROUP(stmmod_oc3_1, NMK_GPIO_ALT_C3), + DB8500_PIN_GROUP(stmmod_oc3_2, NMK_GPIO_ALT_C3), + DB8500_PIN_GROUP(uartmodrx_oc3_1, NMK_GPIO_ALT_C3), + DB8500_PIN_GROUP(uartmodtx_oc3_1, NMK_GPIO_ALT_C3), + DB8500_PIN_GROUP(etmr4_oc3_1, NMK_GPIO_ALT_C3), + /* Other alt C4 column */ + DB8500_PIN_GROUP(sbag_oc4_1, NMK_GPIO_ALT_C4), + DB8500_PIN_GROUP(hwobs_oc4_1, NMK_GPIO_ALT_C4), }; /* We use this macro to define the groups applicable to a function */ @@ -742,7 +826,7 @@ DB8500_FUNC_GROUPS(u1, "u1rxtx_a_1", "u1ctsrts_a_1"); * only available on two pins in alternative function C */ DB8500_FUNC_GROUPS(u2, "u2rxtx_b_1", "u2rxtx_c_1", "u2ctsrts_c_1", - "u2rxtx_c_2", "u2rxtx_c_3"); + "u2rxtx_c_2", "u2rxtx_c_3", "u2rx_oc1_1"); DB8500_FUNC_GROUPS(ipi2c, "ipi2c_a_1", "ipi2c_a_2"); /* * MSP0 can only be on a certain set of pins, but the TX/RX pins can be @@ -757,7 +841,7 @@ DB8500_FUNC_GROUPS(msp1, "msp1txrx_a_1", "msp1_a_1", "msp1txrx_b_1"); DB8500_FUNC_GROUPS(lcdb, "lcdb_a_1"); DB8500_FUNC_GROUPS(lcd, "lcdvsi0_a_1", "lcdvsi1_a_1", "lcd_d0_d7_a_1", "lcd_d8_d11_a_1", "lcd_d12_d23_a_1", "lcd_b_1"); -DB8500_FUNC_GROUPS(kp, "kp_a_1", "kp_b_1", "kp_b_2", "kp_c_1", "kp_oc1_1"); +DB8500_FUNC_GROUPS(kp, "kp_a_1", "kp_a_2", "kp_b_1", "kp_b_2", "kp_c_1", "kp_oc1_1"); DB8500_FUNC_GROUPS(mc2, "mc2_a_1", "mc2rstn_c_1"); DB8500_FUNC_GROUPS(ssp1, "ssp1_a_1"); DB8500_FUNC_GROUPS(ssp0, "ssp0_a_1"); @@ -773,7 +857,8 @@ DB8500_FUNC_GROUPS(msp2, "msp2sck_a_1", "msp2_a_1"); DB8500_FUNC_GROUPS(mc4, "mc4_a_1", "mc4rstn_c_1"); DB8500_FUNC_GROUPS(mc1, "mc1_a_1", "mc1_a_2", "mc1dir_a_1"); DB8500_FUNC_GROUPS(hsi, "hsir_a_1", "hsit_a_1", "hsit_a_2"); -DB8500_FUNC_GROUPS(clkout, "clkout_a_1", "clkout_a_2", "clkout_c_1"); +DB8500_FUNC_GROUPS(clkout, "clkout1_a_1", "clkout1_a_2", "clkout1_c_1", + "clkout2_a_1", "clkout2_a_2", "clkout2_c_1"); DB8500_FUNC_GROUPS(usb, "usb_a_1"); DB8500_FUNC_GROUPS(trig, "trig_b_1"); DB8500_FUNC_GROUPS(i2c4, "i2c4_b_1"); @@ -784,8 +869,10 @@ DB8500_FUNC_GROUPS(i2c2, "i2c2_b_1", "i2c2_b_2"); * so select one of each. */ DB8500_FUNC_GROUPS(uartmod, "uartmodtx_b_1", "uartmodrx_b_1", "uartmodrx_b_2", - "uartmodrx_c_1", "uartmod_tx_c_1"); -DB8500_FUNC_GROUPS(stmmod, "stmmod_b_1", "stmmod_c_1"); + "uartmodrx_c_1", "uartmod_tx_c_1", "uartmodrx_oc1_1", + "uartmodtx_oc1_1", "uartmodrx_oc3_1", "uartmodtx_oc3_1"); +DB8500_FUNC_GROUPS(stmmod, "stmmod_b_1", "stmmod_c_1", "stmmod_oc1_1", + "stmmod_oc3_1", "stmmod_oc3_2"); DB8500_FUNC_GROUPS(spi3, "spi3_b_1"); /* Select between CS0 on alt B or PS1 on alt C */ DB8500_FUNC_GROUPS(sm, "sm_b_1", "smcs0_b_1", "smcs1_b_1", "smcleale_c_1", @@ -799,13 +886,19 @@ DB8500_FUNC_GROUPS(ipjtag, "ipjtag_c_1"); DB8500_FUNC_GROUPS(slim0, "slim0_c_1"); DB8500_FUNC_GROUPS(ms, "ms_c_1"); DB8500_FUNC_GROUPS(iptrigout, "iptrigout_c_1"); -DB8500_FUNC_GROUPS(stmape, "stmape_c_1", "stmape_c_2"); +DB8500_FUNC_GROUPS(stmape, "stmape_c_1", "stmape_c_2", "stmape_oc1_1"); DB8500_FUNC_GROUPS(mc5, "mc5_c_1"); DB8500_FUNC_GROUPS(usbsim, "usbsim_c_1", "usbsim_c_2"); DB8500_FUNC_GROUPS(i2c3, "i2c3_c_1", "i2c3_c_2"); DB8500_FUNC_GROUPS(spi0, "spi0_c_1"); DB8500_FUNC_GROUPS(spi2, "spi2_oc1_1", "spi2_oc1_2"); - +DB8500_FUNC_GROUPS(remap, "remap0_oc1_1", "remap1_oc1_1"); +DB8500_FUNC_GROUPS(sbag, "sbag_oc2_1", "sbag_oc4_1"); +DB8500_FUNC_GROUPS(ptm, "ptma9_oc1_1", "ptma9_oc2_1"); +DB8500_FUNC_GROUPS(rf, "rf_oc1_1", "rf_oc1_2"); +DB8500_FUNC_GROUPS(hx, "hxclk_oc1_1", "hxgpio_oc1_1"); +DB8500_FUNC_GROUPS(etm, "etmr4_oc2_1", "etmr4_oc3_1"); +DB8500_FUNC_GROUPS(hwobs, "hwobs_oc4_1"); #define FUNCTION(fname) \ { \ .name = #fname, \ @@ -858,6 +951,12 @@ static const struct nmk_function nmk_db8500_functions[] = { FUNCTION(i2c3), FUNCTION(spi0), FUNCTION(spi2), + FUNCTION(remap), + FUNCTION(ptm), + FUNCTION(rf), + FUNCTION(hx), + FUNCTION(etm), + FUNCTION(hwobs), }; static const struct prcm_gpiocr_altcx_pin_desc db8500_altcx_pins[] = { diff --git a/drivers/pinctrl/pinctrl-nomadik-db8540.c b/drivers/pinctrl/pinctrl-nomadik-db8540.c index 52fc30181f7..bb6a4016322 100644 --- a/drivers/pinctrl/pinctrl-nomadik-db8540.c +++ b/drivers/pinctrl/pinctrl-nomadik-db8540.c @@ -460,8 +460,10 @@ static const unsigned hsit_a_1_pins[] = { DB8540_PIN_B11, DB8540_PIN_B10, DB8540_PIN_E10, DB8540_PIN_B12, DB8540_PIN_D10 }; static const unsigned hsit_a_2_pins[] = { DB8540_PIN_B11, DB8540_PIN_B10, DB8540_PIN_E10, DB8540_PIN_B12 }; -static const unsigned clkout_a_1_pins[] = { DB8540_PIN_D11, DB8540_PIN_AJ6 }; -static const unsigned clkout_a_2_pins[] = { DB8540_PIN_B13, DB8540_PIN_C12 }; +static const unsigned clkout1_a_1_pins[] = { DB8540_PIN_D11 }; +static const unsigned clkout1_a_2_pins[] = { DB8540_PIN_B13 }; +static const unsigned clkout2_a_1_pins[] = { DB8540_PIN_AJ6 }; +static const unsigned clkout2_a_2_pins[] = { DB8540_PIN_C12 }; static const unsigned msp4_a_1_pins[] = { DB8540_PIN_B14, DB8540_PIN_E11 }; static const unsigned usb_a_1_pins[] = { DB8540_PIN_D12, DB8540_PIN_D15, DB8540_PIN_C13, DB8540_PIN_C14, DB8540_PIN_C18, DB8540_PIN_C16, @@ -698,8 +700,10 @@ static const struct nmk_pingroup nmk_db8540_groups[] = { DB8540_PIN_GROUP(hsir_a_1, NMK_GPIO_ALT_A), DB8540_PIN_GROUP(hsit_a_1, NMK_GPIO_ALT_A), DB8540_PIN_GROUP(hsit_a_2, NMK_GPIO_ALT_A), - DB8540_PIN_GROUP(clkout_a_1, NMK_GPIO_ALT_A), - DB8540_PIN_GROUP(clkout_a_2, NMK_GPIO_ALT_A), + DB8540_PIN_GROUP(clkout1_a_1, NMK_GPIO_ALT_A), + DB8540_PIN_GROUP(clkout1_a_2, NMK_GPIO_ALT_A), + DB8540_PIN_GROUP(clkout2_a_1, NMK_GPIO_ALT_A), + DB8540_PIN_GROUP(clkout2_a_2, NMK_GPIO_ALT_A), DB8540_PIN_GROUP(msp4_a_1, NMK_GPIO_ALT_A), DB8540_PIN_GROUP(usb_a_1, NMK_GPIO_ALT_A), /* Altfunction B column */ @@ -822,6 +826,7 @@ static const struct nmk_pingroup nmk_db8540_groups[] = { DB8540_PIN_GROUP(modaccuarttxrx_oc4_1, NMK_GPIO_ALT_C4), DB8540_PIN_GROUP(modaccuartrtscts_oc4_1, NMK_GPIO_ALT_C4), DB8540_PIN_GROUP(stmmod_oc4_1, NMK_GPIO_ALT_C4), + DB8540_PIN_GROUP(moduartstmmux_oc4_1, NMK_GPIO_ALT_C4), }; @@ -830,7 +835,8 @@ static const struct nmk_pingroup nmk_db8540_groups[] = { static const char * const a##_groups[] = { b }; DB8540_FUNC_GROUPS(apetrig, "apetrig_b_1"); -DB8540_FUNC_GROUPS(clkout, "clkoutreq_a_1", "clkout_a_1", "clkout_a_2"); +DB8540_FUNC_GROUPS(clkout, "clkoutreq_a_1", "clkout1_a_1", "clkout1_a_2", + "clkout2_a_1", "clkout2_a_2"); DB8540_FUNC_GROUPS(ddrtrig, "ddrtrig_b_1"); DB8540_FUNC_GROUPS(hsi, "hsir_a_1", "hsit_a_1", "hsit_a_2"); DB8540_FUNC_GROUPS(hwobs, "hwobs_oc4_1"); diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index cf82d9ce4de..8ef3e85cb01 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -30,26 +30,10 @@ #include <linux/pinctrl/pinconf.h> /* Since we request GPIOs from ourself */ #include <linux/pinctrl/consumer.h> -/* - * For the U8500 archs, use the PRCMU register interface, for the older - * Nomadik, provide some stubs. The functions using these will only be - * called on the U8500 series. - */ -#ifdef CONFIG_ARCH_U8500 -#include <linux/mfd/dbx500-prcmu.h> -#else -static inline u32 prcmu_read(unsigned int reg) { - return 0; -} -static inline void prcmu_write(unsigned int reg, u32 value) {} -static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value) {} -#endif +#include <linux/platform_data/pinctrl-nomadik.h> #include <asm/mach/irq.h> -#include <plat/pincfg.h> -#include <plat/gpio-nomadik.h> - #include "pinctrl-nomadik.h" /* @@ -60,8 +44,6 @@ static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value) {} * Symbols in this file are called "nmk_gpio" for "nomadik gpio" */ -#define NMK_GPIO_PER_CHIP 32 - struct nmk_gpio_chip { struct gpio_chip chip; struct irq_domain *domain; @@ -86,10 +68,18 @@ struct nmk_gpio_chip { u32 lowemi; }; +/** + * struct nmk_pinctrl - state container for the Nomadik pin controller + * @dev: containing device pointer + * @pctl: corresponding pin controller device + * @soc: SoC data for this specific chip + * @prcm_base: PRCM register range virtual base + */ struct nmk_pinctrl { struct device *dev; struct pinctrl_dev *pctl; const struct nmk_pinctrl_soc_data *soc; + void __iomem *prcm_base; }; static struct nmk_gpio_chip * @@ -251,6 +241,15 @@ nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset) dev_dbg(nmk_chip->chip.dev, "%d: clearing interrupt mask\n", gpio); } +static void nmk_write_masked(void __iomem *reg, u32 mask, u32 value) +{ + u32 val; + + val = readl(reg); + val = ((val & ~mask) | (value & mask)); + writel(val, reg); +} + static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct, unsigned offset, unsigned alt_num) { @@ -289,8 +288,8 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct, if (pin_desc->altcx[i].used == true) { reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; bit = pin_desc->altcx[i].control_bit; - if (prcmu_read(reg) & BIT(bit)) { - prcmu_write_masked(reg, BIT(bit), 0); + if (readl(npct->prcm_base + reg) & BIT(bit)) { + nmk_write_masked(npct->prcm_base + reg, BIT(bit), 0); dev_dbg(npct->dev, "PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n", offset, i+1); @@ -318,8 +317,8 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct, if (pin_desc->altcx[i].used == true) { reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; bit = pin_desc->altcx[i].control_bit; - if (prcmu_read(reg) & BIT(bit)) { - prcmu_write_masked(reg, BIT(bit), 0); + if (readl(npct->prcm_base + reg) & BIT(bit)) { + nmk_write_masked(npct->prcm_base + reg, BIT(bit), 0); dev_dbg(npct->dev, "PRCM GPIOCR: pin %i: alternate-C%i has been disabled\n", offset, i+1); @@ -331,7 +330,7 @@ static void nmk_prcm_altcx_set_mode(struct nmk_pinctrl *npct, bit = pin_desc->altcx[alt_index].control_bit; dev_dbg(npct->dev, "PRCM GPIOCR: pin %i: alternate-C%i has been selected\n", offset, alt_index+1); - prcmu_write_masked(reg, BIT(bit), BIT(bit)); + nmk_write_masked(npct->prcm_base + reg, BIT(bit), BIT(bit)); } static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, @@ -536,7 +535,7 @@ static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep) * and its sleep mode based on the specified configuration. The @cfg is * usually one of the SoC specific macros defined in mach/<soc>-pins.h. These * are constructed using, and can be further enhanced with, the macros in - * plat/pincfg.h. + * <linux/platform_data/pinctrl-nomadik.h> * * If a pin's mode is set to GPIO, it is configured as an input to avoid * side-effects. The gpio can be manipulated later using standard GPIO API @@ -675,6 +674,35 @@ int nmk_gpio_set_mode(int gpio, int gpio_mode) } EXPORT_SYMBOL(nmk_gpio_set_mode); +static int nmk_prcm_gpiocr_get_mode(struct pinctrl_dev *pctldev, int gpio) +{ + int i; + u16 reg; + u8 bit; + struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); + const struct prcm_gpiocr_altcx_pin_desc *pin_desc; + const u16 *gpiocr_regs; + + for (i = 0; i < npct->soc->npins_altcx; i++) { + if (npct->soc->altcx_pins[i].pin == gpio) + break; + } + if (i == npct->soc->npins_altcx) + return NMK_GPIO_ALT_C; + + pin_desc = npct->soc->altcx_pins + i; + gpiocr_regs = npct->soc->prcm_gpiocr_registers; + for (i = 0; i < PRCM_IDX_GPIOCR_ALTC_MAX; i++) { + if (pin_desc->altcx[i].used == true) { + reg = gpiocr_regs[pin_desc->altcx[i].reg_index]; + bit = pin_desc->altcx[i].control_bit; + if (readl(npct->prcm_base + reg) & BIT(bit)) + return NMK_GPIO_ALT_C+i+1; + } + } + return NMK_GPIO_ALT_C; +} + int nmk_gpio_get_mode(int gpio) { struct nmk_gpio_chip *nmk_chip; @@ -1063,8 +1091,9 @@ static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset) #include <linux/seq_file.h> -static void nmk_gpio_dbg_show_one(struct seq_file *s, struct gpio_chip *chip, - unsigned offset, unsigned gpio) +static void nmk_gpio_dbg_show_one(struct seq_file *s, + struct pinctrl_dev *pctldev, struct gpio_chip *chip, + unsigned offset, unsigned gpio) { const char *label = gpiochip_is_requested(chip, offset); struct nmk_gpio_chip *nmk_chip = @@ -1078,12 +1107,18 @@ static void nmk_gpio_dbg_show_one(struct seq_file *s, struct gpio_chip *chip, [NMK_GPIO_ALT_A] = "altA", [NMK_GPIO_ALT_B] = "altB", [NMK_GPIO_ALT_C] = "altC", + [NMK_GPIO_ALT_C+1] = "altC1", + [NMK_GPIO_ALT_C+2] = "altC2", + [NMK_GPIO_ALT_C+3] = "altC3", + [NMK_GPIO_ALT_C+4] = "altC4", }; clk_enable(nmk_chip->clk); is_out = !!(readl(nmk_chip->addr + NMK_GPIO_DIR) & bit); pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit); mode = nmk_gpio_get_mode(gpio); + if ((mode == NMK_GPIO_ALT_C) && pctldev) + mode = nmk_prcm_gpiocr_get_mode(pctldev, gpio); seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s", gpio, label ?: "(none)", @@ -1127,13 +1162,14 @@ static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) unsigned gpio = chip->base; for (i = 0; i < chip->ngpio; i++, gpio++) { - nmk_gpio_dbg_show_one(s, chip, i, gpio); + nmk_gpio_dbg_show_one(s, NULL, chip, i, gpio); seq_printf(s, "\n"); } } #else static inline void nmk_gpio_dbg_show_one(struct seq_file *s, + struct pinctrl_dev *pctldev, struct gpio_chip *chip, unsigned offset, unsigned gpio) { @@ -1250,8 +1286,8 @@ void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up) } } -int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) +static int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) { struct nmk_gpio_chip *nmk_chip = d->host_data; @@ -1464,7 +1500,7 @@ static void nmk_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, return; } chip = range->gc; - nmk_gpio_dbg_show_one(s, chip, offset - chip->base, offset); + nmk_gpio_dbg_show_one(s, pctldev, chip, offset - chip->base, offset); } static struct pinctrl_ops nmk_pinctrl_ops = { @@ -1635,9 +1671,9 @@ static void nmk_pmx_disable(struct pinctrl_dev *pctldev, dev_dbg(npct->dev, "disable group %s, %u pins\n", g->name, g->npins); } -int nmk_gpio_request_enable(struct pinctrl_dev *pctldev, - struct pinctrl_gpio_range *range, - unsigned offset) +static int nmk_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) { struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); struct nmk_gpio_chip *nmk_chip; @@ -1666,9 +1702,9 @@ int nmk_gpio_request_enable(struct pinctrl_dev *pctldev, return 0; } -void nmk_gpio_disable_free(struct pinctrl_dev *pctldev, - struct pinctrl_gpio_range *range, - unsigned offset) +static void nmk_gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) { struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); @@ -1686,17 +1722,15 @@ static struct pinmux_ops nmk_pinmux_ops = { .gpio_disable_free = nmk_gpio_disable_free, }; -int nmk_pin_config_get(struct pinctrl_dev *pctldev, - unsigned pin, - unsigned long *config) +static int nmk_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, + unsigned long *config) { /* Not implemented */ return -EINVAL; } -int nmk_pin_config_set(struct pinctrl_dev *pctldev, - unsigned pin, - unsigned long config) +static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, + unsigned long config) { static const char *pullnames[] = { [NMK_GPIO_PULL_NONE] = "none", @@ -1818,6 +1852,7 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev) const struct platform_device_id *platid = platform_get_device_id(pdev); struct device_node *np = pdev->dev.of_node; struct nmk_pinctrl *npct; + struct resource *res; unsigned int version = 0; int i; @@ -1827,9 +1862,14 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev) if (platid) version = platid->driver_data; - else if (np) - version = (unsigned int) - of_match_device(nmk_pinctrl_match, &pdev->dev)->data; + else if (np) { + const struct of_device_id *match; + + match = of_match_device(nmk_pinctrl_match, &pdev->dev); + if (!match) + return -ENODEV; + version = (unsigned int) match->data; + } /* Poke in other ASIC variants here */ if (version == PINCTRL_NMK_STN8815) @@ -1839,22 +1879,37 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev) if (version == PINCTRL_NMK_DB8540) nmk_pinctrl_db8540_init(&npct->soc); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) { + npct->prcm_base = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!npct->prcm_base) { + dev_err(&pdev->dev, + "failed to ioremap PRCM registers\n"); + return -ENOMEM; + } + } else { + dev_info(&pdev->dev, + "No PRCM base, assume no ALT-Cx control is available\n"); + } + /* * We need all the GPIO drivers to probe FIRST, or we will not be able * to obtain references to the struct gpio_chip * for them, and we * need this to proceed. */ for (i = 0; i < npct->soc->gpio_num_ranges; i++) { - if (!nmk_gpio_chips[i]) { + if (!nmk_gpio_chips[npct->soc->gpio_ranges[i].id]) { dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i); return -EPROBE_DEFER; } - npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[i]->chip; + npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[npct->soc->gpio_ranges[i].id]->chip; } nmk_pinctrl_desc.pins = npct->soc->pins; nmk_pinctrl_desc.npins = npct->soc->npins; npct->dev = &pdev->dev; + npct->pctl = pinctrl_register(&nmk_pinctrl_desc, &pdev->dev, npct); if (!npct->pctl) { dev_err(&pdev->dev, "could not register Nomadik pinctrl driver\n"); @@ -1889,6 +1944,7 @@ static const struct platform_device_id nmk_pinctrl_id[] = { { "pinctrl-stn8815", PINCTRL_NMK_STN8815 }, { "pinctrl-db8500", PINCTRL_NMK_DB8500 }, { "pinctrl-db8540", PINCTRL_NMK_DB8540 }, + { } }; static struct platform_driver nmk_pinctrl_driver = { diff --git a/drivers/pinctrl/pinctrl-nomadik.h b/drivers/pinctrl/pinctrl-nomadik.h index eef316e979a..bcd4191e10e 100644 --- a/drivers/pinctrl/pinctrl-nomadik.h +++ b/drivers/pinctrl/pinctrl-nomadik.h @@ -1,7 +1,7 @@ #ifndef PINCTRL_PINCTRL_NOMADIK_H #define PINCTRL_PINCTRL_NOMADIK_H -#include <plat/gpio-nomadik.h> +#include <linux/platform_data/pinctrl-nomadik.h> /* Package definitions */ #define PINCTRL_NMK_STN8815 0 diff --git a/drivers/pinctrl/pinctrl-pxa168.c b/drivers/pinctrl/pinctrl-pxa168.c index c1997fa7f28..cb771e4a635 100644 --- a/drivers/pinctrl/pinctrl-pxa168.c +++ b/drivers/pinctrl/pinctrl-pxa168.c @@ -620,7 +620,7 @@ static int __devinit pxa168_pinmux_probe(struct platform_device *pdev) return pxa3xx_pinctrl_register(pdev, &pxa168_info); } -static int __devexit pxa168_pinmux_remove(struct platform_device *pdev) +static int pxa168_pinmux_remove(struct platform_device *pdev) { return pxa3xx_pinctrl_unregister(pdev); } @@ -631,7 +631,7 @@ static struct platform_driver pxa168_pinmux_driver = { .owner = THIS_MODULE, }, .probe = pxa168_pinmux_probe, - .remove = __devexit_p(pxa168_pinmux_remove), + .remove = pxa168_pinmux_remove, }; static int __init pxa168_pinmux_init(void) diff --git a/drivers/pinctrl/pinctrl-pxa3xx.c b/drivers/pinctrl/pinctrl-pxa3xx.c index f14cd6ba4c0..51f8a388b91 100644 --- a/drivers/pinctrl/pinctrl-pxa3xx.c +++ b/drivers/pinctrl/pinctrl-pxa3xx.c @@ -173,7 +173,6 @@ int pxa3xx_pinctrl_register(struct platform_device *pdev, { struct pinctrl_desc *desc; struct resource *res; - int ret = 0; if (!info || !info->cputype) return -EINVAL; @@ -188,23 +187,17 @@ int pxa3xx_pinctrl_register(struct platform_device *pdev, res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENOENT; - info->phy_base = res->start; - info->phy_size = resource_size(res); - info->virt_base = ioremap(info->phy_base, info->phy_size); + info->virt_base = devm_request_and_ioremap(&pdev->dev, res); if (!info->virt_base) return -ENOMEM; info->pctrl = pinctrl_register(desc, &pdev->dev, info); if (!info->pctrl) { dev_err(&pdev->dev, "failed to register PXA pinmux driver\n"); - ret = -EINVAL; - goto err; + return -EINVAL; } pinctrl_add_gpio_range(info->pctrl, &pxa3xx_pinctrl_gpio_range); platform_set_drvdata(pdev, info); return 0; -err: - iounmap(info->virt_base); - return ret; } int pxa3xx_pinctrl_unregister(struct platform_device *pdev) @@ -212,7 +205,6 @@ int pxa3xx_pinctrl_unregister(struct platform_device *pdev) struct pxa3xx_pinmux_info *info = platform_get_drvdata(pdev); pinctrl_unregister(info->pctrl); - iounmap(info->virt_base); platform_set_drvdata(pdev, NULL); return 0; } diff --git a/drivers/pinctrl/pinctrl-pxa3xx.h b/drivers/pinctrl/pinctrl-pxa3xx.h index 8135744d659..92fad088083 100644 --- a/drivers/pinctrl/pinctrl-pxa3xx.h +++ b/drivers/pinctrl/pinctrl-pxa3xx.h @@ -60,8 +60,6 @@ struct pxa3xx_pinmux_info { struct device *dev; struct pinctrl_dev *pctrl; enum pxa_cpu_type cputype; - unsigned int phy_base; - unsigned int phy_size; void __iomem *virt_base; struct pxa3xx_mfp_pin *mfp; diff --git a/drivers/pinctrl/pinctrl-pxa910.c b/drivers/pinctrl/pinctrl-pxa910.c index c72ab4b9cc8..5fecd221b83 100644 --- a/drivers/pinctrl/pinctrl-pxa910.c +++ b/drivers/pinctrl/pinctrl-pxa910.c @@ -976,7 +976,7 @@ static int __devinit pxa910_pinmux_probe(struct platform_device *pdev) return pxa3xx_pinctrl_register(pdev, &pxa910_info); } -static int __devexit pxa910_pinmux_remove(struct platform_device *pdev) +static int pxa910_pinmux_remove(struct platform_device *pdev) { return pxa3xx_pinctrl_unregister(pdev); } @@ -987,7 +987,7 @@ static struct platform_driver pxa910_pinmux_driver = { .owner = THIS_MODULE, }, .probe = pxa910_pinmux_probe, - .remove = __devexit_p(pxa910_pinmux_remove), + .remove = pxa910_pinmux_remove, }; static int __init pxa910_pinmux_init(void) diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 726a729a2ec..79642831bba 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -30,6 +30,7 @@ #define PCS_MUX_BITS_NAME "pinctrl-single,bits" #define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 1) #define PCS_OFF_DISABLED ~0U +#define PCS_MAX_GPIO_VALUES 2 /** * struct pcs_pingroup - pingroups for a function @@ -77,6 +78,16 @@ struct pcs_function { }; /** + * struct pcs_gpio_range - pinctrl gpio range + * @range: subrange of the GPIO number space + * @gpio_func: gpio function value in the pinmux register + */ +struct pcs_gpio_range { + struct pinctrl_gpio_range range; + int gpio_func; +}; + +/** * struct pcs_data - wrapper for data needed by pinctrl framework * @pa: pindesc array * @cur: index to current element @@ -244,15 +255,15 @@ static int pcs_get_group_pins(struct pinctrl_dev *pctldev, static void pcs_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, - unsigned offset) + unsigned pin) { struct pcs_device *pcs; - unsigned val; + unsigned val, mux_bytes; pcs = pinctrl_dev_get_drvdata(pctldev); - val = pcs->read(pcs->base + offset); - val &= pcs->fmask; + mux_bytes = pcs->width / BITS_PER_BYTE; + val = pcs->read(pcs->base + pin * mux_bytes); seq_printf(s, "%08x %s " , val, DRIVER_NAME); } @@ -403,9 +414,26 @@ static void pcs_disable(struct pinctrl_dev *pctldev, unsigned fselector, } static int pcs_request_gpio(struct pinctrl_dev *pctldev, - struct pinctrl_gpio_range *range, unsigned offset) + struct pinctrl_gpio_range *range, unsigned pin) { - return -ENOTSUPP; + struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev); + struct pcs_gpio_range *gpio = NULL; + int end, mux_bytes; + unsigned data; + + gpio = container_of(range, struct pcs_gpio_range, range); + end = range->pin_base + range->npins - 1; + if (pin < range->pin_base || pin > end) { + dev_err(pctldev->dev, + "pin %d isn't in the range of %d to %d\n", + pin, range->pin_base, end); + return -EINVAL; + } + mux_bytes = pcs->width / BITS_PER_BYTE; + data = pcs->read(pcs->base + pin * mux_bytes) & ~pcs->fmask; + data |= gpio->gpio_func; + pcs->write(data, pcs->base + pin * mux_bytes); + return 0; } static struct pinmux_ops pcs_pinmux_ops = { @@ -772,7 +800,7 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev, pcs = pinctrl_dev_get_drvdata(pctldev); *map = devm_kzalloc(pcs->dev, sizeof(**map), GFP_KERNEL); - if (!map) + if (!*map) return -ENOMEM; *num_maps = 0; @@ -879,6 +907,50 @@ static void pcs_free_resources(struct pcs_device *pcs) static struct of_device_id pcs_of_match[]; +static int __devinit pcs_add_gpio_range(struct device_node *node, + struct pcs_device *pcs) +{ + struct pcs_gpio_range *gpio; + struct device_node *child; + struct resource r; + const char name[] = "pinctrl-single"; + u32 gpiores[PCS_MAX_GPIO_VALUES]; + int ret, i = 0, mux_bytes = 0; + + for_each_child_of_node(node, child) { + ret = of_address_to_resource(child, 0, &r); + if (ret < 0) + continue; + memset(gpiores, 0, sizeof(u32) * PCS_MAX_GPIO_VALUES); + ret = of_property_read_u32_array(child, "pinctrl-single,gpio", + gpiores, PCS_MAX_GPIO_VALUES); + if (ret < 0) + continue; + gpio = devm_kzalloc(pcs->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) { + dev_err(pcs->dev, "failed to allocate pcs gpio\n"); + return -ENOMEM; + } + gpio->range.name = devm_kzalloc(pcs->dev, sizeof(name), + GFP_KERNEL); + if (!gpio->range.name) { + dev_err(pcs->dev, "failed to allocate range name\n"); + return -ENOMEM; + } + memcpy((char *)gpio->range.name, name, sizeof(name)); + + gpio->range.id = i++; + gpio->range.base = gpiores[0]; + gpio->gpio_func = gpiores[1]; + mux_bytes = pcs->width / BITS_PER_BYTE; + gpio->range.pin_base = (r.start - pcs->res->start) / mux_bytes; + gpio->range.npins = (r.end - r.start) / mux_bytes + 1; + + pinctrl_add_gpio_range(pcs->pctl, &gpio->range); + } + return 0; +} + static int __devinit pcs_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -975,6 +1047,10 @@ static int __devinit pcs_probe(struct platform_device *pdev) goto free; } + ret = pcs_add_gpio_range(np, pcs); + if (ret < 0) + goto free; + dev_info(pcs->dev, "%i pins at pa %p size %u\n", pcs->desc.npins, pcs->base, pcs->size); @@ -986,7 +1062,7 @@ free: return ret; } -static int __devexit pcs_remove(struct platform_device *pdev) +static int pcs_remove(struct platform_device *pdev) { struct pcs_device *pcs = platform_get_drvdata(pdev); @@ -998,7 +1074,7 @@ static int __devexit pcs_remove(struct platform_device *pdev) return 0; } -static struct of_device_id pcs_of_match[] __devinitdata = { +static struct of_device_id pcs_of_match[] = { { .compatible = DRIVER_NAME, }, { }, }; @@ -1006,7 +1082,7 @@ MODULE_DEVICE_TABLE(of, pcs_of_match); static struct platform_driver pcs_driver = { .probe = pcs_probe, - .remove = __devexit_p(pcs_remove), + .remove = pcs_remove, .driver = { .owner = THIS_MODULE, .name = DRIVER_NAME, diff --git a/drivers/pinctrl/pinctrl-sirf.c b/drivers/pinctrl/pinctrl-sirf.c index 9ecacf3d0a7..a4f0c5e487d 100644 --- a/drivers/pinctrl/pinctrl-sirf.c +++ b/drivers/pinctrl/pinctrl-sirf.c @@ -32,10 +32,10 @@ #define SIRFSOC_NUM_PADS 622 #define SIRFSOC_RSC_PIN_MUX 0x4 -#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84) +#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84) +#define SIRFSOC_GPIO_PAD_EN_CLR(g) ((g)*0x100 + 0x90) #define SIRFSOC_GPIO_CTRL(g, i) ((g)*0x100 + (i)*4) #define SIRFSOC_GPIO_DSP_EN0 (0x80) -#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84) #define SIRFSOC_GPIO_INT_STATUS(g) ((g)*0x100 + 0x8C) #define SIRFSOC_GPIO_CTL_INTR_LOW_MASK 0x1 @@ -60,6 +60,7 @@ struct sirfsoc_gpio_bank { int id; int parent_irq; spinlock_t lock; + bool is_marco; /* for marco, some registers are different with prima2 */ }; static struct sirfsoc_gpio_bank sgpio_bank[SIRFSOC_GPIO_NO_OF_BANKS]; @@ -191,6 +192,7 @@ struct sirfsoc_pmx { struct pinctrl_dev *pmx; void __iomem *gpio_virtbase; void __iomem *rsc_virtbase; + bool is_marco; }; /* SIRFSOC_GPIO_PAD_EN set */ @@ -1088,12 +1090,21 @@ static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, unsigned selector for (i = 0; i < mux->muxmask_counts; i++) { u32 muxval; - muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group)); - if (enable) - muxval = muxval & ~mask[i].mask; - else - muxval = muxval | mask[i].mask; - writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + if (!spmx->is_marco) { + muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + if (enable) + muxval = muxval & ~mask[i].mask; + else + muxval = muxval | mask[i].mask; + writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + } else { + if (enable) + writel(mask[i].mask, spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN_CLR(mask[i].group)); + else + writel(mask[i].mask, spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN(mask[i].group)); + } } if (mux->funcmask && enable) { @@ -1158,9 +1169,14 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev, spmx = pinctrl_dev_get_drvdata(pmxdev); - muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); - muxval = muxval | (1 << (offset - range->pin_base)); - writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); + if (!spmx->is_marco) { + muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); + muxval = muxval | (1 << (offset - range->pin_base)); + writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group)); + } else { + writel(1 << (offset - range->pin_base), spmx->gpio_virtbase + + SIRFSOC_GPIO_PAD_EN(group)); + } return 0; } @@ -1218,6 +1234,7 @@ static void __iomem *sirfsoc_rsc_of_iomap(void) { const struct of_device_id rsc_ids[] = { { .compatible = "sirf,prima2-rsc" }, + { .compatible = "sirf,marco-rsc" }, {} }; struct device_node *np; @@ -1259,6 +1276,9 @@ static int __devinit sirfsoc_pinmux_probe(struct platform_device *pdev) goto out_no_rsc_remap; } + if (of_device_is_compatible(np, "sirf,marco-pinctrl")) + spmx->is_marco = 1; + /* Now register the pin controller and all pins it handles */ spmx->pmx = pinctrl_register(&sirfsoc_pinmux_desc, &pdev->dev, spmx); if (!spmx->pmx) { @@ -1285,8 +1305,9 @@ out_no_gpio_remap: return ret; } -static const struct of_device_id pinmux_ids[] __devinitconst = { +static const struct of_device_id pinmux_ids[] = { { .compatible = "sirf,prima2-pinctrl" }, + { .compatible = "sirf,marco-pinctrl" }, {} }; @@ -1621,8 +1642,8 @@ static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset, spin_unlock_irqrestore(&bank->lock, flags); } -int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) +static int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) { struct sirfsoc_gpio_bank *bank = d->host_data; @@ -1648,6 +1669,7 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np) struct sirfsoc_gpio_bank *bank; void *regs; struct platform_device *pdev; + bool is_marco = false; pdev = of_find_device_by_node(np); if (!pdev) @@ -1657,6 +1679,9 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np) if (!regs) return -ENOMEM; + if (of_device_is_compatible(np, "sirf,marco-pinctrl")) + is_marco = 1; + for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) { bank = &sgpio_bank[i]; spin_lock_init(&bank->lock); @@ -1673,6 +1698,7 @@ static int __devinit sirfsoc_gpio_probe(struct device_node *np) bank->chip.gc.of_node = np; bank->chip.regs = regs; bank->id = i; + bank->is_marco = is_marco; bank->parent_irq = platform_get_irq(pdev, i); if (bank->parent_irq < 0) { err = bank->parent_irq; diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c index 7da0b371fd6..e356b0380fa 100644 --- a/drivers/pinctrl/pinctrl-tegra.c +++ b/drivers/pinctrl/pinctrl-tegra.c @@ -178,8 +178,9 @@ static int add_config(struct device *dev, unsigned long **configs, return 0; } -void tegra_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, - struct pinctrl_map *map, unsigned num_maps) +static void tegra_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, + unsigned num_maps) { int i; @@ -209,11 +210,11 @@ static const struct cfg_param { {"nvidia,slew-rate-rising", TEGRA_PINCONF_PARAM_SLEW_RATE_RISING}, }; -int tegra_pinctrl_dt_subnode_to_map(struct device *dev, - struct device_node *np, - struct pinctrl_map **map, - unsigned *reserved_maps, - unsigned *num_maps) +static int tegra_pinctrl_dt_subnode_to_map(struct device *dev, + struct device_node *np, + struct pinctrl_map **map, + unsigned *reserved_maps, + unsigned *num_maps) { int ret, i; const char *function; @@ -288,9 +289,10 @@ exit: return ret; } -int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, - struct device_node *np_config, - struct pinctrl_map **map, unsigned *num_maps) +static int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, + unsigned *num_maps) { unsigned reserved_maps; struct device_node *np; @@ -660,7 +662,7 @@ static void tegra_pinconf_config_dbg_show(struct pinctrl_dev *pctldev, } #endif -struct pinconf_ops tegra_pinconf_ops = { +static struct pinconf_ops tegra_pinconf_ops = { .pin_config_get = tegra_pinconf_get, .pin_config_set = tegra_pinconf_set, .pin_config_group_get = tegra_pinconf_group_get, @@ -758,7 +760,7 @@ int __devinit tegra_pinctrl_probe(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(tegra_pinctrl_probe); -int __devexit tegra_pinctrl_remove(struct platform_device *pdev) +int tegra_pinctrl_remove(struct platform_device *pdev) { struct tegra_pmx *pmx = platform_get_drvdata(pdev); diff --git a/drivers/pinctrl/pinctrl-tegra20.c b/drivers/pinctrl/pinctrl-tegra20.c index a74f9a56853..1524bfd6660 100644 --- a/drivers/pinctrl/pinctrl-tegra20.c +++ b/drivers/pinctrl/pinctrl-tegra20.c @@ -2861,7 +2861,7 @@ static int __devinit tegra20_pinctrl_probe(struct platform_device *pdev) return tegra_pinctrl_probe(pdev, &tegra20_pinctrl); } -static struct of_device_id tegra20_pinctrl_of_match[] __devinitdata = { +static struct of_device_id tegra20_pinctrl_of_match[] = { { .compatible = "nvidia,tegra20-pinmux", }, { }, }; @@ -2873,7 +2873,7 @@ static struct platform_driver tegra20_pinctrl_driver = { .of_match_table = tegra20_pinctrl_of_match, }, .probe = tegra20_pinctrl_probe, - .remove = __devexit_p(tegra_pinctrl_remove), + .remove = tegra_pinctrl_remove, }; static int __init tegra20_pinctrl_init(void) diff --git a/drivers/pinctrl/pinctrl-tegra30.c b/drivers/pinctrl/pinctrl-tegra30.c index 7894f14c705..cf579ebf346 100644 --- a/drivers/pinctrl/pinctrl-tegra30.c +++ b/drivers/pinctrl/pinctrl-tegra30.c @@ -3727,7 +3727,7 @@ static int __devinit tegra30_pinctrl_probe(struct platform_device *pdev) return tegra_pinctrl_probe(pdev, &tegra30_pinctrl); } -static struct of_device_id tegra30_pinctrl_of_match[] __devinitdata = { +static struct of_device_id tegra30_pinctrl_of_match[] = { { .compatible = "nvidia,tegra30-pinmux", }, { }, }; @@ -3739,7 +3739,7 @@ static struct platform_driver tegra30_pinctrl_driver = { .of_match_table = tegra30_pinctrl_of_match, }, .probe = tegra30_pinctrl_probe, - .remove = __devexit_p(tegra_pinctrl_remove), + .remove = tegra_pinctrl_remove, }; static int __init tegra30_pinctrl_init(void) diff --git a/drivers/pinctrl/pinctrl-u300.c b/drivers/pinctrl/pinctrl-u300.c index 309f5b9a70e..8c039ad22ba 100644 --- a/drivers/pinctrl/pinctrl-u300.c +++ b/drivers/pinctrl/pinctrl-u300.c @@ -663,8 +663,6 @@ static const struct pinctrl_pin_desc u300_pads[] = { struct u300_pmx { struct device *dev; struct pinctrl_dev *pctl; - u32 phybase; - u32 physize; void __iomem *virtbase; }; @@ -1013,52 +1011,11 @@ static struct pinmux_ops u300_pmx_ops = { .disable = u300_pmx_disable, }; -/* - * GPIO ranges handled by the application-side COH901XXX GPIO controller - * Very many pins can be converted into GPIO pins, but we only list those - * that are useful in practice to cut down on tables. - */ -#define U300_GPIO_RANGE(a, b, c) { .name = "COH901XXX", .id = a, .base= a, \ - .pin_base = b, .npins = c } - -static struct pinctrl_gpio_range u300_gpio_ranges[] = { - U300_GPIO_RANGE(10, 426, 1), - U300_GPIO_RANGE(11, 180, 1), - U300_GPIO_RANGE(12, 165, 1), /* MS/MMC card insertion */ - U300_GPIO_RANGE(13, 179, 1), - U300_GPIO_RANGE(14, 178, 1), - U300_GPIO_RANGE(16, 194, 1), - U300_GPIO_RANGE(17, 193, 1), - U300_GPIO_RANGE(18, 192, 1), - U300_GPIO_RANGE(19, 191, 1), - U300_GPIO_RANGE(20, 186, 1), - U300_GPIO_RANGE(21, 185, 1), - U300_GPIO_RANGE(22, 184, 1), - U300_GPIO_RANGE(23, 183, 1), - U300_GPIO_RANGE(24, 182, 1), - U300_GPIO_RANGE(25, 181, 1), -}; - -static struct pinctrl_gpio_range *u300_match_gpio_range(unsigned pin) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++) { - struct pinctrl_gpio_range *range; - - range = &u300_gpio_ranges[i]; - if (pin >= range->pin_base && - pin <= (range->pin_base + range->npins - 1)) - return range; - } - return NULL; -} - -int u300_pin_config_get(struct pinctrl_dev *pctldev, - unsigned pin, - unsigned long *config) +static int u300_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin, + unsigned long *config) { - struct pinctrl_gpio_range *range = u300_match_gpio_range(pin); + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(pctldev, pin); /* We get config for those pins we CAN get it for and that's it */ if (!range) @@ -1069,11 +1026,11 @@ int u300_pin_config_get(struct pinctrl_dev *pctldev, config); } -int u300_pin_config_set(struct pinctrl_dev *pctldev, - unsigned pin, - unsigned long config) +static int u300_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, + unsigned long config) { - struct pinctrl_gpio_range *range = u300_match_gpio_range(pin); + struct pinctrl_gpio_range *range = + pinctrl_find_gpio_range_from_pin(pctldev, pin); int ret; if (!range) @@ -1109,9 +1066,6 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev) { struct u300_pmx *upmx; struct resource *res; - struct gpio_chip *gpio_chip = dev_get_platdata(&pdev->dev); - int ret; - int i; /* Create state holders etc for this driver */ upmx = devm_kzalloc(&pdev->dev, sizeof(*upmx), GFP_KERNEL); @@ -1123,32 +1077,15 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENOENT; - upmx->phybase = res->start; - upmx->physize = resource_size(res); - - if (request_mem_region(upmx->phybase, upmx->physize, - DRIVER_NAME) == NULL) { - ret = -ENOMEM; - goto out_no_memregion; - } - upmx->virtbase = ioremap(upmx->phybase, upmx->physize); - if (!upmx->virtbase) { - ret = -ENOMEM; - goto out_no_remap; - } + upmx->virtbase = devm_request_and_ioremap(&pdev->dev, res); + if (!upmx->virtbase) + return -ENOMEM; upmx->pctl = pinctrl_register(&u300_pmx_desc, &pdev->dev, upmx); if (!upmx->pctl) { dev_err(&pdev->dev, "could not register U300 pinmux driver\n"); - ret = -EINVAL; - goto out_no_pmx; - } - - /* We will handle a range of GPIO pins */ - for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++) { - u300_gpio_ranges[i].gc = gpio_chip; - pinctrl_add_gpio_range(upmx->pctl, &u300_gpio_ranges[i]); + return -EINVAL; } platform_set_drvdata(pdev, upmx); @@ -1156,23 +1093,13 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev) dev_info(&pdev->dev, "initialized U300 pin control driver\n"); return 0; - -out_no_pmx: - iounmap(upmx->virtbase); -out_no_remap: - platform_set_drvdata(pdev, NULL); -out_no_memregion: - release_mem_region(upmx->phybase, upmx->physize); - return ret; } -static int __devexit u300_pmx_remove(struct platform_device *pdev) +static int u300_pmx_remove(struct platform_device *pdev) { struct u300_pmx *upmx = platform_get_drvdata(pdev); pinctrl_unregister(upmx->pctl); - iounmap(upmx->virtbase); - release_mem_region(upmx->phybase, upmx->physize); platform_set_drvdata(pdev, NULL); return 0; @@ -1184,7 +1111,7 @@ static struct platform_driver u300_pmx_driver = { .owner = THIS_MODULE, }, .probe = u300_pmx_probe, - .remove = __devexit_p(u300_pmx_remove), + .remove = u300_pmx_remove, }; static int __init u300_pmx_init(void) diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c index b9bcaec6622..ad90984ec50 100644 --- a/drivers/pinctrl/pinctrl-xway.c +++ b/drivers/pinctrl/pinctrl-xway.c @@ -522,7 +522,7 @@ static int xway_pinconf_set(struct pinctrl_dev *pctldev, return 0; } -struct pinconf_ops xway_pinconf_ops = { +static struct pinconf_ops xway_pinconf_ops = { .pin_config_get = xway_pinconf_get, .pin_config_set = xway_pinconf_set, }; diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index 9301a7a95ef..1a00658b3ea 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -314,14 +314,11 @@ int pinmux_map_to_setting(struct pinctrl_map const *map, { struct pinctrl_dev *pctldev = setting->pctldev; const struct pinmux_ops *pmxops = pctldev->desc->pmxops; - const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; char const * const *groups; unsigned num_groups; int ret; const char *group; int i; - const unsigned *pins; - unsigned num_pins; if (!pmxops) { dev_err(pctldev->dev, "does not support mux function\n"); @@ -376,53 +373,12 @@ int pinmux_map_to_setting(struct pinctrl_map const *map, } setting->data.mux.group = ret; - ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, &pins, - &num_pins); - if (ret) { - dev_err(pctldev->dev, - "could not get pins for device %s group selector %d\n", - pinctrl_dev_get_name(pctldev), setting->data.mux.group); - return -ENODEV; - } - - /* Try to allocate all pins in this group, one by one */ - for (i = 0; i < num_pins; i++) { - ret = pin_request(pctldev, pins[i], map->dev_name, NULL); - if (ret) { - dev_err(pctldev->dev, - "could not request pin %d on device %s\n", - pins[i], pinctrl_dev_get_name(pctldev)); - /* On error release all taken pins */ - i--; /* this pin just failed */ - for (; i >= 0; i--) - pin_free(pctldev, pins[i], NULL); - return -ENODEV; - } - } - return 0; } void pinmux_free_setting(struct pinctrl_setting const *setting) { - struct pinctrl_dev *pctldev = setting->pctldev; - const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; - const unsigned *pins; - unsigned num_pins; - int ret; - int i; - - ret = pctlops->get_group_pins(pctldev, setting->data.mux.group, - &pins, &num_pins); - if (ret) { - dev_err(pctldev->dev, - "could not get pins for device %s group selector %d\n", - pinctrl_dev_get_name(pctldev), setting->data.mux.group); - return; - } - - for (i = 0; i < num_pins; i++) - pin_free(pctldev, pins[i], NULL); + /* This function is currently unused */ } int pinmux_enable_setting(struct pinctrl_setting const *setting) @@ -446,6 +402,18 @@ int pinmux_enable_setting(struct pinctrl_setting const *setting) num_pins = 0; } + /* Try to allocate all pins in this group, one by one */ + for (i = 0; i < num_pins; i++) { + ret = pin_request(pctldev, pins[i], setting->dev_name, NULL); + if (ret) { + dev_err(pctldev->dev, + "could not request pin %d on device %s\n", + pins[i], pinctrl_dev_get_name(pctldev)); + goto err_pin_request; + } + } + + /* Now that we have acquired the pins, encode the mux setting */ for (i = 0; i < num_pins; i++) { desc = pin_desc_get(pctldev, pins[i]); if (desc == NULL) { @@ -457,8 +425,26 @@ int pinmux_enable_setting(struct pinctrl_setting const *setting) desc->mux_setting = &(setting->data.mux); } - return ops->enable(pctldev, setting->data.mux.func, - setting->data.mux.group); + ret = ops->enable(pctldev, setting->data.mux.func, + setting->data.mux.group); + + if (ret) + goto err_enable; + + return 0; + +err_enable: + for (i = 0; i < num_pins; i++) { + desc = pin_desc_get(pctldev, pins[i]); + if (desc) + desc->mux_setting = NULL; + } +err_pin_request: + /* On error release all taken pins */ + while (--i >= 0) + pin_free(pctldev, pins[i], NULL); + + return ret; } void pinmux_disable_setting(struct pinctrl_setting const *setting) @@ -482,6 +468,7 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting) num_pins = 0; } + /* Flag the descs that no setting is active */ for (i = 0; i < num_pins; i++) { desc = pin_desc_get(pctldev, pins[i]); if (desc == NULL) { @@ -493,6 +480,10 @@ void pinmux_disable_setting(struct pinctrl_setting const *setting) desc->mux_setting = NULL; } + /* And release the pins */ + for (i = 0; i < num_pins; i++) + pin_free(pctldev, pins[i], NULL); + if (ops->disable) ops->disable(pctldev, setting->data.mux.func, setting->data.mux.group); } diff --git a/drivers/pinctrl/spear/Kconfig b/drivers/pinctrl/spear/Kconfig index 91558791e76..04d93e60267 100644 --- a/drivers/pinctrl/spear/Kconfig +++ b/drivers/pinctrl/spear/Kconfig @@ -25,20 +25,31 @@ config PINCTRL_SPEAR310 bool "ST Microelectronics SPEAr310 SoC pin controller driver" depends on MACH_SPEAR310 select PINCTRL_SPEAR3XX + select PINCTRL_SPEAR_PLGPIO config PINCTRL_SPEAR320 bool "ST Microelectronics SPEAr320 SoC pin controller driver" depends on MACH_SPEAR320 select PINCTRL_SPEAR3XX + select PINCTRL_SPEAR_PLGPIO config PINCTRL_SPEAR1310 bool "ST Microelectronics SPEAr1310 SoC pin controller driver" depends on MACH_SPEAR1310 select PINCTRL_SPEAR + select PINCTRL_SPEAR_PLGPIO config PINCTRL_SPEAR1340 bool "ST Microelectronics SPEAr1340 SoC pin controller driver" depends on MACH_SPEAR1340 select PINCTRL_SPEAR + select PINCTRL_SPEAR_PLGPIO + +config PINCTRL_SPEAR_PLGPIO + bool "SPEAr SoC PLGPIO Controller" + depends on GPIOLIB && PINCTRL_SPEAR + help + Say yes here to support PLGPIO controller on ST Microelectronics SPEAr + SoCs. endif diff --git a/drivers/pinctrl/spear/Makefile b/drivers/pinctrl/spear/Makefile index b28a7ba2244..0e400ebeb8f 100644 --- a/drivers/pinctrl/spear/Makefile +++ b/drivers/pinctrl/spear/Makefile @@ -1,5 +1,6 @@ # SPEAr pinmux support +obj-$(CONFIG_PINCTRL_SPEAR_PLGPIO) += pinctrl-plgpio.o obj-$(CONFIG_PINCTRL_SPEAR) += pinctrl-spear.o obj-$(CONFIG_PINCTRL_SPEAR3XX) += pinctrl-spear3xx.o obj-$(CONFIG_PINCTRL_SPEAR300) += pinctrl-spear300.o diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c new file mode 100644 index 00000000000..4c045053bbd --- /dev/null +++ b/drivers/pinctrl/spear/pinctrl-plgpio.c @@ -0,0 +1,758 @@ +/* + * SPEAr platform PLGPIO driver + * + * Copyright (C) 2012 ST Microelectronics + * Viresh Kumar <viresh.kumar@linaro.org> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/module.h> +#include <linux/pinctrl/consumer.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/spinlock.h> +#include <asm/mach/irq.h> + +#define MAX_GPIO_PER_REG 32 +#define PIN_OFFSET(pin) (pin % MAX_GPIO_PER_REG) +#define REG_OFFSET(base, reg, pin) (base + reg + (pin / MAX_GPIO_PER_REG) \ + * sizeof(int *)) + +/* + * plgpio pins in all machines are not one to one mapped, bitwise with registers + * bits. These set of macros define register masks for which below functions + * (pin_to_offset and offset_to_pin) are required to be called. + */ +#define PTO_ENB_REG 0x001 +#define PTO_WDATA_REG 0x002 +#define PTO_DIR_REG 0x004 +#define PTO_IE_REG 0x008 +#define PTO_RDATA_REG 0x010 +#define PTO_MIS_REG 0x020 + +struct plgpio_regs { + u32 enb; /* enable register */ + u32 wdata; /* write data register */ + u32 dir; /* direction set register */ + u32 rdata; /* read data register */ + u32 ie; /* interrupt enable register */ + u32 mis; /* mask interrupt status register */ + u32 eit; /* edge interrupt type */ +}; + +/* + * struct plgpio: plgpio driver specific structure + * + * lock: lock for guarding gpio registers + * base: base address of plgpio block + * irq_base: irq number of plgpio0 + * chip: gpio framework specific chip information structure + * p2o: function ptr for pin to offset conversion. This is required only for + * machines where mapping b/w pin and offset is not 1-to-1. + * o2p: function ptr for offset to pin conversion. This is required only for + * machines where mapping b/w pin and offset is not 1-to-1. + * p2o_regs: mask of registers for which p2o and o2p are applicable + * regs: register offsets + * csave_regs: context save registers for standby/sleep/hibernate cases + */ +struct plgpio { + spinlock_t lock; + void __iomem *base; + struct clk *clk; + unsigned irq_base; + struct irq_domain *irq_domain; + struct gpio_chip chip; + int (*p2o)(int pin); /* pin_to_offset */ + int (*o2p)(int offset); /* offset_to_pin */ + u32 p2o_regs; + struct plgpio_regs regs; +#ifdef CONFIG_PM + struct plgpio_regs *csave_regs; +#endif +}; + +/* register manipulation inline functions */ +static inline u32 is_plgpio_set(void __iomem *base, u32 pin, u32 reg) +{ + u32 offset = PIN_OFFSET(pin); + void __iomem *reg_off = REG_OFFSET(base, reg, pin); + u32 val = readl_relaxed(reg_off); + + return !!(val & (1 << offset)); +} + +static inline void plgpio_reg_set(void __iomem *base, u32 pin, u32 reg) +{ + u32 offset = PIN_OFFSET(pin); + void __iomem *reg_off = REG_OFFSET(base, reg, pin); + u32 val = readl_relaxed(reg_off); + + writel_relaxed(val | (1 << offset), reg_off); +} + +static inline void plgpio_reg_reset(void __iomem *base, u32 pin, u32 reg) +{ + u32 offset = PIN_OFFSET(pin); + void __iomem *reg_off = REG_OFFSET(base, reg, pin); + u32 val = readl_relaxed(reg_off); + + writel_relaxed(val & ~(1 << offset), reg_off); +} + +/* gpio framework specific routines */ +static int plgpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + unsigned long flags; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_DIR_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return -EINVAL; + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_set(plgpio->base, offset, plgpio->regs.dir); + spin_unlock_irqrestore(&plgpio->lock, flags); + + return 0; +} + +static int plgpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + unsigned long flags; + unsigned dir_offset = offset, wdata_offset = offset, tmp; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & (PTO_DIR_REG | PTO_WDATA_REG))) { + tmp = plgpio->p2o(offset); + if (tmp == -1) + return -EINVAL; + + if (plgpio->p2o_regs & PTO_DIR_REG) + dir_offset = tmp; + if (plgpio->p2o_regs & PTO_WDATA_REG) + wdata_offset = tmp; + } + + spin_lock_irqsave(&plgpio->lock, flags); + if (value) + plgpio_reg_set(plgpio->base, wdata_offset, + plgpio->regs.wdata); + else + plgpio_reg_reset(plgpio->base, wdata_offset, + plgpio->regs.wdata); + + plgpio_reg_reset(plgpio->base, dir_offset, plgpio->regs.dir); + spin_unlock_irqrestore(&plgpio->lock, flags); + + return 0; +} + +static int plgpio_get_value(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + + if (offset >= chip->ngpio) + return -EINVAL; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_RDATA_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return -EINVAL; + } + + return is_plgpio_set(plgpio->base, offset, plgpio->regs.rdata); +} + +static void plgpio_set_value(struct gpio_chip *chip, unsigned offset, int value) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + + if (offset >= chip->ngpio) + return; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_WDATA_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return; + } + + if (value) + plgpio_reg_set(plgpio->base, offset, plgpio->regs.wdata); + else + plgpio_reg_reset(plgpio->base, offset, plgpio->regs.wdata); +} + +static int plgpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + int gpio = chip->base + offset; + unsigned long flags; + int ret = 0; + + if (offset >= chip->ngpio) + return -EINVAL; + + ret = pinctrl_request_gpio(gpio); + if (ret) + return ret; + + if (!IS_ERR(plgpio->clk)) { + ret = clk_enable(plgpio->clk); + if (ret) + goto err0; + } + + if (plgpio->regs.enb == -1) + return 0; + + /* + * put gpio in IN mode before enabling it. This make enabling gpio safe + */ + ret = plgpio_direction_input(chip, offset); + if (ret) + goto err1; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_ENB_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) { + ret = -EINVAL; + goto err1; + } + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_set(plgpio->base, offset, plgpio->regs.enb); + spin_unlock_irqrestore(&plgpio->lock, flags); + return 0; + +err1: + if (!IS_ERR(plgpio->clk)) + clk_disable(plgpio->clk); +err0: + pinctrl_free_gpio(gpio); + return ret; +} + +static void plgpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + int gpio = chip->base + offset; + unsigned long flags; + + if (offset >= chip->ngpio) + return; + + if (plgpio->regs.enb == -1) + goto disable_clk; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_ENB_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return; + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_reset(plgpio->base, offset, plgpio->regs.enb); + spin_unlock_irqrestore(&plgpio->lock, flags); + +disable_clk: + if (!IS_ERR(plgpio->clk)) + clk_disable(plgpio->clk); + + pinctrl_free_gpio(gpio); +} + +static int plgpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct plgpio *plgpio = container_of(chip, struct plgpio, chip); + + if (IS_ERR_VALUE(plgpio->irq_base)) + return -EINVAL; + + return irq_find_mapping(plgpio->irq_domain, offset); +} + +/* PLGPIO IRQ */ +static void plgpio_irq_disable(struct irq_data *d) +{ + struct plgpio *plgpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - plgpio->irq_base; + unsigned long flags; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_IE_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return; + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_set(plgpio->base, offset, plgpio->regs.ie); + spin_unlock_irqrestore(&plgpio->lock, flags); +} + +static void plgpio_irq_enable(struct irq_data *d) +{ + struct plgpio *plgpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - plgpio->irq_base; + unsigned long flags; + + /* get correct offset for "offset" pin */ + if (plgpio->p2o && (plgpio->p2o_regs & PTO_IE_REG)) { + offset = plgpio->p2o(offset); + if (offset == -1) + return; + } + + spin_lock_irqsave(&plgpio->lock, flags); + plgpio_reg_reset(plgpio->base, offset, plgpio->regs.ie); + spin_unlock_irqrestore(&plgpio->lock, flags); +} + +static int plgpio_irq_set_type(struct irq_data *d, unsigned trigger) +{ + struct plgpio *plgpio = irq_data_get_irq_chip_data(d); + int offset = d->irq - plgpio->irq_base; + void __iomem *reg_off; + unsigned int supported_type = 0, val; + + if (offset >= plgpio->chip.ngpio) + return -EINVAL; + + if (plgpio->regs.eit == -1) + supported_type = IRQ_TYPE_LEVEL_HIGH; + else + supported_type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; + + if (!(trigger & supported_type)) + return -EINVAL; + + if (plgpio->regs.eit == -1) + return 0; + + reg_off = REG_OFFSET(plgpio->base, plgpio->regs.eit, offset); + val = readl_relaxed(reg_off); + + offset = PIN_OFFSET(offset); + if (trigger & IRQ_TYPE_EDGE_RISING) + writel_relaxed(val | (1 << offset), reg_off); + else + writel_relaxed(val & ~(1 << offset), reg_off); + + return 0; +} + +static struct irq_chip plgpio_irqchip = { + .name = "PLGPIO", + .irq_enable = plgpio_irq_enable, + .irq_disable = plgpio_irq_disable, + .irq_set_type = plgpio_irq_set_type, +}; + +static void plgpio_irq_handler(unsigned irq, struct irq_desc *desc) +{ + struct plgpio *plgpio = irq_get_handler_data(irq); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + int regs_count, count, pin, offset, i = 0; + unsigned long pending; + + count = plgpio->chip.ngpio; + regs_count = DIV_ROUND_UP(count, MAX_GPIO_PER_REG); + + chained_irq_enter(irqchip, desc); + /* check all plgpio MIS registers for a possible interrupt */ + for (; i < regs_count; i++) { + pending = readl_relaxed(plgpio->base + plgpio->regs.mis + + i * sizeof(int *)); + if (!pending) + continue; + + /* clear interrupts */ + writel_relaxed(~pending, plgpio->base + plgpio->regs.mis + + i * sizeof(int *)); + /* + * clear extra bits in last register having gpios < MAX/REG + * ex: Suppose there are max 102 plgpios. then last register + * must have only (102 - MAX_GPIO_PER_REG * 3) = 6 relevant bits + * so, we must not take other 28 bits into consideration for + * checking interrupt. so clear those bits. + */ + count = count - i * MAX_GPIO_PER_REG; + if (count < MAX_GPIO_PER_REG) + pending &= (1 << count) - 1; + + for_each_set_bit(offset, &pending, MAX_GPIO_PER_REG) { + /* get correct pin for "offset" */ + if (plgpio->o2p && (plgpio->p2o_regs & PTO_MIS_REG)) { + pin = plgpio->o2p(offset); + if (pin == -1) + continue; + } else + pin = offset; + + /* get correct irq line number */ + pin = i * MAX_GPIO_PER_REG + pin; + generic_handle_irq(plgpio_to_irq(&plgpio->chip, pin)); + } + } + chained_irq_exit(irqchip, desc); +} + +/* + * pin to offset and offset to pin converter functions + * + * In spear310 there is inconsistency among bit positions in plgpio regiseters, + * for different plgpio pins. For example: for pin 27, bit offset is 23, pin + * 28-33 are not supported, pin 95 has offset bit 95, bit 100 has offset bit 1 + */ +static int spear310_p2o(int pin) +{ + int offset = pin; + + if (pin <= 27) + offset += 4; + else if (pin <= 33) + offset = -1; + else if (pin <= 97) + offset -= 2; + else if (pin <= 101) + offset = 101 - pin; + else + offset = -1; + + return offset; +} + +int spear310_o2p(int offset) +{ + if (offset <= 3) + return 101 - offset; + else if (offset <= 31) + return offset - 4; + else + return offset + 2; +} + +static int __devinit plgpio_probe_dt(struct platform_device *pdev, + struct plgpio *plgpio) +{ + struct device_node *np = pdev->dev.of_node; + int ret = -EINVAL; + u32 val; + + if (of_machine_is_compatible("st,spear310")) { + plgpio->p2o = spear310_p2o; + plgpio->o2p = spear310_o2p; + plgpio->p2o_regs = PTO_WDATA_REG | PTO_DIR_REG | PTO_IE_REG | + PTO_RDATA_REG | PTO_MIS_REG; + } + + if (!of_property_read_u32(np, "st-plgpio,ngpio", &val)) { + plgpio->chip.ngpio = val; + } else { + dev_err(&pdev->dev, "DT: Invalid ngpio field\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,enb-reg", &val)) + plgpio->regs.enb = val; + else + plgpio->regs.enb = -1; + + if (!of_property_read_u32(np, "st-plgpio,wdata-reg", &val)) { + plgpio->regs.wdata = val; + } else { + dev_err(&pdev->dev, "DT: Invalid wdata reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,dir-reg", &val)) { + plgpio->regs.dir = val; + } else { + dev_err(&pdev->dev, "DT: Invalid dir reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,ie-reg", &val)) { + plgpio->regs.ie = val; + } else { + dev_err(&pdev->dev, "DT: Invalid ie reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,rdata-reg", &val)) { + plgpio->regs.rdata = val; + } else { + dev_err(&pdev->dev, "DT: Invalid rdata reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,mis-reg", &val)) { + plgpio->regs.mis = val; + } else { + dev_err(&pdev->dev, "DT: Invalid mis reg\n"); + goto end; + } + + if (!of_property_read_u32(np, "st-plgpio,eit-reg", &val)) + plgpio->regs.eit = val; + else + plgpio->regs.eit = -1; + + return 0; + +end: + return ret; +} +static int __devinit plgpio_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct plgpio *plgpio; + struct resource *res; + int ret, irq, i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "invalid IORESOURCE_MEM\n"); + return -EBUSY; + } + + plgpio = devm_kzalloc(&pdev->dev, sizeof(*plgpio), GFP_KERNEL); + if (!plgpio) { + dev_err(&pdev->dev, "memory allocation fail\n"); + return -ENOMEM; + } + + plgpio->base = devm_request_and_ioremap(&pdev->dev, res); + if (!plgpio->base) { + dev_err(&pdev->dev, "request and ioremap fail\n"); + return -ENOMEM; + } + + ret = plgpio_probe_dt(pdev, plgpio); + if (ret) { + dev_err(&pdev->dev, "DT probe failed\n"); + return ret; + } + + plgpio->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(plgpio->clk)) + dev_warn(&pdev->dev, "clk_get() failed, work without it\n"); + +#ifdef CONFIG_PM + plgpio->csave_regs = devm_kzalloc(&pdev->dev, + sizeof(*plgpio->csave_regs) * + DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG), + GFP_KERNEL); + if (!plgpio->csave_regs) { + dev_err(&pdev->dev, "csave registers memory allocation fail\n"); + return -ENOMEM; + } +#endif + + platform_set_drvdata(pdev, plgpio); + spin_lock_init(&plgpio->lock); + + plgpio->irq_base = -1; + plgpio->chip.base = -1; + plgpio->chip.request = plgpio_request; + plgpio->chip.free = plgpio_free; + plgpio->chip.direction_input = plgpio_direction_input; + plgpio->chip.direction_output = plgpio_direction_output; + plgpio->chip.get = plgpio_get_value; + plgpio->chip.set = plgpio_set_value; + plgpio->chip.to_irq = plgpio_to_irq; + plgpio->chip.label = dev_name(&pdev->dev); + plgpio->chip.dev = &pdev->dev; + plgpio->chip.owner = THIS_MODULE; + + if (!IS_ERR(plgpio->clk)) { + ret = clk_prepare(plgpio->clk); + if (ret) { + dev_err(&pdev->dev, "clk prepare failed\n"); + return ret; + } + } + + ret = gpiochip_add(&plgpio->chip); + if (ret) { + dev_err(&pdev->dev, "unable to add gpio chip\n"); + goto unprepare_clk; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_info(&pdev->dev, "irqs not supported\n"); + return 0; + } + + plgpio->irq_base = irq_alloc_descs(-1, 0, plgpio->chip.ngpio, 0); + if (IS_ERR_VALUE(plgpio->irq_base)) { + /* we would not support irq for gpio */ + dev_warn(&pdev->dev, "couldn't allocate irq base\n"); + return 0; + } + + plgpio->irq_domain = irq_domain_add_legacy(np, plgpio->chip.ngpio, + plgpio->irq_base, 0, &irq_domain_simple_ops, NULL); + if (WARN_ON(!plgpio->irq_domain)) { + dev_err(&pdev->dev, "irq domain init failed\n"); + irq_free_descs(plgpio->irq_base, plgpio->chip.ngpio); + ret = -ENXIO; + goto remove_gpiochip; + } + + irq_set_chained_handler(irq, plgpio_irq_handler); + for (i = 0; i < plgpio->chip.ngpio; i++) { + irq_set_chip_and_handler(i + plgpio->irq_base, &plgpio_irqchip, + handle_simple_irq); + set_irq_flags(i + plgpio->irq_base, IRQF_VALID); + irq_set_chip_data(i + plgpio->irq_base, plgpio); + } + + irq_set_handler_data(irq, plgpio); + dev_info(&pdev->dev, "PLGPIO registered with IRQs\n"); + + return 0; + +remove_gpiochip: + dev_info(&pdev->dev, "Remove gpiochip\n"); + if (gpiochip_remove(&plgpio->chip)) + dev_err(&pdev->dev, "unable to remove gpiochip\n"); +unprepare_clk: + if (!IS_ERR(plgpio->clk)) + clk_unprepare(plgpio->clk); + + return ret; +} + +#ifdef CONFIG_PM +static int plgpio_suspend(struct device *dev) +{ + struct plgpio *plgpio = dev_get_drvdata(dev); + int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG); + void __iomem *off; + + for (i = 0; i < reg_count; i++) { + off = plgpio->base + i * sizeof(int *); + + if (plgpio->regs.enb != -1) + plgpio->csave_regs[i].enb = + readl_relaxed(plgpio->regs.enb + off); + if (plgpio->regs.eit != -1) + plgpio->csave_regs[i].eit = + readl_relaxed(plgpio->regs.eit + off); + plgpio->csave_regs[i].wdata = readl_relaxed(plgpio->regs.wdata + + off); + plgpio->csave_regs[i].dir = readl_relaxed(plgpio->regs.dir + + off); + plgpio->csave_regs[i].ie = readl_relaxed(plgpio->regs.ie + off); + } + + return 0; +} + +/* + * This is used to correct the values in end registers. End registers contain + * extra bits that might be used for other purpose in platform. So, we shouldn't + * overwrite these bits. This macro, reads given register again, preserves other + * bit values (non-plgpio bits), and retain captured value (plgpio bits). + */ +#define plgpio_prepare_reg(__reg, _off, _mask, _tmp) \ +{ \ + _tmp = readl_relaxed(plgpio->regs.__reg + _off); \ + _tmp &= ~_mask; \ + plgpio->csave_regs[i].__reg = \ + _tmp | (plgpio->csave_regs[i].__reg & _mask); \ +} + +static int plgpio_resume(struct device *dev) +{ + struct plgpio *plgpio = dev_get_drvdata(dev); + int i, reg_count = DIV_ROUND_UP(plgpio->chip.ngpio, MAX_GPIO_PER_REG); + void __iomem *off; + u32 mask, tmp; + + for (i = 0; i < reg_count; i++) { + off = plgpio->base + i * sizeof(int *); + + if (i == reg_count - 1) { + mask = (1 << (plgpio->chip.ngpio - i * + MAX_GPIO_PER_REG)) - 1; + + if (plgpio->regs.enb != -1) + plgpio_prepare_reg(enb, off, mask, tmp); + + if (plgpio->regs.eit != -1) + plgpio_prepare_reg(eit, off, mask, tmp); + + plgpio_prepare_reg(wdata, off, mask, tmp); + plgpio_prepare_reg(dir, off, mask, tmp); + plgpio_prepare_reg(ie, off, mask, tmp); + } + + writel_relaxed(plgpio->csave_regs[i].wdata, plgpio->regs.wdata + + off); + writel_relaxed(plgpio->csave_regs[i].dir, plgpio->regs.dir + + off); + + if (plgpio->regs.eit != -1) + writel_relaxed(plgpio->csave_regs[i].eit, + plgpio->regs.eit + off); + + writel_relaxed(plgpio->csave_regs[i].ie, plgpio->regs.ie + off); + + if (plgpio->regs.enb != -1) + writel_relaxed(plgpio->csave_regs[i].enb, + plgpio->regs.enb + off); + } + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(plgpio_dev_pm_ops, plgpio_suspend, plgpio_resume); + +static const struct of_device_id plgpio_of_match[] = { + { .compatible = "st,spear-plgpio" }, + {} +}; +MODULE_DEVICE_TABLE(of, plgpio_of_match); + +static struct platform_driver plgpio_driver = { + .probe = plgpio_probe, + .driver = { + .owner = THIS_MODULE, + .name = "spear-plgpio", + .pm = &plgpio_dev_pm_ops, + .of_match_table = of_match_ptr(plgpio_of_match), + }, +}; + +static int __init plgpio_init(void) +{ + return platform_driver_register(&plgpio_driver); +} +subsys_initcall(plgpio_init); + +MODULE_AUTHOR("Viresh Kumar <viresh.kumar@linaro.org>"); +MODULE_DESCRIPTION("ST Microlectronics SPEAr PLGPIO driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c index b1fd6ee33c6..922c057521a 100644 --- a/drivers/pinctrl/spear/pinctrl-spear.c +++ b/drivers/pinctrl/spear/pinctrl-spear.c @@ -14,10 +14,10 @@ */ #include <linux/err.h> -#include <linux/io.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/of_gpio.h> #include <linux/pinctrl/machine.h> #include <linux/pinctrl/pinctrl.h> #include <linux/pinctrl/pinmux.h> @@ -28,14 +28,26 @@ #define DRIVER_NAME "spear-pinmux" -static inline u32 pmx_readl(struct spear_pmx *pmx, u32 reg) +static void muxregs_endisable(struct spear_pmx *pmx, + struct spear_muxreg *muxregs, u8 count, bool enable) { - return readl_relaxed(pmx->vbase + reg); -} + struct spear_muxreg *muxreg; + u32 val, temp, j; -static inline void pmx_writel(struct spear_pmx *pmx, u32 val, u32 reg) -{ - writel_relaxed(val, pmx->vbase + reg); + for (j = 0; j < count; j++) { + muxreg = &muxregs[j]; + + val = pmx_readl(pmx, muxreg->reg); + val &= ~muxreg->mask; + + if (enable) + temp = muxreg->val; + else + temp = ~muxreg->val; + + val |= muxreg->mask & temp; + pmx_writel(pmx, val, muxreg->reg); + } } static int set_mode(struct spear_pmx *pmx, int mode) @@ -70,6 +82,17 @@ static int set_mode(struct spear_pmx *pmx, int mode) return 0; } +void __devinit +pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup, + unsigned count, u16 reg) +{ + int i, j; + + for (i = 0; i < count; i++) + for (j = 0; j < gpio_pingroup[i].nmuxregs; j++) + gpio_pingroup[i].muxregs[j].reg = reg; +} + void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg) { struct spear_pingroup *pgroup; @@ -121,9 +144,10 @@ static void spear_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, seq_printf(s, " " DRIVER_NAME); } -int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, - struct device_node *np_config, - struct pinctrl_map **map, unsigned *num_maps) +static int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, + unsigned *num_maps) { struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); struct device_node *np; @@ -168,8 +192,9 @@ int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, return 0; } -void spear_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, - struct pinctrl_map *map, unsigned num_maps) +static void spear_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, + struct pinctrl_map *map, + unsigned num_maps) { kfree(map); } @@ -216,9 +241,7 @@ static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev, struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); const struct spear_pingroup *pgroup; const struct spear_modemux *modemux; - struct spear_muxreg *muxreg; - u32 val, temp; - int i, j; + int i; bool found = false; pgroup = pmx->machdata->groups[group]; @@ -233,20 +256,8 @@ static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev, } found = true; - for (j = 0; j < modemux->nmuxregs; j++) { - muxreg = &modemux->muxregs[j]; - - val = pmx_readl(pmx, muxreg->reg); - val &= ~muxreg->mask; - - if (enable) - temp = muxreg->val; - else - temp = ~muxreg->val; - - val |= muxreg->mask & temp; - pmx_writel(pmx, val, muxreg->reg); - } + muxregs_endisable(pmx, modemux->muxregs, modemux->nmuxregs, + enable); } if (!found) { @@ -270,12 +281,74 @@ static void spear_pinctrl_disable(struct pinctrl_dev *pctldev, spear_pinctrl_endisable(pctldev, function, group, false); } +/* gpio with pinmux */ +static struct spear_gpio_pingroup *get_gpio_pingroup(struct spear_pmx *pmx, + unsigned pin) +{ + struct spear_gpio_pingroup *gpio_pingroup; + int i, j; + + if (!pmx->machdata->gpio_pingroups) + return NULL; + + for (i = 0; i < pmx->machdata->ngpio_pingroups; i++) { + gpio_pingroup = &pmx->machdata->gpio_pingroups[i]; + + for (j = 0; j < gpio_pingroup->npins; j++) { + if (gpio_pingroup->pins[j] == pin) + return gpio_pingroup; + } + } + + return NULL; +} + +static int gpio_request_endisable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset, bool enable) +{ + struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); + struct spear_pinctrl_machdata *machdata = pmx->machdata; + struct spear_gpio_pingroup *gpio_pingroup; + + /* + * Some SoC have configuration options applicable to group of pins, + * rather than a single pin. + */ + gpio_pingroup = get_gpio_pingroup(pmx, offset); + if (gpio_pingroup) + muxregs_endisable(pmx, gpio_pingroup->muxregs, + gpio_pingroup->nmuxregs, enable); + + /* + * SoC may need some extra configurations, or configurations for single + * pin + */ + if (machdata->gpio_request_endisable) + machdata->gpio_request_endisable(pmx, offset, enable); + + return 0; +} + +static int gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset) +{ + return gpio_request_endisable(pctldev, range, offset, true); +} + +static void gpio_disable_free(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, unsigned offset) +{ + gpio_request_endisable(pctldev, range, offset, false); +} + static struct pinmux_ops spear_pinmux_ops = { .get_functions_count = spear_pinctrl_get_funcs_count, .get_function_name = spear_pinctrl_get_func_name, .get_function_groups = spear_pinctrl_get_func_groups, .enable = spear_pinctrl_enable, .disable = spear_pinctrl_disable, + .gpio_request_enable = gpio_request_enable, + .gpio_disable_free = gpio_disable_free, }; static struct pinctrl_desc spear_pinctrl_desc = { @@ -344,7 +417,7 @@ int __devinit spear_pinctrl_probe(struct platform_device *pdev, return 0; } -int __devexit spear_pinctrl_remove(struct platform_device *pdev) +int spear_pinctrl_remove(struct platform_device *pdev) { struct spear_pmx *pmx = platform_get_drvdata(pdev); diff --git a/drivers/pinctrl/spear/pinctrl-spear.h b/drivers/pinctrl/spear/pinctrl-spear.h index d950eb78d93..1be46ecc6d9 100644 --- a/drivers/pinctrl/spear/pinctrl-spear.h +++ b/drivers/pinctrl/spear/pinctrl-spear.h @@ -12,11 +12,14 @@ #ifndef __PINMUX_SPEAR_H__ #define __PINMUX_SPEAR_H__ +#include <linux/gpio.h> +#include <linux/io.h> #include <linux/pinctrl/pinctrl.h> #include <linux/types.h> struct platform_device; struct device; +struct spear_pmx; /** * struct spear_pmx_mode - SPEAr pmx mode @@ -46,6 +49,44 @@ struct spear_muxreg { u32 val; }; +struct spear_gpio_pingroup { + const unsigned *pins; + unsigned npins; + struct spear_muxreg *muxregs; + u8 nmuxregs; +}; + +/* ste: set to enable */ +#define DEFINE_MUXREG(__pins, __muxreg, __mask, __ste) \ +static struct spear_muxreg __pins##_muxregs[] = { \ + { \ + .reg = __muxreg, \ + .mask = __mask, \ + .val = __ste ? __mask : 0, \ + }, \ +} + +#define DEFINE_2_MUXREG(__pins, __muxreg1, __muxreg2, __mask, __ste1, __ste2) \ +static struct spear_muxreg __pins##_muxregs[] = { \ + { \ + .reg = __muxreg1, \ + .mask = __mask, \ + .val = __ste1 ? __mask : 0, \ + }, { \ + .reg = __muxreg2, \ + .mask = __mask, \ + .val = __ste2 ? __mask : 0, \ + }, \ +} + +#define GPIO_PINGROUP(__pins) \ + { \ + .pins = __pins, \ + .npins = ARRAY_SIZE(__pins), \ + .muxregs = __pins##_muxregs, \ + .nmuxregs = ARRAY_SIZE(__pins##_muxregs), \ + } + /** * struct spear_modemux - SPEAr mode mux configuration * @modes: mode ids supported by this group of muxregs @@ -100,6 +141,8 @@ struct spear_function { * @nfunctions: The numbmer of entries in @functions. * @groups: An array describing all pin groups the pin SoC supports. * @ngroups: The numbmer of entries in @groups. + * @gpio_pingroups: gpio pingroups + * @ngpio_pingroups: gpio pingroups count * * @modes_supported: Does SoC support modes * @mode: mode configured from probe @@ -113,6 +156,10 @@ struct spear_pinctrl_machdata { unsigned nfunctions; struct spear_pingroup **groups; unsigned ngroups; + struct spear_gpio_pingroup *gpio_pingroups; + void (*gpio_request_endisable)(struct spear_pmx *pmx, int offset, + bool enable); + unsigned ngpio_pingroups; bool modes_supported; u16 mode; @@ -135,10 +182,23 @@ struct spear_pmx { }; /* exported routines */ +static inline u32 pmx_readl(struct spear_pmx *pmx, u32 reg) +{ + return readl_relaxed(pmx->vbase + reg); +} + +static inline void pmx_writel(struct spear_pmx *pmx, u32 val, u32 reg) +{ + writel_relaxed(val, pmx->vbase + reg); +} + void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg); +void __devinit +pmx_init_gpio_pingroup_addr(struct spear_gpio_pingroup *gpio_pingroup, + unsigned count, u16 reg); int __devinit spear_pinctrl_probe(struct platform_device *pdev, struct spear_pinctrl_machdata *machdata); -int __devexit spear_pinctrl_remove(struct platform_device *pdev); +int spear_pinctrl_remove(struct platform_device *pdev); #define SPEAR_PIN_0_TO_101 \ PINCTRL_PIN(0, "PLGPIO0"), \ diff --git a/drivers/pinctrl/spear/pinctrl-spear1310.c b/drivers/pinctrl/spear/pinctrl-spear1310.c index 0436fc7895d..e40d785a3fc 100644 --- a/drivers/pinctrl/spear/pinctrl-spear1310.c +++ b/drivers/pinctrl/spear/pinctrl-spear1310.c @@ -2418,6 +2418,268 @@ static struct spear_function *spear1310_functions[] = { &gpt64_function, }; +static const unsigned pin18[] = { 18, }; +static const unsigned pin19[] = { 19, }; +static const unsigned pin20[] = { 20, }; +static const unsigned pin21[] = { 21, }; +static const unsigned pin22[] = { 22, }; +static const unsigned pin23[] = { 23, }; +static const unsigned pin54[] = { 54, }; +static const unsigned pin55[] = { 55, }; +static const unsigned pin56[] = { 56, }; +static const unsigned pin57[] = { 57, }; +static const unsigned pin58[] = { 58, }; +static const unsigned pin59[] = { 59, }; +static const unsigned pin60[] = { 60, }; +static const unsigned pin61[] = { 61, }; +static const unsigned pin62[] = { 62, }; +static const unsigned pin63[] = { 63, }; +static const unsigned pin143[] = { 143, }; +static const unsigned pin144[] = { 144, }; +static const unsigned pin145[] = { 145, }; +static const unsigned pin146[] = { 146, }; +static const unsigned pin147[] = { 147, }; +static const unsigned pin148[] = { 148, }; +static const unsigned pin149[] = { 149, }; +static const unsigned pin150[] = { 150, }; +static const unsigned pin151[] = { 151, }; +static const unsigned pin152[] = { 152, }; +static const unsigned pin205[] = { 205, }; +static const unsigned pin206[] = { 206, }; +static const unsigned pin211[] = { 211, }; +static const unsigned pin212[] = { 212, }; +static const unsigned pin213[] = { 213, }; +static const unsigned pin214[] = { 214, }; +static const unsigned pin215[] = { 215, }; +static const unsigned pin216[] = { 216, }; +static const unsigned pin217[] = { 217, }; +static const unsigned pin218[] = { 218, }; +static const unsigned pin219[] = { 219, }; +static const unsigned pin220[] = { 220, }; +static const unsigned pin221[] = { 221, }; +static const unsigned pin222[] = { 222, }; +static const unsigned pin223[] = { 223, }; +static const unsigned pin224[] = { 224, }; +static const unsigned pin225[] = { 225, }; +static const unsigned pin226[] = { 226, }; +static const unsigned pin227[] = { 227, }; +static const unsigned pin228[] = { 228, }; +static const unsigned pin229[] = { 229, }; +static const unsigned pin230[] = { 230, }; +static const unsigned pin231[] = { 231, }; +static const unsigned pin232[] = { 232, }; +static const unsigned pin233[] = { 233, }; +static const unsigned pin234[] = { 234, }; +static const unsigned pin235[] = { 235, }; +static const unsigned pin236[] = { 236, }; +static const unsigned pin237[] = { 237, }; +static const unsigned pin238[] = { 238, }; +static const unsigned pin239[] = { 239, }; +static const unsigned pin240[] = { 240, }; +static const unsigned pin241[] = { 241, }; +static const unsigned pin242[] = { 242, }; +static const unsigned pin243[] = { 243, }; +static const unsigned pin244[] = { 244, }; +static const unsigned pin245[] = { 245, }; + +static const unsigned pin_grp0[] = { 173, 174, }; +static const unsigned pin_grp1[] = { 175, 185, 188, 197, 198, }; +static const unsigned pin_grp2[] = { 176, 177, 178, 179, 184, 186, 187, 189, + 190, 191, 192, }; +static const unsigned pin_grp3[] = { 180, 181, 182, 183, 193, 194, 195, 196, }; +static const unsigned pin_grp4[] = { 199, 200, }; +static const unsigned pin_grp5[] = { 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, }; +static const unsigned pin_grp6[] = { 86, 87, 88, 89, 90, 91, 92, 93, }; +static const unsigned pin_grp7[] = { 98, 99, }; +static const unsigned pin_grp8[] = { 158, 159, 160, 161, 162, 163, 164, 165, + 166, 167, 168, 169, 170, 171, 172, }; + +/* Define muxreg arrays */ +DEFINE_2_MUXREG(i2c0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_I2C0_MASK, 0, 1); +DEFINE_2_MUXREG(ssp0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_SSP0_MASK, 0, 1); +DEFINE_2_MUXREG(ssp0_cs0_pins, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_SSP0_CS0_MASK, 0, 1); +DEFINE_2_MUXREG(ssp0_cs1_2_pins, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_SSP0_CS1_2_MASK, 0, 1); +DEFINE_2_MUXREG(i2s0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_I2S0_MASK, 0, 1); +DEFINE_2_MUXREG(i2s1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_I2S1_MASK, 0, 1); +DEFINE_2_MUXREG(clcd_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_CLCD1_MASK, 0, 1); +DEFINE_2_MUXREG(clcd_high_res_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_CLCD2_MASK, 0, 1); +DEFINE_2_MUXREG(pin18, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO15_MASK, 0, 1); +DEFINE_2_MUXREG(pin19, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO14_MASK, 0, 1); +DEFINE_2_MUXREG(pin20, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO13_MASK, 0, 1); +DEFINE_2_MUXREG(pin21, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO12_MASK, 0, 1); +DEFINE_2_MUXREG(pin22, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO11_MASK, 0, 1); +DEFINE_2_MUXREG(pin23, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO10_MASK, 0, 1); +DEFINE_2_MUXREG(pin143, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO00_MASK, 0, 1); +DEFINE_2_MUXREG(pin144, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO01_MASK, 0, 1); +DEFINE_2_MUXREG(pin145, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO02_MASK, 0, 1); +DEFINE_2_MUXREG(pin146, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO03_MASK, 0, 1); +DEFINE_2_MUXREG(pin147, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO04_MASK, 0, 1); +DEFINE_2_MUXREG(pin148, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO05_MASK, 0, 1); +DEFINE_2_MUXREG(pin149, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO06_MASK, 0, 1); +DEFINE_2_MUXREG(pin150, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO07_MASK, 0, 1); +DEFINE_2_MUXREG(pin151, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO08_MASK, 0, 1); +DEFINE_2_MUXREG(pin152, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_EGPIO09_MASK, 0, 1); +DEFINE_2_MUXREG(smi_2_chips_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_SMI_MASK, 0, 1); +DEFINE_2_MUXREG(pin54, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_SMINCS3_MASK, 0, 1); +DEFINE_2_MUXREG(pin55, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_SMINCS2_MASK, 0, 1); +DEFINE_2_MUXREG(pin56, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NFRSTPWDWN3_MASK, 0, 1); +DEFINE_2_MUXREG(pin57, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN2_MASK, 0, 1); +DEFINE_2_MUXREG(pin58, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN1_MASK, 0, 1); +DEFINE_2_MUXREG(pin59, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFRSTPWDWN0_MASK, 0, 1); +DEFINE_2_MUXREG(pin60, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFWPRT3_MASK, 0, 1); +DEFINE_2_MUXREG(pin61, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFCE3_MASK, 0, 1); +DEFINE_2_MUXREG(pin62, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD25_MASK, 0, 1); +DEFINE_2_MUXREG(pin63, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD24_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp0, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIICLK_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp1, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIICOL_CRS_XFERER_MIITXCLK_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp2, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_RXCLK_RDV_TXEN_D03_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp3, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_GMIID47_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp4, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_MDC_MDIO_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp5, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_NFAD23_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp6, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_MCI_DATA8_15_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp7, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NFCE2_MASK, 0, 1); +DEFINE_2_MUXREG(pin_grp8, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NAND8_MASK, 0, 1); +DEFINE_2_MUXREG(nand_16bit_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_NAND16BIT_1_MASK, 0, 1); +DEFINE_2_MUXREG(pin205, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_COL1_MASK | PMX_NFCE1_MASK, 0, 1); +DEFINE_2_MUXREG(pin206, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_COL0_MASK | PMX_NFCE2_MASK, 0, 1); +DEFINE_2_MUXREG(pin211, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROW1_MASK | PMX_NFWPRT1_MASK, 0, 1); +DEFINE_2_MUXREG(pin212, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROW0_MASK | PMX_NFWPRT2_MASK, 0, 1); +DEFINE_2_MUXREG(pin213, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA0_MASK, 0, 1); +DEFINE_2_MUXREG(pin214, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA1_MASK, 0, 1); +DEFINE_2_MUXREG(pin215, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA2_MASK, 0, 1); +DEFINE_2_MUXREG(pin216, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA3_MASK, 0, 1); +DEFINE_2_MUXREG(pin217, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_MCIDATA4_MASK, 0, 1); +DEFINE_2_MUXREG(pin218, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA5_MASK, 0, 1); +DEFINE_2_MUXREG(pin219, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA6_MASK, 0, 1); +DEFINE_2_MUXREG(pin220, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA7_MASK, 0, 1); +DEFINE_2_MUXREG(pin221, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA1SD_MASK, 0, 1); +DEFINE_2_MUXREG(pin222, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA2SD_MASK, 0, 1); +DEFINE_2_MUXREG(pin223, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATA3SD_MASK, 0, 1); +DEFINE_2_MUXREG(pin224, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR0ALE_MASK, 0, 1); +DEFINE_2_MUXREG(pin225, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR1CLECLK_MASK, 0, 1); +DEFINE_2_MUXREG(pin226, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIADDR2_MASK, 0, 1); +DEFINE_2_MUXREG(pin227, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICECF_MASK, 0, 1); +DEFINE_2_MUXREG(pin228, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICEXD_MASK, 0, 1); +DEFINE_2_MUXREG(pin229, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICESDMMC_MASK, 0, 1); +DEFINE_2_MUXREG(pin230, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDCF1_MASK, 0, 1); +DEFINE_2_MUXREG(pin231, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDCF2_MASK, 0, 1); +DEFINE_2_MUXREG(pin232, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDXD_MASK, 0, 1); +DEFINE_2_MUXREG(pin233, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICDSDMMC_MASK, 0, 1); +DEFINE_2_MUXREG(pin234, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDATADIR_MASK, 0, 1); +DEFINE_2_MUXREG(pin235, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDMARQWP_MASK, 0, 1); +DEFINE_2_MUXREG(pin236, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIORDRE_MASK, 0, 1); +DEFINE_2_MUXREG(pin237, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIOWRWE_MASK, 0, 1); +DEFINE_2_MUXREG(pin238, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIRESETCF_MASK, 0, 1); +DEFINE_2_MUXREG(pin239, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICS0CE_MASK, 0, 1); +DEFINE_2_MUXREG(pin240, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICFINTR_MASK, 0, 1); +DEFINE_2_MUXREG(pin241, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIIORDY_MASK, 0, 1); +DEFINE_2_MUXREG(pin242, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCICS1_MASK, 0, 1); +DEFINE_2_MUXREG(pin243, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCIDMAACK_MASK, 0, 1); +DEFINE_2_MUXREG(pin244, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCISDCMD_MASK, 0, 1); +DEFINE_2_MUXREG(pin245, PAD_FUNCTION_EN_2, PAD_DIRECTION_SEL_2, PMX_MCILEDS_MASK, 0, 1); +DEFINE_2_MUXREG(keyboard_rowcol6_8_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_KBD_ROWCOL68_MASK, 0, 1); +DEFINE_2_MUXREG(uart0_pins, PAD_FUNCTION_EN_0, PAD_DIRECTION_SEL_0, PMX_UART0_MASK, 0, 1); +DEFINE_2_MUXREG(uart0_modem_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_UART0_MODEM_MASK, 0, 1); +DEFINE_2_MUXREG(gpt0_tmr0_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT0_TMR0_MASK, 0, 1); +DEFINE_2_MUXREG(gpt0_tmr1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT0_TMR1_MASK, 0, 1); +DEFINE_2_MUXREG(gpt1_tmr0_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT1_TMR0_MASK, 0, 1); +DEFINE_2_MUXREG(gpt1_tmr1_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_GPT1_TMR1_MASK, 0, 1); +DEFINE_2_MUXREG(touch_xy_pins, PAD_FUNCTION_EN_1, PAD_DIRECTION_SEL_1, PMX_TOUCH_XY_MASK, 0, 1); + +static struct spear_gpio_pingroup spear1310_gpio_pingroup[] = { + GPIO_PINGROUP(i2c0_pins), + GPIO_PINGROUP(ssp0_pins), + GPIO_PINGROUP(ssp0_cs0_pins), + GPIO_PINGROUP(ssp0_cs1_2_pins), + GPIO_PINGROUP(i2s0_pins), + GPIO_PINGROUP(i2s1_pins), + GPIO_PINGROUP(clcd_pins), + GPIO_PINGROUP(clcd_high_res_pins), + GPIO_PINGROUP(pin18), + GPIO_PINGROUP(pin19), + GPIO_PINGROUP(pin20), + GPIO_PINGROUP(pin21), + GPIO_PINGROUP(pin22), + GPIO_PINGROUP(pin23), + GPIO_PINGROUP(pin143), + GPIO_PINGROUP(pin144), + GPIO_PINGROUP(pin145), + GPIO_PINGROUP(pin146), + GPIO_PINGROUP(pin147), + GPIO_PINGROUP(pin148), + GPIO_PINGROUP(pin149), + GPIO_PINGROUP(pin150), + GPIO_PINGROUP(pin151), + GPIO_PINGROUP(pin152), + GPIO_PINGROUP(smi_2_chips_pins), + GPIO_PINGROUP(pin54), + GPIO_PINGROUP(pin55), + GPIO_PINGROUP(pin56), + GPIO_PINGROUP(pin57), + GPIO_PINGROUP(pin58), + GPIO_PINGROUP(pin59), + GPIO_PINGROUP(pin60), + GPIO_PINGROUP(pin61), + GPIO_PINGROUP(pin62), + GPIO_PINGROUP(pin63), + GPIO_PINGROUP(pin_grp0), + GPIO_PINGROUP(pin_grp1), + GPIO_PINGROUP(pin_grp2), + GPIO_PINGROUP(pin_grp3), + GPIO_PINGROUP(pin_grp4), + GPIO_PINGROUP(pin_grp5), + GPIO_PINGROUP(pin_grp6), + GPIO_PINGROUP(pin_grp7), + GPIO_PINGROUP(pin_grp8), + GPIO_PINGROUP(nand_16bit_pins), + GPIO_PINGROUP(pin205), + GPIO_PINGROUP(pin206), + GPIO_PINGROUP(pin211), + GPIO_PINGROUP(pin212), + GPIO_PINGROUP(pin213), + GPIO_PINGROUP(pin214), + GPIO_PINGROUP(pin215), + GPIO_PINGROUP(pin216), + GPIO_PINGROUP(pin217), + GPIO_PINGROUP(pin218), + GPIO_PINGROUP(pin219), + GPIO_PINGROUP(pin220), + GPIO_PINGROUP(pin221), + GPIO_PINGROUP(pin222), + GPIO_PINGROUP(pin223), + GPIO_PINGROUP(pin224), + GPIO_PINGROUP(pin225), + GPIO_PINGROUP(pin226), + GPIO_PINGROUP(pin227), + GPIO_PINGROUP(pin228), + GPIO_PINGROUP(pin229), + GPIO_PINGROUP(pin230), + GPIO_PINGROUP(pin231), + GPIO_PINGROUP(pin232), + GPIO_PINGROUP(pin233), + GPIO_PINGROUP(pin234), + GPIO_PINGROUP(pin235), + GPIO_PINGROUP(pin236), + GPIO_PINGROUP(pin237), + GPIO_PINGROUP(pin238), + GPIO_PINGROUP(pin239), + GPIO_PINGROUP(pin240), + GPIO_PINGROUP(pin241), + GPIO_PINGROUP(pin242), + GPIO_PINGROUP(pin243), + GPIO_PINGROUP(pin244), + GPIO_PINGROUP(pin245), + GPIO_PINGROUP(keyboard_rowcol6_8_pins), + GPIO_PINGROUP(uart0_pins), + GPIO_PINGROUP(uart0_modem_pins), + GPIO_PINGROUP(gpt0_tmr0_pins), + GPIO_PINGROUP(gpt0_tmr1_pins), + GPIO_PINGROUP(gpt1_tmr0_pins), + GPIO_PINGROUP(gpt1_tmr1_pins), + GPIO_PINGROUP(touch_xy_pins), +}; + static struct spear_pinctrl_machdata spear1310_machdata = { .pins = spear1310_pins, .npins = ARRAY_SIZE(spear1310_pins), @@ -2425,10 +2687,12 @@ static struct spear_pinctrl_machdata spear1310_machdata = { .ngroups = ARRAY_SIZE(spear1310_pingroups), .functions = spear1310_functions, .nfunctions = ARRAY_SIZE(spear1310_functions), + .gpio_pingroups = spear1310_gpio_pingroup, + .ngpio_pingroups = ARRAY_SIZE(spear1310_gpio_pingroup), .modes_supported = false, }; -static struct of_device_id spear1310_pinctrl_of_match[] __devinitdata = { +static struct of_device_id spear1310_pinctrl_of_match[] = { { .compatible = "st,spear1310-pinmux", }, @@ -2440,7 +2704,7 @@ static int __devinit spear1310_pinctrl_probe(struct platform_device *pdev) return spear_pinctrl_probe(pdev, &spear1310_machdata); } -static int __devexit spear1310_pinctrl_remove(struct platform_device *pdev) +static int spear1310_pinctrl_remove(struct platform_device *pdev) { return spear_pinctrl_remove(pdev); } @@ -2452,7 +2716,7 @@ static struct platform_driver spear1310_pinctrl_driver = { .of_match_table = spear1310_pinctrl_of_match, }, .probe = spear1310_pinctrl_probe, - .remove = __devexit_p(spear1310_pinctrl_remove), + .remove = spear1310_pinctrl_remove, }; static int __init spear1310_pinctrl_init(void) diff --git a/drivers/pinctrl/spear/pinctrl-spear1340.c b/drivers/pinctrl/spear/pinctrl-spear1340.c index 0606b8cf3f2..8deaaff3156 100644 --- a/drivers/pinctrl/spear/pinctrl-spear1340.c +++ b/drivers/pinctrl/spear/pinctrl-spear1340.c @@ -1971,6 +1971,32 @@ static struct spear_function *spear1340_functions[] = { &sata_function, }; +static void gpio_request_endisable(struct spear_pmx *pmx, int pin, + bool enable) +{ + unsigned int regoffset, regindex, bitoffset; + unsigned int val; + + /* pin++ as gpio configuration starts from 2nd bit of base register */ + pin++; + + regindex = pin / 32; + bitoffset = pin % 32; + + if (regindex <= 3) + regoffset = PAD_FUNCTION_EN_1 + regindex * sizeof(int *); + else + regoffset = PAD_FUNCTION_EN_5 + (regindex - 4) * sizeof(int *); + + val = pmx_readl(pmx, regoffset); + if (enable) + val &= ~(0x1 << bitoffset); + else + val |= 0x1 << bitoffset; + + pmx_writel(pmx, val, regoffset); +} + static struct spear_pinctrl_machdata spear1340_machdata = { .pins = spear1340_pins, .npins = ARRAY_SIZE(spear1340_pins), @@ -1978,10 +2004,11 @@ static struct spear_pinctrl_machdata spear1340_machdata = { .ngroups = ARRAY_SIZE(spear1340_pingroups), .functions = spear1340_functions, .nfunctions = ARRAY_SIZE(spear1340_functions), + .gpio_request_endisable = gpio_request_endisable, .modes_supported = false, }; -static struct of_device_id spear1340_pinctrl_of_match[] __devinitdata = { +static struct of_device_id spear1340_pinctrl_of_match[] = { { .compatible = "st,spear1340-pinmux", }, @@ -1993,7 +2020,7 @@ static int __devinit spear1340_pinctrl_probe(struct platform_device *pdev) return spear_pinctrl_probe(pdev, &spear1340_machdata); } -static int __devexit spear1340_pinctrl_remove(struct platform_device *pdev) +static int spear1340_pinctrl_remove(struct platform_device *pdev) { return spear_pinctrl_remove(pdev); } @@ -2005,7 +2032,7 @@ static struct platform_driver spear1340_pinctrl_driver = { .of_match_table = spear1340_pinctrl_of_match, }, .probe = spear1340_pinctrl_probe, - .remove = __devexit_p(spear1340_pinctrl_remove), + .remove = spear1340_pinctrl_remove, }; static int __init spear1340_pinctrl_init(void) diff --git a/drivers/pinctrl/spear/pinctrl-spear300.c b/drivers/pinctrl/spear/pinctrl-spear300.c index 4dfc2849b17..f48e466e605 100644 --- a/drivers/pinctrl/spear/pinctrl-spear300.c +++ b/drivers/pinctrl/spear/pinctrl-spear300.c @@ -646,7 +646,7 @@ static struct spear_function *spear300_functions[] = { &gpio1_function, }; -static struct of_device_id spear300_pinctrl_of_match[] __devinitdata = { +static struct of_device_id spear300_pinctrl_of_match[] = { { .compatible = "st,spear300-pinmux", }, @@ -661,6 +661,8 @@ static int __devinit spear300_pinctrl_probe(struct platform_device *pdev) spear3xx_machdata.ngroups = ARRAY_SIZE(spear300_pingroups); spear3xx_machdata.functions = spear300_functions; spear3xx_machdata.nfunctions = ARRAY_SIZE(spear300_functions); + spear3xx_machdata.gpio_pingroups = NULL; + spear3xx_machdata.ngpio_pingroups = 0; spear3xx_machdata.modes_supported = true; spear3xx_machdata.pmx_modes = spear300_pmx_modes; @@ -675,7 +677,7 @@ static int __devinit spear300_pinctrl_probe(struct platform_device *pdev) return 0; } -static int __devexit spear300_pinctrl_remove(struct platform_device *pdev) +static int spear300_pinctrl_remove(struct platform_device *pdev) { return spear_pinctrl_remove(pdev); } @@ -687,7 +689,7 @@ static struct platform_driver spear300_pinctrl_driver = { .of_match_table = spear300_pinctrl_of_match, }, .probe = spear300_pinctrl_probe, - .remove = __devexit_p(spear300_pinctrl_remove), + .remove = spear300_pinctrl_remove, }; static int __init spear300_pinctrl_init(void) diff --git a/drivers/pinctrl/spear/pinctrl-spear310.c b/drivers/pinctrl/spear/pinctrl-spear310.c index 96883693fb7..5b954c19a6d 100644 --- a/drivers/pinctrl/spear/pinctrl-spear310.c +++ b/drivers/pinctrl/spear/pinctrl-spear310.c @@ -371,7 +371,7 @@ static struct spear_function *spear310_functions[] = { &tdm_function, }; -static struct of_device_id spear310_pinctrl_of_match[] __devinitdata = { +static struct of_device_id spear310_pinctrl_of_match[] = { { .compatible = "st,spear310-pinmux", }, @@ -388,6 +388,8 @@ static int __devinit spear310_pinctrl_probe(struct platform_device *pdev) spear3xx_machdata.nfunctions = ARRAY_SIZE(spear310_functions); pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG); + pmx_init_gpio_pingroup_addr(spear3xx_machdata.gpio_pingroups, + spear3xx_machdata.ngpio_pingroups, PMX_CONFIG_REG); spear3xx_machdata.modes_supported = false; @@ -398,7 +400,7 @@ static int __devinit spear310_pinctrl_probe(struct platform_device *pdev) return 0; } -static int __devexit spear310_pinctrl_remove(struct platform_device *pdev) +static int spear310_pinctrl_remove(struct platform_device *pdev) { return spear_pinctrl_remove(pdev); } @@ -410,7 +412,7 @@ static struct platform_driver spear310_pinctrl_driver = { .of_match_table = spear310_pinctrl_of_match, }, .probe = spear310_pinctrl_probe, - .remove = __devexit_p(spear310_pinctrl_remove), + .remove = spear310_pinctrl_remove, }; static int __init spear310_pinctrl_init(void) diff --git a/drivers/pinctrl/spear/pinctrl-spear320.c b/drivers/pinctrl/spear/pinctrl-spear320.c index ca47b0e5078..e9a5e6d3924 100644 --- a/drivers/pinctrl/spear/pinctrl-spear320.c +++ b/drivers/pinctrl/spear/pinctrl-spear320.c @@ -3410,7 +3410,7 @@ static struct spear_function *spear320_functions[] = { &i2c2_function, }; -static struct of_device_id spear320_pinctrl_of_match[] __devinitdata = { +static struct of_device_id spear320_pinctrl_of_match[] = { { .compatible = "st,spear320-pinmux", }, @@ -3431,6 +3431,8 @@ static int __devinit spear320_pinctrl_probe(struct platform_device *pdev) spear3xx_machdata.npmx_modes = ARRAY_SIZE(spear320_pmx_modes); pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG); + pmx_init_gpio_pingroup_addr(spear3xx_machdata.gpio_pingroups, + spear3xx_machdata.ngpio_pingroups, PMX_CONFIG_REG); ret = spear_pinctrl_probe(pdev, &spear3xx_machdata); if (ret) @@ -3439,7 +3441,7 @@ static int __devinit spear320_pinctrl_probe(struct platform_device *pdev) return 0; } -static int __devexit spear320_pinctrl_remove(struct platform_device *pdev) +static int spear320_pinctrl_remove(struct platform_device *pdev) { return spear_pinctrl_remove(pdev); } @@ -3451,7 +3453,7 @@ static struct platform_driver spear320_pinctrl_driver = { .of_match_table = spear320_pinctrl_of_match, }, .probe = spear320_pinctrl_probe, - .remove = __devexit_p(spear320_pinctrl_remove), + .remove = spear320_pinctrl_remove, }; static int __init spear320_pinctrl_init(void) diff --git a/drivers/pinctrl/spear/pinctrl-spear3xx.c b/drivers/pinctrl/spear/pinctrl-spear3xx.c index 0242378f7cb..12ee21af766 100644 --- a/drivers/pinctrl/spear/pinctrl-spear3xx.c +++ b/drivers/pinctrl/spear/pinctrl-spear3xx.c @@ -481,7 +481,44 @@ struct spear_function spear3xx_timer_2_3_function = { .ngroups = ARRAY_SIZE(timer_2_3_grps), }; +/* Define muxreg arrays */ +DEFINE_MUXREG(firda_pins, 0, PMX_FIRDA_MASK, 0); +DEFINE_MUXREG(i2c_pins, 0, PMX_I2C_MASK, 0); +DEFINE_MUXREG(ssp_cs_pins, 0, PMX_SSP_CS_MASK, 0); +DEFINE_MUXREG(ssp_pins, 0, PMX_SSP_MASK, 0); +DEFINE_MUXREG(mii_pins, 0, PMX_MII_MASK, 0); +DEFINE_MUXREG(gpio0_pin0_pins, 0, PMX_GPIO_PIN0_MASK, 0); +DEFINE_MUXREG(gpio0_pin1_pins, 0, PMX_GPIO_PIN1_MASK, 0); +DEFINE_MUXREG(gpio0_pin2_pins, 0, PMX_GPIO_PIN2_MASK, 0); +DEFINE_MUXREG(gpio0_pin3_pins, 0, PMX_GPIO_PIN3_MASK, 0); +DEFINE_MUXREG(gpio0_pin4_pins, 0, PMX_GPIO_PIN4_MASK, 0); +DEFINE_MUXREG(gpio0_pin5_pins, 0, PMX_GPIO_PIN5_MASK, 0); +DEFINE_MUXREG(uart0_ext_pins, 0, PMX_UART0_MODEM_MASK, 0); +DEFINE_MUXREG(uart0_pins, 0, PMX_UART0_MASK, 0); +DEFINE_MUXREG(timer_0_1_pins, 0, PMX_TIMER_0_1_MASK, 0); +DEFINE_MUXREG(timer_2_3_pins, 0, PMX_TIMER_2_3_MASK, 0); + +static struct spear_gpio_pingroup spear3xx_gpio_pingroup[] = { + GPIO_PINGROUP(firda_pins), + GPIO_PINGROUP(i2c_pins), + GPIO_PINGROUP(ssp_cs_pins), + GPIO_PINGROUP(ssp_pins), + GPIO_PINGROUP(mii_pins), + GPIO_PINGROUP(gpio0_pin0_pins), + GPIO_PINGROUP(gpio0_pin1_pins), + GPIO_PINGROUP(gpio0_pin2_pins), + GPIO_PINGROUP(gpio0_pin3_pins), + GPIO_PINGROUP(gpio0_pin4_pins), + GPIO_PINGROUP(gpio0_pin5_pins), + GPIO_PINGROUP(uart0_ext_pins), + GPIO_PINGROUP(uart0_pins), + GPIO_PINGROUP(timer_0_1_pins), + GPIO_PINGROUP(timer_2_3_pins), +}; + struct spear_pinctrl_machdata spear3xx_machdata = { .pins = spear3xx_pins, .npins = ARRAY_SIZE(spear3xx_pins), + .gpio_pingroups = spear3xx_gpio_pingroup, + .ngpio_pingroups = ARRAY_SIZE(spear3xx_gpio_pingroup), }; diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h index fa4e0a5db3f..ffd53e3eb92 100644 --- a/drivers/pnp/base.h +++ b/drivers/pnp/base.h @@ -159,6 +159,8 @@ struct pnp_resource { void pnp_free_resource(struct pnp_resource *pnp_res); +struct pnp_resource *pnp_add_resource(struct pnp_dev *dev, + struct resource *res); struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq, int flags); struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma, diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 26b5d4b18dd..72e822e17d4 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -58,7 +58,7 @@ static inline int __init is_exclusive_device(struct acpi_device *dev) if (!(('0' <= (c) && (c) <= '9') || ('A' <= (c) && (c) <= 'F'))) \ return 0 #define TEST_ALPHA(c) \ - if (!('@' <= (c) || (c) <= 'Z')) \ + if (!('A' <= (c) && (c) <= 'Z')) \ return 0 static int __init ispnpidacpi(const char *id) { @@ -95,6 +95,9 @@ static int pnpacpi_set_resources(struct pnp_dev *dev) return -ENODEV; } + if (WARN_ON_ONCE(acpi_dev != dev->data)) + dev->data = acpi_dev; + ret = pnpacpi_build_resource_template(dev, &buffer); if (ret) return ret; @@ -242,6 +245,10 @@ static int __init pnpacpi_add_device(struct acpi_device *device) char *pnpid; struct acpi_hardware_id *id; + /* Skip devices that are already bound */ + if (device->physical_node_count) + return 0; + /* * If a PnPacpi device is not present , the device * driver should not be loaded. diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 5be4a392a3a..b8f4ea7b27f 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -28,37 +28,6 @@ #include "../base.h" #include "pnpacpi.h" -#ifdef CONFIG_IA64 -#define valid_IRQ(i) (1) -#else -#define valid_IRQ(i) (((i) != 0) && ((i) != 2)) -#endif - -/* - * Allocated Resources - */ -static int irq_flags(int triggering, int polarity, int shareable) -{ - int flags; - - if (triggering == ACPI_LEVEL_SENSITIVE) { - if (polarity == ACPI_ACTIVE_LOW) - flags = IORESOURCE_IRQ_LOWLEVEL; - else - flags = IORESOURCE_IRQ_HIGHLEVEL; - } else { - if (polarity == ACPI_ACTIVE_LOW) - flags = IORESOURCE_IRQ_LOWEDGE; - else - flags = IORESOURCE_IRQ_HIGHEDGE; - } - - if (shareable == ACPI_SHARED) - flags |= IORESOURCE_IRQ_SHAREABLE; - - return flags; -} - static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering, int *polarity, int *shareable) { @@ -94,45 +63,6 @@ static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering, *shareable = ACPI_EXCLUSIVE; } -static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev, - u32 gsi, int triggering, - int polarity, int shareable) -{ - int irq, flags; - int p, t; - - if (!valid_IRQ(gsi)) { - pnp_add_irq_resource(dev, gsi, IORESOURCE_DISABLED); - return; - } - - /* - * in IO-APIC mode, use overrided attribute. Two reasons: - * 1. BIOS bug in DSDT - * 2. BIOS uses IO-APIC mode Interrupt Source Override - */ - if (!acpi_get_override_irq(gsi, &t, &p)) { - t = t ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE; - p = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH; - - if (triggering != t || polarity != p) { - dev_warn(&dev->dev, "IRQ %d override to %s, %s\n", - gsi, t ? "edge":"level", p ? "low":"high"); - triggering = t; - polarity = p; - } - } - - flags = irq_flags(triggering, polarity, shareable); - irq = acpi_register_gsi(&dev->dev, gsi, triggering, polarity); - if (irq >= 0) - pcibios_penalize_isa_irq(irq, 1); - else - flags |= IORESOURCE_DISABLED; - - pnp_add_irq_resource(dev, irq, flags); -} - static int dma_flags(struct pnp_dev *dev, int type, int bus_master, int transfer) { @@ -177,21 +107,16 @@ static int dma_flags(struct pnp_dev *dev, int type, int bus_master, return flags; } -static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start, - u64 len, int io_decode, - int window) -{ - int flags = 0; - u64 end = start + len - 1; +/* + * Allocated Resources + */ - if (io_decode == ACPI_DECODE_16) - flags |= IORESOURCE_IO_16BIT_ADDR; - if (len == 0 || end >= 0x10003) - flags |= IORESOURCE_DISABLED; - if (window) - flags |= IORESOURCE_WINDOW; +static void pnpacpi_add_irqresource(struct pnp_dev *dev, struct resource *r) +{ + if (!(r->flags & IORESOURCE_DISABLED)) + pcibios_penalize_isa_irq(r->start, 1); - pnp_add_io_resource(dev, start, end, flags); + pnp_add_resource(dev, r); } /* @@ -249,130 +174,49 @@ static void pnpacpi_parse_allocated_vendor(struct pnp_dev *dev, } } -static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev, - u64 start, u64 len, - int write_protect, int window) -{ - int flags = 0; - u64 end = start + len - 1; - - if (len == 0) - flags |= IORESOURCE_DISABLED; - if (write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; - if (window) - flags |= IORESOURCE_WINDOW; - - pnp_add_mem_resource(dev, start, end, flags); -} - -static void pnpacpi_parse_allocated_busresource(struct pnp_dev *dev, - u64 start, u64 len) -{ - u64 end = start + len - 1; - - pnp_add_bus_resource(dev, start, end); -} - -static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev, - struct acpi_resource *res) -{ - struct acpi_resource_address64 addr, *p = &addr; - acpi_status status; - int window; - u64 len; - - status = acpi_resource_to_address64(res, p); - if (!ACPI_SUCCESS(status)) { - dev_warn(&dev->dev, "failed to convert resource type %d\n", - res->type); - return; - } - - /* Windows apparently computes length rather than using _LEN */ - len = p->maximum - p->minimum + 1; - window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0; - - if (p->resource_type == ACPI_MEMORY_RANGE) - pnpacpi_parse_allocated_memresource(dev, p->minimum, len, - p->info.mem.write_protect, window); - else if (p->resource_type == ACPI_IO_RANGE) - pnpacpi_parse_allocated_ioresource(dev, p->minimum, len, - p->granularity == 0xfff ? ACPI_DECODE_10 : - ACPI_DECODE_16, window); - else if (p->resource_type == ACPI_BUS_NUMBER_RANGE) - pnpacpi_parse_allocated_busresource(dev, p->minimum, len); -} - -static void pnpacpi_parse_allocated_ext_address_space(struct pnp_dev *dev, - struct acpi_resource *res) -{ - struct acpi_resource_extended_address64 *p = &res->data.ext_address64; - int window; - u64 len; - - /* Windows apparently computes length rather than using _LEN */ - len = p->maximum - p->minimum + 1; - window = (p->producer_consumer == ACPI_PRODUCER) ? 1 : 0; - - if (p->resource_type == ACPI_MEMORY_RANGE) - pnpacpi_parse_allocated_memresource(dev, p->minimum, len, - p->info.mem.write_protect, window); - else if (p->resource_type == ACPI_IO_RANGE) - pnpacpi_parse_allocated_ioresource(dev, p->minimum, len, - p->granularity == 0xfff ? ACPI_DECODE_10 : - ACPI_DECODE_16, window); - else if (p->resource_type == ACPI_BUS_NUMBER_RANGE) - pnpacpi_parse_allocated_busresource(dev, p->minimum, len); -} - static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, void *data) { struct pnp_dev *dev = data; - struct acpi_resource_irq *irq; struct acpi_resource_dma *dma; - struct acpi_resource_io *io; - struct acpi_resource_fixed_io *fixed_io; struct acpi_resource_vendor_typed *vendor_typed; - struct acpi_resource_memory24 *memory24; - struct acpi_resource_memory32 *memory32; - struct acpi_resource_fixed_memory32 *fixed_memory32; - struct acpi_resource_extended_irq *extended_irq; + struct resource r; int i, flags; - switch (res->type) { - case ACPI_RESOURCE_TYPE_IRQ: - /* - * Per spec, only one interrupt per descriptor is allowed in - * _CRS, but some firmware violates this, so parse them all. - */ - irq = &res->data.irq; - if (irq->interrupt_count == 0) - pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); - else { - for (i = 0; i < irq->interrupt_count; i++) { - pnpacpi_parse_allocated_irqresource(dev, - irq->interrupts[i], - irq->triggering, - irq->polarity, - irq->sharable); - } + if (acpi_dev_resource_memory(res, &r) + || acpi_dev_resource_io(res, &r) + || acpi_dev_resource_address_space(res, &r) + || acpi_dev_resource_ext_address_space(res, &r)) { + pnp_add_resource(dev, &r); + return AE_OK; + } + r.flags = 0; + if (acpi_dev_resource_interrupt(res, 0, &r)) { + pnpacpi_add_irqresource(dev, &r); + for (i = 1; acpi_dev_resource_interrupt(res, i, &r); i++) + pnpacpi_add_irqresource(dev, &r); + + if (i > 1) { /* * The IRQ encoder puts a single interrupt in each * descriptor, so if a _CRS descriptor has more than * one interrupt, we won't be able to re-encode it. */ - if (pnp_can_write(dev) && irq->interrupt_count > 1) { + if (pnp_can_write(dev)) { dev_warn(&dev->dev, "multiple interrupts in " "_CRS descriptor; configuration can't " "be changed\n"); dev->capabilities &= ~PNP_WRITE; } } - break; + return AE_OK; + } else if (r.flags & IORESOURCE_DISABLED) { + pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); + return AE_OK; + } + switch (res->type) { case ACPI_RESOURCE_TYPE_DMA: dma = &res->data.dma; if (dma->channel_count > 0 && dma->channels[0] != (u8) -1) @@ -383,26 +227,10 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, pnp_add_dma_resource(dev, dma->channels[0], flags); break; - case ACPI_RESOURCE_TYPE_IO: - io = &res->data.io; - pnpacpi_parse_allocated_ioresource(dev, - io->minimum, - io->address_length, - io->io_decode, 0); - break; - case ACPI_RESOURCE_TYPE_START_DEPENDENT: case ACPI_RESOURCE_TYPE_END_DEPENDENT: break; - case ACPI_RESOURCE_TYPE_FIXED_IO: - fixed_io = &res->data.fixed_io; - pnpacpi_parse_allocated_ioresource(dev, - fixed_io->address, - fixed_io->address_length, - ACPI_DECODE_10, 0); - break; - case ACPI_RESOURCE_TYPE_VENDOR: vendor_typed = &res->data.vendor_typed; pnpacpi_parse_allocated_vendor(dev, vendor_typed); @@ -411,66 +239,6 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, case ACPI_RESOURCE_TYPE_END_TAG: break; - case ACPI_RESOURCE_TYPE_MEMORY24: - memory24 = &res->data.memory24; - pnpacpi_parse_allocated_memresource(dev, - memory24->minimum, - memory24->address_length, - memory24->write_protect, 0); - break; - case ACPI_RESOURCE_TYPE_MEMORY32: - memory32 = &res->data.memory32; - pnpacpi_parse_allocated_memresource(dev, - memory32->minimum, - memory32->address_length, - memory32->write_protect, 0); - break; - case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: - fixed_memory32 = &res->data.fixed_memory32; - pnpacpi_parse_allocated_memresource(dev, - fixed_memory32->address, - fixed_memory32->address_length, - fixed_memory32->write_protect, 0); - break; - case ACPI_RESOURCE_TYPE_ADDRESS16: - case ACPI_RESOURCE_TYPE_ADDRESS32: - case ACPI_RESOURCE_TYPE_ADDRESS64: - pnpacpi_parse_allocated_address_space(dev, res); - break; - - case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64: - pnpacpi_parse_allocated_ext_address_space(dev, res); - break; - - case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: - extended_irq = &res->data.extended_irq; - - if (extended_irq->interrupt_count == 0) - pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); - else { - for (i = 0; i < extended_irq->interrupt_count; i++) { - pnpacpi_parse_allocated_irqresource(dev, - extended_irq->interrupts[i], - extended_irq->triggering, - extended_irq->polarity, - extended_irq->sharable); - } - - /* - * The IRQ encoder puts a single interrupt in each - * descriptor, so if a _CRS descriptor has more than - * one interrupt, we won't be able to re-encode it. - */ - if (pnp_can_write(dev) && - extended_irq->interrupt_count > 1) { - dev_warn(&dev->dev, "multiple interrupts in " - "_CRS descriptor; configuration can't " - "be changed\n"); - dev->capabilities &= ~PNP_WRITE; - } - } - break; - case ACPI_RESOURCE_TYPE_GENERIC_REGISTER: break; @@ -531,7 +299,7 @@ static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev, if (p->interrupts[i]) __set_bit(p->interrupts[i], map.bits); - flags = irq_flags(p->triggering, p->polarity, p->sharable); + flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable); pnp_register_irq_resource(dev, option_flags, &map, flags); } @@ -555,7 +323,7 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, } } - flags = irq_flags(p->triggering, p->polarity, p->sharable); + flags = acpi_dev_irq_flags(p->triggering, p->polarity, p->sharable); pnp_register_irq_resource(dev, option_flags, &map, flags); } diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index 9d422264864..5d66e5585f9 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -91,8 +91,6 @@ struct pnp_dev_node_info node_info; * */ -#ifdef CONFIG_HOTPLUG - static struct completion unload_sem; /* @@ -199,8 +197,6 @@ static int pnp_dock_thread(void *unused) complete_and_exit(&unload_sem, 0); } -#endif /* CONFIG_HOTPLUG */ - static int pnpbios_get_resources(struct pnp_dev *dev) { u8 nodenum = dev->number; @@ -573,21 +569,19 @@ fs_initcall(pnpbios_init); static int __init pnpbios_thread_init(void) { + struct task_struct *task; #if defined(CONFIG_PPC) if (check_legacy_ioport(PNPBIOS_BASE)) return 0; #endif if (pnpbios_disabled) return 0; -#ifdef CONFIG_HOTPLUG - { - struct task_struct *task; - init_completion(&unload_sem); - task = kthread_run(pnp_dock_thread, NULL, "kpnpbiosd"); - if (IS_ERR(task)) - return PTR_ERR(task); - } -#endif + + init_completion(&unload_sem); + task = kthread_run(pnp_dock_thread, NULL, "kpnpbiosd"); + if (IS_ERR(task)) + return PTR_ERR(task); + return 0; } diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c index b0ecacbe53b..3e6db1c1dc2 100644 --- a/drivers/pnp/resource.c +++ b/drivers/pnp/resource.c @@ -503,6 +503,22 @@ static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev) return pnp_res; } +struct pnp_resource *pnp_add_resource(struct pnp_dev *dev, + struct resource *res) +{ + struct pnp_resource *pnp_res; + + pnp_res = pnp_new_resource(dev); + if (!pnp_res) { + dev_err(&dev->dev, "can't add resource %pR\n", res); + return NULL; + } + + pnp_res->res = *res; + dev_dbg(&dev->dev, "%pR\n", res); + return pnp_res; +} + struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq, int flags) { diff --git a/drivers/power/88pm860x_battery.c b/drivers/power/88pm860x_battery.c index beed5ecf75e..8bc80b05c63 100644 --- a/drivers/power/88pm860x_battery.c +++ b/drivers/power/88pm860x_battery.c @@ -901,7 +901,7 @@ static enum power_supply_property pm860x_batt_props[] = { POWER_SUPPLY_PROP_TEMP, }; -static __devinit int pm860x_battery_probe(struct platform_device *pdev) +static int pm860x_battery_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); struct pm860x_battery_info *info; @@ -989,7 +989,7 @@ out: return ret; } -static int __devexit pm860x_battery_remove(struct platform_device *pdev) +static int pm860x_battery_remove(struct platform_device *pdev) { struct pm860x_battery_info *info = platform_get_drvdata(pdev); @@ -1033,7 +1033,7 @@ static struct platform_driver pm860x_battery_driver = { .pm = &pm860x_battery_pm_ops, }, .probe = pm860x_battery_probe, - .remove = __devexit_p(pm860x_battery_remove), + .remove = pm860x_battery_remove, }; module_platform_driver(pm860x_battery_driver); diff --git a/drivers/power/88pm860x_charger.c b/drivers/power/88pm860x_charger.c index 2dbeb146090..4b37a5af8de 100644 --- a/drivers/power/88pm860x_charger.c +++ b/drivers/power/88pm860x_charger.c @@ -645,7 +645,7 @@ static struct pm860x_irq_desc { { "vchg", pm860x_vchg_handler }, }; -static __devinit int pm860x_charger_probe(struct platform_device *pdev) +static int pm860x_charger_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); struct pm860x_charger_info *info; @@ -718,7 +718,7 @@ out: return ret; } -static int __devexit pm860x_charger_remove(struct platform_device *pdev) +static int pm860x_charger_remove(struct platform_device *pdev) { struct pm860x_charger_info *info = platform_get_drvdata(pdev); int i; @@ -738,7 +738,7 @@ static struct platform_driver pm860x_charger_driver = { .owner = THIS_MODULE, }, .probe = pm860x_charger_probe, - .remove = __devexit_p(pm860x_charger_remove), + .remove = pm860x_charger_remove, }; module_platform_driver(pm860x_charger_driver); diff --git a/drivers/power/ab8500_btemp.c b/drivers/power/ab8500_btemp.c index e3b6395b20d..989b09950af 100644 --- a/drivers/power/ab8500_btemp.c +++ b/drivers/power/ab8500_btemp.c @@ -938,7 +938,7 @@ static int ab8500_btemp_suspend(struct platform_device *pdev, #define ab8500_btemp_resume NULL #endif -static int __devexit ab8500_btemp_remove(struct platform_device *pdev) +static int ab8500_btemp_remove(struct platform_device *pdev) { struct ab8500_btemp *di = platform_get_drvdata(pdev); int i, irq; @@ -960,7 +960,7 @@ static int __devexit ab8500_btemp_remove(struct platform_device *pdev) return 0; } -static int __devinit ab8500_btemp_probe(struct platform_device *pdev) +static int ab8500_btemp_probe(struct platform_device *pdev) { int irq, i, ret = 0; u8 val; @@ -1101,7 +1101,7 @@ free_device_info: static struct platform_driver ab8500_btemp_driver = { .probe = ab8500_btemp_probe, - .remove = __devexit_p(ab8500_btemp_remove), + .remove = ab8500_btemp_remove, .suspend = ab8500_btemp_suspend, .resume = ab8500_btemp_resume, .driver = { diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c index 26ff759e222..7ecb8abe20b 100644 --- a/drivers/power/ab8500_charger.c +++ b/drivers/power/ab8500_charger.c @@ -2490,7 +2490,7 @@ static int ab8500_charger_suspend(struct platform_device *pdev, #define ab8500_charger_resume NULL #endif -static int __devexit ab8500_charger_remove(struct platform_device *pdev) +static int ab8500_charger_remove(struct platform_device *pdev) { struct ab8500_charger *di = platform_get_drvdata(pdev); int i, irq, ret; @@ -2531,7 +2531,7 @@ static int __devexit ab8500_charger_remove(struct platform_device *pdev) return 0; } -static int __devinit ab8500_charger_probe(struct platform_device *pdev) +static int ab8500_charger_probe(struct platform_device *pdev) { int irq, i, charger_status, ret = 0; struct abx500_bm_plat_data *plat_data = pdev->dev.platform_data; @@ -2765,7 +2765,7 @@ free_device_info: static struct platform_driver ab8500_charger_driver = { .probe = ab8500_charger_probe, - .remove = __devexit_p(ab8500_charger_remove), + .remove = ab8500_charger_remove, .suspend = ab8500_charger_suspend, .resume = ab8500_charger_resume, .driver = { diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c index 2db8cc25439..331dc43ded4 100644 --- a/drivers/power/ab8500_fg.c +++ b/drivers/power/ab8500_fg.c @@ -2411,7 +2411,7 @@ static int ab8500_fg_suspend(struct platform_device *pdev, #define ab8500_fg_resume NULL #endif -static int __devexit ab8500_fg_remove(struct platform_device *pdev) +static int ab8500_fg_remove(struct platform_device *pdev) { int ret = 0; struct ab8500_fg *di = platform_get_drvdata(pdev); @@ -2442,7 +2442,7 @@ static struct ab8500_fg_interrupts ab8500_fg_irq[] = { {"CCEOC", ab8500_fg_cc_data_end_handler}, }; -static int __devinit ab8500_fg_probe(struct platform_device *pdev) +static int ab8500_fg_probe(struct platform_device *pdev) { int i, irq; int ret = 0; @@ -2614,7 +2614,7 @@ free_device_info: static struct platform_driver ab8500_fg_driver = { .probe = ab8500_fg_probe, - .remove = __devexit_p(ab8500_fg_remove), + .remove = ab8500_fg_remove, .suspend = ab8500_fg_suspend, .resume = ab8500_fg_resume, .driver = { diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c index 4d302803ffc..19f25419079 100644 --- a/drivers/power/abx500_chargalg.c +++ b/drivers/power/abx500_chargalg.c @@ -1782,7 +1782,7 @@ static int abx500_chargalg_suspend(struct platform_device *pdev, #define abx500_chargalg_resume NULL #endif -static int __devexit abx500_chargalg_remove(struct platform_device *pdev) +static int abx500_chargalg_remove(struct platform_device *pdev) { struct abx500_chargalg *di = platform_get_drvdata(pdev); @@ -1800,7 +1800,7 @@ static int __devexit abx500_chargalg_remove(struct platform_device *pdev) return 0; } -static int __devinit abx500_chargalg_probe(struct platform_device *pdev) +static int abx500_chargalg_probe(struct platform_device *pdev) { struct abx500_bm_plat_data *plat_data; int ret = 0; @@ -1893,7 +1893,7 @@ free_device_info: static struct platform_driver abx500_chargalg_driver = { .probe = abx500_chargalg_probe, - .remove = __devexit_p(abx500_chargalg_remove), + .remove = abx500_chargalg_remove, .suspend = abx500_chargalg_suspend, .resume = abx500_chargalg_resume, .driver = { diff --git a/drivers/power/avs/smartreflex.c b/drivers/power/avs/smartreflex.c index 24768a27e1d..d0fed2c5cf2 100644 --- a/drivers/power/avs/smartreflex.c +++ b/drivers/power/avs/smartreflex.c @@ -1026,7 +1026,7 @@ err_free_devinfo: return ret; } -static int __devexit omap_sr_remove(struct platform_device *pdev) +static int omap_sr_remove(struct platform_device *pdev) { struct omap_sr_data *pdata = pdev->dev.platform_data; struct omap_sr *sr_info; @@ -1059,7 +1059,7 @@ static int __devexit omap_sr_remove(struct platform_device *pdev) return 0; } -static void __devexit omap_sr_shutdown(struct platform_device *pdev) +static void omap_sr_shutdown(struct platform_device *pdev) { struct omap_sr_data *pdata = pdev->dev.platform_data; struct omap_sr *sr_info; @@ -1083,8 +1083,8 @@ static void __devexit omap_sr_shutdown(struct platform_device *pdev) } static struct platform_driver smartreflex_driver = { - .remove = __devexit_p(omap_sr_remove), - .shutdown = __devexit_p(omap_sr_shutdown), + .remove = omap_sr_remove, + .shutdown = omap_sr_shutdown, .driver = { .name = "smartreflex", }, diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c index 5860d4dfbe9..e0edaf7de54 100644 --- a/drivers/power/bq27x00_battery.c +++ b/drivers/power/bq27x00_battery.c @@ -926,7 +926,7 @@ static int bq27000_read_platform(struct bq27x00_device_info *di, u8 reg, return pdata->read(dev, reg); } -static int __devinit bq27000_battery_probe(struct platform_device *pdev) +static int bq27000_battery_probe(struct platform_device *pdev) { struct bq27x00_device_info *di; struct bq27000_platform_data *pdata = pdev->dev.platform_data; @@ -969,7 +969,7 @@ err_free: return ret; } -static int __devexit bq27000_battery_remove(struct platform_device *pdev) +static int bq27000_battery_remove(struct platform_device *pdev) { struct bq27x00_device_info *di = platform_get_drvdata(pdev); @@ -983,7 +983,7 @@ static int __devexit bq27000_battery_remove(struct platform_device *pdev) static struct platform_driver bq27000_battery_driver = { .probe = bq27000_battery_probe, - .remove = __devexit_p(bq27000_battery_remove), + .remove = bq27000_battery_remove, .driver = { .name = "bq27000-battery", .owner = THIS_MODULE, diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c index 8a0aca6364c..adb3a4b59cb 100644 --- a/drivers/power/charger-manager.c +++ b/drivers/power/charger-manager.c @@ -1655,7 +1655,7 @@ err_alloc: return ret; } -static int __devexit charger_manager_remove(struct platform_device *pdev) +static int charger_manager_remove(struct platform_device *pdev) { struct charger_manager *cm = platform_get_drvdata(pdev); struct charger_desc *desc = cm->desc; @@ -1812,7 +1812,7 @@ static struct platform_driver charger_manager_driver = { .pm = &charger_manager_pm, }, .probe = charger_manager_probe, - .remove = __devexit_p(charger_manager_remove), + .remove = charger_manager_remove, .id_table = charger_manager_id, }; diff --git a/drivers/power/collie_battery.c b/drivers/power/collie_battery.c index b19bfe400f8..c58d0e31bde 100644 --- a/drivers/power/collie_battery.c +++ b/drivers/power/collie_battery.c @@ -305,7 +305,7 @@ static int collie_bat_resume(struct ucb1x00_dev *dev) #define collie_bat_resume NULL #endif -static int __devinit collie_bat_probe(struct ucb1x00_dev *dev) +static int collie_bat_probe(struct ucb1x00_dev *dev) { int ret; @@ -349,7 +349,7 @@ err_psy_reg_main: return ret; } -static void __devexit collie_bat_remove(struct ucb1x00_dev *dev) +static void collie_bat_remove(struct ucb1x00_dev *dev) { free_irq(gpio_to_irq(COLLIE_GPIO_CO), &collie_bat_main); @@ -367,7 +367,7 @@ static void __devexit collie_bat_remove(struct ucb1x00_dev *dev) static struct ucb1x00_driver collie_bat_driver = { .add = collie_bat_probe, - .remove = __devexit_p(collie_bat_remove), + .remove = collie_bat_remove, .suspend = collie_bat_suspend, .resume = collie_bat_resume, }; diff --git a/drivers/power/da9052-battery.c b/drivers/power/da9052-battery.c index d9d034d7496..bb0df8917ad 100644 --- a/drivers/power/da9052-battery.c +++ b/drivers/power/da9052-battery.c @@ -576,7 +576,7 @@ static const char *const da9052_bat_irqs[] = { "CHG END", }; -static s32 __devinit da9052_bat_probe(struct platform_device *pdev) +static s32 da9052_bat_probe(struct platform_device *pdev) { struct da9052_pdata *pdata; struct da9052_battery *bat; @@ -630,7 +630,7 @@ err: kfree(bat); return ret; } -static int __devexit da9052_bat_remove(struct platform_device *pdev) +static int da9052_bat_remove(struct platform_device *pdev) { int i; int irq; @@ -648,7 +648,7 @@ static int __devexit da9052_bat_remove(struct platform_device *pdev) static struct platform_driver da9052_bat_driver = { .probe = da9052_bat_probe, - .remove = __devexit_p(da9052_bat_remove), + .remove = da9052_bat_remove, .driver = { .name = "da9052-bat", .owner = THIS_MODULE, diff --git a/drivers/power/ds2780_battery.c b/drivers/power/ds2780_battery.c index 74fad941c56..8b6c4539e7f 100644 --- a/drivers/power/ds2780_battery.c +++ b/drivers/power/ds2780_battery.c @@ -755,7 +755,7 @@ static const struct attribute_group ds2780_attr_group = { .attrs = ds2780_attributes, }; -static int __devinit ds2780_battery_probe(struct platform_device *pdev) +static int ds2780_battery_probe(struct platform_device *pdev) { int ret = 0; struct ds2780_device_info *dev_info; @@ -819,7 +819,7 @@ fail: return ret; } -static int __devexit ds2780_battery_remove(struct platform_device *pdev) +static int ds2780_battery_remove(struct platform_device *pdev) { struct ds2780_device_info *dev_info = platform_get_drvdata(pdev); @@ -837,7 +837,7 @@ static struct platform_driver ds2780_battery_driver = { .name = "ds2780-battery", }, .probe = ds2780_battery_probe, - .remove = __devexit_p(ds2780_battery_remove), + .remove = ds2780_battery_remove, }; module_platform_driver(ds2780_battery_driver); diff --git a/drivers/power/ds2781_battery.c b/drivers/power/ds2781_battery.c index 22b3c8c9355..0a5acc6fc6f 100644 --- a/drivers/power/ds2781_battery.c +++ b/drivers/power/ds2781_battery.c @@ -750,7 +750,7 @@ static const struct attribute_group ds2781_attr_group = { .attrs = ds2781_attributes, }; -static int __devinit ds2781_battery_probe(struct platform_device *pdev) +static int ds2781_battery_probe(struct platform_device *pdev) { int ret = 0; struct ds2781_device_info *dev_info; @@ -810,7 +810,7 @@ fail: return ret; } -static int __devexit ds2781_battery_remove(struct platform_device *pdev) +static int ds2781_battery_remove(struct platform_device *pdev) { struct ds2781_device_info *dev_info = platform_get_drvdata(pdev); @@ -827,7 +827,7 @@ static struct platform_driver ds2781_battery_driver = { .name = "ds2781-battery", }, .probe = ds2781_battery_probe, - .remove = __devexit_p(ds2781_battery_remove), + .remove = ds2781_battery_remove, }; module_platform_driver(ds2781_battery_driver); diff --git a/drivers/power/generic-adc-battery.c b/drivers/power/generic-adc-battery.c index 9bdf4447039..e902b088d52 100644 --- a/drivers/power/generic-adc-battery.c +++ b/drivers/power/generic-adc-battery.c @@ -236,7 +236,7 @@ static irqreturn_t gab_charged(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit gab_probe(struct platform_device *pdev) +static int gab_probe(struct platform_device *pdev) { struct gab *adc_bat; struct power_supply *psy; @@ -351,7 +351,7 @@ first_mem_fail: return ret; } -static int __devexit gab_remove(struct platform_device *pdev) +static int gab_remove(struct platform_device *pdev) { int chan; struct gab *adc_bat = platform_get_drvdata(pdev); @@ -413,7 +413,7 @@ static struct platform_driver gab_driver = { .pm = GAB_PM_OPS }, .probe = gab_probe, - .remove = __devexit_p(gab_remove), + .remove = gab_remove, }; module_platform_driver(gab_driver); diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c index cb2aa319568..e3e40a9f3af 100644 --- a/drivers/power/gpio-charger.c +++ b/drivers/power/gpio-charger.c @@ -68,7 +68,7 @@ static enum power_supply_property gpio_charger_properties[] = { POWER_SUPPLY_PROP_ONLINE, }; -static int __devinit gpio_charger_probe(struct platform_device *pdev) +static int gpio_charger_probe(struct platform_device *pdev) { const struct gpio_charger_platform_data *pdata = pdev->dev.platform_data; struct gpio_charger *gpio_charger; @@ -144,7 +144,7 @@ err_free: return ret; } -static int __devexit gpio_charger_remove(struct platform_device *pdev) +static int gpio_charger_remove(struct platform_device *pdev) { struct gpio_charger *gpio_charger = platform_get_drvdata(pdev); @@ -177,7 +177,7 @@ static SIMPLE_DEV_PM_OPS(gpio_charger_pm_ops, NULL, gpio_charger_resume); static struct platform_driver gpio_charger_driver = { .probe = gpio_charger_probe, - .remove = __devexit_p(gpio_charger_remove), + .remove = gpio_charger_remove, .driver = { .name = "gpio-charger", .owner = THIS_MODULE, diff --git a/drivers/power/intel_mid_battery.c b/drivers/power/intel_mid_battery.c index d09649706bd..18d136b443e 100644 --- a/drivers/power/intel_mid_battery.c +++ b/drivers/power/intel_mid_battery.c @@ -649,7 +649,7 @@ static void pmic_battery_handle_intrpt(struct work_struct *work) * PMIC battery initializes its internal data structue and other * infrastructure components for it to work as expected. */ -static __devinit int probe(int irq, struct device *dev) +static int probe(int irq, struct device *dev) { int retval = 0; struct pmic_power_module_info *pbi; @@ -739,7 +739,7 @@ wqueue_failed: return retval; } -static int __devinit platform_pmic_battery_probe(struct platform_device *pdev) +static int platform_pmic_battery_probe(struct platform_device *pdev) { return probe(pdev->id, &pdev->dev); } @@ -754,7 +754,7 @@ static int __devinit platform_pmic_battery_probe(struct platform_device *pdev) * pmic_battery_probe. */ -static int __devexit platform_pmic_battery_remove(struct platform_device *pdev) +static int platform_pmic_battery_remove(struct platform_device *pdev) { struct pmic_power_module_info *pbi = dev_get_drvdata(&pdev->dev); @@ -776,7 +776,7 @@ static struct platform_driver platform_pmic_battery_driver = { .owner = THIS_MODULE, }, .probe = platform_pmic_battery_probe, - .remove = __devexit_p(platform_pmic_battery_remove), + .remove = platform_pmic_battery_remove, }; module_platform_driver(platform_pmic_battery_driver); diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c index 122911978da..176ad59d99f 100644 --- a/drivers/power/isp1704_charger.c +++ b/drivers/power/isp1704_charger.c @@ -406,7 +406,7 @@ static inline int isp1704_test_ulpi(struct isp1704_charger *isp) return -ENODEV; } -static int __devinit isp1704_charger_probe(struct platform_device *pdev) +static int isp1704_charger_probe(struct platform_device *pdev) { struct isp1704_charger *isp; int ret = -ENODEV; @@ -484,7 +484,7 @@ fail0: return ret; } -static int __devexit isp1704_charger_remove(struct platform_device *pdev) +static int isp1704_charger_remove(struct platform_device *pdev) { struct isp1704_charger *isp = platform_get_drvdata(pdev); @@ -502,7 +502,7 @@ static struct platform_driver isp1704_charger_driver = { .name = "isp1704_charger", }, .probe = isp1704_charger_probe, - .remove = __devexit_p(isp1704_charger_remove), + .remove = isp1704_charger_remove, }; module_platform_driver(isp1704_charger_driver); diff --git a/drivers/power/jz4740-battery.c b/drivers/power/jz4740-battery.c index ffbed5e5b94..74ac69e0687 100644 --- a/drivers/power/jz4740-battery.c +++ b/drivers/power/jz4740-battery.c @@ -238,7 +238,7 @@ static void jz_battery_work(struct work_struct *work) schedule_delayed_work(&jz_battery->work, interval); } -static int __devinit jz_battery_probe(struct platform_device *pdev) +static int jz_battery_probe(struct platform_device *pdev) { int ret = 0; struct jz_battery_platform_data *pdata = pdev->dev.parent->platform_data; @@ -376,7 +376,7 @@ err_free: return ret; } -static int __devexit jz_battery_remove(struct platform_device *pdev) +static int jz_battery_remove(struct platform_device *pdev) { struct jz_battery *jz_battery = platform_get_drvdata(pdev); @@ -431,7 +431,7 @@ static const struct dev_pm_ops jz_battery_pm_ops = { static struct platform_driver jz_battery_driver = { .probe = jz_battery_probe, - .remove = __devexit_p(jz_battery_remove), + .remove = jz_battery_remove, .driver = { .name = "jz4740-battery", .owner = THIS_MODULE, diff --git a/drivers/power/lp8727_charger.c b/drivers/power/lp8727_charger.c index c628224b7f5..4ee71a90e24 100644 --- a/drivers/power/lp8727_charger.c +++ b/drivers/power/lp8727_charger.c @@ -522,7 +522,7 @@ static int lp8727_probe(struct i2c_client *cl, const struct i2c_device_id *id) return 0; } -static int __devexit lp8727_remove(struct i2c_client *cl) +static int lp8727_remove(struct i2c_client *cl) { struct lp8727_chg *pchg = i2c_get_clientdata(cl); @@ -542,7 +542,7 @@ static struct i2c_driver lp8727_driver = { .name = "lp8727", }, .probe = lp8727_probe, - .remove = __devexit_p(lp8727_remove), + .remove = lp8727_remove, .id_table = lp8727_ids, }; module_i2c_driver(lp8727_driver); diff --git a/drivers/power/lp8788-charger.c b/drivers/power/lp8788-charger.c index e852d12cd07..a1c51ac117f 100644 --- a/drivers/power/lp8788-charger.c +++ b/drivers/power/lp8788-charger.c @@ -729,7 +729,7 @@ static const struct attribute_group lp8788_attr_group = { .attrs = lp8788_charger_attr, }; -static __devinit int lp8788_charger_probe(struct platform_device *pdev) +static int lp8788_charger_probe(struct platform_device *pdev) { struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); struct lp8788_charger *pchg; @@ -766,7 +766,7 @@ static __devinit int lp8788_charger_probe(struct platform_device *pdev) return 0; } -static int __devexit lp8788_charger_remove(struct platform_device *pdev) +static int lp8788_charger_remove(struct platform_device *pdev) { struct lp8788_charger *pchg = platform_get_drvdata(pdev); @@ -781,7 +781,7 @@ static int __devexit lp8788_charger_remove(struct platform_device *pdev) static struct platform_driver lp8788_charger_driver = { .probe = lp8788_charger_probe, - .remove = __devexit_p(lp8788_charger_remove), + .remove = lp8788_charger_remove, .driver = { .name = LP8788_DEV_CHARGER, .owner = THIS_MODULE, diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c index 58e67830143..22cfe9cc472 100644 --- a/drivers/power/max17040_battery.c +++ b/drivers/power/max17040_battery.c @@ -197,7 +197,7 @@ static enum power_supply_property max17040_battery_props[] = { POWER_SUPPLY_PROP_CAPACITY, }; -static int __devinit max17040_probe(struct i2c_client *client, +static int max17040_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); @@ -238,7 +238,7 @@ static int __devinit max17040_probe(struct i2c_client *client, return 0; } -static int __devexit max17040_remove(struct i2c_client *client) +static int max17040_remove(struct i2c_client *client) { struct max17040_chip *chip = i2c_get_clientdata(client); @@ -285,7 +285,7 @@ static struct i2c_driver max17040_i2c_driver = { .name = "max17040", }, .probe = max17040_probe, - .remove = __devexit_p(max17040_remove), + .remove = max17040_remove, .suspend = max17040_suspend, .resume = max17040_resume, .id_table = max17040_id, diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c index 74abc6c755b..5ffe46916f0 100644 --- a/drivers/power/max17042_battery.c +++ b/drivers/power/max17042_battery.c @@ -681,7 +681,7 @@ max17042_get_pdata(struct device *dev) } #endif -static int __devinit max17042_probe(struct i2c_client *client, +static int max17042_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); @@ -775,7 +775,7 @@ static int __devinit max17042_probe(struct i2c_client *client, return 0; } -static int __devexit max17042_remove(struct i2c_client *client) +static int max17042_remove(struct i2c_client *client) { struct max17042_chip *chip = i2c_get_clientdata(client); @@ -851,7 +851,7 @@ static struct i2c_driver max17042_i2c_driver = { .pm = MAX17042_PM_OPS, }, .probe = max17042_probe, - .remove = __devexit_p(max17042_remove), + .remove = max17042_remove, .id_table = max17042_id, }; module_i2c_driver(max17042_i2c_driver); diff --git a/drivers/power/max8903_charger.c b/drivers/power/max8903_charger.c index 3e23f43e98a..14e2b96d93b 100644 --- a/drivers/power/max8903_charger.c +++ b/drivers/power/max8903_charger.c @@ -179,7 +179,7 @@ static irqreturn_t max8903_fault(int irq, void *_data) return IRQ_HANDLED; } -static __devinit int max8903_probe(struct platform_device *pdev) +static int max8903_probe(struct platform_device *pdev) { struct max8903_data *data; struct device *dev = &pdev->dev; @@ -345,7 +345,7 @@ err: return ret; } -static __devexit int max8903_remove(struct platform_device *pdev) +static int max8903_remove(struct platform_device *pdev) { struct max8903_data *data = platform_get_drvdata(pdev); @@ -367,7 +367,7 @@ static __devexit int max8903_remove(struct platform_device *pdev) static struct platform_driver max8903_driver = { .probe = max8903_probe, - .remove = __devexit_p(max8903_remove), + .remove = max8903_remove, .driver = { .name = "max8903-charger", .owner = THIS_MODULE, diff --git a/drivers/power/max8925_power.c b/drivers/power/max8925_power.c index daa333bd7eb..1a075f1f1b6 100644 --- a/drivers/power/max8925_power.c +++ b/drivers/power/max8925_power.c @@ -356,7 +356,7 @@ do { \ _irq, ret); \ } while (0) -static __devinit int max8925_init_charger(struct max8925_chip *chip, +static int max8925_init_charger(struct max8925_chip *chip, struct max8925_power_info *info) { int ret; @@ -414,7 +414,7 @@ static __devinit int max8925_init_charger(struct max8925_chip *chip, return 0; } -static __devexit int max8925_deinit_charger(struct max8925_power_info *info) +static int max8925_deinit_charger(struct max8925_power_info *info) { struct max8925_chip *chip = info->chip; int irq; @@ -426,7 +426,7 @@ static __devexit int max8925_deinit_charger(struct max8925_power_info *info) return 0; } -static __devinit int max8925_power_probe(struct platform_device *pdev) +static int max8925_power_probe(struct platform_device *pdev) { struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); struct max8925_power_pdata *pdata = NULL; @@ -501,7 +501,7 @@ out: return ret; } -static __devexit int max8925_power_remove(struct platform_device *pdev) +static int max8925_power_remove(struct platform_device *pdev) { struct max8925_power_info *info = platform_get_drvdata(pdev); @@ -517,7 +517,7 @@ static __devexit int max8925_power_remove(struct platform_device *pdev) static struct platform_driver max8925_power_driver = { .probe = max8925_power_probe, - .remove = __devexit_p(max8925_power_remove), + .remove = max8925_power_remove, .driver = { .name = "max8925-power", }, diff --git a/drivers/power/max8997_charger.c b/drivers/power/max8997_charger.c index 6e88c5d026b..e757885b620 100644 --- a/drivers/power/max8997_charger.c +++ b/drivers/power/max8997_charger.c @@ -86,7 +86,7 @@ static int max8997_battery_get_property(struct power_supply *psy, return 0; } -static __devinit int max8997_battery_probe(struct platform_device *pdev) +static int max8997_battery_probe(struct platform_device *pdev) { int ret = 0; struct charger_data *charger; @@ -167,7 +167,7 @@ err: return ret; } -static int __devexit max8997_battery_remove(struct platform_device *pdev) +static int max8997_battery_remove(struct platform_device *pdev) { struct charger_data *charger = platform_get_drvdata(pdev); @@ -187,7 +187,7 @@ static struct platform_driver max8997_battery_driver = { .owner = THIS_MODULE, }, .probe = max8997_battery_probe, - .remove = __devexit_p(max8997_battery_remove), + .remove = max8997_battery_remove, .id_table = max8997_battery_id, }; diff --git a/drivers/power/max8998_charger.c b/drivers/power/max8998_charger.c index 6dc01c25559..bf677e3daec 100644 --- a/drivers/power/max8998_charger.c +++ b/drivers/power/max8998_charger.c @@ -75,7 +75,7 @@ static int max8998_battery_get_property(struct power_supply *psy, return 0; } -static __devinit int max8998_battery_probe(struct platform_device *pdev) +static int max8998_battery_probe(struct platform_device *pdev) { struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev); @@ -178,7 +178,7 @@ err: return ret; } -static int __devexit max8998_battery_remove(struct platform_device *pdev) +static int max8998_battery_remove(struct platform_device *pdev) { struct max8998_battery_data *max8998 = platform_get_drvdata(pdev); @@ -199,7 +199,7 @@ static struct platform_driver max8998_battery_driver = { .owner = THIS_MODULE, }, .probe = max8998_battery_probe, - .remove = __devexit_p(max8998_battery_remove), + .remove = max8998_battery_remove, .id_table = max8998_battery_id, }; diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index a89a41acf9c..298c47d111b 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -598,7 +598,7 @@ static int olpc_battery_suspend(struct platform_device *pdev, return 0; } -static int __devinit olpc_battery_probe(struct platform_device *pdev) +static int olpc_battery_probe(struct platform_device *pdev) { int ret; uint8_t status; @@ -659,7 +659,7 @@ battery_failed: return ret; } -static int __devexit olpc_battery_remove(struct platform_device *pdev) +static int olpc_battery_remove(struct platform_device *pdev) { device_remove_file(olpc_bat.dev, &olpc_bat_error); device_remove_bin_file(olpc_bat.dev, &olpc_bat_eeprom); @@ -681,7 +681,7 @@ static struct platform_driver olpc_battery_driver = { .of_match_table = olpc_battery_ids, }, .probe = olpc_battery_probe, - .remove = __devexit_p(olpc_battery_remove), + .remove = olpc_battery_remove, .suspend = olpc_battery_suspend, }; diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c index 3d1e9efb6f5..c2122a7ad06 100644 --- a/drivers/power/pcf50633-charger.c +++ b/drivers/power/pcf50633-charger.c @@ -366,7 +366,7 @@ static const u8 mbc_irq_handlers[] = { PCF50633_IRQ_LOWBAT, }; -static int __devinit pcf50633_mbc_probe(struct platform_device *pdev) +static int pcf50633_mbc_probe(struct platform_device *pdev) { struct pcf50633_mbc *mbc; int ret; @@ -447,7 +447,7 @@ static int __devinit pcf50633_mbc_probe(struct platform_device *pdev) return 0; } -static int __devexit pcf50633_mbc_remove(struct platform_device *pdev) +static int pcf50633_mbc_remove(struct platform_device *pdev) { struct pcf50633_mbc *mbc = platform_get_drvdata(pdev); int i; @@ -471,7 +471,7 @@ static struct platform_driver pcf50633_mbc_driver = { .name = "pcf50633-mbc", }, .probe = pcf50633_mbc_probe, - .remove = __devexit_p(pcf50633_mbc_remove), + .remove = pcf50633_mbc_remove, }; module_platform_driver(pcf50633_mbc_driver); diff --git a/drivers/power/s3c_adc_battery.c b/drivers/power/s3c_adc_battery.c index 8b804a56675..d2ca989dcbd 100644 --- a/drivers/power/s3c_adc_battery.c +++ b/drivers/power/s3c_adc_battery.c @@ -286,7 +286,7 @@ static irqreturn_t s3c_adc_bat_charged(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit s3c_adc_bat_probe(struct platform_device *pdev) +static int s3c_adc_bat_probe(struct platform_device *pdev) { struct s3c_adc_client *client; struct s3c_adc_bat_pdata *pdata = pdev->dev.platform_data; diff --git a/drivers/power/sbs-battery.c b/drivers/power/sbs-battery.c index 4146596d254..3960f0b2afe 100644 --- a/drivers/power/sbs-battery.c +++ b/drivers/power/sbs-battery.c @@ -675,7 +675,7 @@ static struct sbs_platform_data *sbs_of_populate_pdata( } #endif -static int __devinit sbs_probe(struct i2c_client *client, +static int sbs_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct sbs_info *chip; @@ -800,7 +800,7 @@ exit_free_name: return rc; } -static int __devexit sbs_remove(struct i2c_client *client) +static int sbs_remove(struct i2c_client *client) { struct sbs_info *chip = i2c_get_clientdata(client); @@ -853,7 +853,7 @@ MODULE_DEVICE_TABLE(i2c, sbs_id); static struct i2c_driver sbs_battery_driver = { .probe = sbs_probe, - .remove = __devexit_p(sbs_remove), + .remove = sbs_remove, .suspend = sbs_suspend, .resume = sbs_resume, .id_table = sbs_id, diff --git a/drivers/power/smb347-charger.c b/drivers/power/smb347-charger.c index a9707c11fbe..acf84e80fe9 100644 --- a/drivers/power/smb347-charger.c +++ b/drivers/power/smb347-charger.c @@ -1313,7 +1313,7 @@ static struct i2c_driver smb347_driver = { .name = "smb347", }, .probe = smb347_probe, - .remove = __devexit_p(smb347_remove), + .remove = smb347_remove, .id_table = smb347_id, }; diff --git a/drivers/power/tosa_battery.c b/drivers/power/tosa_battery.c index 51199b5ce22..0224de50c54 100644 --- a/drivers/power/tosa_battery.c +++ b/drivers/power/tosa_battery.c @@ -342,7 +342,7 @@ static int tosa_bat_resume(struct platform_device *dev) #define tosa_bat_resume NULL #endif -static int __devinit tosa_bat_probe(struct platform_device *dev) +static int tosa_bat_probe(struct platform_device *dev) { int ret; @@ -409,7 +409,7 @@ err_psy_reg_main: return ret; } -static int __devexit tosa_bat_remove(struct platform_device *dev) +static int tosa_bat_remove(struct platform_device *dev) { free_irq(gpio_to_irq(TOSA_GPIO_JACKET_DETECT), &tosa_bat_jacket); free_irq(gpio_to_irq(TOSA_GPIO_BAT1_CRG), &tosa_bat_jacket); @@ -433,7 +433,7 @@ static struct platform_driver tosa_bat_driver = { .driver.name = "wm97xx-battery", .driver.owner = THIS_MODULE, .probe = tosa_bat_probe, - .remove = __devexit_p(tosa_bat_remove), + .remove = tosa_bat_remove, .suspend = tosa_bat_suspend, .resume = tosa_bat_resume, }; diff --git a/drivers/power/wm831x_backup.c b/drivers/power/wm831x_backup.c index 6243e697512..d9cc169f142 100644 --- a/drivers/power/wm831x_backup.c +++ b/drivers/power/wm831x_backup.c @@ -161,7 +161,7 @@ static enum power_supply_property wm831x_backup_props[] = { * Initialisation *********************************************************************/ -static __devinit int wm831x_backup_probe(struct platform_device *pdev) +static int wm831x_backup_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data; @@ -207,7 +207,7 @@ err_kmalloc: return ret; } -static __devexit int wm831x_backup_remove(struct platform_device *pdev) +static int wm831x_backup_remove(struct platform_device *pdev) { struct wm831x_backup *devdata = platform_get_drvdata(pdev); @@ -220,7 +220,7 @@ static __devexit int wm831x_backup_remove(struct platform_device *pdev) static struct platform_driver wm831x_backup_driver = { .probe = wm831x_backup_probe, - .remove = __devexit_p(wm831x_backup_remove), + .remove = wm831x_backup_remove, .driver = { .name = "wm831x-backup", }, diff --git a/drivers/power/wm831x_power.c b/drivers/power/wm831x_power.c index fc1ad955118..3bed2f55cf7 100644 --- a/drivers/power/wm831x_power.c +++ b/drivers/power/wm831x_power.c @@ -489,7 +489,7 @@ static irqreturn_t wm831x_pwr_src_irq(int irq, void *data) return IRQ_HANDLED; } -static __devinit int wm831x_power_probe(struct platform_device *pdev) +static int wm831x_power_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *wm831x_pdata = wm831x->dev->platform_data; @@ -625,7 +625,7 @@ err_kmalloc: return ret; } -static __devexit int wm831x_power_remove(struct platform_device *pdev) +static int wm831x_power_remove(struct platform_device *pdev) { struct wm831x_power *wm831x_power = platform_get_drvdata(pdev); struct wm831x *wm831x = wm831x_power->wm831x; @@ -654,7 +654,7 @@ static __devexit int wm831x_power_remove(struct platform_device *pdev) static struct platform_driver wm831x_power_driver = { .probe = wm831x_power_probe, - .remove = __devexit_p(wm831x_power_remove), + .remove = wm831x_power_remove, .driver = { .name = "wm831x-power", }, diff --git a/drivers/power/wm8350_power.c b/drivers/power/wm8350_power.c index fae04d38465..b3607e2906d 100644 --- a/drivers/power/wm8350_power.c +++ b/drivers/power/wm8350_power.c @@ -442,7 +442,7 @@ static void free_charger_irq(struct wm8350 *wm8350) wm8350_free_irq(wm8350, WM8350_IRQ_EXT_BAT_FB, wm8350); } -static __devinit int wm8350_power_probe(struct platform_device *pdev) +static int wm8350_power_probe(struct platform_device *pdev) { struct wm8350 *wm8350 = platform_get_drvdata(pdev); struct wm8350_power *power = &wm8350->power; @@ -501,7 +501,7 @@ battery_failed: return ret; } -static __devexit int wm8350_power_remove(struct platform_device *pdev) +static int wm8350_power_remove(struct platform_device *pdev) { struct wm8350 *wm8350 = platform_get_drvdata(pdev); struct wm8350_power *power = &wm8350->power; @@ -516,7 +516,7 @@ static __devexit int wm8350_power_remove(struct platform_device *pdev) static struct platform_driver wm8350_power_driver = { .probe = wm8350_power_probe, - .remove = __devexit_p(wm8350_power_remove), + .remove = wm8350_power_remove, .driver = { .name = "wm8350-power", }, diff --git a/drivers/power/wm97xx_battery.c b/drivers/power/wm97xx_battery.c index e128a813dc2..58f7348e6c2 100644 --- a/drivers/power/wm97xx_battery.c +++ b/drivers/power/wm97xx_battery.c @@ -162,7 +162,7 @@ static const struct dev_pm_ops wm97xx_bat_pm_ops = { }; #endif -static int __devinit wm97xx_bat_probe(struct platform_device *dev) +static int wm97xx_bat_probe(struct platform_device *dev) { int ret = 0; int props = 1; /* POWER_SUPPLY_PROP_PRESENT */ @@ -263,7 +263,7 @@ err: return ret; } -static int __devexit wm97xx_bat_remove(struct platform_device *dev) +static int wm97xx_bat_remove(struct platform_device *dev) { struct wm97xx_pdata *wmdata = dev->dev.platform_data; struct wm97xx_batt_pdata *pdata = wmdata->batt_pdata; @@ -287,7 +287,7 @@ static struct platform_driver wm97xx_bat_driver = { #endif }, .probe = wm97xx_bat_probe, - .remove = __devexit_p(wm97xx_bat_remove), + .remove = wm97xx_bat_remove, }; module_platform_driver(wm97xx_bat_driver); diff --git a/drivers/power/z2_battery.c b/drivers/power/z2_battery.c index 5757d0d6782..814d2e31f0c 100644 --- a/drivers/power/z2_battery.c +++ b/drivers/power/z2_battery.c @@ -180,7 +180,7 @@ static int z2_batt_ps_init(struct z2_charger *charger, int props) return 0; } -static int __devinit z2_batt_probe(struct i2c_client *client, +static int z2_batt_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret = 0; @@ -251,7 +251,7 @@ err: return ret; } -static int __devexit z2_batt_remove(struct i2c_client *client) +static int z2_batt_remove(struct i2c_client *client) { struct z2_charger *charger = i2c_get_clientdata(client); struct z2_battery_info *info = charger->info; @@ -313,7 +313,7 @@ static struct i2c_driver z2_batt_driver = { .pm = Z2_BATTERY_PM_OPS }, .probe = z2_batt_probe, - .remove = __devexit_p(z2_batt_remove), + .remove = z2_batt_remove, .id_table = z2_batt_id, }; module_i2c_driver(z2_batt_driver); diff --git a/drivers/ptp/ptp_pch.c b/drivers/ptp/ptp_pch.c index e624e4dd2ab..1367655eee3 100644 --- a/drivers/ptp/ptp_pch.c +++ b/drivers/ptp/ptp_pch.c @@ -557,7 +557,7 @@ static s32 pch_resume(struct pci_dev *pdev) #define pch_resume NULL #endif -static void __devexit pch_remove(struct pci_dev *pdev) +static void pch_remove(struct pci_dev *pdev) { struct pch_dev *chip = pci_get_drvdata(pdev); @@ -581,7 +581,7 @@ static void __devexit pch_remove(struct pci_dev *pdev) dev_info(&pdev->dev, "complete\n"); } -static s32 __devinit +static s32 pch_probe(struct pci_dev *pdev, const struct pci_device_id *id) { s32 ret; diff --git a/drivers/pwm/pwm-ab8500.c b/drivers/pwm/pwm-ab8500.c index cfb72ca873d..4248d041827 100644 --- a/drivers/pwm/pwm-ab8500.c +++ b/drivers/pwm/pwm-ab8500.c @@ -90,7 +90,7 @@ static const struct pwm_ops ab8500_pwm_ops = { .disable = ab8500_pwm_disable, }; -static int __devinit ab8500_pwm_probe(struct platform_device *pdev) +static int ab8500_pwm_probe(struct platform_device *pdev) { struct ab8500_pwm_chip *ab8500; int err; @@ -122,7 +122,7 @@ static int __devinit ab8500_pwm_probe(struct platform_device *pdev) return 0; } -static int __devexit ab8500_pwm_remove(struct platform_device *pdev) +static int ab8500_pwm_remove(struct platform_device *pdev) { struct ab8500_pwm_chip *ab8500 = platform_get_drvdata(pdev); int err; @@ -143,7 +143,7 @@ static struct platform_driver ab8500_pwm_driver = { .owner = THIS_MODULE, }, .probe = ab8500_pwm_probe, - .remove = __devexit_p(ab8500_pwm_remove), + .remove = ab8500_pwm_remove, }; module_platform_driver(ab8500_pwm_driver); diff --git a/drivers/pwm/pwm-bfin.c b/drivers/pwm/pwm-bfin.c index 5da8e185e83..7631ef194de 100644 --- a/drivers/pwm/pwm-bfin.c +++ b/drivers/pwm/pwm-bfin.c @@ -139,7 +139,7 @@ static int bfin_pwm_probe(struct platform_device *pdev) return 0; } -static int __devexit bfin_pwm_remove(struct platform_device *pdev) +static int bfin_pwm_remove(struct platform_device *pdev) { struct bfin_pwm_chip *pwm = platform_get_drvdata(pdev); @@ -151,7 +151,7 @@ static struct platform_driver bfin_pwm_driver = { .name = "bfin-pwm", }, .probe = bfin_pwm_probe, - .remove = __devexit_p(bfin_pwm_remove), + .remove = bfin_pwm_remove, }; module_platform_driver(bfin_pwm_driver); diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 8a5d3ae2946..8f26e9fcea9 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -231,7 +231,7 @@ static const struct of_device_id imx_pwm_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, imx_pwm_dt_ids); -static int __devinit imx_pwm_probe(struct platform_device *pdev) +static int imx_pwm_probe(struct platform_device *pdev) { const struct of_device_id *of_id = of_match_device(imx_pwm_dt_ids, &pdev->dev); @@ -290,7 +290,7 @@ static int __devinit imx_pwm_probe(struct platform_device *pdev) return 0; } -static int __devexit imx_pwm_remove(struct platform_device *pdev) +static int imx_pwm_remove(struct platform_device *pdev) { struct imx_chip *imx; @@ -307,7 +307,7 @@ static struct platform_driver imx_pwm_driver = { .of_match_table = of_match_ptr(imx_pwm_dt_ids), }, .probe = imx_pwm_probe, - .remove = __devexit_p(imx_pwm_remove), + .remove = imx_pwm_remove, }; module_platform_driver(imx_pwm_driver); diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c index 10250fcefb9..0a2ede3c393 100644 --- a/drivers/pwm/pwm-jz4740.c +++ b/drivers/pwm/pwm-jz4740.c @@ -162,7 +162,7 @@ static const struct pwm_ops jz4740_pwm_ops = { .owner = THIS_MODULE, }; -static int __devinit jz4740_pwm_probe(struct platform_device *pdev) +static int jz4740_pwm_probe(struct platform_device *pdev) { struct jz4740_pwm_chip *jz4740; int ret; @@ -191,7 +191,7 @@ static int __devinit jz4740_pwm_probe(struct platform_device *pdev) return 0; } -static int __devexit jz4740_pwm_remove(struct platform_device *pdev) +static int jz4740_pwm_remove(struct platform_device *pdev) { struct jz4740_pwm_chip *jz4740 = platform_get_drvdata(pdev); int ret; @@ -211,7 +211,7 @@ static struct platform_driver jz4740_pwm_driver = { .owner = THIS_MODULE, }, .probe = jz4740_pwm_probe, - .remove = __devexit_p(jz4740_pwm_remove), + .remove = jz4740_pwm_remove, }; module_platform_driver(jz4740_pwm_driver); diff --git a/drivers/pwm/pwm-lpc32xx.c b/drivers/pwm/pwm-lpc32xx.c index adb87f0c163..015a8223562 100644 --- a/drivers/pwm/pwm-lpc32xx.c +++ b/drivers/pwm/pwm-lpc32xx.c @@ -118,7 +118,7 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev) return 0; } -static int __devexit lpc32xx_pwm_remove(struct platform_device *pdev) +static int lpc32xx_pwm_remove(struct platform_device *pdev) { struct lpc32xx_pwm_chip *lpc32xx = platform_get_drvdata(pdev); @@ -138,7 +138,7 @@ static struct platform_driver lpc32xx_pwm_driver = { .of_match_table = of_match_ptr(lpc32xx_pwm_dt_ids), }, .probe = lpc32xx_pwm_probe, - .remove = __devexit_p(lpc32xx_pwm_remove), + .remove = lpc32xx_pwm_remove, }; module_platform_driver(lpc32xx_pwm_driver); diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c index e5852646f08..7ec345f0183 100644 --- a/drivers/pwm/pwm-mxs.c +++ b/drivers/pwm/pwm-mxs.c @@ -174,7 +174,7 @@ static int mxs_pwm_probe(struct platform_device *pdev) return 0; } -static int __devexit mxs_pwm_remove(struct platform_device *pdev) +static int mxs_pwm_remove(struct platform_device *pdev) { struct mxs_pwm_chip *mxs = platform_get_drvdata(pdev); @@ -193,7 +193,7 @@ static struct platform_driver mxs_pwm_driver = { .of_match_table = of_match_ptr(mxs_pwm_dt_ids), }, .probe = mxs_pwm_probe, - .remove = __devexit_p(mxs_pwm_remove), + .remove = mxs_pwm_remove, }; module_platform_driver(mxs_pwm_driver); diff --git a/drivers/pwm/pwm-puv3.c b/drivers/pwm/pwm-puv3.c index 2a93f37c46a..b882f6032fe 100644 --- a/drivers/pwm/pwm-puv3.c +++ b/drivers/pwm/pwm-puv3.c @@ -101,7 +101,7 @@ static const struct pwm_ops puv3_pwm_ops = { .owner = THIS_MODULE, }; -static int __devinit pwm_probe(struct platform_device *pdev) +static int pwm_probe(struct platform_device *pdev) { struct puv3_pwm_chip *puv3; struct resource *r; @@ -142,7 +142,7 @@ static int __devinit pwm_probe(struct platform_device *pdev) return 0; } -static int __devexit pwm_remove(struct platform_device *pdev) +static int pwm_remove(struct platform_device *pdev) { struct puv3_pwm_chip *puv3 = platform_get_drvdata(pdev); @@ -154,7 +154,7 @@ static struct platform_driver puv3_pwm_driver = { .name = "PKUnity-v3-PWM", }, .probe = pwm_probe, - .remove = __devexit_p(pwm_remove), + .remove = pwm_remove, }; module_platform_driver(puv3_pwm_driver); diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index 260c3a88564..f32fc4e66e0 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -135,7 +135,7 @@ static struct pwm_ops pxa_pwm_ops = { .owner = THIS_MODULE, }; -static int __devinit pwm_probe(struct platform_device *pdev) +static int pwm_probe(struct platform_device *pdev) { const struct platform_device_id *id = platform_get_device_id(pdev); struct pxa_pwm_chip *pwm; @@ -179,7 +179,7 @@ static int __devinit pwm_probe(struct platform_device *pdev) return 0; } -static int __devexit pwm_remove(struct platform_device *pdev) +static int pwm_remove(struct platform_device *pdev) { struct pxa_pwm_chip *chip; @@ -196,7 +196,7 @@ static struct platform_driver pwm_driver = { .owner = THIS_MODULE, }, .probe = pwm_probe, - .remove = __devexit_p(pwm_remove), + .remove = pwm_remove, .id_table = pwm_id_table, }; diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c index 023a3bee76e..e9b15d099c0 100644 --- a/drivers/pwm/pwm-samsung.c +++ b/drivers/pwm/pwm-samsung.c @@ -273,7 +273,7 @@ static int s3c_pwm_probe(struct platform_device *pdev) return ret; } -static int __devexit s3c_pwm_remove(struct platform_device *pdev) +static int s3c_pwm_remove(struct platform_device *pdev) { struct s3c_chip *s3c = platform_get_drvdata(pdev); int err; @@ -327,7 +327,7 @@ static struct platform_driver s3c_pwm_driver = { .owner = THIS_MODULE, }, .probe = s3c_pwm_probe, - .remove = __devexit_p(s3c_pwm_remove), + .remove = s3c_pwm_remove, .suspend = s3c_pwm_suspend, .resume = s3c_pwm_resume, }; diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index 057465e0553..30c0e2b70ce 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -210,7 +210,7 @@ static int tegra_pwm_probe(struct platform_device *pdev) return 0; } -static int __devexit tegra_pwm_remove(struct platform_device *pdev) +static int tegra_pwm_remove(struct platform_device *pdev) { struct tegra_pwm_chip *pc = platform_get_drvdata(pdev); int i; @@ -249,7 +249,7 @@ static struct platform_driver tegra_pwm_driver = { .of_match_table = of_match_ptr(tegra_pwm_of_match), }, .probe = tegra_pwm_probe, - .remove = __devexit_p(tegra_pwm_remove), + .remove = tegra_pwm_remove, }; module_platform_driver(tegra_pwm_driver); diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c index d6d4cf05565..87c091b245c 100644 --- a/drivers/pwm/pwm-tiecap.c +++ b/drivers/pwm/pwm-tiecap.c @@ -184,7 +184,7 @@ static const struct pwm_ops ecap_pwm_ops = { .owner = THIS_MODULE, }; -static int __devinit ecap_pwm_probe(struct platform_device *pdev) +static int ecap_pwm_probe(struct platform_device *pdev) { int ret; struct resource *r; @@ -235,7 +235,7 @@ static int __devinit ecap_pwm_probe(struct platform_device *pdev) return 0; } -static int __devexit ecap_pwm_remove(struct platform_device *pdev) +static int ecap_pwm_remove(struct platform_device *pdev) { struct ecap_pwm_chip *pc = platform_get_drvdata(pdev); @@ -249,7 +249,7 @@ static struct platform_driver ecap_pwm_driver = { .name = "ecap", }, .probe = ecap_pwm_probe, - .remove = __devexit_p(ecap_pwm_remove), + .remove = ecap_pwm_remove, }; module_platform_driver(ecap_pwm_driver); diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index d3c1dff0a0d..9ffd389d0c8 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -392,7 +392,7 @@ static const struct pwm_ops ehrpwm_pwm_ops = { .owner = THIS_MODULE, }; -static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev) +static int ehrpwm_pwm_probe(struct platform_device *pdev) { int ret; struct resource *r; @@ -443,7 +443,7 @@ static int __devinit ehrpwm_pwm_probe(struct platform_device *pdev) return 0; } -static int __devexit ehrpwm_pwm_remove(struct platform_device *pdev) +static int ehrpwm_pwm_remove(struct platform_device *pdev) { struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev); @@ -457,7 +457,7 @@ static struct platform_driver ehrpwm_pwm_driver = { .name = "ehrpwm", }, .probe = ehrpwm_pwm_probe, - .remove = __devexit_p(ehrpwm_pwm_remove), + .remove = ehrpwm_pwm_remove, }; module_platform_driver(ehrpwm_pwm_driver); diff --git a/drivers/pwm/pwm-twl6030.c b/drivers/pwm/pwm-twl6030.c index 8e6387864ca..378a7e28636 100644 --- a/drivers/pwm/pwm-twl6030.c +++ b/drivers/pwm/pwm-twl6030.c @@ -176,7 +176,7 @@ static struct platform_driver twl6030_pwm_driver = { .name = "twl6030-pwm", }, .probe = twl6030_pwm_probe, - .remove = __devexit_p(twl6030_pwm_remove), + .remove = twl6030_pwm_remove, }; module_platform_driver(twl6030_pwm_driver); diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c index 38ecd8f4d60..6faba406b6e 100644 --- a/drivers/rapidio/devices/tsi721.c +++ b/drivers/rapidio/devices/tsi721.c @@ -2202,7 +2202,7 @@ static void tsi721_disable_ints(struct tsi721_device *priv) * * Configures Tsi721 as RapidIO master port. */ -static int __devinit tsi721_setup_mport(struct tsi721_device *priv) +static int tsi721_setup_mport(struct tsi721_device *priv) { struct pci_dev *pdev = priv->pdev; int err = 0; @@ -2302,7 +2302,7 @@ err_exit: return err; } -static int __devinit tsi721_probe(struct pci_dev *pdev, +static int tsi721_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct tsi721_device *priv; diff --git a/drivers/rapidio/devices/tsi721.h b/drivers/rapidio/devices/tsi721.h index 7d5b13ba8d4..b4b0d83f9ef 100644 --- a/drivers/rapidio/devices/tsi721.h +++ b/drivers/rapidio/devices/tsi721.h @@ -846,7 +846,7 @@ struct tsi721_device { #ifdef CONFIG_RAPIDIO_DMA_ENGINE extern void tsi721_bdma_handler(struct tsi721_bdma_chan *bdma_chan); -extern int __devinit tsi721_register_dma(struct tsi721_device *priv); +extern int tsi721_register_dma(struct tsi721_device *priv); #endif #endif diff --git a/drivers/rapidio/devices/tsi721_dma.c b/drivers/rapidio/devices/tsi721_dma.c index 92e06a5c62e..502663f5f7c 100644 --- a/drivers/rapidio/devices/tsi721_dma.c +++ b/drivers/rapidio/devices/tsi721_dma.c @@ -765,7 +765,7 @@ static int tsi721_device_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd, return 0; } -int __devinit tsi721_register_dma(struct tsi721_device *priv) +int tsi721_register_dma(struct tsi721_device *priv) { int i; int nr_channels = TSI721_DMA_MAXCH; diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c index 07da58bb495..a965acd3c0e 100644 --- a/drivers/rapidio/rio-scan.c +++ b/drivers/rapidio/rio-scan.c @@ -371,7 +371,7 @@ static void rio_switch_init(struct rio_dev *rdev, int do_enum) * device to the RIO device list. Creates the generic sysfs nodes * for an RIO device. */ -static int __devinit rio_add_device(struct rio_dev *rdev) +static int rio_add_device(struct rio_dev *rdev) { int err; @@ -463,7 +463,7 @@ inline int rio_enable_rx_tx_port(struct rio_mport *port, * to a RIO device on success or NULL on failure. * */ -static struct rio_dev __devinit *rio_setup_device(struct rio_net *net, +static struct rio_dev *rio_setup_device(struct rio_net *net, struct rio_mport *port, u16 destid, u8 hopcount, int do_enum) { @@ -837,7 +837,7 @@ static u16 rio_get_host_deviceid_lock(struct rio_mport *port, u8 hopcount) * Recursively enumerates a RIO network. Transactions are sent via the * master port passed in @port. */ -static int __devinit rio_enum_peer(struct rio_net *net, struct rio_mport *port, +static int rio_enum_peer(struct rio_net *net, struct rio_mport *port, u8 hopcount, struct rio_dev *prev, int prev_port) { struct rio_dev *rdev; @@ -1044,7 +1044,7 @@ static int rio_enum_complete(struct rio_mport *port) * Recursively discovers a RIO network. Transactions are sent via the * master port passed in @port. */ -static int __devinit +static int rio_disc_peer(struct rio_net *net, struct rio_mport *port, u16 destid, u8 hopcount, struct rio_dev *prev, int prev_port) { @@ -1151,7 +1151,7 @@ static int rio_mport_is_active(struct rio_mport *port) * network list of associated master ports. Returns a * RIO network pointer on success or %NULL on failure. */ -static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port, +static struct rio_net *rio_alloc_net(struct rio_mport *port, int do_enum, u16 start) { struct rio_net *net; @@ -1266,7 +1266,7 @@ static void rio_pw_enable(struct rio_mport *port, int enable) * link, then start recursive peer enumeration. Returns %0 if * enumeration succeeds or %-EBUSY if enumeration fails. */ -int __devinit rio_enum_mport(struct rio_mport *mport) +int rio_enum_mport(struct rio_mport *mport) { struct rio_net *net = NULL; int rc = 0; @@ -1369,7 +1369,7 @@ static void rio_build_route_tables(struct rio_net *net) * peer discovery. Returns %0 if discovery succeeds or %-EBUSY * on failure. */ -int __devinit rio_disc_mport(struct rio_mport *mport) +int rio_disc_mport(struct rio_mport *mport) { struct rio_net *net = NULL; unsigned long to_end; diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c index 0c6fcb461fa..d553b5d1372 100644 --- a/drivers/rapidio/rio.c +++ b/drivers/rapidio/rio.c @@ -1250,7 +1250,7 @@ static void rio_fixup_device(struct rio_dev *dev) { } -static int __devinit rio_init(void) +static int rio_init(void) { struct rio_dev *dev = NULL; @@ -1267,7 +1267,7 @@ struct rio_disc_work { struct rio_mport *mport; }; -static void __devinit disc_work_handler(struct work_struct *_work) +static void disc_work_handler(struct work_struct *_work) { struct rio_disc_work *work; @@ -1277,7 +1277,7 @@ static void __devinit disc_work_handler(struct work_struct *_work) rio_disc_mport(work->mport); } -int __devinit rio_init_mports(void) +int rio_init_mports(void) { struct rio_mport *port; struct rio_disc_work *work; diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c index e7a4780e93d..9e198e59067 100644 --- a/drivers/remoteproc/remoteproc_virtio.c +++ b/drivers/remoteproc/remoteproc_virtio.c @@ -120,15 +120,11 @@ static struct virtqueue *rp_find_vq(struct virtio_device *vdev, return vq; } -static void rproc_virtio_del_vqs(struct virtio_device *vdev) +static void __rproc_virtio_del_vqs(struct virtio_device *vdev) { struct virtqueue *vq, *n; - struct rproc *rproc = vdev_to_rproc(vdev); struct rproc_vring *rvring; - /* power down the remote processor before deleting vqs */ - rproc_shutdown(rproc); - list_for_each_entry_safe(vq, n, &vdev->vqs, list) { rvring = vq->priv; rvring->vq = NULL; @@ -137,6 +133,16 @@ static void rproc_virtio_del_vqs(struct virtio_device *vdev) } } +static void rproc_virtio_del_vqs(struct virtio_device *vdev) +{ + struct rproc *rproc = vdev_to_rproc(vdev); + + /* power down the remote processor before deleting vqs */ + rproc_shutdown(rproc); + + __rproc_virtio_del_vqs(vdev); +} + static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], @@ -163,7 +169,7 @@ static int rproc_virtio_find_vqs(struct virtio_device *vdev, unsigned nvqs, return 0; error: - rproc_virtio_del_vqs(vdev); + __rproc_virtio_del_vqs(vdev); return ret; } diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index 7a82337e4de..073108dcf9e 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -288,11 +288,11 @@ static int __devinit tps65910_rtc_probe(struct platform_device *pdev) static int __devexit tps65910_rtc_remove(struct platform_device *pdev) { /* leave rtc running, but disable irqs */ - struct rtc_device *rtc = platform_get_drvdata(pdev); + struct tps65910_rtc *tps_rtc = platform_get_drvdata(pdev); - tps65910_rtc_alarm_irq_enable(&rtc->dev, 0); + tps65910_rtc_alarm_irq_enable(&pdev->dev, 0); - rtc_device_unregister(rtc); + rtc_device_unregister(tps_rtc->rtc); return 0; } diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index c1bafc3f3fb..9594ab62702 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -1972,7 +1972,7 @@ sci_io_request_frame_handler(struct isci_request *ireq, frame_index, (void **)&frame_buffer); - sci_controller_copy_sata_response(&ireq->stp.req, + sci_controller_copy_sata_response(&ireq->stp.rsp, frame_header, frame_buffer); diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 16b7a72a70c..3b2365c8eab 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1276,7 +1276,7 @@ struct megasas_evt_detail { } __attribute__ ((packed)); struct megasas_aen_event { - struct work_struct hotplug_work; + struct delayed_work hotplug_work; struct megasas_instance *instance; }; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index d2c5366aff7..e4f2baacf1e 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -2060,9 +2060,9 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd) } else { ev->instance = instance; instance->ev = ev; - INIT_WORK(&ev->hotplug_work, megasas_aen_polling); - schedule_delayed_work( - (struct delayed_work *)&ev->hotplug_work, 0); + INIT_DELAYED_WORK(&ev->hotplug_work, + megasas_aen_polling); + schedule_delayed_work(&ev->hotplug_work, 0); } } } @@ -4352,8 +4352,7 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state) /* cancel the delayed work if this work still in queue */ if (instance->ev != NULL) { struct megasas_aen_event *ev = instance->ev; - cancel_delayed_work_sync( - (struct delayed_work *)&ev->hotplug_work); + cancel_delayed_work_sync(&ev->hotplug_work); instance->ev = NULL; } @@ -4545,8 +4544,7 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev) /* cancel the delayed work if this work still in queue*/ if (instance->ev != NULL) { struct megasas_aen_event *ev = instance->ev; - cancel_delayed_work_sync( - (struct delayed_work *)&ev->hotplug_work); + cancel_delayed_work_sync(&ev->hotplug_work); instance->ev = NULL; } @@ -5190,7 +5188,7 @@ static void megasas_aen_polling(struct work_struct *work) { struct megasas_aen_event *ev = - container_of(work, struct megasas_aen_event, hotplug_work); + container_of(work, struct megasas_aen_event, hotplug_work.work); struct megasas_instance *instance = ev->instance; union megasas_evt_class_locale class_locale; struct Scsi_Host *host; diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 2936b447cae..2c0d0ec8150 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -55,6 +55,7 @@ #include <linux/cpu.h> #include <linux/mutex.h> #include <linux/async.h> +#include <asm/unaligned.h> #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> @@ -1062,6 +1063,50 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf, EXPORT_SYMBOL_GPL(scsi_get_vpd_page); /** + * scsi_report_opcode - Find out if a given command opcode is supported + * @sdev: scsi device to query + * @buffer: scratch buffer (must be at least 20 bytes long) + * @len: length of buffer + * @opcode: opcode for command to look up + * + * Uses the REPORT SUPPORTED OPERATION CODES to look up the given + * opcode. Returns 0 if RSOC fails or if the command opcode is + * unsupported. Returns 1 if the device claims to support the command. + */ +int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer, + unsigned int len, unsigned char opcode) +{ + unsigned char cmd[16]; + struct scsi_sense_hdr sshdr; + int result; + + if (sdev->no_report_opcodes || sdev->scsi_level < SCSI_SPC_3) + return 0; + + memset(cmd, 0, 16); + cmd[0] = MAINTENANCE_IN; + cmd[1] = MI_REPORT_SUPPORTED_OPERATION_CODES; + cmd[2] = 1; /* One command format */ + cmd[3] = opcode; + put_unaligned_be32(len, &cmd[6]); + memset(buffer, 0, len); + + result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len, + &sshdr, 30 * HZ, 3, NULL); + + if (result && scsi_sense_valid(&sshdr) && + sshdr.sense_key == ILLEGAL_REQUEST && + (sshdr.asc == 0x20 || sshdr.asc == 0x24) && sshdr.ascq == 0x00) + return 0; + + if ((buffer[1] & 3) == 3) /* Command supported */ + return 1; + + return 0; +} +EXPORT_SYMBOL(scsi_report_opcode); + +/** * scsi_device_get - get an additional reference to a scsi_device * @sdev: device to get a reference to * diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index da36a3a81a9..9032e910bca 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -900,11 +900,23 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) action = ACTION_FAIL; error = -EILSEQ; /* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */ - } else if ((sshdr.asc == 0x20 || sshdr.asc == 0x24) && - (cmd->cmnd[0] == UNMAP || - cmd->cmnd[0] == WRITE_SAME_16 || - cmd->cmnd[0] == WRITE_SAME)) { - description = "Discard failure"; + } else if (sshdr.asc == 0x20 || sshdr.asc == 0x24) { + switch (cmd->cmnd[0]) { + case UNMAP: + description = "Discard failure"; + break; + case WRITE_SAME: + case WRITE_SAME_16: + if (cmd->cmnd[1] & 0x8) + description = "Discard failure"; + else + description = + "Write same failure"; + break; + default: + description = "Invalid command failure"; + break; + } action = ACTION_FAIL; error = -EREMOTEIO; } else diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 12f6fdfc114..352bc77b7c8 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -99,6 +99,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC); #endif static void sd_config_discard(struct scsi_disk *, unsigned int); +static void sd_config_write_same(struct scsi_disk *); static int sd_revalidate_disk(struct gendisk *); static void sd_unlock_native_capacity(struct gendisk *disk); static int sd_probe(struct device *); @@ -395,6 +396,45 @@ sd_store_max_medium_access_timeouts(struct device *dev, return err ? err : count; } +static ssize_t +sd_show_write_same_blocks(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + + return snprintf(buf, 20, "%u\n", sdkp->max_ws_blocks); +} + +static ssize_t +sd_store_write_same_blocks(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + struct scsi_device *sdp = sdkp->device; + unsigned long max; + int err; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (sdp->type != TYPE_DISK) + return -EINVAL; + + err = kstrtoul(buf, 10, &max); + + if (err) + return err; + + if (max == 0) + sdp->no_write_same = 1; + else if (max <= SD_MAX_WS16_BLOCKS) + sdkp->max_ws_blocks = max; + + sd_config_write_same(sdkp); + + return count; +} + static struct device_attribute sd_disk_attrs[] = { __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, sd_store_cache_type), @@ -410,6 +450,8 @@ static struct device_attribute sd_disk_attrs[] = { __ATTR(thin_provisioning, S_IRUGO, sd_show_thin_provisioning, NULL), __ATTR(provisioning_mode, S_IRUGO|S_IWUSR, sd_show_provisioning_mode, sd_store_provisioning_mode), + __ATTR(max_write_same_blocks, S_IRUGO|S_IWUSR, + sd_show_write_same_blocks, sd_store_write_same_blocks), __ATTR(max_medium_access_timeouts, S_IRUGO|S_IWUSR, sd_show_max_medium_access_timeouts, sd_store_max_medium_access_timeouts), @@ -561,19 +603,23 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) return; case SD_LBP_UNMAP: - max_blocks = min_not_zero(sdkp->max_unmap_blocks, 0xffffffff); + max_blocks = min_not_zero(sdkp->max_unmap_blocks, + (u32)SD_MAX_WS16_BLOCKS); break; case SD_LBP_WS16: - max_blocks = min_not_zero(sdkp->max_ws_blocks, 0xffffffff); + max_blocks = min_not_zero(sdkp->max_ws_blocks, + (u32)SD_MAX_WS16_BLOCKS); break; case SD_LBP_WS10: - max_blocks = min_not_zero(sdkp->max_ws_blocks, (u32)0xffff); + max_blocks = min_not_zero(sdkp->max_ws_blocks, + (u32)SD_MAX_WS10_BLOCKS); break; case SD_LBP_ZERO: - max_blocks = min_not_zero(sdkp->max_ws_blocks, (u32)0xffff); + max_blocks = min_not_zero(sdkp->max_ws_blocks, + (u32)SD_MAX_WS10_BLOCKS); q->limits.discard_zeroes_data = 1; break; } @@ -583,29 +629,26 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) } /** - * scsi_setup_discard_cmnd - unmap blocks on thinly provisioned device + * sd_setup_discard_cmnd - unmap blocks on thinly provisioned device * @sdp: scsi device to operate one * @rq: Request to prepare * * Will issue either UNMAP or WRITE SAME(16) depending on preference * indicated by target device. **/ -static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) +static int sd_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) { struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); - struct bio *bio = rq->bio; - sector_t sector = bio->bi_sector; - unsigned int nr_sectors = bio_sectors(bio); + sector_t sector = blk_rq_pos(rq); + unsigned int nr_sectors = blk_rq_sectors(rq); + unsigned int nr_bytes = blk_rq_bytes(rq); unsigned int len; int ret; char *buf; struct page *page; - if (sdkp->device->sector_size == 4096) { - sector >>= 3; - nr_sectors >>= 3; - } - + sector >>= ilog2(sdp->sector_size) - 9; + nr_sectors >>= ilog2(sdp->sector_size) - 9; rq->timeout = SD_TIMEOUT; memset(rq->cmd, 0, rq->cmd_len); @@ -660,6 +703,7 @@ static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) blk_add_request_payload(rq, page, len); ret = scsi_setup_blk_pc_cmnd(sdp, rq); rq->buffer = page_address(page); + rq->__data_len = nr_bytes; out: if (ret != BLKPREP_OK) { @@ -669,6 +713,83 @@ out: return ret; } +static void sd_config_write_same(struct scsi_disk *sdkp) +{ + struct request_queue *q = sdkp->disk->queue; + unsigned int logical_block_size = sdkp->device->sector_size; + unsigned int blocks = 0; + + if (sdkp->device->no_write_same) { + sdkp->max_ws_blocks = 0; + goto out; + } + + /* Some devices can not handle block counts above 0xffff despite + * supporting WRITE SAME(16). Consequently we default to 64k + * blocks per I/O unless the device explicitly advertises a + * bigger limit. + */ + if (sdkp->max_ws_blocks == 0) + sdkp->max_ws_blocks = SD_MAX_WS10_BLOCKS; + + if (sdkp->ws16 || sdkp->max_ws_blocks > SD_MAX_WS10_BLOCKS) + blocks = min_not_zero(sdkp->max_ws_blocks, + (u32)SD_MAX_WS16_BLOCKS); + else + blocks = min_not_zero(sdkp->max_ws_blocks, + (u32)SD_MAX_WS10_BLOCKS); + +out: + blk_queue_max_write_same_sectors(q, blocks * (logical_block_size >> 9)); +} + +/** + * sd_setup_write_same_cmnd - write the same data to multiple blocks + * @sdp: scsi device to operate one + * @rq: Request to prepare + * + * Will issue either WRITE SAME(10) or WRITE SAME(16) depending on + * preference indicated by target device. + **/ +static int sd_setup_write_same_cmnd(struct scsi_device *sdp, struct request *rq) +{ + struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); + struct bio *bio = rq->bio; + sector_t sector = blk_rq_pos(rq); + unsigned int nr_sectors = blk_rq_sectors(rq); + unsigned int nr_bytes = blk_rq_bytes(rq); + int ret; + + if (sdkp->device->no_write_same) + return BLKPREP_KILL; + + BUG_ON(bio_offset(bio) || bio_iovec(bio)->bv_len != sdp->sector_size); + + sector >>= ilog2(sdp->sector_size) - 9; + nr_sectors >>= ilog2(sdp->sector_size) - 9; + + rq->__data_len = sdp->sector_size; + rq->timeout = SD_WRITE_SAME_TIMEOUT; + memset(rq->cmd, 0, rq->cmd_len); + + if (sdkp->ws16 || sector > 0xffffffff || nr_sectors > 0xffff) { + rq->cmd_len = 16; + rq->cmd[0] = WRITE_SAME_16; + put_unaligned_be64(sector, &rq->cmd[2]); + put_unaligned_be32(nr_sectors, &rq->cmd[10]); + } else { + rq->cmd_len = 10; + rq->cmd[0] = WRITE_SAME; + put_unaligned_be32(sector, &rq->cmd[2]); + put_unaligned_be16(nr_sectors, &rq->cmd[7]); + } + + ret = scsi_setup_blk_pc_cmnd(sdp, rq); + rq->__data_len = nr_bytes; + + return ret; +} + static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq) { rq->timeout = SD_FLUSH_TIMEOUT; @@ -712,7 +833,10 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) * block PC requests to make life easier. */ if (rq->cmd_flags & REQ_DISCARD) { - ret = scsi_setup_discard_cmnd(sdp, rq); + ret = sd_setup_discard_cmnd(sdp, rq); + goto out; + } else if (rq->cmd_flags & REQ_WRITE_SAME) { + ret = sd_setup_write_same_cmnd(sdp, rq); goto out; } else if (rq->cmd_flags & REQ_FLUSH) { ret = scsi_setup_flush_cmnd(sdp, rq); @@ -1482,12 +1606,21 @@ static int sd_done(struct scsi_cmnd *SCpnt) unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt); struct scsi_sense_hdr sshdr; struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk); + struct request *req = SCpnt->request; int sense_valid = 0; int sense_deferred = 0; unsigned char op = SCpnt->cmnd[0]; + unsigned char unmap = SCpnt->cmnd[1] & 8; - if ((SCpnt->request->cmd_flags & REQ_DISCARD) && !result) - scsi_set_resid(SCpnt, 0); + if (req->cmd_flags & REQ_DISCARD || req->cmd_flags & REQ_WRITE_SAME) { + if (!result) { + good_bytes = blk_rq_bytes(req); + scsi_set_resid(SCpnt, 0); + } else { + good_bytes = 0; + scsi_set_resid(SCpnt, blk_rq_bytes(req)); + } + } if (result) { sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr); @@ -1536,9 +1669,25 @@ static int sd_done(struct scsi_cmnd *SCpnt) if (sshdr.asc == 0x10) /* DIX: Host detected corruption */ good_bytes = sd_completed_bytes(SCpnt); /* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */ - if ((sshdr.asc == 0x20 || sshdr.asc == 0x24) && - (op == UNMAP || op == WRITE_SAME_16 || op == WRITE_SAME)) - sd_config_discard(sdkp, SD_LBP_DISABLE); + if (sshdr.asc == 0x20 || sshdr.asc == 0x24) { + switch (op) { + case UNMAP: + sd_config_discard(sdkp, SD_LBP_DISABLE); + break; + case WRITE_SAME_16: + case WRITE_SAME: + if (unmap) + sd_config_discard(sdkp, SD_LBP_DISABLE); + else { + sdkp->device->no_write_same = 1; + sd_config_write_same(sdkp); + + good_bytes = 0; + req->__data_len = blk_rq_bytes(req); + req->cmd_flags |= REQ_QUIET; + } + } + } break; default: break; @@ -2374,9 +2523,7 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) if (buffer[3] == 0x3c) { unsigned int lba_count, desc_count; - sdkp->max_ws_blocks = - (u32) min_not_zero(get_unaligned_be64(&buffer[36]), - (u64)0xffffffff); + sdkp->max_ws_blocks = (u32)get_unaligned_be64(&buffer[36]); if (!sdkp->lbpme) goto out; @@ -2469,6 +2616,13 @@ static void sd_read_block_provisioning(struct scsi_disk *sdkp) kfree(buffer); } +static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) +{ + if (scsi_report_opcode(sdkp->device, buffer, SD_BUF_SIZE, + WRITE_SAME_16)) + sdkp->ws16 = 1; +} + static int sd_try_extended_inquiry(struct scsi_device *sdp) { /* @@ -2528,6 +2682,7 @@ static int sd_revalidate_disk(struct gendisk *disk) sd_read_write_protect_flag(sdkp, buffer); sd_read_cache_type(sdkp, buffer); sd_read_app_tag_own(sdkp, buffer); + sd_read_write_same(sdkp, buffer); } sdkp->first_scan = 0; @@ -2545,6 +2700,7 @@ static int sd_revalidate_disk(struct gendisk *disk) blk_queue_flush(sdkp->disk->queue, flush); set_capacity(disk, sdkp->capacity); + sd_config_write_same(sdkp); kfree(buffer); out: diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 47c52a6d733..74a1e4ca540 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -14,6 +14,7 @@ #define SD_TIMEOUT (30 * HZ) #define SD_MOD_TIMEOUT (75 * HZ) #define SD_FLUSH_TIMEOUT (60 * HZ) +#define SD_WRITE_SAME_TIMEOUT (120 * HZ) /* * Number of allowed retries @@ -39,6 +40,11 @@ enum { }; enum { + SD_MAX_WS10_BLOCKS = 0xffff, + SD_MAX_WS16_BLOCKS = 0x7fffff, +}; + +enum { SD_LBP_FULL = 0, /* Full logical block provisioning */ SD_LBP_UNMAP, /* Use UNMAP command */ SD_LBP_WS16, /* Use WRITE SAME(16) with UNMAP bit */ @@ -77,6 +83,7 @@ struct scsi_disk { unsigned lbpws : 1; unsigned lbpws10 : 1; unsigned lbpvpd : 1; + unsigned ws16 : 1; }; #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 84c2861d6f4..718cc1f4923 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -35,6 +35,8 @@ #include <linux/sched.h> #include <linux/delay.h> #include <linux/kthread.h> +#include <linux/ioport.h> +#include <linux/acpi.h> static void spidev_release(struct device *dev) { @@ -93,6 +95,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv) if (of_driver_match_device(dev, drv)) return 1; + /* Then try ACPI */ + if (acpi_driver_match_device(dev, drv)) + return 1; + if (sdrv->id_table) return !!spi_match_id(sdrv->id_table, spi); @@ -819,7 +825,7 @@ static void of_register_spi_devices(struct spi_master *master) if (!master->dev.of_node) return; - for_each_child_of_node(master->dev.of_node, nc) { + for_each_available_child_of_node(master->dev.of_node, nc) { /* Alloc an spi_device */ spi = spi_alloc_device(master); if (!spi) { @@ -888,6 +894,100 @@ static void of_register_spi_devices(struct spi_master *master) static void of_register_spi_devices(struct spi_master *master) { } #endif +#ifdef CONFIG_ACPI +static int acpi_spi_add_resource(struct acpi_resource *ares, void *data) +{ + struct spi_device *spi = data; + + if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { + struct acpi_resource_spi_serialbus *sb; + + sb = &ares->data.spi_serial_bus; + if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_SPI) { + spi->chip_select = sb->device_selection; + spi->max_speed_hz = sb->connection_speed; + + if (sb->clock_phase == ACPI_SPI_SECOND_PHASE) + spi->mode |= SPI_CPHA; + if (sb->clock_polarity == ACPI_SPI_START_HIGH) + spi->mode |= SPI_CPOL; + if (sb->device_polarity == ACPI_SPI_ACTIVE_HIGH) + spi->mode |= SPI_CS_HIGH; + } + } else if (spi->irq < 0) { + struct resource r; + + if (acpi_dev_resource_interrupt(ares, 0, &r)) + spi->irq = r.start; + } + + /* Always tell the ACPI core to skip this resource */ + return 1; +} + +static acpi_status acpi_spi_add_device(acpi_handle handle, u32 level, + void *data, void **return_value) +{ + struct spi_master *master = data; + struct list_head resource_list; + struct acpi_device *adev; + struct spi_device *spi; + int ret; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + if (acpi_bus_get_status(adev) || !adev->status.present) + return AE_OK; + + spi = spi_alloc_device(master); + if (!spi) { + dev_err(&master->dev, "failed to allocate SPI device for %s\n", + dev_name(&adev->dev)); + return AE_NO_MEMORY; + } + + ACPI_HANDLE_SET(&spi->dev, handle); + spi->irq = -1; + + INIT_LIST_HEAD(&resource_list); + ret = acpi_dev_get_resources(adev, &resource_list, + acpi_spi_add_resource, spi); + acpi_dev_free_resource_list(&resource_list); + + if (ret < 0 || !spi->max_speed_hz) { + spi_dev_put(spi); + return AE_OK; + } + + strlcpy(spi->modalias, dev_name(&adev->dev), sizeof(spi->modalias)); + if (spi_add_device(spi)) { + dev_err(&master->dev, "failed to add SPI device %s from ACPI\n", + dev_name(&adev->dev)); + spi_dev_put(spi); + } + + return AE_OK; +} + +static void acpi_register_spi_devices(struct spi_master *master) +{ + acpi_status status; + acpi_handle handle; + + handle = ACPI_HANDLE(&master->dev); + if (!handle) + return; + + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + acpi_spi_add_device, NULL, + master, NULL); + if (ACPI_FAILURE(status)) + dev_warn(&master->dev, "failed to enumerate SPI slaves\n"); +} +#else +static inline void acpi_register_spi_devices(struct spi_master *master) {} +#endif /* CONFIG_ACPI */ + static void spi_master_release(struct device *dev) { struct spi_master *master; @@ -1023,8 +1123,9 @@ int spi_register_master(struct spi_master *master) spi_match_master_to_boardinfo(master, &bi->board_info); mutex_unlock(&board_lock); - /* Register devices from the device tree */ + /* Register devices from the device tree and ACPI */ of_register_spi_devices(master); + acpi_register_spi_devices(master); done: return status; } diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 9097155e9eb..dcecbfb1724 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1819,8 +1819,10 @@ void target_execute_cmd(struct se_cmd *cmd) /* * If the received CDB has aleady been aborted stop processing it here. */ - if (transport_check_aborted_status(cmd, 1)) + if (transport_check_aborted_status(cmd, 1)) { + complete(&cmd->t_transport_stop_comp); return; + } /* * Determine if IOCTL context caller in requesting the stopping of this @@ -3067,7 +3069,7 @@ void transport_send_task_abort(struct se_cmd *cmd) unsigned long flags; spin_lock_irqsave(&cmd->t_state_lock, flags); - if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) { + if (cmd->se_cmd_flags & (SCF_SENT_CHECK_CONDITION | SCF_SENT_DELAYED_TAS)) { spin_unlock_irqrestore(&cmd->t_state_lock, flags); return; } diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 3d7e1ee2fa5..65f891be12d 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -39,6 +39,7 @@ #include <linux/atmel_pdc.h> #include <linux/atmel_serial.h> #include <linux/uaccess.h> +#include <linux/pinctrl/consumer.h> #include <asm/io.h> #include <asm/ioctls.h> @@ -1773,6 +1774,7 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev) struct atmel_uart_data *pdata = pdev->dev.platform_data; void *data; int ret = -ENODEV; + struct pinctrl *pinctrl; BUILD_BUG_ON(ATMEL_SERIAL_RINGSIZE & (ATMEL_SERIAL_RINGSIZE - 1)); @@ -1805,6 +1807,12 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev) atmel_init_port(port, pdev); + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) { + ret = PTR_ERR(pinctrl); + goto err; + } + if (!atmel_use_dma_rx(&port->uart)) { ret = -ENOMEM; data = kmalloc(sizeof(struct atmel_uart_char) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index f87d7e8964b..4e0d0c3734b 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -539,25 +539,25 @@ static void insert_char(struct vc_data *vc, unsigned int nr) { unsigned short *p = (unsigned short *) vc->vc_pos; - scr_memmovew(p + nr, p, vc->vc_cols - vc->vc_x); + scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x) * 2); scr_memsetw(p, vc->vc_video_erase_char, nr * 2); vc->vc_need_wrap = 0; if (DO_UPDATE(vc)) do_update_region(vc, (unsigned long) p, - (vc->vc_cols - vc->vc_x) / 2 + 1); + vc->vc_cols - vc->vc_x); } static void delete_char(struct vc_data *vc, unsigned int nr) { unsigned short *p = (unsigned short *) vc->vc_pos; - scr_memcpyw(p, p + nr, vc->vc_cols - vc->vc_x - nr); + scr_memcpyw(p, p + nr, (vc->vc_cols - vc->vc_x - nr) * 2); scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char, nr * 2); vc->vc_need_wrap = 0; if (DO_UPDATE(vc)) do_update_region(vc, (unsigned long) p, - (vc->vc_cols - vc->vc_x) / 2); + vc->vc_cols - vc->vc_x); } static int softcursor_original; diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig index 6f3ea9bbc81..82e2b89d448 100644 --- a/drivers/uio/Kconfig +++ b/drivers/uio/Kconfig @@ -44,6 +44,22 @@ config UIO_PDRV_GENIRQ If you don't know what to do here, say N. +config UIO_DMEM_GENIRQ + tristate "Userspace platform driver with generic irq and dynamic memory" + help + Platform driver for Userspace I/O devices, including generic + interrupt handling code. Shared interrupts are not supported. + + Memory regions can be specified with the same platform device + resources as the UIO_PDRV drivers, but dynamic regions can also + be specified. + The number and size of these regions is static, + but the memory allocation is not performed until + the associated device file is opened. The + memory is freed once the uio device is closed. + + If you don't know what to do here, say N. + config UIO_AEC tristate "AEC video timestamp device" depends on PCI diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile index d4dd9a5552f..b354c539507 100644 --- a/drivers/uio/Makefile +++ b/drivers/uio/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_UIO) += uio.o obj-$(CONFIG_UIO_CIF) += uio_cif.o obj-$(CONFIG_UIO_PDRV) += uio_pdrv.o obj-$(CONFIG_UIO_PDRV_GENIRQ) += uio_pdrv_genirq.o +obj-$(CONFIG_UIO_DMEM_GENIRQ) += uio_dmem_genirq.o obj-$(CONFIG_UIO_AEC) += uio_aec.o obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.o obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o diff --git a/drivers/uio/uio_aec.c b/drivers/uio/uio_aec.c index 72b22d44e8b..1548982db58 100644 --- a/drivers/uio/uio_aec.c +++ b/drivers/uio/uio_aec.c @@ -78,7 +78,7 @@ static void print_board_data(struct pci_dev *pdev, struct uio_info *i) ioread8(i->priv + 0x07)); } -static int __devinit probe(struct pci_dev *pdev, const struct pci_device_id *id) +static int probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct uio_info *info; int ret; diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c index a84a451159e..7dd6fc60539 100644 --- a/drivers/uio/uio_cif.c +++ b/drivers/uio/uio_cif.c @@ -40,7 +40,7 @@ static irqreturn_t hilscher_handler(int irq, struct uio_info *dev_info) return IRQ_HANDLED; } -static int __devinit hilscher_pci_probe(struct pci_dev *dev, +static int hilscher_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct uio_info *info; @@ -112,7 +112,7 @@ static void hilscher_pci_remove(struct pci_dev *dev) kfree (info); } -static struct pci_device_id hilscher_pci_ids[] __devinitdata = { +static struct pci_device_id hilscher_pci_ids[] = { { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9030, diff --git a/drivers/uio/uio_dmem_genirq.c b/drivers/uio/uio_dmem_genirq.c new file mode 100644 index 00000000000..252434c9ea9 --- /dev/null +++ b/drivers/uio/uio_dmem_genirq.c @@ -0,0 +1,359 @@ +/* + * drivers/uio/uio_dmem_genirq.c + * + * Userspace I/O platform driver with generic IRQ handling code. + * + * Copyright (C) 2012 Damian Hobson-Garcia + * + * Based on uio_pdrv_genirq.c by Magnus Damm + * + * 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/platform_device.h> +#include <linux/uio_driver.h> +#include <linux/spinlock.h> +#include <linux/bitops.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/platform_data/uio_dmem_genirq.h> +#include <linux/stringify.h> +#include <linux/pm_runtime.h> +#include <linux/dma-mapping.h> +#include <linux/slab.h> + +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/of_address.h> + +#define DRIVER_NAME "uio_dmem_genirq" +#define DMEM_MAP_ERROR (~0) + +struct uio_dmem_genirq_platdata { + struct uio_info *uioinfo; + spinlock_t lock; + unsigned long flags; + struct platform_device *pdev; + unsigned int dmem_region_start; + unsigned int num_dmem_regions; + void *dmem_region_vaddr[MAX_UIO_MAPS]; + struct mutex alloc_lock; + unsigned int refcnt; +}; + +static int uio_dmem_genirq_open(struct uio_info *info, struct inode *inode) +{ + struct uio_dmem_genirq_platdata *priv = info->priv; + struct uio_mem *uiomem; + int ret = 0; + int dmem_region = priv->dmem_region_start; + + uiomem = &priv->uioinfo->mem[priv->dmem_region_start]; + + mutex_lock(&priv->alloc_lock); + while (!priv->refcnt && uiomem < &priv->uioinfo->mem[MAX_UIO_MAPS]) { + void *addr; + if (!uiomem->size) + break; + + addr = dma_alloc_coherent(&priv->pdev->dev, uiomem->size, + (dma_addr_t *)&uiomem->addr, GFP_KERNEL); + if (!addr) { + uiomem->addr = DMEM_MAP_ERROR; + } + priv->dmem_region_vaddr[dmem_region++] = addr; + ++uiomem; + } + priv->refcnt++; + + mutex_unlock(&priv->alloc_lock); + /* Wait until the Runtime PM code has woken up the device */ + pm_runtime_get_sync(&priv->pdev->dev); + return ret; +} + +static int uio_dmem_genirq_release(struct uio_info *info, struct inode *inode) +{ + struct uio_dmem_genirq_platdata *priv = info->priv; + struct uio_mem *uiomem; + int dmem_region = priv->dmem_region_start; + + /* Tell the Runtime PM code that the device has become idle */ + pm_runtime_put_sync(&priv->pdev->dev); + + uiomem = &priv->uioinfo->mem[priv->dmem_region_start]; + + mutex_lock(&priv->alloc_lock); + + priv->refcnt--; + while (!priv->refcnt && uiomem < &priv->uioinfo->mem[MAX_UIO_MAPS]) { + if (!uiomem->size) + break; + if (priv->dmem_region_vaddr[dmem_region]) { + dma_free_coherent(&priv->pdev->dev, uiomem->size, + priv->dmem_region_vaddr[dmem_region], + uiomem->addr); + } + uiomem->addr = DMEM_MAP_ERROR; + ++dmem_region; + ++uiomem; + } + + mutex_unlock(&priv->alloc_lock); + return 0; +} + +static irqreturn_t uio_dmem_genirq_handler(int irq, struct uio_info *dev_info) +{ + struct uio_dmem_genirq_platdata *priv = dev_info->priv; + + /* Just disable the interrupt in the interrupt controller, and + * remember the state so we can allow user space to enable it later. + */ + + if (!test_and_set_bit(0, &priv->flags)) + disable_irq_nosync(irq); + + return IRQ_HANDLED; +} + +static int uio_dmem_genirq_irqcontrol(struct uio_info *dev_info, s32 irq_on) +{ + struct uio_dmem_genirq_platdata *priv = dev_info->priv; + unsigned long flags; + + /* Allow user space to enable and disable the interrupt + * in the interrupt controller, but keep track of the + * state to prevent per-irq depth damage. + * + * Serialize this operation to support multiple tasks. + */ + + spin_lock_irqsave(&priv->lock, flags); + if (irq_on) { + if (test_and_clear_bit(0, &priv->flags)) + enable_irq(dev_info->irq); + } else { + if (!test_and_set_bit(0, &priv->flags)) + disable_irq(dev_info->irq); + } + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int uio_dmem_genirq_probe(struct platform_device *pdev) +{ + struct uio_dmem_genirq_pdata *pdata = pdev->dev.platform_data; + struct uio_info *uioinfo = &pdata->uioinfo; + struct uio_dmem_genirq_platdata *priv; + struct uio_mem *uiomem; + int ret = -EINVAL; + int i; + + if (pdev->dev.of_node) { + int irq; + + /* alloc uioinfo for one device */ + uioinfo = kzalloc(sizeof(*uioinfo), GFP_KERNEL); + if (!uioinfo) { + ret = -ENOMEM; + dev_err(&pdev->dev, "unable to kmalloc\n"); + goto bad2; + } + uioinfo->name = pdev->dev.of_node->name; + uioinfo->version = "devicetree"; + + /* Multiple IRQs are not supported */ + irq = platform_get_irq(pdev, 0); + if (irq == -ENXIO) + uioinfo->irq = UIO_IRQ_NONE; + else + uioinfo->irq = irq; + } + + if (!uioinfo || !uioinfo->name || !uioinfo->version) { + dev_err(&pdev->dev, "missing platform_data\n"); + goto bad0; + } + + if (uioinfo->handler || uioinfo->irqcontrol || + uioinfo->irq_flags & IRQF_SHARED) { + dev_err(&pdev->dev, "interrupt configuration error\n"); + goto bad0; + } + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + dev_err(&pdev->dev, "unable to kmalloc\n"); + goto bad0; + } + + dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + + priv->uioinfo = uioinfo; + spin_lock_init(&priv->lock); + priv->flags = 0; /* interrupt is enabled to begin with */ + priv->pdev = pdev; + mutex_init(&priv->alloc_lock); + + if (!uioinfo->irq) { + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get IRQ\n"); + goto bad0; + } + uioinfo->irq = ret; + } + uiomem = &uioinfo->mem[0]; + + for (i = 0; i < pdev->num_resources; ++i) { + struct resource *r = &pdev->resource[i]; + + if (r->flags != IORESOURCE_MEM) + continue; + + if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) { + dev_warn(&pdev->dev, "device has more than " + __stringify(MAX_UIO_MAPS) + " I/O memory resources.\n"); + break; + } + + uiomem->memtype = UIO_MEM_PHYS; + uiomem->addr = r->start; + uiomem->size = resource_size(r); + ++uiomem; + } + + priv->dmem_region_start = i; + priv->num_dmem_regions = pdata->num_dynamic_regions; + + for (i = 0; i < pdata->num_dynamic_regions; ++i) { + if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) { + dev_warn(&pdev->dev, "device has more than " + __stringify(MAX_UIO_MAPS) + " dynamic and fixed memory regions.\n"); + break; + } + uiomem->memtype = UIO_MEM_PHYS; + uiomem->addr = DMEM_MAP_ERROR; + uiomem->size = pdata->dynamic_region_sizes[i]; + ++uiomem; + } + + while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) { + uiomem->size = 0; + ++uiomem; + } + + /* This driver requires no hardware specific kernel code to handle + * interrupts. Instead, the interrupt handler simply disables the + * interrupt in the interrupt controller. User space is responsible + * for performing hardware specific acknowledge and re-enabling of + * the interrupt in the interrupt controller. + * + * Interrupt sharing is not supported. + */ + + uioinfo->handler = uio_dmem_genirq_handler; + uioinfo->irqcontrol = uio_dmem_genirq_irqcontrol; + uioinfo->open = uio_dmem_genirq_open; + uioinfo->release = uio_dmem_genirq_release; + uioinfo->priv = priv; + + /* Enable Runtime PM for this device: + * The device starts in suspended state to allow the hardware to be + * turned off by default. The Runtime PM bus code should power on the + * hardware and enable clocks at open(). + */ + pm_runtime_enable(&pdev->dev); + + ret = uio_register_device(&pdev->dev, priv->uioinfo); + if (ret) { + dev_err(&pdev->dev, "unable to register uio device\n"); + goto bad1; + } + + platform_set_drvdata(pdev, priv); + return 0; + bad1: + kfree(priv); + pm_runtime_disable(&pdev->dev); + bad0: + /* kfree uioinfo for OF */ + if (pdev->dev.of_node) + kfree(uioinfo); + bad2: + return ret; +} + +static int uio_dmem_genirq_remove(struct platform_device *pdev) +{ + struct uio_dmem_genirq_platdata *priv = platform_get_drvdata(pdev); + + uio_unregister_device(priv->uioinfo); + pm_runtime_disable(&pdev->dev); + + priv->uioinfo->handler = NULL; + priv->uioinfo->irqcontrol = NULL; + + /* kfree uioinfo for OF */ + if (pdev->dev.of_node) + kfree(priv->uioinfo); + + kfree(priv); + return 0; +} + +static int uio_dmem_genirq_runtime_nop(struct device *dev) +{ + /* Runtime PM callback shared between ->runtime_suspend() + * and ->runtime_resume(). Simply returns success. + * + * In this driver pm_runtime_get_sync() and pm_runtime_put_sync() + * are used at open() and release() time. This allows the + * Runtime PM code to turn off power to the device while the + * device is unused, ie before open() and after release(). + * + * This Runtime PM callback does not need to save or restore + * any registers since user space is responsbile for hardware + * register reinitialization after open(). + */ + return 0; +} + +static const struct dev_pm_ops uio_dmem_genirq_dev_pm_ops = { + .runtime_suspend = uio_dmem_genirq_runtime_nop, + .runtime_resume = uio_dmem_genirq_runtime_nop, +}; + +#ifdef CONFIG_OF +static const struct of_device_id uio_of_genirq_match[] = { + { /* empty for now */ }, +}; +MODULE_DEVICE_TABLE(of, uio_of_genirq_match); +#else +# define uio_of_genirq_match NULL +#endif + +static struct platform_driver uio_dmem_genirq = { + .probe = uio_dmem_genirq_probe, + .remove = uio_dmem_genirq_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .pm = &uio_dmem_genirq_dev_pm_ops, + .of_match_table = uio_of_genirq_match, + }, +}; + +module_platform_driver(uio_dmem_genirq); + +MODULE_AUTHOR("Damian Hobson-Garcia"); +MODULE_DESCRIPTION("Userspace I/O platform driver with dynamic memory."); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/uio/uio_netx.c b/drivers/uio/uio_netx.c index a879fd5741f..6a4ba5e83e3 100644 --- a/drivers/uio/uio_netx.c +++ b/drivers/uio/uio_netx.c @@ -48,7 +48,7 @@ static irqreturn_t netx_handler(int irq, struct uio_info *dev_info) return IRQ_HANDLED; } -static int __devinit netx_pci_probe(struct pci_dev *dev, +static int netx_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct uio_info *info; diff --git a/drivers/uio/uio_pci_generic.c b/drivers/uio/uio_pci_generic.c index 0bd08ef2b39..14aa10c1f6d 100644 --- a/drivers/uio/uio_pci_generic.c +++ b/drivers/uio/uio_pci_generic.c @@ -53,7 +53,7 @@ static irqreturn_t irqhandler(int irq, struct uio_info *info) return IRQ_HANDLED; } -static int __devinit probe(struct pci_dev *pdev, +static int probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct uio_pci_generic_dev *gdev; diff --git a/drivers/uio/uio_pdrv.c b/drivers/uio/uio_pdrv.c index 72d3646c736..39be9e06170 100644 --- a/drivers/uio/uio_pdrv.c +++ b/drivers/uio/uio_pdrv.c @@ -60,6 +60,7 @@ static int uio_pdrv_probe(struct platform_device *pdev) uiomem->memtype = UIO_MEM_PHYS; uiomem->addr = r->start; uiomem->size = resource_size(r); + uiomem->name = r->name; ++uiomem; } diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index 42202cd8315..c122bca669b 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c @@ -102,7 +102,7 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev) int ret = -EINVAL; int i; - if (!uioinfo) { + if (pdev->dev.of_node) { int irq; /* alloc uioinfo for one device */ @@ -172,6 +172,7 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev) uiomem->memtype = UIO_MEM_PHYS; uiomem->addr = r->start; uiomem->size = resource_size(r); + uiomem->name = r->name; ++uiomem; } diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c index 33a7a273b45..cce0f78341c 100644 --- a/drivers/uio/uio_pruss.c +++ b/drivers/uio/uio_pruss.c @@ -112,7 +112,7 @@ static void pruss_cleanup(struct platform_device *dev, kfree(gdev); } -static int __devinit pruss_probe(struct platform_device *dev) +static int pruss_probe(struct platform_device *dev) { struct uio_info *p; struct uio_pruss_dev *gdev; @@ -209,7 +209,7 @@ out_free: return ret; } -static int __devexit pruss_remove(struct platform_device *dev) +static int pruss_remove(struct platform_device *dev) { struct uio_pruss_dev *gdev = platform_get_drvdata(dev); @@ -220,7 +220,7 @@ static int __devexit pruss_remove(struct platform_device *dev) static struct platform_driver pruss_driver = { .probe = pruss_probe, - .remove = __devexit_p(pruss_remove), + .remove = pruss_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, diff --git a/drivers/uio/uio_sercos3.c b/drivers/uio/uio_sercos3.c index a187fa14c5c..81a10a56312 100644 --- a/drivers/uio/uio_sercos3.c +++ b/drivers/uio/uio_sercos3.c @@ -116,7 +116,7 @@ static int sercos3_setup_iomem(struct pci_dev *dev, struct uio_info *info, return 0; } -static int __devinit sercos3_pci_probe(struct pci_dev *dev, +static int sercos3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct uio_info *info; @@ -197,7 +197,7 @@ static void sercos3_pci_remove(struct pci_dev *dev) kfree(info); } -static struct pci_device_id sercos3_pci_ids[] __devinitdata = { +static struct pci_device_id sercos3_pci_ids[] = { { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9030, diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index a3d54366afc..92f35abee92 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -186,6 +186,12 @@ static int slave_configure(struct scsi_device *sdev) /* Some devices don't handle VPD pages correctly */ sdev->skip_vpd_pages = 1; + /* Do not attempt to use REPORT SUPPORTED OPERATION CODES */ + sdev->no_report_opcodes = 1; + + /* Do not attempt to use WRITE SAME */ + sdev->no_write_same = 1; + /* Some disks return the total number of blocks in response * to READ CAPACITY rather than the highest block number. * If this device makes that mistake, tell the sd driver. */ diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 99ac2cb08b4..dedaf81d8f3 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1076,7 +1076,7 @@ static int translate_desc(struct vhost_dev *dev, u64 addr, u32 len, } _iov = iov + ret; size = reg->memory_size - addr + reg->guest_phys_addr; - _iov->iov_len = min((u64)len, size); + _iov->iov_len = min((u64)len - s, size); _iov->iov_base = (void __user *)(unsigned long) (reg->userspace_addr + addr - reg->guest_phys_addr); s += size; diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c index df5db99af23..a1e41d4faa7 100644 --- a/drivers/video/backlight/adp5520_bl.c +++ b/drivers/video/backlight/adp5520_bl.c @@ -282,7 +282,7 @@ static const struct attribute_group adp5520_bl_attr_group = { .attrs = adp5520_bl_attributes, }; -static int __devinit adp5520_bl_probe(struct platform_device *pdev) +static int adp5520_bl_probe(struct platform_device *pdev) { struct backlight_properties props; struct backlight_device *bl; @@ -333,7 +333,7 @@ static int __devinit adp5520_bl_probe(struct platform_device *pdev) return ret; } -static int __devexit adp5520_bl_remove(struct platform_device *pdev) +static int adp5520_bl_remove(struct platform_device *pdev) { struct backlight_device *bl = platform_get_drvdata(pdev); struct adp5520_bl *data = bl_get_data(bl); @@ -375,7 +375,7 @@ static struct platform_driver adp5520_bl_driver = { .owner = THIS_MODULE, }, .probe = adp5520_bl_probe, - .remove = __devexit_p(adp5520_bl_remove), + .remove = adp5520_bl_remove, .suspend = adp5520_bl_suspend, .resume = adp5520_bl_resume, }; diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c index 77d1fdba597..6bb72c0cb80 100644 --- a/drivers/video/backlight/adp8860_bl.c +++ b/drivers/video/backlight/adp8860_bl.c @@ -213,7 +213,7 @@ static int adp8860_led_setup(struct adp8860_led *led) return ret; } -static int __devinit adp8860_led_probe(struct i2c_client *client) +static int adp8860_led_probe(struct i2c_client *client) { struct adp8860_backlight_platform_data *pdata = client->dev.platform_data; @@ -295,7 +295,7 @@ static int __devinit adp8860_led_probe(struct i2c_client *client) return ret; } -static int __devexit adp8860_led_remove(struct i2c_client *client) +static int adp8860_led_remove(struct i2c_client *client) { struct adp8860_backlight_platform_data *pdata = client->dev.platform_data; @@ -310,12 +310,12 @@ static int __devexit adp8860_led_remove(struct i2c_client *client) return 0; } #else -static int __devinit adp8860_led_probe(struct i2c_client *client) +static int adp8860_led_probe(struct i2c_client *client) { return 0; } -static int __devexit adp8860_led_remove(struct i2c_client *client) +static int adp8860_led_remove(struct i2c_client *client) { return 0; } @@ -650,7 +650,7 @@ static const struct attribute_group adp8860_bl_attr_group = { .attrs = adp8860_bl_attributes, }; -static int __devinit adp8860_probe(struct i2c_client *client, +static int adp8860_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct backlight_device *bl; @@ -755,7 +755,7 @@ out1: return ret; } -static int __devexit adp8860_remove(struct i2c_client *client) +static int adp8860_remove(struct i2c_client *client) { struct adp8860_bl *data = i2c_get_clientdata(client); @@ -805,7 +805,7 @@ static struct i2c_driver adp8860_driver = { .name = KBUILD_MODNAME, }, .probe = adp8860_probe, - .remove = __devexit_p(adp8860_remove), + .remove = adp8860_remove, .suspend = adp8860_i2c_suspend, .resume = adp8860_i2c_resume, .id_table = adp8860_id, diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c index edf7f91c8e6..63c882b8177 100644 --- a/drivers/video/backlight/adp8870_bl.c +++ b/drivers/video/backlight/adp8870_bl.c @@ -235,7 +235,7 @@ static int adp8870_led_setup(struct adp8870_led *led) return ret; } -static int __devinit adp8870_led_probe(struct i2c_client *client) +static int adp8870_led_probe(struct i2c_client *client) { struct adp8870_backlight_platform_data *pdata = client->dev.platform_data; @@ -320,7 +320,7 @@ static int __devinit adp8870_led_probe(struct i2c_client *client) return ret; } -static int __devexit adp8870_led_remove(struct i2c_client *client) +static int adp8870_led_remove(struct i2c_client *client) { struct adp8870_backlight_platform_data *pdata = client->dev.platform_data; @@ -335,12 +335,12 @@ static int __devexit adp8870_led_remove(struct i2c_client *client) return 0; } #else -static int __devinit adp8870_led_probe(struct i2c_client *client) +static int adp8870_led_probe(struct i2c_client *client) { return 0; } -static int __devexit adp8870_led_remove(struct i2c_client *client) +static int adp8870_led_remove(struct i2c_client *client) { return 0; } @@ -839,7 +839,7 @@ static const struct attribute_group adp8870_bl_attr_group = { .attrs = adp8870_bl_attributes, }; -static int __devinit adp8870_probe(struct i2c_client *client, +static int adp8870_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct backlight_properties props; @@ -929,7 +929,7 @@ out1: return ret; } -static int __devexit adp8870_remove(struct i2c_client *client) +static int adp8870_remove(struct i2c_client *client) { struct adp8870_bl *data = i2c_get_clientdata(client); @@ -977,7 +977,7 @@ static struct i2c_driver adp8870_driver = { .name = KBUILD_MODNAME, }, .probe = adp8870_probe, - .remove = __devexit_p(adp8870_remove), + .remove = adp8870_remove, .suspend = adp8870_i2c_suspend, .resume = adp8870_i2c_resume, .id_table = adp8870_id, diff --git a/drivers/video/backlight/ams369fg06.c b/drivers/video/backlight/ams369fg06.c index 3729238e709..f57e1905236 100644 --- a/drivers/video/backlight/ams369fg06.c +++ b/drivers/video/backlight/ams369fg06.c @@ -474,7 +474,7 @@ static const struct backlight_ops ams369fg06_backlight_ops = { .update_status = ams369fg06_set_brightness, }; -static int __devinit ams369fg06_probe(struct spi_device *spi) +static int ams369fg06_probe(struct spi_device *spi) { int ret = 0; struct ams369fg06 *lcd = NULL; @@ -548,7 +548,7 @@ out_lcd_unregister: return ret; } -static int __devexit ams369fg06_remove(struct spi_device *spi) +static int ams369fg06_remove(struct spi_device *spi) { struct ams369fg06 *lcd = dev_get_drvdata(&spi->dev); @@ -617,7 +617,7 @@ static struct spi_driver ams369fg06_driver = { .owner = THIS_MODULE, }, .probe = ams369fg06_probe, - .remove = __devexit_p(ams369fg06_remove), + .remove = ams369fg06_remove, .shutdown = ams369fg06_shutdown, .suspend = ams369fg06_suspend, .resume = ams369fg06_resume, diff --git a/drivers/video/backlight/apple_bl.c b/drivers/video/backlight/apple_bl.c index 9dc73ac3709..f088d4c0738 100644 --- a/drivers/video/backlight/apple_bl.c +++ b/drivers/video/backlight/apple_bl.c @@ -137,7 +137,7 @@ static const struct hw_data nvidia_chipset_data = { .set_brightness = nvidia_chipset_set_brightness, }; -static int __devinit apple_bl_add(struct acpi_device *dev) +static int apple_bl_add(struct acpi_device *dev) { struct backlight_properties props; struct pci_dev *host; @@ -196,7 +196,7 @@ static int __devinit apple_bl_add(struct acpi_device *dev) return 0; } -static int __devexit apple_bl_remove(struct acpi_device *dev, int type) +static int apple_bl_remove(struct acpi_device *dev, int type) { backlight_device_unregister(apple_backlight_device); diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c index c781768ba89..eaaebf21993 100644 --- a/drivers/video/backlight/corgi_lcd.c +++ b/drivers/video/backlight/corgi_lcd.c @@ -529,7 +529,7 @@ static int setup_gpio_backlight(struct corgi_lcd *lcd, return 0; } -static int __devinit corgi_lcd_probe(struct spi_device *spi) +static int corgi_lcd_probe(struct spi_device *spi) { struct backlight_properties props; struct corgi_lcd_platform_data *pdata = spi->dev.platform_data; @@ -590,7 +590,7 @@ err_unregister_lcd: return ret; } -static int __devexit corgi_lcd_remove(struct spi_device *spi) +static int corgi_lcd_remove(struct spi_device *spi) { struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev); @@ -611,7 +611,7 @@ static struct spi_driver corgi_lcd_driver = { .owner = THIS_MODULE, }, .probe = corgi_lcd_probe, - .remove = __devexit_p(corgi_lcd_remove), + .remove = corgi_lcd_remove, .suspend = corgi_lcd_suspend, .resume = corgi_lcd_resume, }; diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c index 08214e1f095..ef3e21e8f82 100644 --- a/drivers/video/backlight/ep93xx_bl.c +++ b/drivers/video/backlight/ep93xx_bl.c @@ -141,7 +141,7 @@ static struct platform_driver ep93xxbl_driver = { .owner = THIS_MODULE, }, .probe = ep93xxbl_probe, - .remove = __devexit_p(ep93xxbl_remove), + .remove = ep93xxbl_remove, .suspend = ep93xxbl_suspend, .resume = ep93xxbl_resume, }; diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index 38aa0027214..c9996634244 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -103,7 +103,7 @@ static const struct backlight_ops hp680bl_ops = { .update_status = hp680bl_set_intensity, }; -static int __devinit hp680bl_probe(struct platform_device *pdev) +static int hp680bl_probe(struct platform_device *pdev) { struct backlight_properties props; struct backlight_device *bd; diff --git a/drivers/video/backlight/ili9320.c b/drivers/video/backlight/ili9320.c index 9327cd1b314..66cc313185a 100644 --- a/drivers/video/backlight/ili9320.c +++ b/drivers/video/backlight/ili9320.c @@ -171,7 +171,7 @@ static struct lcd_ops ili9320_ops = { .set_power = ili9320_set_power, }; -static void __devinit ili9320_setup_spi(struct ili9320 *ili, +static void ili9320_setup_spi(struct ili9320 *ili, struct spi_device *dev) { struct ili9320_spi *spi = &ili->access.spi; @@ -197,7 +197,7 @@ static void __devinit ili9320_setup_spi(struct ili9320 *ili, spi_message_add_tail(&spi->xfer[1], &spi->message); } -int __devinit ili9320_probe_spi(struct spi_device *spi, +int ili9320_probe_spi(struct spi_device *spi, struct ili9320_client *client) { struct ili9320_platdata *cfg = spi->dev.platform_data; diff --git a/drivers/video/backlight/l4f00242t03.c b/drivers/video/backlight/l4f00242t03.c index 2d90c0648aa..f5aa0a5961d 100644 --- a/drivers/video/backlight/l4f00242t03.c +++ b/drivers/video/backlight/l4f00242t03.c @@ -150,7 +150,7 @@ static struct lcd_ops l4f_ops = { .get_power = l4f00242t03_lcd_power_get, }; -static int __devinit l4f00242t03_probe(struct spi_device *spi) +static int l4f00242t03_probe(struct spi_device *spi) { struct l4f00242t03_priv *priv; struct l4f00242t03_pdata *pdata = spi->dev.platform_data; @@ -230,7 +230,7 @@ err1: return ret; } -static int __devexit l4f00242t03_remove(struct spi_device *spi) +static int l4f00242t03_remove(struct spi_device *spi) { struct l4f00242t03_priv *priv = dev_get_drvdata(&spi->dev); @@ -260,7 +260,7 @@ static struct spi_driver l4f00242t03_driver = { .owner = THIS_MODULE, }, .probe = l4f00242t03_probe, - .remove = __devexit_p(l4f00242t03_remove), + .remove = l4f00242t03_remove, .shutdown = l4f00242t03_shutdown, }; diff --git a/drivers/video/backlight/ld9040.c b/drivers/video/backlight/ld9040.c index 58f517fb7d4..1cb35241851 100644 --- a/drivers/video/backlight/ld9040.c +++ b/drivers/video/backlight/ld9040.c @@ -788,7 +788,7 @@ out_free_regulator: return ret; } -static int __devexit ld9040_remove(struct spi_device *spi) +static int ld9040_remove(struct spi_device *spi) { struct ld9040 *lcd = dev_get_drvdata(&spi->dev); @@ -847,7 +847,7 @@ static struct spi_driver ld9040_driver = { .owner = THIS_MODULE, }, .probe = ld9040_probe, - .remove = __devexit_p(ld9040_remove), + .remove = ld9040_remove, .shutdown = ld9040_shutdown, .suspend = ld9040_suspend, .resume = ld9040_resume, diff --git a/drivers/video/backlight/lm3533_bl.c b/drivers/video/backlight/lm3533_bl.c index 18dca0c29c6..5d18d4d7f47 100644 --- a/drivers/video/backlight/lm3533_bl.c +++ b/drivers/video/backlight/lm3533_bl.c @@ -257,7 +257,7 @@ static struct attribute_group lm3533_bl_attribute_group = { .attrs = lm3533_bl_attributes }; -static int __devinit lm3533_bl_setup(struct lm3533_bl *bl, +static int lm3533_bl_setup(struct lm3533_bl *bl, struct lm3533_bl_platform_data *pdata) { int ret; @@ -269,7 +269,7 @@ static int __devinit lm3533_bl_setup(struct lm3533_bl *bl, return lm3533_ctrlbank_set_pwm(&bl->cb, pdata->pwm); } -static int __devinit lm3533_bl_probe(struct platform_device *pdev) +static int lm3533_bl_probe(struct platform_device *pdev) { struct lm3533 *lm3533; struct lm3533_bl_platform_data *pdata; @@ -351,7 +351,7 @@ err_unregister: return ret; } -static int __devexit lm3533_bl_remove(struct platform_device *pdev) +static int lm3533_bl_remove(struct platform_device *pdev) { struct lm3533_bl *bl = platform_get_drvdata(pdev); struct backlight_device *bd = bl->bd; @@ -406,7 +406,7 @@ static struct platform_driver lm3533_bl_driver = { .owner = THIS_MODULE, }, .probe = lm3533_bl_probe, - .remove = __devexit_p(lm3533_bl_remove), + .remove = lm3533_bl_remove, .shutdown = lm3533_bl_shutdown, .suspend = lm3533_bl_suspend, .resume = lm3533_bl_resume, diff --git a/drivers/video/backlight/lm3630_bl.c b/drivers/video/backlight/lm3630_bl.c index dc191441796..0207bc0a440 100644 --- a/drivers/video/backlight/lm3630_bl.c +++ b/drivers/video/backlight/lm3630_bl.c @@ -55,7 +55,7 @@ struct lm3630_chip_data { }; /* initialize chip */ -static int __devinit lm3630_chip_init(struct lm3630_chip_data *pchip) +static int lm3630_chip_init(struct lm3630_chip_data *pchip) { int ret; unsigned int reg_val; @@ -349,7 +349,7 @@ static const struct regmap_config lm3630_regmap = { .max_register = REG_MAX, }; -static int __devinit lm3630_probe(struct i2c_client *client, +static int lm3630_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct lm3630_platform_data *pdata = client->dev.platform_data; @@ -429,7 +429,7 @@ err_chip_init: return ret; } -static int __devexit lm3630_remove(struct i2c_client *client) +static int lm3630_remove(struct i2c_client *client) { int ret; struct lm3630_chip_data *pchip = i2c_get_clientdata(client); @@ -463,7 +463,7 @@ static struct i2c_driver lm3630_i2c_driver = { .name = LM3630_NAME, }, .probe = lm3630_probe, - .remove = __devexit_p(lm3630_remove), + .remove = lm3630_remove, .id_table = lm3630_id, }; diff --git a/drivers/video/backlight/lm3639_bl.c b/drivers/video/backlight/lm3639_bl.c index 585949b5705..b0e1e8ba4d9 100644 --- a/drivers/video/backlight/lm3639_bl.c +++ b/drivers/video/backlight/lm3639_bl.c @@ -48,7 +48,7 @@ struct lm3639_chip_data { }; /* initialize chip */ -static int __devinit lm3639_chip_init(struct lm3639_chip_data *pchip) +static int lm3639_chip_init(struct lm3639_chip_data *pchip) { int ret; unsigned int reg_val; @@ -299,7 +299,7 @@ static const struct regmap_config lm3639_regmap = { .max_register = REG_MAX, }; -static int __devinit lm3639_probe(struct i2c_client *client, +static int lm3639_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret; @@ -397,7 +397,7 @@ err_out: return ret; } -static int __devexit lm3639_remove(struct i2c_client *client) +static int lm3639_remove(struct i2c_client *client) { struct lm3639_chip_data *pchip = i2c_get_clientdata(client); @@ -425,7 +425,7 @@ static struct i2c_driver lm3639_i2c_driver = { .name = LM3639_NAME, }, .probe = lm3639_probe, - .remove = __devexit_p(lm3639_remove), + .remove = lm3639_remove, .id_table = lm3639_id, }; diff --git a/drivers/video/backlight/lms283gf05.c b/drivers/video/backlight/lms283gf05.c index ea43f225419..b29c7071c9d 100644 --- a/drivers/video/backlight/lms283gf05.c +++ b/drivers/video/backlight/lms283gf05.c @@ -150,7 +150,7 @@ static struct lcd_ops lms_ops = { .get_power = NULL, }; -static int __devinit lms283gf05_probe(struct spi_device *spi) +static int lms283gf05_probe(struct spi_device *spi) { struct lms283gf05_state *st; struct lms283gf05_pdata *pdata = spi->dev.platform_data; @@ -193,7 +193,7 @@ static int __devinit lms283gf05_probe(struct spi_device *spi) return 0; } -static int __devexit lms283gf05_remove(struct spi_device *spi) +static int lms283gf05_remove(struct spi_device *spi) { struct lms283gf05_state *st = dev_get_drvdata(&spi->dev); @@ -208,7 +208,7 @@ static struct spi_driver lms283gf05_driver = { .owner = THIS_MODULE, }, .probe = lms283gf05_probe, - .remove = __devexit_p(lms283gf05_remove), + .remove = lms283gf05_remove, }; module_spi_driver(lms283gf05_driver); diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c index aa6d4f71131..fd985e0681e 100644 --- a/drivers/video/backlight/lp855x_bl.c +++ b/drivers/video/backlight/lp855x_bl.c @@ -297,7 +297,7 @@ err_dev: return ret; } -static int __devexit lp855x_remove(struct i2c_client *cl) +static int lp855x_remove(struct i2c_client *cl) { struct lp855x *lp = i2c_get_clientdata(cl); @@ -324,7 +324,7 @@ static struct i2c_driver lp855x_driver = { .name = "lp855x", }, .probe = lp855x_probe, - .remove = __devexit_p(lp855x_remove), + .remove = lp855x_remove, .id_table = lp855x_ids, }; diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c index 4066a5bbd82..226d813edf0 100644 --- a/drivers/video/backlight/ltv350qv.c +++ b/drivers/video/backlight/ltv350qv.c @@ -226,7 +226,7 @@ static struct lcd_ops ltv_ops = { .set_power = ltv350qv_set_power, }; -static int __devinit ltv350qv_probe(struct spi_device *spi) +static int ltv350qv_probe(struct spi_device *spi) { struct ltv350qv *lcd; struct lcd_device *ld; @@ -261,7 +261,7 @@ out_unregister: return ret; } -static int __devexit ltv350qv_remove(struct spi_device *spi) +static int ltv350qv_remove(struct spi_device *spi) { struct ltv350qv *lcd = dev_get_drvdata(&spi->dev); @@ -305,7 +305,7 @@ static struct spi_driver ltv350qv_driver = { }, .probe = ltv350qv_probe, - .remove = __devexit_p(ltv350qv_remove), + .remove = ltv350qv_remove, .shutdown = ltv350qv_shutdown, .suspend = ltv350qv_suspend, .resume = ltv350qv_resume, diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index f72ba54f364..c6bec7aab87 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -101,7 +101,7 @@ static const struct backlight_ops max8925_backlight_ops = { .get_brightness = max8925_backlight_get_brightness, }; -static int __devinit max8925_backlight_probe(struct platform_device *pdev) +static int max8925_backlight_probe(struct platform_device *pdev) { struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); struct max8925_backlight_pdata *pdata = pdev->dev.platform_data; @@ -171,7 +171,7 @@ out: return ret; } -static int __devexit max8925_backlight_remove(struct platform_device *pdev) +static int max8925_backlight_remove(struct platform_device *pdev) { struct backlight_device *bl = platform_get_drvdata(pdev); @@ -185,7 +185,7 @@ static struct platform_driver max8925_backlight_driver = { .owner = THIS_MODULE, }, .probe = max8925_backlight_probe, - .remove = __devexit_p(max8925_backlight_remove), + .remove = max8925_backlight_remove, }; module_platform_driver(max8925_backlight_driver); diff --git a/drivers/video/backlight/pcf50633-backlight.c b/drivers/video/backlight/pcf50633-backlight.c index c092159f438..0087396007e 100644 --- a/drivers/video/backlight/pcf50633-backlight.c +++ b/drivers/video/backlight/pcf50633-backlight.c @@ -99,7 +99,7 @@ static const struct backlight_ops pcf50633_bl_ops = { .options = BL_CORE_SUSPENDRESUME, }; -static int __devinit pcf50633_bl_probe(struct platform_device *pdev) +static int pcf50633_bl_probe(struct platform_device *pdev) { struct pcf50633_bl *pcf_bl; struct device *parent = pdev->dev.parent; @@ -145,7 +145,7 @@ static int __devinit pcf50633_bl_probe(struct platform_device *pdev) return 0; } -static int __devexit pcf50633_bl_remove(struct platform_device *pdev) +static int pcf50633_bl_remove(struct platform_device *pdev) { struct pcf50633_bl *pcf_bl = platform_get_drvdata(pdev); @@ -158,7 +158,7 @@ static int __devexit pcf50633_bl_remove(struct platform_device *pdev) static struct platform_driver pcf50633_bl_driver = { .probe = pcf50633_bl_probe, - .remove = __devexit_p(pcf50633_bl_remove), + .remove = pcf50633_bl_remove, .driver = { .name = "pcf50633-backlight", }, diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c index ca4f5d70fe1..894bfc5ce42 100644 --- a/drivers/video/backlight/platform_lcd.c +++ b/drivers/video/backlight/platform_lcd.c @@ -73,7 +73,7 @@ static struct lcd_ops platform_lcd_ops = { .check_fb = platform_lcd_match, }; -static int __devinit platform_lcd_probe(struct platform_device *pdev) +static int platform_lcd_probe(struct platform_device *pdev) { struct plat_lcd_data *pdata; struct platform_lcd *plcd; @@ -112,7 +112,7 @@ static int __devinit platform_lcd_probe(struct platform_device *pdev) return err; } -static int __devexit platform_lcd_remove(struct platform_device *pdev) +static int platform_lcd_remove(struct platform_device *pdev) { struct platform_lcd *plcd = platform_get_drvdata(pdev); @@ -164,7 +164,7 @@ static struct platform_driver platform_lcd_driver = { .of_match_table = of_match_ptr(platform_lcd_of_match), }, .probe = platform_lcd_probe, - .remove = __devexit_p(platform_lcd_remove), + .remove = platform_lcd_remove, }; module_platform_driver(platform_lcd_driver); diff --git a/drivers/video/backlight/s6e63m0.c b/drivers/video/backlight/s6e63m0.c index 6437ae474cf..484e10dd1a8 100644 --- a/drivers/video/backlight/s6e63m0.c +++ b/drivers/video/backlight/s6e63m0.c @@ -733,7 +733,7 @@ static ssize_t s6e63m0_sysfs_show_gamma_table(struct device *dev, static DEVICE_ATTR(gamma_table, 0444, s6e63m0_sysfs_show_gamma_table, NULL); -static int __devinit s6e63m0_probe(struct spi_device *spi) +static int s6e63m0_probe(struct spi_device *spi) { int ret = 0; struct s6e63m0 *lcd = NULL; @@ -825,7 +825,7 @@ out_lcd_unregister: return ret; } -static int __devexit s6e63m0_remove(struct spi_device *spi) +static int s6e63m0_remove(struct spi_device *spi) { struct s6e63m0 *lcd = dev_get_drvdata(&spi->dev); @@ -897,7 +897,7 @@ static struct spi_driver s6e63m0_driver = { .owner = THIS_MODULE, }, .probe = s6e63m0_probe, - .remove = __devexit_p(s6e63m0_remove), + .remove = s6e63m0_remove, .shutdown = s6e63m0_shutdown, .suspend = s6e63m0_suspend, .resume = s6e63m0_resume, diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c index 02444d042cd..146ffb9404d 100644 --- a/drivers/video/backlight/tdo24m.c +++ b/drivers/video/backlight/tdo24m.c @@ -328,7 +328,7 @@ static struct lcd_ops tdo24m_ops = { .set_mode = tdo24m_set_mode, }; -static int __devinit tdo24m_probe(struct spi_device *spi) +static int tdo24m_probe(struct spi_device *spi) { struct tdo24m *lcd; struct spi_message *m; @@ -401,7 +401,7 @@ out_unregister: return err; } -static int __devexit tdo24m_remove(struct spi_device *spi) +static int tdo24m_remove(struct spi_device *spi) { struct tdo24m *lcd = dev_get_drvdata(&spi->dev); @@ -444,7 +444,7 @@ static struct spi_driver tdo24m_driver = { .owner = THIS_MODULE, }, .probe = tdo24m_probe, - .remove = __devexit_p(tdo24m_remove), + .remove = tdo24m_remove, .shutdown = tdo24m_shutdown, .suspend = tdo24m_suspend, .resume = tdo24m_resume, diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c index 49342e1d20b..a0521abdcd8 100644 --- a/drivers/video/backlight/tosa_bl.c +++ b/drivers/video/backlight/tosa_bl.c @@ -78,7 +78,7 @@ static const struct backlight_ops bl_ops = { .update_status = tosa_bl_update_status, }; -static int __devinit tosa_bl_probe(struct i2c_client *client, +static int tosa_bl_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct backlight_properties props; @@ -126,7 +126,7 @@ err_reg: return ret; } -static int __devexit tosa_bl_remove(struct i2c_client *client) +static int tosa_bl_remove(struct i2c_client *client) { struct tosa_bl_data *data = i2c_get_clientdata(client); @@ -170,7 +170,7 @@ static struct i2c_driver tosa_bl_driver = { .owner = THIS_MODULE, }, .probe = tosa_bl_probe, - .remove = __devexit_p(tosa_bl_remove), + .remove = tosa_bl_remove, .suspend = tosa_bl_suspend, .resume = tosa_bl_resume, .id_table = tosa_bl_id, diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c index 33047a66cc2..86fff88c2e4 100644 --- a/drivers/video/backlight/tosa_lcd.c +++ b/drivers/video/backlight/tosa_lcd.c @@ -169,7 +169,7 @@ static struct lcd_ops tosa_lcd_ops = { .set_mode = tosa_lcd_set_mode, }; -static int __devinit tosa_lcd_probe(struct spi_device *spi) +static int tosa_lcd_probe(struct spi_device *spi) { int ret; struct tosa_lcd_data *data; @@ -226,7 +226,7 @@ err_gpio_tg: return ret; } -static int __devexit tosa_lcd_remove(struct spi_device *spi) +static int tosa_lcd_remove(struct spi_device *spi) { struct tosa_lcd_data *data = dev_get_drvdata(&spi->dev); @@ -275,7 +275,7 @@ static struct spi_driver tosa_lcd_driver = { .owner = THIS_MODULE, }, .probe = tosa_lcd_probe, - .remove = __devexit_p(tosa_lcd_remove), + .remove = tosa_lcd_remove, .suspend = tosa_lcd_suspend, .resume = tosa_lcd_resume, }; diff --git a/drivers/video/backlight/vgg2432a4.c b/drivers/video/backlight/vgg2432a4.c index b617fae9aa2..712b0acfd33 100644 --- a/drivers/video/backlight/vgg2432a4.c +++ b/drivers/video/backlight/vgg2432a4.c @@ -227,7 +227,7 @@ static struct ili9320_client vgg2432a4_client = { /* Device probe */ -static int __devinit vgg2432a4_probe(struct spi_device *spi) +static int vgg2432a4_probe(struct spi_device *spi) { int ret; @@ -240,7 +240,7 @@ static int __devinit vgg2432a4_probe(struct spi_device *spi) return 0; } -static int __devexit vgg2432a4_remove(struct spi_device *spi) +static int vgg2432a4_remove(struct spi_device *spi) { return ili9320_remove(dev_get_drvdata(&spi->dev)); } @@ -256,7 +256,7 @@ static struct spi_driver vgg2432a4_driver = { .owner = THIS_MODULE, }, .probe = vgg2432a4_probe, - .remove = __devexit_p(vgg2432a4_remove), + .remove = vgg2432a4_remove, .shutdown = vgg2432a4_shutdown, .suspend = vgg2432a4_suspend, .resume = vgg2432a4_resume, diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index d64ac384288..bee92846cfa 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -365,11 +365,20 @@ struct platform_device *dsi_get_dsidev_from_id(int module) struct omap_dss_output *out; enum omap_dss_output_id id; - id = module == 0 ? OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; + switch (module) { + case 0: + id = OMAP_DSS_OUTPUT_DSI1; + break; + case 1: + id = OMAP_DSS_OUTPUT_DSI2; + break; + default: + return NULL; + } out = omap_dss_get_output(id); - return out->pdev; + return out ? out->pdev : NULL; } static inline void dsi_write_reg(struct platform_device *dsidev, diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 2ab1c3e9655..5f6eea801b0 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -697,11 +697,15 @@ static int dss_get_clocks(void) dss.dss_clk = clk; - clk = clk_get(NULL, dss.feat->clk_name); - if (IS_ERR(clk)) { - DSSERR("Failed to get %s\n", dss.feat->clk_name); - r = PTR_ERR(clk); - goto err; + if (dss.feat->clk_name) { + clk = clk_get(NULL, dss.feat->clk_name); + if (IS_ERR(clk)) { + DSSERR("Failed to get %s\n", dss.feat->clk_name); + r = PTR_ERR(clk); + goto err; + } + } else { + clk = NULL; } dss.dpll4_m4_ck = clk; @@ -805,10 +809,10 @@ static int __init dss_init_features(struct device *dev) if (cpu_is_omap24xx()) src = &omap24xx_dss_feats; - else if (cpu_is_omap34xx()) - src = &omap34xx_dss_feats; else if (cpu_is_omap3630()) src = &omap3630_dss_feats; + else if (cpu_is_omap34xx()) + src = &omap34xx_dss_feats; else if (cpu_is_omap44xx()) src = &omap44xx_dss_feats; else if (soc_is_omap54xx()) diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index a48a7dd75b3..8c9b8b3b7f7 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -644,8 +644,10 @@ static void hdmi_dump_regs(struct seq_file *s) { mutex_lock(&hdmi.lock); - if (hdmi_runtime_get()) + if (hdmi_runtime_get()) { + mutex_unlock(&hdmi.lock); return; + } hdmi.ip_data.ops->dump_wrapper(&hdmi.ip_data, s); hdmi.ip_data.ops->dump_pll(&hdmi.ip_data, s); diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 606b89f1235..d630b26a005 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -787,7 +787,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) case OMAPFB_WAITFORVSYNC: DBG("ioctl WAITFORVSYNC\n"); - if (!display && !display->output && !display->output->manager) { + if (!display || !display->output || !display->output->manager) { r = -EINVAL; break; } diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index 7e984034a11..c433a746e3f 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig @@ -26,7 +26,7 @@ config W1_MASTER_DS2490 config W1_MASTER_DS2482 tristate "Maxim DS2482 I2C to 1-Wire bridge" - depends on I2C && EXPERIMENTAL + depends on I2C help If you say yes here you get support for the Maxim DS2482 I2C to 1-Wire bridge. diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c index e5f74416d4b..6429b9e9fb8 100644 --- a/drivers/w1/masters/ds2482.c +++ b/drivers/w1/masters/ds2482.c @@ -505,19 +505,8 @@ static int ds2482_remove(struct i2c_client *client) return 0; } -static int __init sensors_ds2482_init(void) -{ - return i2c_add_driver(&ds2482_driver); -} - -static void __exit sensors_ds2482_exit(void) -{ - i2c_del_driver(&ds2482_driver); -} +module_i2c_driver(ds2482_driver); MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>"); MODULE_DESCRIPTION("DS2482 driver"); MODULE_LICENSE("GPL"); - -module_init(sensors_ds2482_init); -module_exit(sensors_ds2482_exit); diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c index f667c26b219..d8667b0212d 100644 --- a/drivers/w1/masters/matrox_w1.c +++ b/drivers/w1/masters/matrox_w1.c @@ -48,14 +48,14 @@ static struct pci_device_id matrox_w1_tbl[] = { }; MODULE_DEVICE_TABLE(pci, matrox_w1_tbl); -static int __devinit matrox_w1_probe(struct pci_dev *, const struct pci_device_id *); -static void __devexit matrox_w1_remove(struct pci_dev *); +static int matrox_w1_probe(struct pci_dev *, const struct pci_device_id *); +static void matrox_w1_remove(struct pci_dev *); static struct pci_driver matrox_w1_pci_driver = { .name = "matrox_w1", .id_table = matrox_w1_tbl, .probe = matrox_w1_probe, - .remove = __devexit_p(matrox_w1_remove), + .remove = matrox_w1_remove, }; /* @@ -152,7 +152,7 @@ static void matrox_w1_hw_init(struct matrox_device *dev) matrox_w1_write_reg(dev, MATROX_GET_CONTROL, 0x00); } -static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +static int matrox_w1_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct matrox_device *dev; int err; @@ -220,7 +220,7 @@ err_out_free_device: return err; } -static void __devexit matrox_w1_remove(struct pci_dev *pdev) +static void matrox_w1_remove(struct pci_dev *pdev) { struct matrox_device *dev = pci_get_drvdata(pdev); diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c index 1cc61a700fa..d338b56ea2f 100644 --- a/drivers/w1/masters/mxc_w1.c +++ b/drivers/w1/masters/mxc_w1.c @@ -103,7 +103,7 @@ static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit) return ((__raw_readb(ctrl_addr)) >> 3) & 0x1; } -static int __devinit mxc_w1_probe(struct platform_device *pdev) +static int mxc_w1_probe(struct platform_device *pdev) { struct mxc_w1_device *mdev; struct resource *res; @@ -117,9 +117,9 @@ static int __devinit mxc_w1_probe(struct platform_device *pdev) if (!mdev) return -ENOMEM; - mdev->clk = clk_get(&pdev->dev, "owire"); - if (!mdev->clk) { - err = -ENODEV; + mdev->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(mdev->clk)) { + err = PTR_ERR(mdev->clk); goto failed_clk; } @@ -134,7 +134,7 @@ static int __devinit mxc_w1_probe(struct platform_device *pdev) mdev->regs = ioremap(res->start, resource_size(res)); if (!mdev->regs) { - printk(KERN_ERR "Cannot map frame buffer registers\n"); + dev_err(&pdev->dev, "Cannot map mxc_w1 registers\n"); goto failed_ioremap; } @@ -167,7 +167,7 @@ failed_clk: /* * disassociate the w1 device from the driver */ -static int __devexit mxc_w1_remove(struct platform_device *pdev) +static int mxc_w1_remove(struct platform_device *pdev) { struct mxc_w1_device *mdev = platform_get_drvdata(pdev); struct resource *res; @@ -191,21 +191,9 @@ static struct platform_driver mxc_w1_driver = { .name = "mxc_w1", }, .probe = mxc_w1_probe, - .remove = mxc_w1_remove, + .remove = __devexit_p(mxc_w1_remove), }; - -static int __init mxc_w1_init(void) -{ - return platform_driver_register(&mxc_w1_driver); -} - -static void mxc_w1_exit(void) -{ - platform_driver_unregister(&mxc_w1_driver); -} - -module_init(mxc_w1_init); -module_exit(mxc_w1_exit); +module_platform_driver(mxc_w1_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Freescale Semiconductors Inc"); diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c index ca8e60bb2f9..184dbce4abd 100644 --- a/drivers/w1/masters/omap_hdq.c +++ b/drivers/w1/masters/omap_hdq.c @@ -69,12 +69,12 @@ struct hdq_data { int init_trans; }; -static int __devinit omap_hdq_probe(struct platform_device *pdev); -static int __devexit omap_hdq_remove(struct platform_device *pdev); +static int omap_hdq_probe(struct platform_device *pdev); +static int omap_hdq_remove(struct platform_device *pdev); static struct platform_driver omap_hdq_driver = { .probe = omap_hdq_probe, - .remove = __devexit_p(omap_hdq_remove), + .remove = omap_hdq_remove, .driver = { .name = "omap_hdq", }, @@ -537,7 +537,7 @@ static void omap_w1_write_byte(void *_hdq, u8 byte) } } -static int __devinit omap_hdq_probe(struct platform_device *pdev) +static int omap_hdq_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct hdq_data *hdq_data; @@ -613,7 +613,7 @@ err_w1: return ret; } -static int __devexit omap_hdq_remove(struct platform_device *pdev) +static int omap_hdq_remove(struct platform_device *pdev) { struct hdq_data *hdq_data = platform_get_drvdata(pdev); diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index 6012c4ea320..85b363a5bd0 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -16,6 +16,9 @@ #include <linux/gpio.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> +#include <linux/pinctrl/consumer.h> +#include <linux/err.h> +#include <linux/of.h> #include "../w1.h" #include "../w1_int.h" @@ -44,7 +47,6 @@ static u8 w1_gpio_read_bit(void *data) return gpio_get_value(pdata->pin) ? 1 : 0; } -#ifdef CONFIG_OF static struct of_device_id w1_gpio_dt_ids[] = { { .compatible = "w1-gpio" }, {} @@ -55,11 +57,6 @@ static int w1_gpio_probe_dt(struct platform_device *pdev) { struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; struct device_node *np = pdev->dev.of_node; - const struct of_device_id *of_id = - of_match_device(w1_gpio_dt_ids, &pdev->dev); - - if (!of_id) - return 0; pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -74,41 +71,53 @@ static int w1_gpio_probe_dt(struct platform_device *pdev) return 0; } -#else -static int w1_gpio_probe_dt(struct platform_device *pdev) -{ - return 0; -} -#endif static int __init w1_gpio_probe(struct platform_device *pdev) { struct w1_bus_master *master; struct w1_gpio_platform_data *pdata; + struct pinctrl *pinctrl; int err; - err = w1_gpio_probe_dt(pdev); - if (err < 0) - return err; + pinctrl = devm_pinctrl_get_select_default(&pdev->dev); + if (IS_ERR(pinctrl)) + dev_warn(&pdev->dev, "unable to select pin group\n"); + + if (of_have_populated_dt()) { + err = w1_gpio_probe_dt(pdev); + if (err < 0) { + dev_err(&pdev->dev, "Failed to parse DT\n"); + return err; + } + } pdata = pdev->dev.platform_data; - if (!pdata) + if (!pdata) { + dev_err(&pdev->dev, "No configuration data\n"); return -ENXIO; + } master = kzalloc(sizeof(struct w1_bus_master), GFP_KERNEL); - if (!master) + if (!master) { + dev_err(&pdev->dev, "Out of memory\n"); return -ENOMEM; + } err = gpio_request(pdata->pin, "w1"); - if (err) + if (err) { + dev_err(&pdev->dev, "gpio_request (pin) failed\n"); goto free_master; + } if (gpio_is_valid(pdata->ext_pullup_enable_pin)) { err = gpio_request_one(pdata->ext_pullup_enable_pin, GPIOF_INIT_LOW, "w1 pullup"); - if (err < 0) + if (err < 0) { + dev_err(&pdev->dev, "gpio_request_one " + "(ext_pullup_enable_pin) failed\n"); goto free_gpio; + } } master->data = pdata; @@ -123,8 +132,10 @@ static int __init w1_gpio_probe(struct platform_device *pdev) } err = w1_add_master_device(master); - if (err) + if (err) { + dev_err(&pdev->dev, "w1_add_master device failed\n"); goto free_gpio_ext_pu; + } if (pdata->enable_external_pullup) pdata->enable_external_pullup(1); @@ -198,23 +209,13 @@ static struct platform_driver w1_gpio_driver = { .owner = THIS_MODULE, .of_match_table = of_match_ptr(w1_gpio_dt_ids), }, + .probe = w1_gpio_probe, .remove = __exit_p(w1_gpio_remove), .suspend = w1_gpio_suspend, .resume = w1_gpio_resume, }; -static int __init w1_gpio_init(void) -{ - return platform_driver_probe(&w1_gpio_driver, w1_gpio_probe); -} - -static void __exit w1_gpio_exit(void) -{ - platform_driver_unregister(&w1_gpio_driver); -} - -module_init(w1_gpio_init); -module_exit(w1_gpio_exit); +module_platform_driver(w1_gpio_driver); MODULE_DESCRIPTION("GPIO w1 bus master driver"); MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>"); diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 1a574370d2c..7994d933f04 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -551,7 +551,6 @@ void w1_destroy_master_attributes(struct w1_master *master) sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group); } -#ifdef CONFIG_HOTPLUG static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) { struct w1_master *md = NULL; @@ -587,12 +586,6 @@ static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) end: return err; } -#else -static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - return 0; -} -#endif static int __w1_attach_slave_device(struct w1_slave *sl) { diff --git a/drivers/watchdog/acquirewdt.c b/drivers/watchdog/acquirewdt.c index 4397881c83f..24a517777fa 100644 --- a/drivers/watchdog/acquirewdt.c +++ b/drivers/watchdog/acquirewdt.c @@ -240,7 +240,7 @@ static struct miscdevice acq_miscdev = { * Init & exit routines */ -static int __devinit acq_probe(struct platform_device *dev) +static int acq_probe(struct platform_device *dev) { int ret; @@ -275,7 +275,7 @@ out: return ret; } -static int __devexit acq_remove(struct platform_device *dev) +static int acq_remove(struct platform_device *dev) { misc_deregister(&acq_miscdev); release_region(wdt_start, 1); @@ -293,7 +293,7 @@ static void acq_shutdown(struct platform_device *dev) static struct platform_driver acquirewdt_driver = { .probe = acq_probe, - .remove = __devexit_p(acq_remove), + .remove = acq_remove, .shutdown = acq_shutdown, .driver = { .owner = THIS_MODULE, diff --git a/drivers/watchdog/advantechwdt.c b/drivers/watchdog/advantechwdt.c index 64ae9e9fed9..cc6702fc526 100644 --- a/drivers/watchdog/advantechwdt.c +++ b/drivers/watchdog/advantechwdt.c @@ -238,7 +238,7 @@ static struct miscdevice advwdt_miscdev = { * Init & exit routines */ -static int __devinit advwdt_probe(struct platform_device *dev) +static int advwdt_probe(struct platform_device *dev) { int ret; @@ -282,7 +282,7 @@ unreg_stop: goto out; } -static int __devexit advwdt_remove(struct platform_device *dev) +static int advwdt_remove(struct platform_device *dev) { misc_deregister(&advwdt_miscdev); release_region(wdt_start, 1); @@ -300,7 +300,7 @@ static void advwdt_shutdown(struct platform_device *dev) static struct platform_driver advwdt_driver = { .probe = advwdt_probe, - .remove = __devexit_p(advwdt_remove), + .remove = advwdt_remove, .shutdown = advwdt_shutdown, .driver = { .owner = THIS_MODULE, diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c index dc30dbd21cf..3003e2a9580 100644 --- a/drivers/watchdog/ar7_wdt.c +++ b/drivers/watchdog/ar7_wdt.c @@ -274,7 +274,7 @@ static struct miscdevice ar7_wdt_miscdev = { .fops = &ar7_wdt_fops, }; -static int __devinit ar7_wdt_probe(struct platform_device *pdev) +static int ar7_wdt_probe(struct platform_device *pdev) { int rc; @@ -314,7 +314,7 @@ out: return rc; } -static int __devexit ar7_wdt_remove(struct platform_device *pdev) +static int ar7_wdt_remove(struct platform_device *pdev) { misc_deregister(&ar7_wdt_miscdev); clk_put(vbus_clk); @@ -330,7 +330,7 @@ static void ar7_wdt_shutdown(struct platform_device *pdev) static struct platform_driver ar7_wdt_driver = { .probe = ar7_wdt_probe, - .remove = __devexit_p(ar7_wdt_remove), + .remove = ar7_wdt_remove, .shutdown = ar7_wdt_shutdown, .driver = { .owner = THIS_MODULE, diff --git a/drivers/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c index 7ef99a169e3..89831ed24a4 100644 --- a/drivers/watchdog/at91rm9200_wdt.c +++ b/drivers/watchdog/at91rm9200_wdt.c @@ -199,7 +199,7 @@ static struct miscdevice at91wdt_miscdev = { .fops = &at91wdt_fops, }; -static int __devinit at91wdt_probe(struct platform_device *pdev) +static int at91wdt_probe(struct platform_device *pdev) { int res; @@ -216,7 +216,7 @@ static int __devinit at91wdt_probe(struct platform_device *pdev) return 0; } -static int __devexit at91wdt_remove(struct platform_device *pdev) +static int at91wdt_remove(struct platform_device *pdev) { int res; @@ -254,7 +254,7 @@ static int at91wdt_resume(struct platform_device *pdev) static struct platform_driver at91wdt_driver = { .probe = at91wdt_probe, - .remove = __devexit_p(at91wdt_remove), + .remove = at91wdt_remove, .shutdown = at91wdt_shutdown, .suspend = at91wdt_suspend, .resume = at91wdt_resume, diff --git a/drivers/watchdog/ath79_wdt.c b/drivers/watchdog/ath79_wdt.c index 1f9371f49c4..7c8ede7816b 100644 --- a/drivers/watchdog/ath79_wdt.c +++ b/drivers/watchdog/ath79_wdt.c @@ -224,7 +224,7 @@ static struct miscdevice ath79_wdt_miscdev = { .fops = &ath79_wdt_fops, }; -static int __devinit ath79_wdt_probe(struct platform_device *pdev) +static int ath79_wdt_probe(struct platform_device *pdev) { u32 ctrl; int err; @@ -270,7 +270,7 @@ err_clk_put: return err; } -static int __devexit ath79_wdt_remove(struct platform_device *pdev) +static int ath79_wdt_remove(struct platform_device *pdev) { misc_deregister(&ath79_wdt_miscdev); clk_disable(wdt_clk); @@ -284,7 +284,7 @@ static void ath97_wdt_shutdown(struct platform_device *pdev) } static struct platform_driver ath79_wdt_driver = { - .remove = __devexit_p(ath79_wdt_remove), + .remove = ath79_wdt_remove, .shutdown = ath97_wdt_shutdown, .driver = { .name = DRIVER_NAME, diff --git a/drivers/watchdog/bcm63xx_wdt.c b/drivers/watchdog/bcm63xx_wdt.c index 551880bfd62..b2b80d4ac81 100644 --- a/drivers/watchdog/bcm63xx_wdt.c +++ b/drivers/watchdog/bcm63xx_wdt.c @@ -236,7 +236,7 @@ static struct miscdevice bcm63xx_wdt_miscdev = { }; -static int __devinit bcm63xx_wdt_probe(struct platform_device *pdev) +static int bcm63xx_wdt_probe(struct platform_device *pdev) { int ret; struct resource *r; @@ -286,7 +286,7 @@ unmap: return ret; } -static int __devexit bcm63xx_wdt_remove(struct platform_device *pdev) +static int bcm63xx_wdt_remove(struct platform_device *pdev) { if (!nowayout) bcm63xx_wdt_pause(); @@ -304,7 +304,7 @@ static void bcm63xx_wdt_shutdown(struct platform_device *pdev) static struct platform_driver bcm63xx_wdt_driver = { .probe = bcm63xx_wdt_probe, - .remove = __devexit_p(bcm63xx_wdt_remove), + .remove = bcm63xx_wdt_remove, .shutdown = bcm63xx_wdt_shutdown, .driver = { .owner = THIS_MODULE, diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c index 38bc383e067..5d36d6fb496 100644 --- a/drivers/watchdog/bfin_wdt.c +++ b/drivers/watchdog/bfin_wdt.c @@ -356,7 +356,7 @@ static const struct watchdog_info bfin_wdt_info = { * Registers the misc device. Actual device * initialization is handled by bfin_wdt_open(). */ -static int __devinit bfin_wdt_probe(struct platform_device *pdev) +static int bfin_wdt_probe(struct platform_device *pdev) { int ret; @@ -379,7 +379,7 @@ static int __devinit bfin_wdt_probe(struct platform_device *pdev) * Unregisters the misc device. Actual device * deinitialization is handled by bfin_wdt_close(). */ -static int __devexit bfin_wdt_remove(struct platform_device *pdev) +static int bfin_wdt_remove(struct platform_device *pdev) { misc_deregister(&bfin_wdt_miscdev); return 0; @@ -401,7 +401,7 @@ static struct platform_device *bfin_wdt_device; static struct platform_driver bfin_wdt_driver = { .probe = bfin_wdt_probe, - .remove = __devexit_p(bfin_wdt_remove), + .remove = bfin_wdt_remove, .shutdown = bfin_wdt_shutdown, .suspend = bfin_wdt_suspend, .resume = bfin_wdt_resume, diff --git a/drivers/watchdog/cpu5wdt.c b/drivers/watchdog/cpu5wdt.c index 7e888393de1..cd87758abac 100644 --- a/drivers/watchdog/cpu5wdt.c +++ b/drivers/watchdog/cpu5wdt.c @@ -215,7 +215,7 @@ static struct miscdevice cpu5wdt_misc = { /* init/exit function */ -static int __devinit cpu5wdt_init(void) +static int cpu5wdt_init(void) { unsigned int val; int err; @@ -256,12 +256,12 @@ no_port: return err; } -static int __devinit cpu5wdt_init_module(void) +static int cpu5wdt_init_module(void) { return cpu5wdt_init(); } -static void __devexit cpu5wdt_exit(void) +static void cpu5wdt_exit(void) { if (cpu5wdt_device.queue) { cpu5wdt_device.queue = 0; @@ -274,7 +274,7 @@ static void __devexit cpu5wdt_exit(void) } -static void __devexit cpu5wdt_exit_module(void) +static void cpu5wdt_exit_module(void) { cpu5wdt_exit(); } diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c index 95b1b954de1..11d55ce5ca8 100644 --- a/drivers/watchdog/cpwd.c +++ b/drivers/watchdog/cpwd.c @@ -528,7 +528,7 @@ static const struct file_operations cpwd_fops = { .llseek = no_llseek, }; -static int __devinit cpwd_probe(struct platform_device *op) +static int cpwd_probe(struct platform_device *op) { struct device_node *options; const char *str_prop; @@ -640,7 +640,7 @@ out_free: goto out; } -static int __devexit cpwd_remove(struct platform_device *op) +static int cpwd_remove(struct platform_device *op) { struct cpwd *p = dev_get_drvdata(&op->dev); int i; @@ -684,7 +684,7 @@ static struct platform_driver cpwd_driver = { .of_match_table = cpwd_match, }, .probe = cpwd_probe, - .remove = __devexit_p(cpwd_remove), + .remove = cpwd_remove, }; module_platform_driver(cpwd_driver); diff --git a/drivers/watchdog/da9052_wdt.c b/drivers/watchdog/da9052_wdt.c index f7abbaeebca..8be70d8f268 100644 --- a/drivers/watchdog/da9052_wdt.c +++ b/drivers/watchdog/da9052_wdt.c @@ -179,7 +179,7 @@ static const struct watchdog_ops da9052_wdt_ops = { }; -static int __devinit da9052_wdt_probe(struct platform_device *pdev) +static int da9052_wdt_probe(struct platform_device *pdev) { struct da9052 *da9052 = dev_get_drvdata(pdev->dev.parent); struct da9052_wdt_data *driver_data; @@ -224,7 +224,7 @@ err: return ret; } -static int __devexit da9052_wdt_remove(struct platform_device *pdev) +static int da9052_wdt_remove(struct platform_device *pdev) { struct da9052_wdt_data *driver_data = dev_get_drvdata(&pdev->dev); @@ -236,7 +236,7 @@ static int __devexit da9052_wdt_remove(struct platform_device *pdev) static struct platform_driver da9052_wdt_driver = { .probe = da9052_wdt_probe, - .remove = __devexit_p(da9052_wdt_remove), + .remove = da9052_wdt_remove, .driver = { .name = "da9052-watchdog", }, diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c index c8c5c8032bc..8791879e518 100644 --- a/drivers/watchdog/davinci_wdt.c +++ b/drivers/watchdog/davinci_wdt.c @@ -199,7 +199,7 @@ static struct miscdevice davinci_wdt_miscdev = { .fops = &davinci_wdt_fops, }; -static int __devinit davinci_wdt_probe(struct platform_device *pdev) +static int davinci_wdt_probe(struct platform_device *pdev) { int ret = 0, size; struct device *dev = &pdev->dev; @@ -248,7 +248,7 @@ static int __devinit davinci_wdt_probe(struct platform_device *pdev) return ret; } -static int __devexit davinci_wdt_remove(struct platform_device *pdev) +static int davinci_wdt_remove(struct platform_device *pdev) { misc_deregister(&davinci_wdt_miscdev); if (wdt_mem) { @@ -268,7 +268,7 @@ static struct platform_driver platform_wdt_driver = { .owner = THIS_MODULE, }, .probe = davinci_wdt_probe, - .remove = __devexit_p(davinci_wdt_remove), + .remove = davinci_wdt_remove, }; module_platform_driver(platform_wdt_driver); diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c index 06de1211a44..a0eba3c40e2 100644 --- a/drivers/watchdog/dw_wdt.c +++ b/drivers/watchdog/dw_wdt.c @@ -293,7 +293,7 @@ static struct miscdevice dw_wdt_miscdev = { .minor = WATCHDOG_MINOR, }; -static int __devinit dw_wdt_drv_probe(struct platform_device *pdev) +static int dw_wdt_drv_probe(struct platform_device *pdev) { int ret; struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -333,7 +333,7 @@ out_put_clk: return ret; } -static int __devexit dw_wdt_drv_remove(struct platform_device *pdev) +static int dw_wdt_drv_remove(struct platform_device *pdev) { misc_deregister(&dw_wdt_miscdev); @@ -345,7 +345,7 @@ static int __devexit dw_wdt_drv_remove(struct platform_device *pdev) static struct platform_driver dw_wdt_driver = { .probe = dw_wdt_drv_probe, - .remove = __devexit_p(dw_wdt_drv_remove), + .remove = dw_wdt_drv_remove, .driver = { .name = "dw_wdt", .owner = THIS_MODULE, diff --git a/drivers/watchdog/ep93xx_wdt.c b/drivers/watchdog/ep93xx_wdt.c index 77050037597..e0574844c31 100644 --- a/drivers/watchdog/ep93xx_wdt.c +++ b/drivers/watchdog/ep93xx_wdt.c @@ -112,7 +112,7 @@ static struct watchdog_device ep93xx_wdt_wdd = { .ops = &ep93xx_wdt_ops, }; -static int __devinit ep93xx_wdt_probe(struct platform_device *pdev) +static int ep93xx_wdt_probe(struct platform_device *pdev) { struct resource *res; unsigned long val; @@ -156,7 +156,7 @@ static int __devinit ep93xx_wdt_probe(struct platform_device *pdev) return 0; } -static int __devexit ep93xx_wdt_remove(struct platform_device *pdev) +static int ep93xx_wdt_remove(struct platform_device *pdev) { watchdog_unregister_device(&ep93xx_wdt_wdd); return 0; @@ -168,7 +168,7 @@ static struct platform_driver ep93xx_wdt_driver = { .name = "ep93xx-wdt", }, .probe = ep93xx_wdt_probe, - .remove = __devexit_p(ep93xx_wdt_remove), + .remove = ep93xx_wdt_remove, }; module_platform_driver(ep93xx_wdt_driver); diff --git a/drivers/watchdog/gef_wdt.c b/drivers/watchdog/gef_wdt.c index 17f4cae770c..b9c5b58e59d 100644 --- a/drivers/watchdog/gef_wdt.c +++ b/drivers/watchdog/gef_wdt.c @@ -262,7 +262,7 @@ static struct miscdevice gef_wdt_miscdev = { }; -static int __devinit gef_wdt_probe(struct platform_device *dev) +static int gef_wdt_probe(struct platform_device *dev) { int timeout = 10; u32 freq; @@ -285,7 +285,7 @@ static int __devinit gef_wdt_probe(struct platform_device *dev) return misc_register(&gef_wdt_miscdev); } -static int __devexit gef_wdt_remove(struct platform_device *dev) +static int gef_wdt_remove(struct platform_device *dev) { misc_deregister(&gef_wdt_miscdev); diff --git a/drivers/watchdog/geodewdt.c b/drivers/watchdog/geodewdt.c index dc563b680ab..fcd599d4e22 100644 --- a/drivers/watchdog/geodewdt.c +++ b/drivers/watchdog/geodewdt.c @@ -215,7 +215,7 @@ static struct miscdevice geodewdt_miscdev = { .fops = &geodewdt_fops, }; -static int __devinit geodewdt_probe(struct platform_device *dev) +static int geodewdt_probe(struct platform_device *dev) { int ret; @@ -243,7 +243,7 @@ static int __devinit geodewdt_probe(struct platform_device *dev) return ret; } -static int __devexit geodewdt_remove(struct platform_device *dev) +static int geodewdt_remove(struct platform_device *dev) { misc_deregister(&geodewdt_miscdev); return 0; @@ -256,7 +256,7 @@ static void geodewdt_shutdown(struct platform_device *dev) static struct platform_driver geodewdt_driver = { .probe = geodewdt_probe, - .remove = __devexit_p(geodewdt_remove), + .remove = geodewdt_remove, .shutdown = geodewdt_shutdown, .driver = { .owner = THIS_MODULE, diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index ae60406ea8a..8717255ec7b 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -212,7 +212,7 @@ asm(".text \n\t" * 0 : SUCCESS * <0 : FAILURE */ -static int __devinit cru_detect(unsigned long map_entry, +static int cru_detect(unsigned long map_entry, unsigned long map_offset) { void *bios32_map; @@ -268,7 +268,7 @@ static int __devinit cru_detect(unsigned long map_entry, /* * bios_checksum */ -static int __devinit bios_checksum(const char __iomem *ptr, int len) +static int bios_checksum(const char __iomem *ptr, int len) { char sum = 0; int i; @@ -293,7 +293,7 @@ static int __devinit bios_checksum(const char __iomem *ptr, int len) * 0 : SUCCESS * <0 : FAILURE */ -static int __devinit bios32_present(const char __iomem *p) +static int bios32_present(const char __iomem *p) { struct bios32_service_dir *bios_32_ptr; int length; @@ -323,7 +323,7 @@ static int __devinit bios32_present(const char __iomem *p) return -ENODEV; } -static int __devinit detect_cru_service(void) +static int detect_cru_service(void) { char __iomem *p, *q; int rc = -1; @@ -395,7 +395,7 @@ asm(".text \n\t" * This function checks whether or not a SMBIOS/DMI record is * the 64bit CRU info or not */ -static void __devinit dmi_find_cru(const struct dmi_header *dm, void *dummy) +static void dmi_find_cru(const struct dmi_header *dm, void *dummy) { struct smbios_cru64_info *smbios_cru64_ptr; unsigned long cru_physical_address; @@ -414,7 +414,7 @@ static void __devinit dmi_find_cru(const struct dmi_header *dm, void *dummy) } } -static int __devinit detect_cru_service(void) +static int detect_cru_service(void) { cru_rom_addr = NULL; @@ -647,7 +647,7 @@ static struct miscdevice hpwdt_miscdev = { #ifdef CONFIG_HPWDT_NMI_DECODING #ifdef CONFIG_X86_LOCAL_APIC -static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) +static void hpwdt_check_nmi_decoding(struct pci_dev *dev) { /* * If nmi_watchdog is turned off then we can turn on @@ -656,7 +656,7 @@ static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) hpwdt_nmi_decoding = 1; } #else -static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) +static void hpwdt_check_nmi_decoding(struct pci_dev *dev) { dev_warn(&dev->dev, "NMI decoding is disabled. " "Your kernel does not support a NMI Watchdog.\n"); @@ -671,7 +671,7 @@ static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) * This check is independent of architecture and needs to be made for * any ProLiant system. */ -static void __devinit dmi_find_icru(const struct dmi_header *dm, void *dummy) +static void dmi_find_icru(const struct dmi_header *dm, void *dummy) { struct smbios_proliant_info *smbios_proliant_ptr; @@ -682,7 +682,7 @@ static void __devinit dmi_find_icru(const struct dmi_header *dm, void *dummy) } } -static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev) +static int hpwdt_init_nmi_decoding(struct pci_dev *dev) { int retval; @@ -762,11 +762,11 @@ static void hpwdt_exit_nmi_decoding(void) iounmap(cru_rom_addr); } #else /* !CONFIG_HPWDT_NMI_DECODING */ -static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) +static void hpwdt_check_nmi_decoding(struct pci_dev *dev) { } -static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev) +static int hpwdt_init_nmi_decoding(struct pci_dev *dev) { return 0; } @@ -776,7 +776,7 @@ static void hpwdt_exit_nmi_decoding(void) } #endif /* CONFIG_HPWDT_NMI_DECODING */ -static int __devinit hpwdt_init_one(struct pci_dev *dev, +static int hpwdt_init_one(struct pci_dev *dev, const struct pci_device_id *ent) { int retval; @@ -848,7 +848,7 @@ error_pci_iomap: return retval; } -static void __devexit hpwdt_exit(struct pci_dev *dev) +static void hpwdt_exit(struct pci_dev *dev) { if (!nowayout) hpwdt_stop(); @@ -863,7 +863,7 @@ static struct pci_driver hpwdt_driver = { .name = "hpwdt", .id_table = hpwdt_devices, .probe = hpwdt_init_one, - .remove = __devexit_p(hpwdt_exit), + .remove = hpwdt_exit, }; MODULE_AUTHOR("Tom Mingarelli"); diff --git a/drivers/watchdog/i6300esb.c b/drivers/watchdog/i6300esb.c index 276877d5b6a..2b2ea13d03e 100644 --- a/drivers/watchdog/i6300esb.c +++ b/drivers/watchdog/i6300esb.c @@ -344,7 +344,7 @@ MODULE_DEVICE_TABLE(pci, esb_pci_tbl); * Init & exit routines */ -static unsigned char __devinit esb_getdevice(struct pci_dev *pdev) +static unsigned char esb_getdevice(struct pci_dev *pdev) { if (pci_enable_device(pdev)) { pr_err("failed to enable device\n"); @@ -375,7 +375,7 @@ err_devput: return 0; } -static void __devinit esb_initdevice(void) +static void esb_initdevice(void) { u8 val1; u16 val2; @@ -416,7 +416,7 @@ static void __devinit esb_initdevice(void) esb_timer_set_heartbeat(heartbeat); } -static int __devinit esb_probe(struct pci_dev *pdev, +static int esb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int ret; @@ -465,7 +465,7 @@ err_unmap: return ret; } -static void __devexit esb_remove(struct pci_dev *pdev) +static void esb_remove(struct pci_dev *pdev) { /* Stop the timer before we leave */ if (!nowayout) @@ -488,7 +488,7 @@ static struct pci_driver esb_driver = { .name = ESB_MODULE_NAME, .id_table = esb_pci_tbl, .probe = esb_probe, - .remove = __devexit_p(esb_remove), + .remove = esb_remove, .shutdown = esb_shutdown, }; diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index 545d387de41..6130321da38 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -364,7 +364,7 @@ static struct watchdog_device iTCO_wdt_watchdog_dev = { * Init & exit routines */ -static void __devexit iTCO_wdt_cleanup(void) +static void iTCO_wdt_cleanup(void) { /* Stop the timer before we leave */ if (!nowayout) @@ -390,7 +390,7 @@ static void __devexit iTCO_wdt_cleanup(void) iTCO_wdt_private.gcs = NULL; } -static int __devinit iTCO_wdt_probe(struct platform_device *dev) +static int iTCO_wdt_probe(struct platform_device *dev) { int ret = -ENODEV; unsigned long val32; @@ -533,7 +533,7 @@ out: return ret; } -static int __devexit iTCO_wdt_remove(struct platform_device *dev) +static int iTCO_wdt_remove(struct platform_device *dev) { if (iTCO_wdt_private.tco_res || iTCO_wdt_private.smi_res) iTCO_wdt_cleanup(); @@ -548,7 +548,7 @@ static void iTCO_wdt_shutdown(struct platform_device *dev) static struct platform_driver iTCO_wdt_driver = { .probe = iTCO_wdt_probe, - .remove = __devexit_p(iTCO_wdt_remove), + .remove = iTCO_wdt_remove, .shutdown = iTCO_wdt_shutdown, .driver = { .owner = THIS_MODULE, diff --git a/drivers/watchdog/ib700wdt.c b/drivers/watchdog/ib700wdt.c index 184c0bfc87a..eb6b5cc98ec 100644 --- a/drivers/watchdog/ib700wdt.c +++ b/drivers/watchdog/ib700wdt.c @@ -277,7 +277,7 @@ static struct miscdevice ibwdt_miscdev = { * Init & exit routines */ -static int __devinit ibwdt_probe(struct platform_device *dev) +static int ibwdt_probe(struct platform_device *dev) { int res; @@ -319,7 +319,7 @@ out_nostopreg: return res; } -static int __devexit ibwdt_remove(struct platform_device *dev) +static int ibwdt_remove(struct platform_device *dev) { misc_deregister(&ibwdt_miscdev); release_region(WDT_START, 1); @@ -337,7 +337,7 @@ static void ibwdt_shutdown(struct platform_device *dev) static struct platform_driver ibwdt_driver = { .probe = ibwdt_probe, - .remove = __devexit_p(ibwdt_remove), + .remove = ibwdt_remove, .shutdown = ibwdt_shutdown, .driver = { .owner = THIS_MODULE, diff --git a/drivers/watchdog/ie6xx_wdt.c b/drivers/watchdog/ie6xx_wdt.c index 8f541b94005..e24ef6a6e06 100644 --- a/drivers/watchdog/ie6xx_wdt.c +++ b/drivers/watchdog/ie6xx_wdt.c @@ -225,7 +225,7 @@ static const struct file_operations ie6xx_wdt_dbg_operations = { .release = single_release, }; -static void __devinit ie6xx_wdt_debugfs_init(void) +static void ie6xx_wdt_debugfs_init(void) { /* /sys/kernel/debug/ie6xx_wdt */ ie6xx_wdt_data.debugfs = debugfs_create_file("ie6xx_wdt", @@ -238,7 +238,7 @@ static void ie6xx_wdt_debugfs_exit(void) } #else -static void __devinit ie6xx_wdt_debugfs_init(void) +static void ie6xx_wdt_debugfs_init(void) { } @@ -247,7 +247,7 @@ static void ie6xx_wdt_debugfs_exit(void) } #endif -static int __devinit ie6xx_wdt_probe(struct platform_device *pdev) +static int ie6xx_wdt_probe(struct platform_device *pdev) { struct resource *res; u8 wdtlr; @@ -295,7 +295,7 @@ misc_register_error: return ret; } -static int __devexit ie6xx_wdt_remove(struct platform_device *pdev) +static int ie6xx_wdt_remove(struct platform_device *pdev) { struct resource *res; @@ -311,7 +311,7 @@ static int __devexit ie6xx_wdt_remove(struct platform_device *pdev) static struct platform_driver ie6xx_wdt_driver = { .probe = ie6xx_wdt_probe, - .remove = __devexit_p(ie6xx_wdt_remove), + .remove = ie6xx_wdt_remove, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c index 978615ef899..a61408fa0c9 100644 --- a/drivers/watchdog/jz4740_wdt.c +++ b/drivers/watchdog/jz4740_wdt.c @@ -144,7 +144,7 @@ static const struct watchdog_ops jz4740_wdt_ops = { .set_timeout = jz4740_wdt_set_timeout, }; -static int __devinit jz4740_wdt_probe(struct platform_device *pdev) +static int jz4740_wdt_probe(struct platform_device *pdev) { struct jz4740_wdt_drvdata *drvdata; struct watchdog_device *jz4740_wdt; @@ -197,7 +197,7 @@ err_out: return ret; } -static int __devexit jz4740_wdt_remove(struct platform_device *pdev) +static int jz4740_wdt_remove(struct platform_device *pdev) { struct jz4740_wdt_drvdata *drvdata = platform_get_drvdata(pdev); @@ -210,7 +210,7 @@ static int __devexit jz4740_wdt_remove(struct platform_device *pdev) static struct platform_driver jz4740_wdt_driver = { .probe = jz4740_wdt_probe, - .remove = __devexit_p(jz4740_wdt_remove), + .remove = jz4740_wdt_remove, .driver = { .name = "jz4740-wdt", .owner = THIS_MODULE, diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c index c1a4d3bf581..dce9ecffd44 100644 --- a/drivers/watchdog/ks8695_wdt.c +++ b/drivers/watchdog/ks8695_wdt.c @@ -235,7 +235,7 @@ static struct miscdevice ks8695wdt_miscdev = { .fops = &ks8695wdt_fops, }; -static int __devinit ks8695wdt_probe(struct platform_device *pdev) +static int ks8695wdt_probe(struct platform_device *pdev) { int res; @@ -252,7 +252,7 @@ static int __devinit ks8695wdt_probe(struct platform_device *pdev) return 0; } -static int __devexit ks8695wdt_remove(struct platform_device *pdev) +static int ks8695wdt_remove(struct platform_device *pdev) { int res; @@ -290,7 +290,7 @@ static int ks8695wdt_resume(struct platform_device *pdev) static struct platform_driver ks8695wdt_driver = { .probe = ks8695wdt_probe, - .remove = __devexit_p(ks8695wdt_remove), + .remove = ks8695wdt_remove, .shutdown = ks8695wdt_shutdown, .suspend = ks8695wdt_suspend, .resume = ks8695wdt_resume, diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c index 2e74c3a8ee5..79fe01b4233 100644 --- a/drivers/watchdog/lantiq_wdt.c +++ b/drivers/watchdog/lantiq_wdt.c @@ -186,7 +186,7 @@ static struct miscdevice ltq_wdt_miscdev = { .fops = <q_wdt_fops, }; -static int __devinit +static int ltq_wdt_probe(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -220,7 +220,7 @@ ltq_wdt_probe(struct platform_device *pdev) return misc_register(<q_wdt_miscdev); } -static int __devexit +static int ltq_wdt_remove(struct platform_device *pdev) { misc_deregister(<q_wdt_miscdev); @@ -236,7 +236,7 @@ MODULE_DEVICE_TABLE(of, ltq_wdt_match); static struct platform_driver ltq_wdt_driver = { .probe = ltq_wdt_probe, - .remove = __devexit_p(ltq_wdt_remove), + .remove = ltq_wdt_remove, .driver = { .name = "wdt", .owner = THIS_MODULE, diff --git a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c index 8f4a74e9161..773c661723c 100644 --- a/drivers/watchdog/max63xx_wdt.c +++ b/drivers/watchdog/max63xx_wdt.c @@ -174,7 +174,7 @@ static struct watchdog_device max63xx_wdt_dev = { .ops = &max63xx_wdt_ops, }; -static int __devinit max63xx_wdt_probe(struct platform_device *pdev) +static int max63xx_wdt_probe(struct platform_device *pdev) { struct resource *wdt_mem; struct max63xx_timeout *table; @@ -209,7 +209,7 @@ static int __devinit max63xx_wdt_probe(struct platform_device *pdev) return watchdog_register_device(&max63xx_wdt_dev); } -static int __devexit max63xx_wdt_remove(struct platform_device *pdev) +static int max63xx_wdt_remove(struct platform_device *pdev) { watchdog_unregister_device(&max63xx_wdt_dev); return 0; @@ -228,7 +228,7 @@ MODULE_DEVICE_TABLE(platform, max63xx_id_table); static struct platform_driver max63xx_wdt_driver = { .probe = max63xx_wdt_probe, - .remove = __devexit_p(max63xx_wdt_remove), + .remove = max63xx_wdt_remove, .id_table = max63xx_id_table, .driver = { .name = "max63xx_wdt", diff --git a/drivers/watchdog/mixcomwd.c b/drivers/watchdog/mixcomwd.c index 37e4b52dbce..97d62ee5034 100644 --- a/drivers/watchdog/mixcomwd.c +++ b/drivers/watchdog/mixcomwd.c @@ -73,7 +73,7 @@ static struct { int ioport; int id; -} mixcomwd_io_info[] __devinitdata = { +} mixcomwd_io_info[] = { /* The Mixcom cards */ {0x0d90, MIXCOM_ID}, {0x0e90, MIXCOM_ID}, diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index e6a038ae8dc..da2752063bb 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -188,7 +188,7 @@ static struct miscdevice mpc8xxx_wdt_miscdev = { }; static const struct of_device_id mpc8xxx_wdt_match[]; -static int __devinit mpc8xxx_wdt_probe(struct platform_device *ofdev) +static int mpc8xxx_wdt_probe(struct platform_device *ofdev) { int ret; const struct of_device_id *match; @@ -245,7 +245,7 @@ err_unmap: return ret; } -static int __devexit mpc8xxx_wdt_remove(struct platform_device *ofdev) +static int mpc8xxx_wdt_remove(struct platform_device *ofdev) { mpc8xxx_wdt_pr_warn("watchdog removed"); del_timer_sync(&wdt_timer); @@ -281,7 +281,7 @@ MODULE_DEVICE_TABLE(of, mpc8xxx_wdt_match); static struct platform_driver mpc8xxx_wdt_driver = { .probe = mpc8xxx_wdt_probe, - .remove = __devexit_p(mpc8xxx_wdt_remove), + .remove = mpc8xxx_wdt_remove, .driver = { .name = "mpc8xxx_wdt", .owner = THIS_MODULE, diff --git a/drivers/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c index 7c741dc987b..a84eb551ea2 100644 --- a/drivers/watchdog/mpcore_wdt.c +++ b/drivers/watchdog/mpcore_wdt.c @@ -327,7 +327,7 @@ static struct miscdevice mpcore_wdt_miscdev = { .fops = &mpcore_wdt_fops, }; -static int __devinit mpcore_wdt_probe(struct platform_device *pdev) +static int mpcore_wdt_probe(struct platform_device *pdev) { struct mpcore_wdt *wdt; struct resource *res; @@ -378,7 +378,7 @@ static int __devinit mpcore_wdt_probe(struct platform_device *pdev) return 0; } -static int __devexit mpcore_wdt_remove(struct platform_device *pdev) +static int mpcore_wdt_remove(struct platform_device *pdev) { platform_set_drvdata(pdev, NULL); @@ -415,7 +415,7 @@ MODULE_ALIAS("platform:mpcore_wdt"); static struct platform_driver mpcore_wdt_driver = { .probe = mpcore_wdt_probe, - .remove = __devexit_p(mpcore_wdt_remove), + .remove = mpcore_wdt_remove, .suspend = mpcore_wdt_suspend, .resume = mpcore_wdt_resume, .shutdown = mpcore_wdt_shutdown, diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c index c29e31d99fe..14dab6ff87a 100644 --- a/drivers/watchdog/mtx-1_wdt.c +++ b/drivers/watchdog/mtx-1_wdt.c @@ -204,7 +204,7 @@ static struct miscdevice mtx1_wdt_misc = { }; -static int __devinit mtx1_wdt_probe(struct platform_device *pdev) +static int mtx1_wdt_probe(struct platform_device *pdev) { int ret; @@ -233,7 +233,7 @@ static int __devinit mtx1_wdt_probe(struct platform_device *pdev) return 0; } -static int __devexit mtx1_wdt_remove(struct platform_device *pdev) +static int mtx1_wdt_remove(struct platform_device *pdev) { /* FIXME: do we need to lock this test ? */ if (mtx1_wdt_device.queue) { @@ -248,7 +248,7 @@ static int __devexit mtx1_wdt_remove(struct platform_device *pdev) static struct platform_driver mtx1_wdt_driver = { .probe = mtx1_wdt_probe, - .remove = __devexit_p(mtx1_wdt_remove), + .remove = mtx1_wdt_remove, .driver.name = "mtx1-wdt", .driver.owner = THIS_MODULE, }; diff --git a/drivers/watchdog/mv64x60_wdt.c b/drivers/watchdog/mv64x60_wdt.c index c53d025e70d..c7fb878ca49 100644 --- a/drivers/watchdog/mv64x60_wdt.c +++ b/drivers/watchdog/mv64x60_wdt.c @@ -253,7 +253,7 @@ static struct miscdevice mv64x60_wdt_miscdev = { .fops = &mv64x60_wdt_fops, }; -static int __devinit mv64x60_wdt_probe(struct platform_device *dev) +static int mv64x60_wdt_probe(struct platform_device *dev) { struct mv64x60_wdt_pdata *pdata = dev->dev.platform_data; struct resource *r; @@ -287,7 +287,7 @@ static int __devinit mv64x60_wdt_probe(struct platform_device *dev) return misc_register(&mv64x60_wdt_miscdev); } -static int __devexit mv64x60_wdt_remove(struct platform_device *dev) +static int mv64x60_wdt_remove(struct platform_device *dev) { misc_deregister(&mv64x60_wdt_miscdev); @@ -300,7 +300,7 @@ static int __devexit mv64x60_wdt_remove(struct platform_device *dev) static struct platform_driver mv64x60_wdt_driver = { .probe = mv64x60_wdt_probe, - .remove = __devexit_p(mv64x60_wdt_remove), + .remove = mv64x60_wdt_remove, .driver = { .owner = THIS_MODULE, .name = MV64x60_WDT_NAME, diff --git a/drivers/watchdog/nuc900_wdt.c b/drivers/watchdog/nuc900_wdt.c index ea4c7448b75..04c45a10299 100644 --- a/drivers/watchdog/nuc900_wdt.c +++ b/drivers/watchdog/nuc900_wdt.c @@ -242,7 +242,7 @@ static struct miscdevice nuc900wdt_miscdev = { .fops = &nuc900wdt_fops, }; -static int __devinit nuc900wdt_probe(struct platform_device *pdev) +static int nuc900wdt_probe(struct platform_device *pdev) { int ret = 0; @@ -309,7 +309,7 @@ err_get: return ret; } -static int __devexit nuc900wdt_remove(struct platform_device *pdev) +static int nuc900wdt_remove(struct platform_device *pdev) { misc_deregister(&nuc900wdt_miscdev); @@ -328,7 +328,7 @@ static int __devexit nuc900wdt_remove(struct platform_device *pdev) static struct platform_driver nuc900wdt_driver = { .probe = nuc900wdt_probe, - .remove = __devexit_p(nuc900wdt_remove), + .remove = nuc900wdt_remove, .driver = { .name = "nuc900-wdt", .owner = THIS_MODULE, diff --git a/drivers/watchdog/nv_tco.c b/drivers/watchdog/nv_tco.c index 6bbb9efc612..59cf19eeea0 100644 --- a/drivers/watchdog/nv_tco.c +++ b/drivers/watchdog/nv_tco.c @@ -302,7 +302,7 @@ MODULE_DEVICE_TABLE(pci, tco_pci_tbl); * Init & exit routines */ -static unsigned char __devinit nv_tco_getdevice(void) +static unsigned char nv_tco_getdevice(void) { struct pci_dev *dev = NULL; u32 val; @@ -376,7 +376,7 @@ out: return 0; } -static int __devinit nv_tco_init(struct platform_device *dev) +static int nv_tco_init(struct platform_device *dev) { int ret; @@ -423,7 +423,7 @@ unreg_region: return ret; } -static void __devexit nv_tco_cleanup(void) +static void nv_tco_cleanup(void) { u32 val; @@ -445,7 +445,7 @@ static void __devexit nv_tco_cleanup(void) release_region(tcobase, 0x10); } -static int __devexit nv_tco_remove(struct platform_device *dev) +static int nv_tco_remove(struct platform_device *dev) { if (tcobase) nv_tco_cleanup(); @@ -468,7 +468,7 @@ static void nv_tco_shutdown(struct platform_device *dev) static struct platform_driver nv_tco_driver = { .probe = nv_tco_init, - .remove = __devexit_p(nv_tco_remove), + .remove = nv_tco_remove, .shutdown = nv_tco_shutdown, .driver = { .owner = THIS_MODULE, diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c index 294fb4e0052..2761ddb0850 100644 --- a/drivers/watchdog/of_xilinx_wdt.c +++ b/drivers/watchdog/of_xilinx_wdt.c @@ -289,7 +289,7 @@ static struct miscdevice xwdt_miscdev = { .fops = &xwdt_fops, }; -static int __devinit xwdt_probe(struct platform_device *pdev) +static int xwdt_probe(struct platform_device *pdev) { int rc; u32 *tmptr; @@ -383,7 +383,7 @@ err_out: return rc; } -static int __devexit xwdt_remove(struct platform_device *dev) +static int xwdt_remove(struct platform_device *dev) { misc_deregister(&xwdt_miscdev); iounmap(xdev.base); @@ -393,7 +393,7 @@ static int __devexit xwdt_remove(struct platform_device *dev) } /* Match table for of_platform binding */ -static struct of_device_id __devinitdata xwdt_of_match[] = { +static struct of_device_id xwdt_of_match[] = { { .compatible = "xlnx,xps-timebase-wdt-1.01.a", }, {}, }; @@ -401,7 +401,7 @@ MODULE_DEVICE_TABLE(of, xwdt_of_match); static struct platform_driver xwdt_driver = { .probe = xwdt_probe, - .remove = __devexit_p(xwdt_remove), + .remove = xwdt_remove, .driver = { .owner = THIS_MODULE, .name = WATCHDOG_NAME, diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c index f5db18dbc0f..d8da5162f0d 100644 --- a/drivers/watchdog/omap_wdt.c +++ b/drivers/watchdog/omap_wdt.c @@ -264,7 +264,7 @@ static const struct file_operations omap_wdt_fops = { .llseek = no_llseek, }; -static int __devinit omap_wdt_probe(struct platform_device *pdev) +static int omap_wdt_probe(struct platform_device *pdev) { struct resource *res, *mem; struct omap_wdt_dev *wdev; @@ -359,7 +359,7 @@ static void omap_wdt_shutdown(struct platform_device *pdev) } } -static int __devexit omap_wdt_remove(struct platform_device *pdev) +static int omap_wdt_remove(struct platform_device *pdev) { struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -426,7 +426,7 @@ MODULE_DEVICE_TABLE(of, omap_wdt_of_match); static struct platform_driver omap_wdt_driver = { .probe = omap_wdt_probe, - .remove = __devexit_p(omap_wdt_remove), + .remove = omap_wdt_remove, .shutdown = omap_wdt_shutdown, .suspend = omap_wdt_suspend, .resume = omap_wdt_resume, diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index c20f96b579d..0478b001b1e 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c @@ -142,7 +142,7 @@ static struct watchdog_device orion_wdt = { .ops = &orion_wdt_ops, }; -static int __devinit orion_wdt_probe(struct platform_device *pdev) +static int orion_wdt_probe(struct platform_device *pdev) { struct resource *res; int ret; @@ -181,7 +181,7 @@ static int __devinit orion_wdt_probe(struct platform_device *pdev) return 0; } -static int __devexit orion_wdt_remove(struct platform_device *pdev) +static int orion_wdt_remove(struct platform_device *pdev) { watchdog_unregister_device(&orion_wdt); clk_disable_unprepare(clk); @@ -193,7 +193,7 @@ static void orion_wdt_shutdown(struct platform_device *pdev) orion_wdt_stop(&orion_wdt); } -static const struct of_device_id orion_wdt_of_match_table[] __devinitdata = { +static const struct of_device_id orion_wdt_of_match_table[] = { { .compatible = "marvell,orion-wdt", }, {}, }; @@ -201,7 +201,7 @@ MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table); static struct platform_driver orion_wdt_driver = { .probe = orion_wdt_probe, - .remove = __devexit_p(orion_wdt_remove), + .remove = orion_wdt_remove, .shutdown = orion_wdt_shutdown, .driver = { .owner = THIS_MODULE, diff --git a/drivers/watchdog/pcwd.c b/drivers/watchdog/pcwd.c index 75694cf24f8..33e49a7f889 100644 --- a/drivers/watchdog/pcwd.c +++ b/drivers/watchdog/pcwd.c @@ -801,7 +801,7 @@ static inline int get_revision(void) * The initial rate is once per second at board start up, then twice * per second for normal operation. */ -static int __devinit pcwd_isa_match(struct device *dev, unsigned int id) +static int pcwd_isa_match(struct device *dev, unsigned int id) { int base_addr = pcwd_ioports[id]; int port0, last_port0; /* Reg 0, in case it's REV A */ @@ -846,7 +846,7 @@ static int __devinit pcwd_isa_match(struct device *dev, unsigned int id) return retval; } -static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id) +static int pcwd_isa_probe(struct device *dev, unsigned int id) { int ret; @@ -949,7 +949,7 @@ error_request_region: return ret; } -static int __devexit pcwd_isa_remove(struct device *dev, unsigned int id) +static int pcwd_isa_remove(struct device *dev, unsigned int id) { if (debug >= DEBUG) pr_debug("pcwd_isa_remove id=%d\n", id); @@ -984,7 +984,7 @@ static void pcwd_isa_shutdown(struct device *dev, unsigned int id) static struct isa_driver pcwd_isa_driver = { .match = pcwd_isa_match, .probe = pcwd_isa_probe, - .remove = __devexit_p(pcwd_isa_remove), + .remove = pcwd_isa_remove, .shutdown = pcwd_isa_shutdown, .driver = { .owner = THIS_MODULE, diff --git a/drivers/watchdog/pcwd_pci.c b/drivers/watchdog/pcwd_pci.c index ee6900da867..7890f84edf7 100644 --- a/drivers/watchdog/pcwd_pci.c +++ b/drivers/watchdog/pcwd_pci.c @@ -682,7 +682,7 @@ static struct notifier_block pcipcwd_notifier = { * Init & exit routines */ -static int __devinit pcipcwd_card_init(struct pci_dev *pdev, +static int pcipcwd_card_init(struct pci_dev *pdev, const struct pci_device_id *ent) { int ret = -EIO; @@ -785,7 +785,7 @@ err_out_disable_device: return ret; } -static void __devexit pcipcwd_card_exit(struct pci_dev *pdev) +static void pcipcwd_card_exit(struct pci_dev *pdev) { /* Stop the timer before we leave */ if (!nowayout) @@ -812,7 +812,7 @@ static struct pci_driver pcipcwd_driver = { .name = WATCHDOG_NAME, .id_table = pcipcwd_pci_tbl, .probe = pcipcwd_card_init, - .remove = __devexit_p(pcipcwd_card_exit), + .remove = pcipcwd_card_exit, }; module_pci_driver(pcipcwd_driver); diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c index 87722e12605..dcba5dab6c2 100644 --- a/drivers/watchdog/pnx4008_wdt.c +++ b/drivers/watchdog/pnx4008_wdt.c @@ -146,7 +146,7 @@ static struct watchdog_device pnx4008_wdd = { .max_timeout = MAX_HEARTBEAT, }; -static int __devinit pnx4008_wdt_probe(struct platform_device *pdev) +static int pnx4008_wdt_probe(struct platform_device *pdev) { struct resource *r; int ret = 0; @@ -192,7 +192,7 @@ out: return ret; } -static int __devexit pnx4008_wdt_remove(struct platform_device *pdev) +static int pnx4008_wdt_remove(struct platform_device *pdev) { watchdog_unregister_device(&pnx4008_wdd); @@ -217,7 +217,7 @@ static struct platform_driver platform_wdt_driver = { .of_match_table = of_match_ptr(pnx4008_wdt_match), }, .probe = pnx4008_wdt_probe, - .remove = __devexit_p(pnx4008_wdt_remove), + .remove = pnx4008_wdt_remove, }; module_platform_driver(platform_wdt_driver); diff --git a/drivers/watchdog/rc32434_wdt.c b/drivers/watchdog/rc32434_wdt.c index 547353a50eb..f78bc008cbb 100644 --- a/drivers/watchdog/rc32434_wdt.c +++ b/drivers/watchdog/rc32434_wdt.c @@ -260,7 +260,7 @@ static struct miscdevice rc32434_wdt_miscdev = { .fops = &rc32434_wdt_fops, }; -static int __devinit rc32434_wdt_probe(struct platform_device *pdev) +static int rc32434_wdt_probe(struct platform_device *pdev) { int ret; struct resource *r; @@ -306,7 +306,7 @@ unmap: return ret; } -static int __devexit rc32434_wdt_remove(struct platform_device *pdev) +static int rc32434_wdt_remove(struct platform_device *pdev) { misc_deregister(&rc32434_wdt_miscdev); iounmap(wdt_reg); @@ -320,7 +320,7 @@ static void rc32434_wdt_shutdown(struct platform_device *pdev) static struct platform_driver rc32434_wdt_driver = { .probe = rc32434_wdt_probe, - .remove = __devexit_p(rc32434_wdt_remove), + .remove = rc32434_wdt_remove, .shutdown = rc32434_wdt_shutdown, .driver = { .name = "rc32434_wdt", diff --git a/drivers/watchdog/rdc321x_wdt.c b/drivers/watchdog/rdc321x_wdt.c index 042ccc56ae2..b0f116c2fd5 100644 --- a/drivers/watchdog/rdc321x_wdt.c +++ b/drivers/watchdog/rdc321x_wdt.c @@ -225,7 +225,7 @@ static struct miscdevice rdc321x_wdt_misc = { .fops = &rdc321x_wdt_fops, }; -static int __devinit rdc321x_wdt_probe(struct platform_device *pdev) +static int rdc321x_wdt_probe(struct platform_device *pdev) { int err; struct resource *r; @@ -272,7 +272,7 @@ static int __devinit rdc321x_wdt_probe(struct platform_device *pdev) return 0; } -static int __devexit rdc321x_wdt_remove(struct platform_device *pdev) +static int rdc321x_wdt_remove(struct platform_device *pdev) { if (rdc321x_wdt_device.queue) { rdc321x_wdt_device.queue = 0; @@ -286,7 +286,7 @@ static int __devexit rdc321x_wdt_remove(struct platform_device *pdev) static struct platform_driver rdc321x_wdt_driver = { .probe = rdc321x_wdt_probe, - .remove = __devexit_p(rdc321x_wdt_remove), + .remove = rdc321x_wdt_remove, .driver = { .owner = THIS_MODULE, .name = "rdc321x-wdt", diff --git a/drivers/watchdog/riowd.c b/drivers/watchdog/riowd.c index 49e1b1c2135..0040451aec1 100644 --- a/drivers/watchdog/riowd.c +++ b/drivers/watchdog/riowd.c @@ -174,7 +174,7 @@ static struct miscdevice riowd_miscdev = { .fops = &riowd_fops }; -static int __devinit riowd_probe(struct platform_device *op) +static int riowd_probe(struct platform_device *op) { struct riowd *p; int err = -EINVAL; @@ -220,7 +220,7 @@ out: return err; } -static int __devexit riowd_remove(struct platform_device *op) +static int riowd_remove(struct platform_device *op) { struct riowd *p = dev_get_drvdata(&op->dev); @@ -246,7 +246,7 @@ static struct platform_driver riowd_driver = { .of_match_table = riowd_match, }, .probe = riowd_probe, - .remove = __devexit_p(riowd_remove), + .remove = riowd_remove, }; module_platform_driver(riowd_driver); diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 9245b4d23bf..b0dab10fc6a 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -303,7 +303,7 @@ static inline void s3c2410wdt_cpufreq_deregister(void) } #endif -static int __devinit s3c2410wdt_probe(struct platform_device *pdev) +static int s3c2410wdt_probe(struct platform_device *pdev) { struct device *dev; unsigned int wtcon; @@ -437,7 +437,7 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) return ret; } -static int __devexit s3c2410wdt_remove(struct platform_device *dev) +static int s3c2410wdt_remove(struct platform_device *dev) { watchdog_unregister_device(&s3c2410_wdd); @@ -508,7 +508,7 @@ MODULE_DEVICE_TABLE(of, s3c2410_wdt_match); static struct platform_driver s3c2410wdt_driver = { .probe = s3c2410wdt_probe, - .remove = __devexit_p(s3c2410wdt_remove), + .remove = s3c2410wdt_remove, .shutdown = s3c2410wdt_shutdown, .suspend = s3c2410wdt_suspend, .resume = s3c2410wdt_resume, diff --git a/drivers/watchdog/sch311x_wdt.c b/drivers/watchdog/sch311x_wdt.c index 9681ada0f25..af7b136b187 100644 --- a/drivers/watchdog/sch311x_wdt.c +++ b/drivers/watchdog/sch311x_wdt.c @@ -356,7 +356,7 @@ static struct miscdevice sch311x_wdt_miscdev = { * Init & exit routines */ -static int __devinit sch311x_wdt_probe(struct platform_device *pdev) +static int sch311x_wdt_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; int err; @@ -429,7 +429,7 @@ exit: return err; } -static int __devexit sch311x_wdt_remove(struct platform_device *pdev) +static int sch311x_wdt_remove(struct platform_device *pdev) { /* Stop the timer before we leave */ if (!nowayout) @@ -451,7 +451,7 @@ static void sch311x_wdt_shutdown(struct platform_device *dev) static struct platform_driver sch311x_wdt_driver = { .probe = sch311x_wdt_probe, - .remove = __devexit_p(sch311x_wdt_remove), + .remove = sch311x_wdt_remove, .shutdown = sch311x_wdt_shutdown, .driver = { .owner = THIS_MODULE, diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c index e5b59bebcdb..6a89e4045fb 100644 --- a/drivers/watchdog/shwdt.c +++ b/drivers/watchdog/shwdt.c @@ -217,7 +217,7 @@ static struct watchdog_device sh_wdt_dev = { .ops = &sh_wdt_ops, }; -static int __devinit sh_wdt_probe(struct platform_device *pdev) +static int sh_wdt_probe(struct platform_device *pdev) { struct sh_wdt *wdt; struct resource *res; @@ -298,7 +298,7 @@ err: return rc; } -static int __devexit sh_wdt_remove(struct platform_device *pdev) +static int sh_wdt_remove(struct platform_device *pdev) { struct sh_wdt *wdt = platform_get_drvdata(pdev); @@ -324,7 +324,7 @@ static struct platform_driver sh_wdt_driver = { }, .probe = sh_wdt_probe, - .remove = __devexit_p(sh_wdt_remove), + .remove = sh_wdt_remove, .shutdown = sh_wdt_shutdown, }; diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c index ae5e82cb83f..b3876812ff0 100644 --- a/drivers/watchdog/sp5100_tco.c +++ b/drivers/watchdog/sp5100_tco.c @@ -271,7 +271,7 @@ MODULE_DEVICE_TABLE(pci, sp5100_tco_pci_tbl); * Init & exit routines */ -static unsigned char __devinit sp5100_tco_setupdevice(void) +static unsigned char sp5100_tco_setupdevice(void) { struct pci_dev *dev = NULL; u32 val; @@ -361,7 +361,7 @@ exit: return 0; } -static int __devinit sp5100_tco_init(struct platform_device *dev) +static int sp5100_tco_init(struct platform_device *dev) { int ret; u32 val; @@ -412,7 +412,7 @@ exit: return ret; } -static void __devexit sp5100_tco_cleanup(void) +static void sp5100_tco_cleanup(void) { /* Stop the timer before we leave */ if (!nowayout) @@ -425,7 +425,7 @@ static void __devexit sp5100_tco_cleanup(void) release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); } -static int __devexit sp5100_tco_remove(struct platform_device *dev) +static int sp5100_tco_remove(struct platform_device *dev) { if (tcobase) sp5100_tco_cleanup(); @@ -439,7 +439,7 @@ static void sp5100_tco_shutdown(struct platform_device *dev) static struct platform_driver sp5100_tco_driver = { .probe = sp5100_tco_init, - .remove = __devexit_p(sp5100_tco_remove), + .remove = sp5100_tco_remove, .shutdown = sp5100_tco_shutdown, .driver = { .owner = THIS_MODULE, diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c index e4841c36798..4552847fc7f 100644 --- a/drivers/watchdog/sp805_wdt.c +++ b/drivers/watchdog/sp805_wdt.c @@ -210,7 +210,7 @@ static const struct watchdog_ops wdt_ops = { .get_timeleft = wdt_timeleft, }; -static int __devinit +static int sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id) { struct sp805_wdt *wdt; @@ -272,7 +272,7 @@ err: return ret; } -static int __devexit sp805_wdt_remove(struct amba_device *adev) +static int sp805_wdt_remove(struct amba_device *adev) { struct sp805_wdt *wdt = amba_get_drvdata(adev); @@ -326,7 +326,7 @@ static struct amba_driver sp805_wdt_driver = { }, .id_table = sp805_wdt_ids, .probe = sp805_wdt_probe, - .remove = __devexit_p(sp805_wdt_remove), + .remove = sp805_wdt_remove, }; module_amba_driver(sp805_wdt_driver); diff --git a/drivers/watchdog/stmp3xxx_wdt.c b/drivers/watchdog/stmp3xxx_wdt.c index 21d96b92bfd..1f4f69728fe 100644 --- a/drivers/watchdog/stmp3xxx_wdt.c +++ b/drivers/watchdog/stmp3xxx_wdt.c @@ -204,7 +204,7 @@ static struct miscdevice stmp3xxx_wdt_miscdev = { .fops = &stmp3xxx_wdt_fops, }; -static int __devinit stmp3xxx_wdt_probe(struct platform_device *pdev) +static int stmp3xxx_wdt_probe(struct platform_device *pdev) { int ret = 0; @@ -229,7 +229,7 @@ static int __devinit stmp3xxx_wdt_probe(struct platform_device *pdev) return ret; } -static int __devexit stmp3xxx_wdt_remove(struct platform_device *pdev) +static int stmp3xxx_wdt_remove(struct platform_device *pdev) { misc_deregister(&stmp3xxx_wdt_miscdev); return 0; @@ -269,7 +269,7 @@ static struct platform_driver platform_wdt_driver = { .name = "stmp3xxx_wdt", }, .probe = stmp3xxx_wdt_probe, - .remove = __devexit_p(stmp3xxx_wdt_remove), + .remove = stmp3xxx_wdt_remove, .suspend = stmp3xxx_wdt_suspend, .resume = stmp3xxx_wdt_resume, }; diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c index 8df050d800e..b8a92459f10 100644 --- a/drivers/watchdog/ts72xx_wdt.c +++ b/drivers/watchdog/ts72xx_wdt.c @@ -390,7 +390,7 @@ static struct miscdevice ts72xx_wdt_miscdev = { .fops = &ts72xx_wdt_fops, }; -static __devinit int ts72xx_wdt_probe(struct platform_device *pdev) +static int ts72xx_wdt_probe(struct platform_device *pdev) { struct ts72xx_wdt *wdt; struct resource *r1, *r2; @@ -476,7 +476,7 @@ fail: return error; } -static __devexit int ts72xx_wdt_remove(struct platform_device *pdev) +static int ts72xx_wdt_remove(struct platform_device *pdev) { struct ts72xx_wdt *wdt = platform_get_drvdata(pdev); struct resource *res; @@ -499,7 +499,7 @@ static __devexit int ts72xx_wdt_remove(struct platform_device *pdev) static struct platform_driver ts72xx_wdt_driver = { .probe = ts72xx_wdt_probe, - .remove = __devexit_p(ts72xx_wdt_remove), + .remove = ts72xx_wdt_remove, .driver = { .name = "ts72xx-wdt", .owner = THIS_MODULE, diff --git a/drivers/watchdog/twl4030_wdt.c b/drivers/watchdog/twl4030_wdt.c index 249f11305d2..9f54b1da718 100644 --- a/drivers/watchdog/twl4030_wdt.c +++ b/drivers/watchdog/twl4030_wdt.c @@ -170,7 +170,7 @@ static const struct file_operations twl4030_wdt_fops = { .write = twl4030_wdt_write_fop, }; -static int __devinit twl4030_wdt_probe(struct platform_device *pdev) +static int twl4030_wdt_probe(struct platform_device *pdev) { int ret = 0; struct twl4030_wdt *wdt; @@ -204,7 +204,7 @@ static int __devinit twl4030_wdt_probe(struct platform_device *pdev) return 0; } -static int __devexit twl4030_wdt_remove(struct platform_device *pdev) +static int twl4030_wdt_remove(struct platform_device *pdev) { struct twl4030_wdt *wdt = platform_get_drvdata(pdev); @@ -247,7 +247,7 @@ static int twl4030_wdt_resume(struct platform_device *pdev) static struct platform_driver twl4030_wdt_driver = { .probe = twl4030_wdt_probe, - .remove = __devexit_p(twl4030_wdt_remove), + .remove = twl4030_wdt_remove, .suspend = twl4030_wdt_suspend, .resume = twl4030_wdt_resume, .driver = { diff --git a/drivers/watchdog/via_wdt.c b/drivers/watchdog/via_wdt.c index aa50da3ccfe..1a68f760cf8 100644 --- a/drivers/watchdog/via_wdt.c +++ b/drivers/watchdog/via_wdt.c @@ -155,7 +155,7 @@ static struct watchdog_device wdt_dev = { .max_timeout = WDT_TIMEOUT_MAX, }; -static int __devinit wdt_probe(struct pci_dev *pdev, +static int wdt_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { unsigned char conf; @@ -229,7 +229,7 @@ err_out_disable_device: return ret; } -static void __devexit wdt_remove(struct pci_dev *pdev) +static void wdt_remove(struct pci_dev *pdev) { watchdog_unregister_device(&wdt_dev); del_timer(&timer); @@ -250,7 +250,7 @@ static struct pci_driver wdt_driver = { .name = "via_wdt", .id_table = wdt_pci_table, .probe = wdt_probe, - .remove = __devexit_p(wdt_remove), + .remove = wdt_remove, }; module_pci_driver(wdt_driver); diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c index e32654efdbb..36a54c0e32d 100644 --- a/drivers/watchdog/wdt_pci.c +++ b/drivers/watchdog/wdt_pci.c @@ -605,7 +605,7 @@ static struct notifier_block wdtpci_notifier = { }; -static int __devinit wdtpci_init_one(struct pci_dev *dev, +static int wdtpci_init_one(struct pci_dev *dev, const struct pci_device_id *ent) { int ret = -EIO; @@ -705,7 +705,7 @@ out_pci: } -static void __devexit wdtpci_remove_one(struct pci_dev *pdev) +static void wdtpci_remove_one(struct pci_dev *pdev) { /* here we assume only one device will ever have * been picked up and registered by probe function */ @@ -736,7 +736,7 @@ static struct pci_driver wdtpci_driver = { .name = "wdt_pci", .id_table = wdtpci_pci_tbl, .probe = wdtpci_init_one, - .remove = __devexit_p(wdtpci_remove_one), + .remove = wdtpci_remove_one, }; module_pci_driver(wdtpci_driver); diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c index 87d66d236c3..9dcb6d08227 100644 --- a/drivers/watchdog/wm831x_wdt.c +++ b/drivers/watchdog/wm831x_wdt.c @@ -181,7 +181,7 @@ static const struct watchdog_ops wm831x_wdt_ops = { .set_timeout = wm831x_wdt_set_timeout, }; -static int __devinit wm831x_wdt_probe(struct platform_device *pdev) +static int wm831x_wdt_probe(struct platform_device *pdev) { struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); struct wm831x_pdata *chip_pdata; @@ -292,7 +292,7 @@ err: return ret; } -static int __devexit wm831x_wdt_remove(struct platform_device *pdev) +static int wm831x_wdt_remove(struct platform_device *pdev) { struct wm831x_wdt_drvdata *driver_data = dev_get_drvdata(&pdev->dev); @@ -306,7 +306,7 @@ static int __devexit wm831x_wdt_remove(struct platform_device *pdev) static struct platform_driver wm831x_wdt_driver = { .probe = wm831x_wdt_probe, - .remove = __devexit_p(wm831x_wdt_remove), + .remove = wm831x_wdt_remove, .driver = { .name = "wm831x-watchdog", }, diff --git a/drivers/watchdog/wm8350_wdt.c b/drivers/watchdog/wm8350_wdt.c index 3c76693447f..34d272ada23 100644 --- a/drivers/watchdog/wm8350_wdt.c +++ b/drivers/watchdog/wm8350_wdt.c @@ -140,7 +140,7 @@ static struct watchdog_device wm8350_wdt = { .max_timeout = 4, }; -static int __devinit wm8350_wdt_probe(struct platform_device *pdev) +static int wm8350_wdt_probe(struct platform_device *pdev) { struct wm8350 *wm8350 = platform_get_drvdata(pdev); @@ -158,7 +158,7 @@ static int __devinit wm8350_wdt_probe(struct platform_device *pdev) return watchdog_register_device(&wm8350_wdt); } -static int __devexit wm8350_wdt_remove(struct platform_device *pdev) +static int wm8350_wdt_remove(struct platform_device *pdev) { watchdog_unregister_device(&wm8350_wdt); return 0; @@ -166,7 +166,7 @@ static int __devexit wm8350_wdt_remove(struct platform_device *pdev) static struct platform_driver wm8350_wdt_driver = { .probe = wm8350_wdt_probe, - .remove = __devexit_p(wm8350_wdt_remove), + .remove = wm8350_wdt_remove, .driver = { .name = "wm8350-wdt", }, diff --git a/drivers/watchdog/xen_wdt.c b/drivers/watchdog/xen_wdt.c index e4a25b51165..92ad33d0cb7 100644 --- a/drivers/watchdog/xen_wdt.c +++ b/drivers/watchdog/xen_wdt.c @@ -244,7 +244,7 @@ static struct miscdevice xen_wdt_miscdev = { .fops = &xen_wdt_fops, }; -static int __devinit xen_wdt_probe(struct platform_device *dev) +static int xen_wdt_probe(struct platform_device *dev) { struct sched_watchdog wd = { .id = ~0 }; int ret = HYPERVISOR_sched_op(SCHEDOP_watchdog, &wd); @@ -280,7 +280,7 @@ static int __devinit xen_wdt_probe(struct platform_device *dev) return ret; } -static int __devexit xen_wdt_remove(struct platform_device *dev) +static int xen_wdt_remove(struct platform_device *dev) { /* Stop the timer before we leave */ if (!nowayout) @@ -315,7 +315,7 @@ static int xen_wdt_resume(struct platform_device *dev) static struct platform_driver xen_wdt_driver = { .probe = xen_wdt_probe, - .remove = __devexit_p(xen_wdt_remove), + .remove = xen_wdt_remove, .shutdown = xen_wdt_shutdown, .suspend = xen_wdt_suspend, .resume = xen_wdt_resume, diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 8adb9cc267f..71f5c459b08 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -361,13 +361,13 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) down_write(&mm->mmap_sem); vma = find_vma(mm, m.addr); - ret = -EINVAL; if (!vma || vma->vm_ops != &privcmd_vm_ops || (m.addr != vma->vm_start) || ((m.addr + (nr_pages << PAGE_SHIFT)) != vma->vm_end) || !privcmd_enforce_singleshot_mapping(vma)) { up_write(&mm->mmap_sem); + ret = -EINVAL; goto out; } @@ -383,12 +383,16 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) up_write(&mm->mmap_sem); - if (state.global_error && (version == 1)) { - /* Write back errors in second pass. */ - state.user_mfn = (xen_pfn_t *)m.arr; - state.err = err_array; - ret = traverse_pages(m.num, sizeof(xen_pfn_t), - &pagelist, mmap_return_errors_v1, &state); + if (version == 1) { + if (state.global_error) { + /* Write back errors in second pass. */ + state.user_mfn = (xen_pfn_t *)m.arr; + state.err = err_array; + ret = traverse_pages(m.num, sizeof(xen_pfn_t), + &pagelist, mmap_return_errors_v1, &state); + } else + ret = 0; + } else if (version == 2) { ret = __copy_to_user(m.err, err_array, m.num * sizeof(int)); if (ret) diff --git a/drivers/xen/xen-selfballoon.c b/drivers/xen/xen-selfballoon.c index 7d041cb6da2..2552d3e0a70 100644 --- a/drivers/xen/xen-selfballoon.c +++ b/drivers/xen/xen-selfballoon.c @@ -222,7 +222,7 @@ static void selfballoon_process(struct work_struct *work) if (xen_selfballooning_enabled) { cur_pages = totalram_pages; tgt_pages = cur_pages; /* default is no change */ - goal_pages = percpu_counter_read_positive(&vm_committed_as) + + goal_pages = vm_memory_committed() + totalreserve_pages + MB2PAGES(selfballoon_reserved_mb); #ifdef CONFIG_FRONTSWAP |