diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-22 19:02:13 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-22 19:02:13 -0400 |
| commit | 5d4e2d08e7fdf7339f84a1c670d296a77e02f881 (patch) | |
| tree | 1c419660defa56191091dfdf50fdb57a72009173 /drivers | |
| parent | fb2123fad3b499f0898835b19dbb93b18d27ee98 (diff) | |
| parent | 94ca629e40eb7e997be21d8065c25e4f3797b03f (diff) | |
Merge tag 'driver-core-3.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core
Pull driver core updates from Greg Kroah-Hartman:
"Here's the driver core, and other driver subsystems, pull request for
the 3.5-rc1 merge window.
Outside of a few minor driver core changes, we ended up with the
following different subsystem and core changes as well, due to
interdependancies on the driver core:
- hyperv driver updates
- drivers/memory being created and some drivers moved into it
- extcon driver subsystem created out of the old Android staging
switch driver code
- dynamic debug updates
- printk rework, and /dev/kmsg changes
All of this has been tested in the linux-next releases for a few weeks
with no reported problems.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>"
Fix up conflicts in drivers/extcon/extcon-max8997.c where git noticed
that a patch to the deleted drivers/misc/max8997-muic.c driver needs to
be applied to this one.
* tag 'driver-core-3.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (90 commits)
uio_pdrv_genirq: get irq through platform resource if not set otherwise
memory: tegra{20,30}-mc: Remove empty *_remove()
printk() - isolate KERN_CONT users from ordinary complete lines
sysfs: get rid of some lockdep false positives
Drivers: hv: util: Properly handle version negotiations.
Drivers: hv: Get rid of an unnecessary check in vmbus_prep_negotiate_resp()
memory: tegra{20,30}-mc: Use dev_err_ratelimited()
driver core: Add dev_*_ratelimited() family
Driver Core: don't oops with unregistered driver in driver_find_device()
printk() - restore prefix/timestamp printing for multi-newline strings
printk: add stub for prepend_timestamp()
ARM: tegra30: Make MC optional in Kconfig
ARM: tegra20: Make MC optional in Kconfig
ARM: tegra30: MC: Remove unnecessary BUG*()
ARM: tegra20: MC: Remove unnecessary BUG*()
printk: correctly align __log_buf
ARM: tegra30: Add Tegra Memory Controller(MC) driver
ARM: tegra20: Add Tegra Memory Controller(MC) driver
printk() - restore timestamp printing at console output
printk() - do not merge continuation lines of different threads
...
Diffstat (limited to 'drivers')
43 files changed, 4322 insertions, 625 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index d236aef7e59f..63b81826cb55 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig | |||
| @@ -140,4 +140,8 @@ source "drivers/virt/Kconfig" | |||
| 140 | 140 | ||
| 141 | source "drivers/devfreq/Kconfig" | 141 | source "drivers/devfreq/Kconfig" |
| 142 | 142 | ||
| 143 | source "drivers/extcon/Kconfig" | ||
| 144 | |||
| 145 | source "drivers/memory/Kconfig" | ||
| 146 | |||
| 143 | endmenu | 147 | endmenu |
diff --git a/drivers/Makefile b/drivers/Makefile index 95952c82bf16..265b506a15be 100644 --- a/drivers/Makefile +++ b/drivers/Makefile | |||
| @@ -134,3 +134,5 @@ obj-$(CONFIG_VIRT_DRIVERS) += virt/ | |||
| 134 | obj-$(CONFIG_HYPERV) += hv/ | 134 | obj-$(CONFIG_HYPERV) += hv/ |
| 135 | 135 | ||
| 136 | obj-$(CONFIG_PM_DEVFREQ) += devfreq/ | 136 | obj-$(CONFIG_PM_DEVFREQ) += devfreq/ |
| 137 | obj-$(CONFIG_EXTCON) += extcon/ | ||
| 138 | obj-$(CONFIG_MEMORY) += memory/ | ||
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 4a29763b8eb4..a12808259dfb 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c | |||
| @@ -720,21 +720,21 @@ static int acpi_pci_link_add(struct acpi_device *device) | |||
| 720 | acpi_device_bid(device)); | 720 | acpi_device_bid(device)); |
| 721 | for (i = 0; i < link->irq.possible_count; i++) { | 721 | for (i = 0; i < link->irq.possible_count; i++) { |
| 722 | if (link->irq.active == link->irq.possible[i]) { | 722 | if (link->irq.active == link->irq.possible[i]) { |
| 723 | printk(" *%d", link->irq.possible[i]); | 723 | printk(KERN_CONT " *%d", link->irq.possible[i]); |
| 724 | found = 1; | 724 | found = 1; |
| 725 | } else | 725 | } else |
| 726 | printk(" %d", link->irq.possible[i]); | 726 | printk(KERN_CONT " %d", link->irq.possible[i]); |
| 727 | } | 727 | } |
| 728 | 728 | ||
| 729 | printk(")"); | 729 | printk(KERN_CONT ")"); |
| 730 | 730 | ||
| 731 | if (!found) | 731 | if (!found) |
| 732 | printk(" *%d", link->irq.active); | 732 | printk(KERN_CONT " *%d", link->irq.active); |
| 733 | 733 | ||
| 734 | if (!link->device->status.enabled) | 734 | if (!link->device->status.enabled) |
| 735 | printk(", disabled."); | 735 | printk(KERN_CONT ", disabled."); |
| 736 | 736 | ||
| 737 | printk("\n"); | 737 | printk(KERN_CONT "\n"); |
| 738 | 738 | ||
| 739 | list_add_tail(&link->list, &acpi_link_list); | 739 | list_add_tail(&link->list, &acpi_link_list); |
| 740 | 740 | ||
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index eb6fd233764b..06527c526618 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c | |||
| @@ -887,7 +887,7 @@ int __init acpi_sleep_init(void) | |||
| 887 | status = acpi_get_sleep_type_data(i, &type_a, &type_b); | 887 | status = acpi_get_sleep_type_data(i, &type_a, &type_b); |
| 888 | if (ACPI_SUCCESS(status)) { | 888 | if (ACPI_SUCCESS(status)) { |
| 889 | sleep_states[i] = 1; | 889 | sleep_states[i] = 1; |
| 890 | printk(" S%d", i); | 890 | printk(KERN_CONT " S%d", i); |
| 891 | } | 891 | } |
| 892 | } | 892 | } |
| 893 | 893 | ||
| @@ -901,7 +901,7 @@ int __init acpi_sleep_init(void) | |||
| 901 | hibernation_set_ops(old_suspend_ordering ? | 901 | hibernation_set_ops(old_suspend_ordering ? |
| 902 | &acpi_hibernation_ops_old : &acpi_hibernation_ops); | 902 | &acpi_hibernation_ops_old : &acpi_hibernation_ops); |
| 903 | sleep_states[ACPI_STATE_S4] = 1; | 903 | sleep_states[ACPI_STATE_S4] = 1; |
| 904 | printk(" S4"); | 904 | printk(KERN_CONT " S4"); |
| 905 | if (!nosigcheck) { | 905 | if (!nosigcheck) { |
| 906 | acpi_get_table(ACPI_SIG_FACS, 1, | 906 | acpi_get_table(ACPI_SIG_FACS, 1, |
| 907 | (struct acpi_table_header **)&facs); | 907 | (struct acpi_table_header **)&facs); |
| @@ -914,11 +914,11 @@ int __init acpi_sleep_init(void) | |||
| 914 | status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); | 914 | status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b); |
| 915 | if (ACPI_SUCCESS(status)) { | 915 | if (ACPI_SUCCESS(status)) { |
| 916 | sleep_states[ACPI_STATE_S5] = 1; | 916 | sleep_states[ACPI_STATE_S5] = 1; |
| 917 | printk(" S5"); | 917 | printk(KERN_CONT " S5"); |
| 918 | pm_power_off_prepare = acpi_power_off_prepare; | 918 | pm_power_off_prepare = acpi_power_off_prepare; |
| 919 | pm_power_off = acpi_power_off; | 919 | pm_power_off = acpi_power_off; |
| 920 | } | 920 | } |
| 921 | printk(")\n"); | 921 | printk(KERN_CONT ")\n"); |
| 922 | /* | 922 | /* |
| 923 | * Register the tts_notifier to reboot notifier list so that the _TTS | 923 | * Register the tts_notifier to reboot notifier list so that the _TTS |
| 924 | * object can also be evaluated when the system enters S5. | 924 | * object can also be evaluated when the system enters S5. |
diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 26a06b801b5b..2bcef657a60c 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c | |||
| @@ -21,8 +21,7 @@ | |||
| 21 | #include "power/power.h" | 21 | #include "power/power.h" |
| 22 | 22 | ||
| 23 | /* /sys/devices/system */ | 23 | /* /sys/devices/system */ |
| 24 | /* FIXME: make static after drivers/base/sys.c is deleted */ | 24 | static struct kset *system_kset; |
| 25 | struct kset *system_kset; | ||
| 26 | 25 | ||
| 27 | #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr) | 26 | #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr) |
| 28 | 27 | ||
diff --git a/drivers/base/core.c b/drivers/base/core.c index e28ce9898af4..346be8b78b24 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/mutex.h> | 25 | #include <linux/mutex.h> |
| 26 | #include <linux/async.h> | 26 | #include <linux/async.h> |
| 27 | #include <linux/pm_runtime.h> | 27 | #include <linux/pm_runtime.h> |
| 28 | #include <linux/netdevice.h> | ||
| 28 | 29 | ||
| 29 | #include "base.h" | 30 | #include "base.h" |
| 30 | #include "power/power.h" | 31 | #include "power/power.h" |
| @@ -65,7 +66,7 @@ static inline int device_is_not_partition(struct device *dev) | |||
| 65 | * @dev: struct device to get the name of | 66 | * @dev: struct device to get the name of |
| 66 | * | 67 | * |
| 67 | * Will return the device's driver's name if it is bound to a device. If | 68 | * Will return the device's driver's name if it is bound to a device. If |
| 68 | * the device is not bound to a device, it will return the name of the bus | 69 | * the device is not bound to a driver, it will return the name of the bus |
| 69 | * it is attached to. If it is not attached to a bus either, an empty | 70 | * it is attached to. If it is not attached to a bus either, an empty |
| 70 | * string will be returned. | 71 | * string will be returned. |
| 71 | */ | 72 | */ |
| @@ -878,8 +879,8 @@ EXPORT_SYMBOL_GPL(dev_set_name); | |||
| 878 | * to NULL prevents an entry from being created. class->dev_kobj must | 879 | * to NULL prevents an entry from being created. class->dev_kobj must |
| 879 | * be set (or cleared) before any devices are registered to the class | 880 | * be set (or cleared) before any devices are registered to the class |
| 880 | * otherwise device_create_sys_dev_entry() and | 881 | * otherwise device_create_sys_dev_entry() and |
| 881 | * device_remove_sys_dev_entry() will disagree about the the presence | 882 | * device_remove_sys_dev_entry() will disagree about the presence of |
| 882 | * of the link. | 883 | * the link. |
| 883 | */ | 884 | */ |
| 884 | static struct kobject *device_to_dev_kobj(struct device *dev) | 885 | static struct kobject *device_to_dev_kobj(struct device *dev) |
| 885 | { | 886 | { |
| @@ -1843,15 +1844,60 @@ void device_shutdown(void) | |||
| 1843 | */ | 1844 | */ |
| 1844 | 1845 | ||
| 1845 | #ifdef CONFIG_PRINTK | 1846 | #ifdef CONFIG_PRINTK |
| 1846 | |||
| 1847 | int __dev_printk(const char *level, const struct device *dev, | 1847 | int __dev_printk(const char *level, const struct device *dev, |
| 1848 | struct va_format *vaf) | 1848 | struct va_format *vaf) |
| 1849 | { | 1849 | { |
| 1850 | char dict[128]; | ||
| 1851 | size_t dictlen = 0; | ||
| 1852 | const char *subsys; | ||
| 1853 | |||
| 1850 | if (!dev) | 1854 | if (!dev) |
| 1851 | return printk("%s(NULL device *): %pV", level, vaf); | 1855 | return printk("%s(NULL device *): %pV", level, vaf); |
| 1852 | 1856 | ||
| 1853 | return printk("%s%s %s: %pV", | 1857 | if (dev->class) |
| 1854 | level, dev_driver_string(dev), dev_name(dev), vaf); | 1858 | subsys = dev->class->name; |
| 1859 | else if (dev->bus) | ||
| 1860 | subsys = dev->bus->name; | ||
| 1861 | else | ||
| 1862 | goto skip; | ||
| 1863 | |||
| 1864 | dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen, | ||
| 1865 | "SUBSYSTEM=%s", subsys); | ||
| 1866 | |||
| 1867 | /* | ||
| 1868 | * Add device identifier DEVICE=: | ||
| 1869 | * b12:8 block dev_t | ||
| 1870 | * c127:3 char dev_t | ||
| 1871 | * n8 netdev ifindex | ||
| 1872 | * +sound:card0 subsystem:devname | ||
| 1873 | */ | ||
| 1874 | if (MAJOR(dev->devt)) { | ||
| 1875 | char c; | ||
| 1876 | |||
| 1877 | if (strcmp(subsys, "block") == 0) | ||
| 1878 | c = 'b'; | ||
| 1879 | else | ||
| 1880 | c = 'c'; | ||
| 1881 | dictlen++; | ||
| 1882 | dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen, | ||
| 1883 | "DEVICE=%c%u:%u", | ||
| 1884 | c, MAJOR(dev->devt), MINOR(dev->devt)); | ||
| 1885 | } else if (strcmp(subsys, "net") == 0) { | ||
| 1886 | struct net_device *net = to_net_dev(dev); | ||
| 1887 | |||
| 1888 | dictlen++; | ||
| 1889 | dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen, | ||
| 1890 | "DEVICE=n%u", net->ifindex); | ||
| 1891 | } else { | ||
| 1892 | dictlen++; | ||
| 1893 | dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen, | ||
| 1894 | "DEVICE=+%s:%s", subsys, dev_name(dev)); | ||
| 1895 | } | ||
| 1896 | skip: | ||
| 1897 | return printk_emit(0, level[1] - '0', | ||
| 1898 | dictlen ? dict : NULL, dictlen, | ||
| 1899 | "%s %s: %pV", | ||
| 1900 | dev_driver_string(dev), dev_name(dev), vaf); | ||
| 1855 | } | 1901 | } |
| 1856 | EXPORT_SYMBOL(__dev_printk); | 1902 | EXPORT_SYMBOL(__dev_printk); |
| 1857 | 1903 | ||
diff --git a/drivers/base/devres.c b/drivers/base/devres.c index 524bf96c289f..2360adb7a58f 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c | |||
| @@ -309,6 +309,10 @@ EXPORT_SYMBOL_GPL(devres_remove); | |||
| 309 | * which @match returns 1. If @match is NULL, it's considered to | 309 | * which @match returns 1. If @match is NULL, it's considered to |
| 310 | * match all. If found, the resource is removed atomically and freed. | 310 | * match all. If found, the resource is removed atomically and freed. |
| 311 | * | 311 | * |
| 312 | * Note that the release function for the resource will not be called, | ||
| 313 | * only the devres-allocated data will be freed. The caller becomes | ||
| 314 | * responsible for freeing any other data. | ||
| 315 | * | ||
| 312 | * RETURNS: | 316 | * RETURNS: |
| 313 | * 0 if devres is found and freed, -ENOENT if not found. | 317 | * 0 if devres is found and freed, -ENOENT if not found. |
| 314 | */ | 318 | */ |
| @@ -326,6 +330,37 @@ int devres_destroy(struct device *dev, dr_release_t release, | |||
| 326 | } | 330 | } |
| 327 | EXPORT_SYMBOL_GPL(devres_destroy); | 331 | EXPORT_SYMBOL_GPL(devres_destroy); |
| 328 | 332 | ||
| 333 | |||
| 334 | /** | ||
| 335 | * devres_release - Find a device resource and destroy it, calling release | ||
| 336 | * @dev: Device to find resource from | ||
| 337 | * @release: Look for resources associated with this release function | ||
| 338 | * @match: Match function (optional) | ||
| 339 | * @match_data: Data for the match function | ||
| 340 | * | ||
| 341 | * Find the latest devres of @dev associated with @release and for | ||
| 342 | * which @match returns 1. If @match is NULL, it's considered to | ||
| 343 | * match all. If found, the resource is removed atomically, the | ||
| 344 | * release function called and the resource freed. | ||
| 345 | * | ||
| 346 | * RETURNS: | ||
| 347 | * 0 if devres is found and freed, -ENOENT if not found. | ||
| 348 | */ | ||
| 349 | int devres_release(struct device *dev, dr_release_t release, | ||
| 350 | dr_match_t match, void *match_data) | ||
| 351 | { | ||
| 352 | void *res; | ||
| 353 | |||
| 354 | res = devres_remove(dev, release, match, match_data); | ||
| 355 | if (unlikely(!res)) | ||
| 356 | return -ENOENT; | ||
| 357 | |||
| 358 | (*release)(dev, res); | ||
| 359 | devres_free(res); | ||
| 360 | return 0; | ||
| 361 | } | ||
| 362 | EXPORT_SYMBOL_GPL(devres_release); | ||
| 363 | |||
| 329 | static int remove_nodes(struct device *dev, | 364 | static int remove_nodes(struct device *dev, |
| 330 | struct list_head *first, struct list_head *end, | 365 | struct list_head *first, struct list_head *end, |
| 331 | struct list_head *todo) | 366 | struct list_head *todo) |
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index 8493536ea55b..765c3a28077a 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c | |||
| @@ -7,9 +7,9 @@ | |||
| 7 | * devtmpfs, a tmpfs-based filesystem is created. Every driver-core | 7 | * devtmpfs, a tmpfs-based filesystem is created. Every driver-core |
| 8 | * device which requests a device node, will add a node in this | 8 | * device which requests a device node, will add a node in this |
| 9 | * filesystem. | 9 | * filesystem. |
| 10 | * By default, all devices are named after the the name of the | 10 | * By default, all devices are named after the name of the device, |
| 11 | * device, owned by root and have a default mode of 0600. Subsystems | 11 | * owned by root and have a default mode of 0600. Subsystems can |
| 12 | * can overwrite the default setting if needed. | 12 | * overwrite the default setting if needed. |
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c index 07cbbc6fddb4..05c64c11bad2 100644 --- a/drivers/base/dma-buf.c +++ b/drivers/base/dma-buf.c | |||
| @@ -293,7 +293,7 @@ EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment); | |||
| 293 | * cpu in the kernel context. Calls begin_cpu_access to allow exporter-specific | 293 | * cpu in the kernel context. Calls begin_cpu_access to allow exporter-specific |
| 294 | * preparations. Coherency is only guaranteed in the specified range for the | 294 | * preparations. Coherency is only guaranteed in the specified range for the |
| 295 | * specified access direction. | 295 | * specified access direction. |
| 296 | * @dma_buf: [in] buffer to prepare cpu access for. | 296 | * @dmabuf: [in] buffer to prepare cpu access for. |
| 297 | * @start: [in] start of range for cpu access. | 297 | * @start: [in] start of range for cpu access. |
| 298 | * @len: [in] length of range for cpu access. | 298 | * @len: [in] length of range for cpu access. |
| 299 | * @direction: [in] length of range for cpu access. | 299 | * @direction: [in] length of range for cpu access. |
| @@ -320,7 +320,7 @@ EXPORT_SYMBOL_GPL(dma_buf_begin_cpu_access); | |||
| 320 | * cpu in the kernel context. Calls end_cpu_access to allow exporter-specific | 320 | * cpu in the kernel context. Calls end_cpu_access to allow exporter-specific |
| 321 | * actions. Coherency is only guaranteed in the specified range for the | 321 | * actions. Coherency is only guaranteed in the specified range for the |
| 322 | * specified access direction. | 322 | * specified access direction. |
| 323 | * @dma_buf: [in] buffer to complete cpu access for. | 323 | * @dmabuf: [in] buffer to complete cpu access for. |
| 324 | * @start: [in] start of range for cpu access. | 324 | * @start: [in] start of range for cpu access. |
| 325 | * @len: [in] length of range for cpu access. | 325 | * @len: [in] length of range for cpu access. |
| 326 | * @direction: [in] length of range for cpu access. | 326 | * @direction: [in] length of range for cpu access. |
| @@ -340,7 +340,7 @@ EXPORT_SYMBOL_GPL(dma_buf_end_cpu_access); | |||
| 340 | /** | 340 | /** |
| 341 | * dma_buf_kmap_atomic - Map a page of the buffer object into kernel address | 341 | * dma_buf_kmap_atomic - Map a page of the buffer object into kernel address |
| 342 | * space. The same restrictions as for kmap_atomic and friends apply. | 342 | * space. The same restrictions as for kmap_atomic and friends apply. |
| 343 | * @dma_buf: [in] buffer to map page from. | 343 | * @dmabuf: [in] buffer to map page from. |
| 344 | * @page_num: [in] page in PAGE_SIZE units to map. | 344 | * @page_num: [in] page in PAGE_SIZE units to map. |
| 345 | * | 345 | * |
| 346 | * This call must always succeed, any necessary preparations that might fail | 346 | * This call must always succeed, any necessary preparations that might fail |
| @@ -356,7 +356,7 @@ EXPORT_SYMBOL_GPL(dma_buf_kmap_atomic); | |||
| 356 | 356 | ||
| 357 | /** | 357 | /** |
| 358 | * dma_buf_kunmap_atomic - Unmap a page obtained by dma_buf_kmap_atomic. | 358 | * dma_buf_kunmap_atomic - Unmap a page obtained by dma_buf_kmap_atomic. |
| 359 | * @dma_buf: [in] buffer to unmap page from. | 359 | * @dmabuf: [in] buffer to unmap page from. |
| 360 | * @page_num: [in] page in PAGE_SIZE units to unmap. | 360 | * @page_num: [in] page in PAGE_SIZE units to unmap. |
| 361 | * @vaddr: [in] kernel space pointer obtained from dma_buf_kmap_atomic. | 361 | * @vaddr: [in] kernel space pointer obtained from dma_buf_kmap_atomic. |
| 362 | * | 362 | * |
| @@ -375,7 +375,7 @@ EXPORT_SYMBOL_GPL(dma_buf_kunmap_atomic); | |||
| 375 | /** | 375 | /** |
| 376 | * dma_buf_kmap - Map a page of the buffer object into kernel address space. The | 376 | * dma_buf_kmap - Map a page of the buffer object into kernel address space. The |
| 377 | * same restrictions as for kmap and friends apply. | 377 | * same restrictions as for kmap and friends apply. |
| 378 | * @dma_buf: [in] buffer to map page from. | 378 | * @dmabuf: [in] buffer to map page from. |
| 379 | * @page_num: [in] page in PAGE_SIZE units to map. | 379 | * @page_num: [in] page in PAGE_SIZE units to map. |
| 380 | * | 380 | * |
| 381 | * This call must always succeed, any necessary preparations that might fail | 381 | * This call must always succeed, any necessary preparations that might fail |
| @@ -391,7 +391,7 @@ EXPORT_SYMBOL_GPL(dma_buf_kmap); | |||
| 391 | 391 | ||
| 392 | /** | 392 | /** |
| 393 | * dma_buf_kunmap - Unmap a page obtained by dma_buf_kmap. | 393 | * dma_buf_kunmap - Unmap a page obtained by dma_buf_kmap. |
| 394 | * @dma_buf: [in] buffer to unmap page from. | 394 | * @dmabuf: [in] buffer to unmap page from. |
| 395 | * @page_num: [in] page in PAGE_SIZE units to unmap. | 395 | * @page_num: [in] page in PAGE_SIZE units to unmap. |
| 396 | * @vaddr: [in] kernel space pointer obtained from dma_buf_kmap. | 396 | * @vaddr: [in] kernel space pointer obtained from dma_buf_kmap. |
| 397 | * | 397 | * |
diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 3ec3896c83a6..207c27ddf828 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c | |||
| @@ -80,7 +80,7 @@ struct device *driver_find_device(struct device_driver *drv, | |||
| 80 | struct klist_iter i; | 80 | struct klist_iter i; |
| 81 | struct device *dev; | 81 | struct device *dev; |
| 82 | 82 | ||
| 83 | if (!drv) | 83 | if (!drv || !drv->p) |
| 84 | return NULL; | 84 | return NULL; |
| 85 | 85 | ||
| 86 | klist_iter_init_node(&drv->p->klist_devices, &i, | 86 | klist_iter_init_node(&drv->p->klist_devices, &i, |
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index d6e9d081c8b1..67c3371723cc 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
| @@ -807,44 +807,6 @@ static const struct file_operations oldmem_fops = { | |||
| 807 | }; | 807 | }; |
| 808 | #endif | 808 | #endif |
| 809 | 809 | ||
| 810 | static ssize_t kmsg_writev(struct kiocb *iocb, const struct iovec *iv, | ||
| 811 | unsigned long count, loff_t pos) | ||
| 812 | { | ||
| 813 | char *line, *p; | ||
| 814 | int i; | ||
| 815 | ssize_t ret = -EFAULT; | ||
| 816 | size_t len = iov_length(iv, count); | ||
| 817 | |||
| 818 | line = kmalloc(len + 1, GFP_KERNEL); | ||
| 819 | if (line == NULL) | ||
| 820 | return -ENOMEM; | ||
| 821 | |||
| 822 | /* | ||
| 823 | * copy all vectors into a single string, to ensure we do | ||
| 824 | * not interleave our log line with other printk calls | ||
| 825 | */ | ||
| 826 | p = line; | ||
| 827 | for (i = 0; i < count; i++) { | ||
| 828 | if (copy_from_user(p, iv[i].iov_base, iv[i].iov_len)) | ||
| 829 | goto out; | ||
| 830 | p += iv[i].iov_len; | ||
| 831 | } | ||
| 832 | p[0] = '\0'; | ||
| 833 | |||
| 834 | ret = printk("%s", line); | ||
| 835 | /* printk can add a prefix */ | ||
| 836 | if (ret > len) | ||
| 837 | ret = len; | ||
| 838 | out: | ||
| 839 | kfree(line); | ||
| 840 | return ret; | ||
| 841 | } | ||
| 842 | |||
| 843 | static const struct file_operations kmsg_fops = { | ||
| 844 | .aio_write = kmsg_writev, | ||
| 845 | .llseek = noop_llseek, | ||
| 846 | }; | ||
| 847 | |||
| 848 | static const struct memdev { | 810 | static const struct memdev { |
| 849 | const char *name; | 811 | const char *name; |
| 850 | umode_t mode; | 812 | umode_t mode; |
| @@ -863,7 +825,9 @@ static const struct memdev { | |||
| 863 | [7] = { "full", 0666, &full_fops, NULL }, | 825 | [7] = { "full", 0666, &full_fops, NULL }, |
| 864 | [8] = { "random", 0666, &random_fops, NULL }, | 826 | [8] = { "random", 0666, &random_fops, NULL }, |
| 865 | [9] = { "urandom", 0666, &urandom_fops, NULL }, | 827 | [9] = { "urandom", 0666, &urandom_fops, NULL }, |
| 866 | [11] = { "kmsg", 0, &kmsg_fops, NULL }, | 828 | #ifdef CONFIG_PRINTK |
| 829 | [11] = { "kmsg", 0644, &kmsg_fops, NULL }, | ||
| 830 | #endif | ||
| 867 | #ifdef CONFIG_CRASH_DUMP | 831 | #ifdef CONFIG_CRASH_DUMP |
| 868 | [12] = { "oldmem", 0, &oldmem_fops, NULL }, | 832 | [12] = { "oldmem", 0, &oldmem_fops, NULL }, |
| 869 | #endif | 833 | #endif |
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig new file mode 100644 index 000000000000..29c5cf852efc --- /dev/null +++ b/drivers/extcon/Kconfig | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | menuconfig EXTCON | ||
| 2 | tristate "External Connector Class (extcon) support" | ||
| 3 | help | ||
| 4 | Say Y here to enable external connector class (extcon) support. | ||
| 5 | This allows monitoring external connectors by userspace | ||
| 6 | via sysfs and uevent and supports external connectors with | ||
| 7 | multiple states; i.e., an extcon that may have multiple | ||
| 8 | cables attached. For example, an external connector of a device | ||
| 9 | may be used to connect an HDMI cable and a AC adaptor, and to | ||
| 10 | host USB ports. Many of 30-pin connectors including PDMI are | ||
| 11 | also good examples. | ||
| 12 | |||
| 13 | if EXTCON | ||
| 14 | |||
| 15 | comment "Extcon Device Drivers" | ||
| 16 | |||
| 17 | config EXTCON_GPIO | ||
| 18 | tristate "GPIO extcon support" | ||
| 19 | depends on GENERIC_GPIO | ||
| 20 | help | ||
| 21 | Say Y here to enable GPIO based extcon support. Note that GPIO | ||
| 22 | extcon supports single state per extcon instance. | ||
| 23 | |||
| 24 | config EXTCON_MAX8997 | ||
| 25 | tristate "MAX8997 EXTCON Support" | ||
| 26 | depends on MFD_MAX8997 | ||
| 27 | help | ||
| 28 | If you say yes here you get support for the MUIC device of | ||
| 29 | Maxim MAX8997 PMIC. The MAX8997 MUIC is a USB port accessory | ||
| 30 | detector and switch. | ||
| 31 | |||
| 32 | endif # MULTISTATE_SWITCH | ||
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile new file mode 100644 index 000000000000..86020bdb6da0 --- /dev/null +++ b/drivers/extcon/Makefile | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | # | ||
| 2 | # Makefile for external connector class (extcon) devices | ||
| 3 | # | ||
| 4 | |||
| 5 | obj-$(CONFIG_EXTCON) += extcon_class.o | ||
| 6 | obj-$(CONFIG_EXTCON_GPIO) += extcon_gpio.o | ||
| 7 | obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o | ||
diff --git a/drivers/misc/max8997-muic.c b/drivers/extcon/extcon-max8997.c index 2e7df9c56491..23416e443765 100644 --- a/drivers/misc/max8997-muic.c +++ b/drivers/extcon/extcon-max8997.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * max8997-muic.c - MAX8997 muic driver for the Maxim 8997 | 2 | * extcon-max8997.c - MAX8997 extcon driver to support MAX8997 MUIC |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2011 Samsung Electrnoics | 4 | * Copyright (C) 2012 Samsung Electrnoics |
| 5 | * Donggeun Kim <dg77.kim@samsung.com> | 5 | * Donggeun Kim <dg77.kim@samsung.com> |
| 6 | * | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
| @@ -13,11 +13,6 @@ | |||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | * GNU General Public License for more details. | 15 | * GNU General Public License for more details. |
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | * | ||
| 21 | */ | 16 | */ |
| 22 | 17 | ||
| 23 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
| @@ -30,6 +25,9 @@ | |||
| 30 | #include <linux/kobject.h> | 25 | #include <linux/kobject.h> |
| 31 | #include <linux/mfd/max8997.h> | 26 | #include <linux/mfd/max8997.h> |
| 32 | #include <linux/mfd/max8997-private.h> | 27 | #include <linux/mfd/max8997-private.h> |
| 28 | #include <linux/extcon.h> | ||
| 29 | |||
| 30 | #define DEV_NAME "max8997-muic" | ||
| 33 | 31 | ||
| 34 | /* MAX8997-MUIC STATUS1 register */ | 32 | /* MAX8997-MUIC STATUS1 register */ |
| 35 | #define STATUS1_ADC_SHIFT 0 | 33 | #define STATUS1_ADC_SHIFT 0 |
| @@ -95,7 +93,6 @@ static struct max8997_muic_irq muic_irqs[] = { | |||
| 95 | 93 | ||
| 96 | struct max8997_muic_info { | 94 | struct max8997_muic_info { |
| 97 | struct device *dev; | 95 | struct device *dev; |
| 98 | struct max8997_dev *iodev; | ||
| 99 | struct i2c_client *muic; | 96 | struct i2c_client *muic; |
| 100 | struct max8997_muic_platform_data *muic_pdata; | 97 | struct max8997_muic_platform_data *muic_pdata; |
| 101 | 98 | ||
| @@ -106,12 +103,28 @@ struct max8997_muic_info { | |||
| 106 | int pre_adc; | 103 | int pre_adc; |
| 107 | 104 | ||
| 108 | struct mutex mutex; | 105 | struct mutex mutex; |
| 106 | |||
| 107 | struct extcon_dev *edev; | ||
| 108 | }; | ||
| 109 | |||
| 110 | const char *max8997_extcon_cable[] = { | ||
| 111 | [0] = "USB", | ||
| 112 | [1] = "USB-Host", | ||
| 113 | [2] = "TA", | ||
| 114 | [3] = "Fast-charger", | ||
| 115 | [4] = "Slow-charger", | ||
| 116 | [5] = "Charge-downstream", | ||
| 117 | [6] = "MHL", | ||
| 118 | [7] = "Dock-desk", | ||
| 119 | [7] = "Dock-card", | ||
| 120 | [8] = "JIG", | ||
| 121 | |||
| 122 | NULL, | ||
| 109 | }; | 123 | }; |
| 110 | 124 | ||
| 111 | static int max8997_muic_handle_usb(struct max8997_muic_info *info, | 125 | static int max8997_muic_handle_usb(struct max8997_muic_info *info, |
| 112 | enum max8997_muic_usb_type usb_type, bool attached) | 126 | enum max8997_muic_usb_type usb_type, bool attached) |
| 113 | { | 127 | { |
| 114 | struct max8997_muic_platform_data *mdata = info->muic_pdata; | ||
| 115 | int ret = 0; | 128 | int ret = 0; |
| 116 | 129 | ||
| 117 | if (usb_type == MAX8997_USB_HOST) { | 130 | if (usb_type == MAX8997_USB_HOST) { |
| @@ -125,25 +138,25 @@ static int max8997_muic_handle_usb(struct max8997_muic_info *info, | |||
| 125 | } | 138 | } |
| 126 | } | 139 | } |
| 127 | 140 | ||
| 128 | if (mdata->usb_callback) | 141 | switch (usb_type) { |
| 129 | mdata->usb_callback(usb_type, attached); | 142 | case MAX8997_USB_HOST: |
| 143 | extcon_set_cable_state(info->edev, "USB-Host", attached); | ||
| 144 | break; | ||
| 145 | case MAX8997_USB_DEVICE: | ||
| 146 | extcon_set_cable_state(info->edev, "USB", attached); | ||
| 147 | break; | ||
| 148 | default: | ||
| 149 | ret = -EINVAL; | ||
| 150 | break; | ||
| 151 | } | ||
| 152 | |||
| 130 | out: | 153 | out: |
| 131 | return ret; | 154 | return ret; |
| 132 | } | 155 | } |
| 133 | 156 | ||
| 134 | static void max8997_muic_handle_mhl(struct max8997_muic_info *info, | ||
| 135 | bool attached) | ||
| 136 | { | ||
| 137 | struct max8997_muic_platform_data *mdata = info->muic_pdata; | ||
| 138 | |||
| 139 | if (mdata->mhl_callback) | ||
| 140 | mdata->mhl_callback(attached); | ||
| 141 | } | ||
| 142 | |||
| 143 | static int max8997_muic_handle_dock(struct max8997_muic_info *info, | 157 | static int max8997_muic_handle_dock(struct max8997_muic_info *info, |
| 144 | int adc, bool attached) | 158 | int adc, bool attached) |
| 145 | { | 159 | { |
| 146 | struct max8997_muic_platform_data *mdata = info->muic_pdata; | ||
| 147 | int ret = 0; | 160 | int ret = 0; |
| 148 | 161 | ||
| 149 | /* switch to AUDIO */ | 162 | /* switch to AUDIO */ |
| @@ -157,14 +170,13 @@ static int max8997_muic_handle_dock(struct max8997_muic_info *info, | |||
| 157 | 170 | ||
| 158 | switch (adc) { | 171 | switch (adc) { |
| 159 | case MAX8997_ADC_DESKDOCK: | 172 | case MAX8997_ADC_DESKDOCK: |
| 160 | if (mdata->deskdock_callback) | 173 | extcon_set_cable_state(info->edev, "Dock-desk", attached); |
| 161 | mdata->deskdock_callback(attached); | ||
| 162 | break; | 174 | break; |
| 163 | case MAX8997_ADC_CARDOCK: | 175 | case MAX8997_ADC_CARDOCK: |
| 164 | if (mdata->cardock_callback) | 176 | extcon_set_cable_state(info->edev, "Dock-card", attached); |
| 165 | mdata->cardock_callback(attached); | ||
| 166 | break; | 177 | break; |
| 167 | default: | 178 | default: |
| 179 | ret = -EINVAL; | ||
| 168 | break; | 180 | break; |
| 169 | } | 181 | } |
| 170 | out: | 182 | out: |
| @@ -174,7 +186,6 @@ out: | |||
| 174 | static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info, | 186 | static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info, |
| 175 | bool attached) | 187 | bool attached) |
| 176 | { | 188 | { |
| 177 | struct max8997_muic_platform_data *mdata = info->muic_pdata; | ||
| 178 | int ret = 0; | 189 | int ret = 0; |
| 179 | 190 | ||
| 180 | /* switch to UART */ | 191 | /* switch to UART */ |
| @@ -186,8 +197,7 @@ static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info, | |||
| 186 | goto out; | 197 | goto out; |
| 187 | } | 198 | } |
| 188 | 199 | ||
| 189 | if (mdata->uart_callback) | 200 | extcon_set_cable_state(info->edev, "JIG", attached); |
| 190 | mdata->uart_callback(attached); | ||
| 191 | out: | 201 | out: |
| 192 | return ret; | 202 | return ret; |
| 193 | } | 203 | } |
| @@ -201,7 +211,7 @@ static int max8997_muic_handle_adc_detach(struct max8997_muic_info *info) | |||
| 201 | ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, false); | 211 | ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, false); |
| 202 | break; | 212 | break; |
| 203 | case MAX8997_ADC_MHL: | 213 | case MAX8997_ADC_MHL: |
| 204 | max8997_muic_handle_mhl(info, false); | 214 | extcon_set_cable_state(info->edev, "MHL", false); |
| 205 | break; | 215 | break; |
| 206 | case MAX8997_ADC_JIG_USB_1: | 216 | case MAX8997_ADC_JIG_USB_1: |
| 207 | case MAX8997_ADC_JIG_USB_2: | 217 | case MAX8997_ADC_JIG_USB_2: |
| @@ -230,7 +240,7 @@ static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc) | |||
| 230 | ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, true); | 240 | ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, true); |
| 231 | break; | 241 | break; |
| 232 | case MAX8997_ADC_MHL: | 242 | case MAX8997_ADC_MHL: |
| 233 | max8997_muic_handle_mhl(info, true); | 243 | extcon_set_cable_state(info->edev, "MHL", true); |
| 234 | break; | 244 | break; |
| 235 | case MAX8997_ADC_JIG_USB_1: | 245 | case MAX8997_ADC_JIG_USB_1: |
| 236 | case MAX8997_ADC_JIG_USB_2: | 246 | case MAX8997_ADC_JIG_USB_2: |
| @@ -247,10 +257,40 @@ static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc) | |||
| 247 | ret = max8997_muic_handle_adc_detach(info); | 257 | ret = max8997_muic_handle_adc_detach(info); |
| 248 | break; | 258 | break; |
| 249 | default: | 259 | default: |
| 250 | break; | 260 | ret = -EINVAL; |
| 261 | goto out; | ||
| 251 | } | 262 | } |
| 252 | 263 | ||
| 253 | info->pre_adc = adc; | 264 | info->pre_adc = adc; |
| 265 | out: | ||
| 266 | return ret; | ||
| 267 | } | ||
| 268 | |||
| 269 | static int max8997_muic_handle_charger_type_detach( | ||
| 270 | struct max8997_muic_info *info) | ||
| 271 | { | ||
| 272 | int ret = 0; | ||
| 273 | |||
| 274 | switch (info->pre_charger_type) { | ||
| 275 | case MAX8997_CHARGER_TYPE_USB: | ||
| 276 | extcon_set_cable_state(info->edev, "USB", false); | ||
| 277 | break; | ||
| 278 | case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT: | ||
| 279 | extcon_set_cable_state(info->edev, "Charge-downstream", false); | ||
| 280 | break; | ||
| 281 | case MAX8997_CHARGER_TYPE_DEDICATED_CHG: | ||
| 282 | extcon_set_cable_state(info->edev, "TA", false); | ||
| 283 | break; | ||
| 284 | case MAX8997_CHARGER_TYPE_500MA: | ||
| 285 | extcon_set_cable_state(info->edev, "Slow-charger", false); | ||
| 286 | break; | ||
| 287 | case MAX8997_CHARGER_TYPE_1A: | ||
| 288 | extcon_set_cable_state(info->edev, "Fast-charger", false); | ||
| 289 | break; | ||
| 290 | default: | ||
| 291 | ret = -EINVAL; | ||
| 292 | break; | ||
| 293 | } | ||
| 254 | 294 | ||
| 255 | return ret; | 295 | return ret; |
| 256 | } | 296 | } |
| @@ -258,7 +298,6 @@ static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc) | |||
| 258 | static int max8997_muic_handle_charger_type(struct max8997_muic_info *info, | 298 | static int max8997_muic_handle_charger_type(struct max8997_muic_info *info, |
| 259 | enum max8997_muic_charger_type charger_type) | 299 | enum max8997_muic_charger_type charger_type) |
| 260 | { | 300 | { |
| 261 | struct max8997_muic_platform_data *mdata = info->muic_pdata; | ||
| 262 | u8 adc; | 301 | u8 adc; |
| 263 | int ret; | 302 | int ret; |
| 264 | 303 | ||
| @@ -270,30 +309,29 @@ static int max8997_muic_handle_charger_type(struct max8997_muic_info *info, | |||
| 270 | 309 | ||
| 271 | switch (charger_type) { | 310 | switch (charger_type) { |
| 272 | case MAX8997_CHARGER_TYPE_NONE: | 311 | case MAX8997_CHARGER_TYPE_NONE: |
| 273 | if (mdata->charger_callback) | 312 | ret = max8997_muic_handle_charger_type_detach(info); |
| 274 | mdata->charger_callback(false, charger_type); | ||
| 275 | if (info->pre_charger_type == MAX8997_CHARGER_TYPE_USB) { | ||
| 276 | max8997_muic_handle_usb(info, | ||
| 277 | MAX8997_USB_DEVICE, false); | ||
| 278 | } | ||
| 279 | break; | 313 | break; |
| 280 | case MAX8997_CHARGER_TYPE_USB: | 314 | case MAX8997_CHARGER_TYPE_USB: |
| 281 | if ((adc & STATUS1_ADC_MASK) == MAX8997_ADC_OPEN) { | 315 | if ((adc & STATUS1_ADC_MASK) == MAX8997_ADC_OPEN) { |
| 282 | max8997_muic_handle_usb(info, | 316 | max8997_muic_handle_usb(info, |
| 283 | MAX8997_USB_DEVICE, true); | 317 | MAX8997_USB_DEVICE, true); |
| 284 | } | 318 | } |
| 285 | if (mdata->charger_callback) | ||
| 286 | mdata->charger_callback(true, charger_type); | ||
| 287 | break; | 319 | break; |
| 288 | case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT: | 320 | case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT: |
| 321 | extcon_set_cable_state(info->edev, "Charge-downstream", true); | ||
| 322 | break; | ||
| 289 | case MAX8997_CHARGER_TYPE_DEDICATED_CHG: | 323 | case MAX8997_CHARGER_TYPE_DEDICATED_CHG: |
| 324 | extcon_set_cable_state(info->edev, "TA", true); | ||
| 325 | break; | ||
| 290 | case MAX8997_CHARGER_TYPE_500MA: | 326 | case MAX8997_CHARGER_TYPE_500MA: |
| 327 | extcon_set_cable_state(info->edev, "Slow-charger", true); | ||
| 328 | break; | ||
| 291 | case MAX8997_CHARGER_TYPE_1A: | 329 | case MAX8997_CHARGER_TYPE_1A: |
| 292 | if (mdata->charger_callback) | 330 | extcon_set_cable_state(info->edev, "Fast-charger", true); |
| 293 | mdata->charger_callback(true, charger_type); | ||
| 294 | break; | 331 | break; |
| 295 | default: | 332 | default: |
| 296 | break; | 333 | ret = -EINVAL; |
| 334 | goto out; | ||
| 297 | } | 335 | } |
| 298 | 336 | ||
| 299 | info->pre_charger_type = charger_type; | 337 | info->pre_charger_type = charger_type; |
| @@ -305,18 +343,17 @@ static void max8997_muic_irq_work(struct work_struct *work) | |||
| 305 | { | 343 | { |
| 306 | struct max8997_muic_info *info = container_of(work, | 344 | struct max8997_muic_info *info = container_of(work, |
| 307 | struct max8997_muic_info, irq_work); | 345 | struct max8997_muic_info, irq_work); |
| 308 | struct max8997_platform_data *pdata = | 346 | struct max8997_dev *max8997 = i2c_get_clientdata(info->muic); |
| 309 | dev_get_platdata(info->iodev->dev); | 347 | u8 status[2]; |
| 310 | u8 status[3]; | ||
| 311 | u8 adc, chg_type; | 348 | u8 adc, chg_type; |
| 312 | 349 | ||
| 313 | int irq_type = info->irq - pdata->irq_base; | 350 | int irq_type = info->irq - max8997->irq_base; |
| 314 | int ret; | 351 | int ret; |
| 315 | 352 | ||
| 316 | mutex_lock(&info->mutex); | 353 | mutex_lock(&info->mutex); |
| 317 | 354 | ||
| 318 | ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1, | 355 | ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1, |
| 319 | 3, status); | 356 | 2, status); |
| 320 | if (ret) { | 357 | if (ret) { |
| 321 | dev_err(info->dev, "failed to read muic register\n"); | 358 | dev_err(info->dev, "failed to read muic register\n"); |
| 322 | mutex_unlock(&info->mutex); | 359 | mutex_unlock(&info->mutex); |
| @@ -340,8 +377,8 @@ static void max8997_muic_irq_work(struct work_struct *work) | |||
| 340 | max8997_muic_handle_charger_type(info, chg_type); | 377 | max8997_muic_handle_charger_type(info, chg_type); |
| 341 | break; | 378 | break; |
| 342 | default: | 379 | default: |
| 343 | dev_info(info->dev, "misc interrupt: %s occurred\n", | 380 | dev_info(info->dev, "misc interrupt: irq %d occurred\n", |
| 344 | muic_irqs[irq_type].name); | 381 | irq_type); |
| 345 | break; | 382 | break; |
| 346 | } | 383 | } |
| 347 | 384 | ||
| @@ -387,21 +424,10 @@ static void max8997_muic_detect_dev(struct max8997_muic_info *info) | |||
| 387 | max8997_muic_handle_charger_type(info, chg_type); | 424 | max8997_muic_handle_charger_type(info, chg_type); |
| 388 | } | 425 | } |
| 389 | 426 | ||
| 390 | static void max8997_initialize_device(struct max8997_muic_info *info) | ||
| 391 | { | ||
| 392 | struct max8997_muic_platform_data *mdata = info->muic_pdata; | ||
| 393 | int i; | ||
| 394 | |||
| 395 | for (i = 0; i < mdata->num_init_data; i++) { | ||
| 396 | max8997_write_reg(info->muic, mdata->init_data[i].addr, | ||
| 397 | mdata->init_data[i].data); | ||
| 398 | } | ||
| 399 | } | ||
| 400 | |||
| 401 | static int __devinit max8997_muic_probe(struct platform_device *pdev) | 427 | static int __devinit max8997_muic_probe(struct platform_device *pdev) |
| 402 | { | 428 | { |
| 403 | struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 429 | struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent); |
| 404 | struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev); | 430 | struct max8997_platform_data *pdata = dev_get_platdata(max8997->dev); |
| 405 | struct max8997_muic_info *info; | 431 | struct max8997_muic_info *info; |
| 406 | int ret, i; | 432 | int ret, i; |
| 407 | 433 | ||
| @@ -412,16 +438,8 @@ static int __devinit max8997_muic_probe(struct platform_device *pdev) | |||
| 412 | goto err_kfree; | 438 | goto err_kfree; |
| 413 | } | 439 | } |
| 414 | 440 | ||
| 415 | if (!pdata->muic_pdata) { | ||
| 416 | dev_err(&pdev->dev, "failed to get platform_data\n"); | ||
| 417 | ret = -EINVAL; | ||
| 418 | goto err_pdata; | ||
| 419 | } | ||
| 420 | info->muic_pdata = pdata->muic_pdata; | ||
| 421 | |||
| 422 | info->dev = &pdev->dev; | 441 | info->dev = &pdev->dev; |
| 423 | info->iodev = iodev; | 442 | info->muic = max8997->muic; |
| 424 | info->muic = iodev->muic; | ||
| 425 | 443 | ||
| 426 | platform_set_drvdata(pdev, info); | 444 | platform_set_drvdata(pdev, info); |
| 427 | mutex_init(&info->mutex); | 445 | mutex_init(&info->mutex); |
| @@ -444,18 +462,41 @@ static int __devinit max8997_muic_probe(struct platform_device *pdev) | |||
| 444 | } | 462 | } |
| 445 | } | 463 | } |
| 446 | 464 | ||
| 465 | /* External connector */ | ||
| 466 | info->edev = kzalloc(sizeof(struct extcon_dev), GFP_KERNEL); | ||
| 467 | if (!info->edev) { | ||
| 468 | dev_err(&pdev->dev, "failed to allocate memory for extcon\n"); | ||
| 469 | ret = -ENOMEM; | ||
| 470 | goto err_irq; | ||
| 471 | } | ||
| 472 | info->edev->name = DEV_NAME; | ||
| 473 | info->edev->supported_cable = max8997_extcon_cable; | ||
| 474 | ret = extcon_dev_register(info->edev, NULL); | ||
| 475 | if (ret) { | ||
| 476 | dev_err(&pdev->dev, "failed to register extcon device\n"); | ||
| 477 | goto err_extcon; | ||
| 478 | } | ||
| 479 | |||
| 447 | /* Initialize registers according to platform data */ | 480 | /* Initialize registers according to platform data */ |
| 448 | max8997_initialize_device(info); | 481 | if (pdata->muic_pdata) { |
| 482 | struct max8997_muic_platform_data *mdata = info->muic_pdata; | ||
| 483 | |||
| 484 | for (i = 0; i < mdata->num_init_data; i++) { | ||
| 485 | max8997_write_reg(info->muic, mdata->init_data[i].addr, | ||
| 486 | mdata->init_data[i].data); | ||
| 487 | } | ||
| 488 | } | ||
| 449 | 489 | ||
| 450 | /* Initial device detection */ | 490 | /* Initial device detection */ |
| 451 | max8997_muic_detect_dev(info); | 491 | max8997_muic_detect_dev(info); |
| 452 | 492 | ||
| 453 | return ret; | 493 | return ret; |
| 454 | 494 | ||
| 495 | err_extcon: | ||
| 496 | kfree(info->edev); | ||
| 455 | err_irq: | 497 | err_irq: |
| 456 | while (--i >= 0) | 498 | while (--i >= 0) |
| 457 | free_irq(pdata->irq_base + muic_irqs[i].irq, info); | 499 | free_irq(pdata->irq_base + muic_irqs[i].irq, info); |
| 458 | err_pdata: | ||
| 459 | kfree(info); | 500 | kfree(info); |
| 460 | err_kfree: | 501 | err_kfree: |
| 461 | return ret; | 502 | return ret; |
| @@ -464,14 +505,15 @@ err_kfree: | |||
| 464 | static int __devexit max8997_muic_remove(struct platform_device *pdev) | 505 | static int __devexit max8997_muic_remove(struct platform_device *pdev) |
| 465 | { | 506 | { |
| 466 | struct max8997_muic_info *info = platform_get_drvdata(pdev); | 507 | struct max8997_muic_info *info = platform_get_drvdata(pdev); |
| 467 | struct max8997_platform_data *pdata = | 508 | struct max8997_dev *max8997 = i2c_get_clientdata(info->muic); |
| 468 | dev_get_platdata(info->iodev->dev); | ||
| 469 | int i; | 509 | int i; |
| 470 | 510 | ||
| 471 | for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) | 511 | for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) |
| 472 | free_irq(pdata->irq_base + muic_irqs[i].irq, info); | 512 | free_irq(max8997->irq_base + muic_irqs[i].irq, info); |
| 473 | cancel_work_sync(&info->irq_work); | 513 | cancel_work_sync(&info->irq_work); |
| 474 | 514 | ||
| 515 | extcon_dev_unregister(info->edev); | ||
| 516 | |||
| 475 | kfree(info); | 517 | kfree(info); |
| 476 | 518 | ||
| 477 | return 0; | 519 | return 0; |
| @@ -479,7 +521,7 @@ static int __devexit max8997_muic_remove(struct platform_device *pdev) | |||
| 479 | 521 | ||
| 480 | static struct platform_driver max8997_muic_driver = { | 522 | static struct platform_driver max8997_muic_driver = { |
| 481 | .driver = { | 523 | .driver = { |
| 482 | .name = "max8997-muic", | 524 | .name = DEV_NAME, |
| 483 | .owner = THIS_MODULE, | 525 | .owner = THIS_MODULE, |
| 484 | }, | 526 | }, |
| 485 | .probe = max8997_muic_probe, | 527 | .probe = max8997_muic_probe, |
| @@ -488,6 +530,6 @@ static struct platform_driver max8997_muic_driver = { | |||
| 488 | 530 | ||
| 489 | module_platform_driver(max8997_muic_driver); | 531 | module_platform_driver(max8997_muic_driver); |
| 490 | 532 | ||
| 491 | MODULE_DESCRIPTION("Maxim MAX8997 MUIC driver"); | 533 | MODULE_DESCRIPTION("Maxim MAX8997 Extcon driver"); |
| 492 | MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>"); | 534 | MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>"); |
| 493 | MODULE_LICENSE("GPL"); | 535 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/extcon/extcon_class.c b/drivers/extcon/extcon_class.c new file mode 100644 index 000000000000..f598a700ec15 --- /dev/null +++ b/drivers/extcon/extcon_class.c | |||
| @@ -0,0 +1,832 @@ | |||
| 1 | /* | ||
| 2 | * drivers/extcon/extcon_class.c | ||
| 3 | * | ||
| 4 | * External connector (extcon) class driver | ||
| 5 | * | ||
| 6 | * Copyright (C) 2012 Samsung Electronics | ||
| 7 | * Author: Donggeun Kim <dg77.kim@samsung.com> | ||
| 8 | * Author: MyungJoo Ham <myungjoo.ham@samsung.com> | ||
| 9 | * | ||
| 10 | * based on android/drivers/switch/switch_class.c | ||
| 11 | * Copyright (C) 2008 Google, Inc. | ||
| 12 | * Author: Mike Lockwood <lockwood@android.com> | ||
| 13 | * | ||
| 14 | * This software is licensed under the terms of the GNU General Public | ||
| 15 | * License version 2, as published by the Free Software Foundation, and | ||
| 16 | * may be copied, distributed, and modified under those terms. | ||
| 17 | * | ||
| 18 | * This program is distributed in the hope that it will be useful, | ||
| 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 21 | * GNU General Public License for more details. | ||
| 22 | * | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include <linux/module.h> | ||
| 26 | #include <linux/types.h> | ||
| 27 | #include <linux/init.h> | ||
| 28 | #include <linux/device.h> | ||
| 29 | #include <linux/fs.h> | ||
| 30 | #include <linux/err.h> | ||
| 31 | #include <linux/extcon.h> | ||
| 32 | #include <linux/slab.h> | ||
| 33 | |||
| 34 | /* | ||
| 35 | * extcon_cable_name suggests the standard cable names for commonly used | ||
| 36 | * cable types. | ||
| 37 | * | ||
| 38 | * However, please do not use extcon_cable_name directly for extcon_dev | ||
| 39 | * struct's supported_cable pointer unless your device really supports | ||
| 40 | * every single port-type of the following cable names. Please choose cable | ||
| 41 | * names that are actually used in your extcon device. | ||
| 42 | */ | ||
| 43 | const char *extcon_cable_name[] = { | ||
| 44 | [EXTCON_USB] = "USB", | ||
| 45 | [EXTCON_USB_HOST] = "USB-Host", | ||
| 46 | [EXTCON_TA] = "TA", | ||
| 47 | [EXTCON_FAST_CHARGER] = "Fast-charger", | ||
| 48 | [EXTCON_SLOW_CHARGER] = "Slow-charger", | ||
| 49 | [EXTCON_CHARGE_DOWNSTREAM] = "Charge-downstream", | ||
| 50 | [EXTCON_HDMI] = "HDMI", | ||
| 51 | [EXTCON_MHL] = "MHL", | ||
| 52 | [EXTCON_DVI] = "DVI", | ||
| 53 | [EXTCON_VGA] = "VGA", | ||
| 54 | [EXTCON_DOCK] = "Dock", | ||
| 55 | [EXTCON_LINE_IN] = "Line-in", | ||
| 56 | [EXTCON_LINE_OUT] = "Line-out", | ||
| 57 | [EXTCON_MIC_IN] = "Microphone", | ||
| 58 | [EXTCON_HEADPHONE_OUT] = "Headphone", | ||
| 59 | [EXTCON_SPDIF_IN] = "SPDIF-in", | ||
| 60 | [EXTCON_SPDIF_OUT] = "SPDIF-out", | ||
| 61 | [EXTCON_VIDEO_IN] = "Video-in", | ||
| 62 | [EXTCON_VIDEO_OUT] = "Video-out", | ||
| 63 | [EXTCON_MECHANICAL] = "Mechanical", | ||
| 64 | |||
| 65 | NULL, | ||
| 66 | }; | ||
| 67 | |||
| 68 | struct class *extcon_class; | ||
| 69 | #if defined(CONFIG_ANDROID) | ||
| 70 | static struct class_compat *switch_class; | ||
| 71 | #endif /* CONFIG_ANDROID */ | ||
| 72 | |||
| 73 | static LIST_HEAD(extcon_dev_list); | ||
| 74 | static DEFINE_MUTEX(extcon_dev_list_lock); | ||
| 75 | |||
| 76 | /** | ||
| 77 | * check_mutually_exclusive - Check if new_state violates mutually_exclusive | ||
| 78 | * condition. | ||
| 79 | * @edev: the extcon device | ||
| 80 | * @new_state: new cable attach status for @edev | ||
| 81 | * | ||
| 82 | * Returns 0 if nothing violates. Returns the index + 1 for the first | ||
| 83 | * violated condition. | ||
| 84 | */ | ||
| 85 | static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state) | ||
| 86 | { | ||
| 87 | int i = 0; | ||
| 88 | |||
| 89 | if (!edev->mutually_exclusive) | ||
| 90 | return 0; | ||
| 91 | |||
| 92 | for (i = 0; edev->mutually_exclusive[i]; i++) { | ||
| 93 | int count = 0, j; | ||
| 94 | u32 correspondants = new_state & edev->mutually_exclusive[i]; | ||
| 95 | u32 exp = 1; | ||
| 96 | |||
| 97 | for (j = 0; j < 32; j++) { | ||
| 98 | if (exp & correspondants) | ||
| 99 | count++; | ||
| 100 | if (count > 1) | ||
| 101 | return i + 1; | ||
| 102 | exp <<= 1; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | |||
| 109 | static ssize_t state_show(struct device *dev, struct device_attribute *attr, | ||
| 110 | char *buf) | ||
| 111 | { | ||
| 112 | int i, count = 0; | ||
| 113 | struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev); | ||
| 114 | |||
| 115 | if (edev->print_state) { | ||
| 116 | int ret = edev->print_state(edev, buf); | ||
| 117 | |||
| 118 | if (ret >= 0) | ||
| 119 | return ret; | ||
| 120 | /* Use default if failed */ | ||
| 121 | } | ||
| 122 | |||
| 123 | if (edev->max_supported == 0) | ||
| 124 | return sprintf(buf, "%u\n", edev->state); | ||
| 125 | |||
| 126 | for (i = 0; i < SUPPORTED_CABLE_MAX; i++) { | ||
| 127 | if (!edev->supported_cable[i]) | ||
| 128 | break; | ||
| 129 | count += sprintf(buf + count, "%s=%d\n", | ||
| 130 | edev->supported_cable[i], | ||
| 131 | !!(edev->state & (1 << i))); | ||
| 132 | } | ||
| 133 | |||
| 134 | return count; | ||
| 135 | } | ||
| 136 | |||
| 137 | int extcon_set_state(struct extcon_dev *edev, u32 state); | ||
| 138 | static ssize_t state_store(struct device *dev, struct device_attribute *attr, | ||
| 139 | const char *buf, size_t count) | ||
| 140 | { | ||
| 141 | u32 state; | ||
| 142 | ssize_t ret = 0; | ||
| 143 | struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev); | ||
| 144 | |||
| 145 | ret = sscanf(buf, "0x%x", &state); | ||
| 146 | if (ret == 0) | ||
| 147 | ret = -EINVAL; | ||
| 148 | else | ||
| 149 | ret = extcon_set_state(edev, state); | ||
| 150 | |||
| 151 | if (ret < 0) | ||
| 152 | return ret; | ||
| 153 | |||
| 154 | return count; | ||
| 155 | } | ||
| 156 | |||
| 157 | static ssize_t name_show(struct device *dev, struct device_attribute *attr, | ||
| 158 | char *buf) | ||
| 159 | { | ||
| 160 | struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev); | ||
| 161 | |||
| 162 | /* Optional callback given by the user */ | ||
| 163 | if (edev->print_name) { | ||
| 164 | int ret = edev->print_name(edev, buf); | ||
| 165 | if (ret >= 0) | ||
| 166 | return ret; | ||
| 167 | } | ||
| 168 | |||
| 169 | return sprintf(buf, "%s\n", dev_name(edev->dev)); | ||
| 170 | } | ||
| 171 | |||
| 172 | static ssize_t cable_name_show(struct device *dev, | ||
| 173 | struct device_attribute *attr, char *buf) | ||
| 174 | { | ||
| 175 | struct extcon_cable *cable = container_of(attr, struct extcon_cable, | ||
| 176 | attr_name); | ||
| 177 | |||
| 178 | return sprintf(buf, "%s\n", | ||
| 179 | cable->edev->supported_cable[cable->cable_index]); | ||
| 180 | } | ||
| 181 | |||
| 182 | static ssize_t cable_state_show(struct device *dev, | ||
| 183 | struct device_attribute *attr, char *buf) | ||
| 184 | { | ||
| 185 | struct extcon_cable *cable = container_of(attr, struct extcon_cable, | ||
| 186 | attr_state); | ||
| 187 | |||
| 188 | return sprintf(buf, "%d\n", | ||
| 189 | extcon_get_cable_state_(cable->edev, | ||
| 190 | cable->cable_index)); | ||
| 191 | } | ||
| 192 | |||
| 193 | static ssize_t cable_state_store(struct device *dev, | ||
| 194 | struct device_attribute *attr, const char *buf, | ||
| 195 | size_t count) | ||
| 196 | { | ||
| 197 | struct extcon_cable *cable = container_of(attr, struct extcon_cable, | ||
| 198 | attr_state); | ||
| 199 | int ret, state; | ||
| 200 | |||
| 201 | ret = sscanf(buf, "%d", &state); | ||
| 202 | if (ret == 0) | ||
| 203 | ret = -EINVAL; | ||
| 204 | else | ||
| 205 | ret = extcon_set_cable_state_(cable->edev, cable->cable_index, | ||
| 206 | state); | ||
| 207 | |||
| 208 | if (ret < 0) | ||
| 209 | return ret; | ||
| 210 | return count; | ||
| 211 | } | ||
| 212 | |||
| 213 | /** | ||
| 214 | * extcon_update_state() - Update the cable attach states of the extcon device | ||
| 215 | * only for the masked bits. | ||
| 216 | * @edev: the extcon device | ||
| 217 | * @mask: the bit mask to designate updated bits. | ||
| 218 | * @state: new cable attach status for @edev | ||
| 219 | * | ||
| 220 | * Changing the state sends uevent with environment variable containing | ||
| 221 | * the name of extcon device (envp[0]) and the state output (envp[1]). | ||
| 222 | * Tizen uses this format for extcon device to get events from ports. | ||
| 223 | * Android uses this format as well. | ||
| 224 | * | ||
| 225 | * Note that the notifier provides which bits are changed in the state | ||
| 226 | * variable with the val parameter (second) to the callback. | ||
| 227 | */ | ||
| 228 | int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) | ||
| 229 | { | ||
| 230 | char name_buf[120]; | ||
| 231 | char state_buf[120]; | ||
| 232 | char *prop_buf; | ||
| 233 | char *envp[3]; | ||
| 234 | int env_offset = 0; | ||
| 235 | int length; | ||
| 236 | unsigned long flags; | ||
| 237 | |||
| 238 | spin_lock_irqsave(&edev->lock, flags); | ||
| 239 | |||
| 240 | if (edev->state != ((edev->state & ~mask) | (state & mask))) { | ||
| 241 | u32 old_state = edev->state; | ||
| 242 | |||
| 243 | if (check_mutually_exclusive(edev, (edev->state & ~mask) | | ||
| 244 | (state & mask))) { | ||
| 245 | spin_unlock_irqrestore(&edev->lock, flags); | ||
| 246 | return -EPERM; | ||
| 247 | } | ||
| 248 | |||
| 249 | edev->state &= ~mask; | ||
| 250 | edev->state |= state & mask; | ||
| 251 | |||
| 252 | raw_notifier_call_chain(&edev->nh, old_state, edev); | ||
| 253 | |||
| 254 | /* This could be in interrupt handler */ | ||
| 255 | prop_buf = (char *)get_zeroed_page(GFP_ATOMIC); | ||
| 256 | if (prop_buf) { | ||
| 257 | length = name_show(edev->dev, NULL, prop_buf); | ||
| 258 | if (length > 0) { | ||
| 259 | if (prop_buf[length - 1] == '\n') | ||
| 260 | prop_buf[length - 1] = 0; | ||
| 261 | snprintf(name_buf, sizeof(name_buf), | ||
| 262 | "NAME=%s", prop_buf); | ||
| 263 | envp[env_offset++] = name_buf; | ||
| 264 | } | ||
| 265 | length = state_show(edev->dev, NULL, prop_buf); | ||
| 266 | if (length > 0) { | ||
| 267 | if (prop_buf[length - 1] == '\n') | ||
| 268 | prop_buf[length - 1] = 0; | ||
| 269 | snprintf(state_buf, sizeof(state_buf), | ||
| 270 | "STATE=%s", prop_buf); | ||
| 271 | envp[env_offset++] = state_buf; | ||
| 272 | } | ||
| 273 | envp[env_offset] = NULL; | ||
| 274 | /* Unlock early before uevent */ | ||
| 275 | spin_unlock_irqrestore(&edev->lock, flags); | ||
| 276 | |||
| 277 | kobject_uevent_env(&edev->dev->kobj, KOBJ_CHANGE, envp); | ||
| 278 | free_page((unsigned long)prop_buf); | ||
| 279 | } else { | ||
| 280 | /* Unlock early before uevent */ | ||
| 281 | spin_unlock_irqrestore(&edev->lock, flags); | ||
| 282 | |||
| 283 | dev_err(edev->dev, "out of memory in extcon_set_state\n"); | ||
| 284 | kobject_uevent(&edev->dev->kobj, KOBJ_CHANGE); | ||
| 285 | } | ||
| 286 | } else { | ||
| 287 | /* No changes */ | ||
| 288 | spin_unlock_irqrestore(&edev->lock, flags); | ||
| 289 | } | ||
| 290 | |||
| 291 | return 0; | ||
| 292 | } | ||
| 293 | EXPORT_SYMBOL_GPL(extcon_update_state); | ||
| 294 | |||
| 295 | /** | ||
| 296 | * extcon_set_state() - Set the cable attach states of the extcon device. | ||
| 297 | * @edev: the extcon device | ||
| 298 | * @state: new cable attach status for @edev | ||
| 299 | * | ||
| 300 | * Note that notifier provides which bits are changed in the state | ||
| 301 | * variable with the val parameter (second) to the callback. | ||
| 302 | */ | ||
| 303 | int extcon_set_state(struct extcon_dev *edev, u32 state) | ||
| 304 | { | ||
| 305 | return extcon_update_state(edev, 0xffffffff, state); | ||
| 306 | } | ||
| 307 | EXPORT_SYMBOL_GPL(extcon_set_state); | ||
| 308 | |||
| 309 | /** | ||
| 310 | * extcon_find_cable_index() - Get the cable index based on the cable name. | ||
| 311 | * @edev: the extcon device that has the cable. | ||
| 312 | * @cable_name: cable name to be searched. | ||
| 313 | * | ||
| 314 | * Note that accessing a cable state based on cable_index is faster than | ||
| 315 | * cable_name because using cable_name induces a loop with strncmp(). | ||
| 316 | * Thus, when get/set_cable_state is repeatedly used, using cable_index | ||
| 317 | * is recommended. | ||
| 318 | */ | ||
| 319 | int extcon_find_cable_index(struct extcon_dev *edev, const char *cable_name) | ||
| 320 | { | ||
| 321 | int i; | ||
| 322 | |||
| 323 | if (edev->supported_cable) { | ||
| 324 | for (i = 0; edev->supported_cable[i]; i++) { | ||
| 325 | if (!strncmp(edev->supported_cable[i], | ||
| 326 | cable_name, CABLE_NAME_MAX)) | ||
| 327 | return i; | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | return -EINVAL; | ||
| 332 | } | ||
| 333 | EXPORT_SYMBOL_GPL(extcon_find_cable_index); | ||
| 334 | |||
| 335 | /** | ||
| 336 | * extcon_get_cable_state_() - Get the status of a specific cable. | ||
| 337 | * @edev: the extcon device that has the cable. | ||
| 338 | * @index: cable index that can be retrieved by extcon_find_cable_index(). | ||
| 339 | */ | ||
| 340 | int extcon_get_cable_state_(struct extcon_dev *edev, int index) | ||
| 341 | { | ||
| 342 | if (index < 0 || (edev->max_supported && edev->max_supported <= index)) | ||
| 343 | return -EINVAL; | ||
| 344 | |||
| 345 | return !!(edev->state & (1 << index)); | ||
| 346 | } | ||
| 347 | EXPORT_SYMBOL_GPL(extcon_get_cable_state_); | ||
| 348 | |||
| 349 | /** | ||
| 350 | * extcon_get_cable_state() - Get the status of a specific cable. | ||
| 351 | * @edev: the extcon device that has the cable. | ||
| 352 | * @cable_name: cable name. | ||
| 353 | * | ||
| 354 | * Note that this is slower than extcon_get_cable_state_. | ||
| 355 | */ | ||
| 356 | int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name) | ||
| 357 | { | ||
| 358 | return extcon_get_cable_state_(edev, extcon_find_cable_index | ||
| 359 | (edev, cable_name)); | ||
| 360 | } | ||
| 361 | EXPORT_SYMBOL_GPL(extcon_get_cable_state); | ||
| 362 | |||
| 363 | /** | ||
| 364 | * extcon_get_cable_state_() - Set the status of a specific cable. | ||
| 365 | * @edev: the extcon device that has the cable. | ||
| 366 | * @index: cable index that can be retrieved by extcon_find_cable_index(). | ||
| 367 | * @cable_state: the new cable status. The default semantics is | ||
| 368 | * true: attached / false: detached. | ||
| 369 | */ | ||
| 370 | int extcon_set_cable_state_(struct extcon_dev *edev, | ||
| 371 | int index, bool cable_state) | ||
| 372 | { | ||
| 373 | u32 state; | ||
| 374 | |||
| 375 | if (index < 0 || (edev->max_supported && edev->max_supported <= index)) | ||
| 376 | return -EINVAL; | ||
| 377 | |||
| 378 | state = cable_state ? (1 << index) : 0; | ||
| 379 | return extcon_update_state(edev, 1 << index, state); | ||
| 380 | } | ||
| 381 | EXPORT_SYMBOL_GPL(extcon_set_cable_state_); | ||
| 382 | |||
| 383 | /** | ||
| 384 | * extcon_get_cable_state() - Set the status of a specific cable. | ||
| 385 | * @edev: the extcon device that has the cable. | ||
| 386 | * @cable_name: cable name. | ||
| 387 | * @cable_state: the new cable status. The default semantics is | ||
| 388 | * true: attached / false: detached. | ||
| 389 | * | ||
| 390 | * Note that this is slower than extcon_set_cable_state_. | ||
| 391 | */ | ||
| 392 | int extcon_set_cable_state(struct extcon_dev *edev, | ||
| 393 | const char *cable_name, bool cable_state) | ||
| 394 | { | ||
| 395 | return extcon_set_cable_state_(edev, extcon_find_cable_index | ||
| 396 | (edev, cable_name), cable_state); | ||
| 397 | } | ||
| 398 | EXPORT_SYMBOL_GPL(extcon_set_cable_state); | ||
| 399 | |||
| 400 | /** | ||
| 401 | * extcon_get_extcon_dev() - Get the extcon device instance from the name | ||
| 402 | * @extcon_name: The extcon name provided with extcon_dev_register() | ||
| 403 | */ | ||
| 404 | struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name) | ||
| 405 | { | ||
| 406 | struct extcon_dev *sd; | ||
| 407 | |||
| 408 | mutex_lock(&extcon_dev_list_lock); | ||
| 409 | list_for_each_entry(sd, &extcon_dev_list, entry) { | ||
| 410 | if (!strcmp(sd->name, extcon_name)) | ||
| 411 | goto out; | ||
| 412 | } | ||
| 413 | sd = NULL; | ||
| 414 | out: | ||
| 415 | mutex_unlock(&extcon_dev_list_lock); | ||
| 416 | return sd; | ||
| 417 | } | ||
| 418 | EXPORT_SYMBOL_GPL(extcon_get_extcon_dev); | ||
| 419 | |||
| 420 | static int _call_per_cable(struct notifier_block *nb, unsigned long val, | ||
| 421 | void *ptr) | ||
| 422 | { | ||
| 423 | struct extcon_specific_cable_nb *obj = container_of(nb, | ||
| 424 | struct extcon_specific_cable_nb, internal_nb); | ||
| 425 | struct extcon_dev *edev = ptr; | ||
| 426 | |||
| 427 | if ((val & (1 << obj->cable_index)) != | ||
| 428 | (edev->state & (1 << obj->cable_index))) { | ||
| 429 | bool cable_state = true; | ||
| 430 | |||
| 431 | obj->previous_value = val; | ||
| 432 | |||
| 433 | if (val & (1 << obj->cable_index)) | ||
| 434 | cable_state = false; | ||
| 435 | |||
| 436 | return obj->user_nb->notifier_call(obj->user_nb, | ||
| 437 | cable_state, ptr); | ||
| 438 | } | ||
| 439 | |||
| 440 | return NOTIFY_OK; | ||
| 441 | } | ||
| 442 | |||
| 443 | /** | ||
| 444 | * extcon_register_interest() - Register a notifier for a state change of a | ||
| 445 | * specific cable, not a entier set of cables of a | ||
| 446 | * extcon device. | ||
| 447 | * @obj: an empty extcon_specific_cable_nb object to be returned. | ||
| 448 | * @extcon_name: the name of extcon device. | ||
| 449 | * @cable_name: the target cable name. | ||
| 450 | * @nb: the notifier block to get notified. | ||
| 451 | * | ||
| 452 | * Provide an empty extcon_specific_cable_nb. extcon_register_interest() sets | ||
| 453 | * the struct for you. | ||
| 454 | * | ||
| 455 | * extcon_register_interest is a helper function for those who want to get | ||
| 456 | * notification for a single specific cable's status change. If a user wants | ||
| 457 | * to get notification for any changes of all cables of a extcon device, | ||
| 458 | * he/she should use the general extcon_register_notifier(). | ||
| 459 | * | ||
| 460 | * Note that the second parameter given to the callback of nb (val) is | ||
| 461 | * "old_state", not the current state. The current state can be retrieved | ||
| 462 | * by looking at the third pameter (edev pointer)'s state value. | ||
| 463 | */ | ||
| 464 | int extcon_register_interest(struct extcon_specific_cable_nb *obj, | ||
| 465 | const char *extcon_name, const char *cable_name, | ||
| 466 | struct notifier_block *nb) | ||
| 467 | { | ||
| 468 | if (!obj || !extcon_name || !cable_name || !nb) | ||
| 469 | return -EINVAL; | ||
| 470 | |||
| 471 | obj->edev = extcon_get_extcon_dev(extcon_name); | ||
| 472 | if (!obj->edev) | ||
| 473 | return -ENODEV; | ||
| 474 | |||
| 475 | obj->cable_index = extcon_find_cable_index(obj->edev, cable_name); | ||
| 476 | if (obj->cable_index < 0) | ||
| 477 | return -ENODEV; | ||
| 478 | |||
| 479 | obj->user_nb = nb; | ||
| 480 | |||
| 481 | obj->internal_nb.notifier_call = _call_per_cable; | ||
| 482 | |||
| 483 | return raw_notifier_chain_register(&obj->edev->nh, &obj->internal_nb); | ||
| 484 | } | ||
| 485 | |||
| 486 | /** | ||
| 487 | * extcon_unregister_interest() - Unregister the notifier registered by | ||
| 488 | * extcon_register_interest(). | ||
| 489 | * @obj: the extcon_specific_cable_nb object returned by | ||
| 490 | * extcon_register_interest(). | ||
| 491 | */ | ||
| 492 | int extcon_unregister_interest(struct extcon_specific_cable_nb *obj) | ||
| 493 | { | ||
| 494 | if (!obj) | ||
| 495 | return -EINVAL; | ||
| 496 | |||
| 497 | return raw_notifier_chain_unregister(&obj->edev->nh, &obj->internal_nb); | ||
| 498 | } | ||
| 499 | |||
| 500 | /** | ||
| 501 | * extcon_register_notifier() - Register a notifee to get notified by | ||
| 502 | * any attach status changes from the extcon. | ||
| 503 | * @edev: the extcon device. | ||
| 504 | * @nb: a notifier block to be registered. | ||
| 505 | * | ||
| 506 | * Note that the second parameter given to the callback of nb (val) is | ||
| 507 | * "old_state", not the current state. The current state can be retrieved | ||
| 508 | * by looking at the third pameter (edev pointer)'s state value. | ||
| 509 | */ | ||
| 510 | int extcon_register_notifier(struct extcon_dev *edev, | ||
| 511 | struct notifier_block *nb) | ||
| 512 | { | ||
| 513 | return raw_notifier_chain_register(&edev->nh, nb); | ||
| 514 | } | ||
| 515 | EXPORT_SYMBOL_GPL(extcon_register_notifier); | ||
| 516 | |||
| 517 | /** | ||
| 518 | * extcon_unregister_notifier() - Unregister a notifee from the extcon device. | ||
| 519 | * @edev: the extcon device. | ||
| 520 | * @nb: a registered notifier block to be unregistered. | ||
| 521 | */ | ||
| 522 | int extcon_unregister_notifier(struct extcon_dev *edev, | ||
| 523 | struct notifier_block *nb) | ||
| 524 | { | ||
| 525 | return raw_notifier_chain_unregister(&edev->nh, nb); | ||
| 526 | } | ||
| 527 | EXPORT_SYMBOL_GPL(extcon_unregister_notifier); | ||
| 528 | |||
| 529 | static struct device_attribute extcon_attrs[] = { | ||
| 530 | __ATTR(state, S_IRUGO | S_IWUSR, state_show, state_store), | ||
| 531 | __ATTR_RO(name), | ||
| 532 | __ATTR_NULL, | ||
| 533 | }; | ||
| 534 | |||
| 535 | static int create_extcon_class(void) | ||
| 536 | { | ||
| 537 | if (!extcon_class) { | ||
| 538 | extcon_class = class_create(THIS_MODULE, "extcon"); | ||
| 539 | if (IS_ERR(extcon_class)) | ||
| 540 | return PTR_ERR(extcon_class); | ||
| 541 | extcon_class->dev_attrs = extcon_attrs; | ||
| 542 | |||
| 543 | #if defined(CONFIG_ANDROID) | ||
| 544 | switch_class = class_compat_register("switch"); | ||
| 545 | if (WARN(!switch_class, "cannot allocate")) | ||
| 546 | return -ENOMEM; | ||
| 547 | #endif /* CONFIG_ANDROID */ | ||
| 548 | } | ||
| 549 | |||
| 550 | return 0; | ||
| 551 | } | ||
| 552 | |||
| 553 | static void extcon_cleanup(struct extcon_dev *edev, bool skip) | ||
| 554 | { | ||
| 555 | mutex_lock(&extcon_dev_list_lock); | ||
| 556 | list_del(&edev->entry); | ||
| 557 | mutex_unlock(&extcon_dev_list_lock); | ||
| 558 | |||
| 559 | if (!skip && get_device(edev->dev)) { | ||
| 560 | int index; | ||
| 561 | |||
| 562 | if (edev->mutually_exclusive && edev->max_supported) { | ||
| 563 | for (index = 0; edev->mutually_exclusive[index]; | ||
| 564 | index++) | ||
| 565 | kfree(edev->d_attrs_muex[index].attr.name); | ||
| 566 | kfree(edev->d_attrs_muex); | ||
| 567 | kfree(edev->attrs_muex); | ||
| 568 | } | ||
| 569 | |||
| 570 | for (index = 0; index < edev->max_supported; index++) | ||
| 571 | kfree(edev->cables[index].attr_g.name); | ||
| 572 | |||
| 573 | if (edev->max_supported) { | ||
| 574 | kfree(edev->extcon_dev_type.groups); | ||
| 575 | kfree(edev->cables); | ||
| 576 | } | ||
| 577 | |||
| 578 | device_unregister(edev->dev); | ||
| 579 | put_device(edev->dev); | ||
| 580 | } | ||
| 581 | |||
| 582 | kfree(edev->dev); | ||
| 583 | } | ||
| 584 | |||
| 585 | static void extcon_dev_release(struct device *dev) | ||
| 586 | { | ||
| 587 | struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev); | ||
| 588 | |||
| 589 | extcon_cleanup(edev, true); | ||
| 590 | } | ||
| 591 | |||
| 592 | static const char *muex_name = "mutually_exclusive"; | ||
| 593 | static void dummy_sysfs_dev_release(struct device *dev) | ||
| 594 | { | ||
| 595 | } | ||
| 596 | |||
| 597 | /** | ||
| 598 | * extcon_dev_register() - Register a new extcon device | ||
| 599 | * @edev : the new extcon device (should be allocated before calling) | ||
| 600 | * @dev : the parent device for this extcon device. | ||
| 601 | * | ||
| 602 | * Among the members of edev struct, please set the "user initializing data" | ||
| 603 | * in any case and set the "optional callbacks" if required. However, please | ||
| 604 | * do not set the values of "internal data", which are initialized by | ||
| 605 | * this function. | ||
| 606 | */ | ||
| 607 | int extcon_dev_register(struct extcon_dev *edev, struct device *dev) | ||
| 608 | { | ||
| 609 | int ret, index = 0; | ||
| 610 | |||
| 611 | if (!extcon_class) { | ||
| 612 | ret = create_extcon_class(); | ||
| 613 | if (ret < 0) | ||
| 614 | return ret; | ||
| 615 | } | ||
| 616 | |||
| 617 | if (edev->supported_cable) { | ||
| 618 | /* Get size of array */ | ||
| 619 | for (index = 0; edev->supported_cable[index]; index++) | ||
| 620 | ; | ||
| 621 | edev->max_supported = index; | ||
| 622 | } else { | ||
| 623 | edev->max_supported = 0; | ||
| 624 | } | ||
| 625 | |||
| 626 | if (index > SUPPORTED_CABLE_MAX) { | ||
| 627 | dev_err(edev->dev, "extcon: maximum number of supported cables exceeded.\n"); | ||
| 628 | return -EINVAL; | ||
| 629 | } | ||
| 630 | |||
| 631 | edev->dev = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
| 632 | if (!edev->dev) | ||
| 633 | return -ENOMEM; | ||
| 634 | edev->dev->parent = dev; | ||
| 635 | edev->dev->class = extcon_class; | ||
| 636 | edev->dev->release = extcon_dev_release; | ||
| 637 | |||
| 638 | dev_set_name(edev->dev, edev->name ? edev->name : dev_name(dev)); | ||
| 639 | |||
| 640 | if (edev->max_supported) { | ||
| 641 | char buf[10]; | ||
| 642 | char *str; | ||
| 643 | struct extcon_cable *cable; | ||
| 644 | |||
| 645 | edev->cables = kzalloc(sizeof(struct extcon_cable) * | ||
| 646 | edev->max_supported, GFP_KERNEL); | ||
| 647 | if (!edev->cables) { | ||
| 648 | ret = -ENOMEM; | ||
| 649 | goto err_sysfs_alloc; | ||
| 650 | } | ||
| 651 | for (index = 0; index < edev->max_supported; index++) { | ||
| 652 | cable = &edev->cables[index]; | ||
| 653 | |||
| 654 | snprintf(buf, 10, "cable.%d", index); | ||
| 655 | str = kzalloc(sizeof(char) * (strlen(buf) + 1), | ||
| 656 | GFP_KERNEL); | ||
| 657 | if (!str) { | ||
| 658 | for (index--; index >= 0; index--) { | ||
| 659 | cable = &edev->cables[index]; | ||
| 660 | kfree(cable->attr_g.name); | ||
| 661 | } | ||
| 662 | ret = -ENOMEM; | ||
| 663 | |||
| 664 | goto err_alloc_cables; | ||
| 665 | } | ||
| 666 | strcpy(str, buf); | ||
| 667 | |||
| 668 | cable->edev = edev; | ||
| 669 | cable->cable_index = index; | ||
| 670 | cable->attrs[0] = &cable->attr_name.attr; | ||
| 671 | cable->attrs[1] = &cable->attr_state.attr; | ||
| 672 | cable->attrs[2] = NULL; | ||
| 673 | cable->attr_g.name = str; | ||
| 674 | cable->attr_g.attrs = cable->attrs; | ||
| 675 | |||
| 676 | cable->attr_name.attr.name = "name"; | ||
| 677 | cable->attr_name.attr.mode = 0444; | ||
| 678 | cable->attr_name.show = cable_name_show; | ||
| 679 | |||
| 680 | cable->attr_state.attr.name = "state"; | ||
| 681 | cable->attr_state.attr.mode = 0644; | ||
| 682 | cable->attr_state.show = cable_state_show; | ||
| 683 | cable->attr_state.store = cable_state_store; | ||
| 684 | } | ||
| 685 | } | ||
| 686 | |||
| 687 | if (edev->max_supported && edev->mutually_exclusive) { | ||
| 688 | char buf[80]; | ||
| 689 | char *name; | ||
| 690 | |||
| 691 | /* Count the size of mutually_exclusive array */ | ||
| 692 | for (index = 0; edev->mutually_exclusive[index]; index++) | ||
| 693 | ; | ||
| 694 | |||
| 695 | edev->attrs_muex = kzalloc(sizeof(struct attribute *) * | ||
| 696 | (index + 1), GFP_KERNEL); | ||
| 697 | if (!edev->attrs_muex) { | ||
| 698 | ret = -ENOMEM; | ||
| 699 | goto err_muex; | ||
| 700 | } | ||
| 701 | |||
| 702 | edev->d_attrs_muex = kzalloc(sizeof(struct device_attribute) * | ||
| 703 | index, GFP_KERNEL); | ||
| 704 | if (!edev->d_attrs_muex) { | ||
| 705 | ret = -ENOMEM; | ||
| 706 | kfree(edev->attrs_muex); | ||
| 707 | goto err_muex; | ||
| 708 | } | ||
| 709 | |||
| 710 | for (index = 0; edev->mutually_exclusive[index]; index++) { | ||
| 711 | sprintf(buf, "0x%x", edev->mutually_exclusive[index]); | ||
| 712 | name = kzalloc(sizeof(char) * (strlen(buf) + 1), | ||
| 713 | GFP_KERNEL); | ||
| 714 | if (!name) { | ||
| 715 | for (index--; index >= 0; index--) { | ||
| 716 | kfree(edev->d_attrs_muex[index].attr. | ||
| 717 | name); | ||
| 718 | } | ||
| 719 | kfree(edev->d_attrs_muex); | ||
| 720 | kfree(edev->attrs_muex); | ||
| 721 | ret = -ENOMEM; | ||
| 722 | goto err_muex; | ||
| 723 | } | ||
| 724 | strcpy(name, buf); | ||
| 725 | edev->d_attrs_muex[index].attr.name = name; | ||
| 726 | edev->d_attrs_muex[index].attr.mode = 0000; | ||
| 727 | edev->attrs_muex[index] = &edev->d_attrs_muex[index] | ||
| 728 | .attr; | ||
| 729 | } | ||
| 730 | edev->attr_g_muex.name = muex_name; | ||
| 731 | edev->attr_g_muex.attrs = edev->attrs_muex; | ||
| 732 | |||
| 733 | } | ||
| 734 | |||
| 735 | if (edev->max_supported) { | ||
| 736 | edev->extcon_dev_type.groups = | ||
| 737 | kzalloc(sizeof(struct attribute_group *) * | ||
| 738 | (edev->max_supported + 2), GFP_KERNEL); | ||
| 739 | if (!edev->extcon_dev_type.groups) { | ||
| 740 | ret = -ENOMEM; | ||
| 741 | goto err_alloc_groups; | ||
| 742 | } | ||
| 743 | |||
| 744 | edev->extcon_dev_type.name = dev_name(edev->dev); | ||
| 745 | edev->extcon_dev_type.release = dummy_sysfs_dev_release; | ||
| 746 | |||
| 747 | for (index = 0; index < edev->max_supported; index++) | ||
| 748 | edev->extcon_dev_type.groups[index] = | ||
| 749 | &edev->cables[index].attr_g; | ||
| 750 | if (edev->mutually_exclusive) | ||
| 751 | edev->extcon_dev_type.groups[index] = | ||
| 752 | &edev->attr_g_muex; | ||
| 753 | |||
| 754 | edev->dev->type = &edev->extcon_dev_type; | ||
| 755 | } | ||
| 756 | |||
| 757 | ret = device_register(edev->dev); | ||
| 758 | if (ret) { | ||
| 759 | put_device(edev->dev); | ||
| 760 | goto err_dev; | ||
| 761 | } | ||
| 762 | #if defined(CONFIG_ANDROID) | ||
| 763 | if (switch_class) | ||
| 764 | ret = class_compat_create_link(switch_class, edev->dev, | ||
| 765 | dev); | ||
| 766 | #endif /* CONFIG_ANDROID */ | ||
| 767 | |||
| 768 | spin_lock_init(&edev->lock); | ||
| 769 | |||
| 770 | RAW_INIT_NOTIFIER_HEAD(&edev->nh); | ||
| 771 | |||
| 772 | dev_set_drvdata(edev->dev, edev); | ||
| 773 | edev->state = 0; | ||
| 774 | |||
| 775 | mutex_lock(&extcon_dev_list_lock); | ||
| 776 | list_add(&edev->entry, &extcon_dev_list); | ||
| 777 | mutex_unlock(&extcon_dev_list_lock); | ||
| 778 | |||
| 779 | return 0; | ||
| 780 | |||
| 781 | err_dev: | ||
| 782 | if (edev->max_supported) | ||
| 783 | kfree(edev->extcon_dev_type.groups); | ||
| 784 | err_alloc_groups: | ||
| 785 | if (edev->max_supported && edev->mutually_exclusive) { | ||
| 786 | for (index = 0; edev->mutually_exclusive[index]; index++) | ||
| 787 | kfree(edev->d_attrs_muex[index].attr.name); | ||
| 788 | kfree(edev->d_attrs_muex); | ||
| 789 | kfree(edev->attrs_muex); | ||
| 790 | } | ||
| 791 | err_muex: | ||
| 792 | for (index = 0; index < edev->max_supported; index++) | ||
| 793 | kfree(edev->cables[index].attr_g.name); | ||
| 794 | err_alloc_cables: | ||
| 795 | if (edev->max_supported) | ||
| 796 | kfree(edev->cables); | ||
| 797 | err_sysfs_alloc: | ||
| 798 | kfree(edev->dev); | ||
| 799 | return ret; | ||
| 800 | } | ||
| 801 | EXPORT_SYMBOL_GPL(extcon_dev_register); | ||
| 802 | |||
| 803 | /** | ||
| 804 | * extcon_dev_unregister() - Unregister the extcon device. | ||
| 805 | * @edev: the extcon device instance to be unregitered. | ||
| 806 | * | ||
| 807 | * Note that this does not call kfree(edev) because edev was not allocated | ||
| 808 | * by this class. | ||
| 809 | */ | ||
| 810 | void extcon_dev_unregister(struct extcon_dev *edev) | ||
| 811 | { | ||
| 812 | extcon_cleanup(edev, false); | ||
| 813 | } | ||
| 814 | EXPORT_SYMBOL_GPL(extcon_dev_unregister); | ||
| 815 | |||
| 816 | static int __init extcon_class_init(void) | ||
| 817 | { | ||
| 818 | return create_extcon_class(); | ||
| 819 | } | ||
| 820 | module_init(extcon_class_init); | ||
| 821 | |||
| 822 | static void __exit extcon_class_exit(void) | ||
| 823 | { | ||
| 824 | class_destroy(extcon_class); | ||
| 825 | } | ||
| 826 | module_exit(extcon_class_exit); | ||
| 827 | |||
| 828 | MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); | ||
| 829 | MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>"); | ||
| 830 | MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); | ||
| 831 | MODULE_DESCRIPTION("External connector (extcon) class driver"); | ||
| 832 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/extcon/extcon_gpio.c b/drivers/extcon/extcon_gpio.c new file mode 100644 index 000000000000..fe7a07b47336 --- /dev/null +++ b/drivers/extcon/extcon_gpio.c | |||
| @@ -0,0 +1,169 @@ | |||
| 1 | /* | ||
| 2 | * drivers/extcon/extcon_gpio.c | ||
| 3 | * | ||
| 4 | * Single-state GPIO extcon driver based on extcon class | ||
| 5 | * | ||
| 6 | * Copyright (C) 2008 Google, Inc. | ||
| 7 | * Author: Mike Lockwood <lockwood@android.com> | ||
| 8 | * | ||
| 9 | * Modified by MyungJoo Ham <myungjoo.ham@samsung.com> to support extcon | ||
| 10 | * (originally switch class is supported) | ||
| 11 | * | ||
| 12 | * This software is licensed under the terms of the GNU General Public | ||
| 13 | * License version 2, as published by the Free Software Foundation, and | ||
| 14 | * may be copied, distributed, and modified under those terms. | ||
| 15 | * | ||
| 16 | * This program is distributed in the hope that it will be useful, | ||
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | * GNU General Public License for more details. | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/module.h> | ||
| 24 | #include <linux/kernel.h> | ||
| 25 | #include <linux/init.h> | ||
| 26 | #include <linux/interrupt.h> | ||
| 27 | #include <linux/platform_device.h> | ||
| 28 | #include <linux/slab.h> | ||
| 29 | #include <linux/extcon.h> | ||
| 30 | #include <linux/workqueue.h> | ||
| 31 | #include <linux/gpio.h> | ||
| 32 | #include <linux/extcon.h> | ||
| 33 | #include <linux/extcon/extcon_gpio.h> | ||
| 34 | |||
| 35 | struct gpio_extcon_data { | ||
| 36 | struct extcon_dev edev; | ||
| 37 | unsigned gpio; | ||
| 38 | const char *state_on; | ||
| 39 | const char *state_off; | ||
| 40 | int irq; | ||
| 41 | struct delayed_work work; | ||
| 42 | unsigned long debounce_jiffies; | ||
| 43 | }; | ||
| 44 | |||
| 45 | static void gpio_extcon_work(struct work_struct *work) | ||
| 46 | { | ||
| 47 | int state; | ||
| 48 | struct gpio_extcon_data *data = | ||
| 49 | container_of(to_delayed_work(work), struct gpio_extcon_data, | ||
| 50 | work); | ||
| 51 | |||
| 52 | state = gpio_get_value(data->gpio); | ||
| 53 | extcon_set_state(&data->edev, state); | ||
| 54 | } | ||
| 55 | |||
| 56 | static irqreturn_t gpio_irq_handler(int irq, void *dev_id) | ||
| 57 | { | ||
| 58 | struct gpio_extcon_data *extcon_data = dev_id; | ||
| 59 | |||
| 60 | schedule_delayed_work(&extcon_data->work, | ||
| 61 | extcon_data->debounce_jiffies); | ||
| 62 | return IRQ_HANDLED; | ||
| 63 | } | ||
| 64 | |||
| 65 | static ssize_t extcon_gpio_print_state(struct extcon_dev *edev, char *buf) | ||
| 66 | { | ||
| 67 | struct gpio_extcon_data *extcon_data = | ||
| 68 | container_of(edev, struct gpio_extcon_data, edev); | ||
| 69 | const char *state; | ||
| 70 | if (extcon_get_state(edev)) | ||
| 71 | state = extcon_data->state_on; | ||
| 72 | else | ||
| 73 | state = extcon_data->state_off; | ||
| 74 | |||
| 75 | if (state) | ||
| 76 | return sprintf(buf, "%s\n", state); | ||
| 77 | return -EINVAL; | ||
| 78 | } | ||
| 79 | |||
| 80 | static int __devinit gpio_extcon_probe(struct platform_device *pdev) | ||
| 81 | { | ||
| 82 | struct gpio_extcon_platform_data *pdata = pdev->dev.platform_data; | ||
| 83 | struct gpio_extcon_data *extcon_data; | ||
| 84 | int ret = 0; | ||
| 85 | |||
| 86 | if (!pdata) | ||
| 87 | return -EBUSY; | ||
| 88 | if (!pdata->irq_flags) { | ||
| 89 | dev_err(&pdev->dev, "IRQ flag is not specified.\n"); | ||
| 90 | return -EINVAL; | ||
| 91 | } | ||
| 92 | |||
| 93 | extcon_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data), | ||
| 94 | GFP_KERNEL); | ||
| 95 | if (!extcon_data) | ||
| 96 | return -ENOMEM; | ||
| 97 | |||
| 98 | extcon_data->edev.name = pdata->name; | ||
| 99 | extcon_data->gpio = pdata->gpio; | ||
| 100 | extcon_data->state_on = pdata->state_on; | ||
| 101 | extcon_data->state_off = pdata->state_off; | ||
| 102 | if (pdata->state_on && pdata->state_off) | ||
| 103 | extcon_data->edev.print_state = extcon_gpio_print_state; | ||
| 104 | extcon_data->debounce_jiffies = msecs_to_jiffies(pdata->debounce); | ||
| 105 | |||
| 106 | ret = extcon_dev_register(&extcon_data->edev, &pdev->dev); | ||
| 107 | if (ret < 0) | ||
| 108 | goto err_extcon_dev_register; | ||
| 109 | |||
| 110 | ret = gpio_request_one(extcon_data->gpio, GPIOF_DIR_IN, pdev->name); | ||
| 111 | if (ret < 0) | ||
| 112 | goto err_request_gpio; | ||
| 113 | |||
| 114 | INIT_DELAYED_WORK(&extcon_data->work, gpio_extcon_work); | ||
| 115 | |||
| 116 | extcon_data->irq = gpio_to_irq(extcon_data->gpio); | ||
| 117 | if (extcon_data->irq < 0) { | ||
| 118 | ret = extcon_data->irq; | ||
| 119 | goto err_detect_irq_num_failed; | ||
| 120 | } | ||
| 121 | |||
| 122 | ret = request_any_context_irq(extcon_data->irq, gpio_irq_handler, | ||
| 123 | pdata->irq_flags, pdev->name, | ||
| 124 | extcon_data); | ||
| 125 | if (ret < 0) | ||
| 126 | goto err_request_irq; | ||
| 127 | |||
| 128 | /* Perform initial detection */ | ||
| 129 | gpio_extcon_work(&extcon_data->work.work); | ||
| 130 | |||
| 131 | return 0; | ||
| 132 | |||
| 133 | err_request_irq: | ||
| 134 | err_detect_irq_num_failed: | ||
| 135 | gpio_free(extcon_data->gpio); | ||
| 136 | err_request_gpio: | ||
| 137 | extcon_dev_unregister(&extcon_data->edev); | ||
| 138 | err_extcon_dev_register: | ||
| 139 | devm_kfree(&pdev->dev, extcon_data); | ||
| 140 | |||
| 141 | return ret; | ||
| 142 | } | ||
| 143 | |||
| 144 | static int __devexit gpio_extcon_remove(struct platform_device *pdev) | ||
| 145 | { | ||
| 146 | struct gpio_extcon_data *extcon_data = platform_get_drvdata(pdev); | ||
| 147 | |||
| 148 | cancel_delayed_work_sync(&extcon_data->work); | ||
| 149 | gpio_free(extcon_data->gpio); | ||
| 150 | extcon_dev_unregister(&extcon_data->edev); | ||
| 151 | devm_kfree(&pdev->dev, extcon_data); | ||
| 152 | |||
| 153 | return 0; | ||
| 154 | } | ||
| 155 | |||
| 156 | static struct platform_driver gpio_extcon_driver = { | ||
| 157 | .probe = gpio_extcon_probe, | ||
| 158 | .remove = __devexit_p(gpio_extcon_remove), | ||
| 159 | .driver = { | ||
| 160 | .name = "extcon-gpio", | ||
| 161 | .owner = THIS_MODULE, | ||
| 162 | }, | ||
| 163 | }; | ||
| 164 | |||
| 165 | module_platform_driver(gpio_extcon_driver); | ||
| 166 | |||
| 167 | MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); | ||
| 168 | MODULE_DESCRIPTION("GPIO extcon driver"); | ||
| 169 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index 3dd29399cef5..8950f6261bbb 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c | |||
| @@ -83,8 +83,7 @@ EXPORT_SYMBOL(devm_gpio_request); | |||
| 83 | void devm_gpio_free(struct device *dev, unsigned int gpio) | 83 | void devm_gpio_free(struct device *dev, unsigned int gpio) |
| 84 | { | 84 | { |
| 85 | 85 | ||
| 86 | WARN_ON(devres_destroy(dev, devm_gpio_release, devm_gpio_match, | 86 | WARN_ON(devres_release(dev, devm_gpio_release, devm_gpio_match, |
| 87 | &gpio)); | 87 | &gpio)); |
| 88 | gpio_free(gpio); | ||
| 89 | } | 88 | } |
| 90 | EXPORT_SYMBOL(devm_gpio_free); | 89 | EXPORT_SYMBOL(devm_gpio_free); |
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 9ffbfc575a0c..2b8b8d4558d2 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c | |||
| @@ -46,40 +46,61 @@ struct vmbus_channel_message_table_entry { | |||
| 46 | * | 46 | * |
| 47 | * @icmsghdrp is of type &struct icmsg_hdr. | 47 | * @icmsghdrp is of type &struct icmsg_hdr. |
| 48 | * @negop is of type &struct icmsg_negotiate. | 48 | * @negop is of type &struct icmsg_negotiate. |
| 49 | * Set up and fill in default negotiate response message. This response can | 49 | * Set up and fill in default negotiate response message. |
| 50 | * come from both the vmbus driver and the hv_utils driver. The current api | 50 | * |
| 51 | * will respond properly to both Windows 2008 and Windows 2008-R2 operating | 51 | * The max_fw_version specifies the maximum framework version that |
| 52 | * systems. | 52 | * we can support and max _srv_version specifies the maximum service |
| 53 | * version we can support. A special value MAX_SRV_VER can be | ||
| 54 | * specified to indicate that we can handle the maximum version | ||
| 55 | * exposed by the host. | ||
| 53 | * | 56 | * |
| 54 | * Mainly used by Hyper-V drivers. | 57 | * Mainly used by Hyper-V drivers. |
| 55 | */ | 58 | */ |
| 56 | void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp, | 59 | void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp, |
| 57 | struct icmsg_negotiate *negop, u8 *buf) | 60 | struct icmsg_negotiate *negop, u8 *buf, |
| 61 | int max_fw_version, int max_srv_version) | ||
| 58 | { | 62 | { |
| 59 | if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { | 63 | int icframe_vercnt; |
| 60 | icmsghdrp->icmsgsize = 0x10; | 64 | int icmsg_vercnt; |
| 61 | 65 | int i; | |
| 62 | negop = (struct icmsg_negotiate *)&buf[ | 66 | |
| 63 | sizeof(struct vmbuspipe_hdr) + | 67 | icmsghdrp->icmsgsize = 0x10; |
| 64 | sizeof(struct icmsg_hdr)]; | 68 | |
| 65 | 69 | negop = (struct icmsg_negotiate *)&buf[ | |
| 66 | if (negop->icframe_vercnt == 2 && | 70 | sizeof(struct vmbuspipe_hdr) + |
| 67 | negop->icversion_data[1].major == 3) { | 71 | sizeof(struct icmsg_hdr)]; |
| 68 | negop->icversion_data[0].major = 3; | 72 | |
| 69 | negop->icversion_data[0].minor = 0; | 73 | icframe_vercnt = negop->icframe_vercnt; |
| 70 | negop->icversion_data[1].major = 3; | 74 | icmsg_vercnt = negop->icmsg_vercnt; |
| 71 | negop->icversion_data[1].minor = 0; | 75 | |
| 72 | } else { | 76 | /* |
| 73 | negop->icversion_data[0].major = 1; | 77 | * Select the framework version number we will |
| 74 | negop->icversion_data[0].minor = 0; | 78 | * support. |
| 75 | negop->icversion_data[1].major = 1; | 79 | */ |
| 76 | negop->icversion_data[1].minor = 0; | 80 | |
| 77 | } | 81 | for (i = 0; i < negop->icframe_vercnt; i++) { |
| 82 | if (negop->icversion_data[i].major <= max_fw_version) | ||
| 83 | icframe_vercnt = negop->icversion_data[i].major; | ||
| 84 | } | ||
| 78 | 85 | ||
| 79 | negop->icframe_vercnt = 1; | 86 | for (i = negop->icframe_vercnt; |
| 80 | negop->icmsg_vercnt = 1; | 87 | (i < negop->icframe_vercnt + negop->icmsg_vercnt); i++) { |
| 88 | if (negop->icversion_data[i].major <= max_srv_version) | ||
| 89 | icmsg_vercnt = negop->icversion_data[i].major; | ||
| 81 | } | 90 | } |
| 91 | |||
| 92 | /* | ||
| 93 | * Respond with the maximum framework and service | ||
| 94 | * version numbers we can support. | ||
| 95 | */ | ||
| 96 | negop->icframe_vercnt = 1; | ||
| 97 | negop->icmsg_vercnt = 1; | ||
| 98 | negop->icversion_data[0].major = icframe_vercnt; | ||
| 99 | negop->icversion_data[0].minor = 0; | ||
| 100 | negop->icversion_data[1].major = icmsg_vercnt; | ||
| 101 | negop->icversion_data[1].minor = 0; | ||
| 82 | } | 102 | } |
| 103 | |||
| 83 | EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp); | 104 | EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp); |
| 84 | 105 | ||
| 85 | /* | 106 | /* |
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 15956bd48b48..86f8885aeb45 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c | |||
| @@ -252,7 +252,7 @@ void hv_cleanup(void) | |||
| 252 | * | 252 | * |
| 253 | * This involves a hypercall. | 253 | * This involves a hypercall. |
| 254 | */ | 254 | */ |
| 255 | u16 hv_post_message(union hv_connection_id connection_id, | 255 | int hv_post_message(union hv_connection_id connection_id, |
| 256 | enum hv_message_type message_type, | 256 | enum hv_message_type message_type, |
| 257 | void *payload, size_t payload_size) | 257 | void *payload, size_t payload_size) |
| 258 | { | 258 | { |
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index 6186025209ce..0012eed6d872 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c | |||
| @@ -394,7 +394,8 @@ void hv_kvp_onchannelcallback(void *context) | |||
| 394 | sizeof(struct vmbuspipe_hdr)]; | 394 | sizeof(struct vmbuspipe_hdr)]; |
| 395 | 395 | ||
| 396 | if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { | 396 | if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { |
| 397 | vmbus_prep_negotiate_resp(icmsghdrp, negop, recv_buffer); | 397 | vmbus_prep_negotiate_resp(icmsghdrp, negop, |
| 398 | recv_buffer, MAX_SRV_VER, MAX_SRV_VER); | ||
| 398 | } else { | 399 | } else { |
| 399 | kvp_msg = (struct hv_kvp_msg *)&recv_buffer[ | 400 | kvp_msg = (struct hv_kvp_msg *)&recv_buffer[ |
| 400 | sizeof(struct vmbuspipe_hdr) + | 401 | sizeof(struct vmbuspipe_hdr) + |
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c index dbb8b8eec210..d3ac6a40118b 100644 --- a/drivers/hv/hv_util.c +++ b/drivers/hv/hv_util.c | |||
| @@ -70,7 +70,8 @@ static void shutdown_onchannelcallback(void *context) | |||
| 70 | sizeof(struct vmbuspipe_hdr)]; | 70 | sizeof(struct vmbuspipe_hdr)]; |
| 71 | 71 | ||
| 72 | if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { | 72 | if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { |
| 73 | vmbus_prep_negotiate_resp(icmsghdrp, negop, shut_txf_buf); | 73 | vmbus_prep_negotiate_resp(icmsghdrp, negop, |
| 74 | shut_txf_buf, MAX_SRV_VER, MAX_SRV_VER); | ||
| 74 | } else { | 75 | } else { |
| 75 | shutdown_msg = | 76 | shutdown_msg = |
| 76 | (struct shutdown_msg_data *)&shut_txf_buf[ | 77 | (struct shutdown_msg_data *)&shut_txf_buf[ |
| @@ -195,7 +196,8 @@ static void timesync_onchannelcallback(void *context) | |||
| 195 | sizeof(struct vmbuspipe_hdr)]; | 196 | sizeof(struct vmbuspipe_hdr)]; |
| 196 | 197 | ||
| 197 | if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { | 198 | if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { |
| 198 | vmbus_prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf); | 199 | vmbus_prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf, |
| 200 | MAX_SRV_VER, MAX_SRV_VER); | ||
| 199 | } else { | 201 | } else { |
| 200 | timedatap = (struct ictimesync_data *)&time_txf_buf[ | 202 | timedatap = (struct ictimesync_data *)&time_txf_buf[ |
| 201 | sizeof(struct vmbuspipe_hdr) + | 203 | sizeof(struct vmbuspipe_hdr) + |
| @@ -234,7 +236,8 @@ static void heartbeat_onchannelcallback(void *context) | |||
| 234 | sizeof(struct vmbuspipe_hdr)]; | 236 | sizeof(struct vmbuspipe_hdr)]; |
| 235 | 237 | ||
| 236 | if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { | 238 | if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) { |
| 237 | vmbus_prep_negotiate_resp(icmsghdrp, NULL, hbeat_txf_buf); | 239 | vmbus_prep_negotiate_resp(icmsghdrp, NULL, |
| 240 | hbeat_txf_buf, MAX_SRV_VER, MAX_SRV_VER); | ||
| 238 | } else { | 241 | } else { |
| 239 | heartbeat_msg = | 242 | heartbeat_msg = |
| 240 | (struct heartbeat_msg_data *)&hbeat_txf_buf[ | 243 | (struct heartbeat_msg_data *)&hbeat_txf_buf[ |
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 699f0d8e59ed..b9426a6592ee 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h | |||
| @@ -495,7 +495,7 @@ extern int hv_init(void); | |||
| 495 | 495 | ||
| 496 | extern void hv_cleanup(void); | 496 | extern void hv_cleanup(void); |
| 497 | 497 | ||
| 498 | extern u16 hv_post_message(union hv_connection_id connection_id, | 498 | extern int hv_post_message(union hv_connection_id connection_id, |
| 499 | enum hv_message_type message_type, | 499 | enum hv_message_type message_type, |
| 500 | void *payload, size_t payload_size); | 500 | void *payload, size_t payload_size); |
| 501 | 501 | ||
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig new file mode 100644 index 000000000000..067f31174a0e --- /dev/null +++ b/drivers/memory/Kconfig | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | # | ||
| 2 | # Memory devices | ||
| 3 | # | ||
| 4 | |||
| 5 | menuconfig MEMORY | ||
| 6 | bool "Memory Controller drivers" | ||
| 7 | |||
| 8 | if MEMORY | ||
| 9 | |||
| 10 | config TI_EMIF | ||
| 11 | tristate "Texas Instruments EMIF driver" | ||
| 12 | depends on ARCH_OMAP2PLUS | ||
| 13 | select DDR | ||
| 14 | help | ||
| 15 | This driver is for the EMIF module available in Texas Instruments | ||
| 16 | SoCs. EMIF is an SDRAM controller that, based on its revision, | ||
| 17 | supports one or more of DDR2, DDR3, and LPDDR2 SDRAM protocols. | ||
| 18 | This driver takes care of only LPDDR2 memories presently. The | ||
| 19 | functions of the driver includes re-configuring AC timing | ||
| 20 | parameters and other settings during frequency, voltage and | ||
| 21 | temperature changes | ||
| 22 | |||
| 23 | config TEGRA20_MC | ||
| 24 | bool "Tegra20 Memory Controller(MC) driver" | ||
| 25 | default y | ||
| 26 | depends on ARCH_TEGRA_2x_SOC | ||
| 27 | help | ||
| 28 | This driver is for the Memory Controller(MC) module available | ||
| 29 | in Tegra20 SoCs, mainly for a address translation fault | ||
| 30 | analysis, especially for IOMMU/GART(Graphics Address | ||
| 31 | Relocation Table) module. | ||
| 32 | |||
| 33 | config TEGRA30_MC | ||
| 34 | bool "Tegra30 Memory Controller(MC) driver" | ||
| 35 | default y | ||
| 36 | depends on ARCH_TEGRA_3x_SOC | ||
| 37 | help | ||
| 38 | This driver is for the Memory Controller(MC) module available | ||
| 39 | in Tegra30 SoCs, mainly for a address translation fault | ||
| 40 | analysis, especially for IOMMU/SMMU(System Memory Management | ||
| 41 | Unit) module. | ||
| 42 | |||
| 43 | endif | ||
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile new file mode 100644 index 000000000000..42b3ce9d80fc --- /dev/null +++ b/drivers/memory/Makefile | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | # | ||
| 2 | # Makefile for memory devices | ||
| 3 | # | ||
| 4 | |||
| 5 | obj-$(CONFIG_TI_EMIF) += emif.o | ||
| 6 | obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o | ||
| 7 | obj-$(CONFIG_TEGRA30_MC) += tegra30-mc.o | ||
diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c new file mode 100644 index 000000000000..33a4396b24cb --- /dev/null +++ b/drivers/memory/emif.c | |||
| @@ -0,0 +1,1670 @@ | |||
| 1 | /* | ||
| 2 | * EMIF driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 Texas Instruments, Inc. | ||
| 5 | * | ||
| 6 | * Aneesh V <aneesh@ti.com> | ||
| 7 | * Santosh Shilimkar <santosh.shilimkar@ti.com> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | */ | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/reboot.h> | ||
| 15 | #include <linux/platform_data/emif_plat.h> | ||
| 16 | #include <linux/io.h> | ||
| 17 | #include <linux/device.h> | ||
| 18 | #include <linux/platform_device.h> | ||
| 19 | #include <linux/interrupt.h> | ||
| 20 | #include <linux/slab.h> | ||
| 21 | #include <linux/debugfs.h> | ||
| 22 | #include <linux/seq_file.h> | ||
| 23 | #include <linux/module.h> | ||
| 24 | #include <linux/list.h> | ||
| 25 | #include <linux/spinlock.h> | ||
| 26 | #include <memory/jedec_ddr.h> | ||
| 27 | #include "emif.h" | ||
| 28 | |||
| 29 | /** | ||
| 30 | * struct emif_data - Per device static data for driver's use | ||
| 31 | * @duplicate: Whether the DDR devices attached to this EMIF | ||
| 32 | * instance are exactly same as that on EMIF1. In | ||
| 33 | * this case we can save some memory and processing | ||
| 34 | * @temperature_level: Maximum temperature of LPDDR2 devices attached | ||
| 35 | * to this EMIF - read from MR4 register. If there | ||
| 36 | * are two devices attached to this EMIF, this | ||
| 37 | * value is the maximum of the two temperature | ||
| 38 | * levels. | ||
| 39 | * @node: node in the device list | ||
| 40 | * @base: base address of memory-mapped IO registers. | ||
| 41 | * @dev: device pointer. | ||
| 42 | * @addressing table with addressing information from the spec | ||
| 43 | * @regs_cache: An array of 'struct emif_regs' that stores | ||
| 44 | * calculated register values for different | ||
| 45 | * frequencies, to avoid re-calculating them on | ||
| 46 | * each DVFS transition. | ||
| 47 | * @curr_regs: The set of register values used in the last | ||
| 48 | * frequency change (i.e. corresponding to the | ||
| 49 | * frequency in effect at the moment) | ||
| 50 | * @plat_data: Pointer to saved platform data. | ||
| 51 | * @debugfs_root: dentry to the root folder for EMIF in debugfs | ||
| 52 | */ | ||
| 53 | struct emif_data { | ||
| 54 | u8 duplicate; | ||
| 55 | u8 temperature_level; | ||
| 56 | u8 lpmode; | ||
| 57 | struct list_head node; | ||
| 58 | unsigned long irq_state; | ||
| 59 | void __iomem *base; | ||
| 60 | struct device *dev; | ||
| 61 | const struct lpddr2_addressing *addressing; | ||
| 62 | struct emif_regs *regs_cache[EMIF_MAX_NUM_FREQUENCIES]; | ||
| 63 | struct emif_regs *curr_regs; | ||
| 64 | struct emif_platform_data *plat_data; | ||
| 65 | struct dentry *debugfs_root; | ||
| 66 | }; | ||
| 67 | |||
| 68 | static struct emif_data *emif1; | ||
| 69 | static spinlock_t emif_lock; | ||
| 70 | static unsigned long irq_state; | ||
| 71 | static u32 t_ck; /* DDR clock period in ps */ | ||
| 72 | static LIST_HEAD(device_list); | ||
| 73 | |||
| 74 | static void do_emif_regdump_show(struct seq_file *s, struct emif_data *emif, | ||
| 75 | struct emif_regs *regs) | ||
| 76 | { | ||
| 77 | u32 type = emif->plat_data->device_info->type; | ||
| 78 | u32 ip_rev = emif->plat_data->ip_rev; | ||
| 79 | |||
| 80 | seq_printf(s, "EMIF register cache dump for %dMHz\n", | ||
| 81 | regs->freq/1000000); | ||
| 82 | |||
| 83 | seq_printf(s, "ref_ctrl_shdw\t: 0x%08x\n", regs->ref_ctrl_shdw); | ||
| 84 | seq_printf(s, "sdram_tim1_shdw\t: 0x%08x\n", regs->sdram_tim1_shdw); | ||
| 85 | seq_printf(s, "sdram_tim2_shdw\t: 0x%08x\n", regs->sdram_tim2_shdw); | ||
| 86 | seq_printf(s, "sdram_tim3_shdw\t: 0x%08x\n", regs->sdram_tim3_shdw); | ||
| 87 | |||
| 88 | if (ip_rev == EMIF_4D) { | ||
| 89 | seq_printf(s, "read_idle_ctrl_shdw_normal\t: 0x%08x\n", | ||
| 90 | regs->read_idle_ctrl_shdw_normal); | ||
| 91 | seq_printf(s, "read_idle_ctrl_shdw_volt_ramp\t: 0x%08x\n", | ||
| 92 | regs->read_idle_ctrl_shdw_volt_ramp); | ||
| 93 | } else if (ip_rev == EMIF_4D5) { | ||
| 94 | seq_printf(s, "dll_calib_ctrl_shdw_normal\t: 0x%08x\n", | ||
| 95 | regs->dll_calib_ctrl_shdw_normal); | ||
| 96 | seq_printf(s, "dll_calib_ctrl_shdw_volt_ramp\t: 0x%08x\n", | ||
| 97 | regs->dll_calib_ctrl_shdw_volt_ramp); | ||
| 98 | } | ||
| 99 | |||
| 100 | if (type == DDR_TYPE_LPDDR2_S2 || type == DDR_TYPE_LPDDR2_S4) { | ||
| 101 | seq_printf(s, "ref_ctrl_shdw_derated\t: 0x%08x\n", | ||
| 102 | regs->ref_ctrl_shdw_derated); | ||
| 103 | seq_printf(s, "sdram_tim1_shdw_derated\t: 0x%08x\n", | ||
| 104 | regs->sdram_tim1_shdw_derated); | ||
| 105 | seq_printf(s, "sdram_tim3_shdw_derated\t: 0x%08x\n", | ||
| 106 | regs->sdram_tim3_shdw_derated); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | static int emif_regdump_show(struct seq_file *s, void *unused) | ||
| 111 | { | ||
| 112 | struct emif_data *emif = s->private; | ||
| 113 | struct emif_regs **regs_cache; | ||
| 114 | int i; | ||
| 115 | |||
| 116 | if (emif->duplicate) | ||
| 117 | regs_cache = emif1->regs_cache; | ||
| 118 | else | ||
| 119 | regs_cache = emif->regs_cache; | ||
| 120 | |||
| 121 | for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++) { | ||
| 122 | do_emif_regdump_show(s, emif, regs_cache[i]); | ||
| 123 | seq_printf(s, "\n"); | ||
| 124 | } | ||
| 125 | |||
| 126 | return 0; | ||
| 127 | } | ||
| 128 | |||
| 129 | static int emif_regdump_open(struct inode *inode, struct file *file) | ||
| 130 | { | ||
| 131 | return single_open(file, emif_regdump_show, inode->i_private); | ||
| 132 | } | ||
| 133 | |||
| 134 | static const struct file_operations emif_regdump_fops = { | ||
| 135 | .open = emif_regdump_open, | ||
| 136 | .read = seq_read, | ||
| 137 | .release = single_release, | ||
| 138 | }; | ||
| 139 | |||
| 140 | static int emif_mr4_show(struct seq_file *s, void *unused) | ||
| 141 | { | ||
| 142 | struct emif_data *emif = s->private; | ||
| 143 | |||
| 144 | seq_printf(s, "MR4=%d\n", emif->temperature_level); | ||
| 145 | return 0; | ||
| 146 | } | ||
| 147 | |||
| 148 | static int emif_mr4_open(struct inode *inode, struct file *file) | ||
| 149 | { | ||
| 150 | return single_open(file, emif_mr4_show, inode->i_private); | ||
| 151 | } | ||
| 152 | |||
| 153 | static const struct file_operations emif_mr4_fops = { | ||
| 154 | .open = emif_mr4_open, | ||
| 155 | .read = seq_read, | ||
| 156 | .release = single_release, | ||
| 157 | }; | ||
| 158 | |||
| 159 | static int __init_or_module emif_debugfs_init(struct emif_data *emif) | ||
| 160 | { | ||
| 161 | struct dentry *dentry; | ||
| 162 | int ret; | ||
| 163 | |||
| 164 | dentry = debugfs_create_dir(dev_name(emif->dev), NULL); | ||
| 165 | if (IS_ERR(dentry)) { | ||
| 166 | ret = PTR_ERR(dentry); | ||
| 167 | goto err0; | ||
| 168 | } | ||
| 169 | emif->debugfs_root = dentry; | ||
| 170 | |||
| 171 | dentry = debugfs_create_file("regcache_dump", S_IRUGO, | ||
| 172 | emif->debugfs_root, emif, &emif_regdump_fops); | ||
| 173 | if (IS_ERR(dentry)) { | ||
| 174 | ret = PTR_ERR(dentry); | ||
| 175 | goto err1; | ||
| 176 | } | ||
| 177 | |||
| 178 | dentry = debugfs_create_file("mr4", S_IRUGO, | ||
| 179 | emif->debugfs_root, emif, &emif_mr4_fops); | ||
| 180 | if (IS_ERR(dentry)) { | ||
| 181 | ret = PTR_ERR(dentry); | ||
| 182 | goto err1; | ||
| 183 | } | ||
| 184 | |||
| 185 | return 0; | ||
| 186 | err1: | ||
| 187 | debugfs_remove_recursive(emif->debugfs_root); | ||
| 188 | err0: | ||
| 189 | return ret; | ||
| 190 | } | ||
| 191 | |||
| 192 | static void __exit emif_debugfs_exit(struct emif_data *emif) | ||
| 193 | { | ||
| 194 | debugfs_remove_recursive(emif->debugfs_root); | ||
| 195 | emif->debugfs_root = NULL; | ||
| 196 | } | ||
| 197 | |||
| 198 | /* | ||
| 199 | * Calculate the period of DDR clock from frequency value | ||
| 200 | */ | ||
| 201 | static void set_ddr_clk_period(u32 freq) | ||
| 202 | { | ||
| 203 | /* Divide 10^12 by frequency to get period in ps */ | ||
| 204 | t_ck = (u32)DIV_ROUND_UP_ULL(1000000000000ull, freq); | ||
| 205 | } | ||
| 206 | |||
| 207 | /* | ||
| 208 | * Get bus width used by EMIF. Note that this may be different from the | ||
| 209 | * bus width of the DDR devices used. For instance two 16-bit DDR devices | ||
| 210 | * may be connected to a given CS of EMIF. In this case bus width as far | ||
| 211 | * as EMIF is concerned is 32, where as the DDR bus width is 16 bits. | ||
| 212 | */ | ||
| 213 | static u32 get_emif_bus_width(struct emif_data *emif) | ||
| 214 | { | ||
| 215 | u32 width; | ||
| 216 | void __iomem *base = emif->base; | ||
| 217 | |||
| 218 | width = (readl(base + EMIF_SDRAM_CONFIG) & NARROW_MODE_MASK) | ||
| 219 | >> NARROW_MODE_SHIFT; | ||
| 220 | width = width == 0 ? 32 : 16; | ||
| 221 | |||
| 222 | return width; | ||
| 223 | } | ||
| 224 | |||
| 225 | /* | ||
| 226 | * Get the CL from SDRAM_CONFIG register | ||
| 227 | */ | ||
| 228 | static u32 get_cl(struct emif_data *emif) | ||
| 229 | { | ||
| 230 | u32 cl; | ||
| 231 | void __iomem *base = emif->base; | ||
| 232 | |||
| 233 | cl = (readl(base + EMIF_SDRAM_CONFIG) & CL_MASK) >> CL_SHIFT; | ||
| 234 | |||
| 235 | return cl; | ||
| 236 | } | ||
| 237 | |||
| 238 | static void set_lpmode(struct emif_data *emif, u8 lpmode) | ||
| 239 | { | ||
| 240 | u32 temp; | ||
| 241 | void __iomem *base = emif->base; | ||
| 242 | |||
| 243 | temp = readl(base + EMIF_POWER_MANAGEMENT_CONTROL); | ||
| 244 | temp &= ~LP_MODE_MASK; | ||
| 245 | temp |= (lpmode << LP_MODE_SHIFT); | ||
| 246 | writel(temp, base + EMIF_POWER_MANAGEMENT_CONTROL); | ||
| 247 | } | ||
| 248 | |||
| 249 | static void do_freq_update(void) | ||
| 250 | { | ||
| 251 | struct emif_data *emif; | ||
| 252 | |||
| 253 | /* | ||
| 254 | * Workaround for errata i728: Disable LPMODE during FREQ_UPDATE | ||
| 255 | * | ||
| 256 | * i728 DESCRIPTION: | ||
| 257 | * The EMIF automatically puts the SDRAM into self-refresh mode | ||
| 258 | * after the EMIF has not performed accesses during | ||
| 259 | * EMIF_PWR_MGMT_CTRL[7:4] REG_SR_TIM number of DDR clock cycles | ||
| 260 | * and the EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE bit field is set | ||
| 261 | * to 0x2. If during a small window the following three events | ||
| 262 | * occur: | ||
| 263 | * - The SR_TIMING counter expires | ||
| 264 | * - And frequency change is requested | ||
| 265 | * - And OCP access is requested | ||
| 266 | * Then it causes instable clock on the DDR interface. | ||
| 267 | * | ||
| 268 | * WORKAROUND | ||
| 269 | * To avoid the occurrence of the three events, the workaround | ||
| 270 | * is to disable the self-refresh when requesting a frequency | ||
| 271 | * change. Before requesting a frequency change the software must | ||
| 272 | * program EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE to 0x0. When the | ||
| 273 | * frequency change has been done, the software can reprogram | ||
| 274 | * EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE to 0x2 | ||
| 275 | */ | ||
| 276 | list_for_each_entry(emif, &device_list, node) { | ||
| 277 | if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH) | ||
| 278 | set_lpmode(emif, EMIF_LP_MODE_DISABLE); | ||
| 279 | } | ||
| 280 | |||
| 281 | /* | ||
| 282 | * TODO: Do FREQ_UPDATE here when an API | ||
| 283 | * is available for this as part of the new | ||
| 284 | * clock framework | ||
| 285 | */ | ||
| 286 | |||
| 287 | list_for_each_entry(emif, &device_list, node) { | ||
| 288 | if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH) | ||
| 289 | set_lpmode(emif, EMIF_LP_MODE_SELF_REFRESH); | ||
| 290 | } | ||
| 291 | } | ||
| 292 | |||
| 293 | /* Find addressing table entry based on the device's type and density */ | ||
| 294 | static const struct lpddr2_addressing *get_addressing_table( | ||
| 295 | const struct ddr_device_info *device_info) | ||
| 296 | { | ||
| 297 | u32 index, type, density; | ||
| 298 | |||
| 299 | type = device_info->type; | ||
| 300 | density = device_info->density; | ||
| 301 | |||
| 302 | switch (type) { | ||
| 303 | case DDR_TYPE_LPDDR2_S4: | ||
| 304 | index = density - 1; | ||
| 305 | break; | ||
| 306 | case DDR_TYPE_LPDDR2_S2: | ||
| 307 | switch (density) { | ||
| 308 | case DDR_DENSITY_1Gb: | ||
| 309 | case DDR_DENSITY_2Gb: | ||
| 310 | index = density + 3; | ||
| 311 | break; | ||
| 312 | default: | ||
| 313 | index = density - 1; | ||
| 314 | } | ||
| 315 | break; | ||
| 316 | default: | ||
| 317 | return NULL; | ||
| 318 | } | ||
| 319 | |||
| 320 | return &lpddr2_jedec_addressing_table[index]; | ||
| 321 | } | ||
| 322 | |||
| 323 | /* | ||
| 324 | * Find the the right timing table from the array of timing | ||
| 325 | * tables of the device using DDR clock frequency | ||
| 326 | */ | ||
| 327 | static const struct lpddr2_timings *get_timings_table(struct emif_data *emif, | ||
| 328 | u32 freq) | ||
| 329 | { | ||
| 330 | u32 i, min, max, freq_nearest; | ||
| 331 | const struct lpddr2_timings *timings = NULL; | ||
| 332 | const struct lpddr2_timings *timings_arr = emif->plat_data->timings; | ||
| 333 | struct device *dev = emif->dev; | ||
| 334 | |||
| 335 | /* Start with a very high frequency - 1GHz */ | ||
| 336 | freq_nearest = 1000000000; | ||
| 337 | |||
| 338 | /* | ||
| 339 | * Find the timings table such that: | ||
| 340 | * 1. the frequency range covers the required frequency(safe) AND | ||
| 341 | * 2. the max_freq is closest to the required frequency(optimal) | ||
| 342 | */ | ||
| 343 | for (i = 0; i < emif->plat_data->timings_arr_size; i++) { | ||
| 344 | max = timings_arr[i].max_freq; | ||
| 345 | min = timings_arr[i].min_freq; | ||
| 346 | if ((freq >= min) && (freq <= max) && (max < freq_nearest)) { | ||
| 347 | freq_nearest = max; | ||
| 348 | timings = &timings_arr[i]; | ||
| 349 | } | ||
| 350 | } | ||
| 351 | |||
| 352 | if (!timings) | ||
| 353 | dev_err(dev, "%s: couldn't find timings for - %dHz\n", | ||
| 354 | __func__, freq); | ||
| 355 | |||
| 356 | dev_dbg(dev, "%s: timings table: freq %d, speed bin freq %d\n", | ||
| 357 | __func__, freq, freq_nearest); | ||
| 358 | |||
| 359 | return timings; | ||
| 360 | } | ||
| 361 | |||
| 362 | static u32 get_sdram_ref_ctrl_shdw(u32 freq, | ||
| 363 | const struct lpddr2_addressing *addressing) | ||
| 364 | { | ||
| 365 | u32 ref_ctrl_shdw = 0, val = 0, freq_khz, t_refi; | ||
| 366 | |||
| 367 | /* Scale down frequency and t_refi to avoid overflow */ | ||
| 368 | freq_khz = freq / 1000; | ||
| 369 | t_refi = addressing->tREFI_ns / 100; | ||
| 370 | |||
| 371 | /* | ||
| 372 | * refresh rate to be set is 'tREFI(in us) * freq in MHz | ||
| 373 | * division by 10000 to account for change in units | ||
| 374 | */ | ||
| 375 | val = t_refi * freq_khz / 10000; | ||
| 376 | ref_ctrl_shdw |= val << REFRESH_RATE_SHIFT; | ||
| 377 | |||
| 378 | return ref_ctrl_shdw; | ||
| 379 | } | ||
| 380 | |||
| 381 | static u32 get_sdram_tim_1_shdw(const struct lpddr2_timings *timings, | ||
| 382 | const struct lpddr2_min_tck *min_tck, | ||
| 383 | const struct lpddr2_addressing *addressing) | ||
| 384 | { | ||
| 385 | u32 tim1 = 0, val = 0; | ||
| 386 | |||
| 387 | val = max(min_tck->tWTR, DIV_ROUND_UP(timings->tWTR, t_ck)) - 1; | ||
| 388 | tim1 |= val << T_WTR_SHIFT; | ||
| 389 | |||
| 390 | if (addressing->num_banks == B8) | ||
| 391 | val = DIV_ROUND_UP(timings->tFAW, t_ck*4); | ||
| 392 | else | ||
| 393 | val = max(min_tck->tRRD, DIV_ROUND_UP(timings->tRRD, t_ck)); | ||
| 394 | tim1 |= (val - 1) << T_RRD_SHIFT; | ||
| 395 | |||
| 396 | val = DIV_ROUND_UP(timings->tRAS_min + timings->tRPab, t_ck) - 1; | ||
| 397 | tim1 |= val << T_RC_SHIFT; | ||
| 398 | |||
| 399 | val = max(min_tck->tRASmin, DIV_ROUND_UP(timings->tRAS_min, t_ck)); | ||
| 400 | tim1 |= (val - 1) << T_RAS_SHIFT; | ||
| 401 | |||
| 402 | val = max(min_tck->tWR, DIV_ROUND_UP(timings->tWR, t_ck)) - 1; | ||
| 403 | tim1 |= val << T_WR_SHIFT; | ||
| 404 | |||
| 405 | val = max(min_tck->tRCD, DIV_ROUND_UP(timings->tRCD, t_ck)) - 1; | ||
| 406 | tim1 |= val << T_RCD_SHIFT; | ||
| 407 | |||
| 408 | val = max(min_tck->tRPab, DIV_ROUND_UP(timings->tRPab, t_ck)) - 1; | ||
| 409 | tim1 |= val << T_RP_SHIFT; | ||
| 410 | |||
| 411 | return tim1; | ||
| 412 | } | ||
| 413 | |||
| 414 | static u32 get_sdram_tim_1_shdw_derated(const struct lpddr2_timings *timings, | ||
| 415 | const struct lpddr2_min_tck *min_tck, | ||
| 416 | const struct lpddr2_addressing *addressing) | ||
| 417 | { | ||
| 418 | u32 tim1 = 0, val = 0; | ||
| 419 | |||
| 420 | val = max(min_tck->tWTR, DIV_ROUND_UP(timings->tWTR, t_ck)) - 1; | ||
| 421 | tim1 = val << T_WTR_SHIFT; | ||
| 422 | |||
| 423 | /* | ||
| 424 | * tFAW is approximately 4 times tRRD. So add 1875*4 = 7500ps | ||
| 425 | * to tFAW for de-rating | ||
| 426 | */ | ||
| 427 | if (addressing->num_banks == B8) { | ||
| 428 | val = DIV_ROUND_UP(timings->tFAW + 7500, 4 * t_ck) - 1; | ||
| 429 | } else { | ||
| 430 | val = DIV_ROUND_UP(timings->tRRD + 1875, t_ck); | ||
| 431 | val = max(min_tck->tRRD, val) - 1; | ||
| 432 | } | ||
| 433 | tim1 |= val << T_RRD_SHIFT; | ||
| 434 | |||
| 435 | val = DIV_ROUND_UP(timings->tRAS_min + timings->tRPab + 1875, t_ck); | ||
| 436 | tim1 |= (val - 1) << T_RC_SHIFT; | ||
| 437 | |||
| 438 | val = DIV_ROUND_UP(timings->tRAS_min + 1875, t_ck); | ||
| 439 | val = max(min_tck->tRASmin, val) - 1; | ||
| 440 | tim1 |= val << T_RAS_SHIFT; | ||
| 441 | |||
| 442 | val = max(min_tck->tWR, DIV_ROUND_UP(timings->tWR, t_ck)) - 1; | ||
| 443 | tim1 |= val << T_WR_SHIFT; | ||
| 444 | |||
| 445 | val = max(min_tck->tRCD, DIV_ROUND_UP(timings->tRCD + 1875, t_ck)); | ||
| 446 | tim1 |= (val - 1) << T_RCD_SHIFT; | ||
| 447 | |||
| 448 | val = max(min_tck->tRPab, DIV_ROUND_UP(timings->tRPab + 1875, t_ck)); | ||
| 449 | tim1 |= (val - 1) << T_RP_SHIFT; | ||
| 450 | |||
| 451 | return tim1; | ||
| 452 | } | ||
| 453 | |||
| 454 | static u32 get_sdram_tim_2_shdw(const struct lpddr2_timings *timings, | ||
| 455 | const struct lpddr2_min_tck *min_tck, | ||
| 456 | const struct lpddr2_addressing *addressing, | ||
| 457 | u32 type) | ||
| 458 | { | ||
| 459 | u32 tim2 = 0, val = 0; | ||
| 460 | |||
| 461 | val = min_tck->tCKE - 1; | ||
| 462 | tim2 |= val << T_CKE_SHIFT; | ||
| 463 | |||
| 464 | val = max(min_tck->tRTP, DIV_ROUND_UP(timings->tRTP, t_ck)) - 1; | ||
| 465 | tim2 |= val << T_RTP_SHIFT; | ||
| 466 | |||
| 467 | /* tXSNR = tRFCab_ps + 10 ns(tRFCab_ps for LPDDR2). */ | ||
| 468 | val = DIV_ROUND_UP(addressing->tRFCab_ps + 10000, t_ck) - 1; | ||
| 469 | tim2 |= val << T_XSNR_SHIFT; | ||
| 470 | |||
| 471 | /* XSRD same as XSNR for LPDDR2 */ | ||
| 472 | tim2 |= val << T_XSRD_SHIFT; | ||
| 473 | |||
| 474 | val = max(min_tck->tXP, DIV_ROUND_UP(timings->tXP, t_ck)) - 1; | ||
| 475 | tim2 |= val << T_XP_SHIFT; | ||
| 476 | |||
| 477 | return tim2; | ||
| 478 | } | ||
| 479 | |||
| 480 | static u32 get_sdram_tim_3_shdw(const struct lpddr2_timings *timings, | ||
| 481 | const struct lpddr2_min_tck *min_tck, | ||
| 482 | const struct lpddr2_addressing *addressing, | ||
| 483 | u32 type, u32 ip_rev, u32 derated) | ||
| 484 | { | ||
| 485 | u32 tim3 = 0, val = 0, t_dqsck; | ||
| 486 | |||
| 487 | val = timings->tRAS_max_ns / addressing->tREFI_ns - 1; | ||
| 488 | val = val > 0xF ? 0xF : val; | ||
| 489 | tim3 |= val << T_RAS_MAX_SHIFT; | ||
| 490 | |||
| 491 | val = DIV_ROUND_UP(addressing->tRFCab_ps, t_ck) - 1; | ||
| 492 | tim3 |= val << T_RFC_SHIFT; | ||
| 493 | |||
| 494 | t_dqsck = (derated == EMIF_DERATED_TIMINGS) ? | ||
| 495 | timings->tDQSCK_max_derated : timings->tDQSCK_max; | ||
| 496 | if (ip_rev == EMIF_4D5) | ||
| 497 | val = DIV_ROUND_UP(t_dqsck + 1000, t_ck) - 1; | ||
| 498 | else | ||
| 499 | val = DIV_ROUND_UP(t_dqsck, t_ck) - 1; | ||
| 500 | |||
| 501 | tim3 |= val << T_TDQSCKMAX_SHIFT; | ||
| 502 | |||
| 503 | val = DIV_ROUND_UP(timings->tZQCS, t_ck) - 1; | ||
| 504 | tim3 |= val << ZQ_ZQCS_SHIFT; | ||
| 505 | |||
| 506 | val = DIV_ROUND_UP(timings->tCKESR, t_ck); | ||
| 507 | val = max(min_tck->tCKESR, val) - 1; | ||
| 508 | tim3 |= val << T_CKESR_SHIFT; | ||
| 509 | |||
| 510 | if (ip_rev == EMIF_4D5) { | ||
| 511 | tim3 |= (EMIF_T_CSTA - 1) << T_CSTA_SHIFT; | ||
| 512 | |||
| 513 | val = DIV_ROUND_UP(EMIF_T_PDLL_UL, 128) - 1; | ||
| 514 | tim3 |= val << T_PDLL_UL_SHIFT; | ||
| 515 | } | ||
| 516 | |||
| 517 | return tim3; | ||
| 518 | } | ||
| 519 | |||
| 520 | static u32 get_zq_config_reg(const struct lpddr2_addressing *addressing, | ||
| 521 | bool cs1_used, bool cal_resistors_per_cs) | ||
| 522 | { | ||
| 523 | u32 zq = 0, val = 0; | ||
| 524 | |||
| 525 | val = EMIF_ZQCS_INTERVAL_US * 1000 / addressing->tREFI_ns; | ||
| 526 | zq |= val << ZQ_REFINTERVAL_SHIFT; | ||
| 527 | |||
| 528 | val = DIV_ROUND_UP(T_ZQCL_DEFAULT_NS, T_ZQCS_DEFAULT_NS) - 1; | ||
| 529 | zq |= val << ZQ_ZQCL_MULT_SHIFT; | ||
| 530 | |||
| 531 | val = DIV_ROUND_UP(T_ZQINIT_DEFAULT_NS, T_ZQCL_DEFAULT_NS) - 1; | ||
| 532 | zq |= val << ZQ_ZQINIT_MULT_SHIFT; | ||
| 533 | |||
| 534 | zq |= ZQ_SFEXITEN_ENABLE << ZQ_SFEXITEN_SHIFT; | ||
| 535 | |||
| 536 | if (cal_resistors_per_cs) | ||
| 537 | zq |= ZQ_DUALCALEN_ENABLE << ZQ_DUALCALEN_SHIFT; | ||
| 538 | else | ||
| 539 | zq |= ZQ_DUALCALEN_DISABLE << ZQ_DUALCALEN_SHIFT; | ||
| 540 | |||
| 541 | zq |= ZQ_CS0EN_MASK; /* CS0 is used for sure */ | ||
| 542 | |||
| 543 | val = cs1_used ? 1 : 0; | ||
| 544 | zq |= val << ZQ_CS1EN_SHIFT; | ||
| 545 | |||
| 546 | return zq; | ||
| 547 | } | ||
| 548 | |||
| 549 | static u32 get_temp_alert_config(const struct lpddr2_addressing *addressing, | ||
| 550 | const struct emif_custom_configs *custom_configs, bool cs1_used, | ||
| 551 | u32 sdram_io_width, u32 emif_bus_width) | ||
| 552 | { | ||
| 553 | u32 alert = 0, interval, devcnt; | ||
| 554 | |||
| 555 | if (custom_configs && (custom_configs->mask & | ||
| 556 | EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL)) | ||
| 557 | interval = custom_configs->temp_alert_poll_interval_ms; | ||
| 558 | else | ||
| 559 | interval = TEMP_ALERT_POLL_INTERVAL_DEFAULT_MS; | ||
| 560 | |||
| 561 | interval *= 1000000; /* Convert to ns */ | ||
| 562 | interval /= addressing->tREFI_ns; /* Convert to refresh cycles */ | ||
| 563 | alert |= (interval << TA_REFINTERVAL_SHIFT); | ||
| 564 | |||
| 565 | /* | ||
| 566 | * sdram_io_width is in 'log2(x) - 1' form. Convert emif_bus_width | ||
| 567 | * also to this form and subtract to get TA_DEVCNT, which is | ||
| 568 | * in log2(x) form. | ||
| 569 | */ | ||
| 570 | emif_bus_width = __fls(emif_bus_width) - 1; | ||
| 571 | devcnt = emif_bus_width - sdram_io_width; | ||
| 572 | alert |= devcnt << TA_DEVCNT_SHIFT; | ||
| 573 | |||
| 574 | /* DEVWDT is in 'log2(x) - 3' form */ | ||
| 575 | alert |= (sdram_io_width - 2) << TA_DEVWDT_SHIFT; | ||
| 576 | |||
| 577 | alert |= 1 << TA_SFEXITEN_SHIFT; | ||
| 578 | alert |= 1 << TA_CS0EN_SHIFT; | ||
| 579 | alert |= (cs1_used ? 1 : 0) << TA_CS1EN_SHIFT; | ||
| 580 | |||
| 581 | return alert; | ||
| 582 | } | ||
| 583 | |||
| 584 | static u32 get_read_idle_ctrl_shdw(u8 volt_ramp) | ||
| 585 | { | ||
| 586 | u32 idle = 0, val = 0; | ||
| 587 | |||
| 588 | /* | ||
| 589 | * Maximum value in normal conditions and increased frequency | ||
| 590 | * when voltage is ramping | ||
| 591 | */ | ||
| 592 | if (volt_ramp) | ||
| 593 | val = READ_IDLE_INTERVAL_DVFS / t_ck / 64 - 1; | ||
| 594 | else | ||
| 595 | val = 0x1FF; | ||
| 596 | |||
| 597 | /* | ||
| 598 | * READ_IDLE_CTRL register in EMIF4D has same offset and fields | ||
| 599 | * as DLL_CALIB_CTRL in EMIF4D5, so use the same shifts | ||
| 600 | */ | ||
| 601 | idle |= val << DLL_CALIB_INTERVAL_SHIFT; | ||
| 602 | idle |= EMIF_READ_IDLE_LEN_VAL << ACK_WAIT_SHIFT; | ||
| 603 | |||
| 604 | return idle; | ||
| 605 | } | ||
| 606 | |||
| 607 | static u32 get_dll_calib_ctrl_shdw(u8 volt_ramp) | ||
| 608 | { | ||
| 609 | u32 calib = 0, val = 0; | ||
| 610 | |||
| 611 | if (volt_ramp == DDR_VOLTAGE_RAMPING) | ||
| 612 | val = DLL_CALIB_INTERVAL_DVFS / t_ck / 16 - 1; | ||
| 613 | else | ||
| 614 | val = 0; /* Disabled when voltage is stable */ | ||
| 615 | |||
| 616 | calib |= val << DLL_CALIB_INTERVAL_SHIFT; | ||
| 617 | calib |= DLL_CALIB_ACK_WAIT_VAL << ACK_WAIT_SHIFT; | ||
| 618 | |||
| 619 | return calib; | ||
| 620 | } | ||
| 621 | |||
| 622 | static u32 get_ddr_phy_ctrl_1_attilaphy_4d(const struct lpddr2_timings *timings, | ||
| 623 | u32 freq, u8 RL) | ||
| 624 | { | ||
| 625 | u32 phy = EMIF_DDR_PHY_CTRL_1_BASE_VAL_ATTILAPHY, val = 0; | ||
| 626 | |||
| 627 | val = RL + DIV_ROUND_UP(timings->tDQSCK_max, t_ck) - 1; | ||
| 628 | phy |= val << READ_LATENCY_SHIFT_4D; | ||
| 629 | |||
| 630 | if (freq <= 100000000) | ||
| 631 | val = EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS_ATTILAPHY; | ||
| 632 | else if (freq <= 200000000) | ||
| 633 | val = EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ_ATTILAPHY; | ||
| 634 | else | ||
| 635 | val = EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ_ATTILAPHY; | ||
| 636 | |||
| 637 | phy |= val << DLL_SLAVE_DLY_CTRL_SHIFT_4D; | ||
| 638 | |||
| 639 | return phy; | ||
| 640 | } | ||
| 641 | |||
| 642 | static u32 get_phy_ctrl_1_intelliphy_4d5(u32 freq, u8 cl) | ||
| 643 | { | ||
| 644 | u32 phy = EMIF_DDR_PHY_CTRL_1_BASE_VAL_INTELLIPHY, half_delay; | ||
| 645 | |||
| 646 | /* | ||
| 647 | * DLL operates at 266 MHz. If DDR frequency is near 266 MHz, | ||
| 648 | * half-delay is not needed else set half-delay | ||
| 649 | */ | ||
| 650 | if (freq >= 265000000 && freq < 267000000) | ||
| 651 | half_delay = 0; | ||
| 652 | else | ||
| 653 | half_delay = 1; | ||
| 654 | |||
| 655 | phy |= half_delay << DLL_HALF_DELAY_SHIFT_4D5; | ||
| 656 | phy |= ((cl + DIV_ROUND_UP(EMIF_PHY_TOTAL_READ_LATENCY_INTELLIPHY_PS, | ||
| 657 | t_ck) - 1) << READ_LATENCY_SHIFT_4D5); | ||
| 658 | |||
| 659 | return phy; | ||
| 660 | } | ||
| 661 | |||
| 662 | static u32 get_ext_phy_ctrl_2_intelliphy_4d5(void) | ||
| 663 | { | ||
| 664 | u32 fifo_we_slave_ratio; | ||
| 665 | |||
| 666 | fifo_we_slave_ratio = DIV_ROUND_CLOSEST( | ||
| 667 | EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256 , t_ck); | ||
| 668 | |||
| 669 | return fifo_we_slave_ratio | fifo_we_slave_ratio << 11 | | ||
| 670 | fifo_we_slave_ratio << 22; | ||
| 671 | } | ||
| 672 | |||
| 673 | static u32 get_ext_phy_ctrl_3_intelliphy_4d5(void) | ||
| 674 | { | ||
| 675 | u32 fifo_we_slave_ratio; | ||
| 676 | |||
| 677 | fifo_we_slave_ratio = DIV_ROUND_CLOSEST( | ||
| 678 | EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256 , t_ck); | ||
| 679 | |||
| 680 | return fifo_we_slave_ratio >> 10 | fifo_we_slave_ratio << 1 | | ||
| 681 | fifo_we_slave_ratio << 12 | fifo_we_slave_ratio << 23; | ||
| 682 | } | ||
| 683 | |||
| 684 | static u32 get_ext_phy_ctrl_4_intelliphy_4d5(void) | ||
| 685 | { | ||
| 686 | u32 fifo_we_slave_ratio; | ||
| 687 | |||
| 688 | fifo_we_slave_ratio = DIV_ROUND_CLOSEST( | ||
| 689 | EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256 , t_ck); | ||
| 690 | |||
| 691 | return fifo_we_slave_ratio >> 9 | fifo_we_slave_ratio << 2 | | ||
| 692 | fifo_we_slave_ratio << 13; | ||
| 693 | } | ||
| 694 | |||
| 695 | static u32 get_pwr_mgmt_ctrl(u32 freq, struct emif_data *emif, u32 ip_rev) | ||
| 696 | { | ||
| 697 | u32 pwr_mgmt_ctrl = 0, timeout; | ||
| 698 | u32 lpmode = EMIF_LP_MODE_SELF_REFRESH; | ||
| 699 | u32 timeout_perf = EMIF_LP_MODE_TIMEOUT_PERFORMANCE; | ||
| 700 | u32 timeout_pwr = EMIF_LP_MODE_TIMEOUT_POWER; | ||
| 701 | u32 freq_threshold = EMIF_LP_MODE_FREQ_THRESHOLD; | ||
| 702 | |||
| 703 | struct emif_custom_configs *cust_cfgs = emif->plat_data->custom_configs; | ||
| 704 | |||
| 705 | if (cust_cfgs && (cust_cfgs->mask & EMIF_CUSTOM_CONFIG_LPMODE)) { | ||
| 706 | lpmode = cust_cfgs->lpmode; | ||
| 707 | timeout_perf = cust_cfgs->lpmode_timeout_performance; | ||
| 708 | timeout_pwr = cust_cfgs->lpmode_timeout_power; | ||
| 709 | freq_threshold = cust_cfgs->lpmode_freq_threshold; | ||
| 710 | } | ||
| 711 | |||
| 712 | /* Timeout based on DDR frequency */ | ||
| 713 | timeout = freq >= freq_threshold ? timeout_perf : timeout_pwr; | ||
| 714 | |||
| 715 | /* The value to be set in register is "log2(timeout) - 3" */ | ||
| 716 | if (timeout < 16) { | ||
| 717 | timeout = 0; | ||
| 718 | } else { | ||
| 719 | timeout = __fls(timeout) - 3; | ||
| 720 | if (timeout & (timeout - 1)) | ||
| 721 | timeout++; | ||
| 722 | } | ||
| 723 | |||
| 724 | switch (lpmode) { | ||
| 725 | case EMIF_LP_MODE_CLOCK_STOP: | ||
| 726 | pwr_mgmt_ctrl = (timeout << CS_TIM_SHIFT) | | ||
| 727 | SR_TIM_MASK | PD_TIM_MASK; | ||
| 728 | break; | ||
| 729 | case EMIF_LP_MODE_SELF_REFRESH: | ||
| 730 | /* Workaround for errata i735 */ | ||
| 731 | if (timeout < 6) | ||
| 732 | timeout = 6; | ||
| 733 | |||
| 734 | pwr_mgmt_ctrl = (timeout << SR_TIM_SHIFT) | | ||
| 735 | CS_TIM_MASK | PD_TIM_MASK; | ||
| 736 | break; | ||
| 737 | case EMIF_LP_MODE_PWR_DN: | ||
| 738 | pwr_mgmt_ctrl = (timeout << PD_TIM_SHIFT) | | ||
| 739 | CS_TIM_MASK | SR_TIM_MASK; | ||
| 740 | break; | ||
| 741 | case EMIF_LP_MODE_DISABLE: | ||
| 742 | default: | ||
| 743 | pwr_mgmt_ctrl = CS_TIM_MASK | | ||
| 744 | PD_TIM_MASK | SR_TIM_MASK; | ||
| 745 | } | ||
| 746 | |||
| 747 | /* No CS_TIM in EMIF_4D5 */ | ||
| 748 | if (ip_rev == EMIF_4D5) | ||
| 749 | pwr_mgmt_ctrl &= ~CS_TIM_MASK; | ||
| 750 | |||
| 751 | pwr_mgmt_ctrl |= lpmode << LP_MODE_SHIFT; | ||
| 752 | |||
| 753 | return pwr_mgmt_ctrl; | ||
| 754 | } | ||
| 755 | |||
| 756 | /* | ||
| 757 | * Get the temperature level of the EMIF instance: | ||
| 758 | * Reads the MR4 register of attached SDRAM parts to find out the temperature | ||
| 759 | * level. If there are two parts attached(one on each CS), then the temperature | ||
| 760 | * level for the EMIF instance is the higher of the two temperatures. | ||
| 761 | */ | ||
| 762 | static void get_temperature_level(struct emif_data *emif) | ||
| 763 | { | ||
| 764 | u32 temp, temperature_level; | ||
| 765 | void __iomem *base; | ||
| 766 | |||
| 767 | base = emif->base; | ||
| 768 | |||
| 769 | /* Read mode register 4 */ | ||
| 770 | writel(DDR_MR4, base + EMIF_LPDDR2_MODE_REG_CONFIG); | ||
| 771 | temperature_level = readl(base + EMIF_LPDDR2_MODE_REG_DATA); | ||
| 772 | temperature_level = (temperature_level & MR4_SDRAM_REF_RATE_MASK) >> | ||
| 773 | MR4_SDRAM_REF_RATE_SHIFT; | ||
| 774 | |||
| 775 | if (emif->plat_data->device_info->cs1_used) { | ||
| 776 | writel(DDR_MR4 | CS_MASK, base + EMIF_LPDDR2_MODE_REG_CONFIG); | ||
| 777 | temp = readl(base + EMIF_LPDDR2_MODE_REG_DATA); | ||
| 778 | temp = (temp & MR4_SDRAM_REF_RATE_MASK) | ||
| 779 | >> MR4_SDRAM_REF_RATE_SHIFT; | ||
| 780 | temperature_level = max(temp, temperature_level); | ||
| 781 | } | ||
| 782 | |||
| 783 | /* treat everything less than nominal(3) in MR4 as nominal */ | ||
| 784 | if (unlikely(temperature_level < SDRAM_TEMP_NOMINAL)) | ||
| 785 | temperature_level = SDRAM_TEMP_NOMINAL; | ||
| 786 | |||
| 787 | /* if we get reserved value in MR4 persist with the existing value */ | ||
| 788 | if (likely(temperature_level != SDRAM_TEMP_RESERVED_4)) | ||
| 789 | emif->temperature_level = temperature_level; | ||
| 790 | } | ||
| 791 | |||
| 792 | /* | ||
| 793 | * Program EMIF shadow registers that are not dependent on temperature | ||
| 794 | * or voltage | ||
| 795 | */ | ||
| 796 | static void setup_registers(struct emif_data *emif, struct emif_regs *regs) | ||
| 797 | { | ||
| 798 | void __iomem *base = emif->base; | ||
| 799 | |||
| 800 | writel(regs->sdram_tim2_shdw, base + EMIF_SDRAM_TIMING_2_SHDW); | ||
| 801 | writel(regs->phy_ctrl_1_shdw, base + EMIF_DDR_PHY_CTRL_1_SHDW); | ||
| 802 | |||
| 803 | /* Settings specific for EMIF4D5 */ | ||
| 804 | if (emif->plat_data->ip_rev != EMIF_4D5) | ||
| 805 | return; | ||
| 806 | writel(regs->ext_phy_ctrl_2_shdw, base + EMIF_EXT_PHY_CTRL_2_SHDW); | ||
| 807 | writel(regs->ext_phy_ctrl_3_shdw, base + EMIF_EXT_PHY_CTRL_3_SHDW); | ||
| 808 | writel(regs->ext_phy_ctrl_4_shdw, base + EMIF_EXT_PHY_CTRL_4_SHDW); | ||
| 809 | } | ||
| 810 | |||
| 811 | /* | ||
| 812 | * When voltage ramps dll calibration and forced read idle should | ||
| 813 | * happen more often | ||
| 814 | */ | ||
| 815 | static void setup_volt_sensitive_regs(struct emif_data *emif, | ||
| 816 | struct emif_regs *regs, u32 volt_state) | ||
| 817 | { | ||
| 818 | u32 calib_ctrl; | ||
| 819 | void __iomem *base = emif->base; | ||
| 820 | |||
| 821 | /* | ||
| 822 | * EMIF_READ_IDLE_CTRL in EMIF4D refers to the same register as | ||
| 823 | * EMIF_DLL_CALIB_CTRL in EMIF4D5 and dll_calib_ctrl_shadow_* | ||
| 824 | * is an alias of the respective read_idle_ctrl_shdw_* (members of | ||
| 825 | * a union). So, the below code takes care of both cases | ||
| 826 | */ | ||
| 827 | if (volt_state == DDR_VOLTAGE_RAMPING) | ||
| 828 | calib_ctrl = regs->dll_calib_ctrl_shdw_volt_ramp; | ||
| 829 | else | ||
| 830 | calib_ctrl = regs->dll_calib_ctrl_shdw_normal; | ||
| 831 | |||
| 832 | writel(calib_ctrl, base + EMIF_DLL_CALIB_CTRL_SHDW); | ||
| 833 | } | ||
| 834 | |||
| 835 | /* | ||
| 836 | * setup_temperature_sensitive_regs() - set the timings for temperature | ||
| 837 | * sensitive registers. This happens once at initialisation time based | ||
| 838 | * on the temperature at boot time and subsequently based on the temperature | ||
| 839 | * alert interrupt. Temperature alert can happen when the temperature | ||
| 840 | * increases or drops. So this function can have the effect of either | ||
| 841 | * derating the timings or going back to nominal values. | ||
| 842 | */ | ||
| 843 | static void setup_temperature_sensitive_regs(struct emif_data *emif, | ||
| 844 | struct emif_regs *regs) | ||
| 845 | { | ||
| 846 | u32 tim1, tim3, ref_ctrl, type; | ||
| 847 | void __iomem *base = emif->base; | ||
| 848 | u32 temperature; | ||
| 849 | |||
| 850 | type = emif->plat_data->device_info->type; | ||
| 851 | |||
| 852 | tim1 = regs->sdram_tim1_shdw; | ||
| 853 | tim3 = regs->sdram_tim3_shdw; | ||
| 854 | ref_ctrl = regs->ref_ctrl_shdw; | ||
| 855 | |||
| 856 | /* No de-rating for non-lpddr2 devices */ | ||
| 857 | if (type != DDR_TYPE_LPDDR2_S2 && type != DDR_TYPE_LPDDR2_S4) | ||
| 858 | goto out; | ||
| 859 | |||
| 860 | temperature = emif->temperature_level; | ||
| 861 | if (temperature == SDRAM_TEMP_HIGH_DERATE_REFRESH) { | ||
| 862 | ref_ctrl = regs->ref_ctrl_shdw_derated; | ||
| 863 | } else if (temperature == SDRAM_TEMP_HIGH_DERATE_REFRESH_AND_TIMINGS) { | ||
| 864 | tim1 = regs->sdram_tim1_shdw_derated; | ||
| 865 | tim3 = regs->sdram_tim3_shdw_derated; | ||
| 866 | ref_ctrl = regs->ref_ctrl_shdw_derated; | ||
| 867 | } | ||
| 868 | |||
| 869 | out: | ||
| 870 | writel(tim1, base + EMIF_SDRAM_TIMING_1_SHDW); | ||
| 871 | writel(tim3, base + EMIF_SDRAM_TIMING_3_SHDW); | ||
| 872 | writel(ref_ctrl, base + EMIF_SDRAM_REFRESH_CTRL_SHDW); | ||
| 873 | } | ||
| 874 | |||
| 875 | static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif) | ||
| 876 | { | ||
| 877 | u32 old_temp_level; | ||
| 878 | irqreturn_t ret = IRQ_HANDLED; | ||
| 879 | |||
| 880 | spin_lock_irqsave(&emif_lock, irq_state); | ||
| 881 | old_temp_level = emif->temperature_level; | ||
| 882 | get_temperature_level(emif); | ||
| 883 | |||
| 884 | if (unlikely(emif->temperature_level == old_temp_level)) { | ||
| 885 | goto out; | ||
| 886 | } else if (!emif->curr_regs) { | ||
| 887 | dev_err(emif->dev, "temperature alert before registers are calculated, not de-rating timings\n"); | ||
| 888 | goto out; | ||
| 889 | } | ||
| 890 | |||
| 891 | if (emif->temperature_level < old_temp_level || | ||
| 892 | emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) { | ||
| 893 | /* | ||
| 894 | * Temperature coming down - defer handling to thread OR | ||
| 895 | * Temperature far too high - do kernel_power_off() from | ||
| 896 | * thread context | ||
| 897 | */ | ||
| 898 | ret = IRQ_WAKE_THREAD; | ||
| 899 | } else { | ||
| 900 | /* Temperature is going up - handle immediately */ | ||
| 901 | setup_temperature_sensitive_regs(emif, emif->curr_regs); | ||
| 902 | do_freq_update(); | ||
| 903 | } | ||
| 904 | |||
| 905 | out: | ||
| 906 | spin_unlock_irqrestore(&emif_lock, irq_state); | ||
| 907 | return ret; | ||
| 908 | } | ||
| 909 | |||
| 910 | static irqreturn_t emif_interrupt_handler(int irq, void *dev_id) | ||
| 911 | { | ||
| 912 | u32 interrupts; | ||
| 913 | struct emif_data *emif = dev_id; | ||
| 914 | void __iomem *base = emif->base; | ||
| 915 | struct device *dev = emif->dev; | ||
| 916 | irqreturn_t ret = IRQ_HANDLED; | ||
| 917 | |||
| 918 | /* Save the status and clear it */ | ||
| 919 | interrupts = readl(base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS); | ||
| 920 | writel(interrupts, base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS); | ||
| 921 | |||
| 922 | /* | ||
| 923 | * Handle temperature alert | ||
| 924 | * Temperature alert should be same for all ports | ||
| 925 | * So, it's enough to process it only for one of the ports | ||
| 926 | */ | ||
| 927 | if (interrupts & TA_SYS_MASK) | ||
| 928 | ret = handle_temp_alert(base, emif); | ||
| 929 | |||
| 930 | if (interrupts & ERR_SYS_MASK) | ||
| 931 | dev_err(dev, "Access error from SYS port - %x\n", interrupts); | ||
| 932 | |||
| 933 | if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE) { | ||
| 934 | /* Save the status and clear it */ | ||
| 935 | interrupts = readl(base + EMIF_LL_OCP_INTERRUPT_STATUS); | ||
| 936 | writel(interrupts, base + EMIF_LL_OCP_INTERRUPT_STATUS); | ||
| 937 | |||
| 938 | if (interrupts & ERR_LL_MASK) | ||
| 939 | dev_err(dev, "Access error from LL port - %x\n", | ||
| 940 | interrupts); | ||
| 941 | } | ||
| 942 | |||
| 943 | return ret; | ||
| 944 | } | ||
| 945 | |||
| 946 | static irqreturn_t emif_threaded_isr(int irq, void *dev_id) | ||
| 947 | { | ||
| 948 | struct emif_data *emif = dev_id; | ||
| 949 | |||
| 950 | if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) { | ||
| 951 | dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n"); | ||
| 952 | kernel_power_off(); | ||
| 953 | return IRQ_HANDLED; | ||
| 954 | } | ||
| 955 | |||
| 956 | spin_lock_irqsave(&emif_lock, irq_state); | ||
| 957 | |||
| 958 | if (emif->curr_regs) { | ||
| 959 | setup_temperature_sensitive_regs(emif, emif->curr_regs); | ||
| 960 | do_freq_update(); | ||
| 961 | } else { | ||
| 962 | dev_err(emif->dev, "temperature alert before registers are calculated, not de-rating timings\n"); | ||
| 963 | } | ||
| 964 | |||
| 965 | spin_unlock_irqrestore(&emif_lock, irq_state); | ||
| 966 | |||
| 967 | return IRQ_HANDLED; | ||
| 968 | } | ||
| 969 | |||
| 970 | static void clear_all_interrupts(struct emif_data *emif) | ||
| 971 | { | ||
| 972 | void __iomem *base = emif->base; | ||
| 973 | |||
| 974 | writel(readl(base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS), | ||
| 975 | base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS); | ||
| 976 | if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE) | ||
| 977 | writel(readl(base + EMIF_LL_OCP_INTERRUPT_STATUS), | ||
| 978 | base + EMIF_LL_OCP_INTERRUPT_STATUS); | ||
| 979 | } | ||
| 980 | |||
| 981 | static void disable_and_clear_all_interrupts(struct emif_data *emif) | ||
| 982 | { | ||
| 983 | void __iomem *base = emif->base; | ||
| 984 | |||
| 985 | /* Disable all interrupts */ | ||
| 986 | writel(readl(base + EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET), | ||
| 987 | base + EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_CLEAR); | ||
| 988 | if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE) | ||
| 989 | writel(readl(base + EMIF_LL_OCP_INTERRUPT_ENABLE_SET), | ||
| 990 | base + EMIF_LL_OCP_INTERRUPT_ENABLE_CLEAR); | ||
| 991 | |||
| 992 | /* Clear all interrupts */ | ||
| 993 | clear_all_interrupts(emif); | ||
| 994 | } | ||
| 995 | |||
| 996 | static int __init_or_module setup_interrupts(struct emif_data *emif, u32 irq) | ||
| 997 | { | ||
| 998 | u32 interrupts, type; | ||
| 999 | void __iomem *base = emif->base; | ||
| 1000 | |||
| 1001 | type = emif->plat_data->device_info->type; | ||
| 1002 | |||
| 1003 | clear_all_interrupts(emif); | ||
| 1004 | |||
| 1005 | /* Enable interrupts for SYS interface */ | ||
| 1006 | interrupts = EN_ERR_SYS_MASK; | ||
| 1007 | if (type == DDR_TYPE_LPDDR2_S2 || type == DDR_TYPE_LPDDR2_S4) | ||
| 1008 | interrupts |= EN_TA_SYS_MASK; | ||
| 1009 | writel(interrupts, base + EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET); | ||
| 1010 | |||
| 1011 | /* Enable interrupts for LL interface */ | ||
| 1012 | if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE) { | ||
| 1013 | /* TA need not be enabled for LL */ | ||
| 1014 | interrupts = EN_ERR_LL_MASK; | ||
| 1015 | writel(interrupts, base + EMIF_LL_OCP_INTERRUPT_ENABLE_SET); | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | /* setup IRQ handlers */ | ||
| 1019 | return devm_request_threaded_irq(emif->dev, irq, | ||
| 1020 | emif_interrupt_handler, | ||
| 1021 | emif_threaded_isr, | ||
| 1022 | 0, dev_name(emif->dev), | ||
| 1023 | emif); | ||
| 1024 | |||
| 1025 | } | ||
| 1026 | |||
| 1027 | static void __init_or_module emif_onetime_settings(struct emif_data *emif) | ||
| 1028 | { | ||
| 1029 | u32 pwr_mgmt_ctrl, zq, temp_alert_cfg; | ||
| 1030 | void __iomem *base = emif->base; | ||
| 1031 | const struct lpddr2_addressing *addressing; | ||
| 1032 | const struct ddr_device_info *device_info; | ||
| 1033 | |||
| 1034 | device_info = emif->plat_data->device_info; | ||
| 1035 | addressing = get_addressing_table(device_info); | ||
| 1036 | |||
| 1037 | /* | ||
| 1038 | * Init power management settings | ||
| 1039 | * We don't know the frequency yet. Use a high frequency | ||
| 1040 | * value for a conservative timeout setting | ||
| 1041 | */ | ||
| 1042 | pwr_mgmt_ctrl = get_pwr_mgmt_ctrl(1000000000, emif, | ||
| 1043 | emif->plat_data->ip_rev); | ||
| 1044 | emif->lpmode = (pwr_mgmt_ctrl & LP_MODE_MASK) >> LP_MODE_SHIFT; | ||
| 1045 | writel(pwr_mgmt_ctrl, base + EMIF_POWER_MANAGEMENT_CONTROL); | ||
| 1046 | |||
| 1047 | /* Init ZQ calibration settings */ | ||
| 1048 | zq = get_zq_config_reg(addressing, device_info->cs1_used, | ||
| 1049 | device_info->cal_resistors_per_cs); | ||
| 1050 | writel(zq, base + EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG); | ||
| 1051 | |||
| 1052 | /* Check temperature level temperature level*/ | ||
| 1053 | get_temperature_level(emif); | ||
| 1054 | if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) | ||
| 1055 | dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n"); | ||
| 1056 | |||
| 1057 | /* Init temperature polling */ | ||
| 1058 | temp_alert_cfg = get_temp_alert_config(addressing, | ||
| 1059 | emif->plat_data->custom_configs, device_info->cs1_used, | ||
| 1060 | device_info->io_width, get_emif_bus_width(emif)); | ||
| 1061 | writel(temp_alert_cfg, base + EMIF_TEMPERATURE_ALERT_CONFIG); | ||
| 1062 | |||
| 1063 | /* | ||
| 1064 | * Program external PHY control registers that are not frequency | ||
| 1065 | * dependent | ||
| 1066 | */ | ||
| 1067 | if (emif->plat_data->phy_type != EMIF_PHY_TYPE_INTELLIPHY) | ||
| 1068 | return; | ||
| 1069 | writel(EMIF_EXT_PHY_CTRL_1_VAL, base + EMIF_EXT_PHY_CTRL_1_SHDW); | ||
| 1070 | writel(EMIF_EXT_PHY_CTRL_5_VAL, base + EMIF_EXT_PHY_CTRL_5_SHDW); | ||
| 1071 | writel(EMIF_EXT_PHY_CTRL_6_VAL, base + EMIF_EXT_PHY_CTRL_6_SHDW); | ||
| 1072 | writel(EMIF_EXT_PHY_CTRL_7_VAL, base + EMIF_EXT_PHY_CTRL_7_SHDW); | ||
| 1073 | writel(EMIF_EXT_PHY_CTRL_8_VAL, base + EMIF_EXT_PHY_CTRL_8_SHDW); | ||
| 1074 | writel(EMIF_EXT_PHY_CTRL_9_VAL, base + EMIF_EXT_PHY_CTRL_9_SHDW); | ||
| 1075 | writel(EMIF_EXT_PHY_CTRL_10_VAL, base + EMIF_EXT_PHY_CTRL_10_SHDW); | ||
| 1076 | writel(EMIF_EXT_PHY_CTRL_11_VAL, base + EMIF_EXT_PHY_CTRL_11_SHDW); | ||
| 1077 | writel(EMIF_EXT_PHY_CTRL_12_VAL, base + EMIF_EXT_PHY_CTRL_12_SHDW); | ||
| 1078 | writel(EMIF_EXT_PHY_CTRL_13_VAL, base + EMIF_EXT_PHY_CTRL_13_SHDW); | ||
| 1079 | writel(EMIF_EXT_PHY_CTRL_14_VAL, base + EMIF_EXT_PHY_CTRL_14_SHDW); | ||
| 1080 | writel(EMIF_EXT_PHY_CTRL_15_VAL, base + EMIF_EXT_PHY_CTRL_15_SHDW); | ||
| 1081 | writel(EMIF_EXT_PHY_CTRL_16_VAL, base + EMIF_EXT_PHY_CTRL_16_SHDW); | ||
| 1082 | writel(EMIF_EXT_PHY_CTRL_17_VAL, base + EMIF_EXT_PHY_CTRL_17_SHDW); | ||
| 1083 | writel(EMIF_EXT_PHY_CTRL_18_VAL, base + EMIF_EXT_PHY_CTRL_18_SHDW); | ||
| 1084 | writel(EMIF_EXT_PHY_CTRL_19_VAL, base + EMIF_EXT_PHY_CTRL_19_SHDW); | ||
| 1085 | writel(EMIF_EXT_PHY_CTRL_20_VAL, base + EMIF_EXT_PHY_CTRL_20_SHDW); | ||
| 1086 | writel(EMIF_EXT_PHY_CTRL_21_VAL, base + EMIF_EXT_PHY_CTRL_21_SHDW); | ||
| 1087 | writel(EMIF_EXT_PHY_CTRL_22_VAL, base + EMIF_EXT_PHY_CTRL_22_SHDW); | ||
| 1088 | writel(EMIF_EXT_PHY_CTRL_23_VAL, base + EMIF_EXT_PHY_CTRL_23_SHDW); | ||
| 1089 | writel(EMIF_EXT_PHY_CTRL_24_VAL, base + EMIF_EXT_PHY_CTRL_24_SHDW); | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | static void get_default_timings(struct emif_data *emif) | ||
| 1093 | { | ||
| 1094 | struct emif_platform_data *pd = emif->plat_data; | ||
| 1095 | |||
| 1096 | pd->timings = lpddr2_jedec_timings; | ||
| 1097 | pd->timings_arr_size = ARRAY_SIZE(lpddr2_jedec_timings); | ||
| 1098 | |||
| 1099 | dev_warn(emif->dev, "%s: using default timings\n", __func__); | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | static int is_dev_data_valid(u32 type, u32 density, u32 io_width, u32 phy_type, | ||
| 1103 | u32 ip_rev, struct device *dev) | ||
| 1104 | { | ||
| 1105 | int valid; | ||
| 1106 | |||
| 1107 | valid = (type == DDR_TYPE_LPDDR2_S4 || | ||
| 1108 | type == DDR_TYPE_LPDDR2_S2) | ||
| 1109 | && (density >= DDR_DENSITY_64Mb | ||
| 1110 | && density <= DDR_DENSITY_8Gb) | ||
| 1111 | && (io_width >= DDR_IO_WIDTH_8 | ||
| 1112 | && io_width <= DDR_IO_WIDTH_32); | ||
| 1113 | |||
| 1114 | /* Combinations of EMIF and PHY revisions that we support today */ | ||
| 1115 | switch (ip_rev) { | ||
| 1116 | case EMIF_4D: | ||
| 1117 | valid = valid && (phy_type == EMIF_PHY_TYPE_ATTILAPHY); | ||
| 1118 | break; | ||
| 1119 | case EMIF_4D5: | ||
| 1120 | valid = valid && (phy_type == EMIF_PHY_TYPE_INTELLIPHY); | ||
| 1121 | break; | ||
| 1122 | default: | ||
| 1123 | valid = 0; | ||
| 1124 | } | ||
| 1125 | |||
| 1126 | if (!valid) | ||
| 1127 | dev_err(dev, "%s: invalid DDR details\n", __func__); | ||
| 1128 | return valid; | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | static int is_custom_config_valid(struct emif_custom_configs *cust_cfgs, | ||
| 1132 | struct device *dev) | ||
| 1133 | { | ||
| 1134 | int valid = 1; | ||
| 1135 | |||
| 1136 | if ((cust_cfgs->mask & EMIF_CUSTOM_CONFIG_LPMODE) && | ||
| 1137 | (cust_cfgs->lpmode != EMIF_LP_MODE_DISABLE)) | ||
| 1138 | valid = cust_cfgs->lpmode_freq_threshold && | ||
| 1139 | cust_cfgs->lpmode_timeout_performance && | ||
| 1140 | cust_cfgs->lpmode_timeout_power; | ||
| 1141 | |||
| 1142 | if (cust_cfgs->mask & EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL) | ||
| 1143 | valid = valid && cust_cfgs->temp_alert_poll_interval_ms; | ||
| 1144 | |||
| 1145 | if (!valid) | ||
| 1146 | dev_warn(dev, "%s: invalid custom configs\n", __func__); | ||
| 1147 | |||
| 1148 | return valid; | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | static struct emif_data *__init_or_module get_device_details( | ||
| 1152 | struct platform_device *pdev) | ||
| 1153 | { | ||
| 1154 | u32 size; | ||
| 1155 | struct emif_data *emif = NULL; | ||
| 1156 | struct ddr_device_info *dev_info; | ||
| 1157 | struct emif_custom_configs *cust_cfgs; | ||
| 1158 | struct emif_platform_data *pd; | ||
| 1159 | struct device *dev; | ||
| 1160 | void *temp; | ||
| 1161 | |||
| 1162 | pd = pdev->dev.platform_data; | ||
| 1163 | dev = &pdev->dev; | ||
| 1164 | |||
| 1165 | if (!(pd && pd->device_info && is_dev_data_valid(pd->device_info->type, | ||
| 1166 | pd->device_info->density, pd->device_info->io_width, | ||
| 1167 | pd->phy_type, pd->ip_rev, dev))) { | ||
| 1168 | dev_err(dev, "%s: invalid device data\n", __func__); | ||
| 1169 | goto error; | ||
| 1170 | } | ||
| 1171 | |||
| 1172 | emif = devm_kzalloc(dev, sizeof(*emif), GFP_KERNEL); | ||
| 1173 | temp = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); | ||
| 1174 | dev_info = devm_kzalloc(dev, sizeof(*dev_info), GFP_KERNEL); | ||
| 1175 | |||
| 1176 | if (!emif || !pd || !dev_info) { | ||
| 1177 | dev_err(dev, "%s:%d: allocation error\n", __func__, __LINE__); | ||
| 1178 | goto error; | ||
| 1179 | } | ||
| 1180 | |||
| 1181 | memcpy(temp, pd, sizeof(*pd)); | ||
| 1182 | pd = temp; | ||
| 1183 | memcpy(dev_info, pd->device_info, sizeof(*dev_info)); | ||
| 1184 | |||
| 1185 | pd->device_info = dev_info; | ||
| 1186 | emif->plat_data = pd; | ||
| 1187 | emif->dev = dev; | ||
| 1188 | emif->temperature_level = SDRAM_TEMP_NOMINAL; | ||
| 1189 | |||
| 1190 | /* | ||
| 1191 | * For EMIF instances other than EMIF1 see if the devices connected | ||
| 1192 | * are exactly same as on EMIF1(which is typically the case). If so, | ||
| 1193 | * mark it as a duplicate of EMIF1 and skip copying timings data. | ||
| 1194 | * This will save some memory and some computation later. | ||
| 1195 | */ | ||
| 1196 | emif->duplicate = emif1 && (memcmp(dev_info, | ||
| 1197 | emif1->plat_data->device_info, | ||
| 1198 | sizeof(struct ddr_device_info)) == 0); | ||
| 1199 | |||
| 1200 | if (emif->duplicate) { | ||
| 1201 | pd->timings = NULL; | ||
| 1202 | pd->min_tck = NULL; | ||
| 1203 | goto out; | ||
| 1204 | } else if (emif1) { | ||
| 1205 | dev_warn(emif->dev, "%s: Non-symmetric DDR geometry\n", | ||
| 1206 | __func__); | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | /* | ||
| 1210 | * Copy custom configs - ignore allocation error, if any, as | ||
| 1211 | * custom_configs is not very critical | ||
| 1212 | */ | ||
| 1213 | cust_cfgs = pd->custom_configs; | ||
| 1214 | if (cust_cfgs && is_custom_config_valid(cust_cfgs, dev)) { | ||
| 1215 | temp = devm_kzalloc(dev, sizeof(*cust_cfgs), GFP_KERNEL); | ||
| 1216 | if (temp) | ||
| 1217 | memcpy(temp, cust_cfgs, sizeof(*cust_cfgs)); | ||
| 1218 | else | ||
| 1219 | dev_warn(dev, "%s:%d: allocation error\n", __func__, | ||
| 1220 | __LINE__); | ||
| 1221 | pd->custom_configs = temp; | ||
| 1222 | } | ||
| 1223 | |||
| 1224 | /* | ||
| 1225 | * Copy timings and min-tck values from platform data. If it is not | ||
| 1226 | * available or if memory allocation fails, use JEDEC defaults | ||
| 1227 | */ | ||
| 1228 | size = sizeof(struct lpddr2_timings) * pd->timings_arr_size; | ||
| 1229 | if (pd->timings) { | ||
| 1230 | temp = devm_kzalloc(dev, size, GFP_KERNEL); | ||
| 1231 | if (temp) { | ||
| 1232 | memcpy(temp, pd->timings, sizeof(*pd->timings)); | ||
| 1233 | pd->timings = temp; | ||
| 1234 | } else { | ||
| 1235 | dev_warn(dev, "%s:%d: allocation error\n", __func__, | ||
| 1236 | __LINE__); | ||
| 1237 | get_default_timings(emif); | ||
| 1238 | } | ||
| 1239 | } else { | ||
| 1240 | get_default_timings(emif); | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | if (pd->min_tck) { | ||
| 1244 | temp = devm_kzalloc(dev, sizeof(*pd->min_tck), GFP_KERNEL); | ||
| 1245 | if (temp) { | ||
| 1246 | memcpy(temp, pd->min_tck, sizeof(*pd->min_tck)); | ||
| 1247 | pd->min_tck = temp; | ||
| 1248 | } else { | ||
| 1249 | dev_warn(dev, "%s:%d: allocation error\n", __func__, | ||
| 1250 | __LINE__); | ||
| 1251 | pd->min_tck = &lpddr2_jedec_min_tck; | ||
| 1252 | } | ||
| 1253 | } else { | ||
| 1254 | pd->min_tck = &lpddr2_jedec_min_tck; | ||
| 1255 | } | ||
| 1256 | |||
| 1257 | out: | ||
| 1258 | return emif; | ||
| 1259 | |||
| 1260 | error: | ||
| 1261 | return NULL; | ||
| 1262 | } | ||
| 1263 | |||
| 1264 | static int __init_or_module emif_probe(struct platform_device *pdev) | ||
| 1265 | { | ||
| 1266 | struct emif_data *emif; | ||
| 1267 | struct resource *res; | ||
| 1268 | int irq; | ||
| 1269 | |||
| 1270 | emif = get_device_details(pdev); | ||
| 1271 | if (!emif) { | ||
| 1272 | pr_err("%s: error getting device data\n", __func__); | ||
| 1273 | goto error; | ||
| 1274 | } | ||
| 1275 | |||
| 1276 | list_add(&emif->node, &device_list); | ||
| 1277 | emif->addressing = get_addressing_table(emif->plat_data->device_info); | ||
| 1278 | |||
| 1279 | /* Save pointers to each other in emif and device structures */ | ||
| 1280 | emif->dev = &pdev->dev; | ||
| 1281 | platform_set_drvdata(pdev, emif); | ||
| 1282 | |||
| 1283 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 1284 | if (!res) { | ||
| 1285 | dev_err(emif->dev, "%s: error getting memory resource\n", | ||
| 1286 | __func__); | ||
| 1287 | goto error; | ||
| 1288 | } | ||
| 1289 | |||
| 1290 | emif->base = devm_request_and_ioremap(emif->dev, res); | ||
| 1291 | if (!emif->base) { | ||
| 1292 | dev_err(emif->dev, "%s: devm_request_and_ioremap() failed\n", | ||
| 1293 | __func__); | ||
| 1294 | goto error; | ||
| 1295 | } | ||
| 1296 | |||
| 1297 | irq = platform_get_irq(pdev, 0); | ||
| 1298 | if (irq < 0) { | ||
| 1299 | dev_err(emif->dev, "%s: error getting IRQ resource - %d\n", | ||
| 1300 | __func__, irq); | ||
| 1301 | goto error; | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | emif_onetime_settings(emif); | ||
| 1305 | emif_debugfs_init(emif); | ||
| 1306 | disable_and_clear_all_interrupts(emif); | ||
| 1307 | setup_interrupts(emif, irq); | ||
| 1308 | |||
| 1309 | /* One-time actions taken on probing the first device */ | ||
| 1310 | if (!emif1) { | ||
| 1311 | emif1 = emif; | ||
| 1312 | spin_lock_init(&emif_lock); | ||
| 1313 | |||
| 1314 | /* | ||
| 1315 | * TODO: register notifiers for frequency and voltage | ||
| 1316 | * change here once the respective frameworks are | ||
| 1317 | * available | ||
| 1318 | */ | ||
| 1319 | } | ||
| 1320 | |||
| 1321 | dev_info(&pdev->dev, "%s: device configured with addr = %p and IRQ%d\n", | ||
| 1322 | __func__, emif->base, irq); | ||
| 1323 | |||
| 1324 | return 0; | ||
| 1325 | error: | ||
| 1326 | return -ENODEV; | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | static int __exit emif_remove(struct platform_device *pdev) | ||
| 1330 | { | ||
| 1331 | struct emif_data *emif = platform_get_drvdata(pdev); | ||
| 1332 | |||
| 1333 | emif_debugfs_exit(emif); | ||
| 1334 | |||
| 1335 | return 0; | ||
| 1336 | } | ||
| 1337 | |||
| 1338 | static void emif_shutdown(struct platform_device *pdev) | ||
| 1339 | { | ||
| 1340 | struct emif_data *emif = platform_get_drvdata(pdev); | ||
| 1341 | |||
| 1342 | disable_and_clear_all_interrupts(emif); | ||
| 1343 | } | ||
| 1344 | |||
| 1345 | static int get_emif_reg_values(struct emif_data *emif, u32 freq, | ||
| 1346 | struct emif_regs *regs) | ||
| 1347 | { | ||
| 1348 | u32 cs1_used, ip_rev, phy_type; | ||
| 1349 | u32 cl, type; | ||
| 1350 | const struct lpddr2_timings *timings; | ||
| 1351 | const struct lpddr2_min_tck *min_tck; | ||
| 1352 | const struct ddr_device_info *device_info; | ||
| 1353 | const struct lpddr2_addressing *addressing; | ||
| 1354 | struct emif_data *emif_for_calc; | ||
| 1355 | struct device *dev; | ||
| 1356 | const struct emif_custom_configs *custom_configs; | ||
| 1357 | |||
| 1358 | dev = emif->dev; | ||
| 1359 | /* | ||
| 1360 | * If the devices on this EMIF instance is duplicate of EMIF1, | ||
| 1361 | * use EMIF1 details for the calculation | ||
| 1362 | */ | ||
| 1363 | emif_for_calc = emif->duplicate ? emif1 : emif; | ||
| 1364 | timings = get_timings_table(emif_for_calc, freq); | ||
| 1365 | addressing = emif_for_calc->addressing; | ||
| 1366 | if (!timings || !addressing) { | ||
| 1367 | dev_err(dev, "%s: not enough data available for %dHz", | ||
| 1368 | __func__, freq); | ||
| 1369 | return -1; | ||
| 1370 | } | ||
| 1371 | |||
| 1372 | device_info = emif_for_calc->plat_data->device_info; | ||
| 1373 | type = device_info->type; | ||
| 1374 | cs1_used = device_info->cs1_used; | ||
| 1375 | ip_rev = emif_for_calc->plat_data->ip_rev; | ||
| 1376 | phy_type = emif_for_calc->plat_data->phy_type; | ||
| 1377 | |||
| 1378 | min_tck = emif_for_calc->plat_data->min_tck; | ||
| 1379 | custom_configs = emif_for_calc->plat_data->custom_configs; | ||
| 1380 | |||
| 1381 | set_ddr_clk_period(freq); | ||
| 1382 | |||
| 1383 | regs->ref_ctrl_shdw = get_sdram_ref_ctrl_shdw(freq, addressing); | ||
| 1384 | regs->sdram_tim1_shdw = get_sdram_tim_1_shdw(timings, min_tck, | ||
| 1385 | addressing); | ||
| 1386 | regs->sdram_tim2_shdw = get_sdram_tim_2_shdw(timings, min_tck, | ||
| 1387 | addressing, type); | ||
| 1388 | regs->sdram_tim3_shdw = get_sdram_tim_3_shdw(timings, min_tck, | ||
| 1389 | addressing, type, ip_rev, EMIF_NORMAL_TIMINGS); | ||
| 1390 | |||
| 1391 | cl = get_cl(emif); | ||
| 1392 | |||
| 1393 | if (phy_type == EMIF_PHY_TYPE_ATTILAPHY && ip_rev == EMIF_4D) { | ||
| 1394 | regs->phy_ctrl_1_shdw = get_ddr_phy_ctrl_1_attilaphy_4d( | ||
| 1395 | timings, freq, cl); | ||
| 1396 | } else if (phy_type == EMIF_PHY_TYPE_INTELLIPHY && ip_rev == EMIF_4D5) { | ||
| 1397 | regs->phy_ctrl_1_shdw = get_phy_ctrl_1_intelliphy_4d5(freq, cl); | ||
| 1398 | regs->ext_phy_ctrl_2_shdw = get_ext_phy_ctrl_2_intelliphy_4d5(); | ||
| 1399 | regs->ext_phy_ctrl_3_shdw = get_ext_phy_ctrl_3_intelliphy_4d5(); | ||
| 1400 | regs->ext_phy_ctrl_4_shdw = get_ext_phy_ctrl_4_intelliphy_4d5(); | ||
| 1401 | } else { | ||
| 1402 | return -1; | ||
| 1403 | } | ||
| 1404 | |||
| 1405 | /* Only timeout values in pwr_mgmt_ctrl_shdw register */ | ||
| 1406 | regs->pwr_mgmt_ctrl_shdw = | ||
| 1407 | get_pwr_mgmt_ctrl(freq, emif_for_calc, ip_rev) & | ||
| 1408 | (CS_TIM_MASK | SR_TIM_MASK | PD_TIM_MASK); | ||
| 1409 | |||
| 1410 | if (ip_rev & EMIF_4D) { | ||
| 1411 | regs->read_idle_ctrl_shdw_normal = | ||
| 1412 | get_read_idle_ctrl_shdw(DDR_VOLTAGE_STABLE); | ||
| 1413 | |||
| 1414 | regs->read_idle_ctrl_shdw_volt_ramp = | ||
| 1415 | get_read_idle_ctrl_shdw(DDR_VOLTAGE_RAMPING); | ||
| 1416 | } else if (ip_rev & EMIF_4D5) { | ||
| 1417 | regs->dll_calib_ctrl_shdw_normal = | ||
| 1418 | get_dll_calib_ctrl_shdw(DDR_VOLTAGE_STABLE); | ||
| 1419 | |||
| 1420 | regs->dll_calib_ctrl_shdw_volt_ramp = | ||
| 1421 | get_dll_calib_ctrl_shdw(DDR_VOLTAGE_RAMPING); | ||
| 1422 | } | ||
| 1423 | |||
| 1424 | if (type == DDR_TYPE_LPDDR2_S2 || type == DDR_TYPE_LPDDR2_S4) { | ||
| 1425 | regs->ref_ctrl_shdw_derated = get_sdram_ref_ctrl_shdw(freq / 4, | ||
| 1426 | addressing); | ||
| 1427 | |||
| 1428 | regs->sdram_tim1_shdw_derated = | ||
| 1429 | get_sdram_tim_1_shdw_derated(timings, min_tck, | ||
| 1430 | addressing); | ||
| 1431 | |||
| 1432 | regs->sdram_tim3_shdw_derated = get_sdram_tim_3_shdw(timings, | ||
| 1433 | min_tck, addressing, type, ip_rev, | ||
| 1434 | EMIF_DERATED_TIMINGS); | ||
| 1435 | } | ||
| 1436 | |||
| 1437 | regs->freq = freq; | ||
| 1438 | |||
| 1439 | return 0; | ||
| 1440 | } | ||
| 1441 | |||
| 1442 | /* | ||
| 1443 | * get_regs() - gets the cached emif_regs structure for a given EMIF instance | ||
| 1444 | * given frequency(freq): | ||
| 1445 | * | ||
| 1446 | * As an optimisation, every EMIF instance other than EMIF1 shares the | ||
| 1447 | * register cache with EMIF1 if the devices connected on this instance | ||
| 1448 | * are same as that on EMIF1(indicated by the duplicate flag) | ||
| 1449 | * | ||
| 1450 | * If we do not have an entry corresponding to the frequency given, we | ||
| 1451 | * allocate a new entry and calculate the values | ||
| 1452 | * | ||
| 1453 | * Upon finding the right reg dump, save it in curr_regs. It can be | ||
| 1454 | * directly used for thermal de-rating and voltage ramping changes. | ||
| 1455 | */ | ||
| 1456 | static struct emif_regs *get_regs(struct emif_data *emif, u32 freq) | ||
| 1457 | { | ||
| 1458 | int i; | ||
| 1459 | struct emif_regs **regs_cache; | ||
| 1460 | struct emif_regs *regs = NULL; | ||
| 1461 | struct device *dev; | ||
| 1462 | |||
| 1463 | dev = emif->dev; | ||
| 1464 | if (emif->curr_regs && emif->curr_regs->freq == freq) { | ||
| 1465 | dev_dbg(dev, "%s: using curr_regs - %u Hz", __func__, freq); | ||
| 1466 | return emif->curr_regs; | ||
| 1467 | } | ||
| 1468 | |||
| 1469 | if (emif->duplicate) | ||
| 1470 | regs_cache = emif1->regs_cache; | ||
| 1471 | else | ||
| 1472 | regs_cache = emif->regs_cache; | ||
| 1473 | |||
| 1474 | for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++) { | ||
| 1475 | if (regs_cache[i]->freq == freq) { | ||
| 1476 | regs = regs_cache[i]; | ||
| 1477 | dev_dbg(dev, | ||
| 1478 | "%s: reg dump found in reg cache for %u Hz\n", | ||
| 1479 | __func__, freq); | ||
| 1480 | break; | ||
| 1481 | } | ||
| 1482 | } | ||
| 1483 | |||
| 1484 | /* | ||
| 1485 | * If we don't have an entry for this frequency in the cache create one | ||
| 1486 | * and calculate the values | ||
| 1487 | */ | ||
| 1488 | if (!regs) { | ||
| 1489 | regs = devm_kzalloc(emif->dev, sizeof(*regs), GFP_ATOMIC); | ||
| 1490 | if (!regs) | ||
| 1491 | return NULL; | ||
| 1492 | |||
| 1493 | if (get_emif_reg_values(emif, freq, regs)) { | ||
| 1494 | devm_kfree(emif->dev, regs); | ||
| 1495 | return NULL; | ||
| 1496 | } | ||
| 1497 | |||
| 1498 | /* | ||
| 1499 | * Now look for an un-used entry in the cache and save the | ||
| 1500 | * newly created struct. If there are no free entries | ||
| 1501 | * over-write the last entry | ||
| 1502 | */ | ||
| 1503 | for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++) | ||
| 1504 | ; | ||
| 1505 | |||
| 1506 | if (i >= EMIF_MAX_NUM_FREQUENCIES) { | ||
| 1507 | dev_warn(dev, "%s: regs_cache full - reusing a slot!!\n", | ||
| 1508 | __func__); | ||
| 1509 | i = EMIF_MAX_NUM_FREQUENCIES - 1; | ||
| 1510 | devm_kfree(emif->dev, regs_cache[i]); | ||
| 1511 | } | ||
| 1512 | regs_cache[i] = regs; | ||
| 1513 | } | ||
| 1514 | |||
| 1515 | return regs; | ||
| 1516 | } | ||
| 1517 | |||
| 1518 | static void do_volt_notify_handling(struct emif_data *emif, u32 volt_state) | ||
| 1519 | { | ||
| 1520 | dev_dbg(emif->dev, "%s: voltage notification : %d", __func__, | ||
| 1521 | volt_state); | ||
| 1522 | |||
| 1523 | if (!emif->curr_regs) { | ||
| 1524 | dev_err(emif->dev, | ||
| 1525 | "%s: volt-notify before registers are ready: %d\n", | ||
| 1526 | __func__, volt_state); | ||
| 1527 | return; | ||
| 1528 | } | ||
| 1529 | |||
| 1530 | setup_volt_sensitive_regs(emif, emif->curr_regs, volt_state); | ||
| 1531 | } | ||
| 1532 | |||
| 1533 | /* | ||
| 1534 | * TODO: voltage notify handling should be hooked up to | ||
| 1535 | * regulator framework as soon as the necessary support | ||
| 1536 | * is available in mainline kernel. This function is un-used | ||
| 1537 | * right now. | ||
| 1538 | */ | ||
| 1539 | static void __attribute__((unused)) volt_notify_handling(u32 volt_state) | ||
| 1540 | { | ||
| 1541 | struct emif_data *emif; | ||
| 1542 | |||
| 1543 | spin_lock_irqsave(&emif_lock, irq_state); | ||
| 1544 | |||
| 1545 | list_for_each_entry(emif, &device_list, node) | ||
| 1546 | do_volt_notify_handling(emif, volt_state); | ||
| 1547 | do_freq_update(); | ||
| 1548 | |||
| 1549 | spin_unlock_irqrestore(&emif_lock, irq_state); | ||
| 1550 | } | ||
| 1551 | |||
| 1552 | static void do_freq_pre_notify_handling(struct emif_data *emif, u32 new_freq) | ||
| 1553 | { | ||
| 1554 | struct emif_regs *regs; | ||
| 1555 | |||
| 1556 | regs = get_regs(emif, new_freq); | ||
| 1557 | if (!regs) | ||
| 1558 | return; | ||
| 1559 | |||
| 1560 | emif->curr_regs = regs; | ||
| 1561 | |||
| 1562 | /* | ||
| 1563 | * Update the shadow registers: | ||
| 1564 | * Temperature and voltage-ramp sensitive settings are also configured | ||
| 1565 | * in terms of DDR cycles. So, we need to update them too when there | ||
| 1566 | * is a freq change | ||
| 1567 | */ | ||
| 1568 | dev_dbg(emif->dev, "%s: setting up shadow registers for %uHz", | ||
| 1569 | __func__, new_freq); | ||
| 1570 | setup_registers(emif, regs); | ||
| 1571 | setup_temperature_sensitive_regs(emif, regs); | ||
| 1572 | setup_volt_sensitive_regs(emif, regs, DDR_VOLTAGE_STABLE); | ||
| 1573 | |||
| 1574 | /* | ||
| 1575 | * Part of workaround for errata i728. See do_freq_update() | ||
| 1576 | * for more details | ||
| 1577 | */ | ||
| 1578 | if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH) | ||
| 1579 | set_lpmode(emif, EMIF_LP_MODE_DISABLE); | ||
| 1580 | } | ||
| 1581 | |||
| 1582 | /* | ||
| 1583 | * TODO: frequency notify handling should be hooked up to | ||
| 1584 | * clock framework as soon as the necessary support is | ||
| 1585 | * available in mainline kernel. This function is un-used | ||
| 1586 | * right now. | ||
| 1587 | */ | ||
| 1588 | static void __attribute__((unused)) freq_pre_notify_handling(u32 new_freq) | ||
| 1589 | { | ||
| 1590 | struct emif_data *emif; | ||
| 1591 | |||
| 1592 | /* | ||
| 1593 | * NOTE: we are taking the spin-lock here and releases it | ||
| 1594 | * only in post-notifier. This doesn't look good and | ||
| 1595 | * Sparse complains about it, but this seems to be | ||
| 1596 | * un-avoidable. We need to lock a sequence of events | ||
| 1597 | * that is split between EMIF and clock framework. | ||
| 1598 | * | ||
| 1599 | * 1. EMIF driver updates EMIF timings in shadow registers in the | ||
| 1600 | * frequency pre-notify callback from clock framework | ||
| 1601 | * 2. clock framework sets up the registers for the new frequency | ||
| 1602 | * 3. clock framework initiates a hw-sequence that updates | ||
| 1603 | * the frequency EMIF timings synchronously. | ||
| 1604 | * | ||
| 1605 | * All these 3 steps should be performed as an atomic operation | ||
| 1606 | * vis-a-vis similar sequence in the EMIF interrupt handler | ||
| 1607 | * for temperature events. Otherwise, there could be race | ||
| 1608 | * conditions that could result in incorrect EMIF timings for | ||
| 1609 | * a given frequency | ||
| 1610 | */ | ||
| 1611 | spin_lock_irqsave(&emif_lock, irq_state); | ||
| 1612 | |||
| 1613 | list_for_each_entry(emif, &device_list, node) | ||
| 1614 | do_freq_pre_notify_handling(emif, new_freq); | ||
| 1615 | } | ||
| 1616 | |||
| 1617 | static void do_freq_post_notify_handling(struct emif_data *emif) | ||
| 1618 | { | ||
| 1619 | /* | ||
| 1620 | * Part of workaround for errata i728. See do_freq_update() | ||
| 1621 | * for more details | ||
| 1622 | */ | ||
| 1623 | if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH) | ||
| 1624 | set_lpmode(emif, EMIF_LP_MODE_SELF_REFRESH); | ||
| 1625 | } | ||
| 1626 | |||
| 1627 | /* | ||
| 1628 | * TODO: frequency notify handling should be hooked up to | ||
| 1629 | * clock framework as soon as the necessary support is | ||
| 1630 | * available in mainline kernel. This function is un-used | ||
| 1631 | * right now. | ||
| 1632 | */ | ||
| 1633 | static void __attribute__((unused)) freq_post_notify_handling(void) | ||
| 1634 | { | ||
| 1635 | struct emif_data *emif; | ||
| 1636 | |||
| 1637 | list_for_each_entry(emif, &device_list, node) | ||
| 1638 | do_freq_post_notify_handling(emif); | ||
| 1639 | |||
| 1640 | /* | ||
| 1641 | * Lock is done in pre-notify handler. See freq_pre_notify_handling() | ||
| 1642 | * for more details | ||
| 1643 | */ | ||
| 1644 | spin_unlock_irqrestore(&emif_lock, irq_state); | ||
| 1645 | } | ||
| 1646 | |||
| 1647 | static struct platform_driver emif_driver = { | ||
| 1648 | .remove = __exit_p(emif_remove), | ||
| 1649 | .shutdown = emif_shutdown, | ||
| 1650 | .driver = { | ||
| 1651 | .name = "emif", | ||
| 1652 | }, | ||
| 1653 | }; | ||
| 1654 | |||
| 1655 | static int __init_or_module emif_register(void) | ||
| 1656 | { | ||
| 1657 | return platform_driver_probe(&emif_driver, emif_probe); | ||
| 1658 | } | ||
| 1659 | |||
| 1660 | static void __exit emif_unregister(void) | ||
| 1661 | { | ||
| 1662 | platform_driver_unregister(&emif_driver); | ||
| 1663 | } | ||
| 1664 | |||
| 1665 | module_init(emif_register); | ||
| 1666 | module_exit(emif_unregister); | ||
| 1667 | MODULE_DESCRIPTION("TI EMIF SDRAM Controller Driver"); | ||
| 1668 | MODULE_LICENSE("GPL"); | ||
| 1669 | MODULE_ALIAS("platform:emif"); | ||
| 1670 | MODULE_AUTHOR("Texas Instruments Inc"); | ||
diff --git a/drivers/memory/emif.h b/drivers/memory/emif.h new file mode 100644 index 000000000000..bfe08bae961a --- /dev/null +++ b/drivers/memory/emif.h | |||
| @@ -0,0 +1,589 @@ | |||
| 1 | /* | ||
| 2 | * Defines for the EMIF driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 Texas Instruments, Inc. | ||
| 5 | * | ||
| 6 | * Benoit Cousson (b-cousson@ti.com) | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | */ | ||
| 12 | #ifndef __EMIF_H | ||
| 13 | #define __EMIF_H | ||
| 14 | |||
| 15 | /* | ||
| 16 | * Maximum number of different frequencies supported by EMIF driver | ||
| 17 | * Determines the number of entries in the pointer array for register | ||
| 18 | * cache | ||
| 19 | */ | ||
| 20 | #define EMIF_MAX_NUM_FREQUENCIES 6 | ||
| 21 | |||
| 22 | /* State of the core voltage */ | ||
| 23 | #define DDR_VOLTAGE_STABLE 0 | ||
| 24 | #define DDR_VOLTAGE_RAMPING 1 | ||
| 25 | |||
| 26 | /* Defines for timing De-rating */ | ||
| 27 | #define EMIF_NORMAL_TIMINGS 0 | ||
| 28 | #define EMIF_DERATED_TIMINGS 1 | ||
| 29 | |||
| 30 | /* Length of the forced read idle period in terms of cycles */ | ||
| 31 | #define EMIF_READ_IDLE_LEN_VAL 5 | ||
| 32 | |||
| 33 | /* | ||
| 34 | * forced read idle interval to be used when voltage | ||
| 35 | * is changed as part of DVFS/DPS - 1ms | ||
| 36 | */ | ||
| 37 | #define READ_IDLE_INTERVAL_DVFS (1*1000000) | ||
| 38 | |||
| 39 | /* | ||
| 40 | * Forced read idle interval to be used when voltage is stable | ||
| 41 | * 50us - or maximum value will do | ||
| 42 | */ | ||
| 43 | #define READ_IDLE_INTERVAL_NORMAL (50*1000000) | ||
| 44 | |||
| 45 | /* DLL calibration interval when voltage is NOT stable - 1us */ | ||
| 46 | #define DLL_CALIB_INTERVAL_DVFS (1*1000000) | ||
| 47 | |||
| 48 | #define DLL_CALIB_ACK_WAIT_VAL 5 | ||
| 49 | |||
| 50 | /* Interval between ZQCS commands - hw team recommended value */ | ||
| 51 | #define EMIF_ZQCS_INTERVAL_US (50*1000) | ||
| 52 | /* Enable ZQ Calibration on exiting Self-refresh */ | ||
| 53 | #define ZQ_SFEXITEN_ENABLE 1 | ||
| 54 | /* | ||
| 55 | * ZQ Calibration simultaneously on both chip-selects: | ||
| 56 | * Needs one calibration resistor per CS | ||
| 57 | */ | ||
| 58 | #define ZQ_DUALCALEN_DISABLE 0 | ||
| 59 | #define ZQ_DUALCALEN_ENABLE 1 | ||
| 60 | |||
| 61 | #define T_ZQCS_DEFAULT_NS 90 | ||
| 62 | #define T_ZQCL_DEFAULT_NS 360 | ||
| 63 | #define T_ZQINIT_DEFAULT_NS 1000 | ||
| 64 | |||
| 65 | /* DPD_EN */ | ||
| 66 | #define DPD_DISABLE 0 | ||
| 67 | #define DPD_ENABLE 1 | ||
| 68 | |||
| 69 | /* | ||
| 70 | * Default values for the low-power entry to be used if not provided by user. | ||
| 71 | * OMAP4/5 has a hw bug(i735) due to which this value can not be less than 512 | ||
| 72 | * Timeout values are in DDR clock 'cycles' and frequency threshold in Hz | ||
| 73 | */ | ||
| 74 | #define EMIF_LP_MODE_TIMEOUT_PERFORMANCE 2048 | ||
| 75 | #define EMIF_LP_MODE_TIMEOUT_POWER 512 | ||
| 76 | #define EMIF_LP_MODE_FREQ_THRESHOLD 400000000 | ||
| 77 | |||
| 78 | /* DDR_PHY_CTRL_1 values for EMIF4D - ATTILA PHY combination */ | ||
| 79 | #define EMIF_DDR_PHY_CTRL_1_BASE_VAL_ATTILAPHY 0x049FF000 | ||
| 80 | #define EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ_ATTILAPHY 0x41 | ||
| 81 | #define EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ_ATTILAPHY 0x80 | ||
| 82 | #define EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS_ATTILAPHY 0xFF | ||
| 83 | |||
| 84 | /* DDR_PHY_CTRL_1 values for EMIF4D5 INTELLIPHY combination */ | ||
| 85 | #define EMIF_DDR_PHY_CTRL_1_BASE_VAL_INTELLIPHY 0x0E084200 | ||
| 86 | #define EMIF_PHY_TOTAL_READ_LATENCY_INTELLIPHY_PS 10000 | ||
| 87 | |||
| 88 | /* TEMP_ALERT_CONFIG - corresponding to temp gradient 5 C/s */ | ||
| 89 | #define TEMP_ALERT_POLL_INTERVAL_DEFAULT_MS 360 | ||
| 90 | |||
| 91 | #define EMIF_T_CSTA 3 | ||
| 92 | #define EMIF_T_PDLL_UL 128 | ||
| 93 | |||
| 94 | /* External PHY control registers magic values */ | ||
| 95 | #define EMIF_EXT_PHY_CTRL_1_VAL 0x04020080 | ||
| 96 | #define EMIF_EXT_PHY_CTRL_5_VAL 0x04010040 | ||
| 97 | #define EMIF_EXT_PHY_CTRL_6_VAL 0x01004010 | ||
| 98 | #define EMIF_EXT_PHY_CTRL_7_VAL 0x00001004 | ||
| 99 | #define EMIF_EXT_PHY_CTRL_8_VAL 0x04010040 | ||
| 100 | #define EMIF_EXT_PHY_CTRL_9_VAL 0x01004010 | ||
| 101 | #define EMIF_EXT_PHY_CTRL_10_VAL 0x00001004 | ||
| 102 | #define EMIF_EXT_PHY_CTRL_11_VAL 0x00000000 | ||
| 103 | #define EMIF_EXT_PHY_CTRL_12_VAL 0x00000000 | ||
| 104 | #define EMIF_EXT_PHY_CTRL_13_VAL 0x00000000 | ||
| 105 | #define EMIF_EXT_PHY_CTRL_14_VAL 0x80080080 | ||
| 106 | #define EMIF_EXT_PHY_CTRL_15_VAL 0x00800800 | ||
| 107 | #define EMIF_EXT_PHY_CTRL_16_VAL 0x08102040 | ||
| 108 | #define EMIF_EXT_PHY_CTRL_17_VAL 0x00000001 | ||
| 109 | #define EMIF_EXT_PHY_CTRL_18_VAL 0x540A8150 | ||
| 110 | #define EMIF_EXT_PHY_CTRL_19_VAL 0xA81502A0 | ||
| 111 | #define EMIF_EXT_PHY_CTRL_20_VAL 0x002A0540 | ||
| 112 | #define EMIF_EXT_PHY_CTRL_21_VAL 0x00000000 | ||
| 113 | #define EMIF_EXT_PHY_CTRL_22_VAL 0x00000000 | ||
| 114 | #define EMIF_EXT_PHY_CTRL_23_VAL 0x00000000 | ||
| 115 | #define EMIF_EXT_PHY_CTRL_24_VAL 0x00000077 | ||
| 116 | |||
| 117 | #define EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS 1200 | ||
| 118 | |||
| 119 | /* Registers offset */ | ||
| 120 | #define EMIF_MODULE_ID_AND_REVISION 0x0000 | ||
| 121 | #define EMIF_STATUS 0x0004 | ||
| 122 | #define EMIF_SDRAM_CONFIG 0x0008 | ||
| 123 | #define EMIF_SDRAM_CONFIG_2 0x000c | ||
| 124 | #define EMIF_SDRAM_REFRESH_CONTROL 0x0010 | ||
| 125 | #define EMIF_SDRAM_REFRESH_CTRL_SHDW 0x0014 | ||
| 126 | #define EMIF_SDRAM_TIMING_1 0x0018 | ||
| 127 | #define EMIF_SDRAM_TIMING_1_SHDW 0x001c | ||
| 128 | #define EMIF_SDRAM_TIMING_2 0x0020 | ||
| 129 | #define EMIF_SDRAM_TIMING_2_SHDW 0x0024 | ||
| 130 | #define EMIF_SDRAM_TIMING_3 0x0028 | ||
| 131 | #define EMIF_SDRAM_TIMING_3_SHDW 0x002c | ||
| 132 | #define EMIF_LPDDR2_NVM_TIMING 0x0030 | ||
| 133 | #define EMIF_LPDDR2_NVM_TIMING_SHDW 0x0034 | ||
| 134 | #define EMIF_POWER_MANAGEMENT_CONTROL 0x0038 | ||
| 135 | #define EMIF_POWER_MANAGEMENT_CTRL_SHDW 0x003c | ||
| 136 | #define EMIF_LPDDR2_MODE_REG_DATA 0x0040 | ||
| 137 | #define EMIF_LPDDR2_MODE_REG_CONFIG 0x0050 | ||
| 138 | #define EMIF_OCP_CONFIG 0x0054 | ||
| 139 | #define EMIF_OCP_CONFIG_VALUE_1 0x0058 | ||
| 140 | #define EMIF_OCP_CONFIG_VALUE_2 0x005c | ||
| 141 | #define EMIF_IODFT_TEST_LOGIC_GLOBAL_CONTROL 0x0060 | ||
| 142 | #define EMIF_IODFT_TEST_LOGIC_CTRL_MISR_RESULT 0x0064 | ||
| 143 | #define EMIF_IODFT_TEST_LOGIC_ADDRESS_MISR_RESULT 0x0068 | ||
| 144 | #define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_1 0x006c | ||
| 145 | #define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_2 0x0070 | ||
| 146 | #define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_3 0x0074 | ||
| 147 | #define EMIF_PERFORMANCE_COUNTER_1 0x0080 | ||
| 148 | #define EMIF_PERFORMANCE_COUNTER_2 0x0084 | ||
| 149 | #define EMIF_PERFORMANCE_COUNTER_CONFIG 0x0088 | ||
| 150 | #define EMIF_PERFORMANCE_COUNTER_MASTER_REGION_SELECT 0x008c | ||
| 151 | #define EMIF_PERFORMANCE_COUNTER_TIME 0x0090 | ||
| 152 | #define EMIF_MISC_REG 0x0094 | ||
| 153 | #define EMIF_DLL_CALIB_CTRL 0x0098 | ||
| 154 | #define EMIF_DLL_CALIB_CTRL_SHDW 0x009c | ||
| 155 | #define EMIF_END_OF_INTERRUPT 0x00a0 | ||
| 156 | #define EMIF_SYSTEM_OCP_INTERRUPT_RAW_STATUS 0x00a4 | ||
| 157 | #define EMIF_LL_OCP_INTERRUPT_RAW_STATUS 0x00a8 | ||
| 158 | #define EMIF_SYSTEM_OCP_INTERRUPT_STATUS 0x00ac | ||
| 159 | #define EMIF_LL_OCP_INTERRUPT_STATUS 0x00b0 | ||
| 160 | #define EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET 0x00b4 | ||
| 161 | #define EMIF_LL_OCP_INTERRUPT_ENABLE_SET 0x00b8 | ||
| 162 | #define EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_CLEAR 0x00bc | ||
| 163 | #define EMIF_LL_OCP_INTERRUPT_ENABLE_CLEAR 0x00c0 | ||
| 164 | #define EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG 0x00c8 | ||
| 165 | #define EMIF_TEMPERATURE_ALERT_CONFIG 0x00cc | ||
| 166 | #define EMIF_OCP_ERROR_LOG 0x00d0 | ||
| 167 | #define EMIF_READ_WRITE_LEVELING_RAMP_WINDOW 0x00d4 | ||
| 168 | #define EMIF_READ_WRITE_LEVELING_RAMP_CONTROL 0x00d8 | ||
| 169 | #define EMIF_READ_WRITE_LEVELING_CONTROL 0x00dc | ||
| 170 | #define EMIF_DDR_PHY_CTRL_1 0x00e4 | ||
| 171 | #define EMIF_DDR_PHY_CTRL_1_SHDW 0x00e8 | ||
| 172 | #define EMIF_DDR_PHY_CTRL_2 0x00ec | ||
| 173 | #define EMIF_PRIORITY_TO_CLASS_OF_SERVICE_MAPPING 0x0100 | ||
| 174 | #define EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_1_MAPPING 0x0104 | ||
| 175 | #define EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_2_MAPPING 0x0108 | ||
| 176 | #define EMIF_READ_WRITE_EXECUTION_THRESHOLD 0x0120 | ||
| 177 | #define EMIF_COS_CONFIG 0x0124 | ||
| 178 | #define EMIF_PHY_STATUS_1 0x0140 | ||
| 179 | #define EMIF_PHY_STATUS_2 0x0144 | ||
| 180 | #define EMIF_PHY_STATUS_3 0x0148 | ||
| 181 | #define EMIF_PHY_STATUS_4 0x014c | ||
| 182 | #define EMIF_PHY_STATUS_5 0x0150 | ||
| 183 | #define EMIF_PHY_STATUS_6 0x0154 | ||
| 184 | #define EMIF_PHY_STATUS_7 0x0158 | ||
| 185 | #define EMIF_PHY_STATUS_8 0x015c | ||
| 186 | #define EMIF_PHY_STATUS_9 0x0160 | ||
| 187 | #define EMIF_PHY_STATUS_10 0x0164 | ||
| 188 | #define EMIF_PHY_STATUS_11 0x0168 | ||
| 189 | #define EMIF_PHY_STATUS_12 0x016c | ||
| 190 | #define EMIF_PHY_STATUS_13 0x0170 | ||
| 191 | #define EMIF_PHY_STATUS_14 0x0174 | ||
| 192 | #define EMIF_PHY_STATUS_15 0x0178 | ||
| 193 | #define EMIF_PHY_STATUS_16 0x017c | ||
| 194 | #define EMIF_PHY_STATUS_17 0x0180 | ||
| 195 | #define EMIF_PHY_STATUS_18 0x0184 | ||
| 196 | #define EMIF_PHY_STATUS_19 0x0188 | ||
| 197 | #define EMIF_PHY_STATUS_20 0x018c | ||
| 198 | #define EMIF_PHY_STATUS_21 0x0190 | ||
| 199 | #define EMIF_EXT_PHY_CTRL_1 0x0200 | ||
| 200 | #define EMIF_EXT_PHY_CTRL_1_SHDW 0x0204 | ||
| 201 | #define EMIF_EXT_PHY_CTRL_2 0x0208 | ||
| 202 | #define EMIF_EXT_PHY_CTRL_2_SHDW 0x020c | ||
| 203 | #define EMIF_EXT_PHY_CTRL_3 0x0210 | ||
| 204 | #define EMIF_EXT_PHY_CTRL_3_SHDW 0x0214 | ||
| 205 | #define EMIF_EXT_PHY_CTRL_4 0x0218 | ||
| 206 | #define EMIF_EXT_PHY_CTRL_4_SHDW 0x021c | ||
| 207 | #define EMIF_EXT_PHY_CTRL_5 0x0220 | ||
| 208 | #define EMIF_EXT_PHY_CTRL_5_SHDW 0x0224 | ||
| 209 | #define EMIF_EXT_PHY_CTRL_6 0x0228 | ||
| 210 | #define EMIF_EXT_PHY_CTRL_6_SHDW 0x022c | ||
| 211 | #define EMIF_EXT_PHY_CTRL_7 0x0230 | ||
| 212 | #define EMIF_EXT_PHY_CTRL_7_SHDW 0x0234 | ||
| 213 | #define EMIF_EXT_PHY_CTRL_8 0x0238 | ||
| 214 | #define EMIF_EXT_PHY_CTRL_8_SHDW 0x023c | ||
| 215 | #define EMIF_EXT_PHY_CTRL_9 0x0240 | ||
| 216 | #define EMIF_EXT_PHY_CTRL_9_SHDW 0x0244 | ||
| 217 | #define EMIF_EXT_PHY_CTRL_10 0x0248 | ||
| 218 | #define EMIF_EXT_PHY_CTRL_10_SHDW 0x024c | ||
| 219 | #define EMIF_EXT_PHY_CTRL_11 0x0250 | ||
| 220 | #define EMIF_EXT_PHY_CTRL_11_SHDW 0x0254 | ||
| 221 | #define EMIF_EXT_PHY_CTRL_12 0x0258 | ||
| 222 | #define EMIF_EXT_PHY_CTRL_12_SHDW 0x025c | ||
| 223 | #define EMIF_EXT_PHY_CTRL_13 0x0260 | ||
| 224 | #define EMIF_EXT_PHY_CTRL_13_SHDW 0x0264 | ||
| 225 | #define EMIF_EXT_PHY_CTRL_14 0x0268 | ||
| 226 | #define EMIF_EXT_PHY_CTRL_14_SHDW 0x026c | ||
| 227 | #define EMIF_EXT_PHY_CTRL_15 0x0270 | ||
| 228 | #define EMIF_EXT_PHY_CTRL_15_SHDW 0x0274 | ||
| 229 | #define EMIF_EXT_PHY_CTRL_16 0x0278 | ||
| 230 | #define EMIF_EXT_PHY_CTRL_16_SHDW 0x027c | ||
| 231 | #define EMIF_EXT_PHY_CTRL_17 0x0280 | ||
| 232 | #define EMIF_EXT_PHY_CTRL_17_SHDW 0x0284 | ||
| 233 | #define EMIF_EXT_PHY_CTRL_18 0x0288 | ||
| 234 | #define EMIF_EXT_PHY_CTRL_18_SHDW 0x028c | ||
| 235 | #define EMIF_EXT_PHY_CTRL_19 0x0290 | ||
| 236 | #define EMIF_EXT_PHY_CTRL_19_SHDW 0x0294 | ||
| 237 | #define EMIF_EXT_PHY_CTRL_20 0x0298 | ||
| 238 | #define EMIF_EXT_PHY_CTRL_20_SHDW 0x029c | ||
| 239 | #define EMIF_EXT_PHY_CTRL_21 0x02a0 | ||
| 240 | #define EMIF_EXT_PHY_CTRL_21_SHDW 0x02a4 | ||
| 241 | #define EMIF_EXT_PHY_CTRL_22 0x02a8 | ||
| 242 | #define EMIF_EXT_PHY_CTRL_22_SHDW 0x02ac | ||
| 243 | #define EMIF_EXT_PHY_CTRL_23 0x02b0 | ||
| 244 | #define EMIF_EXT_PHY_CTRL_23_SHDW 0x02b4 | ||
| 245 | #define EMIF_EXT_PHY_CTRL_24 0x02b8 | ||
| 246 | #define EMIF_EXT_PHY_CTRL_24_SHDW 0x02bc | ||
| 247 | #define EMIF_EXT_PHY_CTRL_25 0x02c0 | ||
| 248 | #define EMIF_EXT_PHY_CTRL_25_SHDW 0x02c4 | ||
| 249 | #define EMIF_EXT_PHY_CTRL_26 0x02c8 | ||
| 250 | #define EMIF_EXT_PHY_CTRL_26_SHDW 0x02cc | ||
| 251 | #define EMIF_EXT_PHY_CTRL_27 0x02d0 | ||
| 252 | #define EMIF_EXT_PHY_CTRL_27_SHDW 0x02d4 | ||
| 253 | #define EMIF_EXT_PHY_CTRL_28 0x02d8 | ||
| 254 | #define EMIF_EXT_PHY_CTRL_28_SHDW 0x02dc | ||
| 255 | #define EMIF_EXT_PHY_CTRL_29 0x02e0 | ||
| 256 | #define EMIF_EXT_PHY_CTRL_29_SHDW 0x02e4 | ||
| 257 | #define EMIF_EXT_PHY_CTRL_30 0x02e8 | ||
| 258 | #define EMIF_EXT_PHY_CTRL_30_SHDW 0x02ec | ||
| 259 | |||
| 260 | /* Registers shifts and masks */ | ||
| 261 | |||
| 262 | /* EMIF_MODULE_ID_AND_REVISION */ | ||
| 263 | #define SCHEME_SHIFT 30 | ||
| 264 | #define SCHEME_MASK (0x3 << 30) | ||
| 265 | #define MODULE_ID_SHIFT 16 | ||
| 266 | #define MODULE_ID_MASK (0xfff << 16) | ||
| 267 | #define RTL_VERSION_SHIFT 11 | ||
| 268 | #define RTL_VERSION_MASK (0x1f << 11) | ||
| 269 | #define MAJOR_REVISION_SHIFT 8 | ||
| 270 | #define MAJOR_REVISION_MASK (0x7 << 8) | ||
| 271 | #define MINOR_REVISION_SHIFT 0 | ||
| 272 | #define MINOR_REVISION_MASK (0x3f << 0) | ||
| 273 | |||
| 274 | /* STATUS */ | ||
| 275 | #define BE_SHIFT 31 | ||
| 276 | #define BE_MASK (1 << 31) | ||
| 277 | #define DUAL_CLK_MODE_SHIFT 30 | ||
| 278 | #define DUAL_CLK_MODE_MASK (1 << 30) | ||
| 279 | #define FAST_INIT_SHIFT 29 | ||
| 280 | #define FAST_INIT_MASK (1 << 29) | ||
| 281 | #define RDLVLGATETO_SHIFT 6 | ||
| 282 | #define RDLVLGATETO_MASK (1 << 6) | ||
| 283 | #define RDLVLTO_SHIFT 5 | ||
| 284 | #define RDLVLTO_MASK (1 << 5) | ||
| 285 | #define WRLVLTO_SHIFT 4 | ||
| 286 | #define WRLVLTO_MASK (1 << 4) | ||
| 287 | #define PHY_DLL_READY_SHIFT 2 | ||
| 288 | #define PHY_DLL_READY_MASK (1 << 2) | ||
| 289 | |||
| 290 | /* SDRAM_CONFIG */ | ||
| 291 | #define SDRAM_TYPE_SHIFT 29 | ||
| 292 | #define SDRAM_TYPE_MASK (0x7 << 29) | ||
| 293 | #define IBANK_POS_SHIFT 27 | ||
| 294 | #define IBANK_POS_MASK (0x3 << 27) | ||
| 295 | #define DDR_TERM_SHIFT 24 | ||
| 296 | #define DDR_TERM_MASK (0x7 << 24) | ||
| 297 | #define DDR2_DDQS_SHIFT 23 | ||
| 298 | #define DDR2_DDQS_MASK (1 << 23) | ||
| 299 | #define DYN_ODT_SHIFT 21 | ||
| 300 | #define DYN_ODT_MASK (0x3 << 21) | ||
| 301 | #define DDR_DISABLE_DLL_SHIFT 20 | ||
| 302 | #define DDR_DISABLE_DLL_MASK (1 << 20) | ||
| 303 | #define SDRAM_DRIVE_SHIFT 18 | ||
| 304 | #define SDRAM_DRIVE_MASK (0x3 << 18) | ||
| 305 | #define CWL_SHIFT 16 | ||
| 306 | #define CWL_MASK (0x3 << 16) | ||
| 307 | #define NARROW_MODE_SHIFT 14 | ||
| 308 | #define NARROW_MODE_MASK (0x3 << 14) | ||
| 309 | #define CL_SHIFT 10 | ||
| 310 | #define CL_MASK (0xf << 10) | ||
| 311 | #define ROWSIZE_SHIFT 7 | ||
| 312 | #define ROWSIZE_MASK (0x7 << 7) | ||
| 313 | #define IBANK_SHIFT 4 | ||
| 314 | #define IBANK_MASK (0x7 << 4) | ||
| 315 | #define EBANK_SHIFT 3 | ||
| 316 | #define EBANK_MASK (1 << 3) | ||
| 317 | #define PAGESIZE_SHIFT 0 | ||
| 318 | #define PAGESIZE_MASK (0x7 << 0) | ||
| 319 | |||
| 320 | /* SDRAM_CONFIG_2 */ | ||
| 321 | #define CS1NVMEN_SHIFT 30 | ||
| 322 | #define CS1NVMEN_MASK (1 << 30) | ||
| 323 | #define EBANK_POS_SHIFT 27 | ||
| 324 | #define EBANK_POS_MASK (1 << 27) | ||
| 325 | #define RDBNUM_SHIFT 4 | ||
| 326 | #define RDBNUM_MASK (0x3 << 4) | ||
| 327 | #define RDBSIZE_SHIFT 0 | ||
| 328 | #define RDBSIZE_MASK (0x7 << 0) | ||
| 329 | |||
| 330 | /* SDRAM_REFRESH_CONTROL */ | ||
| 331 | #define INITREF_DIS_SHIFT 31 | ||
| 332 | #define INITREF_DIS_MASK (1 << 31) | ||
| 333 | #define SRT_SHIFT 29 | ||
| 334 | #define SRT_MASK (1 << 29) | ||
| 335 | #define ASR_SHIFT 28 | ||
| 336 | #define ASR_MASK (1 << 28) | ||
| 337 | #define PASR_SHIFT 24 | ||
| 338 | #define PASR_MASK (0x7 << 24) | ||
| 339 | #define REFRESH_RATE_SHIFT 0 | ||
| 340 | #define REFRESH_RATE_MASK (0xffff << 0) | ||
| 341 | |||
| 342 | /* SDRAM_TIMING_1 */ | ||
| 343 | #define T_RTW_SHIFT 29 | ||
| 344 | #define T_RTW_MASK (0x7 << 29) | ||
| 345 | #define T_RP_SHIFT 25 | ||
| 346 | #define T_RP_MASK (0xf << 25) | ||
| 347 | #define T_RCD_SHIFT 21 | ||
| 348 | #define T_RCD_MASK (0xf << 21) | ||
| 349 | #define T_WR_SHIFT 17 | ||
| 350 | #define T_WR_MASK (0xf << 17) | ||
| 351 | #define T_RAS_SHIFT 12 | ||
| 352 | #define T_RAS_MASK (0x1f << 12) | ||
| 353 | #define T_RC_SHIFT 6 | ||
| 354 | #define T_RC_MASK (0x3f << 6) | ||
| 355 | #define T_RRD_SHIFT 3 | ||
| 356 | #define T_RRD_MASK (0x7 << 3) | ||
| 357 | #define T_WTR_SHIFT 0 | ||
| 358 | #define T_WTR_MASK (0x7 << 0) | ||
| 359 | |||
| 360 | /* SDRAM_TIMING_2 */ | ||
| 361 | #define T_XP_SHIFT 28 | ||
| 362 | #define T_XP_MASK (0x7 << 28) | ||
| 363 | #define T_ODT_SHIFT 25 | ||
| 364 | #define T_ODT_MASK (0x7 << 25) | ||
| 365 | #define T_XSNR_SHIFT 16 | ||
| 366 | #define T_XSNR_MASK (0x1ff << 16) | ||
| 367 | #define T_XSRD_SHIFT 6 | ||
| 368 | #define T_XSRD_MASK (0x3ff << 6) | ||
| 369 | #define T_RTP_SHIFT 3 | ||
| 370 | #define T_RTP_MASK (0x7 << 3) | ||
| 371 | #define T_CKE_SHIFT 0 | ||
| 372 | #define T_CKE_MASK (0x7 << 0) | ||
| 373 | |||
| 374 | /* SDRAM_TIMING_3 */ | ||
| 375 | #define T_PDLL_UL_SHIFT 28 | ||
| 376 | #define T_PDLL_UL_MASK (0xf << 28) | ||
| 377 | #define T_CSTA_SHIFT 24 | ||
| 378 | #define T_CSTA_MASK (0xf << 24) | ||
| 379 | #define T_CKESR_SHIFT 21 | ||
| 380 | #define T_CKESR_MASK (0x7 << 21) | ||
| 381 | #define ZQ_ZQCS_SHIFT 15 | ||
| 382 | #define ZQ_ZQCS_MASK (0x3f << 15) | ||
| 383 | #define T_TDQSCKMAX_SHIFT 13 | ||
| 384 | #define T_TDQSCKMAX_MASK (0x3 << 13) | ||
| 385 | #define T_RFC_SHIFT 4 | ||
| 386 | #define T_RFC_MASK (0x1ff << 4) | ||
| 387 | #define T_RAS_MAX_SHIFT 0 | ||
| 388 | #define T_RAS_MAX_MASK (0xf << 0) | ||
| 389 | |||
| 390 | /* POWER_MANAGEMENT_CONTROL */ | ||
| 391 | #define PD_TIM_SHIFT 12 | ||
| 392 | #define PD_TIM_MASK (0xf << 12) | ||
| 393 | #define DPD_EN_SHIFT 11 | ||
| 394 | #define DPD_EN_MASK (1 << 11) | ||
| 395 | #define LP_MODE_SHIFT 8 | ||
| 396 | #define LP_MODE_MASK (0x7 << 8) | ||
| 397 | #define SR_TIM_SHIFT 4 | ||
| 398 | #define SR_TIM_MASK (0xf << 4) | ||
| 399 | #define CS_TIM_SHIFT 0 | ||
| 400 | #define CS_TIM_MASK (0xf << 0) | ||
| 401 | |||
| 402 | /* LPDDR2_MODE_REG_DATA */ | ||
| 403 | #define VALUE_0_SHIFT 0 | ||
| 404 | #define VALUE_0_MASK (0x7f << 0) | ||
| 405 | |||
| 406 | /* LPDDR2_MODE_REG_CONFIG */ | ||
| 407 | #define CS_SHIFT 31 | ||
| 408 | #define CS_MASK (1 << 31) | ||
| 409 | #define REFRESH_EN_SHIFT 30 | ||
| 410 | #define REFRESH_EN_MASK (1 << 30) | ||
| 411 | #define ADDRESS_SHIFT 0 | ||
| 412 | #define ADDRESS_MASK (0xff << 0) | ||
| 413 | |||
| 414 | /* OCP_CONFIG */ | ||
| 415 | #define SYS_THRESH_MAX_SHIFT 24 | ||
| 416 | #define SYS_THRESH_MAX_MASK (0xf << 24) | ||
| 417 | #define MPU_THRESH_MAX_SHIFT 20 | ||
| 418 | #define MPU_THRESH_MAX_MASK (0xf << 20) | ||
| 419 | #define LL_THRESH_MAX_SHIFT 16 | ||
| 420 | #define LL_THRESH_MAX_MASK (0xf << 16) | ||
| 421 | |||
| 422 | /* PERFORMANCE_COUNTER_1 */ | ||
| 423 | #define COUNTER1_SHIFT 0 | ||
| 424 | #define COUNTER1_MASK (0xffffffff << 0) | ||
| 425 | |||
| 426 | /* PERFORMANCE_COUNTER_2 */ | ||
| 427 | #define COUNTER2_SHIFT 0 | ||
| 428 | #define COUNTER2_MASK (0xffffffff << 0) | ||
| 429 | |||
| 430 | /* PERFORMANCE_COUNTER_CONFIG */ | ||
| 431 | #define CNTR2_MCONNID_EN_SHIFT 31 | ||
| 432 | #define CNTR2_MCONNID_EN_MASK (1 << 31) | ||
| 433 | #define CNTR2_REGION_EN_SHIFT 30 | ||
| 434 | #define CNTR2_REGION_EN_MASK (1 << 30) | ||
| 435 | #define CNTR2_CFG_SHIFT 16 | ||
| 436 | #define CNTR2_CFG_MASK (0xf << 16) | ||
| 437 | #define CNTR1_MCONNID_EN_SHIFT 15 | ||
| 438 | #define CNTR1_MCONNID_EN_MASK (1 << 15) | ||
| 439 | #define CNTR1_REGION_EN_SHIFT 14 | ||
| 440 | #define CNTR1_REGION_EN_MASK (1 << 14) | ||
| 441 | #define CNTR1_CFG_SHIFT 0 | ||
| 442 | #define CNTR1_CFG_MASK (0xf << 0) | ||
| 443 | |||
| 444 | /* PERFORMANCE_COUNTER_MASTER_REGION_SELECT */ | ||
| 445 | #define MCONNID2_SHIFT 24 | ||
| 446 | #define MCONNID2_MASK (0xff << 24) | ||
| 447 | #define REGION_SEL2_SHIFT 16 | ||
| 448 | #define REGION_SEL2_MASK (0x3 << 16) | ||
| 449 | #define MCONNID1_SHIFT 8 | ||
| 450 | #define MCONNID1_MASK (0xff << 8) | ||
| 451 | #define REGION_SEL1_SHIFT 0 | ||
| 452 | #define REGION_SEL1_MASK (0x3 << 0) | ||
| 453 | |||
| 454 | /* PERFORMANCE_COUNTER_TIME */ | ||
| 455 | #define TOTAL_TIME_SHIFT 0 | ||
| 456 | #define TOTAL_TIME_MASK (0xffffffff << 0) | ||
| 457 | |||
| 458 | /* DLL_CALIB_CTRL */ | ||
| 459 | #define ACK_WAIT_SHIFT 16 | ||
| 460 | #define ACK_WAIT_MASK (0xf << 16) | ||
| 461 | #define DLL_CALIB_INTERVAL_SHIFT 0 | ||
| 462 | #define DLL_CALIB_INTERVAL_MASK (0x1ff << 0) | ||
| 463 | |||
| 464 | /* END_OF_INTERRUPT */ | ||
| 465 | #define EOI_SHIFT 0 | ||
| 466 | #define EOI_MASK (1 << 0) | ||
| 467 | |||
| 468 | /* SYSTEM_OCP_INTERRUPT_RAW_STATUS */ | ||
| 469 | #define DNV_SYS_SHIFT 2 | ||
| 470 | #define DNV_SYS_MASK (1 << 2) | ||
| 471 | #define TA_SYS_SHIFT 1 | ||
| 472 | #define TA_SYS_MASK (1 << 1) | ||
| 473 | #define ERR_SYS_SHIFT 0 | ||
| 474 | #define ERR_SYS_MASK (1 << 0) | ||
| 475 | |||
| 476 | /* LOW_LATENCY_OCP_INTERRUPT_RAW_STATUS */ | ||
| 477 | #define DNV_LL_SHIFT 2 | ||
| 478 | #define DNV_LL_MASK (1 << 2) | ||
| 479 | #define TA_LL_SHIFT 1 | ||
| 480 | #define TA_LL_MASK (1 << 1) | ||
| 481 | #define ERR_LL_SHIFT 0 | ||
| 482 | #define ERR_LL_MASK (1 << 0) | ||
| 483 | |||
| 484 | /* SYSTEM_OCP_INTERRUPT_ENABLE_SET */ | ||
| 485 | #define EN_DNV_SYS_SHIFT 2 | ||
| 486 | #define EN_DNV_SYS_MASK (1 << 2) | ||
| 487 | #define EN_TA_SYS_SHIFT 1 | ||
| 488 | #define EN_TA_SYS_MASK (1 << 1) | ||
| 489 | #define EN_ERR_SYS_SHIFT 0 | ||
| 490 | #define EN_ERR_SYS_MASK (1 << 0) | ||
| 491 | |||
| 492 | /* LOW_LATENCY_OCP_INTERRUPT_ENABLE_SET */ | ||
| 493 | #define EN_DNV_LL_SHIFT 2 | ||
| 494 | #define EN_DNV_LL_MASK (1 << 2) | ||
| 495 | #define EN_TA_LL_SHIFT 1 | ||
| 496 | #define EN_TA_LL_MASK (1 << 1) | ||
| 497 | #define EN_ERR_LL_SHIFT 0 | ||
| 498 | #define EN_ERR_LL_MASK (1 << 0) | ||
| 499 | |||
| 500 | /* SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG */ | ||
| 501 | #define ZQ_CS1EN_SHIFT 31 | ||
| 502 | #define ZQ_CS1EN_MASK (1 << 31) | ||
| 503 | #define ZQ_CS0EN_SHIFT 30 | ||
| 504 | #define ZQ_CS0EN_MASK (1 << 30) | ||
| 505 | #define ZQ_DUALCALEN_SHIFT 29 | ||
| 506 | #define ZQ_DUALCALEN_MASK (1 << 29) | ||
| 507 | #define ZQ_SFEXITEN_SHIFT 28 | ||
| 508 | #define ZQ_SFEXITEN_MASK (1 << 28) | ||
| 509 | #define ZQ_ZQINIT_MULT_SHIFT 18 | ||
| 510 | #define ZQ_ZQINIT_MULT_MASK (0x3 << 18) | ||
| 511 | #define ZQ_ZQCL_MULT_SHIFT 16 | ||
| 512 | #define ZQ_ZQCL_MULT_MASK (0x3 << 16) | ||
| 513 | #define ZQ_REFINTERVAL_SHIFT 0 | ||
| 514 | #define ZQ_REFINTERVAL_MASK (0xffff << 0) | ||
| 515 | |||
| 516 | /* TEMPERATURE_ALERT_CONFIG */ | ||
| 517 | #define TA_CS1EN_SHIFT 31 | ||
| 518 | #define TA_CS1EN_MASK (1 << 31) | ||
| 519 | #define TA_CS0EN_SHIFT 30 | ||
| 520 | #define TA_CS0EN_MASK (1 << 30) | ||
| 521 | #define TA_SFEXITEN_SHIFT 28 | ||
| 522 | #define TA_SFEXITEN_MASK (1 << 28) | ||
| 523 | #define TA_DEVWDT_SHIFT 26 | ||
| 524 | #define TA_DEVWDT_MASK (0x3 << 26) | ||
| 525 | #define TA_DEVCNT_SHIFT 24 | ||
| 526 | #define TA_DEVCNT_MASK (0x3 << 24) | ||
| 527 | #define TA_REFINTERVAL_SHIFT 0 | ||
| 528 | #define TA_REFINTERVAL_MASK (0x3fffff << 0) | ||
| 529 | |||
| 530 | /* OCP_ERROR_LOG */ | ||
| 531 | #define MADDRSPACE_SHIFT 14 | ||
| 532 | #define MADDRSPACE_MASK (0x3 << 14) | ||
| 533 | #define MBURSTSEQ_SHIFT 11 | ||
| 534 | #define MBURSTSEQ_MASK (0x7 << 11) | ||
| 535 | #define MCMD_SHIFT 8 | ||
| 536 | #define MCMD_MASK (0x7 << 8) | ||
| 537 | #define MCONNID_SHIFT 0 | ||
| 538 | #define MCONNID_MASK (0xff << 0) | ||
| 539 | |||
| 540 | /* DDR_PHY_CTRL_1 - EMIF4D */ | ||
| 541 | #define DLL_SLAVE_DLY_CTRL_SHIFT_4D 4 | ||
| 542 | #define DLL_SLAVE_DLY_CTRL_MASK_4D (0xFF << 4) | ||
| 543 | #define READ_LATENCY_SHIFT_4D 0 | ||
| 544 | #define READ_LATENCY_MASK_4D (0xf << 0) | ||
| 545 | |||
| 546 | /* DDR_PHY_CTRL_1 - EMIF4D5 */ | ||
| 547 | #define DLL_HALF_DELAY_SHIFT_4D5 21 | ||
| 548 | #define DLL_HALF_DELAY_MASK_4D5 (1 << 21) | ||
| 549 | #define READ_LATENCY_SHIFT_4D5 0 | ||
| 550 | #define READ_LATENCY_MASK_4D5 (0x1f << 0) | ||
| 551 | |||
| 552 | /* DDR_PHY_CTRL_1_SHDW */ | ||
| 553 | #define DDR_PHY_CTRL_1_SHDW_SHIFT 5 | ||
| 554 | #define DDR_PHY_CTRL_1_SHDW_MASK (0x7ffffff << 5) | ||
| 555 | #define READ_LATENCY_SHDW_SHIFT 0 | ||
| 556 | #define READ_LATENCY_SHDW_MASK (0x1f << 0) | ||
| 557 | |||
| 558 | #ifndef __ASSEMBLY__ | ||
| 559 | /* | ||
| 560 | * Structure containing shadow of important registers in EMIF | ||
| 561 | * The calculation function fills in this structure to be later used for | ||
| 562 | * initialisation and DVFS | ||
| 563 | */ | ||
| 564 | struct emif_regs { | ||
| 565 | u32 freq; | ||
| 566 | u32 ref_ctrl_shdw; | ||
| 567 | u32 ref_ctrl_shdw_derated; | ||
| 568 | u32 sdram_tim1_shdw; | ||
| 569 | u32 sdram_tim1_shdw_derated; | ||
| 570 | u32 sdram_tim2_shdw; | ||
| 571 | u32 sdram_tim3_shdw; | ||
| 572 | u32 sdram_tim3_shdw_derated; | ||
| 573 | u32 pwr_mgmt_ctrl_shdw; | ||
| 574 | union { | ||
| 575 | u32 read_idle_ctrl_shdw_normal; | ||
| 576 | u32 dll_calib_ctrl_shdw_normal; | ||
| 577 | }; | ||
| 578 | union { | ||
| 579 | u32 read_idle_ctrl_shdw_volt_ramp; | ||
| 580 | u32 dll_calib_ctrl_shdw_volt_ramp; | ||
| 581 | }; | ||
| 582 | |||
| 583 | u32 phy_ctrl_1_shdw; | ||
| 584 | u32 ext_phy_ctrl_2_shdw; | ||
| 585 | u32 ext_phy_ctrl_3_shdw; | ||
| 586 | u32 ext_phy_ctrl_4_shdw; | ||
| 587 | }; | ||
| 588 | #endif /* __ASSEMBLY__ */ | ||
| 589 | #endif /* __EMIF_H */ | ||
diff --git a/drivers/memory/tegra20-mc.c b/drivers/memory/tegra20-mc.c new file mode 100644 index 000000000000..3ed49c1c2b91 --- /dev/null +++ b/drivers/memory/tegra20-mc.c | |||
| @@ -0,0 +1,257 @@ | |||
| 1 | /* | ||
| 2 | * Tegra20 Memory Controller | ||
| 3 | * | ||
| 4 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms and conditions of the GNU General Public License, | ||
| 8 | * version 2, as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 13 | * more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License along with | ||
| 16 | * this program; if not, write to the Free Software Foundation, Inc., | ||
| 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/ratelimit.h> | ||
| 23 | #include <linux/platform_device.h> | ||
| 24 | #include <linux/interrupt.h> | ||
| 25 | #include <linux/io.h> | ||
| 26 | |||
| 27 | #define DRV_NAME "tegra20-mc" | ||
| 28 | |||
| 29 | #define MC_INTSTATUS 0x0 | ||
| 30 | #define MC_INTMASK 0x4 | ||
| 31 | |||
| 32 | #define MC_INT_ERR_SHIFT 6 | ||
| 33 | #define MC_INT_ERR_MASK (0x1f << MC_INT_ERR_SHIFT) | ||
| 34 | #define MC_INT_DECERR_EMEM BIT(MC_INT_ERR_SHIFT) | ||
| 35 | #define MC_INT_INVALID_GART_PAGE BIT(MC_INT_ERR_SHIFT + 1) | ||
| 36 | #define MC_INT_SECURITY_VIOLATION BIT(MC_INT_ERR_SHIFT + 2) | ||
| 37 | #define MC_INT_ARBITRATION_EMEM BIT(MC_INT_ERR_SHIFT + 3) | ||
| 38 | |||
| 39 | #define MC_GART_ERROR_REQ 0x30 | ||
| 40 | #define MC_DECERR_EMEM_OTHERS_STATUS 0x58 | ||
| 41 | #define MC_SECURITY_VIOLATION_STATUS 0x74 | ||
| 42 | |||
| 43 | #define SECURITY_VIOLATION_TYPE BIT(30) /* 0=TRUSTZONE, 1=CARVEOUT */ | ||
| 44 | |||
| 45 | #define MC_CLIENT_ID_MASK 0x3f | ||
| 46 | |||
| 47 | #define NUM_MC_REG_BANKS 2 | ||
| 48 | |||
| 49 | struct tegra20_mc { | ||
| 50 | void __iomem *regs[NUM_MC_REG_BANKS]; | ||
| 51 | struct device *dev; | ||
| 52 | }; | ||
| 53 | |||
| 54 | static inline u32 mc_readl(struct tegra20_mc *mc, u32 offs) | ||
| 55 | { | ||
| 56 | u32 val = 0; | ||
| 57 | |||
| 58 | if (offs < 0x24) | ||
| 59 | val = readl(mc->regs[0] + offs); | ||
| 60 | if (offs < 0x400) | ||
| 61 | val = readl(mc->regs[1] + offs - 0x3c); | ||
| 62 | |||
| 63 | return val; | ||
| 64 | } | ||
| 65 | |||
| 66 | static inline void mc_writel(struct tegra20_mc *mc, u32 val, u32 offs) | ||
| 67 | { | ||
| 68 | if (offs < 0x24) { | ||
| 69 | writel(val, mc->regs[0] + offs); | ||
| 70 | return; | ||
| 71 | } | ||
| 72 | if (offs < 0x400) { | ||
| 73 | writel(val, mc->regs[1] + offs - 0x3c); | ||
| 74 | return; | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | static const char * const tegra20_mc_client[] = { | ||
| 79 | "cbr_display0a", | ||
| 80 | "cbr_display0ab", | ||
| 81 | "cbr_display0b", | ||
| 82 | "cbr_display0bb", | ||
| 83 | "cbr_display0c", | ||
| 84 | "cbr_display0cb", | ||
| 85 | "cbr_display1b", | ||
| 86 | "cbr_display1bb", | ||
| 87 | "cbr_eppup", | ||
| 88 | "cbr_g2pr", | ||
| 89 | "cbr_g2sr", | ||
| 90 | "cbr_mpeunifbr", | ||
| 91 | "cbr_viruv", | ||
| 92 | "csr_avpcarm7r", | ||
| 93 | "csr_displayhc", | ||
| 94 | "csr_displayhcb", | ||
| 95 | "csr_fdcdrd", | ||
| 96 | "csr_g2dr", | ||
| 97 | "csr_host1xdmar", | ||
| 98 | "csr_host1xr", | ||
| 99 | "csr_idxsrd", | ||
| 100 | "csr_mpcorer", | ||
| 101 | "csr_mpe_ipred", | ||
| 102 | "csr_mpeamemrd", | ||
| 103 | "csr_mpecsrd", | ||
| 104 | "csr_ppcsahbdmar", | ||
| 105 | "csr_ppcsahbslvr", | ||
| 106 | "csr_texsrd", | ||
| 107 | "csr_vdebsevr", | ||
| 108 | "csr_vdember", | ||
| 109 | "csr_vdemcer", | ||
| 110 | "csr_vdetper", | ||
| 111 | "cbw_eppu", | ||
| 112 | "cbw_eppv", | ||
| 113 | "cbw_eppy", | ||
| 114 | "cbw_mpeunifbw", | ||
| 115 | "cbw_viwsb", | ||
| 116 | "cbw_viwu", | ||
| 117 | "cbw_viwv", | ||
| 118 | "cbw_viwy", | ||
| 119 | "ccw_g2dw", | ||
| 120 | "csw_avpcarm7w", | ||
| 121 | "csw_fdcdwr", | ||
| 122 | "csw_host1xw", | ||
| 123 | "csw_ispw", | ||
| 124 | "csw_mpcorew", | ||
| 125 | "csw_mpecswr", | ||
| 126 | "csw_ppcsahbdmaw", | ||
| 127 | "csw_ppcsahbslvw", | ||
| 128 | "csw_vdebsevw", | ||
| 129 | "csw_vdembew", | ||
| 130 | "csw_vdetpmw", | ||
| 131 | }; | ||
| 132 | |||
| 133 | static void tegra20_mc_decode(struct tegra20_mc *mc, int n) | ||
| 134 | { | ||
| 135 | u32 addr, req; | ||
| 136 | const char *client = "Unknown"; | ||
| 137 | int idx, cid; | ||
| 138 | const struct reg_info { | ||
| 139 | u32 offset; | ||
| 140 | u32 write_bit; /* 0=READ, 1=WRITE */ | ||
| 141 | int cid_shift; | ||
| 142 | char *message; | ||
| 143 | } reg[] = { | ||
| 144 | { | ||
| 145 | .offset = MC_DECERR_EMEM_OTHERS_STATUS, | ||
| 146 | .write_bit = 31, | ||
| 147 | .message = "MC_DECERR", | ||
| 148 | }, | ||
| 149 | { | ||
| 150 | .offset = MC_GART_ERROR_REQ, | ||
| 151 | .cid_shift = 1, | ||
| 152 | .message = "MC_GART_ERR", | ||
| 153 | |||
| 154 | }, | ||
| 155 | { | ||
| 156 | .offset = MC_SECURITY_VIOLATION_STATUS, | ||
| 157 | .write_bit = 31, | ||
| 158 | .message = "MC_SECURITY_ERR", | ||
| 159 | }, | ||
| 160 | }; | ||
| 161 | |||
| 162 | idx = n - MC_INT_ERR_SHIFT; | ||
| 163 | if ((idx < 0) || (idx >= ARRAY_SIZE(reg))) { | ||
| 164 | dev_err_ratelimited(mc->dev, "Unknown interrupt status %08lx\n", | ||
| 165 | BIT(n)); | ||
| 166 | return; | ||
| 167 | } | ||
| 168 | |||
| 169 | req = mc_readl(mc, reg[idx].offset); | ||
| 170 | cid = (req >> reg[idx].cid_shift) & MC_CLIENT_ID_MASK; | ||
| 171 | if (cid < ARRAY_SIZE(tegra20_mc_client)) | ||
| 172 | client = tegra20_mc_client[cid]; | ||
| 173 | |||
| 174 | addr = mc_readl(mc, reg[idx].offset + sizeof(u32)); | ||
| 175 | |||
| 176 | dev_err_ratelimited(mc->dev, "%s (0x%08x): 0x%08x %s (%s %s)\n", | ||
| 177 | reg[idx].message, req, addr, client, | ||
| 178 | (req & BIT(reg[idx].write_bit)) ? "write" : "read", | ||
| 179 | (reg[idx].offset == MC_SECURITY_VIOLATION_STATUS) ? | ||
| 180 | ((req & SECURITY_VIOLATION_TYPE) ? | ||
| 181 | "carveout" : "trustzone") : ""); | ||
| 182 | } | ||
| 183 | |||
| 184 | static const struct of_device_id tegra20_mc_of_match[] __devinitconst = { | ||
| 185 | { .compatible = "nvidia,tegra20-mc", }, | ||
| 186 | {}, | ||
| 187 | }; | ||
| 188 | |||
| 189 | static irqreturn_t tegra20_mc_isr(int irq, void *data) | ||
| 190 | { | ||
| 191 | u32 stat, mask, bit; | ||
| 192 | struct tegra20_mc *mc = data; | ||
| 193 | |||
| 194 | stat = mc_readl(mc, MC_INTSTATUS); | ||
| 195 | mask = mc_readl(mc, MC_INTMASK); | ||
| 196 | mask &= stat; | ||
| 197 | if (!mask) | ||
| 198 | return IRQ_NONE; | ||
| 199 | while ((bit = ffs(mask)) != 0) | ||
| 200 | tegra20_mc_decode(mc, bit - 1); | ||
| 201 | mc_writel(mc, stat, MC_INTSTATUS); | ||
| 202 | return IRQ_HANDLED; | ||
| 203 | } | ||
| 204 | |||
| 205 | static int __devinit tegra20_mc_probe(struct platform_device *pdev) | ||
| 206 | { | ||
| 207 | struct resource *irq; | ||
| 208 | struct tegra20_mc *mc; | ||
| 209 | int i, err; | ||
| 210 | u32 intmask; | ||
| 211 | |||
| 212 | mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL); | ||
| 213 | if (!mc) | ||
| 214 | return -ENOMEM; | ||
| 215 | mc->dev = &pdev->dev; | ||
| 216 | |||
| 217 | for (i = 0; i < ARRAY_SIZE(mc->regs); i++) { | ||
| 218 | struct resource *res; | ||
| 219 | |||
| 220 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); | ||
| 221 | if (!res) | ||
| 222 | return -ENODEV; | ||
| 223 | mc->regs[i] = devm_request_and_ioremap(&pdev->dev, res); | ||
| 224 | if (!mc->regs[i]) | ||
| 225 | return -EBUSY; | ||
| 226 | } | ||
| 227 | |||
| 228 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
| 229 | if (!irq) | ||
| 230 | return -ENODEV; | ||
| 231 | err = devm_request_irq(&pdev->dev, irq->start, tegra20_mc_isr, | ||
| 232 | IRQF_SHARED, dev_name(&pdev->dev), mc); | ||
| 233 | if (err) | ||
| 234 | return -ENODEV; | ||
| 235 | |||
| 236 | platform_set_drvdata(pdev, mc); | ||
| 237 | |||
| 238 | intmask = MC_INT_INVALID_GART_PAGE | | ||
| 239 | MC_INT_DECERR_EMEM | MC_INT_SECURITY_VIOLATION; | ||
| 240 | mc_writel(mc, intmask, MC_INTMASK); | ||
| 241 | return 0; | ||
| 242 | } | ||
| 243 | |||
| 244 | static struct platform_driver tegra20_mc_driver = { | ||
| 245 | .probe = tegra20_mc_probe, | ||
| 246 | .driver = { | ||
| 247 | .name = DRV_NAME, | ||
| 248 | .owner = THIS_MODULE, | ||
| 249 | .of_match_table = tegra20_mc_of_match, | ||
| 250 | }, | ||
| 251 | }; | ||
| 252 | module_platform_driver(tegra20_mc_driver); | ||
| 253 | |||
| 254 | MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>"); | ||
| 255 | MODULE_DESCRIPTION("Tegra20 MC driver"); | ||
| 256 | MODULE_LICENSE("GPL v2"); | ||
| 257 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/drivers/memory/tegra30-mc.c b/drivers/memory/tegra30-mc.c new file mode 100644 index 000000000000..e56ff04eb5cc --- /dev/null +++ b/drivers/memory/tegra30-mc.c | |||
| @@ -0,0 +1,382 @@ | |||
| 1 | /* | ||
| 2 | * Tegra30 Memory Controller | ||
| 3 | * | ||
| 4 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms and conditions of the GNU General Public License, | ||
| 8 | * version 2, as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 13 | * more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License along with | ||
| 16 | * this program; if not, write to the Free Software Foundation, Inc., | ||
| 17 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/ratelimit.h> | ||
| 23 | #include <linux/platform_device.h> | ||
| 24 | #include <linux/interrupt.h> | ||
| 25 | #include <linux/io.h> | ||
| 26 | |||
| 27 | #define DRV_NAME "tegra30-mc" | ||
| 28 | |||
| 29 | #define MC_INTSTATUS 0x0 | ||
| 30 | #define MC_INTMASK 0x4 | ||
| 31 | |||
| 32 | #define MC_INT_ERR_SHIFT 6 | ||
| 33 | #define MC_INT_ERR_MASK (0x1f << MC_INT_ERR_SHIFT) | ||
| 34 | #define MC_INT_DECERR_EMEM BIT(MC_INT_ERR_SHIFT) | ||
| 35 | #define MC_INT_SECURITY_VIOLATION BIT(MC_INT_ERR_SHIFT + 2) | ||
| 36 | #define MC_INT_ARBITRATION_EMEM BIT(MC_INT_ERR_SHIFT + 3) | ||
| 37 | #define MC_INT_INVALID_SMMU_PAGE BIT(MC_INT_ERR_SHIFT + 4) | ||
| 38 | |||
| 39 | #define MC_ERR_STATUS 0x8 | ||
| 40 | #define MC_ERR_ADR 0xc | ||
| 41 | |||
| 42 | #define MC_ERR_TYPE_SHIFT 28 | ||
| 43 | #define MC_ERR_TYPE_MASK (7 << MC_ERR_TYPE_SHIFT) | ||
| 44 | #define MC_ERR_TYPE_DECERR_EMEM 2 | ||
| 45 | #define MC_ERR_TYPE_SECURITY_TRUSTZONE 3 | ||
| 46 | #define MC_ERR_TYPE_SECURITY_CARVEOUT 4 | ||
| 47 | #define MC_ERR_TYPE_INVALID_SMMU_PAGE 6 | ||
| 48 | |||
| 49 | #define MC_ERR_INVALID_SMMU_PAGE_SHIFT 25 | ||
| 50 | #define MC_ERR_INVALID_SMMU_PAGE_MASK (7 << MC_ERR_INVALID_SMMU_PAGE_SHIFT) | ||
| 51 | #define MC_ERR_RW_SHIFT 16 | ||
| 52 | #define MC_ERR_RW BIT(MC_ERR_RW_SHIFT) | ||
| 53 | #define MC_ERR_SECURITY BIT(MC_ERR_RW_SHIFT + 1) | ||
| 54 | |||
| 55 | #define SECURITY_VIOLATION_TYPE BIT(30) /* 0=TRUSTZONE, 1=CARVEOUT */ | ||
| 56 | |||
| 57 | #define MC_EMEM_ARB_CFG 0x90 | ||
| 58 | #define MC_EMEM_ARB_OUTSTANDING_REQ 0x94 | ||
| 59 | #define MC_EMEM_ARB_TIMING_RCD 0x98 | ||
| 60 | #define MC_EMEM_ARB_TIMING_RP 0x9c | ||
| 61 | #define MC_EMEM_ARB_TIMING_RC 0xa0 | ||
| 62 | #define MC_EMEM_ARB_TIMING_RAS 0xa4 | ||
| 63 | #define MC_EMEM_ARB_TIMING_FAW 0xa8 | ||
| 64 | #define MC_EMEM_ARB_TIMING_RRD 0xac | ||
| 65 | #define MC_EMEM_ARB_TIMING_RAP2PRE 0xb0 | ||
| 66 | #define MC_EMEM_ARB_TIMING_WAP2PRE 0xb4 | ||
| 67 | #define MC_EMEM_ARB_TIMING_R2R 0xb8 | ||
| 68 | #define MC_EMEM_ARB_TIMING_W2W 0xbc | ||
| 69 | #define MC_EMEM_ARB_TIMING_R2W 0xc0 | ||
| 70 | #define MC_EMEM_ARB_TIMING_W2R 0xc4 | ||
| 71 | |||
| 72 | #define MC_EMEM_ARB_DA_TURNS 0xd0 | ||
| 73 | #define MC_EMEM_ARB_DA_COVERS 0xd4 | ||
| 74 | #define MC_EMEM_ARB_MISC0 0xd8 | ||
| 75 | #define MC_EMEM_ARB_MISC1 0xdc | ||
| 76 | |||
| 77 | #define MC_EMEM_ARB_RING3_THROTTLE 0xe4 | ||
| 78 | #define MC_EMEM_ARB_OVERRIDE 0xe8 | ||
| 79 | |||
| 80 | #define MC_TIMING_CONTROL 0xfc | ||
| 81 | |||
| 82 | #define MC_CLIENT_ID_MASK 0x7f | ||
| 83 | |||
| 84 | #define NUM_MC_REG_BANKS 4 | ||
| 85 | |||
| 86 | struct tegra30_mc { | ||
| 87 | void __iomem *regs[NUM_MC_REG_BANKS]; | ||
| 88 | struct device *dev; | ||
| 89 | u32 ctx[0]; | ||
| 90 | }; | ||
| 91 | |||
| 92 | static inline u32 mc_readl(struct tegra30_mc *mc, u32 offs) | ||
| 93 | { | ||
| 94 | u32 val = 0; | ||
| 95 | |||
| 96 | if (offs < 0x10) | ||
| 97 | val = readl(mc->regs[0] + offs); | ||
| 98 | if (offs < 0x1f0) | ||
| 99 | val = readl(mc->regs[1] + offs - 0x3c); | ||
| 100 | if (offs < 0x228) | ||
| 101 | val = readl(mc->regs[2] + offs - 0x200); | ||
| 102 | if (offs < 0x400) | ||
| 103 | val = readl(mc->regs[3] + offs - 0x284); | ||
| 104 | |||
| 105 | return val; | ||
| 106 | } | ||
| 107 | |||
| 108 | static inline void mc_writel(struct tegra30_mc *mc, u32 val, u32 offs) | ||
| 109 | { | ||
| 110 | if (offs < 0x10) { | ||
| 111 | writel(val, mc->regs[0] + offs); | ||
| 112 | return; | ||
| 113 | } | ||
| 114 | if (offs < 0x1f0) { | ||
| 115 | writel(val, mc->regs[1] + offs - 0x3c); | ||
| 116 | return; | ||
| 117 | } | ||
| 118 | if (offs < 0x228) { | ||
| 119 | writel(val, mc->regs[2] + offs - 0x200); | ||
| 120 | return; | ||
| 121 | } | ||
| 122 | if (offs < 0x400) { | ||
| 123 | writel(val, mc->regs[3] + offs - 0x284); | ||
| 124 | return; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | static const char * const tegra30_mc_client[] = { | ||
| 129 | "csr_ptcr", | ||
| 130 | "cbr_display0a", | ||
| 131 | "cbr_display0ab", | ||
| 132 | "cbr_display0b", | ||
| 133 | "cbr_display0bb", | ||
| 134 | "cbr_display0c", | ||
| 135 | "cbr_display0cb", | ||
| 136 | "cbr_display1b", | ||
| 137 | "cbr_display1bb", | ||
| 138 | "cbr_eppup", | ||
| 139 | "cbr_g2pr", | ||
| 140 | "cbr_g2sr", | ||
| 141 | "cbr_mpeunifbr", | ||
| 142 | "cbr_viruv", | ||
| 143 | "csr_afir", | ||
| 144 | "csr_avpcarm7r", | ||
| 145 | "csr_displayhc", | ||
| 146 | "csr_displayhcb", | ||
| 147 | "csr_fdcdrd", | ||
| 148 | "csr_fdcdrd2", | ||
| 149 | "csr_g2dr", | ||
| 150 | "csr_hdar", | ||
| 151 | "csr_host1xdmar", | ||
| 152 | "csr_host1xr", | ||
| 153 | "csr_idxsrd", | ||
| 154 | "csr_idxsrd2", | ||
| 155 | "csr_mpe_ipred", | ||
| 156 | "csr_mpeamemrd", | ||
| 157 | "csr_mpecsrd", | ||
| 158 | "csr_ppcsahbdmar", | ||
| 159 | "csr_ppcsahbslvr", | ||
| 160 | "csr_satar", | ||
| 161 | "csr_texsrd", | ||
| 162 | "csr_texsrd2", | ||
| 163 | "csr_vdebsevr", | ||
| 164 | "csr_vdember", | ||
| 165 | "csr_vdemcer", | ||
| 166 | "csr_vdetper", | ||
| 167 | "csr_mpcorelpr", | ||
| 168 | "csr_mpcorer", | ||
| 169 | "cbw_eppu", | ||
| 170 | "cbw_eppv", | ||
| 171 | "cbw_eppy", | ||
| 172 | "cbw_mpeunifbw", | ||
| 173 | "cbw_viwsb", | ||
| 174 | "cbw_viwu", | ||
| 175 | "cbw_viwv", | ||
| 176 | "cbw_viwy", | ||
| 177 | "ccw_g2dw", | ||
| 178 | "csw_afiw", | ||
| 179 | "csw_avpcarm7w", | ||
| 180 | "csw_fdcdwr", | ||
| 181 | "csw_fdcdwr2", | ||
| 182 | "csw_hdaw", | ||
| 183 | "csw_host1xw", | ||
| 184 | "csw_ispw", | ||
| 185 | "csw_mpcorelpw", | ||
| 186 | "csw_mpcorew", | ||
| 187 | "csw_mpecswr", | ||
| 188 | "csw_ppcsahbdmaw", | ||
| 189 | "csw_ppcsahbslvw", | ||
| 190 | "csw_sataw", | ||
| 191 | "csw_vdebsevw", | ||
| 192 | "csw_vdedbgw", | ||
| 193 | "csw_vdembew", | ||
| 194 | "csw_vdetpmw", | ||
| 195 | }; | ||
| 196 | |||
| 197 | static void tegra30_mc_decode(struct tegra30_mc *mc, int n) | ||
| 198 | { | ||
| 199 | u32 err, addr; | ||
| 200 | const char * const mc_int_err[] = { | ||
| 201 | "MC_DECERR", | ||
| 202 | "Unknown", | ||
| 203 | "MC_SECURITY_ERR", | ||
| 204 | "MC_ARBITRATION_EMEM", | ||
| 205 | "MC_SMMU_ERR", | ||
| 206 | }; | ||
| 207 | const char * const err_type[] = { | ||
| 208 | "Unknown", | ||
| 209 | "Unknown", | ||
| 210 | "DECERR_EMEM", | ||
| 211 | "SECURITY_TRUSTZONE", | ||
| 212 | "SECURITY_CARVEOUT", | ||
| 213 | "Unknown", | ||
| 214 | "INVALID_SMMU_PAGE", | ||
| 215 | "Unknown", | ||
| 216 | }; | ||
| 217 | char attr[6]; | ||
| 218 | int cid, perm, type, idx; | ||
| 219 | const char *client = "Unknown"; | ||
| 220 | |||
| 221 | idx = n - MC_INT_ERR_SHIFT; | ||
| 222 | if ((idx < 0) || (idx >= ARRAY_SIZE(mc_int_err)) || (idx == 1)) { | ||
| 223 | dev_err_ratelimited(mc->dev, "Unknown interrupt status %08lx\n", | ||
| 224 | BIT(n)); | ||
| 225 | return; | ||
| 226 | } | ||
| 227 | |||
| 228 | err = readl(mc + MC_ERR_STATUS); | ||
| 229 | |||
| 230 | type = (err & MC_ERR_TYPE_MASK) >> MC_ERR_TYPE_SHIFT; | ||
| 231 | perm = (err & MC_ERR_INVALID_SMMU_PAGE_MASK) >> | ||
| 232 | MC_ERR_INVALID_SMMU_PAGE_SHIFT; | ||
| 233 | if (type == MC_ERR_TYPE_INVALID_SMMU_PAGE) | ||
| 234 | sprintf(attr, "%c-%c-%c", | ||
| 235 | (perm & BIT(2)) ? 'R' : '-', | ||
| 236 | (perm & BIT(1)) ? 'W' : '-', | ||
| 237 | (perm & BIT(0)) ? 'S' : '-'); | ||
| 238 | else | ||
| 239 | attr[0] = '\0'; | ||
| 240 | |||
| 241 | cid = err & MC_CLIENT_ID_MASK; | ||
| 242 | if (cid < ARRAY_SIZE(tegra30_mc_client)) | ||
| 243 | client = tegra30_mc_client[cid]; | ||
| 244 | |||
| 245 | addr = readl(mc + MC_ERR_ADR); | ||
| 246 | |||
| 247 | dev_err_ratelimited(mc->dev, "%s (0x%08x): 0x%08x %s (%s %s %s %s)\n", | ||
| 248 | mc_int_err[idx], err, addr, client, | ||
| 249 | (err & MC_ERR_SECURITY) ? "secure" : "non-secure", | ||
| 250 | (err & MC_ERR_RW) ? "write" : "read", | ||
| 251 | err_type[type], attr); | ||
| 252 | } | ||
| 253 | |||
| 254 | static const u32 tegra30_mc_ctx[] = { | ||
| 255 | MC_EMEM_ARB_CFG, | ||
| 256 | MC_EMEM_ARB_OUTSTANDING_REQ, | ||
| 257 | MC_EMEM_ARB_TIMING_RCD, | ||
| 258 | MC_EMEM_ARB_TIMING_RP, | ||
| 259 | MC_EMEM_ARB_TIMING_RC, | ||
| 260 | MC_EMEM_ARB_TIMING_RAS, | ||
| 261 | MC_EMEM_ARB_TIMING_FAW, | ||
| 262 | MC_EMEM_ARB_TIMING_RRD, | ||
| 263 | MC_EMEM_ARB_TIMING_RAP2PRE, | ||
| 264 | MC_EMEM_ARB_TIMING_WAP2PRE, | ||
| 265 | MC_EMEM_ARB_TIMING_R2R, | ||
| 266 | MC_EMEM_ARB_TIMING_W2W, | ||
| 267 | MC_EMEM_ARB_TIMING_R2W, | ||
| 268 | MC_EMEM_ARB_TIMING_W2R, | ||
| 269 | MC_EMEM_ARB_DA_TURNS, | ||
| 270 | MC_EMEM_ARB_DA_COVERS, | ||
| 271 | MC_EMEM_ARB_MISC0, | ||
| 272 | MC_EMEM_ARB_MISC1, | ||
| 273 | MC_EMEM_ARB_RING3_THROTTLE, | ||
| 274 | MC_EMEM_ARB_OVERRIDE, | ||
| 275 | MC_INTMASK, | ||
| 276 | }; | ||
| 277 | |||
| 278 | static int tegra30_mc_suspend(struct device *dev) | ||
| 279 | { | ||
| 280 | int i; | ||
| 281 | struct tegra30_mc *mc = dev_get_drvdata(dev); | ||
| 282 | |||
| 283 | for (i = 0; i < ARRAY_SIZE(tegra30_mc_ctx); i++) | ||
| 284 | mc->ctx[i] = mc_readl(mc, tegra30_mc_ctx[i]); | ||
| 285 | return 0; | ||
| 286 | } | ||
| 287 | |||
| 288 | static int tegra30_mc_resume(struct device *dev) | ||
| 289 | { | ||
| 290 | int i; | ||
| 291 | struct tegra30_mc *mc = dev_get_drvdata(dev); | ||
| 292 | |||
| 293 | for (i = 0; i < ARRAY_SIZE(tegra30_mc_ctx); i++) | ||
| 294 | mc_writel(mc, mc->ctx[i], tegra30_mc_ctx[i]); | ||
| 295 | |||
| 296 | mc_writel(mc, 1, MC_TIMING_CONTROL); | ||
| 297 | /* Read-back to ensure that write reached */ | ||
| 298 | mc_readl(mc, MC_TIMING_CONTROL); | ||
| 299 | return 0; | ||
| 300 | } | ||
| 301 | |||
| 302 | static UNIVERSAL_DEV_PM_OPS(tegra30_mc_pm, | ||
| 303 | tegra30_mc_suspend, | ||
| 304 | tegra30_mc_resume, NULL); | ||
| 305 | |||
| 306 | static const struct of_device_id tegra30_mc_of_match[] __devinitconst = { | ||
| 307 | { .compatible = "nvidia,tegra30-mc", }, | ||
| 308 | {}, | ||
| 309 | }; | ||
| 310 | |||
| 311 | static irqreturn_t tegra30_mc_isr(int irq, void *data) | ||
| 312 | { | ||
| 313 | u32 stat, mask, bit; | ||
| 314 | struct tegra30_mc *mc = data; | ||
| 315 | |||
| 316 | stat = mc_readl(mc, MC_INTSTATUS); | ||
| 317 | mask = mc_readl(mc, MC_INTMASK); | ||
| 318 | mask &= stat; | ||
| 319 | if (!mask) | ||
| 320 | return IRQ_NONE; | ||
| 321 | while ((bit = ffs(mask)) != 0) | ||
| 322 | tegra30_mc_decode(mc, bit - 1); | ||
| 323 | mc_writel(mc, stat, MC_INTSTATUS); | ||
| 324 | return IRQ_HANDLED; | ||
| 325 | } | ||
| 326 | |||
| 327 | static int __devinit tegra30_mc_probe(struct platform_device *pdev) | ||
| 328 | { | ||
| 329 | struct resource *irq; | ||
| 330 | struct tegra30_mc *mc; | ||
| 331 | size_t bytes; | ||
| 332 | int err, i; | ||
| 333 | u32 intmask; | ||
| 334 | |||
| 335 | bytes = sizeof(*mc) + sizeof(u32) * ARRAY_SIZE(tegra30_mc_ctx); | ||
| 336 | mc = devm_kzalloc(&pdev->dev, bytes, GFP_KERNEL); | ||
| 337 | if (!mc) | ||
| 338 | return -ENOMEM; | ||
| 339 | mc->dev = &pdev->dev; | ||
| 340 | |||
| 341 | for (i = 0; i < ARRAY_SIZE(mc->regs); i++) { | ||
| 342 | struct resource *res; | ||
| 343 | |||
| 344 | res = platform_get_resource(pdev, IORESOURCE_MEM, i); | ||
| 345 | if (!res) | ||
| 346 | return -ENODEV; | ||
| 347 | mc->regs[i] = devm_request_and_ioremap(&pdev->dev, res); | ||
| 348 | if (!mc->regs[i]) | ||
| 349 | return -EBUSY; | ||
| 350 | } | ||
| 351 | |||
| 352 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
| 353 | if (!irq) | ||
| 354 | return -ENODEV; | ||
| 355 | err = devm_request_irq(&pdev->dev, irq->start, tegra30_mc_isr, | ||
| 356 | IRQF_SHARED, dev_name(&pdev->dev), mc); | ||
| 357 | if (err) | ||
| 358 | return -ENODEV; | ||
| 359 | |||
| 360 | platform_set_drvdata(pdev, mc); | ||
| 361 | |||
| 362 | intmask = MC_INT_INVALID_SMMU_PAGE | | ||
| 363 | MC_INT_DECERR_EMEM | MC_INT_SECURITY_VIOLATION; | ||
| 364 | mc_writel(mc, intmask, MC_INTMASK); | ||
| 365 | return 0; | ||
| 366 | } | ||
| 367 | |||
| 368 | static struct platform_driver tegra30_mc_driver = { | ||
| 369 | .probe = tegra30_mc_probe, | ||
| 370 | .driver = { | ||
| 371 | .name = DRV_NAME, | ||
| 372 | .owner = THIS_MODULE, | ||
| 373 | .of_match_table = tegra30_mc_of_match, | ||
| 374 | .pm = &tegra30_mc_pm, | ||
| 375 | }, | ||
| 376 | }; | ||
| 377 | module_platform_driver(tegra30_mc_driver); | ||
| 378 | |||
| 379 | MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>"); | ||
| 380 | MODULE_DESCRIPTION("Tegra30 MC driver"); | ||
| 381 | MODULE_LICENSE("GPL v2"); | ||
| 382 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 968469555956..757fbd0f2a14 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
| @@ -508,14 +508,6 @@ config USB_SWITCH_FSA9480 | |||
| 508 | stereo and mono audio, video, microphone and UART data to use | 508 | stereo and mono audio, video, microphone and UART data to use |
| 509 | a common connector port. | 509 | a common connector port. |
| 510 | 510 | ||
| 511 | config MAX8997_MUIC | ||
| 512 | tristate "MAX8997 MUIC Support" | ||
| 513 | depends on MFD_MAX8997 | ||
| 514 | help | ||
| 515 | If you say yes here you get support for the MUIC device of | ||
| 516 | Maxim MAX8997 PMIC. | ||
| 517 | The MAX8997 MUIC is a USB port accessory detector and switch. | ||
| 518 | |||
| 519 | source "drivers/misc/c2port/Kconfig" | 511 | source "drivers/misc/c2port/Kconfig" |
| 520 | source "drivers/misc/eeprom/Kconfig" | 512 | source "drivers/misc/eeprom/Kconfig" |
| 521 | source "drivers/misc/cb710/Kconfig" | 513 | source "drivers/misc/cb710/Kconfig" |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 509d0569dc04..162861788c6d 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
| @@ -50,4 +50,3 @@ obj-y += lis3lv02d/ | |||
| 50 | obj-y += carma/ | 50 | obj-y += carma/ |
| 51 | obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o | 51 | obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o |
| 52 | obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ | 52 | obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ |
| 53 | obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o | ||
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 402956321d33..5abffe58a9d2 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c | |||
| @@ -2075,7 +2075,7 @@ struct parport *parport_pc_probe_port(unsigned long int base, | |||
| 2075 | 2075 | ||
| 2076 | printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base); | 2076 | printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base); |
| 2077 | if (p->base_hi && priv->ecr) | 2077 | if (p->base_hi && priv->ecr) |
| 2078 | printk(" (0x%lx)", p->base_hi); | 2078 | printk(KERN_CONT " (0x%lx)", p->base_hi); |
| 2079 | if (p->irq == PARPORT_IRQ_AUTO) { | 2079 | if (p->irq == PARPORT_IRQ_AUTO) { |
| 2080 | p->irq = PARPORT_IRQ_NONE; | 2080 | p->irq = PARPORT_IRQ_NONE; |
| 2081 | parport_irq_probe(p); | 2081 | parport_irq_probe(p); |
| @@ -2086,7 +2086,7 @@ struct parport *parport_pc_probe_port(unsigned long int base, | |||
| 2086 | p->irq = PARPORT_IRQ_NONE; | 2086 | p->irq = PARPORT_IRQ_NONE; |
| 2087 | } | 2087 | } |
| 2088 | if (p->irq != PARPORT_IRQ_NONE) { | 2088 | if (p->irq != PARPORT_IRQ_NONE) { |
| 2089 | printk(", irq %d", p->irq); | 2089 | printk(KERN_CONT ", irq %d", p->irq); |
| 2090 | priv->ctr_writable |= 0x10; | 2090 | priv->ctr_writable |= 0x10; |
| 2091 | 2091 | ||
| 2092 | if (p->dma == PARPORT_DMA_AUTO) { | 2092 | if (p->dma == PARPORT_DMA_AUTO) { |
| @@ -2110,21 +2110,21 @@ struct parport *parport_pc_probe_port(unsigned long int base, | |||
| 2110 | /* p->ops->ecp_read_data = parport_pc_ecp_read_block_pio; */ | 2110 | /* p->ops->ecp_read_data = parport_pc_ecp_read_block_pio; */ |
| 2111 | #endif /* IEEE 1284 support */ | 2111 | #endif /* IEEE 1284 support */ |
| 2112 | if (p->dma != PARPORT_DMA_NONE) { | 2112 | if (p->dma != PARPORT_DMA_NONE) { |
| 2113 | printk(", dma %d", p->dma); | 2113 | printk(KERN_CONT ", dma %d", p->dma); |
| 2114 | p->modes |= PARPORT_MODE_DMA; | 2114 | p->modes |= PARPORT_MODE_DMA; |
| 2115 | } else | 2115 | } else |
| 2116 | printk(", using FIFO"); | 2116 | printk(KERN_CONT ", using FIFO"); |
| 2117 | } else | 2117 | } else |
| 2118 | /* We can't use the DMA channel after all. */ | 2118 | /* We can't use the DMA channel after all. */ |
| 2119 | p->dma = PARPORT_DMA_NONE; | 2119 | p->dma = PARPORT_DMA_NONE; |
| 2120 | #endif /* Allowed to use FIFO/DMA */ | 2120 | #endif /* Allowed to use FIFO/DMA */ |
| 2121 | 2121 | ||
| 2122 | printk(" ["); | 2122 | printk(KERN_CONT " ["); |
| 2123 | 2123 | ||
| 2124 | #define printmode(x) \ | 2124 | #define printmode(x) \ |
| 2125 | {\ | 2125 | {\ |
| 2126 | if (p->modes & PARPORT_MODE_##x) {\ | 2126 | if (p->modes & PARPORT_MODE_##x) {\ |
| 2127 | printk("%s%s", f ? "," : "", #x);\ | 2127 | printk(KERN_CONT "%s%s", f ? "," : "", #x);\ |
| 2128 | f++;\ | 2128 | f++;\ |
| 2129 | } \ | 2129 | } \ |
| 2130 | } | 2130 | } |
| @@ -2140,9 +2140,9 @@ struct parport *parport_pc_probe_port(unsigned long int base, | |||
| 2140 | } | 2140 | } |
| 2141 | #undef printmode | 2141 | #undef printmode |
| 2142 | #ifndef CONFIG_PARPORT_1284 | 2142 | #ifndef CONFIG_PARPORT_1284 |
| 2143 | printk("(,...)"); | 2143 | printk(KERN_CONT "(,...)"); |
| 2144 | #endif /* CONFIG_PARPORT_1284 */ | 2144 | #endif /* CONFIG_PARPORT_1284 */ |
| 2145 | printk("]\n"); | 2145 | printk(KERN_CONT "]\n"); |
| 2146 | if (probedirq != PARPORT_IRQ_NONE) | 2146 | if (probedirq != PARPORT_IRQ_NONE) |
| 2147 | printk(KERN_INFO "%s: irq %d detected\n", p->name, probedirq); | 2147 | printk(KERN_INFO "%s: irq %d detected\n", p->name, probedirq); |
| 2148 | 2148 | ||
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index eb1dee26bda3..c706635f3f82 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig | |||
| @@ -53,8 +53,6 @@ config ANDROID_LOW_MEMORY_KILLER | |||
| 53 | ---help--- | 53 | ---help--- |
| 54 | Register processes to be killed when memory is low | 54 | Register processes to be killed when memory is low |
| 55 | 55 | ||
| 56 | source "drivers/staging/android/switch/Kconfig" | ||
| 57 | |||
| 58 | config ANDROID_INTF_ALARM | 56 | config ANDROID_INTF_ALARM |
| 59 | bool "Android alarm driver" | 57 | bool "Android alarm driver" |
| 60 | depends on RTC_CLASS | 58 | depends on RTC_CLASS |
| @@ -80,7 +78,6 @@ config ANDROID_ALARM_OLDDRV_COMPAT | |||
| 80 | Provides preprocessor alias to aid compatability with | 78 | Provides preprocessor alias to aid compatability with |
| 81 | older out-of-tree drivers that use the Android Alarm | 79 | older out-of-tree drivers that use the Android Alarm |
| 82 | in-kernel API. This will be removed eventually. | 80 | in-kernel API. This will be removed eventually. |
| 83 | |||
| 84 | endif # if ANDROID | 81 | endif # if ANDROID |
| 85 | 82 | ||
| 86 | endmenu | 83 | endmenu |
diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile index 9b6c9ed91f69..045d17bde524 100644 --- a/drivers/staging/android/Makefile +++ b/drivers/staging/android/Makefile | |||
| @@ -6,6 +6,5 @@ obj-$(CONFIG_ANDROID_RAM_CONSOLE) += ram_console.o | |||
| 6 | obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o | 6 | obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o |
| 7 | obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o | 7 | obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o |
| 8 | obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o | 8 | obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o |
| 9 | obj-$(CONFIG_ANDROID_SWITCH) += switch/ | ||
| 10 | obj-$(CONFIG_ANDROID_INTF_ALARM) += alarm.o | 9 | obj-$(CONFIG_ANDROID_INTF_ALARM) += alarm.o |
| 11 | obj-$(CONFIG_ANDROID_INTF_ALARM_DEV) += alarm-dev.o | 10 | obj-$(CONFIG_ANDROID_INTF_ALARM_DEV) += alarm-dev.o |
diff --git a/drivers/staging/android/switch/Kconfig b/drivers/staging/android/switch/Kconfig deleted file mode 100644 index 36846f62f4bc..000000000000 --- a/drivers/staging/android/switch/Kconfig +++ /dev/null | |||
| @@ -1,11 +0,0 @@ | |||
| 1 | menuconfig ANDROID_SWITCH | ||
| 2 | tristate "Android Switch class support" | ||
| 3 | help | ||
| 4 | Say Y here to enable Android switch class support. This allows | ||
| 5 | monitoring switches by userspace via sysfs and uevent. | ||
| 6 | |||
| 7 | config ANDROID_SWITCH_GPIO | ||
| 8 | tristate "Android GPIO Switch support" | ||
| 9 | depends on GENERIC_GPIO && ANDROID_SWITCH | ||
| 10 | help | ||
| 11 | Say Y here to enable GPIO based switch support. | ||
diff --git a/drivers/staging/android/switch/Makefile b/drivers/staging/android/switch/Makefile deleted file mode 100644 index d76bfdcedfaf..000000000000 --- a/drivers/staging/android/switch/Makefile +++ /dev/null | |||
| @@ -1,4 +0,0 @@ | |||
| 1 | # Android Switch Class Driver | ||
| 2 | obj-$(CONFIG_ANDROID_SWITCH) += switch_class.o | ||
| 3 | obj-$(CONFIG_ANDROID_SWITCH_GPIO) += switch_gpio.o | ||
| 4 | |||
diff --git a/drivers/staging/android/switch/switch.h b/drivers/staging/android/switch/switch.h deleted file mode 100644 index 4fcb3109875a..000000000000 --- a/drivers/staging/android/switch/switch.h +++ /dev/null | |||
| @@ -1,53 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Switch class driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Google, Inc. | ||
| 5 | * Author: Mike Lockwood <lockwood@android.com> | ||
| 6 | * | ||
| 7 | * This software is licensed under the terms of the GNU General Public | ||
| 8 | * License version 2, as published by the Free Software Foundation, and | ||
| 9 | * may be copied, distributed, and modified under those terms. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #ifndef __LINUX_SWITCH_H__ | ||
| 19 | #define __LINUX_SWITCH_H__ | ||
| 20 | |||
| 21 | struct switch_dev { | ||
| 22 | const char *name; | ||
| 23 | struct device *dev; | ||
| 24 | int index; | ||
| 25 | int state; | ||
| 26 | |||
| 27 | ssize_t (*print_name)(struct switch_dev *sdev, char *buf); | ||
| 28 | ssize_t (*print_state)(struct switch_dev *sdev, char *buf); | ||
| 29 | }; | ||
| 30 | |||
| 31 | struct gpio_switch_platform_data { | ||
| 32 | const char *name; | ||
| 33 | unsigned gpio; | ||
| 34 | |||
| 35 | /* if NULL, switch_dev.name will be printed */ | ||
| 36 | const char *name_on; | ||
| 37 | const char *name_off; | ||
| 38 | /* if NULL, "0" or "1" will be printed */ | ||
| 39 | const char *state_on; | ||
| 40 | const char *state_off; | ||
| 41 | }; | ||
| 42 | |||
| 43 | extern int switch_dev_register(struct switch_dev *sdev); | ||
| 44 | extern void switch_dev_unregister(struct switch_dev *sdev); | ||
| 45 | |||
| 46 | static inline int switch_get_state(struct switch_dev *sdev) | ||
| 47 | { | ||
| 48 | return sdev->state; | ||
| 49 | } | ||
| 50 | |||
| 51 | extern void switch_set_state(struct switch_dev *sdev, int state); | ||
| 52 | |||
| 53 | #endif /* __LINUX_SWITCH_H__ */ | ||
diff --git a/drivers/staging/android/switch/switch_class.c b/drivers/staging/android/switch/switch_class.c deleted file mode 100644 index 74680446fc66..000000000000 --- a/drivers/staging/android/switch/switch_class.c +++ /dev/null | |||
| @@ -1,174 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * switch_class.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Google, Inc. | ||
| 5 | * Author: Mike Lockwood <lockwood@android.com> | ||
| 6 | * | ||
| 7 | * This software is licensed under the terms of the GNU General Public | ||
| 8 | * License version 2, as published by the Free Software Foundation, and | ||
| 9 | * may be copied, distributed, and modified under those terms. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/types.h> | ||
| 20 | #include <linux/init.h> | ||
| 21 | #include <linux/device.h> | ||
| 22 | #include <linux/fs.h> | ||
| 23 | #include <linux/err.h> | ||
| 24 | #include "switch.h" | ||
| 25 | |||
| 26 | struct class *switch_class; | ||
| 27 | static atomic_t device_count; | ||
| 28 | |||
| 29 | static ssize_t state_show(struct device *dev, struct device_attribute *attr, | ||
| 30 | char *buf) | ||
| 31 | { | ||
| 32 | struct switch_dev *sdev = (struct switch_dev *) | ||
| 33 | dev_get_drvdata(dev); | ||
| 34 | |||
| 35 | if (sdev->print_state) { | ||
| 36 | int ret = sdev->print_state(sdev, buf); | ||
| 37 | if (ret >= 0) | ||
| 38 | return ret; | ||
| 39 | } | ||
| 40 | return sprintf(buf, "%d\n", sdev->state); | ||
| 41 | } | ||
| 42 | |||
| 43 | static ssize_t name_show(struct device *dev, struct device_attribute *attr, | ||
| 44 | char *buf) | ||
| 45 | { | ||
| 46 | struct switch_dev *sdev = (struct switch_dev *) | ||
| 47 | dev_get_drvdata(dev); | ||
| 48 | |||
| 49 | if (sdev->print_name) { | ||
| 50 | int ret = sdev->print_name(sdev, buf); | ||
| 51 | if (ret >= 0) | ||
| 52 | return ret; | ||
| 53 | } | ||
| 54 | return sprintf(buf, "%s\n", sdev->name); | ||
| 55 | } | ||
| 56 | |||
| 57 | static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, state_show, NULL); | ||
| 58 | static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, name_show, NULL); | ||
| 59 | |||
| 60 | void switch_set_state(struct switch_dev *sdev, int state) | ||
| 61 | { | ||
| 62 | char name_buf[120]; | ||
| 63 | char state_buf[120]; | ||
| 64 | char *prop_buf; | ||
| 65 | char *envp[3]; | ||
| 66 | int env_offset = 0; | ||
| 67 | int length; | ||
| 68 | |||
| 69 | if (sdev->state != state) { | ||
| 70 | sdev->state = state; | ||
| 71 | |||
| 72 | prop_buf = (char *)get_zeroed_page(GFP_KERNEL); | ||
| 73 | if (prop_buf) { | ||
| 74 | length = name_show(sdev->dev, NULL, prop_buf); | ||
| 75 | if (length > 0) { | ||
| 76 | if (prop_buf[length - 1] == '\n') | ||
| 77 | prop_buf[length - 1] = 0; | ||
| 78 | snprintf(name_buf, sizeof(name_buf), | ||
| 79 | "SWITCH_NAME=%s", prop_buf); | ||
| 80 | envp[env_offset++] = name_buf; | ||
| 81 | } | ||
| 82 | length = state_show(sdev->dev, NULL, prop_buf); | ||
| 83 | if (length > 0) { | ||
| 84 | if (prop_buf[length - 1] == '\n') | ||
| 85 | prop_buf[length - 1] = 0; | ||
| 86 | snprintf(state_buf, sizeof(state_buf), | ||
| 87 | "SWITCH_STATE=%s", prop_buf); | ||
| 88 | envp[env_offset++] = state_buf; | ||
| 89 | } | ||
| 90 | envp[env_offset] = NULL; | ||
| 91 | kobject_uevent_env(&sdev->dev->kobj, KOBJ_CHANGE, envp); | ||
| 92 | free_page((unsigned long)prop_buf); | ||
| 93 | } else { | ||
| 94 | printk(KERN_ERR "out of memory in switch_set_state\n"); | ||
| 95 | kobject_uevent(&sdev->dev->kobj, KOBJ_CHANGE); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | } | ||
| 99 | EXPORT_SYMBOL_GPL(switch_set_state); | ||
| 100 | |||
| 101 | static int create_switch_class(void) | ||
| 102 | { | ||
| 103 | if (!switch_class) { | ||
| 104 | switch_class = class_create(THIS_MODULE, "switch"); | ||
| 105 | if (IS_ERR(switch_class)) | ||
| 106 | return PTR_ERR(switch_class); | ||
| 107 | atomic_set(&device_count, 0); | ||
| 108 | } | ||
| 109 | |||
| 110 | return 0; | ||
| 111 | } | ||
| 112 | |||
| 113 | int switch_dev_register(struct switch_dev *sdev) | ||
| 114 | { | ||
| 115 | int ret; | ||
| 116 | |||
| 117 | if (!switch_class) { | ||
| 118 | ret = create_switch_class(); | ||
| 119 | if (ret < 0) | ||
| 120 | return ret; | ||
| 121 | } | ||
| 122 | |||
| 123 | sdev->index = atomic_inc_return(&device_count); | ||
| 124 | sdev->dev = device_create(switch_class, NULL, | ||
| 125 | MKDEV(0, sdev->index), NULL, sdev->name); | ||
| 126 | if (IS_ERR(sdev->dev)) | ||
| 127 | return PTR_ERR(sdev->dev); | ||
| 128 | |||
| 129 | ret = device_create_file(sdev->dev, &dev_attr_state); | ||
| 130 | if (ret < 0) | ||
| 131 | goto err_create_file_1; | ||
| 132 | ret = device_create_file(sdev->dev, &dev_attr_name); | ||
| 133 | if (ret < 0) | ||
| 134 | goto err_create_file_2; | ||
| 135 | |||
| 136 | dev_set_drvdata(sdev->dev, sdev); | ||
| 137 | sdev->state = 0; | ||
| 138 | return 0; | ||
| 139 | |||
| 140 | err_create_file_2: | ||
| 141 | device_remove_file(sdev->dev, &dev_attr_state); | ||
| 142 | err_create_file_1: | ||
| 143 | device_destroy(switch_class, MKDEV(0, sdev->index)); | ||
| 144 | printk(KERN_ERR "switch: Failed to register driver %s\n", sdev->name); | ||
| 145 | |||
| 146 | return ret; | ||
| 147 | } | ||
| 148 | EXPORT_SYMBOL_GPL(switch_dev_register); | ||
| 149 | |||
| 150 | void switch_dev_unregister(struct switch_dev *sdev) | ||
| 151 | { | ||
| 152 | device_remove_file(sdev->dev, &dev_attr_name); | ||
| 153 | device_remove_file(sdev->dev, &dev_attr_state); | ||
| 154 | device_destroy(switch_class, MKDEV(0, sdev->index)); | ||
| 155 | dev_set_drvdata(sdev->dev, NULL); | ||
| 156 | } | ||
| 157 | EXPORT_SYMBOL_GPL(switch_dev_unregister); | ||
| 158 | |||
| 159 | static int __init switch_class_init(void) | ||
| 160 | { | ||
| 161 | return create_switch_class(); | ||
| 162 | } | ||
| 163 | |||
| 164 | static void __exit switch_class_exit(void) | ||
| 165 | { | ||
| 166 | class_destroy(switch_class); | ||
| 167 | } | ||
| 168 | |||
| 169 | module_init(switch_class_init); | ||
| 170 | module_exit(switch_class_exit); | ||
| 171 | |||
| 172 | MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); | ||
| 173 | MODULE_DESCRIPTION("Switch class driver"); | ||
| 174 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/staging/android/switch/switch_gpio.c b/drivers/staging/android/switch/switch_gpio.c deleted file mode 100644 index 38b2c2f6004e..000000000000 --- a/drivers/staging/android/switch/switch_gpio.c +++ /dev/null | |||
| @@ -1,172 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * switch_gpio.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Google, Inc. | ||
| 5 | * Author: Mike Lockwood <lockwood@android.com> | ||
| 6 | * | ||
| 7 | * This software is licensed under the terms of the GNU General Public | ||
| 8 | * License version 2, as published by the Free Software Foundation, and | ||
| 9 | * may be copied, distributed, and modified under those terms. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/kernel.h> | ||
| 20 | #include <linux/init.h> | ||
| 21 | #include <linux/interrupt.h> | ||
| 22 | #include <linux/platform_device.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include <linux/workqueue.h> | ||
| 25 | #include <linux/gpio.h> | ||
| 26 | #include "switch.h" | ||
| 27 | |||
| 28 | struct gpio_switch_data { | ||
| 29 | struct switch_dev sdev; | ||
| 30 | unsigned gpio; | ||
| 31 | const char *name_on; | ||
| 32 | const char *name_off; | ||
| 33 | const char *state_on; | ||
| 34 | const char *state_off; | ||
| 35 | int irq; | ||
| 36 | struct work_struct work; | ||
| 37 | }; | ||
| 38 | |||
| 39 | static void gpio_switch_work(struct work_struct *work) | ||
| 40 | { | ||
| 41 | int state; | ||
| 42 | struct gpio_switch_data *data = | ||
| 43 | container_of(work, struct gpio_switch_data, work); | ||
| 44 | |||
| 45 | state = gpio_get_value(data->gpio); | ||
| 46 | switch_set_state(&data->sdev, state); | ||
| 47 | } | ||
| 48 | |||
| 49 | static irqreturn_t gpio_irq_handler(int irq, void *dev_id) | ||
| 50 | { | ||
| 51 | struct gpio_switch_data *switch_data = | ||
| 52 | (struct gpio_switch_data *)dev_id; | ||
| 53 | |||
| 54 | schedule_work(&switch_data->work); | ||
| 55 | return IRQ_HANDLED; | ||
| 56 | } | ||
| 57 | |||
| 58 | static ssize_t switch_gpio_print_state(struct switch_dev *sdev, char *buf) | ||
| 59 | { | ||
| 60 | struct gpio_switch_data *switch_data = | ||
| 61 | container_of(sdev, struct gpio_switch_data, sdev); | ||
| 62 | const char *state; | ||
| 63 | if (switch_get_state(sdev)) | ||
| 64 | state = switch_data->state_on; | ||
| 65 | else | ||
| 66 | state = switch_data->state_off; | ||
| 67 | |||
| 68 | if (state) | ||
| 69 | return sprintf(buf, "%s\n", state); | ||
| 70 | return -1; | ||
| 71 | } | ||
| 72 | |||
| 73 | static int gpio_switch_probe(struct platform_device *pdev) | ||
| 74 | { | ||
| 75 | struct gpio_switch_platform_data *pdata = pdev->dev.platform_data; | ||
| 76 | struct gpio_switch_data *switch_data; | ||
| 77 | int ret = 0; | ||
| 78 | |||
| 79 | if (!pdata) | ||
| 80 | return -EBUSY; | ||
| 81 | |||
| 82 | switch_data = kzalloc(sizeof(struct gpio_switch_data), GFP_KERNEL); | ||
| 83 | if (!switch_data) | ||
| 84 | return -ENOMEM; | ||
| 85 | |||
| 86 | switch_data->sdev.name = pdata->name; | ||
| 87 | switch_data->gpio = pdata->gpio; | ||
| 88 | switch_data->name_on = pdata->name_on; | ||
| 89 | switch_data->name_off = pdata->name_off; | ||
| 90 | switch_data->state_on = pdata->state_on; | ||
| 91 | switch_data->state_off = pdata->state_off; | ||
| 92 | switch_data->sdev.print_state = switch_gpio_print_state; | ||
| 93 | |||
| 94 | ret = switch_dev_register(&switch_data->sdev); | ||
| 95 | if (ret < 0) | ||
| 96 | goto err_switch_dev_register; | ||
| 97 | |||
| 98 | ret = gpio_request(switch_data->gpio, pdev->name); | ||
| 99 | if (ret < 0) | ||
| 100 | goto err_request_gpio; | ||
| 101 | |||
| 102 | ret = gpio_direction_input(switch_data->gpio); | ||
| 103 | if (ret < 0) | ||
| 104 | goto err_set_gpio_input; | ||
| 105 | |||
| 106 | INIT_WORK(&switch_data->work, gpio_switch_work); | ||
| 107 | |||
| 108 | switch_data->irq = gpio_to_irq(switch_data->gpio); | ||
| 109 | if (switch_data->irq < 0) { | ||
| 110 | ret = switch_data->irq; | ||
| 111 | goto err_detect_irq_num_failed; | ||
| 112 | } | ||
| 113 | |||
| 114 | ret = request_irq(switch_data->irq, gpio_irq_handler, | ||
| 115 | IRQF_TRIGGER_LOW, pdev->name, switch_data); | ||
| 116 | if (ret < 0) | ||
| 117 | goto err_request_irq; | ||
| 118 | |||
| 119 | /* Perform initial detection */ | ||
| 120 | gpio_switch_work(&switch_data->work); | ||
| 121 | |||
| 122 | return 0; | ||
| 123 | |||
| 124 | err_request_irq: | ||
| 125 | err_detect_irq_num_failed: | ||
| 126 | err_set_gpio_input: | ||
| 127 | gpio_free(switch_data->gpio); | ||
| 128 | err_request_gpio: | ||
| 129 | switch_dev_unregister(&switch_data->sdev); | ||
| 130 | err_switch_dev_register: | ||
| 131 | kfree(switch_data); | ||
| 132 | |||
| 133 | return ret; | ||
| 134 | } | ||
| 135 | |||
| 136 | static int __devexit gpio_switch_remove(struct platform_device *pdev) | ||
| 137 | { | ||
| 138 | struct gpio_switch_data *switch_data = platform_get_drvdata(pdev); | ||
| 139 | |||
| 140 | cancel_work_sync(&switch_data->work); | ||
| 141 | gpio_free(switch_data->gpio); | ||
| 142 | switch_dev_unregister(&switch_data->sdev); | ||
| 143 | kfree(switch_data); | ||
| 144 | |||
| 145 | return 0; | ||
| 146 | } | ||
| 147 | |||
| 148 | static struct platform_driver gpio_switch_driver = { | ||
| 149 | .probe = gpio_switch_probe, | ||
| 150 | .remove = __devexit_p(gpio_switch_remove), | ||
| 151 | .driver = { | ||
| 152 | .name = "switch-gpio", | ||
| 153 | .owner = THIS_MODULE, | ||
| 154 | }, | ||
| 155 | }; | ||
| 156 | |||
| 157 | static int __init gpio_switch_init(void) | ||
| 158 | { | ||
| 159 | return platform_driver_register(&gpio_switch_driver); | ||
| 160 | } | ||
| 161 | |||
| 162 | static void __exit gpio_switch_exit(void) | ||
| 163 | { | ||
| 164 | platform_driver_unregister(&gpio_switch_driver); | ||
| 165 | } | ||
| 166 | |||
| 167 | module_init(gpio_switch_init); | ||
| 168 | module_exit(gpio_switch_exit); | ||
| 169 | |||
| 170 | MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); | ||
| 171 | MODULE_DESCRIPTION("GPIO Switch driver"); | ||
| 172 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index b98371d93a92..42202cd83158 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c | |||
| @@ -146,6 +146,14 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev) | |||
| 146 | priv->flags = 0; /* interrupt is enabled to begin with */ | 146 | priv->flags = 0; /* interrupt is enabled to begin with */ |
| 147 | priv->pdev = pdev; | 147 | priv->pdev = pdev; |
| 148 | 148 | ||
| 149 | if (!uioinfo->irq) { | ||
| 150 | ret = platform_get_irq(pdev, 0); | ||
| 151 | if (ret < 0) { | ||
| 152 | dev_err(&pdev->dev, "failed to get IRQ\n"); | ||
| 153 | goto bad0; | ||
| 154 | } | ||
| 155 | uioinfo->irq = ret; | ||
| 156 | } | ||
| 149 | uiomem = &uioinfo->mem[0]; | 157 | uiomem = &uioinfo->mem[0]; |
| 150 | 158 | ||
| 151 | for (i = 0; i < pdev->num_resources; ++i) { | 159 | for (i = 0; i < pdev->num_resources; ++i) { |
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 566d9f94f735..9a56e3adf476 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c | |||
| @@ -73,7 +73,7 @@ set_bConfigurationValue(struct device *dev, struct device_attribute *attr, | |||
| 73 | return (value < 0) ? value : count; | 73 | return (value < 0) ? value : count; |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, | 76 | static DEVICE_ATTR_IGNORE_LOCKDEP(bConfigurationValue, S_IRUGO | S_IWUSR, |
| 77 | show_bConfigurationValue, set_bConfigurationValue); | 77 | show_bConfigurationValue, set_bConfigurationValue); |
| 78 | 78 | ||
| 79 | /* String fields */ | 79 | /* String fields */ |
| @@ -595,7 +595,7 @@ static ssize_t usb_dev_authorized_store(struct device *dev, | |||
| 595 | return result < 0? result : size; | 595 | return result < 0? result : size; |
| 596 | } | 596 | } |
| 597 | 597 | ||
| 598 | static DEVICE_ATTR(authorized, 0644, | 598 | static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, 0644, |
| 599 | usb_dev_authorized_show, usb_dev_authorized_store); | 599 | usb_dev_authorized_show, usb_dev_authorized_store); |
| 600 | 600 | ||
| 601 | /* "Safely remove a device" */ | 601 | /* "Safely remove a device" */ |
| @@ -618,7 +618,7 @@ static ssize_t usb_remove_store(struct device *dev, | |||
| 618 | usb_unlock_device(udev); | 618 | usb_unlock_device(udev); |
| 619 | return rc; | 619 | return rc; |
| 620 | } | 620 | } |
| 621 | static DEVICE_ATTR(remove, 0200, NULL, usb_remove_store); | 621 | static DEVICE_ATTR_IGNORE_LOCKDEP(remove, 0200, NULL, usb_remove_store); |
| 622 | 622 | ||
| 623 | 623 | ||
| 624 | static struct attribute *dev_attrs[] = { | 624 | static struct attribute *dev_attrs[] = { |
diff --git a/drivers/w1/slaves/w1_ds2408.c b/drivers/w1/slaves/w1_ds2408.c index 7c8cdb8aed26..8e813eed0f0a 100644 --- a/drivers/w1/slaves/w1_ds2408.c +++ b/drivers/w1/slaves/w1_ds2408.c | |||
| @@ -332,7 +332,6 @@ static struct bin_attribute w1_f29_sysfs_bin_files[NB_SYSFS_BIN_FILES] = { | |||
| 332 | }, | 332 | }, |
| 333 | .size = 1, | 333 | .size = 1, |
| 334 | .read = w1_f29_read_cond_search_mask, | 334 | .read = w1_f29_read_cond_search_mask, |
| 335 | .write = 0, | ||
| 336 | }, | 335 | }, |
| 337 | { | 336 | { |
| 338 | .attr = { | 337 | .attr = { |
| @@ -341,7 +340,6 @@ static struct bin_attribute w1_f29_sysfs_bin_files[NB_SYSFS_BIN_FILES] = { | |||
| 341 | }, | 340 | }, |
| 342 | .size = 1, | 341 | .size = 1, |
| 343 | .read = w1_f29_read_cond_search_polarity, | 342 | .read = w1_f29_read_cond_search_polarity, |
| 344 | .write = 0, | ||
| 345 | }, | 343 | }, |
| 346 | { | 344 | { |
| 347 | .attr = { | 345 | .attr = { |
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 9761950697b4..2f2e894ea0c8 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c | |||
| @@ -1027,7 +1027,7 @@ static int __init w1_init(void) | |||
| 1027 | retval = driver_register(&w1_slave_driver); | 1027 | retval = driver_register(&w1_slave_driver); |
| 1028 | if (retval) { | 1028 | if (retval) { |
| 1029 | printk(KERN_ERR | 1029 | printk(KERN_ERR |
| 1030 | "Failed to register master driver. err=%d.\n", | 1030 | "Failed to register slave driver. err=%d.\n", |
| 1031 | retval); | 1031 | retval); |
| 1032 | goto err_out_master_unregister; | 1032 | goto err_out_master_unregister; |
| 1033 | } | 1033 | } |
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c index 3135b2c63998..e10acc237733 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c | |||
| @@ -31,6 +31,9 @@ | |||
| 31 | static int w1_delay_parm = 1; | 31 | static int w1_delay_parm = 1; |
| 32 | module_param_named(delay_coef, w1_delay_parm, int, 0); | 32 | module_param_named(delay_coef, w1_delay_parm, int, 0); |
| 33 | 33 | ||
| 34 | static int w1_disable_irqs = 0; | ||
| 35 | module_param_named(disable_irqs, w1_disable_irqs, int, 0); | ||
| 36 | |||
| 34 | static u8 w1_crc8_table[] = { | 37 | static u8 w1_crc8_table[] = { |
| 35 | 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65, | 38 | 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65, |
| 36 | 157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220, | 39 | 157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220, |
| @@ -79,6 +82,10 @@ static u8 w1_touch_bit(struct w1_master *dev, int bit) | |||
| 79 | */ | 82 | */ |
| 80 | static void w1_write_bit(struct w1_master *dev, int bit) | 83 | static void w1_write_bit(struct w1_master *dev, int bit) |
| 81 | { | 84 | { |
| 85 | unsigned long flags = 0; | ||
| 86 | |||
| 87 | if(w1_disable_irqs) local_irq_save(flags); | ||
| 88 | |||
| 82 | if (bit) { | 89 | if (bit) { |
| 83 | dev->bus_master->write_bit(dev->bus_master->data, 0); | 90 | dev->bus_master->write_bit(dev->bus_master->data, 0); |
| 84 | w1_delay(6); | 91 | w1_delay(6); |
| @@ -90,6 +97,8 @@ static void w1_write_bit(struct w1_master *dev, int bit) | |||
| 90 | dev->bus_master->write_bit(dev->bus_master->data, 1); | 97 | dev->bus_master->write_bit(dev->bus_master->data, 1); |
| 91 | w1_delay(10); | 98 | w1_delay(10); |
| 92 | } | 99 | } |
| 100 | |||
| 101 | if(w1_disable_irqs) local_irq_restore(flags); | ||
| 93 | } | 102 | } |
| 94 | 103 | ||
| 95 | /** | 104 | /** |
| @@ -158,7 +167,7 @@ EXPORT_SYMBOL_GPL(w1_write_8); | |||
| 158 | static u8 w1_read_bit(struct w1_master *dev) | 167 | static u8 w1_read_bit(struct w1_master *dev) |
| 159 | { | 168 | { |
| 160 | int result; | 169 | int result; |
| 161 | unsigned long flags; | 170 | unsigned long flags = 0; |
| 162 | 171 | ||
| 163 | /* sample timing is critical here */ | 172 | /* sample timing is critical here */ |
| 164 | local_irq_save(flags); | 173 | local_irq_save(flags); |
| @@ -318,6 +327,9 @@ EXPORT_SYMBOL_GPL(w1_read_block); | |||
| 318 | int w1_reset_bus(struct w1_master *dev) | 327 | int w1_reset_bus(struct w1_master *dev) |
| 319 | { | 328 | { |
| 320 | int result; | 329 | int result; |
| 330 | unsigned long flags = 0; | ||
| 331 | |||
| 332 | if(w1_disable_irqs) local_irq_save(flags); | ||
| 321 | 333 | ||
| 322 | if (dev->bus_master->reset_bus) | 334 | if (dev->bus_master->reset_bus) |
| 323 | result = dev->bus_master->reset_bus(dev->bus_master->data) & 0x1; | 335 | result = dev->bus_master->reset_bus(dev->bus_master->data) & 0x1; |
| @@ -330,19 +342,21 @@ int w1_reset_bus(struct w1_master *dev) | |||
| 330 | * cpu for such a short amount of time AND get it back in | 342 | * cpu for such a short amount of time AND get it back in |
| 331 | * the maximum amount of time. | 343 | * the maximum amount of time. |
| 332 | */ | 344 | */ |
| 333 | w1_delay(480); | 345 | w1_delay(500); |
| 334 | dev->bus_master->write_bit(dev->bus_master->data, 1); | 346 | dev->bus_master->write_bit(dev->bus_master->data, 1); |
| 335 | w1_delay(70); | 347 | w1_delay(70); |
| 336 | 348 | ||
| 337 | result = dev->bus_master->read_bit(dev->bus_master->data) & 0x1; | 349 | result = dev->bus_master->read_bit(dev->bus_master->data) & 0x1; |
| 338 | /* minmum 70 (above) + 410 = 480 us | 350 | /* minmum 70 (above) + 430 = 500 us |
| 339 | * There aren't any timing requirements between a reset and | 351 | * There aren't any timing requirements between a reset and |
| 340 | * the following transactions. Sleeping is safe here. | 352 | * the following transactions. Sleeping is safe here. |
| 341 | */ | 353 | */ |
| 342 | /* w1_delay(410); min required time */ | 354 | /* w1_delay(430); min required time */ |
| 343 | msleep(1); | 355 | msleep(1); |
| 344 | } | 356 | } |
| 345 | 357 | ||
| 358 | if(w1_disable_irqs) local_irq_restore(flags); | ||
| 359 | |||
| 346 | return result; | 360 | return result; |
| 347 | } | 361 | } |
| 348 | EXPORT_SYMBOL_GPL(w1_reset_bus); | 362 | EXPORT_SYMBOL_GPL(w1_reset_bus); |
